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 <processor3d/zbufferprocessor3d.hxx>
21 #include <basegfx/raster/bzpixelraster.hxx>
22 #include <basegfx/raster/rasterconvert3d.hxx>
23 #include <drawinglayer/attribute/materialattribute3d.hxx>
24 #include <texture/texture.hxx>
25 #include <basegfx/polygon/b3dpolygon.hxx>
26 #include <basegfx/polygon/b3dpolypolygon.hxx>
27 #include <basegfx/polygon/b3dpolygontools.hxx>
28 #include <basegfx/polygon/b3dpolypolygontools.hxx>
29 #include <drawinglayer/attribute/sdrlightingattribute3d.hxx>
30 #include <o3tl/safeint.hxx>
31 #include <svtools/optionsdrawinglayer.hxx>
34 using namespace com::sun::star
;
36 class ZBufferRasterConverter3D
: public basegfx::RasterConverter3D
39 const drawinglayer::processor3d::DefaultProcessor3D
& mrProcessor
;
40 basegfx::BZPixelRaster
& mrBuffer
;
42 // interpolators for a single line span
43 basegfx::ip_single maIntZ
;
44 basegfx::ip_triple maIntColor
;
45 basegfx::ip_triple maIntNormal
;
46 basegfx::ip_double maIntTexture
;
47 basegfx::ip_triple maIntInvTexture
;
49 // current material to use for rasterconversion
50 const drawinglayer::attribute::MaterialAttribute3D
* mpCurrentMaterial
;
52 // some boolean flags for line span interpolator usages
53 bool mbModifyColor
: 1;
55 bool mbHasTexCoor
: 1;
56 bool mbHasInvTexCoor
: 1;
60 void getTextureCoor(basegfx::B2DPoint
& rTarget
) const
64 rTarget
.setX(maIntTexture
.getX().getVal());
65 rTarget
.setY(maIntTexture
.getY().getVal());
67 else if(mbHasInvTexCoor
)
69 const double fZFactor(maIntInvTexture
.getZ().getVal());
70 const double fInvZFactor(basegfx::fTools::equalZero(fZFactor
) ? 1.0 : 1.0 / fZFactor
);
71 rTarget
.setX(maIntInvTexture
.getX().getVal() * fInvZFactor
);
72 rTarget
.setY(maIntInvTexture
.getY().getVal() * fInvZFactor
);
76 void incrementLineSpanInterpolators(double fStep
)
78 maIntZ
.increment(fStep
);
84 maIntTexture
.increment(fStep
);
86 else if(mbHasInvTexCoor
)
88 maIntInvTexture
.increment(fStep
);
94 maIntNormal
.increment(fStep
);
99 maIntColor
.increment(fStep
);
103 double decideColorAndOpacity(basegfx::BColor
& rColor
) const
105 // init values with full opacity and material color
106 assert(nullptr != mpCurrentMaterial
&& "CurrentMaterial not set (!)");
107 double fOpacity(1.0);
108 rColor
= mpCurrentMaterial
->getColor();
112 basegfx::B2DPoint
aTexCoor(0.0, 0.0);
113 getTextureCoor(aTexCoor
);
115 if(mrProcessor
.getGeoTexSvx())
117 // calc color in spot. This may also set to invisible already when
118 // e.g. bitmap textures have transparent parts
119 mrProcessor
.getGeoTexSvx()->modifyBColor(aTexCoor
, rColor
, fOpacity
);
122 if (fOpacity
> 0.0 && !basegfx::fTools::equalZero(fOpacity
) && mrProcessor
.getTransparenceGeoTexSvx())
124 // calc opacity. Object has a 2nd texture, a transparence texture
125 mrProcessor
.getTransparenceGeoTexSvx()->modifyOpacity(aTexCoor
, fOpacity
);
129 if (fOpacity
> 0.0 && !basegfx::fTools::equalZero(fOpacity
))
131 if(mrProcessor
.getGeoTexSvx())
135 // blend texture with phong
136 rColor
= mrProcessor
.getSdrLightingAttribute().solveColorModel(
137 basegfx::B3DVector(maIntNormal
.getX().getVal(), maIntNormal
.getY().getVal(), maIntNormal
.getZ().getVal()),
139 mpCurrentMaterial
->getSpecular(),
140 mpCurrentMaterial
->getEmission(),
141 mpCurrentMaterial
->getSpecularIntensity());
145 // blend texture with gouraud
146 basegfx::BColor
aBlendColor(maIntColor
.getX().getVal(), maIntColor
.getY().getVal(), maIntColor
.getZ().getVal());
147 rColor
*= aBlendColor
;
149 else if(mrProcessor
.getModulate())
151 // blend texture with single material color
152 rColor
*= mpCurrentMaterial
->getColor();
159 // modify color with phong
160 rColor
= mrProcessor
.getSdrLightingAttribute().solveColorModel(
161 basegfx::B3DVector(maIntNormal
.getX().getVal(), maIntNormal
.getY().getVal(), maIntNormal
.getZ().getVal()),
163 mpCurrentMaterial
->getSpecular(),
164 mpCurrentMaterial
->getEmission(),
165 mpCurrentMaterial
->getSpecularIntensity());
169 // modify color with gouraud
170 rColor
.setRed(maIntColor
.getX().getVal());
171 rColor
.setGreen(maIntColor
.getY().getVal());
172 rColor
.setBlue(maIntColor
.getZ().getVal());
178 rColor
= mrProcessor
.getBColorModifierStack().getModifiedColor(rColor
);
185 void setupLineSpanInterpolators(const basegfx::RasterConversionLineEntry3D
& rA
, const basegfx::RasterConversionLineEntry3D
& rB
)
187 // get inverse XDelta
188 const double xInvDelta(1.0 / (rB
.getX().getVal() - rA
.getX().getVal()));
190 // prepare Z-interpolator
191 const double fZA(rA
.getZ().getVal());
192 const double fZB(rB
.getZ().getVal());
193 maIntZ
= basegfx::ip_single(fZA
, (fZB
- fZA
) * xInvDelta
);
195 // get bools and init other interpolators on demand accordingly
196 mbModifyColor
= mrProcessor
.getBColorModifierStack().count();
197 mbHasTexCoor
= SCANLINE_EMPTY_INDEX
!= rA
.getTextureIndex() && SCANLINE_EMPTY_INDEX
!= rB
.getTextureIndex();
198 mbHasInvTexCoor
= SCANLINE_EMPTY_INDEX
!= rA
.getInverseTextureIndex() && SCANLINE_EMPTY_INDEX
!= rB
.getInverseTextureIndex();
199 const bool bTextureActive(mrProcessor
.getGeoTexSvx() || mrProcessor
.getTransparenceGeoTexSvx());
200 mbUseTex
= bTextureActive
&& (mbHasTexCoor
|| mbHasInvTexCoor
|| mrProcessor
.getSimpleTextureActive());
201 const bool bUseColorTex(mbUseTex
&& mrProcessor
.getGeoTexSvx());
202 const bool bNeedNrmOrCol(!bUseColorTex
|| mrProcessor
.getModulate());
203 mbUseNrm
= bNeedNrmOrCol
&& SCANLINE_EMPTY_INDEX
!= rA
.getNormalIndex() && SCANLINE_EMPTY_INDEX
!= rB
.getNormalIndex();
204 mbUseCol
= !mbUseNrm
&& bNeedNrmOrCol
&& SCANLINE_EMPTY_INDEX
!= rA
.getColorIndex() && SCANLINE_EMPTY_INDEX
!= rB
.getColorIndex();
210 const basegfx::ip_double
& rTA(getTextureInterpolators()[rA
.getTextureIndex()]);
211 const basegfx::ip_double
& rTB(getTextureInterpolators()[rB
.getTextureIndex()]);
212 maIntTexture
= basegfx::ip_double(
213 rTA
.getX().getVal(), (rTB
.getX().getVal() - rTA
.getX().getVal()) * xInvDelta
,
214 rTA
.getY().getVal(), (rTB
.getY().getVal() - rTA
.getY().getVal()) * xInvDelta
);
216 else if(mbHasInvTexCoor
)
218 const basegfx::ip_triple
& rITA(getInverseTextureInterpolators()[rA
.getInverseTextureIndex()]);
219 const basegfx::ip_triple
& rITB(getInverseTextureInterpolators()[rB
.getInverseTextureIndex()]);
220 maIntInvTexture
= basegfx::ip_triple(
221 rITA
.getX().getVal(), (rITB
.getX().getVal() - rITA
.getX().getVal()) * xInvDelta
,
222 rITA
.getY().getVal(), (rITB
.getY().getVal() - rITA
.getY().getVal()) * xInvDelta
,
223 rITA
.getZ().getVal(), (rITB
.getZ().getVal() - rITA
.getZ().getVal()) * xInvDelta
);
229 const basegfx::ip_triple
& rNA(getNormalInterpolators()[rA
.getNormalIndex()]);
230 const basegfx::ip_triple
& rNB(getNormalInterpolators()[rB
.getNormalIndex()]);
231 maIntNormal
= basegfx::ip_triple(
232 rNA
.getX().getVal(), (rNB
.getX().getVal() - rNA
.getX().getVal()) * xInvDelta
,
233 rNA
.getY().getVal(), (rNB
.getY().getVal() - rNA
.getY().getVal()) * xInvDelta
,
234 rNA
.getZ().getVal(), (rNB
.getZ().getVal() - rNA
.getZ().getVal()) * xInvDelta
);
239 const basegfx::ip_triple
& rCA(getColorInterpolators()[rA
.getColorIndex()]);
240 const basegfx::ip_triple
& rCB(getColorInterpolators()[rB
.getColorIndex()]);
241 maIntColor
= basegfx::ip_triple(
242 rCA
.getX().getVal(), (rCB
.getX().getVal() - rCA
.getX().getVal()) * xInvDelta
,
243 rCA
.getY().getVal(), (rCB
.getY().getVal() - rCA
.getY().getVal()) * xInvDelta
,
244 rCA
.getZ().getVal(), (rCB
.getZ().getVal() - rCA
.getZ().getVal()) * xInvDelta
);
248 virtual void processLineSpan(const basegfx::RasterConversionLineEntry3D
& rA
, const basegfx::RasterConversionLineEntry3D
& rB
, sal_Int32 nLine
, sal_uInt32 nSpanCount
) override
;
251 ZBufferRasterConverter3D(basegfx::BZPixelRaster
& rBuffer
, const drawinglayer::processor3d::ZBufferProcessor3D
& rProcessor
)
252 : mrProcessor(rProcessor
),
254 mpCurrentMaterial(nullptr),
255 mbModifyColor(false),
258 mbHasInvTexCoor(false),
263 void setCurrentMaterial(const drawinglayer::attribute::MaterialAttribute3D
& rMaterial
)
265 mpCurrentMaterial
= &rMaterial
;
269 void ZBufferRasterConverter3D::processLineSpan(const basegfx::RasterConversionLineEntry3D
& rA
, const basegfx::RasterConversionLineEntry3D
& rB
, sal_Int32 nLine
, sal_uInt32 nSpanCount
)
271 if(nSpanCount
& 0x0001)
274 if(nLine
< 0 || o3tl::make_unsigned(nLine
) >= mrBuffer
.getHeight())
277 sal_uInt32
nXA(std::min(mrBuffer
.getWidth(), static_cast<sal_uInt32
>(std::max(sal_Int32(0), basegfx::fround(rA
.getX().getVal())))));
278 const sal_uInt32
nXB(std::min(mrBuffer
.getWidth(), static_cast<sal_uInt32
>(std::max(sal_Int32(0), basegfx::fround(rB
.getX().getVal())))));
283 // prepare the span interpolators
284 setupLineSpanInterpolators(rA
, rB
);
286 // bring span interpolators to start condition by incrementing with the possible difference of
287 // clamped and non-clamped XStart. Interpolators are setup relying on double precision
288 // X-values, so that difference is the correct value to compensate for possible clampings
289 incrementLineSpanInterpolators(static_cast<double>(nXA
) - rA
.getX().getVal());
291 // prepare scanline index
292 sal_uInt32
nScanlineIndex(mrBuffer
.getIndexFromXY(nXA
, static_cast<sal_uInt32
>(nLine
)));
293 basegfx::BColor aNewColor
;
297 // early-test Z values if we need to do anything at all
298 const double fNewZ(std::clamp(maIntZ
.getVal(), 0.0, 65535.0));
299 const sal_uInt16
nNewZ(static_cast< sal_uInt16
>(fNewZ
));
300 sal_uInt16
& rOldZ(mrBuffer
.getZ(nScanlineIndex
));
304 // detect color and opacity for this pixel
305 const sal_uInt16
nOpacity(std::max(sal_Int16(0), static_cast< sal_Int16
>(decideColorAndOpacity(aNewColor
) * 255.0)));
309 // avoid color overrun
312 if(nOpacity
>= 0x00ff)
314 // full opacity (not transparent), set z and color
316 mrBuffer
.getBPixel(nScanlineIndex
) = basegfx::BPixel(aNewColor
, 0xff);
320 basegfx::BPixel
& rDest
= mrBuffer
.getBPixel(nScanlineIndex
);
324 // mix new color by using
325 // color' = color * (1 - opacity) + newcolor * opacity
326 const sal_uInt16
nTransparence(255 - nOpacity
);
327 rDest
.setRed(static_cast<sal_uInt8
>(((rDest
.getRed() * nTransparence
) + (static_cast<sal_uInt16
>(255.0 * aNewColor
.getRed()) * nOpacity
)) >> 8));
328 rDest
.setGreen(static_cast<sal_uInt8
>(((rDest
.getGreen() * nTransparence
) + (static_cast<sal_uInt16
>(255.0 * aNewColor
.getGreen()) * nOpacity
)) >> 8));
329 rDest
.setBlue(static_cast<sal_uInt8
>(((rDest
.getBlue() * nTransparence
) + (static_cast<sal_uInt16
>(255.0 * aNewColor
.getBlue()) * nOpacity
)) >> 8));
331 if(255 != rDest
.getAlpha())
333 // both are transparent, mix new opacity by using
334 // opacity = newopacity * (1 - oldopacity) + oldopacity
335 rDest
.setAlpha(static_cast<sal_uInt8
>((nOpacity
* (255 - rDest
.getAlpha())) >> 8) + rDest
.getAlpha());
340 // dest is unused, set color
341 rDest
= basegfx::BPixel(aNewColor
, static_cast<sal_uInt8
>(nOpacity
));
350 incrementLineSpanInterpolators(1.0);
354 // helper class to buffer output for transparent rasterprimitives (filled areas
355 // and lines) until the end of processing. To ensure correct transparent
356 // visualisation, ZBuffers require to not set Z and to mix with the transparent
357 // color. If transparent rasterprimitives overlap, it gets necessary to
358 // paint transparent rasterprimitives from back to front to ensure that the
359 // mixing happens from back to front. For that purpose, transparent
360 // rasterprimitives are held in this class during the processing run, remember
361 // all data and will be rendered
363 class RasterPrimitive3D
366 std::shared_ptr
< drawinglayer::texture::GeoTexSvx
> mpGeoTexSvx
;
367 std::shared_ptr
< drawinglayer::texture::GeoTexSvx
> mpTransparenceGeoTexSvx
;
368 drawinglayer::attribute::MaterialAttribute3D maMaterial
;
369 basegfx::B3DPolyPolygon maPolyPolygon
;
374 bool mbSimpleTextureActive
: 1;
379 std::shared_ptr
< drawinglayer::texture::GeoTexSvx
> pGeoTexSvx
,
380 std::shared_ptr
< drawinglayer::texture::GeoTexSvx
> pTransparenceGeoTexSvx
,
381 const drawinglayer::attribute::MaterialAttribute3D
& rMaterial
,
382 const basegfx::B3DPolyPolygon
& rPolyPolygon
,
385 bool bSimpleTextureActive
,
387 : mpGeoTexSvx(std::move(pGeoTexSvx
)),
388 mpTransparenceGeoTexSvx(std::move(pTransparenceGeoTexSvx
)),
389 maMaterial(rMaterial
),
390 maPolyPolygon(rPolyPolygon
),
391 mfCenterZ(basegfx::utils::getRange(rPolyPolygon
).getCenter().getZ()),
392 mbModulate(bModulate
),
394 mbSimpleTextureActive(bSimpleTextureActive
),
399 bool operator<(const RasterPrimitive3D
& rComp
) const
401 return mfCenterZ
< rComp
.mfCenterZ
;
404 const std::shared_ptr
< drawinglayer::texture::GeoTexSvx
>& getGeoTexSvx() const { return mpGeoTexSvx
; }
405 const std::shared_ptr
< drawinglayer::texture::GeoTexSvx
>& getTransparenceGeoTexSvx() const { return mpTransparenceGeoTexSvx
; }
406 const drawinglayer::attribute::MaterialAttribute3D
& getMaterial() const { return maMaterial
; }
407 const basegfx::B3DPolyPolygon
& getPolyPolygon() const { return maPolyPolygon
; }
408 bool getModulate() const { return mbModulate
; }
409 bool getFilter() const { return mbFilter
; }
410 bool getSimpleTextureActive() const { return mbSimpleTextureActive
; }
411 bool getIsLine() const { return mbIsLine
; }
414 namespace drawinglayer::processor3d
416 void ZBufferProcessor3D::rasterconvertB3DPolygon(const attribute::MaterialAttribute3D
& rMaterial
, const basegfx::B3DPolygon
& rHairline
) const
418 if(getTransparenceCounter())
420 // transparent output; record for later sorting and painting from
423 maRasterPrimitive3Ds
.push_back(RasterPrimitive3D(
425 getTransparenceGeoTexSvx(),
427 basegfx::B3DPolyPolygon(rHairline
),
430 getSimpleTextureActive(),
435 // do rasterconversion
436 mpZBufferRasterConverter3D
->setCurrentMaterial(rMaterial
);
438 if(mnAntiAlialize
> 1)
440 const bool bForceLineSnap(SvtOptionsDrawinglayer::IsAntiAliasing() && SvtOptionsDrawinglayer::IsSnapHorVerLinesToDiscrete());
444 basegfx::B3DHomMatrix aTransform
;
445 basegfx::B3DPolygon
aSnappedHairline(rHairline
);
446 const double fScaleDown(1.0 / mnAntiAlialize
);
447 const double fScaleUp(mnAntiAlialize
);
449 // take oversampling out
450 aTransform
.scale(fScaleDown
, fScaleDown
, 1.0);
451 aSnappedHairline
.transform(aTransform
);
454 aSnappedHairline
= basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aSnappedHairline
);
456 // add oversampling again
457 aTransform
.identity();
458 aTransform
.scale(fScaleUp
, fScaleUp
, 1.0);
460 aSnappedHairline
.transform(aTransform
);
462 mpZBufferRasterConverter3D
->rasterconvertB3DPolygon(aSnappedHairline
, mnStartLine
, mnStopLine
, mnAntiAlialize
);
466 mpZBufferRasterConverter3D
->rasterconvertB3DPolygon(rHairline
, mnStartLine
, mnStopLine
, mnAntiAlialize
);
471 mpZBufferRasterConverter3D
->rasterconvertB3DPolygon(rHairline
, mnStartLine
, mnStopLine
, 1);
476 void ZBufferProcessor3D::rasterconvertB3DPolyPolygon(const attribute::MaterialAttribute3D
& rMaterial
, const basegfx::B3DPolyPolygon
& rFill
) const
478 if(getTransparenceCounter())
480 // transparent output; record for later sorting and painting from
482 maRasterPrimitive3Ds
.push_back(RasterPrimitive3D(
484 getTransparenceGeoTexSvx(),
489 getSimpleTextureActive(),
494 mpZBufferRasterConverter3D
->setCurrentMaterial(rMaterial
);
495 mpZBufferRasterConverter3D
->rasterconvertB3DPolyPolygon(rFill
, &maInvEyeToView
, mnStartLine
, mnStopLine
);
499 ZBufferProcessor3D::ZBufferProcessor3D(
500 const geometry::ViewInformation3D
& rViewInformation3D
,
501 const attribute::SdrSceneAttribute
& rSdrSceneAttribute
,
502 const attribute::SdrLightingAttribute
& rSdrLightingAttribute
,
503 const basegfx::B2DRange
& rVisiblePart
,
504 sal_uInt16 nAntiAlialize
,
505 double fFullViewSizeX
,
506 double fFullViewSizeY
,
507 basegfx::BZPixelRaster
& rBZPixelRaster
,
508 sal_uInt32 nStartLine
,
509 sal_uInt32 nStopLine
)
510 : DefaultProcessor3D(rViewInformation3D
, rSdrSceneAttribute
, rSdrLightingAttribute
),
511 mnAntiAlialize(nAntiAlialize
),
512 mnStartLine(nStartLine
),
513 mnStopLine(nStopLine
)
515 // create DeviceToView for Z-Buffer renderer since Z is handled
516 // different from standard 3D transformations (Z is mirrored). Also
517 // the transformation includes the step from unit device coordinates
518 // to discrete units ([-1.0 .. 1.0] -> [minDiscrete .. maxDiscrete]
519 basegfx::B3DHomMatrix aDeviceToView
;
524 // bring from [-1.0 .. 1.0] in X,Y and Z to [0.0 .. 1.0]. Also
526 // - flip Y due to screen orientation
527 // - flip Z due to Z-Buffer orientation from back to front
529 aDeviceToView
.scale(0.5, -0.5, -0.5);
530 aDeviceToView
.translate(0.5, 0.5, 0.5);
536 // bring from [0.0 .. 1.0] in X,Y and Z to view coordinates
539 // also: scale Z to [1.5 .. 65534.5]. Normally, a range of [0.0 .. 65535.0]
540 // could be used, but a 'unused' value is needed, so '0' is used what reduces
541 // the range to [1.0 .. 65535.0]. It has also shown that small numerical errors
542 // (smaller as basegfx::fTools::mfSmallValue, which is 0.000000001) happen.
543 // Instead of checking those by basegfx::fTools methods which would cost
544 // runtime, just add another 0.5 tolerance to the start and end of the Z-Buffer
545 // range, thus resulting in [1.5 .. 65534.5]
546 const double fMaxZDepth(65533.0);
547 aDeviceToView
.translate(-rVisiblePart
.getMinX(), -rVisiblePart
.getMinY(), 0.0);
550 aDeviceToView
.scale(fFullViewSizeX
* mnAntiAlialize
, fFullViewSizeY
* mnAntiAlialize
, fMaxZDepth
);
552 aDeviceToView
.scale(fFullViewSizeX
, fFullViewSizeY
, fMaxZDepth
);
554 aDeviceToView
.translate(0.0, 0.0, 1.5);
557 // update local ViewInformation3D with own DeviceToView
558 const geometry::ViewInformation3D
aNewViewInformation3D(
559 getViewInformation3D().getObjectTransformation(),
560 getViewInformation3D().getOrientation(),
561 getViewInformation3D().getProjection(),
563 getViewInformation3D().getViewTime(),
564 getViewInformation3D().getExtendedInformationSequence());
565 updateViewInformation(aNewViewInformation3D
);
567 // prepare inverse EyeToView transformation. This can be done in constructor
568 // since changes in object transformations when processing TransformPrimitive3Ds
569 // do not influence this prepared partial transformation
570 maInvEyeToView
= getViewInformation3D().getDeviceToView() * getViewInformation3D().getProjection();
571 maInvEyeToView
.invert();
573 // prepare maRasterRange
574 maRasterRange
.reset();
575 maRasterRange
.expand(basegfx::B2DPoint(0.0, nStartLine
));
576 maRasterRange
.expand(basegfx::B2DPoint(rBZPixelRaster
.getWidth(), nStopLine
));
578 // create the raster converter
579 mpZBufferRasterConverter3D
.reset( new ZBufferRasterConverter3D(rBZPixelRaster
, *this) );
582 ZBufferProcessor3D::~ZBufferProcessor3D()
584 mpZBufferRasterConverter3D
.reset();
586 if(!maRasterPrimitive3Ds
.empty())
588 OSL_FAIL("ZBufferProcessor3D: destructed, but there are unrendered transparent geometries. Use ZBufferProcessor3D::finish() to render these (!)");
592 void ZBufferProcessor3D::finish()
594 if(maRasterPrimitive3Ds
.empty())
597 // there are transparent rasterprimitives
598 const sal_uInt32
nSize(maRasterPrimitive3Ds
.size());
602 // sort them from back to front
603 std::sort(maRasterPrimitive3Ds
.begin(), maRasterPrimitive3Ds
.end());
606 for(sal_uInt32
a(0); a
< nSize
; a
++)
608 // paint each one by setting the remembered data and calling
610 const RasterPrimitive3D
& rCandidate
= maRasterPrimitive3Ds
[a
];
612 mpGeoTexSvx
= rCandidate
.getGeoTexSvx();
613 mpTransparenceGeoTexSvx
= rCandidate
.getTransparenceGeoTexSvx();
614 mbModulate
= rCandidate
.getModulate();
615 mbFilter
= rCandidate
.getFilter();
616 mbSimpleTextureActive
= rCandidate
.getSimpleTextureActive();
618 if(rCandidate
.getIsLine())
620 rasterconvertB3DPolygon(
621 rCandidate
.getMaterial(),
622 rCandidate
.getPolyPolygon().getB3DPolygon(0));
626 rasterconvertB3DPolyPolygon(
627 rCandidate
.getMaterial(),
628 rCandidate
.getPolyPolygon());
632 // delete them to signal the destructor that all is done and
633 // to allow asserting there
634 maRasterPrimitive3Ds
.clear();
637 } // end of namespace
639 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */