CollisionModel_translate.cpp 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
  17. If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
  18. ===========================================================================
  19. */
  20. /*
  21. ===============================================================================
  22. Trace model vs. polygonal model collision detection.
  23. ===============================================================================
  24. */
  25. #pragma hdrstop
  26. #include "../idlib/precompiled.h"
  27. #include "CollisionModel_local.h"
  28. /*
  29. ===============================================================================
  30. Collision detection for translational motion
  31. ===============================================================================
  32. */
  33. /*
  34. ================
  35. idCollisionModelManagerLocal::TranslateEdgeThroughEdge
  36. calculates fraction of the translation completed at which the edges collide
  37. ================
  38. */
  39. ID_INLINE int idCollisionModelManagerLocal::TranslateEdgeThroughEdge( idVec3 &cross, idPluecker &l1, idPluecker &l2, float *fraction ) {
  40. float d, t;
  41. /*
  42. a = start of line
  43. b = end of line
  44. dir = movement direction
  45. l1 = pluecker coordinate for line
  46. l2 = pluecker coordinate for edge we might collide with
  47. a+dir = start of line after movement
  48. b+dir = end of line after movement
  49. t = scale factor
  50. solve pluecker inner product for t of line (a+t*dir : b+t*dir) and line l2
  51. v[0] = (a[0]+t*dir[0]) * (b[1]+t*dir[1]) - (b[0]+t*dir[0]) * (a[1]+t*dir[1]);
  52. v[1] = (a[0]+t*dir[0]) * (b[2]+t*dir[2]) - (b[0]+t*dir[0]) * (a[2]+t*dir[2]);
  53. v[2] = (a[0]+t*dir[0]) - (b[0]+t*dir[0]);
  54. v[3] = (a[1]+t*dir[1]) * (b[2]+t*dir[2]) - (b[1]+t*dir[1]) * (a[2]+t*dir[2]);
  55. v[4] = (a[2]+t*dir[2]) - (b[2]+t*dir[2]);
  56. v[5] = (b[1]+t*dir[1]) - (a[1]+t*dir[1]);
  57. l2[0] * v[4] + l2[1] * v[5] + l2[2] * v[3] + l2[4] * v[0] + l2[5] * v[1] + l2[3] * v[2] = 0;
  58. solve t
  59. v[0] = (a[0]+t*dir[0]) * (b[1]+t*dir[1]) - (b[0]+t*dir[0]) * (a[1]+t*dir[1]);
  60. v[0] = (a[0]*b[1]) + a[0]*t*dir[1] + b[1]*t*dir[0] + (t*t*dir[0]*dir[1]) -
  61. ((b[0]*a[1]) + b[0]*t*dir[1] + a[1]*t*dir[0] + (t*t*dir[0]*dir[1]));
  62. v[0] = a[0]*b[1] + a[0]*t*dir[1] + b[1]*t*dir[0] - b[0]*a[1] - b[0]*t*dir[1] - a[1]*t*dir[0];
  63. v[1] = (a[0]+t*dir[0]) * (b[2]+t*dir[2]) - (b[0]+t*dir[0]) * (a[2]+t*dir[2]);
  64. v[1] = (a[0]*b[2]) + a[0]*t*dir[2] + b[2]*t*dir[0] + (t*t*dir[0]*dir[2]) -
  65. ((b[0]*a[2]) + b[0]*t*dir[2] + a[2]*t*dir[0] + (t*t*dir[0]*dir[2]));
  66. v[1] = a[0]*b[2] + a[0]*t*dir[2] + b[2]*t*dir[0] - b[0]*a[2] - b[0]*t*dir[2] - a[2]*t*dir[0];
  67. v[2] = (a[0]+t*dir[0]) - (b[0]+t*dir[0]);
  68. v[2] = a[0] - b[0];
  69. v[3] = (a[1]+t*dir[1]) * (b[2]+t*dir[2]) - (b[1]+t*dir[1]) * (a[2]+t*dir[2]);
  70. v[3] = (a[1]*b[2]) + a[1]*t*dir[2] + b[2]*t*dir[1] + (t*t*dir[1]*dir[2]) -
  71. ((b[1]*a[2]) + b[1]*t*dir[2] + a[2]*t*dir[1] + (t*t*dir[1]*dir[2]));
  72. v[3] = a[1]*b[2] + a[1]*t*dir[2] + b[2]*t*dir[1] - b[1]*a[2] - b[1]*t*dir[2] - a[2]*t*dir[1];
  73. v[4] = (a[2]+t*dir[2]) - (b[2]+t*dir[2]);
  74. v[4] = a[2] - b[2];
  75. v[5] = (b[1]+t*dir[1]) - (a[1]+t*dir[1]);
  76. v[5] = b[1] - a[1];
  77. v[0] = a[0]*b[1] + a[0]*t*dir[1] + b[1]*t*dir[0] - b[0]*a[1] - b[0]*t*dir[1] - a[1]*t*dir[0];
  78. v[1] = a[0]*b[2] + a[0]*t*dir[2] + b[2]*t*dir[0] - b[0]*a[2] - b[0]*t*dir[2] - a[2]*t*dir[0];
  79. v[2] = a[0] - b[0];
  80. v[3] = a[1]*b[2] + a[1]*t*dir[2] + b[2]*t*dir[1] - b[1]*a[2] - b[1]*t*dir[2] - a[2]*t*dir[1];
  81. v[4] = a[2] - b[2];
  82. v[5] = b[1] - a[1];
  83. v[0] = (a[0]*dir[1] + b[1]*dir[0] - b[0]*dir[1] - a[1]*dir[0]) * t + a[0]*b[1] - b[0]*a[1];
  84. v[1] = (a[0]*dir[2] + b[2]*dir[0] - b[0]*dir[2] - a[2]*dir[0]) * t + a[0]*b[2] - b[0]*a[2];
  85. v[2] = a[0] - b[0];
  86. v[3] = (a[1]*dir[2] + b[2]*dir[1] - b[1]*dir[2] - a[2]*dir[1]) * t + a[1]*b[2] - b[1]*a[2];
  87. v[4] = a[2] - b[2];
  88. v[5] = b[1] - a[1];
  89. l2[4] * (a[0]*dir[1] + b[1]*dir[0] - b[0]*dir[1] - a[1]*dir[0]) * t + l2[4] * (a[0]*b[1] - b[0]*a[1])
  90. + l2[5] * (a[0]*dir[2] + b[2]*dir[0] - b[0]*dir[2] - a[2]*dir[0]) * t + l2[5] * (a[0]*b[2] - b[0]*a[2])
  91. + l2[3] * (a[0] - b[0])
  92. + l2[2] * (a[1]*dir[2] + b[2]*dir[1] - b[1]*dir[2] - a[2]*dir[1]) * t + l2[2] * (a[1]*b[2] - b[1]*a[2])
  93. + l2[0] * (a[2] - b[2])
  94. + l2[1] * (b[1] - a[1]) = 0
  95. t = (- l2[4] * (a[0]*b[1] - b[0]*a[1]) -
  96. l2[5] * (a[0]*b[2] - b[0]*a[2]) -
  97. l2[3] * (a[0] - b[0]) -
  98. l2[2] * (a[1]*b[2] - b[1]*a[2]) -
  99. l2[0] * (a[2] - b[2]) -
  100. l2[1] * (b[1] - a[1])) /
  101. (l2[4] * (a[0]*dir[1] + b[1]*dir[0] - b[0]*dir[1] - a[1]*dir[0]) +
  102. l2[5] * (a[0]*dir[2] + b[2]*dir[0] - b[0]*dir[2] - a[2]*dir[0]) +
  103. l2[2] * (a[1]*dir[2] + b[2]*dir[1] - b[1]*dir[2] - a[2]*dir[1]));
  104. d = l2[4] * (a[0]*dir[1] + b[1]*dir[0] - b[0]*dir[1] - a[1]*dir[0]) +
  105. l2[5] * (a[0]*dir[2] + b[2]*dir[0] - b[0]*dir[2] - a[2]*dir[0]) +
  106. l2[2] * (a[1]*dir[2] + b[2]*dir[1] - b[1]*dir[2] - a[2]*dir[1]);
  107. t = - ( l2[4] * (a[0]*b[1] - b[0]*a[1]) +
  108. l2[5] * (a[0]*b[2] - b[0]*a[2]) +
  109. l2[3] * (a[0] - b[0]) +
  110. l2[2] * (a[1]*b[2] - b[1]*a[2]) +
  111. l2[0] * (a[2] - b[2]) +
  112. l2[1] * (b[1] - a[1]));
  113. t /= d;
  114. MrE pats Pluecker on the head.. good monkey
  115. edgeDir = a - b;
  116. d = l2[4] * (edgeDir[0]*dir[1] - edgeDir[1]*dir[0]) +
  117. l2[5] * (edgeDir[0]*dir[2] - edgeDir[2]*dir[0]) +
  118. l2[2] * (edgeDir[1]*dir[2] - edgeDir[2]*dir[1]);
  119. */
  120. d = l2[4] * cross[0] + l2[5] * cross[1] + l2[2] * cross[2];
  121. if ( d == 0.0f ) {
  122. *fraction = 1.0f;
  123. // no collision ever
  124. return false;
  125. }
  126. t = -l1.PermutedInnerProduct( l2 );
  127. // if the lines cross each other to begin with
  128. if ( fabs( t ) < idMath::FLT_SMALLEST_NON_DENORMAL ) {
  129. *fraction = 0.0f;
  130. return true;
  131. }
  132. // fraction of movement at the time the lines cross each other
  133. *fraction = t / d;
  134. return true;
  135. }
  136. /*
  137. ================
  138. CM_AddContact
  139. ================
  140. */
  141. ID_INLINE void CM_AddContact( cm_traceWork_t *tw ) {
  142. if ( tw->numContacts >= tw->maxContacts ) {
  143. return;
  144. }
  145. // copy contact information from trace_t
  146. tw->contacts[tw->numContacts] = tw->trace.c;
  147. tw->numContacts++;
  148. // set fraction back to 1 to find all other contacts
  149. tw->trace.fraction = 1.0f;
  150. }
  151. /*
  152. ================
  153. CM_SetVertexSidedness
  154. stores for the given model vertex at which side of one of the trm edges it passes
  155. ================
  156. */
  157. ID_INLINE void CM_SetVertexSidedness( cm_vertex_t *v, const idPluecker &vpl, const idPluecker &epl, const int bitNum ) {
  158. const int mask = 1 << bitNum;
  159. if ( ( v->sideSet & mask ) == 0 ) {
  160. const float fl = vpl.PermutedInnerProduct( epl );
  161. v->side = ( v->side & ~mask ) | ( ( fl < 0.0f ) ? mask : 0 );
  162. v->sideSet |= mask;
  163. }
  164. }
  165. /*
  166. ================
  167. CM_SetEdgeSidedness
  168. stores for the given model edge at which side one of the trm vertices
  169. ================
  170. */
  171. ID_INLINE void CM_SetEdgeSidedness( cm_edge_t *edge, const idPluecker &vpl, const idPluecker &epl, const int bitNum ) {
  172. const int mask = 1 << bitNum;
  173. if ( ( edge->sideSet & mask ) == 0 ) {
  174. const float fl = vpl.PermutedInnerProduct( epl );
  175. edge->side = ( edge->side & ~mask ) | ( ( fl < 0.0f ) ? mask : 0 );
  176. edge->sideSet |= mask;
  177. }
  178. }
  179. /*
  180. ================
  181. idCollisionModelManagerLocal::TranslateTrmEdgeThroughPolygon
  182. ================
  183. */
  184. void idCollisionModelManagerLocal::TranslateTrmEdgeThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmEdge_t *trmEdge ) {
  185. int i, edgeNum;
  186. float f1, f2, dist, d1, d2;
  187. idVec3 start, end, normal;
  188. cm_edge_t *edge;
  189. cm_vertex_t *v1, *v2;
  190. idPluecker *pl, epsPl;
  191. // check edges for a collision
  192. for ( i = 0; i < poly->numEdges; i++) {
  193. edgeNum = poly->edges[i];
  194. edge = tw->model->edges + abs(edgeNum);
  195. // if this edge is already checked
  196. if ( edge->checkcount == idCollisionModelManagerLocal::checkCount ) {
  197. continue;
  198. }
  199. // can never collide with internal edges
  200. if ( edge->internal ) {
  201. continue;
  202. }
  203. pl = &tw->polygonEdgePlueckerCache[i];
  204. // get the sides at which the trm edge vertices pass the polygon edge
  205. CM_SetEdgeSidedness( edge, *pl, tw->vertices[trmEdge->vertexNum[0]].pl, trmEdge->vertexNum[0] );
  206. CM_SetEdgeSidedness( edge, *pl, tw->vertices[trmEdge->vertexNum[1]].pl, trmEdge->vertexNum[1] );
  207. // if the trm edge start and end vertex do not pass the polygon edge at different sides
  208. if ( !(((edge->side >> trmEdge->vertexNum[0]) ^ (edge->side >> trmEdge->vertexNum[1])) & 1) ) {
  209. continue;
  210. }
  211. // get the sides at which the polygon edge vertices pass the trm edge
  212. v1 = tw->model->vertices + edge->vertexNum[INT32_SIGNBITSET( edgeNum )];
  213. CM_SetVertexSidedness( v1, tw->polygonVertexPlueckerCache[i], trmEdge->pl, trmEdge->bitNum );
  214. v2 = tw->model->vertices + edge->vertexNum[INT32_SIGNBITNOTSET( edgeNum )];
  215. CM_SetVertexSidedness( v2, tw->polygonVertexPlueckerCache[i+1], trmEdge->pl, trmEdge->bitNum );
  216. // if the polygon edge start and end vertex do not pass the trm edge at different sides
  217. if ( !((v1->side ^ v2->side) & (1<<trmEdge->bitNum)) ) {
  218. continue;
  219. }
  220. // if there is no possible collision between the trm edge and the polygon edge
  221. if ( !idCollisionModelManagerLocal::TranslateEdgeThroughEdge( trmEdge->cross, trmEdge->pl, *pl, &f1 ) ) {
  222. continue;
  223. }
  224. // if moving away from edge
  225. if ( f1 < 0.0f ) {
  226. continue;
  227. }
  228. // pluecker coordinate for epsilon expanded edge
  229. epsPl.FromLine( tw->model->vertices[edge->vertexNum[0]].p + edge->normal * CM_CLIP_EPSILON,
  230. tw->model->vertices[edge->vertexNum[1]].p + edge->normal * CM_CLIP_EPSILON );
  231. // calculate collision fraction with epsilon expanded edge
  232. if ( !idCollisionModelManagerLocal::TranslateEdgeThroughEdge( trmEdge->cross, trmEdge->pl, epsPl, &f2 ) ) {
  233. continue;
  234. }
  235. // if no collision with epsilon edge or moving away from edge
  236. if ( f2 > 1.0f || f1 < f2 ) {
  237. continue;
  238. }
  239. if ( f2 < 0.0f ) {
  240. f2 = 0.0f;
  241. }
  242. if ( f2 < tw->trace.fraction ) {
  243. tw->trace.fraction = f2;
  244. // create plane with normal vector orthogonal to both the polygon edge and the trm edge
  245. start = tw->model->vertices[edge->vertexNum[0]].p;
  246. end = tw->model->vertices[edge->vertexNum[1]].p;
  247. tw->trace.c.normal = ( end - start ).Cross( trmEdge->end - trmEdge->start );
  248. // FIXME: do this normalize when we know the first collision
  249. tw->trace.c.normal.Normalize();
  250. tw->trace.c.dist = tw->trace.c.normal * start;
  251. // make sure the collision plane faces the trace model
  252. if ( tw->trace.c.normal * trmEdge->start - tw->trace.c.dist < 0.0f ) {
  253. tw->trace.c.normal = -tw->trace.c.normal;
  254. tw->trace.c.dist = -tw->trace.c.dist;
  255. }
  256. tw->trace.c.contents = poly->contents;
  257. tw->trace.c.material = poly->material;
  258. tw->trace.c.type = CONTACT_EDGE;
  259. tw->trace.c.modelFeature = edgeNum;
  260. tw->trace.c.trmFeature = trmEdge - tw->edges;
  261. // calculate collision point
  262. normal[0] = trmEdge->cross[2];
  263. normal[1] = -trmEdge->cross[1];
  264. normal[2] = trmEdge->cross[0];
  265. dist = normal * trmEdge->start;
  266. d1 = normal * start - dist;
  267. d2 = normal * end - dist;
  268. f1 = d1 / ( d1 - d2 );
  269. //assert( f1 >= 0.0f && f1 <= 1.0f );
  270. tw->trace.c.point = start + f1 * ( end - start );
  271. // if retrieving contacts
  272. if ( tw->getContacts ) {
  273. CM_AddContact( tw );
  274. }
  275. }
  276. }
  277. }
  278. /*
  279. ================
  280. CM_TranslationPlaneFraction
  281. ================
  282. */
  283. float CM_TranslationPlaneFraction( const idPlane &plane, const idVec3 &start, const idVec3 &end ) {
  284. const float d2 = plane.Distance( end );
  285. // if the end point is closer to the plane than an epsilon we still take it for a collision
  286. if ( d2 >= CM_CLIP_EPSILON ) {
  287. return 1.0f;
  288. }
  289. const float d1 = plane.Distance( start );
  290. // if completely behind the polygon
  291. if ( d1 <= 0.0f ) {
  292. return 1.0f;
  293. }
  294. // leaves polygon
  295. if ( d1 - d2 < idMath::FLT_SMALLEST_NON_DENORMAL ) {
  296. return 1.0f;
  297. }
  298. return ( d1 - CM_CLIP_EPSILON ) / ( d1 - d2 );
  299. }
  300. /*
  301. ================
  302. idCollisionModelManagerLocal::TranslateTrmVertexThroughPolygon
  303. ================
  304. */
  305. void idCollisionModelManagerLocal::TranslateTrmVertexThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmVertex_t *v, int bitNum ) {
  306. int i, edgeNum;
  307. float f;
  308. cm_edge_t *edge;
  309. f = CM_TranslationPlaneFraction( poly->plane, v->p, v->endp );
  310. if ( f < tw->trace.fraction ) {
  311. for ( i = 0; i < poly->numEdges; i++ ) {
  312. edgeNum = poly->edges[i];
  313. edge = tw->model->edges + abs(edgeNum);
  314. CM_SetEdgeSidedness( edge, tw->polygonEdgePlueckerCache[i], v->pl, bitNum );
  315. if ( INT32_SIGNBITSET( edgeNum ) ^ ( ( edge->side >> bitNum ) & 1 ) ) {
  316. return;
  317. }
  318. }
  319. if ( f < 0.0f ) {
  320. f = 0.0f;
  321. }
  322. tw->trace.fraction = f;
  323. // collision plane is the polygon plane
  324. tw->trace.c.normal = poly->plane.Normal();
  325. tw->trace.c.dist = poly->plane.Dist();
  326. tw->trace.c.contents = poly->contents;
  327. tw->trace.c.material = poly->material;
  328. tw->trace.c.type = CONTACT_TRMVERTEX;
  329. tw->trace.c.modelFeature = *reinterpret_cast<int *>(&poly);
  330. tw->trace.c.trmFeature = v - tw->vertices;
  331. tw->trace.c.point = v->p + tw->trace.fraction * ( v->endp - v->p );
  332. // if retrieving contacts
  333. if ( tw->getContacts ) {
  334. CM_AddContact( tw );
  335. // no need to store the trm vertex more than once as a contact
  336. v->used = false;
  337. }
  338. }
  339. }
  340. /*
  341. ================
  342. idCollisionModelManagerLocal::TranslatePointThroughPolygon
  343. ================
  344. */
  345. void idCollisionModelManagerLocal::TranslatePointThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmVertex_t *v ) {
  346. int i, edgeNum;
  347. float f;
  348. cm_edge_t *edge;
  349. idPluecker pl;
  350. f = CM_TranslationPlaneFraction( poly->plane, v->p, v->endp );
  351. if ( f < tw->trace.fraction ) {
  352. for ( i = 0; i < poly->numEdges; i++ ) {
  353. edgeNum = poly->edges[i];
  354. edge = tw->model->edges + abs(edgeNum);
  355. // if we didn't yet calculate the sidedness for this edge
  356. if ( edge->checkcount != idCollisionModelManagerLocal::checkCount ) {
  357. float fl;
  358. edge->checkcount = idCollisionModelManagerLocal::checkCount;
  359. pl.FromLine(tw->model->vertices[edge->vertexNum[0]].p, tw->model->vertices[edge->vertexNum[1]].p);
  360. fl = v->pl.PermutedInnerProduct( pl );
  361. edge->side = ( fl < 0.0f );
  362. }
  363. // if the point passes the edge at the wrong side
  364. //if ( (edgeNum > 0) == edge->side ) {
  365. if ( INT32_SIGNBITSET( edgeNum ) ^ edge->side ) {
  366. return;
  367. }
  368. }
  369. if ( f < 0.0f ) {
  370. f = 0.0f;
  371. }
  372. tw->trace.fraction = f;
  373. // collision plane is the polygon plane
  374. tw->trace.c.normal = poly->plane.Normal();
  375. tw->trace.c.dist = poly->plane.Dist();
  376. tw->trace.c.contents = poly->contents;
  377. tw->trace.c.material = poly->material;
  378. tw->trace.c.type = CONTACT_TRMVERTEX;
  379. tw->trace.c.modelFeature = *reinterpret_cast<int *>(&poly);
  380. tw->trace.c.trmFeature = v - tw->vertices;
  381. tw->trace.c.point = v->p + tw->trace.fraction * ( v->endp - v->p );
  382. // if retrieving contacts
  383. if ( tw->getContacts ) {
  384. CM_AddContact( tw );
  385. // no need to store the trm vertex more than once as a contact
  386. v->used = false;
  387. }
  388. }
  389. }
  390. /*
  391. ================
  392. idCollisionModelManagerLocal::TranslateVertexThroughTrmPolygon
  393. ================
  394. */
  395. void idCollisionModelManagerLocal::TranslateVertexThroughTrmPolygon( cm_traceWork_t *tw, cm_trmPolygon_t *trmpoly, cm_polygon_t *poly, cm_vertex_t *v, idVec3 &endp, idPluecker &pl ) {
  396. int i, edgeNum;
  397. float f;
  398. cm_trmEdge_t *edge;
  399. f = CM_TranslationPlaneFraction( trmpoly->plane, v->p, endp );
  400. if ( f < tw->trace.fraction ) {
  401. for ( i = 0; i < trmpoly->numEdges; i++ ) {
  402. edgeNum = trmpoly->edges[i];
  403. edge = tw->edges + abs(edgeNum);
  404. CM_SetVertexSidedness( v, pl, edge->pl, edge->bitNum );
  405. if ( INT32_SIGNBITSET( edgeNum ) ^ ( ( v->side >> edge->bitNum ) & 1 ) ) {
  406. return;
  407. }
  408. }
  409. if ( f < 0.0f ) {
  410. f = 0.0f;
  411. }
  412. tw->trace.fraction = f;
  413. // collision plane is the inverse trm polygon plane
  414. tw->trace.c.normal = -trmpoly->plane.Normal();
  415. tw->trace.c.dist = -trmpoly->plane.Dist();
  416. tw->trace.c.contents = poly->contents;
  417. tw->trace.c.material = poly->material;
  418. tw->trace.c.type = CONTACT_MODELVERTEX;
  419. tw->trace.c.modelFeature = v - tw->model->vertices;
  420. tw->trace.c.trmFeature = trmpoly - tw->polys;
  421. tw->trace.c.point = v->p + tw->trace.fraction * ( endp - v->p );
  422. // if retrieving contacts
  423. if ( tw->getContacts ) {
  424. CM_AddContact( tw );
  425. }
  426. }
  427. }
  428. /*
  429. ================
  430. idCollisionModelManagerLocal::TranslateTrmThroughPolygon
  431. returns true if the polygon blocks the complete translation
  432. ================
  433. */
  434. bool idCollisionModelManagerLocal::TranslateTrmThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *p ) {
  435. int i, j, k, edgeNum;
  436. float fraction, d;
  437. idVec3 endp;
  438. idPluecker *pl;
  439. cm_trmVertex_t *bv;
  440. cm_trmEdge_t *be;
  441. cm_trmPolygon_t *bp;
  442. cm_vertex_t *v;
  443. cm_edge_t *e;
  444. // if already checked this polygon
  445. if ( p->checkcount == idCollisionModelManagerLocal::checkCount ) {
  446. return false;
  447. }
  448. p->checkcount = idCollisionModelManagerLocal::checkCount;
  449. // if this polygon does not have the right contents behind it
  450. if ( !(p->contents & tw->contents) ) {
  451. return false;
  452. }
  453. // if the the trace bounds do not intersect the polygon bounds
  454. if ( !tw->bounds.IntersectsBounds( p->bounds ) ) {
  455. return false;
  456. }
  457. // only collide with the polygon if approaching at the front
  458. if ( ( p->plane.Normal() * tw->dir ) > 0.0f ) {
  459. return false;
  460. }
  461. // if the polygon is too far from the first heart plane
  462. d = p->bounds.PlaneDistance( tw->heartPlane1 );
  463. if ( idMath::Fabs(d) > tw->maxDistFromHeartPlane1 ) {
  464. return false;
  465. }
  466. // if the polygon is too far from the second heart plane
  467. d = p->bounds.PlaneDistance( tw->heartPlane2 );
  468. if ( idMath::Fabs(d) > tw->maxDistFromHeartPlane2 ) {
  469. return false;
  470. }
  471. fraction = tw->trace.fraction;
  472. // fast point trace
  473. if ( tw->pointTrace ) {
  474. idCollisionModelManagerLocal::TranslatePointThroughPolygon( tw, p, &tw->vertices[0] );
  475. }
  476. else {
  477. // trace bounds should cross polygon plane
  478. switch ( tw->bounds.PlaneSide( p->plane ) ) {
  479. case PLANESIDE_CROSS:
  480. break;
  481. case PLANESIDE_FRONT:
  482. if ( tw->model->isConvex ) {
  483. tw->quickExit = true;
  484. return true;
  485. }
  486. default:
  487. return false;
  488. }
  489. // calculate pluecker coordinates for the polygon edges and polygon vertices
  490. for ( i = 0; i < p->numEdges; i++ ) {
  491. edgeNum = p->edges[i];
  492. e = tw->model->edges + abs(edgeNum);
  493. // reset sidedness cache if this is the first time we encounter this edge during this trace
  494. if ( e->checkcount != idCollisionModelManagerLocal::checkCount ) {
  495. e->sideSet = 0;
  496. }
  497. // pluecker coordinate for edge
  498. tw->polygonEdgePlueckerCache[i].FromLine( tw->model->vertices[e->vertexNum[0]].p,
  499. tw->model->vertices[e->vertexNum[1]].p );
  500. v = &tw->model->vertices[e->vertexNum[INT32_SIGNBITSET( edgeNum )]];
  501. // reset sidedness cache if this is the first time we encounter this vertex during this trace
  502. if ( v->checkcount != idCollisionModelManagerLocal::checkCount ) {
  503. v->sideSet = 0;
  504. }
  505. // pluecker coordinate for vertex movement vector
  506. tw->polygonVertexPlueckerCache[i].FromRay( v->p, -tw->dir );
  507. }
  508. // copy first to last so we can easily cycle through for the edges
  509. tw->polygonVertexPlueckerCache[p->numEdges] = tw->polygonVertexPlueckerCache[0];
  510. // trace trm vertices through polygon
  511. for ( i = 0; i < tw->numVerts; i++ ) {
  512. bv = tw->vertices + i;
  513. if ( bv->used ) {
  514. idCollisionModelManagerLocal::TranslateTrmVertexThroughPolygon( tw, p, bv, i );
  515. }
  516. }
  517. // trace trm edges through polygon
  518. for ( i = 1; i <= tw->numEdges; i++ ) {
  519. be = tw->edges + i;
  520. if ( be->used ) {
  521. idCollisionModelManagerLocal::TranslateTrmEdgeThroughPolygon( tw, p, be);
  522. }
  523. }
  524. // trace all polygon vertices through the trm
  525. for ( i = 0; i < p->numEdges; i++ ) {
  526. edgeNum = p->edges[i];
  527. e = tw->model->edges + abs(edgeNum);
  528. if ( e->checkcount == idCollisionModelManagerLocal::checkCount ) {
  529. continue;
  530. }
  531. // set edge check count
  532. e->checkcount = idCollisionModelManagerLocal::checkCount;
  533. // can never collide with internal edges
  534. if ( e->internal ) {
  535. continue;
  536. }
  537. // got to check both vertices because we skip internal edges
  538. for ( k = 0; k < 2; k++ ) {
  539. v = tw->model->vertices + e->vertexNum[k ^ INT32_SIGNBITSET( edgeNum )];
  540. // if this vertex is already checked
  541. if ( v->checkcount == idCollisionModelManagerLocal::checkCount ) {
  542. continue;
  543. }
  544. // set vertex check count
  545. v->checkcount = idCollisionModelManagerLocal::checkCount;
  546. // if the vertex is outside the trace bounds
  547. if ( !tw->bounds.ContainsPoint( v->p ) ) {
  548. continue;
  549. }
  550. // vertex end point after movement
  551. endp = v->p - tw->dir;
  552. // pluecker coordinate for vertex movement vector
  553. pl = &tw->polygonVertexPlueckerCache[i+k];
  554. for ( j = 0; j < tw->numPolys; j++ ) {
  555. bp = tw->polys + j;
  556. if ( bp->used ) {
  557. idCollisionModelManagerLocal::TranslateVertexThroughTrmPolygon( tw, bp, p, v, endp, *pl );
  558. }
  559. }
  560. }
  561. }
  562. }
  563. // if there was a collision with this polygon and we are not retrieving contacts
  564. if ( tw->trace.fraction < fraction && !tw->getContacts ) {
  565. fraction = tw->trace.fraction;
  566. endp = tw->start + fraction * tw->dir;
  567. // decrease bounds
  568. for ( i = 0; i < 3; i++ ) {
  569. if ( tw->start[i] < endp[i] ) {
  570. tw->bounds[0][i] = tw->start[i] + tw->size[0][i] - CM_BOX_EPSILON;
  571. tw->bounds[1][i] = endp[i] + tw->size[1][i] + CM_BOX_EPSILON;
  572. }
  573. else {
  574. tw->bounds[0][i] = endp[i] + tw->size[0][i] - CM_BOX_EPSILON;
  575. tw->bounds[1][i] = tw->start[i] + tw->size[1][i] + CM_BOX_EPSILON;
  576. }
  577. }
  578. }
  579. return ( tw->trace.fraction == 0.0f );
  580. }
  581. /*
  582. ================
  583. idCollisionModelManagerLocal::SetupTrm
  584. ================
  585. */
  586. void idCollisionModelManagerLocal::SetupTrm( cm_traceWork_t *tw, const idTraceModel *trm ) {
  587. int i, j;
  588. // vertices
  589. tw->numVerts = trm->numVerts;
  590. for ( i = 0; i < trm->numVerts; i++ ) {
  591. tw->vertices[i].p = trm->verts[i];
  592. tw->vertices[i].used = false;
  593. }
  594. // edges
  595. tw->numEdges = trm->numEdges;
  596. for ( i = 1; i <= trm->numEdges; i++ ) {
  597. tw->edges[i].vertexNum[0] = trm->edges[i].v[0];
  598. tw->edges[i].vertexNum[1] = trm->edges[i].v[1];
  599. tw->edges[i].used = false;
  600. }
  601. // polygons
  602. tw->numPolys = trm->numPolys;
  603. for ( i = 0; i < trm->numPolys; i++ ) {
  604. tw->polys[i].numEdges = trm->polys[i].numEdges;
  605. for ( j = 0; j < trm->polys[i].numEdges; j++ ) {
  606. tw->polys[i].edges[j] = trm->polys[i].edges[j];
  607. }
  608. tw->polys[i].plane.SetNormal( trm->polys[i].normal );
  609. tw->polys[i].used = false;
  610. }
  611. // is the trace model convex or not
  612. tw->isConvex = trm->isConvex;
  613. }
  614. /*
  615. ================
  616. idCollisionModelManagerLocal::SetupTranslationHeartPlanes
  617. ================
  618. */
  619. void idCollisionModelManagerLocal::SetupTranslationHeartPlanes( cm_traceWork_t *tw ) {
  620. idVec3 dir, normal1, normal2;
  621. // calculate trace heart planes
  622. dir = tw->dir;
  623. dir.Normalize();
  624. dir.NormalVectors( normal1, normal2 );
  625. tw->heartPlane1.SetNormal( normal1 );
  626. tw->heartPlane1.FitThroughPoint( tw->start );
  627. tw->heartPlane2.SetNormal( normal2 );
  628. tw->heartPlane2.FitThroughPoint( tw->start );
  629. }
  630. /*
  631. ================
  632. idCollisionModelManagerLocal::Translation
  633. ================
  634. */
  635. #ifdef _DEBUG
  636. static int entered = 0;
  637. #endif
  638. void idCollisionModelManagerLocal::Translation( trace_t *results, const idVec3 &start, const idVec3 &end,
  639. const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
  640. cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
  641. int i, j;
  642. float dist;
  643. bool model_rotated, trm_rotated;
  644. idVec3 dir1, dir2, dir;
  645. idMat3 invModelAxis, tmpAxis;
  646. cm_trmPolygon_t *poly;
  647. cm_trmEdge_t *edge;
  648. cm_trmVertex_t *vert;
  649. ALIGN16( static cm_traceWork_t tw );
  650. assert( ((byte *)&start) < ((byte *)results) || ((byte *)&start) >= (((byte *)results) + sizeof( trace_t )) );
  651. assert( ((byte *)&end) < ((byte *)results) || ((byte *)&end) >= (((byte *)results) + sizeof( trace_t )) );
  652. assert( ((byte *)&trmAxis) < ((byte *)results) || ((byte *)&trmAxis) >= (((byte *)results) + sizeof( trace_t )) );
  653. memset( results, 0, sizeof( *results ) );
  654. if ( model < 0 || model > MAX_SUBMODELS || model > idCollisionModelManagerLocal::maxModels ) {
  655. common->Printf("idCollisionModelManagerLocal::Translation: invalid model handle\n");
  656. return;
  657. }
  658. if ( !idCollisionModelManagerLocal::models[model] ) {
  659. common->Printf("idCollisionModelManagerLocal::Translation: invalid model\n");
  660. return;
  661. }
  662. // if case special position test
  663. if ( start[0] == end[0] && start[1] == end[1] && start[2] == end[2] ) {
  664. idCollisionModelManagerLocal::ContentsTrm( results, start, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
  665. return;
  666. }
  667. #ifdef _DEBUG
  668. bool startsolid = false;
  669. // test whether or not stuck to begin with
  670. if ( cm_debugCollision.GetBool() ) {
  671. if ( !entered && !idCollisionModelManagerLocal::getContacts ) {
  672. entered = 1;
  673. // if already messed up to begin with
  674. if ( idCollisionModelManagerLocal::Contents( start, trm, trmAxis, -1, model, modelOrigin, modelAxis ) & contentMask ) {
  675. startsolid = true;
  676. }
  677. entered = 0;
  678. }
  679. }
  680. #endif
  681. idCollisionModelManagerLocal::checkCount++;
  682. tw.trace.fraction = 1.0f;
  683. tw.trace.c.contents = 0;
  684. tw.trace.c.type = CONTACT_NONE;
  685. tw.contents = contentMask;
  686. tw.isConvex = true;
  687. tw.rotation = false;
  688. tw.positionTest = false;
  689. tw.quickExit = false;
  690. tw.getContacts = idCollisionModelManagerLocal::getContacts;
  691. tw.contacts = idCollisionModelManagerLocal::contacts;
  692. tw.maxContacts = idCollisionModelManagerLocal::maxContacts;
  693. tw.numContacts = 0;
  694. tw.model = idCollisionModelManagerLocal::models[model];
  695. tw.start = start - modelOrigin;
  696. tw.end = end - modelOrigin;
  697. tw.dir = end - start;
  698. model_rotated = modelAxis.IsRotated();
  699. if ( model_rotated ) {
  700. invModelAxis = modelAxis.Transpose();
  701. }
  702. // if optimized point trace
  703. if ( !trm || ( trm->bounds[1][0] - trm->bounds[0][0] <= 0.0f &&
  704. trm->bounds[1][1] - trm->bounds[0][1] <= 0.0f &&
  705. trm->bounds[1][2] - trm->bounds[0][2] <= 0.0f ) ) {
  706. if ( model_rotated ) {
  707. // rotate trace instead of model
  708. tw.start *= invModelAxis;
  709. tw.end *= invModelAxis;
  710. tw.dir *= invModelAxis;
  711. }
  712. // trace bounds
  713. for ( i = 0; i < 3; i++ ) {
  714. if ( tw.start[i] < tw.end[i] ) {
  715. tw.bounds[0][i] = tw.start[i] - CM_BOX_EPSILON;
  716. tw.bounds[1][i] = tw.end[i] + CM_BOX_EPSILON;
  717. }
  718. else {
  719. tw.bounds[0][i] = tw.end[i] - CM_BOX_EPSILON;
  720. tw.bounds[1][i] = tw.start[i] + CM_BOX_EPSILON;
  721. }
  722. }
  723. tw.extents[0] = tw.extents[1] = tw.extents[2] = CM_BOX_EPSILON;
  724. tw.size.Zero();
  725. // setup trace heart planes
  726. idCollisionModelManagerLocal::SetupTranslationHeartPlanes( &tw );
  727. tw.maxDistFromHeartPlane1 = CM_BOX_EPSILON;
  728. tw.maxDistFromHeartPlane2 = CM_BOX_EPSILON;
  729. // collision with single point
  730. tw.numVerts = 1;
  731. tw.vertices[0].p = tw.start;
  732. tw.vertices[0].endp = tw.vertices[0].p + tw.dir;
  733. tw.vertices[0].pl.FromRay( tw.vertices[0].p, tw.dir );
  734. tw.numEdges = tw.numPolys = 0;
  735. tw.pointTrace = true;
  736. // trace through the model
  737. idCollisionModelManagerLocal::TraceThroughModel( &tw );
  738. // store results
  739. *results = tw.trace;
  740. results->endpos = start + results->fraction * (end - start);
  741. results->endAxis = mat3_identity;
  742. if ( results->fraction < 1.0f ) {
  743. // rotate trace plane normal if there was a collision with a rotated model
  744. if ( model_rotated ) {
  745. results->c.normal *= modelAxis;
  746. results->c.point *= modelAxis;
  747. }
  748. results->c.point += modelOrigin;
  749. results->c.dist += modelOrigin * results->c.normal;
  750. }
  751. idCollisionModelManagerLocal::numContacts = tw.numContacts;
  752. return;
  753. }
  754. // the trace fraction is too inaccurate to describe translations over huge distances
  755. if ( tw.dir.LengthSqr() > Square( CM_MAX_TRACE_DIST ) ) {
  756. results->fraction = 0.0f;
  757. results->endpos = start;
  758. results->endAxis = trmAxis;
  759. results->c.normal = vec3_origin;
  760. results->c.material = NULL;
  761. results->c.point = start;
  762. if ( common->RW() ) {
  763. common->RW()->DebugArrow( colorRed, start, end, 1 );
  764. }
  765. common->Printf( "idCollisionModelManagerLocal::Translation: huge translation\n" );
  766. return;
  767. }
  768. tw.pointTrace = false;
  769. tw.size.Clear();
  770. // setup trm structure
  771. idCollisionModelManagerLocal::SetupTrm( &tw, trm );
  772. trm_rotated = trmAxis.IsRotated();
  773. // calculate vertex positions
  774. if ( trm_rotated ) {
  775. for ( i = 0; i < tw.numVerts; i++ ) {
  776. // rotate trm around the start position
  777. tw.vertices[i].p *= trmAxis;
  778. }
  779. }
  780. for ( i = 0; i < tw.numVerts; i++ ) {
  781. // set trm at start position
  782. tw.vertices[i].p += tw.start;
  783. }
  784. if ( model_rotated ) {
  785. for ( i = 0; i < tw.numVerts; i++ ) {
  786. // rotate trm around model instead of rotating the model
  787. tw.vertices[i].p *= invModelAxis;
  788. }
  789. }
  790. // add offset to start point
  791. if ( trm_rotated ) {
  792. dir = trm->offset * trmAxis;
  793. tw.start += dir;
  794. tw.end += dir;
  795. } else {
  796. tw.start += trm->offset;
  797. tw.end += trm->offset;
  798. }
  799. if ( model_rotated ) {
  800. // rotate trace instead of model
  801. tw.start *= invModelAxis;
  802. tw.end *= invModelAxis;
  803. tw.dir *= invModelAxis;
  804. }
  805. // rotate trm polygon planes
  806. if ( trm_rotated & model_rotated ) {
  807. tmpAxis = trmAxis * invModelAxis;
  808. for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
  809. poly->plane *= tmpAxis;
  810. }
  811. } else if ( trm_rotated ) {
  812. for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
  813. poly->plane *= trmAxis;
  814. }
  815. } else if ( model_rotated ) {
  816. for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
  817. poly->plane *= invModelAxis;
  818. }
  819. }
  820. // setup trm polygons
  821. for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
  822. // if the trm poly plane is facing in the movement direction
  823. dist = poly->plane.Normal() * tw.dir;
  824. if ( dist > 0.0f || ( !trm->isConvex && dist == 0.0f ) ) {
  825. // this trm poly and it's edges and vertices need to be used for collision
  826. poly->used = true;
  827. for ( j = 0; j < poly->numEdges; j++ ) {
  828. edge = &tw.edges[abs( poly->edges[j] )];
  829. edge->used = true;
  830. tw.vertices[edge->vertexNum[0]].used = true;
  831. tw.vertices[edge->vertexNum[1]].used = true;
  832. }
  833. }
  834. }
  835. // setup trm vertices
  836. for ( vert = tw.vertices, i = 0; i < tw.numVerts; i++, vert++ ) {
  837. if ( !vert->used ) {
  838. continue;
  839. }
  840. // get axial trm size after rotations
  841. tw.size.AddPoint( vert->p - tw.start );
  842. // calculate the end position of each vertex for a full trace
  843. vert->endp = vert->p + tw.dir;
  844. // pluecker coordinate for vertex movement line
  845. vert->pl.FromRay( vert->p, tw.dir );
  846. }
  847. // setup trm edges
  848. for ( edge = tw.edges + 1, i = 1; i <= tw.numEdges; i++, edge++ ) {
  849. if ( !edge->used ) {
  850. continue;
  851. }
  852. // edge start, end and pluecker coordinate
  853. edge->start = tw.vertices[edge->vertexNum[0]].p;
  854. edge->end = tw.vertices[edge->vertexNum[1]].p;
  855. edge->pl.FromLine( edge->start, edge->end );
  856. // calculate normal of plane through movement plane created by the edge
  857. dir = edge->start - edge->end;
  858. edge->cross[0] = dir[0] * tw.dir[1] - dir[1] * tw.dir[0];
  859. edge->cross[1] = dir[0] * tw.dir[2] - dir[2] * tw.dir[0];
  860. edge->cross[2] = dir[1] * tw.dir[2] - dir[2] * tw.dir[1];
  861. // bit for vertex sidedness bit cache
  862. edge->bitNum = i;
  863. }
  864. // set trm plane distances
  865. for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
  866. if ( poly->used ) {
  867. poly->plane.FitThroughPoint( tw.edges[abs(poly->edges[0])].start );
  868. }
  869. }
  870. // bounds for full trace, a little bit larger for epsilons
  871. for ( i = 0; i < 3; i++ ) {
  872. if ( tw.start[i] < tw.end[i] ) {
  873. tw.bounds[0][i] = tw.start[i] + tw.size[0][i] - CM_BOX_EPSILON;
  874. tw.bounds[1][i] = tw.end[i] + tw.size[1][i] + CM_BOX_EPSILON;
  875. } else {
  876. tw.bounds[0][i] = tw.end[i] + tw.size[0][i] - CM_BOX_EPSILON;
  877. tw.bounds[1][i] = tw.start[i] + tw.size[1][i] + CM_BOX_EPSILON;
  878. }
  879. if ( idMath::Fabs( tw.size[0][i] ) > idMath::Fabs( tw.size[1][i] ) ) {
  880. tw.extents[i] = idMath::Fabs( tw.size[0][i] ) + CM_BOX_EPSILON;
  881. } else {
  882. tw.extents[i] = idMath::Fabs( tw.size[1][i] ) + CM_BOX_EPSILON;
  883. }
  884. }
  885. // setup trace heart planes
  886. idCollisionModelManagerLocal::SetupTranslationHeartPlanes( &tw );
  887. tw.maxDistFromHeartPlane1 = 0;
  888. tw.maxDistFromHeartPlane2 = 0;
  889. // calculate maximum trm vertex distance from both heart planes
  890. for ( vert = tw.vertices, i = 0; i < tw.numVerts; i++, vert++ ) {
  891. if ( !vert->used ) {
  892. continue;
  893. }
  894. dist = idMath::Fabs( tw.heartPlane1.Distance( vert->p ) );
  895. if ( dist > tw.maxDistFromHeartPlane1 ) {
  896. tw.maxDistFromHeartPlane1 = dist;
  897. }
  898. dist = idMath::Fabs( tw.heartPlane2.Distance( vert->p ) );
  899. if ( dist > tw.maxDistFromHeartPlane2 ) {
  900. tw.maxDistFromHeartPlane2 = dist;
  901. }
  902. }
  903. // for epsilons
  904. tw.maxDistFromHeartPlane1 += CM_BOX_EPSILON;
  905. tw.maxDistFromHeartPlane2 += CM_BOX_EPSILON;
  906. // trace through the model
  907. idCollisionModelManagerLocal::TraceThroughModel( &tw );
  908. // if we're getting contacts
  909. if ( tw.getContacts ) {
  910. // move all contacts to world space
  911. if ( model_rotated ) {
  912. for ( i = 0; i < tw.numContacts; i++ ) {
  913. tw.contacts[i].normal *= modelAxis;
  914. tw.contacts[i].point *= modelAxis;
  915. }
  916. }
  917. if ( modelOrigin != vec3_origin ) {
  918. for ( i = 0; i < tw.numContacts; i++ ) {
  919. tw.contacts[i].point += modelOrigin;
  920. tw.contacts[i].dist += modelOrigin * tw.contacts[i].normal;
  921. }
  922. }
  923. idCollisionModelManagerLocal::numContacts = tw.numContacts;
  924. } else {
  925. // store results
  926. *results = tw.trace;
  927. results->endpos = start + results->fraction * ( end - start );
  928. results->endAxis = trmAxis;
  929. if ( results->fraction < 1.0f ) {
  930. // if the fraction is tiny the actual movement could end up zero
  931. if ( results->fraction > 0.0f && results->endpos.Compare( start ) ) {
  932. results->fraction = 0.0f;
  933. }
  934. // rotate trace plane normal if there was a collision with a rotated model
  935. if ( model_rotated ) {
  936. results->c.normal *= modelAxis;
  937. results->c.point *= modelAxis;
  938. }
  939. results->c.point += modelOrigin;
  940. results->c.dist += modelOrigin * results->c.normal;
  941. }
  942. }
  943. #ifdef _DEBUG
  944. // test for missed collisions
  945. if ( cm_debugCollision.GetBool() ) {
  946. if ( !entered && !idCollisionModelManagerLocal::getContacts ) {
  947. entered = 1;
  948. // if the trm is stuck in the model
  949. if ( idCollisionModelManagerLocal::Contents( results->endpos, trm, trmAxis, -1, model, modelOrigin, modelAxis ) & contentMask ) {
  950. trace_t tr;
  951. // test where the trm is stuck in the model
  952. idCollisionModelManagerLocal::Contents( results->endpos, trm, trmAxis, -1, model, modelOrigin, modelAxis );
  953. // re-run collision detection to find out where it failed
  954. idCollisionModelManagerLocal::Translation( &tr, start, end, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
  955. }
  956. entered = 0;
  957. }
  958. }
  959. #endif
  960. }