1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 
5 This file is part of Quake III Arena source code.
6 
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 // cmodel.c -- model loading
23 
24 #include "cm_local.h"
25 
26 #ifdef BSPC
27 
28 #include "../bspc/l_qfiles.h"
29 
SetPlaneSignbits(cplane_t * out)30 void SetPlaneSignbits (cplane_t *out) {
31 	int	bits, j;
32 
33 	// for fast box on planeside test
34 	bits = 0;
35 	for (j=0 ; j<3 ; j++) {
36 		if (out->normal[j] < 0) {
37 			bits |= 1<<j;
38 		}
39 	}
40 	out->signbits = bits;
41 }
42 #endif //BSPC
43 
44 // to allow boxes to be treated as brush models, we allocate
45 // some extra indexes along with those needed by the map
46 #define	BOX_BRUSHES		1
47 #define	BOX_SIDES		6
48 #define	BOX_LEAFS		2
49 #define	BOX_PLANES		12
50 
51 #define	LL(x) x=LittleLong(x)
52 
53 
54 clipMap_t	cm;
55 int			c_pointcontents;
56 int			c_traces, c_brush_traces, c_patch_traces;
57 
58 
59 byte		*cmod_base;
60 
61 #ifndef BSPC
62 cvar_t		*cm_noAreas;
63 cvar_t		*cm_noCurves;
64 cvar_t		*cm_playerCurveClip;
65 #endif
66 
67 cmodel_t	box_model;
68 cplane_t	*box_planes;
69 cbrush_t	*box_brush;
70 
71 
72 
73 void	CM_InitBoxHull (void);
74 void	CM_FloodAreaConnections (void);
75 
76 
77 /*
78 ===============================================================================
79 
80 					MAP LOADING
81 
82 ===============================================================================
83 */
84 
85 /*
86 =================
87 CMod_LoadShaders
88 =================
89 */
CMod_LoadShaders(lump_t * l)90 void CMod_LoadShaders( lump_t *l ) {
91 	dshader_t	*in, *out;
92 	int			i, count;
93 
94 	in = (void *)(cmod_base + l->fileofs);
95 	if (l->filelen % sizeof(*in)) {
96 		Com_Error (ERR_DROP, "CMod_LoadShaders: funny lump size");
97 	}
98 	count = l->filelen / sizeof(*in);
99 
100 	if (count < 1) {
101 		Com_Error (ERR_DROP, "Map with no shaders");
102 	}
103 	cm.shaders = Hunk_Alloc( count * sizeof( *cm.shaders ), h_high );
104 	cm.numShaders = count;
105 
106 	Com_Memcpy( cm.shaders, in, count * sizeof( *cm.shaders ) );
107 
108 	out = cm.shaders;
109 	for ( i=0 ; i<count ; i++, in++, out++ ) {
110 		out->contentFlags = LittleLong( out->contentFlags );
111 		out->surfaceFlags = LittleLong( out->surfaceFlags );
112 	}
113 }
114 
115 
116 /*
117 =================
118 CMod_LoadSubmodels
119 =================
120 */
CMod_LoadSubmodels(lump_t * l)121 void CMod_LoadSubmodels( lump_t *l ) {
122 	dmodel_t	*in;
123 	cmodel_t	*out;
124 	int			i, j, count;
125 	int			*indexes;
126 
127 	in = (void *)(cmod_base + l->fileofs);
128 	if (l->filelen % sizeof(*in))
129 		Com_Error (ERR_DROP, "CMod_LoadSubmodels: funny lump size");
130 	count = l->filelen / sizeof(*in);
131 
132 	if (count < 1)
133 		Com_Error (ERR_DROP, "Map with no models");
134 	cm.cmodels = Hunk_Alloc( count * sizeof( *cm.cmodels ), h_high );
135 	cm.numSubModels = count;
136 
137 	if ( count > MAX_SUBMODELS ) {
138 		Com_Error( ERR_DROP, "MAX_SUBMODELS exceeded" );
139 	}
140 
141 	for ( i=0 ; i<count ; i++, in++, out++)
142 	{
143 		out = &cm.cmodels[i];
144 
145 		for (j=0 ; j<3 ; j++)
146 		{	// spread the mins / maxs by a pixel
147 			out->mins[j] = LittleFloat (in->mins[j]) - 1;
148 			out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
149 		}
150 
151 		if ( i == 0 ) {
152 			continue;	// world model doesn't need other info
153 		}
154 
155 		// make a "leaf" just to hold the model's brushes and surfaces
156 		out->leaf.numLeafBrushes = LittleLong( in->numBrushes );
157 		indexes = Hunk_Alloc( out->leaf.numLeafBrushes * 4, h_high );
158 		out->leaf.firstLeafBrush = indexes - cm.leafbrushes;
159 		for ( j = 0 ; j < out->leaf.numLeafBrushes ; j++ ) {
160 			indexes[j] = LittleLong( in->firstBrush ) + j;
161 		}
162 
163 		out->leaf.numLeafSurfaces = LittleLong( in->numSurfaces );
164 		indexes = Hunk_Alloc( out->leaf.numLeafSurfaces * 4, h_high );
165 		out->leaf.firstLeafSurface = indexes - cm.leafsurfaces;
166 		for ( j = 0 ; j < out->leaf.numLeafSurfaces ; j++ ) {
167 			indexes[j] = LittleLong( in->firstSurface ) + j;
168 		}
169 	}
170 }
171 
172 
173 /*
174 =================
175 CMod_LoadNodes
176 
177 =================
178 */
CMod_LoadNodes(lump_t * l)179 void CMod_LoadNodes( lump_t *l ) {
180 	dnode_t		*in;
181 	int			child;
182 	cNode_t		*out;
183 	int			i, j, count;
184 
185 	in = (void *)(cmod_base + l->fileofs);
186 	if (l->filelen % sizeof(*in))
187 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
188 	count = l->filelen / sizeof(*in);
189 
190 	if (count < 1)
191 		Com_Error (ERR_DROP, "Map has no nodes");
192 	cm.nodes = Hunk_Alloc( count * sizeof( *cm.nodes ), h_high );
193 	cm.numNodes = count;
194 
195 	out = cm.nodes;
196 
197 	for (i=0 ; i<count ; i++, out++, in++)
198 	{
199 		out->plane = cm.planes + LittleLong( in->planeNum );
200 		for (j=0 ; j<2 ; j++)
201 		{
202 			child = LittleLong (in->children[j]);
203 			out->children[j] = child;
204 		}
205 	}
206 
207 }
208 
209 /*
210 =================
211 CM_BoundBrush
212 
213 =================
214 */
CM_BoundBrush(cbrush_t * b)215 void CM_BoundBrush( cbrush_t *b ) {
216 	b->bounds[0][0] = -b->sides[0].plane->dist;
217 	b->bounds[1][0] = b->sides[1].plane->dist;
218 
219 	b->bounds[0][1] = -b->sides[2].plane->dist;
220 	b->bounds[1][1] = b->sides[3].plane->dist;
221 
222 	b->bounds[0][2] = -b->sides[4].plane->dist;
223 	b->bounds[1][2] = b->sides[5].plane->dist;
224 }
225 
226 
227 /*
228 =================
229 CMod_LoadBrushes
230 
231 =================
232 */
CMod_LoadBrushes(lump_t * l)233 void CMod_LoadBrushes( lump_t *l ) {
234 	dbrush_t	*in;
235 	cbrush_t	*out;
236 	int			i, count;
237 
238 	in = (void *)(cmod_base + l->fileofs);
239 	if (l->filelen % sizeof(*in)) {
240 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
241 	}
242 	count = l->filelen / sizeof(*in);
243 
244 	cm.brushes = Hunk_Alloc( ( BOX_BRUSHES + count ) * sizeof( *cm.brushes ), h_high );
245 	cm.numBrushes = count;
246 
247 	out = cm.brushes;
248 
249 	for ( i=0 ; i<count ; i++, out++, in++ ) {
250 		out->sides = cm.brushsides + LittleLong(in->firstSide);
251 		out->numsides = LittleLong(in->numSides);
252 
253 		out->shaderNum = LittleLong( in->shaderNum );
254 		if ( out->shaderNum < 0 || out->shaderNum >= cm.numShaders ) {
255 			Com_Error( ERR_DROP, "CMod_LoadBrushes: bad shaderNum: %i", out->shaderNum );
256 		}
257 		out->contents = cm.shaders[out->shaderNum].contentFlags;
258 
259 		CM_BoundBrush( out );
260 	}
261 
262 }
263 
264 /*
265 =================
266 CMod_LoadLeafs
267 =================
268 */
CMod_LoadLeafs(lump_t * l)269 void CMod_LoadLeafs (lump_t *l)
270 {
271 	int			i;
272 	cLeaf_t		*out;
273 	dleaf_t 	*in;
274 	int			count;
275 
276 	in = (void *)(cmod_base + l->fileofs);
277 	if (l->filelen % sizeof(*in))
278 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
279 	count = l->filelen / sizeof(*in);
280 
281 	if (count < 1)
282 		Com_Error (ERR_DROP, "Map with no leafs");
283 
284 	cm.leafs = Hunk_Alloc( ( BOX_LEAFS + count ) * sizeof( *cm.leafs ), h_high );
285 	cm.numLeafs = count;
286 
287 	out = cm.leafs;
288 	for ( i=0 ; i<count ; i++, in++, out++)
289 	{
290 		out->cluster = LittleLong (in->cluster);
291 		out->area = LittleLong (in->area);
292 		out->firstLeafBrush = LittleLong (in->firstLeafBrush);
293 		out->numLeafBrushes = LittleLong (in->numLeafBrushes);
294 		out->firstLeafSurface = LittleLong (in->firstLeafSurface);
295 		out->numLeafSurfaces = LittleLong (in->numLeafSurfaces);
296 
297 		if (out->cluster >= cm.numClusters)
298 			cm.numClusters = out->cluster + 1;
299 		if (out->area >= cm.numAreas)
300 			cm.numAreas = out->area + 1;
301 	}
302 
303 	cm.areas = Hunk_Alloc( cm.numAreas * sizeof( *cm.areas ), h_high );
304 	cm.areaPortals = Hunk_Alloc( cm.numAreas * cm.numAreas * sizeof( *cm.areaPortals ), h_high );
305 }
306 
307 /*
308 =================
309 CMod_LoadPlanes
310 =================
311 */
CMod_LoadPlanes(lump_t * l)312 void CMod_LoadPlanes (lump_t *l)
313 {
314 	int			i, j;
315 	cplane_t	*out;
316 	dplane_t 	*in;
317 	int			count;
318 	int			bits;
319 
320 	in = (void *)(cmod_base + l->fileofs);
321 	if (l->filelen % sizeof(*in))
322 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
323 	count = l->filelen / sizeof(*in);
324 
325 	if (count < 1)
326 		Com_Error (ERR_DROP, "Map with no planes");
327 	cm.planes = Hunk_Alloc( ( BOX_PLANES + count ) * sizeof( *cm.planes ), h_high );
328 	cm.numPlanes = count;
329 
330 	out = cm.planes;
331 
332 	for ( i=0 ; i<count ; i++, in++, out++)
333 	{
334 		bits = 0;
335 		for (j=0 ; j<3 ; j++)
336 		{
337 			out->normal[j] = LittleFloat (in->normal[j]);
338 			if (out->normal[j] < 0)
339 				bits |= 1<<j;
340 		}
341 
342 		out->dist = LittleFloat (in->dist);
343 		out->type = PlaneTypeForNormal( out->normal );
344 		out->signbits = bits;
345 	}
346 }
347 
348 /*
349 =================
350 CMod_LoadLeafBrushes
351 =================
352 */
CMod_LoadLeafBrushes(lump_t * l)353 void CMod_LoadLeafBrushes (lump_t *l)
354 {
355 	int			i;
356 	int			*out;
357 	int		 	*in;
358 	int			count;
359 
360 	in = (void *)(cmod_base + l->fileofs);
361 	if (l->filelen % sizeof(*in))
362 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
363 	count = l->filelen / sizeof(*in);
364 
365 	cm.leafbrushes = Hunk_Alloc( (count + BOX_BRUSHES) * sizeof( *cm.leafbrushes ), h_high );
366 	cm.numLeafBrushes = count;
367 
368 	out = cm.leafbrushes;
369 
370 	for ( i=0 ; i<count ; i++, in++, out++) {
371 		*out = LittleLong (*in);
372 	}
373 }
374 
375 /*
376 =================
377 CMod_LoadLeafSurfaces
378 =================
379 */
CMod_LoadLeafSurfaces(lump_t * l)380 void CMod_LoadLeafSurfaces( lump_t *l )
381 {
382 	int			i;
383 	int			*out;
384 	int		 	*in;
385 	int			count;
386 
387 	in = (void *)(cmod_base + l->fileofs);
388 	if (l->filelen % sizeof(*in))
389 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
390 	count = l->filelen / sizeof(*in);
391 
392 	cm.leafsurfaces = Hunk_Alloc( count * sizeof( *cm.leafsurfaces ), h_high );
393 	cm.numLeafSurfaces = count;
394 
395 	out = cm.leafsurfaces;
396 
397 	for ( i=0 ; i<count ; i++, in++, out++) {
398 		*out = LittleLong (*in);
399 	}
400 }
401 
402 /*
403 =================
404 CMod_LoadBrushSides
405 =================
406 */
CMod_LoadBrushSides(lump_t * l)407 void CMod_LoadBrushSides (lump_t *l)
408 {
409 	int				i;
410 	cbrushside_t	*out;
411 	dbrushside_t 	*in;
412 	int				count;
413 	int				num;
414 
415 	in = (void *)(cmod_base + l->fileofs);
416 	if ( l->filelen % sizeof(*in) ) {
417 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
418 	}
419 	count = l->filelen / sizeof(*in);
420 
421 	cm.brushsides = Hunk_Alloc( ( BOX_SIDES + count ) * sizeof( *cm.brushsides ), h_high );
422 	cm.numBrushSides = count;
423 
424 	out = cm.brushsides;
425 
426 	for ( i=0 ; i<count ; i++, in++, out++) {
427 		num = LittleLong( in->planeNum );
428 		out->plane = &cm.planes[num];
429 		out->shaderNum = LittleLong( in->shaderNum );
430 		if ( out->shaderNum < 0 || out->shaderNum >= cm.numShaders ) {
431 			Com_Error( ERR_DROP, "CMod_LoadBrushSides: bad shaderNum: %i", out->shaderNum );
432 		}
433 		out->surfaceFlags = cm.shaders[out->shaderNum].surfaceFlags;
434 	}
435 }
436 
437 
438 /*
439 =================
440 CMod_LoadEntityString
441 =================
442 */
CMod_LoadEntityString(lump_t * l)443 void CMod_LoadEntityString( lump_t *l ) {
444 	cm.entityString = Hunk_Alloc( l->filelen, h_high );
445 	cm.numEntityChars = l->filelen;
446 	Com_Memcpy (cm.entityString, cmod_base + l->fileofs, l->filelen);
447 }
448 
449 /*
450 =================
451 CMod_LoadVisibility
452 =================
453 */
454 #define	VIS_HEADER	8
CMod_LoadVisibility(lump_t * l)455 void CMod_LoadVisibility( lump_t *l ) {
456 	int		len;
457 	byte	*buf;
458 
459     len = l->filelen;
460 	if ( !len ) {
461 		cm.clusterBytes = ( cm.numClusters + 31 ) & ~31;
462 		cm.visibility = Hunk_Alloc( cm.clusterBytes, h_high );
463 		Com_Memset( cm.visibility, 255, cm.clusterBytes );
464 		return;
465 	}
466 	buf = cmod_base + l->fileofs;
467 
468 	cm.vised = qtrue;
469 	cm.visibility = Hunk_Alloc( len, h_high );
470 	cm.numClusters = LittleLong( ((int *)buf)[0] );
471 	cm.clusterBytes = LittleLong( ((int *)buf)[1] );
472 	Com_Memcpy (cm.visibility, buf + VIS_HEADER, len - VIS_HEADER );
473 }
474 
475 //==================================================================
476 
477 
478 /*
479 =================
480 CMod_LoadPatches
481 =================
482 */
483 #define	MAX_PATCH_VERTS		1024
CMod_LoadPatches(lump_t * surfs,lump_t * verts)484 void CMod_LoadPatches( lump_t *surfs, lump_t *verts ) {
485 	drawVert_t	*dv, *dv_p;
486 	dsurface_t	*in;
487 	int			count;
488 	int			i, j;
489 	int			c;
490 	cPatch_t	*patch;
491 	vec3_t		points[MAX_PATCH_VERTS];
492 	int			width, height;
493 	int			shaderNum;
494 
495 	in = (void *)(cmod_base + surfs->fileofs);
496 	if (surfs->filelen % sizeof(*in))
497 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
498 	cm.numSurfaces = count = surfs->filelen / sizeof(*in);
499 	cm.surfaces = Hunk_Alloc( cm.numSurfaces * sizeof( cm.surfaces[0] ), h_high );
500 
501 	dv = (void *)(cmod_base + verts->fileofs);
502 	if (verts->filelen % sizeof(*dv))
503 		Com_Error (ERR_DROP, "MOD_LoadBmodel: funny lump size");
504 
505 	// scan through all the surfaces, but only load patches,
506 	// not planar faces
507 	for ( i = 0 ; i < count ; i++, in++ ) {
508 		if ( LittleLong( in->surfaceType ) != MST_PATCH ) {
509 			continue;		// ignore other surfaces
510 		}
511 		// FIXME: check for non-colliding patches
512 
513 		cm.surfaces[ i ] = patch = Hunk_Alloc( sizeof( *patch ), h_high );
514 
515 		// load the full drawverts onto the stack
516 		width = LittleLong( in->patchWidth );
517 		height = LittleLong( in->patchHeight );
518 		c = width * height;
519 		if ( c > MAX_PATCH_VERTS ) {
520 			Com_Error( ERR_DROP, "ParseMesh: MAX_PATCH_VERTS" );
521 		}
522 
523 		dv_p = dv + LittleLong( in->firstVert );
524 		for ( j = 0 ; j < c ; j++, dv_p++ ) {
525 			points[j][0] = LittleFloat( dv_p->xyz[0] );
526 			points[j][1] = LittleFloat( dv_p->xyz[1] );
527 			points[j][2] = LittleFloat( dv_p->xyz[2] );
528 		}
529 
530 		shaderNum = LittleLong( in->shaderNum );
531 		patch->contents = cm.shaders[shaderNum].contentFlags;
532 		patch->surfaceFlags = cm.shaders[shaderNum].surfaceFlags;
533 
534 		// create the internal facet structure
535 		patch->pc = CM_GeneratePatchCollide( width, height, points );
536 	}
537 }
538 
539 //==================================================================
540 
CM_LumpChecksum(lump_t * lump)541 unsigned CM_LumpChecksum(lump_t *lump) {
542 	return LittleLong (Com_BlockChecksum (cmod_base + lump->fileofs, lump->filelen));
543 }
544 
CM_Checksum(dheader_t * header)545 unsigned CM_Checksum(dheader_t *header) {
546 	unsigned checksums[16];
547 	checksums[0] = CM_LumpChecksum(&header->lumps[LUMP_SHADERS]);
548 	checksums[1] = CM_LumpChecksum(&header->lumps[LUMP_LEAFS]);
549 	checksums[2] = CM_LumpChecksum(&header->lumps[LUMP_LEAFBRUSHES]);
550 	checksums[3] = CM_LumpChecksum(&header->lumps[LUMP_LEAFSURFACES]);
551 	checksums[4] = CM_LumpChecksum(&header->lumps[LUMP_PLANES]);
552 	checksums[5] = CM_LumpChecksum(&header->lumps[LUMP_BRUSHSIDES]);
553 	checksums[6] = CM_LumpChecksum(&header->lumps[LUMP_BRUSHES]);
554 	checksums[7] = CM_LumpChecksum(&header->lumps[LUMP_MODELS]);
555 	checksums[8] = CM_LumpChecksum(&header->lumps[LUMP_NODES]);
556 	checksums[9] = CM_LumpChecksum(&header->lumps[LUMP_SURFACES]);
557 	checksums[10] = CM_LumpChecksum(&header->lumps[LUMP_DRAWVERTS]);
558 
559 	return LittleLong(Com_BlockChecksum(checksums, 11 * 4));
560 }
561 
562 /*
563 ==================
564 CM_LoadMap
565 
566 Loads in the map and all submodels
567 ==================
568 */
CM_LoadMap(const char * name,qboolean clientload,int * checksum)569 void CM_LoadMap( const char *name, qboolean clientload, int *checksum ) {
570 	int				*buf;
571 	int				i;
572 	dheader_t		header;
573 	int				length;
574 	static unsigned	last_checksum;
575 
576 	if ( !name || !name[0] ) {
577 		Com_Error( ERR_DROP, "CM_LoadMap: NULL name" );
578 	}
579 
580 #ifndef BSPC
581 	cm_noAreas = Cvar_Get ("cm_noAreas", "0", CVAR_CHEAT);
582 	cm_noCurves = Cvar_Get ("cm_noCurves", "0", CVAR_CHEAT);
583 	cm_playerCurveClip = Cvar_Get ("cm_playerCurveClip", "1", CVAR_ARCHIVE|CVAR_CHEAT );
584 #endif
585 	Com_DPrintf( "CM_LoadMap( %s, %i )\n", name, clientload );
586 
587 	if ( !strcmp( cm.name, name ) && clientload ) {
588 		*checksum = last_checksum;
589 		return;
590 	}
591 
592 	// free old stuff
593 	Com_Memset( &cm, 0, sizeof( cm ) );
594 	CM_ClearLevelPatches();
595 
596 	if ( !name[0] ) {
597 		cm.numLeafs = 1;
598 		cm.numClusters = 1;
599 		cm.numAreas = 1;
600 		cm.cmodels = Hunk_Alloc( sizeof( *cm.cmodels ), h_high );
601 		*checksum = 0;
602 		return;
603 	}
604 
605 	//
606 	// load the file
607 	//
608 #ifndef BSPC
609 	length = FS_ReadFile( name, (void **)&buf );
610 #else
611 	length = LoadQuakeFile((quakefile_t *) name, (void **)&buf);
612 #endif
613 
614 	if ( !buf ) {
615 		Com_Error (ERR_DROP, "Couldn't load %s", name);
616 	}
617 
618 	last_checksum = LittleLong (Com_BlockChecksum (buf, length));
619 	*checksum = last_checksum;
620 
621 	header = *(dheader_t *)buf;
622 	for (i=0 ; i<sizeof(dheader_t)/4 ; i++) {
623 		((int *)&header)[i] = LittleLong ( ((int *)&header)[i]);
624 	}
625 
626 	if ( header.version != BSP_VERSION ) {
627 		Com_Error (ERR_DROP, "CM_LoadMap: %s has wrong version number (%i should be %i)"
628 		, name, header.version, BSP_VERSION );
629 	}
630 
631 	cmod_base = (byte *)buf;
632 
633 	// load into heap
634 	CMod_LoadShaders( &header.lumps[LUMP_SHADERS] );
635 	CMod_LoadLeafs (&header.lumps[LUMP_LEAFS]);
636 	CMod_LoadLeafBrushes (&header.lumps[LUMP_LEAFBRUSHES]);
637 	CMod_LoadLeafSurfaces (&header.lumps[LUMP_LEAFSURFACES]);
638 	CMod_LoadPlanes (&header.lumps[LUMP_PLANES]);
639 	CMod_LoadBrushSides (&header.lumps[LUMP_BRUSHSIDES]);
640 	CMod_LoadBrushes (&header.lumps[LUMP_BRUSHES]);
641 	CMod_LoadSubmodels (&header.lumps[LUMP_MODELS]);
642 	CMod_LoadNodes (&header.lumps[LUMP_NODES]);
643 	CMod_LoadEntityString (&header.lumps[LUMP_ENTITIES]);
644 	CMod_LoadVisibility( &header.lumps[LUMP_VISIBILITY] );
645 	CMod_LoadPatches( &header.lumps[LUMP_SURFACES], &header.lumps[LUMP_DRAWVERTS] );
646 
647 	// we are NOT freeing the file, because it is cached for the ref
648 	FS_FreeFile (buf);
649 
650 	CM_InitBoxHull ();
651 
652 	CM_FloodAreaConnections ();
653 
654 	// allow this to be cached if it is loaded by the server
655 	if ( !clientload ) {
656 		Q_strncpyz( cm.name, name, sizeof( cm.name ) );
657 	}
658 }
659 
660 /*
661 ==================
662 CM_ClearMap
663 ==================
664 */
CM_ClearMap(void)665 void CM_ClearMap( void ) {
666 	Com_Memset( &cm, 0, sizeof( cm ) );
667 	CM_ClearLevelPatches();
668 }
669 
670 /*
671 ==================
672 CM_ClipHandleToModel
673 ==================
674 */
CM_ClipHandleToModel(clipHandle_t handle)675 cmodel_t	*CM_ClipHandleToModel( clipHandle_t handle ) {
676 	if ( handle < 0 ) {
677 		Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i", handle );
678 	}
679 	if ( handle < cm.numSubModels ) {
680 		return &cm.cmodels[handle];
681 	}
682 	if ( handle == BOX_MODEL_HANDLE ) {
683 		return &box_model;
684 	}
685 	if ( handle < MAX_SUBMODELS ) {
686 		Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i < %i < %i",
687 			cm.numSubModels, handle, MAX_SUBMODELS );
688 	}
689 	Com_Error( ERR_DROP, "CM_ClipHandleToModel: bad handle %i", handle + MAX_SUBMODELS );
690 
691 	return NULL;
692 
693 }
694 
695 /*
696 ==================
697 CM_InlineModel
698 ==================
699 */
CM_InlineModel(int index)700 clipHandle_t	CM_InlineModel( int index ) {
701 	if ( index < 0 || index >= cm.numSubModels ) {
702 		Com_Error (ERR_DROP, "CM_InlineModel: bad number");
703 	}
704 	return index;
705 }
706 
CM_NumClusters(void)707 int		CM_NumClusters( void ) {
708 	return cm.numClusters;
709 }
710 
CM_NumInlineModels(void)711 int		CM_NumInlineModels( void ) {
712 	return cm.numSubModels;
713 }
714 
CM_EntityString(void)715 char	*CM_EntityString( void ) {
716 	return cm.entityString;
717 }
718 
CM_LeafCluster(int leafnum)719 int		CM_LeafCluster( int leafnum ) {
720 	if (leafnum < 0 || leafnum >= cm.numLeafs) {
721 		Com_Error (ERR_DROP, "CM_LeafCluster: bad number");
722 	}
723 	return cm.leafs[leafnum].cluster;
724 }
725 
CM_LeafArea(int leafnum)726 int		CM_LeafArea( int leafnum ) {
727 	if ( leafnum < 0 || leafnum >= cm.numLeafs ) {
728 		Com_Error (ERR_DROP, "CM_LeafArea: bad number");
729 	}
730 	return cm.leafs[leafnum].area;
731 }
732 
733 //=======================================================================
734 
735 
736 /*
737 ===================
738 CM_InitBoxHull
739 
740 Set up the planes and nodes so that the six floats of a bounding box
741 can just be stored out and get a proper clipping hull structure.
742 ===================
743 */
CM_InitBoxHull(void)744 void CM_InitBoxHull (void)
745 {
746 	int			i;
747 	int			side;
748 	cplane_t	*p;
749 	cbrushside_t	*s;
750 
751 	box_planes = &cm.planes[cm.numPlanes];
752 
753 	box_brush = &cm.brushes[cm.numBrushes];
754 	box_brush->numsides = 6;
755 	box_brush->sides = cm.brushsides + cm.numBrushSides;
756 	box_brush->contents = CONTENTS_BODY;
757 
758 	box_model.leaf.numLeafBrushes = 1;
759 //	box_model.leaf.firstLeafBrush = cm.numBrushes;
760 	box_model.leaf.firstLeafBrush = cm.numLeafBrushes;
761 	cm.leafbrushes[cm.numLeafBrushes] = cm.numBrushes;
762 
763 	for (i=0 ; i<6 ; i++)
764 	{
765 		side = i&1;
766 
767 		// brush sides
768 		s = &cm.brushsides[cm.numBrushSides+i];
769 		s->plane = 	cm.planes + (cm.numPlanes+i*2+side);
770 		s->surfaceFlags = 0;
771 
772 		// planes
773 		p = &box_planes[i*2];
774 		p->type = i>>1;
775 		p->signbits = 0;
776 		VectorClear (p->normal);
777 		p->normal[i>>1] = 1;
778 
779 		p = &box_planes[i*2+1];
780 		p->type = 3 + (i>>1);
781 		p->signbits = 0;
782 		VectorClear (p->normal);
783 		p->normal[i>>1] = -1;
784 
785 		SetPlaneSignbits( p );
786 	}
787 }
788 
789 /*
790 ===================
791 CM_TempBoxModel
792 
793 To keep everything totally uniform, bounding boxes are turned into small
794 BSP trees instead of being compared directly.
795 Capsules are handled differently though.
796 ===================
797 */
CM_TempBoxModel(const vec3_t mins,const vec3_t maxs,int capsule)798 clipHandle_t CM_TempBoxModel( const vec3_t mins, const vec3_t maxs, int capsule ) {
799 
800 	VectorCopy( mins, box_model.mins );
801 	VectorCopy( maxs, box_model.maxs );
802 
803 	if ( capsule ) {
804 		return CAPSULE_MODEL_HANDLE;
805 	}
806 
807 	box_planes[0].dist = maxs[0];
808 	box_planes[1].dist = -maxs[0];
809 	box_planes[2].dist = mins[0];
810 	box_planes[3].dist = -mins[0];
811 	box_planes[4].dist = maxs[1];
812 	box_planes[5].dist = -maxs[1];
813 	box_planes[6].dist = mins[1];
814 	box_planes[7].dist = -mins[1];
815 	box_planes[8].dist = maxs[2];
816 	box_planes[9].dist = -maxs[2];
817 	box_planes[10].dist = mins[2];
818 	box_planes[11].dist = -mins[2];
819 
820 	VectorCopy( mins, box_brush->bounds[0] );
821 	VectorCopy( maxs, box_brush->bounds[1] );
822 
823 	return BOX_MODEL_HANDLE;
824 }
825 
826 /*
827 ===================
828 CM_ModelBounds
829 ===================
830 */
CM_ModelBounds(clipHandle_t model,vec3_t mins,vec3_t maxs)831 void CM_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) {
832 	cmodel_t	*cmod;
833 
834 	cmod = CM_ClipHandleToModel( model );
835 	VectorCopy( cmod->mins, mins );
836 	VectorCopy( cmod->maxs, maxs );
837 }
838 
839 
840