Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / drawinglayer / source / processor3d / defaultprocessor3d.cxx
blobab07e055d8949a9cfc6a245d894256fd75a7e1b1
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>
37 #include <vcl/graph.hxx>
38 #include <basegfx/matrix/b2dhommatrixtools.hxx>
41 using namespace com::sun::star;
44 namespace drawinglayer
46 namespace processor3d
48 void DefaultProcessor3D::impRenderGradientTexturePrimitive3D(const primitive3d::GradientTexturePrimitive3D& rPrimitive, bool bTransparence)
50 const primitive3d::Primitive3DContainer& rSubSequence = rPrimitive.getChildren();
52 if(!rSubSequence.empty())
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 std::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 std::shared_ptr< texture::GeoTexSvx > pNewTex;
70 if(nMaxSteps)
72 // there IS a color distance
73 if(nSteps == 0)
75 nSteps = nMaxSteps;
78 if(nSteps < 2)
80 nSteps = 2;
83 if(nSteps > nMaxSteps)
85 nSteps = nMaxSteps;
88 switch(aGradientStyle)
90 case attribute::GradientStyle::Linear:
92 pNewTex.reset(
93 new texture::GeoTexSvxGradientLinear(
94 aOutlineRange,
95 aOutlineRange,
96 aStart,
97 aEnd,
98 nSteps,
99 rFillGradient.getBorder(),
100 rFillGradient.getAngle()));
101 break;
103 case attribute::GradientStyle::Axial:
105 pNewTex.reset(
106 new texture::GeoTexSvxGradientAxial(
107 aOutlineRange,
108 aOutlineRange,
109 aStart,
110 aEnd,
111 nSteps,
112 rFillGradient.getBorder(),
113 rFillGradient.getAngle()));
114 break;
116 case attribute::GradientStyle::Radial:
118 pNewTex.reset(
119 new texture::GeoTexSvxGradientRadial(
120 aOutlineRange,
121 aStart,
122 aEnd,
123 nSteps,
124 rFillGradient.getBorder(),
125 rFillGradient.getOffsetX(),
126 rFillGradient.getOffsetY()));
127 break;
129 case attribute::GradientStyle::Elliptical:
131 pNewTex.reset(
132 new texture::GeoTexSvxGradientElliptical(
133 aOutlineRange,
134 aStart,
135 aEnd,
136 nSteps,
137 rFillGradient.getBorder(),
138 rFillGradient.getOffsetX(),
139 rFillGradient.getOffsetY(),
140 rFillGradient.getAngle()));
141 break;
143 case attribute::GradientStyle::Square:
145 pNewTex.reset(
146 new texture::GeoTexSvxGradientSquare(
147 aOutlineRange,
148 aStart,
149 aEnd,
150 nSteps,
151 rFillGradient.getBorder(),
152 rFillGradient.getOffsetX(),
153 rFillGradient.getOffsetY(),
154 rFillGradient.getAngle()));
155 break;
157 case attribute::GradientStyle::Rect:
159 pNewTex.reset(
160 new texture::GeoTexSvxGradientRect(
161 aOutlineRange,
162 aStart,
163 aEnd,
164 nSteps,
165 rFillGradient.getBorder(),
166 rFillGradient.getOffsetX(),
167 rFillGradient.getOffsetY(),
168 rFillGradient.getAngle()));
169 break;
173 mbSimpleTextureActive = false;
175 else
177 // no color distance -> same color, use simple texture
178 pNewTex.reset(new texture::GeoTexSvxMono(aStart, 1.0 - aStart.luminance()));
179 mbSimpleTextureActive = true;
182 // set created texture
183 if(bTransparence)
185 mpTransparenceGeoTexSvx = pNewTex;
187 else
189 mpGeoTexSvx = pNewTex;
192 // process sub-list
193 process(rSubSequence);
195 // restore values
196 mbModulate = bOldModulate;
197 mbFilter = bOldFilter;
198 mbSimpleTextureActive = bOldSimpleTextureActive;
200 if(bTransparence)
202 mpTransparenceGeoTexSvx = pOldTex;
204 else
206 mpGeoTexSvx = pOldTex;
211 void DefaultProcessor3D::impRenderHatchTexturePrimitive3D(const primitive3d::HatchTexturePrimitive3D& rPrimitive)
213 const primitive3d::Primitive3DContainer& rSubSequence = rPrimitive.getChildren();
215 if(!rSubSequence.empty())
217 // rescue values
218 const bool bOldModulate(getModulate()); mbModulate = rPrimitive.getModulate();
219 const bool bOldFilter(getFilter()); mbFilter = rPrimitive.getFilter();
220 std::shared_ptr< texture::GeoTexSvx > pOldTex = mpGeoTexSvx;
222 // calculate logic pixel size in object coordinates. Create transformation view
223 // to object by inverting ObjectToView
224 basegfx::B3DHomMatrix aInvObjectToView(getViewInformation3D().getObjectToView());
225 aInvObjectToView.invert();
227 // back-project discrete coordinates to object coordinates and extract
228 // maximum distance
229 const basegfx::B3DPoint aZero(aInvObjectToView * basegfx::B3DPoint(0.0, 0.0, 0.0));
230 const basegfx::B3DPoint aOne(aInvObjectToView * basegfx::B3DPoint(1.0, 1.0, 1.0));
231 const basegfx::B3DVector aLogicPixel(aOne - aZero);
232 double fLogicPixelSizeWorld(std::max(std::max(fabs(aLogicPixel.getX()), fabs(aLogicPixel.getY())), fabs(aLogicPixel.getZ())));
234 // calculate logic pixel size in texture coordinates
235 const double fLogicTexSizeX(fLogicPixelSizeWorld / rPrimitive.getTextureSize().getX());
236 const double fLogicTexSizeY(fLogicPixelSizeWorld / rPrimitive.getTextureSize().getY());
237 const double fLogicTexSize(std::max(fLogicTexSizeX, fLogicTexSizeY));
239 // create texture and set
240 mpGeoTexSvx.reset(new texture::GeoTexSvxMultiHatch(rPrimitive, fLogicTexSize));
242 // process sub-list
243 process(rSubSequence);
245 // restore values
246 mbModulate = bOldModulate;
247 mbFilter = bOldFilter;
248 mpGeoTexSvx = pOldTex;
252 void DefaultProcessor3D::impRenderBitmapTexturePrimitive3D(const primitive3d::BitmapTexturePrimitive3D& rPrimitive)
254 const primitive3d::Primitive3DContainer& rSubSequence = rPrimitive.getChildren();
256 if(!rSubSequence.empty())
258 // rescue values
259 const bool bOldModulate(getModulate()); mbModulate = rPrimitive.getModulate();
260 const bool bOldFilter(getFilter()); mbFilter = rPrimitive.getFilter();
261 std::shared_ptr< texture::GeoTexSvx > pOldTex = mpGeoTexSvx;
263 // create texture
264 const attribute::FillGraphicAttribute& rFillGraphicAttribute = rPrimitive.getFillGraphicAttribute();
266 // #121194# For 3D texture we will use the BitmapRex representation
267 const BitmapEx aBitmapEx(rFillGraphicAttribute.getGraphic().GetBitmapEx());
269 // create range scaled by texture size
270 basegfx::B2DRange aGraphicRange(rFillGraphicAttribute.getGraphicRange());
272 aGraphicRange.transform(
273 basegfx::utils::createScaleB2DHomMatrix(
274 rPrimitive.getTextureSize()));
276 if(rFillGraphicAttribute.getTiling())
278 mpGeoTexSvx.reset(
279 new texture::GeoTexSvxBitmapExTiled(
280 aBitmapEx,
281 aGraphicRange,
282 rFillGraphicAttribute.getOffsetX(),
283 rFillGraphicAttribute.getOffsetY()));
285 else
287 mpGeoTexSvx.reset(
288 new texture::GeoTexSvxBitmapEx(
289 aBitmapEx,
290 aGraphicRange));
293 // process sub-list
294 process(rSubSequence);
296 // restore values
297 mbModulate = bOldModulate;
298 mbFilter = bOldFilter;
299 mpGeoTexSvx = pOldTex;
303 void DefaultProcessor3D::impRenderModifiedColorPrimitive3D(const primitive3d::ModifiedColorPrimitive3D& rModifiedCandidate)
305 const primitive3d::Primitive3DContainer& rSubSequence = rModifiedCandidate.getChildren();
307 if(!rSubSequence.empty())
309 // put modifier on stack
310 maBColorModifierStack.push(rModifiedCandidate.getColorModifier());
312 // process sub-list
313 process(rModifiedCandidate.getChildren());
315 // remove modifier from stack
316 maBColorModifierStack.pop();
320 void DefaultProcessor3D::impRenderPolygonHairlinePrimitive3D(const primitive3d::PolygonHairlinePrimitive3D& rPrimitive) const
322 basegfx::B3DPolygon aHairline(rPrimitive.getB3DPolygon());
324 if(aHairline.count())
326 // hairlines need no extra data, clear it
327 aHairline.clearTextureCoordinates();
328 aHairline.clearNormals();
329 aHairline.clearBColors();
331 // transform to device coordinates (-1.0 .. 1.0) and check for visibility
332 aHairline.transform(getViewInformation3D().getObjectToView());
333 const basegfx::B3DRange a3DRange(basegfx::utils::getRange(aHairline));
334 const basegfx::B2DRange a2DRange(a3DRange.getMinX(), a3DRange.getMinY(), a3DRange.getMaxX(), a3DRange.getMaxY());
336 if(a2DRange.overlaps(maRasterRange))
338 const attribute::MaterialAttribute3D aMaterial(maBColorModifierStack.getModifiedColor(rPrimitive.getBColor()));
340 rasterconvertB3DPolygon(aMaterial, aHairline);
345 void DefaultProcessor3D::impRenderPolyPolygonMaterialPrimitive3D(const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive) const
347 basegfx::B3DPolyPolygon aFill(rPrimitive.getB3DPolyPolygon());
348 basegfx::BColor aObjectColor(rPrimitive.getMaterial().getColor());
349 bool bPaintIt(aFill.count());
351 // #i98295# get ShadeMode. Correct early when only flat is possible due to missing normals
352 const css::drawing::ShadeMode aShadeMode(
353 aFill.areNormalsUsed() ?
354 getSdrSceneAttribute().getShadeMode() : css::drawing::ShadeMode_FLAT);
356 if(bPaintIt)
358 // get rid of texture coordinates if there is no texture
359 if(aFill.areTextureCoordinatesUsed() && !getGeoTexSvx().get() && !getTransparenceGeoTexSvx().get())
361 aFill.clearTextureCoordinates();
364 // #i98295# get rid of normals and color early when not needed
365 if(css::drawing::ShadeMode_FLAT == aShadeMode)
367 aFill.clearNormals();
368 aFill.clearBColors();
371 // transform to device coordinates (-1.0 .. 1.0) and check for visibility
372 aFill.transform(getViewInformation3D().getObjectToView());
373 const basegfx::B3DRange a3DRange(basegfx::utils::getRange(aFill));
374 const basegfx::B2DRange a2DRange(a3DRange.getMinX(), a3DRange.getMinY(), a3DRange.getMaxX(), a3DRange.getMaxY());
376 bPaintIt = a2DRange.overlaps(maRasterRange);
379 // check if it shall be painted regarding hiding of normals (backface culling)
380 if(bPaintIt && !rPrimitive.getDoubleSided())
382 // get plane normal of polygon in view coordinates (with ZBuffer values),
383 // left-handed coordinate system
384 const basegfx::B3DVector aPlaneNormal(aFill.getB3DPolygon(0).getNormal());
386 if(aPlaneNormal.getZ() > 0.0)
388 bPaintIt = false;
392 if(bPaintIt)
394 // prepare ObjectToEye in NormalTransform
395 basegfx::B3DHomMatrix aNormalTransform(getViewInformation3D().getOrientation() * getViewInformation3D().getObjectTransformation());
397 if(getSdrSceneAttribute().getTwoSidedLighting())
399 // get plane normal of polygon in view coordinates (with ZBuffer values),
400 // left-handed coordinate system
401 const basegfx::B3DVector aPlaneNormal(aFill.getB3DPolygon(0).getNormal());
403 if(aPlaneNormal.getZ() > 0.0)
405 // mirror normals
406 aNormalTransform.scale(-1.0, -1.0, -1.0);
410 switch(aShadeMode)
412 case css::drawing::ShadeMode_PHONG:
414 // phong shading. Transform normals to eye coor
415 aFill.transformNormals(aNormalTransform);
416 break;
418 case css::drawing::ShadeMode_SMOOTH:
420 // gouraud shading. Transform normals to eye coor
421 aFill.transformNormals(aNormalTransform);
423 // prepare color model parameters, evtl. use blend color
424 const basegfx::BColor aColor(getModulate() ? basegfx::BColor(1.0, 1.0, 1.0) : rPrimitive.getMaterial().getColor());
425 const basegfx::BColor& rSpecular(rPrimitive.getMaterial().getSpecular());
426 const basegfx::BColor& rEmission(rPrimitive.getMaterial().getEmission());
427 const sal_uInt16 nSpecularIntensity(rPrimitive.getMaterial().getSpecularIntensity());
429 // solve color model for each normal vector, set colors at points. Clear normals.
430 for(sal_uInt32 a(0); a < aFill.count(); a++)
432 basegfx::B3DPolygon aPartFill(aFill.getB3DPolygon(a));
434 for(sal_uInt32 b(0); b < aPartFill.count(); b++)
436 // solve color model. Transform normal to eye coor
437 const basegfx::B3DVector aNormal(aPartFill.getNormal(b));
438 const basegfx::BColor aSolvedColor(getSdrLightingAttribute().solveColorModel(aNormal, aColor, rSpecular, rEmission, nSpecularIntensity));
439 aPartFill.setBColor(b, aSolvedColor);
442 // clear normals on this part polygon and write it back
443 aPartFill.clearNormals();
444 aFill.setB3DPolygon(a, aPartFill);
446 break;
448 case css::drawing::ShadeMode_FLAT:
450 // flat shading. Get plane vector in eye coordinates
451 const basegfx::B3DVector aPlaneEyeNormal(aNormalTransform * rPrimitive.getB3DPolyPolygon().getB3DPolygon(0).getNormal());
453 // prepare color model parameters, evtl. use blend color
454 const basegfx::BColor aColor(getModulate() ? basegfx::BColor(1.0, 1.0, 1.0) : rPrimitive.getMaterial().getColor());
455 const basegfx::BColor& rSpecular(rPrimitive.getMaterial().getSpecular());
456 const basegfx::BColor& rEmission(rPrimitive.getMaterial().getEmission());
457 const sal_uInt16 nSpecularIntensity(rPrimitive.getMaterial().getSpecularIntensity());
459 // solve color model for plane vector and use that color for whole plane
460 aObjectColor = getSdrLightingAttribute().solveColorModel(aPlaneEyeNormal, aColor, rSpecular, rEmission, nSpecularIntensity);
461 break;
463 default: // case css::drawing::ShadeMode_DRAFT:
465 // draft, just use object color which is already set. Delete all other infos
466 aFill.clearNormals();
467 aFill.clearBColors();
468 break;
472 // draw it to ZBuffer
473 const attribute::MaterialAttribute3D aMaterial(
474 maBColorModifierStack.getModifiedColor(aObjectColor),
475 rPrimitive.getMaterial().getSpecular(),
476 rPrimitive.getMaterial().getEmission(),
477 rPrimitive.getMaterial().getSpecularIntensity());
479 rasterconvertB3DPolyPolygon(aMaterial, aFill);
483 void DefaultProcessor3D::impRenderTransformPrimitive3D(const primitive3d::TransformPrimitive3D& rTransformCandidate)
485 // transform group. Remember current transformations
486 const geometry::ViewInformation3D aLastViewInformation3D(getViewInformation3D());
488 // create new transformation; add new object transform from right side
489 const geometry::ViewInformation3D aNewViewInformation3D(
490 aLastViewInformation3D.getObjectTransformation() * rTransformCandidate.getTransformation(),
491 aLastViewInformation3D.getOrientation(),
492 aLastViewInformation3D.getProjection(),
493 aLastViewInformation3D.getDeviceToView(),
494 aLastViewInformation3D.getViewTime(),
495 aLastViewInformation3D.getExtendedInformationSequence());
496 updateViewInformation(aNewViewInformation3D);
498 // let break down recursively
499 process(rTransformCandidate.getChildren());
501 // restore transformations
502 updateViewInformation(aLastViewInformation3D);
505 void DefaultProcessor3D::processBasePrimitive3D(const primitive3d::BasePrimitive3D& rBasePrimitive)
507 // it is a BasePrimitive3D implementation, use getPrimitive3DID() call for switch
508 switch(rBasePrimitive.getPrimitive3DID())
510 case PRIMITIVE3D_ID_GRADIENTTEXTUREPRIMITIVE3D :
512 // GradientTexturePrimitive3D
513 const primitive3d::GradientTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::GradientTexturePrimitive3D& >(rBasePrimitive);
514 impRenderGradientTexturePrimitive3D(rPrimitive, false);
515 break;
517 case PRIMITIVE3D_ID_HATCHTEXTUREPRIMITIVE3D :
519 // hatchTexturePrimitive3D
520 const primitive3d::HatchTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::HatchTexturePrimitive3D& >(rBasePrimitive);
521 impRenderHatchTexturePrimitive3D(rPrimitive);
522 break;
524 case PRIMITIVE3D_ID_BITMAPTEXTUREPRIMITIVE3D :
526 // BitmapTexturePrimitive3D
527 const primitive3d::BitmapTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::BitmapTexturePrimitive3D& >(rBasePrimitive);
528 impRenderBitmapTexturePrimitive3D(rPrimitive);
529 break;
531 case PRIMITIVE3D_ID_TRANSPARENCETEXTUREPRIMITIVE3D :
533 // TransparenceTexturePrimitive3D
534 const primitive3d::TransparenceTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::TransparenceTexturePrimitive3D& >(rBasePrimitive);
535 mnTransparenceCounter++;
536 impRenderGradientTexturePrimitive3D(rPrimitive, true);
537 mnTransparenceCounter--;
538 break;
540 case PRIMITIVE3D_ID_MODIFIEDCOLORPRIMITIVE3D :
542 // ModifiedColorPrimitive3D
543 // Force output to unified color.
544 const primitive3d::ModifiedColorPrimitive3D& rPrimitive = static_cast< const primitive3d::ModifiedColorPrimitive3D& >(rBasePrimitive);
545 impRenderModifiedColorPrimitive3D(rPrimitive);
546 break;
548 case PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D :
550 // directdraw of PolygonHairlinePrimitive3D
551 const primitive3d::PolygonHairlinePrimitive3D& rPrimitive = static_cast< const primitive3d::PolygonHairlinePrimitive3D& >(rBasePrimitive);
552 impRenderPolygonHairlinePrimitive3D(rPrimitive);
553 break;
555 case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D :
557 // directdraw of PolyPolygonMaterialPrimitive3D
558 const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive = static_cast< const primitive3d::PolyPolygonMaterialPrimitive3D& >(rBasePrimitive);
559 impRenderPolyPolygonMaterialPrimitive3D(rPrimitive);
560 break;
562 case PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D :
564 // transform group (TransformPrimitive3D)
565 impRenderTransformPrimitive3D(static_cast< const primitive3d::TransformPrimitive3D& >(rBasePrimitive));
566 break;
568 default:
570 // process recursively
571 process(rBasePrimitive.get3DDecomposition(getViewInformation3D()));
572 break;
577 DefaultProcessor3D::DefaultProcessor3D(
578 const geometry::ViewInformation3D& rViewInformation,
579 const attribute::SdrSceneAttribute& rSdrSceneAttribute,
580 const attribute::SdrLightingAttribute& rSdrLightingAttribute)
581 : BaseProcessor3D(rViewInformation),
582 mrSdrSceneAttribute(rSdrSceneAttribute),
583 mrSdrLightingAttribute(rSdrLightingAttribute),
584 maRasterRange(),
585 maBColorModifierStack(),
586 mpGeoTexSvx(),
587 mpTransparenceGeoTexSvx(),
588 maDrawinglayerOpt(),
589 mnTransparenceCounter(0),
590 mbModulate(false),
591 mbFilter(false),
592 mbSimpleTextureActive(false)
594 // a derivation has to set maRasterRange which is used in the basic render methods.
595 // Setting to default here ([0.0 .. 1.0] in X,Y) to avoid problems
596 maRasterRange.expand(basegfx::B2DTuple(0.0, 0.0));
597 maRasterRange.expand(basegfx::B2DTuple(1.0, 1.0));
600 DefaultProcessor3D::~DefaultProcessor3D()
603 } // end of namespace processor3d
604 } // end of namespace drawinglayer
606 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */