CollisionModel_translate.cpp 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 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 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. #include "../idlib/precompiled.h"
  26. #pragma hdrstop
  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 ( t == 0.0f ) {
  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. if ( !(v->sideSet & (1<<bitNum)) ) {
  159. float fl;
  160. fl = vpl.PermutedInnerProduct( epl );
  161. v->side = (v->side & ~(1<<bitNum)) | (FLOATSIGNBITSET(fl) << bitNum);
  162. v->sideSet |= (1 << bitNum);
  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. if ( !(edge->sideSet & (1<<bitNum)) ) {
  173. float fl;
  174. fl = vpl.PermutedInnerProduct( epl );
  175. edge->side = (edge->side & ~(1<<bitNum)) | (FLOATSIGNBITSET(fl) << bitNum);
  176. edge->sideSet |= (1 << bitNum);
  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[INTSIGNBITSET(edgeNum)];
  213. CM_SetVertexSidedness( v1, tw->polygonVertexPlueckerCache[i], trmEdge->pl, trmEdge->bitNum );
  214. v2 = tw->model->vertices + edge->vertexNum[INTSIGNBITNOTSET(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. #if 0
  284. float CM_TranslationPlaneFraction( idPlane &plane, idVec3 &start, idVec3 &end ) {
  285. float d1, d2;
  286. d2 = plane.Distance( end );
  287. // if the end point is closer to the plane than an epsilon we still take it for a collision
  288. if ( d2 >= CM_CLIP_EPSILON ) {
  289. return 1.0f;
  290. }
  291. d1 = plane.Distance( start );
  292. // if completely behind the polygon
  293. if ( d1 <= 0.0f ) {
  294. return 1.0f;
  295. }
  296. // leaves polygon
  297. if ( d1 <= d2 ) {
  298. return 1.0f;
  299. }
  300. return (d1-CM_CLIP_EPSILON) / (d1-d2);
  301. }
  302. #else
  303. float CM_TranslationPlaneFraction( idPlane &plane, idVec3 &start, idVec3 &end ) {
  304. float d1, d2, d2eps;
  305. d2 = plane.Distance( end );
  306. // if the end point is closer to the plane than an epsilon we still take it for a collision
  307. // if ( d2 >= CM_CLIP_EPSILON ) {
  308. d2eps = d2 - CM_CLIP_EPSILON;
  309. if ( FLOATSIGNBITNOTSET(d2eps) ) {
  310. return 1.0f;
  311. }
  312. d1 = plane.Distance( start );
  313. // if completely behind the polygon
  314. if ( FLOATSIGNBITSET(d1) ) {
  315. return 1.0f;
  316. }
  317. // if going towards the front of the plane and
  318. // the start and end point are not at equal distance from the plane
  319. // if ( d1 > d2 )
  320. d2 = d1 - d2;
  321. if ( d2 <= 0.0f ) {
  322. return 1.0f;
  323. }
  324. return (d1-CM_CLIP_EPSILON) / d2;
  325. }
  326. #endif
  327. /*
  328. ================
  329. idCollisionModelManagerLocal::TranslateTrmVertexThroughPolygon
  330. ================
  331. */
  332. void idCollisionModelManagerLocal::TranslateTrmVertexThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmVertex_t *v, int bitNum ) {
  333. int i, edgeNum;
  334. float f;
  335. cm_edge_t *edge;
  336. f = CM_TranslationPlaneFraction( poly->plane, v->p, v->endp );
  337. if ( f < tw->trace.fraction ) {
  338. for ( i = 0; i < poly->numEdges; i++ ) {
  339. edgeNum = poly->edges[i];
  340. edge = tw->model->edges + abs(edgeNum);
  341. CM_SetEdgeSidedness( edge, tw->polygonEdgePlueckerCache[i], v->pl, bitNum );
  342. if ( INTSIGNBITSET(edgeNum) ^ ((edge->side >> bitNum) & 1) ) {
  343. return;
  344. }
  345. }
  346. if ( f < 0.0f ) {
  347. f = 0.0f;
  348. }
  349. tw->trace.fraction = f;
  350. // collision plane is the polygon plane
  351. tw->trace.c.normal = poly->plane.Normal();
  352. tw->trace.c.dist = poly->plane.Dist();
  353. tw->trace.c.contents = poly->contents;
  354. tw->trace.c.material = poly->material;
  355. tw->trace.c.type = CONTACT_TRMVERTEX;
  356. tw->trace.c.modelFeature = *reinterpret_cast<int *>(&poly);
  357. tw->trace.c.trmFeature = v - tw->vertices;
  358. tw->trace.c.point = v->p + tw->trace.fraction * ( v->endp - v->p );
  359. // if retrieving contacts
  360. if ( tw->getContacts ) {
  361. CM_AddContact( tw );
  362. // no need to store the trm vertex more than once as a contact
  363. v->used = false;
  364. }
  365. }
  366. }
  367. /*
  368. ================
  369. idCollisionModelManagerLocal::TranslatePointThroughPolygon
  370. ================
  371. */
  372. void idCollisionModelManagerLocal::TranslatePointThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *poly, cm_trmVertex_t *v ) {
  373. int i, edgeNum;
  374. float f;
  375. cm_edge_t *edge;
  376. idPluecker pl;
  377. f = CM_TranslationPlaneFraction( poly->plane, v->p, v->endp );
  378. if ( f < tw->trace.fraction ) {
  379. for ( i = 0; i < poly->numEdges; i++ ) {
  380. edgeNum = poly->edges[i];
  381. edge = tw->model->edges + abs(edgeNum);
  382. // if we didn't yet calculate the sidedness for this edge
  383. if ( edge->checkcount != idCollisionModelManagerLocal::checkCount ) {
  384. float fl;
  385. edge->checkcount = idCollisionModelManagerLocal::checkCount;
  386. pl.FromLine(tw->model->vertices[edge->vertexNum[0]].p, tw->model->vertices[edge->vertexNum[1]].p);
  387. fl = v->pl.PermutedInnerProduct( pl );
  388. edge->side = FLOATSIGNBITSET(fl);
  389. }
  390. // if the point passes the edge at the wrong side
  391. //if ( (edgeNum > 0) == edge->side ) {
  392. if ( INTSIGNBITSET(edgeNum) ^ edge->side ) {
  393. return;
  394. }
  395. }
  396. if ( f < 0.0f ) {
  397. f = 0.0f;
  398. }
  399. tw->trace.fraction = f;
  400. // collision plane is the polygon plane
  401. tw->trace.c.normal = poly->plane.Normal();
  402. tw->trace.c.dist = poly->plane.Dist();
  403. tw->trace.c.contents = poly->contents;
  404. tw->trace.c.material = poly->material;
  405. tw->trace.c.type = CONTACT_TRMVERTEX;
  406. tw->trace.c.modelFeature = *reinterpret_cast<int *>(&poly);
  407. tw->trace.c.trmFeature = v - tw->vertices;
  408. tw->trace.c.point = v->p + tw->trace.fraction * ( v->endp - v->p );
  409. // if retrieving contacts
  410. if ( tw->getContacts ) {
  411. CM_AddContact( tw );
  412. // no need to store the trm vertex more than once as a contact
  413. v->used = false;
  414. }
  415. }
  416. }
  417. /*
  418. ================
  419. idCollisionModelManagerLocal::TranslateVertexThroughTrmPolygon
  420. ================
  421. */
  422. void idCollisionModelManagerLocal::TranslateVertexThroughTrmPolygon( cm_traceWork_t *tw, cm_trmPolygon_t *trmpoly, cm_polygon_t *poly, cm_vertex_t *v, idVec3 &endp, idPluecker &pl ) {
  423. int i, edgeNum;
  424. float f;
  425. cm_trmEdge_t *edge;
  426. f = CM_TranslationPlaneFraction( trmpoly->plane, v->p, endp );
  427. if ( f < tw->trace.fraction ) {
  428. for ( i = 0; i < trmpoly->numEdges; i++ ) {
  429. edgeNum = trmpoly->edges[i];
  430. edge = tw->edges + abs(edgeNum);
  431. CM_SetVertexSidedness( v, pl, edge->pl, edge->bitNum );
  432. if ( INTSIGNBITSET(edgeNum) ^ ((v->side >> edge->bitNum) & 1) ) {
  433. return;
  434. }
  435. }
  436. if ( f < 0.0f ) {
  437. f = 0.0f;
  438. }
  439. tw->trace.fraction = f;
  440. // collision plane is the inverse trm polygon plane
  441. tw->trace.c.normal = -trmpoly->plane.Normal();
  442. tw->trace.c.dist = -trmpoly->plane.Dist();
  443. tw->trace.c.contents = poly->contents;
  444. tw->trace.c.material = poly->material;
  445. tw->trace.c.type = CONTACT_MODELVERTEX;
  446. tw->trace.c.modelFeature = v - tw->model->vertices;
  447. tw->trace.c.trmFeature = trmpoly - tw->polys;
  448. tw->trace.c.point = v->p + tw->trace.fraction * ( endp - v->p );
  449. // if retrieving contacts
  450. if ( tw->getContacts ) {
  451. CM_AddContact( tw );
  452. }
  453. }
  454. }
  455. /*
  456. ================
  457. idCollisionModelManagerLocal::TranslateTrmThroughPolygon
  458. returns true if the polygon blocks the complete translation
  459. ================
  460. */
  461. bool idCollisionModelManagerLocal::TranslateTrmThroughPolygon( cm_traceWork_t *tw, cm_polygon_t *p ) {
  462. int i, j, k, edgeNum;
  463. float fraction, d;
  464. idVec3 endp;
  465. idPluecker *pl;
  466. cm_trmVertex_t *bv;
  467. cm_trmEdge_t *be;
  468. cm_trmPolygon_t *bp;
  469. cm_vertex_t *v;
  470. cm_edge_t *e;
  471. // if already checked this polygon
  472. if ( p->checkcount == idCollisionModelManagerLocal::checkCount ) {
  473. return false;
  474. }
  475. p->checkcount = idCollisionModelManagerLocal::checkCount;
  476. // if this polygon does not have the right contents behind it
  477. if ( !(p->contents & tw->contents) ) {
  478. return false;
  479. }
  480. // if the the trace bounds do not intersect the polygon bounds
  481. if ( !tw->bounds.IntersectsBounds( p->bounds ) ) {
  482. return false;
  483. }
  484. // only collide with the polygon if approaching at the front
  485. if ( ( p->plane.Normal() * tw->dir ) > 0.0f ) {
  486. return false;
  487. }
  488. // if the polygon is too far from the first heart plane
  489. d = p->bounds.PlaneDistance( tw->heartPlane1 );
  490. if ( idMath::Fabs(d) > tw->maxDistFromHeartPlane1 ) {
  491. return false;
  492. }
  493. // if the polygon is too far from the second heart plane
  494. d = p->bounds.PlaneDistance( tw->heartPlane2 );
  495. if ( idMath::Fabs(d) > tw->maxDistFromHeartPlane2 ) {
  496. return false;
  497. }
  498. fraction = tw->trace.fraction;
  499. // fast point trace
  500. if ( tw->pointTrace ) {
  501. idCollisionModelManagerLocal::TranslatePointThroughPolygon( tw, p, &tw->vertices[0] );
  502. }
  503. else {
  504. // trace bounds should cross polygon plane
  505. switch ( tw->bounds.PlaneSide( p->plane ) ) {
  506. case PLANESIDE_CROSS:
  507. break;
  508. case PLANESIDE_FRONT:
  509. if ( tw->model->isConvex ) {
  510. tw->quickExit = true;
  511. return true;
  512. }
  513. default:
  514. return false;
  515. }
  516. // calculate pluecker coordinates for the polygon edges and polygon vertices
  517. for ( i = 0; i < p->numEdges; i++ ) {
  518. edgeNum = p->edges[i];
  519. e = tw->model->edges + abs(edgeNum);
  520. // reset sidedness cache if this is the first time we encounter this edge during this trace
  521. if ( e->checkcount != idCollisionModelManagerLocal::checkCount ) {
  522. e->sideSet = 0;
  523. }
  524. // pluecker coordinate for edge
  525. tw->polygonEdgePlueckerCache[i].FromLine( tw->model->vertices[e->vertexNum[0]].p,
  526. tw->model->vertices[e->vertexNum[1]].p );
  527. v = &tw->model->vertices[e->vertexNum[INTSIGNBITSET(edgeNum)]];
  528. // reset sidedness cache if this is the first time we encounter this vertex during this trace
  529. if ( v->checkcount != idCollisionModelManagerLocal::checkCount ) {
  530. v->sideSet = 0;
  531. }
  532. // pluecker coordinate for vertex movement vector
  533. tw->polygonVertexPlueckerCache[i].FromRay( v->p, -tw->dir );
  534. }
  535. // copy first to last so we can easily cycle through for the edges
  536. tw->polygonVertexPlueckerCache[p->numEdges] = tw->polygonVertexPlueckerCache[0];
  537. // trace trm vertices through polygon
  538. for ( i = 0; i < tw->numVerts; i++ ) {
  539. bv = tw->vertices + i;
  540. if ( bv->used ) {
  541. idCollisionModelManagerLocal::TranslateTrmVertexThroughPolygon( tw, p, bv, i );
  542. }
  543. }
  544. // trace trm edges through polygon
  545. for ( i = 1; i <= tw->numEdges; i++ ) {
  546. be = tw->edges + i;
  547. if ( be->used ) {
  548. idCollisionModelManagerLocal::TranslateTrmEdgeThroughPolygon( tw, p, be);
  549. }
  550. }
  551. // trace all polygon vertices through the trm
  552. for ( i = 0; i < p->numEdges; i++ ) {
  553. edgeNum = p->edges[i];
  554. e = tw->model->edges + abs(edgeNum);
  555. if ( e->checkcount == idCollisionModelManagerLocal::checkCount ) {
  556. continue;
  557. }
  558. // set edge check count
  559. e->checkcount = idCollisionModelManagerLocal::checkCount;
  560. // can never collide with internal edges
  561. if ( e->internal ) {
  562. continue;
  563. }
  564. // got to check both vertices because we skip internal edges
  565. for ( k = 0; k < 2; k++ ) {
  566. v = tw->model->vertices + e->vertexNum[k ^ INTSIGNBITSET(edgeNum)];
  567. // if this vertex is already checked
  568. if ( v->checkcount == idCollisionModelManagerLocal::checkCount ) {
  569. continue;
  570. }
  571. // set vertex check count
  572. v->checkcount = idCollisionModelManagerLocal::checkCount;
  573. // if the vertex is outside the trace bounds
  574. if ( !tw->bounds.ContainsPoint( v->p ) ) {
  575. continue;
  576. }
  577. // vertex end point after movement
  578. endp = v->p - tw->dir;
  579. // pluecker coordinate for vertex movement vector
  580. pl = &tw->polygonVertexPlueckerCache[i+k];
  581. for ( j = 0; j < tw->numPolys; j++ ) {
  582. bp = tw->polys + j;
  583. if ( bp->used ) {
  584. idCollisionModelManagerLocal::TranslateVertexThroughTrmPolygon( tw, bp, p, v, endp, *pl );
  585. }
  586. }
  587. }
  588. }
  589. }
  590. // if there was a collision with this polygon and we are not retrieving contacts
  591. if ( tw->trace.fraction < fraction && !tw->getContacts ) {
  592. fraction = tw->trace.fraction;
  593. endp = tw->start + fraction * tw->dir;
  594. // decrease bounds
  595. for ( i = 0; i < 3; i++ ) {
  596. if ( tw->start[i] < endp[i] ) {
  597. tw->bounds[0][i] = tw->start[i] + tw->size[0][i] - CM_BOX_EPSILON;
  598. tw->bounds[1][i] = endp[i] + tw->size[1][i] + CM_BOX_EPSILON;
  599. }
  600. else {
  601. tw->bounds[0][i] = endp[i] + tw->size[0][i] - CM_BOX_EPSILON;
  602. tw->bounds[1][i] = tw->start[i] + tw->size[1][i] + CM_BOX_EPSILON;
  603. }
  604. }
  605. }
  606. return ( tw->trace.fraction == 0.0f );
  607. }
  608. /*
  609. ================
  610. idCollisionModelManagerLocal::SetupTrm
  611. ================
  612. */
  613. void idCollisionModelManagerLocal::SetupTrm( cm_traceWork_t *tw, const idTraceModel *trm ) {
  614. int i, j;
  615. // vertices
  616. tw->numVerts = trm->numVerts;
  617. for ( i = 0; i < trm->numVerts; i++ ) {
  618. tw->vertices[i].p = trm->verts[i];
  619. tw->vertices[i].used = false;
  620. }
  621. // edges
  622. tw->numEdges = trm->numEdges;
  623. for ( i = 1; i <= trm->numEdges; i++ ) {
  624. tw->edges[i].vertexNum[0] = trm->edges[i].v[0];
  625. tw->edges[i].vertexNum[1] = trm->edges[i].v[1];
  626. tw->edges[i].used = false;
  627. }
  628. // polygons
  629. tw->numPolys = trm->numPolys;
  630. for ( i = 0; i < trm->numPolys; i++ ) {
  631. tw->polys[i].numEdges = trm->polys[i].numEdges;
  632. for ( j = 0; j < trm->polys[i].numEdges; j++ ) {
  633. tw->polys[i].edges[j] = trm->polys[i].edges[j];
  634. }
  635. tw->polys[i].plane.SetNormal( trm->polys[i].normal );
  636. tw->polys[i].used = false;
  637. }
  638. // is the trace model convex or not
  639. tw->isConvex = trm->isConvex;
  640. }
  641. /*
  642. ================
  643. idCollisionModelManagerLocal::SetupTranslationHeartPlanes
  644. ================
  645. */
  646. void idCollisionModelManagerLocal::SetupTranslationHeartPlanes( cm_traceWork_t *tw ) {
  647. idVec3 dir, normal1, normal2;
  648. // calculate trace heart planes
  649. dir = tw->dir;
  650. dir.Normalize();
  651. dir.NormalVectors( normal1, normal2 );
  652. tw->heartPlane1.SetNormal( normal1 );
  653. tw->heartPlane1.FitThroughPoint( tw->start );
  654. tw->heartPlane2.SetNormal( normal2 );
  655. tw->heartPlane2.FitThroughPoint( tw->start );
  656. }
  657. /*
  658. ================
  659. idCollisionModelManagerLocal::Translation
  660. ================
  661. */
  662. #ifdef _DEBUG
  663. static int entered = 0;
  664. #endif
  665. void idCollisionModelManagerLocal::Translation( trace_t *results, const idVec3 &start, const idVec3 &end,
  666. const idTraceModel *trm, const idMat3 &trmAxis, int contentMask,
  667. cmHandle_t model, const idVec3 &modelOrigin, const idMat3 &modelAxis ) {
  668. int i, j;
  669. float dist;
  670. bool model_rotated, trm_rotated;
  671. idVec3 dir1, dir2, dir;
  672. idMat3 invModelAxis, tmpAxis;
  673. cm_trmPolygon_t *poly;
  674. cm_trmEdge_t *edge;
  675. cm_trmVertex_t *vert;
  676. ALIGN16( static cm_traceWork_t tw );
  677. assert( ((byte *)&start) < ((byte *)results) || ((byte *)&start) >= (((byte *)results) + sizeof( trace_t )) );
  678. assert( ((byte *)&end) < ((byte *)results) || ((byte *)&end) >= (((byte *)results) + sizeof( trace_t )) );
  679. assert( ((byte *)&trmAxis) < ((byte *)results) || ((byte *)&trmAxis) >= (((byte *)results) + sizeof( trace_t )) );
  680. memset( results, 0, sizeof( *results ) );
  681. if ( model < 0 || model > MAX_SUBMODELS || model > idCollisionModelManagerLocal::maxModels ) {
  682. common->Printf("idCollisionModelManagerLocal::Translation: invalid model handle\n");
  683. return;
  684. }
  685. if ( !idCollisionModelManagerLocal::models[model] ) {
  686. common->Printf("idCollisionModelManagerLocal::Translation: invalid model\n");
  687. return;
  688. }
  689. // if case special position test
  690. if ( start[0] == end[0] && start[1] == end[1] && start[2] == end[2] ) {
  691. idCollisionModelManagerLocal::ContentsTrm( results, start, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
  692. return;
  693. }
  694. #ifdef _DEBUG
  695. bool startsolid = false;
  696. // test whether or not stuck to begin with
  697. if ( cm_debugCollision.GetBool() ) {
  698. if ( !entered && !idCollisionModelManagerLocal::getContacts ) {
  699. entered = 1;
  700. // if already messed up to begin with
  701. if ( idCollisionModelManagerLocal::Contents( start, trm, trmAxis, -1, model, modelOrigin, modelAxis ) & contentMask ) {
  702. startsolid = true;
  703. }
  704. entered = 0;
  705. }
  706. }
  707. #endif
  708. idCollisionModelManagerLocal::checkCount++;
  709. tw.trace.fraction = 1.0f;
  710. tw.trace.c.contents = 0;
  711. tw.trace.c.type = CONTACT_NONE;
  712. tw.contents = contentMask;
  713. tw.isConvex = true;
  714. tw.rotation = false;
  715. tw.positionTest = false;
  716. tw.quickExit = false;
  717. tw.getContacts = idCollisionModelManagerLocal::getContacts;
  718. tw.contacts = idCollisionModelManagerLocal::contacts;
  719. tw.maxContacts = idCollisionModelManagerLocal::maxContacts;
  720. tw.numContacts = 0;
  721. tw.model = idCollisionModelManagerLocal::models[model];
  722. tw.start = start - modelOrigin;
  723. tw.end = end - modelOrigin;
  724. tw.dir = end - start;
  725. model_rotated = modelAxis.IsRotated();
  726. if ( model_rotated ) {
  727. invModelAxis = modelAxis.Transpose();
  728. }
  729. // if optimized point trace
  730. if ( !trm || ( trm->bounds[1][0] - trm->bounds[0][0] <= 0.0f &&
  731. trm->bounds[1][1] - trm->bounds[0][1] <= 0.0f &&
  732. trm->bounds[1][2] - trm->bounds[0][2] <= 0.0f ) ) {
  733. if ( model_rotated ) {
  734. // rotate trace instead of model
  735. tw.start *= invModelAxis;
  736. tw.end *= invModelAxis;
  737. tw.dir *= invModelAxis;
  738. }
  739. // trace bounds
  740. for ( i = 0; i < 3; i++ ) {
  741. if ( tw.start[i] < tw.end[i] ) {
  742. tw.bounds[0][i] = tw.start[i] - CM_BOX_EPSILON;
  743. tw.bounds[1][i] = tw.end[i] + CM_BOX_EPSILON;
  744. }
  745. else {
  746. tw.bounds[0][i] = tw.end[i] - CM_BOX_EPSILON;
  747. tw.bounds[1][i] = tw.start[i] + CM_BOX_EPSILON;
  748. }
  749. }
  750. tw.extents[0] = tw.extents[1] = tw.extents[2] = CM_BOX_EPSILON;
  751. tw.size.Zero();
  752. // setup trace heart planes
  753. idCollisionModelManagerLocal::SetupTranslationHeartPlanes( &tw );
  754. tw.maxDistFromHeartPlane1 = CM_BOX_EPSILON;
  755. tw.maxDistFromHeartPlane2 = CM_BOX_EPSILON;
  756. // collision with single point
  757. tw.numVerts = 1;
  758. tw.vertices[0].p = tw.start;
  759. tw.vertices[0].endp = tw.vertices[0].p + tw.dir;
  760. tw.vertices[0].pl.FromRay( tw.vertices[0].p, tw.dir );
  761. tw.numEdges = tw.numPolys = 0;
  762. tw.pointTrace = true;
  763. // trace through the model
  764. idCollisionModelManagerLocal::TraceThroughModel( &tw );
  765. // store results
  766. *results = tw.trace;
  767. results->endpos = start + results->fraction * (end - start);
  768. results->endAxis = mat3_identity;
  769. if ( results->fraction < 1.0f ) {
  770. // rotate trace plane normal if there was a collision with a rotated model
  771. if ( model_rotated ) {
  772. results->c.normal *= modelAxis;
  773. results->c.point *= modelAxis;
  774. }
  775. results->c.point += modelOrigin;
  776. results->c.dist += modelOrigin * results->c.normal;
  777. }
  778. idCollisionModelManagerLocal::numContacts = tw.numContacts;
  779. return;
  780. }
  781. // the trace fraction is too inaccurate to describe translations over huge distances
  782. if ( tw.dir.LengthSqr() > Square( CM_MAX_TRACE_DIST ) ) {
  783. results->fraction = 0.0f;
  784. results->endpos = start;
  785. results->endAxis = trmAxis;
  786. results->c.normal = vec3_origin;
  787. results->c.material = NULL;
  788. results->c.point = start;
  789. if ( session->rw ) {
  790. session->rw->DebugArrow( colorRed, start, end, 1 );
  791. }
  792. common->Printf( "idCollisionModelManagerLocal::Translation: huge translation\n" );
  793. return;
  794. }
  795. tw.pointTrace = false;
  796. tw.size.Clear();
  797. // setup trm structure
  798. idCollisionModelManagerLocal::SetupTrm( &tw, trm );
  799. trm_rotated = trmAxis.IsRotated();
  800. // calculate vertex positions
  801. if ( trm_rotated ) {
  802. for ( i = 0; i < tw.numVerts; i++ ) {
  803. // rotate trm around the start position
  804. tw.vertices[i].p *= trmAxis;
  805. }
  806. }
  807. for ( i = 0; i < tw.numVerts; i++ ) {
  808. // set trm at start position
  809. tw.vertices[i].p += tw.start;
  810. }
  811. if ( model_rotated ) {
  812. for ( i = 0; i < tw.numVerts; i++ ) {
  813. // rotate trm around model instead of rotating the model
  814. tw.vertices[i].p *= invModelAxis;
  815. }
  816. }
  817. // add offset to start point
  818. if ( trm_rotated ) {
  819. dir = trm->offset * trmAxis;
  820. tw.start += dir;
  821. tw.end += dir;
  822. } else {
  823. tw.start += trm->offset;
  824. tw.end += trm->offset;
  825. }
  826. if ( model_rotated ) {
  827. // rotate trace instead of model
  828. tw.start *= invModelAxis;
  829. tw.end *= invModelAxis;
  830. tw.dir *= invModelAxis;
  831. }
  832. // rotate trm polygon planes
  833. if ( trm_rotated & model_rotated ) {
  834. tmpAxis = trmAxis * invModelAxis;
  835. for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
  836. poly->plane *= tmpAxis;
  837. }
  838. } else if ( trm_rotated ) {
  839. for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
  840. poly->plane *= trmAxis;
  841. }
  842. } else if ( model_rotated ) {
  843. for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
  844. poly->plane *= invModelAxis;
  845. }
  846. }
  847. // setup trm polygons
  848. for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
  849. // if the trm poly plane is facing in the movement direction
  850. dist = poly->plane.Normal() * tw.dir;
  851. if ( dist > 0.0f || ( !trm->isConvex && dist == 0.0f ) ) {
  852. // this trm poly and it's edges and vertices need to be used for collision
  853. poly->used = true;
  854. for ( j = 0; j < poly->numEdges; j++ ) {
  855. edge = &tw.edges[abs( poly->edges[j] )];
  856. edge->used = true;
  857. tw.vertices[edge->vertexNum[0]].used = true;
  858. tw.vertices[edge->vertexNum[1]].used = true;
  859. }
  860. }
  861. }
  862. // setup trm vertices
  863. for ( vert = tw.vertices, i = 0; i < tw.numVerts; i++, vert++ ) {
  864. if ( !vert->used ) {
  865. continue;
  866. }
  867. // get axial trm size after rotations
  868. tw.size.AddPoint( vert->p - tw.start );
  869. // calculate the end position of each vertex for a full trace
  870. vert->endp = vert->p + tw.dir;
  871. // pluecker coordinate for vertex movement line
  872. vert->pl.FromRay( vert->p, tw.dir );
  873. }
  874. // setup trm edges
  875. for ( edge = tw.edges + 1, i = 1; i <= tw.numEdges; i++, edge++ ) {
  876. if ( !edge->used ) {
  877. continue;
  878. }
  879. // edge start, end and pluecker coordinate
  880. edge->start = tw.vertices[edge->vertexNum[0]].p;
  881. edge->end = tw.vertices[edge->vertexNum[1]].p;
  882. edge->pl.FromLine( edge->start, edge->end );
  883. // calculate normal of plane through movement plane created by the edge
  884. dir = edge->start - edge->end;
  885. edge->cross[0] = dir[0] * tw.dir[1] - dir[1] * tw.dir[0];
  886. edge->cross[1] = dir[0] * tw.dir[2] - dir[2] * tw.dir[0];
  887. edge->cross[2] = dir[1] * tw.dir[2] - dir[2] * tw.dir[1];
  888. // bit for vertex sidedness bit cache
  889. edge->bitNum = i;
  890. }
  891. // set trm plane distances
  892. for ( poly = tw.polys, i = 0; i < tw.numPolys; i++, poly++ ) {
  893. if ( poly->used ) {
  894. poly->plane.FitThroughPoint( tw.edges[abs(poly->edges[0])].start );
  895. }
  896. }
  897. // bounds for full trace, a little bit larger for epsilons
  898. for ( i = 0; i < 3; i++ ) {
  899. if ( tw.start[i] < tw.end[i] ) {
  900. tw.bounds[0][i] = tw.start[i] + tw.size[0][i] - CM_BOX_EPSILON;
  901. tw.bounds[1][i] = tw.end[i] + tw.size[1][i] + CM_BOX_EPSILON;
  902. } else {
  903. tw.bounds[0][i] = tw.end[i] + tw.size[0][i] - CM_BOX_EPSILON;
  904. tw.bounds[1][i] = tw.start[i] + tw.size[1][i] + CM_BOX_EPSILON;
  905. }
  906. if ( idMath::Fabs( tw.size[0][i] ) > idMath::Fabs( tw.size[1][i] ) ) {
  907. tw.extents[i] = idMath::Fabs( tw.size[0][i] ) + CM_BOX_EPSILON;
  908. } else {
  909. tw.extents[i] = idMath::Fabs( tw.size[1][i] ) + CM_BOX_EPSILON;
  910. }
  911. }
  912. // setup trace heart planes
  913. idCollisionModelManagerLocal::SetupTranslationHeartPlanes( &tw );
  914. tw.maxDistFromHeartPlane1 = 0;
  915. tw.maxDistFromHeartPlane2 = 0;
  916. // calculate maximum trm vertex distance from both heart planes
  917. for ( vert = tw.vertices, i = 0; i < tw.numVerts; i++, vert++ ) {
  918. if ( !vert->used ) {
  919. continue;
  920. }
  921. dist = idMath::Fabs( tw.heartPlane1.Distance( vert->p ) );
  922. if ( dist > tw.maxDistFromHeartPlane1 ) {
  923. tw.maxDistFromHeartPlane1 = dist;
  924. }
  925. dist = idMath::Fabs( tw.heartPlane2.Distance( vert->p ) );
  926. if ( dist > tw.maxDistFromHeartPlane2 ) {
  927. tw.maxDistFromHeartPlane2 = dist;
  928. }
  929. }
  930. // for epsilons
  931. tw.maxDistFromHeartPlane1 += CM_BOX_EPSILON;
  932. tw.maxDistFromHeartPlane2 += CM_BOX_EPSILON;
  933. // trace through the model
  934. idCollisionModelManagerLocal::TraceThroughModel( &tw );
  935. // if we're getting contacts
  936. if ( tw.getContacts ) {
  937. // move all contacts to world space
  938. if ( model_rotated ) {
  939. for ( i = 0; i < tw.numContacts; i++ ) {
  940. tw.contacts[i].normal *= modelAxis;
  941. tw.contacts[i].point *= modelAxis;
  942. }
  943. }
  944. if ( modelOrigin != vec3_origin ) {
  945. for ( i = 0; i < tw.numContacts; i++ ) {
  946. tw.contacts[i].point += modelOrigin;
  947. tw.contacts[i].dist += modelOrigin * tw.contacts[i].normal;
  948. }
  949. }
  950. idCollisionModelManagerLocal::numContacts = tw.numContacts;
  951. } else {
  952. // store results
  953. *results = tw.trace;
  954. results->endpos = start + results->fraction * ( end - start );
  955. results->endAxis = trmAxis;
  956. if ( results->fraction < 1.0f ) {
  957. // if the fraction is tiny the actual movement could end up zero
  958. if ( results->fraction > 0.0f && results->endpos.Compare( start ) ) {
  959. results->fraction = 0.0f;
  960. }
  961. // rotate trace plane normal if there was a collision with a rotated model
  962. if ( model_rotated ) {
  963. results->c.normal *= modelAxis;
  964. results->c.point *= modelAxis;
  965. }
  966. results->c.point += modelOrigin;
  967. results->c.dist += modelOrigin * results->c.normal;
  968. }
  969. }
  970. #ifdef _DEBUG
  971. // test for missed collisions
  972. if ( cm_debugCollision.GetBool() ) {
  973. if ( !entered && !idCollisionModelManagerLocal::getContacts ) {
  974. entered = 1;
  975. // if the trm is stuck in the model
  976. if ( idCollisionModelManagerLocal::Contents( results->endpos, trm, trmAxis, -1, model, modelOrigin, modelAxis ) & contentMask ) {
  977. trace_t tr;
  978. // test where the trm is stuck in the model
  979. idCollisionModelManagerLocal::Contents( results->endpos, trm, trmAxis, -1, model, modelOrigin, modelAxis );
  980. // re-run collision detection to find out where it failed
  981. idCollisionModelManagerLocal::Translation( &tr, start, end, trm, trmAxis, contentMask, model, modelOrigin, modelAxis );
  982. }
  983. entered = 0;
  984. }
  985. }
  986. #endif
  987. }