Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <drawinglayer/processor3d/zbufferprocessor3d.hxx>
30 : : #include <basegfx/raster/bpixelraster.hxx>
31 : : #include <vcl/bmpacc.hxx>
32 : : #include <basegfx/raster/rasterconvert3d.hxx>
33 : : #include <basegfx/raster/bzpixelraster.hxx>
34 : : #include <drawinglayer/attribute/materialattribute3d.hxx>
35 : : #include <drawinglayer/texture/texture.hxx>
36 : : #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx>
37 : : #include <drawinglayer/primitive3d/textureprimitive3d.hxx>
38 : : #include <drawinglayer/primitive3d/polygonprimitive3d.hxx>
39 : : #include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx>
40 : : #include <drawinglayer/geometry/viewinformation2d.hxx>
41 : : #include <basegfx/polygon/b3dpolygontools.hxx>
42 : : #include <basegfx/polygon/b3dpolypolygontools.hxx>
43 : : #include <drawinglayer/attribute/sdrlightingattribute3d.hxx>
44 : :
45 : : //////////////////////////////////////////////////////////////////////////////
46 : :
47 : : using namespace com::sun::star;
48 : :
49 : : //////////////////////////////////////////////////////////////////////////////
50 : :
51 : : namespace
52 : : {
53 : 15 : BitmapEx BPixelRasterToBitmapEx(const basegfx::BPixelRaster& rRaster, sal_uInt16 mnAntiAlialize)
54 : : {
55 : 15 : BitmapEx aRetval;
56 [ - + ]: 15 : const sal_uInt32 nWidth(mnAntiAlialize ? rRaster.getWidth()/mnAntiAlialize : rRaster.getWidth());
57 [ - + ]: 15 : const sal_uInt32 nHeight(mnAntiAlialize ? rRaster.getHeight()/mnAntiAlialize : rRaster.getHeight());
58 : :
59 [ + - ][ + - ]: 15 : if(nWidth && nHeight)
60 : : {
61 : 15 : const Size aDestSize(nWidth, nHeight);
62 [ + - ]: 15 : Bitmap aContent(aDestSize, 24);
63 [ + - ]: 15 : AlphaMask aAlpha(aDestSize);
64 [ + - ]: 15 : BitmapWriteAccess* pContent = aContent.AcquireWriteAccess();
65 [ + - ]: 15 : BitmapWriteAccess* pAlpha = aAlpha.AcquireWriteAccess();
66 : :
67 [ + - ][ + - ]: 15 : if(pContent && pAlpha)
68 : : {
69 [ - + ]: 15 : if(mnAntiAlialize)
70 : : {
71 : 0 : const sal_uInt16 nDivisor(mnAntiAlialize * mnAntiAlialize);
72 : :
73 [ # # ]: 0 : for(sal_uInt32 y(0L); y < nHeight; y++)
74 : : {
75 [ # # ]: 0 : for(sal_uInt32 x(0L); x < nWidth; x++)
76 : : {
77 : 0 : sal_uInt16 nRed(0);
78 : 0 : sal_uInt16 nGreen(0);
79 : 0 : sal_uInt16 nBlue(0);
80 : 0 : sal_uInt16 nOpacity(0);
81 : 0 : sal_uInt32 nIndex(rRaster.getIndexFromXY(x * mnAntiAlialize, y * mnAntiAlialize));
82 : :
83 [ # # ]: 0 : for(sal_uInt32 c(0); c < mnAntiAlialize; c++)
84 : : {
85 [ # # ]: 0 : for(sal_uInt32 d(0); d < mnAntiAlialize; d++)
86 : : {
87 : 0 : const basegfx::BPixel& rPixel(rRaster.getBPixel(nIndex++));
88 : 0 : nRed = nRed + rPixel.getRed();
89 : 0 : nGreen = nGreen + rPixel.getGreen();
90 : 0 : nBlue = nBlue + rPixel.getBlue();
91 : 0 : nOpacity = nOpacity + rPixel.getOpacity();
92 : : }
93 : :
94 : 0 : nIndex += rRaster.getWidth() - mnAntiAlialize;
95 : : }
96 : :
97 : 0 : nOpacity = nOpacity / nDivisor;
98 [ # # ]: 0 : if(nOpacity)
99 : : {
100 : : pContent->SetPixel(y, x, BitmapColor(
101 : : (sal_uInt8)(nRed / nDivisor),
102 : : (sal_uInt8)(nGreen / nDivisor),
103 [ # # ]: 0 : (sal_uInt8)(nBlue / nDivisor)));
104 : : pAlpha->SetPixel(
105 : : y, x,
106 [ # # ]: 0 : BitmapColor(255 - (sal_uInt8)nOpacity));
107 : : }
108 : : else
109 : : {
110 [ # # ]: 0 : pContent->SetPixel(y, x, BitmapColor(0, 0, 0));
111 [ # # ]: 0 : pAlpha->SetPixel(y, x, BitmapColor(255));
112 : : }
113 : : }
114 : : }
115 : : }
116 : : else
117 : : {
118 : 15 : sal_uInt32 nIndex(0L);
119 : :
120 [ + + ]: 5180 : for(sal_uInt32 y(0L); y < nHeight; y++)
121 : : {
122 [ + + ]: 3911149 : for(sal_uInt32 x(0L); x < nWidth; x++)
123 : : {
124 : 3905984 : const basegfx::BPixel& rPixel(rRaster.getBPixel(nIndex++));
125 [ + - ]: 3905984 : pContent->SetPixel(y, x, BitmapColor(rPixel.getRed(), rPixel.getGreen(), rPixel.getBlue()));
126 [ + - ]: 3905984 : pAlpha->SetPixel(y, x, BitmapColor(255 - rPixel.getOpacity()));
127 : : }
128 : : }
129 : : }
130 : :
131 [ + - ]: 15 : aContent.ReleaseAccess(pContent);
132 [ + - ]: 15 : aAlpha.ReleaseAccess(pAlpha);
133 : : }
134 : :
135 [ + - ][ + - ]: 15 : aRetval = BitmapEx(aContent, aAlpha);
[ + - ]
136 : :
137 : : // #i101811# set PrefMapMode and PrefSize at newly created Bitmap
138 [ + - ][ + - ]: 15 : aRetval.SetPrefMapMode(MAP_100TH_MM);
[ + - ]
139 [ + - ][ + - ]: 15 : aRetval.SetPrefSize(Size(nWidth, nHeight));
140 : : }
141 : :
142 : 15 : return aRetval;
143 : : }
144 : : } // end of anonymous namespace
145 : :
146 : : //////////////////////////////////////////////////////////////////////////////
147 : :
148 [ - + ]: 30 : class ZBufferRasterConverter3D : public basegfx::RasterConverter3D
149 : : {
150 : : private:
151 : : const drawinglayer::processor3d::DefaultProcessor3D& mrProcessor;
152 : : basegfx::BZPixelRaster& mrBuffer;
153 : :
154 : : // interpolators for a single line span
155 : : basegfx::ip_single maIntZ;
156 : : basegfx::ip_triple maIntColor;
157 : : basegfx::ip_triple maIntNormal;
158 : : basegfx::ip_double maIntTexture;
159 : : basegfx::ip_triple maIntInvTexture;
160 : :
161 : : // current material to use for ratsreconversion
162 : : const drawinglayer::attribute::MaterialAttribute3D* mpCurrentMaterial;
163 : :
164 : : // bitfield
165 : : // some boolean flags for line span interpolator usages
166 : : unsigned mbModifyColor : 1;
167 : : unsigned mbUseTex : 1;
168 : : unsigned mbHasTexCoor : 1;
169 : : unsigned mbHasInvTexCoor : 1;
170 : : unsigned mbUseNrm : 1;
171 : : unsigned mbUseCol : 1;
172 : :
173 : 184336 : void getTextureCoor(basegfx::B2DPoint& rTarget) const
174 : : {
175 [ - + ]: 184336 : if(mbHasTexCoor)
176 : : {
177 : 0 : rTarget.setX(maIntTexture.getX().getVal());
178 : 0 : rTarget.setY(maIntTexture.getY().getVal());
179 : : }
180 [ + - ]: 184336 : else if(mbHasInvTexCoor)
181 : : {
182 : 184336 : const double fZFactor(maIntInvTexture.getZ().getVal());
183 [ - + ]: 184336 : const double fInvZFactor(basegfx::fTools::equalZero(fZFactor) ? 1.0 : 1.0 / fZFactor);
184 : 184336 : rTarget.setX(maIntInvTexture.getX().getVal() * fInvZFactor);
185 : 184336 : rTarget.setY(maIntInvTexture.getY().getVal() * fInvZFactor);
186 : : }
187 : 184336 : }
188 : :
189 : 2586552 : void incrementLineSpanInterpolators(double fStep)
190 : : {
191 : 2586552 : maIntZ.increment(fStep);
192 : :
193 [ + + ]: 2586552 : if(mbUseTex)
194 : : {
195 [ - + ]: 190968 : if(mbHasTexCoor)
196 : : {
197 : 0 : maIntTexture.increment(fStep);
198 : : }
199 [ + - ]: 190968 : else if(mbHasInvTexCoor)
200 : : {
201 : 190968 : maIntInvTexture.increment(fStep);
202 : : }
203 : : }
204 : :
205 [ - + ]: 2586552 : if(mbUseNrm)
206 : : {
207 : 0 : maIntNormal.increment(fStep);
208 : : }
209 : :
210 [ + + ]: 2586552 : if(mbUseCol)
211 : : {
212 : 190968 : maIntColor.increment(fStep);
213 : : }
214 : 2586552 : }
215 : :
216 : 2183290 : double decideColorAndOpacity(basegfx::BColor& rColor)
217 : : {
218 : : // init values with full opacity and material color
219 : : OSL_ENSURE(0 != mpCurrentMaterial, "CurrentMaterial not set (!)");
220 : 2183290 : double fOpacity(1.0);
221 [ + - ][ + - ]: 2183290 : rColor = mpCurrentMaterial->getColor();
222 : :
223 [ + + ]: 2183290 : if(mbUseTex)
224 : : {
225 : 184336 : basegfx::B2DPoint aTexCoor(0.0, 0.0);
226 : 184336 : getTextureCoor(aTexCoor);
227 : :
228 [ + + ]: 184336 : if(mrProcessor.getGeoTexSvx().get())
229 : : {
230 : : // calc color in spot. This may also set to invisible already when
231 : : // e.g. bitmap textures have transparent parts
232 [ + - ]: 47800 : mrProcessor.getGeoTexSvx()->modifyBColor(aTexCoor, rColor, fOpacity);
233 : : }
234 : :
235 [ + - ][ + + ]: 184336 : if(basegfx::fTools::more(fOpacity, 0.0) && mrProcessor.getTransparenceGeoTexSvx().get())
[ + - ][ + + ]
236 : : {
237 : : // calc opacity. Object has a 2nd texture, a transparence texture
238 [ + - ]: 136536 : mrProcessor.getTransparenceGeoTexSvx()->modifyOpacity(aTexCoor, fOpacity);
239 : 184336 : }
240 : : }
241 : :
242 [ + + ]: 2183290 : if(basegfx::fTools::more(fOpacity, 0.0))
243 : : {
244 [ + + ]: 2183274 : if(mrProcessor.getGeoTexSvx().get())
245 : : {
246 [ - + ]: 47800 : if(mbUseNrm)
247 : : {
248 : : // blend texture with phong
249 : 0 : rColor = mrProcessor.getSdrLightingAttribute().solveColorModel(
250 : 0 : basegfx::B3DVector(maIntNormal.getX().getVal(), maIntNormal.getY().getVal(), maIntNormal.getZ().getVal()),
251 : : rColor,
252 [ # # ]: 0 : mpCurrentMaterial->getSpecular(),
253 [ # # ]: 0 : mpCurrentMaterial->getEmission(),
254 [ # # # # ]: 0 : mpCurrentMaterial->getSpecularIntensity());
[ # # ]
255 : : }
256 [ + - ]: 47800 : else if(mbUseCol)
257 : : {
258 : : // blend texture with gouraud
259 : 47800 : basegfx::BColor aBlendColor(maIntColor.getX().getVal(), maIntColor.getY().getVal(), maIntColor.getZ().getVal());
260 : 47800 : rColor *= aBlendColor;
261 : : }
262 [ # # ]: 0 : else if(mrProcessor.getModulate())
263 : : {
264 : : // blend texture with single material color
265 [ # # ]: 0 : rColor *= mpCurrentMaterial->getColor();
266 : : }
267 : : }
268 : : else
269 : : {
270 [ - + ]: 2135474 : if(mbUseNrm)
271 : : {
272 : : // modify color with phong
273 : 0 : rColor = mrProcessor.getSdrLightingAttribute().solveColorModel(
274 : 0 : basegfx::B3DVector(maIntNormal.getX().getVal(), maIntNormal.getY().getVal(), maIntNormal.getZ().getVal()),
275 : : rColor,
276 [ # # ]: 0 : mpCurrentMaterial->getSpecular(),
277 [ # # ]: 0 : mpCurrentMaterial->getEmission(),
278 [ # # # # ]: 0 : mpCurrentMaterial->getSpecularIntensity());
[ # # ]
279 : : }
280 [ + + ]: 2135474 : else if(mbUseCol)
281 : : {
282 : : // modify color with gouraud
283 : 136520 : rColor.setRed(maIntColor.getX().getVal());
284 : 136520 : rColor.setGreen(maIntColor.getY().getVal());
285 : 136520 : rColor.setBlue(maIntColor.getZ().getVal());
286 : : }
287 : : }
288 : :
289 [ - + ]: 2183274 : if(mbModifyColor)
290 : : {
291 [ # # ][ # # ]: 0 : rColor = mrProcessor.getBColorModifierStack().getModifiedColor(rColor);
292 : : }
293 : : }
294 : :
295 : 2183290 : return fOpacity;
296 : : }
297 : :
298 : 51530 : void setupLineSpanInterpolators(const basegfx::RasterConversionLineEntry3D& rA, const basegfx::RasterConversionLineEntry3D& rB)
299 : : {
300 : : // get inverse XDelta
301 : 51530 : const double xInvDelta(1.0 / (rB.getX().getVal() - rA.getX().getVal()));
302 : :
303 : : // prepare Z-interpolator
304 : 51530 : const double fZA(rA.getZ().getVal());
305 : 51530 : const double fZB(rB.getZ().getVal());
306 : 51530 : maIntZ = basegfx::ip_single(fZA, (fZB - fZA) * xInvDelta);
307 : :
308 : : // get bools and init other interpolators on demand accordingly
309 : 51530 : mbModifyColor = mrProcessor.getBColorModifierStack().count();
310 [ # # ][ - + ]: 51530 : mbHasTexCoor = SCANLINE_EMPTY_INDEX != rA.getTextureIndex() && SCANLINE_EMPTY_INDEX != rB.getTextureIndex();
311 [ + + ][ + - ]: 51530 : mbHasInvTexCoor = SCANLINE_EMPTY_INDEX != rA.getInverseTextureIndex() && SCANLINE_EMPTY_INDEX != rB.getInverseTextureIndex();
312 [ + + ][ + + ]: 51530 : const bool bTextureActive(mrProcessor.getGeoTexSvx().get() || mrProcessor.getTransparenceGeoTexSvx().get());
313 [ + + ][ + - ]: 51530 : mbUseTex = bTextureActive && (mbHasTexCoor || mbHasInvTexCoor || mrProcessor.getSimpleTextureActive());
[ - + ][ # # ]
314 [ + + ][ + + ]: 51530 : const bool bUseColorTex(mbUseTex && mrProcessor.getGeoTexSvx().get());
315 [ + + ][ + - ]: 51530 : const bool bNeedNrmOrCol(!bUseColorTex || (bUseColorTex && mrProcessor.getModulate()));
[ + - ]
316 [ + - ][ - + ]: 51530 : mbUseNrm = bNeedNrmOrCol && SCANLINE_EMPTY_INDEX != rA.getNormalIndex() && SCANLINE_EMPTY_INDEX != rB.getNormalIndex();
[ # # ]
317 [ + - ][ + - ]: 51530 : mbUseCol = !mbUseNrm && bNeedNrmOrCol && SCANLINE_EMPTY_INDEX != rA.getColorIndex() && SCANLINE_EMPTY_INDEX != rB.getColorIndex();
[ + + ][ + - ]
318 : :
319 [ + + ]: 51530 : if(mbUseTex)
320 : : {
321 [ - + ]: 6482 : if(mbHasTexCoor)
322 : : {
323 : 0 : const basegfx::ip_double& rTA(getTextureInterpolators()[rA.getTextureIndex()]);
324 : 0 : const basegfx::ip_double& rTB(getTextureInterpolators()[rB.getTextureIndex()]);
325 : : maIntTexture = basegfx::ip_double(
326 : 0 : rTA.getX().getVal(), (rTB.getX().getVal() - rTA.getX().getVal()) * xInvDelta,
327 : 0 : rTA.getY().getVal(), (rTB.getY().getVal() - rTA.getY().getVal()) * xInvDelta);
328 : : }
329 [ + - ]: 6482 : else if(mbHasInvTexCoor)
330 : : {
331 : 6482 : const basegfx::ip_triple& rITA(getInverseTextureInterpolators()[rA.getInverseTextureIndex()]);
332 : 6482 : const basegfx::ip_triple& rITB(getInverseTextureInterpolators()[rB.getInverseTextureIndex()]);
333 : : maIntInvTexture = basegfx::ip_triple(
334 : 6482 : rITA.getX().getVal(), (rITB.getX().getVal() - rITA.getX().getVal()) * xInvDelta,
335 : 6482 : rITA.getY().getVal(), (rITB.getY().getVal() - rITA.getY().getVal()) * xInvDelta,
336 : 19446 : rITA.getZ().getVal(), (rITB.getZ().getVal() - rITA.getZ().getVal()) * xInvDelta);
337 : : }
338 : : }
339 : :
340 [ - + ]: 51530 : if(mbUseNrm)
341 : : {
342 : 0 : const basegfx::ip_triple& rNA(getNormalInterpolators()[rA.getNormalIndex()]);
343 : 0 : const basegfx::ip_triple& rNB(getNormalInterpolators()[rB.getNormalIndex()]);
344 : : maIntNormal = basegfx::ip_triple(
345 : 0 : rNA.getX().getVal(), (rNB.getX().getVal() - rNA.getX().getVal()) * xInvDelta,
346 : 0 : rNA.getY().getVal(), (rNB.getY().getVal() - rNA.getY().getVal()) * xInvDelta,
347 : 0 : rNA.getZ().getVal(), (rNB.getZ().getVal() - rNA.getZ().getVal()) * xInvDelta);
348 : : }
349 : :
350 [ + + ]: 51530 : if(mbUseCol)
351 : : {
352 : 6482 : const basegfx::ip_triple& rCA(getColorInterpolators()[rA.getColorIndex()]);
353 : 6482 : const basegfx::ip_triple& rCB(getColorInterpolators()[rB.getColorIndex()]);
354 : : maIntColor = basegfx::ip_triple(
355 : 6482 : rCA.getX().getVal(), (rCB.getX().getVal() - rCA.getX().getVal()) * xInvDelta,
356 : 6482 : rCA.getY().getVal(), (rCB.getY().getVal() - rCA.getY().getVal()) * xInvDelta,
357 : 19446 : rCA.getZ().getVal(), (rCB.getZ().getVal() - rCA.getZ().getVal()) * xInvDelta);
358 : : }
359 : 51530 : }
360 : :
361 : : virtual void processLineSpan(const basegfx::RasterConversionLineEntry3D& rA, const basegfx::RasterConversionLineEntry3D& rB, sal_Int32 nLine, sal_uInt32 nSpanCount);
362 : :
363 : : public:
364 : 15 : ZBufferRasterConverter3D(basegfx::BZPixelRaster& rBuffer, const drawinglayer::processor3d::ZBufferProcessor3D& rProcessor)
365 : : : basegfx::RasterConverter3D(),
366 : : mrProcessor(rProcessor),
367 : : mrBuffer(rBuffer),
368 : : maIntZ(),
369 : : maIntColor(),
370 : : maIntNormal(),
371 : : maIntTexture(),
372 : : maIntInvTexture(),
373 : : mpCurrentMaterial(0),
374 : : mbModifyColor(false),
375 : : mbUseTex(false),
376 : : mbHasTexCoor(false),
377 : : mbHasInvTexCoor(false),
378 : : mbUseNrm(false),
379 : 15 : mbUseCol(false)
380 : 15 : {}
381 : :
382 : 581 : void setCurrentMaterial(const drawinglayer::attribute::MaterialAttribute3D& rMaterial)
383 : : {
384 : 581 : mpCurrentMaterial = &rMaterial;
385 : 581 : }
386 : : };
387 : :
388 : 52234 : void ZBufferRasterConverter3D::processLineSpan(const basegfx::RasterConversionLineEntry3D& rA, const basegfx::RasterConversionLineEntry3D& rB, sal_Int32 nLine, sal_uInt32 nSpanCount)
389 : : {
390 [ + - ]: 52234 : if(!(nSpanCount & 0x0001))
391 : : {
392 [ + - ][ + - ]: 52234 : if(nLine >= 0 && nLine < (sal_Int32)mrBuffer.getHeight())
[ + - ]
393 : : {
394 [ + - ][ + - ]: 52234 : sal_uInt32 nXA(::std::min(mrBuffer.getWidth(), (sal_uInt32)::std::max((sal_Int32)0, basegfx::fround(rA.getX().getVal()))));
395 [ + - ][ + - ]: 52234 : const sal_uInt32 nXB(::std::min(mrBuffer.getWidth(), (sal_uInt32)::std::max((sal_Int32)0, basegfx::fround(rB.getX().getVal()))));
396 : :
397 [ + + ]: 52234 : if(nXA < nXB)
398 : : {
399 : : // prepare the span interpolators
400 [ + - ]: 51530 : setupLineSpanInterpolators(rA, rB);
401 : :
402 : : // bring span interpolators to start condition by incrementing with the possible difference of
403 : : // clamped and non-clamped XStart. Interpolators are setup relying on double precision
404 : : // X-values, so that difference is the correct value to compensate for possible clampings
405 : 51530 : incrementLineSpanInterpolators(static_cast<double>(nXA) - rA.getX().getVal());
406 : :
407 : : // prepare scanline index
408 : 51530 : sal_uInt32 nScanlineIndex(mrBuffer.getIndexFromXY(nXA, static_cast<sal_uInt32>(nLine)));
409 : 51530 : basegfx::BColor aNewColor;
410 : :
411 [ + + ]: 2586552 : while(nXA < nXB)
412 : : {
413 : : // early-test Z values if we need to do anything at all
414 [ + - ][ + - ]: 2535022 : const double fNewZ(::std::max(0.0, ::std::min((double)0xffff, maIntZ.getVal())));
415 : 2535022 : const sal_uInt16 nNewZ(static_cast< sal_uInt16 >(fNewZ));
416 : 2535022 : sal_uInt16& rOldZ(mrBuffer.getZ(nScanlineIndex));
417 : :
418 [ + + ]: 2535022 : if(nNewZ > rOldZ)
419 : : {
420 : : // detect color and opacity for this pixel
421 [ + - ][ + - ]: 2183290 : const sal_uInt16 nOpacity(::std::max((sal_Int16)0, static_cast< sal_Int16 >(decideColorAndOpacity(aNewColor) * 255.0)));
422 : :
423 [ + + ]: 2183290 : if(nOpacity > 0)
424 : : {
425 : : // avoid color overrun
426 [ + - ]: 2183132 : aNewColor.clamp();
427 : :
428 [ + + ]: 2183132 : if(nOpacity >= 0x00ff)
429 : : {
430 : : // full opacity (not transparent), set z and color
431 : 2049510 : rOldZ = nNewZ;
432 : 2049510 : mrBuffer.getBPixel(nScanlineIndex) = basegfx::BPixel(aNewColor, 0xff);
433 : : }
434 : : else
435 : : {
436 : 133622 : basegfx::BPixel& rDest = mrBuffer.getBPixel(nScanlineIndex);
437 : :
438 [ + - ]: 133622 : if(rDest.getOpacity())
439 : : {
440 : : // mix new color by using
441 : : // color' = color * (1 - opacity) + newcolor * opacity
442 : 133622 : const sal_uInt16 nTransparence(0x0100 - nOpacity);
443 : 133622 : rDest.setRed((sal_uInt8)(((rDest.getRed() * nTransparence) + ((sal_uInt16)(255.0 * aNewColor.getRed()) * nOpacity)) >> 8));
444 : 133622 : rDest.setGreen((sal_uInt8)(((rDest.getGreen() * nTransparence) + ((sal_uInt16)(255.0 * aNewColor.getGreen()) * nOpacity)) >> 8));
445 : 133622 : rDest.setBlue((sal_uInt8)(((rDest.getBlue() * nTransparence) + ((sal_uInt16)(255.0 * aNewColor.getBlue()) * nOpacity)) >> 8));
446 : :
447 [ - + ]: 133622 : if(0xff != rDest.getOpacity())
448 : : {
449 : : // both are transparent, mix new opacity by using
450 : : // opacity = newopacity * (1 - oldopacity) + oldopacity
451 : 0 : rDest.setOpacity(((sal_uInt8)((nOpacity * (0x0100 - rDest.getOpacity())) >> 8)) + rDest.getOpacity());
452 : : }
453 : : }
454 : : else
455 : : {
456 : : // dest is unused, set color
457 : 0 : rDest = basegfx::BPixel(aNewColor, (sal_uInt8)nOpacity);
458 : : }
459 : : }
460 : : }
461 : : }
462 : :
463 : : // increments
464 : 2535022 : nScanlineIndex++;
465 : 2535022 : nXA++;
466 : 2535022 : incrementLineSpanInterpolators(1.0);
467 : 51530 : }
468 : : }
469 : : }
470 : : }
471 : 52234 : }
472 : :
473 : : //////////////////////////////////////////////////////////////////////////////
474 : : // helper class to buffer output for transparent rasterprimitives (filled areas
475 : : // and lines) until the end of processing. To ensure correct transparent
476 : : // visualisation, ZBuffers require to not set Z and to mix with the transparent
477 : : // color. If transparent rasterprimitives overlap, it gets necessary to
478 : : // paint transparent rasterprimitives from back to front to ensure that the
479 : : // mixing happens from back to front. For that purpose, transparent
480 : : // rasterprimitives are held in this class during the processing run, remember
481 : : // all data and will be rendered
482 : :
483 [ + - ][ + - ]: 354 : class RasterPrimitive3D
[ + - ][ + - ]
[ + - ][ + - ]
484 : : {
485 : : private:
486 : : boost::shared_ptr< drawinglayer::texture::GeoTexSvx > mpGeoTexSvx;
487 : : boost::shared_ptr< drawinglayer::texture::GeoTexSvx > mpTransparenceGeoTexSvx;
488 : : drawinglayer::attribute::MaterialAttribute3D maMaterial;
489 : : basegfx::B3DPolyPolygon maPolyPolygon;
490 : : double mfCenterZ;
491 : :
492 : : // bitfield
493 : : bool mbModulate : 1;
494 : : bool mbFilter : 1;
495 : : bool mbSimpleTextureActive : 1;
496 : : bool mbIsLine : 1;
497 : :
498 : : public:
499 : 42 : RasterPrimitive3D(
500 : : const boost::shared_ptr< drawinglayer::texture::GeoTexSvx >& pGeoTexSvx,
501 : : const boost::shared_ptr< drawinglayer::texture::GeoTexSvx >& pTransparenceGeoTexSvx,
502 : : const drawinglayer::attribute::MaterialAttribute3D& rMaterial,
503 : : const basegfx::B3DPolyPolygon& rPolyPolygon,
504 : : bool bModulate,
505 : : bool bFilter,
506 : : bool bSimpleTextureActive,
507 : : bool bIsLine)
508 : : : mpGeoTexSvx(pGeoTexSvx),
509 : : mpTransparenceGeoTexSvx(pTransparenceGeoTexSvx),
510 : : maMaterial(rMaterial),
511 : : maPolyPolygon(rPolyPolygon),
512 [ + - ][ + - ]: 42 : mfCenterZ(basegfx::tools::getRange(rPolyPolygon).getCenter().getZ()),
513 : : mbModulate(bModulate),
514 : : mbFilter(bFilter),
515 : : mbSimpleTextureActive(bSimpleTextureActive),
516 [ + - ][ + - ]: 42 : mbIsLine(bIsLine)
[ + - ]
517 : : {
518 : 42 : }
519 : :
520 : 142 : RasterPrimitive3D& operator=(const RasterPrimitive3D& rComp)
521 : : {
522 : 142 : mpGeoTexSvx = rComp.mpGeoTexSvx;
523 : 142 : mpTransparenceGeoTexSvx = rComp.mpTransparenceGeoTexSvx;
524 : 142 : maMaterial = rComp.maMaterial;
525 : 142 : maPolyPolygon = rComp.maPolyPolygon;
526 : 142 : mfCenterZ = rComp.mfCenterZ;
527 : 142 : mbModulate = rComp.mbModulate;
528 : 142 : mbFilter = rComp.mbFilter;
529 : 142 : mbSimpleTextureActive = rComp.mbSimpleTextureActive;
530 : 142 : mbIsLine = rComp.mbIsLine;
531 : :
532 : 142 : return *this;
533 : : }
534 : :
535 : 232 : bool operator<(const RasterPrimitive3D& rComp) const
536 : : {
537 : 232 : return mfCenterZ < rComp.mfCenterZ;
538 : : }
539 : :
540 : 42 : const boost::shared_ptr< drawinglayer::texture::GeoTexSvx >& getGeoTexSvx() const { return mpGeoTexSvx; }
541 : 42 : const boost::shared_ptr< drawinglayer::texture::GeoTexSvx >& getTransparenceGeoTexSvx() const { return mpTransparenceGeoTexSvx; }
542 : 42 : const drawinglayer::attribute::MaterialAttribute3D& getMaterial() const { return maMaterial; }
543 : 42 : const basegfx::B3DPolyPolygon& getPolyPolygon() const { return maPolyPolygon; }
544 : 42 : bool getModulate() const { return mbModulate; }
545 : 42 : bool getFilter() const { return mbFilter; }
546 : 42 : bool getSimpleTextureActive() const { return mbSimpleTextureActive; }
547 : 42 : bool getIsLine() const { return mbIsLine; }
548 : : };
549 : :
550 : : //////////////////////////////////////////////////////////////////////////////
551 : :
552 : : namespace drawinglayer
553 : : {
554 : : namespace processor3d
555 : : {
556 : 30 : void ZBufferProcessor3D::rasterconvertB3DPolygon(const attribute::MaterialAttribute3D& rMaterial, const basegfx::B3DPolygon& rHairline) const
557 : : {
558 [ + - ]: 30 : if(mpBZPixelRaster)
559 : : {
560 [ - + ]: 30 : if(getTransparenceCounter())
561 : : {
562 : : // transparent output; record for later sorting and painting from
563 : : // back to front
564 [ # # ]: 0 : if(!mpRasterPrimitive3Ds)
565 : : {
566 [ # # ]: 0 : const_cast< ZBufferProcessor3D* >(this)->mpRasterPrimitive3Ds = new std::vector< RasterPrimitive3D >;
567 : : }
568 : :
569 : : mpRasterPrimitive3Ds->push_back(RasterPrimitive3D(
570 : 0 : getGeoTexSvx(),
571 : 0 : getTransparenceGeoTexSvx(),
572 : : rMaterial,
573 : : basegfx::B3DPolyPolygon(rHairline),
574 : 0 : getModulate(),
575 : 0 : getFilter(),
576 : 0 : getSimpleTextureActive(),
577 [ # # ][ # # ]: 0 : true));
[ # # ]
578 : : }
579 : : else
580 : : {
581 : : // do rasterconversion
582 : 30 : mpZBufferRasterConverter3D->setCurrentMaterial(rMaterial);
583 : :
584 [ - + ]: 30 : if(mnAntiAlialize > 1)
585 : : {
586 [ # # ][ # # ]: 0 : const bool bForceLineSnap(getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete());
587 : :
588 [ # # ]: 0 : if(bForceLineSnap)
589 : : {
590 [ # # ]: 0 : basegfx::B3DHomMatrix aTransform;
591 [ # # ]: 0 : basegfx::B3DPolygon aSnappedHairline(rHairline);
592 : 0 : const double fScaleDown(1.0 / mnAntiAlialize);
593 : 0 : const double fScaleUp(mnAntiAlialize);
594 : :
595 : : // take oversampling out
596 [ # # ]: 0 : aTransform.scale(fScaleDown, fScaleDown, 1.0);
597 [ # # ]: 0 : aSnappedHairline.transform(aTransform);
598 : :
599 : : // snap to integer
600 [ # # ][ # # ]: 0 : aSnappedHairline = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges(aSnappedHairline);
[ # # ]
601 : :
602 : : // add oversampling again
603 [ # # ]: 0 : aTransform.identity();
604 [ # # ]: 0 : aTransform.scale(fScaleUp, fScaleUp, 1.0);
605 : :
606 [ # # ]: 0 : aSnappedHairline.transform(aTransform);
607 : :
608 [ # # ][ # # ]: 0 : mpZBufferRasterConverter3D->rasterconvertB3DPolygon(aSnappedHairline, 0, mpBZPixelRaster->getHeight(), mnAntiAlialize);
[ # # ]
609 : : }
610 : : else
611 : : {
612 : 0 : mpZBufferRasterConverter3D->rasterconvertB3DPolygon(rHairline, 0, mpBZPixelRaster->getHeight(), mnAntiAlialize);
613 : : }
614 : : }
615 : : else
616 : : {
617 : 30 : mpZBufferRasterConverter3D->rasterconvertB3DPolygon(rHairline, 0, mpBZPixelRaster->getHeight(), 1);
618 : : }
619 : : }
620 : : }
621 : 30 : }
622 : :
623 : 593 : void ZBufferProcessor3D::rasterconvertB3DPolyPolygon(const attribute::MaterialAttribute3D& rMaterial, const basegfx::B3DPolyPolygon& rFill) const
624 : : {
625 [ + - ]: 593 : if(mpBZPixelRaster)
626 : : {
627 [ + + ]: 593 : if(getTransparenceCounter())
628 : : {
629 : : // transparent output; record for later sorting and painting from
630 : : // back to front
631 [ + + ]: 42 : if(!mpRasterPrimitive3Ds)
632 : : {
633 [ + - ]: 2 : const_cast< ZBufferProcessor3D* >(this)->mpRasterPrimitive3Ds = new std::vector< RasterPrimitive3D >;
634 : : }
635 : :
636 : : mpRasterPrimitive3Ds->push_back(RasterPrimitive3D(
637 : 42 : getGeoTexSvx(),
638 : 42 : getTransparenceGeoTexSvx(),
639 : : rMaterial,
640 : : rFill,
641 : 42 : getModulate(),
642 : 42 : getFilter(),
643 : 42 : getSimpleTextureActive(),
644 [ + - ]: 42 : false));
645 : : }
646 : : else
647 : : {
648 : 551 : mpZBufferRasterConverter3D->setCurrentMaterial(rMaterial);
649 : 551 : mpZBufferRasterConverter3D->rasterconvertB3DPolyPolygon(rFill, &maInvEyeToView, 0, mpBZPixelRaster->getHeight());
650 : : }
651 : : }
652 : 593 : }
653 : :
654 : 15 : ZBufferProcessor3D::ZBufferProcessor3D(
655 : : const geometry::ViewInformation3D& rViewInformation3D,
656 : : const geometry::ViewInformation2D& rViewInformation2D,
657 : : const attribute::SdrSceneAttribute& rSdrSceneAttribute,
658 : : const attribute::SdrLightingAttribute& rSdrLightingAttribute,
659 : : double fSizeX,
660 : : double fSizeY,
661 : : const basegfx::B2DRange& rVisiblePart,
662 : : sal_uInt16 nAntiAlialize)
663 : : : DefaultProcessor3D(rViewInformation3D, rSdrSceneAttribute, rSdrLightingAttribute),
664 : : mpBZPixelRaster(0),
665 : : maInvEyeToView(),
666 : : mpZBufferRasterConverter3D(0),
667 : : mnAntiAlialize(nAntiAlialize),
668 [ + - ]: 15 : mpRasterPrimitive3Ds(0)
669 : : {
670 : : // generate ViewSizes
671 [ + - ][ + - ]: 15 : const double fFullViewSizeX((rViewInformation2D.getObjectToViewTransformation() * basegfx::B2DVector(fSizeX, 0.0)).getLength());
[ + - ]
672 [ + - ][ + - ]: 15 : const double fFullViewSizeY((rViewInformation2D.getObjectToViewTransformation() * basegfx::B2DVector(0.0, fSizeY)).getLength());
[ + - ]
673 [ + - ]: 15 : const double fViewSizeX(fFullViewSizeX * rVisiblePart.getWidth());
674 [ + - ]: 15 : const double fViewSizeY(fFullViewSizeY * rVisiblePart.getHeight());
675 : :
676 : : // generate RasterWidth and RasterHeight
677 : 15 : const sal_uInt32 nRasterWidth((sal_uInt32)basegfx::fround(fViewSizeX) + 1);
678 : 15 : const sal_uInt32 nRasterHeight((sal_uInt32)basegfx::fround(fViewSizeY) + 1);
679 : :
680 [ + - ][ + - ]: 15 : if(nRasterWidth && nRasterHeight)
681 : : {
682 : : // create view unit buffer
683 : : mpBZPixelRaster = new basegfx::BZPixelRaster(
684 : : mnAntiAlialize ? nRasterWidth * mnAntiAlialize : nRasterWidth,
685 [ + - ][ - + ]: 15 : mnAntiAlialize ? nRasterHeight * mnAntiAlialize : nRasterHeight);
[ - + ][ + - ]
686 : : OSL_ENSURE(mpBZPixelRaster, "ZBufferProcessor3D: Could not allocate basegfx::BZPixelRaster (!)");
687 : :
688 : : // create DeviceToView for Z-Buffer renderer since Z is handled
689 : : // different from standard 3D transformations (Z is mirrored). Also
690 : : // the transformation includes the step from unit device coordinates
691 : : // to discrete units ([-1.0 .. 1.0] -> [minDiscrete .. maxDiscrete]
692 : :
693 [ + - ]: 15 : basegfx::B3DHomMatrix aDeviceToView;
694 : :
695 : : {
696 : : // step one:
697 : : //
698 : : // bring from [-1.0 .. 1.0] in X,Y and Z to [0.0 .. 1.0]. Also
699 : : // necessary to
700 : : // - flip Y due to screen orientation
701 : : // - flip Z due to Z-Buffer orientation from back to front
702 : :
703 [ + - ]: 15 : aDeviceToView.scale(0.5, -0.5, -0.5);
704 [ + - ]: 15 : aDeviceToView.translate(0.5, 0.5, 0.5);
705 : : }
706 : :
707 : : {
708 : : // step two:
709 : : //
710 : : // bring from [0.0 .. 1.0] in X,Y and Z to view cordinates
711 : : //
712 : : // #i102611#
713 : : // also: scale Z to [1.5 .. 65534.5]. Normally, a range of [0.0 .. 65535.0]
714 : : // could be used, but a 'unused' value is needed, so '0' is used what reduces
715 : : // the range to [1.0 .. 65535.0]. It has also shown that small numerical errors
716 : : // (smaller as basegfx::fTools::mfSmallValue, which is 0.000000001) happen.
717 : : // Instead of checking those by basegfx::fTools methods which would cost
718 : : // runtime, just add another 0.5 tolerance to the start and end of the Z-Buffer
719 : : // range, thus resulting in [1.5 .. 65534.5]
720 : 15 : const double fMaxZDepth(65533.0);
721 [ + - ][ + - ]: 15 : aDeviceToView.translate(-rVisiblePart.getMinX(), -rVisiblePart.getMinY(), 0.0);
[ + - ]
722 : :
723 [ - + ]: 15 : if(mnAntiAlialize)
724 [ # # ]: 0 : aDeviceToView.scale(fFullViewSizeX * mnAntiAlialize, fFullViewSizeY * mnAntiAlialize, fMaxZDepth);
725 : : else
726 [ + - ]: 15 : aDeviceToView.scale(fFullViewSizeX, fFullViewSizeY, fMaxZDepth);
727 : :
728 [ + - ]: 15 : aDeviceToView.translate(0.0, 0.0, 1.5);
729 : : }
730 : :
731 : : // update local ViewInformation3D with own DeviceToView
732 : : const geometry::ViewInformation3D aNewViewInformation3D(
733 [ + - ]: 15 : getViewInformation3D().getObjectTransformation(),
734 [ + - ]: 15 : getViewInformation3D().getOrientation(),
735 [ + - ]: 15 : getViewInformation3D().getProjection(),
736 : : aDeviceToView,
737 : 15 : getViewInformation3D().getViewTime(),
738 [ + - + - ]: 45 : getViewInformation3D().getExtendedInformationSequence());
[ + - ]
739 [ + - ]: 15 : updateViewInformation(aNewViewInformation3D);
740 : :
741 : : // prepare inverse EyeToView transformation. This can be done in constructor
742 : : // since changes in object transformations when processing TransformPrimitive3Ds
743 : : // do not influence this prepared partial transformation
744 [ + - ][ + - ]: 15 : maInvEyeToView = getViewInformation3D().getDeviceToView() * getViewInformation3D().getProjection();
[ + - ][ + - ]
[ + - ]
745 [ + - ]: 15 : maInvEyeToView.invert();
746 : :
747 : : // prepare maRasterRange
748 [ + - ]: 15 : maRasterRange.reset();
749 [ + - ]: 15 : maRasterRange.expand(basegfx::B2DPoint(0.0, 0.0));
750 [ + - ]: 15 : maRasterRange.expand(basegfx::B2DPoint(mpBZPixelRaster->getWidth(), mpBZPixelRaster->getHeight()));
751 : :
752 : : // create the raster converter
753 [ + - ][ + - ]: 15 : mpZBufferRasterConverter3D = new ZBufferRasterConverter3D(*mpBZPixelRaster, *this);
[ + - ][ + - ]
754 : : }
755 : 15 : }
756 : :
757 [ + - ]: 15 : ZBufferProcessor3D::~ZBufferProcessor3D()
758 : : {
759 [ + - ]: 15 : if(mpBZPixelRaster)
760 : : {
761 [ + - ][ + - ]: 15 : delete mpZBufferRasterConverter3D;
762 [ + - ]: 15 : delete mpBZPixelRaster;
763 : : }
764 : :
765 [ - + ]: 15 : if(mpRasterPrimitive3Ds)
766 : : {
767 : : OSL_FAIL("ZBufferProcessor3D: destructed, but there are unrendered transparent geometries. Use ZBufferProcessor3D::finish() to render these (!)");
768 [ # # ]: 0 : delete mpRasterPrimitive3Ds;
769 : : }
770 [ - + ]: 15 : }
771 : :
772 : 15 : void ZBufferProcessor3D::finish()
773 : : {
774 [ + + ]: 15 : if(mpRasterPrimitive3Ds)
775 : : {
776 : : // there are transparent rasterprimitives
777 : 2 : const sal_uInt32 nSize(mpRasterPrimitive3Ds->size());
778 : :
779 [ + - ]: 2 : if(nSize > 1)
780 : : {
781 : : // sort them from back to front
782 : 2 : std::sort(mpRasterPrimitive3Ds->begin(), mpRasterPrimitive3Ds->end());
783 : : }
784 : :
785 [ + + ]: 44 : for(sal_uInt32 a(0); a < nSize; a++)
786 : : {
787 : : // paint each one by setting the remembered data and calling
788 : : // the render method
789 : 42 : const RasterPrimitive3D& rCandidate = (*mpRasterPrimitive3Ds)[a];
790 : :
791 : 42 : mpGeoTexSvx = rCandidate.getGeoTexSvx();
792 : 42 : mpTransparenceGeoTexSvx = rCandidate.getTransparenceGeoTexSvx();
793 : 42 : mbModulate = rCandidate.getModulate();
794 : 42 : mbFilter = rCandidate.getFilter();
795 : 42 : mbSimpleTextureActive = rCandidate.getSimpleTextureActive();
796 : :
797 [ - + ]: 42 : if(rCandidate.getIsLine())
798 : : {
799 : : rasterconvertB3DPolygon(
800 : 0 : rCandidate.getMaterial(),
801 [ # # ]: 0 : rCandidate.getPolyPolygon().getB3DPolygon(0));
802 : : }
803 : : else
804 : : {
805 : : rasterconvertB3DPolyPolygon(
806 : 42 : rCandidate.getMaterial(),
807 : 84 : rCandidate.getPolyPolygon());
808 : : }
809 : : }
810 : :
811 : : // delete them to signal the destructor that all is done and
812 : : // to allow asserting there
813 [ + - ]: 2 : delete mpRasterPrimitive3Ds;
814 : 2 : mpRasterPrimitive3Ds = 0;
815 : : }
816 : 15 : }
817 : :
818 : 15 : BitmapEx ZBufferProcessor3D::getBitmapEx() const
819 : : {
820 [ + - ]: 15 : if(mpBZPixelRaster)
821 : : {
822 : 15 : return BPixelRasterToBitmapEx(*mpBZPixelRaster, mnAntiAlialize);
823 : : }
824 : :
825 : 15 : return BitmapEx();
826 : : }
827 : : } // end of namespace processor3d
828 : : } // end of namespace drawinglayer
829 : :
830 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|