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