processList.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  23. // Arcane-FX for MIT Licensed Open Source version of Torque 3D from GarageGames
  24. // Copyright (C) 2015 Faust Logic, Inc.
  25. //~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~//~~~~~~~~~~~~~~~~~~~~~//
  26. #include "platform/platform.h"
  27. #include "T3D/gameBase/processList.h"
  28. #include "T3D/gameBase/gameBase.h"
  29. #include "platform/profiler.h"
  30. #include "console/consoleTypes.h"
  31. #include "T3D/components/coreInterfaces.h"
  32. #include "T3D/components/component.h"
  33. //----------------------------------------------------------------------------
  34. ProcessObject::ProcessObject()
  35. : mProcessTag( 0 ),
  36. mOrderGUID( 0 ),
  37. mProcessTick( false ),
  38. mIsGameBase( false )
  39. {
  40. mProcessLink.next = mProcessLink.prev = this;
  41. }
  42. void ProcessObject::plUnlink()
  43. {
  44. mProcessLink.next->mProcessLink.prev = mProcessLink.prev;
  45. mProcessLink.prev->mProcessLink.next = mProcessLink.next;
  46. mProcessLink.next = mProcessLink.prev = this;
  47. }
  48. void ProcessObject::plLinkAfter(ProcessObject * obj)
  49. {
  50. AssertFatal(mProcessLink.next == this && mProcessLink.prev == this,"ProcessObject::plLinkAfter: must be unlinked before calling this");
  51. #ifdef TORQUE_DEBUG
  52. ProcessObject * test1 = obj;
  53. ProcessObject * test2 = obj->mProcessLink.next;
  54. ProcessObject * test3 = obj->mProcessLink.prev;
  55. ProcessObject * test4 = this;
  56. #endif
  57. // Link this after obj
  58. mProcessLink.next = obj->mProcessLink.next;
  59. mProcessLink.prev = obj;
  60. obj->mProcessLink.next = this;
  61. mProcessLink.next->mProcessLink.prev = this;
  62. #ifdef TORQUE_DEBUG
  63. AssertFatal(test1->mProcessLink.next->mProcessLink.prev==test1 && test1->mProcessLink.prev->mProcessLink.next==test1,"Doh!");
  64. AssertFatal(test2->mProcessLink.next->mProcessLink.prev==test2 && test2->mProcessLink.prev->mProcessLink.next==test2,"Doh!");
  65. AssertFatal(test3->mProcessLink.next->mProcessLink.prev==test3 && test3->mProcessLink.prev->mProcessLink.next==test3,"Doh!");
  66. AssertFatal(test4->mProcessLink.next->mProcessLink.prev==test4 && test4->mProcessLink.prev->mProcessLink.next==test4,"Doh!");
  67. #endif
  68. }
  69. void ProcessObject::plLinkBefore(ProcessObject * obj)
  70. {
  71. AssertFatal(mProcessLink.next == this && mProcessLink.prev == this,"ProcessObject::plLinkBefore: must be unlinked before calling this");
  72. #ifdef TORQUE_DEBUG
  73. ProcessObject * test1 = obj;
  74. ProcessObject * test2 = obj->mProcessLink.next;
  75. ProcessObject * test3 = obj->mProcessLink.prev;
  76. ProcessObject * test4 = this;
  77. #endif
  78. // Link this before obj
  79. mProcessLink.next = obj;
  80. mProcessLink.prev = obj->mProcessLink.prev;
  81. obj->mProcessLink.prev = this;
  82. mProcessLink.prev->mProcessLink.next = this;
  83. #ifdef TORQUE_DEBUG
  84. AssertFatal(test1->mProcessLink.next->mProcessLink.prev==test1 && test1->mProcessLink.prev->mProcessLink.next==test1,"Doh!");
  85. AssertFatal(test2->mProcessLink.next->mProcessLink.prev==test2 && test2->mProcessLink.prev->mProcessLink.next==test2,"Doh!");
  86. AssertFatal(test3->mProcessLink.next->mProcessLink.prev==test3 && test3->mProcessLink.prev->mProcessLink.next==test3,"Doh!");
  87. AssertFatal(test4->mProcessLink.next->mProcessLink.prev==test4 && test4->mProcessLink.prev->mProcessLink.next==test4,"Doh!");
  88. #endif
  89. }
  90. void ProcessObject::plJoin(ProcessObject * head)
  91. {
  92. ProcessObject * tail1 = head->mProcessLink.prev;
  93. ProcessObject * tail2 = mProcessLink.prev;
  94. tail1->mProcessLink.next = this;
  95. mProcessLink.prev = tail1;
  96. tail2->mProcessLink.next = head;
  97. head->mProcessLink.prev = tail2;
  98. }
  99. //--------------------------------------------------------------------------
  100. ProcessList::ProcessList()
  101. {
  102. mCurrentTag = 0;
  103. mDirty = false;
  104. mTotalTicks = 0;
  105. mLastTick = 0;
  106. mLastTime = 0;
  107. mLastDelta = 0.0f;
  108. }
  109. void ProcessList::addObject( ProcessObject *obj )
  110. {
  111. obj->plLinkAfter(&mHead);
  112. }
  113. //----------------------------------------------------------------------------
  114. void ProcessList::orderList()
  115. {
  116. // ProcessObject tags are initialized to 0, so current tag should never be 0.
  117. if (++mCurrentTag == 0)
  118. mCurrentTag++;
  119. // Install a temporary head node
  120. ProcessObject list;
  121. list.plLinkBefore(mHead.mProcessLink.next);
  122. mHead.plUnlink();
  123. // start out by (bubble) sorting list by GUID
  124. for (ProcessObject * cur = list.mProcessLink.next; cur != &list; cur = cur->mProcessLink.next)
  125. {
  126. if (cur->mOrderGUID == 0)
  127. // special case -- can be no lower, so accept as lowest (this is also
  128. // a common value since it is what non ordered objects have)
  129. continue;
  130. for (ProcessObject * walk = cur->mProcessLink.next; walk != &list; walk = walk->mProcessLink.next)
  131. {
  132. if (walk->mOrderGUID < cur->mOrderGUID)
  133. {
  134. // swap walk and cur -- need to be careful because walk might be just after cur
  135. // so insert after item before cur and before item after walk
  136. ProcessObject * before = cur->mProcessLink.prev;
  137. ProcessObject * after = walk->mProcessLink.next;
  138. cur->plUnlink();
  139. walk->plUnlink();
  140. cur->plLinkBefore(after);
  141. walk->plLinkAfter(before);
  142. ProcessObject * swap = walk;
  143. walk = cur;
  144. cur = swap;
  145. }
  146. }
  147. }
  148. // Reverse topological sort into the original head node
  149. while (list.mProcessLink.next != &list)
  150. {
  151. ProcessObject * ptr = list.mProcessLink.next;
  152. ProcessObject * afterObject = ptr->getAfterObject();
  153. ptr->mProcessTag = mCurrentTag;
  154. ptr->plUnlink();
  155. if (afterObject)
  156. {
  157. // Build chain "stack" of dependent objects and patch
  158. // it to the end of the current list.
  159. while (afterObject && afterObject->mProcessTag != mCurrentTag)
  160. {
  161. afterObject->mProcessTag = mCurrentTag;
  162. afterObject->plUnlink();
  163. afterObject->plLinkBefore(ptr);
  164. ptr = afterObject;
  165. afterObject = ptr->getAfterObject();
  166. }
  167. ptr->plJoin(&mHead);
  168. }
  169. else
  170. ptr->plLinkBefore(&mHead);
  171. }
  172. mDirty = false;
  173. }
  174. GameBase* ProcessList::getGameBase( ProcessObject *obj )
  175. {
  176. if ( !obj->mIsGameBase )
  177. return NULL;
  178. return static_cast< GameBase* >( obj );
  179. }
  180. void ProcessList::dumpToConsole()
  181. {
  182. for (ProcessObject * pobj = mHead.mProcessLink.next; pobj != &mHead; pobj = pobj->mProcessLink.next)
  183. {
  184. SimObject * obj = dynamic_cast<SimObject*>(pobj);
  185. if (obj)
  186. Con::printf("id %i, order guid %i, type %s", obj->getId(), pobj->mOrderGUID, obj->getClassName());
  187. else
  188. Con::printf("---unknown object type, order guid %i", pobj->mOrderGUID);
  189. }
  190. }
  191. //----------------------------------------------------------------------------
  192. bool ProcessList::advanceTime(SimTime timeDelta)
  193. {
  194. PROFILE_START(ProcessList_AdvanceTime);
  195. // some drivers change the FPU control state, which will break our control object simulation
  196. // (leading to packet mismatch errors due to small FP differences). So set it to the known
  197. // state before advancing.
  198. U32 mathState = Platform::getMathControlState();
  199. Platform::setMathControlStateKnown();
  200. if (mDirty)
  201. orderList();
  202. SimTime targetTime = mLastTime + timeDelta;
  203. SimTime targetTick = targetTime - (targetTime % TickMs);
  204. SimTime tickDelta = targetTick - mLastTick;
  205. bool tickPass = mLastTick != targetTick;
  206. if ( tickPass )
  207. mPreTick.trigger();
  208. // Advance all the objects.
  209. for (; mLastTick != targetTick; mLastTick += TickMs)
  210. onAdvanceObjects();
  211. mLastTime = targetTime;
  212. mLastDelta = ((TickMs - ((targetTime+1) % TickMs)) % TickMs) / F32(TickMs);
  213. if ( tickPass )
  214. mPostTick.trigger( tickDelta );
  215. // restore math control state in case others are relying on it being a certain value
  216. Platform::setMathControlState(mathState);
  217. PROFILE_END();
  218. return tickPass;
  219. }
  220. //----------------------------------------------------------------------------
  221. void ProcessList::advanceObjects()
  222. {
  223. PROFILE_START(ProcessList_AdvanceObjects);
  224. // A little link list shuffling is done here to avoid problems
  225. // with objects being deleted from within the process method.
  226. ProcessObject list;
  227. list.plLinkBefore(mHead.mProcessLink.next);
  228. mHead.plUnlink();
  229. for (ProcessObject * pobj = list.mProcessLink.next; pobj != &list; pobj = list.mProcessLink.next)
  230. {
  231. pobj->plUnlink();
  232. pobj->plLinkBefore(&mHead);
  233. onTickObject(pobj);
  234. }
  235. for (U32 i = 0; i < UpdateInterface::all.size(); i++)
  236. {
  237. UpdateInterface::all[i]->processTick();
  238. }
  239. mTotalTicks++;
  240. PROFILE_END();
  241. }
  242. ProcessObject* ProcessList::findNearestToEnd(Vector<ProcessObject*>& objs) const
  243. {
  244. if (objs.empty())
  245. return 0;
  246. for (ProcessObject* obj = mHead.mProcessLink.prev; obj != &mHead; obj = obj->mProcessLink.prev)
  247. {
  248. for (S32 i = 0; i < objs.size(); i++)
  249. {
  250. if (obj == objs[i])
  251. return obj;
  252. }
  253. }
  254. return 0;
  255. }