merge the formfield patch from ooo-build
[ooovba.git] / drawinglayer / source / primitive2d / sceneprimitive2d.cxx
bloba50ab8ed05a2205c3a088e26d3269267e9d1ff65
1 /*************************************************************************
3 * OpenOffice.org - a multi-platform office productivity suite
5 * $RCSfile: sceneprimitive2d.cxx,v $
7 * $Revision: 1.16 $
9 * last change: $Author: aw $ $Date: 2008-06-24 15:31:08 $
11 * The Contents of this file are made available subject to
12 * the terms of GNU Lesser General Public License Version 2.1.
15 * GNU Lesser General Public License Version 2.1
16 * =============================================
17 * Copyright 2005 by Sun Microsystems, Inc.
18 * 901 San Antonio Road, Palo Alto, CA 94303, USA
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License version 2.1, as published by the Free Software Foundation.
24 * This library is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * Lesser General Public License for more details.
29 * You should have received a copy of the GNU Lesser General Public
30 * License along with this library; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
32 * MA 02111-1307 USA
34 ************************************************************************/
36 // MARKER(update_precomp.py): autogen include statement, do not remove
37 #include "precompiled_drawinglayer.hxx"
39 #include <drawinglayer/primitive2d/sceneprimitive2d.hxx>
40 #include <basegfx/tools/canvastools.hxx>
41 #include <basegfx/polygon/b2dpolygontools.hxx>
42 #include <basegfx/polygon/b2dpolygon.hxx>
43 #include <basegfx/polygon/b2dpolygonclipper.hxx>
44 #include <basegfx/polygon/b2dpolypolygontools.hxx>
45 #include <basegfx/matrix/b2dhommatrix.hxx>
46 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
47 #include <drawinglayer/processor3d/zbufferprocessor3d.hxx>
48 #include <drawinglayer/processor3d/shadow3dextractor.hxx>
49 #include <drawinglayer/geometry/viewinformation2d.hxx>
50 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
51 #include <svtools/optionsdrawinglayer.hxx>
52 #include <drawinglayer/processor3d/geometry2dextractor.hxx>
53 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
55 //////////////////////////////////////////////////////////////////////////////
57 using namespace com::sun::star;
59 //////////////////////////////////////////////////////////////////////////////
61 namespace drawinglayer
63 namespace primitive2d
65 bool ScenePrimitive2D::impGetShadow3D(const geometry::ViewInformation2D& /*rViewInformation*/) const
67 ::osl::MutexGuard aGuard( m_aMutex );
69 // create on demand
70 if(!mbShadow3DChecked && getChildren3D().hasElements())
72 basegfx::B3DVector aLightNormal;
73 const double fShadowSlant(getSdrSceneAttribute().getShadowSlant());
74 const basegfx::B3DRange aScene3DRange(primitive3d::getB3DRangeFromPrimitive3DSequence(getChildren3D(), getViewInformation3D()));
76 if(maSdrLightingAttribute.getLightVector().size())
78 // get light normal from first light and normalize
79 aLightNormal = maSdrLightingAttribute.getLightVector()[0].getDirection();
80 aLightNormal.normalize();
83 // create shadow extraction processor
84 processor3d::Shadow3DExtractingProcessor aShadowProcessor(
85 getViewInformation3D(),
86 getObjectTransformation(),
87 aLightNormal,
88 fShadowSlant,
89 aScene3DRange);
91 // process local primitives
92 aShadowProcessor.process(getChildren3D());
94 // fetch result and set checked flag
95 const_cast< ScenePrimitive2D* >(this)->maShadowPrimitives = aShadowProcessor.getPrimitive2DSequence();
96 const_cast< ScenePrimitive2D* >(this)->mbShadow3DChecked = true;
99 // return if there are shadow primitives
100 return maShadowPrimitives.hasElements();
103 void ScenePrimitive2D::calculateDsicreteSizes(
104 const geometry::ViewInformation2D& rViewInformation,
105 basegfx::B2DRange& rDiscreteRange,
106 basegfx::B2DRange& rVisibleDiscreteRange,
107 basegfx::B2DRange& rUnitVisibleRange) const
109 // use unit range and transform to discrete coordinates
110 rDiscreteRange = basegfx::B2DRange(0.0, 0.0, 1.0, 1.0);
111 rDiscreteRange.transform(rViewInformation.getObjectToViewTransformation() * getObjectTransformation());
113 // force to discrete expanded bounds (it grows, so expanding works perfectly well)
114 rDiscreteRange.expand(basegfx::B2DTuple(floor(rDiscreteRange.getMinX()), floor(rDiscreteRange.getMinY())));
115 rDiscreteRange.expand(basegfx::B2DTuple(ceil(rDiscreteRange.getMaxX()), ceil(rDiscreteRange.getMaxY())));
117 // clip it against discrete Viewport (if set)
118 rVisibleDiscreteRange = rDiscreteRange;
120 if(!rViewInformation.getViewport().isEmpty())
122 rVisibleDiscreteRange.intersect(rViewInformation.getDiscreteViewport());
124 if(!rVisibleDiscreteRange.isEmpty())
126 // force to discrete expanded bounds, too
127 rVisibleDiscreteRange.expand(basegfx::B2DTuple(floor(rVisibleDiscreteRange.getMinX()), floor(rVisibleDiscreteRange.getMinY())));
128 rVisibleDiscreteRange.expand(basegfx::B2DTuple(ceil(rVisibleDiscreteRange.getMaxX()), ceil(rVisibleDiscreteRange.getMaxY())));
132 if(rVisibleDiscreteRange.isEmpty())
134 rUnitVisibleRange = rVisibleDiscreteRange;
136 else
138 // create UnitVisibleRange containing unit range values [0.0 .. 1.0] describing
139 // the relative position of rVisibleDiscreteRange inside rDiscreteRange
140 const double fDiscreteScaleFactorX(basegfx::fTools::equalZero(rDiscreteRange.getWidth()) ? 1.0 : 1.0 / rDiscreteRange.getWidth());
141 const double fDiscreteScaleFactorY(basegfx::fTools::equalZero(rDiscreteRange.getHeight()) ? 1.0 : 1.0 / rDiscreteRange.getHeight());
143 const double fMinX(basegfx::fTools::equal(rVisibleDiscreteRange.getMinX(), rDiscreteRange.getMinX())
144 ? 0.0
145 : (rVisibleDiscreteRange.getMinX() - rDiscreteRange.getMinX()) * fDiscreteScaleFactorX);
146 const double fMinY(basegfx::fTools::equal(rVisibleDiscreteRange.getMinY(), rDiscreteRange.getMinY())
147 ? 0.0
148 : (rVisibleDiscreteRange.getMinY() - rDiscreteRange.getMinY()) * fDiscreteScaleFactorY);
150 const double fMaxX(basegfx::fTools::equal(rVisibleDiscreteRange.getMaxX(), rDiscreteRange.getMaxX())
151 ? 1.0
152 : (rVisibleDiscreteRange.getMaxX() - rDiscreteRange.getMinX()) * fDiscreteScaleFactorX);
153 const double fMaxY(basegfx::fTools::equal(rVisibleDiscreteRange.getMaxY(), rDiscreteRange.getMaxY())
154 ? 1.0
155 : (rVisibleDiscreteRange.getMaxY() - rDiscreteRange.getMinY()) * fDiscreteScaleFactorY);
157 rUnitVisibleRange = basegfx::B2DRange(fMinX, fMinY, fMaxX, fMaxY);
161 Primitive2DSequence ScenePrimitive2D::createLocalDecomposition(const geometry::ViewInformation2D& rViewInformation) const
163 Primitive2DSequence aRetval;
165 // create 2D shadows from contained 3D primitives. This creates the shadow primitives on demand and tells if
166 // there are some or not. Do this at start, the shadow might still be visible even when the scene is not
167 if(impGetShadow3D(rViewInformation))
169 // test visibility
170 const basegfx::B2DRange aShadow2DRange(getB2DRangeFromPrimitive2DSequence(maShadowPrimitives, rViewInformation));
171 const basegfx::B2DRange aViewRange(rViewInformation.getViewport());
173 if(aViewRange.isEmpty() || aShadow2DRange.overlaps(aViewRange))
175 // add extracted 2d shadows (before 3d scene creations itself)
176 aRetval = maShadowPrimitives;
180 // get the involved ranges (see helper method calculateDsicreteSizes for details)
181 basegfx::B2DRange aDiscreteRange;
182 basegfx::B2DRange aVisibleDiscreteRange;
183 basegfx::B2DRange aUnitVisibleRange;
184 calculateDsicreteSizes(rViewInformation, aDiscreteRange, aVisibleDiscreteRange, aUnitVisibleRange);
186 if(!aVisibleDiscreteRange.isEmpty())
188 // test if discrete view size (pixel) maybe too big and limit it
189 double fViewSizeX(aVisibleDiscreteRange.getWidth());
190 double fViewSizeY(aVisibleDiscreteRange.getHeight());
191 const double fViewVisibleArea(fViewSizeX * fViewSizeY);
192 const SvtOptionsDrawinglayer aDrawinglayerOpt;
193 const double fMaximumVisibleArea(aDrawinglayerOpt.GetQuadratic3DRenderLimit());
194 double fReduceFactor(1.0);
196 if(fViewVisibleArea > fMaximumVisibleArea)
198 fReduceFactor = sqrt(fMaximumVisibleArea / fViewVisibleArea);
199 fViewSizeX *= fReduceFactor;
200 fViewSizeY *= fReduceFactor;
203 // calculate logic render size in world coordinates for usage in renderer
204 basegfx::B2DVector aLogicRenderSize(
205 aDiscreteRange.getWidth() * fReduceFactor,
206 aDiscreteRange.getHeight() * fReduceFactor);
207 aLogicRenderSize *= rViewInformation.getInverseObjectToViewTransformation();
209 // determine the oversample value
210 static bool bDoOversample(false);
211 static sal_uInt16 nDefaultOversampleValue(3);
212 const sal_uInt16 nOversampleValue((bDoOversample || aDrawinglayerOpt.IsAntiAliasing()) ? nDefaultOversampleValue : 0);
214 // use default 3D primitive processor to create BitmapEx for aUnitVisiblePart and process
215 processor3d::ZBufferProcessor3D aZBufferProcessor3D(
216 getViewInformation3D(),
217 rViewInformation,
218 getSdrSceneAttribute(),
219 getSdrLightingAttribute(),
220 aLogicRenderSize.getX(),
221 aLogicRenderSize.getY(),
222 aUnitVisibleRange,
223 nOversampleValue);
225 aZBufferProcessor3D.processNonTransparent(getChildren3D());
226 aZBufferProcessor3D.processTransparent(getChildren3D());
227 const BitmapEx aNewBitmap(aZBufferProcessor3D.getBitmapEx());
228 const Size aBitmapSizePixel(aNewBitmap.GetSizePixel());
230 if(aBitmapSizePixel.getWidth() && aBitmapSizePixel.getHeight())
232 // create transform for the created bitmap in discrete coordinates first.
233 // #i97772# Do not forget to apply evtl. render size reduction to scaling
234 basegfx::B2DHomMatrix aNew2DTransform;
235 const double fSizeReductionFactor(1.0 / fReduceFactor);
237 aNew2DTransform.set(0, 0, (double)(aBitmapSizePixel.getWidth() - 1) * fSizeReductionFactor);
238 aNew2DTransform.set(1, 1, (double)(aBitmapSizePixel.getHeight() - 1) * fSizeReductionFactor);
239 aNew2DTransform.set(0, 2, aVisibleDiscreteRange.getMinX());
240 aNew2DTransform.set(1, 2, aVisibleDiscreteRange.getMinY());
242 // transform back to world coordinates for usage in primitive creation
243 aNew2DTransform *= rViewInformation.getInverseObjectToViewTransformation();
245 // create bitmap primitive and add
246 const Primitive2DReference xRef(new BitmapPrimitive2D(aNewBitmap, aNew2DTransform));
247 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xRef);
249 // test: Allow to add an outline in the debugger when tests are needed
250 static bool bAddOutlineToCreated3DSceneRepresentation(false);
252 if(bAddOutlineToCreated3DSceneRepresentation)
254 basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(0.0, 0.0, 1.0, 1.0)));
255 aOutline.transform(aNew2DTransform);
256 const Primitive2DReference xRef2(new PolygonHairlinePrimitive2D(aOutline, basegfx::BColor(1.0, 0.0, 0.0)));
257 appendPrimitive2DReferenceToPrimitive2DSequence(aRetval, xRef2);
262 return aRetval;
265 Primitive2DSequence ScenePrimitive2D::getGeometry2D(const geometry::ViewInformation2D& rViewInformation) const
267 Primitive2DSequence aRetval;
269 // create 2D shadows from contained 3D primitives
270 if(impGetShadow3D(rViewInformation))
272 // add extracted 2d shadows (before 3d scene creations itself)
273 aRetval = maShadowPrimitives;
276 // create 2D projected geometry from 3D geometry
277 if(getChildren3D().hasElements())
279 // create 2D geometry extraction processor
280 processor3d::Geometry2DExtractingProcessor aGeometryProcessor(
281 getViewInformation3D(),
282 getObjectTransformation());
284 // process local primitives
285 aGeometryProcessor.process(getChildren3D());
287 // fetch result and append
288 Primitive2DSequence a2DExtractedPrimitives(aGeometryProcessor.getPrimitive2DSequence());
289 appendPrimitive2DSequenceToPrimitive2DSequence(aRetval, a2DExtractedPrimitives);
292 return aRetval;
295 ScenePrimitive2D::ScenePrimitive2D(
296 const primitive3d::Primitive3DSequence& rxChildren3D,
297 const attribute::SdrSceneAttribute& rSdrSceneAttribute,
298 const attribute::SdrLightingAttribute& rSdrLightingAttribute,
299 const basegfx::B2DHomMatrix& rObjectTransformation,
300 const geometry::ViewInformation3D& rViewInformation3D)
301 : BasePrimitive2D(),
302 mxChildren3D(rxChildren3D),
303 maSdrSceneAttribute(rSdrSceneAttribute),
304 maSdrLightingAttribute(rSdrLightingAttribute),
305 maObjectTransformation(rObjectTransformation),
306 maViewInformation3D(rViewInformation3D),
307 maShadowPrimitives(),
308 mbShadow3DChecked(false),
309 mfOldDiscreteSizeX(0.0),
310 mfOldDiscreteSizeY(0.0),
311 maOldUnitVisiblePart()
315 bool ScenePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
317 if(BasePrimitive2D::operator==(rPrimitive))
319 const ScenePrimitive2D& rCompare = (ScenePrimitive2D&)rPrimitive;
321 return (primitive3d::arePrimitive3DSequencesEqual(getChildren3D(), rCompare.getChildren3D())
322 && getSdrSceneAttribute() == rCompare.getSdrSceneAttribute()
323 && getSdrLightingAttribute() == rCompare.getSdrLightingAttribute()
324 && getObjectTransformation() == rCompare.getObjectTransformation()
325 && getViewInformation3D() == rCompare.getViewInformation3D());
328 return false;
331 basegfx::B2DRange ScenePrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
333 // transform unit range to discrete coordinate range
334 basegfx::B2DRange aRetval(0.0, 0.0, 1.0, 1.0);
335 aRetval.transform(rViewInformation.getObjectToViewTransformation() * getObjectTransformation());
337 // force to discrete expanded bounds (it grows, so expanding works perfectly well)
338 aRetval.expand(basegfx::B2DTuple(floor(aRetval.getMinX()), floor(aRetval.getMinY())));
339 aRetval.expand(basegfx::B2DTuple(ceil(aRetval.getMaxX()), ceil(aRetval.getMaxY())));
341 // transform back from discrete (view) to world coordinates
342 aRetval.transform(rViewInformation.getInverseObjectToViewTransformation());
344 // expand by evtl. existing shadow primitives
345 if(impGetShadow3D(rViewInformation))
347 const basegfx::B2DRange aShadow2DRange(getB2DRangeFromPrimitive2DSequence(maShadowPrimitives, rViewInformation));
349 if(!aShadow2DRange.isEmpty())
351 aRetval.expand(aShadow2DRange);
355 return aRetval;
358 Primitive2DSequence ScenePrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
360 ::osl::MutexGuard aGuard( m_aMutex );
362 // get the involved ranges (see helper method calculateDsicreteSizes for details)
363 basegfx::B2DRange aDiscreteRange;
364 basegfx::B2DRange aUnitVisibleRange;
365 bool bNeedNewDecomposition(false);
366 bool bDiscreteSizesAreCalculated(false);
368 if(getLocalDecomposition().hasElements())
370 basegfx::B2DRange aVisibleDiscreteRange;
371 calculateDsicreteSizes(rViewInformation, aDiscreteRange, aVisibleDiscreteRange, aUnitVisibleRange);
372 bDiscreteSizesAreCalculated = true;
374 // display has changed and cannot be reused when resolution did change
375 if(!basegfx::fTools::equal(aDiscreteRange.getWidth(), mfOldDiscreteSizeX) ||
376 !basegfx::fTools::equal(aDiscreteRange.getHeight(), mfOldDiscreteSizeY))
378 bNeedNewDecomposition = true;
381 if(!bNeedNewDecomposition)
383 // needs to be painted when the new part is not part of the last
384 // decomposition
385 if(!maOldUnitVisiblePart.isInside(aUnitVisibleRange))
387 bNeedNewDecomposition = true;
392 if(bNeedNewDecomposition)
394 // conditions of last local decomposition have changed, delete
395 const_cast< ScenePrimitive2D* >(this)->setLocalDecomposition(Primitive2DSequence());
398 if(!getLocalDecomposition().hasElements())
400 if(!bDiscreteSizesAreCalculated)
402 basegfx::B2DRange aVisibleDiscreteRange;
403 calculateDsicreteSizes(rViewInformation, aDiscreteRange, aVisibleDiscreteRange, aUnitVisibleRange);
406 // remember last used NewDiscreteSize and NewUnitVisiblePart
407 ScenePrimitive2D* pThat = const_cast< ScenePrimitive2D* >(this);
408 pThat->mfOldDiscreteSizeX = aDiscreteRange.getWidth();
409 pThat->mfOldDiscreteSizeY = aDiscreteRange.getHeight();
410 pThat->maOldUnitVisiblePart = aUnitVisibleRange;
413 // use parent implementation
414 return BasePrimitive2D::get2DDecomposition(rViewInformation);
417 // provide unique ID
418 ImplPrimitrive2DIDBlock(ScenePrimitive2D, PRIMITIVE2D_ID_SCENEPRIMITIVE2D)
420 } // end of namespace primitive2d
421 } // end of namespace drawinglayer
423 //////////////////////////////////////////////////////////////////////////////
424 // eof