processList.cpp
Engine/source/T3D/gameBase/processList.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//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~// 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