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