Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / drawinglayer / source / primitive2d / sceneprimitive2d.cxx
blob6d9dd7a9c8c29d7c188c5014a849cefc8a43bb52
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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;
42 namespace
44 BitmapEx BPixelRasterToBitmapEx(const basegfx::BZPixelRaster& rRaster, sal_uInt16 mnAntiAlialize)
46 BitmapEx aRetval;
47 const sal_uInt32 nWidth(mnAntiAlialize ? rRaster.getWidth()/mnAntiAlialize : rRaster.getWidth());
48 const sal_uInt32 nHeight(mnAntiAlialize ? rRaster.getHeight()/mnAntiAlialize : rRaster.getHeight());
50 if(nWidth && nHeight)
52 const Size aDestSize(nWidth, nHeight);
53 vcl::bitmap::RawBitmap aContent(aDestSize, 32);
55 if(mnAntiAlialize)
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++)
63 sal_uInt16 nRed(0);
64 sal_uInt16 nGreen(0);
65 sal_uInt16 nBlue(0);
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;
85 if(nOpacity)
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) ));
93 else
94 aContent.SetPixel(y, x, Color(255, 0, 0, 0));
98 else
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()));
112 else
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));
125 return aRetval;
127 } // end of anonymous namespace
129 namespace drawinglayer
131 namespace primitive2d
133 bool ScenePrimitive2D::impGetShadow3D() const
135 ::osl::MutexGuard aGuard( m_aMutex );
137 // create on demand
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(),
155 aLightNormal,
156 fShadowSlant,
157 aScene3DRange);
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;
193 else
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())
201 ? 0.0
202 : (rVisibleDiscreteRange.getMinX() - rDiscreteRange.getMinX()) * fDiscreteScaleFactorX);
203 const double fMinY(basegfx::fTools::equal(rVisibleDiscreteRange.getMinY(), rDiscreteRange.getMinY())
204 ? 0.0
205 : (rVisibleDiscreteRange.getMinY() - rDiscreteRange.getMinY()) * fDiscreteScaleFactorY);
207 const double fMaxX(basegfx::fTools::equal(rVisibleDiscreteRange.getMaxX(), rDiscreteRange.getMaxX())
208 ? 1.0
209 : (rVisibleDiscreteRange.getMaxX() - rDiscreteRange.getMinX()) * fDiscreteScaleFactorX);
210 const double fMaxY(basegfx::fTools::equal(rVisibleDiscreteRange.getMaxY(), rDiscreteRange.getMaxY())
211 ? 1.0
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
222 if(impGetShadow3D())
224 // test visibility
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);
266 if (fArea != 0.0)
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(),
347 aExtendedProjection,
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();
383 if(nThreadCount > 1)
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);
391 if(nThreadCount > 1)
393 class Executor : public comphelper::ThreadTask
395 private:
396 std::unique_ptr<processor3d::ZBufferProcessor3D> mpZBufferProcessor3D;
397 const primitive3d::Primitive3DContainer& mrChildren3D;
399 public:
400 explicit Executor(
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(
424 aViewInformation3D,
425 getSdrSceneAttribute(),
426 getSdrLightingAttribute(),
427 aUnitVisibleRange,
428 nOversampleValue,
429 fFullViewSizeX,
430 fFullViewSizeY,
431 aBZPixelRaster,
432 nLinesPerThread * a,
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);
440 else
442 // use default 3D primitive processor to create BitmapEx for aUnitVisiblePart and process
443 processor3d::ZBufferProcessor3D aZBufferProcessor3D(
444 aViewInformation3D,
445 getSdrSceneAttribute(),
446 getSdrLightingAttribute(),
447 aUnitVisibleRange,
448 nOversampleValue,
449 fFullViewSizeX,
450 fFullViewSizeY,
451 aBZPixelRaster,
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());
507 // fetch result
508 aRetval = aGeometryProcessor.getPrimitive2DSequence();
511 return aRetval;
514 Primitive2DContainer ScenePrimitive2D::getShadow2D() const
516 Primitive2DContainer aRetval;
518 // create 2D shadows from contained 3D primitives
519 if(impGetShadow3D())
521 // add extracted 2d shadows (before 3d scene creations itself)
522 aRetval = maShadowPrimitives;
525 return aRetval;
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))
544 fDivisorX = 1.0;
547 if(basegfx::fTools::equalZero(fDivisorY))
549 fDivisorY = 1.0;
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));
562 return true;
566 return false;
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());
603 return false;
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
620 if(impGetShadow3D())
622 const basegfx::B2DRange aShadow2DRange(maShadowPrimitives.getB2DRange(rViewInformation));
624 if(!aShadow2DRange.isEmpty())
626 aRetval.expand(aShadow2DRange);
630 return aRetval;
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
650 // decomposition
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);
693 // provide unique ID
694 ImplPrimitive2DIDBlock(ScenePrimitive2D, PRIMITIVE2D_ID_SCENEPRIMITIVE2D)
696 } // end of namespace primitive2d
697 } // end of namespace drawinglayer
699 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */