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