00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
00036
00037
00038
00045 static void CM_CalculateBoundingBox (const cBspModel_t* model, vec3_t mins, vec3_t maxs)
00046 {
00047
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
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
00110 VectorSubtract(start, origin, start_l);
00111 VectorSubtract(end, origin, end_l);
00112
00113
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
00135
00136 if (VectorNotEmpty(origin)) {
00137 VectorAdd(start_l, rmaShift, start_l);
00138 VectorAdd(end_l, rmaShift, end_l);
00139 }
00140
00141
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
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
00203 if (TR_TestLine(mapTiles, start, stop, levelmask))
00204
00205 return qtrue;
00206
00207
00208 if (!entlist)
00209 return qfalse;
00210
00211 for (name = entlist; *name; name++) {
00212 const cBspModel_t *model;
00213
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
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
00228
00229 if (trace.startsolid || trace.fraction < 1.0)
00230 return qtrue;
00231 }
00232
00233
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
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
00261 if (*name[0] != '*') {
00262
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
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
00278 if (trace.startsolid) {
00279 VectorCopy(start, end);
00280 return qtrue;
00281 }
00282
00283 if (trace.fraction < fraction) {
00284 blocked = qtrue;
00285 fraction = trace.fraction;
00286 VectorCopy(trace.endpos, end);
00287 }
00288 }
00289
00290
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
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
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
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
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
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
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
00383 VectorAdd(bmins, traceBox->mins, bmins);
00384 VectorAdd(bmaxs, traceBox->maxs, bmaxs);
00385
00386
00387 for (name = list; *name; name++) {
00388 vec3_t amins, amaxs;
00389 const cBspModel_t *model;
00390
00391
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
00400 CM_CalculateBoundingBox(model, amins, amaxs);
00401
00402
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
00415 if (newtr.fraction == 0.0)
00416 return newtr;
00417 if (newtr.fraction < trace.fraction)
00418 trace = newtr;
00419 }
00420 return trace;
00421 }