cmodel.c

Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 1997-2001 Id Software, Inc.
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00018 
00019 See the GNU General Public License for more details.
00020 
00021 You should have received a copy of the GNU General Public License
00022 along with this program; if not, write to the Free Software
00023 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00024 
00025 */
00026 
00027 #include "common.h"
00028 #include "grid.h"
00029 #include "tracing.h"
00030 #include "routing.h"
00031 #include "../shared/parse.h"
00032 
00033 /*
00034 ===============================================================================
00035 GAME RELATED TRACING USING ENTITIES
00036 ===============================================================================
00037 */
00038 
00045 static void CM_CalculateBoundingBox (const cBspModel_t* model, vec3_t mins, vec3_t maxs)
00046 {
00047     /* Quickly calculate the bounds of this model to see if they can overlap. */
00048     VectorAdd(model->origin, model->mins, mins);
00049     VectorAdd(model->origin, model->maxs, maxs);
00050     if (VectorNotEmpty(model->angles)) {
00051         vec3_t acenter, aoffset;
00052         const float offset = max(max(fabs(mins[0] - maxs[0]), fabs(mins[1] - maxs[1])), fabs(mins[2] - maxs[2])) / 2.0;
00053         VectorCenterFromMinsMaxs(mins, maxs, acenter);
00054         VectorSet(aoffset, offset, offset, offset);
00055         VectorAdd(acenter, aoffset, maxs);
00056         VectorSubtract(acenter, aoffset, mins);
00057     }
00058 }
00059 
00067 static qboolean CM_LineMissesModel (const vec3_t start, const vec3_t stop, const cBspModel_t *model)
00068 {
00069     vec3_t amins, amaxs;
00070     CM_CalculateBoundingBox(model, amins, amaxs);
00071     /* If the bounds of the extents box and the line do not overlap, then skip tracing this model. */
00072     if ((start[0] > amaxs[0] && stop[0] > amaxs[0])
00073         || (start[1] > amaxs[1] && stop[1] > amaxs[1])
00074         || (start[2] > amaxs[2] && stop[2] > amaxs[2])
00075         || (start[0] < amins[0] && stop[0] < amins[0])
00076         || (start[1] < amins[1] && stop[1] < amins[1])
00077         || (start[2] < amins[2] && stop[2] < amins[2]))
00078         return qtrue;
00079 
00080     return qfalse;
00081 }
00082 
00083 
00100 trace_t CM_HintedTransformedBoxTrace (mapTile_t *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 brushrejects, const vec3_t origin, const vec3_t angles, const vec3_t rmaShift, const float fraction)
00101 {
00102     trace_t trace;
00103     vec3_t start_l, end_l;
00104     vec3_t a;
00105     vec3_t forward, right, up;
00106     vec3_t temp;
00107     qboolean rotated;
00108 
00109     /* subtract origin offset */
00110     VectorSubtract(start, origin, start_l);
00111     VectorSubtract(end, origin, end_l);
00112 
00113     /* rotate start and end into the models frame of reference */
00114     if (headnode != tile->box_headnode && VectorNotEmpty(angles)) {
00115         rotated = qtrue;
00116     } else {
00117         rotated = qfalse;
00118     }
00119 
00120     if (rotated) {
00121         AngleVectors(angles, forward, right, up);
00122 
00123         VectorCopy(start_l, temp);
00124         start_l[0] = DotProduct(temp, forward);
00125         start_l[1] = -DotProduct(temp, right);
00126         start_l[2] = DotProduct(temp, up);
00127 
00128         VectorCopy(end_l, temp);
00129         end_l[0] = DotProduct(temp, forward);
00130         end_l[1] = -DotProduct(temp, right);
00131         end_l[2] = DotProduct(temp, up);
00132     }
00133 
00134     /* When tracing through a model, we want to use the nodes, planes etc. as calculated by ufo2map.
00135      * But nodes and planes have been shifted in case of an RMA. At least for doors we need to undo the shift. */
00136     if (VectorNotEmpty(origin)) {                   /* only doors seem to have their origin set */
00137         VectorAdd(start_l, rmaShift, start_l);      /* undo the shift */
00138         VectorAdd(end_l, rmaShift, end_l);
00139     }
00140 
00141     /* sweep the box through the model */
00142     trace = TR_BoxTrace(tile, start_l, end_l, mins, maxs, headnode, brushmask, brushrejects, fraction);
00143     trace.mapTile = tile->idx;
00144 
00145     if (rotated && trace.fraction != 1.0) {
00147         VectorNegate(angles, a);
00148         AngleVectors(a, forward, right, up);
00149 
00150         VectorCopy(trace.plane.normal, temp);
00151         trace.plane.normal[0] = DotProduct(temp, forward);
00152         trace.plane.normal[1] = -DotProduct(temp, right);
00153         trace.plane.normal[2] = DotProduct(temp, up);
00154     }
00155 
00156     VectorInterpolation(start, end, trace.fraction, trace.endpos);
00157 
00158     return trace;
00159 }
00160 
00165 int32_t CM_HeadnodeForBox (mapTile_t *tile, const vec3_t mins, const vec3_t maxs)
00166 {
00167     tile->box_planes[0].dist = maxs[0];
00168     tile->box_planes[1].dist = -maxs[0];
00169     tile->box_planes[2].dist = mins[0];
00170     tile->box_planes[3].dist = -mins[0];
00171     tile->box_planes[4].dist = maxs[1];
00172     tile->box_planes[5].dist = -maxs[1];
00173     tile->box_planes[6].dist = mins[1];
00174     tile->box_planes[7].dist = -mins[1];
00175     tile->box_planes[8].dist = maxs[2];
00176     tile->box_planes[9].dist = -maxs[2];
00177     tile->box_planes[10].dist = mins[2];
00178     tile->box_planes[11].dist = -mins[2];
00179 
00180     assert(tile->box_headnode < MAX_MAP_NODES);
00181     return tile->box_headnode;
00182 }
00183 
00184 /* TRACING FUNCTIONS */
00185 
00197 qboolean CM_EntTestLine (mapTiles_t *mapTiles, const const vec3_t start, const vec3_t stop, const int levelmask, const char **entlist)
00198 {
00199     trace_t trace;
00200     const char **name;
00201 
00202     /* trace against world first */
00203     if (TR_TestLine(mapTiles, start, stop, levelmask))
00204         /* We hit the world, so we didn't make it anyway... */
00205         return qtrue;
00206 
00207     /* no local models, so we made it. */
00208     if (!entlist)
00209         return qfalse;
00210 
00211     for (name = entlist; *name; name++) {
00212         const cBspModel_t *model;
00213         /* check whether this is really an inline model */
00214         if (*name[0] != '*')
00215             Com_Error(ERR_DROP, "name in the inlineList is no inline model: '%s'", *name);
00216         model = CM_InlineModel(mapTiles, *name);
00217         assert(model);
00218         if (model->headnode >= mapTiles->mapTiles[model->tile].numnodes + 6)
00219             continue;
00220 
00221         /* check if we can safely exclude that the trace can hit the model */
00222         if (CM_LineMissesModel(start, stop, model))
00223             continue;
00224 
00225         trace = CM_HintedTransformedBoxTrace(&mapTiles->mapTiles[model->tile], start, stop, vec3_origin, vec3_origin,
00226                 model->headnode, MASK_VISIBILILITY, 0, model->origin, model->angles, model->shift, 1.0);
00227         /* if we started the trace in a wall */
00228         /* or the trace is not finished */
00229         if (trace.startsolid || trace.fraction < 1.0)
00230             return qtrue;
00231     }
00232 
00233     /* not blocked */
00234     return qfalse;
00235 }
00236 
00246 qboolean CM_EntTestLineDM (mapTiles_t *mapTiles, const vec3_t start, const vec3_t stop, vec3_t end, const int levelmask, const char **entlist)
00247 {
00248     trace_t trace;
00249     const char **name;
00250     int blocked;
00251     float fraction = 2.0f;
00252 
00253     /* trace against world first */
00254     blocked = TR_TestLineDM(mapTiles, start, stop, end, levelmask);
00255     if (!entlist)
00256         return blocked;
00257 
00258     for (name = entlist; *name; name++) {
00259         const cBspModel_t *model;
00260         /* check whether this is really an inline model */
00261         if (*name[0] != '*') {
00262             /* Let's see what the data looks like... */
00263             Com_Error(ERR_DROP, "name in the inlineList is no inline model: '%s' (inlines: %p, name: %p)",
00264                     *name, entlist, name);
00265         }
00266         model = CM_InlineModel(mapTiles, *name);
00267         assert(model);
00268         if (model->headnode >= mapTiles->mapTiles[model->tile].numnodes + 6)
00269             continue;
00270 
00271         /* check if we can safely exclude that the trace can hit the model */
00272         if (CM_LineMissesModel(start, stop, model))
00273             continue;
00274 
00275         trace = CM_HintedTransformedBoxTrace(&mapTiles->mapTiles[model->tile], start, end, vec3_origin, vec3_origin,
00276                 model->headnode, MASK_ALL, 0, model->origin, model->angles, vec3_origin, fraction);
00277         /* if we started the trace in a wall */
00278         if (trace.startsolid) {
00279             VectorCopy(start, end);
00280             return qtrue;
00281         }
00282         /* trace not finishd */
00283         if (trace.fraction < fraction) {
00284             blocked = qtrue;
00285             fraction = trace.fraction;
00286             VectorCopy(trace.endpos, end);
00287         }
00288     }
00289 
00290     /* return result */
00291     return blocked;
00292 }
00293 
00304 trace_t CM_CompleteBoxTrace (mapTiles_t *mapTiles, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, int levelmask, int brushmask, int brushreject)
00305 {
00306     trace_t newtr, tr;
00307     int tile, i;
00308     vec3_t smin, smax, emin, emax, wpmins, wpmaxs;
00309     const vec3_t offset = {UNIT_SIZE / 2, UNIT_SIZE / 2, UNIT_HEIGHT / 2};
00310 
00311     memset(&tr, 0, sizeof(tr));
00312     tr.fraction = 2.0f;
00313 
00314     /* Prep the mins and maxs */
00315     for (i = 0; i < 3; i++) {
00316         smin[i] = start[i] + min(mins[i], maxs[i]);
00317         smax[i] = start[i] + max(mins[i], maxs[i]);
00318         emin[i] = end[i] + min(mins[i], maxs[i]);
00319         emax[i] = end[i] + max(mins[i], maxs[i]);
00320     }
00321 
00322     /* trace against all loaded map tiles */
00323     for (tile = 0; tile < mapTiles->numTiles; tile++) {
00324         mapTile_t *myTile = &mapTiles->mapTiles[tile];
00325         PosToVec(myTile->wpMins, wpmins);
00326         VectorSubtract(wpmins, offset, wpmins);
00327         PosToVec(myTile->wpMaxs, wpmaxs);
00328         VectorAdd(wpmaxs, offset, wpmaxs);
00329         /* If the trace is completely outside of the tile, then skip it. */
00330         if (smax[0] < wpmins[0] && emax[0] < wpmins[0])
00331             continue;
00332         if (smax[1] < wpmins[1] && emax[1] < wpmins[1])
00333             continue;
00334         if (smax[2] < wpmins[2] && emax[2] < wpmins[2])
00335             continue;
00336         if (smin[0] > wpmaxs[0] && emin[0] > wpmaxs[0])
00337             continue;
00338         if (smin[1] > wpmaxs[1] && emin[1] > wpmaxs[1])
00339             continue;
00340         if (smin[2] > wpmaxs[2] && emin[2] > wpmaxs[2])
00341             continue;
00342         newtr = TR_TileBoxTrace(myTile, start, end, mins, maxs, levelmask, brushmask, brushreject);
00343         newtr.mapTile = tile;
00344 
00345         /* memorize the trace with the minimal fraction */
00346         if (newtr.fraction == 0.0)
00347             return newtr;
00348         if (newtr.fraction < tr.fraction)
00349             tr = newtr;
00350     }
00351     return tr;
00352 }
00353 
00354 
00368 trace_t CM_EntCompleteBoxTrace (mapTiles_t *mapTiles, const vec3_t start, const vec3_t end, const box_t* traceBox, int levelmask, int brushmask, int brushreject, const char **list)
00369 {
00370     trace_t trace, newtr;
00371     const char **name;
00372     vec3_t bmins, bmaxs;
00373 
00374     /* trace against world first */
00375     trace = CM_CompleteBoxTrace(mapTiles, start, end, traceBox->mins, traceBox->maxs, levelmask, brushmask, brushreject);
00376     if (!list || trace.fraction == 0.0)
00377         return trace;
00378 
00379     /* Find the original bounding box for the tracing line. */
00380     VectorSet(bmins, min(start[0], end[0]), min(start[1], end[1]), min(start[2], end[2]));
00381     VectorSet(bmaxs, max(start[0], end[0]), max(start[1], end[1]), max(start[2], end[2]));
00382     /* Now increase the bounding box by mins and maxs in both directions. */
00383     VectorAdd(bmins, traceBox->mins, bmins);
00384     VectorAdd(bmaxs, traceBox->maxs, bmaxs);
00385     /* Now bmins and bmaxs specify the whole volume to be traced through. */
00386 
00387     for (name = list; *name; name++) {
00388         vec3_t amins, amaxs;
00389         const cBspModel_t *model;
00390 
00391         /* check whether this is really an inline model */
00392         if (*name[0] != '*')
00393             Com_Error(ERR_DROP, "name in the inlineList is no inline model: '%s'", *name);
00394         model = CM_InlineModel(mapTiles, *name);
00395         assert(model);
00396         if (model->headnode >= mapTiles->mapTiles[model->tile].numnodes + 6)
00397             continue;
00398 
00399         /* Quickly calculate the bounds of this model to see if they can overlap. */
00400         CM_CalculateBoundingBox(model, amins, amaxs);
00401 
00402         /* If the bounds of the extents box and the line do not overlap, then skip tracing this model. */
00403         if (bmins[0] > amaxs[0]
00404          || bmins[1] > amaxs[1]
00405          || bmins[2] > amaxs[2]
00406          || bmaxs[0] < amins[0]
00407          || bmaxs[1] < amins[1]
00408          || bmaxs[2] < amins[2])
00409             continue;
00410 
00411         newtr = CM_HintedTransformedBoxTrace(&mapTiles->mapTiles[model->tile], start, end, traceBox->mins, traceBox->maxs,
00412                 model->headnode, brushmask, brushreject, model->origin, model->angles, model->shift, trace.fraction);
00413 
00414         /* memorize the trace with the minimal fraction */
00415         if (newtr.fraction == 0.0)
00416             return newtr;
00417         if (newtr.fraction < trace.fraction)
00418             trace = newtr;
00419     }
00420     return trace;
00421 }

Generated by  doxygen 1.6.2