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