diff options
Diffstat (limited to 'drawinglayer/source/processor3d/defaultprocessor3d.cxx')
-rw-r--r-- | drawinglayer/source/processor3d/defaultprocessor3d.cxx | 598 |
1 files changed, 598 insertions, 0 deletions
diff --git a/drawinglayer/source/processor3d/defaultprocessor3d.cxx b/drawinglayer/source/processor3d/defaultprocessor3d.cxx new file mode 100644 index 000000000..b9159c46c --- /dev/null +++ b/drawinglayer/source/processor3d/defaultprocessor3d.cxx @@ -0,0 +1,598 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <processor3d/defaultprocessor3d.hxx> +#include <primitive3d/textureprimitive3d.hxx> +#include <texture/texture.hxx> +#include <texture/texture3d.hxx> +#include <primitive3d/hatchtextureprimitive3d.hxx> +#include <drawinglayer/primitive3d/modifiedcolorprimitive3d.hxx> +#include <drawinglayer/primitive3d/polygonprimitive3d.hxx> +#include <basegfx/polygon/b3dpolygontools.hxx> +#include <drawinglayer/attribute/materialattribute3d.hxx> +#include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> +#include <basegfx/polygon/b3dpolypolygontools.hxx> +#include <com/sun/star/drawing/ShadeMode.hpp> +#include <drawinglayer/primitive3d/transformprimitive3d.hxx> +#include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> +#include <vcl/bitmapex.hxx> +#include <drawinglayer/attribute/sdrsceneattribute3d.hxx> +#include <drawinglayer/attribute/sdrlightingattribute3d.hxx> +#include <vcl/graph.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> + + +using namespace com::sun::star; + + +namespace drawinglayer::processor3d +{ + void DefaultProcessor3D::impRenderGradientTexturePrimitive3D(const primitive3d::GradientTexturePrimitive3D& rPrimitive, bool bTransparence) + { + const primitive3d::Primitive3DContainer& rSubSequence = rPrimitive.getChildren(); + + if(rSubSequence.empty()) + return; + + // rescue values + const bool bOldModulate(getModulate()); mbModulate = rPrimitive.getModulate(); + const bool bOldFilter(getFilter()); mbFilter = rPrimitive.getFilter(); + const bool bOldSimpleTextureActive(getSimpleTextureActive()); + std::shared_ptr< texture::GeoTexSvx > pOldTex = bTransparence ? mpTransparenceGeoTexSvx : mpGeoTexSvx; + + // create texture + const attribute::FillGradientAttribute& rFillGradient = rPrimitive.getGradient(); + const basegfx::B2DRange aOutlineRange(0.0, 0.0, rPrimitive.getTextureSize().getX(), rPrimitive.getTextureSize().getY()); + const attribute::GradientStyle aGradientStyle(rFillGradient.getStyle()); + sal_uInt32 nSteps(rFillGradient.getSteps()); + const basegfx::BColor& aStart(rFillGradient.getStartColor()); + const basegfx::BColor& aEnd(rFillGradient.getEndColor()); + const sal_uInt32 nMaxSteps(sal_uInt32((aStart.getMaximumDistance(aEnd) * 127.5) + 0.5)); + std::shared_ptr< texture::GeoTexSvx > pNewTex; + + if(nMaxSteps) + { + // there IS a color distance + if(nSteps == 0) + { + nSteps = nMaxSteps; + } + + if(nSteps < 2) + { + nSteps = 2; + } + + if(nSteps > nMaxSteps) + { + nSteps = nMaxSteps; + } + + switch(aGradientStyle) + { + case attribute::GradientStyle::Linear: + { + pNewTex = std::make_shared<texture::GeoTexSvxGradientLinear>( + aOutlineRange, + aOutlineRange, + aStart, + aEnd, + nSteps, + rFillGradient.getBorder(), + rFillGradient.getAngle()); + break; + } + case attribute::GradientStyle::Axial: + { + pNewTex = std::make_shared<texture::GeoTexSvxGradientAxial>( + aOutlineRange, + aOutlineRange, + aStart, + aEnd, + nSteps, + rFillGradient.getBorder(), + rFillGradient.getAngle()); + break; + } + case attribute::GradientStyle::Radial: + { + pNewTex = + std::make_shared<texture::GeoTexSvxGradientRadial>( + aOutlineRange, + aStart, + aEnd, + nSteps, + rFillGradient.getBorder(), + rFillGradient.getOffsetX(), + rFillGradient.getOffsetY()); + break; + } + case attribute::GradientStyle::Elliptical: + { + pNewTex = + std::make_shared<texture::GeoTexSvxGradientElliptical>( + aOutlineRange, + aStart, + aEnd, + nSteps, + rFillGradient.getBorder(), + rFillGradient.getOffsetX(), + rFillGradient.getOffsetY(), + rFillGradient.getAngle()); + break; + } + case attribute::GradientStyle::Square: + { + pNewTex = + std::make_shared<texture::GeoTexSvxGradientSquare>( + aOutlineRange, + aStart, + aEnd, + nSteps, + rFillGradient.getBorder(), + rFillGradient.getOffsetX(), + rFillGradient.getOffsetY(), + rFillGradient.getAngle()); + break; + } + case attribute::GradientStyle::Rect: + { + pNewTex = + std::make_shared<texture::GeoTexSvxGradientRect>( + aOutlineRange, + aStart, + aEnd, + nSteps, + rFillGradient.getBorder(), + rFillGradient.getOffsetX(), + rFillGradient.getOffsetY(), + rFillGradient.getAngle()); + break; + } + } + + mbSimpleTextureActive = false; + } + else + { + // no color distance -> same color, use simple texture + pNewTex = std::make_shared<texture::GeoTexSvxMono>(aStart, 1.0 - aStart.luminance()); + mbSimpleTextureActive = true; + } + + // set created texture + if(bTransparence) + { + mpTransparenceGeoTexSvx = pNewTex; + } + else + { + mpGeoTexSvx = pNewTex; + } + + // process sub-list + process(rSubSequence); + + // restore values + mbModulate = bOldModulate; + mbFilter = bOldFilter; + mbSimpleTextureActive = bOldSimpleTextureActive; + + if(bTransparence) + { + mpTransparenceGeoTexSvx = pOldTex; + } + else + { + mpGeoTexSvx = pOldTex; + } + } + + void DefaultProcessor3D::impRenderHatchTexturePrimitive3D(const primitive3d::HatchTexturePrimitive3D& rPrimitive) + { + const primitive3d::Primitive3DContainer& rSubSequence = rPrimitive.getChildren(); + + if(rSubSequence.empty()) + return; + + // rescue values + const bool bOldModulate(getModulate()); mbModulate = rPrimitive.getModulate(); + const bool bOldFilter(getFilter()); mbFilter = rPrimitive.getFilter(); + std::shared_ptr< texture::GeoTexSvx > pOldTex = mpGeoTexSvx; + + // calculate logic pixel size in object coordinates. Create transformation view + // to object by inverting ObjectToView + basegfx::B3DHomMatrix aInvObjectToView(getViewInformation3D().getObjectToView()); + aInvObjectToView.invert(); + + // back-project discrete coordinates to object coordinates and extract + // maximum distance + const basegfx::B3DPoint aZero(aInvObjectToView * basegfx::B3DPoint(0.0, 0.0, 0.0)); + const basegfx::B3DPoint aOne(aInvObjectToView * basegfx::B3DPoint(1.0, 1.0, 1.0)); + const basegfx::B3DVector aLogicPixel(aOne - aZero); + double fLogicPixelSizeWorld(std::max(std::max(fabs(aLogicPixel.getX()), fabs(aLogicPixel.getY())), fabs(aLogicPixel.getZ()))); + + // calculate logic pixel size in texture coordinates + const double fLogicTexSizeX(fLogicPixelSizeWorld / rPrimitive.getTextureSize().getX()); + const double fLogicTexSizeY(fLogicPixelSizeWorld / rPrimitive.getTextureSize().getY()); + const double fLogicTexSize(std::max(fLogicTexSizeX, fLogicTexSizeY)); + + // create texture and set + mpGeoTexSvx = std::make_shared<texture::GeoTexSvxMultiHatch>(rPrimitive, fLogicTexSize); + + // process sub-list + process(rSubSequence); + + // restore values + mbModulate = bOldModulate; + mbFilter = bOldFilter; + mpGeoTexSvx = pOldTex; + } + + void DefaultProcessor3D::impRenderBitmapTexturePrimitive3D(const primitive3d::BitmapTexturePrimitive3D& rPrimitive) + { + const primitive3d::Primitive3DContainer& rSubSequence = rPrimitive.getChildren(); + + if(rSubSequence.empty()) + return; + + // rescue values + const bool bOldModulate(getModulate()); mbModulate = rPrimitive.getModulate(); + const bool bOldFilter(getFilter()); mbFilter = rPrimitive.getFilter(); + std::shared_ptr< texture::GeoTexSvx > pOldTex = mpGeoTexSvx; + + // create texture + const attribute::FillGraphicAttribute& rFillGraphicAttribute = rPrimitive.getFillGraphicAttribute(); + + // #121194# For 3D texture we will use the BitmapRex representation + const BitmapEx aBitmapEx(rFillGraphicAttribute.getGraphic().GetBitmapEx()); + + // create range scaled by texture size + basegfx::B2DRange aGraphicRange(rFillGraphicAttribute.getGraphicRange()); + + aGraphicRange.transform( + basegfx::utils::createScaleB2DHomMatrix( + rPrimitive.getTextureSize())); + + if(rFillGraphicAttribute.getTiling()) + { + mpGeoTexSvx = + std::make_shared<texture::GeoTexSvxBitmapExTiled>( + aBitmapEx, + aGraphicRange, + rFillGraphicAttribute.getOffsetX(), + rFillGraphicAttribute.getOffsetY()); + } + else + { + mpGeoTexSvx = + std::make_shared<texture::GeoTexSvxBitmapEx>( + aBitmapEx, + aGraphicRange); + } + + // process sub-list + process(rSubSequence); + + // restore values + mbModulate = bOldModulate; + mbFilter = bOldFilter; + mpGeoTexSvx = pOldTex; + } + + void DefaultProcessor3D::impRenderModifiedColorPrimitive3D(const primitive3d::ModifiedColorPrimitive3D& rModifiedCandidate) + { + const primitive3d::Primitive3DContainer& rSubSequence = rModifiedCandidate.getChildren(); + + if(!rSubSequence.empty()) + { + // put modifier on stack + maBColorModifierStack.push(rModifiedCandidate.getColorModifier()); + + // process sub-list + process(rModifiedCandidate.getChildren()); + + // remove modifier from stack + maBColorModifierStack.pop(); + } + } + + void DefaultProcessor3D::impRenderPolygonHairlinePrimitive3D(const primitive3d::PolygonHairlinePrimitive3D& rPrimitive) const + { + basegfx::B3DPolygon aHairline(rPrimitive.getB3DPolygon()); + + if(!aHairline.count()) + return; + + // hairlines need no extra data, clear it + aHairline.clearTextureCoordinates(); + aHairline.clearNormals(); + aHairline.clearBColors(); + + // transform to device coordinates (-1.0 .. 1.0) and check for visibility + aHairline.transform(getViewInformation3D().getObjectToView()); + const basegfx::B3DRange a3DRange(basegfx::utils::getRange(aHairline)); + const basegfx::B2DRange a2DRange(a3DRange.getMinX(), a3DRange.getMinY(), a3DRange.getMaxX(), a3DRange.getMaxY()); + + if(a2DRange.overlaps(maRasterRange)) + { + const attribute::MaterialAttribute3D aMaterial(maBColorModifierStack.getModifiedColor(rPrimitive.getBColor())); + + rasterconvertB3DPolygon(aMaterial, aHairline); + } + } + + void DefaultProcessor3D::impRenderPolyPolygonMaterialPrimitive3D(const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive) const + { + basegfx::B3DPolyPolygon aFill(rPrimitive.getB3DPolyPolygon()); + basegfx::BColor aObjectColor(rPrimitive.getMaterial().getColor()); + bool bPaintIt(aFill.count()); + + // #i98295# get ShadeMode. Correct early when only flat is possible due to missing normals + const css::drawing::ShadeMode aShadeMode( + aFill.areNormalsUsed() ? + getSdrSceneAttribute().getShadeMode() : css::drawing::ShadeMode_FLAT); + + if(bPaintIt) + { + // get rid of texture coordinates if there is no texture + if(aFill.areTextureCoordinatesUsed() && !getGeoTexSvx() && !getTransparenceGeoTexSvx()) + { + aFill.clearTextureCoordinates(); + } + + // #i98295# get rid of normals and color early when not needed + if(css::drawing::ShadeMode_FLAT == aShadeMode) + { + aFill.clearNormals(); + aFill.clearBColors(); + } + + // transform to device coordinates (-1.0 .. 1.0) and check for visibility + aFill.transform(getViewInformation3D().getObjectToView()); + const basegfx::B3DRange a3DRange(basegfx::utils::getRange(aFill)); + const basegfx::B2DRange a2DRange(a3DRange.getMinX(), a3DRange.getMinY(), a3DRange.getMaxX(), a3DRange.getMaxY()); + + bPaintIt = a2DRange.overlaps(maRasterRange); + } + + // check if it shall be painted regarding hiding of normals (backface culling) + if(bPaintIt && !rPrimitive.getDoubleSided()) + { + // get plane normal of polygon in view coordinates (with ZBuffer values), + // left-handed coordinate system + const basegfx::B3DVector aPlaneNormal(aFill.getB3DPolygon(0).getNormal()); + + if(aPlaneNormal.getZ() > 0.0) + { + bPaintIt = false; + } + } + + if(!bPaintIt) + return; + + // prepare ObjectToEye in NormalTransform + basegfx::B3DHomMatrix aNormalTransform(getViewInformation3D().getOrientation() * getViewInformation3D().getObjectTransformation()); + + if(getSdrSceneAttribute().getTwoSidedLighting()) + { + // get plane normal of polygon in view coordinates (with ZBuffer values), + // left-handed coordinate system + const basegfx::B3DVector aPlaneNormal(aFill.getB3DPolygon(0).getNormal()); + + if(aPlaneNormal.getZ() > 0.0) + { + // mirror normals + aNormalTransform.scale(-1.0, -1.0, -1.0); + } + } + + switch(aShadeMode) + { + case css::drawing::ShadeMode_PHONG: + { + // phong shading. Transform normals to eye coor + aFill.transformNormals(aNormalTransform); + break; + } + case css::drawing::ShadeMode_SMOOTH: + { + // gouraud shading. Transform normals to eye coor + aFill.transformNormals(aNormalTransform); + + // prepare color model parameters, evtl. use blend color + const basegfx::BColor aColor(getModulate() ? basegfx::BColor(1.0, 1.0, 1.0) : rPrimitive.getMaterial().getColor()); + const basegfx::BColor& rSpecular(rPrimitive.getMaterial().getSpecular()); + const basegfx::BColor& rEmission(rPrimitive.getMaterial().getEmission()); + const sal_uInt16 nSpecularIntensity(rPrimitive.getMaterial().getSpecularIntensity()); + + // solve color model for each normal vector, set colors at points. Clear normals. + for(sal_uInt32 a(0); a < aFill.count(); a++) + { + basegfx::B3DPolygon aPartFill(aFill.getB3DPolygon(a)); + + for(sal_uInt32 b(0); b < aPartFill.count(); b++) + { + // solve color model. Transform normal to eye coor + const basegfx::B3DVector aNormal(aPartFill.getNormal(b)); + const basegfx::BColor aSolvedColor(getSdrLightingAttribute().solveColorModel(aNormal, aColor, rSpecular, rEmission, nSpecularIntensity)); + aPartFill.setBColor(b, aSolvedColor); + } + + // clear normals on this part polygon and write it back + aPartFill.clearNormals(); + aFill.setB3DPolygon(a, aPartFill); + } + break; + } + case css::drawing::ShadeMode_FLAT: + { + // flat shading. Get plane vector in eye coordinates + const basegfx::B3DVector aPlaneEyeNormal(aNormalTransform * rPrimitive.getB3DPolyPolygon().getB3DPolygon(0).getNormal()); + + // prepare color model parameters, evtl. use blend color + const basegfx::BColor aColor(getModulate() ? basegfx::BColor(1.0, 1.0, 1.0) : rPrimitive.getMaterial().getColor()); + const basegfx::BColor& rSpecular(rPrimitive.getMaterial().getSpecular()); + const basegfx::BColor& rEmission(rPrimitive.getMaterial().getEmission()); + const sal_uInt16 nSpecularIntensity(rPrimitive.getMaterial().getSpecularIntensity()); + + // solve color model for plane vector and use that color for whole plane + aObjectColor = getSdrLightingAttribute().solveColorModel(aPlaneEyeNormal, aColor, rSpecular, rEmission, nSpecularIntensity); + break; + } + default: // case css::drawing::ShadeMode_DRAFT: + { + // draft, just use object color which is already set. Delete all other infos + aFill.clearNormals(); + aFill.clearBColors(); + break; + } + } + + // draw it to ZBuffer + const attribute::MaterialAttribute3D aMaterial( + maBColorModifierStack.getModifiedColor(aObjectColor), + rPrimitive.getMaterial().getSpecular(), + rPrimitive.getMaterial().getEmission(), + rPrimitive.getMaterial().getSpecularIntensity()); + + rasterconvertB3DPolyPolygon(aMaterial, aFill); + } + + void DefaultProcessor3D::impRenderTransformPrimitive3D(const primitive3d::TransformPrimitive3D& rTransformCandidate) + { + // transform group. Remember current transformations + const geometry::ViewInformation3D aLastViewInformation3D(getViewInformation3D()); + + // create new transformation; add new object transform from right side + const geometry::ViewInformation3D aNewViewInformation3D( + aLastViewInformation3D.getObjectTransformation() * rTransformCandidate.getTransformation(), + aLastViewInformation3D.getOrientation(), + aLastViewInformation3D.getProjection(), + aLastViewInformation3D.getDeviceToView(), + aLastViewInformation3D.getViewTime(), + aLastViewInformation3D.getExtendedInformationSequence()); + updateViewInformation(aNewViewInformation3D); + + // let break down recursively + process(rTransformCandidate.getChildren()); + + // restore transformations + updateViewInformation(aLastViewInformation3D); + } + + void DefaultProcessor3D::processBasePrimitive3D(const primitive3d::BasePrimitive3D& rBasePrimitive) + { + // it is a BasePrimitive3D implementation, use getPrimitive3DID() call for switch + switch(rBasePrimitive.getPrimitive3DID()) + { + case PRIMITIVE3D_ID_GRADIENTTEXTUREPRIMITIVE3D : + { + // GradientTexturePrimitive3D + const primitive3d::GradientTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::GradientTexturePrimitive3D& >(rBasePrimitive); + impRenderGradientTexturePrimitive3D(rPrimitive, false); + break; + } + case PRIMITIVE3D_ID_HATCHTEXTUREPRIMITIVE3D : + { + // hatchTexturePrimitive3D + const primitive3d::HatchTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::HatchTexturePrimitive3D& >(rBasePrimitive); + impRenderHatchTexturePrimitive3D(rPrimitive); + break; + } + case PRIMITIVE3D_ID_BITMAPTEXTUREPRIMITIVE3D : + { + // BitmapTexturePrimitive3D + const primitive3d::BitmapTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::BitmapTexturePrimitive3D& >(rBasePrimitive); + impRenderBitmapTexturePrimitive3D(rPrimitive); + break; + } + case PRIMITIVE3D_ID_TRANSPARENCETEXTUREPRIMITIVE3D : + { + // TransparenceTexturePrimitive3D + const primitive3d::TransparenceTexturePrimitive3D& rPrimitive = static_cast< const primitive3d::TransparenceTexturePrimitive3D& >(rBasePrimitive); + mnTransparenceCounter++; + impRenderGradientTexturePrimitive3D(rPrimitive, true); + mnTransparenceCounter--; + break; + } + case PRIMITIVE3D_ID_MODIFIEDCOLORPRIMITIVE3D : + { + // ModifiedColorPrimitive3D + // Force output to unified color. + const primitive3d::ModifiedColorPrimitive3D& rPrimitive = static_cast< const primitive3d::ModifiedColorPrimitive3D& >(rBasePrimitive); + impRenderModifiedColorPrimitive3D(rPrimitive); + break; + } + case PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D : + { + // directdraw of PolygonHairlinePrimitive3D + const primitive3d::PolygonHairlinePrimitive3D& rPrimitive = static_cast< const primitive3d::PolygonHairlinePrimitive3D& >(rBasePrimitive); + impRenderPolygonHairlinePrimitive3D(rPrimitive); + break; + } + case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D : + { + // directdraw of PolyPolygonMaterialPrimitive3D + const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive = static_cast< const primitive3d::PolyPolygonMaterialPrimitive3D& >(rBasePrimitive); + impRenderPolyPolygonMaterialPrimitive3D(rPrimitive); + break; + } + case PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D : + { + // transform group (TransformPrimitive3D) + impRenderTransformPrimitive3D(static_cast< const primitive3d::TransformPrimitive3D& >(rBasePrimitive)); + break; + } + default: + { + // process recursively + process(rBasePrimitive.get3DDecomposition(getViewInformation3D())); + break; + } + } + } + + DefaultProcessor3D::DefaultProcessor3D( + const geometry::ViewInformation3D& rViewInformation, + const attribute::SdrSceneAttribute& rSdrSceneAttribute, + const attribute::SdrLightingAttribute& rSdrLightingAttribute) + : BaseProcessor3D(rViewInformation), + mrSdrSceneAttribute(rSdrSceneAttribute), + mrSdrLightingAttribute(rSdrLightingAttribute), + maBColorModifierStack(), + mnTransparenceCounter(0), + mbModulate(false), + mbFilter(false), + mbSimpleTextureActive(false) + { + // a derivation has to set maRasterRange which is used in the basic render methods. + // Setting to default here ([0.0 .. 1.0] in X,Y) to avoid problems + maRasterRange.expand(basegfx::B2DTuple(0.0, 0.0)); + maRasterRange.expand(basegfx::B2DTuple(1.0, 1.0)); + } + + DefaultProcessor3D::~DefaultProcessor3D() + { + } + +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |