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