1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2013 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 PCZSceneManager.cpp - description 28 ----------------------------------------------------------------------------- 29 begin : Mon Feb 19 2007 30 author : Eric Cha 31 email : ericc@xenopi.com 32 ----------------------------------------------------------------------------- 33 */ 34 35 #include "OgrePCZSceneManager.h" 36 #include "OgrePCZSceneQuery.h" 37 #include "OgrePCZone.h" 38 #include "OgrePCZCamera.h" 39 #include "OgrePCZLight.h" 40 #include "OgrePortal.h" 41 #include "OgreSceneNode.h" 42 #include "OgreMesh.h" 43 #include "OgreSubMesh.h" 44 #include "OgreLogManager.h" 45 #include <OgreRenderSystem.h> 46 #include "OgreRoot.h" 47 48 49 namespace Ogre 50 { PCZSceneManager(const String & name)51 PCZSceneManager::PCZSceneManager(const String& name) : 52 SceneManager(name), 53 mDefaultZoneTypeName("ZoneType_Default"), 54 mDefaultZoneFileName("none"), 55 mLastActiveCamera(0), 56 mDefaultZone(0), 57 mShowPortals(false), 58 mZoneFactoryManager(0), 59 mActiveCameraZone(0) 60 { } 61 ~PCZSceneManager()62 PCZSceneManager::~PCZSceneManager() 63 { 64 // we don't delete the root scene node here because the 65 // base scene manager class does that. 66 67 // delete ALL portals 68 Portal * p; 69 PortalList::iterator i = mPortals.begin(); 70 for (i = mPortals.begin(); i != mPortals.end(); i++) 71 { 72 p = *i; 73 OGRE_DELETE p; 74 } 75 mPortals.clear(); 76 77 // delete all the zones 78 for (ZoneMap::iterator j = mZones.begin(); 79 j != mZones.end(); ++j) 80 { 81 OGRE_DELETE j->second; 82 } 83 mZones.clear(); 84 mDefaultZone = 0; 85 } 86 getTypeName(void) const87 const String& PCZSceneManager::getTypeName(void) const 88 { 89 return PCZSceneManagerFactory::FACTORY_TYPE_NAME; 90 } 91 init(const String & defaultZoneTypeName,const String & filename)92 void PCZSceneManager::init( const String &defaultZoneTypeName, 93 const String &filename) 94 { 95 96 // delete ALL portals 97 Portal * p; 98 PortalList::iterator i = mPortals.begin(); 99 for (i = mPortals.begin(); i != mPortals.end(); i++) 100 { 101 p = *i; 102 OGRE_DELETE p; 103 } 104 mPortals.clear(); 105 106 // delete all the zones 107 for (ZoneMap::iterator j = mZones.begin(); 108 j != mZones.end(); ++j) 109 { 110 OGRE_DELETE j->second; 111 } 112 mZones.clear(); 113 114 mFrameCount = 0; 115 116 mDefaultZoneTypeName = defaultZoneTypeName; 117 mDefaultZoneFileName = filename; 118 119 // create a new default zone 120 mZoneFactoryManager = PCZoneFactoryManager::getSingletonPtr(); 121 mDefaultZone = createZoneFromFile(mDefaultZoneTypeName, "Default_Zone", (PCZSceneNode*)getRootSceneNode(), mDefaultZoneFileName); 122 } 123 124 // Create a portal instance createPortal(const String & name,PortalBase::PORTAL_TYPE type)125 Portal* PCZSceneManager::createPortal(const String& name, PortalBase::PORTAL_TYPE type) 126 { 127 Portal* newPortal = OGRE_NEW Portal(name, type); 128 newPortal->_notifyCreator(Root::getSingleton().getMovableObjectFactory("Portal")); 129 newPortal->_notifyManager(this); 130 mPortals.push_front(newPortal); 131 return newPortal; 132 } 133 134 // delete a portal instance by pointer destroyPortal(Portal * p)135 void PCZSceneManager::destroyPortal(Portal * p) 136 { 137 // remove the portal from it's target portal 138 Portal * targetPortal = p->getTargetPortal(); 139 if (targetPortal) 140 { 141 targetPortal->setTargetPortal(0); // the targetPortal will still have targetZone value, but targetPortal will be invalid 142 } 143 // remove the Portal from it's home zone 144 PCZone * homeZone = p->getCurrentHomeZone(); 145 if (homeZone) 146 { 147 // inform zone of portal change. Do here since PCZone is abstract 148 homeZone->setPortalsUpdated(true); 149 homeZone->_removePortal(p); 150 } 151 152 // remove the portal from the master portal list 153 PortalList::iterator it = std::find( mPortals.begin(), mPortals.end(), p ); 154 if (it != mPortals.end()) 155 { 156 mPortals.erase(it); 157 } 158 // delete the portal instance 159 OGRE_DELETE p; 160 } 161 162 // delete a portal instance by pointer destroyPortal(const String & portalName)163 void PCZSceneManager::destroyPortal(const String & portalName) 164 { 165 // find the portal from the master portal list 166 Portal * p; 167 Portal * thePortal = 0; 168 PortalList::iterator it = mPortals.begin(); 169 while (it != mPortals.end()) 170 { 171 p = *it; 172 if (p->getName() == portalName) 173 { 174 thePortal = p; 175 // erase entry in the master list 176 mPortals.erase(it); 177 break; 178 } 179 it++; 180 } 181 if (thePortal) 182 { 183 // remove the portal from it's target portal 184 Portal * targetPortal = thePortal->getTargetPortal(); 185 if (targetPortal) 186 { 187 targetPortal->setTargetPortal(0); // the targetPortal will still have targetZone value, but targetPortal will be invalid 188 } 189 // remove the Portal from it's home zone 190 PCZone * homeZone = thePortal->getCurrentHomeZone(); 191 if (homeZone) 192 { 193 // inform zone of portal change 194 homeZone->setPortalsUpdated(true); 195 homeZone->_removePortal(thePortal); 196 } 197 198 // delete the portal instance 199 OGRE_DELETE thePortal; 200 } 201 } 202 203 /** Create a new anti portal instance */ createAntiPortal(const String & name,PortalBase::PORTAL_TYPE type)204 AntiPortal* PCZSceneManager::createAntiPortal(const String& name, PortalBase::PORTAL_TYPE type) 205 { 206 AntiPortal* newAntiPortal = OGRE_NEW AntiPortal(name, type); 207 newAntiPortal->_notifyCreator(Root::getSingleton().getMovableObjectFactory("AntiPortal")); 208 newAntiPortal->_notifyManager(this); 209 mAntiPortals.push_front(newAntiPortal); 210 return newAntiPortal; 211 } 212 213 /** Delete a anti portal instance by pointer */ destroyAntiPortal(AntiPortal * p)214 void PCZSceneManager::destroyAntiPortal(AntiPortal * p) 215 { 216 // remove the Portal from it's home zone 217 PCZone* homeZone = p->getCurrentHomeZone(); 218 if (homeZone) 219 { 220 // inform zone of portal change. Do here since PCZone is abstract 221 homeZone->setPortalsUpdated(true); 222 homeZone->_removeAntiPortal(p); 223 } 224 225 // remove the portal from the master portal list 226 AntiPortalList::iterator it = std::find(mAntiPortals.begin(), mAntiPortals.end(), p); 227 if (it != mAntiPortals.end()) mAntiPortals.erase(it); 228 229 // delete the portal instance 230 OGRE_DELETE p; 231 } 232 233 /** Delete a anti portal instance by name */ destroyAntiPortal(const String & portalName)234 void PCZSceneManager::destroyAntiPortal(const String& portalName) 235 { 236 // find the anti portal from the master portal list 237 AntiPortal* p; 238 AntiPortal* thePortal = 0; 239 AntiPortalList::iterator it = mAntiPortals.begin(); 240 while (it != mAntiPortals.end()) 241 { 242 p = *it; 243 if (p->getName() == portalName) 244 { 245 thePortal = p; 246 // erase entry in the master list 247 mAntiPortals.erase(it); 248 break; 249 } 250 it++; 251 } 252 if (thePortal) 253 { 254 // remove the Portal from it's home zone 255 PCZone* homeZone = thePortal->getCurrentHomeZone(); 256 if (homeZone) 257 { 258 // inform zone of portal change 259 homeZone->setPortalsUpdated(true); 260 homeZone->_removeAntiPortal(thePortal); 261 } 262 263 // delete the portal instance 264 OGRE_DELETE thePortal; 265 } 266 } 267 268 /** Create a zone from a file (type of file 269 * depends on the zone type 270 * ZoneType_Default uses an Ogre Model (.mesh) file 271 * ZoneType_Octree uses an Ogre Model (.mesh) file 272 * ZoneType_Terrain uses a Terrain.CFG file 273 */ createZoneFromFile(const String & zoneTypeName,const String & zoneName,PCZSceneNode * parentNode,const String & filename)274 PCZone * PCZSceneManager::createZoneFromFile(const String &zoneTypeName, 275 const String &zoneName, 276 PCZSceneNode * parentNode, 277 const String &filename) 278 { 279 PCZone * newZone; 280 281 // create a new default zone 282 newZone = mZoneFactoryManager->createPCZone(this, zoneTypeName, zoneName); 283 // add to the global list of zones 284 mZones[newZone->getName()] = newZone; 285 if (filename != "none") 286 { 287 // set the zone geometry 288 newZone->setZoneGeometry(filename, parentNode); 289 } 290 291 return newZone; 292 } 293 294 /* Get a zone by name */ getZoneByName(const String & zoneName)295 PCZone * PCZSceneManager::getZoneByName(const String & zoneName) 296 { 297 ZoneMap::iterator i; 298 PCZone * zone; 299 i = mZones.find(zoneName); 300 if (i != mZones.end()) 301 { 302 zone = i->second; 303 return zone; 304 } 305 return 0; // couldn't find the zone 306 } 307 setZoneGeometry(const String & zoneName,PCZSceneNode * parentNode,const String & filename)308 void PCZSceneManager::setZoneGeometry(const String & zoneName, 309 PCZSceneNode * parentNode, 310 const String & filename) 311 { 312 ZoneMap::iterator i; 313 PCZone * zone; 314 i = mZones.find(zoneName); 315 if (i != mZones.end()) 316 { 317 zone = i->second; 318 zone->setZoneGeometry( filename, parentNode ); 319 return; 320 } 321 322 } 323 createSceneNodeImpl(void)324 SceneNode* PCZSceneManager::createSceneNodeImpl(void) 325 { 326 return OGRE_NEW PCZSceneNode(this); 327 } 328 createSceneNodeImpl(const String & name)329 SceneNode* PCZSceneManager::createSceneNodeImpl(const String& name) 330 { 331 return OGRE_NEW PCZSceneNode(this, name); 332 } 333 createSceneNode(void)334 SceneNode * PCZSceneManager::createSceneNode( void ) 335 { 336 SceneNode * on = createSceneNodeImpl(); 337 mSceneNodes[ on->getName() ] = on; 338 // create any zone-specific data necessary 339 createZoneSpecificNodeData((PCZSceneNode*)on); 340 // return pointer to the node 341 return on; 342 } 343 createSceneNode(const String & name)344 SceneNode * PCZSceneManager::createSceneNode( const String &name ) 345 { 346 // Check name not used 347 if (mSceneNodes.find(name) != mSceneNodes.end()) 348 { 349 OGRE_EXCEPT( 350 Exception::ERR_DUPLICATE_ITEM, 351 "A scene node with the name " + name + " already exists", 352 "PCZSceneManager::createSceneNode" ); 353 } 354 SceneNode * on = createSceneNodeImpl( name ); 355 mSceneNodes[ on->getName() ] = on; 356 // create any zone-specific data necessary 357 createZoneSpecificNodeData((PCZSceneNode*)on); 358 // return pointer to the node 359 return on; 360 } 361 362 // Create a camera for the scene createCamera(const String & name)363 Camera * PCZSceneManager::createCamera( const String &name ) 364 { 365 // Check name not used 366 if (mCameras.find(name) != mCameras.end()) 367 { 368 OGRE_EXCEPT( 369 Exception::ERR_DUPLICATE_ITEM, 370 "A camera with the name " + name + " already exists", 371 "PCZSceneManager::createCamera" ); 372 } 373 374 Camera * c = OGRE_NEW PCZCamera( name, this ); 375 mCameras.insert( CameraList::value_type( name, c ) ); 376 377 // create visible bounds aab map entry 378 mCamVisibleObjectsMap[c] = VisibleObjectsBoundsInfo(); 379 380 // tell all the zones about the new camera 381 ZoneMap::iterator i; 382 PCZone * zone; 383 for (i = mZones.begin(); i != mZones.end(); i++) 384 { 385 zone = i->second; 386 zone->notifyCameraCreated( c ); 387 } 388 389 return c; 390 } 391 392 // Destroy a Scene Node by name. destroySceneNode(const String & name)393 void PCZSceneManager::destroySceneNode( const String &name ) 394 { 395 SceneNode * on = ( getSceneNode( name ) ); 396 397 if ( on != 0 ) 398 { 399 // destroy the node 400 destroySceneNode( on ); 401 } 402 } 403 404 // Destroy a scene node destroySceneNode(SceneNode * sn)405 void PCZSceneManager::destroySceneNode(SceneNode* sn) 406 { 407 if ( sn != 0 ) 408 { 409 // remove references to the node from zones 410 removeSceneNode( sn ); 411 412 // destroy the node 413 SceneManager::destroySceneNode( sn->getName() ); 414 } 415 } 416 417 //----------------------------------------------------------------------- clearScene(void)418 void PCZSceneManager::clearScene(void) 419 { 420 destroyAllStaticGeometry(); 421 destroyAllMovableObjects(); 422 423 // Clear root node of all children 424 getRootSceneNode()->removeAllChildren(); 425 getRootSceneNode()->detachAllObjects(); 426 427 // Delete all SceneNodes, except root that is 428 for (SceneNodeList::iterator i = mSceneNodes.begin(); 429 i != mSceneNodes.end(); ++i) 430 { 431 OGRE_DELETE i->second; 432 } 433 mSceneNodes.clear(); 434 mAutoTrackingSceneNodes.clear(); 435 436 // delete all the zones 437 for (ZoneMap::iterator j = mZones.begin(); 438 j != mZones.end(); ++j) 439 { 440 OGRE_DELETE j->second; 441 } 442 mZones.clear(); 443 mDefaultZone = 0; 444 445 // Clear animations 446 destroyAllAnimations(); 447 448 // Remove sky nodes since they've been deleted 449 mSkyBoxNode = mSkyPlaneNode = mSkyDomeNode = 0; 450 mSkyBoxEnabled = mSkyPlaneEnabled = mSkyDomeEnabled = false; 451 452 // Clear render queue, empty completely 453 if (mRenderQueue) 454 mRenderQueue->clear(true); 455 456 // re-initialize 457 init(mDefaultZoneTypeName, mDefaultZoneFileName); 458 } 459 460 /** Overridden from SceneManager */ setWorldGeometryRenderQueue(uint8 qid)461 void PCZSceneManager::setWorldGeometryRenderQueue(uint8 qid) 462 { 463 // tell all the zones about the new WorldGeometryRenderQueue 464 ZoneMap::iterator i; 465 PCZone * zone; 466 for (i = mZones.begin(); i != mZones.end(); i++) 467 { 468 zone = i->second; 469 zone->notifyWorldGeometryRenderQueue( qid ); 470 } 471 // call the regular scene manager version 472 SceneManager::setWorldGeometryRenderQueue(qid); 473 474 } 475 /** Overridden from SceneManager */ _renderScene(Camera * cam,Viewport * vp,bool includeOverlays)476 void PCZSceneManager::_renderScene(Camera* cam, Viewport *vp, bool includeOverlays) 477 { 478 // notify all the zones that a scene render is starting 479 ZoneMap::iterator i; 480 PCZone * zone; 481 for (i = mZones.begin(); i != mZones.end(); i++) 482 { 483 zone = i->second; 484 zone->notifyBeginRenderScene(); 485 } 486 487 // do the regular _renderScene 488 SceneManager::_renderScene(cam, vp, includeOverlays); 489 } 490 491 /* enable/disable sky rendering */ enableSky(bool onoff)492 void PCZSceneManager::enableSky(bool onoff) 493 { 494 if (mSkyBoxNode) 495 { 496 mSkyBoxEnabled = onoff; 497 } 498 else if (mSkyDomeNode) 499 { 500 mSkyDomeEnabled = onoff; 501 } 502 else if (mSkyPlaneNode) 503 { 504 mSkyPlaneEnabled = onoff; 505 } 506 } 507 508 /* Set the zone which contains the sky node */ setSkyZone(PCZone * zone)509 void PCZSceneManager::setSkyZone(PCZone * zone) 510 { 511 if (zone == 0) 512 { 513 // if no zone specified, use default zone 514 zone = mDefaultZone; 515 } 516 if (mSkyBoxNode) 517 { 518 ((PCZSceneNode*)mSkyBoxNode)->setHomeZone(zone); 519 ((PCZSceneNode*)mSkyBoxNode)->anchorToHomeZone(zone); 520 zone->setHasSky(true); 521 } 522 if (mSkyDomeNode) 523 { 524 ((PCZSceneNode*)mSkyDomeNode)->setHomeZone(zone); 525 ((PCZSceneNode*)mSkyDomeNode)->anchorToHomeZone(zone); 526 zone->setHasSky(true); 527 } 528 if (mSkyPlaneNode) 529 { 530 ((PCZSceneNode*)mSkyPlaneNode)->setHomeZone(zone); 531 ((PCZSceneNode*)mSkyPlaneNode)->anchorToHomeZone(zone); 532 zone->setHasSky(true); 533 } 534 535 } 536 537 //----------------------------------------------------------------------- 538 // THIS IS THE MAIN LOOP OF THE MANAGER 539 //----------------------------------------------------------------------- 540 /* _updateSceneGraph does several things now: 541 1) standard scene graph update (transform all nodes in the node tree) 542 2) update the spatial data for all zones (& portals in the zones) 543 3) Update the PCZSNMap entry for every scene node 544 */ _updateSceneGraph(Camera * cam)545 void PCZSceneManager::_updateSceneGraph( Camera * cam ) 546 { 547 // First do the standard scene graph update 548 SceneManager::_updateSceneGraph( cam ); 549 // check for portal zone-related changes (portals intersecting other portals) 550 _updatePortalZoneData(); 551 // mark nodes dirty base on portals that changed. 552 _dirtyNodeByMovingPortals(); 553 // update all scene nodes 554 _updatePCZSceneNodes(); 555 // calculate zones affected by each light 556 _calcZonesAffectedByLights(cam); 557 // clear update flags at end so user triggered updated are 558 // not cleared prematurely 559 _clearAllZonesPortalUpdateFlag(); 560 } 561 562 /** Update the zone data for every zone portal in the scene */ 563 _updatePortalZoneData(void)564 void PCZSceneManager::_updatePortalZoneData(void) 565 { 566 PCZone * zone; 567 ZoneMap::iterator zit = mZones.begin(); 568 569 while ( zit != mZones.end() ) 570 { 571 zone = zit->second; 572 // this callchecks for portal zone changes & applies zone data changes as necessary 573 zone->updatePortalsZoneData(); 574 // proceed to next zone in the list 575 ++zit; 576 } 577 } 578 579 /** Mark nodes dirty for every zone with moving portal in the scene */ _dirtyNodeByMovingPortals(void)580 void PCZSceneManager::_dirtyNodeByMovingPortals(void) 581 { 582 PCZone * zone; 583 ZoneMap::iterator zit = mZones.begin(); 584 585 while ( zit != mZones.end() ) 586 { 587 zone = zit->second; 588 // this call mark nodes dirty base on moving portals 589 zone->dirtyNodeByMovingPortals(); 590 // proceed to next zone in the list 591 ++zit; 592 } 593 } 594 595 /* Update all PCZSceneNodes. 596 */ _updatePCZSceneNodes(void)597 void PCZSceneManager::_updatePCZSceneNodes(void) 598 { 599 SceneNodeList::iterator it = mSceneNodes.begin(); 600 PCZSceneNode * pczsn; 601 602 while ( it != mSceneNodes.end() ) 603 { 604 pczsn = (PCZSceneNode*)(it->second); 605 if (pczsn->isMoved() && pczsn->isEnabled()) 606 { 607 // Update a single entry 608 _updatePCZSceneNode(pczsn); 609 610 // reset moved state. 611 pczsn->setMoved(false); 612 } 613 // proceed to next entry in the list 614 ++it; 615 } 616 } 617 618 /* 619 */ _calcZonesAffectedByLights(Camera * cam)620 void PCZSceneManager::_calcZonesAffectedByLights(Camera * cam) 621 { 622 MovableObjectCollection* lights = 623 getMovableObjectCollection(PCZLightFactory::FACTORY_TYPE_NAME); 624 { 625 OGRE_LOCK_MUTEX(lights->mutex); 626 627 MovableObjectIterator it(lights->map.begin(), lights->map.end()); 628 629 while(it.hasMoreElements()) 630 { 631 PCZLight* l = static_cast<PCZLight*>(it.getNext()); 632 if(l->getNeedsUpdate()) 633 { 634 // only update if necessary 635 l->updateZones(((PCZSceneNode*)(cam->getParentSceneNode()))->getHomeZone(), mFrameCount); 636 } 637 // clear update flag 638 l->clearNeedsUpdate(); 639 } 640 } 641 } 642 643 //----------------------------------------------------------------------- 644 // Update all the zone info for a given node. This function 645 // makes sure the home zone of the node is correct, and references 646 // to any zones it is visiting are added and a reference to the 647 // node is added to the visitor lists of any zone it is visiting. 648 // _updatePCZSceneNode(PCZSceneNode * pczsn)649 void PCZSceneManager::_updatePCZSceneNode( PCZSceneNode * pczsn ) 650 { 651 // Skip if root Zone has been destroyed (shutdown conditions) 652 if (!mDefaultZone) 653 return; 654 655 // Skip if the node is the sceneroot node 656 if (pczsn == getRootSceneNode()) 657 return; 658 659 // clear all references to visiting zones 660 pczsn->clearNodeFromVisitedZones(); 661 662 // Find the current home zone of the node associated with the pczsn entry. 663 _updateHomeZone( pczsn, false ); 664 665 /* The following function does the following: 666 * 1) Check all portals in the home zone - if the node is touching the portal 667 * then add the node to the connected zone as a visitor 668 * 2) Recurse into visited zones in case the node spans several zones 669 */ 670 // (recursively) check each portal of home zone to see if the node is touching 671 if (pczsn->getHomeZone() && 672 pczsn->allowedToVisit() == true) 673 { 674 pczsn->getHomeZone()->_checkNodeAgainstPortals(pczsn, 0); 675 } 676 677 // update zone-specific data for the node for any zones that require it 678 pczsn->updateZoneData(); 679 } 680 681 /** Removes all references to the node from every zone in the scene. 682 */ removeSceneNode(SceneNode * sn)683 void PCZSceneManager::removeSceneNode( SceneNode * sn ) 684 { 685 // Skip if mDefaultZone has been destroyed (shutdown conditions) 686 if (!mDefaultZone) 687 return; 688 689 PCZSceneNode * pczsn = (PCZSceneNode*)sn; 690 691 // clear all references to the node in visited zones 692 pczsn->clearNodeFromVisitedZones(); 693 694 // tell the node it's not in a zone 695 pczsn->setHomeZone(0); 696 } 697 698 // Set the home zone for a node addPCZSceneNode(PCZSceneNode * sn,PCZone * homeZone)699 void PCZSceneManager::addPCZSceneNode(PCZSceneNode * sn, PCZone * homeZone) 700 { 701 // set the home zone 702 sn->setHomeZone(homeZone); 703 // add the node 704 homeZone->_addNode(sn); 705 } 706 707 //----------------------------------------------------------------------- 708 /* Create a zone with the given name and parent zone */ createZone(const String & zoneType,const String & instanceName)709 PCZone * PCZSceneManager::createZone(const String& zoneType, const String& instanceName) 710 { 711 if (mZones.find(instanceName) != mZones.end()) 712 { 713 OGRE_EXCEPT( 714 Exception::ERR_DUPLICATE_ITEM, 715 "A zone with the name " + instanceName + " already exists", 716 "PCZSceneManager::createZone" ); 717 } 718 PCZone * newZone = mZoneFactoryManager->createPCZone(this, zoneType, instanceName); 719 if (newZone) 720 { 721 // add to the global list of zones 722 mZones[instanceName] = newZone; 723 724 if (newZone->requiresZoneSpecificNodeData()) 725 { 726 createZoneSpecificNodeData(newZone); 727 } 728 } 729 return newZone; 730 } 731 732 /* destroy an existing zone within the scene */ 733 /* if destroySceneNodes is true, then all nodes which have the destroyed 734 zone as their homezone are desroyed too. If destroySceneNodes is false 735 then all scene nodes which have the zone as their homezone will have 736 their homezone pointer set to 0, which will allow them to be re-assigned 737 either by the user or via the automatic re-assignment routine */ destroyZone(PCZone * zone,bool destroySceneNodes)738 void PCZSceneManager::destroyZone(PCZone* zone, bool destroySceneNodes) 739 { 740 // need to remove this zone from all lights affected zones list, 741 // otherwise next frame _calcZonesAffectedByLights will call PCZLight::getNeedsUpdate() 742 // which will try to access the zone pointer and will cause an access violation 743 MovableObjectCollection* lights = 744 getMovableObjectCollection(PCZLightFactory::FACTORY_TYPE_NAME); 745 { 746 OGRE_LOCK_MUTEX(lights->mutex); // Is locking necessary in destroyZone? I don't know.. 747 748 MovableObjectIterator it(lights->map.begin(), lights->map.end()); 749 750 while(it.hasMoreElements()) 751 { 752 PCZLight* l = static_cast<PCZLight*>(it.getNext()); 753 if(l) 754 { 755 // no need to check, this function does that anyway. if exists, is erased. 756 l->removeZoneFromAffectedZonesList(zone); 757 } 758 } 759 } 760 // if not destroying scene nodes, then make sure any nodes who have 761 // this zone as homezone are set to have 0 for a homezone 762 for (SceneNodeList::iterator i = mSceneNodes.begin(); 763 i != mSceneNodes.end(); ++i) 764 { 765 PCZSceneNode * pczsn = (PCZSceneNode*)(i->second); 766 if (!destroySceneNodes) 767 { 768 if (pczsn->getHomeZone() == zone) 769 { 770 pczsn->setHomeZone(0); 771 } 772 } 773 // reset all node visitor lists 774 // note, it might be more efficient to only do this to nodes which 775 // are actually visiting the zone being destroyed, but visitor lists 776 // get cleared every frame anyway, so it's not THAT big a deal. 777 pczsn->clearNodeFromVisitedZones(); 778 } 779 780 ZoneMap::iterator it; 781 it = mZones.find(zone->getName()); 782 if (it != mZones.end()) 783 { 784 mZones.erase(zone->getName()); 785 } 786 OGRE_DELETE zone; 787 } 788 789 /* The following function checks if a node has left it's current home zone. 790 * This is done by checking each portal in the zone. If the node has crossed 791 * the portal, then the current zone is no longer the home zone of the node. The 792 * function then recurses into the connected zones. Once a zone is found where 793 * the node does NOT cross out through a portal, that zone is the new home zone. 794 * When this function is done, the node should have the correct home zone already 795 * set. A pointer is returned to this zone as well. 796 * 797 * NOTE: If the node does not have a home zone when this function is called on it, 798 * the function will do its best to find the proper zone for the node using 799 * bounding box volume testing. This CAN fail to find the correct zone in 800 * some scenarios, so it is best for the user to EXPLICITLY set the home 801 * zone of the node when the node is added to the scene using 802 * PCZSceneNode::setHomeZone() 803 */ _updateHomeZone(PCZSceneNode * pczsn,bool allowBackTouches)804 void PCZSceneManager::_updateHomeZone( PCZSceneNode * pczsn, bool allowBackTouches ) 805 { 806 // Skip if root PCZoneTree has been destroyed (shutdown conditions) 807 if (!mDefaultZone) 808 return; 809 810 PCZone * startzone; 811 PCZone * newHomeZone; 812 813 // start with current home zone of the node 814 startzone = pczsn->getHomeZone(); 815 816 if (startzone) 817 { 818 if (!pczsn->isAnchored()) 819 { 820 newHomeZone = startzone->updateNodeHomeZone(pczsn, false); 821 } 822 else 823 { 824 newHomeZone = startzone; 825 } 826 827 if (newHomeZone != startzone) 828 { 829 // add the node to the home zone 830 newHomeZone->_addNode(pczsn); 831 } 832 } 833 else 834 { 835 // the node hasn't had it's home zone set yet, so do our best to 836 // find the home zone using volume testing. 837 Vector3 nodeCenter = pczsn->_getDerivedPosition(); 838 PCZone * bestZone = findZoneForPoint(nodeCenter); 839 // set the best zone as the node's home zone 840 pczsn->setHomeZone(bestZone); 841 // add the node to the zone 842 bestZone->_addNode(pczsn); 843 } 844 845 return; 846 847 } 848 849 /* Find the best (smallest) zone that contains a point 850 */ findZoneForPoint(Vector3 & point)851 PCZone * PCZSceneManager::findZoneForPoint(Vector3 & point) 852 { 853 PCZone * zone; 854 PCZone * bestZone = mDefaultZone; 855 Real bestVolume = Ogre::Math::POS_INFINITY; 856 857 ZoneMap::iterator zit = mZones.begin(); 858 859 while ( zit != mZones.end() ) 860 { 861 zone = zit->second; 862 AxisAlignedBox aabb; 863 zone->getAABB(aabb); 864 SceneNode * enclosureNode = zone->getEnclosureNode(); 865 if (enclosureNode != 0) 866 { 867 // since this is the "local" AABB, add in world translation of the enclosure node 868 aabb.setMinimum(aabb.getMinimum() + enclosureNode->_getDerivedPosition()); 869 aabb.setMaximum(aabb.getMaximum() + enclosureNode->_getDerivedPosition()); 870 } 871 if (aabb.contains(point)) 872 { 873 if (aabb.volume() < bestVolume) 874 { 875 // this zone is "smaller" than the current best zone, so make it 876 // the new best zone 877 bestZone = zone; 878 bestVolume = aabb.volume(); 879 } 880 } 881 // proceed to next zone in the list 882 ++zit; 883 } 884 return bestZone; 885 } 886 887 // create any zone-specific data necessary for all zones for the given node createZoneSpecificNodeData(PCZSceneNode * node)888 void PCZSceneManager::createZoneSpecificNodeData(PCZSceneNode * node) 889 { 890 ZoneMap::iterator i; 891 PCZone * zone; 892 for (i = mZones.begin(); i != mZones.end(); i++) 893 { 894 zone = i->second; 895 if (zone->requiresZoneSpecificNodeData()) 896 { 897 zone->createNodeZoneData(node); 898 } 899 } 900 } 901 902 // create any zone-specific data necessary for all nodes for the given zone createZoneSpecificNodeData(PCZone * zone)903 void PCZSceneManager::createZoneSpecificNodeData(PCZone * zone) 904 { 905 SceneNodeList::iterator it = mSceneNodes.begin(); 906 PCZSceneNode * pczsn; 907 if (zone->requiresZoneSpecificNodeData()) 908 { 909 while ( it != mSceneNodes.end() ) 910 { 911 pczsn = (PCZSceneNode*)(it->second); 912 // create zone specific data for the node 913 zone->createNodeZoneData(pczsn); 914 // proceed to next entry in the list 915 ++it; 916 } 917 } 918 } 919 920 // set the home zone for a scene node setNodeHomeZone(SceneNode * node,PCZone * zone)921 void PCZSceneManager::setNodeHomeZone(SceneNode *node, PCZone *zone) 922 { 923 // cast the Ogre::SceneNode to a PCZSceneNode 924 PCZSceneNode * pczsn = (PCZSceneNode*)node; 925 pczsn->setHomeZone(zone); 926 } 927 928 // (optional) post processing for any scene node found visible for the frame _alertVisibleObjects(void)929 void PCZSceneManager::_alertVisibleObjects( void ) 930 { 931 OGRE_EXCEPT( Exception::ERR_NOT_IMPLEMENTED, 932 "Function doesn't do as advertised", 933 "PCZSceneManager::_alertVisibleObjects" ); 934 935 // NodeList::iterator it = mVisible.begin(); 936 // 937 // while ( it != mVisible.end() ) 938 // { 939 // SceneNode * node = *it; 940 // // this is where you would do whatever you wanted to the visible node 941 // // but right now, it does nothing. 942 // ++it; 943 // } 944 } 945 946 //----------------------------------------------------------------------- createLight(const String & name)947 Light* PCZSceneManager::createLight(const String& name) 948 { 949 return static_cast<Light*>( 950 createMovableObject(name, PCZLightFactory::FACTORY_TYPE_NAME)); 951 } 952 //----------------------------------------------------------------------- getLight(const String & name) const953 Light* PCZSceneManager::getLight(const String& name) const 954 { 955 return static_cast<Light*>( 956 getMovableObject(name, PCZLightFactory::FACTORY_TYPE_NAME)); 957 } 958 //----------------------------------------------------------------------- hasLight(const String & name) const959 bool PCZSceneManager::hasLight(const String& name) const 960 { 961 return hasMovableObject(name, PCZLightFactory::FACTORY_TYPE_NAME); 962 } 963 //----------------------------------------------------------------------- destroyLight(const String & name)964 void PCZSceneManager::destroyLight(const String& name) 965 { 966 destroyMovableObject(name, PCZLightFactory::FACTORY_TYPE_NAME); 967 } 968 //----------------------------------------------------------------------- destroyAllLights(void)969 void PCZSceneManager::destroyAllLights(void) 970 { 971 destroyAllMovableObjectsByType(PCZLightFactory::FACTORY_TYPE_NAME); 972 } 973 //--------------------------------------------------------------------- findLightsAffectingFrustum(const Camera * camera)974 void PCZSceneManager::findLightsAffectingFrustum(const Camera* camera) 975 { 976 // Similar to the basic SceneManager, we iterate through 977 // lights to see which ones affect the frustum. However, 978 // since we have camera & lights partitioned by zones, 979 // we can check only those lights which either affect the 980 // zone the camera is in, or affect zones which are visible to 981 // the camera 982 983 MovableObjectCollection* lights = 984 getMovableObjectCollection(PCZLightFactory::FACTORY_TYPE_NAME); 985 986 987 { 988 OGRE_LOCK_MUTEX(lights->mutex); 989 990 // Pre-allocate memory 991 mTestLightInfos.clear(); 992 mTestLightInfos.reserve(lights->map.size()); 993 994 MovableObjectIterator it(lights->map.begin(), lights->map.end()); 995 996 while(it.hasMoreElements()) 997 { 998 PCZLight* l = static_cast<PCZLight*>(it.getNext()); 999 if (l->isVisible() && 1000 l->affectsVisibleZone()) 1001 { 1002 LightInfo lightInfo; 1003 lightInfo.light = l; 1004 lightInfo.type = l->getType(); 1005 if (lightInfo.type == Light::LT_DIRECTIONAL) 1006 { 1007 // Always visible 1008 lightInfo.position = Vector3::ZERO; 1009 lightInfo.range = 0; 1010 mTestLightInfos.push_back(lightInfo); 1011 } 1012 else 1013 { 1014 // NB treating spotlight as point for simplicity 1015 // Just see if the lights attenuation range is within the frustum 1016 lightInfo.range = l->getAttenuationRange(); 1017 lightInfo.position = l->getDerivedPosition(); 1018 Sphere sphere(lightInfo.position, lightInfo.range); 1019 if (camera->isVisible(sphere)) 1020 { 1021 mTestLightInfos.push_back(lightInfo); 1022 } 1023 } 1024 } 1025 } 1026 } // release lock on lights collection 1027 1028 // from here on down this function is same as Ogre::SceneManager 1029 1030 // Update lights affecting frustum if changed 1031 if (mCachedLightInfos != mTestLightInfos) 1032 { 1033 mLightsAffectingFrustum.resize(mTestLightInfos.size()); 1034 LightInfoList::const_iterator i; 1035 LightList::iterator j = mLightsAffectingFrustum.begin(); 1036 for (i = mTestLightInfos.begin(); i != mTestLightInfos.end(); ++i, ++j) 1037 { 1038 *j = i->light; 1039 // add cam distance for sorting if texture shadows 1040 if (isShadowTechniqueTextureBased()) 1041 { 1042 (*j)->_calcTempSquareDist(camera->getDerivedPosition()); 1043 } 1044 } 1045 1046 // Sort the lights if using texture shadows, since the first 'n' will be 1047 // used to generate shadow textures and we should pick the most appropriate 1048 if (isShadowTechniqueTextureBased()) 1049 { 1050 // Allow a ShadowListener to override light sorting 1051 // Reverse iterate so last takes precedence 1052 bool overridden = false; 1053 for (ListenerList::reverse_iterator ri = mListeners.rbegin(); 1054 ri != mListeners.rend(); ++ri) 1055 { 1056 overridden = (*ri)->sortLightsAffectingFrustum(mLightsAffectingFrustum); 1057 if (overridden) 1058 break; 1059 } 1060 if (!overridden) 1061 { 1062 // default sort (stable to preserve directional light ordering 1063 std::stable_sort( 1064 mLightsAffectingFrustum.begin(), mLightsAffectingFrustum.end(), 1065 lightsForShadowTextureLess()); 1066 } 1067 1068 } 1069 1070 // Use swap instead of copy operator for efficiently 1071 mCachedLightInfos.swap(mTestLightInfos); 1072 1073 // notify light dirty, so all movable objects will re-populate 1074 // their light list next time 1075 _notifyLightsDirty(); 1076 } 1077 1078 } 1079 //--------------------------------------------------------------------- ensureShadowTexturesCreated()1080 void PCZSceneManager::ensureShadowTexturesCreated() 1081 { 1082 bool shadowTextureConfigDirty = mShadowTextureConfigDirty; 1083 SceneManager::ensureShadowTexturesCreated(); 1084 if (!shadowTextureConfigDirty) return; 1085 1086 size_t count = mShadowTextureCameras.size(); 1087 for (size_t i = 0; i < count; ++i) 1088 { 1089 PCZSceneNode* node = (PCZSceneNode*)mSceneRoot->createChildSceneNode( 1090 mShadowTextureCameras[i]->getName()); 1091 node->attachObject(mShadowTextureCameras[i]); 1092 addPCZSceneNode(node, mDefaultZone); 1093 } 1094 } 1095 //--------------------------------------------------------------------- destroyShadowTextures(void)1096 void PCZSceneManager::destroyShadowTextures(void) 1097 { 1098 size_t count = mShadowTextureCameras.size(); 1099 for (size_t i = 0; i < count; ++i) 1100 { 1101 SceneNode* node = mShadowTextureCameras[i]->getParentSceneNode(); 1102 mSceneRoot->removeAndDestroyChild(node->getName()); 1103 } 1104 SceneManager::destroyShadowTextures(); 1105 } 1106 //--------------------------------------------------------------------- fireShadowTexturesPreCaster(Light * light,Camera * camera,size_t iteration)1107 void PCZSceneManager::fireShadowTexturesPreCaster(Light* light, Camera* camera, size_t iteration) 1108 { 1109 PCZSceneNode* camNode = (PCZSceneNode*)camera->getParentSceneNode(); 1110 1111 if (light->getType() == Light::LT_DIRECTIONAL) 1112 { 1113 if (camNode->getHomeZone() != mActiveCameraZone) 1114 addPCZSceneNode(camNode, mActiveCameraZone); 1115 } 1116 else 1117 { 1118 PCZSceneNode* lightNode = (PCZSceneNode*)light->getParentSceneNode(); 1119 assert(lightNode); 1120 PCZone* lightZone = lightNode->getHomeZone(); 1121 if (camNode->getHomeZone() != lightZone) 1122 addPCZSceneNode(camNode, lightZone); 1123 } 1124 1125 SceneManager::fireShadowTexturesPreCaster(light, camera, iteration); 1126 } 1127 1128 /* Attempt to automatically connect unconnected portals to proper target zones 1129 * by looking for matching portals in other zones which are at the same location 1130 */ connectPortalsToTargetZonesByLocation(void)1131 void PCZSceneManager::connectPortalsToTargetZonesByLocation(void) 1132 { 1133 // go through every zone to find portals 1134 ZoneMap::iterator i, iend; 1135 PCZone* zone; 1136 iend = mZones.end(); 1137 bool foundMatch; 1138 for (i = mZones.begin(); i != iend; i++) 1139 { 1140 zone = i->second; 1141 // go through all the portals in the zone 1142 Portal* portal; 1143 PortalList::iterator pi, piend; 1144 piend = zone->mPortals.end(); 1145 for (pi = zone->mPortals.begin(); pi != piend; pi++) 1146 { 1147 portal = *pi; 1148 //portal->updateDerivedValues(); 1149 if (portal->getTargetZone() == 0) 1150 { 1151 // this is a portal without a connected zone - look for 1152 // a matching portal in another zone 1153 PCZone* zone2; 1154 ZoneMap::iterator j= mZones.begin(); 1155 foundMatch = false; 1156 while (!foundMatch && j != mZones.end()) 1157 { 1158 zone2 = j->second; 1159 if (zone2 != zone) // make sure we don't look in the same zone 1160 { 1161 Portal * portal2 = zone2->findMatchingPortal(portal); 1162 if (portal2) 1163 { 1164 // found a match! 1165 Ogre::LogManager::getSingletonPtr()->logMessage("Connecting portal "+portal->getName()+" to portal "+portal2->getName()); 1166 foundMatch = true; 1167 portal->setTargetZone(zone2); 1168 portal->setTargetPortal(portal2); 1169 portal2->setTargetZone(zone); 1170 portal2->setTargetPortal(portal); 1171 } 1172 } 1173 j++; 1174 } 1175 if (foundMatch == false) 1176 { 1177 // error, didn't find a matching portal! 1178 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 1179 "Could not find matching portal for portal " + portal->getName(), 1180 "PCZSceneManager::connectPortalsToTargetZonesByLocation"); 1181 1182 } 1183 } 1184 } 1185 } 1186 } 1187 1188 // main visibility determination & render queue filling routine 1189 // over-ridden from base/default scene manager. This is *the* 1190 // main call. _findVisibleObjects(Camera * cam,VisibleObjectsBoundsInfo * visibleBounds,bool onlyShadowCasters)1191 void PCZSceneManager::_findVisibleObjects(Camera* cam, 1192 VisibleObjectsBoundsInfo* visibleBounds, 1193 bool onlyShadowCasters) 1194 { 1195 // clear the render queue 1196 getRenderQueue()->clear(); 1197 1198 // if we are re-rendering the scene again with the same camera, we can just use the cache. 1199 // this helps post processing compositors. 1200 unsigned long frameCount = Root::getSingleton().getNextFrameNumber(); 1201 if (mLastActiveCamera == cam && mFrameCount == frameCount) 1202 { 1203 RenderQueue* queue = getRenderQueue(); 1204 size_t count = mVisible.size(); 1205 for (size_t i = 0; i < count; ++i) 1206 { 1207 ((PCZSceneNode*)mVisible[i])->_addToRenderQueue( 1208 cam, queue, onlyShadowCasters, visibleBounds); 1209 } 1210 return; 1211 } 1212 1213 // increment the visibility frame counter 1214 mFrameCount = frameCount; 1215 mLastActiveCamera = cam; 1216 1217 // clear the list of visible nodes 1218 mVisible.clear(); 1219 1220 // turn off sky 1221 enableSky(false); 1222 1223 // remove all extra culling planes 1224 ((PCZCamera*)cam)->removeAllExtraCullingPlanes(); 1225 1226 // update the camera 1227 ((PCZCamera*)cam)->update(); 1228 1229 // get the home zone of the camera 1230 PCZone* cameraHomeZone = ((PCZSceneNode*)(cam->getParentSceneNode()))->getHomeZone(); 1231 1232 // walk the zones, starting from the camera home zone, 1233 // adding all visible scene nodes to the mVisibles list 1234 cameraHomeZone->setLastVisibleFrame(mFrameCount); 1235 cameraHomeZone->findVisibleNodes((PCZCamera*)cam, 1236 mVisible, 1237 getRenderQueue(), 1238 visibleBounds, 1239 onlyShadowCasters, 1240 mDisplayNodes, 1241 mShowBoundingBoxes); 1242 } 1243 findNodesIn(const AxisAlignedBox & box,PCZSceneNodeList & list,PCZone * startZone,PCZSceneNode * exclude)1244 void PCZSceneManager::findNodesIn( const AxisAlignedBox &box, 1245 PCZSceneNodeList &list, 1246 PCZone * startZone, 1247 PCZSceneNode *exclude ) 1248 { 1249 PortalList visitedPortals; 1250 if (startZone) 1251 { 1252 // start in startzone, and recurse through portals if necessary 1253 startZone->_findNodes(box, list, visitedPortals, true, true, exclude); 1254 } 1255 else 1256 { 1257 // no start zone specified, so check all zones 1258 ZoneMap::iterator i; 1259 PCZone * zone; 1260 for (i = mZones.begin(); i != mZones.end(); i++) 1261 { 1262 zone = i->second; 1263 zone->_findNodes( box, list, visitedPortals, false, false, exclude ); 1264 } 1265 } 1266 } 1267 findNodesIn(const Sphere & sphere,PCZSceneNodeList & list,PCZone * startZone,PCZSceneNode * exclude)1268 void PCZSceneManager::findNodesIn( const Sphere &sphere, 1269 PCZSceneNodeList &list, 1270 PCZone * startZone, 1271 PCZSceneNode *exclude ) 1272 { 1273 PortalList visitedPortals; 1274 if (startZone) 1275 { 1276 // start in startzone, and recurse through portals if necessary 1277 startZone->_findNodes(sphere, list, visitedPortals, true, true, exclude); 1278 } 1279 else 1280 { 1281 // no start zone specified, so check all zones 1282 ZoneMap::iterator i; 1283 PCZone * zone; 1284 for (i = mZones.begin(); i != mZones.end(); i++) 1285 { 1286 zone = i->second; 1287 zone->_findNodes( sphere, list, visitedPortals, false, false, exclude ); 1288 } 1289 } 1290 } 1291 findNodesIn(const PlaneBoundedVolume & volume,PCZSceneNodeList & list,PCZone * startZone,PCZSceneNode * exclude)1292 void PCZSceneManager::findNodesIn( const PlaneBoundedVolume &volume, 1293 PCZSceneNodeList &list, 1294 PCZone * startZone, 1295 PCZSceneNode *exclude ) 1296 { 1297 PortalList visitedPortals; 1298 if (startZone) 1299 { 1300 // start in startzone, and recurse through portals if necessary 1301 startZone->_findNodes(volume, list, visitedPortals, true, true, exclude); 1302 } 1303 else 1304 { 1305 // no start zone specified, so check all zones 1306 ZoneMap::iterator i; 1307 PCZone * zone; 1308 for (i = mZones.begin(); i != mZones.end(); i++) 1309 { 1310 zone = i->second; 1311 zone->_findNodes( volume, list, visitedPortals, false, false, exclude ); 1312 } 1313 } 1314 } 1315 findNodesIn(const Ray & r,PCZSceneNodeList & list,PCZone * startZone,PCZSceneNode * exclude)1316 void PCZSceneManager::findNodesIn( const Ray &r, 1317 PCZSceneNodeList &list, 1318 PCZone * startZone, 1319 PCZSceneNode *exclude ) 1320 { 1321 PortalList visitedPortals; 1322 if (startZone) 1323 { 1324 // start in startzone, and recurse through portals if necessary 1325 startZone->_findNodes(r, list, visitedPortals, true, true, exclude); 1326 } 1327 else 1328 { 1329 ZoneMap::iterator i; 1330 PCZone * zone; 1331 for (i = mZones.begin(); i != mZones.end(); i++) 1332 { 1333 zone = i->second; 1334 zone->_findNodes( r, list, visitedPortals, false, false, exclude ); 1335 } 1336 } 1337 } 1338 1339 // get the current value of a scene manager option getOptionValues(const String & key,StringVector & refValueList)1340 bool PCZSceneManager::getOptionValues( const String & key, StringVector &refValueList ) 1341 { 1342 return SceneManager::getOptionValues( key, refValueList ); 1343 } 1344 1345 // get option keys (base along with PCZ-specific) getOptionKeys(StringVector & refKeys)1346 bool PCZSceneManager::getOptionKeys( StringVector & refKeys ) 1347 { 1348 SceneManager::getOptionKeys( refKeys ); 1349 refKeys.push_back( "ShowBoundingBoxes" ); 1350 refKeys.push_back( "ShowPortals" ); 1351 1352 return true; 1353 } 1354 setOption(const String & key,const void * val)1355 bool PCZSceneManager::setOption( const String & key, const void * val ) 1356 { 1357 if ( key == "ShowBoundingBoxes" ) 1358 { 1359 mShowBoundingBoxes = * static_cast < const bool * > ( val ); 1360 return true; 1361 } 1362 1363 else if ( key == "ShowPortals" ) 1364 { 1365 mShowPortals = * static_cast < const bool * > ( val ); 1366 return true; 1367 } 1368 // send option to each zone 1369 ZoneMap::iterator i; 1370 PCZone * zone; 1371 for (i = mZones.begin(); i != mZones.end(); i++) 1372 { 1373 zone = i->second; 1374 if (zone->setOption(key, val ) == true) 1375 { 1376 return true; 1377 } 1378 } 1379 1380 // try regular scenemanager option 1381 return SceneManager::setOption( key, val ); 1382 1383 1384 } 1385 getOption(const String & key,void * val)1386 bool PCZSceneManager::getOption( const String & key, void *val ) 1387 { 1388 if ( key == "ShowBoundingBoxes" ) 1389 { 1390 1391 * static_cast < bool * > ( val ) = mShowBoundingBoxes; 1392 return true; 1393 } 1394 if ( key == "ShowPortals" ) 1395 { 1396 1397 * static_cast < bool * > ( val ) = mShowPortals; 1398 return true; 1399 } 1400 return SceneManager::getOption( key, val ); 1401 1402 } 1403 1404 //--------------------------------------------------------------------- 1405 AxisAlignedBoxSceneQuery* createAABBQuery(const AxisAlignedBox & box,uint32 mask)1406 PCZSceneManager::createAABBQuery(const AxisAlignedBox& box, uint32 mask) 1407 { 1408 PCZAxisAlignedBoxSceneQuery* q = OGRE_NEW PCZAxisAlignedBoxSceneQuery(this); 1409 q->setBox(box); 1410 q->setQueryMask(mask); 1411 return q; 1412 } 1413 //--------------------------------------------------------------------- 1414 SphereSceneQuery* createSphereQuery(const Sphere & sphere,uint32 mask)1415 PCZSceneManager::createSphereQuery(const Sphere& sphere, uint32 mask) 1416 { 1417 PCZSphereSceneQuery* q = OGRE_NEW PCZSphereSceneQuery(this); 1418 q->setSphere(sphere); 1419 q->setQueryMask(mask); 1420 return q; 1421 } 1422 //--------------------------------------------------------------------- 1423 PlaneBoundedVolumeListSceneQuery* createPlaneBoundedVolumeQuery(const PlaneBoundedVolumeList & volumes,uint32 mask)1424 PCZSceneManager::createPlaneBoundedVolumeQuery(const PlaneBoundedVolumeList& volumes, 1425 uint32 mask) 1426 { 1427 PCZPlaneBoundedVolumeListSceneQuery* q = OGRE_NEW PCZPlaneBoundedVolumeListSceneQuery(this); 1428 q->setVolumes(volumes); 1429 q->setQueryMask(mask); 1430 return q; 1431 } 1432 1433 //--------------------------------------------------------------------- 1434 RaySceneQuery* createRayQuery(const Ray & ray,uint32 mask)1435 PCZSceneManager::createRayQuery(const Ray& ray, uint32 mask) 1436 { 1437 PCZRaySceneQuery* q = OGRE_NEW PCZRaySceneQuery(this); 1438 q->setRay(ray); 1439 q->setQueryMask(mask); 1440 return q; 1441 } 1442 //--------------------------------------------------------------------- 1443 IntersectionSceneQuery* createIntersectionQuery(uint32 mask)1444 PCZSceneManager::createIntersectionQuery(uint32 mask) 1445 { 1446 1447 PCZIntersectionSceneQuery* q = OGRE_NEW PCZIntersectionSceneQuery(this); 1448 q->setQueryMask(mask); 1449 return q; 1450 } 1451 //--------------------------------------------------------------------- 1452 // clear portal update flag from all zones _clearAllZonesPortalUpdateFlag(void)1453 void PCZSceneManager::_clearAllZonesPortalUpdateFlag(void) 1454 { 1455 ZoneMap::iterator zoneIterator = mZones.begin(); 1456 1457 while ( zoneIterator != mZones.end() ) 1458 { 1459 (zoneIterator->second)->setPortalsUpdated(false); 1460 zoneIterator++; 1461 } 1462 } 1463 //--------------------------------------------------------------------- 1464 /// See SceneManager::prepareShadowTextures. prepareShadowTextures(Camera * cam,Viewport * vp,const LightList * lightList)1465 void PCZSceneManager::prepareShadowTextures(Camera* cam, Viewport* vp, const LightList* lightList) 1466 { 1467 mActiveCameraZone = ((PCZSceneNode*)cam->getParentSceneNode())->getHomeZone(); 1468 SceneManager::prepareShadowTextures(cam, vp); 1469 } 1470 1471 //----------------------------------------------------------------------- 1472 const String PCZSceneManagerFactory::FACTORY_TYPE_NAME = "PCZSceneManager"; 1473 //----------------------------------------------------------------------- initMetaData(void) const1474 void PCZSceneManagerFactory::initMetaData(void) const 1475 { 1476 mMetaData.typeName = FACTORY_TYPE_NAME; 1477 mMetaData.description = "Scene manager organising the scene using Portal Connected Zones."; 1478 mMetaData.sceneTypeMask = 0xFFFF; // support all types 1479 mMetaData.worldGeometrySupported = false; 1480 } 1481 //----------------------------------------------------------------------- createInstance(const String & instanceName)1482 SceneManager* PCZSceneManagerFactory::createInstance( 1483 const String& instanceName) 1484 { 1485 return OGRE_NEW PCZSceneManager(instanceName); 1486 } 1487 //----------------------------------------------------------------------- destroyInstance(SceneManager * instance)1488 void PCZSceneManagerFactory::destroyInstance(SceneManager* instance) 1489 { 1490 OGRE_DELETE instance; 1491 } 1492 1493 1494 } 1495