cm_load.c (20416B)
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 Foobar; 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 541 unsigned CM_LumpChecksum(lump_t *lump) { 542 return LittleLong (Com_BlockChecksum (cmod_base + lump->fileofs, lump->filelen)); 543 } 544 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 */ 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 */ 665 void CM_ClearMap( void ) { 666 Com_Memset( &cm, 0, sizeof( cm ) ); 667 CM_ClearLevelPatches(); 668 } 669 670 /* 671 ================== 672 CM_ClipHandleToModel 673 ================== 674 */ 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 */ 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 707 int CM_NumClusters( void ) { 708 return cm.numClusters; 709 } 710 711 int CM_NumInlineModels( void ) { 712 return cm.numSubModels; 713 } 714 715 char *CM_EntityString( void ) { 716 return cm.entityString; 717 } 718 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 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 */ 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 */ 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 */ 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