1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_drawinglayer.hxx" 30 31 #include <drawinglayer/processor3d/shadow3dextractor.hxx> 32 #include <drawinglayer/primitive3d/shadowprimitive3d.hxx> 33 #include <drawinglayer/primitive2d/shadowprimitive2d.hxx> 34 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx> 35 #include <drawinglayer/primitive3d/transformprimitive3d.hxx> 36 #include <drawinglayer/primitive3d/polygonprimitive3d.hxx> 37 #include <basegfx/polygon/b2dpolygontools.hxx> 38 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> 39 #include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx> 40 #include <basegfx/polygon/b2dpolypolygontools.hxx> 41 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx> 42 #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> 43 44 ////////////////////////////////////////////////////////////////////////////// 45 46 using namespace com::sun::star; 47 48 ////////////////////////////////////////////////////////////////////////////// 49 50 namespace drawinglayer 51 { 52 namespace processor3d 53 { 54 /// helper to convert from BasePrimitive2DVector to primitive2d::Primitive2DSequence 55 const primitive2d::Primitive2DSequence Shadow3DExtractingProcessor::getPrimitive2DSequenceFromBasePrimitive2DVector( 56 const BasePrimitive2DVector& rVector) const 57 { 58 const sal_uInt32 nCount(rVector.size()); 59 primitive2d::Primitive2DSequence aRetval(nCount); 60 61 for(sal_uInt32 a(0); a < nCount; a++) 62 { 63 aRetval[a] = rVector[a]; 64 } 65 66 // all entries taken over; no need to delete entries, just reset to 67 // mark as empty 68 const_cast< BasePrimitive2DVector& >(rVector).clear(); 69 70 return aRetval; 71 } 72 73 // as tooling, the process() implementation takes over API handling and calls this 74 // virtual render method when the primitive implementation is BasePrimitive3D-based. 75 void Shadow3DExtractingProcessor::processBasePrimitive3D(const primitive3d::BasePrimitive3D& rCandidate) 76 { 77 // it is a BasePrimitive3D implementation, use getPrimitive3DID() call for switch 78 switch(rCandidate.getPrimitive3DID()) 79 { 80 case PRIMITIVE3D_ID_SHADOWPRIMITIVE3D : 81 { 82 // shadow3d object. Call recursive with content and start conversion 83 const primitive3d::ShadowPrimitive3D& rPrimitive = static_cast< const primitive3d::ShadowPrimitive3D& >(rCandidate); 84 85 // set new target 86 BasePrimitive2DVector aNewSubList; 87 BasePrimitive2DVector* pLastTargetSequence = mpPrimitive2DSequence; 88 mpPrimitive2DSequence = &aNewSubList; 89 90 // activate convert 91 const bool bLastConvert(mbConvert); 92 mbConvert = true; 93 94 // set projection flag 95 const bool bLastUseProjection(mbUseProjection); 96 mbUseProjection = rPrimitive.getShadow3D(); 97 98 // process content 99 process(rPrimitive.getChildren()); 100 101 // restore values 102 mbUseProjection = bLastUseProjection; 103 mbConvert = bLastConvert; 104 mpPrimitive2DSequence = pLastTargetSequence; 105 106 // create 2d shadow primitive with result. This also fetches all entries 107 // from aNewSubList, so there is no need to delete them 108 primitive2d::BasePrimitive2D* pNew = new primitive2d::ShadowPrimitive2D( 109 rPrimitive.getShadowTransform(), 110 rPrimitive.getShadowColor(), 111 getPrimitive2DSequenceFromBasePrimitive2DVector(aNewSubList)); 112 113 if(basegfx::fTools::more(rPrimitive.getShadowTransparence(), 0.0)) 114 { 115 // create simpleTransparencePrimitive, add created primitives 116 const primitive2d::Primitive2DReference xRef(pNew); 117 const primitive2d::Primitive2DSequence aNewTransPrimitiveVector(&xRef, 1); 118 119 pNew = new primitive2d::UnifiedTransparencePrimitive2D( 120 aNewTransPrimitiveVector, 121 rPrimitive.getShadowTransparence()); 122 } 123 124 mpPrimitive2DSequence->push_back(pNew); 125 126 break; 127 } 128 case PRIMITIVE3D_ID_TRANSFORMPRIMITIVE3D : 129 { 130 // transform group. Remember current transformations 131 const primitive3d::TransformPrimitive3D& rPrimitive = static_cast< const primitive3d::TransformPrimitive3D& >(rCandidate); 132 const geometry::ViewInformation3D aLastViewInformation3D(getViewInformation3D()); 133 134 // create new transformation; add new object transform from right side 135 const geometry::ViewInformation3D aNewViewInformation3D( 136 aLastViewInformation3D.getObjectTransformation() * rPrimitive.getTransformation(), 137 aLastViewInformation3D.getOrientation(), 138 aLastViewInformation3D.getProjection(), 139 aLastViewInformation3D.getDeviceToView(), 140 aLastViewInformation3D.getViewTime(), 141 aLastViewInformation3D.getExtendedInformationSequence()); 142 updateViewInformation(aNewViewInformation3D); 143 144 if(mbShadowProjectionIsValid) 145 { 146 // update buffered WorldToEye and EyeToView 147 maWorldToEye = getViewInformation3D().getOrientation() * getViewInformation3D().getObjectTransformation(); 148 maEyeToView = getViewInformation3D().getDeviceToView() * getViewInformation3D().getProjection(); 149 } 150 151 // let break down 152 process(rPrimitive.getChildren()); 153 154 // restore transformations 155 updateViewInformation(aLastViewInformation3D); 156 157 if(mbShadowProjectionIsValid) 158 { 159 // update buffered WorldToEye and EyeToView 160 maWorldToEye = getViewInformation3D().getOrientation() * getViewInformation3D().getObjectTransformation(); 161 maEyeToView = getViewInformation3D().getDeviceToView() * getViewInformation3D().getProjection(); 162 } 163 break; 164 } 165 case PRIMITIVE3D_ID_POLYGONHAIRLINEPRIMITIVE3D : 166 { 167 // PolygonHairlinePrimitive3D 168 if(mbConvert) 169 { 170 const primitive3d::PolygonHairlinePrimitive3D& rPrimitive = static_cast< const primitive3d::PolygonHairlinePrimitive3D& >(rCandidate); 171 basegfx::B2DPolygon a2DHairline; 172 173 if(mbUseProjection) 174 { 175 if(mbShadowProjectionIsValid) 176 { 177 a2DHairline = impDoShadowProjection(rPrimitive.getB3DPolygon()); 178 } 179 } 180 else 181 { 182 a2DHairline = basegfx::tools::createB2DPolygonFromB3DPolygon(rPrimitive.getB3DPolygon(), getViewInformation3D().getObjectToView()); 183 } 184 185 if(a2DHairline.count()) 186 { 187 a2DHairline.transform(getObjectTransformation()); 188 mpPrimitive2DSequence->push_back( 189 new primitive2d::PolygonHairlinePrimitive2D( 190 a2DHairline, 191 maPrimitiveColor)); 192 } 193 } 194 break; 195 } 196 case PRIMITIVE3D_ID_POLYPOLYGONMATERIALPRIMITIVE3D : 197 { 198 // PolyPolygonMaterialPrimitive3D 199 if(mbConvert) 200 { 201 const primitive3d::PolyPolygonMaterialPrimitive3D& rPrimitive = static_cast< const primitive3d::PolyPolygonMaterialPrimitive3D& >(rCandidate); 202 basegfx::B2DPolyPolygon a2DFill; 203 204 if(mbUseProjection) 205 { 206 if(mbShadowProjectionIsValid) 207 { 208 a2DFill = impDoShadowProjection(rPrimitive.getB3DPolyPolygon()); 209 } 210 } 211 else 212 { 213 a2DFill = basegfx::tools::createB2DPolyPolygonFromB3DPolyPolygon(rPrimitive.getB3DPolyPolygon(), getViewInformation3D().getObjectToView()); 214 } 215 216 if(a2DFill.count()) 217 { 218 a2DFill.transform(getObjectTransformation()); 219 mpPrimitive2DSequence->push_back( 220 new primitive2d::PolyPolygonColorPrimitive2D( 221 a2DFill, 222 maPrimitiveColor)); 223 } 224 } 225 break; 226 } 227 default : 228 { 229 // process recursively 230 process(rCandidate.get3DDecomposition(getViewInformation3D())); 231 break; 232 } 233 } 234 } 235 236 Shadow3DExtractingProcessor::Shadow3DExtractingProcessor( 237 const geometry::ViewInformation3D& rViewInformation, 238 const basegfx::B2DHomMatrix& rObjectTransformation, 239 const basegfx::B3DVector& rLightNormal, 240 double fShadowSlant, 241 const basegfx::B3DRange& rContained3DRange) 242 : BaseProcessor3D(rViewInformation), 243 maPrimitive2DSequence(), 244 mpPrimitive2DSequence(&maPrimitive2DSequence), 245 maObjectTransformation(rObjectTransformation), 246 maWorldToEye(), 247 maEyeToView(), 248 maLightNormal(rLightNormal), 249 maShadowPlaneNormal(), 250 maPlanePoint(), 251 mfLightPlaneScalar(0.0), 252 maPrimitiveColor(), 253 mbShadowProjectionIsValid(false), 254 mbConvert(false), 255 mbUseProjection(false) 256 { 257 // normalize light normal, get and normalize shadow plane normal and calculate scalar from it 258 maLightNormal.normalize(); 259 maShadowPlaneNormal = basegfx::B3DVector(0.0, sin(fShadowSlant), cos(fShadowSlant)); 260 maShadowPlaneNormal.normalize(); 261 mfLightPlaneScalar = maLightNormal.scalar(maShadowPlaneNormal); 262 263 // use only when scalar is > 0.0, so the light is in front of the object 264 if(basegfx::fTools::more(mfLightPlaneScalar, 0.0)) 265 { 266 // prepare buffered WorldToEye and EyeToView 267 maWorldToEye = getViewInformation3D().getOrientation() * getViewInformation3D().getObjectTransformation(); 268 maEyeToView = getViewInformation3D().getDeviceToView() * getViewInformation3D().getProjection(); 269 270 // calculate range to get front edge around which to rotate the shadow's projection 271 basegfx::B3DRange aContained3DRange(rContained3DRange); 272 aContained3DRange.transform(getWorldToEye()); 273 maPlanePoint.setX(maShadowPlaneNormal.getX() < 0.0 ? aContained3DRange.getMinX() : aContained3DRange.getMaxX()); 274 maPlanePoint.setY(maShadowPlaneNormal.getY() > 0.0 ? aContained3DRange.getMinY() : aContained3DRange.getMaxY()); 275 maPlanePoint.setZ(aContained3DRange.getMinZ() - (aContained3DRange.getDepth() / 8.0)); 276 277 // set flag that shadow projection is prepared and allowed 278 mbShadowProjectionIsValid = true; 279 } 280 } 281 282 Shadow3DExtractingProcessor::~Shadow3DExtractingProcessor() 283 { 284 OSL_ENSURE(0 == maPrimitive2DSequence.size(), 285 "OOps, someone used Shadow3DExtractingProcessor, but did not fetch the results (!)"); 286 for(sal_uInt32 a(0); a < maPrimitive2DSequence.size(); a++) 287 { 288 delete maPrimitive2DSequence[a]; 289 } 290 } 291 292 basegfx::B2DPolygon Shadow3DExtractingProcessor::impDoShadowProjection(const basegfx::B3DPolygon& rSource) 293 { 294 basegfx::B2DPolygon aRetval; 295 296 for(sal_uInt32 a(0L); a < rSource.count(); a++) 297 { 298 // get point, transform to eye coordinate system 299 basegfx::B3DPoint aCandidate(rSource.getB3DPoint(a)); 300 aCandidate *= getWorldToEye(); 301 302 // we are in eye coordinates 303 // ray is (aCandidate + fCut * maLightNormal) 304 // plane is (maPlanePoint, maShadowPlaneNormal) 305 // maLightNormal.scalar(maShadowPlaneNormal) is already in mfLightPlaneScalar and > 0.0 306 // get cut point of ray with shadow plane 307 const double fCut(basegfx::B3DVector(maPlanePoint - aCandidate).scalar(maShadowPlaneNormal) / mfLightPlaneScalar); 308 aCandidate += maLightNormal * fCut; 309 310 // transform to view, use 2d coordinates 311 aCandidate *= getEyeToView(); 312 aRetval.append(basegfx::B2DPoint(aCandidate.getX(), aCandidate.getY())); 313 } 314 315 // copy closed flag 316 aRetval.setClosed(rSource.isClosed()); 317 318 return aRetval; 319 } 320 321 basegfx::B2DPolyPolygon Shadow3DExtractingProcessor::impDoShadowProjection(const basegfx::B3DPolyPolygon& rSource) 322 { 323 basegfx::B2DPolyPolygon aRetval; 324 325 for(sal_uInt32 a(0L); a < rSource.count(); a++) 326 { 327 aRetval.append(impDoShadowProjection(rSource.getB3DPolygon(a))); 328 } 329 330 return aRetval; 331 } 332 333 const primitive2d::Primitive2DSequence Shadow3DExtractingProcessor::getPrimitive2DSequence() const 334 { 335 return getPrimitive2DSequenceFromBasePrimitive2DVector(maPrimitive2DSequence); 336 } 337 338 } // end of namespace processor3d 339 } // end of namespace drawinglayer 340 341 ////////////////////////////////////////////////////////////////////////////// 342 // eof 343