/* -*- 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 #include #include "ximp3dscene.hxx" #include #include #include #include #include #include #include #include "eventimp.hxx" #include "descriptionimp.hxx" using namespace ::com::sun::star; using namespace ::xmloff::token; // dr3d:3dlight context SdXML3DLightContext::SdXML3DLightContext( SvXMLImport& rImport, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) : SvXMLImportContext( rImport ), maDiffuseColor(0x00000000), maDirection(0.0, 0.0, 1.0), mbEnabled(false), mbSpecular(false) { // read attributes for the 3DScene for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) { switch(aIter.getToken()) { case XML_ELEMENT(DR3D, XML_DIFFUSE_COLOR): { ::sax::Converter::convertColor(maDiffuseColor, aIter.toView()); break; } case XML_ELEMENT(DR3D, XML_DIRECTION): { ::basegfx::B3DVector aVal; SvXMLUnitConverter::convertB3DVector(aVal, aIter.toView()); if (!std::isnan(aVal.getX()) && !std::isnan(aVal.getY()) && !std::isnan(aVal.getZ())) { maDirection = aVal; } else { SAL_WARN("xmloff", "NaNs found in light direction: " << aIter.toString()); } break; } case XML_ELEMENT(DR3D, XML_ENABLED): { (void)::sax::Converter::convertBool(mbEnabled, aIter.toView()); break; } case XML_ELEMENT(DR3D, XML_SPECULAR): { (void)::sax::Converter::convertBool(mbSpecular, aIter.toView()); break; } default: XMLOFF_WARN_UNKNOWN("xmloff", aIter); } } } SdXML3DLightContext::~SdXML3DLightContext() { } SdXML3DSceneShapeContext::SdXML3DSceneShapeContext( SvXMLImport& rImport, const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, uno::Reference< drawing::XShapes > const & rShapes, bool bTemporaryShapes) : SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShapes ), SdXML3DSceneAttributesHelper( rImport ) { } SdXML3DSceneShapeContext::~SdXML3DSceneShapeContext() { } void SdXML3DSceneShapeContext::startFastElement( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) { // create new 3DScene shape and add it to rShapes, use it // as base for the new 3DScene import AddShape( u"com.sun.star.drawing.Shape3DSceneObject"_ustr ); if( mxShape.is() ) { SetStyle(); mxChildren.set( mxShape, uno::UNO_QUERY ); if( mxChildren.is() ) GetImport().GetShapeImport()->pushGroupForPostProcessing( mxChildren ); SetLayer(); // set pos, size, shear and rotate SetTransformation(); } // read attributes for the 3DScene for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) processSceneAttribute( aIter ); // #91047# call parent function is missing here, added it if(mxShape.is()) { // call parent SdXMLShapeContext::startFastElement(nElement, xAttrList); } } void SdXML3DSceneShapeContext::endFastElement(sal_Int32 nElement) { if(!mxShape.is()) return; uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); if(xPropSet.is()) { setSceneAttributes( xPropSet ); } if( mxChildren.is() ) GetImport().GetShapeImport()->popGroupAndPostProcess(); // call parent SdXMLShapeContext::endFastElement(nElement); } css::uno::Reference< css::xml::sax::XFastContextHandler > SdXML3DSceneShapeContext::createFastChildContext( sal_Int32 nElement, const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) { SvXMLImportContextRef xContext; switch (nElement) { // #i68101# case XML_ELEMENT(SVG, XML_TITLE): case XML_ELEMENT(SVG_COMPAT, XML_TITLE): case XML_ELEMENT(SVG, XML_DESC): case XML_ELEMENT(SVG_COMPAT, XML_DESC): xContext = new SdXMLDescriptionContext( GetImport(), nElement, mxShape ); break; case XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS): xContext = new SdXMLEventsContext( GetImport(), mxShape ); break; // look for local light context first case XML_ELEMENT(DR3D, XML_LIGHT): // dr3d:light inside dr3d:scene context xContext = create3DLightContext( xAttrList ); break; default: // call GroupChildContext function at common ShapeImport return XMLShapeImportHelper::Create3DSceneChildContext( GetImport(), nElement, xAttrList, mxChildren); } return xContext; } SdXML3DSceneAttributesHelper::SdXML3DSceneAttributesHelper( SvXMLImport& rImporter ) : mrImport( rImporter ), mbSetTransform( false ), mxPrjMode(drawing::ProjectionMode_PERSPECTIVE), mnDistance(1000), mnFocalLength(1000), mnShadowSlant(0), mxShadeMode(drawing::ShadeMode_SMOOTH), maAmbientColor(0x00666666), mbLightingMode(false), maVRP(0.0, 0.0, 1.0), maVPN(0.0, 0.0, 1.0), maVUP(0.0, 1.0, 0.0), mbVRPUsed(false) { } /** creates a 3d light context and adds it to the internal list for later processing */ SvXMLImportContext * SdXML3DSceneAttributesHelper::create3DLightContext( const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) { const rtl::Reference xContext{new SdXML3DLightContext(mrImport, xAttrList)}; // remember SdXML3DLightContext for later evaluation maList.push_back(xContext); return xContext.get(); } /** this should be called for each scene attribute */ void SdXML3DSceneAttributesHelper::processSceneAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) { auto nAttributeToken = aIter.getToken(); if( !IsTokenInNamespace(nAttributeToken, XML_NAMESPACE_DR3D) ) return; switch(nAttributeToken & TOKEN_MASK) { case XML_TRANSFORM: { SdXMLImExTransform3D aTransform(aIter.toString(), mrImport.GetMM100UnitConverter()); if(aTransform.NeedsAction()) mbSetTransform = aTransform.GetFullHomogenTransform(mxHomMat); return; } case XML_VRP: { ::basegfx::B3DVector aNewVec; SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); if(aNewVec != maVRP) { maVRP = aNewVec; mbVRPUsed = true; } return; } case XML_VPN: { ::basegfx::B3DVector aNewVec; SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); if(aNewVec != maVPN) { maVPN = aNewVec; } return; } case XML_VUP: { ::basegfx::B3DVector aNewVec; SvXMLUnitConverter::convertB3DVector(aNewVec, aIter.toView()); if(aNewVec != maVUP) { maVUP = aNewVec; } return; } case XML_PROJECTION: { if( IsXMLToken( aIter, XML_PARALLEL ) ) mxPrjMode = drawing::ProjectionMode_PARALLEL; else mxPrjMode = drawing::ProjectionMode_PERSPECTIVE; return; } case XML_DISTANCE: { mrImport.GetMM100UnitConverter().convertMeasureToCore(mnDistance, aIter.toView()); return; } case XML_FOCAL_LENGTH: { mrImport.GetMM100UnitConverter().convertMeasureToCore(mnFocalLength, aIter.toView()); return; } case XML_SHADOW_SLANT: { double fAngle = 0.0; if (::sax::Converter::convertAngle(fAngle, aIter.toView())) mnShadowSlant = static_cast(basegfx::fround(fAngle)); else mnShadowSlant = 0; return; } case XML_SHADE_MODE: { if( IsXMLToken( aIter, XML_FLAT ) ) mxShadeMode = drawing::ShadeMode_FLAT; else if( IsXMLToken( aIter, XML_PHONG ) ) mxShadeMode = drawing::ShadeMode_PHONG; else if( IsXMLToken( aIter, XML_GOURAUD ) ) mxShadeMode = drawing::ShadeMode_SMOOTH; else mxShadeMode = drawing::ShadeMode_DRAFT; return; } case XML_AMBIENT_COLOR: { ::sax::Converter::convertColor(maAmbientColor, aIter.toView()); return; } case XML_LIGHTING_MODE: { (void)::sax::Converter::convertBool(mbLightingMode, aIter.toView()); return; } default: XMLOFF_WARN_UNKNOWN("xmloff", aIter); } } /** this sets the scene attributes at this propertyset */ void SdXML3DSceneAttributesHelper::setSceneAttributes( const css::uno::Reference< css::beans::XPropertySet >& xPropSet ) { uno::Any aAny; // world transformation if(mbSetTransform) { xPropSet->setPropertyValue(u"D3DTransformMatrix"_ustr, uno::Any(mxHomMat)); } // distance xPropSet->setPropertyValue(u"D3DSceneDistance"_ustr, uno::Any(mnDistance)); // focalLength xPropSet->setPropertyValue(u"D3DSceneFocalLength"_ustr, uno::Any(mnFocalLength)); // shadowSlant xPropSet->setPropertyValue(u"D3DSceneShadowSlant"_ustr, uno::Any(static_cast(mnShadowSlant))); // shadeMode xPropSet->setPropertyValue(u"D3DSceneShadeMode"_ustr, uno::Any(mxShadeMode)); // ambientColor xPropSet->setPropertyValue(u"D3DSceneAmbientColor"_ustr, uno::Any(maAmbientColor)); // lightingMode xPropSet->setPropertyValue(u"D3DSceneTwoSidedLighting"_ustr, uno::Any(mbLightingMode)); if( !maList.empty() ) { uno::Any aAny2; uno::Any aAny3; // set lights for( size_t a = 0; a < maList.size(); a++) { SdXML3DLightContext* pCtx = maList[ a ].get(); // set anys aAny <<= pCtx->GetDiffuseColor(); drawing::Direction3D aLightDir; aLightDir.DirectionX = pCtx->GetDirection().getX(); aLightDir.DirectionY = pCtx->GetDirection().getY(); aLightDir.DirectionZ = pCtx->GetDirection().getZ(); aAny2 <<= aLightDir; aAny3 <<= pCtx->GetEnabled(); switch(a) { case 0: { xPropSet->setPropertyValue(u"D3DSceneLightColor1"_ustr, aAny); xPropSet->setPropertyValue(u"D3DSceneLightDirection1"_ustr, aAny2); xPropSet->setPropertyValue(u"D3DSceneLightOn1"_ustr, aAny3); break; } case 1: { xPropSet->setPropertyValue(u"D3DSceneLightColor2"_ustr, aAny); xPropSet->setPropertyValue(u"D3DSceneLightDirection2"_ustr, aAny2); xPropSet->setPropertyValue(u"D3DSceneLightOn2"_ustr, aAny3); break; } case 2: { xPropSet->setPropertyValue(u"D3DSceneLightColor3"_ustr, aAny); xPropSet->setPropertyValue(u"D3DSceneLightDirection3"_ustr, aAny2); xPropSet->setPropertyValue(u"D3DSceneLightOn3"_ustr, aAny3); break; } case 3: { xPropSet->setPropertyValue(u"D3DSceneLightColor4"_ustr, aAny); xPropSet->setPropertyValue(u"D3DSceneLightDirection4"_ustr, aAny2); xPropSet->setPropertyValue(u"D3DSceneLightOn4"_ustr, aAny3); break; } case 4: { xPropSet->setPropertyValue(u"D3DSceneLightColor5"_ustr, aAny); xPropSet->setPropertyValue(u"D3DSceneLightDirection5"_ustr, aAny2); xPropSet->setPropertyValue(u"D3DSceneLightOn5"_ustr, aAny3); break; } case 5: { xPropSet->setPropertyValue(u"D3DSceneLightColor6"_ustr, aAny); xPropSet->setPropertyValue(u"D3DSceneLightDirection6"_ustr, aAny2); xPropSet->setPropertyValue(u"D3DSceneLightOn6"_ustr, aAny3); break; } case 6: { xPropSet->setPropertyValue(u"D3DSceneLightColor7"_ustr, aAny); xPropSet->setPropertyValue(u"D3DSceneLightDirection7"_ustr, aAny2); xPropSet->setPropertyValue(u"D3DSceneLightOn7"_ustr, aAny3); break; } case 7: { xPropSet->setPropertyValue(u"D3DSceneLightColor8"_ustr, aAny); xPropSet->setPropertyValue(u"D3DSceneLightDirection8"_ustr, aAny2); xPropSet->setPropertyValue(u"D3DSceneLightOn8"_ustr, aAny3); break; } } } } // CameraGeometry and camera settings drawing::CameraGeometry aCamGeo; aCamGeo.vrp.PositionX = maVRP.getX(); aCamGeo.vrp.PositionY = maVRP.getY(); aCamGeo.vrp.PositionZ = maVRP.getZ(); aCamGeo.vpn.DirectionX = maVPN.getX(); aCamGeo.vpn.DirectionY = maVPN.getY(); aCamGeo.vpn.DirectionZ = maVPN.getZ(); aCamGeo.vup.DirectionX = maVUP.getX(); aCamGeo.vup.DirectionY = maVUP.getY(); aCamGeo.vup.DirectionZ = maVUP.getZ(); xPropSet->setPropertyValue(u"D3DCameraGeometry"_ustr, uno::Any(aCamGeo)); // #91047# set drawing::ProjectionMode AFTER camera geometry is set // projection "D3DScenePerspective" drawing::ProjectionMode xPropSet->setPropertyValue(u"D3DScenePerspective"_ustr, uno::Any(mxPrjMode)); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */