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