cm_trace.c 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. #include "cm_local.h"
  19. // always use bbox vs. bbox collision and never capsule vs. bbox or vice versa
  20. //#define ALWAYS_BBOX_VS_BBOX
  21. // always use capsule vs. capsule collision and never capsule vs. bbox or vice versa
  22. //#define ALWAYS_CAPSULE_VS_CAPSULE
  23. //#define CAPSULE_DEBUG
  24. /*
  25. ===============================================================================
  26. BASIC MATH
  27. ===============================================================================
  28. */
  29. /*
  30. ================
  31. RotatePoint
  32. ================
  33. */
  34. void RotatePoint(vec3_t point, /*const*/ vec3_t matrix[3]) { // bk: FIXME
  35. vec3_t tvec;
  36. VectorCopy(point, tvec);
  37. point[0] = DotProduct(matrix[0], tvec);
  38. point[1] = DotProduct(matrix[1], tvec);
  39. point[2] = DotProduct(matrix[2], tvec);
  40. }
  41. /*
  42. ================
  43. TransposeMatrix
  44. ================
  45. */
  46. void TransposeMatrix(/*const*/ vec3_t matrix[3], vec3_t transpose[3]) { // bk: FIXME
  47. int i, j;
  48. for (i = 0; i < 3; i++) {
  49. for (j = 0; j < 3; j++) {
  50. transpose[i][j] = matrix[j][i];
  51. }
  52. }
  53. }
  54. /*
  55. ================
  56. CreateRotationMatrix
  57. ================
  58. */
  59. void CreateRotationMatrix(const vec3_t angles, vec3_t matrix[3]) {
  60. AngleVectors(angles, matrix[0], matrix[1], matrix[2]);
  61. VectorInverse(matrix[1]);
  62. }
  63. /*
  64. ================
  65. CM_ProjectPointOntoVector
  66. ================
  67. */
  68. void CM_ProjectPointOntoVector( vec3_t point, vec3_t vStart, vec3_t vDir, vec3_t vProj )
  69. {
  70. vec3_t pVec;
  71. VectorSubtract( point, vStart, pVec );
  72. // project onto the directional vector for this segment
  73. VectorMA( vStart, DotProduct( pVec, vDir ), vDir, vProj );
  74. }
  75. /*
  76. ================
  77. CM_DistanceFromLineSquared
  78. ================
  79. */
  80. float CM_DistanceFromLineSquared(vec3_t p, vec3_t lp1, vec3_t lp2, vec3_t dir) {
  81. vec3_t proj, t;
  82. int j;
  83. CM_ProjectPointOntoVector(p, lp1, dir, proj);
  84. for (j = 0; j < 3; j++)
  85. if ((proj[j] > lp1[j] && proj[j] > lp2[j]) ||
  86. (proj[j] < lp1[j] && proj[j] < lp2[j]))
  87. break;
  88. if (j < 3) {
  89. if (fabs(proj[j] - lp1[j]) < fabs(proj[j] - lp2[j]))
  90. VectorSubtract(p, lp1, t);
  91. else
  92. VectorSubtract(p, lp2, t);
  93. return VectorLengthSquared(t);
  94. }
  95. VectorSubtract(p, proj, t);
  96. return VectorLengthSquared(t);
  97. }
  98. /*
  99. ================
  100. CM_VectorDistanceSquared
  101. ================
  102. */
  103. float CM_VectorDistanceSquared(vec3_t p1, vec3_t p2) {
  104. vec3_t dir;
  105. VectorSubtract(p2, p1, dir);
  106. return VectorLengthSquared(dir);
  107. }
  108. /*
  109. ================
  110. SquareRootFloat
  111. ================
  112. */
  113. float SquareRootFloat(float number) {
  114. long i;
  115. float x, y;
  116. const float f = 1.5F;
  117. x = number * 0.5F;
  118. y = number;
  119. i = * ( long * ) &y;
  120. i = 0x5f3759df - ( i >> 1 );
  121. y = * ( float * ) &i;
  122. y = y * ( f - ( x * y * y ) );
  123. y = y * ( f - ( x * y * y ) );
  124. return number * y;
  125. }
  126. /*
  127. ===============================================================================
  128. POSITION TESTING
  129. ===============================================================================
  130. */
  131. /*
  132. ================
  133. CM_TestBoxInBrush
  134. ================
  135. */
  136. void CM_TestBoxInBrush( traceWork_t *tw, cbrush_t *brush ) {
  137. int i;
  138. cplane_t *plane;
  139. float dist;
  140. float d1;
  141. cbrushside_t *side;
  142. float t;
  143. vec3_t startp;
  144. if (!brush->numsides) {
  145. return;
  146. }
  147. // special test for axial
  148. if ( tw->bounds[0][0] > brush->bounds[1][0]
  149. || tw->bounds[0][1] > brush->bounds[1][1]
  150. || tw->bounds[0][2] > brush->bounds[1][2]
  151. || tw->bounds[1][0] < brush->bounds[0][0]
  152. || tw->bounds[1][1] < brush->bounds[0][1]
  153. || tw->bounds[1][2] < brush->bounds[0][2]
  154. ) {
  155. return;
  156. }
  157. if ( tw->sphere.use ) {
  158. // the first six planes are the axial planes, so we only
  159. // need to test the remainder
  160. for ( i = 6 ; i < brush->numsides ; i++ ) {
  161. side = brush->sides + i;
  162. plane = side->plane;
  163. // adjust the plane distance apropriately for radius
  164. dist = plane->dist + tw->sphere.radius;
  165. // find the closest point on the capsule to the plane
  166. t = DotProduct( plane->normal, tw->sphere.offset );
  167. if ( t > 0 )
  168. {
  169. VectorSubtract( tw->start, tw->sphere.offset, startp );
  170. }
  171. else
  172. {
  173. VectorAdd( tw->start, tw->sphere.offset, startp );
  174. }
  175. d1 = DotProduct( startp, plane->normal ) - dist;
  176. // if completely in front of face, no intersection
  177. if ( d1 > 0 ) {
  178. return;
  179. }
  180. }
  181. } else {
  182. // the first six planes are the axial planes, so we only
  183. // need to test the remainder
  184. for ( i = 6 ; i < brush->numsides ; i++ ) {
  185. side = brush->sides + i;
  186. plane = side->plane;
  187. // adjust the plane distance apropriately for mins/maxs
  188. dist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal );
  189. d1 = DotProduct( tw->start, plane->normal ) - dist;
  190. // if completely in front of face, no intersection
  191. if ( d1 > 0 ) {
  192. return;
  193. }
  194. }
  195. }
  196. // inside this brush
  197. tw->trace.startsolid = tw->trace.allsolid = qtrue;
  198. tw->trace.fraction = 0;
  199. tw->trace.contents = brush->contents;
  200. }
  201. /*
  202. ================
  203. CM_TestInLeaf
  204. ================
  205. */
  206. void CM_TestInLeaf( traceWork_t *tw, cLeaf_t *leaf ) {
  207. int k;
  208. int brushnum;
  209. cbrush_t *b;
  210. cPatch_t *patch;
  211. // test box position against all brushes in the leaf
  212. for (k=0 ; k<leaf->numLeafBrushes ; k++) {
  213. brushnum = cm.leafbrushes[leaf->firstLeafBrush+k];
  214. b = &cm.brushes[brushnum];
  215. if (b->checkcount == cm.checkcount) {
  216. continue; // already checked this brush in another leaf
  217. }
  218. b->checkcount = cm.checkcount;
  219. if ( !(b->contents & tw->contents)) {
  220. continue;
  221. }
  222. CM_TestBoxInBrush( tw, b );
  223. if ( tw->trace.allsolid ) {
  224. return;
  225. }
  226. }
  227. // test against all patches
  228. #ifdef BSPC
  229. if (1) {
  230. #else
  231. if ( !cm_noCurves->integer ) {
  232. #endif //BSPC
  233. for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
  234. patch = cm.surfaces[ cm.leafsurfaces[ leaf->firstLeafSurface + k ] ];
  235. if ( !patch ) {
  236. continue;
  237. }
  238. if ( patch->checkcount == cm.checkcount ) {
  239. continue; // already checked this brush in another leaf
  240. }
  241. patch->checkcount = cm.checkcount;
  242. if ( !(patch->contents & tw->contents)) {
  243. continue;
  244. }
  245. if ( CM_PositionTestInPatchCollide( tw, patch->pc ) ) {
  246. tw->trace.startsolid = tw->trace.allsolid = qtrue;
  247. tw->trace.fraction = 0;
  248. tw->trace.contents = patch->contents;
  249. return;
  250. }
  251. }
  252. }
  253. }
  254. /*
  255. ==================
  256. CM_TestCapsuleInCapsule
  257. capsule inside capsule check
  258. ==================
  259. */
  260. void CM_TestCapsuleInCapsule( traceWork_t *tw, clipHandle_t model ) {
  261. int i;
  262. vec3_t mins, maxs;
  263. vec3_t top, bottom;
  264. vec3_t p1, p2, tmp;
  265. vec3_t offset, symetricSize[2];
  266. float radius, halfwidth, halfheight, offs, r;
  267. CM_ModelBounds(model, mins, maxs);
  268. VectorAdd(tw->start, tw->sphere.offset, top);
  269. VectorSubtract(tw->start, tw->sphere.offset, bottom);
  270. for ( i = 0 ; i < 3 ; i++ ) {
  271. offset[i] = ( mins[i] + maxs[i] ) * 0.5;
  272. symetricSize[0][i] = mins[i] - offset[i];
  273. symetricSize[1][i] = maxs[i] - offset[i];
  274. }
  275. halfwidth = symetricSize[ 1 ][ 0 ];
  276. halfheight = symetricSize[ 1 ][ 2 ];
  277. radius = ( halfwidth > halfheight ) ? halfheight : halfwidth;
  278. offs = halfheight - radius;
  279. r = Square(tw->sphere.radius + radius);
  280. // check if any of the spheres overlap
  281. VectorCopy(offset, p1);
  282. p1[2] += offs;
  283. VectorSubtract(p1, top, tmp);
  284. if ( VectorLengthSquared(tmp) < r ) {
  285. tw->trace.startsolid = tw->trace.allsolid = qtrue;
  286. tw->trace.fraction = 0;
  287. }
  288. VectorSubtract(p1, bottom, tmp);
  289. if ( VectorLengthSquared(tmp) < r ) {
  290. tw->trace.startsolid = tw->trace.allsolid = qtrue;
  291. tw->trace.fraction = 0;
  292. }
  293. VectorCopy(offset, p2);
  294. p2[2] -= offs;
  295. VectorSubtract(p2, top, tmp);
  296. if ( VectorLengthSquared(tmp) < r ) {
  297. tw->trace.startsolid = tw->trace.allsolid = qtrue;
  298. tw->trace.fraction = 0;
  299. }
  300. VectorSubtract(p2, bottom, tmp);
  301. if ( VectorLengthSquared(tmp) < r ) {
  302. tw->trace.startsolid = tw->trace.allsolid = qtrue;
  303. tw->trace.fraction = 0;
  304. }
  305. // if between cylinder up and lower bounds
  306. if ( (top[2] >= p1[2] && top[2] <= p2[2]) ||
  307. (bottom[2] >= p1[2] && bottom[2] <= p2[2]) ) {
  308. // 2d coordinates
  309. top[2] = p1[2] = 0;
  310. // if the cylinders overlap
  311. VectorSubtract(top, p1, tmp);
  312. if ( VectorLengthSquared(tmp) < r ) {
  313. tw->trace.startsolid = tw->trace.allsolid = qtrue;
  314. tw->trace.fraction = 0;
  315. }
  316. }
  317. }
  318. /*
  319. ==================
  320. CM_TestBoundingBoxInCapsule
  321. bounding box inside capsule check
  322. ==================
  323. */
  324. void CM_TestBoundingBoxInCapsule( traceWork_t *tw, clipHandle_t model ) {
  325. vec3_t mins, maxs, offset, size[2];
  326. clipHandle_t h;
  327. cmodel_t *cmod;
  328. int i;
  329. // mins maxs of the capsule
  330. CM_ModelBounds(model, mins, maxs);
  331. // offset for capsule center
  332. for ( i = 0 ; i < 3 ; i++ ) {
  333. offset[i] = ( mins[i] + maxs[i] ) * 0.5;
  334. size[0][i] = mins[i] - offset[i];
  335. size[1][i] = maxs[i] - offset[i];
  336. tw->start[i] -= offset[i];
  337. tw->end[i] -= offset[i];
  338. }
  339. // replace the bounding box with the capsule
  340. tw->sphere.use = qtrue;
  341. tw->sphere.radius = ( size[1][0] > size[1][2] ) ? size[1][2]: size[1][0];
  342. tw->sphere.halfheight = size[1][2];
  343. VectorSet( tw->sphere.offset, 0, 0, size[1][2] - tw->sphere.radius );
  344. // replace the capsule with the bounding box
  345. h = CM_TempBoxModel(tw->size[0], tw->size[1], qfalse);
  346. // calculate collision
  347. cmod = CM_ClipHandleToModel( h );
  348. CM_TestInLeaf( tw, &cmod->leaf );
  349. }
  350. /*
  351. ==================
  352. CM_PositionTest
  353. ==================
  354. */
  355. #define MAX_POSITION_LEAFS 1024
  356. void CM_PositionTest( traceWork_t *tw ) {
  357. int leafs[MAX_POSITION_LEAFS];
  358. int i;
  359. leafList_t ll;
  360. // identify the leafs we are touching
  361. VectorAdd( tw->start, tw->size[0], ll.bounds[0] );
  362. VectorAdd( tw->start, tw->size[1], ll.bounds[1] );
  363. for (i=0 ; i<3 ; i++) {
  364. ll.bounds[0][i] -= 1;
  365. ll.bounds[1][i] += 1;
  366. }
  367. ll.count = 0;
  368. ll.maxcount = MAX_POSITION_LEAFS;
  369. ll.list = leafs;
  370. ll.storeLeafs = CM_StoreLeafs;
  371. ll.lastLeaf = 0;
  372. ll.overflowed = qfalse;
  373. cm.checkcount++;
  374. CM_BoxLeafnums_r( &ll, 0 );
  375. cm.checkcount++;
  376. // test the contents of the leafs
  377. for (i=0 ; i < ll.count ; i++) {
  378. CM_TestInLeaf( tw, &cm.leafs[leafs[i]] );
  379. if ( tw->trace.allsolid ) {
  380. break;
  381. }
  382. }
  383. }
  384. /*
  385. ===============================================================================
  386. TRACING
  387. ===============================================================================
  388. */
  389. /*
  390. ================
  391. CM_TraceThroughPatch
  392. ================
  393. */
  394. void CM_TraceThroughPatch( traceWork_t *tw, cPatch_t *patch ) {
  395. float oldFrac;
  396. c_patch_traces++;
  397. oldFrac = tw->trace.fraction;
  398. CM_TraceThroughPatchCollide( tw, patch->pc );
  399. if ( tw->trace.fraction < oldFrac ) {
  400. tw->trace.surfaceFlags = patch->surfaceFlags;
  401. tw->trace.contents = patch->contents;
  402. }
  403. }
  404. /*
  405. ================
  406. CM_TraceThroughBrush
  407. ================
  408. */
  409. void CM_TraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) {
  410. int i;
  411. cplane_t *plane, *clipplane;
  412. float dist;
  413. float enterFrac, leaveFrac;
  414. float d1, d2;
  415. qboolean getout, startout;
  416. float f;
  417. cbrushside_t *side, *leadside;
  418. float t;
  419. vec3_t startp;
  420. vec3_t endp;
  421. enterFrac = -1.0;
  422. leaveFrac = 1.0;
  423. clipplane = NULL;
  424. if ( !brush->numsides ) {
  425. return;
  426. }
  427. c_brush_traces++;
  428. getout = qfalse;
  429. startout = qfalse;
  430. leadside = NULL;
  431. if ( tw->sphere.use ) {
  432. //
  433. // compare the trace against all planes of the brush
  434. // find the latest time the trace crosses a plane towards the interior
  435. // and the earliest time the trace crosses a plane towards the exterior
  436. //
  437. for (i = 0; i < brush->numsides; i++) {
  438. side = brush->sides + i;
  439. plane = side->plane;
  440. // adjust the plane distance apropriately for radius
  441. dist = plane->dist + tw->sphere.radius;
  442. // find the closest point on the capsule to the plane
  443. t = DotProduct( plane->normal, tw->sphere.offset );
  444. if ( t > 0 )
  445. {
  446. VectorSubtract( tw->start, tw->sphere.offset, startp );
  447. VectorSubtract( tw->end, tw->sphere.offset, endp );
  448. }
  449. else
  450. {
  451. VectorAdd( tw->start, tw->sphere.offset, startp );
  452. VectorAdd( tw->end, tw->sphere.offset, endp );
  453. }
  454. d1 = DotProduct( startp, plane->normal ) - dist;
  455. d2 = DotProduct( endp, plane->normal ) - dist;
  456. if (d2 > 0) {
  457. getout = qtrue; // endpoint is not in solid
  458. }
  459. if (d1 > 0) {
  460. startout = qtrue;
  461. }
  462. // if completely in front of face, no intersection with the entire brush
  463. if (d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 ) ) {
  464. return;
  465. }
  466. // if it doesn't cross the plane, the plane isn't relevent
  467. if (d1 <= 0 && d2 <= 0 ) {
  468. continue;
  469. }
  470. // crosses face
  471. if (d1 > d2) { // enter
  472. f = (d1-SURFACE_CLIP_EPSILON) / (d1-d2);
  473. if ( f < 0 ) {
  474. f = 0;
  475. }
  476. if (f > enterFrac) {
  477. enterFrac = f;
  478. clipplane = plane;
  479. leadside = side;
  480. }
  481. } else { // leave
  482. f = (d1+SURFACE_CLIP_EPSILON) / (d1-d2);
  483. if ( f > 1 ) {
  484. f = 1;
  485. }
  486. if (f < leaveFrac) {
  487. leaveFrac = f;
  488. }
  489. }
  490. }
  491. } else {
  492. //
  493. // compare the trace against all planes of the brush
  494. // find the latest time the trace crosses a plane towards the interior
  495. // and the earliest time the trace crosses a plane towards the exterior
  496. //
  497. for (i = 0; i < brush->numsides; i++) {
  498. side = brush->sides + i;
  499. plane = side->plane;
  500. // adjust the plane distance apropriately for mins/maxs
  501. dist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal );
  502. d1 = DotProduct( tw->start, plane->normal ) - dist;
  503. d2 = DotProduct( tw->end, plane->normal ) - dist;
  504. if (d2 > 0) {
  505. getout = qtrue; // endpoint is not in solid
  506. }
  507. if (d1 > 0) {
  508. startout = qtrue;
  509. }
  510. // if completely in front of face, no intersection with the entire brush
  511. if (d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 ) ) {
  512. return;
  513. }
  514. // if it doesn't cross the plane, the plane isn't relevent
  515. if (d1 <= 0 && d2 <= 0 ) {
  516. continue;
  517. }
  518. // crosses face
  519. if (d1 > d2) { // enter
  520. f = (d1-SURFACE_CLIP_EPSILON) / (d1-d2);
  521. if ( f < 0 ) {
  522. f = 0;
  523. }
  524. if (f > enterFrac) {
  525. enterFrac = f;
  526. clipplane = plane;
  527. leadside = side;
  528. }
  529. } else { // leave
  530. f = (d1+SURFACE_CLIP_EPSILON) / (d1-d2);
  531. if ( f > 1 ) {
  532. f = 1;
  533. }
  534. if (f < leaveFrac) {
  535. leaveFrac = f;
  536. }
  537. }
  538. }
  539. }
  540. //
  541. // all planes have been checked, and the trace was not
  542. // completely outside the brush
  543. //
  544. if (!startout) { // original point was inside brush
  545. tw->trace.startsolid = qtrue;
  546. if (!getout) {
  547. tw->trace.allsolid = qtrue;
  548. tw->trace.fraction = 0;
  549. tw->trace.contents = brush->contents;
  550. }
  551. return;
  552. }
  553. if (enterFrac < leaveFrac) {
  554. if (enterFrac > -1 && enterFrac < tw->trace.fraction) {
  555. if (enterFrac < 0) {
  556. enterFrac = 0;
  557. }
  558. tw->trace.fraction = enterFrac;
  559. tw->trace.plane = *clipplane;
  560. tw->trace.surfaceFlags = leadside->surfaceFlags;
  561. tw->trace.contents = brush->contents;
  562. }
  563. }
  564. }
  565. /*
  566. ================
  567. CM_TraceThroughLeaf
  568. ================
  569. */
  570. void CM_TraceThroughLeaf( traceWork_t *tw, cLeaf_t *leaf ) {
  571. int k;
  572. int brushnum;
  573. cbrush_t *b;
  574. cPatch_t *patch;
  575. // trace line against all brushes in the leaf
  576. for ( k = 0 ; k < leaf->numLeafBrushes ; k++ ) {
  577. brushnum = cm.leafbrushes[leaf->firstLeafBrush+k];
  578. b = &cm.brushes[brushnum];
  579. if ( b->checkcount == cm.checkcount ) {
  580. continue; // already checked this brush in another leaf
  581. }
  582. b->checkcount = cm.checkcount;
  583. if ( !(b->contents & tw->contents) ) {
  584. continue;
  585. }
  586. CM_TraceThroughBrush( tw, b );
  587. if ( !tw->trace.fraction ) {
  588. return;
  589. }
  590. }
  591. // trace line against all patches in the leaf
  592. #ifdef BSPC
  593. if (1) {
  594. #else
  595. if ( !cm_noCurves->integer ) {
  596. #endif
  597. for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
  598. patch = cm.surfaces[ cm.leafsurfaces[ leaf->firstLeafSurface + k ] ];
  599. if ( !patch ) {
  600. continue;
  601. }
  602. if ( patch->checkcount == cm.checkcount ) {
  603. continue; // already checked this patch in another leaf
  604. }
  605. patch->checkcount = cm.checkcount;
  606. if ( !(patch->contents & tw->contents) ) {
  607. continue;
  608. }
  609. CM_TraceThroughPatch( tw, patch );
  610. if ( !tw->trace.fraction ) {
  611. return;
  612. }
  613. }
  614. }
  615. }
  616. #define RADIUS_EPSILON 1.0f
  617. /*
  618. ================
  619. CM_TraceThroughSphere
  620. get the first intersection of the ray with the sphere
  621. ================
  622. */
  623. void CM_TraceThroughSphere( traceWork_t *tw, vec3_t origin, float radius, vec3_t start, vec3_t end ) {
  624. float l1, l2, length, scale, fraction;
  625. float a, b, c, d, sqrtd;
  626. vec3_t v1, dir, intersection;
  627. // if inside the sphere
  628. VectorSubtract(start, origin, dir);
  629. l1 = VectorLengthSquared(dir);
  630. if (l1 < Square(radius)) {
  631. tw->trace.fraction = 0;
  632. tw->trace.startsolid = qtrue;
  633. // test for allsolid
  634. VectorSubtract(end, origin, dir);
  635. l1 = VectorLengthSquared(dir);
  636. if (l1 < Square(radius)) {
  637. tw->trace.allsolid = qtrue;
  638. }
  639. return;
  640. }
  641. //
  642. VectorSubtract(end, start, dir);
  643. length = VectorNormalize(dir);
  644. //
  645. l1 = CM_DistanceFromLineSquared(origin, start, end, dir);
  646. VectorSubtract(end, origin, v1);
  647. l2 = VectorLengthSquared(v1);
  648. // if no intersection with the sphere and the end point is at least an epsilon away
  649. if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {
  650. return;
  651. }
  652. //
  653. // | origin - (start + t * dir) | = radius
  654. // a = dir[0]^2 + dir[1]^2 + dir[2]^2;
  655. // b = 2 * (dir[0] * (start[0] - origin[0]) + dir[1] * (start[1] - origin[1]) + dir[2] * (start[2] - origin[2]));
  656. // c = (start[0] - origin[0])^2 + (start[1] - origin[1])^2 + (start[2] - origin[2])^2 - radius^2;
  657. //
  658. VectorSubtract(start, origin, v1);
  659. // dir is normalized so a = 1
  660. a = 1.0f;//dir[0] * dir[0] + dir[1] * dir[1] + dir[2] * dir[2];
  661. b = 2.0f * (dir[0] * v1[0] + dir[1] * v1[1] + dir[2] * v1[2]);
  662. c = v1[0] * v1[0] + v1[1] * v1[1] + v1[2] * v1[2] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);
  663. d = b * b - 4.0f * c;// * a;
  664. if (d > 0) {
  665. sqrtd = SquareRootFloat(d);
  666. // = (- b + sqrtd) * 0.5f; // / (2.0f * a);
  667. fraction = (- b - sqrtd) * 0.5f; // / (2.0f * a);
  668. //
  669. if (fraction < 0) {
  670. fraction = 0;
  671. }
  672. else {
  673. fraction /= length;
  674. }
  675. if ( fraction < tw->trace.fraction ) {
  676. tw->trace.fraction = fraction;
  677. VectorSubtract(end, start, dir);
  678. VectorMA(start, fraction, dir, intersection);
  679. VectorSubtract(intersection, origin, dir);
  680. #ifdef CAPSULE_DEBUG
  681. l2 = VectorLength(dir);
  682. if (l2 < radius) {
  683. int bah = 1;
  684. }
  685. #endif
  686. scale = 1 / (radius+RADIUS_EPSILON);
  687. VectorScale(dir, scale, dir);
  688. VectorCopy(dir, tw->trace.plane.normal);
  689. VectorAdd( tw->modelOrigin, intersection, intersection);
  690. tw->trace.plane.dist = DotProduct(tw->trace.plane.normal, intersection);
  691. tw->trace.contents = CONTENTS_BODY;
  692. }
  693. }
  694. else if (d == 0) {
  695. //t1 = (- b ) / 2;
  696. // slide along the sphere
  697. }
  698. // no intersection at all
  699. }
  700. /*
  701. ================
  702. CM_TraceThroughVerticalCylinder
  703. get the first intersection of the ray with the cylinder
  704. the cylinder extends halfheight above and below the origin
  705. ================
  706. */
  707. void CM_TraceThroughVerticalCylinder( traceWork_t *tw, vec3_t origin, float radius, float halfheight, vec3_t start, vec3_t end) {
  708. float length, scale, fraction, l1, l2;
  709. float a, b, c, d, sqrtd;
  710. vec3_t v1, dir, start2d, end2d, org2d, intersection;
  711. // 2d coordinates
  712. VectorSet(start2d, start[0], start[1], 0);
  713. VectorSet(end2d, end[0], end[1], 0);
  714. VectorSet(org2d, origin[0], origin[1], 0);
  715. // if between lower and upper cylinder bounds
  716. if (start[2] <= origin[2] + halfheight &&
  717. start[2] >= origin[2] - halfheight) {
  718. // if inside the cylinder
  719. VectorSubtract(start2d, org2d, dir);
  720. l1 = VectorLengthSquared(dir);
  721. if (l1 < Square(radius)) {
  722. tw->trace.fraction = 0;
  723. tw->trace.startsolid = qtrue;
  724. VectorSubtract(end2d, org2d, dir);
  725. l1 = VectorLengthSquared(dir);
  726. if (l1 < Square(radius)) {
  727. tw->trace.allsolid = qtrue;
  728. }
  729. return;
  730. }
  731. }
  732. //
  733. VectorSubtract(end2d, start2d, dir);
  734. length = VectorNormalize(dir);
  735. //
  736. l1 = CM_DistanceFromLineSquared(org2d, start2d, end2d, dir);
  737. VectorSubtract(end2d, org2d, v1);
  738. l2 = VectorLengthSquared(v1);
  739. // if no intersection with the cylinder and the end point is at least an epsilon away
  740. if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) {
  741. return;
  742. }
  743. //
  744. //
  745. // (start[0] - origin[0] - t * dir[0]) ^ 2 + (start[1] - origin[1] - t * dir[1]) ^ 2 = radius ^ 2
  746. // (v1[0] + t * dir[0]) ^ 2 + (v1[1] + t * dir[1]) ^ 2 = radius ^ 2;
  747. // v1[0] ^ 2 + 2 * v1[0] * t * dir[0] + (t * dir[0]) ^ 2 +
  748. // v1[1] ^ 2 + 2 * v1[1] * t * dir[1] + (t * dir[1]) ^ 2 = radius ^ 2
  749. // t ^ 2 * (dir[0] ^ 2 + dir[1] ^ 2) + t * (2 * v1[0] * dir[0] + 2 * v1[1] * dir[1]) +
  750. // v1[0] ^ 2 + v1[1] ^ 2 - radius ^ 2 = 0
  751. //
  752. VectorSubtract(start, origin, v1);
  753. // dir is normalized so we can use a = 1
  754. a = 1.0f;// * (dir[0] * dir[0] + dir[1] * dir[1]);
  755. b = 2.0f * (v1[0] * dir[0] + v1[1] * dir[1]);
  756. c = v1[0] * v1[0] + v1[1] * v1[1] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON);
  757. d = b * b - 4.0f * c;// * a;
  758. if (d > 0) {
  759. sqrtd = SquareRootFloat(d);
  760. // = (- b + sqrtd) * 0.5f;// / (2.0f * a);
  761. fraction = (- b - sqrtd) * 0.5f;// / (2.0f * a);
  762. //
  763. if (fraction < 0) {
  764. fraction = 0;
  765. }
  766. else {
  767. fraction /= length;
  768. }
  769. if ( fraction < tw->trace.fraction ) {
  770. VectorSubtract(end, start, dir);
  771. VectorMA(start, fraction, dir, intersection);
  772. // if the intersection is between the cylinder lower and upper bound
  773. if (intersection[2] <= origin[2] + halfheight &&
  774. intersection[2] >= origin[2] - halfheight) {
  775. //
  776. tw->trace.fraction = fraction;
  777. VectorSubtract(intersection, origin, dir);
  778. dir[2] = 0;
  779. #ifdef CAPSULE_DEBUG
  780. l2 = VectorLength(dir);
  781. if (l2 <= radius) {
  782. int bah = 1;
  783. }
  784. #endif
  785. scale = 1 / (radius+RADIUS_EPSILON);
  786. VectorScale(dir, scale, dir);
  787. VectorCopy(dir, tw->trace.plane.normal);
  788. VectorAdd( tw->modelOrigin, intersection, intersection);
  789. tw->trace.plane.dist = DotProduct(tw->trace.plane.normal, intersection);
  790. tw->trace.contents = CONTENTS_BODY;
  791. }
  792. }
  793. }
  794. else if (d == 0) {
  795. //t[0] = (- b ) / 2 * a;
  796. // slide along the cylinder
  797. }
  798. // no intersection at all
  799. }
  800. /*
  801. ================
  802. CM_TraceCapsuleThroughCapsule
  803. capsule vs. capsule collision (not rotated)
  804. ================
  805. */
  806. void CM_TraceCapsuleThroughCapsule( traceWork_t *tw, clipHandle_t model ) {
  807. int i;
  808. vec3_t mins, maxs;
  809. vec3_t top, bottom, starttop, startbottom, endtop, endbottom;
  810. vec3_t offset, symetricSize[2];
  811. float radius, halfwidth, halfheight, offs, h;
  812. CM_ModelBounds(model, mins, maxs);
  813. // test trace bounds vs. capsule bounds
  814. if ( tw->bounds[0][0] > maxs[0] + RADIUS_EPSILON
  815. || tw->bounds[0][1] > maxs[1] + RADIUS_EPSILON
  816. || tw->bounds[0][2] > maxs[2] + RADIUS_EPSILON
  817. || tw->bounds[1][0] < mins[0] - RADIUS_EPSILON
  818. || tw->bounds[1][1] < mins[1] - RADIUS_EPSILON
  819. || tw->bounds[1][2] < mins[2] - RADIUS_EPSILON
  820. ) {
  821. return;
  822. }
  823. // top origin and bottom origin of each sphere at start and end of trace
  824. VectorAdd(tw->start, tw->sphere.offset, starttop);
  825. VectorSubtract(tw->start, tw->sphere.offset, startbottom);
  826. VectorAdd(tw->end, tw->sphere.offset, endtop);
  827. VectorSubtract(tw->end, tw->sphere.offset, endbottom);
  828. // calculate top and bottom of the capsule spheres to collide with
  829. for ( i = 0 ; i < 3 ; i++ ) {
  830. offset[i] = ( mins[i] + maxs[i] ) * 0.5;
  831. symetricSize[0][i] = mins[i] - offset[i];
  832. symetricSize[1][i] = maxs[i] - offset[i];
  833. }
  834. halfwidth = symetricSize[ 1 ][ 0 ];
  835. halfheight = symetricSize[ 1 ][ 2 ];
  836. radius = ( halfwidth > halfheight ) ? halfheight : halfwidth;
  837. offs = halfheight - radius;
  838. VectorCopy(offset, top);
  839. top[2] += offs;
  840. VectorCopy(offset, bottom);
  841. bottom[2] -= offs;
  842. // expand radius of spheres
  843. radius += tw->sphere.radius;
  844. // if there is horizontal movement
  845. if ( tw->start[0] != tw->end[0] || tw->start[1] != tw->end[1] ) {
  846. // height of the expanded cylinder is the height of both cylinders minus the radius of both spheres
  847. h = halfheight + tw->sphere.halfheight - radius;
  848. // if the cylinder has a height
  849. if ( h > 0 ) {
  850. // test for collisions between the cylinders
  851. CM_TraceThroughVerticalCylinder(tw, offset, radius, h, tw->start, tw->end);
  852. }
  853. }
  854. // test for collision between the spheres
  855. CM_TraceThroughSphere(tw, top, radius, startbottom, endbottom);
  856. CM_TraceThroughSphere(tw, bottom, radius, starttop, endtop);
  857. }
  858. /*
  859. ================
  860. CM_TraceBoundingBoxThroughCapsule
  861. bounding box vs. capsule collision
  862. ================
  863. */
  864. void CM_TraceBoundingBoxThroughCapsule( traceWork_t *tw, clipHandle_t model ) {
  865. vec3_t mins, maxs, offset, size[2];
  866. clipHandle_t h;
  867. cmodel_t *cmod;
  868. int i;
  869. // mins maxs of the capsule
  870. CM_ModelBounds(model, mins, maxs);
  871. // offset for capsule center
  872. for ( i = 0 ; i < 3 ; i++ ) {
  873. offset[i] = ( mins[i] + maxs[i] ) * 0.5;
  874. size[0][i] = mins[i] - offset[i];
  875. size[1][i] = maxs[i] - offset[i];
  876. tw->start[i] -= offset[i];
  877. tw->end[i] -= offset[i];
  878. }
  879. // replace the bounding box with the capsule
  880. tw->sphere.use = qtrue;
  881. tw->sphere.radius = ( size[1][0] > size[1][2] ) ? size[1][2]: size[1][0];
  882. tw->sphere.halfheight = size[1][2];
  883. VectorSet( tw->sphere.offset, 0, 0, size[1][2] - tw->sphere.radius );
  884. // replace the capsule with the bounding box
  885. h = CM_TempBoxModel(tw->size[0], tw->size[1], qfalse);
  886. // calculate collision
  887. cmod = CM_ClipHandleToModel( h );
  888. CM_TraceThroughLeaf( tw, &cmod->leaf );
  889. }
  890. //=========================================================================================
  891. /*
  892. ==================
  893. CM_TraceThroughTree
  894. Traverse all the contacted leafs from the start to the end position.
  895. If the trace is a point, they will be exactly in order, but for larger
  896. trace volumes it is possible to hit something in a later leaf with
  897. a smaller intercept fraction.
  898. ==================
  899. */
  900. void CM_TraceThroughTree( traceWork_t *tw, int num, float p1f, float p2f, vec3_t p1, vec3_t p2) {
  901. cNode_t *node;
  902. cplane_t *plane;
  903. float t1, t2, offset;
  904. float frac, frac2;
  905. float idist;
  906. vec3_t mid;
  907. int side;
  908. float midf;
  909. if (tw->trace.fraction <= p1f) {
  910. return; // already hit something nearer
  911. }
  912. // if < 0, we are in a leaf node
  913. if (num < 0) {
  914. CM_TraceThroughLeaf( tw, &cm.leafs[-1-num] );
  915. return;
  916. }
  917. //
  918. // find the point distances to the seperating plane
  919. // and the offset for the size of the box
  920. //
  921. node = cm.nodes + num;
  922. plane = node->plane;
  923. // adjust the plane distance apropriately for mins/maxs
  924. if ( plane->type < 3 ) {
  925. t1 = p1[plane->type] - plane->dist;
  926. t2 = p2[plane->type] - plane->dist;
  927. offset = tw->extents[plane->type];
  928. } else {
  929. t1 = DotProduct (plane->normal, p1) - plane->dist;
  930. t2 = DotProduct (plane->normal, p2) - plane->dist;
  931. if ( tw->isPoint ) {
  932. offset = 0;
  933. } else {
  934. #if 0 // bk010201 - DEAD
  935. // an axial brush right behind a slanted bsp plane
  936. // will poke through when expanded, so adjust
  937. // by sqrt(3)
  938. offset = fabs(tw->extents[0]*plane->normal[0]) +
  939. fabs(tw->extents[1]*plane->normal[1]) +
  940. fabs(tw->extents[2]*plane->normal[2]);
  941. offset *= 2;
  942. offset = tw->maxOffset;
  943. #endif
  944. // this is silly
  945. offset = 2048;
  946. }
  947. }
  948. // see which sides we need to consider
  949. if ( t1 >= offset + 1 && t2 >= offset + 1 ) {
  950. CM_TraceThroughTree( tw, node->children[0], p1f, p2f, p1, p2 );
  951. return;
  952. }
  953. if ( t1 < -offset - 1 && t2 < -offset - 1 ) {
  954. CM_TraceThroughTree( tw, node->children[1], p1f, p2f, p1, p2 );
  955. return;
  956. }
  957. // put the crosspoint SURFACE_CLIP_EPSILON pixels on the near side
  958. if ( t1 < t2 ) {
  959. idist = 1.0/(t1-t2);
  960. side = 1;
  961. frac2 = (t1 + offset + SURFACE_CLIP_EPSILON)*idist;
  962. frac = (t1 - offset + SURFACE_CLIP_EPSILON)*idist;
  963. } else if (t1 > t2) {
  964. idist = 1.0/(t1-t2);
  965. side = 0;
  966. frac2 = (t1 - offset - SURFACE_CLIP_EPSILON)*idist;
  967. frac = (t1 + offset + SURFACE_CLIP_EPSILON)*idist;
  968. } else {
  969. side = 0;
  970. frac = 1;
  971. frac2 = 0;
  972. }
  973. // move up to the node
  974. if ( frac < 0 ) {
  975. frac = 0;
  976. }
  977. if ( frac > 1 ) {
  978. frac = 1;
  979. }
  980. midf = p1f + (p2f - p1f)*frac;
  981. mid[0] = p1[0] + frac*(p2[0] - p1[0]);
  982. mid[1] = p1[1] + frac*(p2[1] - p1[1]);
  983. mid[2] = p1[2] + frac*(p2[2] - p1[2]);
  984. CM_TraceThroughTree( tw, node->children[side], p1f, midf, p1, mid );
  985. // go past the node
  986. if ( frac2 < 0 ) {
  987. frac2 = 0;
  988. }
  989. if ( frac2 > 1 ) {
  990. frac2 = 1;
  991. }
  992. midf = p1f + (p2f - p1f)*frac2;
  993. mid[0] = p1[0] + frac2*(p2[0] - p1[0]);
  994. mid[1] = p1[1] + frac2*(p2[1] - p1[1]);
  995. mid[2] = p1[2] + frac2*(p2[2] - p1[2]);
  996. CM_TraceThroughTree( tw, node->children[side^1], midf, p2f, mid, p2 );
  997. }
  998. //======================================================================
  999. /*
  1000. ==================
  1001. CM_Trace
  1002. ==================
  1003. */
  1004. void CM_Trace( trace_t *results, const vec3_t start, const vec3_t end, vec3_t mins, vec3_t maxs,
  1005. clipHandle_t model, const vec3_t origin, int brushmask, int capsule, sphere_t *sphere ) {
  1006. int i;
  1007. traceWork_t tw;
  1008. vec3_t offset;
  1009. cmodel_t *cmod;
  1010. cmod = CM_ClipHandleToModel( model );
  1011. cm.checkcount++; // for multi-check avoidance
  1012. c_traces++; // for statistics, may be zeroed
  1013. // fill in a default trace
  1014. Com_Memset( &tw, 0, sizeof(tw) );
  1015. tw.trace.fraction = 1; // assume it goes the entire distance until shown otherwise
  1016. VectorCopy(origin, tw.modelOrigin);
  1017. if (!cm.numNodes) {
  1018. *results = tw.trace;
  1019. return; // map not loaded, shouldn't happen
  1020. }
  1021. // allow NULL to be passed in for 0,0,0
  1022. if ( !mins ) {
  1023. mins = vec3_origin;
  1024. }
  1025. if ( !maxs ) {
  1026. maxs = vec3_origin;
  1027. }
  1028. // set basic parms
  1029. tw.contents = brushmask;
  1030. // adjust so that mins and maxs are always symetric, which
  1031. // avoids some complications with plane expanding of rotated
  1032. // bmodels
  1033. for ( i = 0 ; i < 3 ; i++ ) {
  1034. offset[i] = ( mins[i] + maxs[i] ) * 0.5;
  1035. tw.size[0][i] = mins[i] - offset[i];
  1036. tw.size[1][i] = maxs[i] - offset[i];
  1037. tw.start[i] = start[i] + offset[i];
  1038. tw.end[i] = end[i] + offset[i];
  1039. }
  1040. // if a sphere is already specified
  1041. if ( sphere ) {
  1042. tw.sphere = *sphere;
  1043. }
  1044. else {
  1045. tw.sphere.use = capsule;
  1046. tw.sphere.radius = ( tw.size[1][0] > tw.size[1][2] ) ? tw.size[1][2]: tw.size[1][0];
  1047. tw.sphere.halfheight = tw.size[1][2];
  1048. VectorSet( tw.sphere.offset, 0, 0, tw.size[1][2] - tw.sphere.radius );
  1049. }
  1050. tw.maxOffset = tw.size[1][0] + tw.size[1][1] + tw.size[1][2];
  1051. // tw.offsets[signbits] = vector to apropriate corner from origin
  1052. tw.offsets[0][0] = tw.size[0][0];
  1053. tw.offsets[0][1] = tw.size[0][1];
  1054. tw.offsets[0][2] = tw.size[0][2];
  1055. tw.offsets[1][0] = tw.size[1][0];
  1056. tw.offsets[1][1] = tw.size[0][1];
  1057. tw.offsets[1][2] = tw.size[0][2];
  1058. tw.offsets[2][0] = tw.size[0][0];
  1059. tw.offsets[2][1] = tw.size[1][1];
  1060. tw.offsets[2][2] = tw.size[0][2];
  1061. tw.offsets[3][0] = tw.size[1][0];
  1062. tw.offsets[3][1] = tw.size[1][1];
  1063. tw.offsets[3][2] = tw.size[0][2];
  1064. tw.offsets[4][0] = tw.size[0][0];
  1065. tw.offsets[4][1] = tw.size[0][1];
  1066. tw.offsets[4][2] = tw.size[1][2];
  1067. tw.offsets[5][0] = tw.size[1][0];
  1068. tw.offsets[5][1] = tw.size[0][1];
  1069. tw.offsets[5][2] = tw.size[1][2];
  1070. tw.offsets[6][0] = tw.size[0][0];
  1071. tw.offsets[6][1] = tw.size[1][1];
  1072. tw.offsets[6][2] = tw.size[1][2];
  1073. tw.offsets[7][0] = tw.size[1][0];
  1074. tw.offsets[7][1] = tw.size[1][1];
  1075. tw.offsets[7][2] = tw.size[1][2];
  1076. //
  1077. // calculate bounds
  1078. //
  1079. if ( tw.sphere.use ) {
  1080. for ( i = 0 ; i < 3 ; i++ ) {
  1081. if ( tw.start[i] < tw.end[i] ) {
  1082. tw.bounds[0][i] = tw.start[i] - fabs(tw.sphere.offset[i]) - tw.sphere.radius;
  1083. tw.bounds[1][i] = tw.end[i] + fabs(tw.sphere.offset[i]) + tw.sphere.radius;
  1084. } else {
  1085. tw.bounds[0][i] = tw.end[i] - fabs(tw.sphere.offset[i]) - tw.sphere.radius;
  1086. tw.bounds[1][i] = tw.start[i] + fabs(tw.sphere.offset[i]) + tw.sphere.radius;
  1087. }
  1088. }
  1089. }
  1090. else {
  1091. for ( i = 0 ; i < 3 ; i++ ) {
  1092. if ( tw.start[i] < tw.end[i] ) {
  1093. tw.bounds[0][i] = tw.start[i] + tw.size[0][i];
  1094. tw.bounds[1][i] = tw.end[i] + tw.size[1][i];
  1095. } else {
  1096. tw.bounds[0][i] = tw.end[i] + tw.size[0][i];
  1097. tw.bounds[1][i] = tw.start[i] + tw.size[1][i];
  1098. }
  1099. }
  1100. }
  1101. //
  1102. // check for position test special case
  1103. //
  1104. if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) {
  1105. if ( model ) {
  1106. #ifdef ALWAYS_BBOX_VS_BBOX // bk010201 - FIXME - compile time flag?
  1107. if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {
  1108. tw.sphere.use = qfalse;
  1109. CM_TestInLeaf( &tw, &cmod->leaf );
  1110. }
  1111. else
  1112. #elif defined(ALWAYS_CAPSULE_VS_CAPSULE)
  1113. if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {
  1114. CM_TestCapsuleInCapsule( &tw, model );
  1115. }
  1116. else
  1117. #endif
  1118. if ( model == CAPSULE_MODEL_HANDLE ) {
  1119. if ( tw.sphere.use ) {
  1120. CM_TestCapsuleInCapsule( &tw, model );
  1121. }
  1122. else {
  1123. CM_TestBoundingBoxInCapsule( &tw, model );
  1124. }
  1125. }
  1126. else {
  1127. CM_TestInLeaf( &tw, &cmod->leaf );
  1128. }
  1129. } else {
  1130. CM_PositionTest( &tw );
  1131. }
  1132. } else {
  1133. //
  1134. // check for point special case
  1135. //
  1136. if ( tw.size[0][0] == 0 && tw.size[0][1] == 0 && tw.size[0][2] == 0 ) {
  1137. tw.isPoint = qtrue;
  1138. VectorClear( tw.extents );
  1139. } else {
  1140. tw.isPoint = qfalse;
  1141. tw.extents[0] = tw.size[1][0];
  1142. tw.extents[1] = tw.size[1][1];
  1143. tw.extents[2] = tw.size[1][2];
  1144. }
  1145. //
  1146. // general sweeping through world
  1147. //
  1148. if ( model ) {
  1149. #ifdef ALWAYS_BBOX_VS_BBOX
  1150. if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {
  1151. tw.sphere.use = qfalse;
  1152. CM_TraceThroughLeaf( &tw, &cmod->leaf );
  1153. }
  1154. else
  1155. #elif defined(ALWAYS_CAPSULE_VS_CAPSULE)
  1156. if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) {
  1157. CM_TraceCapsuleThroughCapsule( &tw, model );
  1158. }
  1159. else
  1160. #endif
  1161. if ( model == CAPSULE_MODEL_HANDLE ) {
  1162. if ( tw.sphere.use ) {
  1163. CM_TraceCapsuleThroughCapsule( &tw, model );
  1164. }
  1165. else {
  1166. CM_TraceBoundingBoxThroughCapsule( &tw, model );
  1167. }
  1168. }
  1169. else {
  1170. CM_TraceThroughLeaf( &tw, &cmod->leaf );
  1171. }
  1172. } else {
  1173. CM_TraceThroughTree( &tw, 0, 0, 1, tw.start, tw.end );
  1174. }
  1175. }
  1176. // generate endpos from the original, unmodified start/end
  1177. if ( tw.trace.fraction == 1 ) {
  1178. VectorCopy (end, tw.trace.endpos);
  1179. } else {
  1180. for ( i=0 ; i<3 ; i++ ) {
  1181. tw.trace.endpos[i] = start[i] + tw.trace.fraction * (end[i] - start[i]);
  1182. }
  1183. }
  1184. // If allsolid is set (was entirely inside something solid), the plane is not valid.
  1185. // If fraction == 1.0, we never hit anything, and thus the plane is not valid.
  1186. // Otherwise, the normal on the plane should have unit length
  1187. assert(tw.trace.allsolid ||
  1188. tw.trace.fraction == 1.0 ||
  1189. VectorLengthSquared(tw.trace.plane.normal) > 0.9999);
  1190. *results = tw.trace;
  1191. }
  1192. /*
  1193. ==================
  1194. CM_BoxTrace
  1195. ==================
  1196. */
  1197. void CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
  1198. vec3_t mins, vec3_t maxs,
  1199. clipHandle_t model, int brushmask, int capsule ) {
  1200. CM_Trace( results, start, end, mins, maxs, model, vec3_origin, brushmask, capsule, NULL );
  1201. }
  1202. /*
  1203. ==================
  1204. CM_TransformedBoxTrace
  1205. Handles offseting and rotation of the end points for moving and
  1206. rotating entities
  1207. ==================
  1208. */
  1209. void CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
  1210. vec3_t mins, vec3_t maxs,
  1211. clipHandle_t model, int brushmask,
  1212. const vec3_t origin, const vec3_t angles, int capsule ) {
  1213. trace_t trace;
  1214. vec3_t start_l, end_l;
  1215. qboolean rotated;
  1216. vec3_t offset;
  1217. vec3_t symetricSize[2];
  1218. vec3_t matrix[3], transpose[3];
  1219. int i;
  1220. float halfwidth;
  1221. float halfheight;
  1222. float t;
  1223. sphere_t sphere;
  1224. if ( !mins ) {
  1225. mins = vec3_origin;
  1226. }
  1227. if ( !maxs ) {
  1228. maxs = vec3_origin;
  1229. }
  1230. // adjust so that mins and maxs are always symetric, which
  1231. // avoids some complications with plane expanding of rotated
  1232. // bmodels
  1233. for ( i = 0 ; i < 3 ; i++ ) {
  1234. offset[i] = ( mins[i] + maxs[i] ) * 0.5;
  1235. symetricSize[0][i] = mins[i] - offset[i];
  1236. symetricSize[1][i] = maxs[i] - offset[i];
  1237. start_l[i] = start[i] + offset[i];
  1238. end_l[i] = end[i] + offset[i];
  1239. }
  1240. // subtract origin offset
  1241. VectorSubtract( start_l, origin, start_l );
  1242. VectorSubtract( end_l, origin, end_l );
  1243. // rotate start and end into the models frame of reference
  1244. if ( model != BOX_MODEL_HANDLE &&
  1245. (angles[0] || angles[1] || angles[2]) ) {
  1246. rotated = qtrue;
  1247. } else {
  1248. rotated = qfalse;
  1249. }
  1250. halfwidth = symetricSize[ 1 ][ 0 ];
  1251. halfheight = symetricSize[ 1 ][ 2 ];
  1252. sphere.use = capsule;
  1253. sphere.radius = ( halfwidth > halfheight ) ? halfheight : halfwidth;
  1254. sphere.halfheight = halfheight;
  1255. t = halfheight - sphere.radius;
  1256. if (rotated) {
  1257. // rotation on trace line (start-end) instead of rotating the bmodel
  1258. // NOTE: This is still incorrect for bounding boxes because the actual bounding
  1259. // box that is swept through the model is not rotated. We cannot rotate
  1260. // the bounding box or the bmodel because that would make all the brush
  1261. // bevels invalid.
  1262. // However this is correct for capsules since a capsule itself is rotated too.
  1263. CreateRotationMatrix(angles, matrix);
  1264. RotatePoint(start_l, matrix);
  1265. RotatePoint(end_l, matrix);
  1266. // rotated sphere offset for capsule
  1267. sphere.offset[0] = matrix[0][ 2 ] * t;
  1268. sphere.offset[1] = -matrix[1][ 2 ] * t;
  1269. sphere.offset[2] = matrix[2][ 2 ] * t;
  1270. }
  1271. else {
  1272. VectorSet( sphere.offset, 0, 0, t );
  1273. }
  1274. // sweep the box through the model
  1275. CM_Trace( &trace, start_l, end_l, symetricSize[0], symetricSize[1], model, origin, brushmask, capsule, &sphere );
  1276. // if the bmodel was rotated and there was a collision
  1277. if ( rotated && trace.fraction != 1.0 ) {
  1278. // rotation of bmodel collision plane
  1279. TransposeMatrix(matrix, transpose);
  1280. RotatePoint(trace.plane.normal, transpose);
  1281. }
  1282. // re-calculate the end position of the trace because the trace.endpos
  1283. // calculated by CM_Trace could be rotated and have an offset
  1284. trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);
  1285. trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);
  1286. trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);
  1287. *results = trace;
  1288. }