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