cm_trace.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224
  1. #include "cm_local.h"
  2. #ifdef _XBOX
  3. #include "../renderer/tr_local.h"
  4. #endif
  5. /*
  6. ===============================================================================
  7. POSITION TESTING
  8. ===============================================================================
  9. */
  10. extern cvar_t *com_terrainPhysics;
  11. void VectorAdvance( const vec3_t veca, const float scale, const vec3_t vecb, vec3_t vecc);
  12. /*
  13. ================
  14. CM_TestBoxInBrush
  15. ================
  16. */
  17. void CM_TestBoxInBrush( traceWork_t *tw, cbrush_t *brush ) {
  18. int i;
  19. cplane_t *plane;
  20. float dist;
  21. float d1;
  22. cbrushside_t *side;
  23. if (!brush->numsides) {
  24. return;
  25. }
  26. // special test for axial
  27. if ( tw->bounds[0][0] > brush->bounds[1][0]
  28. || tw->bounds[0][1] > brush->bounds[1][1]
  29. || tw->bounds[0][2] > brush->bounds[1][2]
  30. || tw->bounds[1][0] < brush->bounds[0][0]
  31. || tw->bounds[1][1] < brush->bounds[0][1]
  32. || tw->bounds[1][2] < brush->bounds[0][2]
  33. ) {
  34. return;
  35. }
  36. // the first six planes are the axial planes, so we only
  37. // need to test the remainder
  38. for ( i = 6 ; i < brush->numsides ; i++ ) {
  39. side = brush->sides + i;
  40. #ifdef _XBOX
  41. plane = &cmg.planes[side->planeNum.GetValue()];
  42. #else
  43. plane = side->plane;
  44. #endif
  45. // adjust the plane distance apropriately for mins/maxs
  46. dist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal );
  47. d1 = DotProduct( tw->start, plane->normal ) - dist;
  48. // if completely in front of face, no intersection
  49. if ( d1 > 0 ) {
  50. return;
  51. }
  52. }
  53. // inside this brush
  54. tw->trace.startsolid = tw->trace.allsolid = qtrue;
  55. tw->trace.fraction = 0;
  56. tw->trace.contents = brush->contents;
  57. }
  58. /*
  59. ================
  60. CM_PlaneCollision
  61. Returns false for a quick getout
  62. ================
  63. */
  64. bool CM_PlaneCollision(traceWork_t *tw, cbrushside_t *side)
  65. {
  66. float dist, f;
  67. float d1, d2;
  68. #ifdef _XBOX
  69. cplane_t *plane = &cmg.planes[side->planeNum.GetValue()];
  70. #else
  71. cplane_t *plane = side->plane;
  72. #endif
  73. // adjust the plane distance apropriately for mins/maxs
  74. dist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal );
  75. d1 = DotProduct( tw->start, plane->normal ) - dist;
  76. d2 = DotProduct( tw->end, plane->normal ) - dist;
  77. if (d2 > 0.0f)
  78. {
  79. // endpoint is not in solid
  80. tw->getout = true;
  81. }
  82. if (d1 > 0.0f)
  83. {
  84. // startpoint is not in solid
  85. tw->startout = true;
  86. }
  87. // if completely in front of face, no intersection with the entire brush
  88. if ((d1 > 0.0f) && ( (d2 >= SURFACE_CLIP_EPSILON) || (d2 >= d1) ) )
  89. {
  90. return(false);
  91. }
  92. // if it doesn't cross the plane, the plane isn't relevent
  93. if ((d1 <= 0.0f) && (d2 <= 0.0f))
  94. {
  95. return(true);
  96. }
  97. // crosses face
  98. if (d1 > d2)
  99. { // enter
  100. f = (d1 - SURFACE_CLIP_EPSILON);
  101. if ( f < 0.0f )
  102. {
  103. f = 0.0f;
  104. if (f > tw->enterFrac)
  105. {
  106. tw->enterFrac = f;
  107. tw->clipplane = plane;
  108. tw->leadside = side;
  109. }
  110. }
  111. else if (f > tw->enterFrac * (d1 - d2) )
  112. {
  113. tw->enterFrac = f / (d1 - d2);
  114. tw->clipplane = plane;
  115. tw->leadside = side;
  116. }
  117. }
  118. else
  119. { // leave
  120. f = (d1 + SURFACE_CLIP_EPSILON);
  121. if ( f < (d1 - d2) )
  122. {
  123. f = 1.0f;
  124. if (f < tw->leaveFrac)
  125. {
  126. tw->leaveFrac = f;
  127. }
  128. }
  129. else if (f > tw->leaveFrac * (d1 - d2) )
  130. {
  131. tw->leaveFrac = f / (d1 - d2);
  132. }
  133. }
  134. return(true);
  135. }
  136. /*
  137. ================
  138. CM_TraceThroughBrush
  139. ================
  140. */
  141. void CM_TraceThroughBrush( traceWork_t *tw, trace_t &trace, cbrush_t *brush, bool infoOnly )
  142. {
  143. int i;
  144. cbrushside_t *side;
  145. tw->enterFrac = -1.0f;
  146. tw->leaveFrac = 1.0f;
  147. tw->clipplane = NULL;
  148. if ( !brush->numsides )
  149. {
  150. return;
  151. }
  152. tw->getout = false;
  153. tw->startout = false;
  154. tw->leadside = NULL;
  155. //
  156. // compare the trace against all planes of the brush
  157. // find the latest time the trace crosses a plane towards the interior
  158. // and the earliest time the trace crosses a plane towards the exterior
  159. //
  160. for (i = 0; i < brush->numsides; i++)
  161. {
  162. side = brush->sides + i;
  163. if(!CM_PlaneCollision(tw, side))
  164. {
  165. return;
  166. }
  167. }
  168. //
  169. // all planes have been checked, and the trace was not
  170. // completely outside the brush
  171. //
  172. if (!tw->startout)
  173. {
  174. if(!infoOnly)
  175. {
  176. // original point was inside brush
  177. trace.startsolid = qtrue;
  178. if (!tw->getout)
  179. {
  180. trace.allsolid = qtrue;
  181. trace.fraction = 0.0f;
  182. }
  183. }
  184. tw->enterFrac = 0.0f;
  185. return;
  186. }
  187. if (tw->enterFrac < tw->leaveFrac)
  188. {
  189. if ((tw->enterFrac > -1.0f) && (tw->enterFrac < trace.fraction))
  190. {
  191. if (tw->enterFrac < 0.0f)
  192. {
  193. tw->enterFrac = 0.0f;
  194. }
  195. if(!infoOnly)
  196. {
  197. trace.fraction = tw->enterFrac;
  198. trace.plane = *tw->clipplane;
  199. trace.surfaceFlags = cmg.shaders[tw->leadside->shaderNum].surfaceFlags;
  200. // tw->trace.sideNum = tw->leadside - cmg.brushsides;
  201. trace.contents = brush->contents;
  202. }
  203. }
  204. }
  205. }
  206. #ifndef BSPC
  207. #ifndef _XBOX // Removing terrain from Xbox
  208. void CM_TraceThroughTerrain( traceWork_t *tw, trace_t &trace, cbrush_t *brush )
  209. {
  210. CCMLandScape *landscape;
  211. vec3_t tBegin, tEnd, tDistance, tStep;
  212. vec3_t baseStart;
  213. vec3_t baseEnd;
  214. int count;
  215. int i;
  216. float fraction;
  217. // At this point we know we may be colliding with a terrain brush (and we know we have a valid terrain structure)
  218. landscape = cmg.landScape;
  219. if (!landscape)
  220. {
  221. assert(landscape);
  222. Com_Error(ERR_FATAL,"Brush had surfaceparm terrain, but there is no Terrain entity on this map!");
  223. }
  224. // Check for absolutely no connection
  225. if(!CM_GenericBoxCollide(tw->bounds, landscape->GetBounds()))
  226. {
  227. return;
  228. }
  229. // Now we know that at least some part of the trace needs to collide with the terrain
  230. // The regular brush collision is handled elsewhere, so advance the ray to an edge in the terrain brush
  231. CM_TraceThroughBrush( tw, trace, brush, true );
  232. // Remember the base entering and leaving fractions
  233. tw->baseEnterFrac = tw->enterFrac;
  234. tw->baseLeaveFrac = tw->leaveFrac;
  235. // Reset to full spread within the brush
  236. tw->enterFrac = -1.0f;
  237. tw->leaveFrac = 1.0f;
  238. // Work out the corners of the AABB when the trace first hits the terrain brush and when it leaves
  239. VectorAdvance(tw->start, tw->baseEnterFrac, tw->end, tBegin);
  240. VectorAdvance(tw->start, tw->baseLeaveFrac, tw->end, tEnd);
  241. VectorSubtract(tEnd, tBegin, tDistance);
  242. // Calculate number of iterations to process
  243. count = ceilf(VectorLength(tDistance) / (landscape->GetPatchScalarSize() * TERRAIN_STEP_MAGIC));
  244. count = 1;
  245. fraction = trace.fraction;
  246. VectorScale(tDistance, 1.0f / count, tStep);
  247. // Save the base start and end vectors
  248. VectorCopy ( tw->start, baseStart );
  249. VectorCopy ( tw->end, baseEnd );
  250. // Use the terrain vectors. Start both at the beginning since the
  251. // step will be added to the end as the first step of the loop
  252. VectorCopy ( tBegin, tw->start );
  253. VectorCopy ( tBegin, tw->end );
  254. // Step thru terrain patches moving on about 1 patch at a time
  255. for ( i = 0; i < count; i ++ )
  256. {
  257. // Add the step to the end
  258. VectorAdd(tw->end, tStep, tw->end);
  259. CM_CalcExtents(tBegin, tw->end, tw, tw->localBounds);
  260. landscape->PatchCollide(tw, trace, tw->start, tw->end, brush->checkcount);
  261. // If collision with something closer than water then just stop here
  262. if ( trace.fraction < fraction )
  263. {
  264. // Convert the fraction of this sub tract into the full trace's fraction
  265. trace.fraction = i * (1.0f / count) + (1.0f / count) * trace.fraction;
  266. break;
  267. }
  268. // Move the end to the start so the next trace starts
  269. // where this one left off
  270. VectorCopy(tw->end, tw->start);
  271. }
  272. // Put the original start and end back
  273. VectorCopy ( baseStart, tw->start );
  274. VectorCopy ( baseEnd, tw->end );
  275. // Convert to global fraction only if something was hit along the way
  276. if ( trace.fraction != 1.0 )
  277. {
  278. trace.fraction = tw->baseEnterFrac + ((tw->baseLeaveFrac - tw->baseEnterFrac) * trace.fraction);
  279. trace.contents = brush->contents;
  280. }
  281. // Collide with any water
  282. if ( tw->contents & CONTENTS_WATER )
  283. {
  284. fraction = landscape->WaterCollide(tw->start, tw->end, trace.fraction);
  285. if( fraction < trace.fraction )
  286. {
  287. VectorSet(trace.plane.normal, 0.0f, 0.0f, 1.0f);
  288. trace.contents = landscape->GetWaterContents();
  289. trace.fraction = fraction;
  290. trace.surfaceFlags = landscape->GetWaterSurfaceFlags();
  291. }
  292. }
  293. }
  294. #endif // _XBOX
  295. #endif
  296. #ifdef _XBOX
  297. static int CM_GetSurfaceIndex(int firstLeafSurface)
  298. {
  299. if(!tr.world ||
  300. firstLeafSurface > tr.world->nummarksurfaces ||
  301. firstLeafSurface < 0) {
  302. return cmg.leafsurfaces[ firstLeafSurface ] ;
  303. } else {
  304. return tr.world->marksurfaces[firstLeafSurface] - tr.world->surfaces;
  305. }
  306. }
  307. #endif
  308. /*
  309. ================
  310. CM_TestInLeaf
  311. ================
  312. */
  313. void CM_TestInLeaf( traceWork_t *tw, cLeaf_t *leaf, clipMap_t *local ) {
  314. int k;
  315. int brushnum;
  316. cbrush_t *b;
  317. cPatch_t *patch;
  318. // test box position against all brushes in the leaf
  319. for (k=0 ; k<leaf->numLeafBrushes ; k++) {
  320. brushnum = local->leafbrushes[leaf->firstLeafBrush+k];
  321. b = &local->brushes[brushnum];
  322. if (b->checkcount == local->checkcount) {
  323. continue; // already checked this brush in another leaf
  324. }
  325. b->checkcount = local->checkcount;
  326. if ( !(b->contents & tw->contents)) {
  327. continue;
  328. }
  329. #ifndef BSPC
  330. #ifndef _XBOX // Removing terrain from Xbox
  331. if (com_terrainPhysics->integer && cmg.landScape && (b->contents & CONTENTS_TERRAIN) )
  332. {
  333. // Invalidate the checkcount for terrain as the terrain brush has to be processed
  334. // many times.
  335. b->checkcount--;
  336. CM_TraceThroughTerrain( tw, tw->trace, b );
  337. // If inside a terrain brush don't bother with regular brush collision
  338. continue;
  339. }
  340. #endif
  341. #endif
  342. CM_TestBoxInBrush( tw, b );
  343. if ( tw->trace.allsolid ) {
  344. return;
  345. }
  346. }
  347. // test against all patches
  348. #ifdef BSPC
  349. if (1) {
  350. #else
  351. if ( !cm_noCurves->integer ) {
  352. #endif //BSPC
  353. for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
  354. #ifdef _XBOX
  355. int index = CM_GetSurfaceIndex(leaf->firstLeafSurface + k);
  356. patch = cmg.surfaces[ index ];
  357. #else
  358. patch = local->surfaces[ local->leafsurfaces[ leaf->firstLeafSurface + k ] ];
  359. #endif
  360. if ( !patch ) {
  361. continue;
  362. }
  363. if ( patch->checkcount == local->checkcount ) {
  364. continue; // already checked this brush in another leaf
  365. }
  366. patch->checkcount = local->checkcount;
  367. if ( !(patch->contents & tw->contents)) {
  368. continue;
  369. }
  370. if ( CM_PositionTestInPatchCollide( tw, patch->pc ) ) {
  371. tw->trace.startsolid = tw->trace.allsolid = qtrue;
  372. tw->trace.fraction = 0;
  373. tw->trace.contents = patch->contents;
  374. return;
  375. }
  376. }
  377. }
  378. }
  379. /*
  380. ==================
  381. CM_PositionTest
  382. ==================
  383. */
  384. #define MAX_POSITION_LEAFS 1024
  385. void CM_PositionTest( traceWork_t *tw ) {
  386. int leafs[MAX_POSITION_LEAFS];
  387. int i;
  388. leafList_t ll;
  389. // identify the leafs we are touching
  390. VectorAdd( tw->start, tw->size[0], ll.bounds[0] );
  391. VectorAdd( tw->start, tw->size[1], ll.bounds[1] );
  392. for (i=0 ; i<3 ; i++) {
  393. ll.bounds[0][i] -= 1;
  394. ll.bounds[1][i] += 1;
  395. }
  396. ll.count = 0;
  397. ll.maxcount = MAX_POSITION_LEAFS;
  398. ll.list = leafs;
  399. ll.storeLeafs = CM_StoreLeafs;
  400. ll.lastLeaf = 0;
  401. ll.overflowed = qfalse;
  402. cmg.checkcount++;
  403. CM_BoxLeafnums_r( &ll, 0 );
  404. cmg.checkcount++;
  405. // test the contents of the leafs
  406. for (i=0 ; i < ll.count ; i++) {
  407. CM_TestInLeaf( tw, &cmg.leafs[leafs[i]], &cmg );
  408. if ( tw->trace.allsolid ) {
  409. break;
  410. }
  411. }
  412. }
  413. /*
  414. ===============================================================================
  415. BOX TRACING
  416. ===============================================================================
  417. */
  418. /*
  419. ================
  420. CM_TraceThroughPatch
  421. ================
  422. */
  423. void CM_TraceThroughPatch( traceWork_t *tw, cPatch_t *patch ) {
  424. float oldFrac;
  425. c_patch_traces++;
  426. oldFrac = tw->trace.fraction;
  427. CM_TraceThroughPatchCollide( tw, patch->pc );
  428. if ( tw->trace.fraction < oldFrac ) {
  429. tw->trace.surfaceFlags = patch->surfaceFlags;
  430. tw->trace.contents = patch->contents;
  431. }
  432. }
  433. /*
  434. ================
  435. CM_TraceThroughBrush
  436. ================
  437. */
  438. void CM_TraceThroughBrush( traceWork_t *tw, cbrush_t *brush ) {
  439. int i;
  440. cplane_t *plane, *clipplane;
  441. float dist;
  442. float enterFrac, leaveFrac;
  443. float d1, d2;
  444. qboolean getout, startout;
  445. float f;
  446. cbrushside_t *side, *leadside;
  447. enterFrac = -1.0;
  448. leaveFrac = 1.0;
  449. clipplane = NULL;
  450. if ( !brush->numsides ) {
  451. return;
  452. }
  453. // I'm not sure if test is strictly correct. Are all
  454. // bboxes axis aligned? Do I care? It seems to work
  455. // good enough...
  456. if ( tw->bounds[0][0] > brush->bounds[1][0]
  457. || tw->bounds[0][1] > brush->bounds[1][1]
  458. || tw->bounds[0][2] > brush->bounds[1][2]
  459. || tw->bounds[1][0] < brush->bounds[0][0]
  460. || tw->bounds[1][1] < brush->bounds[0][1]
  461. || tw->bounds[1][2] < brush->bounds[0][2]
  462. ) {
  463. return;
  464. }
  465. c_brush_traces++;
  466. getout = qfalse;
  467. startout = qfalse;
  468. leadside = NULL;
  469. //
  470. // compare the trace against all planes of the brush
  471. // find the latest time the trace crosses a plane towards the interior
  472. // and the earliest time the trace crosses a plane towards the exterior
  473. //
  474. for (i=0 ; i<brush->numsides ; i++) {
  475. side = brush->sides + i;
  476. #ifdef _XBOX
  477. plane = &cmg.planes[side->planeNum.GetValue()];
  478. #else
  479. plane = side->plane;
  480. #endif
  481. // adjust the plane distance apropriately for mins/maxs
  482. dist = plane->dist - DotProduct( tw->offsets[ plane->signbits ], plane->normal );
  483. d1 = DotProduct( tw->start, plane->normal ) - dist;
  484. d2 = DotProduct( tw->end, plane->normal ) - dist;
  485. if (d2 > 0) {
  486. getout = qtrue; // endpoint is not in solid
  487. }
  488. if (d1 > 0) {
  489. startout = qtrue;
  490. }
  491. // if completely in front of face, no intersection with the entire brush
  492. if (d1 > 0 && ( d2 >= SURFACE_CLIP_EPSILON || d2 >= d1 ) ) {
  493. return;
  494. }
  495. // if it doesn't cross the plane, the plane isn't relevent
  496. if (d1 <= 0 && d2 <= 0 ) {
  497. continue;
  498. }
  499. // crosses face
  500. if (d1 > d2) { // enter
  501. f = (d1-SURFACE_CLIP_EPSILON) / (d1-d2);
  502. if ( f < 0 ) {
  503. f = 0;
  504. }
  505. if (f > enterFrac) {
  506. enterFrac = f;
  507. clipplane = plane;
  508. leadside = side;
  509. }
  510. } else { // leave
  511. f = (d1+SURFACE_CLIP_EPSILON) / (d1-d2);
  512. if ( f > 1 ) {
  513. f = 1;
  514. }
  515. if (f < leaveFrac) {
  516. leaveFrac = f;
  517. }
  518. }
  519. }
  520. //
  521. // all planes have been checked, and the trace was not
  522. // completely outside the brush
  523. //
  524. if (!startout) { // original point was inside brush
  525. tw->trace.startsolid = qtrue;
  526. tw->trace.contents |= brush->contents; //note, we always want to know the contents of something we're inside of
  527. if (!getout)
  528. { //endpoint was inside brush
  529. tw->trace.allsolid = qtrue;
  530. tw->trace.fraction = 0;
  531. }
  532. return;
  533. }
  534. if (enterFrac < leaveFrac) {
  535. if (enterFrac > -1 && enterFrac < tw->trace.fraction) {
  536. if (enterFrac < 0) {
  537. enterFrac = 0;
  538. }
  539. tw->trace.fraction = enterFrac;
  540. tw->trace.plane = *clipplane;
  541. tw->trace.surfaceFlags = cmg.shaders[leadside->shaderNum].surfaceFlags;
  542. tw->trace.contents = brush->contents;
  543. }
  544. }
  545. }
  546. /*
  547. ================
  548. CM_PatchCollide
  549. By the time we get here we know the AABB is within the patch AABB ie there is a chance of collision
  550. The collision data is made up of bounds, 2 triangle planes
  551. There is an BB check for the terxel check to see if it is worth checking the planes.
  552. Collide with both triangles to find the shortest fraction
  553. ================
  554. */
  555. void CM_HandlePatchCollision(struct traceWork_s *tw, trace_t &trace, const vec3_t tStart, const vec3_t tEnd, CCMPatch *patch, int checkcount)
  556. {
  557. int numBrushes, i;
  558. cbrush_t *brush;
  559. // Get the collision data
  560. brush = patch->GetCollisionData();
  561. numBrushes = patch->GetNumBrushes();
  562. for(i = 0; i < numBrushes; i++, brush++)
  563. {
  564. if(brush->checkcount == checkcount)
  565. {
  566. return;
  567. }
  568. // Generic collision of terxel bounds to line segment bounds
  569. if(!CM_GenericBoxCollide(brush->bounds, tw->localBounds))
  570. {
  571. continue;
  572. }
  573. brush->checkcount = checkcount;
  574. //CM_TraceThroughBrush(tw, trace, brush, false );
  575. CM_TraceThroughBrush(tw, brush);
  576. if (trace.fraction <= 0.0)
  577. {
  578. break;
  579. }
  580. }
  581. }
  582. /*
  583. ================
  584. CM_GenericBoxCollide
  585. ================
  586. */
  587. bool CM_GenericBoxCollide(const vec3pair_t abounds, const vec3pair_t bbounds)
  588. {
  589. int i;
  590. // Check for completely no intersection
  591. for(i = 0; i < 3; i++)
  592. {
  593. if(abounds[1][i] < bbounds[0][i])
  594. {
  595. return(false);
  596. }
  597. if(abounds[0][i] > bbounds[1][i])
  598. {
  599. return(false);
  600. }
  601. }
  602. return(true);
  603. }
  604. /*
  605. ================
  606. CM_TraceToLeaf
  607. ================
  608. */
  609. void CM_TraceToLeaf( traceWork_t *tw, cLeaf_t *leaf, clipMap_t *local ) {
  610. int k;
  611. int brushnum;
  612. cbrush_t *b;
  613. cPatch_t *patch;
  614. // trace line against all brushes in the leaf
  615. for ( k = 0 ; k < leaf->numLeafBrushes ; k++ ) {
  616. brushnum = local->leafbrushes[leaf->firstLeafBrush+k];
  617. b = &local->brushes[brushnum];
  618. if ( b->checkcount == local->checkcount ) {
  619. continue; // already checked this brush in another leaf
  620. }
  621. b->checkcount = local->checkcount;
  622. if ( !(b->contents & tw->contents) ) {
  623. continue;
  624. }
  625. #ifndef BSPC
  626. #ifndef _XBOX // Removing terrain from Xbox
  627. if ( com_terrainPhysics->integer && cmg.landScape && (b->contents & CONTENTS_TERRAIN) )
  628. {
  629. // Invalidate the checkcount for terrain as the terrain brush has to be processed
  630. // many times.
  631. b->checkcount--;
  632. CM_TraceThroughTerrain( tw, tw->trace, b );
  633. // If inside a terrain brush don't bother with regular brush collision
  634. continue;
  635. }
  636. #endif
  637. #endif
  638. //if (b->contents & CONTENTS_PLAYERCLIP) continue;
  639. CM_TraceThroughBrush( tw, b );
  640. if ( !tw->trace.fraction ) {
  641. return;
  642. }
  643. }
  644. // trace line against all patches in the leaf
  645. #ifdef BSPC
  646. if (1) {
  647. #else
  648. if ( !cm_noCurves->integer ) {
  649. #endif
  650. for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
  651. #ifdef _XBOX
  652. int index = CM_GetSurfaceIndex(leaf->firstLeafSurface + k);
  653. patch = cmg.surfaces[ index ];
  654. #else
  655. patch = local->surfaces[ local->leafsurfaces[ leaf->firstLeafSurface + k ] ];
  656. #endif
  657. if ( !patch ) {
  658. continue;
  659. }
  660. if ( patch->checkcount == local->checkcount ) {
  661. continue; // already checked this patch in another leaf
  662. }
  663. patch->checkcount = local->checkcount;
  664. if ( !(patch->contents & tw->contents) ) {
  665. continue;
  666. }
  667. CM_TraceThroughPatch( tw, patch );
  668. if ( !tw->trace.fraction ) {
  669. return;
  670. }
  671. }
  672. }
  673. }
  674. //=========================================================================================
  675. /*
  676. ==================
  677. CM_TraceThroughTree
  678. Traverse all the contacted leafs from the start to the end position.
  679. If the trace is a point, they will be exactly in order, but for larger
  680. trace volumes it is possible to hit something in a later leaf with
  681. a smaller intercept fraction.
  682. ==================
  683. */
  684. void CM_TraceThroughTree( traceWork_t *tw, clipMap_t *local, int num, float p1f, float p2f, vec3_t p1, vec3_t p2) {
  685. cNode_t *node;
  686. cplane_t *plane;
  687. float t1, t2, offset;
  688. float frac, frac2;
  689. float idist;
  690. vec3_t mid;
  691. int side;
  692. float midf;
  693. #ifdef _XBOX
  694. if(!tr.world) {
  695. return;
  696. }
  697. #endif
  698. if (tw->trace.fraction <= p1f) {
  699. return; // already hit something nearer
  700. }
  701. // if < 0, we are in a leaf node
  702. if (num < 0) {
  703. CM_TraceToLeaf( tw, &local->leafs[-1-num], local );
  704. return;
  705. }
  706. //
  707. // find the point distances to the seperating plane
  708. // and the offset for the size of the box
  709. //
  710. node = local->nodes + num;
  711. #ifdef _XBOX
  712. plane = cmg.planes + tr.world->nodes[num].planeNum;
  713. #else mnode_s
  714. plane = node->plane;
  715. #endif
  716. // adjust the plane distance apropriately for mins/maxs
  717. if ( plane->type < 3 ) {
  718. t1 = p1[plane->type] - plane->dist;
  719. t2 = p2[plane->type] - plane->dist;
  720. offset = tw->extents[plane->type];
  721. } else {
  722. t1 = DotProduct (plane->normal, p1) - plane->dist;
  723. t2 = DotProduct (plane->normal, p2) - plane->dist;
  724. if ( tw->isPoint ) {
  725. offset = 0;
  726. } else {
  727. // this is silly
  728. offset = 2048;
  729. }
  730. }
  731. // see which sides we need to consider
  732. if ( t1 >= offset + 1 && t2 >= offset + 1 ) {
  733. CM_TraceThroughTree( tw, local, node->children[0], p1f, p2f, p1, p2 );
  734. return;
  735. }
  736. if ( t1 < -offset - 1 && t2 < -offset - 1 ) {
  737. CM_TraceThroughTree( tw, local, node->children[1], p1f, p2f, p1, p2 );
  738. return;
  739. }
  740. // put the crosspoint SURFACE_CLIP_EPSILON pixels on the near side
  741. if ( t1 < t2 ) {
  742. idist = 1.0/(t1-t2);
  743. side = 1;
  744. frac2 = (t1 + offset + SURFACE_CLIP_EPSILON)*idist;
  745. frac = (t1 - offset + SURFACE_CLIP_EPSILON)*idist;
  746. } else if (t1 > t2) {
  747. idist = 1.0/(t1-t2);
  748. side = 0;
  749. frac2 = (t1 - offset - SURFACE_CLIP_EPSILON)*idist;
  750. frac = (t1 + offset + SURFACE_CLIP_EPSILON)*idist;
  751. } else {
  752. side = 0;
  753. frac = 1;
  754. frac2 = 0;
  755. }
  756. // move up to the node
  757. if ( frac < 0 ) {
  758. frac = 0;
  759. }
  760. if ( frac > 1 ) {
  761. frac = 1;
  762. }
  763. midf = p1f + (p2f - p1f)*frac;
  764. mid[0] = p1[0] + frac*(p2[0] - p1[0]);
  765. mid[1] = p1[1] + frac*(p2[1] - p1[1]);
  766. mid[2] = p1[2] + frac*(p2[2] - p1[2]);
  767. CM_TraceThroughTree( tw, local, node->children[side], p1f, midf, p1, mid );
  768. // go past the node
  769. if ( frac2 < 0 ) {
  770. frac2 = 0;
  771. }
  772. if ( frac2 > 1 ) {
  773. frac2 = 1;
  774. }
  775. midf = p1f + (p2f - p1f)*frac2;
  776. mid[0] = p1[0] + frac2*(p2[0] - p1[0]);
  777. mid[1] = p1[1] + frac2*(p2[1] - p1[1]);
  778. mid[2] = p1[2] + frac2*(p2[2] - p1[2]);
  779. CM_TraceThroughTree( tw, local, node->children[side^1], midf, p2f, mid, p2 );
  780. }
  781. void CM_CalcExtents(const vec3_t start, const vec3_t end, const traceWork_t *tw, vec3pair_t bounds)
  782. {
  783. int i;
  784. for ( i = 0 ; i < 3 ; i++ )
  785. {
  786. if ( start[i] < end[i] )
  787. {
  788. bounds[0][i] = start[i] + tw->size[0][i];
  789. bounds[1][i] = end[i] + tw->size[1][i];
  790. }
  791. else
  792. {
  793. bounds[0][i] = end[i] + tw->size[0][i];
  794. bounds[1][i] = start[i] + tw->size[1][i];
  795. }
  796. }
  797. }
  798. //======================================================================
  799. /*
  800. ==================
  801. CM_BoxTrace
  802. ==================
  803. */
  804. void CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
  805. const vec3_t mins, const vec3_t maxs,
  806. clipHandle_t model, int brushmask) {
  807. int i;
  808. traceWork_t tw;
  809. vec3_t offset;
  810. cmodel_t *cmod;
  811. clipMap_t *local = 0;
  812. cmod = CM_ClipHandleToModel( model, &local );
  813. local->checkcount++; // for multi-check avoidance
  814. c_traces++; // for statistics, may be zeroed
  815. // fill in a default trace
  816. memset( &tw, 0, sizeof(tw) - sizeof(tw.trace.G2CollisionMap));
  817. tw.trace.fraction = 1; // assume it goes the entire distance until shown otherwise
  818. if (!local->numNodes) {
  819. *results = tw.trace;
  820. return; // map not loaded, shouldn't happen
  821. }
  822. // allow NULL to be passed in for 0,0,0
  823. if ( !mins ) {
  824. mins = vec3_origin;
  825. }
  826. if ( !maxs ) {
  827. maxs = vec3_origin;
  828. }
  829. // set basic parms
  830. tw.contents = brushmask;
  831. // adjust so that mins and maxs are always symetric, which
  832. // avoids some complications with plane expanding of rotated
  833. // bmodels
  834. for ( i = 0 ; i < 3 ; i++ ) {
  835. offset[i] = ( mins[i] + maxs[i] ) * 0.5;
  836. tw.size[0][i] = mins[i] - offset[i];
  837. tw.size[1][i] = maxs[i] - offset[i];
  838. tw.start[i] = start[i] + offset[i];
  839. tw.end[i] = end[i] + offset[i];
  840. }
  841. tw.maxOffset = tw.size[1][0] + tw.size[1][1] + tw.size[1][2];
  842. // tw.offsets[signbits] = vector to apropriate corner from origin
  843. tw.offsets[0][0] = tw.size[0][0];
  844. tw.offsets[0][1] = tw.size[0][1];
  845. tw.offsets[0][2] = tw.size[0][2];
  846. tw.offsets[1][0] = tw.size[1][0];
  847. tw.offsets[1][1] = tw.size[0][1];
  848. tw.offsets[1][2] = tw.size[0][2];
  849. tw.offsets[2][0] = tw.size[0][0];
  850. tw.offsets[2][1] = tw.size[1][1];
  851. tw.offsets[2][2] = tw.size[0][2];
  852. tw.offsets[3][0] = tw.size[1][0];
  853. tw.offsets[3][1] = tw.size[1][1];
  854. tw.offsets[3][2] = tw.size[0][2];
  855. tw.offsets[4][0] = tw.size[0][0];
  856. tw.offsets[4][1] = tw.size[0][1];
  857. tw.offsets[4][2] = tw.size[1][2];
  858. tw.offsets[5][0] = tw.size[1][0];
  859. tw.offsets[5][1] = tw.size[0][1];
  860. tw.offsets[5][2] = tw.size[1][2];
  861. tw.offsets[6][0] = tw.size[0][0];
  862. tw.offsets[6][1] = tw.size[1][1];
  863. tw.offsets[6][2] = tw.size[1][2];
  864. tw.offsets[7][0] = tw.size[1][0];
  865. tw.offsets[7][1] = tw.size[1][1];
  866. tw.offsets[7][2] = tw.size[1][2];
  867. //
  868. // calculate bounds
  869. //
  870. for ( i = 0 ; i < 3 ; i++ ) {
  871. if ( tw.start[i] < tw.end[i] ) {
  872. tw.bounds[0][i] = tw.start[i] + tw.size[0][i];
  873. tw.bounds[1][i] = tw.end[i] + tw.size[1][i];
  874. } else {
  875. tw.bounds[0][i] = tw.end[i] + tw.size[0][i];
  876. tw.bounds[1][i] = tw.start[i] + tw.size[1][i];
  877. }
  878. }
  879. //
  880. // check for position test special case
  881. //
  882. if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) {
  883. if ( model ) {
  884. CM_TestInLeaf( &tw, &cmod->leaf, local );
  885. } else {
  886. CM_PositionTest( &tw );
  887. }
  888. } else {
  889. //
  890. // check for point special case
  891. //
  892. if ( tw.size[0][0] == 0 && tw.size[0][1] == 0 && tw.size[0][2] == 0 ) {
  893. tw.isPoint = qtrue;
  894. VectorClear( tw.extents );
  895. } else {
  896. tw.isPoint = qfalse;
  897. tw.extents[0] = tw.size[1][0];
  898. tw.extents[1] = tw.size[1][1];
  899. tw.extents[2] = tw.size[1][2];
  900. }
  901. //
  902. // general sweeping through world
  903. //
  904. if ( model ) {
  905. CM_TraceToLeaf( &tw, &cmod->leaf, local );
  906. } else {
  907. CM_TraceThroughTree( &tw, local, 0, 0, 1, tw.start, tw.end );
  908. }
  909. }
  910. // generate endpos from the original, unmodified start/end
  911. if ( tw.trace.fraction == 1 ) {
  912. VectorCopy (end, tw.trace.endpos);
  913. } else {
  914. for ( i=0 ; i<3 ; i++ ) {
  915. tw.trace.endpos[i] = start[i] + tw.trace.fraction * (end[i] - start[i]);
  916. }
  917. }
  918. *results = tw.trace;
  919. }
  920. /*
  921. ==================
  922. CM_TransformedBoxTrace
  923. Handles offseting and rotation of the end points for moving and
  924. rotating entities
  925. ==================
  926. */
  927. void CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end,
  928. const vec3_t mins, const vec3_t maxs,
  929. clipHandle_t model, int brushmask,
  930. const vec3_t origin, const vec3_t angles) {
  931. trace_t trace;
  932. vec3_t start_l, end_l;
  933. vec3_t a;
  934. vec3_t forward, right, up;
  935. vec3_t temp;
  936. qboolean rotated;
  937. vec3_t offset;
  938. vec3_t symetricSize[2];
  939. int i;
  940. if ( !mins ) {
  941. mins = vec3_origin;
  942. }
  943. if ( !maxs ) {
  944. maxs = vec3_origin;
  945. }
  946. // adjust so that mins and maxs are always symetric, which
  947. // avoids some complications with plane expanding of rotated
  948. // bmodels
  949. for ( i = 0 ; i < 3 ; i++ ) {
  950. offset[i] = ( mins[i] + maxs[i] ) * 0.5;
  951. symetricSize[0][i] = mins[i] - offset[i];
  952. symetricSize[1][i] = maxs[i] - offset[i];
  953. start_l[i] = start[i] + offset[i];
  954. end_l[i] = end[i] + offset[i];
  955. }
  956. // subtract origin offset
  957. VectorSubtract( start_l, origin, start_l );
  958. VectorSubtract( end_l, origin, end_l );
  959. // rotate start and end into the models frame of reference
  960. if ( model != BOX_MODEL_HANDLE &&
  961. (angles[0] || angles[1] || angles[2]) ) {
  962. rotated = qtrue;
  963. } else {
  964. rotated = qfalse;
  965. }
  966. if (rotated) {
  967. AngleVectors (angles, forward, right, up);
  968. VectorCopy (start_l, temp);
  969. start_l[0] = DotProduct (temp, forward);
  970. start_l[1] = -DotProduct (temp, right);
  971. start_l[2] = DotProduct (temp, up);
  972. VectorCopy (end_l, temp);
  973. end_l[0] = DotProduct (temp, forward);
  974. end_l[1] = -DotProduct (temp, right);
  975. end_l[2] = DotProduct (temp, up);
  976. }
  977. // sweep the box through the model
  978. CM_BoxTrace( &trace, start_l, end_l, symetricSize[0], symetricSize[1], model, brushmask);
  979. if ( rotated && trace.fraction != 1.0 ) {
  980. // FIXME: figure out how to do this with existing angles
  981. VectorNegate (angles, a);
  982. AngleVectors (a, forward, right, up);
  983. VectorCopy (trace.plane.normal, temp);
  984. trace.plane.normal[0] = DotProduct (temp, forward);
  985. trace.plane.normal[1] = -DotProduct (temp, right);
  986. trace.plane.normal[2] = DotProduct (temp, up);
  987. }
  988. trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);
  989. trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);
  990. trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);
  991. *results = trace;
  992. }
  993. /*
  994. =================
  995. CM_CullBox
  996. Returns true if culled out
  997. =================
  998. */
  999. bool CM_CullBox(const cplane_t *frustum, const vec3_t transformed[8])
  1000. {
  1001. int i, j;
  1002. const cplane_t *frust;
  1003. // check against frustum planes
  1004. for (i=0, frust=frustum; i<4 ; i++, frust++)
  1005. {
  1006. for (j=0 ; j<8 ; j++)
  1007. {
  1008. if (DotProduct(transformed[j], frust->normal) > frust->dist)
  1009. { // a point is in front
  1010. break;
  1011. }
  1012. }
  1013. if (j == 8)
  1014. { // all points were behind one of the planes
  1015. return true;
  1016. }
  1017. }
  1018. return false;
  1019. }
  1020. /*
  1021. =================
  1022. CM_CullWorldBox
  1023. Returns true if culled out
  1024. =================
  1025. */
  1026. bool CM_CullWorldBox (const cplane_t *frustum, const vec3pair_t bounds)
  1027. {
  1028. int i;
  1029. vec3_t transformed[8];
  1030. for (i = 0 ; i < 8 ; i++)
  1031. {
  1032. transformed[i][0] = bounds[i & 1][0];
  1033. transformed[i][1] = bounds[(i >> 1) & 1][1];
  1034. transformed[i][2] = bounds[(i >> 2) & 1][2];
  1035. }
  1036. //rwwFIXMEFIXME: Was not ! before. But that seems the way it should be and it works that way. Why?
  1037. return(!CM_CullBox(frustum, transformed));
  1038. }