collisionInterfaces.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  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. #include "T3D/components/collision/collisionInterfaces.h"
  23. #include "scene/sceneObject.h"
  24. #include "T3D/entity.h"
  25. #include "console/engineAPI.h"
  26. #include "T3D/trigger.h"
  27. #include "materials/baseMatInstance.h"
  28. void CollisionInterface::handleCollisionList( CollisionList &collisionList, VectorF velocity )
  29. {
  30. Collision bestCol;
  31. mCollisionList = collisionList;
  32. for (U32 i=0; i < collisionList.getCount(); ++i)
  33. {
  34. Collision& colCheck = collisionList[i];
  35. if (colCheck.object)
  36. {
  37. if (colCheck.object->getTypeMask() & PlayerObjectType)
  38. {
  39. handleCollision( colCheck, velocity );
  40. }
  41. else if (colCheck.object->getTypeMask() & TriggerObjectType)
  42. {
  43. // We've hit it's bounding box, that's close enough for triggers
  44. Trigger* pTrigger = static_cast<Trigger*>(colCheck.object);
  45. Component *comp = dynamic_cast<Component*>(this);
  46. pTrigger->potentialEnterObject(comp->getOwner());
  47. }
  48. else if (colCheck.object->getTypeMask() & DynamicShapeObjectType)
  49. {
  50. Con::printf("HIT A GENERICALLY DYNAMIC OBJECT");
  51. handleCollision(colCheck, velocity);
  52. }
  53. else if(colCheck.object->getTypeMask() & EntityObjectType)
  54. {
  55. Entity* ent = dynamic_cast<Entity*>(colCheck.object);
  56. if (ent)
  57. {
  58. CollisionInterface *colObjectInterface = ent->getComponent<CollisionInterface>();
  59. if (colObjectInterface)
  60. {
  61. //convert us to our component
  62. Component *thisComp = dynamic_cast<Component*>(this);
  63. if (thisComp)
  64. {
  65. colObjectInterface->onCollisionSignal.trigger(thisComp->getOwner());
  66. //TODO: properly do this
  67. Collision oppositeCol = colCheck;
  68. oppositeCol.object = thisComp->getOwner();
  69. colObjectInterface->handleCollision(oppositeCol, velocity);
  70. }
  71. }
  72. }
  73. }
  74. else
  75. {
  76. handleCollision(colCheck, velocity);
  77. }
  78. }
  79. }
  80. }
  81. void CollisionInterface::handleCollision( Collision &col, VectorF velocity )
  82. {
  83. if (col.object && (mContactInfo.contactObject == NULL ||
  84. col.object->getId() != mContactInfo.contactObject->getId()))
  85. {
  86. queueCollision(col.object, velocity - col.object->getVelocity());
  87. //do the callbacks to script for this collision
  88. Component *comp = dynamic_cast<Component*>(this);
  89. if (comp->isMethod("onCollision"))
  90. {
  91. S32 matId = col.material != NULL ? col.material->getMaterial()->getId() : 0;
  92. Con::executef(comp, "onCollision", col.object, col.normal, col.point, matId, velocity);
  93. }
  94. if (comp->getOwner()->isMethod("onCollisionEvent"))
  95. {
  96. S32 matId = col.material != NULL ? col.material->getMaterial()->getId() : 0;
  97. Con::executef(comp->getOwner(), "onCollisionEvent", col.object, col.normal, col.point, matId, velocity);
  98. }
  99. }
  100. }
  101. void CollisionInterface::handleCollisionNotifyList()
  102. {
  103. //special handling for any collision components we should notify that a collision happened.
  104. for (U32 i = 0; i < mCollisionNotifyList.size(); ++i)
  105. {
  106. //convert us to our component
  107. Component *thisComp = dynamic_cast<Component*>(this);
  108. if (thisComp)
  109. {
  110. mCollisionNotifyList[i]->onCollisionSignal.trigger(thisComp->getOwner());
  111. }
  112. }
  113. mCollisionNotifyList.clear();
  114. }
  115. Chunker<CollisionInterface::CollisionTimeout> sTimeoutChunker;
  116. CollisionInterface::CollisionTimeout* CollisionInterface::sFreeTimeoutList = 0;
  117. void CollisionInterface::queueCollision( SceneObject *obj, const VectorF &vec)
  118. {
  119. // Add object to list of collisions.
  120. SimTime time = Sim::getCurrentTime();
  121. S32 num = obj->getId();
  122. CollisionTimeout** adr = &mTimeoutList;
  123. CollisionTimeout* ptr = mTimeoutList;
  124. while (ptr)
  125. {
  126. if (ptr->objectNumber == num)
  127. {
  128. if (ptr->expireTime < time)
  129. {
  130. ptr->expireTime = time + CollisionTimeoutValue;
  131. ptr->object = obj;
  132. ptr->vector = vec;
  133. }
  134. return;
  135. }
  136. // Recover expired entries
  137. if (ptr->expireTime < time)
  138. {
  139. CollisionTimeout* cur = ptr;
  140. *adr = ptr->next;
  141. ptr = ptr->next;
  142. cur->next = sFreeTimeoutList;
  143. sFreeTimeoutList = cur;
  144. }
  145. else
  146. {
  147. adr = &ptr->next;
  148. ptr = ptr->next;
  149. }
  150. }
  151. // New entry for the object
  152. if (sFreeTimeoutList != NULL)
  153. {
  154. ptr = sFreeTimeoutList;
  155. sFreeTimeoutList = ptr->next;
  156. ptr->next = NULL;
  157. }
  158. else
  159. {
  160. ptr = sTimeoutChunker.alloc();
  161. }
  162. ptr->object = obj;
  163. ptr->objectNumber = obj->getId();
  164. ptr->vector = vec;
  165. ptr->expireTime = time + CollisionTimeoutValue;
  166. ptr->next = mTimeoutList;
  167. mTimeoutList = ptr;
  168. }
  169. bool CollisionInterface::checkEarlyOut(Point3F start, VectorF velocity, F32 time, Box3F objectBox, Point3F objectScale,
  170. Box3F collisionBox, U32 collisionMask, CollisionWorkingList &colWorkingList)
  171. {
  172. Point3F end = start + velocity * time;
  173. Point3F distance = end - start;
  174. Box3F scaledBox = objectBox;
  175. scaledBox.minExtents.convolve(objectScale);
  176. scaledBox.maxExtents.convolve(objectScale);
  177. if (mFabs(distance.x) < objectBox.len_x() &&
  178. mFabs(distance.y) < objectBox.len_y() &&
  179. mFabs(distance.z) < objectBox.len_z())
  180. {
  181. // We can potentially early out of this. If there are no polys in the clipped polylist at our
  182. // end position, then we can bail, and just set start = end;
  183. Box3F wBox = scaledBox;
  184. wBox.minExtents += end;
  185. wBox.maxExtents += end;
  186. static EarlyOutPolyList eaPolyList;
  187. eaPolyList.clear();
  188. eaPolyList.mNormal.set(0.0f, 0.0f, 0.0f);
  189. eaPolyList.mPlaneList.clear();
  190. eaPolyList.mPlaneList.setSize(6);
  191. eaPolyList.mPlaneList[0].set(wBox.minExtents,VectorF(-1.0f, 0.0f, 0.0f));
  192. eaPolyList.mPlaneList[1].set(wBox.maxExtents,VectorF(0.0f, 1.0f, 0.0f));
  193. eaPolyList.mPlaneList[2].set(wBox.maxExtents,VectorF(1.0f, 0.0f, 0.0f));
  194. eaPolyList.mPlaneList[3].set(wBox.minExtents,VectorF(0.0f, -1.0f, 0.0f));
  195. eaPolyList.mPlaneList[4].set(wBox.minExtents,VectorF(0.0f, 0.0f, -1.0f));
  196. eaPolyList.mPlaneList[5].set(wBox.maxExtents,VectorF(0.0f, 0.0f, 1.0f));
  197. // Build list from convex states here...
  198. CollisionWorkingList& rList = colWorkingList;
  199. CollisionWorkingList* pList = rList.wLink.mNext;
  200. while (pList != &rList)
  201. {
  202. Convex* pConvex = pList->mConvex;
  203. if (pConvex->getObject()->getTypeMask() & collisionMask)
  204. {
  205. Box3F convexBox = pConvex->getBoundingBox();
  206. if (wBox.isOverlapped(convexBox))
  207. {
  208. // No need to separate out the physical zones here, we want those
  209. // to cause a fallthrough as well...
  210. pConvex->getPolyList(&eaPolyList);
  211. }
  212. }
  213. pList = pList->wLink.mNext;
  214. }
  215. if (eaPolyList.isEmpty())
  216. {
  217. return true;
  218. }
  219. }
  220. return false;
  221. }
  222. Collision* CollisionInterface::getCollision(S32 col)
  223. {
  224. if(col < mCollisionList.getCount() && col >= 0)
  225. return &mCollisionList[col];
  226. else
  227. return NULL;
  228. }