1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (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.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 // cmodel.c -- model loading
21
22 #include "qcommon.h"
23
24 typedef struct
25 {
26 cplane_t *plane;
27 int children[2]; // negative numbers are leafs
28 } cnode_t;
29
30 typedef struct
31 {
32 cplane_t *plane;
33 mapsurface_t *surface;
34 } cbrushside_t;
35
36 typedef struct
37 {
38 int contents;
39 int cluster;
40 int area;
41 unsigned short firstleafbrush;
42 unsigned short numleafbrushes;
43 } cleaf_t;
44
45 typedef struct
46 {
47 int contents;
48 int numsides;
49 int firstbrushside;
50 int checkcount; // to avoid repeated testings
51 } cbrush_t;
52
53 typedef struct
54 {
55 int numareaportals;
56 int firstareaportal;
57 int floodnum; // if two areas have equal floodnums, they are connected
58 int floodvalid;
59 } carea_t;
60
61 int checkcount;
62
63 char map_name[MAX_QPATH];
64
65 int numbrushsides;
66 cbrushside_t map_brushsides[MAX_MAP_BRUSHSIDES];
67
68 int numtexinfo;
69 mapsurface_t map_surfaces[MAX_MAP_TEXINFO];
70
71 int numplanes;
72 cplane_t map_planes[MAX_MAP_PLANES+6]; // extra for box hull
73
74 int numnodes;
75 cnode_t map_nodes[MAX_MAP_NODES+6]; // extra for box hull
76
77 int numleafs = 1; // allow leaf funcs to be called without a map
78 cleaf_t map_leafs[MAX_MAP_LEAFS];
79 int emptyleaf, solidleaf;
80
81 int numleafbrushes;
82 unsigned short map_leafbrushes[MAX_MAP_LEAFBRUSHES];
83
84 int numcmodels;
85 cmodel_t map_cmodels[MAX_MAP_MODELS];
86
87 int numbrushes;
88 cbrush_t map_brushes[MAX_MAP_BRUSHES];
89
90 int numvisibility;
91 byte map_visibility[MAX_MAP_VISIBILITY];
92 dvis_t *map_vis = (dvis_t *)map_visibility;
93
94 int numentitychars;
95 char map_entitystring[MAX_MAP_ENTSTRING];
96
97 int numareas = 1;
98 carea_t map_areas[MAX_MAP_AREAS];
99
100 int numareaportals;
101 dareaportal_t map_areaportals[MAX_MAP_AREAPORTALS];
102
103 int numclusters = 1;
104
105 mapsurface_t nullsurface;
106
107 int floodvalid;
108
109 qboolean portalopen[MAX_MAP_AREAPORTALS];
110
111
112 cvar_t *map_noareas;
113
114 void CM_InitBoxHull (void);
115 void FloodAreaConnections (void);
116
117
118 int c_pointcontents;
119 int c_traces, c_brush_traces;
120
121
122 /*
123 ===============================================================================
124
125 MAP LOADING
126
127 ===============================================================================
128 */
129
130 byte *cmod_base;
131
132 /*
133 =================
134 CMod_LoadSubmodels
135 =================
136 */
CMod_LoadSubmodels(lump_t * l)137 void CMod_LoadSubmodels (lump_t *l)
138 {
139 dmodel_t *in;
140 cmodel_t *out;
141 int i, j, count;
142
143 in = (void *)(cmod_base + l->fileofs);
144 if (l->filelen % sizeof(*in))
145 Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
146 count = l->filelen / sizeof(*in);
147
148 if (count < 1)
149 Com_Error (ERR_DROP, "Map with no models");
150 if (count > MAX_MAP_MODELS)
151 Com_Error (ERR_DROP, "Map has too many models");
152
153 numcmodels = count;
154
155 for ( i=0 ; i<count ; i++, in++, out++)
156 {
157 out = &map_cmodels[i];
158
159 for (j=0 ; j<3 ; j++)
160 { // spread the mins / maxs by a pixel
161 out->mins[j] = LittleFloat (in->mins[j]) - 1;
162 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
163 out->origin[j] = LittleFloat (in->origin[j]);
164 }
165 out->headnode = LittleLong (in->headnode);
166 }
167 }
168
169
170 /*
171 =================
172 CMod_LoadSurfaces
173 =================
174 */
CMod_LoadSurfaces(lump_t * l)175 void CMod_LoadSurfaces (lump_t *l)
176 {
177 texinfo_t *in;
178 mapsurface_t *out;
179 int i, count;
180
181 in = (void *)(cmod_base + l->fileofs);
182 if (l->filelen % sizeof(*in))
183 Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
184 count = l->filelen / sizeof(*in);
185 if (count < 1)
186 Com_Error (ERR_DROP, "Map with no surfaces");
187 if (count > MAX_MAP_TEXINFO)
188 Com_Error (ERR_DROP, "Map has too many surfaces");
189
190 numtexinfo = count;
191 out = map_surfaces;
192
193 for ( i=0 ; i<count ; i++, in++, out++)
194 {
195 strncpy (out->c.name, in->texture, sizeof(out->c.name)-1);
196 strncpy (out->rname, in->texture, sizeof(out->rname)-1);
197 out->c.flags = LittleLong (in->flags);
198 out->c.value = LittleLong (in->value);
199 }
200 }
201
202
203 /*
204 =================
205 CMod_LoadNodes
206
207 =================
208 */
CMod_LoadNodes(lump_t * l)209 void CMod_LoadNodes (lump_t *l)
210 {
211 dnode_t *in;
212 int child;
213 cnode_t *out;
214 int i, j, count;
215
216 in = (void *)(cmod_base + l->fileofs);
217 if (l->filelen % sizeof(*in))
218 Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
219 count = l->filelen / sizeof(*in);
220
221 if (count < 1)
222 Com_Error (ERR_DROP, "Map has no nodes");
223 if (count > MAX_MAP_NODES)
224 Com_Error (ERR_DROP, "Map has too many nodes");
225
226 out = map_nodes;
227
228 numnodes = count;
229
230 for (i=0 ; i<count ; i++, out++, in++)
231 {
232 out->plane = map_planes + LittleLong(in->planenum);
233 for (j=0 ; j<2 ; j++)
234 {
235 child = LittleLong (in->children[j]);
236 out->children[j] = child;
237 }
238 }
239
240 }
241
242 /*
243 =================
244 CMod_LoadBrushes
245
246 =================
247 */
CMod_LoadBrushes(lump_t * l)248 void CMod_LoadBrushes (lump_t *l)
249 {
250 dbrush_t *in;
251 cbrush_t *out;
252 int i, count;
253
254 in = (void *)(cmod_base + l->fileofs);
255 if (l->filelen % sizeof(*in))
256 Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
257 count = l->filelen / sizeof(*in);
258
259 if (count > MAX_MAP_BRUSHES)
260 Com_Error (ERR_DROP, "Map has too many brushes");
261
262 out = map_brushes;
263
264 numbrushes = count;
265
266 for (i=0 ; i<count ; i++, out++, in++)
267 {
268 out->firstbrushside = LittleLong(in->firstside);
269 out->numsides = LittleLong(in->numsides);
270 out->contents = LittleLong(in->contents);
271 }
272
273 }
274
275 /*
276 =================
277 CMod_LoadLeafs
278 =================
279 */
CMod_LoadLeafs(lump_t * l)280 void CMod_LoadLeafs (lump_t *l)
281 {
282 int i;
283 cleaf_t *out;
284 dleaf_t *in;
285 int count;
286
287 in = (void *)(cmod_base + l->fileofs);
288 if (l->filelen % sizeof(*in))
289 Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
290 count = l->filelen / sizeof(*in);
291
292 if (count < 1)
293 Com_Error (ERR_DROP, "Map with no leafs");
294 // need to save space for box planes
295 if (count > MAX_MAP_PLANES)
296 Com_Error (ERR_DROP, "Map has too many planes");
297
298 out = map_leafs;
299 numleafs = count;
300 numclusters = 0;
301
302 for ( i=0 ; i<count ; i++, in++, out++)
303 {
304 out->contents = LittleLong (in->contents);
305 out->cluster = LittleShort (in->cluster);
306 out->area = LittleShort (in->area);
307 out->firstleafbrush = LittleShort (in->firstleafbrush);
308 out->numleafbrushes = LittleShort (in->numleafbrushes);
309
310 if (out->cluster >= numclusters)
311 numclusters = out->cluster + 1;
312 }
313
314 if (map_leafs[0].contents != CONTENTS_SOLID)
315 Com_Error (ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID");
316 solidleaf = 0;
317 emptyleaf = -1;
318 for (i=1 ; i<numleafs ; i++)
319 {
320 if (!map_leafs[i].contents)
321 {
322 emptyleaf = i;
323 break;
324 }
325 }
326 if (emptyleaf == -1)
327 Com_Error (ERR_DROP, "Map does not have an empty leaf");
328 }
329
330 /*
331 =================
332 CMod_LoadPlanes
333 =================
334 */
CMod_LoadPlanes(lump_t * l)335 void CMod_LoadPlanes (lump_t *l)
336 {
337 int i, j;
338 cplane_t *out;
339 dplane_t *in;
340 int count;
341 int bits;
342
343 in = (void *)(cmod_base + l->fileofs);
344 if (l->filelen % sizeof(*in))
345 Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
346 count = l->filelen / sizeof(*in);
347
348 if (count < 1)
349 Com_Error (ERR_DROP, "Map with no planes");
350 // need to save space for box planes
351 if (count > MAX_MAP_PLANES)
352 Com_Error (ERR_DROP, "Map has too many planes");
353
354 out = map_planes;
355 numplanes = count;
356
357 for ( i=0 ; i<count ; i++, in++, out++)
358 {
359 bits = 0;
360 for (j=0 ; j<3 ; j++)
361 {
362 out->normal[j] = LittleFloat (in->normal[j]);
363 if (out->normal[j] < 0)
364 bits |= 1<<j;
365 }
366
367 out->dist = LittleFloat (in->dist);
368 out->type = LittleLong (in->type);
369 out->signbits = bits;
370 }
371 }
372
373 /*
374 =================
375 CMod_LoadLeafBrushes
376 =================
377 */
CMod_LoadLeafBrushes(lump_t * l)378 void CMod_LoadLeafBrushes (lump_t *l)
379 {
380 int i;
381 unsigned short *out;
382 unsigned short *in;
383 int count;
384
385 in = (void *)(cmod_base + l->fileofs);
386 if (l->filelen % sizeof(*in))
387 Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
388 count = l->filelen / sizeof(*in);
389
390 if (count < 1)
391 Com_Error (ERR_DROP, "Map with no planes");
392 // need to save space for box planes
393 if (count > MAX_MAP_LEAFBRUSHES)
394 Com_Error (ERR_DROP, "Map has too many leafbrushes");
395
396 out = map_leafbrushes;
397 numleafbrushes = count;
398
399 for ( i=0 ; i<count ; i++, in++, out++)
400 *out = LittleShort (*in);
401 }
402
403 /*
404 =================
405 CMod_LoadBrushSides
406 =================
407 */
CMod_LoadBrushSides(lump_t * l)408 void CMod_LoadBrushSides (lump_t *l)
409 {
410 int i, j;
411 cbrushside_t *out;
412 dbrushside_t *in;
413 int count;
414 int num;
415
416 in = (void *)(cmod_base + l->fileofs);
417 if (l->filelen % sizeof(*in))
418 Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
419 count = l->filelen / sizeof(*in);
420
421 // need to save space for box planes
422 if (count > MAX_MAP_BRUSHSIDES)
423 Com_Error (ERR_DROP, "Map has too many planes");
424
425 out = map_brushsides;
426 numbrushsides = count;
427
428 for ( i=0 ; i<count ; i++, in++, out++)
429 {
430 num = LittleShort (in->planenum);
431 out->plane = &map_planes[num];
432 j = LittleShort (in->texinfo);
433 if (j >= numtexinfo)
434 Com_Error (ERR_DROP, "Bad brushside texinfo");
435 out->surface = &map_surfaces[j];
436 }
437 }
438
439 /*
440 =================
441 CMod_LoadAreas
442 =================
443 */
CMod_LoadAreas(lump_t * l)444 void CMod_LoadAreas (lump_t *l)
445 {
446 int i;
447 carea_t *out;
448 darea_t *in;
449 int count;
450
451 in = (void *)(cmod_base + l->fileofs);
452 if (l->filelen % sizeof(*in))
453 Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
454 count = l->filelen / sizeof(*in);
455
456 if (count > MAX_MAP_AREAS)
457 Com_Error (ERR_DROP, "Map has too many areas");
458
459 out = map_areas;
460 numareas = count;
461
462 for ( i=0 ; i<count ; i++, in++, out++)
463 {
464 out->numareaportals = LittleLong (in->numareaportals);
465 out->firstareaportal = LittleLong (in->firstareaportal);
466 out->floodvalid = 0;
467 out->floodnum = 0;
468 }
469 }
470
471 /*
472 =================
473 CMod_LoadAreaPortals
474 =================
475 */
CMod_LoadAreaPortals(lump_t * l)476 void CMod_LoadAreaPortals (lump_t *l)
477 {
478 int i;
479 dareaportal_t *out;
480 dareaportal_t *in;
481 int count;
482
483 in = (void *)(cmod_base + l->fileofs);
484 if (l->filelen % sizeof(*in))
485 Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
486 count = l->filelen / sizeof(*in);
487
488 if (count > MAX_MAP_AREAS)
489 Com_Error (ERR_DROP, "Map has too many areas");
490
491 out = map_areaportals;
492 numareaportals = count;
493
494 for ( i=0 ; i<count ; i++, in++, out++)
495 {
496 out->portalnum = LittleLong (in->portalnum);
497 out->otherarea = LittleLong (in->otherarea);
498 }
499 }
500
501 /*
502 =================
503 CMod_LoadVisibility
504 =================
505 */
CMod_LoadVisibility(lump_t * l)506 void CMod_LoadVisibility (lump_t *l)
507 {
508 int i;
509
510 numvisibility = l->filelen;
511 if (l->filelen > MAX_MAP_VISIBILITY)
512 Com_Error (ERR_DROP, "Map has too large visibility lump");
513
514 memcpy (map_visibility, cmod_base + l->fileofs, l->filelen);
515
516 map_vis->numclusters = LittleLong (map_vis->numclusters);
517 for (i=0 ; i<map_vis->numclusters ; i++)
518 {
519 map_vis->bitofs[i][0] = LittleLong (map_vis->bitofs[i][0]);
520 map_vis->bitofs[i][1] = LittleLong (map_vis->bitofs[i][1]);
521 }
522 }
523
524
525 /*
526 =================
527 CMod_LoadEntityString
528 =================
529 */
CMod_LoadEntityString(lump_t * l)530 void CMod_LoadEntityString (lump_t *l)
531 {
532 numentitychars = l->filelen;
533 if (l->filelen > MAX_MAP_ENTSTRING)
534 Com_Error (ERR_DROP, "Map has too large entity lump");
535
536 memcpy (map_entitystring, cmod_base + l->fileofs, l->filelen);
537 }
538
539
540
541 /*
542 ==================
543 CM_LoadMap
544
545 Loads in the map and all submodels
546 ==================
547 */
CM_LoadMap(char * name,qboolean clientload,unsigned * checksum)548 cmodel_t *CM_LoadMap (char *name, qboolean clientload, unsigned *checksum)
549 {
550 unsigned *buf;
551 int i;
552 dheader_t header;
553 int length;
554 static unsigned last_checksum;
555
556 map_noareas = Cvar_Get ("map_noareas", "0", 0);
557
558 if ( !strcmp (map_name, name) && (clientload || !Cvar_VariableValue ("flushmap")) )
559 {
560 *checksum = last_checksum;
561 if (!clientload)
562 {
563 memset (portalopen, 0, sizeof(portalopen));
564 FloodAreaConnections ();
565 }
566 return &map_cmodels[0]; // still have the right version
567 }
568
569 // free old stuff
570 numplanes = 0;
571 numnodes = 0;
572 numleafs = 0;
573 numcmodels = 0;
574 numvisibility = 0;
575 numentitychars = 0;
576 map_entitystring[0] = 0;
577 map_name[0] = 0;
578
579 if (!name || !name[0])
580 {
581 numleafs = 1;
582 numclusters = 1;
583 numareas = 1;
584 *checksum = 0;
585 return &map_cmodels[0]; // cinematic servers won't have anything at all
586 }
587
588 //
589 // load the file
590 //
591 length = FS_LoadFile (name, (void **)&buf);
592 if (!buf)
593 Com_Error (ERR_DROP, "Couldn't load %s", name);
594
595 last_checksum = LittleLong (Com_BlockChecksum (buf, length));
596 *checksum = last_checksum;
597
598 header = *(dheader_t *)buf;
599 for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
600 ((int *)&header)[i] = LittleLong ( ((int *)&header)[i]);
601
602 if (header.version != BSPVERSION)
603 Com_Error (ERR_DROP, "CMod_LoadBrushModel: %s has wrong version number (%i should be %i)"
604 , name, header.version, BSPVERSION);
605
606 cmod_base = (byte *)buf;
607
608 // load into heap
609 CMod_LoadSurfaces (&header.lumps[LUMP_TEXINFO]);
610 CMod_LoadLeafs (&header.lumps[LUMP_LEAFS]);
611 CMod_LoadLeafBrushes (&header.lumps[LUMP_LEAFBRUSHES]);
612 CMod_LoadPlanes (&header.lumps[LUMP_PLANES]);
613 CMod_LoadBrushes (&header.lumps[LUMP_BRUSHES]);
614 CMod_LoadBrushSides (&header.lumps[LUMP_BRUSHSIDES]);
615 CMod_LoadSubmodels (&header.lumps[LUMP_MODELS]);
616 CMod_LoadNodes (&header.lumps[LUMP_NODES]);
617 CMod_LoadAreas (&header.lumps[LUMP_AREAS]);
618 CMod_LoadAreaPortals (&header.lumps[LUMP_AREAPORTALS]);
619 CMod_LoadVisibility (&header.lumps[LUMP_VISIBILITY]);
620 CMod_LoadEntityString (&header.lumps[LUMP_ENTITIES]);
621
622 FS_FreeFile (buf);
623
624 CM_InitBoxHull ();
625
626 memset (portalopen, 0, sizeof(portalopen));
627 FloodAreaConnections ();
628
629 strcpy (map_name, name);
630
631 return &map_cmodels[0];
632 }
633
634 /*
635 ==================
636 CM_InlineModel
637 ==================
638 */
CM_InlineModel(char * name)639 cmodel_t *CM_InlineModel (char *name)
640 {
641 int num;
642
643 if (!name || name[0] != '*')
644 Com_Error (ERR_DROP, "CM_InlineModel: bad name");
645 num = atoi (name+1);
646 if (num < 1 || num >= numcmodels)
647 Com_Error (ERR_DROP, "CM_InlineModel: bad number");
648
649 return &map_cmodels[num];
650 }
651
CM_NumClusters(void)652 int CM_NumClusters (void)
653 {
654 return numclusters;
655 }
656
CM_NumInlineModels(void)657 int CM_NumInlineModels (void)
658 {
659 return numcmodels;
660 }
661
CM_EntityString(void)662 char *CM_EntityString (void)
663 {
664 return map_entitystring;
665 }
666
CM_LeafContents(int leafnum)667 int CM_LeafContents (int leafnum)
668 {
669 if (leafnum < 0 || leafnum >= numleafs)
670 Com_Error (ERR_DROP, "CM_LeafContents: bad number");
671 return map_leafs[leafnum].contents;
672 }
673
CM_LeafCluster(int leafnum)674 int CM_LeafCluster (int leafnum)
675 {
676 if (leafnum < 0 || leafnum >= numleafs)
677 Com_Error (ERR_DROP, "CM_LeafCluster: bad number");
678 return map_leafs[leafnum].cluster;
679 }
680
CM_LeafArea(int leafnum)681 int CM_LeafArea (int leafnum)
682 {
683 if (leafnum < 0 || leafnum >= numleafs)
684 Com_Error (ERR_DROP, "CM_LeafArea: bad number");
685 return map_leafs[leafnum].area;
686 }
687
688 //=======================================================================
689
690
691 cplane_t *box_planes;
692 int box_headnode;
693 cbrush_t *box_brush;
694 cleaf_t *box_leaf;
695
696 /*
697 ===================
698 CM_InitBoxHull
699
700 Set up the planes and nodes so that the six floats of a bounding box
701 can just be stored out and get a proper clipping hull structure.
702 ===================
703 */
CM_InitBoxHull(void)704 void CM_InitBoxHull (void)
705 {
706 int i;
707 int side;
708 cnode_t *c;
709 cplane_t *p;
710 cbrushside_t *s;
711
712 box_headnode = numnodes;
713 box_planes = &map_planes[numplanes];
714 if (numnodes+6 > MAX_MAP_NODES
715 || numbrushes+1 > MAX_MAP_BRUSHES
716 || numleafbrushes+1 > MAX_MAP_LEAFBRUSHES
717 || numbrushsides+6 > MAX_MAP_BRUSHSIDES
718 || numplanes+12 > MAX_MAP_PLANES)
719 Com_Error (ERR_DROP, "Not enough room for box tree");
720
721 box_brush = &map_brushes[numbrushes];
722 box_brush->numsides = 6;
723 box_brush->firstbrushside = numbrushsides;
724 box_brush->contents = CONTENTS_MONSTER;
725
726 box_leaf = &map_leafs[numleafs];
727 box_leaf->contents = CONTENTS_MONSTER;
728 box_leaf->firstleafbrush = numleafbrushes;
729 box_leaf->numleafbrushes = 1;
730
731 map_leafbrushes[numleafbrushes] = numbrushes;
732
733 for (i=0 ; i<6 ; i++)
734 {
735 side = i&1;
736
737 // brush sides
738 s = &map_brushsides[numbrushsides+i];
739 s->plane = map_planes + (numplanes+i*2+side);
740 s->surface = &nullsurface;
741
742 // nodes
743 c = &map_nodes[box_headnode+i];
744 c->plane = map_planes + (numplanes+i*2);
745 c->children[side] = -1 - emptyleaf;
746 if (i != 5)
747 c->children[side^1] = box_headnode+i + 1;
748 else
749 c->children[side^1] = -1 - numleafs;
750
751 // planes
752 p = &box_planes[i*2];
753 p->type = i>>1;
754 p->signbits = 0;
755 VectorClear (p->normal);
756 p->normal[i>>1] = 1;
757
758 p = &box_planes[i*2+1];
759 p->type = 3 + (i>>1);
760 p->signbits = 0;
761 VectorClear (p->normal);
762 p->normal[i>>1] = -1;
763 }
764 }
765
766
767 /*
768 ===================
769 CM_HeadnodeForBox
770
771 To keep everything totally uniform, bounding boxes are turned into small
772 BSP trees instead of being compared directly.
773 ===================
774 */
CM_HeadnodeForBox(vec3_t mins,vec3_t maxs)775 int CM_HeadnodeForBox (vec3_t mins, vec3_t maxs)
776 {
777 box_planes[0].dist = maxs[0];
778 box_planes[1].dist = -maxs[0];
779 box_planes[2].dist = mins[0];
780 box_planes[3].dist = -mins[0];
781 box_planes[4].dist = maxs[1];
782 box_planes[5].dist = -maxs[1];
783 box_planes[6].dist = mins[1];
784 box_planes[7].dist = -mins[1];
785 box_planes[8].dist = maxs[2];
786 box_planes[9].dist = -maxs[2];
787 box_planes[10].dist = mins[2];
788 box_planes[11].dist = -mins[2];
789
790 return box_headnode;
791 }
792
793
794 /*
795 ==================
796 CM_PointLeafnum_r
797
798 ==================
799 */
CM_PointLeafnum_r(vec3_t p,int num)800 int CM_PointLeafnum_r (vec3_t p, int num)
801 {
802 float d;
803 cnode_t *node;
804 cplane_t *plane;
805
806 while (num >= 0)
807 {
808 node = map_nodes + num;
809 plane = node->plane;
810
811 if (plane->type < 3)
812 d = p[plane->type] - plane->dist;
813 else
814 d = DotProduct (plane->normal, p) - plane->dist;
815 if (d < 0)
816 num = node->children[1];
817 else
818 num = node->children[0];
819 }
820
821 c_pointcontents++; // optimize counter
822
823 return -1 - num;
824 }
825
CM_PointLeafnum(vec3_t p)826 int CM_PointLeafnum (vec3_t p)
827 {
828 if (!numplanes)
829 return 0; // sound may call this without map loaded
830 return CM_PointLeafnum_r (p, 0);
831 }
832
833
834
835 /*
836 =============
837 CM_BoxLeafnums
838
839 Fills in a list of all the leafs touched
840 =============
841 */
842 int leaf_count, leaf_maxcount;
843 int *leaf_list;
844 float *leaf_mins, *leaf_maxs;
845 int leaf_topnode;
846
CM_BoxLeafnums_r(int nodenum)847 void CM_BoxLeafnums_r (int nodenum)
848 {
849 cplane_t *plane;
850 cnode_t *node;
851 int s;
852
853 while (1)
854 {
855 if (nodenum < 0)
856 {
857 if (leaf_count >= leaf_maxcount)
858 {
859 // Com_Printf ("CM_BoxLeafnums_r: overflow\n");
860 return;
861 }
862 leaf_list[leaf_count++] = -1 - nodenum;
863 return;
864 }
865
866 node = &map_nodes[nodenum];
867 plane = node->plane;
868 // s = BoxOnPlaneSide (leaf_mins, leaf_maxs, plane);
869 s = BOX_ON_PLANE_SIDE(leaf_mins, leaf_maxs, plane);
870 if (s == 1)
871 nodenum = node->children[0];
872 else if (s == 2)
873 nodenum = node->children[1];
874 else
875 { // go down both
876 if (leaf_topnode == -1)
877 leaf_topnode = nodenum;
878 CM_BoxLeafnums_r (node->children[0]);
879 nodenum = node->children[1];
880 }
881
882 }
883 }
884
CM_BoxLeafnums_headnode(vec3_t mins,vec3_t maxs,int * list,int listsize,int headnode,int * topnode)885 int CM_BoxLeafnums_headnode (vec3_t mins, vec3_t maxs, int *list, int listsize, int headnode, int *topnode)
886 {
887 leaf_list = list;
888 leaf_count = 0;
889 leaf_maxcount = listsize;
890 leaf_mins = mins;
891 leaf_maxs = maxs;
892
893 leaf_topnode = -1;
894
895 CM_BoxLeafnums_r (headnode);
896
897 if (topnode)
898 *topnode = leaf_topnode;
899
900 return leaf_count;
901 }
902
CM_BoxLeafnums(vec3_t mins,vec3_t maxs,int * list,int listsize,int * topnode)903 int CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list, int listsize, int *topnode)
904 {
905 return CM_BoxLeafnums_headnode (mins, maxs, list,
906 listsize, map_cmodels[0].headnode, topnode);
907 }
908
909
910
911 /*
912 ==================
913 CM_PointContents
914
915 ==================
916 */
CM_PointContents(vec3_t p,int headnode)917 int CM_PointContents (vec3_t p, int headnode)
918 {
919 int l;
920
921 if (!numnodes) // map not loaded
922 return 0;
923
924 l = CM_PointLeafnum_r (p, headnode);
925
926 return map_leafs[l].contents;
927 }
928
929 /*
930 ==================
931 CM_TransformedPointContents
932
933 Handles offseting and rotation of the end points for moving and
934 rotating entities
935 ==================
936 */
CM_TransformedPointContents(vec3_t p,int headnode,vec3_t origin,vec3_t angles)937 int CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles)
938 {
939 vec3_t p_l;
940 vec3_t temp;
941 vec3_t forward, right, up;
942 int l;
943
944 // subtract origin offset
945 VectorSubtract (p, origin, p_l);
946
947 // rotate start and end into the models frame of reference
948 if (headnode != box_headnode &&
949 (angles[0] || angles[1] || angles[2]) )
950 {
951 AngleVectors (angles, forward, right, up);
952
953 VectorCopy (p_l, temp);
954 p_l[0] = DotProduct (temp, forward);
955 p_l[1] = -DotProduct (temp, right);
956 p_l[2] = DotProduct (temp, up);
957 }
958
959 l = CM_PointLeafnum_r (p_l, headnode);
960
961 return map_leafs[l].contents;
962 }
963
964
965 /*
966 ===============================================================================
967
968 BOX TRACING
969
970 ===============================================================================
971 */
972
973 // 1/32 epsilon to keep floating point happy
974 #define DIST_EPSILON (0.03125)
975
976 vec3_t trace_start, trace_end;
977 vec3_t trace_mins, trace_maxs;
978 vec3_t trace_extents;
979
980 trace_t trace_trace;
981 int trace_contents;
982 qboolean trace_ispoint; // optimized case
983
984 /*
985 ================
986 CM_ClipBoxToBrush
987 ================
988 */
CM_ClipBoxToBrush(vec3_t mins,vec3_t maxs,vec3_t p1,vec3_t p2,trace_t * trace,cbrush_t * brush)989 void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2,
990 trace_t *trace, cbrush_t *brush)
991 {
992 int i, j;
993 cplane_t *plane, *clipplane;
994 float dist;
995 float enterfrac, leavefrac;
996 vec3_t ofs;
997 float d1, d2;
998 qboolean getout, startout;
999 float f;
1000 cbrushside_t *side, *leadside;
1001
1002 enterfrac = -1;
1003 leavefrac = 1;
1004 clipplane = NULL;
1005
1006 if (!brush->numsides)
1007 return;
1008
1009 c_brush_traces++;
1010
1011 getout = false;
1012 startout = false;
1013 leadside = NULL;
1014
1015 for (i=0 ; i<brush->numsides ; i++)
1016 {
1017 side = &map_brushsides[brush->firstbrushside+i];
1018 plane = side->plane;
1019
1020 // FIXME: special case for axial
1021
1022 if (!trace_ispoint)
1023 { // general box case
1024
1025 // push the plane out apropriately for mins/maxs
1026
1027 // FIXME: use signbits into 8 way lookup for each mins/maxs
1028 for (j=0 ; j<3 ; j++)
1029 {
1030 if (plane->normal[j] < 0)
1031 ofs[j] = maxs[j];
1032 else
1033 ofs[j] = mins[j];
1034 }
1035 dist = DotProduct (ofs, plane->normal);
1036 dist = plane->dist - dist;
1037 }
1038 else
1039 { // special point case
1040 dist = plane->dist;
1041 }
1042
1043 d1 = DotProduct (p1, plane->normal) - dist;
1044 d2 = DotProduct (p2, plane->normal) - dist;
1045
1046 if (d2 > 0)
1047 getout = true; // endpoint is not in solid
1048 if (d1 > 0)
1049 startout = true;
1050
1051 // if completely in front of face, no intersection
1052 if (d1 > 0 && d2 >= d1)
1053 return;
1054
1055 if (d1 <= 0 && d2 <= 0)
1056 continue;
1057
1058 // crosses face
1059 if (d1 > d2)
1060 { // enter
1061 f = (d1-DIST_EPSILON) / (d1-d2);
1062 if (f > enterfrac)
1063 {
1064 enterfrac = f;
1065 clipplane = plane;
1066 leadside = side;
1067 }
1068 }
1069 else
1070 { // leave
1071 f = (d1+DIST_EPSILON) / (d1-d2);
1072 if (f < leavefrac)
1073 leavefrac = f;
1074 }
1075 }
1076
1077 if (!startout)
1078 { // original point was inside brush
1079 trace->startsolid = true;
1080 if (!getout)
1081 trace->allsolid = true;
1082 return;
1083 }
1084 if (enterfrac < leavefrac)
1085 {
1086 if (enterfrac > -1 && enterfrac < trace->fraction)
1087 {
1088 if (enterfrac < 0)
1089 enterfrac = 0;
1090 trace->fraction = enterfrac;
1091 trace->plane = *clipplane;
1092 trace->surface = &(leadside->surface->c);
1093 trace->contents = brush->contents;
1094 }
1095 }
1096 }
1097
1098 /*
1099 ================
1100 CM_TestBoxInBrush
1101 ================
1102 */
CM_TestBoxInBrush(vec3_t mins,vec3_t maxs,vec3_t p1,trace_t * trace,cbrush_t * brush)1103 void CM_TestBoxInBrush (vec3_t mins, vec3_t maxs, vec3_t p1,
1104 trace_t *trace, cbrush_t *brush)
1105 {
1106 int i, j;
1107 cplane_t *plane;
1108 float dist;
1109 vec3_t ofs;
1110 float d1;
1111 cbrushside_t *side;
1112
1113 if (!brush->numsides)
1114 return;
1115
1116 for (i=0 ; i<brush->numsides ; i++)
1117 {
1118 side = &map_brushsides[brush->firstbrushside+i];
1119 plane = side->plane;
1120
1121 // FIXME: special case for axial
1122
1123 // general box case
1124
1125 // push the plane out apropriately for mins/maxs
1126
1127 // FIXME: use signbits into 8 way lookup for each mins/maxs
1128 for (j=0 ; j<3 ; j++)
1129 {
1130 if (plane->normal[j] < 0)
1131 ofs[j] = maxs[j];
1132 else
1133 ofs[j] = mins[j];
1134 }
1135 dist = DotProduct (ofs, plane->normal);
1136 dist = plane->dist - dist;
1137
1138 d1 = DotProduct (p1, plane->normal) - dist;
1139
1140 // if completely in front of face, no intersection
1141 if (d1 > 0)
1142 return;
1143
1144 }
1145
1146 // inside this brush
1147 trace->startsolid = trace->allsolid = true;
1148 trace->fraction = 0;
1149 trace->contents = brush->contents;
1150 }
1151
1152
1153 /*
1154 ================
1155 CM_TraceToLeaf
1156 ================
1157 */
CM_TraceToLeaf(int leafnum)1158 void CM_TraceToLeaf (int leafnum)
1159 {
1160 int k;
1161 int brushnum;
1162 cleaf_t *leaf;
1163 cbrush_t *b;
1164
1165 leaf = &map_leafs[leafnum];
1166 if ( !(leaf->contents & trace_contents))
1167 return;
1168 // trace line against all brushes in the leaf
1169 for (k=0 ; k<leaf->numleafbrushes ; k++)
1170 {
1171 brushnum = map_leafbrushes[leaf->firstleafbrush+k];
1172 b = &map_brushes[brushnum];
1173 if (b->checkcount == checkcount)
1174 continue; // already checked this brush in another leaf
1175 b->checkcount = checkcount;
1176
1177 if ( !(b->contents & trace_contents))
1178 continue;
1179 CM_ClipBoxToBrush (trace_mins, trace_maxs, trace_start, trace_end, &trace_trace, b);
1180 if (!trace_trace.fraction)
1181 return;
1182 }
1183
1184 }
1185
1186
1187 /*
1188 ================
1189 CM_TestInLeaf
1190 ================
1191 */
CM_TestInLeaf(int leafnum)1192 void CM_TestInLeaf (int leafnum)
1193 {
1194 int k;
1195 int brushnum;
1196 cleaf_t *leaf;
1197 cbrush_t *b;
1198
1199 leaf = &map_leafs[leafnum];
1200 if ( !(leaf->contents & trace_contents))
1201 return;
1202 // trace line against all brushes in the leaf
1203 for (k=0 ; k<leaf->numleafbrushes ; k++)
1204 {
1205 brushnum = map_leafbrushes[leaf->firstleafbrush+k];
1206 b = &map_brushes[brushnum];
1207 if (b->checkcount == checkcount)
1208 continue; // already checked this brush in another leaf
1209 b->checkcount = checkcount;
1210
1211 if ( !(b->contents & trace_contents))
1212 continue;
1213 CM_TestBoxInBrush (trace_mins, trace_maxs, trace_start, &trace_trace, b);
1214 if (!trace_trace.fraction)
1215 return;
1216 }
1217
1218 }
1219
1220
1221 /*
1222 ==================
1223 CM_RecursiveHullCheck
1224
1225 ==================
1226 */
CM_RecursiveHullCheck(int num,float p1f,float p2f,vec3_t p1,vec3_t p2)1227 void CM_RecursiveHullCheck (int num, float p1f, float p2f, vec3_t p1, vec3_t p2)
1228 {
1229 cnode_t *node;
1230 cplane_t *plane;
1231 float t1, t2, offset;
1232 float frac, frac2;
1233 float idist;
1234 int i;
1235 vec3_t mid;
1236 int side;
1237 float midf;
1238
1239 if (trace_trace.fraction <= p1f)
1240 return; // already hit something nearer
1241
1242 // if < 0, we are in a leaf node
1243 if (num < 0)
1244 {
1245 CM_TraceToLeaf (-1-num);
1246 return;
1247 }
1248
1249 //
1250 // find the point distances to the seperating plane
1251 // and the offset for the size of the box
1252 //
1253 node = map_nodes + num;
1254 plane = node->plane;
1255
1256 if (plane->type < 3)
1257 {
1258 t1 = p1[plane->type] - plane->dist;
1259 t2 = p2[plane->type] - plane->dist;
1260 offset = trace_extents[plane->type];
1261 }
1262 else
1263 {
1264 t1 = DotProduct (plane->normal, p1) - plane->dist;
1265 t2 = DotProduct (plane->normal, p2) - plane->dist;
1266 if (trace_ispoint)
1267 offset = 0;
1268 else
1269 offset = fabs(trace_extents[0]*plane->normal[0]) +
1270 fabs(trace_extents[1]*plane->normal[1]) +
1271 fabs(trace_extents[2]*plane->normal[2]);
1272 }
1273
1274
1275 #if 0
1276 CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
1277 CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
1278 return;
1279 #endif
1280
1281 // see which sides we need to consider
1282 if (t1 >= offset && t2 >= offset)
1283 {
1284 CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
1285 return;
1286 }
1287 if (t1 < -offset && t2 < -offset)
1288 {
1289 CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
1290 return;
1291 }
1292
1293 // put the crosspoint DIST_EPSILON pixels on the near side
1294 if (t1 < t2)
1295 {
1296 idist = 1.0/(t1-t2);
1297 side = 1;
1298 frac2 = (t1 + offset + DIST_EPSILON)*idist;
1299 frac = (t1 - offset + DIST_EPSILON)*idist;
1300 }
1301 else if (t1 > t2)
1302 {
1303 idist = 1.0/(t1-t2);
1304 side = 0;
1305 frac2 = (t1 - offset - DIST_EPSILON)*idist;
1306 frac = (t1 + offset + DIST_EPSILON)*idist;
1307 }
1308 else
1309 {
1310 side = 0;
1311 frac = 1;
1312 frac2 = 0;
1313 }
1314
1315 // move up to the node
1316 if (frac < 0)
1317 frac = 0;
1318 if (frac > 1)
1319 frac = 1;
1320
1321 midf = p1f + (p2f - p1f)*frac;
1322 for (i=0 ; i<3 ; i++)
1323 mid[i] = p1[i] + frac*(p2[i] - p1[i]);
1324
1325 CM_RecursiveHullCheck (node->children[side], p1f, midf, p1, mid);
1326
1327
1328 // go past the node
1329 if (frac2 < 0)
1330 frac2 = 0;
1331 if (frac2 > 1)
1332 frac2 = 1;
1333
1334 midf = p1f + (p2f - p1f)*frac2;
1335 for (i=0 ; i<3 ; i++)
1336 mid[i] = p1[i] + frac2*(p2[i] - p1[i]);
1337
1338 CM_RecursiveHullCheck (node->children[side^1], midf, p2f, mid, p2);
1339 }
1340
1341
1342
1343 //======================================================================
1344
1345 /*
1346 ==================
1347 CM_BoxTrace
1348 ==================
1349 */
CM_BoxTrace(vec3_t start,vec3_t end,vec3_t mins,vec3_t maxs,int headnode,int brushmask)1350 trace_t CM_BoxTrace (vec3_t start, vec3_t end,
1351 vec3_t mins, vec3_t maxs,
1352 int headnode, int brushmask)
1353 {
1354 int i;
1355
1356 checkcount++; // for multi-check avoidance
1357
1358 c_traces++; // for statistics, may be zeroed
1359
1360 // fill in a default trace
1361 memset (&trace_trace, 0, sizeof(trace_trace));
1362 trace_trace.fraction = 1;
1363 trace_trace.surface = &(nullsurface.c);
1364
1365 if (!numnodes) // map not loaded
1366 return trace_trace;
1367
1368 trace_contents = brushmask;
1369 VectorCopy (start, trace_start);
1370 VectorCopy (end, trace_end);
1371 VectorCopy (mins, trace_mins);
1372 VectorCopy (maxs, trace_maxs);
1373
1374 //
1375 // check for position test special case
1376 //
1377 if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2])
1378 {
1379 int leafs[1024];
1380 int i, numleafs;
1381 vec3_t c1, c2;
1382 int topnode;
1383
1384 VectorAdd (start, mins, c1);
1385 VectorAdd (start, maxs, c2);
1386 for (i=0 ; i<3 ; i++)
1387 {
1388 c1[i] -= 1;
1389 c2[i] += 1;
1390 }
1391
1392 numleafs = CM_BoxLeafnums_headnode (c1, c2, leafs, 1024, headnode, &topnode);
1393 for (i=0 ; i<numleafs ; i++)
1394 {
1395 CM_TestInLeaf (leafs[i]);
1396 if (trace_trace.allsolid)
1397 break;
1398 }
1399 VectorCopy (start, trace_trace.endpos);
1400 return trace_trace;
1401 }
1402
1403 //
1404 // check for point special case
1405 //
1406 if (mins[0] == 0 && mins[1] == 0 && mins[2] == 0
1407 && maxs[0] == 0 && maxs[1] == 0 && maxs[2] == 0)
1408 {
1409 trace_ispoint = true;
1410 VectorClear (trace_extents);
1411 }
1412 else
1413 {
1414 trace_ispoint = false;
1415 trace_extents[0] = -mins[0] > maxs[0] ? -mins[0] : maxs[0];
1416 trace_extents[1] = -mins[1] > maxs[1] ? -mins[1] : maxs[1];
1417 trace_extents[2] = -mins[2] > maxs[2] ? -mins[2] : maxs[2];
1418 }
1419
1420 //
1421 // general sweeping through world
1422 //
1423 CM_RecursiveHullCheck (headnode, 0, 1, start, end);
1424
1425 if (trace_trace.fraction == 1)
1426 {
1427 VectorCopy (end, trace_trace.endpos);
1428 }
1429 else
1430 {
1431 for (i=0 ; i<3 ; i++)
1432 trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]);
1433 }
1434 return trace_trace;
1435 }
1436
1437
1438 /*
1439 ==================
1440 CM_TransformedBoxTrace
1441
1442 Handles offseting and rotation of the end points for moving and
1443 rotating entities
1444 ==================
1445 */
1446 #ifdef _WIN32
1447 #pragma optimize( "", off )
1448 #endif
1449
1450
CM_TransformedBoxTrace(vec3_t start,vec3_t end,vec3_t mins,vec3_t maxs,int headnode,int brushmask,vec3_t origin,vec3_t angles)1451 trace_t CM_TransformedBoxTrace (vec3_t start, vec3_t end,
1452 vec3_t mins, vec3_t maxs,
1453 int headnode, int brushmask,
1454 vec3_t origin, vec3_t angles)
1455 {
1456 trace_t trace;
1457 vec3_t start_l, end_l;
1458 vec3_t a;
1459 vec3_t forward, right, up;
1460 vec3_t temp;
1461 qboolean rotated;
1462
1463 // subtract origin offset
1464 VectorSubtract (start, origin, start_l);
1465 VectorSubtract (end, origin, end_l);
1466
1467 // rotate start and end into the models frame of reference
1468 if (headnode != box_headnode &&
1469 (angles[0] || angles[1] || angles[2]) )
1470 rotated = true;
1471 else
1472 rotated = false;
1473
1474 if (rotated)
1475 {
1476 AngleVectors (angles, forward, right, up);
1477
1478 VectorCopy (start_l, temp);
1479 start_l[0] = DotProduct (temp, forward);
1480 start_l[1] = -DotProduct (temp, right);
1481 start_l[2] = DotProduct (temp, up);
1482
1483 VectorCopy (end_l, temp);
1484 end_l[0] = DotProduct (temp, forward);
1485 end_l[1] = -DotProduct (temp, right);
1486 end_l[2] = DotProduct (temp, up);
1487 }
1488
1489 // sweep the box through the model
1490 trace = CM_BoxTrace (start_l, end_l, mins, maxs, headnode, brushmask);
1491
1492 if (rotated && trace.fraction != 1.0)
1493 {
1494 // FIXME: figure out how to do this with existing angles
1495 VectorNegate (angles, a);
1496 AngleVectors (a, forward, right, up);
1497
1498 VectorCopy (trace.plane.normal, temp);
1499 trace.plane.normal[0] = DotProduct (temp, forward);
1500 trace.plane.normal[1] = -DotProduct (temp, right);
1501 trace.plane.normal[2] = DotProduct (temp, up);
1502 }
1503
1504 trace.endpos[0] = start[0] + trace.fraction * (end[0] - start[0]);
1505 trace.endpos[1] = start[1] + trace.fraction * (end[1] - start[1]);
1506 trace.endpos[2] = start[2] + trace.fraction * (end[2] - start[2]);
1507
1508 return trace;
1509 }
1510
1511 #ifdef _WIN32
1512 #pragma optimize( "", on )
1513 #endif
1514
1515
1516
1517 /*
1518 ===============================================================================
1519
1520 PVS / PHS
1521
1522 ===============================================================================
1523 */
1524
1525 /*
1526 ===================
1527 CM_DecompressVis
1528 ===================
1529 */
CM_DecompressVis(byte * in,byte * out)1530 void CM_DecompressVis (byte *in, byte *out)
1531 {
1532 int c;
1533 byte *out_p;
1534 int row;
1535
1536 row = (numclusters+7)>>3;
1537 out_p = out;
1538
1539 if (!in || !numvisibility)
1540 { // no vis info, so make all visible
1541 while (row)
1542 {
1543 *out_p++ = 0xff;
1544 row--;
1545 }
1546 return;
1547 }
1548
1549 do
1550 {
1551 if (*in)
1552 {
1553 *out_p++ = *in++;
1554 continue;
1555 }
1556
1557 c = in[1];
1558 in += 2;
1559 if ((out_p - out) + c > row)
1560 {
1561 c = row - (out_p - out);
1562 Com_DPrintf ("warning: Vis decompression overrun\n");
1563 }
1564 while (c)
1565 {
1566 *out_p++ = 0;
1567 c--;
1568 }
1569 } while (out_p - out < row);
1570 }
1571
1572 byte pvsrow[MAX_MAP_LEAFS/8];
1573 byte phsrow[MAX_MAP_LEAFS/8];
1574
CM_ClusterPVS(int cluster)1575 byte *CM_ClusterPVS (int cluster)
1576 {
1577 if (cluster == -1)
1578 memset (pvsrow, 0, (numclusters+7)>>3);
1579 else
1580 CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PVS], pvsrow);
1581 return pvsrow;
1582 }
1583
CM_ClusterPHS(int cluster)1584 byte *CM_ClusterPHS (int cluster)
1585 {
1586 if (cluster == -1)
1587 memset (phsrow, 0, (numclusters+7)>>3);
1588 else
1589 CM_DecompressVis (map_visibility + map_vis->bitofs[cluster][DVIS_PHS], phsrow);
1590 return phsrow;
1591 }
1592
1593
1594 /*
1595 ===============================================================================
1596
1597 AREAPORTALS
1598
1599 ===============================================================================
1600 */
1601
FloodArea_r(carea_t * area,int floodnum)1602 void FloodArea_r (carea_t *area, int floodnum)
1603 {
1604 int i;
1605 dareaportal_t *p;
1606
1607 if (area->floodvalid == floodvalid)
1608 {
1609 if (area->floodnum == floodnum)
1610 return;
1611 Com_Error (ERR_DROP, "FloodArea_r: reflooded");
1612 }
1613
1614 area->floodnum = floodnum;
1615 area->floodvalid = floodvalid;
1616 p = &map_areaportals[area->firstareaportal];
1617 for (i=0 ; i<area->numareaportals ; i++, p++)
1618 {
1619 if (portalopen[p->portalnum])
1620 FloodArea_r (&map_areas[p->otherarea], floodnum);
1621 }
1622 }
1623
1624 /*
1625 ====================
1626 FloodAreaConnections
1627
1628
1629 ====================
1630 */
FloodAreaConnections(void)1631 void FloodAreaConnections (void)
1632 {
1633 int i;
1634 carea_t *area;
1635 int floodnum;
1636
1637 // all current floods are now invalid
1638 floodvalid++;
1639 floodnum = 0;
1640
1641 // area 0 is not used
1642 for (i=1 ; i<numareas ; i++)
1643 {
1644 area = &map_areas[i];
1645 if (area->floodvalid == floodvalid)
1646 continue; // already flooded into
1647 floodnum++;
1648 FloodArea_r (area, floodnum);
1649 }
1650
1651 }
1652
CM_SetAreaPortalState(int portalnum,qboolean open)1653 void CM_SetAreaPortalState (int portalnum, qboolean open)
1654 {
1655 if (portalnum > numareaportals)
1656 Com_Error (ERR_DROP, "areaportal > numareaportals");
1657
1658 portalopen[portalnum] = open;
1659 FloodAreaConnections ();
1660 }
1661
CM_AreasConnected(int area1,int area2)1662 qboolean CM_AreasConnected (int area1, int area2)
1663 {
1664 if (map_noareas->value)
1665 return true;
1666
1667 if (area1 > numareas || area2 > numareas)
1668 Com_Error (ERR_DROP, "area > numareas");
1669
1670 if (map_areas[area1].floodnum == map_areas[area2].floodnum)
1671 return true;
1672 return false;
1673 }
1674
1675
1676 /*
1677 =================
1678 CM_WriteAreaBits
1679
1680 Writes a length byte followed by a bit vector of all the areas
1681 that area in the same flood as the area parameter
1682
1683 This is used by the client refreshes to cull visibility
1684 =================
1685 */
CM_WriteAreaBits(byte * buffer,int area)1686 int CM_WriteAreaBits (byte *buffer, int area)
1687 {
1688 int i;
1689 int floodnum;
1690 int bytes;
1691
1692 bytes = (numareas+7)>>3;
1693
1694 if (map_noareas->value)
1695 { // for debugging, send everything
1696 memset (buffer, 255, bytes);
1697 }
1698 else
1699 {
1700 memset (buffer, 0, bytes);
1701
1702 floodnum = map_areas[area].floodnum;
1703 for (i=0 ; i<numareas ; i++)
1704 {
1705 if (map_areas[i].floodnum == floodnum || !area)
1706 buffer[i>>3] |= 1<<(i&7);
1707 }
1708 }
1709
1710 return bytes;
1711 }
1712
1713
1714 /*
1715 ===================
1716 CM_WritePortalState
1717
1718 Writes the portal state to a savegame file
1719 ===================
1720 */
CM_WritePortalState(FILE * f)1721 void CM_WritePortalState (FILE *f)
1722 {
1723 fwrite (portalopen, sizeof(portalopen), 1, f);
1724 }
1725
1726 /*
1727 ===================
1728 CM_ReadPortalState
1729
1730 Reads the portal state from a savegame file
1731 and recalculates the area connections
1732 ===================
1733 */
CM_ReadPortalState(FILE * f)1734 void CM_ReadPortalState (FILE *f)
1735 {
1736 FS_Read (portalopen, sizeof(portalopen), f);
1737 FloodAreaConnections ();
1738 }
1739
1740 /*
1741 =============
1742 CM_HeadnodeVisible
1743
1744 Returns true if any leaf under headnode has a cluster that
1745 is potentially visible
1746 =============
1747 */
CM_HeadnodeVisible(int nodenum,byte * visbits)1748 qboolean CM_HeadnodeVisible (int nodenum, byte *visbits)
1749 {
1750 int leafnum;
1751 int cluster;
1752 cnode_t *node;
1753
1754 if (nodenum < 0)
1755 {
1756 leafnum = -1-nodenum;
1757 cluster = map_leafs[leafnum].cluster;
1758 if (cluster == -1)
1759 return false;
1760 if (visbits[cluster>>3] & (1<<(cluster&7)))
1761 return true;
1762 return false;
1763 }
1764
1765 node = &map_nodes[nodenum];
1766 if (CM_HeadnodeVisible(node->children[0], visbits))
1767 return true;
1768 return CM_HeadnodeVisible(node->children[1], visbits);
1769 }
1770
1771