UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
tracing.cpp
Go to the documentation of this file.
1 
7 /*
8 All original material Copyright (C) 2002-2020 UFO: Alien Invasion.
9 
10 Copyright (C) 1997-2001 Id Software, Inc.
11 
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License
14 as published by the Free Software Foundation; either version 2
15 of the License, or (at your option) any later version.
16 
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
20 
21 See the GNU General Public License for more details.
22 
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 
27 */
28 
29 #include "tracing.h"
30 #include "common.h"
31 
32 /* TR_TILE_TYPE and TR_PLANE_TYPE are defined in tracing.h */
33 #if defined(COMPILE_MAP)
34  #define TR_NODE_TYPE dBspNode_t
35  #define TR_LEAF_TYPE dBspLeaf_t
36  #define TR_BRUSHSIDE_TYPE dBspBrushSide_t
37 #elif defined(COMPILE_UFO)
38  #define TR_NODE_TYPE cBspNode_t
39  #define TR_LEAF_TYPE cBspLeaf_t
40  #define TR_BRUSHSIDE_TYPE cBspBrushSide_t
41 #else
42  #error Either COMPILE_MAP or COMPILE_UFO must be defined in order for tracing.c to work.
43 #endif
44 
46 void boxtrace_s::init (TR_TILE_TYPE* _tile, const int contentmask, const int brushreject, const float fraction)
47 {
48  trace.init();
49  trace.surface = nullptr;
50  contents = contentmask;
51  rejects = brushreject;
52  tile = _tile;
53  trace.fraction = std::min(fraction, 1.0f);
54 }
55 
56 /* Optimize the trace by moving the line to be traced across into the origin of the box trace. */
57 void boxtrace_s::setLineAndBox(const Line& line, const AABB& box)
58 {
59  /* Calculate the offset needed to center the trace about the line */
60  box.getCenter(offset);
61 
62  /* Now remove the offset from bmin and bmax (effectively centering the trace box about the origin of the line)
63  * and add the offset to the trace line (effectively repositioning the trace box at the desired coordinates) */
64  VectorSubtract(box.mins, offset, this->mins);
65  VectorSubtract(box.maxs, offset, this->maxs);
66  VectorAdd(line.start, offset, this->start);
67  VectorAdd(line.stop, offset, this->end);
68 }
69 
72 static int checkcount;
73 
74 /*
75 ===============================================================================
76 TRACING NODES
77 ===============================================================================
78 */
79 
83 static void TR_MakeTracingNode (TR_TILE_TYPE* tile, tnode_t** tnode, int32_t nodenum)
84 {
85  tnode_t* t = (*tnode)++; /* the tracing node to build */
86  TR_NODE_TYPE* node = tile->nodes + nodenum; /* the node we are investigating */
87 
88 #ifdef COMPILE_UFO
89  const TR_PLANE_TYPE* plane = node->plane;
90 #else
91  const TR_PLANE_TYPE* plane = tile->planes + node->planenum;
92 #endif
93 
94  t->type = plane->type;
95  VectorCopy(plane->normal, t->normal);
96  t->dist = plane->dist;
97 
98  for (int i = 0; i < 2; i++) {
99  if (node->children[i] < 0) { /* is it a leaf ? */
100  const int32_t leafnum = -(node->children[i]) - 1;
101  const TR_LEAF_TYPE* leaf = &tile->leafs[leafnum];
102  const uint32_t contentFlags = leaf->contentFlags & ~(1 << 31);
103  if ((contentFlags & (CONTENTS_SOLID | MASK_CLIP)) && !(contentFlags & CONTENTS_PASSABLE))
104  t->children[i] = -node->children[i] | (1 << 31); /* mark as 'blocking' */
105  else
106  t->children[i] = (1 << 31); /* mark as 'empty leaf' */
107  } else { /* not a leaf */
108  t->children[i] = *tnode - tile->tnodes;
109  if (t->children[i] > tile->numnodes) {
110  Com_Printf("Exceeded allocated memory for tracing structure (%i > %i)\n",
111  t->children[i], tile->numnodes);
112  }
113  TR_MakeTracingNode(tile, tnode, node->children[i]); /* recurse further down the tree */
114  }
115  }
116 }
117 
122 void TR_BuildTracingNode_r (TR_TILE_TYPE* tile, tnode_t** tnode, int32_t nodenum, int level)
123 {
124  assert(nodenum < tile->numnodes + 6); /* +6 => bbox */
125 
130 #ifdef COMPILE_UFO
131  if (!tile->nodes[nodenum].plane) {
132 #else
133  if (tile->nodes[nodenum].planenum == PLANENUM_LEAF) {
134 #endif
135  TR_NODE_TYPE* n = &tile->nodes[nodenum];
136 
137  /* alloc new node */
138  tnode_t* t = (*tnode)++;
139 
140  /* no leafs here */
141  if (n->children[0] < 0 || n->children[1] < 0)
142 #ifdef COMPILE_UFO
143  Com_Error(ERR_DROP, "Unexpected leaf");
144 #else
145  Sys_Error("Unexpected leaf");
146 #endif
147 
148  vec3_t c0maxs, c1mins;
149  VectorCopy(tile->nodes[n->children[0]].maxs, c0maxs);
150  VectorCopy(tile->nodes[n->children[1]].mins, c1mins);
151 
152 #if 0
153  Com_Printf("(%i %i : %i %i) (%i %i : %i %i)\n",
154  (int)tile->nodes[n->children[0]].mins[0], (int)tile->nodes[n->children[0]].mins[1],
155  (int)tile->nodes[n->children[0]].maxs[0], (int)tile->nodes[n->children[0]].maxs[1],
156  (int)tile->nodes[n->children[1]].mins[0], (int)tile->nodes[n->children[1]].mins[1],
157  (int)tile->nodes[n->children[1]].maxs[0], (int)tile->nodes[n->children[1]].maxs[1]);
158 #endif
159 
160  for (int i = 0; i < 2; i++)
161  if (c0maxs[i] <= c1mins[i]) {
162  /* create a separation plane */
163  t->type = i;
164  VectorSet(t->normal, i, (i ^ 1), 0);
165  t->dist = (c0maxs[i] + c1mins[i]) / 2;
166 
167  t->children[1] = *tnode - tile->tnodes;
168  TR_BuildTracingNode_r(tile, tnode, n->children[0], level);
169  t->children[0] = *tnode - tile->tnodes;
170  TR_BuildTracingNode_r(tile, tnode, n->children[1], level);
171  return;
172  }
173 
174  /* can't construct such a separation plane */
175  t->type = PLANE_NONE;
176 
177  for (int i = 0; i < 2; i++) {
178  t->children[i] = *tnode - tile->tnodes;
179  TR_BuildTracingNode_r(tile, tnode, n->children[i], level);
180  }
181  } else {
182  /* Make a lookup table */
183  tile->cheads[tile->numcheads].cnode = nodenum;
184  tile->cheads[tile->numcheads].level = level;
185  tile->numcheads++;
186  assert(tile->numcheads <= MAX_MAP_NODES);
187  /* Make the tracing node. */
188  TR_MakeTracingNode(tile, tnode, nodenum);
189  }
190 }
191 
192 
193 /*
194 ===============================================================================
195 LINE TRACING - TEST FOR BRUSH PRESENCE
196 ===============================================================================
197 */
198 
199 
209 int TR_TestLine_r (TR_TILE_TYPE* tile, int32_t nodenum, const vec3_t start, const vec3_t end)
210 {
211  float front, back;
212  int r;
213 
214  /* negative numbers indicate leaf nodes. Empty leaf nodes are marked as (1 << 31).
215  * Turning off that bit makes us return 0 or the positive node number to indicate blocking. */
216  if (nodenum & (1 << 31))
217  return nodenum & ~(1 << 31);
218 
219  const tnode_t* tnode = &tile->tnodes[nodenum];
220  assert(tnode);
221  switch (tnode->type) {
222  case PLANE_X:
223  case PLANE_Y:
224  case PLANE_Z:
225  front = start[tnode->type] - tnode->dist;
226  back = end[tnode->type] - tnode->dist;
227  break;
228  case PLANE_NONE:
229  r = TR_TestLine_r(tile, tnode->children[0], start, end);
230  if (r)
231  return r;
232  return TR_TestLine_r(tile, tnode->children[1], start, end);
233  default:
234  front = DotProduct(start, tnode->normal) - tnode->dist;
235  back = DotProduct(end, tnode->normal) - tnode->dist;
236  break;
237  }
238 
239  if (front >= -ON_EPSILON && back >= -ON_EPSILON)
240  return TR_TestLine_r(tile, tnode->children[0], start, end);
241  else if (front < ON_EPSILON && back < ON_EPSILON)
242  return TR_TestLine_r(tile, tnode->children[1], start, end);
243  else {
244  const int side = front < 0;
245  const float frac = front / (front - back);
246  vec3_t mid;
247 
248  VectorInterpolation(start, end, frac, mid);
249 
250  r = TR_TestLine_r(tile, tnode->children[side], start, mid);
251  if (r)
252  return r;
253  return TR_TestLine_r(tile, tnode->children[!side], mid, end);
254  }
255 }
256 
257 
279 static bool TR_TileTestLine (TR_TILE_TYPE* tile, const vec3_t start, const vec3_t end, const int levelmask)
280 {
281  const int corelevels = (levelmask & TL_FLAG_REGULAR_LEVELS);
282 
283  /* loop over all theads */
284  for (int i = 0; i < tile->numtheads; i++) {
285  const int level = tile->theadlevel[i];
286  if (level && corelevels && !(level & corelevels))
287  continue;
288  if (level == LEVEL_LIGHTCLIP) /* lightclips are only used in ufo2map, and it does not use this function */
289  continue;
290  if (level == LEVEL_ACTORCLIP && !(levelmask & TL_FLAG_ACTORCLIP))
291  continue;
292  if (level == LEVEL_WEAPONCLIP && !(levelmask & TL_FLAG_WEAPONCLIP))
293  continue;
294  if (TR_TestLine_r(tile, tile->thead[i], start, end))
295  return true;
296  }
297  return false;
298 }
299 
310 bool TR_TestLine (mapTiles_t* mapTiles, const vec3_t start, const vec3_t end, const int levelmask)
311 {
312  for (int tile = 0; tile < mapTiles->numTiles; tile++) {
313  if (TR_TileTestLine(&mapTiles->mapTiles[tile], start, end, levelmask))
314  return true;
315  }
316  return false;
317 }
318 
319 
320 /*
321 ===============================================================================
322 LINE TRACING - TEST FOR BRUSH LOCATION
323 ===============================================================================
324 */
325 
326 
336 static int TR_TestLineDist_r (TR_TILE_TYPE* tile, int32_t nodenum, const vec3_t start, const vec3_t end, vec3_t tr_end)
337 {
338  float front, back;
339  vec3_t mid;
340  int side;
341  int r;
342 
343  if (nodenum & (1 << 31)) {
344  r = nodenum & ~(1 << 31);
345  if (r)
346  VectorCopy(start, tr_end);
347  return r; /* leaf node */
348  }
349 
350  const tnode_t* tnode = &tile->tnodes[nodenum];
351  assert(tnode);
352  switch (tnode->type) {
353  case PLANE_X:
354  case PLANE_Y:
355  case PLANE_Z:
356  front = start[tnode->type] - tnode->dist;
357  back = end[tnode->type] - tnode->dist;
358  break;
359  case PLANE_NONE:
360  r = TR_TestLineDist_r(tile, tnode->children[0], start, end, tr_end);
361  if (r)
362  VectorCopy(tr_end, mid);
363  side = TR_TestLineDist_r(tile, tnode->children[1], start, end, tr_end);
364  if (side && r) {
365  if (VectorNearer(mid, tr_end, start)) {
366  VectorCopy(mid, tr_end);
367  return r;
368  } else {
369  return side;
370  }
371  }
372 
373  if (r) {
374  VectorCopy(mid, tr_end);
375  return r;
376  }
377 
378  return side;
379  default:
380  front = (start[0] * tnode->normal[0] + start[1] * tnode->normal[1] + start[2] * tnode->normal[2]) - tnode->dist;
381  back = (end[0] * tnode->normal[0] + end[1] * tnode->normal[1] + end[2] * tnode->normal[2]) - tnode->dist;
382  break;
383  }
384 
385  if (front >= -ON_EPSILON && back >= -ON_EPSILON)
386  return TR_TestLineDist_r(tile, tnode->children[0], start, end, tr_end);
387 
388  if (front < ON_EPSILON && back < ON_EPSILON)
389  return TR_TestLineDist_r(tile, tnode->children[1], start, end, tr_end);
390 
391  side = front < 0;
392 
393  const float frac = front / (front - back);
394 
395  VectorInterpolation(start, end, frac, mid);
396 
397  r = TR_TestLineDist_r(tile, tnode->children[side], start, mid, tr_end);
398  if (r)
399  return r;
400  return TR_TestLineDist_r(tile, tnode->children[!side], mid, end, tr_end);
401 }
402 
414 static bool TR_TileTestLineDM (TR_TILE_TYPE* tile, const vec3_t start, const vec3_t end, vec3_t hit, const int levelmask)
415 {
416 #ifdef COMPILE_MAP
417  const int corelevels = (levelmask & TL_FLAG_REGULAR_LEVELS);
418 #endif
419 
420  VectorCopy(end, hit);
421 
422  for (int i = 0; i < tile->numtheads; i++) {
423 #ifdef COMPILE_MAP
424  const int level = tile->theadlevel[i];
425  if (level && corelevels && !(level & levelmask))
426  continue;
427 /* if (level == LEVEL_LIGHTCLIP)
428  continue;*/
429  if (level == LEVEL_ACTORCLIP && !(levelmask & TL_FLAG_ACTORCLIP))
430  continue;
431  if (level == LEVEL_WEAPONCLIP && !(levelmask & TL_FLAG_WEAPONCLIP))
432  continue;
433 #endif
434  vec3_t tr_end;
435  if (TR_TestLineDist_r(tile, tile->thead[i], start, end, tr_end))
436  if (VectorNearer(tr_end, hit, start))
437  VectorCopy(tr_end, hit);
438  }
439 
440  if (VectorCompareEps(hit, end, EQUAL_EPSILON))
441  return false;
442  else
443  return true;
444 }
445 
446 
458 bool TR_TestLineDM (mapTiles_t* mapTiles, const vec3_t start, const vec3_t end, vec3_t hit, const int levelmask)
459 {
460  vec3_t t_end;
461 
462  VectorCopy(end, hit);
463  VectorCopy(end, t_end);
464 
465  for (int tile = 0; tile < mapTiles->numTiles; tile++) {
466  if (TR_TileTestLineDM(&mapTiles->mapTiles[tile], start, end, t_end, levelmask)) {
467  if (VectorNearer(t_end, hit, start))
468  VectorCopy(t_end, hit);
469  }
470  }
471 
472  if (VectorCompareEps(hit, end, EQUAL_EPSILON))
473  return false;
474  else
475  return true;
476 }
477 
478 void mapTiles_s::getTilesAt (int x ,int y, byte& fromTile1, byte& fromTile2, byte& fromTile3)
479 {
480 #if defined(COMPILE_UFO)
481  for (int i = 0; i < numTiles; i++) {
482  if ( mapTiles[i].wpMins[0] > x
483  || mapTiles[i].wpMaxs[0] - 1 < x /* the -1 is a temporary fix for wpMaxs being off by 1 */
484  || mapTiles[i].wpMins[1] > y
485  || mapTiles[i].wpMaxs[1] - 1 < y)
486  continue;
487  /* this tile exists at x/y, so store it */
488  if (!fromTile1)
489  fromTile1 = mapTiles[i].idx + 1; /* tile number, not index */
490  else if (!fromTile2)
491  fromTile2 = mapTiles[i].idx + 1; /* tile number, not index */
492  else
493  fromTile3 = 99; /* stacking of more than two tiles is not supported */
494  }
495 #endif
496 }
497 
498 void mapTiles_s::getTileOverlap (const byte tile1, const byte tile2, int& minZ, int& maxZ)
499 {
500 #if defined(COMPILE_UFO)
501  const int lowZ1 = mapTiles[tile1 - 1].wpMins[2];
502  const int lowZ2 = mapTiles[tile2 - 1].wpMins[2];
503  const int highZ1 = mapTiles[tile1 - 1].wpMaxs[2];
504  const int highZ2 = mapTiles[tile2 - 1].wpMaxs[2];
505  minZ = std::max(lowZ1, lowZ2);
506  if (minZ > 0)
507  minZ--; /* routing needs to start one level below the actual overlap */
508  maxZ = std::min(highZ1, highZ2);
509  maxZ++; /* ... and one level above */
510 #endif
511 }
512 
513 void mapTiles_s::printTilesAt (int x ,int y)
514 {
515 #if defined(COMPILE_UFO)
516  byte fromTile1 = 0; /* tile number, not index */
517  byte fromTile2 = 0;
518  byte fromTile3 = 0;
519  getTilesAt(x ,y, fromTile1, fromTile2, fromTile3);
520  if (fromTile1) {
521  const MapTile& tile = mapTiles[fromTile1 - 1];
522  Com_Printf("Tilenames: %s (%i %i) (%i %i)", tile.name, tile.wpMins[0], tile.wpMins[1], tile.wpMaxs[0], tile.wpMaxs[1]);
523  }
524  if (fromTile2)
525  Com_Printf(", %s", mapTiles[fromTile2 - 1].name);
526  if (fromTile3)
527  Com_Printf(", %s", mapTiles[fromTile3 - 1].name);
528  Com_Printf("\n");
529 #endif
530 }
531 
532 /*
533 ===============================================================================
534 BOX TRACING
535 ===============================================================================
536 */
537 
538 
542 int TR_BoxOnPlaneSide (const vec3_t mins, const vec3_t maxs, const TR_PLANE_TYPE* plane)
543 {
544  /* axial planes are easy */
545  if (AXIAL(plane)) {
546  int side = 0;
547  if (maxs[plane->type] > plane->dist + PLANESIDE_EPSILON)
548  side |= PSIDE_FRONT;
549  if (mins[plane->type] < plane->dist - PLANESIDE_EPSILON)
550  side |= PSIDE_BACK;
551  return side;
552  }
553 
554  /* create the proper leading and trailing verts for the box */
555 
556  vec3_t corners[2];
557  for (int i = 0; i < 3; i++) {
558  if (plane->normal[i] < 0) {
559  corners[0][i] = mins[i];
560  corners[1][i] = maxs[i];
561  } else {
562  corners[1][i] = mins[i];
563  corners[0][i] = maxs[i];
564  }
565  }
566 
567  vec_t dist1 = DotProduct(plane->normal, corners[0]) - plane->dist;
568  vec_t dist2 = DotProduct(plane->normal, corners[1]) - plane->dist;
569  int side = 0;
570  if (dist1 >= PLANESIDE_EPSILON)
571  side = PSIDE_FRONT;
572  if (dist2 < PLANESIDE_EPSILON)
573  side |= PSIDE_BACK;
574 
575  return side;
576 }
577 
578 typedef struct leaf_check_s {
580  int32_t* leaf_list;
581  int32_t leaf_topnode;
582 } leaf_check_t;
583 
589 static void TR_BoxLeafnums_r (boxtrace_t* traceData, int32_t nodenum, leaf_check_t* lc)
590 {
591  const TR_TILE_TYPE* myTile = traceData->tile;
592 
593  while (1) {
594  if (nodenum <= LEAFNODE) {
595  if (lc->leaf_count >= lc->leaf_maxcount) {
596 /* Com_Printf("CM_BoxLeafnums_r: overflow\n"); */
597  return;
598  }
599  lc->leaf_list[lc->leaf_count++] = -1 - nodenum;
600  return;
601  }
602 
603  assert(nodenum < myTile->numnodes + 6); /* +6 => bbox */
604  const TR_NODE_TYPE* node = &myTile->nodes[nodenum];
605 
606 #ifdef COMPILE_UFO
607  const TR_PLANE_TYPE* plane = node->plane;
608 #else
609  const TR_PLANE_TYPE* plane = myTile->planes + node->planenum;
610 #endif
611 
612  const int s = TR_BoxOnPlaneSide(traceData->absmins, traceData->absmaxs, plane);
613  if (s == PSIDE_FRONT)
614  nodenum = node->children[0];
615  else if (s == PSIDE_BACK)
616  nodenum = node->children[1];
617  else { /* go down both */
618  if (lc->leaf_topnode == LEAFNODE)
619  lc->leaf_topnode = nodenum;
620  TR_BoxLeafnums_r(traceData, node->children[0], lc);
621  nodenum = node->children[1];
622  }
623  }
624 }
625 
633 static int TR_BoxLeafnums_headnode (boxtrace_t* traceData, int32_t* list, int listsize, int32_t headnode)
634 {
635  leaf_check_t lc;
636  lc.leaf_list = list;
637  lc.leaf_count = 0;
638  lc.leaf_maxcount = listsize;
639  lc.leaf_topnode = LEAFNODE;
640 
641  assert(headnode < traceData->tile->numnodes + 6); /* +6 => bbox */
642  TR_BoxLeafnums_r(traceData, headnode, &lc);
643 
644  return lc.leaf_count;
645 }
646 
647 
656 static void TR_ClipBoxToBrush (boxtrace_t* traceData, cBspBrush_t* brush, TR_LEAF_TYPE* leaf)
657 {
658  if (!brush || !brush->numsides)
659  return;
660 
661 #ifdef COMPILE_UFO
662  const TR_BRUSHSIDE_TYPE* leadside = nullptr;
663 #endif
664  const TR_TILE_TYPE* myTile = traceData->tile;
665 
666  float enterfrac = -1.0;
667  float leavefrac = 1.0;
668  bool getout = false;
669  bool startout = false;
670 
671  const TR_PLANE_TYPE* clipplane = nullptr;
672  int clipplanenum = 0;
673 
674  float dist;
675  vec3_t ofs;
676  for (int i = 0; i < brush->numsides; i++) {
677  const TR_BRUSHSIDE_TYPE* side = &myTile->brushsides[brush->firstbrushside + i];
678 #ifdef COMPILE_UFO
679  const TR_PLANE_TYPE* plane = side->plane;
680 #else
681  const TR_PLANE_TYPE* plane = myTile->planes + side->planenum;
682 #endif
683 
685  if (!traceData->ispoint) { /* general box case */
686  /* push the plane out appropriately for mins/maxs */
687  for (int j = 0; j < 3; j++) {
688  if (plane->normal[j] < 0)
689  ofs[j] = traceData->maxs[j];
690  else
691  ofs[j] = traceData->mins[j];
692  }
693  dist = DotProduct(ofs, plane->normal);
694  dist = plane->dist - dist;
695  } else { /* special point case */
696  dist = plane->dist;
697  }
698 
699  const float d1 = DotProduct(traceData->start, plane->normal) - dist;
700  const float d2 = DotProduct(traceData->end, plane->normal) - dist;
701 
702  if (d2 > 0)
703  getout = true; /* endpoint is not in solid */
704  if (d1 > 0)
705  startout = true; /* startpoint is not in solid */
706 
707  /* if completely in front of face, no intersection */
708  if (d1 > 0 && d2 >= d1)
709  return;
710 
711  if (d1 <= 0 && d2 <= 0)
712  continue;
713 
714  /* crosses face */
715  if (d1 > d2) { /* enter */
716  const float f = (d1 - DIST_EPSILON) / (d1 - d2);
717  if (f > enterfrac) {
718  enterfrac = f;
719  clipplane = plane;
720 #ifdef COMPILE_MAP
721  clipplanenum = side->planenum;
722 #else
723  leadside = side;
724 #endif
725  }
726  } else { /* leave */
727  const float f = (d1 + DIST_EPSILON) / (d1 - d2);
728  if (f < leavefrac)
729  leavefrac = f;
730  }
731  }
732 
733  if (!startout) { /* original point was inside brush */
734  traceData->trace.startsolid = true;
735  if (!getout)
736  traceData->trace.allsolid = true;
737  traceData->trace.leafnum = leaf - myTile->leafs;
738  return;
739  }
740  if (enterfrac < leavefrac) {
741  if (enterfrac > -1 && enterfrac < traceData->trace.fraction) {
742  if (enterfrac < 0)
743  enterfrac = 0;
744  traceData->trace.fraction = enterfrac;
745  traceData->trace.plane = *clipplane;
746  traceData->trace.planenum = clipplanenum;
747 #ifdef COMPILE_UFO
748  traceData->trace.surface = leadside->surface;
749 #endif
750  traceData->trace.contentFlags = brush->brushContentFlags;
751  traceData->trace.leafnum = leaf - myTile->leafs;
752  }
753  }
754 }
755 
759 static void TR_TestBoxInBrush (boxtrace_t* traceData, cBspBrush_t* brush)
760 {
761  vec3_t ofs;
762  const TR_TILE_TYPE* myTile = traceData->tile;
763 
764  if (!brush || !brush->numsides)
765  return;
766 
767  for (int i = 0; i < brush->numsides; i++) {
768  const TR_BRUSHSIDE_TYPE* side = &myTile->brushsides[brush->firstbrushside + i];
769 #ifdef COMPILE_UFO
770  const TR_PLANE_TYPE* plane = side->plane;
771 #else
772  const TR_PLANE_TYPE* plane = myTile->planes + side->planenum;
773 #endif
774 
776  /* general box case */
777  /* push the plane out appropriately for mins/maxs */
778  for (int j = 0; j < 3; j++) {
779  if (plane->normal[j] < 0)
780  ofs[j] = traceData->maxs[j];
781  else
782  ofs[j] = traceData->mins[j];
783  }
784  const float dist = plane->dist - DotProduct(ofs, plane->normal);
785 
786  float d1 = DotProduct(traceData->start, plane->normal) - dist;
787 
788  /* if completely in front of face, no intersection */
789  if (d1 > 0)
790  return;
791  }
792 
793  /* inside this brush */
794  traceData->trace.startsolid = traceData->trace.allsolid = true;
795  traceData->trace.fraction = 0;
796  traceData->trace.contentFlags = brush->brushContentFlags;
797 }
798 
799 
811 static void TR_TraceToLeaf (boxtrace_t* traceData, int32_t leafnum)
812 {
813  TR_TILE_TYPE* myTile = traceData->tile;
814 
815  assert(leafnum > LEAFNODE);
816  assert(leafnum <= myTile->numleafs);
817 
818  TR_LEAF_TYPE* leaf = &myTile->leafs[leafnum];
819 
820  if (traceData->contents != MASK_ALL && (!(leaf->contentFlags & traceData->contents) || (leaf->contentFlags & traceData->rejects)))
821  return;
822 
823  /* trace line against all brushes in the leaf */
824  for (int k = 0; k < leaf->numleafbrushes; k++) {
825  const int brushnum = myTile->leafbrushes[leaf->firstleafbrush + k];
826  cBspBrush_t* b = &myTile->brushes[brushnum];
827 
828  if (b->checkcount == checkcount)
829  continue; /* already checked this brush in another leaf */
830  b->checkcount = checkcount;
831 
832  if (traceData->contents != MASK_ALL && (!(b->brushContentFlags & traceData->contents) || (b->brushContentFlags & traceData->rejects)))
833  continue;
834 
835  TR_ClipBoxToBrush(traceData, b, leaf);
836  if (!traceData->trace.fraction)
837  return;
838  }
839 }
840 
841 
845 static void TR_TestInLeaf (boxtrace_t* traceData, int32_t leafnum)
846 {
847  TR_TILE_TYPE* myTile = traceData->tile;
848 
849  assert(leafnum > LEAFNODE);
850  assert(leafnum <= myTile->numleafs);
851 
852  const TR_LEAF_TYPE* leaf = &myTile->leafs[leafnum];
853  /* If this leaf contains no flags we need to look for, then skip it. */
854  if (!(leaf->contentFlags & traceData->contents)) /* || (leaf->contentFlags & traceData->rejects) */
855  return;
856 
857  /* trace line against all brushes in the leaf */
858  for (int k = 0; k < leaf->numleafbrushes; k++) {
859  const int brushnum = myTile->leafbrushes[leaf->firstleafbrush + k];
860  cBspBrush_t* b = &myTile->brushes[brushnum];
861  if (b->checkcount == checkcount)
862  continue; /* already checked this brush in another leaf */
863  b->checkcount = checkcount;
864 
865  if (!(traceData->contents && (b->brushContentFlags & traceData->contents)) || (b->brushContentFlags & traceData->rejects))
866  continue;
867  TR_TestBoxInBrush(traceData, b);
868  if (!traceData->trace.fraction)
869  return;
870  }
871 }
872 
873 
891 static void TR_RecursiveHullCheck (boxtrace_t* traceData, int32_t nodenum, float p1f, float p2f, const vec3_t p1, const vec3_t p2)
892 {
893  if (traceData->trace.fraction <= p1f)
894  return; /* already hit something nearer */
895 
896  /* if < 0, we are in a leaf node */
897  if (nodenum <= LEAFNODE) {
898  TR_TraceToLeaf(traceData, LEAFNODE - nodenum);
899  return;
900  }
901 
902  assert(nodenum < MAX_MAP_NODES);
903 
904  /* find the point distances to the seperating plane
905  * and the offset for the size of the box */
906  const TR_TILE_TYPE* myTile = traceData->tile;
907  const TR_NODE_TYPE* node = myTile->nodes + nodenum;
908 
909 #ifdef COMPILE_UFO
910  const TR_PLANE_TYPE* plane = node->plane;
911 #else
912  assert(node->planenum < MAX_MAP_PLANES);
913  const TR_PLANE_TYPE* plane = myTile->planes + node->planenum;
914 #endif
915 
916  float t1, t2, offset;
917  if (AXIAL(plane)) {
918  const int type = plane->type;
919  t1 = p1[type] - plane->dist;
920  t2 = p2[type] - plane->dist;
921  offset = traceData->extents[type];
922  } else {
923  t1 = DotProduct(plane->normal, p1) - plane->dist;
924  t2 = DotProduct(plane->normal, p2) - plane->dist;
925  if (traceData->ispoint)
926  offset = 0;
927  else
928  offset = fabs(traceData->extents[0] * plane->normal[0])
929  + fabs(traceData->extents[1] * plane->normal[1])
930  + fabs(traceData->extents[2] * plane->normal[2]);
931  }
932 
933  /* see which sides we need to consider */
934  if (t1 >= offset && t2 >= offset) {
935  TR_RecursiveHullCheck(traceData, node->children[0], p1f, p2f, p1, p2);
936  return;
937  } else if (t1 < -offset && t2 < -offset) {
938  TR_RecursiveHullCheck(traceData, node->children[1], p1f, p2f, p1, p2);
939  return;
940  }
941 
942  /* put the crosspoint DIST_EPSILON pixels on the near side */
949  float frac, frac2;
950  int side;
951  if (t1 < t2) {
952  const float idist = 1.0 / (t1 - t2);
953  side = 1;
954  frac2 = (t1 + offset + DIST_EPSILON) * idist;
955  frac = (t1 - offset + DIST_EPSILON) * idist;
956  } else if (t1 > t2) {
957  const float idist = 1.0 / (t1 - t2);
958  side = 0;
959  frac2 = (t1 - offset - DIST_EPSILON) * idist;
960  frac = (t1 + offset + DIST_EPSILON) * idist;
961  } else {
962  side = 0;
963  frac = 1;
964  frac2 = 0;
965  }
966 
967  /* move up to the node */
968  if (frac < 0)
969  frac = 0;
970  else if (frac > 1)
971  frac = 1;
972 
973  float midf = p1f + (p2f - p1f) * frac;
974  vec3_t mid;
975  VectorInterpolation(p1, p2, frac, mid);
976  TR_RecursiveHullCheck(traceData, node->children[side], p1f, midf, p1, mid);
977 
978  /* go past the node */
979  if (frac2 < 0)
980  frac2 = 0;
981  else if (frac2 > 1)
982  frac2 = 1;
983 
984  midf = p1f + (p2f - p1f) * frac2;
985  VectorInterpolation(p1, p2, frac2, mid);
986  TR_RecursiveHullCheck(traceData, node->children[side ^ 1], midf, p2f, mid, p2);
987 }
988 
1003 trace_t TR_BoxTrace (boxtrace_t& traceData, const Line& traceLine, const AABB& traceBox, const int headnode, const float fraction)
1004 {
1005  checkcount++; /* for multi-check avoidance */
1006 
1007 #ifdef COMPILE_UFO
1008  if (headnode >= traceData.tile->numnodes + 6)
1009  Com_Error(ERR_DROP, "headnode (%i) is out of bounds: %i", headnode, traceData.tile->numnodes + 6);
1010 #else
1011  assert(headnode < traceData.tile->numnodes + 6); /* +6 => bbox */
1012 #endif
1013 
1014  if (!traceData.tile->numnodes) /* map not loaded */
1015  return traceData.trace;
1016 
1017  /* check for position test special case */
1018  if (VectorEqual(traceData.start, traceData.end)) {
1019  int32_t leafs[MAX_LEAFS];
1020 
1021  VectorAdd(traceData.start, traceData.maxs, traceData.absmaxs);
1022  VectorAdd(traceData.start, traceData.mins, traceData.absmins);
1023 
1024  const int numleafs = TR_BoxLeafnums_headnode(&traceData, leafs, MAX_LEAFS, headnode);
1025  for (int i = 0; i < numleafs; i++) {
1026  TR_TestInLeaf(&traceData, leafs[i]);
1027  if (traceData.trace.allsolid)
1028  break;
1029  }
1030  VectorCopy(traceLine.start, traceData.trace.endpos);
1031  return traceData.trace;
1032  }
1033 
1034  /* check for point special case */
1035  if (VectorEmpty(traceData.mins) && VectorEmpty(traceData.maxs)) {
1036  traceData.ispoint = true;
1037  VectorClear(traceData.extents);
1038  } else {
1039  traceData.ispoint = false;
1040  VectorCopy(traceData.maxs, traceData.extents);
1041  }
1042 
1043  /* general sweeping through world */
1045  TR_RecursiveHullCheck(&traceData, headnode, 0.0f, 1.0f, traceData.start, traceData.end);
1046 
1047  if (traceData.trace.fraction >= 1.0f) {
1048  VectorCopy(traceData.end, traceData.trace.endpos);
1049  } else {
1050  VectorInterpolation(traceData.start, traceData.end, traceData.trace.fraction, traceData.trace.endpos);
1051  }
1052  /* Now un-offset the end position. */
1053  VectorSubtract(traceData.trace.endpos, traceData.offset, traceData.trace.endpos);
1054  return traceData.trace;
1055 }
1056 
1067 trace_t TR_TileBoxTrace (TR_TILE_TYPE* myTile, const Line& traceLine, const AABB& aabb, const int levelmask, const int brushmask, const int brushreject)
1068 {
1069  int i;
1070  cBspHead_t* h;
1071  trace_t tr;
1072 
1073  /* ensure that the first trace is set in every case */
1074  tr.fraction = 2.0f;
1075 
1076  boxtrace_t traceData;
1077  traceData.init(myTile, brushmask, brushreject, tr.fraction);
1078  traceData.setLineAndBox(traceLine, aabb);
1079  /* trace against all loaded map tiles */
1080  for (i = 0, h = myTile->cheads; i < myTile->numcheads; i++, h++) {
1081  /* This code uses levelmask to limit by maplevel. Supposedly maplevels 1-255
1082  * are bitmasks of game levels 1-8. 0 is a special case repeat of 255.
1083  * However a levelmask including 0x100 is usually included so the CLIP levels are
1084  * examined. */
1085  if (h->level && h->level <= LEVEL_LASTVISIBLE && levelmask && !(h->level & levelmask))
1086  continue;
1087 
1088  assert(h->cnode < myTile->numnodes + 6); /* +6 => bbox */
1089  const trace_t newtr = TR_BoxTrace(traceData, traceLine, aabb, h->cnode, tr.fraction);
1090 
1091  /* memorize the trace with the minimal fraction */
1092  if (newtr.fraction == 0.0)
1093  return newtr;
1094  if (newtr.fraction < tr.fraction)
1095  tr = newtr;
1096  }
1097  return tr;
1098 }
1099 
1100 #ifdef COMPILE_MAP
1101 
1112 trace_t TR_SingleTileBoxTrace (mapTiles_t* mapTiles, const Line& traceLine, const AABB* traceBox, const int levelmask, const int brushmask, const int brushreject)
1113 {
1114  /* Trace the whole line against the first tile. */
1115  trace_t tr = TR_TileBoxTrace(&mapTiles->mapTiles[0], traceLine, *traceBox, levelmask, brushmask, brushreject);
1116  tr.mapTile = 0;
1117  return tr;
1118 }
1119 #endif
static void TR_BoxLeafnums_r(boxtrace_t *traceData, int32_t nodenum, leaf_check_t *lc)
Fills in a list of all the leafs touched call with topnode set to the headnode, returns with topnode ...
Definition: tracing.cpp:589
#define LEAFNODE
Definition: defines.h:44
void getTileOverlap(const byte tile1, const byte tile2, int &minZ, int &maxZ)
Definition: tracing.cpp:498
trace_t TR_BoxTrace(boxtrace_t &traceData, const Line &traceLine, const AABB &traceBox, const int headnode, const float fraction)
This function traces a line from start to end. It returns a trace_t indicating what portion of the li...
Definition: tracing.cpp:1003
#define VectorCopy(src, dest)
Definition: vector.h:51
int firstbrushside
Definition: typedefs.h:62
TR_TILE_TYPE * tile
Definition: tracing.h:106
void setLineAndBox(const Line &line, const AABB &box)
Definition: tracing.cpp:57
void Sys_Error(const char *error,...)
Definition: g_main.cpp:421
#define VectorSet(v, x, y, z)
Definition: vector.h:59
uint32_t contents
Definition: tracing.h:102
QGL_EXTERN GLint GLenum type
Definition: r_gl.h:94
uint32_t rejects
Definition: tracing.h:103
static ipos3_t wpMaxs
Definition: routing.cpp:35
#define PSIDE_BACK
Definition: defines.h:368
#define CONTENTS_PASSABLE
Definition: defines.h:244
bool VectorNearer(const vec3_t v1, const vec3_t v2, const vec3_t comp)
Checks whether the given vector v1 is closer to comp as the vector v2.
Definition: mathlib.cpp:219
int leaf_maxcount
Definition: tracing.cpp:579
static void TR_MakeTracingNode(TR_TILE_TYPE *tile, tnode_t **tnode, int32_t nodenum)
Converts the disk node structure into the efficient tracing structure for LineTraces.
Definition: tracing.cpp:83
#define CONTENTS_SOLID
Definition: defines.h:223
#define MAX_MAP_PLANES
Definition: defines.h:139
#define PLANE_Z
Definition: defines.h:193
vec3_t endpos
Definition: tracing.h:59
Definition: aabb.h:42
#define LEVEL_LASTVISIBLE
Definition: defines.h:348
int cnode
Definition: typedefs.h:78
#define LEVEL_ACTORCLIP
Definition: defines.h:352
bool ispoint
Definition: tracing.h:104
#define TL_FLAG_REGULAR_LEVELS
Definition: defines.h:358
float vec_t
Definition: ufotypes.h:37
TR_PLANE_TYPE plane
Definition: tracing.h:60
trace_t TR_TileBoxTrace(TR_TILE_TYPE *myTile, const Line &traceLine, const AABB &aabb, const int levelmask, const int brushmask, const int brushreject)
Traces all submodels in the specified tile. Provides for a short circuit if the trace tries to move p...
Definition: tracing.cpp:1067
int32_t children[2]
Definition: typedefs.h:73
struct leaf_check_s leaf_check_t
Data for line tracing (?)
Definition: typedefs.h:69
int level
Definition: typedefs.h:79
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
vec3_t maxs
Definition: aabb.h:258
#define PSIDE_FRONT
Definition: defines.h:367
#define MASK_ALL
Definition: defines.h:271
vec3_t normal
Definition: typedefs.h:71
float fraction
Definition: tracing.h:58
static void TR_ClipBoxToBrush(boxtrace_t *traceData, cBspBrush_t *brush, TR_LEAF_TYPE *leaf)
This function checks to see if any sides of a brush intersect the line from p1 to p2 or are located w...
Definition: tracing.cpp:656
#define TL_FLAG_ACTORCLIP
Definition: defines.h:359
void Com_Error(int code, const char *fmt,...)
Definition: common.cpp:417
Stores the data of a map tile, mostly the BSP stuff.
Definition: typedefs.h:85
int32_t leaf_topnode
Definition: tracing.cpp:581
#define AXIAL(p)
Definition: defines.h:201
int planenum
Definition: tracing.h:62
bool TR_TestLineDM(mapTiles_t *mapTiles, const vec3_t start, const vec3_t end, vec3_t hit, const int levelmask)
Checks traces against the world, gives hit position back.
Definition: tracing.cpp:458
#define DotProduct(x, y)
Returns the distance between two 3-dimensional vectors.
Definition: vector.h:44
#define ERR_DROP
Definition: common.h:211
void TR_BuildTracingNode_r(TR_TILE_TYPE *tile, tnode_t **tnode, int32_t nodenum, int level)
Definition: tracing.cpp:122
static bool TR_TileTestLine(TR_TILE_TYPE *tile, const vec3_t start, const vec3_t end, const int levelmask)
Tests to see if a line intersects any brushes in a tile.
Definition: tracing.cpp:279
void init(TR_TILE_TYPE *_tile, const int contentmask, const int brushreject, const float fraction)
Definition: tracing.cpp:46
vec3_t absmaxs
Definition: tracing.h:97
vec3_t end
Definition: tracing.h:95
int32_t leafnum
Definition: tracing.h:64
#define VectorEmpty(a)
Definition: vector.h:73
#define MAX_LEAFS
Definition: defines.h:152
int TR_TestLine_r(TR_TILE_TYPE *tile, int32_t nodenum, const vec3_t start, const vec3_t end)
Definition: tracing.cpp:209
static transfer_t tr
Definition: line.h:31
#define VectorInterpolation(p1, p2, frac, mid)
Definition: vector.h:80
vec3_t maxs
Definition: tracing.h:96
void getTilesAt(int x, int y, byte &fromTile1, byte &fromTile2, byte &fromTile3)
Definition: tracing.cpp:478
vec3_t stop
Definition: line.h:55
void getCenter(vec3_t center) const
Calculates the center of the bounding box.
Definition: aabb.h:155
uint32_t brushContentFlags
Definition: typedefs.h:60
static int TR_BoxLeafnums_headnode(boxtrace_t *traceData, int32_t *list, int listsize, int32_t headnode)
Fill a list of leafnodes that the trace touches.
Definition: tracing.cpp:633
vec3_t absmins
Definition: tracing.h:97
#define EQUAL_EPSILON
Definition: mathlib.h:40
#define PLANESIDE_EPSILON
Definition: defines.h:38
trace_t trace
Definition: tracing.h:101
int leaf_count
Definition: tracing.cpp:579
QGL_EXTERN GLfloat f
Definition: r_gl.h:114
#define VectorClear(a)
Definition: vector.h:55
void init()
Definition: tracing.h:72
int type
Definition: typedefs.h:70
float dist
Definition: typedefs.h:72
int checkcount
Definition: typedefs.h:63
#define VectorAdd(a, b, dest)
Definition: vector.h:47
static int TR_TestLineDist_r(TR_TILE_TYPE *tile, int32_t nodenum, const vec3_t start, const vec3_t end, vec3_t tr_end)
Definition: tracing.cpp:336
static void TR_TestInLeaf(boxtrace_t *traceData, int32_t leafnum)
Definition: tracing.cpp:845
static void TR_TraceToLeaf(boxtrace_t *traceData, int32_t leafnum)
This function checks if the specified leaf matches any mask specified in traceData.contents. and does not contain any mask specified in traceData.rejects If so, each brush in the leaf is examined to see if it is intersected by the line drawn in TR_RecursiveHullCheck or is within the bounding box set in trace_mins and trace_maxs with the origin on the line.
Definition: tracing.cpp:811
#define PLANE_NONE
Definition: defines.h:199
int numTiles
Definition: tracing.h:82
static int checkcount
Definition: tracing.cpp:72
#define PLANENUM_LEAF
Definition: defines.h:45
TR_TILE_TYPE mapTiles[MAX_MAPTILES]
Definition: tracing.h:79
QGL_EXTERN GLint i
Definition: r_gl.h:113
ipos3_t wpMaxs
Definition: typedefs.h:131
vec3_t start
Definition: tracing.h:95
vec3_t start
Definition: line.h:54
int mapTile
Definition: tracing.h:65
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition: r_gl.h:110
#define MASK_CLIP
Definition: defines.h:278
static bool TR_TileTestLineDM(TR_TILE_TYPE *tile, const vec3_t start, const vec3_t end, vec3_t hit, const int levelmask)
Checks traces against the world, gives hit position back.
Definition: tracing.cpp:414
int numsides
Definition: typedefs.h:61
bool TR_TestLine(mapTiles_t *mapTiles, const vec3_t start, const vec3_t end, const int levelmask)
Checks traces against the world.
Definition: tracing.cpp:310
#define DIST_EPSILON
Definition: defines.h:377
bool startsolid
Definition: tracing.h:57
vec_t vec3_t[3]
Definition: ufotypes.h:39
#define LEVEL_LIGHTCLIP
Definition: defines.h:349
definitions common between client and server, but not game lib
static void TR_TestBoxInBrush(boxtrace_t *traceData, cBspBrush_t *brush)
Definition: tracing.cpp:759
uint32_t contentFlags
Definition: tracing.h:63
ipos3_t wpMins
Definition: typedefs.h:130
vec3_t mins
Definition: aabb.h:257
char name[MAX_QPATH]
Definition: typedefs.h:87
int VectorCompareEps(const vec3_t v1, const vec3_t v2, float epsilon)
Compare two vectors that may have an epsilon difference but still be the same vectors.
Definition: mathlib.cpp:413
vec3_t offset
Definition: tracing.h:99
void printTilesAt(int x, int y)
Definition: tracing.cpp:513
voidpf uLong offset
Definition: ioapi.h:45
cBspSurface_t * surface
Definition: tracing.h:61
bool allsolid
Definition: tracing.h:56
#define LEVEL_WEAPONCLIP
Definition: defines.h:351
#define PLANE_Y
Definition: defines.h:192
uint8_t byte
Definition: ufotypes.h:34
vec3_t extents
Definition: tracing.h:98
#define VectorEqual(a, b)
Definition: vector.h:65
static ipos3_t wpMins
world min and max values converted from vec to pos
Definition: routing.cpp:35
#define TL_FLAG_WEAPONCLIP
Definition: defines.h:360
#define VectorSubtract(a, b, dest)
Definition: vector.h:45
Tracing functions.
vec3_t mins
Definition: tracing.h:96
int32_t * leaf_list
Definition: tracing.cpp:580
#define PLANE_X
Definition: defines.h:191
static mapTiles_t mapTiles
#define ON_EPSILON
Definition: defines.h:374
level_locals_t level
Definition: g_main.cpp:38
static void TR_RecursiveHullCheck(boxtrace_t *traceData, int32_t nodenum, float p1f, float p2f, const vec3_t p1, const vec3_t p2)
This recursive function traces through the bsp tree looking to see if a brush can be found that inter...
Definition: tracing.cpp:891
int TR_BoxOnPlaneSide(const vec3_t mins, const vec3_t maxs, const TR_PLANE_TYPE *plane)
Returns PSIDE_FRONT, PSIDE_BACK, or PSIDE_BOTH.
Definition: tracing.cpp:542
#define MAX_MAP_NODES
Definition: defines.h:140