123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #ifndef _SCENEZONESPACEMANAGER_H_
- #define _SCENEZONESPACEMANAGER_H_
- #ifndef _SCENEOBJECT_H_
- #include "scene/sceneObject.h"
- #endif
- #ifndef _TVECTOR_H_
- #include "core/util/tVector.h"
- #endif
- #ifndef _TSIGNAL_H_
- #include "core/util/tSignal.h"
- #endif
- #ifndef _DATACHUNKER_H_
- #include "core/dataChunker.h"
- #endif
- class SceneContainer;
- class SceneRootZone;
- class SceneZoneSpace;
- /// Object that manages zone spaces in a scene.
- class SceneZoneSpaceManager
- {
- public:
- class ZoneContentIterator;
- friend class SceneZoneSpace; // mZoneLists
- friend class ZoneContentIterator; // mZoneLists
- /// A signal used to notify that the zone setup of the scene has changed.
- ///
- /// @note If you use this signal to maintain state that depends on the zoning
- /// setup, it's best to not immediately update the sate in response to this
- /// signal. The reason is that during loading and editing, the signal may
- /// be fired a lot and continuously updating dependent data may waste a lot
- /// of time.
- typedef Signal< void( SceneZoneSpaceManager* ) > ZoningChangedSignal;
- enum : U32
- {
- /// Zone ID of the exterior zone.
- RootZoneId = 0,
- /// Constant to indicate an invalid zone ID.
- InvalidZoneId = 0xFFFFFFFF,
- };
- /// Iterator for the contents of a given zone.
- class ZoneContentIterator
- {
- public:
- ZoneContentIterator( SceneZoneSpaceManager* manager, S32 zoneId, bool upToDate = true )
- {
- AssertFatal( zoneId < manager->getNumZones(), "SceneZoneSpaceManager::ZoneContentIterator - Zone ID out of range" );
- if( upToDate )
- {
- // Since zoning is updated lazily, the zone contents may actually
- // be out of date. Force an update by triggering rezoning on the
- // zone object. This is brute-force but this iterator is not meant
- // to be used for high-frequency code anyway.
- //
- // Use the area-based rezoning so that we can also properly iterate
- // over the contents of SceneRootZone.
- manager->_rezoneObjects( ( ( SceneObject* ) manager->getZoneOwner( zoneId ) )->getWorldBox() );
- }
- mCurrent = manager->mZoneLists[ zoneId ]->nextInBin; // Skip zone object entry.
- }
- bool isValid() const
- {
- return ( mCurrent != NULL );
- }
- bool operator !() const
- {
- return ( mCurrent == NULL );
- }
- ZoneContentIterator& operator ++()
- {
- if( mCurrent )
- mCurrent = mCurrent->nextInBin;
- return *this;
- }
- ZoneContentIterator& operator --()
- {
- if( mCurrent )
- mCurrent = mCurrent->prevInBin;
- return *this;
- }
- SceneObject* operator *() const
- {
- AssertFatal( mCurrent != NULL, "SceneManager::ZoneContentIterator::operator* - Invalid iterator" );
- return mCurrent->object;
- }
- SceneObject* operator ->() const
- {
- AssertFatal( mCurrent != NULL, "SceneManager::ZoneContentIterator::operator-> - Invalid iterator" );
- return mCurrent->object;
- }
- private:
- SceneObject::ZoneRef* mCurrent;
- };
- protected:
- /// The root and outdoor zone of the scene.
- SceneRootZone* mRootZone;
- /// Scene container that holds the zone spaces we are managing.
- SceneContainer* mContainer;
- /// Collection of objects that manage zones.
- Vector< SceneZoneSpace* > mZoneSpaces;
- /// Total number of zones that have been allocated in the scene.
- U32 mNumTotalAllocatedZones;
- /// Number of zone IDs that are in active use.
- U32 mNumActiveZones;
- /// Object list for each zone in the scene.
- /// First entry in the list points back to the zone manager.
- Vector< SceneObject::ZoneRef* > mZoneLists;
- /// Vector used repeatedly for zone space queries on the container.
- mutable Vector< SceneObject* > mZoneSpacesQueryList;
- /// Allocator for ZoneRefs.
- static ClassChunker< SceneObject::ZoneRef > smZoneRefChunker;
- /// @name Dirty Lists
- /// Updating the zoning state of a scene is done en block rather than
- /// individually for each object as it changes transforms or size.
- /// @{
- /// Area of the scene that needs to be rezoned.
- Box3F mDirtyArea;
- /// List of zone spaces that have changed state and need updating.
- Vector< SceneZoneSpace* > mDirtyZoneSpaces;
- /// List of objects (non-zone spaces) that have changed state and need
- /// updating.
- Vector< SceneObject* > mDirtyObjects;
- /// @}
- /// Check to see if we have accumulated a lot of unallocate zone IDs and if so,
- /// compact the zoning lists by reassigning IDs.
- ///
- /// @warn This method may alter all zone IDs in the scene!
- void _compactZonesCheck();
- /// Return the index into #mZoneSpaces for the given object or -1 if
- /// @object is not a zone manager.
- S32 _getZoneSpaceIndex( SceneZoneSpace* object ) const;
- /// Attach zoning state to the given object.
- void _zoneInsert( SceneObject* object, bool queryListInitialized = false );
- /// Detach zoning state from the given object.
- void _zoneRemove( SceneObject* object );
- /// Add to given object to the zone list of the given zone.
- void _addToZoneList( U32 zoneId, SceneObject* object );
- /// Clear all objects assigned to the given zone.
- /// @note This does not remove the first link in the zone list which is the link
- /// back to the zone manager.
- void _clearZoneList( U32 zoneId );
- /// Find the given object in the zone list of the given zone.
- SceneObject::ZoneRef* _findInZoneList( U32 zoneId, SceneObject* object ) const;
- /// Assign the given object to the outdoor zone.
- void _addToOutdoorZone( SceneObject* object );
- /// Rezone all objects in the given area.
- void _rezoneObjects( const Box3F& area );
- /// Update the zoning state of the given object.
- void _rezoneObject( SceneObject* object );
- /// Fill #mZoneSpacesQueryList with all ZoneObjectType objects in the given area.
- void _queryZoneSpaces( const Box3F& area ) const;
- public:
- SceneZoneSpaceManager( SceneContainer* container );
- ~SceneZoneSpaceManager();
- /// Bring the zoning state of the scene up to date. This will cause objects
- /// that have moved or have been resized to be rezoned and will updated regions
- /// of the scene that had their zoning setup changed.
- ///
- /// @note This method depends on proper use of notifyObjectChanged().
- void updateZoningState();
- /// @name Objects
- /// @{
- /// Add zoning state to the given object.
- void registerObject( SceneObject* object );
- /// Remove the given object from the zoning state.
- void unregisterObject( SceneObject* object );
- /// Let the manager know that state relevant to zoning of the given
- /// object has changed.
- void notifyObjectChanged( SceneObject* object );
- /// Update the zoning state of the given object.
- void updateObject( SceneObject* object );
- /// @}
- /// @name Zones
- /// @{
- /// Return the root zone of the scene.
- SceneRootZone* getRootZone() const { return mRootZone; }
- /// Register a zone manager.
- ///
- /// @param object SceneZoneSpace object that contains zones.
- /// @param numZones Number of zones that @a object contains.
- void registerZones( SceneZoneSpace* object, U32 numZones );
- /// Unregister a zone manager.
- ///
- /// @param object Object that contains zones.
- void unregisterZones( SceneZoneSpace* object );
- /// Return true if the given ID belongs to a currently registered zone.
- bool isValidZoneId( const U32 zoneId ) const
- {
- return ( zoneId < mNumTotalAllocatedZones && mZoneLists[ zoneId ] );
- }
- /// Get the scene object that contains the zone with the given ID.
- ///
- /// @param zoneId ID of the zone. Must be valid.
- /// @return The zone space that has registered the given zone.
- SceneZoneSpace* getZoneOwner( const U32 zoneId ) const
- {
- AssertFatal( isValidZoneId( zoneId ), "SceneManager::getZoneOwner - Invalid zone ID!");
- return ( SceneZoneSpace* ) mZoneLists[ zoneId ]->object;
- }
- /// Return the total number of zones in the scene.
- U32 getNumZones() const { return mNumTotalAllocatedZones; }
- /// Return the effective amount of used zone IDs in the scene.
- U32 getNumActiveZones() const { return mNumActiveZones; }
- /// Return the total number of objects in the scene that manage zones.
- U32 getNumZoneSpaces() const { return mZoneSpaces.size(); }
- /// Find the zone that contains the given point.
- ///
- /// Note that the result can be <em>any</em> zone containing the given
- /// point.
- void findZone( const Point3F& point, SceneZoneSpace*& outZoneSpace, U32& outZoneID ) const;
- /// Collect the IDs of all zones that overlap the given area.
- ///
- /// @param area AABB of scene space to query.
- /// @param outZones IDs of all overlapped zones are added to this vector.
- ///
- /// @return Number of zones that have been added to @a outZones. Always at least
- /// 1 as at least the outdoor zone always overlaps the given area (though if another zone
- /// manager fully contains @a area, the outdoor zone will not be added to the list).
- U32 findZones( const Box3F& area, Vector< U32 >& outZones ) const;
- static ZoningChangedSignal& getZoningChangedSignal()
- {
- static ZoningChangedSignal sSignal;
- return sSignal;
- }
- /// @name Debugging
- /// @{
- /// Verify the current zoning state. This makes sure all the connectivity
- /// information and all the zone assignments appear to be correct.
- void verifyState();
- /// Dump the current state of all zone spaces in the scene to the console.
- /// @param update If true, zoning state states are updated first; if false, zoning is
- /// dumped as is.
- void dumpZoneStates( bool update = true );
- /// @}
- /// @}
- };
- #endif // !_SCENEZONESPACEMANAGER_H_
|