update credits
[LibreOffice.git] / drawinglayer / source / processor3d / defaultprocessor3d.cxx
blob1781efbbe282c0f53cdb05048ea84ebe0a10d0ee
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/processor3d/defaultprocessor3d.hxx>
21 #include <drawinglayer/primitive3d/textureprimitive3d.hxx>
22 #include <drawinglayer/texture/texture.hxx>
23 #include <drawinglayer/texture/texture3d.hxx>
24 #include <drawinglayer/primitive3d/hatchtextureprimitive3d.hxx>
25 #include <drawinglayer/primitive3d/modifiedcolorprimitive3d.hxx>
26 #include <drawinglayer/primitive3d/polygonprimitive3d.hxx>
27 #include <basegfx/polygon/b3dpolygontools.hxx>
28 #include <drawinglayer/attribute/materialattribute3d.hxx>
29 #include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx>
30 #include <basegfx/polygon/b3dpolypolygontools.hxx>
31 #include <com/sun/star/drawing/ShadeMode.hpp>
32 #include <drawinglayer/primitive3d/transformprimitive3d.hxx>
33 #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx>
34 #include <vcl/bitmapex.hxx>
35 #include <drawinglayer/attribute/sdrsceneattribute3d.hxx>
36 #include <drawinglayer/attribute/sdrlightingattribute3d.hxx>
38 //////////////////////////////////////////////////////////////////////////////
40 using namespace com::sun::star;
42 //////////////////////////////////////////////////////////////////////////////
44 namespace drawinglayer
46 namespace processor3d
48 void DefaultProcessor3D::impRenderGradientTexturePrimitive3D(const primitive3d::GradientTexturePrimitive3D& rPrimitive, bool bTransparence)
50 const primitive3d::Primitive3DSequence& rSubSequence = rPrimitive.getChildren();
52 if(rSubSequence.hasElements())
54 // rescue values
55 const bool bOldModulate(getModulate()); mbModulate = rPrimitive.getModulate();
56 const bool bOldFilter(getFilter()); mbFilter = rPrimitive.getFilter();
57 const bool bOldSimpleTextureActive(getSimpleTextureActive());
58 boost::shared_ptr< texture::GeoTexSvx > pOldTex = (bTransparence) ? mpTransparenceGeoTexSvx : mpGeoTexSvx;
60 // create texture
61 const attribute::FillGradientAttribute& rFillGradient = rPrimitive.getGradient();
62 const basegfx::B2DRange aOutlineRange(0.0, 0.0, rPrimitive.getTextureSize().getX(), rPrimitive.getTextureSize().getY());
63 const attribute::GradientStyle aGradientStyle(rFillGradient.getStyle());
64 sal_uInt32 nSteps(rFillGradient.getSteps());
65 const basegfx::BColor aStart(rFillGradient.getStartColor());
66 const basegfx::BColor aEnd(rFillGradient.getEndColor());
67 const sal_uInt32 nMaxSteps(sal_uInt32((aStart.getMaximumDistance(aEnd) * 127.5) + 0.5));
68 boost::shared_ptr< texture::GeoTexSvx > pNewTex;
70 if(nMaxSteps)
72 // there IS a color distance
73 if(nSteps == 0L)
75 nSteps = nMaxSteps;
78 if(nSteps < 2L)
80 nSteps = 2L;
83 if(nSteps > nMaxSteps)
85 nSteps = nMaxSteps;
88 switch(aGradientStyle)
90 case attribute::GRADIENTSTYLE_LINEAR:
92 pNewTex.reset(new texture::GeoTexSvxGradientLinear(aOutlineRange, aStart, aEnd, nSteps, rFillGradient.getBorder(), rFillGradient.getAngle()));
93 break;
95 case attribute::GRADIENTSTYLE_AXIAL:
97 pNewTex.reset(new texture::GeoTexSvxGradientAxial(aOutlineRange, aStart, aEnd, nSteps, rFillGradient.getBorder(), rFillGradient.getAngle()));
98 break;
100 case attribute::GRADIENTSTYLE_RADIAL:
102 pNewTex.reset(new texture::GeoTexSvxGradientRadial(aOutlineRange, aStart, aEnd, nSteps, rFillGradient.getBorder(), rFillGradient.getOffsetX(), rFillGradient.getOffsetY()));
103 break;
105 case attribute::GRADIENTSTYLE_ELLIPTICAL:
107 pNewTex.reset(new texture::GeoTexSvxGradientElliptical(aOutlineRange, aStart, aEnd, nSteps, rFillGradient.getBorder(), rFillGradient.getOffsetX(), rFillGradient.getOffsetY(), rFillGradient.getAngle()));
108 break;
110 case attribute::GRADIENTSTYLE_SQUARE:
112 pNewTex.reset(new texture::GeoTexSvxGradientSquare(aOutlineRange, aStart, aEnd, nSteps, rFillGradient.getBorder(), rFillGradient.getOffsetX(), rFillGradient.getOffsetY(), rFillGradient.getAngle()));
113 break;
115 case attribute::GRADIENTSTYLE_RECT:
117 pNewTex.reset(new texture::GeoTexSvxGradientRect(aOutlineRange, aStart, aEnd, nSteps, rFillGradient.getBorder(), rFillGradient.getOffsetX(), rFillGradient.getOffsetY(), rFillGradient.getAngle()));
118 break;
122 mbSimpleTextureActive = false;
124 else
126 // no color distance -> same color, use simple texture
127 pNewTex.reset(new texture::GeoTexSvxMono(aStart, 1.0 - aStart.luminance()));
128 mbSimpleTextureActive = true;
131 // set created texture
132 if(bTransparence)
134 mpTransparenceGeoTexSvx = pNewTex;
136 else
138 mpGeoTexSvx = pNewTex;
141 // process sub-list
142 process(rSubSequence);
144 // restore values
145 mbModulate = bOldModulate;
146 mbFilter = bOldFilter;
147 mbSimpleTextureActive = bOldSimpleTextureActive;
149 if(bTransparence)
151 mpTransparenceGeoTexSvx = pOldTex;
153 else
155 mpGeoTexSvx = pOldTex;
160 void DefaultProcessor3D::impRenderHatchTexturePrimitive3D(const primitive3d::HatchTexturePrimitive3D& rPrimitive)
162 const primitive3d::Primitive3DSequence& rSubSequence = rPrimitive.getChildren();
164 if(rSubSequence.hasElements())
166 // rescue values
167 const bool bOldModulate(getModulate()); mbModulate = rPrimitive.getModulate();
168 const bool bOldFilter(getFilter()); mbFilter = rPrimitive.getFilter();
169 boost::shared_ptr< texture::GeoTexSvx > pOldTex = mpGeoTexSvx;
171 // calculate logic pixel size in object coordinates. Create transformation view
172 // to object by inverting ObjectToView
173 basegfx::B3DHomMatrix aInvObjectToView(getViewInformation3D().getObjectToView());
174 aInvObjectToView.invert();
176 // back-project discrete coordinates to object coordinates and extract
177 // maximum distance
178 const basegfx::B3DPoint aZero(aInvObjectToView * basegfx::B3DPoint(0.0, 0.0, 0.0));
179 const basegfx::B3DPoint aOne(aInvObjectToView * basegfx::B3DPoint(1.0, 1.0, 1.0));
180 const basegfx::B3DVector aLogicPixel(aOne - aZero);
181 double fLogicPixelSizeWorld(::std::max(::std::max(fabs(aLogicPixel.getX()), fabs(aLogicPixel.getY())), fabs(aLogicPixel.getZ())));
183 // calculate logic pixel size in texture coordinates
184 const double fLogicTexSizeX(fLogicPixelSizeWorld / rPrimitive.getTextureSize().getX());
185 const double fLogicTexSizeY(fLogicPixelSizeWorld / rPrimitive.getTextureSize().getY());
186 const double fLogicTexSize(fLogicTexSizeX > fLogicTexSizeY ? fLogicTexSizeX : fLogicTexSizeY);
188 // create texture and set
189 mpGeoTexSvx.reset(new texture::GeoTexSvxMultiHatch(rPrimitive, fLogicTexSize));
191 // process sub-list
192 process(rSubSequence);
194 // restore values
195 mbModulate = bOldModulate;
196 mbFilter = bOldFilter;
197 mpGeoTexSvx = pOldTex;
201 void DefaultProcessor3D::impRenderBitmapTexturePrimitive3D(const primitive3d::BitmapTexturePrimitive3D& rPrimitive)
203 const primitive3d::Primitive3DSequence& rSubSequence = rPrimitive.getChildren();
205 if(rSubSequence.hasElements())
207 // rescue values
208 const bool bOldModulate(getModulate()); mbModulate = rPrimitive.getModulate();
209 const bool bOldFilter(getFilter()); mbFilter = rPrimitive.getFilter();
210 boost::shared_ptr< texture::GeoTexSvx > pOldTex = mpGeoTexSvx;
212 // create texture
213 const attribute::FillBitmapAttribute& rFillBitmapAttribute = rPrimitive.getFillBitmapAttribute();
215 if(rFillBitmapAttribute.getTiling())
217 mpGeoTexSvx.reset(new texture::GeoTexSvxBitmapTiled(
218 rFillBitmapAttribute.getBitmapEx().GetBitmap(),
219 rFillBitmapAttribute.getTopLeft() * rPrimitive.getTextureSize(),
220 rFillBitmapAttribute.getSize() * rPrimitive.getTextureSize()));
222 else
224 mpGeoTexSvx.reset(new texture::GeoTexSvxBitmap(
225 rFillBitmapAttribute.getBitmapEx().GetBitmap(),
226 rFillBitmapAttribute.getTopLeft() * rPrimitive.getTextureSize(),
227 rFillBitmapAttribute.getSize() * rPrimitive.getTextureSize()));
230 // process sub-list
231 process(rSubSequence);
233 // restore values
234 mbModulate = bOldModulate;
235 mbFilter = bOldFilter;
236 mpGeoTexSvx = pOldTex;
240 void DefaultProcessor3D::impRenderModifiedColorPrimitive3D(const primitive3d::ModifiedColorPrimitive3D& rModifiedCandidate)
242 const primitive3d::Primitive3DSequence& rSubSequence = rModifiedCandidate.getChildren();
244 if(rSubSequence.hasElements())
246 // put modifier on stack
247 maBColorModifierStack.push(rModifiedCandidate.getColorModifier());
249 // process sub-list
250 process(rModifiedCandidate.getChildren());
252 // remove modifier from stack
253 maBColorModifierStack.pop();
257 void DefaultProcessor3D::impRenderPolygonHairlinePrimitive3D(const primitive3d::PolygonHairlinePrimitive3D& rPrimitive)
259 basegfx::B3DPolygon aHairline(rPrimitive.getB3DPolygon());
261 if(aHairline.count())
263 // hairlines need no extra data, clear it
264 aHairline.clearTextureCoordinates();
265 aHairline.clearNormals();
266 aHairline.clearBColors();
268 // transform to device coordinates (-1.0 .. 1.0) and check for visibility
269 aHairline.transform(getViewInformation3D().getObjectToView());
270 const basegfx::B3DRange a3DRange(basegfx::tools::getRange(aHairline));
271 const basegfx::B2DRange a2DRange(a3DRange.getMinX(), a3DRange.getMinY(), a3DRange.getMaxX(), a3DRange.getMaxY());
273 if(a2DRange.overlaps(maRasterRange))
275 const attribute::MaterialAttribute3D aMaterial(maBColorModifierStack.getModifiedColor(rPrimitive.getBColor()));
277 rasterconvertB3DPolygon(aMaterial, aHairline);
282 void DefaultProcessor3D::impRenderPolyPolygonMaterialPrimitive3D(const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive)
284 basegfx::B3DPolyPolygon aFill(rPrimitive.getB3DPolyPolygon());
285 basegfx::BColor aObjectColor(rPrimitive.getMaterial().getColor());
286 bool bPaintIt(aFill.count());
288 // #i98295# get ShadeMode. Correct early when only flat is possible due to missing normals
289 const ::com::sun::star::drawing::ShadeMode aShadeMode(
290 aFill.areNormalsUsed() ?
291 getSdrSceneAttribute().getShadeMode() : ::com::sun::star::drawing::ShadeMode_FLAT);
293 if(bPaintIt)
295 // get rid of texture coordinates if there is no texture
296 if(aFill.areTextureCoordinatesUsed() && !getGeoTexSvx().get() && !getTransparenceGeoTexSvx().get())
298 aFill.clearTextureCoordinates();
301 // #i98295# get rid of normals and color early when not needed
302 if(::com::sun::star::drawing::ShadeMode_FLAT == aShadeMode)
304 aFill.clearNormals();
305 aFill.clearBColors();
308 // transform to device coordinates (-1.0 .. 1.0) and check for visibility
309 aFill.transform(getViewInformation3D().getObjectToView());
310 const basegfx::B3DRange a3DRange(basegfx::tools::getRange(aFill));
311 const basegfx::B2DRange a2DRange(a3DRange.getMinX(), a3DRange.getMinY(), a3DRange.getMaxX(), a3DRange.getMaxY());
313 bPaintIt = a2DRange.overlaps(maRasterRange);
316 // check if it shall be painted regarding hiding of normals (backface culling)
317 if(bPaintIt && !rPrimitive.getDoubleSided())
319 // get plane normal of polygon in view coordinates (with ZBuffer values),
320 // left-handed coordinate system
321 const basegfx::B3DVector aPlaneNormal(aFill.getB3DPolygon(0L).getNormal());
323 if(aPlaneNormal.getZ() > 0.0)
325 bPaintIt = false;
329 if(bPaintIt)
331 // prepare ObjectToEye in NormalTransform
332 basegfx::B3DHomMatrix aNormalTransform(getViewInformation3D().getOrientation() * getViewInformation3D().getObjectTransformation());
334 if(getSdrSceneAttribute().getTwoSidedLighting())
336 // get plane normal of polygon in view coordinates (with ZBuffer values),
337 // left-handed coordinate system
338 const basegfx::B3DVector aPlaneNormal(aFill.getB3DPolygon(0L).getNormal());
340 if(aPlaneNormal.getZ() > 0.0)
342 // mirror normals
343 aNormalTransform.scale(-1.0, -1.0, -1.0);
347 switch(aShadeMode)
349 case ::com::sun::star::drawing::ShadeMode_PHONG:
351 // phong shading. Transform normals to eye coor
352 aFill.transformNormals(aNormalTransform);
353 break;
355 case ::com::sun::star::drawing::ShadeMode_SMOOTH:
357 // gouraud shading. Transform normals to eye coor
358 aFill.transformNormals(aNormalTransform);
360 // prepare color model parameters, evtl. use blend color
361 const basegfx::BColor aColor(getModulate() ? basegfx::BColor(1.0, 1.0, 1.0) : rPrimitive.getMaterial().getColor());
362 const basegfx::BColor& rSpecular(rPrimitive.getMaterial().getSpecular());
363 const basegfx::BColor& rEmission(rPrimitive.getMaterial().getEmission());
364 const sal_uInt16 nSpecularIntensity(rPrimitive.getMaterial().getSpecularIntensity());
366 // solve color model for each normal vector, set colors at points. Clear normals.
367 for(sal_uInt32 a(0L); a < aFill.count(); a++)
369 basegfx::B3DPolygon aPartFill(aFill.getB3DPolygon(a));
371 for(sal_uInt32 b(0L); b < aPartFill.count(); b++)
373 // solve color model. Transform normal to eye coor
374 const basegfx::B3DVector aNormal(aPartFill.getNormal(b));
375 const basegfx::BColor aSolvedColor(getSdrLightingAttribute().solveColorModel(aNormal, aColor, rSpecular, rEmission, nSpecularIntensity));
376 aPartFill.setBColor(b, aSolvedColor);
379 // clear normals on this part polygon and write it back
380 aPartFill.clearNormals();
381 aFill.setB3DPolygon(a, aPartFill);
383 break;
385 case ::com::sun::star::drawing::ShadeMode_FLAT:
387 // flat shading. Get plane vector in eye coordinates
388 const basegfx::B3DVector aPlaneEyeNormal(aNormalTransform * rPrimitive.getB3DPolyPolygon().getB3DPolygon(0L).getNormal());
390 // prepare color model parameters, evtl. use blend color
391 const basegfx::BColor aColor(getModulate() ? basegfx::BColor(1.0, 1.0, 1.0) : rPrimitive.getMaterial().getColor());
392 const basegfx::BColor& rSpecular(rPrimitive.getMaterial().getSpecular());
393 const basegfx::BColor& rEmission(rPrimitive.getMaterial().getEmission());
394 const sal_uInt16 nSpecularIntensity(rPrimitive.getMaterial().getSpecularIntensity());
396 // solve color model for plane vector and use that color for whole plane
397 aObjectColor = getSdrLightingAttribute().solveColorModel(aPlaneEyeNormal, aColor, rSpecular, rEmission, nSpecularIntensity);
398 break;
400 default: // case ::com::sun::star::drawing::ShadeMode_DRAFT:
402 // draft, just use object color which is already set. Delete all other infos
403 aFill.clearNormals();
404 aFill.clearBColors();
405 break;
409 // draw it to ZBuffer
410 const attribute::MaterialAttribute3D aMaterial(
411 maBColorModifierStack.getModifiedColor(aObjectColor),
412 rPrimitive.getMaterial().getSpecular(),
413 rPrimitive.getMaterial().getEmission(),
414 rPrimitive.getMaterial().getSpecularIntensity());
416 rasterconvertB3DPolyPolygon(aMaterial, aFill);
420 void DefaultProcessor3D::impRenderTransformPrimitive3D(const primitive3d::TransformPrimitive3D& rTransformCandidate)
422 // transform group. Remember current transformations
423 const geometry::ViewInformation3D aLastViewInformation3D(getViewInformation3D());
425 // create new transformation; add new object transform from right side
426 const geometry::ViewInformation3D aNewViewInformation3D(
427 aLastViewInformation3D.getObjectTransformation() * rTransformCandidate.getTransformation(),
428 aLastViewInformation3D.getOrientation(),
429 aLastViewInformation3D.getProjection(),
430 aLastViewInformation3D.getDeviceToView(),
431 aLastViewInformation3D.getViewTime(),
432 aLastViewInformation3D.getExtendedInformationSequence());
433 updateViewInformation(aNewViewInformation3D);
435 // let break down recursively
436 process(rTransformCandidate.getChildren());
438 // restore transformations
439 updateViewInformation(aLastViewInformation3D);
442 void DefaultProcessor3D::processBasePrimitive3D(const primitive3d::BasePrimitive3D& rBasePrimitive)
444 // it is a BasePrimitive3D implementation, use getPrimitive3DID() call for switch
445 switch(rBasePrimitive.getPrimitive3DID())
447 case PRIMITIVE3D_ID_GRADIENTTEXTUREPRIMITIVE3D :
449 // GradientTexturePrimitive3D
450 const primitive3d::GradientTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::GradientTexturePrimitive3D& >(rBasePrimitive);
451 impRenderGradientTexturePrimitive3D(rPrimitive, false);
452 break;
454 case PRIMITIVE3D_ID_HATCHTEXTUREPRIMITIVE3D :
456 // HatchTexturePrimitive3D
457 static bool bDoHatchDecomposition(false);
459 if(bDoHatchDecomposition)
461 // let break down
462 process(rBasePrimitive.get3DDecomposition(getViewInformation3D()));
464 else
466 // hatchTexturePrimitive3D
467 const primitive3d::HatchTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::HatchTexturePrimitive3D& >(rBasePrimitive);
468 impRenderHatchTexturePrimitive3D(rPrimitive);
470 break;
472 case PRIMITIVE3D_ID_BITMAPTEXTUREPRIMITIVE3D :
474 // BitmapTexturePrimitive3D
475 const primitive3d::BitmapTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::BitmapTexturePrimitive3D& >(rBasePrimitive);
476 impRenderBitmapTexturePrimitive3D(rPrimitive);
477 break;
479 case PRIMITIVE3D_ID_TRANSPARENCETEXTUREPRIMITIVE3D :
481 // TransparenceTexturePrimitive3D
482 const primitive3d::TransparenceTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::TransparenceTexturePrimitive3D& >(rBasePrimitive);
483 mnTransparenceCounter++;
484 impRenderGradientTexturePrimitive3D(rPrimitive, true);
485 mnTransparenceCounter--;
486 break;
488 case PRIMITIVE3D_ID_MODIFIEDCOLORPRIMITIVE3D :
490 // ModifiedColorPrimitive3D
491 // Force output to unified color.
492 const primitive3d::ModifiedColorPrimitive3D& rPrimitive = static_cast< const primitive3d::ModifiedColorPrimitive3D& >(rBasePrimitive);
493 impRenderModifiedColorPrimitive3D(rPrimitive);
494 break;
496 case PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D :
498 // directdraw of PolygonHairlinePrimitive3D
499 const primitive3d::PolygonHairlinePrimitive3D& rPrimitive = static_cast< const primitive3d::PolygonHairlinePrimitive3D& >(rBasePrimitive);
500 impRenderPolygonHairlinePrimitive3D(rPrimitive);
501 break;
503 case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D :
505 // directdraw of PolyPolygonMaterialPrimitive3D
506 const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive = static_cast< const primitive3d::PolyPolygonMaterialPrimitive3D& >(rBasePrimitive);
507 impRenderPolyPolygonMaterialPrimitive3D(rPrimitive);
508 break;
510 case PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D :
512 // transform group (TransformPrimitive3D)
513 impRenderTransformPrimitive3D(static_cast< const primitive3d::TransformPrimitive3D& >(rBasePrimitive));
514 break;
516 default:
518 // process recursively
519 process(rBasePrimitive.get3DDecomposition(getViewInformation3D()));
520 break;
525 DefaultProcessor3D::DefaultProcessor3D(
526 const geometry::ViewInformation3D& rViewInformation,
527 const attribute::SdrSceneAttribute& rSdrSceneAttribute,
528 const attribute::SdrLightingAttribute& rSdrLightingAttribute)
529 : BaseProcessor3D(rViewInformation),
530 mrSdrSceneAttribute(rSdrSceneAttribute),
531 mrSdrLightingAttribute(rSdrLightingAttribute),
532 maRasterRange(),
533 maBColorModifierStack(),
534 mpGeoTexSvx(),
535 mpTransparenceGeoTexSvx(),
536 maDrawinglayerOpt(),
537 mnTransparenceCounter(0),
538 mbModulate(false),
539 mbFilter(false),
540 mbSimpleTextureActive(false)
542 // a derivation has to set maRasterRange which is used in the basic render methods.
543 // Setting to default here ([0.0 .. 1.0] in X,Y) to avoid problems
544 maRasterRange.expand(basegfx::B2DTuple(0.0, 0.0));
545 maRasterRange.expand(basegfx::B2DTuple(1.0, 1.0));
548 DefaultProcessor3D::~DefaultProcessor3D()
551 } // end of namespace processor3d
552 } // end of namespace drawinglayer
554 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */