|
|
1.1.1.3 ! root 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: */ 1.1 root 20: // cmodel.c -- model loading 1.1.1.2 root 21: 1.1 root 22: #include "qcommon.h" 1.1.1.2 root 23: 1.1 root 24: typedef struct 25: { 26: cplane_t *plane; 27: int children[2]; // negative numbers are leafs 28: } cnode_t; 1.1.1.2 root 29: 1.1 root 30: typedef struct 31: { 32: cplane_t *plane; 1.1.1.2 root 33: mapsurface_t *surface; 1.1 root 34: } cbrushside_t; 1.1.1.2 root 35: 1.1 root 36: typedef struct 37: { 38: int contents; 39: int cluster; 40: int area; 41: unsigned short firstleafbrush; 42: unsigned short numleafbrushes; 43: } cleaf_t; 1.1.1.2 root 44: 1.1 root 45: typedef struct 46: { 47: int contents; 48: int numsides; 49: int firstbrushside; 50: int checkcount; // to avoid repeated testings 51: } cbrush_t; 1.1.1.2 root 52: 1.1 root 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; 1.1.1.2 root 60: 1.1 root 61: int checkcount; 1.1.1.2 root 62: 1.1 root 63: char map_name[MAX_QPATH]; 1.1.1.2 root 64: 1.1 root 65: int numbrushsides; 66: cbrushside_t map_brushsides[MAX_MAP_BRUSHSIDES]; 1.1.1.2 root 67: 1.1 root 68: int numtexinfo; 1.1.1.2 root 69: mapsurface_t map_surfaces[MAX_MAP_TEXINFO]; 70: 1.1 root 71: int numplanes; 72: cplane_t map_planes[MAX_MAP_PLANES+6]; // extra for box hull 1.1.1.2 root 73: 1.1 root 74: int numnodes; 75: cnode_t map_nodes[MAX_MAP_NODES+6]; // extra for box hull 1.1.1.2 root 76: 1.1 root 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; 1.1.1.2 root 80: 1.1 root 81: int numleafbrushes; 82: unsigned short map_leafbrushes[MAX_MAP_LEAFBRUSHES]; 1.1.1.2 root 83: 1.1 root 84: int numcmodels; 85: cmodel_t map_cmodels[MAX_MAP_MODELS]; 1.1.1.2 root 86: 1.1 root 87: int numbrushes; 88: cbrush_t map_brushes[MAX_MAP_BRUSHES]; 1.1.1.2 root 89: 1.1 root 90: int numvisibility; 91: byte map_visibility[MAX_MAP_VISIBILITY]; 92: dvis_t *map_vis = (dvis_t *)map_visibility; 1.1.1.2 root 93: 1.1 root 94: int numentitychars; 95: char map_entitystring[MAX_MAP_ENTSTRING]; 1.1.1.2 root 96: 1.1 root 97: int numareas = 1; 98: carea_t map_areas[MAX_MAP_AREAS]; 1.1.1.2 root 99: 1.1 root 100: int numareaportals; 101: dareaportal_t map_areaportals[MAX_MAP_AREAPORTALS]; 1.1.1.2 root 102: 1.1 root 103: int numclusters = 1; 1.1.1.2 root 104: 105: mapsurface_t nullsurface; 106: 1.1 root 107: int floodvalid; 1.1.1.2 root 108: 1.1 root 109: qboolean portalopen[MAX_MAP_AREAPORTALS]; 1.1.1.2 root 110: 111: 1.1 root 112: cvar_t *map_noareas; 1.1.1.2 root 113: 1.1 root 114: void CM_InitBoxHull (void); 115: void FloodAreaConnections (void); 1.1.1.2 root 116: 117: 1.1 root 118: int c_pointcontents; 119: int c_traces, c_brush_traces; 1.1.1.2 root 120: 121: 1.1 root 122: /* 123: =============================================================================== 1.1.1.2 root 124: 1.1 root 125: MAP LOADING 1.1.1.2 root 126: 1.1 root 127: =============================================================================== 128: */ 1.1.1.2 root 129: 1.1 root 130: byte *cmod_base; 1.1.1.2 root 131: 1.1 root 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; 1.1.1.2 root 142: 1.1 root 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); 1.1.1.2 root 147: 1.1 root 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"); 1.1.1.2 root 152: 1.1 root 153: numcmodels = count; 1.1.1.2 root 154: 1.1 root 155: for ( i=0 ; i<count ; i++, in++, out++) 156: { 157: out = &map_cmodels[i]; 1.1.1.2 root 158: 1.1 root 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: } 1.1.1.2 root 168: 169: 1.1 root 170: /* 171: ================= 172: CMod_LoadSurfaces 173: ================= 174: */ 175: void CMod_LoadSurfaces (lump_t *l) 176: { 177: texinfo_t *in; 1.1.1.2 root 178: mapsurface_t *out; 1.1 root 179: int i, count; 1.1.1.2 root 180: 1.1 root 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"); 1.1.1.2 root 189: 1.1 root 190: numtexinfo = count; 191: out = map_surfaces; 1.1.1.2 root 192: 1.1 root 193: for ( i=0 ; i<count ; i++, in++, out++) 194: { 1.1.1.2 root 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); 1.1 root 199: } 200: } 1.1.1.2 root 201: 202: 1.1 root 203: /* 204: ================= 205: CMod_LoadNodes 1.1.1.2 root 206: 1.1 root 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); 1.1.1.2 root 220: 1.1 root 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"); 1.1.1.2 root 225: 1.1 root 226: out = map_nodes; 1.1.1.2 root 227: 1.1 root 228: numnodes = count; 1.1.1.2 root 229: 1.1 root 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: } 1.1.1.2 root 239: 1.1 root 240: } 1.1.1.2 root 241: 1.1 root 242: /* 243: ================= 244: CMod_LoadBrushes 1.1.1.2 root 245: 1.1 root 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); 1.1.1.2 root 258: 1.1 root 259: if (count > MAX_MAP_BRUSHES) 260: Com_Error (ERR_DROP, "Map has too many brushes"); 1.1.1.2 root 261: 1.1 root 262: out = map_brushes; 1.1.1.2 root 263: 1.1 root 264: numbrushes = count; 1.1.1.2 root 265: 1.1 root 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: } 1.1.1.2 root 272: 1.1 root 273: } 1.1.1.2 root 274: 1.1 root 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); 1.1.1.2 root 291: 1.1 root 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"); 1.1.1.2 root 297: 1.1 root 298: out = map_leafs; 299: numleafs = count; 300: numclusters = 0; 1.1.1.2 root 301: 1.1 root 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); 1.1.1.2 root 309: 1.1 root 310: if (out->cluster >= numclusters) 311: numclusters = out->cluster + 1; 312: } 1.1.1.2 root 313: 1.1 root 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: } 1.1.1.2 root 329: 1.1 root 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); 1.1.1.2 root 347: 1.1 root 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"); 1.1.1.2 root 353: 1.1 root 354: out = map_planes; 355: numplanes = count; 1.1.1.2 root 356: 1.1 root 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: } 1.1.1.2 root 366: 1.1 root 367: out->dist = LittleFloat (in->dist); 368: out->type = LittleLong (in->type); 369: out->signbits = bits; 370: } 371: } 1.1.1.2 root 372: 1.1 root 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); 1.1.1.2 root 389: 1.1 root 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"); 1.1.1.2 root 395: 1.1 root 396: out = map_leafbrushes; 397: numleafbrushes = count; 1.1.1.2 root 398: 1.1 root 399: for ( i=0 ; i<count ; i++, in++, out++) 400: *out = LittleShort (*in); 401: } 1.1.1.2 root 402: 1.1 root 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; 1.1.1.2 root 415: 1.1 root 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); 1.1.1.2 root 420: 1.1 root 421: // need to save space for box planes 422: if (count > MAX_MAP_BRUSHSIDES) 423: Com_Error (ERR_DROP, "Map has too many planes"); 1.1.1.2 root 424: 1.1 root 425: out = map_brushsides; 426: numbrushsides = count; 1.1.1.2 root 427: 1.1 root 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: } 1.1.1.2 root 438: 1.1 root 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; 1.1.1.2 root 450: 1.1 root 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); 1.1.1.2 root 455: 1.1 root 456: if (count > MAX_MAP_AREAS) 457: Com_Error (ERR_DROP, "Map has too many areas"); 1.1.1.2 root 458: 1.1 root 459: out = map_areas; 460: numareas = count; 1.1.1.2 root 461: 1.1 root 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: } 1.1.1.2 root 470: 1.1 root 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; 1.1.1.2 root 482: 1.1 root 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); 1.1.1.2 root 487: 1.1 root 488: if (count > MAX_MAP_AREAS) 489: Com_Error (ERR_DROP, "Map has too many areas"); 1.1.1.2 root 490: 1.1 root 491: out = map_areaportals; 492: numareaportals = count; 1.1.1.2 root 493: 1.1 root 494: for ( i=0 ; i<count ; i++, in++, out++) 495: { 496: out->portalnum = LittleLong (in->portalnum); 497: out->otherarea = LittleLong (in->otherarea); 498: } 499: } 1.1.1.2 root 500: 1.1 root 501: /* 502: ================= 503: CMod_LoadVisibility 504: ================= 505: */ 506: void CMod_LoadVisibility (lump_t *l) 507: { 508: int i; 1.1.1.2 root 509: 1.1 root 510: numvisibility = l->filelen; 511: if (l->filelen > MAX_MAP_VISIBILITY) 512: Com_Error (ERR_DROP, "Map has too large visibility lump"); 1.1.1.2 root 513: 1.1 root 514: memcpy (map_visibility, cmod_base + l->fileofs, l->filelen); 1.1.1.2 root 515: 1.1 root 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: } 1.1.1.2 root 523: 524: 1.1 root 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"); 1.1.1.2 root 535: 1.1 root 536: memcpy (map_entitystring, cmod_base + l->fileofs, l->filelen); 537: } 1.1.1.2 root 538: 539: 540: 1.1 root 541: /* 542: ================== 543: CM_LoadMap 1.1.1.2 root 544: 1.1 root 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; 1.1.1.2 root 555: 1.1 root 556: map_noareas = Cvar_Get ("map_noareas", "0", 0); 1.1.1.2 root 557: 1.1 root 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: } 1.1.1.2 root 568: 1.1 root 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; 1.1.1.2 root 578: 1.1 root 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: } 1.1.1.2 root 587: 1.1 root 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; 1.1.1.2 root 597: 1.1 root 598: header = *(dheader_t *)buf; 599: for (i=0 ; i<sizeof(dheader_t)/4 ; i++) 600: ((int *)&header)[i] = LittleLong ( ((int *)&header)[i]); 1.1.1.2 root 601: 1.1 root 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); 1.1.1.2 root 605: 1.1 root 606: cmod_base = (byte *)buf; 1.1.1.2 root 607: 1.1 root 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]); 1.1.1.2 root 621: 1.1 root 622: FS_FreeFile (buf); 1.1.1.2 root 623: 1.1 root 624: CM_InitBoxHull (); 1.1.1.2 root 625: 1.1 root 626: memset (portalopen, 0, sizeof(portalopen)); 627: FloodAreaConnections (); 1.1.1.2 root 628: 1.1 root 629: strcpy (map_name, name); 1.1.1.2 root 630: 1.1 root 631: return &map_cmodels[0]; 632: } 1.1.1.2 root 633: 1.1 root 634: /* 635: ================== 636: CM_InlineModel 637: ================== 638: */ 639: cmodel_t *CM_InlineModel (char *name) 640: { 641: int num; 1.1.1.2 root 642: 1.1 root 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"); 1.1.1.2 root 648: 1.1 root 649: return &map_cmodels[num]; 650: } 1.1.1.2 root 651: 1.1 root 652: int CM_NumClusters (void) 653: { 654: return numclusters; 655: } 1.1.1.2 root 656: 1.1 root 657: int CM_NumInlineModels (void) 658: { 659: return numcmodels; 660: } 1.1.1.2 root 661: 1.1 root 662: char *CM_EntityString (void) 663: { 664: return map_entitystring; 665: } 1.1.1.2 root 666: 1.1 root 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: } 1.1.1.2 root 673: 1.1 root 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: } 1.1.1.2 root 680: 1.1 root 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: } 1.1.1.2 root 687: 1.1 root 688: //======================================================================= 1.1.1.2 root 689: 690: 1.1 root 691: cplane_t *box_planes; 692: int box_headnode; 693: cbrush_t *box_brush; 694: cleaf_t *box_leaf; 1.1.1.2 root 695: 1.1 root 696: /* 697: =================== 698: CM_InitBoxHull 1.1.1.2 root 699: 1.1 root 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; 1.1.1.2 root 711: 1.1 root 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"); 1.1.1.2 root 720: 1.1 root 721: box_brush = &map_brushes[numbrushes]; 722: box_brush->numsides = 6; 723: box_brush->firstbrushside = numbrushsides; 724: box_brush->contents = CONTENTS_MONSTER; 1.1.1.2 root 725: 1.1 root 726: box_leaf = &map_leafs[numleafs]; 727: box_leaf->contents = CONTENTS_MONSTER; 728: box_leaf->firstleafbrush = numleafbrushes; 729: box_leaf->numleafbrushes = 1; 1.1.1.2 root 730: 1.1 root 731: map_leafbrushes[numleafbrushes] = numbrushes; 1.1.1.2 root 732: 1.1 root 733: for (i=0 ; i<6 ; i++) 734: { 735: side = i&1; 1.1.1.2 root 736: 1.1 root 737: // brush sides 738: s = &map_brushsides[numbrushsides+i]; 739: s->plane = map_planes + (numplanes+i*2+side); 740: s->surface = &nullsurface; 1.1.1.2 root 741: 1.1 root 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; 1.1.1.2 root 750: 1.1 root 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; 1.1.1.2 root 757: 1.1 root 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: } 1.1.1.2 root 765: 766: 1.1 root 767: /* 768: =================== 769: CM_HeadnodeForBox 1.1.1.2 root 770: 1.1 root 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]; 1.1.1.2 root 789: 1.1 root 790: return box_headnode; 791: } 1.1.1.2 root 792: 793: 1.1 root 794: /* 795: ================== 796: CM_PointLeafnum_r 1.1.1.2 root 797: 1.1 root 798: ================== 799: */ 800: int CM_PointLeafnum_r (vec3_t p, int num) 801: { 802: float d; 803: cnode_t *node; 804: cplane_t *plane; 1.1.1.2 root 805: 1.1 root 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: } 1.1.1.2 root 820: 1.1 root 821: c_pointcontents++; // optimize counter 1.1.1.2 root 822: 1.1 root 823: return -1 - num; 824: } 1.1.1.2 root 825: 1.1 root 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: } 1.1.1.2 root 832: 833: 834: 1.1 root 835: /* 836: ============= 837: CM_BoxLeafnums 1.1.1.2 root 838: 1.1 root 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; 1.1.1.2 root 846: 1.1 root 847: void CM_BoxLeafnums_r (int nodenum) 848: { 849: cplane_t *plane; 850: cnode_t *node; 851: int s; 1.1.1.2 root 852: 1.1 root 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: } 1.1.1.2 root 881: 1.1 root 882: } 883: } 1.1.1.2 root 884: 1.1 root 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; 1.1.1.2 root 892: 1.1 root 893: leaf_topnode = -1; 1.1.1.2 root 894: 1.1 root 895: CM_BoxLeafnums_r (headnode); 1.1.1.2 root 896: 1.1 root 897: if (topnode) 898: *topnode = leaf_topnode; 1.1.1.2 root 899: 1.1 root 900: return leaf_count; 901: } 1.1.1.2 root 902: 1.1 root 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: } 1.1.1.2 root 908: 909: 910: 1.1 root 911: /* 912: ================== 913: CM_PointContents 1.1.1.2 root 914: 1.1 root 915: ================== 916: */ 917: int CM_PointContents (vec3_t p, int headnode) 918: { 919: int l; 1.1.1.2 root 920: 1.1 root 921: if (!numnodes) // map not loaded 922: return 0; 923: 924: l = CM_PointLeafnum_r (p, headnode); 1.1.1.2 root 925: 1.1 root 926: return map_leafs[l].contents; 927: } 1.1.1.2 root 928: 1.1 root 929: /* 930: ================== 931: CM_TransformedPointContents 1.1.1.2 root 932: 1.1 root 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; 1.1.1.2 root 943: 1.1 root 944: // subtract origin offset 945: VectorSubtract (p, origin, p_l); 1.1.1.2 root 946: 1.1 root 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); 1.1.1.2 root 952: 1.1 root 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: } 1.1.1.2 root 958: 1.1 root 959: l = CM_PointLeafnum_r (p_l, headnode); 1.1.1.2 root 960: 1.1 root 961: return map_leafs[l].contents; 962: } 1.1.1.2 root 963: 964: 1.1 root 965: /* 966: =============================================================================== 1.1.1.2 root 967: 1.1 root 968: BOX TRACING 1.1.1.2 root 969: 1.1 root 970: =============================================================================== 971: */ 1.1.1.2 root 972: 1.1 root 973: // 1/32 epsilon to keep floating point happy 974: #define DIST_EPSILON (0.03125) 1.1.1.2 root 975: 1.1 root 976: vec3_t trace_start, trace_end; 977: vec3_t trace_mins, trace_maxs; 978: vec3_t trace_extents; 1.1.1.2 root 979: 1.1 root 980: trace_t trace_trace; 981: int trace_contents; 982: qboolean trace_ispoint; // optimized case 1.1.1.2 root 983: 1.1 root 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; 1.1.1.2 root 1092: trace->surface = &(leadside->surface->c); 1.1 root 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: 1.1.1.2 root 1152: 1.1 root 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 1.1.1.2 root 1224: 1.1 root 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; 1.1.1.2 root 1238: 1.1 root 1239: if (trace_trace.fraction <= p1f) 1240: return; // already hit something nearer 1.1.1.2 root 1241: 1.1 root 1242: // if < 0, we are in a leaf node 1243: if (num < 0) 1244: { 1245: CM_TraceToLeaf (-1-num); 1246: return; 1247: } 1.1.1.2 root 1248: 1.1 root 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; 1.1.1.2 root 1255: 1.1 root 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: } 1.1.1.2 root 1273: 1274: 1.1 root 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 1.1.1.2 root 1280: 1.1 root 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: } 1.1.1.2 root 1292: 1.1 root 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: } 1.1.1.2 root 1314: 1.1 root 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]); 1.1.1.2 root 1324: 1.1 root 1325: CM_RecursiveHullCheck (node->children[side], p1f, midf, p1, mid); 1.1.1.2 root 1326: 1327: 1.1 root 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]); 1.1.1.2 root 1337: 1.1 root 1338: CM_RecursiveHullCheck (node->children[side^1], midf, p2f, mid, p2); 1339: } 1.1.1.2 root 1340: 1341: 1342: 1.1 root 1343: //====================================================================== 1.1.1.2 root 1344: 1.1 root 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; 1.1.1.2 root 1355: 1.1 root 1356: checkcount++; // for multi-check avoidance 1.1.1.2 root 1357: 1.1 root 1358: c_traces++; // for statistics, may be zeroed 1.1.1.2 root 1359: 1.1 root 1360: // fill in a default trace 1361: memset (&trace_trace, 0, sizeof(trace_trace)); 1362: trace_trace.fraction = 1; 1.1.1.2 root 1363: trace_trace.surface = &(nullsurface.c); 1.1 root 1364: 1365: if (!numnodes) // map not loaded 1366: return trace_trace; 1.1.1.2 root 1367: 1.1 root 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); 1.1.1.2 root 1424: 1.1 root 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: } 1.1.1.2 root 1436: 1437: 1.1 root 1438: /* 1439: ================== 1440: CM_TransformedBoxTrace 1.1.1.2 root 1441: 1.1 root 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; 1.1.1.2 root 1462: 1.1 root 1463: // subtract origin offset 1464: VectorSubtract (start, origin, start_l); 1465: VectorSubtract (end, origin, end_l); 1.1.1.2 root 1466: 1.1 root 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; 1.1.1.2 root 1473: 1.1 root 1474: if (rotated) 1475: { 1476: AngleVectors (angles, forward, right, up); 1.1.1.2 root 1477: 1.1 root 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); 1.1.1.2 root 1482: 1.1 root 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: } 1.1.1.2 root 1488: 1.1 root 1489: // sweep the box through the model 1490: trace = CM_BoxTrace (start_l, end_l, mins, maxs, headnode, brushmask); 1.1.1.2 root 1491: 1.1 root 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); 1.1.1.2 root 1497: 1.1 root 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: } 1.1.1.2 root 1503: 1.1 root 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]); 1.1.1.2 root 1507: 1.1 root 1508: return trace; 1509: } 1.1.1.2 root 1510: 1.1 root 1511: #ifdef _WIN32 1512: #pragma optimize( "", on ) 1513: #endif 1514: 1515: 1.1.1.2 root 1516: 1.1 root 1517: /* 1518: =============================================================================== 1.1.1.2 root 1519: 1.1 root 1520: PVS / PHS 1.1.1.2 root 1521: 1.1 root 1522: =============================================================================== 1523: */ 1.1.1.2 root 1524: 1.1 root 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; 1.1.1.2 root 1535: 1.1 root 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: } 1.1.1.2 root 1548: 1.1 root 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: } 1.1.1.2 root 1571: 1.1 root 1572: byte pvsrow[MAX_MAP_LEAFS/8]; 1573: byte phsrow[MAX_MAP_LEAFS/8]; 1.1.1.2 root 1574: 1.1 root 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: } 1.1.1.2 root 1583: 1.1 root 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: } 1.1.1.2 root 1592: 1593: 1.1 root 1594: /* 1595: =============================================================================== 1.1.1.2 root 1596: 1.1 root 1597: AREAPORTALS 1.1.1.2 root 1598: 1.1 root 1599: =============================================================================== 1600: */ 1.1.1.2 root 1601: 1.1 root 1602: void FloodArea_r (carea_t *area, int floodnum) 1603: { 1604: int i; 1605: dareaportal_t *p; 1.1.1.2 root 1606: 1.1 root 1607: if (area->floodvalid == floodvalid) 1608: { 1609: if (area->floodnum == floodnum) 1610: return; 1611: Com_Error (ERR_DROP, "FloodArea_r: reflooded"); 1612: } 1.1.1.2 root 1613: 1.1 root 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: } 1.1.1.2 root 1623: 1.1 root 1624: /* 1625: ==================== 1626: FloodAreaConnections 1.1.1.2 root 1627: 1628: 1.1 root 1629: ==================== 1630: */ 1631: void FloodAreaConnections (void) 1632: { 1633: int i; 1634: carea_t *area; 1635: int floodnum; 1.1.1.2 root 1636: 1.1 root 1637: // all current floods are now invalid 1638: floodvalid++; 1639: floodnum = 0; 1.1.1.2 root 1640: 1.1 root 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: } 1.1.1.2 root 1650: 1.1 root 1651: } 1.1.1.2 root 1652: 1.1 root 1653: void CM_SetAreaPortalState (int portalnum, qboolean open) 1654: { 1655: if (portalnum > numareaportals) 1656: Com_Error (ERR_DROP, "areaportal > numareaportals"); 1.1.1.2 root 1657: 1.1 root 1658: portalopen[portalnum] = open; 1659: FloodAreaConnections (); 1660: } 1.1.1.2 root 1661: 1.1 root 1662: qboolean CM_AreasConnected (int area1, int area2) 1663: { 1664: if (map_noareas->value) 1665: return true; 1.1.1.2 root 1666: 1.1 root 1667: if (area1 > numareas || area2 > numareas) 1668: Com_Error (ERR_DROP, "area > numareas"); 1.1.1.2 root 1669: 1.1 root 1670: if (map_areas[area1].floodnum == map_areas[area2].floodnum) 1671: return true; 1672: return false; 1673: } 1.1.1.2 root 1674: 1675: 1.1 root 1676: /* 1677: ================= 1678: CM_WriteAreaBits 1.1.1.2 root 1679: 1.1 root 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 1.1.1.2 root 1682: 1.1 root 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; 1.1.1.2 root 1691: 1.1 root 1692: bytes = (numareas+7)>>3; 1.1.1.2 root 1693: 1.1 root 1694: if (map_noareas->value) 1695: { // for debugging, send everything 1696: memset (buffer, 255, bytes); 1697: } 1698: else 1699: { 1700: memset (buffer, 0, bytes); 1.1.1.2 root 1701: 1.1 root 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: } 1.1.1.2 root 1709: 1.1 root 1710: return bytes; 1711: } 1.1.1.2 root 1712: 1713: 1.1 root 1714: /* 1715: =================== 1716: CM_WritePortalState 1.1.1.2 root 1717: 1.1 root 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: } 1.1.1.2 root 1725: 1.1 root 1726: /* 1727: =================== 1728: CM_ReadPortalState 1.1.1.2 root 1729: 1.1 root 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: } 1.1.1.2 root 1739: 1.1 root 1740: /* 1741: ============= 1742: CM_HeadnodeVisible 1.1.1.2 root 1743: 1.1 root 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; 1.1.1.2 root 1753: 1.1 root 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: } 1.1.1.2 root 1764: 1.1 root 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: } 1.1.1.2 root 1770:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.