1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <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
48 void DefaultProcessor3D::impRenderGradientTexturePrimitive3D(const primitive3d::GradientTexturePrimitive3D
& rPrimitive
, bool bTransparence
)
50 const primitive3d::Primitive3DContainer
& rSubSequence
= rPrimitive
.getChildren();
52 if(!rSubSequence
.empty())
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
;
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
;
72 // there IS a color distance
83 if(nSteps
> nMaxSteps
)
88 switch(aGradientStyle
)
90 case attribute::GradientStyle::Linear
:
93 new texture::GeoTexSvxGradientLinear(
99 rFillGradient
.getBorder(),
100 rFillGradient
.getAngle()));
103 case attribute::GradientStyle::Axial
:
106 new texture::GeoTexSvxGradientAxial(
112 rFillGradient
.getBorder(),
113 rFillGradient
.getAngle()));
116 case attribute::GradientStyle::Radial
:
119 new texture::GeoTexSvxGradientRadial(
124 rFillGradient
.getBorder(),
125 rFillGradient
.getOffsetX(),
126 rFillGradient
.getOffsetY()));
129 case attribute::GradientStyle::Elliptical
:
132 new texture::GeoTexSvxGradientElliptical(
137 rFillGradient
.getBorder(),
138 rFillGradient
.getOffsetX(),
139 rFillGradient
.getOffsetY(),
140 rFillGradient
.getAngle()));
143 case attribute::GradientStyle::Square
:
146 new texture::GeoTexSvxGradientSquare(
151 rFillGradient
.getBorder(),
152 rFillGradient
.getOffsetX(),
153 rFillGradient
.getOffsetY(),
154 rFillGradient
.getAngle()));
157 case attribute::GradientStyle::Rect
:
160 new texture::GeoTexSvxGradientRect(
165 rFillGradient
.getBorder(),
166 rFillGradient
.getOffsetX(),
167 rFillGradient
.getOffsetY(),
168 rFillGradient
.getAngle()));
173 mbSimpleTextureActive
= false;
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
185 mpTransparenceGeoTexSvx
= pNewTex
;
189 mpGeoTexSvx
= pNewTex
;
193 process(rSubSequence
);
196 mbModulate
= bOldModulate
;
197 mbFilter
= bOldFilter
;
198 mbSimpleTextureActive
= bOldSimpleTextureActive
;
202 mpTransparenceGeoTexSvx
= pOldTex
;
206 mpGeoTexSvx
= pOldTex
;
211 void DefaultProcessor3D::impRenderHatchTexturePrimitive3D(const primitive3d::HatchTexturePrimitive3D
& rPrimitive
)
213 const primitive3d::Primitive3DContainer
& rSubSequence
= rPrimitive
.getChildren();
215 if(!rSubSequence
.empty())
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
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
));
243 process(rSubSequence
);
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())
259 const bool bOldModulate(getModulate()); mbModulate
= rPrimitive
.getModulate();
260 const bool bOldFilter(getFilter()); mbFilter
= rPrimitive
.getFilter();
261 std::shared_ptr
< texture::GeoTexSvx
> pOldTex
= mpGeoTexSvx
;
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())
279 new texture::GeoTexSvxBitmapExTiled(
282 rFillGraphicAttribute
.getOffsetX(),
283 rFillGraphicAttribute
.getOffsetY()));
288 new texture::GeoTexSvxBitmapEx(
294 process(rSubSequence
);
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());
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
);
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)
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)
406 aNormalTransform
.scale(-1.0, -1.0, -1.0);
412 case css::drawing::ShadeMode_PHONG
:
414 // phong shading. Transform normals to eye coor
415 aFill
.transformNormals(aNormalTransform
);
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
);
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
);
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();
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);
517 case PRIMITIVE3D_ID_HATCHTEXTUREPRIMITIVE3D
:
519 // hatchTexturePrimitive3D
520 const primitive3d::HatchTexturePrimitive3D
& rPrimitive
= static_cast< const primitive3d::HatchTexturePrimitive3D
& >(rBasePrimitive
);
521 impRenderHatchTexturePrimitive3D(rPrimitive
);
524 case PRIMITIVE3D_ID_BITMAPTEXTUREPRIMITIVE3D
:
526 // BitmapTexturePrimitive3D
527 const primitive3d::BitmapTexturePrimitive3D
& rPrimitive
= static_cast< const primitive3d::BitmapTexturePrimitive3D
& >(rBasePrimitive
);
528 impRenderBitmapTexturePrimitive3D(rPrimitive
);
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
--;
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
);
548 case PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D
:
550 // directdraw of PolygonHairlinePrimitive3D
551 const primitive3d::PolygonHairlinePrimitive3D
& rPrimitive
= static_cast< const primitive3d::PolygonHairlinePrimitive3D
& >(rBasePrimitive
);
552 impRenderPolygonHairlinePrimitive3D(rPrimitive
);
555 case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D
:
557 // directdraw of PolyPolygonMaterialPrimitive3D
558 const primitive3d::PolyPolygonMaterialPrimitive3D
& rPrimitive
= static_cast< const primitive3d::PolyPolygonMaterialPrimitive3D
& >(rBasePrimitive
);
559 impRenderPolyPolygonMaterialPrimitive3D(rPrimitive
);
562 case PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D
:
564 // transform group (TransformPrimitive3D)
565 impRenderTransformPrimitive3D(static_cast< const primitive3d::TransformPrimitive3D
& >(rBasePrimitive
));
570 // process recursively
571 process(rBasePrimitive
.get3DDecomposition(getViewInformation3D()));
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
),
585 maBColorModifierStack(),
587 mpTransparenceGeoTexSvx(),
589 mnTransparenceCounter(0),
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: */