tracing.c

Go to the documentation of this file.
00001 
00007 /*
00008 All original material Copyright (C) 2002-2010 UFO: Alien Invasion.
00009 
00010 Copyright (C) 1997-2001 Id Software, Inc.
00011 
00012 This program is free software; you can redistribute it and/or
00013 modify it under the terms of the GNU General Public License
00014 as published by the Free Software Foundation; either version 2
00015 of the License, or (at your option) any later version.
00016 
00017 This program is distributed in the hope that it will be useful,
00018 but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00020 
00021 See the GNU General Public License for more details.
00022 
00023 You should have received a copy of the GNU General Public License
00024 along with this program; if not, write to the Free Software
00025 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00026 
00027 */
00028 
00029 #include "tracing.h"
00030 #include "common.h"
00031 #include "mem.h"
00032 
00035 static int checkcount;
00036 
00037 /*
00038 ===============================================================================
00039 TRACING NODES
00040 ===============================================================================
00041 */
00042 
00046 static void TR_MakeTracingNode (TR_TILE_TYPE *tile, tnode_t ** tnode, int32_t nodenum)
00047 {
00048     tnode_t *t;             /* the tracing node to build */
00049     TR_PLANE_TYPE *plane;
00050     int i;
00051     TR_NODE_TYPE *node;     /* the node we are investigating */
00052 
00053     t = (*tnode)++;
00054 
00055     node = tile->nodes + nodenum;
00056 #ifdef COMPILE_UFO
00057     plane = node->plane;
00058 #else
00059     plane = tile->planes + node->planenum;
00060 #endif
00061 
00062     t->type = plane->type;
00063     VectorCopy(plane->normal, t->normal);
00064     t->dist = plane->dist;
00065 
00066     for (i = 0; i < 2; i++) {
00067         if (node->children[i] < 0) {    /* is it a leaf ? */
00068             const int32_t leafnum = -(node->children[i]) - 1;
00069             const TR_LEAF_TYPE *leaf = &tile->leafs[leafnum];
00070             const uint32_t contentFlags = leaf->contentFlags & ~(1 << 31);
00071             if ((contentFlags & (CONTENTS_SOLID | MASK_CLIP)) && !(contentFlags & CONTENTS_PASSABLE))
00072                 t->children[i] = -node->children[i] | (1 << 31);    /* mark as 'blocking' */
00073             else
00074                 t->children[i] = (1 << 31);             /* mark as 'empty leaf' */
00075         } else {                                        /* not a leaf */
00076             t->children[i] = *tnode - tile->tnodes;
00077             if (t->children[i] > tile->numnodes) {
00078                 Com_Printf("Exceeded allocated memory for tracing structure (%i > %i)\n",
00079                         t->children[i], tile->numnodes);
00080             }
00081             TR_MakeTracingNode(tile, tnode, node->children[i]);     /* recurse further down the tree */
00082         }
00083     }
00084 }
00085 
00090 void TR_BuildTracingNode_r (TR_TILE_TYPE *tile, tnode_t ** tnode, int32_t nodenum, int level)
00091 {
00092     assert(nodenum < tile->numnodes + 6); /* +6 => bbox */
00093 
00098 #ifdef COMPILE_UFO
00099     if (!tile->nodes[nodenum].plane) {
00100 #else
00101     if (tile->nodes[nodenum].planenum == PLANENUM_LEAF) {
00102 #endif
00103         TR_NODE_TYPE *n;
00104         tnode_t *t;
00105         vec3_t c0maxs, c1mins;
00106         int i;
00107 
00108         n = &tile->nodes[nodenum];
00109 
00110         /* alloc new node */
00111         t = (*tnode)++;
00112 
00113         /* no leafs here */
00114         if (n->children[0] < 0 || n->children[1] < 0)
00115 #ifdef COMPILE_UFO
00116             Com_Error(ERR_DROP, "Unexpected leaf");
00117 #else
00118             Sys_Error("Unexpected leaf");
00119 #endif
00120 
00121         VectorCopy(tile->nodes[n->children[0]].maxs, c0maxs);
00122         VectorCopy(tile->nodes[n->children[1]].mins, c1mins);
00123 
00124 #if 0
00125         Com_Printf("(%i %i : %i %i) (%i %i : %i %i)\n",
00126             (int)tile->nodes[n->children[0]].mins[0], (int)tile->nodes[n->children[0]].mins[1],
00127             (int)tile->nodes[n->children[0]].maxs[0], (int)tile->nodes[n->children[0]].maxs[1],
00128             (int)tile->nodes[n->children[1]].mins[0], (int)tile->nodes[n->children[1]].mins[1],
00129             (int)tile->nodes[n->children[1]].maxs[0], (int)tile->nodes[n->children[1]].maxs[1]);
00130 #endif
00131 
00132         for (i = 0; i < 2; i++)
00133             if (c0maxs[i] <= c1mins[i]) {
00134                 /* create a separation plane */
00135                 t->type = i;
00136                 VectorSet(t->normal, i, (i ^ 1), 0);
00137                 t->dist = (c0maxs[i] + c1mins[i]) / 2;
00138 
00139                 t->children[1] = *tnode - tile->tnodes;
00140                 TR_BuildTracingNode_r(tile, tnode, n->children[0], level);
00141                 t->children[0] = *tnode - tile->tnodes;
00142                 TR_BuildTracingNode_r(tile, tnode, n->children[1], level);
00143                 return;
00144             }
00145 
00146         /* can't construct such a separation plane */
00147         t->type = PLANE_NONE;
00148 
00149         for (i = 0; i < 2; i++) {
00150             t->children[i] = *tnode - tile->tnodes;
00151             TR_BuildTracingNode_r(tile, tnode, n->children[i], level);
00152         }
00153     } else {
00154         /* Make a lookup table */
00155         tile->cheads[tile->numcheads].cnode = nodenum;
00156         tile->cheads[tile->numcheads].level = level;
00157         tile->numcheads++;
00158         assert(tile->numcheads <= MAX_MAP_NODES);
00159         /* Make the tracing node. */
00160         TR_MakeTracingNode(tile, tnode, nodenum);
00161     }
00162 }
00163 
00164 
00165 /*
00166 ===============================================================================
00167 LINE TRACING - TEST FOR BRUSH PRESENCE
00168 ===============================================================================
00169 */
00170 
00171 
00181 int TR_TestLine_r (TR_TILE_TYPE *tile, int32_t nodenum, const vec3_t start, const vec3_t stop)
00182 {
00183     tnode_t *tnode;
00184     float front, back;
00185     int r;
00186 
00187     /* negative numbers indicate leaf nodes. Empty leaf nodes are marked as (1 << 31).
00188      * Turning off that bit makes us return 0 or the positive node number to indicate blocking. */
00189     if (nodenum & (1 << 31))
00190         return nodenum & ~(1 << 31);
00191 
00192     tnode = &tile->tnodes[nodenum];
00193     assert(tnode);
00194     switch (tnode->type) {
00195     case PLANE_X:
00196     case PLANE_Y:
00197     case PLANE_Z:
00198         front = start[tnode->type] - tnode->dist;
00199         back = stop[tnode->type] - tnode->dist;
00200         break;
00201     case PLANE_NONE:
00202         r = TR_TestLine_r(tile, tnode->children[0], start, stop);
00203         if (r)
00204             return r;
00205         return TR_TestLine_r(tile, tnode->children[1], start, stop);
00206     default:
00207         front = DotProduct(start, tnode->normal) - tnode->dist;
00208         back = DotProduct(stop, tnode->normal) - tnode->dist;
00209         break;
00210     }
00211 
00212     if (front >= -ON_EPSILON && back >= -ON_EPSILON)
00213         return TR_TestLine_r(tile, tnode->children[0], start, stop);
00214     else if (front < ON_EPSILON && back < ON_EPSILON)
00215         return TR_TestLine_r(tile, tnode->children[1], start, stop);
00216     else {
00217         const int side = front < 0;
00218         const float frac = front / (front - back);
00219         vec3_t mid;
00220 
00221         VectorInterpolation(start, stop, frac, mid);
00222 
00223         r = TR_TestLine_r(tile, tnode->children[side], start, mid);
00224         if (r)
00225             return r;
00226         return TR_TestLine_r(tile, tnode->children[!side], mid, stop);
00227     }
00228 }
00229 
00230 
00252 static qboolean TR_TileTestLine (TR_TILE_TYPE *tile, const vec3_t start, const vec3_t stop, const int levelmask)
00253 {
00254     const int corelevels = (levelmask & TL_FLAG_REGULAR_LEVELS);
00255     int i;
00256 
00257     /* loop over all theads */
00258     for (i = 0; i < tile->numtheads; i++) {
00259         const int level = tile->theadlevel[i];
00260         if (level && corelevels && !(level & corelevels))
00261             continue;
00262         if (level == LEVEL_LIGHTCLIP)   /* lightclips are only used in ufo2map, and it does not use this function */
00263             continue;
00264         if (level == LEVEL_ACTORCLIP && !(levelmask & TL_FLAG_ACTORCLIP))
00265             continue;
00266         if (level == LEVEL_WEAPONCLIP && !(levelmask & TL_FLAG_WEAPONCLIP))
00267             continue;
00268         if (TR_TestLine_r(tile, tile->thead[i], start, stop))
00269             return qtrue;
00270     }
00271     return qfalse;
00272 }
00273 
00283 qboolean TR_TestLine (mapTiles_t *mapTiles, const vec3_t start, const vec3_t stop, const int levelmask)
00284 {
00285     int tile;
00286 
00287     for (tile = 0; tile < mapTiles->numTiles; tile++) {
00288         if (TR_TileTestLine(&mapTiles->mapTiles[tile], start, stop, levelmask))
00289             return qtrue;
00290     }
00291     return qfalse;
00292 }
00293 
00294 
00295 /*
00296 ===============================================================================
00297 LINE TRACING - TEST FOR BRUSH LOCATION
00298 ===============================================================================
00299 */
00300 
00301 
00311 static int TR_TestLineDist_r (TR_TILE_TYPE *tile, int32_t nodenum, const vec3_t start, const vec3_t stop, vec3_t tr_end)
00312 {
00313     tnode_t *tnode;
00314     float front, back;
00315     vec3_t mid;
00316     float frac;
00317     int side;
00318     int r;
00319 
00320     if (nodenum & (1 << 31)) {
00321         r = nodenum & ~(1 << 31);
00322         if (r)
00323             VectorCopy(start, tr_end);
00324         return r;               /* leaf node */
00325     }
00326 
00327     tnode = &tile->tnodes[nodenum];
00328     assert(tnode);
00329     switch (tnode->type) {
00330     case PLANE_X:
00331     case PLANE_Y:
00332     case PLANE_Z:
00333         front = start[tnode->type] - tnode->dist;
00334         back = stop[tnode->type] - tnode->dist;
00335         break;
00336     case PLANE_NONE:
00337         r = TR_TestLineDist_r(tile, tnode->children[0], start, stop, tr_end);
00338         if (r)
00339             VectorCopy(tr_end, mid);
00340         side = TR_TestLineDist_r(tile, tnode->children[1], start, stop, tr_end);
00341         if (side && r) {
00342             if (VectorNearer(mid, tr_end, start)) {
00343                 VectorCopy(mid, tr_end);
00344                 return r;
00345             } else {
00346                 return side;
00347             }
00348         }
00349 
00350         if (r) {
00351             VectorCopy(mid, tr_end);
00352             return r;
00353         }
00354 
00355         return side;
00356     default:
00357         front = (start[0] * tnode->normal[0] + start[1] * tnode->normal[1] + start[2] * tnode->normal[2]) - tnode->dist;
00358         back = (stop[0] * tnode->normal[0] + stop[1] * tnode->normal[1] + stop[2] * tnode->normal[2]) - tnode->dist;
00359         break;
00360     }
00361 
00362     if (front >= -ON_EPSILON && back >= -ON_EPSILON)
00363         return TR_TestLineDist_r(tile, tnode->children[0], start, stop, tr_end);
00364 
00365     if (front < ON_EPSILON && back < ON_EPSILON)
00366         return TR_TestLineDist_r(tile, tnode->children[1], start, stop, tr_end);
00367 
00368     side = front < 0;
00369 
00370     frac = front / (front - back);
00371 
00372     VectorInterpolation(start, stop, frac, mid);
00373 
00374     r = TR_TestLineDist_r(tile, tnode->children[side], start, mid, tr_end);
00375     if (r)
00376         return r;
00377     return TR_TestLineDist_r(tile, tnode->children[!side], mid, stop, tr_end);
00378 }
00379 
00391 static qboolean TR_TileTestLineDM (TR_TILE_TYPE *tile, const vec3_t start, const vec3_t stop, vec3_t end, const int levelmask)
00392 {
00393 #ifdef COMPILE_MAP
00394     const int corelevels = (levelmask & TL_FLAG_REGULAR_LEVELS);
00395 #endif
00396     vec3_t tr_end;
00397     int i;
00398 
00399     VectorCopy(stop, end);
00400 
00401     for (i = 0; i < tile->numtheads; i++) {
00402 #ifdef COMPILE_MAP
00403         const int level = tile->theadlevel[i];
00404         if (level && corelevels && !(level & levelmask))
00405             continue;
00406 /*      if (level == LEVEL_LIGHTCLIP)
00407             continue;*/
00408         if (level == LEVEL_ACTORCLIP && !(levelmask & TL_FLAG_ACTORCLIP))
00409             continue;
00410         if (level == LEVEL_WEAPONCLIP && !(levelmask & TL_FLAG_WEAPONCLIP))
00411             continue;
00412 #endif
00413         if (TR_TestLineDist_r(tile, tile->thead[i], start, stop, tr_end))
00414             if (VectorNearer(tr_end, end, start))
00415                 VectorCopy(tr_end, end);
00416     }
00417 
00418     if (VectorCompareEps(end, stop, EQUAL_EPSILON))
00419         return qfalse;
00420     else
00421         return qtrue;
00422 }
00423 
00424 
00435 qboolean TR_TestLineDM (mapTiles_t* mapTiles, const vec3_t start, const vec3_t stop, vec3_t end, const int levelmask)
00436 {
00437     int tile;
00438     vec3_t t_end;
00439 
00440     VectorCopy(stop, end);
00441     VectorCopy(stop, t_end);
00442 
00443     for (tile = 0; tile < mapTiles->numTiles; tile++) {
00444         if (TR_TileTestLineDM(&mapTiles->mapTiles[tile], start, stop, t_end, levelmask)) {
00445             if (VectorNearer(t_end, end, start))
00446                 VectorCopy(t_end, end);
00447         }
00448     }
00449 
00450     if (VectorCompareEps(end, stop, EQUAL_EPSILON))
00451         return qfalse;
00452     else
00453         return qtrue;
00454 }
00455 
00456 
00457 /*
00458 ===============================================================================
00459 BOX TRACING
00460 ===============================================================================
00461 */
00462 
00463 
00467 int TR_BoxOnPlaneSide (const vec3_t mins, const vec3_t maxs, const TR_PLANE_TYPE *plane)
00468 {
00469     int side, i;
00470     vec3_t corners[2];
00471     vec_t dist1, dist2;
00472 
00473     /* axial planes are easy */
00474     if (AXIAL(plane)) {
00475         side = 0;
00476         if (maxs[plane->type] > plane->dist + PLANESIDE_EPSILON)
00477             side |= PSIDE_FRONT;
00478         if (mins[plane->type] < plane->dist - PLANESIDE_EPSILON)
00479             side |= PSIDE_BACK;
00480         return side;
00481     }
00482 
00483     /* create the proper leading and trailing verts for the box */
00484 
00485     for (i = 0; i < 3; i++) {
00486         if (plane->normal[i] < 0) {
00487             corners[0][i] = mins[i];
00488             corners[1][i] = maxs[i];
00489         } else {
00490             corners[1][i] = mins[i];
00491             corners[0][i] = maxs[i];
00492         }
00493     }
00494 
00495     dist1 = DotProduct(plane->normal, corners[0]) - plane->dist;
00496     dist2 = DotProduct(plane->normal, corners[1]) - plane->dist;
00497     side = 0;
00498     if (dist1 >= PLANESIDE_EPSILON)
00499         side = PSIDE_FRONT;
00500     if (dist2 < PLANESIDE_EPSILON)
00501         side |= PSIDE_BACK;
00502 
00503     return side;
00504 }
00505 
00506 typedef struct leaf_check_s {
00507     int leaf_count, leaf_maxcount;
00508     int32_t *leaf_list;
00509     int32_t leaf_topnode;
00510 } leaf_check_t;
00511 
00517 static void TR_BoxLeafnums_r (boxtrace_t *traceData, int32_t nodenum, leaf_check_t *lc)
00518 {
00519     TR_PLANE_TYPE *plane;
00520     TR_NODE_TYPE *node;
00521     int s;
00522     TR_TILE_TYPE *myTile = traceData->tile;
00523 
00524     while (1) {
00525         if (nodenum <= LEAFNODE) {
00526             if (lc->leaf_count >= lc->leaf_maxcount) {
00527 /*              Com_Printf("CM_BoxLeafnums_r: overflow\n"); */
00528                 return;
00529             }
00530             lc->leaf_list[lc->leaf_count++] = -1 - nodenum;
00531             return;
00532         }
00533 
00534         assert(nodenum < myTile->numnodes + 6); /* +6 => bbox */
00535         node = &myTile->nodes[nodenum];
00536 #ifdef COMPILE_UFO
00537         plane = node->plane;
00538 #else
00539         plane = myTile->planes + node->planenum;
00540 #endif
00541 
00542         s = TR_BoxOnPlaneSide(traceData->absmins, traceData->absmaxs, plane);
00543         if (s == PSIDE_FRONT)
00544             nodenum = node->children[0];
00545         else if (s == PSIDE_BACK)
00546             nodenum = node->children[1];
00547         else {                  /* go down both */
00548             if (lc->leaf_topnode == LEAFNODE)
00549                 lc->leaf_topnode = nodenum;
00550             TR_BoxLeafnums_r(traceData, node->children[0], lc);
00551             nodenum = node->children[1];
00552         }
00553     }
00554 }
00555 
00560 static int TR_BoxLeafnums_headnode (boxtrace_t *traceData, int32_t *list, int listsize, int32_t headnode, int32_t *topnode)
00561 {
00562     leaf_check_t lc;
00563     lc.leaf_list = list;
00564     lc.leaf_count = 0;
00565     lc.leaf_maxcount = listsize;
00566     lc.leaf_topnode = LEAFNODE;
00567 
00568     assert(headnode < traceData->tile->numnodes + 6); /* +6 => bbox */
00569     TR_BoxLeafnums_r(traceData, headnode, &lc);
00570 
00571     if (topnode)
00572         *topnode = lc.leaf_topnode;
00573 
00574     return lc.leaf_count;
00575 }
00576 
00577 
00586 static void TR_ClipBoxToBrush (boxtrace_t *traceData, cBspBrush_t *brush, TR_LEAF_TYPE *leaf)
00587 {
00588     int i, j;
00589     TR_PLANE_TYPE *clipplane;
00590     int clipplanenum;
00591     float dist;
00592     float enterfrac, leavefrac;
00593     vec3_t ofs;
00594     float d1, d2;
00595     qboolean getout, startout;
00596 #ifdef COMPILE_UFO
00597     TR_BRUSHSIDE_TYPE *leadside = NULL;
00598 #endif
00599     TR_TILE_TYPE *myTile = traceData->tile;
00600 
00601     enterfrac = -1.0;
00602     leavefrac = 1.0;
00603     clipplane = NULL;
00604 
00605     if (!brush || !brush->numsides)
00606         return;
00607 
00608     getout = qfalse;
00609     startout = qfalse;
00610     clipplanenum = 0;
00611 
00612     for (i = 0; i < brush->numsides; i++) {
00613         TR_BRUSHSIDE_TYPE *side = &myTile->brushsides[brush->firstbrushside + i];
00614 #ifdef COMPILE_UFO
00615         TR_PLANE_TYPE *plane = side->plane;
00616 #else
00617         TR_PLANE_TYPE *plane = myTile->planes + side->planenum;
00618 #endif
00619 
00621         if (!traceData->ispoint) {  /* general box case */
00622             /* push the plane out appropriately for mins/maxs */
00623             for (j = 0; j < 3; j++) {
00624                 if (plane->normal[j] < 0)
00625                     ofs[j] = traceData->maxs[j];
00626                 else
00627                     ofs[j] = traceData->mins[j];
00628             }
00629             dist = DotProduct(ofs, plane->normal);
00630             dist = plane->dist - dist;
00631         } else {                /* special point case */
00632             dist = plane->dist;
00633         }
00634 
00635         d1 = DotProduct(traceData->start, plane->normal) - dist;
00636         d2 = DotProduct(traceData->end, plane->normal) - dist;
00637 
00638         if (d2 > 0)
00639             getout = qtrue;     /* endpoint is not in solid */
00640         if (d1 > 0)
00641             startout = qtrue;   /* startpoint is not in solid */
00642 
00643         /* if completely in front of face, no intersection */
00644         if (d1 > 0 && d2 >= d1)
00645             return;
00646 
00647         if (d1 <= 0 && d2 <= 0)
00648             continue;
00649 
00650         /* crosses face */
00651         if (d1 > d2) {          /* enter */
00652             const float f = (d1 - DIST_EPSILON) / (d1 - d2);
00653             if (f > enterfrac) {
00654                 enterfrac = f;
00655                 clipplane = plane;
00656 #ifdef COMPILE_MAP
00657                 clipplanenum = side->planenum;
00658 #else
00659                 leadside = side;
00660 #endif
00661             }
00662         } else {                /* leave */
00663             const float f = (d1 + DIST_EPSILON) / (d1 - d2);
00664             if (f < leavefrac)
00665                 leavefrac = f;
00666         }
00667     }
00668 
00669     if (!startout) {            /* original point was inside brush */
00670         traceData->trace.startsolid = qtrue;
00671         if (!getout)
00672             traceData->trace.allsolid = qtrue;
00673         traceData->trace.leafnum = leaf - myTile->leafs;
00674         return;
00675     }
00676     if (enterfrac < leavefrac) {
00677         if (enterfrac > -1 && enterfrac < traceData->trace.fraction) {
00678             if (enterfrac < 0)
00679                 enterfrac = 0;
00680             traceData->trace.fraction = enterfrac;
00681             traceData->trace.plane = *clipplane;
00682             traceData->trace.planenum = clipplanenum;
00683 #ifdef COMPILE_UFO
00684             traceData->trace.surface = leadside->surface;
00685 #endif
00686             traceData->trace.contentFlags = brush->contentFlags;
00687             traceData->trace.leafnum = leaf - myTile->leafs;
00688         }
00689     }
00690 }
00691 
00695 static void TR_TestBoxInBrush (boxtrace_t *traceData, cBspBrush_t * brush)
00696 {
00697     int i, j;
00698     TR_PLANE_TYPE *plane;
00699     float dist;
00700     vec3_t ofs;
00701     float d1;
00702     TR_TILE_TYPE *myTile = traceData->tile;
00703 
00704     if (!brush || !brush->numsides)
00705         return;
00706 
00707     for (i = 0; i < brush->numsides; i++) {
00708         TR_BRUSHSIDE_TYPE *side = &myTile->brushsides[brush->firstbrushside + i];
00709 #ifdef COMPILE_UFO
00710         plane = side->plane;
00711 #else
00712         plane = myTile->planes + side->planenum;
00713 #endif
00714 
00716         /* general box case */
00717         /* push the plane out appropriately for mins/maxs */
00718         for (j = 0; j < 3; j++) {
00719             if (plane->normal[j] < 0)
00720                 ofs[j] = traceData->maxs[j];
00721             else
00722                 ofs[j] = traceData->mins[j];
00723         }
00724         dist = DotProduct(ofs, plane->normal);
00725         dist = plane->dist - dist;
00726 
00727         d1 = DotProduct(traceData->start, plane->normal) - dist;
00728 
00729         /* if completely in front of face, no intersection */
00730         if (d1 > 0)
00731             return;
00732     }
00733 
00734     /* inside this brush */
00735     traceData->trace.startsolid = traceData->trace.allsolid = qtrue;
00736     traceData->trace.fraction = 0;
00737     traceData->trace.contentFlags = brush->contentFlags;
00738 }
00739 
00740 
00752 static void TR_TraceToLeaf (boxtrace_t *traceData, int32_t leafnum)
00753 {
00754     int k;
00755     TR_LEAF_TYPE *leaf;
00756     TR_TILE_TYPE *myTile = traceData->tile;
00757 
00758     assert(leafnum > LEAFNODE);
00759     assert(leafnum <= myTile->numleafs);
00760 
00761     leaf = &myTile->leafs[leafnum];
00762 
00763     if (traceData->contents != MASK_ALL && (!(leaf->contentFlags & traceData->contents) || (leaf->contentFlags & traceData->rejects)))
00764         return;
00765 
00766     /* trace line against all brushes in the leaf */
00767     for (k = 0; k < leaf->numleafbrushes; k++) {
00768         const int brushnum = myTile->leafbrushes[leaf->firstleafbrush + k];
00769         cBspBrush_t *b = &myTile->brushes[brushnum];
00770 
00771         if (b->checkcount == checkcount)
00772             continue;           /* already checked this brush in another leaf */
00773         b->checkcount = checkcount;
00774 
00775         if (traceData->contents != MASK_ALL && (!(b->contentFlags & traceData->contents) || (b->contentFlags & traceData->rejects)))
00776             continue;
00777 
00778         TR_ClipBoxToBrush(traceData, b, leaf);
00779         if (!traceData->trace.fraction)
00780             return;
00781     }
00782 }
00783 
00784 
00788 static void TR_TestInLeaf (boxtrace_t *traceData, int32_t leafnum)
00789 {
00790     int k;
00791     const TR_LEAF_TYPE *leaf;
00792     TR_TILE_TYPE *myTile = traceData->tile;
00793 
00794     assert(leafnum > LEAFNODE);
00795     assert(leafnum <= myTile->numleafs);
00796 
00797     leaf = &myTile->leafs[leafnum];
00798     /* If this leaf contains no flags we need to look for, then skip it. */
00799     if (!(leaf->contentFlags & traceData->contents)) /* || (leaf->contentFlags & traceData->rejects) */
00800         return;
00801 
00802     /* trace line against all brushes in the leaf */
00803     for (k = 0; k < leaf->numleafbrushes; k++) {
00804         const int brushnum = myTile->leafbrushes[leaf->firstleafbrush + k];
00805         cBspBrush_t *b = &myTile->brushes[brushnum];
00806         if (b->checkcount == checkcount)
00807             continue;           /* already checked this brush in another leaf */
00808         b->checkcount = checkcount;
00809 
00810         if (!(traceData->contents && b->contentFlags & traceData->contents) || (b->contentFlags & traceData->rejects))
00811             continue;
00812         TR_TestBoxInBrush(traceData, b);
00813         if (!traceData->trace.fraction)
00814             return;
00815     }
00816 }
00817 
00818 
00836 static void TR_RecursiveHullCheck (boxtrace_t *traceData, int32_t nodenum, float p1f, float p2f, const vec3_t p1, const vec3_t p2)
00837 {
00838     TR_NODE_TYPE *node;
00839     TR_PLANE_TYPE *plane;
00840     float t1, t2, offset;
00841     float frac, frac2;
00842     int side;
00843     float midf;
00844     vec3_t mid;
00845     TR_TILE_TYPE *myTile = traceData->tile;
00846 
00847     if (traceData->trace.fraction <= p1f)
00848         return;                 /* already hit something nearer */
00849 
00850     /* if < 0, we are in a leaf node */
00851     if (nodenum <= LEAFNODE) {
00852         TR_TraceToLeaf(traceData, LEAFNODE - nodenum);
00853         return;
00854     }
00855 
00856     assert(nodenum < MAX_MAP_NODES);
00857 
00858     /* find the point distances to the seperating plane
00859      * and the offset for the size of the box */
00860     node = myTile->nodes + nodenum;
00861 
00862 #ifdef COMPILE_UFO
00863     plane = node->plane;
00864 #else
00865     assert(node->planenum < MAX_MAP_PLANES);
00866     plane = myTile->planes + node->planenum;
00867 #endif
00868 
00869     if (AXIAL(plane)) {
00870         const int type = plane->type;
00871         t1 = p1[type] - plane->dist;
00872         t2 = p2[type] - plane->dist;
00873         offset = traceData->extents[type];
00874     } else {
00875         t1 = DotProduct(plane->normal, p1) - plane->dist;
00876         t2 = DotProduct(plane->normal, p2) - plane->dist;
00877         if (traceData->ispoint)
00878             offset = 0;
00879         else
00880             offset = fabs(traceData->extents[0] * plane->normal[0])
00881                 + fabs(traceData->extents[1] * plane->normal[1])
00882                 + fabs(traceData->extents[2] * plane->normal[2]);
00883     }
00884 
00885     /* see which sides we need to consider */
00886     if (t1 >= offset && t2 >= offset) {
00887         TR_RecursiveHullCheck(traceData, node->children[0], p1f, p2f, p1, p2);
00888         return;
00889     } else if (t1 < -offset && t2 < -offset) {
00890         TR_RecursiveHullCheck(traceData, node->children[1], p1f, p2f, p1, p2);
00891         return;
00892     }
00893 
00894     /* put the crosspoint DIST_EPSILON pixels on the near side */
00901     if (t1 < t2) {
00902         const float idist = 1.0 / (t1 - t2);
00903         side = 1;
00904         frac2 = (t1 + offset + DIST_EPSILON) * idist;
00905         frac = (t1 - offset + DIST_EPSILON) * idist;
00906     } else if (t1 > t2) {
00907         const float idist = 1.0 / (t1 - t2);
00908         side = 0;
00909         frac2 = (t1 - offset - DIST_EPSILON) * idist;
00910         frac = (t1 + offset + DIST_EPSILON) * idist;
00911     } else {
00912         side = 0;
00913         frac = 1;
00914         frac2 = 0;
00915     }
00916 
00917     /* move up to the node */
00918     if (frac < 0)
00919         frac = 0;
00920     else if (frac > 1)
00921         frac = 1;
00922 
00923     midf = p1f + (p2f - p1f) * frac;
00924     VectorInterpolation(p1, p2, frac, mid);
00925     TR_RecursiveHullCheck(traceData, node->children[side], p1f, midf, p1, mid);
00926 
00927     /* go past the node */
00928     if (frac2 < 0)
00929         frac2 = 0;
00930     else if (frac2 > 1)
00931         frac2 = 1;
00932 
00933     midf = p1f + (p2f - p1f) * frac2;
00934     VectorInterpolation(p1, p2, frac2, mid);
00935     TR_RecursiveHullCheck(traceData, node->children[side ^ 1], midf, p2f, mid, p2);
00936 }
00937 
00958 trace_t TR_BoxTrace (TR_TILE_TYPE *tile, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, const int headnode, const int brushmask, const int brushreject, const float fraction)
00959 {
00960     vec3_t offset, amins, amaxs, astart, aend;
00961     boxtrace_t traceData;
00962 
00963     checkcount++;   /* for multi-check avoidance */
00964 
00965 #ifdef COMPILE_UFO
00966     if (headnode >= tile->numnodes + 6)
00967         Com_Error(ERR_DROP, "headnode (%i) is out of bounds: %i", headnode, tile->numnodes + 6);
00968 #else
00969     assert(headnode < tile->numnodes + 6); /* +6 => bbox */
00970 #endif
00971 
00972     /* fill in a default trace */
00973     memset(&traceData.trace, 0, sizeof(traceData.trace));
00974     traceData.trace.fraction = min(fraction, 1.0f); /* Use 1 or fraction, whichever is lower. */
00975     traceData.trace.surface = NULL;
00976 
00977     if (!tile->numnodes)        /* map not loaded */
00978         return traceData.trace;
00979 
00980     /* Optimize the trace by moving the line to be traced across into the origin of the box trace. */
00981     /* Calculate the offset needed to center the trace about the line */
00982     VectorCenterFromMinsMaxs(mins, maxs, offset);
00983 
00984     /* Now remove the offset from bmin and bmax (effectively centering the trace box about the origin of the line)
00985      * and add the offset to the trace line (effectively repositioning the trace box at the desired coordinates) */
00986     VectorSubtract(mins, offset, amins);
00987     VectorSubtract(maxs, offset, amaxs);
00988     VectorAdd(start, offset, astart);
00989     VectorAdd(end, offset, aend);
00990 
00991     traceData.contents = brushmask;
00992     traceData.rejects = brushreject;
00993     traceData.tile = tile;
00994     VectorCopy(astart, traceData.start);
00995     VectorCopy(aend, traceData.end);
00996     VectorCopy(amins, traceData.mins);
00997     VectorCopy(amaxs, traceData.maxs);
00998 
00999     /* check for position test special case */
01000     if (VectorCompare(astart, aend)) {
01001         int32_t leafs[MAX_LEAFS];
01002         int numleafs;
01003         int32_t topnode;
01004         int i;
01005 
01006         VectorAdd(astart, amaxs, traceData.absmaxs);
01007         VectorAdd(astart, amins, traceData.absmins);
01008         /* Removed because if creates a buffer- is this needed?
01009         for (i = 0; i < 3; i++) {
01010             / * expand the box by 1 * /
01011             traceData.absmins[i] -= 1;
01012             traceData.absmaxs[i] += 1;
01013         }
01014         */
01015 
01016         numleafs = TR_BoxLeafnums_headnode(&traceData, leafs, MAX_LEAFS, headnode, &topnode);
01017         for (i = 0; i < numleafs; i++) {
01018             TR_TestInLeaf(&traceData, leafs[i]);
01019             if (traceData.trace.allsolid)
01020                 break;
01021         }
01022         VectorCopy(start, traceData.trace.endpos);
01023         return traceData.trace;
01024     }
01025 
01026     /* check for point special case */
01027     if (VectorCompare(amins, vec3_origin) && VectorCompare(amaxs, vec3_origin)) {
01028         traceData.ispoint = qtrue;
01029         VectorClear(traceData.extents);
01030     } else {
01031         traceData.ispoint = qfalse;
01032         VectorCopy(amaxs, traceData.extents);
01033     }
01034 
01035     /* general sweeping through world */
01037     TR_RecursiveHullCheck(&traceData, headnode, 0.0, 1.0, astart, aend);
01038 
01039     if (traceData.trace.fraction >= 1.0) {
01040         VectorCopy(aend, traceData.trace.endpos);
01041     } else {
01042         VectorInterpolation(traceData.start, traceData.end, traceData.trace.fraction, traceData.trace.endpos);
01043     }
01044     /* Now un-offset the end position. */
01045     VectorSubtract(traceData.trace.endpos, offset, traceData.trace.endpos);
01046     return traceData.trace;
01047 }
01048 
01063 trace_t TR_TileBoxTrace (TR_TILE_TYPE *myTile, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, const int levelmask, const int brushmask, const int brushreject)
01064 {
01065     trace_t newtr, tr;
01066     int i;
01067     cBspHead_t *h;
01068 
01069     memset(&tr, 0, sizeof(tr));
01070     /* ensure that the first trace is set in every case */
01071     tr.fraction = 2.0f;
01072 
01073     /* trace against all loaded map tiles */
01074     for (i = 0, h = myTile->cheads; i < myTile->numcheads; i++, h++) {
01075         /* This code uses levelmask to limit by maplevel.  Supposedly maplevels 1-255
01076          * are bitmasks of game levels 1-8.  0 is a special case repeat of 255.
01077          * However a levelmask including 0x100 is usually included so the CLIP levels are
01078          * examined. */
01079         if (h->level && h->level <= LEVEL_LASTVISIBLE && levelmask && !(h->level & levelmask))
01080             continue;
01081 
01082         assert(h->cnode < myTile->numnodes + 6); /* +6 => bbox */
01083         newtr = TR_BoxTrace(myTile, start, end, mins, maxs, h->cnode, brushmask, brushreject, tr.fraction);
01084 
01085         /* memorize the trace with the minimal fraction */
01086         if (newtr.fraction == 0.0)
01087             return newtr;
01088         if (newtr.fraction < tr.fraction)
01089             tr = newtr;
01090     }
01091     return tr;
01092 }
01093 
01094 #ifdef COMPILE_MAP
01095 
01106 trace_t TR_SingleTileBoxTrace (mapTiles_t *mapTiles, const vec3_t start, const vec3_t end, const box_t* traceBox, const int levelmask, const int brushmask, const int brushreject)
01107 {
01108     trace_t tr;
01109     /* Trace the whole line against the first tile. */
01110     tr = TR_TileBoxTrace(&mapTiles->mapTiles[0], start, end, traceBox->mins, traceBox->maxs, levelmask, brushmask, brushreject);
01111     tr.mapTile = 0;
01112     return tr;
01113 }
01114 #endif

Generated by  doxygen 1.6.2