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