processList.cpp 10 KB

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