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