Torque3D Documentation / _generateds / processList.cpp

processList.cpp

Engine/source/T3D/gameBase/processList.cpp

More...

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//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 25// Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
 26// Copyright (C) 2015 Faust Logic, Inc.
 27//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
 28
 29#include "platform/platform.h"
 30#include "T3D/gameBase/processList.h"
 31
 32#include "T3D/gameBase/gameBase.h"
 33#include "platform/profiler.h"
 34#include "console/consoleTypes.h"
 35
 36//----------------------------------------------------------------------------
 37
 38ProcessObject::ProcessObject()
 39 : mProcessTag( 0 ),   
 40   mOrderGUID( 0 ),
 41   mProcessTick( false ),
 42   mIsGameBase( false )
 43{ 
 44   mProcessLink.next = mProcessLink.prev = this;
 45}
 46
 47void ProcessObject::plUnlink()
 48{
 49   mProcessLink.next->mProcessLink.prev = mProcessLink.prev;
 50   mProcessLink.prev->mProcessLink.next = mProcessLink.next;
 51   mProcessLink.next = mProcessLink.prev = this;
 52}
 53
 54void ProcessObject::plLinkAfter(ProcessObject * obj)
 55{
 56   AssertFatal(mProcessLink.next == this && mProcessLink.prev == this,"ProcessObject::plLinkAfter: must be unlinked before calling this");
 57#ifdef TORQUE_DEBUG
 58   ProcessObject * test1 = obj;
 59   ProcessObject * test2 = obj->mProcessLink.next;
 60   ProcessObject * test3 = obj->mProcessLink.prev;
 61   ProcessObject * test4 = this;
 62#endif
 63
 64   // Link this after obj
 65   mProcessLink.next = obj->mProcessLink.next;
 66   mProcessLink.prev = obj;
 67   obj->mProcessLink.next = this;
 68   mProcessLink.next->mProcessLink.prev = this;
 69
 70#ifdef TORQUE_DEBUG
 71   AssertFatal(test1->mProcessLink.next->mProcessLink.prev==test1 && test1->mProcessLink.prev->mProcessLink.next==test1,"Doh!");
 72   AssertFatal(test2->mProcessLink.next->mProcessLink.prev==test2 && test2->mProcessLink.prev->mProcessLink.next==test2,"Doh!");
 73   AssertFatal(test3->mProcessLink.next->mProcessLink.prev==test3 && test3->mProcessLink.prev->mProcessLink.next==test3,"Doh!");
 74   AssertFatal(test4->mProcessLink.next->mProcessLink.prev==test4 && test4->mProcessLink.prev->mProcessLink.next==test4,"Doh!");
 75#endif
 76}
 77
 78void ProcessObject::plLinkBefore(ProcessObject * obj)
 79{
 80   AssertFatal(mProcessLink.next == this && mProcessLink.prev == this,"ProcessObject::plLinkBefore: must be unlinked before calling this");
 81#ifdef TORQUE_DEBUG
 82   ProcessObject * test1 = obj;
 83   ProcessObject * test2 = obj->mProcessLink.next;
 84   ProcessObject * test3 = obj->mProcessLink.prev;
 85   ProcessObject * test4 = this;
 86#endif
 87
 88   // Link this before obj
 89   mProcessLink.next = obj;
 90   mProcessLink.prev = obj->mProcessLink.prev;
 91   obj->mProcessLink.prev = this;
 92   mProcessLink.prev->mProcessLink.next = this;
 93
 94#ifdef TORQUE_DEBUG
 95   AssertFatal(test1->mProcessLink.next->mProcessLink.prev==test1 && test1->mProcessLink.prev->mProcessLink.next==test1,"Doh!");
 96   AssertFatal(test2->mProcessLink.next->mProcessLink.prev==test2 && test2->mProcessLink.prev->mProcessLink.next==test2,"Doh!");
 97   AssertFatal(test3->mProcessLink.next->mProcessLink.prev==test3 && test3->mProcessLink.prev->mProcessLink.next==test3,"Doh!");
 98   AssertFatal(test4->mProcessLink.next->mProcessLink.prev==test4 && test4->mProcessLink.prev->mProcessLink.next==test4,"Doh!");
 99#endif
100}
101
102void ProcessObject::plJoin(ProcessObject * head)
103{
104   ProcessObject * tail1 = head->mProcessLink.prev;
105   ProcessObject * tail2 = mProcessLink.prev;
106   tail1->mProcessLink.next = this;
107   mProcessLink.prev = tail1;
108   tail2->mProcessLink.next = head;
109   head->mProcessLink.prev = tail2;
110}
111
112//--------------------------------------------------------------------------
113
114ProcessList::ProcessList()
115{
116   mCurrentTag = 0;
117   mDirty = false;
118
119   mTotalTicks = 0;
120   mLastTick = 0;
121   mLastTime = 0;
122   mLastDelta = 0.0f;
123}
124
125void ProcessList::addObject( ProcessObject *obj )
126{
127   obj->plLinkAfter(&mHead);
128}
129
130//----------------------------------------------------------------------------
131
132void ProcessList::orderList()
133{
134   // ProcessObject tags are initialized to 0, so current tag should never be 0.
135   if (++mCurrentTag == 0)
136      mCurrentTag++;
137
138   // Install a temporary head node
139   ProcessObject list;
140   list.plLinkBefore(mHead.mProcessLink.next);
141   mHead.plUnlink();
142
143   // start out by (bubble) sorting list by GUID
144   for (ProcessObject * cur = list.mProcessLink.next; cur != &list; cur = cur->mProcessLink.next)
145   {
146      if (cur->mOrderGUID == 0)
147         // special case -- can be no lower, so accept as lowest (this is also
148         // a common value since it is what non ordered objects have)
149         continue;
150
151      for (ProcessObject * walk = cur->mProcessLink.next; walk != &list; walk = walk->mProcessLink.next)
152      {
153         if (walk->mOrderGUID < cur->mOrderGUID)
154         {
155            // swap walk and cur -- need to be careful because walk might be just after cur
156            // so insert after item before cur and before item after walk
157            ProcessObject * before = cur->mProcessLink.prev;
158            ProcessObject * after = walk->mProcessLink.next;
159            cur->plUnlink();
160            walk->plUnlink();
161            cur->plLinkBefore(after);
162            walk->plLinkAfter(before);
163            ProcessObject * swap = walk;
164            walk = cur;
165            cur = swap;
166         }
167      }
168   }
169
170   // Reverse topological sort into the original head node
171   while (list.mProcessLink.next != &list) 
172   {
173      ProcessObject * ptr = list.mProcessLink.next;
174      ProcessObject * afterObject = ptr->getAfterObject();
175      ptr->mProcessTag = mCurrentTag;
176      ptr->plUnlink();
177      if (afterObject) 
178      {
179         // Build chain "stack" of dependent objects and patch
180         // it to the end of the current list.
181         while (afterObject && afterObject->mProcessTag != mCurrentTag)
182         {
183            afterObject->mProcessTag = mCurrentTag;
184            afterObject->plUnlink();
185            afterObject->plLinkBefore(ptr);
186            ptr = afterObject;
187            afterObject = ptr->getAfterObject();
188         }
189         ptr->plJoin(&mHead);
190      }
191      else
192         ptr->plLinkBefore(&mHead);
193   }
194   mDirty = false;
195}
196
197GameBase* ProcessList::getGameBase( ProcessObject *obj )
198{
199   if ( !obj->mIsGameBase )
200      return NULL;
201
202   return static_cast< GameBase* >( obj );
203}
204
205
206void ProcessList::dumpToConsole()
207{
208   for (ProcessObject * pobj = mHead.mProcessLink.next; pobj != &mHead; pobj = pobj->mProcessLink.next)
209   {
210      SimObject * obj = dynamic_cast<SimObject*>(pobj);
211      if (obj)
212         Con::printf("id %i, order guid %i, type %s", obj->getId(), pobj->mOrderGUID, obj->getClassName());
213      else
214         Con::printf("---unknown object type, order guid %i", pobj->mOrderGUID);
215   }
216}
217
218//----------------------------------------------------------------------------
219
220bool ProcessList::advanceTime(SimTime timeDelta)
221{
222   PROFILE_START(ProcessList_AdvanceTime);
223
224   // some drivers change the FPU control state, which will break our control object simulation
225   // (leading to packet mismatch errors due to small FP differences).  So set it to the known 
226   // state before advancing.
227   U32 mathState = Platform::getMathControlState();
228   Platform::setMathControlStateKnown();
229
230   if (mDirty) 
231      orderList();
232
233   SimTime targetTime = mLastTime + timeDelta;
234   SimTime targetTick = targetTime - (targetTime % TickMs);
235   SimTime tickDelta = targetTick - mLastTick;
236   bool tickPass = mLastTick != targetTick;
237
238   if ( tickPass )
239      mPreTick.trigger();
240
241   // Advance all the objects.
242   for (; mLastTick != targetTick; mLastTick += TickMs)
243      onAdvanceObjects();
244
245   mLastTime = targetTime;
246   mLastDelta = ((TickMs - ((targetTime+1) % TickMs)) % TickMs) / F32(TickMs);
247
248   if ( tickPass )
249      mPostTick.trigger( tickDelta );
250
251   // restore math control state in case others are relying on it being a certain value
252   Platform::setMathControlState(mathState);
253
254   PROFILE_END();
255   return tickPass;
256}
257
258//----------------------------------------------------------------------------
259
260void ProcessList::advanceObjects()
261{
262   PROFILE_START(ProcessList_AdvanceObjects);
263
264   // A little link list shuffling is done here to avoid problems
265   // with objects being deleted from within the process method.
266   ProcessObject list;
267   list.plLinkBefore(mHead.mProcessLink.next);
268   mHead.plUnlink();
269   for (ProcessObject * pobj = list.mProcessLink.next; pobj != &list; pobj = list.mProcessLink.next)
270   {
271      pobj->plUnlink();
272      pobj->plLinkBefore(&mHead);
273      
274      onTickObject(pobj);
275   }
276
277   mTotalTicks++;
278
279   PROFILE_END();
280}
281
282ProcessObject* ProcessList::findNearestToEnd(Vector<ProcessObject*>& objs) const
283{
284   if (objs.empty())
285      return 0;
286
287   for (ProcessObject* obj = mHead.mProcessLink.prev; obj != &mHead; obj = obj->mProcessLink.prev)
288   {
289      for (S32 i = 0; i < objs.size(); i++)
290      {
291         if (obj == objs[i])
292            return obj;
293      }
294   }
295
296   return 0;
297}
298
299