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_svx.hxx" 30 #include <svx/sdr/contact/viewcontactofe3dscene.hxx> 31 #include <svx/polysc3d.hxx> 32 #include <svx/sdr/contact/displayinfo.hxx> 33 #include <svx/sdr/contact/viewobjectcontact.hxx> 34 #include <basegfx/polygon/b2dpolygontools.hxx> 35 #include <basegfx/color/bcolor.hxx> 36 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> 37 #include <svx/sdr/primitive2d/sdrattributecreator.hxx> 38 #include <svx/sdr/contact/viewobjectcontactofe3dscene.hxx> 39 #include <basegfx/matrix/b2dhommatrix.hxx> 40 #include <basegfx/range/b3drange.hxx> 41 #include <drawinglayer/primitive3d/baseprimitive3d.hxx> 42 #include <svx/sdr/contact/viewcontactofe3d.hxx> 43 #include <drawinglayer/primitive2d/sceneprimitive2d.hxx> 44 #include <drawinglayer/primitive3d/transformprimitive3d.hxx> 45 #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx> 46 47 ////////////////////////////////////////////////////////////////////////////// 48 49 using namespace com::sun::star; 50 51 ////////////////////////////////////////////////////////////////////////////// 52 53 namespace 54 { 55 // pActiveVC is only true if ghosted is still activated and maybe needs to be switched off in this path 56 void createSubPrimitive3DVector( 57 const sdr::contact::ViewContact& rCandidate, 58 drawinglayer::primitive3d::Primitive3DSequence& o_rAllTarget, 59 drawinglayer::primitive3d::Primitive3DSequence* o_pVisibleTarget, 60 const SetOfByte* pVisibleLayerSet, 61 const bool bTestSelectedVisibility) 62 { 63 const sdr::contact::ViewContactOfE3dScene* pViewContactOfE3dScene = dynamic_cast< const sdr::contact::ViewContactOfE3dScene* >(&rCandidate); 64 65 if(pViewContactOfE3dScene) 66 { 67 const sal_uInt32 nChildrenCount(rCandidate.GetObjectCount()); 68 69 if(nChildrenCount) 70 { 71 // provide new collection sequences 72 drawinglayer::primitive3d::Primitive3DSequence aNewAllTarget; 73 drawinglayer::primitive3d::Primitive3DSequence aNewVisibleTarget; 74 75 // add children recursively 76 for(sal_uInt32 a(0L); a < nChildrenCount; a++) 77 { 78 createSubPrimitive3DVector( 79 rCandidate.GetViewContact(a), 80 aNewAllTarget, 81 o_pVisibleTarget ? &aNewVisibleTarget : 0, 82 pVisibleLayerSet, 83 bTestSelectedVisibility); 84 } 85 86 // create transform primitive for the created content combining content and transformtion 87 const drawinglayer::primitive3d::Primitive3DReference xReference(new drawinglayer::primitive3d::TransformPrimitive3D( 88 pViewContactOfE3dScene->GetE3dScene().GetTransform(), 89 aNewAllTarget)); 90 91 // add created content to all target 92 drawinglayer::primitive3d::appendPrimitive3DReferenceToPrimitive3DSequence(o_rAllTarget, xReference); 93 94 // add created content to visibiel target if exists 95 if(o_pVisibleTarget) 96 { 97 drawinglayer::primitive3d::appendPrimitive3DReferenceToPrimitive3DSequence(*o_pVisibleTarget, xReference); 98 } 99 } 100 } 101 else 102 { 103 // access view independent representation of rCandidate 104 const sdr::contact::ViewContactOfE3d* pViewContactOfE3d = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&rCandidate); 105 106 if(pViewContactOfE3d) 107 { 108 drawinglayer::primitive3d::Primitive3DSequence xPrimitive3DSeq(pViewContactOfE3d->getViewIndependentPrimitive3DSequence()); 109 110 if(xPrimitive3DSeq.hasElements()) 111 { 112 // add to all target vector 113 drawinglayer::primitive3d::appendPrimitive3DSequenceToPrimitive3DSequence(o_rAllTarget, xPrimitive3DSeq); 114 115 if(o_pVisibleTarget) 116 { 117 // test visibility. Primitive is visible when both tests are true (AND) 118 bool bVisible(true); 119 120 if(pVisibleLayerSet) 121 { 122 // test layer visibility 123 const E3dObject& rE3dObject = pViewContactOfE3d->GetE3dObject(); 124 const SdrLayerID aLayerID(rE3dObject.GetLayer()); 125 126 bVisible = pVisibleLayerSet->IsSet(aLayerID); 127 } 128 129 if(bVisible && bTestSelectedVisibility) 130 { 131 // test selected visibility (see 3D View's DrawMarkedObj implementation) 132 const E3dObject& rE3dObject = pViewContactOfE3d->GetE3dObject(); 133 134 bVisible = rE3dObject.GetSelected(); 135 } 136 137 if(bVisible && o_pVisibleTarget) 138 { 139 // add to visible target vector 140 drawinglayer::primitive3d::appendPrimitive3DSequenceToPrimitive3DSequence(*o_pVisibleTarget, xPrimitive3DSeq); 141 } 142 } 143 } 144 } 145 } 146 } 147 } // end of anonymous namespace 148 149 ////////////////////////////////////////////////////////////////////////////// 150 151 namespace sdr 152 { 153 namespace contact 154 { 155 // Create a Object-Specific ViewObjectContact, set ViewContact and 156 // ObjectContact. Always needs to return something. 157 ViewObjectContact& ViewContactOfE3dScene::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) 158 { 159 ViewObjectContact* pRetval = new ViewObjectContactOfE3dScene(rObjectContact, *this); 160 DBG_ASSERT(pRetval, "ViewContactOfE3dScene::CreateObjectSpecificViewObjectContact() failed (!)"); 161 162 return *pRetval; 163 } 164 165 ViewContactOfE3dScene::ViewContactOfE3dScene(E3dScene& rScene) 166 : ViewContactOfSdrObj(rScene), 167 maViewInformation3D(), 168 maObjectTransformation(), 169 maSdrSceneAttribute(), 170 maSdrLightingAttribute() 171 { 172 } 173 174 void ViewContactOfE3dScene::createViewInformation3D(const basegfx::B3DRange& rContentRange) 175 { 176 basegfx::B3DHomMatrix aTransformation; 177 basegfx::B3DHomMatrix aOrientation; 178 basegfx::B3DHomMatrix aProjection; 179 basegfx::B3DHomMatrix aDeviceToView; 180 181 // create transformation (scene as group's transformation) 182 // For historical reasons, the outmost scene's transformation is handles as part of the 183 // view transformation. This means that the BoundRect of the contained 3D Objects is 184 // without that transformation and makes it necessary to NOT add the first scene to the 185 // Primitive3DSequence of contained objects. 186 { 187 aTransformation = GetE3dScene().GetTransform(); 188 } 189 190 // create orientation (world to camera coordinate system) 191 { 192 // calculate orientation from VRP, VPN and VUV 193 const B3dCamera& rSceneCamera = GetE3dScene().GetCameraSet(); 194 const basegfx::B3DPoint aVRP(rSceneCamera.GetVRP()); 195 const basegfx::B3DVector aVPN(rSceneCamera.GetVRP()); 196 const basegfx::B3DVector aVUV(rSceneCamera.GetVUV()); 197 198 aOrientation.orientation(aVRP, aVPN, aVUV); 199 } 200 201 // create projection (camera coordinate system to relative 2d where X,Y and Z are [0.0 .. 1.0]) 202 { 203 const basegfx::B3DHomMatrix aWorldToCamera(aOrientation * aTransformation); 204 basegfx::B3DRange aCameraRange(rContentRange); 205 aCameraRange.transform(aWorldToCamera); 206 207 // remember Z-Values, but change orientation 208 const double fMinZ(-aCameraRange.getMaxZ()); 209 const double fMaxZ(-aCameraRange.getMinZ()); 210 211 // construct temorary matrix from world to device. Use unit values here to measure expansion 212 basegfx::B3DHomMatrix aWorldToDevice(aWorldToCamera); 213 const drawinglayer::attribute::SdrSceneAttribute& rSdrSceneAttribute = getSdrSceneAttribute(); 214 215 if(::com::sun::star::drawing::ProjectionMode_PERSPECTIVE == rSdrSceneAttribute.getProjectionMode()) 216 { 217 aWorldToDevice.frustum(-1.0, 1.0, -1.0, 1.0, fMinZ, fMaxZ); 218 } 219 else 220 { 221 aWorldToDevice.ortho(-1.0, 1.0, -1.0, 1.0, fMinZ, fMaxZ); 222 } 223 224 // create B3DRange in device. This will create the real used ranges 225 // in camera space. Do not use the Z-Values, though. 226 basegfx::B3DRange aDeviceRange(rContentRange); 227 aDeviceRange.transform(aWorldToDevice); 228 229 // set projection 230 if(::com::sun::star::drawing::ProjectionMode_PERSPECTIVE == rSdrSceneAttribute.getProjectionMode()) 231 { 232 aProjection.frustum( 233 aDeviceRange.getMinX(), aDeviceRange.getMaxX(), 234 aDeviceRange.getMinY(), aDeviceRange.getMaxY(), 235 fMinZ, fMaxZ); 236 } 237 else 238 { 239 aProjection.ortho( 240 aDeviceRange.getMinX(), aDeviceRange.getMaxX(), 241 aDeviceRange.getMinY(), aDeviceRange.getMaxY(), 242 fMinZ, fMaxZ); 243 } 244 } 245 246 // create device to view transform 247 { 248 // create standard deviceToView projection for geometry 249 // input is [-1.0 .. 1.0] in X,Y and Z. bring to [0.0 .. 1.0]. Also 250 // necessary to flip Y due to screen orientation 251 // Z is not needed, but will also be brought to [0.0 .. 1.0] 252 aDeviceToView.scale(0.5, -0.5, 0.5); 253 aDeviceToView.translate(0.5, 0.5, 0.5); 254 } 255 256 const uno::Sequence< beans::PropertyValue > aEmptyProperties; 257 maViewInformation3D = drawinglayer::geometry::ViewInformation3D( 258 aTransformation, aOrientation, aProjection, 259 aDeviceToView, 0.0, aEmptyProperties); 260 } 261 262 void ViewContactOfE3dScene::createObjectTransformation() 263 { 264 // create 2d Object Transformation from relative point in 2d scene to world 265 const Rectangle& rRectangle = GetE3dScene().GetSnapRect(); 266 267 maObjectTransformation.set(0, 0, rRectangle.getWidth()); 268 maObjectTransformation.set(1, 1, rRectangle.getHeight()); 269 maObjectTransformation.set(0, 2, rRectangle.Left()); 270 maObjectTransformation.set(1, 2, rRectangle.Top()); 271 } 272 273 void ViewContactOfE3dScene::createSdrSceneAttribute() 274 { 275 const SfxItemSet& rItemSet = GetE3dScene().GetMergedItemSet(); 276 maSdrSceneAttribute = drawinglayer::primitive2d::createNewSdrSceneAttribute(rItemSet); 277 } 278 279 void ViewContactOfE3dScene::createSdrLightingAttribute() 280 { 281 const SfxItemSet& rItemSet = GetE3dScene().GetMergedItemSet(); 282 maSdrLightingAttribute = drawinglayer::primitive2d::createNewSdrLightingAttribute(rItemSet); 283 } 284 285 drawinglayer::primitive2d::Primitive2DSequence ViewContactOfE3dScene::createScenePrimitive2DSequence( 286 const SetOfByte* pLayerVisibility) const 287 { 288 drawinglayer::primitive2d::Primitive2DSequence xRetval; 289 const sal_uInt32 nChildrenCount(GetObjectCount()); 290 291 if(nChildrenCount) 292 { 293 // create 3d scene primitive with visible content tested against rLayerVisibility 294 drawinglayer::primitive3d::Primitive3DSequence aAllSequence; 295 drawinglayer::primitive3d::Primitive3DSequence aVisibleSequence; 296 const bool bTestLayerVisibility(0 != pLayerVisibility); 297 const bool bTestSelectedVisibility(GetE3dScene().GetDrawOnlySelected()); 298 const bool bTestVisibility(bTestLayerVisibility || bTestSelectedVisibility); 299 300 // add children recursively. Do NOT start with (*this), this would create 301 // a 3D transformPrimitive for the start scene. While this is theoretically not 302 // a bad thing, for historical reasons the transformation of the outmost scene 303 // is seen as part of the ViewTransformation (see text in createViewInformation3D) 304 for(sal_uInt32 a(0L); a < nChildrenCount; a++) 305 { 306 createSubPrimitive3DVector( 307 GetViewContact(a), 308 aAllSequence, 309 bTestLayerVisibility ? &aVisibleSequence : 0, 310 bTestLayerVisibility ? pLayerVisibility : 0, 311 bTestSelectedVisibility); 312 } 313 314 const sal_uInt32 nAllSize(aAllSequence.hasElements() ? aAllSequence.getLength() : 0); 315 const sal_uInt32 nVisibleSize(aVisibleSequence.hasElements() ? aVisibleSequence.getLength() : 0); 316 317 if((bTestVisibility && nVisibleSize) || nAllSize) 318 { 319 // for getting the 3D range using getB3DRangeFromPrimitive3DSequence a ViewInformation3D 320 // needs to be given for evtl. decompositions. At the same time createViewInformation3D 321 // currently is based on creating the target-ViewInformation3D using a given range. To 322 // get the true range, use a neutral ViewInformation3D here. This leaves all matrices 323 // on identity and the time on 0.0. 324 const uno::Sequence< beans::PropertyValue > aEmptyProperties; 325 const drawinglayer::geometry::ViewInformation3D aNeutralViewInformation3D(aEmptyProperties); 326 const basegfx::B3DRange aContentRange( 327 drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(aAllSequence, aNeutralViewInformation3D)); 328 329 // create 2d primitive 3dscene with generated sub-list from collector 330 const drawinglayer::primitive2d::Primitive2DReference xReference( 331 new drawinglayer::primitive2d::ScenePrimitive2D( 332 bTestVisibility ? aVisibleSequence : aAllSequence, 333 getSdrSceneAttribute(), 334 getSdrLightingAttribute(), 335 getObjectTransformation(), 336 getViewInformation3D(aContentRange))); 337 338 xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); 339 } 340 } 341 342 // always append an invisible outline for the cases where no visible content exists 343 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval, 344 drawinglayer::primitive2d::createHiddenGeometryPrimitives2D( 345 false, getObjectTransformation())); 346 347 return xRetval; 348 } 349 350 drawinglayer::primitive2d::Primitive2DSequence ViewContactOfE3dScene::createViewIndependentPrimitive2DSequence() const 351 { 352 drawinglayer::primitive2d::Primitive2DSequence xRetval; 353 354 if(GetObjectCount()) 355 { 356 // create a default ScenePrimitive2D (without visibility test of members) 357 xRetval = createScenePrimitive2DSequence(0); 358 } 359 360 return xRetval; 361 } 362 363 void ViewContactOfE3dScene::ActionChanged() 364 { 365 // call parent 366 ViewContactOfSdrObj::ActionChanged(); 367 368 // mark locally cached values as invalid 369 maViewInformation3D = drawinglayer::geometry::ViewInformation3D(); 370 maObjectTransformation.identity(); 371 maSdrSceneAttribute = drawinglayer::attribute::SdrSceneAttribute(); 372 maSdrLightingAttribute = drawinglayer::attribute::SdrLightingAttribute(); 373 } 374 375 const drawinglayer::geometry::ViewInformation3D& ViewContactOfE3dScene::getViewInformation3D() const 376 { 377 if(maViewInformation3D.isDefault()) 378 { 379 // this version will create the content range on demand locally and thus is less 380 // performant than the other one. Since the information is buffered the planned 381 // behaviour is that the version with the given range is used initially. 382 basegfx::B3DRange aContentRange(getAllContentRange3D()); 383 384 if(aContentRange.isEmpty()) 385 { 386 // empty scene, no 3d action should be necessary. Prepare some 387 // fallback size 388 OSL_ENSURE(false, "No need to get ViewInformation3D from an empty scene (!)"); 389 aContentRange.expand(basegfx::B3DPoint(-100.0, -100.0, -100.0)); 390 aContentRange.expand(basegfx::B3DPoint( 100.0, 100.0, 100.0)); 391 } 392 393 const_cast < ViewContactOfE3dScene* >(this)->createViewInformation3D(aContentRange); 394 } 395 396 return maViewInformation3D; 397 } 398 399 const drawinglayer::geometry::ViewInformation3D& ViewContactOfE3dScene::getViewInformation3D(const basegfx::B3DRange& rContentRange) const 400 { 401 if(maViewInformation3D.isDefault()) 402 { 403 const_cast < ViewContactOfE3dScene* >(this)->createViewInformation3D(rContentRange); 404 } 405 406 return maViewInformation3D; 407 } 408 409 const basegfx::B2DHomMatrix& ViewContactOfE3dScene::getObjectTransformation() const 410 { 411 if(maObjectTransformation.isIdentity()) 412 { 413 const_cast < ViewContactOfE3dScene* >(this)->createObjectTransformation(); 414 } 415 416 return maObjectTransformation; 417 } 418 419 const drawinglayer::attribute::SdrSceneAttribute& ViewContactOfE3dScene::getSdrSceneAttribute() const 420 { 421 if(maSdrSceneAttribute.isDefault()) 422 { 423 const_cast < ViewContactOfE3dScene* >(this)->createSdrSceneAttribute(); 424 } 425 426 return maSdrSceneAttribute; 427 } 428 429 const drawinglayer::attribute::SdrLightingAttribute& ViewContactOfE3dScene::getSdrLightingAttribute() const 430 { 431 if(maSdrLightingAttribute.isDefault()) 432 { 433 const_cast < ViewContactOfE3dScene* >(this)->createSdrLightingAttribute(); 434 } 435 436 return maSdrLightingAttribute; 437 } 438 439 drawinglayer::primitive3d::Primitive3DSequence ViewContactOfE3dScene::getAllPrimitive3DSequence() const 440 { 441 drawinglayer::primitive3d::Primitive3DSequence aAllPrimitive3DSequence; 442 const sal_uInt32 nChildrenCount(GetObjectCount()); 443 444 // add children recursively. Do NOT start with (*this), this would create 445 // a 3D transformPrimitive for the start scene. While this is theoretically not 446 // a bad thing, for historical reasons the transformation of the outmost scene 447 // is seen as part of the ViewTransformation (see text in createViewInformation3D) 448 for(sal_uInt32 a(0L); a < nChildrenCount; a++) 449 { 450 createSubPrimitive3DVector(GetViewContact(a), aAllPrimitive3DSequence, 0, 0, false); 451 } 452 453 return aAllPrimitive3DSequence; 454 } 455 456 basegfx::B3DRange ViewContactOfE3dScene::getAllContentRange3D() const 457 { 458 const drawinglayer::primitive3d::Primitive3DSequence xAllSequence(getAllPrimitive3DSequence()); 459 basegfx::B3DRange aAllContentRange3D; 460 461 if(xAllSequence.hasElements()) 462 { 463 // for getting the 3D range using getB3DRangeFromPrimitive3DSequence a ViewInformation3D 464 // needs to be given for evtl. decompositions. Use a neutral ViewInformation3D here. This 465 // leaves all matrices on identity and the time on 0.0. 466 const uno::Sequence< beans::PropertyValue > aEmptyProperties; 467 const drawinglayer::geometry::ViewInformation3D aNeutralViewInformation3D(aEmptyProperties); 468 469 aAllContentRange3D = drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(xAllSequence, aNeutralViewInformation3D); 470 } 471 472 return aAllContentRange3D; 473 } 474 } // end of namespace contact 475 } // end of namespace sdr 476 477 ////////////////////////////////////////////////////////////////////////////// 478 // eof 479