Quake II RTX doxygen  1.0 dev
world.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 // world.c -- world query functions
19 
20 #include "server.h"
21 
22 /*
23 ===============================================================================
24 
25 ENTITY AREA CHECKING
26 
27 FIXME: this use of "area" is different from the bsp file use
28 ===============================================================================
29 */
30 
31 typedef struct areanode_s {
32  int axis; // -1 = leaf node
33  float dist;
34  struct areanode_s *children[2];
36  list_t solid_edicts;
37 } areanode_t;
38 
39 #define AREA_DEPTH 4
40 #define AREA_NODES 32
41 
43 static int sv_numareanodes;
44 
45 static float *area_mins, *area_maxs;
46 static edict_t **area_list;
48 static int area_type;
49 
50 /*
51 ===============
52 SV_CreateAreaNode
53 
54 Builds a uniformly subdivided tree for the given world size
55 ===============
56 */
57 static areanode_t *SV_CreateAreaNode(int depth, vec3_t mins, vec3_t maxs)
58 {
59  areanode_t *anode;
60  vec3_t size;
61  vec3_t mins1, maxs1, mins2, maxs2;
62 
63  anode = &sv_areanodes[sv_numareanodes];
65 
66  List_Init(&anode->trigger_edicts);
67  List_Init(&anode->solid_edicts);
68 
69  if (depth == AREA_DEPTH) {
70  anode->axis = -1;
71  anode->children[0] = anode->children[1] = NULL;
72  return anode;
73  }
74 
75  VectorSubtract(maxs, mins, size);
76  if (size[0] > size[1])
77  anode->axis = 0;
78  else
79  anode->axis = 1;
80 
81  anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);
82  VectorCopy(mins, mins1);
83  VectorCopy(mins, mins2);
84  VectorCopy(maxs, maxs1);
85  VectorCopy(maxs, maxs2);
86 
87  maxs1[anode->axis] = mins2[anode->axis] = anode->dist;
88 
89  anode->children[0] = SV_CreateAreaNode(depth + 1, mins2, maxs2);
90  anode->children[1] = SV_CreateAreaNode(depth + 1, mins1, maxs1);
91 
92  return anode;
93 }
94 
95 /*
96 ===============
97 SV_ClearWorld
98 
99 ===============
100 */
101 void SV_ClearWorld(void)
102 {
103  mmodel_t *cm;
104  edict_t *ent;
105  int i;
106 
107  memset(sv_areanodes, 0, sizeof(sv_areanodes));
108  sv_numareanodes = 0;
109 
110  if (sv.cm.cache) {
111  cm = &sv.cm.cache->models[0];
112  SV_CreateAreaNode(0, cm->mins, cm->maxs);
113  }
114 
115  // make sure all entities are unlinked
116  for (i = 0; i < ge->max_edicts; i++) {
117  ent = EDICT_NUM(i);
118  ent->area.prev = ent->area.next = NULL;
119  }
120 }
121 
122 /*
123 ===============
124 SV_EdictIsVisible
125 
126 Checks if edict is potentially visible from the given PVS row.
127 ===============
128 */
129 qboolean SV_EdictIsVisible(cm_t *cm, edict_t *ent, byte *mask)
130 {
131  int i;
132 
133  if (ent->num_clusters == -1) {
134  // too many leafs for individual check, go by headnode
135  return CM_HeadnodeVisible(CM_NodeNum(cm, ent->headnode), mask);
136  }
137 
138  // check individual leafs
139  for (i = 0; i < ent->num_clusters; i++) {
140  if (Q_IsBitSet(mask, ent->clusternums[i])) {
141  return qtrue;
142  }
143  }
144 
145  return qfalse; // not visible
146 }
147 
148 /*
149 ===============
150 SV_LinkEdict
151 
152 General purpose routine shared between game DLL and MVD code.
153 Links entity to PVS leafs.
154 ===============
155 */
156 void SV_LinkEdict(cm_t *cm, edict_t *ent)
157 {
158  mleaf_t *leafs[MAX_TOTAL_ENT_LEAFS];
159  int clusters[MAX_TOTAL_ENT_LEAFS];
160  int num_leafs;
161  int i, j;
162  int area;
163  mnode_t *topnode;
164 
165  // set the size
166  VectorSubtract(ent->maxs, ent->mins, ent->size);
167 
168  // set the abs box
169  if (ent->solid == SOLID_BSP &&
170  (ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2])) {
171  // expand for rotation
172  float max, v;
173  int i;
174 
175  max = 0;
176  for (i = 0; i < 3; i++) {
177  v = Q_fabs(ent->mins[i]);
178  if (v > max)
179  max = v;
180  v = Q_fabs(ent->maxs[i]);
181  if (v > max)
182  max = v;
183  }
184  for (i = 0; i < 3; i++) {
185  ent->absmin[i] = ent->s.origin[i] - max;
186  ent->absmax[i] = ent->s.origin[i] + max;
187  }
188  } else {
189  // normal
190  VectorAdd(ent->s.origin, ent->mins, ent->absmin);
191  VectorAdd(ent->s.origin, ent->maxs, ent->absmax);
192  }
193 
194  // because movement is clipped an epsilon away from an actual edge,
195  // we must fully check even when bounding boxes don't quite touch
196  ent->absmin[0] -= 1;
197  ent->absmin[1] -= 1;
198  ent->absmin[2] -= 1;
199  ent->absmax[0] += 1;
200  ent->absmax[1] += 1;
201  ent->absmax[2] += 1;
202 
203 // link to PVS leafs
204  ent->num_clusters = 0;
205  ent->areanum = 0;
206  ent->areanum2 = 0;
207 
208  //get all leafs, including solids
209  num_leafs = CM_BoxLeafs(cm, ent->absmin, ent->absmax,
210  leafs, MAX_TOTAL_ENT_LEAFS, &topnode);
211 
212  // set areas
213  for (i = 0; i < num_leafs; i++) {
214  clusters[i] = CM_LeafCluster(leafs[i]);
215  area = CM_LeafArea(leafs[i]);
216  if (area) {
217  // doors may legally straggle two areas,
218  // but nothing should evern need more than that
219  if (ent->areanum && ent->areanum != area) {
220  if (ent->areanum2 && ent->areanum2 != area && sv.state == ss_loading) {
221  Com_DPrintf("Object touching 3 areas at %f %f %f\n",
222  ent->absmin[0], ent->absmin[1], ent->absmin[2]);
223  }
224  ent->areanum2 = area;
225  } else
226  ent->areanum = area;
227  }
228  }
229 
230  if (num_leafs >= MAX_TOTAL_ENT_LEAFS) {
231  // assume we missed some leafs, and mark by headnode
232  ent->num_clusters = -1;
233  ent->headnode = CM_NumNode(cm, topnode);
234  } else {
235  ent->num_clusters = 0;
236  for (i = 0; i < num_leafs; i++) {
237  if (clusters[i] == -1)
238  continue; // not a visible leaf
239  for (j = 0; j < i; j++)
240  if (clusters[j] == clusters[i])
241  break;
242  if (j == i) {
243  if (ent->num_clusters == MAX_ENT_CLUSTERS) {
244  // assume we missed some leafs, and mark by headnode
245  ent->num_clusters = -1;
246  ent->headnode = CM_NumNode(cm, topnode);
247  break;
248  }
249 
250  ent->clusternums[ent->num_clusters++] = clusters[i];
251  }
252  }
253  }
254 }
255 
256 void PF_UnlinkEdict(edict_t *ent)
257 {
258  if (!ent->area.prev)
259  return; // not linked in anywhere
260  List_Remove(&ent->area);
261  ent->area.prev = ent->area.next = NULL;
262 }
263 
264 void PF_LinkEdict(edict_t *ent)
265 {
266  areanode_t *node;
267  server_entity_t *sent;
268  int entnum;
269 #if USE_FPS
270  int i;
271 #endif
272 
273  if (ent->area.prev)
274  PF_UnlinkEdict(ent); // unlink from old position
275 
276  if (ent == ge->edicts)
277  return; // don't add the world
278 
279  if (!ent->inuse) {
280  Com_DPrintf("%s: entity %d is not in use\n", __func__, NUM_FOR_EDICT(ent));
281  return;
282  }
283 
284  if (!sv.cm.cache) {
285  return;
286  }
287 
288  entnum = NUM_FOR_EDICT(ent);
289  sent = &sv.entities[entnum];
290 
291  // encode the size into the entity_state for client prediction
292  switch (ent->solid) {
293  case SOLID_BBOX:
294  if ((ent->svflags & SVF_DEADMONSTER) || VectorCompare(ent->mins, ent->maxs)) {
295  ent->s.solid = 0;
296  sent->solid32 = 0;
297  } else {
298  ent->s.solid = MSG_PackSolid16(ent->mins, ent->maxs);
299  sent->solid32 = MSG_PackSolid32(ent->mins, ent->maxs);
300  }
301  break;
302  case SOLID_BSP:
303  ent->s.solid = PACKED_BSP; // a SOLID_BBOX will never create this value
304  sent->solid32 = PACKED_BSP; // FIXME: use 255?
305  break;
306  default:
307  ent->s.solid = 0;
308  sent->solid32 = 0;
309  break;
310  }
311 
312  SV_LinkEdict(&sv.cm, ent);
313 
314  // if first time, make sure old_origin is valid
315  if (!ent->linkcount) {
316  VectorCopy(ent->s.origin, ent->s.old_origin);
317 #if USE_FPS
318  VectorCopy(ent->s.origin, sent->create_origin);
319  sent->create_framenum = sv.framenum;
320 #endif
321  }
322  ent->linkcount++;
323 
324 #if USE_FPS
325  // save origin for later recovery
326  i = sv.framenum & ENT_HISTORY_MASK;
327  VectorCopy(ent->s.origin, sent->history[i].origin);
328  sent->history[i].framenum = sv.framenum;
329 #endif
330 
331  if (ent->solid == SOLID_NOT)
332  return;
333 
334 // find the first node that the ent's box crosses
335  node = sv_areanodes;
336  while (1) {
337  if (node->axis == -1)
338  break;
339  if (ent->absmin[node->axis] > node->dist)
340  node = node->children[0];
341  else if (ent->absmax[node->axis] < node->dist)
342  node = node->children[1];
343  else
344  break; // crosses the node
345  }
346 
347  // link it in
348  if (ent->solid == SOLID_TRIGGER)
349  List_Append(&node->trigger_edicts, &ent->area);
350  else
351  List_Append(&node->solid_edicts, &ent->area);
352 }
353 
354 
355 /*
356 ====================
357 SV_AreaEdicts_r
358 
359 ====================
360 */
361 static void SV_AreaEdicts_r(areanode_t *node)
362 {
363  list_t *start;
364  edict_t *check;
365 
366  // touch linked edicts
367  if (area_type == AREA_SOLID)
368  start = &node->solid_edicts;
369  else
370  start = &node->trigger_edicts;
371 
372  LIST_FOR_EACH(edict_t, check, start, area) {
373  if (check->solid == SOLID_NOT)
374  continue; // deactivated
375  if (check->absmin[0] > area_maxs[0]
376  || check->absmin[1] > area_maxs[1]
377  || check->absmin[2] > area_maxs[2]
378  || check->absmax[0] < area_mins[0]
379  || check->absmax[1] < area_mins[1]
380  || check->absmax[2] < area_mins[2])
381  continue; // not touching
382 
383  if (area_count == area_maxcount) {
384  Com_WPrintf("SV_AreaEdicts: MAXCOUNT\n");
385  return;
386  }
387 
388  area_list[area_count] = check;
389  area_count++;
390  }
391 
392  if (node->axis == -1)
393  return; // terminal node
394 
395  // recurse down both sides
396  if (area_maxs[node->axis] > node->dist)
397  SV_AreaEdicts_r(node->children[0]);
398  if (area_mins[node->axis] < node->dist)
399  SV_AreaEdicts_r(node->children[1]);
400 }
401 
402 /*
403 ================
404 SV_AreaEdicts
405 ================
406 */
407 int SV_AreaEdicts(vec3_t mins, vec3_t maxs, edict_t **list,
408  int maxcount, int areatype)
409 {
410  area_mins = mins;
411  area_maxs = maxs;
412  area_list = list;
413  area_count = 0;
414  area_maxcount = maxcount;
415  area_type = areatype;
416 
418 
419  return area_count;
420 }
421 
422 
423 //===========================================================================
424 
425 /*
426 ================
427 SV_HullForEntity
428 
429 Returns a headnode that can be used for testing or clipping an
430 object of mins/maxs size.
431 ================
432 */
433 static mnode_t *SV_HullForEntity(edict_t *ent)
434 {
435  if (ent->solid == SOLID_BSP) {
436  int i = ent->s.modelindex - 1;
437 
438  // explicit hulls in the BSP model
439  if (i <= 0 || i >= sv.cm.cache->nummodels)
440  Com_Error(ERR_DROP, "%s: inline model %d out of range", __func__, i);
441 
442  return sv.cm.cache->models[i].headnode;
443  }
444 
445  // create a temp hull from bounding box sizes
446  return CM_HeadnodeForBox(ent->mins, ent->maxs);
447 }
448 
449 /*
450 =============
451 SV_PointContents
452 =============
453 */
454 int SV_PointContents(vec3_t p)
455 {
456  edict_t *touch[MAX_EDICTS], *hit;
457  int i, num;
458  int contents;
459 
460  if (!sv.cm.cache) {
461  Com_Error(ERR_DROP, "%s: no map loaded", __func__);
462  }
463 
464  // get base contents from world
465  contents = CM_PointContents(p, sv.cm.cache->nodes);
466 
467  // or in contents from all the other entities
468  num = SV_AreaEdicts(p, p, touch, MAX_EDICTS, AREA_SOLID);
469 
470  for (i = 0; i < num; i++) {
471  hit = touch[i];
472 
473  // might intersect, so do an exact clip
474  contents |= CM_TransformedPointContents(p, SV_HullForEntity(hit),
475  hit->s.origin, hit->s.angles);
476  }
477 
478  return contents;
479 }
480 
481 /*
482 ====================
483 SV_ClipMoveToEntities
484 
485 ====================
486 */
487 static void SV_ClipMoveToEntities(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end,
488  edict_t *passedict, int contentmask, trace_t *tr)
489 {
490  vec3_t boxmins, boxmaxs;
491  int i, num;
492  edict_t *touchlist[MAX_EDICTS], *touch;
493  trace_t trace;
494 
495  // create the bounding box of the entire move
496  for (i = 0; i < 3; i++) {
497  if (end[i] > start[i]) {
498  boxmins[i] = start[i] + mins[i] - 1;
499  boxmaxs[i] = end[i] + maxs[i] + 1;
500  } else {
501  boxmins[i] = end[i] + mins[i] - 1;
502  boxmaxs[i] = start[i] + maxs[i] + 1;
503  }
504  }
505 
506  num = SV_AreaEdicts(boxmins, boxmaxs, touchlist, MAX_EDICTS, AREA_SOLID);
507 
508  // be careful, it is possible to have an entity in this
509  // list removed before we get to it (killtriggered)
510  for (i = 0; i < num; i++) {
511  touch = touchlist[i];
512  if (touch->solid == SOLID_NOT)
513  continue;
514  if (touch == passedict)
515  continue;
516  if (tr->allsolid)
517  return;
518  if (passedict) {
519  if (touch->owner == passedict)
520  continue; // don't clip against own missiles
521  if (passedict->owner == touch)
522  continue; // don't clip against owner
523  }
524 
525  if (!(contentmask & CONTENTS_DEADMONSTER)
526  && (touch->svflags & SVF_DEADMONSTER))
527  continue;
528 
529  // might intersect, so do an exact clip
530  CM_TransformedBoxTrace(&trace, start, end, mins, maxs,
531  SV_HullForEntity(touch), contentmask,
532  touch->s.origin, touch->s.angles);
533 
534  CM_ClipEntity(tr, &trace, touch);
535  }
536 }
537 
538 /*
539 ==================
540 SV_Trace
541 
542 Moves the given mins/maxs volume through the world from start to end.
543 Passedict and edicts owned by passedict are explicitly not checked.
544 ==================
545 */
546 trace_t q_gameabi SV_Trace(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end,
547  edict_t *passedict, int contentmask)
548 {
549  trace_t trace;
550 
551  if (!sv.cm.cache) {
552  Com_Error(ERR_DROP, "%s: no map loaded", __func__);
553  }
554 
555  // work around game bugs
556  if (++sv.tracecount > 10000) {
557  Com_EPrintf("%s: runaway loop avoided\n", __func__);
558  memset(&trace, 0, sizeof(trace));
559  trace.fraction = 1;
560  trace.ent = ge->edicts;
561  VectorCopy(end, trace.endpos);
562  sv.tracecount = 0;
563  return trace;
564  }
565 
566  if (!mins)
567  mins = vec3_origin;
568  if (!maxs)
569  maxs = vec3_origin;
570 
571  // clip to world
572  CM_BoxTrace(&trace, start, end, mins, maxs, sv.cm.cache->nodes, contentmask);
573  trace.ent = ge->edicts;
574  if (trace.fraction == 0) {
575  return trace; // blocked by the world
576  }
577 
578  // clip to other solid entities
579  SV_ClipMoveToEntities(start, mins, maxs, end, passedict, contentmask, &trace);
580  return trace;
581 }
582 
server_t::framenum
int framenum
Definition: server.h:155
SV_ClipMoveToEntities
static void SV_ClipMoveToEntities(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask, trace_t *tr)
Definition: world.c:487
CM_BoxTrace
void CM_BoxTrace(trace_t *trace, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, mnode_t *headnode, int brushmask)
Definition: cmodel.c:683
area_mins
static float * area_mins
Definition: world.c:45
sv_numareanodes
static int sv_numareanodes
Definition: world.c:43
SV_LinkEdict
void SV_LinkEdict(cm_t *cm, edict_t *ent)
Definition: world.c:156
CM_HeadnodeVisible
qboolean CM_HeadnodeVisible(mnode_t *node, byte *visbits)
Definition: cmodel.c:1016
PF_LinkEdict
void PF_LinkEdict(edict_t *ent)
Definition: world.c:264
SV_CreateAreaNode
static areanode_t * SV_CreateAreaNode(int depth, vec3_t mins, vec3_t maxs)
Definition: world.c:57
server_t::tracecount
unsigned tracecount
Definition: server.h:168
area_list
static edict_t ** area_list
Definition: world.c:46
CM_HeadnodeForBox
mnode_t * CM_HeadnodeForBox(vec3_t mins, vec3_t maxs)
Definition: cmodel.c:190
area_type
static int area_type
Definition: world.c:48
SV_ClearWorld
void SV_ClearWorld(void)
Definition: world.c:101
PF_UnlinkEdict
void PF_UnlinkEdict(edict_t *ent)
Definition: world.c:256
CM_BoxLeafs
int CM_BoxLeafs(cm_t *cm, vec3_t mins, vec3_t maxs, mleaf_t **list, int listsize, mnode_t **topnode)
Definition: cmodel.c:273
area_maxcount
static int area_maxcount
Definition: world.c:47
server_entity_t::solid32
int solid32
Definition: server.h:112
areanode_s::solid_edicts
list_t solid_edicts
Definition: world.c:36
vec3_origin
vec3_t vec3_origin
Definition: shared.c:21
SV_HullForEntity
static mnode_t * SV_HullForEntity(edict_t *ent)
Definition: world.c:433
areanode_s::trigger_edicts
list_t trigger_edicts
Definition: world.c:35
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
NUM_FOR_EDICT
#define NUM_FOR_EDICT(e)
Definition: server.h:174
sv
server_t sv
Definition: init.c:22
CM_ClipEntity
void CM_ClipEntity(trace_t *dst, const trace_t *src, struct edict_s *ent)
Definition: cmodel.c:804
area_maxs
static float * area_maxs
Definition: world.c:45
SV_PointContents
int SV_PointContents(vec3_t p)
Definition: world.c:454
areanode_s
Definition: world.c:31
areanode_t
struct areanode_s areanode_t
ge
game_export_t * ge
Definition: game.c:22
CM_TransformedBoxTrace
void CM_TransformedBoxTrace(trace_t *trace, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, mnode_t *headnode, int brushmask, vec3_t origin, vec3_t angles)
Definition: cmodel.c:764
areanode_s::dist
float dist
Definition: world.c:33
MAX_TOTAL_ENT_LEAFS
#define MAX_TOTAL_ENT_LEAFS
Definition: server.h:176
CM_PointContents
int CM_PointContents(vec3_t p, mnode_t *headnode)
Definition: cmodel.c:289
server_entity_t
Definition: server.h:111
server_t::cm
cm_t cm
Definition: server.h:161
areanode_s::axis
int axis
Definition: world.c:32
SV_EdictIsVisible
qboolean SV_EdictIsVisible(cm_t *cm, edict_t *ent, byte *mask)
Definition: world.c:129
SV_AreaEdicts_r
static void SV_AreaEdicts_r(areanode_t *node)
Definition: world.c:361
area_count
static int area_count
Definition: world.c:47
server_t::state
server_state_t state
Definition: server.h:146
SV_Trace
trace_t q_gameabi SV_Trace(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask)
Definition: world.c:546
SV_AreaEdicts
int SV_AreaEdicts(vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype)
Definition: world.c:407
sv_areanodes
static areanode_t sv_areanodes[AREA_NODES]
Definition: world.c:42
EDICT_NUM
#define EDICT_NUM(n)
Definition: server.h:173
areanode_s::children
struct areanode_s * children[2]
Definition: world.c:34
server_t::entities
server_entity_t entities[MAX_EDICTS]
Definition: server.h:166
server.h
AREA_DEPTH
#define AREA_DEPTH
Definition: world.c:39
CM_NodeNum
mnode_t * CM_NodeNum(cm_t *cm, int number)
Definition: cmodel.c:83
CM_TransformedPointContents
int CM_TransformedPointContents(vec3_t p, mnode_t *headnode, vec3_t origin, vec3_t angles)
Definition: cmodel.c:310
AREA_NODES
#define AREA_NODES
Definition: world.c:40