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