UFO: Alien Invasion
Loading...
Searching...
No Matches
cmodel.cpp
Go to the documentation of this file.
1
6
7/*
8Copyright (C) 1997-2001 Id Software, Inc.
9
10This program is free software; you can redistribute it and/or
11modify it under the terms of the GNU General Public License
12as published by the Free Software Foundation; either version 2
13of the License, or (at your option) any later version.
14
15This program is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
19See the GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License
22along with this program; if not, write to the Free Software
23Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25*/
26
27#include "common.h"
28#include "tracing.h"
29
30/*
31===============================================================================
32GAME RELATED TRACING USING ENTITIES
33===============================================================================
34*/
35
41static void CM_CalculateWidestBoundingBox (const cBspModel_t* model, AABB& box)
42{
43 /* Quickly calculate the bounds of this model to see if they can overlap. */
44 box.set(model->cbmBox);
45 box.shift(model->origin);
46 if (VectorNotEmpty(model->angles)) {
47 const float offset = std::max(std::max(box.getWidthX(), box.getWidthY()), box.getWidthZ()) / 2.0f;
48 box.expand(offset); /* expand the whole box by the highest extent we found */
49 }
50}
51
58static bool CM_LineMissesModel (const Line& tLine, const cBspModel_t* model)
59{
60 AABB absbox;
61 CM_CalculateWidestBoundingBox(model, absbox);
62 /* If the bounds of the extents box and the line do not overlap, then skip tracing this model. */
63 if (!absbox.canBeHitBy(tLine))
64 return true; /* impossible */
65
66 return false; /* maybe */
67}
68
69
84trace_t CM_HintedTransformedBoxTrace (MapTile& tile, const Line& traceLine, const AABB& traceBox, const int headnode, const int contentmask, const int brushrejects, const vec3_t origin, const vec3_t angles, const vec3_t rmaShift, const float fraction)
85{
86 vec3_t start_l, end_l;
87 vec3_t forward, right, up;
88 vec3_t temp;
89 bool rotated;
90
91 /* subtract origin offset */
92 VectorSubtract(traceLine.start, origin, start_l);
93 VectorSubtract(traceLine.stop, origin, end_l);
94
95 /* rotate start and end into the models frame of reference */
96 if (headnode != tile.box_headnode && VectorNotEmpty(angles)) {
97 rotated = true;
98 } else {
99 rotated = false;
100 }
101
102 if (rotated) {
103 AngleVectors(angles, forward, right, up);
104
105 VectorCopy(start_l, temp);
106 start_l[0] = DotProduct(temp, forward);
107 start_l[1] = -DotProduct(temp, right);
108 start_l[2] = DotProduct(temp, up);
109
110 VectorCopy(end_l, temp);
111 end_l[0] = DotProduct(temp, forward);
112 end_l[1] = -DotProduct(temp, right);
113 end_l[2] = DotProduct(temp, up);
114 }
115
116 /* When tracing through a model, we want to use the nodes, planes etc. as calculated by ufo2map.
117 * But nodes and planes have been shifted in case of an RMA. At least for doors we need to undo the shift. */
118 if (VectorNotEmpty(origin)) { /* only doors seem to have their origin set */
119 VectorAdd(start_l, rmaShift, start_l); /* undo the shift */
120 VectorAdd(end_l, rmaShift, end_l);
121 }
122
123 /* sweep the box through the model */
124 boxtrace_t traceData;
125 traceData.init(&tile, contentmask, brushrejects, fraction);
126 traceData.setLineAndBox(Line(start_l, end_l), traceBox);
127 trace_t trace = TR_BoxTrace(traceData, Line(start_l, end_l), traceBox, headnode, fraction);
128 trace.mapTile = tile.idx;
129
130 if (rotated && trace.fraction != 1.0f) {
131 vec3_t a;
133 VectorNegate(angles, a);
134 AngleVectors(a, forward, right, up);
135
136 VectorCopy(trace.plane.normal, temp);
137 trace.plane.normal[0] = DotProduct(temp, forward);
138 trace.plane.normal[1] = -DotProduct(temp, right);
139 trace.plane.normal[2] = DotProduct(temp, up);
140 }
141
142 VectorInterpolation(traceLine.start, traceLine.stop, trace.fraction, trace.endpos);
143
144 return trace;
145}
146
151int32_t CM_HeadnodeForBox (MapTile& tile, const AABB& box)
152{
153 tile.box_planes[0].dist = box.maxs[0];
154 tile.box_planes[1].dist = -box.maxs[0];
155 tile.box_planes[2].dist = box.mins[0];
156 tile.box_planes[3].dist = -box.mins[0];
157 tile.box_planes[4].dist = box.maxs[1];
158 tile.box_planes[5].dist = -box.maxs[1];
159 tile.box_planes[6].dist = box.mins[1];
160 tile.box_planes[7].dist = -box.mins[1];
161 tile.box_planes[8].dist = box.maxs[2];
162 tile.box_planes[9].dist = -box.maxs[2];
163 tile.box_planes[10].dist = box.mins[2];
164 tile.box_planes[11].dist = -box.mins[2];
165
166 assert(tile.box_headnode < MAX_MAP_NODES);
167 return tile.box_headnode;
168}
169
170/* TRACING FUNCTIONS */
171
184bool CM_EntTestLine (mapTiles_t* mapTiles, const Line& traceLine, const int levelmask, const char** entlist)
185{
186 /* trace against world first */
187 if (TR_TestLine(mapTiles, traceLine.start, traceLine.stop, levelmask))
188 /* We hit the world, so we didn't make it anyway... */
189 return true;
190
191 /* no local models, so we made it. */
192 if (!entlist)
193 return false;
194
195 for (const char** name = entlist; *name; name++) {
196 /* check whether this is really an inline model */
197 if (*name[0] != '*')
198 Com_Error(ERR_DROP, "name in the inlineList is no inline model: '%s'", *name);
199 const cBspModel_t* model = CM_InlineModel(mapTiles, *name);
200 assert(model);
201 if (model->headnode >= mapTiles->mapTiles[model->tile].numnodes + 6)
202 continue;
203
204 /* check if we can safely exclude that the trace can hit the model */
205 if (CM_LineMissesModel(traceLine, model))
206 continue;
207
208 const trace_t trace = CM_HintedTransformedBoxTrace(mapTiles->mapTiles[model->tile], traceLine, AABB(),
209 model->headnode, MASK_VISIBILILITY, 0, model->origin, model->angles, model->shift, 1.0f);
210 /* if we started the trace in a wall */
211 /* or the trace is not finished */
212 if (trace.startsolid || trace.fraction < 1.0f)
213 return true;
214 }
215
216 /* not blocked */
217 return false;
218}
219
230bool CM_EntTestLineDM (mapTiles_t* mapTiles, const Line& trLine, vec3_t hit, const int levelmask, const char** entlist)
231{
232 float fraction = 2.0f;
233
234 /* trace against world first */
235 bool blocked = TR_TestLineDM(mapTiles, trLine.start, trLine.stop, hit, levelmask);
236 if (!entlist)
237 return blocked;
238
239 for (const char** name = entlist; *name; name++) {
240 /* check whether this is really an inline model */
241 if (*name[0] != '*') {
242 /* Let's see what the data looks like... */
243 Com_Error(ERR_DROP, "name in the inlineList is no inline model: '%s' (inlines: %p, name: %p)",
244 *name, (void*)entlist, (void*)name);
245 }
246 const cBspModel_t* model = CM_InlineModel(mapTiles, *name);
247 assert(model);
248 if (model->headnode >= mapTiles->mapTiles[model->tile].numnodes + 6)
249 continue;
250
251 /* check if we can safely exclude that the trace can hit the model */
252 if (CM_LineMissesModel(trLine, model))
253 continue;
254
255 const trace_t trace = CM_HintedTransformedBoxTrace(mapTiles->mapTiles[model->tile], Line(trLine.start, hit), AABB(),
256 model->headnode, MASK_ALL, 0, model->origin, model->angles, vec3_origin, fraction);
257 /* if we started the trace in a wall */
258 if (trace.startsolid) {
259 VectorCopy(trLine.start, hit);
260 return true;
261 }
262 /* trace not finished */
263 if (trace.fraction < fraction) {
264 blocked = true;
265 fraction = trace.fraction;
266 VectorCopy(trace.endpos, hit);
267 }
268 }
269
270 /* return result */
271 return blocked;
272}
273
283trace_t CM_CompleteBoxTrace (mapTiles_t* mapTiles, const Line& trLine, const AABB& box, int levelmask, int brushmask, int brushreject)
284{
285 trace_t tr;
286 tr.fraction = 2.0f;
287 VectorCopy(trLine.stop, tr.endpos); /* optimistically set the endpos just in case we are outside of ALL the tiles, so TR_TileBoxTrace won't do it */
288
289 /* create a box that covers the whole volume of the trace */
290 AABB moveBox;
291 moveBox.set(box, trLine);
292
293 /* trace against all loaded map tiles */
294 for (int tile = 0; tile < mapTiles->numTiles; tile++) {
295 MapTile& myTile = mapTiles->mapTiles[tile];
296 AABB tileBox;
297 myTile.getTileBox(tileBox);
298 /* If the trace is completely outside of the tile, then skip it. */
299 if (!moveBox.doesIntersect(tileBox))
300 continue;
301 trace_t newtr = TR_TileBoxTrace(&myTile, trLine, box, levelmask, brushmask, brushreject);
302 newtr.mapTile = tile;
303
304 /* memorize the trace with the minimal fraction */
305 if (newtr.fraction == 0.0f)
306 return newtr;
307 if (newtr.fraction < tr.fraction)
308 tr = newtr;
309 }
310 return tr;
311}
312
313
327trace_t CM_EntCompleteBoxTrace (mapTiles_t* mapTiles, const Line& traceLine, const AABB* traceBox, int levelmask, int brushmask, int brushreject, const char** list)
328{
329 AABB lineBox;
330 lineBox.set(*traceBox, traceLine);
331 /* Now lineBox specifies the whole volume involved in the trace. */
332
333 /* reconstruct a levelmask */
334 const vec_t minZ = lineBox.getMinZ();
335 const vec_t maxZ = lineBox.getMaxZ();
336 int newLevelMask = 0;
337 if (levelmask & TL_FLAG_ACTORCLIP) /* if the passed levelmask contains the bit for the cliplevels, */
338 newLevelMask = TL_FLAG_ACTORCLIP; /* preserve it */
339 for (int i = 0; i < PATHFINDING_HEIGHT; i++) {
340 const vec_t lower = i * UNIT_HEIGHT; /* the height bounds of the level */
341 const vec_t upper = (i + 1) * UNIT_HEIGHT;
342 if (minZ > upper || maxZ < lower)
343 continue;
344 newLevelMask |= (1 << i);
345 }
346
347 /* trace against world first */
348 const trace_t tr = CM_CompleteBoxTrace(mapTiles, traceLine, *traceBox, newLevelMask, brushmask, brushreject);
349 if (!list || tr.fraction == 0.0f)
350 return tr;
351
352 trace_t trace = tr;
353 for (const char** name = list; *name; name++) {
354 /* check whether this is really an inline model */
355 if (*name[0] != '*')
356 Com_Error(ERR_DROP, "name in the inlineList is no inline model: '%s'", *name);
357 const cBspModel_t* model = CM_InlineModel(mapTiles, *name);
358 assert(model);
359 if (model->headnode >= mapTiles->mapTiles[model->tile].numnodes + 6)
360 continue;
361
362 AABB modelBox;
363 /* Quickly calculate the bounds of this model to see if they can overlap. */
364 CM_CalculateWidestBoundingBox(model, modelBox);
365
366 /* If the bounds of the extents box and the line do not overlap, then skip tracing this model. */
367 if (!lineBox.doesIntersect(modelBox))
368 continue;
369
370 const trace_t newtr = CM_HintedTransformedBoxTrace(mapTiles->mapTiles[model->tile], traceLine, *traceBox,
371 model->headnode, brushmask, brushreject, model->origin, model->angles, model->shift, trace.fraction);
372
373 /* memorize the trace with the minimal fraction */
374 if (newtr.fraction == 0.0f)
375 return newtr;
376 if (newtr.fraction < trace.fraction)
377 trace = newtr;
378 }
379 return trace;
380}
Definition aabb.h:42
float getWidthY() const
Definition aabb.h:144
float getMaxZ() const
Definition aabb.h:137
vec3_t maxs
Definition aabb.h:258
float getWidthX() const
Definition aabb.h:141
vec3_t mins
Definition aabb.h:257
bool canBeHitBy(const Line &line) const
Checks if the given line has a chance to hit our box.
Definition aabb.h:192
float getMinZ() const
Definition aabb.h:125
void set(const AABB &other)
Copies the values from the given aabb.
Definition aabb.h:60
void shift(const vec3_t shiftVec)
shove the whole box by the given vector
Definition aabb.h:246
float getWidthZ() const
Definition aabb.h:147
void expand(const float byVal)
expand the box in all directions, but clip them to the maximum boundaries
Definition aabb.h:240
bool doesIntersect(const AABB &other) const
Checks if the aabb touches or intersects with the given aabb.
Definition aabb.h:183
Definition line.h:31
vec3_t start
Definition line.h:54
vec3_t stop
Definition line.h:55
Stores the data of a map tile, mostly the BSP stuff.
Definition typedefs.h:85
int box_headnode
Definition typedefs.h:117
int idx
Definition typedefs.h:88
cBspPlane_t * box_planes
Definition typedefs.h:116
void getTileBox(AABB &box)
Calculate the bounding box for the tile (in mapunits).
Definition typedefs.h:137
bool CM_EntTestLine(mapTiles_t *mapTiles, const Line &traceLine, const int levelmask, const char **entlist)
Checks traces against the world and all inline models.
Definition cmodel.cpp:184
trace_t CM_HintedTransformedBoxTrace(MapTile &tile, const Line &traceLine, const AABB &traceBox, const int headnode, const int contentmask, const int brushrejects, const vec3_t origin, const vec3_t angles, const vec3_t rmaShift, const float fraction)
Handles offseting and rotation of the end points for moving and rotating entities.
Definition cmodel.cpp:84
bool CM_EntTestLineDM(mapTiles_t *mapTiles, const Line &trLine, vec3_t hit, const int levelmask, const char **entlist)
Checks traces against the world and all inline models, gives the hit position back.
Definition cmodel.cpp:230
trace_t CM_CompleteBoxTrace(mapTiles_t *mapTiles, const Line &trLine, const AABB &box, int levelmask, int brushmask, int brushreject)
Traces all submodels in all tiles. Used by ufo and ufo_ded.
Definition cmodel.cpp:283
static void CM_CalculateWidestBoundingBox(const cBspModel_t *model, AABB &box)
Calculates the worst case bounding box for the given bsp model.
Definition cmodel.cpp:41
int32_t CM_HeadnodeForBox(MapTile &tile, const AABB &box)
To keep everything totally uniform, bounding boxes are turned into small BSP trees instead of being c...
Definition cmodel.cpp:151
trace_t CM_EntCompleteBoxTrace(mapTiles_t *mapTiles, const Line &traceLine, const AABB *traceBox, int levelmask, int brushmask, int brushreject, const char **list)
Performs box traces against the world and all inline models, gives the hit position back.
Definition cmodel.cpp:327
static bool CM_LineMissesModel(const Line &tLine, const cBspModel_t *model)
A quick test if the trace might hit the inline model.
Definition cmodel.cpp:58
cBspModel_t * CM_InlineModel(const mapTiles_t *mapTiles, const char *name)
Searches all inline models and return the cBspModel_t pointer for the given modelnumber or -name.
Definition bsp.cpp:929
void Com_Error(int code, const char *fmt,...)
Definition common.cpp:459
definitions common between client and server, but not game lib
#define ERR_DROP
Definition common.h:211
static transfer_t tr
#define TL_FLAG_ACTORCLIP
Definition defines.h:359
#define MASK_ALL
Definition defines.h:271
#define UNIT_HEIGHT
Definition defines.h:122
#define MAX_MAP_NODES
Definition defines.h:140
#define MASK_VISIBILILITY
Definition defines.h:277
#define PATHFINDING_HEIGHT
15 max, adjusting above 8 will require a rewrite to the DV code
Definition defines.h:294
voidpf uLong int origin
Definition ioapi.h:45
voidpf uLong offset
Definition ioapi.h:45
const vec3_t vec3_origin
Definition mathlib.cpp:35
void AngleVectors(const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
Create the rotation matrix in order to rotate something.
Definition mathlib.cpp:631
QGL_EXTERN GLint i
Definition r_gl.h:113
QGL_EXTERN GLuint GLsizei GLsizei GLint GLenum GLchar * name
Definition r_gl.h:110
void setLineAndBox(const Line &line, const AABB &box)
void init(TR_TILE_TYPE *_tile, const int contentmask, const int brushreject, const float fraction)
int32_t headnode
Definition typedefs.h:29
vec3_t shift
Definition typedefs.h:28
vec3_t angles
Definition typedefs.h:28
AABB cbmBox
Definition typedefs.h:27
vec3_t origin
Definition typedefs.h:28
float dist
Definition typedefs.h:22
vec3_t endpos
Definition tracing.h:59
float fraction
Definition tracing.h:58
TR_PLANE_TYPE plane
Definition tracing.h:60
bool startsolid
Definition tracing.h:57
int mapTile
Definition tracing.h:65
static mapTiles_t mapTiles
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
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
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
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
Tracing functions.
float vec_t
Definition ufotypes.h:37
vec_t vec3_t[3]
Definition ufotypes.h:39
#define VectorNegate(src, dest)
Definition vector.h:58
#define VectorNotEmpty(a)
Definition vector.h:72
#define VectorInterpolation(p1, p2, frac, mid)
Definition vector.h:80
#define VectorSubtract(a, b, dest)
Definition vector.h:45
#define VectorCopy(src, dest)
Definition vector.h:51
#define VectorAdd(a, b, dest)
Definition vector.h:47
#define DotProduct(x, y)
Returns the distance between two 3-dimensional vectors.
Definition vector.h:44