123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873 |
- //-----------------------------------------------------------------------------
- // 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 _SCOPETRACKER_H_
- #define _SCOPETRACKER_H_
- #ifndef _TYPETRAITS_H_
- #include "platform/typetraits.h"
- #endif
- #ifndef _BITSET_H_
- #include "core/bitSet.h"
- #endif
- #ifndef _TVECTOR_H_
- #include "core/util/tVector.h"
- #endif
- #ifndef _CONSOLE_H_
- #include "console/console.h"
- #endif
- #ifndef _PROFILER_H_
- #include "platform/profiler.h"
- #endif
- //#define DEBUG_SPEW
- /// @file
- /// A mechanism for continuous tracking of point/box intersections.
- /// Base class for objects registered with a ScopeTracker.
- template< S32 NUM_DIMENSIONS >
- class ScopeTrackerObject
- {
- public:
-
- typedef void Parent;
- /// TrackingNodes are used to track object bounds along individual world axes.
- class TrackingNode
- {
- public:
-
- typedef void Parent;
-
- enum EFlags
- {
- FLAG_Min = BIT( 0 ),
- FLAG_Max = BIT( 1 ),
- FLAG_Reference = BIT( 2 ),
- };
-
- ///
- BitSet32 mFlags;
-
- ///
- TrackingNode* mOpposite;
-
- /// Distance along axis.
- F32 mPosition;
- /// The object being tracked by this node or NULL.
- ScopeTrackerObject* mObject;
-
- /// Next node on axis tracking chain.
- TrackingNode* mNext;
-
- /// Previous node on axis tracking chain.
- TrackingNode* mPrev;
-
- ///
- TrackingNode()
- : mOpposite( NULL ), mPosition( 0.0f ), mObject( NULL ), mNext( NULL ), mPrev( NULL ) {}
-
- /// Return the object to which this tracking node belongs.
- ScopeTrackerObject* getObject() const { return mObject; }
-
- ///
- TrackingNode* getOpposite() const { return mOpposite; }
-
- ///
- F32 getPosition() const { return mPosition; }
-
- ///
- void setPosition( F32 value ) { mPosition = value; }
-
- ///
- TrackingNode* getNext() const { return mNext; }
-
- ///
- void setNext( TrackingNode* node ) { mNext = node; }
-
- ///
- TrackingNode* getPrev() const { return mPrev; }
-
- ///
- void setPrev( TrackingNode* node ) { mPrev = node; }
- /// Return true if this is left/lower bound node of an object.
- bool isMin() const { return mFlags.test( FLAG_Min ); }
-
- /// Return true if this is the right/upper bound node of an object.
- bool isMax() const { return mFlags.test( FLAG_Max ); }
-
- /// Return true if this is the reference center tracking node. There will only
- /// ever be one such node on each tracking list.
- bool isReference() const { return mFlags.test( FLAG_Reference ); }
- };
-
- enum
- {
- AllInScope = ( 0x01010101 >> ( ( 4 - NUM_DIMENSIONS ) * 8 ) )
- };
-
- protected:
-
- ///
- union
- {
- U8 mBytes[ 4 ];
- U32 mDWord;
- } mScopeMask;
- ///
- TrackingNode mTrackingNodes[ NUM_DIMENSIONS ][ 2 ];
- public:
-
- ///
- ScopeTrackerObject( U32 flags = 0 )
- {
- clearScopeMask();
- for( U32 n = 0; n < NUM_DIMENSIONS; ++ n )
- {
- TrackingNode* minNode = getMinTrackingNode( n );
- TrackingNode* maxNode = getMaxTrackingNode( n );
-
- minNode->mFlags = flags;
- maxNode->mFlags = flags;
-
- minNode->mObject = this;
- maxNode->mObject = this;
-
- minNode->mOpposite = maxNode;
- maxNode->mOpposite = minNode;
-
- minNode->mFlags.set( TrackingNode::FLAG_Min );
- maxNode->mFlags.set( TrackingNode::FLAG_Max );
- }
- }
-
- /// Return true if the object is currently being tracked.
- bool isRegistered() const
- {
- for( U32 n = 0; n < NUM_DIMENSIONS; ++ n )
- if( getMinTrackingNode( n )->getNext() != NULL )
- return true;
- return false;
- }
-
- /// Return true if the reference center lies within the object bound's on all axes.
- bool isInScope() const { return ( mScopeMask.mDWord == AllInScope ); }
-
- ///
- bool isInScope( U32 dimension ) const { return mScopeMask.mBytes[ dimension ]; }
-
- ///
- void setInScope( U32 dimension, bool state ) { mScopeMask.mBytes[ dimension ] = ( state ? 1 : 0 ); }
-
- ///
- void clearScopeMask() { mScopeMask.mDWord = 0; }
-
- ///
- TrackingNode* getMinTrackingNode( U32 dimension ) { return &mTrackingNodes[ dimension ][ 0 ]; }
- const TrackingNode* getMinTrackingNode( U32 dimension ) const { return &mTrackingNodes[ dimension ][ 0 ]; }
-
- ///
- TrackingNode* getMaxTrackingNode( U32 dimension ) { return &mTrackingNodes[ dimension ][ 1 ]; }
- const TrackingNode* getMaxTrackingNode( U32 dimension ) const { return &mTrackingNodes[ dimension ][ 1 ]; }
-
- /// @name Implementor Interface
- ///
- /// The following methods must be implemented by the client. They are defined here
- /// just for reference. If you don't override them, you'll get link errors.
- ///
- /// @{
-
- /// Return the position of the object in world-space.
- void getPosition( F32 pos[ NUM_DIMENSIONS ] ) const;
-
- /// If this object is the reference object, this method should return the world-space pivot
- /// point in the object that will be the world reference center.
- void getReferenceCenter( F32 pos[ NUM_DIMENSIONS ] ) const;
-
- /// Return the object's bounding box in world-space.
- void getBounds( F32 minBounds[ NUM_DIMENSIONS ], F32 maxBounds[ NUM_DIMENSIONS ] ) const;
-
- ///
- String describeSelf() const;
-
- /// @}
- };
- /// Helper class to track the position of a point in N-dimensional space relative to a collection
- /// of N-dimensional volumes.
- ///
- /// This class works by breaking the N-dimensional case down into N one-dimensional cases. By tracking
- /// objects independently along each of their axes, intersection testing becomes a trivial matter of
- /// doing point-on-line tests. The line segments can be conveniently represented as ordered linked
- /// lists along which the reference point is being moved.
- ///
- /// To determine N-dimensional containment of the reference point, the result of each of the one-dimensional
- /// point-on-line tests simply has to be combined. If the point lies on each of N 1D segments of a
- /// given volume, then the point is fully contained in the volume.
- ///
- /// This class may be used in places where otherwise a spatial subdivision scheme would be necessary in
- /// order to limit the number of containment tests triggered by each movement of the reference point.
- /// Once the tracker has been set up, each position change of an object or the reference center will result
- /// in a usually small number of incremental list updates.
- ///
- /// Another advantage is that this class makes it easy to reduce 3D tracking to 2D tracking if tracking on
- /// the height axis isn't important.
- ///
- /// The following interface must be implemented by the given "Object" type:
- ///
- /// @code
- /// struct Object : public ScopeTrackerObject< NUM_DIMENSIONS >
- /// {
- /// /// Return the position of the object in world-space.
- /// void getPosition( F32 pos[ NUM_DIMENSIONS ] ) const;
- ///
- /// /// If this object is the reference object, this method should return the world-space pivot
- /// /// point in the object that will be the world reference center.
- /// void getReferenceCenter( F32 pos[ NUM_DIMENSIONS ] ) const;
- ///
- /// /// Return the object's bounding box in world-space.
- /// void getBounds( F32 minBounds[ NUM_DIMENSIONS ], F32 maxBounds[ NUM_DIMENSIONS ] ) const;
- /// };
- /// @endcode
- ///
- /// Terminology:
- ///
- /// - "In Scope": A volume is in scope if it fully contains the reference center.
- /// - "Reference Object": Object that is the designated center of the world.
- ///
- /// @param NUM_DIMENSIONS Number of dimensions to track; must be <=4.
- /// @param Object Value type for objects tracked by the ScopeTracker. Must have pointer behavior.
- template< S32 NUM_DIMENSIONS, typename Object >
- class ScopeTracker
- {
- public:
-
- typedef void Parent;
- typedef typename TypeTraits< Object >::BaseType ObjectType;
- typedef typename ObjectType::TrackingNode NodeType;
-
- protected:
-
- enum
- {
- MIN = 0,
- MAX = 1
- };
-
- /// The reference object. This is the center relative to which all
- /// tracking occurs. Any other object is in scope when it contains the
- /// reference object.
- Object mReferenceObject;
-
- ///
- NodeType* mTrackingList[ NUM_DIMENSIONS ][ 2 ];
-
- ///
- NodeType mBoundaryNodes[ NUM_DIMENSIONS ][ 2 ];
-
- ///
- Vector< Object > mPotentialScopeInObjects;
-
- /// @name Scoping
- /// @{
-
- virtual void _onScopeIn( Object object ) {}
-
- virtual void _onScopeOut( Object object ) {}
-
- /// Set the scoping state of the given object.
- void _setScope( Object object );
-
- /// @}
-
- /// @name Tracking
- /// @{
- ///
- void _insertTrackingNode( U32 dimension, NodeType* node );
-
- ///
- void _removeTrackingNode( U32 dimension, NodeType* node );
-
- ///
- void _moveTrackingNode( U32 dimension, NodeType* node, F32 newPos );
-
- ///
- void _initTracking();
-
- ///
- void _uninitTracking();
-
- /// @}
-
- public:
-
- ///
- ScopeTracker();
-
- /// Add a volume object to the world.
- void registerObject( Object object );
-
- /// Remove a volume object from the world.
- void unregisterObject( Object object );
-
- /// Update the position of the object in the world.
- void updateObject( Object object );
-
- ///
- Object getReferenceObject() const { return mReferenceObject; }
-
- ///
- ///
- /// @note Switching reference centers is potentially costly.
- void setReferenceObject( Object object );
-
- ///
- void debugDump();
- };
- //-----------------------------------------------------------------------------
- template< S32 NUM_DIMENSIONS, class Object >
- ScopeTracker< NUM_DIMENSIONS, Object >::ScopeTracker()
- : mReferenceObject( NULL )
- {
- VECTOR_SET_ASSOCIATION( mPotentialScopeInObjects );
-
- // Initialize the tracking lists. Put the boundary
- // nodes in place that will always be the heads and tails
- // of each list.
-
- dMemset( mTrackingList, 0, sizeof( mTrackingList ) );
- for( U32 n = 0; n < NUM_DIMENSIONS; ++ n )
- {
- mBoundaryNodes[ n ][ MIN ].setPosition( TypeTraits< F32 >::MIN );
- mBoundaryNodes[ n ][ MAX ].setPosition( TypeTraits< F32 >::MAX );
-
- mBoundaryNodes[ n ][ MIN ].setNext( &mBoundaryNodes[ n ][ MAX ] );
- mBoundaryNodes[ n ][ MAX ].setPrev( &mBoundaryNodes[ n ][ MIN ] );
-
- mBoundaryNodes[ n ][ MIN ].mOpposite = &mBoundaryNodes[ n ][ MAX ];
- mBoundaryNodes[ n ][ MAX ].mOpposite = &mBoundaryNodes[ n ][ MIN ];
-
- mTrackingList[ n ][ MIN ] = &mBoundaryNodes[ n ][ MIN ];
- mTrackingList[ n ][ MAX ] = &mBoundaryNodes[ n ][ MAX ];
- }
- }
- //-----------------------------------------------------------------------------
- template< S32 NUM_DIMENSIONS, class Object >
- void ScopeTracker< NUM_DIMENSIONS, Object >::setReferenceObject( Object object )
- {
- AssertFatal( !object || !Deref( object ).isRegistered(),
- "ScopeTracker::setReferenceObject - reference object must not be volume object" );
-
- if( mReferenceObject == object )
- return;
-
- // If object is invalid, remove the reference center
- // tracking.
- if( !object )
- {
- // Transition all objects to out-of-scope and
- // deactivate tracking.
- _uninitTracking();
- mReferenceObject = object;
- return;
- }
- if( mReferenceObject )
- {
- //RDFIXME: this is very disruptive
-
- // We have an existing reference object so we need to update
- // the scoping to match it. Brute-force this for now.
- _uninitTracking();
- mReferenceObject = object;
- _initTracking();
- }
- else
- {
- // No reference object yet.
- mReferenceObject = object;
- _initTracking();
- }
-
- #ifdef DEBUG_SPEW
- Platform::outputDebugString( "[ScopeTracker] Reference object is now 0x%x", object );
- #endif
- }
- //-----------------------------------------------------------------------------
- template< S32 NUM_DIMENSIONS, class Object >
- void ScopeTracker< NUM_DIMENSIONS, Object >::registerObject( Object object )
- {
- PROFILE_SCOPE( ScopeTracker_registerObject );
-
- // Get the object bounds.
-
- F32 minBounds[ NUM_DIMENSIONS ];
- F32 maxBounds[ NUM_DIMENSIONS ];
-
- Deref( object ).getBounds( minBounds, maxBounds );
-
- // Insert the object's tracking nodes.
- for( U32 n = 0; n < NUM_DIMENSIONS; ++ n )
- {
- NodeType* minNode = Deref( object ).getMinTrackingNode( n );
- NodeType* maxNode = Deref( object ).getMaxTrackingNode( n );
- minNode->setPosition( minBounds[ n ] );
- maxNode->setPosition( maxBounds[ n ] );
-
- // Insert max before min so that max always comes out
- // to the right of min.
- _insertTrackingNode( n, maxNode );
- _insertTrackingNode( n, minNode );
- }
-
- // Set the scoping state of the object.
-
- _setScope( object );
- }
- //-----------------------------------------------------------------------------
- template< S32 NUM_DIMENSIONS, class Object >
- void ScopeTracker< NUM_DIMENSIONS, Object >::unregisterObject( Object object )
- {
- PROFILE_SCOPE( ScopeTracker_unregisterObject );
-
- if( !Deref( object ).isRegistered() )
- return;
-
- // Clear its scoping state.
-
- if( Deref( object ).isInScope() )
- _onScopeOut( object );
- Deref( object ).clearScopeMask();
-
- // Remove the tracking state.
- for( U32 n = 0; n < NUM_DIMENSIONS; ++ n )
- {
- _removeTrackingNode( n, Deref( object ).getMinTrackingNode( n ) );
- _removeTrackingNode( n, Deref( object ).getMaxTrackingNode( n ) );
- }
- }
- //-----------------------------------------------------------------------------
- template< S32 NUM_DIMENSIONS, class Object >
- void ScopeTracker< NUM_DIMENSIONS, Object >::updateObject( Object object )
- {
- PROFILE_SCOPE( ScopeTracker_updateObject );
-
- if( object == mReferenceObject )
- {
- // Get the reference center position.
-
- F32 position[ NUM_DIMENSIONS ];
- Deref( mReferenceObject ).getReferenceCenter( position );
-
- // Move the reference tracking node.
-
- for( U32 n = 0; n < NUM_DIMENSIONS; ++ n )
- _moveTrackingNode( n, Deref( mReferenceObject ).getMinTrackingNode( n ), position[ n ] );
-
- // Flush the potential-scope-in list.
-
- while( !mPotentialScopeInObjects.empty() )
- {
- Object obj = mPotentialScopeInObjects.last();
- mPotentialScopeInObjects.decrement();
-
- if( Deref(obj).isInScope() )
- _onScopeIn(obj);
- }
- }
- else
- {
- // Get the object bounds.
-
- F32 minBounds[ NUM_DIMENSIONS ];
- F32 maxBounds[ NUM_DIMENSIONS ];
-
- Deref( object ).getBounds( minBounds, maxBounds );
-
- // Move the object's tracking nodes.
- bool wasInScope = Deref( object ).isInScope();
- for( U32 n = 0; n < NUM_DIMENSIONS; ++ n )
- {
- NodeType* minNode = Deref( object ).getMinTrackingNode( n );
- NodeType* maxNode = Deref( object ).getMaxTrackingNode( n );
- _moveTrackingNode( n, minNode, minBounds[ n ] );
- _moveTrackingNode( n, maxNode, maxBounds[ n ] );
- }
-
- // Rescope the object, if necessary.
-
- if( wasInScope && !Deref( object ).isInScope() )
- _onScopeOut( object );
- else if( !wasInScope && Deref( object ).isInScope() )
- _onScopeIn( object );
- }
- }
- //-----------------------------------------------------------------------------
- template< S32 NUM_DIMENSIONS, class Object >
- void ScopeTracker< NUM_DIMENSIONS, Object >::_insertTrackingNode( U32 dimension, NodeType* node )
- {
- //RDTODO: substitute brute-force search with some smarter insertion algorithm
- // (at least dynamically decide on direction for search)
- F32 pos = node->getPosition();
- NodeType* current = mTrackingList[ dimension ][ MIN ]->getNext();
- NodeType* prev = mTrackingList[ dimension ][ MIN ];
- while( current->getPosition() < pos )
- {
- prev = current;
- current = current->getNext();
- }
-
- prev->setNext( node );
- current->setPrev( node );
- node->setPrev( prev );
- node->setNext( current );
- }
- //-----------------------------------------------------------------------------
- template< S32 NUM_DIMENSIONS, class Object >
- void ScopeTracker< NUM_DIMENSIONS, Object >::_removeTrackingNode( U32 dimension, NodeType* node )
- {
- NodeType* next = node->getNext();
- NodeType* prev = node->getPrev();
-
- AssertFatal( next != NULL, "ScopeTracker::_insertTrackingNode - invalid list state (no next node)!" );
- AssertFatal( prev != NULL, "ScopeTracker::_insertTrackingNode - invalid list state (no prev node)!" );
- next->setPrev( prev );
- prev->setNext( next );
-
- node->setNext( NULL );
- node->setPrev( NULL );
- }
- //-----------------------------------------------------------------------------
- template< S32 NUM_DIMENSIONS, class Object >
- void ScopeTracker< NUM_DIMENSIONS, Object >::_moveTrackingNode( U32 dimension, NodeType* node, F32 newPosition )
- {
- PROFILE_SCOPE( ScopeTracker_moveTrackingNode );
-
- AssertFatal( TypeTraits< F32 >::MIN <= newPosition && newPosition <= TypeTraits< F32 >::MAX, "Invalid float in object coordinate!" );
- enum EDirection
- {
- DIRECTION_Up,
- DIRECTION_Down
- };
- // Determine in which direction we are sliding the node.
- EDirection direction;
- if( newPosition < node->getPosition() )
- {
- direction = DIRECTION_Down;
- if( node->getPrev()->getPosition() <= newPosition )
- {
- node->setPosition( newPosition );
- return; // Nothing to do.
- }
- }
- else if( newPosition > node->getPosition() )
- {
- direction = DIRECTION_Up;
- if( node->getNext()->getPosition() >= newPosition )
- {
- node->setPosition( newPosition );
- return; // Nothing to do.
- }
- }
- else
- return; // Nothing to to.
- const bool isReferenceNode = node->isReference();
-
- // Unlink the node.
- NodeType* next = node->getNext();
- NodeType* prev = node->getPrev();
-
- next->setPrev( prev );
- prev->setNext( next );
- // Iterate through to the node's new position.
-
- while( ( direction == DIRECTION_Up && next->getPosition() < newPosition )
- || ( direction == DIRECTION_Down && prev->getPosition() > newPosition ) )
- {
- NodeType* current = 0;
- switch( direction )
- {
- case DIRECTION_Up: current = next; break;
- case DIRECTION_Down: current = prev; break;
- }
- if( isReferenceNode )
- {
- Object object = ( Object ) current->getObject();
- if( ( direction == DIRECTION_Up && current->isMin() )
- || ( direction == DIRECTION_Down && current->isMax() ) )
- {
- Deref( object ).setInScope( dimension, true );
- mPotentialScopeInObjects.push_back( object );
- }
- else
- {
- const bool wasInScope = Deref( object ).isInScope();
- Deref( object ).setInScope( dimension, false );
- if( wasInScope )
- _onScopeOut( object );
- }
- }
- else
- {
- if( current->isReference() )
- {
- Object object = ( Object ) node->getObject();
- if( ( direction == DIRECTION_Up && node->isMin() )
- || ( direction == DIRECTION_Down && node->isMax() ) )
- Deref( object ).setInScope( dimension, false );
- else
- Deref( object ).setInScope( dimension, true );
- }
- }
-
- switch( direction )
- {
- case DIRECTION_Down:
- next = current;
- prev = current->getPrev();
- break;
-
- case DIRECTION_Up:
- prev = current;
- next = current->getNext();
- break;
- }
- }
-
- // Relink the node.
- prev->setNext( node );
- next->setPrev( node );
-
- node->setPrev( prev );
- node->setNext( next );
- node->setPosition( newPosition );
- }
- //-----------------------------------------------------------------------------
- template< S32 NUM_DIMENSIONS, class Object >
- void ScopeTracker< NUM_DIMENSIONS, Object >::_setScope( Object object )
- {
- // If there's no reference object, all objects are out of scope.
-
- if( !mReferenceObject || object == mReferenceObject )
- {
- Deref( object ).clearScopeMask();
- return;
- }
- const bool wasInScope = Deref( object ).isInScope();
- // Set the scoping state on each axis.
-
- for( U32 n = 0; n < NUM_DIMENSIONS; ++ n )
- {
- const F32 referencePos = Deref( mReferenceObject ).getMinTrackingNode( n )->getPosition();
- const F32 objectMin = Deref( object ).getMinTrackingNode( n )->getPosition();
- const F32 objectMax = Deref( object ).getMaxTrackingNode( n )->getPosition();
- bool isInScope = referencePos >= objectMin
- && referencePos <= objectMax;
-
- Deref( object ).setInScope( n, isInScope );
- }
-
- // Scope in/out if the scoping state has changed.
-
- if( Deref( object ).isInScope() )
- {
- if( !wasInScope )
- _onScopeIn( object );
- }
- else
- {
- if( wasInScope )
- _onScopeOut( object );
- }
- }
- //-----------------------------------------------------------------------------
- template< S32 NUM_DIMENSIONS, class Object >
- void ScopeTracker< NUM_DIMENSIONS, Object >::_initTracking()
- {
- PROFILE_SCOPE( ScopeTracker_initTracking );
-
- AssertFatal( bool( getReferenceObject() ),
- "ScopeTracker::_initTracking - can only be called with a valid reference object" );
-
- // Put a single tracking node onto each of the lists for
- // the reference object center.
-
- F32 position[ NUM_DIMENSIONS ];
- Deref( mReferenceObject ).getReferenceCenter( position );
-
- for( U32 n = 0; n < NUM_DIMENSIONS; ++ n )
- {
- AssertFatal( TypeTraits< F32 >::MIN <= position[ n ] && position[ n ] <= TypeTraits< F32 >::MAX, "Invalid float in object coordinate!" );
- NodeType* node = Deref( mReferenceObject ).getMinTrackingNode( n );
- node->mFlags.set( NodeType::FLAG_Reference );
-
- node->setPosition( position[ n ] );
-
- _insertTrackingNode( n, node );
- }
- // Update the surroundings of the reference object
- // in the tracking lists for each dimension.
-
- for( U32 n = 0; n < NUM_DIMENSIONS; ++ n )
- {
- //TODO: this could be optimized by dynamically determining whether to walk upwards
- // or downwards depending on which span has fewer nodes; finding that out is not immediately
- // obvious, though
-
- // Walk from the left bound node upwards until we reach the
- // reference object's marker. Everything that has its max node
- // past the reference object is in scope.
-
- F32 referencePos = Deref( mReferenceObject ).getMinTrackingNode( n )->getPosition();
- for( NodeType* node = mTrackingList[ n ][ 0 ]->getNext(); node->getPosition() < referencePos; node = node->getNext() )
- if( !node->isMax() && node->getOpposite()->getPosition() > referencePos )
- {
- node->getObject()->setInScope( n, true );
-
- // If this is the last dimension we're working on and
- // the current object is in-scope on all dimension,
- // promote to in-scope status.
-
- if( n == ( NUM_DIMENSIONS - 1 ) && node->getObject()->isInScope() )
- _onScopeIn( ( Object ) node->getObject() );
- }
- }
- }
- //-----------------------------------------------------------------------------
- template< S32 NUM_DIMENSIONS, class Object >
- void ScopeTracker< NUM_DIMENSIONS, Object >::_uninitTracking()
- {
- PROFILE_SCOPE( ScopeTracker_uninitTracking );
-
- AssertFatal( bool( getReferenceObject() ),
- "ScopeTracker::_uninitTracking - can only be called with a valid reference object" );
-
- // Put all objects currently in scope, out of scope.
-
- for( U32 n = 0; n < NUM_DIMENSIONS; ++ n )
- {
- U32 referencePos = Deref( mReferenceObject ).getMinTrackingNode( n )->getPosition();
- for( NodeType* node = mTrackingList[ n ][ 0 ]->getNext(); node->getPosition() < referencePos; node = node->getNext() )
- {
- if( node->getObject()->isInScope() )
- _onScopeOut( ( Object ) node->getObject() );
- node->getObject()->clearScopeMask();
- }
- }
-
- // Remove the reference object's tracking nodes.
-
- for( U32 n = 0; n < NUM_DIMENSIONS; ++ n )
- _removeTrackingNode( n, Deref( mReferenceObject ).getMinTrackingNode( n ) );
- }
- //-----------------------------------------------------------------------------
- template< S32 NUM_DIMENSIONS, class Object >
- void ScopeTracker< NUM_DIMENSIONS, Object >::debugDump()
- {
- for( U32 n = 0; n < NUM_DIMENSIONS; ++ n )
- {
- Con::printf( "Dimension %i", n );
- Con::printf( "----------------" );
-
- for( NodeType* node = mTrackingList[ n ][ 0 ]; node != NULL; node = node->getNext() )
- {
- String desc;
- if( node->getObject() )
- {
- Object object = ( Object ) node->getObject();
- desc = Deref( object ).describeSelf();
- }
- Con::printf( "pos=%f, type=%s, scope=%s, object=%s",
- node->getPosition(),
- node->isReference() ? "reference" : node->isMin() ? "min" : "max",
- node->getObject() ? node->getObject()->isInScope( n ) ? "1" : "0" : "0",
- desc.c_str() );
- }
-
- Con::printf( "" );
- }
- }
- #endif // !_SCOPETRACKER_H_
|