1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <drawinglayer/primitive2d/sceneprimitive2d.hxx>
21 #include <basegfx/utils/canvastools.hxx>
22 #include <basegfx/polygon/b2dpolygontools.hxx>
23 #include <basegfx/polygon/b2dpolygon.hxx>
24 #include <basegfx/polygon/b2dpolygonclipper.hxx>
25 #include <basegfx/polygon/b2dpolypolygontools.hxx>
26 #include <basegfx/matrix/b2dhommatrix.hxx>
27 #include <drawinglayer/attribute/sdrlightattribute3d.hxx>
28 #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
29 #include <drawinglayer/processor3d/zbufferprocessor3d.hxx>
30 #include <drawinglayer/processor3d/shadow3dextractor.hxx>
31 #include <drawinglayer/geometry/viewinformation2d.hxx>
32 #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
33 #include <svtools/optionsdrawinglayer.hxx>
34 #include <drawinglayer/processor3d/geometry2dextractor.hxx>
35 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
36 #include <basegfx/raster/bzpixelraster.hxx>
37 #include <vcl/BitmapTools.hxx>
38 #include <comphelper/threadpool.hxx>
40 using namespace com::sun::star
;
44 BitmapEx
BPixelRasterToBitmapEx(const basegfx::BZPixelRaster
& rRaster
, sal_uInt16 mnAntiAlialize
)
47 const sal_uInt32
nWidth(mnAntiAlialize
? rRaster
.getWidth()/mnAntiAlialize
: rRaster
.getWidth());
48 const sal_uInt32
nHeight(mnAntiAlialize
? rRaster
.getHeight()/mnAntiAlialize
: rRaster
.getHeight());
52 const Size
aDestSize(nWidth
, nHeight
);
53 vcl::bitmap::RawBitmap
aContent(aDestSize
, 32);
57 const sal_uInt16
nDivisor(mnAntiAlialize
* mnAntiAlialize
);
59 for(sal_uInt32
y(0); y
< nHeight
; y
++)
61 for(sal_uInt32
x(0); x
< nWidth
; x
++)
66 sal_uInt16
nOpacity(0);
67 sal_uInt32
nIndex(rRaster
.getIndexFromXY(x
* mnAntiAlialize
, y
* mnAntiAlialize
));
69 for(sal_uInt32
c(0); c
< mnAntiAlialize
; c
++)
71 for(sal_uInt32
d(0); d
< mnAntiAlialize
; d
++)
73 const basegfx::BPixel
& rPixel(rRaster
.getBPixel(nIndex
++));
74 nRed
= nRed
+ rPixel
.getRed();
75 nGreen
= nGreen
+ rPixel
.getGreen();
76 nBlue
= nBlue
+ rPixel
.getBlue();
77 nOpacity
= nOpacity
+ rPixel
.getOpacity();
80 nIndex
+= rRaster
.getWidth() - mnAntiAlialize
;
83 nOpacity
= nOpacity
/ nDivisor
;
87 aContent
.SetPixel(y
, x
, Color(
88 255 - static_cast<sal_uInt8
>(nOpacity
),
89 static_cast<sal_uInt8
>(nRed
/ nDivisor
),
90 static_cast<sal_uInt8
>(nGreen
/ nDivisor
),
91 static_cast<sal_uInt8
>(nBlue
/ nDivisor
) ));
94 aContent
.SetPixel(y
, x
, Color(255, 0, 0, 0));
100 sal_uInt32
nIndex(0);
102 for(sal_uInt32
y(0); y
< nHeight
; y
++)
104 for(sal_uInt32
x(0); x
< nWidth
; x
++)
106 const basegfx::BPixel
& rPixel(rRaster
.getBPixel(nIndex
++));
108 if(rPixel
.getOpacity())
110 aContent
.SetPixel(y
, x
, Color(255 - rPixel
.getOpacity(), rPixel
.getRed(), rPixel
.getGreen(), rPixel
.getBlue()));
113 aContent
.SetPixel(y
, x
, Color(255, 0, 0, 0));
118 aRetval
= vcl::bitmap::CreateFromData(std::move(aContent
));
120 // #i101811# set PrefMapMode and PrefSize at newly created Bitmap
121 aRetval
.SetPrefMapMode(MapMode(MapUnit::MapPixel
));
122 aRetval
.SetPrefSize(Size(nWidth
, nHeight
));
127 } // end of anonymous namespace
129 namespace drawinglayer
131 namespace primitive2d
133 bool ScenePrimitive2D::impGetShadow3D() const
135 ::osl::MutexGuard
aGuard( m_aMutex
);
138 if(!mbShadow3DChecked
&& !getChildren3D().empty())
140 basegfx::B3DVector aLightNormal
;
141 const double fShadowSlant(getSdrSceneAttribute().getShadowSlant());
142 const basegfx::B3DRange
aScene3DRange(getChildren3D().getB3DRange(getViewInformation3D()));
144 if(!maSdrLightingAttribute
.getLightVector().empty())
146 // get light normal from first light and normalize
147 aLightNormal
= maSdrLightingAttribute
.getLightVector()[0].getDirection();
148 aLightNormal
.normalize();
151 // create shadow extraction processor
152 processor3d::Shadow3DExtractingProcessor
aShadowProcessor(
153 getViewInformation3D(),
154 getObjectTransformation(),
159 // process local primitives
160 aShadowProcessor
.process(getChildren3D());
162 // fetch result and set checked flag
163 const_cast< ScenePrimitive2D
* >(this)->maShadowPrimitives
= aShadowProcessor
.getPrimitive2DSequence();
164 const_cast< ScenePrimitive2D
* >(this)->mbShadow3DChecked
= true;
167 // return if there are shadow primitives
168 return !maShadowPrimitives
.empty();
171 void ScenePrimitive2D::calculateDiscreteSizes(
172 const geometry::ViewInformation2D
& rViewInformation
,
173 basegfx::B2DRange
& rDiscreteRange
,
174 basegfx::B2DRange
& rVisibleDiscreteRange
,
175 basegfx::B2DRange
& rUnitVisibleRange
) const
177 // use unit range and transform to discrete coordinates
178 rDiscreteRange
= basegfx::B2DRange(0.0, 0.0, 1.0, 1.0);
179 rDiscreteRange
.transform(rViewInformation
.getObjectToViewTransformation() * getObjectTransformation());
181 // clip it against discrete Viewport (if set)
182 rVisibleDiscreteRange
= rDiscreteRange
;
184 if(!rViewInformation
.getViewport().isEmpty())
186 rVisibleDiscreteRange
.intersect(rViewInformation
.getDiscreteViewport());
189 if(rVisibleDiscreteRange
.isEmpty())
191 rUnitVisibleRange
= rVisibleDiscreteRange
;
195 // create UnitVisibleRange containing unit range values [0.0 .. 1.0] describing
196 // the relative position of rVisibleDiscreteRange inside rDiscreteRange
197 const double fDiscreteScaleFactorX(basegfx::fTools::equalZero(rDiscreteRange
.getWidth()) ? 1.0 : 1.0 / rDiscreteRange
.getWidth());
198 const double fDiscreteScaleFactorY(basegfx::fTools::equalZero(rDiscreteRange
.getHeight()) ? 1.0 : 1.0 / rDiscreteRange
.getHeight());
200 const double fMinX(basegfx::fTools::equal(rVisibleDiscreteRange
.getMinX(), rDiscreteRange
.getMinX())
202 : (rVisibleDiscreteRange
.getMinX() - rDiscreteRange
.getMinX()) * fDiscreteScaleFactorX
);
203 const double fMinY(basegfx::fTools::equal(rVisibleDiscreteRange
.getMinY(), rDiscreteRange
.getMinY())
205 : (rVisibleDiscreteRange
.getMinY() - rDiscreteRange
.getMinY()) * fDiscreteScaleFactorY
);
207 const double fMaxX(basegfx::fTools::equal(rVisibleDiscreteRange
.getMaxX(), rDiscreteRange
.getMaxX())
209 : (rVisibleDiscreteRange
.getMaxX() - rDiscreteRange
.getMinX()) * fDiscreteScaleFactorX
);
210 const double fMaxY(basegfx::fTools::equal(rVisibleDiscreteRange
.getMaxY(), rDiscreteRange
.getMaxY())
212 : (rVisibleDiscreteRange
.getMaxY() - rDiscreteRange
.getMinY()) * fDiscreteScaleFactorY
);
214 rUnitVisibleRange
= basegfx::B2DRange(fMinX
, fMinY
, fMaxX
, fMaxY
);
218 void ScenePrimitive2D::create2DDecomposition(Primitive2DContainer
& rContainer
, const geometry::ViewInformation2D
& rViewInformation
) const
220 // create 2D shadows from contained 3D primitives. This creates the shadow primitives on demand and tells if
221 // there are some or not. Do this at start, the shadow might still be visible even when the scene is not
225 const basegfx::B2DRange
aShadow2DRange(maShadowPrimitives
.getB2DRange(rViewInformation
));
226 const basegfx::B2DRange
aViewRange(
227 rViewInformation
.getViewport());
229 if(aViewRange
.isEmpty() || aShadow2DRange
.overlaps(aViewRange
))
231 // add extracted 2d shadows (before 3d scene creations itself)
232 rContainer
.insert(rContainer
.end(), maShadowPrimitives
.begin(), maShadowPrimitives
.end());
236 // get the involved ranges (see helper method calculateDiscreteSizes for details)
237 basegfx::B2DRange aDiscreteRange
;
238 basegfx::B2DRange aVisibleDiscreteRange
;
239 basegfx::B2DRange aUnitVisibleRange
;
241 calculateDiscreteSizes(rViewInformation
, aDiscreteRange
, aVisibleDiscreteRange
, aUnitVisibleRange
);
243 if(!aVisibleDiscreteRange
.isEmpty())
245 // test if discrete view size (pixel) maybe too big and limit it
246 double fViewSizeX(aVisibleDiscreteRange
.getWidth());
247 double fViewSizeY(aVisibleDiscreteRange
.getHeight());
248 const double fViewVisibleArea(fViewSizeX
* fViewSizeY
);
249 const SvtOptionsDrawinglayer aDrawinglayerOpt
;
250 const double fMaximumVisibleArea(aDrawinglayerOpt
.GetQuadratic3DRenderLimit());
251 double fReduceFactor(1.0);
253 if(fViewVisibleArea
> fMaximumVisibleArea
)
255 fReduceFactor
= sqrt(fMaximumVisibleArea
/ fViewVisibleArea
);
256 fViewSizeX
*= fReduceFactor
;
257 fViewSizeY
*= fReduceFactor
;
260 if(rViewInformation
.getReducedDisplayQuality())
262 // when reducing the visualisation is allowed (e.g. an OverlayObject
263 // only needed for dragging), reduce resolution extra
264 // to speed up dragging interactions
265 const double fArea(fViewSizeX
* fViewSizeY
);
268 double fReducedVisualisationFactor(1.0 / (sqrt(fArea
) * (1.0 / 170.0)));
270 if(fReducedVisualisationFactor
> 1.0)
272 fReducedVisualisationFactor
= 1.0;
274 else if(fReducedVisualisationFactor
< 0.20)
276 fReducedVisualisationFactor
= 0.20;
279 if(fReducedVisualisationFactor
!= 1.0)
281 fReduceFactor
*= fReducedVisualisationFactor
;
286 // determine the oversample value
287 static const sal_uInt16
nDefaultOversampleValue(3);
288 const sal_uInt16
nOversampleValue(aDrawinglayerOpt
.IsAntiAliasing() ? nDefaultOversampleValue
: 0);
290 geometry::ViewInformation3D
aViewInformation3D(getViewInformation3D());
292 // calculate a transformation from DiscreteRange to evtl. rotated/sheared content.
293 // Start with full transformation from object to discrete units
294 basegfx::B2DHomMatrix
aObjToUnit(rViewInformation
.getObjectToViewTransformation() * getObjectTransformation());
296 // bring to unit coordinates by applying inverse DiscreteRange
297 aObjToUnit
.translate(-aDiscreteRange
.getMinX(), -aDiscreteRange
.getMinY());
298 if (aDiscreteRange
.getWidth() != 0.0 && aDiscreteRange
.getHeight() != 0.0)
300 aObjToUnit
.scale(1.0 / aDiscreteRange
.getWidth(), 1.0 / aDiscreteRange
.getHeight());
303 // calculate transformed user coordinate system
304 const basegfx::B2DPoint
aStandardNull(0.0, 0.0);
305 const basegfx::B2DPoint
aUnitRangeTopLeft(aObjToUnit
* aStandardNull
);
306 const basegfx::B2DVector
aStandardXAxis(1.0, 0.0);
307 const basegfx::B2DVector
aUnitRangeXAxis(aObjToUnit
* aStandardXAxis
);
308 const basegfx::B2DVector
aStandardYAxis(0.0, 1.0);
309 const basegfx::B2DVector
aUnitRangeYAxis(aObjToUnit
* aStandardYAxis
);
311 if(!aUnitRangeTopLeft
.equal(aStandardNull
) || !aUnitRangeXAxis
.equal(aStandardXAxis
) || !aUnitRangeYAxis
.equal(aStandardYAxis
))
313 // build transformation from unit range to user coordinate system; the unit range
314 // X and Y axes are the column vectors, the null point is the offset
315 basegfx::B2DHomMatrix aUnitRangeToUser
;
317 aUnitRangeToUser
.set3x2(
318 aUnitRangeXAxis
.getX(), aUnitRangeYAxis
.getX(), aUnitRangeTopLeft
.getX(),
319 aUnitRangeXAxis
.getY(), aUnitRangeYAxis
.getY(), aUnitRangeTopLeft
.getY());
321 // decompose to allow to apply this to the 3D transformation
322 basegfx::B2DVector aScale
, aTranslate
;
323 double fRotate
, fShearX
;
324 aUnitRangeToUser
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
326 // apply before DeviceToView and after Projection, 3D is in range [-1.0 .. 1.0] in X,Y and Z
327 // and not yet flipped in Y
328 basegfx::B3DHomMatrix
aExtendedProjection(aViewInformation3D
.getProjection());
330 // bring to unit coordinates, flip Y, leave Z unchanged
331 aExtendedProjection
.scale(0.5, -0.5, 1.0);
332 aExtendedProjection
.translate(0.5, 0.5, 0.0);
334 // apply extra; Y is flipped now, go with positive shear and rotate values
335 aExtendedProjection
.scale(aScale
.getX(), aScale
.getY(), 1.0);
336 aExtendedProjection
.shearXZ(fShearX
, 0.0);
337 aExtendedProjection
.rotate(0.0, 0.0, fRotate
);
338 aExtendedProjection
.translate(aTranslate
.getX(), aTranslate
.getY(), 0.0);
340 // back to state after projection
341 aExtendedProjection
.translate(-0.5, -0.5, 0.0);
342 aExtendedProjection
.scale(2.0, -2.0, 1.0);
344 aViewInformation3D
= geometry::ViewInformation3D(
345 aViewInformation3D
.getObjectTransformation(),
346 aViewInformation3D
.getOrientation(),
348 aViewInformation3D
.getDeviceToView(),
349 aViewInformation3D
.getViewTime(),
350 aViewInformation3D
.getExtendedInformationSequence());
354 // calculate logic render size in world coordinates for usage in renderer
355 const basegfx::B2DHomMatrix
& aInverseOToV(rViewInformation
.getInverseObjectToViewTransformation());
356 const double fLogicX((aInverseOToV
* basegfx::B2DVector(aDiscreteRange
.getWidth() * fReduceFactor
, 0.0)).getLength());
357 const double fLogicY((aInverseOToV
* basegfx::B2DVector(0.0, aDiscreteRange
.getHeight() * fReduceFactor
)).getLength());
359 // generate ViewSizes
360 const double fFullViewSizeX((rViewInformation
.getObjectToViewTransformation() * basegfx::B2DVector(fLogicX
, 0.0)).getLength());
361 const double fFullViewSizeY((rViewInformation
.getObjectToViewTransformation() * basegfx::B2DVector(0.0, fLogicY
)).getLength());
363 // generate RasterWidth and RasterHeight for visible part
364 const sal_Int32
nRasterWidth(basegfx::fround(fFullViewSizeX
* aUnitVisibleRange
.getWidth()) + 1);
365 const sal_Int32
nRasterHeight(basegfx::fround(fFullViewSizeY
* aUnitVisibleRange
.getHeight()) + 1);
367 if(nRasterWidth
&& nRasterHeight
)
369 // create view unit buffer
370 basegfx::BZPixelRaster
aBZPixelRaster(
371 nOversampleValue
? nRasterWidth
* nOversampleValue
: nRasterWidth
,
372 nOversampleValue
? nRasterHeight
* nOversampleValue
: nRasterHeight
);
374 // check for parallel execution possibilities
375 static bool bMultithreadAllowed
= false; // loplugin:constvars:ignore
376 sal_Int32
nThreadCount(0);
377 comphelper::ThreadPool
& rThreadPool(comphelper::ThreadPool::getSharedOptimalPool());
379 if(bMultithreadAllowed
)
381 nThreadCount
= rThreadPool
.getWorkerCount();
385 // at least use 10px per processor, so limit number of processors to
386 // target pixel size divided by 10 (which might be zero what is okay)
387 nThreadCount
= std::min(nThreadCount
, nRasterHeight
/ 10);
393 class Executor
: public comphelper::ThreadTask
396 std::unique_ptr
<processor3d::ZBufferProcessor3D
> mpZBufferProcessor3D
;
397 const primitive3d::Primitive3DContainer
& mrChildren3D
;
401 std::shared_ptr
<comphelper::ThreadTaskTag
> const & rTag
,
402 std::unique_ptr
<processor3d::ZBufferProcessor3D
> pZBufferProcessor3D
,
403 const primitive3d::Primitive3DContainer
& rChildren3D
)
404 : comphelper::ThreadTask(rTag
),
405 mpZBufferProcessor3D(std::move(pZBufferProcessor3D
)),
406 mrChildren3D(rChildren3D
)
410 virtual void doWork() override
412 mpZBufferProcessor3D
->process(mrChildren3D
);
413 mpZBufferProcessor3D
->finish();
414 mpZBufferProcessor3D
.reset();
418 const sal_uInt32
nLinesPerThread(aBZPixelRaster
.getHeight() / nThreadCount
);
419 std::shared_ptr
<comphelper::ThreadTaskTag
> aTag
= comphelper::ThreadPool::createThreadTaskTag();
421 for(sal_Int32
a(0); a
< nThreadCount
; a
++)
423 std::unique_ptr
<processor3d::ZBufferProcessor3D
> pNewZBufferProcessor3D(new processor3d::ZBufferProcessor3D(
425 getSdrSceneAttribute(),
426 getSdrLightingAttribute(),
433 a
+ 1 == nThreadCount
? aBZPixelRaster
.getHeight() : nLinesPerThread
* (a
+ 1)));
434 std::unique_ptr
<Executor
> pExecutor(new Executor(aTag
, std::move(pNewZBufferProcessor3D
), getChildren3D()));
435 rThreadPool
.pushTask(std::move(pExecutor
));
438 rThreadPool
.waitUntilDone(aTag
);
442 // use default 3D primitive processor to create BitmapEx for aUnitVisiblePart and process
443 processor3d::ZBufferProcessor3D
aZBufferProcessor3D(
445 getSdrSceneAttribute(),
446 getSdrLightingAttribute(),
453 aBZPixelRaster
.getHeight());
455 aZBufferProcessor3D
.process(getChildren3D());
456 aZBufferProcessor3D
.finish();
459 const_cast< ScenePrimitive2D
* >(this)->maOldRenderedBitmap
= BPixelRasterToBitmapEx(aBZPixelRaster
, nOversampleValue
);
460 const Size
aBitmapSizePixel(maOldRenderedBitmap
.GetSizePixel());
462 if(aBitmapSizePixel
.getWidth() && aBitmapSizePixel
.getHeight())
464 // create transform for the created bitmap in discrete coordinates first.
465 basegfx::B2DHomMatrix aNew2DTransform
;
467 aNew2DTransform
.set(0, 0, aVisibleDiscreteRange
.getWidth());
468 aNew2DTransform
.set(1, 1, aVisibleDiscreteRange
.getHeight());
469 aNew2DTransform
.set(0, 2, aVisibleDiscreteRange
.getMinX());
470 aNew2DTransform
.set(1, 2, aVisibleDiscreteRange
.getMinY());
472 // transform back to world coordinates for usage in primitive creation
473 aNew2DTransform
*= aInverseOToV
;
475 // create bitmap primitive and add
476 rContainer
.push_back(new BitmapPrimitive2D(maOldRenderedBitmap
, aNew2DTransform
));
478 // test: Allow to add an outline in the debugger when tests are needed
479 static bool bAddOutlineToCreated3DSceneRepresentation(false); // loplugin:constvars:ignore
481 if(bAddOutlineToCreated3DSceneRepresentation
)
483 basegfx::B2DPolygon
aOutline(basegfx::utils::createUnitPolygon());
484 aOutline
.transform(aNew2DTransform
);
485 rContainer
.push_back(new PolygonHairlinePrimitive2D(aOutline
, basegfx::BColor(1.0, 0.0, 0.0)));
492 Primitive2DContainer
ScenePrimitive2D::getGeometry2D() const
494 Primitive2DContainer aRetval
;
496 // create 2D projected geometry from 3D geometry
497 if(!getChildren3D().empty())
499 // create 2D geometry extraction processor
500 processor3d::Geometry2DExtractingProcessor
aGeometryProcessor(
501 getViewInformation3D(),
502 getObjectTransformation());
504 // process local primitives
505 aGeometryProcessor
.process(getChildren3D());
508 aRetval
= aGeometryProcessor
.getPrimitive2DSequence();
514 Primitive2DContainer
ScenePrimitive2D::getShadow2D() const
516 Primitive2DContainer aRetval
;
518 // create 2D shadows from contained 3D primitives
521 // add extracted 2d shadows (before 3d scene creations itself)
522 aRetval
= maShadowPrimitives
;
528 bool ScenePrimitive2D::tryToCheckLastVisualisationDirectHit(const basegfx::B2DPoint
& rLogicHitPoint
, bool& o_rResult
) const
530 if(!maOldRenderedBitmap
.IsEmpty() && !maOldUnitVisiblePart
.isEmpty())
532 basegfx::B2DHomMatrix
aInverseSceneTransform(getObjectTransformation());
533 aInverseSceneTransform
.invert();
534 const basegfx::B2DPoint
aRelativePoint(aInverseSceneTransform
* rLogicHitPoint
);
536 if(maOldUnitVisiblePart
.isInside(aRelativePoint
))
538 // calculate coordinates relative to visualized part
539 double fDivisorX(maOldUnitVisiblePart
.getWidth());
540 double fDivisorY(maOldUnitVisiblePart
.getHeight());
542 if(basegfx::fTools::equalZero(fDivisorX
))
547 if(basegfx::fTools::equalZero(fDivisorY
))
552 const double fRelativeX((aRelativePoint
.getX() - maOldUnitVisiblePart
.getMinX()) / fDivisorX
);
553 const double fRelativeY((aRelativePoint
.getY() - maOldUnitVisiblePart
.getMinY()) / fDivisorY
);
555 // combine with real BitmapSizePixel to get bitmap coordinates
556 const Size
aBitmapSizePixel(maOldRenderedBitmap
.GetSizePixel());
557 const sal_Int32
nX(basegfx::fround(fRelativeX
* aBitmapSizePixel
.Width()));
558 const sal_Int32
nY(basegfx::fround(fRelativeY
* aBitmapSizePixel
.Height()));
560 // try to get a statement about transparency in that pixel
561 o_rResult
= (0xff != maOldRenderedBitmap
.GetTransparency(nX
, nY
));
569 ScenePrimitive2D::ScenePrimitive2D(
570 const primitive3d::Primitive3DContainer
& rxChildren3D
,
571 const attribute::SdrSceneAttribute
& rSdrSceneAttribute
,
572 const attribute::SdrLightingAttribute
& rSdrLightingAttribute
,
573 const basegfx::B2DHomMatrix
& rObjectTransformation
,
574 const geometry::ViewInformation3D
& rViewInformation3D
)
575 : BufferedDecompositionPrimitive2D(),
576 mxChildren3D(rxChildren3D
),
577 maSdrSceneAttribute(rSdrSceneAttribute
),
578 maSdrLightingAttribute(rSdrLightingAttribute
),
579 maObjectTransformation(rObjectTransformation
),
580 maViewInformation3D(rViewInformation3D
),
581 maShadowPrimitives(),
582 mbShadow3DChecked(false),
583 mfOldDiscreteSizeX(0.0),
584 mfOldDiscreteSizeY(0.0),
585 maOldUnitVisiblePart(),
586 maOldRenderedBitmap()
590 bool ScenePrimitive2D::operator==(const BasePrimitive2D
& rPrimitive
) const
592 if(BufferedDecompositionPrimitive2D::operator==(rPrimitive
))
594 const ScenePrimitive2D
& rCompare
= static_cast<const ScenePrimitive2D
&>(rPrimitive
);
596 return (getChildren3D() == rCompare
.getChildren3D()
597 && getSdrSceneAttribute() == rCompare
.getSdrSceneAttribute()
598 && getSdrLightingAttribute() == rCompare
.getSdrLightingAttribute()
599 && getObjectTransformation() == rCompare
.getObjectTransformation()
600 && getViewInformation3D() == rCompare
.getViewInformation3D());
606 basegfx::B2DRange
ScenePrimitive2D::getB2DRange(const geometry::ViewInformation2D
& rViewInformation
) const
608 // transform unit range to discrete coordinate range
609 basegfx::B2DRange
aRetval(0.0, 0.0, 1.0, 1.0);
610 aRetval
.transform(rViewInformation
.getObjectToViewTransformation() * getObjectTransformation());
612 // force to discrete expanded bounds (it grows, so expanding works perfectly well)
613 aRetval
.expand(basegfx::B2DTuple(floor(aRetval
.getMinX()), floor(aRetval
.getMinY())));
614 aRetval
.expand(basegfx::B2DTuple(ceil(aRetval
.getMaxX()), ceil(aRetval
.getMaxY())));
616 // transform back from discrete (view) to world coordinates
617 aRetval
.transform(rViewInformation
.getInverseObjectToViewTransformation());
619 // expand by evtl. existing shadow primitives
622 const basegfx::B2DRange
aShadow2DRange(maShadowPrimitives
.getB2DRange(rViewInformation
));
624 if(!aShadow2DRange
.isEmpty())
626 aRetval
.expand(aShadow2DRange
);
633 void ScenePrimitive2D::get2DDecomposition(Primitive2DDecompositionVisitor
& rVisitor
, const geometry::ViewInformation2D
& rViewInformation
) const
635 ::osl::MutexGuard
aGuard( m_aMutex
);
637 // get the involved ranges (see helper method calculateDiscreteSizes for details)
638 basegfx::B2DRange aDiscreteRange
;
639 basegfx::B2DRange aUnitVisibleRange
;
640 bool bNeedNewDecomposition(false);
641 bool bDiscreteSizesAreCalculated(false);
643 if(!getBuffered2DDecomposition().empty())
645 basegfx::B2DRange aVisibleDiscreteRange
;
646 calculateDiscreteSizes(rViewInformation
, aDiscreteRange
, aVisibleDiscreteRange
, aUnitVisibleRange
);
647 bDiscreteSizesAreCalculated
= true;
649 // needs to be painted when the new part is not part of the last
651 if(!maOldUnitVisiblePart
.isInside(aUnitVisibleRange
))
653 bNeedNewDecomposition
= true;
656 // display has changed and cannot be reused when resolution got bigger. It
657 // can be reused when resolution got smaller, though.
658 if(!bNeedNewDecomposition
)
660 if(basegfx::fTools::more(aDiscreteRange
.getWidth(), mfOldDiscreteSizeX
) ||
661 basegfx::fTools::more(aDiscreteRange
.getHeight(), mfOldDiscreteSizeY
))
663 bNeedNewDecomposition
= true;
668 if(bNeedNewDecomposition
)
670 // conditions of last local decomposition have changed, delete
671 const_cast< ScenePrimitive2D
* >(this)->setBuffered2DDecomposition(Primitive2DContainer());
674 if(getBuffered2DDecomposition().empty())
676 if(!bDiscreteSizesAreCalculated
)
678 basegfx::B2DRange aVisibleDiscreteRange
;
679 calculateDiscreteSizes(rViewInformation
, aDiscreteRange
, aVisibleDiscreteRange
, aUnitVisibleRange
);
682 // remember last used NewDiscreteSize and NewUnitVisiblePart
683 ScenePrimitive2D
* pThat
= const_cast< ScenePrimitive2D
* >(this);
684 pThat
->mfOldDiscreteSizeX
= aDiscreteRange
.getWidth();
685 pThat
->mfOldDiscreteSizeY
= aDiscreteRange
.getHeight();
686 pThat
->maOldUnitVisiblePart
= aUnitVisibleRange
;
689 // use parent implementation
690 BufferedDecompositionPrimitive2D::get2DDecomposition(rVisitor
, rViewInformation
);
694 ImplPrimitive2DIDBlock(ScenePrimitive2D
, PRIMITIVE2D_ID_SCENEPRIMITIVE2D
)
696 } // end of namespace primitive2d
697 } // end of namespace drawinglayer
699 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */