iTickable.cpp
Engine/source/core/iTickable.cpp
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "core/iTickable.h" 25 26// The statics 27U32 ITickable::smLastTick = 0; 28U32 ITickable::smLastTime = 0; 29U32 ITickable::smLastDelta = 0; 30 31U32 ITickable::smTickShift = 5; 32U32 ITickable::smTickMs = ( 1 << smTickShift ); 33F32 ITickable::smTickSec = ( F32( ITickable::smTickMs ) / 1000.f ); 34U32 ITickable::smTickMask = ( smTickMs - 1 ); 35 36//------------------------------------------------------------------------------ 37 38ITickable::ITickable() : mProcessTick( true ) 39{ 40 getProcessList().push_back( this ); 41} 42 43//------------------------------------------------------------------------------ 44 45ITickable::~ITickable() 46{ 47 for( ProcessListIterator i = getProcessList().begin(); i != getProcessList().end(); i++ ) 48 { 49 if( (*i) == this ) 50 { 51 getProcessList().erase( i ); 52 return; 53 } 54 } 55} 56 57//------------------------------------------------------------------------------ 58 59void ITickable::init( const U32 tickShift ) 60{ 61 // Sanity! 62 AssertFatal( tickShift == 0 || tickShift <= 31, "ITickable::init() - Invalid 'tickShift' parameter!" ); 63 64 // Calculate tick constants. 65 smTickShift = tickShift; 66 smTickMs = ( 1 << smTickShift ); 67 smTickSec = ( F32( smTickMs ) / 1000.f ); 68 smTickMask = ( smTickMs - 1 ); 69} 70 71//------------------------------------------------------------------------------ 72 73Vector<ITickable*>& ITickable::getProcessList() 74{ 75 // This helps to avoid the static initialization order fiasco 76 static Vector<ITickable*> smProcessList( __FILE__, __LINE__ ); ///< List of tick controls 77 return smProcessList; 78} 79 80//------------------------------------------------------------------------------ 81 82bool ITickable::advanceTime( U32 timeDelta ) 83{ 84 U32 targetTime = smLastTime + timeDelta; 85 U32 targetTick = ( targetTime + smTickMask ) & ~smTickMask; 86 U32 tickCount = ( targetTick - smLastTick ) >> smTickShift; 87 88 // Advance objects 89 if( tickCount ) 90 { 91 for( ; smLastTick != targetTick; smLastTick += smTickMs ) 92 { 93 for( U32 i=0; i < getProcessList().size(); ) 94 { 95 ITickable* iTick = getProcessList()[i]; 96 if( iTick->isProcessingTicks() ) 97 { 98 iTick->processTick(); 99 100 // Only advance counter if the tickable hasn't deleted itself 101 if( i < getProcessList().size() && iTick == getProcessList()[i] ) 102 ++i; 103 } 104 else 105 { 106 // Move onto the next tickable 107 ++i; 108 } 109 } 110 } 111 } 112 113 smLastDelta = ( smTickMs - ( targetTime & smTickMask ) ) & smTickMask; 114 F32 dt = smLastDelta / F32( smTickMs ); 115 116 // Now interpolate objects that want ticks. Note that an object should never delete 117 // itself during an interpolateTick(). 118 for( ProcessListIterator i = getProcessList().begin(); i != getProcessList().end(); i++ ) 119 if( (*i)->isProcessingTicks() ) 120 (*i)->interpolateTick( dt ); 121 122 123 // Inform ALL objects that time was advanced 124 dt = F32( timeDelta ) / 1000.f; 125 for( U32 i=0; i < getProcessList().size(); ) 126 { 127 ITickable* iTick = getProcessList()[i]; 128 iTick->advanceTime( dt ); 129 130 // Only advance counter if the tickable hasn't deleted itself 131 if( i < getProcessList().size() && iTick == getProcessList()[i] ) 132 ++i; 133 } 134 135 smLastTime = targetTime; 136 137 return tickCount != 0; 138} 139