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>
38 //////////////////////////////////////////////////////////////////////////////
40 using namespace com::sun::star
;
42 //////////////////////////////////////////////////////////////////////////////
44 namespace drawinglayer
48 void DefaultProcessor3D::impRenderGradientTexturePrimitive3D(const primitive3d::GradientTexturePrimitive3D
& rPrimitive
, bool bTransparence
)
50 const primitive3d::Primitive3DSequence
& rSubSequence
= rPrimitive
.getChildren();
52 if(rSubSequence
.hasElements())
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
;
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
;
72 // there IS a color distance
83 if(nSteps
> nMaxSteps
)
88 switch(aGradientStyle
)
90 case attribute::GRADIENTSTYLE_LINEAR
:
92 pNewTex
.reset(new texture::GeoTexSvxGradientLinear(aOutlineRange
, aStart
, aEnd
, nSteps
, rFillGradient
.getBorder(), rFillGradient
.getAngle()));
95 case attribute::GRADIENTSTYLE_AXIAL
:
97 pNewTex
.reset(new texture::GeoTexSvxGradientAxial(aOutlineRange
, aStart
, aEnd
, nSteps
, rFillGradient
.getBorder(), rFillGradient
.getAngle()));
100 case attribute::GRADIENTSTYLE_RADIAL
:
102 pNewTex
.reset(new texture::GeoTexSvxGradientRadial(aOutlineRange
, aStart
, aEnd
, nSteps
, rFillGradient
.getBorder(), rFillGradient
.getOffsetX(), rFillGradient
.getOffsetY()));
105 case attribute::GRADIENTSTYLE_ELLIPTICAL
:
107 pNewTex
.reset(new texture::GeoTexSvxGradientElliptical(aOutlineRange
, aStart
, aEnd
, nSteps
, rFillGradient
.getBorder(), rFillGradient
.getOffsetX(), rFillGradient
.getOffsetY(), rFillGradient
.getAngle()));
110 case attribute::GRADIENTSTYLE_SQUARE
:
112 pNewTex
.reset(new texture::GeoTexSvxGradientSquare(aOutlineRange
, aStart
, aEnd
, nSteps
, rFillGradient
.getBorder(), rFillGradient
.getOffsetX(), rFillGradient
.getOffsetY(), rFillGradient
.getAngle()));
115 case attribute::GRADIENTSTYLE_RECT
:
117 pNewTex
.reset(new texture::GeoTexSvxGradientRect(aOutlineRange
, aStart
, aEnd
, nSteps
, rFillGradient
.getBorder(), rFillGradient
.getOffsetX(), rFillGradient
.getOffsetY(), rFillGradient
.getAngle()));
122 mbSimpleTextureActive
= false;
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
134 mpTransparenceGeoTexSvx
= pNewTex
;
138 mpGeoTexSvx
= pNewTex
;
142 process(rSubSequence
);
145 mbModulate
= bOldModulate
;
146 mbFilter
= bOldFilter
;
147 mbSimpleTextureActive
= bOldSimpleTextureActive
;
151 mpTransparenceGeoTexSvx
= pOldTex
;
155 mpGeoTexSvx
= pOldTex
;
160 void DefaultProcessor3D::impRenderHatchTexturePrimitive3D(const primitive3d::HatchTexturePrimitive3D
& rPrimitive
)
162 const primitive3d::Primitive3DSequence
& rSubSequence
= rPrimitive
.getChildren();
164 if(rSubSequence
.hasElements())
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
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
));
192 process(rSubSequence
);
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())
208 const bool bOldModulate(getModulate()); mbModulate
= rPrimitive
.getModulate();
209 const bool bOldFilter(getFilter()); mbFilter
= rPrimitive
.getFilter();
210 boost::shared_ptr
< texture::GeoTexSvx
> pOldTex
= mpGeoTexSvx
;
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()));
224 mpGeoTexSvx
.reset(new texture::GeoTexSvxBitmap(
225 rFillBitmapAttribute
.getBitmapEx().GetBitmap(),
226 rFillBitmapAttribute
.getTopLeft() * rPrimitive
.getTextureSize(),
227 rFillBitmapAttribute
.getSize() * rPrimitive
.getTextureSize()));
231 process(rSubSequence
);
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());
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
);
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)
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)
343 aNormalTransform
.scale(-1.0, -1.0, -1.0);
349 case ::com::sun::star::drawing::ShadeMode_PHONG
:
351 // phong shading. Transform normals to eye coor
352 aFill
.transformNormals(aNormalTransform
);
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
);
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
);
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();
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);
454 case PRIMITIVE3D_ID_HATCHTEXTUREPRIMITIVE3D
:
456 // HatchTexturePrimitive3D
457 static bool bDoHatchDecomposition(false);
459 if(bDoHatchDecomposition
)
462 process(rBasePrimitive
.get3DDecomposition(getViewInformation3D()));
466 // hatchTexturePrimitive3D
467 const primitive3d::HatchTexturePrimitive3D
& rPrimitive
= static_cast< const primitive3d::HatchTexturePrimitive3D
& >(rBasePrimitive
);
468 impRenderHatchTexturePrimitive3D(rPrimitive
);
472 case PRIMITIVE3D_ID_BITMAPTEXTUREPRIMITIVE3D
:
474 // BitmapTexturePrimitive3D
475 const primitive3d::BitmapTexturePrimitive3D
& rPrimitive
= static_cast< const primitive3d::BitmapTexturePrimitive3D
& >(rBasePrimitive
);
476 impRenderBitmapTexturePrimitive3D(rPrimitive
);
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
--;
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
);
496 case PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D
:
498 // directdraw of PolygonHairlinePrimitive3D
499 const primitive3d::PolygonHairlinePrimitive3D
& rPrimitive
= static_cast< const primitive3d::PolygonHairlinePrimitive3D
& >(rBasePrimitive
);
500 impRenderPolygonHairlinePrimitive3D(rPrimitive
);
503 case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D
:
505 // directdraw of PolyPolygonMaterialPrimitive3D
506 const primitive3d::PolyPolygonMaterialPrimitive3D
& rPrimitive
= static_cast< const primitive3d::PolyPolygonMaterialPrimitive3D
& >(rBasePrimitive
);
507 impRenderPolyPolygonMaterialPrimitive3D(rPrimitive
);
510 case PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D
:
512 // transform group (TransformPrimitive3D)
513 impRenderTransformPrimitive3D(static_cast< const primitive3d::TransformPrimitive3D
& >(rBasePrimitive
));
518 // process recursively
519 process(rBasePrimitive
.get3DDecomposition(getViewInformation3D()));
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
),
533 maBColorModifierStack(),
535 mpTransparenceGeoTexSvx(),
537 mnTransparenceCounter(0),
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: */