map_sin.c (32168B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 //----------------------------------------------------------------------------- 23 // 24 // $Logfile:: /MissionPack/code/bspc/map_sin.c $ 25 26 #include "qbsp.h" 27 #include "l_bsp_sin.h" 28 #include "aas_map.h" //AAS_CreateMapBrushes 29 30 31 //==================================================================== 32 33 34 /* 35 =========== 36 Sin_BrushContents 37 =========== 38 */ 39 40 int Sin_BrushContents(mapbrush_t *b) 41 { 42 int contents; 43 side_t *s; 44 int i; 45 #ifdef SIN 46 float trans = 0; 47 #else 48 int trans; 49 #endif 50 51 s = &b->original_sides[0]; 52 contents = s->contents; 53 54 #ifdef SIN 55 trans = sin_texinfo[s->texinfo].translucence; 56 #else 57 trans = texinfo[s->texinfo].flags; 58 #endif 59 for (i=1 ; i<b->numsides ; i++, s++) 60 { 61 s = &b->original_sides[i]; 62 #ifdef SIN 63 trans += sin_texinfo[s->texinfo].translucence; 64 #else 65 trans |= texinfo[s->texinfo].flags; 66 #endif 67 if (s->contents != contents) 68 { 69 #ifdef SIN 70 if ( 71 ( s->contents & CONTENTS_DETAIL && !(contents & CONTENTS_DETAIL) ) || 72 ( !(s->contents & CONTENTS_DETAIL) && contents & CONTENTS_DETAIL ) 73 ) 74 { 75 s->contents |= CONTENTS_DETAIL; 76 contents |= CONTENTS_DETAIL; 77 continue; 78 } 79 #endif 80 printf ("Entity %i, Brush %i: mixed face contents\n" 81 , b->entitynum, b->brushnum); 82 break; 83 } 84 } 85 86 87 #ifdef SIN 88 if (contents & CONTENTS_FENCE) 89 { 90 // contents |= CONTENTS_TRANSLUCENT; 91 contents |= CONTENTS_DETAIL; 92 contents |= CONTENTS_DUMMYFENCE; 93 contents &= ~CONTENTS_SOLID; 94 contents &= ~CONTENTS_FENCE; 95 contents |= CONTENTS_WINDOW; 96 } 97 #endif 98 99 // if any side is translucent, mark the contents 100 // and change solid to window 101 #ifdef SIN 102 if ( trans > 0 ) 103 #else 104 if ( trans & (SURF_TRANS33|SURF_TRANS66) ) 105 #endif 106 { 107 contents |= CONTENTS_Q2TRANSLUCENT; 108 if (contents & CONTENTS_SOLID) 109 { 110 contents &= ~CONTENTS_SOLID; 111 contents |= CONTENTS_WINDOW; 112 } 113 } 114 115 return contents; 116 } //*/ 117 118 119 //============================================================================ 120 121 122 123 /* 124 ================= 125 ParseBrush 126 ================= 127 * / 128 void ParseBrush (entity_t *mapent) 129 { 130 mapbrush_t *b; 131 int i,j, k; 132 int mt; 133 side_t *side, *s2; 134 int planenum; 135 brush_texture_t td; 136 #ifdef SIN 137 textureref_t newref; 138 #endif 139 int planepts[3][3]; 140 141 if (nummapbrushes == MAX_MAP_BRUSHES) 142 Error ("nummapbrushes == MAX_MAP_BRUSHES"); 143 144 b = &mapbrushes[nummapbrushes]; 145 b->original_sides = &brushsides[nummapbrushsides]; 146 b->entitynum = num_entities-1; 147 b->brushnum = nummapbrushes - mapent->firstbrush; 148 149 do 150 { 151 if (!GetToken (true)) 152 break; 153 if (!strcmp (token, "}") ) 154 break; 155 156 if (nummapbrushsides == MAX_MAP_BRUSHSIDES) 157 Error ("MAX_MAP_BRUSHSIDES"); 158 side = &brushsides[nummapbrushsides]; 159 160 // read the three point plane definition 161 for (i=0 ; i<3 ; i++) 162 { 163 if (i != 0) 164 GetToken (true); 165 if (strcmp (token, "(") ) 166 Error ("parsing brush"); 167 168 for (j=0 ; j<3 ; j++) 169 { 170 GetToken (false); 171 planepts[i][j] = atoi(token); 172 } 173 174 GetToken (false); 175 if (strcmp (token, ")") ) 176 Error ("parsing brush"); 177 178 } 179 180 181 // 182 // read the texturedef 183 // 184 GetToken (false); 185 strcpy (td.name, token); 186 187 GetToken (false); 188 td.shift[0] = atoi(token); 189 GetToken (false); 190 td.shift[1] = atoi(token); 191 GetToken (false); 192 #ifdef SIN 193 td.rotate = atof(token); 194 #else 195 td.rotate = atoi(token); 196 #endif 197 GetToken (false); 198 td.scale[0] = atof(token); 199 GetToken (false); 200 td.scale[1] = atof(token); 201 202 // find default flags and values 203 mt = FindMiptex (td.name); 204 #ifdef SIN 205 // clear out the masks on newref 206 memset(&newref,0,sizeof(newref)); 207 // copy over the name 208 strcpy( newref.name, td.name ); 209 210 ParseSurfaceInfo( &newref ); 211 MergeRefs( &bsp_textureref[mt], &newref, &td.tref ); 212 side->contents = td.tref.contents; 213 side->surf = td.tref.flags; 214 #else 215 td.flags = textureref[mt].flags; 216 td.value = textureref[mt].value; 217 side->contents = textureref[mt].contents; 218 side->surf = td.flags = textureref[mt].flags; 219 220 if (TokenAvailable()) 221 { 222 GetToken (false); 223 side->contents = atoi(token); 224 GetToken (false); 225 side->surf = td.flags = atoi(token); 226 GetToken (false); 227 td.value = atoi(token); 228 } 229 #endif 230 231 // translucent objects are automatically classified as detail 232 #ifdef SIN 233 if ( td.tref.translucence > 0 ) 234 #else 235 if (side->surf & (SURF_TRANS33|SURF_TRANS66) ) 236 #endif 237 side->contents |= CONTENTS_DETAIL; 238 if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) ) 239 side->contents |= CONTENTS_DETAIL; 240 if (fulldetail) 241 side->contents &= ~CONTENTS_DETAIL; 242 if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1) 243 | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) ) 244 side->contents |= CONTENTS_SOLID; 245 246 // hints and skips are never detail, and have no content 247 if (side->surf & (SURF_HINT|SURF_SKIP) ) 248 { 249 side->contents = 0; 250 #ifndef SIN // I think this is a bug of some kind 251 side->surf &= ~CONTENTS_DETAIL; 252 #endif 253 } 254 255 // 256 // find the plane number 257 // 258 planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]); 259 if (planenum == -1) 260 { 261 printf ("Entity %i, Brush %i: plane with no normal\n" 262 , b->entitynum, b->brushnum); 263 continue; 264 } 265 266 // 267 // see if the plane has been used already 268 // 269 for (k=0 ; k<b->numsides ; k++) 270 { 271 s2 = b->original_sides + k; 272 if (s2->planenum == planenum) 273 { 274 printf ("Entity %i, Brush %i: duplicate plane\n" 275 , b->entitynum, b->brushnum); 276 break; 277 } 278 if ( s2->planenum == (planenum^1) ) 279 { 280 printf ("Entity %i, Brush %i: mirrored plane\n" 281 , b->entitynum, b->brushnum); 282 break; 283 } 284 } 285 if (k != b->numsides) 286 continue; // duplicated 287 288 // 289 // keep this side 290 // 291 292 side = b->original_sides + b->numsides; 293 side->planenum = planenum; 294 #ifdef SIN 295 side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum], 296 &td, vec3_origin, &newref); 297 // 298 // save off lightinfo 299 // 300 side->lightinfo = LightinfoForBrushTexture ( &td ); 301 #else 302 side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum], 303 &td, vec3_origin); 304 305 #endif 306 307 // save the td off in case there is an origin brush and we 308 // have to recalculate the texinfo 309 side_brushtextures[nummapbrushsides] = td; 310 #ifdef SIN 311 // save off the merged tref for animating textures 312 side_newrefs[nummapbrushsides] = newref; 313 #endif 314 315 nummapbrushsides++; 316 b->numsides++; 317 } while (1); 318 319 // get the content for the entire brush 320 b->contents = Sin_BrushContents (b); 321 322 // allow detail brushes to be removed 323 if (nodetail && (b->contents & CONTENTS_DETAIL) ) 324 { 325 b->numsides = 0; 326 return; 327 } 328 329 // allow water brushes to be removed 330 if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) ) 331 { 332 b->numsides = 0; 333 return; 334 } 335 336 // create windings for sides and bounds for brush 337 MakeBrushWindings (b); 338 339 // brushes that will not be visible at all will never be 340 // used as bsp splitters 341 if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) ) 342 { 343 c_clipbrushes++; 344 for (i=0 ; i<b->numsides ; i++) 345 b->original_sides[i].texinfo = TEXINFO_NODE; 346 } 347 348 // 349 // origin brushes are removed, but they set 350 // the rotation origin for the rest of the brushes 351 // in the entity. After the entire entity is parsed, 352 // the planenums and texinfos will be adjusted for 353 // the origin brush 354 // 355 if (b->contents & CONTENTS_ORIGIN) 356 { 357 char string[32]; 358 vec3_t origin; 359 360 if (num_entities == 1) 361 { 362 Error ("Entity %i, Brush %i: origin brushes not allowed in world" 363 , b->entitynum, b->brushnum); 364 return; 365 } 366 367 VectorAdd (b->mins, b->maxs, origin); 368 VectorScale (origin, 0.5, origin); 369 370 sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]); 371 SetKeyValue (&entities[b->entitynum], "origin", string); 372 373 VectorCopy (origin, entities[b->entitynum].origin); 374 375 // don't keep this brush 376 b->numsides = 0; 377 378 return; 379 } 380 381 AddBrushBevels (b); 382 383 nummapbrushes++; 384 mapent->numbrushes++; 385 } //*/ 386 387 /* 388 ================ 389 MoveBrushesToWorld 390 391 Takes all of the brushes from the current entity and 392 adds them to the world's brush list. 393 394 Used by func_group and func_areaportal 395 ================ 396 * / 397 void MoveBrushesToWorld (entity_t *mapent) 398 { 399 int newbrushes; 400 int worldbrushes; 401 mapbrush_t *temp; 402 int i; 403 404 // this is pretty gross, because the brushes are expected to be 405 // in linear order for each entity 406 407 newbrushes = mapent->numbrushes; 408 worldbrushes = entities[0].numbrushes; 409 410 temp = malloc(newbrushes*sizeof(mapbrush_t)); 411 memcpy (temp, mapbrushes + mapent->firstbrush, newbrushes*sizeof(mapbrush_t)); 412 413 #if 0 // let them keep their original brush numbers 414 for (i=0 ; i<newbrushes ; i++) 415 temp[i].entitynum = 0; 416 #endif 417 418 // make space to move the brushes (overlapped copy) 419 memmove (mapbrushes + worldbrushes + newbrushes, 420 mapbrushes + worldbrushes, 421 sizeof(mapbrush_t) * (nummapbrushes - worldbrushes - newbrushes) ); 422 423 // copy the new brushes down 424 memcpy (mapbrushes + worldbrushes, temp, sizeof(mapbrush_t) * newbrushes); 425 426 // fix up indexes 427 entities[0].numbrushes += newbrushes; 428 for (i=1 ; i<num_entities ; i++) 429 entities[i].firstbrush += newbrushes; 430 free (temp); 431 432 mapent->numbrushes = 0; 433 } //*/ 434 435 /* 436 ================ 437 ParseMapEntity 438 ================ 439 * / 440 qboolean Sin_ParseMapEntity (void) 441 { 442 entity_t *mapent; 443 epair_t *e; 444 side_t *s; 445 int i, j; 446 int startbrush, startsides; 447 vec_t newdist; 448 mapbrush_t *b; 449 450 if (!GetToken (true)) 451 return false; 452 453 if (strcmp (token, "{") ) 454 Error ("ParseEntity: { not found"); 455 456 if (num_entities == MAX_MAP_ENTITIES) 457 Error ("num_entities == MAX_MAP_ENTITIES"); 458 459 startbrush = nummapbrushes; 460 startsides = nummapbrushsides; 461 462 mapent = &entities[num_entities]; 463 num_entities++; 464 memset (mapent, 0, sizeof(*mapent)); 465 mapent->firstbrush = nummapbrushes; 466 mapent->numbrushes = 0; 467 // mapent->portalareas[0] = -1; 468 // mapent->portalareas[1] = -1; 469 470 do 471 { 472 if (!GetToken (true)) 473 Error ("ParseEntity: EOF without closing brace"); 474 if (!strcmp (token, "}") ) 475 break; 476 if (!strcmp (token, "{") ) 477 ParseBrush (mapent); 478 else 479 { 480 e = ParseEpair (); 481 #ifdef SIN 482 //HACK HACK HACK 483 // MED Gotta do this here 484 if ( !stricmp(e->key, "surfacefile") ) 485 { 486 if (!surfacefile[0]) 487 { 488 strcpy( surfacefile, e->value ); 489 } 490 printf ("--- ParseSurfaceFile ---\n"); 491 printf ("Surface script: %s\n", surfacefile); 492 if (!ParseSurfaceFile(surfacefile)) 493 { 494 Error ("Script file not found: %s\n", surfacefile); 495 } 496 } 497 #endif 498 e->next = mapent->epairs; 499 mapent->epairs = e; 500 } 501 } while (1); 502 503 #ifdef SIN 504 if (!(strlen(ValueForKey(mapent, "origin"))) && ((num_entities-1) != 0)) 505 { 506 mapbrush_t *brush; 507 vec3_t origin; 508 char string[32]; 509 vec3_t mins, maxs; 510 int start, end; 511 // Calculate bounds 512 513 start = mapent->firstbrush; 514 end = start + mapent->numbrushes; 515 ClearBounds (mins, maxs); 516 517 for (j=start ; j<end ; j++) 518 { 519 brush = &mapbrushes[j]; 520 if (!brush->numsides) 521 continue; // not a real brush (origin brush) - shouldn't happen 522 AddPointToBounds (brush->mins, mins, maxs); 523 AddPointToBounds (brush->maxs, mins, maxs); 524 } 525 526 // Set the origin to be the centroid of the entity. 527 VectorAdd ( mins, maxs, origin); 528 VectorScale( origin, 0.5f, origin ); 529 530 sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]); 531 SetKeyValue ( mapent, "origin", string); 532 // qprintf("Setting origin to %s\n",string); 533 } 534 #endif 535 536 GetVectorForKey (mapent, "origin", mapent->origin); 537 538 #ifdef SIN 539 if ( 540 (!strcmp ("func_areaportal", ValueForKey (mapent, "classname"))) || 541 (!strcmp ("func_group", ValueForKey (mapent, "classname"))) || 542 (!strcmp ("detail", ValueForKey (mapent, "classname")) && !entitydetails) 543 ) 544 { 545 VectorClear( mapent->origin ); 546 } 547 #endif 548 549 // 550 // if there was an origin brush, offset all of the planes and texinfo 551 // 552 if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2]) 553 { 554 for (i=0 ; i<mapent->numbrushes ; i++) 555 { 556 b = &mapbrushes[mapent->firstbrush + i]; 557 for (j=0 ; j<b->numsides ; j++) 558 { 559 s = &b->original_sides[j]; 560 newdist = mapplanes[s->planenum].dist - 561 DotProduct (mapplanes[s->planenum].normal, mapent->origin); 562 s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist); 563 #ifdef SIN 564 s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum], 565 &side_brushtextures[s-brushsides], mapent->origin, &side_newrefs[s-brushsides]); 566 // 567 // save off lightinfo 568 // 569 s->lightinfo = LightinfoForBrushTexture ( &side_brushtextures[s-brushsides] ); 570 #else 571 s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum], 572 &side_brushtextures[s-brushsides], mapent->origin); 573 #endif 574 } 575 MakeBrushWindings (b); 576 } 577 } 578 579 // group entities are just for editor convenience 580 // toss all brushes into the world entity 581 if (!strcmp ("func_group", ValueForKey (mapent, "classname"))) 582 { 583 MoveBrushesToWorld (mapent); 584 mapent->numbrushes = 0; 585 mapent->wasdetail = true; 586 FreeValueKeys( mapent ); 587 return true; 588 } 589 #ifdef SIN 590 // detail entities are just for editor convenience 591 // toss all brushes into the world entity as detail brushes 592 if (!strcmp ("detail", ValueForKey (mapent, "classname")) && !entitydetails) 593 { 594 for (i=0 ; i<mapent->numbrushes ; i++) 595 { 596 int j; 597 side_t * s; 598 b = &mapbrushes[mapent->firstbrush + i]; 599 if (nodetail) 600 { 601 b->numsides = 0; 602 continue; 603 } 604 if (!fulldetail) 605 { 606 // set the contents for the entire brush 607 b->contents |= CONTENTS_DETAIL; 608 // set the contents in the sides as well 609 for (j=0, s=b->original_sides ; j<b->numsides ; j++,s++) 610 { 611 s->contents |= CONTENTS_DETAIL; 612 } 613 } 614 else 615 { 616 // set the contents for the entire brush 617 b->contents |= CONTENTS_SOLID; 618 // set the contents in the sides as well 619 for (j=0, s=b->original_sides ; j<b->numsides ; j++,s++) 620 { 621 s->contents |= CONTENTS_SOLID; 622 } 623 } 624 } 625 MoveBrushesToWorld (mapent); 626 mapent->wasdetail = true; 627 FreeValueKeys( mapent ); 628 // kill off the entity 629 // num_entities--; 630 return true; 631 } 632 #endif 633 634 // areaportal entities move their brushes, but don't eliminate 635 // the entity 636 if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname"))) 637 { 638 char str[128]; 639 640 if (mapent->numbrushes != 1) 641 Error ("Entity %i: func_areaportal can only be a single brush", num_entities-1); 642 643 b = &mapbrushes[nummapbrushes-1]; 644 b->contents = CONTENTS_AREAPORTAL; 645 c_areaportals++; 646 mapent->areaportalnum = c_areaportals; 647 // set the portal number as "style" 648 sprintf (str, "%i", c_areaportals); 649 SetKeyValue (mapent, "style", str); 650 MoveBrushesToWorld (mapent); 651 return true; 652 } 653 654 return true; 655 } //end of the function Sin_ParseMapEntity */ 656 657 //=================================================================== 658 659 /* 660 ================ 661 LoadMapFile 662 ================ 663 * / 664 void Sin_LoadMapFile (char *filename) 665 { 666 int i; 667 #ifdef SIN 668 int num_detailsides=0; 669 int num_detailbrushes=0; 670 int num_worldsides=0; 671 int num_worldbrushes=0; 672 int j,k; 673 #endif 674 675 qprintf ("--- LoadMapFile ---\n"); 676 677 LoadScriptFile (filename); 678 679 nummapbrushsides = 0; 680 num_entities = 0; 681 682 while (ParseMapEntity ()) 683 { 684 } 685 686 ClearBounds (map_mins, map_maxs); 687 for (i=0 ; i<entities[0].numbrushes ; i++) 688 { 689 if (mapbrushes[i].mins[0] > 4096) 690 continue; // no valid points 691 AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs); 692 AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs); 693 } 694 #ifdef SIN 695 for (j=0; j<num_entities; j++) 696 { 697 for (i=0 ; i<entities[j].numbrushes ; i++) 698 { 699 side_t * s; 700 mapbrush_t *b; 701 b = &mapbrushes[entities[j].firstbrush + i]; 702 if (b->numsides && b->contents & CONTENTS_DETAIL) 703 num_detailbrushes++; 704 else if (b->numsides) 705 num_worldbrushes++; 706 for (k=0, s=b->original_sides ; k<b->numsides ; k++,s++) 707 { 708 if (s->contents & CONTENTS_DETAIL) 709 num_detailsides++; 710 else 711 num_worldsides++; 712 } 713 } 714 } 715 #endif 716 717 qprintf ("%5i brushes\n", nummapbrushes); 718 qprintf ("%5i clipbrushes\n", c_clipbrushes); 719 qprintf ("%5i total sides\n", nummapbrushsides); 720 qprintf ("%5i boxbevels\n", c_boxbevels); 721 qprintf ("%5i edgebevels\n", c_edgebevels); 722 qprintf ("%5i entities\n", num_entities); 723 qprintf ("%5i planes\n", nummapplanes); 724 qprintf ("%5i areaportals\n", c_areaportals); 725 qprintf ("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2], 726 map_maxs[0],map_maxs[1],map_maxs[2]); 727 #ifdef SIN 728 qprintf ("%5i detailbrushes\n", num_detailbrushes); 729 qprintf ("%5i worldbrushes\n", num_worldbrushes); 730 qprintf ("%5i detailsides\n", num_detailsides); 731 qprintf ("%5i worldsides\n", num_worldsides); 732 #endif 733 734 } //end of the function Sin_LoadMap */ 735 736 737 #ifdef ME //Begin MAP loading from BSP file 738 //=========================================================================== 739 // 740 // Parameter: - 741 // Returns: - 742 // Changes Globals: - 743 //=========================================================================== 744 void Sin_CreateMapTexinfo(void) 745 { 746 int i; 747 vec_t defaultvec[4] = {1, 0, 0, 0}; 748 749 memcpy(map_texinfo[0].vecs[0], defaultvec, sizeof(defaultvec)); 750 memcpy(map_texinfo[0].vecs[1], defaultvec, sizeof(defaultvec)); 751 map_texinfo[0].flags = 0; 752 map_texinfo[0].value = 0; 753 strcpy(map_texinfo[0].texture, "generic/misc/red"); //no texture 754 map_texinfo[0].nexttexinfo = -1; 755 for (i = 1; i < sin_numtexinfo; i++) 756 { 757 memcpy(map_texinfo[i].vecs, sin_texinfo[i].vecs, sizeof(float) * 2 * 4); 758 map_texinfo[i].flags = sin_texinfo[i].flags; 759 map_texinfo[i].value = 0; 760 strcpy(map_texinfo[i].texture, sin_texinfo[i].texture); 761 map_texinfo[i].nexttexinfo = -1; 762 } //end for 763 } //end of the function Sin_CreateMapTexinfo 764 //=========================================================================== 765 // 766 // Parameter: - 767 // Returns: - 768 // Changes Globals: - 769 //=========================================================================== 770 void Sin_SetLeafBrushesModelNumbers(int leafnum, int modelnum) 771 { 772 int i, brushnum; 773 sin_dleaf_t *leaf; 774 775 leaf = &sin_dleafs[leafnum]; 776 for (i = 0; i < leaf->numleafbrushes; i++) 777 { 778 brushnum = sin_dleafbrushes[leaf->firstleafbrush + i]; 779 brushmodelnumbers[brushnum] = modelnum; 780 dbrushleafnums[brushnum] = leafnum; 781 } //end for 782 } //end of the function Sin_SetLeafBrushesModelNumbers 783 //=========================================================================== 784 // 785 // Parameter: - 786 // Returns: - 787 // Changes Globals: - 788 //=========================================================================== 789 void Sin_InitNodeStack(void) 790 { 791 nodestackptr = nodestack; 792 nodestacksize = 0; 793 } //end of the function Sin_InitNodeStack 794 //=========================================================================== 795 // 796 // Parameter: - 797 // Returns: - 798 // Changes Globals: - 799 //=========================================================================== 800 void Sin_PushNodeStack(int num) 801 { 802 *nodestackptr = num; 803 nodestackptr++; 804 nodestacksize++; 805 // 806 if (nodestackptr >= &nodestack[NODESTACKSIZE]) 807 { 808 Error("Sin_PushNodeStack: stack overflow\n"); 809 } //end if 810 } //end of the function Sin_PushNodeStack 811 //=========================================================================== 812 // 813 // Parameter: - 814 // Returns: - 815 // Changes Globals: - 816 //=========================================================================== 817 int Sin_PopNodeStack(void) 818 { 819 //if the stack is empty 820 if (nodestackptr <= nodestack) return -1; 821 //decrease stack pointer 822 nodestackptr--; 823 nodestacksize--; 824 //return the top value from the stack 825 return *nodestackptr; 826 } //end of the function Sin_PopNodeStack 827 //=========================================================================== 828 // 829 // Parameter: - 830 // Returns: - 831 // Changes Globals: - 832 //=========================================================================== 833 void Sin_SetBrushModelNumbers(entity_t *mapent) 834 { 835 int n, pn; 836 int leafnum; 837 838 // 839 Sin_InitNodeStack(); 840 //head node (root) of the bsp tree 841 n = sin_dmodels[mapent->modelnum].headnode; 842 pn = 0; 843 844 do 845 { 846 //if we are in a leaf (negative node number) 847 if (n < 0) 848 { 849 //number of the leaf 850 leafnum = (-n) - 1; 851 //set the brush numbers 852 Sin_SetLeafBrushesModelNumbers(leafnum, mapent->modelnum); 853 //walk back into the tree to find a second child to continue with 854 for (pn = Sin_PopNodeStack(); pn >= 0; n = pn, pn = Sin_PopNodeStack()) 855 { 856 //if we took the first child at the parent node 857 if (sin_dnodes[pn].children[0] == n) break; 858 } //end for 859 //if the stack wasn't empty (if not processed whole tree) 860 if (pn >= 0) 861 { 862 //push the parent node again 863 Sin_PushNodeStack(pn); 864 //we proceed with the second child of the parent node 865 n = sin_dnodes[pn].children[1]; 866 } //end if 867 } //end if 868 else 869 { 870 //push the current node onto the stack 871 Sin_PushNodeStack(n); 872 //walk forward into the tree to the first child 873 n = sin_dnodes[n].children[0]; 874 } //end else 875 } while(pn >= 0); 876 } //end of the function Sin_SetBrushModelNumbers 877 //=========================================================================== 878 // 879 // Parameter: - 880 // Returns: - 881 // Changes Globals: - 882 //=========================================================================== 883 void Sin_BSPBrushToMapBrush(sin_dbrush_t *bspbrush, entity_t *mapent) 884 { 885 mapbrush_t *b; 886 int i, k, n; 887 side_t *side, *s2; 888 int planenum; 889 sin_dbrushside_t *bspbrushside; 890 sin_dplane_t *bspplane; 891 892 if (nummapbrushes >= MAX_MAPFILE_BRUSHES) 893 Error ("nummapbrushes >= MAX_MAPFILE_BRUSHES"); 894 895 b = &mapbrushes[nummapbrushes]; 896 b->original_sides = &brushsides[nummapbrushsides]; 897 b->entitynum = mapent-entities; 898 b->brushnum = nummapbrushes - mapent->firstbrush; 899 b->leafnum = dbrushleafnums[bspbrush - sin_dbrushes]; 900 901 for (n = 0; n < bspbrush->numsides; n++) 902 { 903 //pointer to the bsp brush side 904 bspbrushside = &sin_dbrushsides[bspbrush->firstside + n]; 905 906 if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES) 907 { 908 Error ("MAX_MAPFILE_BRUSHSIDES"); 909 } //end if 910 //pointer to the map brush side 911 side = &brushsides[nummapbrushsides]; 912 //if the BSP brush side is textured 913 if (sin_dbrushsidetextured[bspbrush->firstside + n]) side->flags |= SFL_TEXTURED; 914 else side->flags &= ~SFL_TEXTURED; 915 //ME: can get side contents and surf directly from BSP file 916 side->contents = bspbrush->contents; 917 //if the texinfo is TEXINFO_NODE 918 if (bspbrushside->texinfo < 0) side->surf = 0; 919 else side->surf = sin_texinfo[bspbrushside->texinfo].flags; 920 921 // translucent objects are automatically classified as detail 922 if (side->surf & (SURF_TRANS33|SURF_TRANS66) ) 923 side->contents |= CONTENTS_DETAIL; 924 if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) ) 925 side->contents |= CONTENTS_DETAIL; 926 if (fulldetail) 927 side->contents &= ~CONTENTS_DETAIL; 928 if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1) 929 | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) ) 930 side->contents |= CONTENTS_SOLID; 931 932 // hints and skips are never detail, and have no content 933 if (side->surf & (SURF_HINT|SURF_SKIP) ) 934 { 935 side->contents = 0; 936 side->surf &= ~CONTENTS_DETAIL; 937 } 938 939 //ME: get a plane for this side 940 bspplane = &sin_dplanes[bspbrushside->planenum]; 941 planenum = FindFloatPlane(bspplane->normal, bspplane->dist); 942 // 943 // see if the plane has been used already 944 // 945 //ME: this really shouldn't happen!!! 946 //ME: otherwise the bsp file is corrupted?? 947 //ME: still it seems to happen, maybe Johny Boy's 948 //ME: brush bevel adding is crappy ? 949 for (k = 0; k < b->numsides; k++) 950 { 951 s2 = b->original_sides + k; 952 if (s2->planenum == planenum) 953 { 954 Log_Print("Entity %i, Brush %i: duplicate plane\n" 955 , b->entitynum, b->brushnum); 956 break; 957 } 958 if ( s2->planenum == (planenum^1) ) 959 { 960 Log_Print("Entity %i, Brush %i: mirrored plane\n" 961 , b->entitynum, b->brushnum); 962 break; 963 } 964 } 965 if (k != b->numsides) 966 continue; // duplicated 967 968 // 969 // keep this side 970 // 971 //ME: reset pointer to side, why? hell I dunno (pointer is set above already) 972 side = b->original_sides + b->numsides; 973 //ME: store the plane number 974 side->planenum = planenum; 975 //ME: texinfo is already stored when bsp is loaded 976 //NOTE: check for TEXINFO_NODE, otherwise crash in Sin_BrushContents 977 if (bspbrushside->texinfo < 0) side->texinfo = 0; 978 else side->texinfo = bspbrushside->texinfo; 979 980 // save the td off in case there is an origin brush and we 981 // have to recalculate the texinfo 982 // ME: don't need to recalculate because it's already done 983 // (for non-world entities) in the BSP file 984 // side_brushtextures[nummapbrushsides] = td; 985 986 nummapbrushsides++; 987 b->numsides++; 988 } //end for 989 990 // get the content for the entire brush 991 b->contents = bspbrush->contents; 992 Sin_BrushContents(b); 993 994 if (BrushExists(b)) 995 { 996 c_squattbrushes++; 997 b->numsides = 0; 998 return; 999 } //end if 1000 1001 //if we're creating AAS 1002 if (create_aas) 1003 { 1004 //create the AAS brushes from this brush, don't add brush bevels 1005 AAS_CreateMapBrushes(b, mapent, false); 1006 return; 1007 } //end if 1008 1009 // allow detail brushes to be removed 1010 if (nodetail && (b->contents & CONTENTS_DETAIL) ) 1011 { 1012 b->numsides = 0; 1013 return; 1014 } //end if 1015 1016 // allow water brushes to be removed 1017 if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) ) 1018 { 1019 b->numsides = 0; 1020 return; 1021 } //end if 1022 1023 // create windings for sides and bounds for brush 1024 MakeBrushWindings(b); 1025 1026 //mark brushes without winding or with a tiny window as bevels 1027 MarkBrushBevels(b); 1028 1029 // brushes that will not be visible at all will never be 1030 // used as bsp splitters 1031 if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) ) 1032 { 1033 c_clipbrushes++; 1034 for (i = 0; i < b->numsides; i++) 1035 b->original_sides[i].texinfo = TEXINFO_NODE; 1036 } //end for 1037 1038 // 1039 // origin brushes are removed, but they set 1040 // the rotation origin for the rest of the brushes 1041 // in the entity. After the entire entity is parsed, 1042 // the planenums and texinfos will be adjusted for 1043 // the origin brush 1044 // 1045 //ME: not needed because the entities in the BSP file already 1046 // have an origin set 1047 // if (b->contents & CONTENTS_ORIGIN) 1048 // { 1049 // char string[32]; 1050 // vec3_t origin; 1051 // 1052 // if (num_entities == 1) 1053 // { 1054 // Error ("Entity %i, Brush %i: origin brushes not allowed in world" 1055 // , b->entitynum, b->brushnum); 1056 // return; 1057 // } 1058 // 1059 // VectorAdd (b->mins, b->maxs, origin); 1060 // VectorScale (origin, 0.5, origin); 1061 // 1062 // sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]); 1063 // SetKeyValue (&entities[b->entitynum], "origin", string); 1064 // 1065 // VectorCopy (origin, entities[b->entitynum].origin); 1066 // 1067 // // don't keep this brush 1068 // b->numsides = 0; 1069 // 1070 // return; 1071 // } 1072 1073 //ME: the bsp brushes already have bevels, so we won't try to 1074 // add them again (especially since Johny Boy's bevel adding might 1075 // be crappy) 1076 // AddBrushBevels(b); 1077 1078 nummapbrushes++; 1079 mapent->numbrushes++; 1080 } //end of the function Sin_BSPBrushToMapBrush 1081 //=========================================================================== 1082 //=========================================================================== 1083 void Sin_ParseBSPBrushes(entity_t *mapent) 1084 { 1085 int i, testnum = 0; 1086 1087 //give all the brushes that belong to this entity the number of the 1088 //BSP model used by this entity 1089 Sin_SetBrushModelNumbers(mapent); 1090 //now parse all the brushes with the correct mapent->modelnum 1091 for (i = 0; i < sin_numbrushes; i++) 1092 { 1093 if (brushmodelnumbers[i] == mapent->modelnum) 1094 { 1095 testnum++; 1096 Sin_BSPBrushToMapBrush(&sin_dbrushes[i], mapent); 1097 } //end if 1098 } //end for 1099 } //end of the function Sin_ParseBSPBrushes 1100 //=========================================================================== 1101 //=========================================================================== 1102 qboolean Sin_ParseBSPEntity(int entnum) 1103 { 1104 entity_t *mapent; 1105 char *model; 1106 int startbrush, startsides; 1107 1108 startbrush = nummapbrushes; 1109 startsides = nummapbrushsides; 1110 1111 mapent = &entities[entnum];//num_entities]; 1112 mapent->firstbrush = nummapbrushes; 1113 mapent->numbrushes = 0; 1114 mapent->modelnum = -1; //-1 = no model 1115 1116 model = ValueForKey(mapent, "model"); 1117 if (model && *model == '*') 1118 { 1119 mapent->modelnum = atoi(&model[1]); 1120 //Log_Print("model = %s\n", model); 1121 //Log_Print("mapent->modelnum = %d\n", mapent->modelnum); 1122 } //end if 1123 1124 GetVectorForKey(mapent, "origin", mapent->origin); 1125 1126 //if this is the world entity it has model number zero 1127 //the world entity has no model key 1128 if (!strcmp("worldspawn", ValueForKey(mapent, "classname"))) 1129 { 1130 mapent->modelnum = 0; 1131 } //end if 1132 //if the map entity has a BSP model (a modelnum of -1 is used for 1133 //entities that aren't using a BSP model) 1134 if (mapent->modelnum >= 0) 1135 { 1136 //parse the bsp brushes 1137 Sin_ParseBSPBrushes(mapent); 1138 } //end if 1139 // 1140 //the origin of the entity is already taken into account 1141 // 1142 //func_group entities can't be in the bsp file 1143 // 1144 //check out the func_areaportal entities 1145 if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname"))) 1146 { 1147 c_areaportals++; 1148 mapent->areaportalnum = c_areaportals; 1149 return true; 1150 } //end if 1151 return true; 1152 } //end of the function Sin_ParseBSPEntity 1153 //=========================================================================== 1154 // 1155 // Parameter: - 1156 // Returns: - 1157 // Changes Globals: - 1158 //=========================================================================== 1159 void Sin_LoadMapFromBSP(char *filename, int offset, int length) 1160 { 1161 int i; 1162 1163 Log_Print("-- Sin_LoadMapFromBSP --\n"); 1164 //loaded map type 1165 loadedmaptype = MAPTYPE_SIN; 1166 1167 Log_Print("Loading map from %s...\n", filename); 1168 //load the bsp file 1169 Sin_LoadBSPFile(filename, offset, length); 1170 1171 //create an index from bsp planes to map planes 1172 //DPlanes2MapPlanes(); 1173 //clear brush model numbers 1174 for (i = 0; i < MAX_MAPFILE_BRUSHES; i++) 1175 brushmodelnumbers[i] = -1; 1176 1177 nummapbrushsides = 0; 1178 num_entities = 0; 1179 1180 Sin_ParseEntities(); 1181 // 1182 for (i = 0; i < num_entities; i++) 1183 { 1184 Sin_ParseBSPEntity(i); 1185 } //end for 1186 1187 //get the map mins and maxs from the world model 1188 ClearBounds(map_mins, map_maxs); 1189 for (i = 0; i < entities[0].numbrushes; i++) 1190 { 1191 if (mapbrushes[i].mins[0] > 4096) 1192 continue; //no valid points 1193 AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs); 1194 AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs); 1195 } //end for 1196 // 1197 Sin_CreateMapTexinfo(); 1198 } //end of the function Sin_LoadMapFromBSP 1199 1200 void Sin_ResetMapLoading(void) 1201 { 1202 //reset for map loading from bsp 1203 memset(nodestack, 0, NODESTACKSIZE * sizeof(int)); 1204 nodestackptr = NULL; 1205 nodestacksize = 0; 1206 memset(brushmodelnumbers, 0, MAX_MAPFILE_BRUSHES * sizeof(int)); 1207 } //end of the function Sin_ResetMapLoading 1208 1209 //End MAP loading from BSP file 1210 1211 #endif //ME