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