map_hl.c (31500B)
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 #include "qbsp.h" 24 #include "l_bsp_hl.h" 25 #include "aas_map.h" //AAS_CreateMapBrushes 26 27 int hl_numbrushes; 28 int hl_numclipbrushes; 29 30 //#define HL_PRINT 31 #define HLCONTENTS 32 33 //=========================================================================== 34 // 35 // Parameter: - 36 // Returns: - 37 // Changes Globals: - 38 //=========================================================================== 39 int HL_TextureContents(char *name) 40 { 41 if (!Q_strncasecmp (name, "sky",3)) 42 return CONTENTS_SOLID; 43 44 if (!Q_strncasecmp(name+1,"!lava",5)) 45 return CONTENTS_LAVA; 46 47 if (!Q_strncasecmp(name+1,"!slime",6)) 48 return CONTENTS_SLIME; 49 50 /* 51 if (!Q_strncasecmp (name, "!cur_90",7)) 52 return CONTENTS_CURRENT_90; 53 if (!Q_strncasecmp (name, "!cur_0",6)) 54 return CONTENTS_CURRENT_0; 55 if (!Q_strncasecmp (name, "!cur_270",8)) 56 return CONTENTS_CURRENT_270; 57 if (!Q_strncasecmp (name, "!cur_180",8)) 58 return CONTENTS_CURRENT_180; 59 if (!Q_strncasecmp (name, "!cur_up",7)) 60 return CONTENTS_CURRENT_UP; 61 if (!Q_strncasecmp (name, "!cur_dwn",8)) 62 return CONTENTS_CURRENT_DOWN; 63 //*/ 64 if (name[0] == '!') 65 return CONTENTS_WATER; 66 /* 67 if (!Q_strncasecmp (name, "origin",6)) 68 return CONTENTS_ORIGIN; 69 if (!Q_strncasecmp (name, "clip",4)) 70 return CONTENTS_CLIP; 71 if( !Q_strncasecmp( name, "translucent", 11 ) ) 72 return CONTENTS_TRANSLUCENT; 73 if( name[0] == '@' ) 74 return CONTENTS_TRANSLUCENT; 75 //*/ 76 77 return CONTENTS_SOLID; 78 } //end of the function HL_TextureContents 79 //=========================================================================== 80 // Generates two new brushes, leaving the original 81 // unchanged 82 // 83 // modified for Half-Life because there are quite a lot of tiny node leaves 84 // in the Half-Life bsps 85 // 86 // Parameter: - 87 // Returns: - 88 // Changes Globals: - 89 //=========================================================================== 90 void HL_SplitBrush(bspbrush_t *brush, int planenum, int nodenum, 91 bspbrush_t **front, bspbrush_t **back) 92 { 93 bspbrush_t *b[2]; 94 int i, j; 95 winding_t *w, *cw[2], *midwinding; 96 plane_t *plane, *plane2; 97 side_t *s, *cs; 98 float d, d_front, d_back; 99 100 *front = *back = NULL; 101 plane = &mapplanes[planenum]; 102 103 // check all points 104 d_front = d_back = 0; 105 for (i=0 ; i<brush->numsides ; i++) 106 { 107 w = brush->sides[i].winding; 108 if (!w) 109 continue; 110 for (j=0 ; j<w->numpoints ; j++) 111 { 112 d = DotProduct (w->p[j], plane->normal) - plane->dist; 113 if (d > 0 && d > d_front) 114 d_front = d; 115 if (d < 0 && d < d_back) 116 d_back = d; 117 } //end for 118 } //end for 119 120 if (d_front < 0.1) // PLANESIDE_EPSILON) 121 { // only on back 122 *back = CopyBrush (brush); 123 Log_Print("HL_SplitBrush: only on back\n"); 124 return; 125 } //end if 126 if (d_back > -0.1) // PLANESIDE_EPSILON) 127 { // only on front 128 *front = CopyBrush (brush); 129 Log_Print("HL_SplitBrush: only on front\n"); 130 return; 131 } //end if 132 133 // create a new winding from the split plane 134 135 w = BaseWindingForPlane (plane->normal, plane->dist); 136 for (i = 0; i < brush->numsides && w; i++) 137 { 138 plane2 = &mapplanes[brush->sides[i].planenum ^ 1]; 139 ChopWindingInPlace(&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON); 140 } //end for 141 142 if (!w || WindingIsTiny(w)) 143 { // the brush isn't really split 144 int side; 145 146 Log_Print("HL_SplitBrush: no split winding\n"); 147 side = BrushMostlyOnSide (brush, plane); 148 if (side == PSIDE_FRONT) 149 *front = CopyBrush (brush); 150 if (side == PSIDE_BACK) 151 *back = CopyBrush (brush); 152 return; 153 } 154 155 if (WindingIsHuge(w)) 156 { 157 Log_Print("HL_SplitBrush: WARNING huge split winding\n"); 158 } //end of 159 160 midwinding = w; 161 162 // split it for real 163 164 for (i = 0; i < 2; i++) 165 { 166 b[i] = AllocBrush (brush->numsides+1); 167 b[i]->original = brush->original; 168 } //end for 169 170 // split all the current windings 171 172 for (i=0 ; i<brush->numsides ; i++) 173 { 174 s = &brush->sides[i]; 175 w = s->winding; 176 if (!w) 177 continue; 178 ClipWindingEpsilon (w, plane->normal, plane->dist, 179 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]); 180 for (j=0 ; j<2 ; j++) 181 { 182 if (!cw[j]) 183 continue; 184 #if 0 185 if (WindingIsTiny (cw[j])) 186 { 187 FreeWinding (cw[j]); 188 continue; 189 } 190 #endif 191 cs = &b[j]->sides[b[j]->numsides]; 192 b[j]->numsides++; 193 *cs = *s; 194 // cs->planenum = s->planenum; 195 // cs->texinfo = s->texinfo; 196 // cs->visible = s->visible; 197 // cs->original = s->original; 198 cs->winding = cw[j]; 199 cs->flags &= ~SFL_TESTED; 200 } //end for 201 } //end for 202 203 204 // see if we have valid polygons on both sides 205 206 for (i=0 ; i<2 ; i++) 207 { 208 BoundBrush (b[i]); 209 for (j=0 ; j<3 ; j++) 210 { 211 if (b[i]->mins[j] < -4096 || b[i]->maxs[j] > 4096) 212 { 213 Log_Print("HL_SplitBrush: bogus brush after clip\n"); 214 break; 215 } //end if 216 } //end for 217 218 if (b[i]->numsides < 3 || j < 3) 219 { 220 FreeBrush (b[i]); 221 b[i] = NULL; 222 Log_Print("HL_SplitBrush: numsides < 3\n"); 223 } //end if 224 } //end for 225 226 if ( !(b[0] && b[1]) ) 227 { 228 if (!b[0] && !b[1]) 229 Log_Print("HL_SplitBrush: split removed brush\n"); 230 else 231 Log_Print("HL_SplitBrush: split not on both sides\n"); 232 if (b[0]) 233 { 234 FreeBrush (b[0]); 235 *front = CopyBrush (brush); 236 } //end if 237 if (b[1]) 238 { 239 FreeBrush (b[1]); 240 *back = CopyBrush (brush); 241 } //end if 242 return; 243 } //end if 244 245 // add the midwinding to both sides 246 for (i = 0; i < 2; i++) 247 { 248 cs = &b[i]->sides[b[i]->numsides]; 249 b[i]->numsides++; 250 251 cs->planenum = planenum^i^1; 252 cs->texinfo = 0; 253 //store the node number in the surf to find the texinfo later on 254 cs->surf = nodenum; 255 // 256 cs->flags &= ~SFL_VISIBLE; 257 cs->flags &= ~SFL_TESTED; 258 if (i==0) 259 cs->winding = CopyWinding (midwinding); 260 else 261 cs->winding = midwinding; 262 } //end for 263 264 265 { 266 vec_t v1; 267 int i; 268 269 for (i=0 ; i<2 ; i++) 270 { 271 v1 = BrushVolume (b[i]); 272 if (v1 < 1) 273 { 274 FreeBrush (b[i]); 275 b[i] = NULL; 276 Log_Print("HL_SplitBrush: tiny volume after clip\n"); 277 } //end if 278 } //end for 279 } //*/ 280 281 *front = b[0]; 282 *back = b[1]; 283 } //end of the function HL_SplitBrush 284 //=========================================================================== 285 // returns true if the tree starting at nodenum has only solid leaves 286 // 287 // Parameter: - 288 // Returns: - 289 // Changes Globals: - 290 //=========================================================================== 291 int HL_SolidTree_r(int nodenum) 292 { 293 if (nodenum < 0) 294 { 295 switch(hl_dleafs[(-nodenum) - 1].contents) 296 { 297 case HL_CONTENTS_EMPTY: 298 { 299 return false; 300 } //end case 301 case HL_CONTENTS_SOLID: 302 #ifdef HLCONTENTS 303 case HL_CONTENTS_CLIP: 304 #endif //HLCONTENTS 305 case HL_CONTENTS_SKY: 306 #ifdef HLCONTENTS 307 case HL_CONTENTS_TRANSLUCENT: 308 #endif //HLCONTENTS 309 { 310 return true; 311 } //end case 312 case HL_CONTENTS_WATER: 313 case HL_CONTENTS_SLIME: 314 case HL_CONTENTS_LAVA: 315 #ifdef HLCONTENTS 316 //these contents should not be found in the BSP 317 case HL_CONTENTS_ORIGIN: 318 case HL_CONTENTS_CURRENT_0: 319 case HL_CONTENTS_CURRENT_90: 320 case HL_CONTENTS_CURRENT_180: 321 case HL_CONTENTS_CURRENT_270: 322 case HL_CONTENTS_CURRENT_UP: 323 case HL_CONTENTS_CURRENT_DOWN: 324 #endif //HLCONTENTS 325 default: 326 { 327 return false; 328 } //end default 329 } //end switch 330 return false; 331 } //end if 332 if (!HL_SolidTree_r(hl_dnodes[nodenum].children[0])) return false; 333 if (!HL_SolidTree_r(hl_dnodes[nodenum].children[1])) return false; 334 return true; 335 } //end of the function HL_SolidTree_r 336 //=========================================================================== 337 // 338 // Parameter: - 339 // Returns: - 340 // Changes Globals: - 341 //=========================================================================== 342 bspbrush_t *HL_CreateBrushes_r(bspbrush_t *brush, int nodenum) 343 { 344 int planenum; 345 bspbrush_t *front, *back; 346 hl_dleaf_t *leaf; 347 348 //if it is a leaf 349 if (nodenum < 0) 350 { 351 leaf = &hl_dleafs[(-nodenum) - 1]; 352 if (leaf->contents != HL_CONTENTS_EMPTY) 353 { 354 #ifdef HL_PRINT 355 qprintf("\r%5i", ++hl_numbrushes); 356 #endif //HL_PRINT 357 } //end if 358 switch(leaf->contents) 359 { 360 case HL_CONTENTS_EMPTY: 361 { 362 FreeBrush(brush); 363 return NULL; 364 } //end case 365 case HL_CONTENTS_SOLID: 366 #ifdef HLCONTENTS 367 case HL_CONTENTS_CLIP: 368 #endif //HLCONTENTS 369 case HL_CONTENTS_SKY: 370 #ifdef HLCONTENTS 371 case HL_CONTENTS_TRANSLUCENT: 372 #endif //HLCONTENTS 373 { 374 brush->side = CONTENTS_SOLID; 375 return brush; 376 } //end case 377 case HL_CONTENTS_WATER: 378 { 379 brush->side = CONTENTS_WATER; 380 return brush; 381 } //end case 382 case HL_CONTENTS_SLIME: 383 { 384 brush->side = CONTENTS_SLIME; 385 return brush; 386 } //end case 387 case HL_CONTENTS_LAVA: 388 { 389 brush->side = CONTENTS_LAVA; 390 return brush; 391 } //end case 392 #ifdef HLCONTENTS 393 //these contents should not be found in the BSP 394 case HL_CONTENTS_ORIGIN: 395 case HL_CONTENTS_CURRENT_0: 396 case HL_CONTENTS_CURRENT_90: 397 case HL_CONTENTS_CURRENT_180: 398 case HL_CONTENTS_CURRENT_270: 399 case HL_CONTENTS_CURRENT_UP: 400 case HL_CONTENTS_CURRENT_DOWN: 401 { 402 Error("HL_CreateBrushes_r: found contents %d in Half-Life BSP", leaf->contents); 403 return NULL; 404 } //end case 405 #endif //HLCONTENTS 406 default: 407 { 408 Error("HL_CreateBrushes_r: unknown contents %d in Half-Life BSP", leaf->contents); 409 return NULL; 410 } //end default 411 } //end switch 412 return NULL; 413 } //end if 414 //if the rest of the tree is solid 415 /*if (HL_SolidTree_r(nodenum)) 416 { 417 brush->side = CONTENTS_SOLID; 418 return brush; 419 } //end if*/ 420 // 421 planenum = hl_dnodes[nodenum].planenum; 422 planenum = FindFloatPlane(hl_dplanes[planenum].normal, hl_dplanes[planenum].dist); 423 //split the brush with the node plane 424 HL_SplitBrush(brush, planenum, nodenum, &front, &back); 425 //free the original brush 426 FreeBrush(brush); 427 //every node must split the brush in two 428 if (!front || !back) 429 { 430 Log_Print("HL_CreateBrushes_r: WARNING node not splitting brush\n"); 431 //return NULL; 432 } //end if 433 //create brushes recursively 434 if (front) front = HL_CreateBrushes_r(front, hl_dnodes[nodenum].children[0]); 435 if (back) back = HL_CreateBrushes_r(back, hl_dnodes[nodenum].children[1]); 436 //link the brushes if possible and return them 437 if (front) 438 { 439 for (brush = front; brush->next; brush = brush->next); 440 brush->next = back; 441 return front; 442 } //end if 443 else 444 { 445 return back; 446 } //end else 447 } //end of the function HL_CreateBrushes_r 448 //=========================================================================== 449 // 450 // Parameter: - 451 // Returns: - 452 // Changes Globals: - 453 //=========================================================================== 454 bspbrush_t *HL_CreateBrushesFromBSP(int modelnum) 455 { 456 bspbrush_t *brushlist; 457 bspbrush_t *brush; 458 hl_dnode_t *headnode; 459 vec3_t mins, maxs; 460 int i; 461 462 // 463 headnode = &hl_dnodes[hl_dmodels[modelnum].headnode[0]]; 464 //get the mins and maxs of the world 465 VectorCopy(headnode->mins, mins); 466 VectorCopy(headnode->maxs, maxs); 467 //enlarge these mins and maxs 468 for (i = 0; i < 3; i++) 469 { 470 mins[i] -= 8; 471 maxs[i] += 8; 472 } //end for 473 //NOTE: have to add the BSP tree mins and maxs to the MAP mins and maxs 474 AddPointToBounds(mins, map_mins, map_maxs); 475 AddPointToBounds(maxs, map_mins, map_maxs); 476 // 477 if (!modelnum) 478 { 479 Log_Print("brush size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", 480 map_mins[0], map_mins[1], map_mins[2], 481 map_maxs[0], map_maxs[1], map_maxs[2]); 482 } //end if 483 //create one huge brush containing the whole world 484 brush = BrushFromBounds(mins, maxs); 485 VectorCopy(mins, brush->mins); 486 VectorCopy(maxs, brush->maxs); 487 // 488 #ifdef HL_PRINT 489 qprintf("creating Half-Life brushes\n"); 490 qprintf("%5d brushes", hl_numbrushes = 0); 491 #endif //HL_PRINT 492 //create the brushes 493 brushlist = HL_CreateBrushes_r(brush, hl_dmodels[modelnum].headnode[0]); 494 // 495 #ifdef HL_PRINT 496 qprintf("\n"); 497 #endif //HL_PRINT 498 //now we've got a list with brushes! 499 return brushlist; 500 } //end of the function HL_CreateBrushesFromBSP 501 //=========================================================================== 502 // 503 // Parameter: - 504 // Returns: - 505 // Changes Globals: - 506 //=========================================================================== 507 bspbrush_t *HL_MergeBrushes(bspbrush_t *brushlist, int modelnum) 508 { 509 int nummerges, merged; 510 bspbrush_t *b1, *b2, *tail, *newbrush, *newbrushlist; 511 bspbrush_t *lastb2; 512 513 if (!brushlist) return NULL; 514 515 if (!modelnum) qprintf("%5d brushes merged", nummerges = 0); 516 do 517 { 518 for (tail = brushlist; tail; tail = tail->next) 519 { 520 if (!tail->next) break; 521 } //end for 522 merged = 0; 523 newbrushlist = NULL; 524 for (b1 = brushlist; b1; b1 = brushlist) 525 { 526 lastb2 = b1; 527 for (b2 = b1->next; b2; b2 = b2->next) 528 { 529 //can't merge brushes with different contents 530 if (b1->side != b2->side) newbrush = NULL; 531 else newbrush = TryMergeBrushes(b1, b2); 532 //if a merged brush is created 533 if (newbrush) 534 { 535 //copy the brush contents 536 newbrush->side = b1->side; 537 //add the new brush to the end of the list 538 tail->next = newbrush; 539 //remove the second brush from the list 540 lastb2->next = b2->next; 541 //remove the first brush from the list 542 brushlist = brushlist->next; 543 //free the merged brushes 544 FreeBrush(b1); 545 FreeBrush(b2); 546 //get a new tail brush 547 for (tail = brushlist; tail; tail = tail->next) 548 { 549 if (!tail->next) break; 550 } //end for 551 merged++; 552 if (!modelnum) qprintf("\r%5d", nummerges++); 553 break; 554 } //end if 555 lastb2 = b2; 556 } //end for 557 //if b1 can't be merged with any of the other brushes 558 if (!b2) 559 { 560 brushlist = brushlist->next; 561 //keep b1 562 b1->next = newbrushlist; 563 newbrushlist = b1; 564 } //end else 565 } //end for 566 brushlist = newbrushlist; 567 } while(merged); 568 if (!modelnum) qprintf("\n"); 569 return newbrushlist; 570 } //end of the function HL_MergeBrushes 571 //=========================================================================== 572 // returns the amount the face and the winding have overlap 573 // 574 // Parameter: - 575 // Returns: - 576 // Changes Globals: - 577 //=========================================================================== 578 float HL_FaceOnWinding(hl_dface_t *face, winding_t *winding) 579 { 580 int i, edgenum, side; 581 float dist, area; 582 hl_dplane_t plane; 583 vec_t *v1, *v2; 584 vec3_t normal, edgevec; 585 winding_t *w; 586 587 // 588 w = CopyWinding(winding); 589 memcpy(&plane, &hl_dplanes[face->planenum], sizeof(hl_dplane_t)); 590 //check on which side of the plane the face is 591 if (face->side) 592 { 593 VectorNegate(plane.normal, plane.normal); 594 plane.dist = -plane.dist; 595 } //end if 596 for (i = 0; i < face->numedges && w; i++) 597 { 598 //get the first and second vertex of the edge 599 edgenum = hl_dsurfedges[face->firstedge + i]; 600 side = edgenum > 0; 601 //if the face plane is flipped 602 v1 = hl_dvertexes[hl_dedges[abs(edgenum)].v[side]].point; 603 v2 = hl_dvertexes[hl_dedges[abs(edgenum)].v[!side]].point; 604 //create a plane through the edge vector, orthogonal to the face plane 605 //and with the normal vector pointing out of the face 606 VectorSubtract(v1, v2, edgevec); 607 CrossProduct(edgevec, plane.normal, normal); 608 VectorNormalize(normal); 609 dist = DotProduct(normal, v1); 610 // 611 ChopWindingInPlace(&w, normal, dist, 0.9); //CLIP_EPSILON 612 } //end for 613 if (w) 614 { 615 area = WindingArea(w); 616 FreeWinding(w); 617 return area; 618 } //end if 619 return 0; 620 } //end of the function HL_FaceOnWinding 621 //=========================================================================== 622 // returns a list with brushes created by splitting the given brush with 623 // planes that go through the face edges and are orthogonal to the face plane 624 // 625 // Parameter: - 626 // Returns: - 627 // Changes Globals: - 628 //=========================================================================== 629 bspbrush_t *HL_SplitBrushWithFace(bspbrush_t *brush, hl_dface_t *face) 630 { 631 int i, edgenum, side, planenum, splits; 632 float dist; 633 hl_dplane_t plane; 634 vec_t *v1, *v2; 635 vec3_t normal, edgevec; 636 bspbrush_t *front, *back, *brushlist; 637 638 memcpy(&plane, &hl_dplanes[face->planenum], sizeof(hl_dplane_t)); 639 //check on which side of the plane the face is 640 if (face->side) 641 { 642 VectorNegate(plane.normal, plane.normal); 643 plane.dist = -plane.dist; 644 } //end if 645 splits = 0; 646 brushlist = NULL; 647 for (i = 0; i < face->numedges; i++) 648 { 649 //get the first and second vertex of the edge 650 edgenum = hl_dsurfedges[face->firstedge + i]; 651 side = edgenum > 0; 652 //if the face plane is flipped 653 v1 = hl_dvertexes[hl_dedges[abs(edgenum)].v[side]].point; 654 v2 = hl_dvertexes[hl_dedges[abs(edgenum)].v[!side]].point; 655 //create a plane through the edge vector, orthogonal to the face plane 656 //and with the normal vector pointing out of the face 657 VectorSubtract(v1, v2, edgevec); 658 CrossProduct(edgevec, plane.normal, normal); 659 VectorNormalize(normal); 660 dist = DotProduct(normal, v1); 661 // 662 planenum = FindFloatPlane(normal, dist); 663 //split the current brush 664 SplitBrush(brush, planenum, &front, &back); 665 //if there is a back brush just put it in the list 666 if (back) 667 { 668 //copy the brush contents 669 back->side = brush->side; 670 // 671 back->next = brushlist; 672 brushlist = back; 673 splits++; 674 } //end if 675 if (!front) 676 { 677 Log_Print("HL_SplitBrushWithFace: no new brush\n"); 678 FreeBrushList(brushlist); 679 return NULL; 680 } //end if 681 //copy the brush contents 682 front->side = brush->side; 683 //continue splitting the front brush 684 brush = front; 685 } //end for 686 if (!splits) 687 { 688 FreeBrush(front); 689 return NULL; 690 } //end if 691 front->next = brushlist; 692 brushlist = front; 693 return brushlist; 694 } //end of the function HL_SplitBrushWithFace 695 //=========================================================================== 696 // 697 // Parameter: - 698 // Returns: - 699 // Changes Globals: - 700 //=========================================================================== 701 bspbrush_t *HL_TextureBrushes(bspbrush_t *brushlist, int modelnum) 702 { 703 float area, largestarea; 704 int i, n, texinfonum, sn, numbrushes, ofs; 705 int bestfacenum, sidenodenum; 706 side_t *side; 707 hl_dmiptexlump_t *miptexlump; 708 hl_miptex_t *miptex; 709 bspbrush_t *brush, *nextbrush, *prevbrush, *newbrushes, *brushlistend; 710 vec_t defaultvec[4] = {1, 0, 0, 0}; 711 712 if (!modelnum) qprintf("texturing brushes\n"); 713 if (!modelnum) qprintf("%5d brushes", numbrushes = 0); 714 //get a pointer to the last brush in the list 715 for (brushlistend = brushlist; brushlistend; brushlistend = brushlistend->next) 716 { 717 if (!brushlistend->next) break; 718 } //end for 719 //there's no previous brush when at the start of the list 720 prevbrush = NULL; 721 //go over the brush list 722 for (brush = brushlist; brush; brush = nextbrush) 723 { 724 nextbrush = brush->next; 725 //find a texinfo for every brush side 726 for (sn = 0; sn < brush->numsides; sn++) 727 { 728 side = &brush->sides[sn]; 729 // 730 if (side->flags & SFL_TEXTURED) continue; 731 //number of the node that created this brush side 732 sidenodenum = side->surf; //see midwinding in HL_SplitBrush 733 //no face found yet 734 bestfacenum = -1; 735 //minimum face size 736 largestarea = 1; 737 //if optimizing the texture placement and not going for the 738 //least number of brushes 739 if (!lessbrushes) 740 { 741 for (i = 0; i < hl_numfaces; i++) 742 { 743 //the face must be in the same plane as the node plane that created 744 //this brush side 745 if (hl_dfaces[i].planenum == hl_dnodes[sidenodenum].planenum) 746 { 747 //get the area the face and the brush side overlap 748 area = HL_FaceOnWinding(&hl_dfaces[i], side->winding); 749 //if this face overlaps the brush side winding more than previous faces 750 if (area > largestarea) 751 { 752 //if there already was a face for texturing this brush side with 753 //a different texture 754 if (bestfacenum >= 0 && 755 (hl_dfaces[bestfacenum].texinfo != hl_dfaces[i].texinfo)) 756 { 757 //split the brush to fit the texture 758 newbrushes = HL_SplitBrushWithFace(brush, &hl_dfaces[i]); 759 //if new brushes where created 760 if (newbrushes) 761 { 762 //remove the current brush from the list 763 if (prevbrush) prevbrush->next = brush->next; 764 else brushlist = brush->next; 765 if (brushlistend == brush) 766 { 767 brushlistend = prevbrush; 768 nextbrush = newbrushes; 769 } //end if 770 //add the new brushes to the end of the list 771 if (brushlistend) brushlistend->next = newbrushes; 772 else brushlist = newbrushes; 773 //free the current brush 774 FreeBrush(brush); 775 //don't forget about the prevbrush pointer at the bottom of 776 //the outer loop 777 brush = prevbrush; 778 //find the end of the list 779 for (brushlistend = brushlist; brushlistend; brushlistend = brushlistend->next) 780 { 781 if (!brushlistend->next) break; 782 } //end for 783 break; 784 } //end if 785 else 786 { 787 Log_Write("brush %d: no real texture split", numbrushes); 788 } //end else 789 } //end if 790 else 791 { 792 //best face for texturing this brush side 793 bestfacenum = i; 794 } //end else 795 } //end if 796 } //end if 797 } //end for 798 //if the brush was split the original brush is removed 799 //and we just continue with the next one in the list 800 if (i < hl_numfaces) break; 801 } //end if 802 else 803 { 804 //find the face with the largest overlap with this brush side 805 //for texturing the brush side 806 for (i = 0; i < hl_numfaces; i++) 807 { 808 //the face must be in the same plane as the node plane that created 809 //this brush side 810 if (hl_dfaces[i].planenum == hl_dnodes[sidenodenum].planenum) 811 { 812 //get the area the face and the brush side overlap 813 area = HL_FaceOnWinding(&hl_dfaces[i], side->winding); 814 //if this face overlaps the brush side winding more than previous faces 815 if (area > largestarea) 816 { 817 largestarea = area; 818 bestfacenum = i; 819 } //end if 820 } //end if 821 } //end for 822 } //end else 823 //if a face was found for texturing this brush side 824 if (bestfacenum >= 0) 825 { 826 //set the MAP texinfo values 827 texinfonum = hl_dfaces[bestfacenum].texinfo; 828 for (n = 0; n < 4; n++) 829 { 830 map_texinfo[texinfonum].vecs[0][n] = hl_texinfo[texinfonum].vecs[0][n]; 831 map_texinfo[texinfonum].vecs[1][n] = hl_texinfo[texinfonum].vecs[1][n]; 832 } //end for 833 //make sure the two vectors aren't of zero length otherwise use the default 834 //vector to prevent a divide by zero in the map writing 835 if (VectorLength(map_texinfo[texinfonum].vecs[0]) < 0.01) 836 memcpy(map_texinfo[texinfonum].vecs[0], defaultvec, sizeof(defaultvec)); 837 if (VectorLength(map_texinfo[texinfonum].vecs[1]) < 0.01) 838 memcpy(map_texinfo[texinfonum].vecs[1], defaultvec, sizeof(defaultvec)); 839 // 840 map_texinfo[texinfonum].flags = hl_texinfo[texinfonum].flags; 841 map_texinfo[texinfonum].value = 0; //HL_ and HL texinfos don't have a value 842 //the mip texture 843 miptexlump = (hl_dmiptexlump_t *) hl_dtexdata; 844 ofs = miptexlump->dataofs[hl_texinfo[texinfonum].miptex]; 845 if ( ofs > hl_texdatasize ) { 846 ofs = miptexlump->dataofs[0]; 847 } 848 miptex = (hl_miptex_t *)((byte *)miptexlump + ofs ); 849 //get the mip texture name 850 strcpy(map_texinfo[texinfonum].texture, miptex->name); 851 //no animations in Quake1 and Half-Life mip textures 852 map_texinfo[texinfonum].nexttexinfo = -1; 853 //store the texinfo number 854 side->texinfo = texinfonum; 855 // 856 if (texinfonum > map_numtexinfo) map_numtexinfo = texinfonum; 857 //this side is textured 858 side->flags |= SFL_TEXTURED; 859 } //end if 860 else 861 { 862 //no texture for this side 863 side->texinfo = TEXINFO_NODE; 864 //this side is textured 865 side->flags |= SFL_TEXTURED; 866 } //end if 867 } //end for 868 // 869 if (!modelnum && prevbrush != brush) qprintf("\r%5d", ++numbrushes); 870 //previous brush in the list 871 prevbrush = brush; 872 } //end for 873 if (!modelnum) qprintf("\n"); 874 //return the new list with brushes 875 return brushlist; 876 } //end of the function HL_TextureBrushes 877 //=========================================================================== 878 // 879 // Parameter: - 880 // Returns: - 881 // Changes Globals: - 882 //=========================================================================== 883 void HL_FixContentsTextures(bspbrush_t *brushlist) 884 { 885 int i, texinfonum; 886 bspbrush_t *brush; 887 888 for (brush = brushlist; brush; brush = brush->next) 889 { 890 //only fix the textures of water, slime and lava brushes 891 if (brush->side != CONTENTS_WATER && 892 brush->side != CONTENTS_SLIME && 893 brush->side != CONTENTS_LAVA) continue; 894 // 895 for (i = 0; i < brush->numsides; i++) 896 { 897 texinfonum = brush->sides[i].texinfo; 898 if (HL_TextureContents(map_texinfo[texinfonum].texture) == brush->side) break; 899 } //end for 900 //if no specific contents texture was found 901 if (i >= brush->numsides) 902 { 903 texinfonum = -1; 904 for (i = 0; i < map_numtexinfo; i++) 905 { 906 if (HL_TextureContents(map_texinfo[i].texture) == brush->side) 907 { 908 texinfonum = i; 909 break; 910 } //end if 911 } //end for 912 } //end if 913 // 914 if (texinfonum >= 0) 915 { 916 //give all the brush sides this contents texture 917 for (i = 0; i < brush->numsides; i++) 918 { 919 brush->sides[i].texinfo = texinfonum; 920 } //end for 921 } //end if 922 else Log_Print("brush contents %d with wrong textures\n", brush->side); 923 // 924 } //end for 925 /* 926 for (brush = brushlist; brush; brush = brush->next) 927 { 928 //give all the brush sides this contents texture 929 for (i = 0; i < brush->numsides; i++) 930 { 931 if (HL_TextureContents(map_texinfo[texinfonum].texture) != brush->side) 932 { 933 Error("brush contents %d with wrong contents textures %s\n", brush->side, 934 HL_TextureContents(map_texinfo[texinfonum].texture)); 935 } //end if 936 } //end for 937 } //end for*/ 938 } //end of the function HL_FixContentsTextures 939 //=========================================================================== 940 // 941 // Parameter: - 942 // Returns: - 943 // Changes Globals: - 944 //=========================================================================== 945 void HL_BSPBrushToMapBrush(bspbrush_t *bspbrush, entity_t *mapent) 946 { 947 mapbrush_t *mapbrush; 948 side_t *side; 949 int i, besttexinfo; 950 951 if (nummapbrushes >= MAX_MAPFILE_BRUSHES) 952 Error ("nummapbrushes == MAX_MAPFILE_BRUSHES"); 953 954 mapbrush = &mapbrushes[nummapbrushes]; 955 mapbrush->original_sides = &brushsides[nummapbrushsides]; 956 mapbrush->entitynum = mapent - entities; 957 mapbrush->brushnum = nummapbrushes - mapent->firstbrush; 958 mapbrush->leafnum = -1; 959 mapbrush->numsides = 0; 960 961 besttexinfo = TEXINFO_NODE; 962 for (i = 0; i < bspbrush->numsides; i++) 963 { 964 if (!bspbrush->sides[i].winding) continue; 965 // 966 if (nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES) 967 Error ("MAX_MAPFILE_BRUSHSIDES"); 968 side = &brushsides[nummapbrushsides]; 969 //the contents of the bsp brush is stored in the side variable 970 side->contents = bspbrush->side; 971 side->surf = 0; 972 side->planenum = bspbrush->sides[i].planenum; 973 side->texinfo = bspbrush->sides[i].texinfo; 974 if (side->texinfo != TEXINFO_NODE) 975 { 976 //this brush side is textured 977 side->flags |= SFL_TEXTURED; 978 besttexinfo = side->texinfo; 979 } //end if 980 // 981 nummapbrushsides++; 982 mapbrush->numsides++; 983 } //end for 984 // 985 if (besttexinfo == TEXINFO_NODE) 986 { 987 mapbrush->numsides = 0; 988 hl_numclipbrushes++; 989 return; 990 } //end if 991 //set the texinfo for all the brush sides without texture 992 for (i = 0; i < mapbrush->numsides; i++) 993 { 994 if (mapbrush->original_sides[i].texinfo == TEXINFO_NODE) 995 { 996 mapbrush->original_sides[i].texinfo = besttexinfo; 997 } //end if 998 } //end for 999 //contents of the brush 1000 mapbrush->contents = bspbrush->side; 1001 // 1002 if (create_aas) 1003 { 1004 //create the AAS brushes from this brush, add brush bevels 1005 AAS_CreateMapBrushes(mapbrush, mapent, true); 1006 return; 1007 } //end if 1008 //create windings for sides and bounds for brush 1009 MakeBrushWindings(mapbrush); 1010 //add brush bevels 1011 AddBrushBevels(mapbrush); 1012 //a new brush has been created 1013 nummapbrushes++; 1014 mapent->numbrushes++; 1015 } //end of the function HL_BSPBrushToMapBrush 1016 //=========================================================================== 1017 // 1018 // Parameter: - 1019 // Returns: - 1020 // Changes Globals: - 1021 //=========================================================================== 1022 void HL_CreateMapBrushes(entity_t *mapent, int modelnum) 1023 { 1024 bspbrush_t *brushlist, *brush, *nextbrush; 1025 int i; 1026 1027 //create brushes from the model BSP tree 1028 brushlist = HL_CreateBrushesFromBSP(modelnum); 1029 //texture the brushes and split them when necesary 1030 brushlist = HL_TextureBrushes(brushlist, modelnum); 1031 //fix the contents textures of all brushes 1032 HL_FixContentsTextures(brushlist); 1033 // 1034 if (!nobrushmerge) 1035 { 1036 brushlist = HL_MergeBrushes(brushlist, modelnum); 1037 //brushlist = HL_MergeBrushes(brushlist, modelnum); 1038 } //end if 1039 // 1040 if (!modelnum) qprintf("converting brushes to map brushes\n"); 1041 if (!modelnum) qprintf("%5d brushes", i = 0); 1042 for (brush = brushlist; brush; brush = nextbrush) 1043 { 1044 nextbrush = brush->next; 1045 HL_BSPBrushToMapBrush(brush, mapent); 1046 brush->next = NULL; 1047 FreeBrush(brush); 1048 if (!modelnum) qprintf("\r%5d", ++i); 1049 } //end for 1050 if (!modelnum) qprintf("\n"); 1051 } //end of the function HL_CreateMapBrushes 1052 //=========================================================================== 1053 // 1054 // Parameter: - 1055 // Returns: - 1056 // Changes Globals: - 1057 //=========================================================================== 1058 void HL_ResetMapLoading(void) 1059 { 1060 } //end of the function HL_ResetMapLoading 1061 //=========================================================================== 1062 // 1063 // Parameter: - 1064 // Returns: - 1065 // Changes Globals: - 1066 //=========================================================================== 1067 void HL_LoadMapFromBSP(char *filename, int offset, int length) 1068 { 1069 int i, modelnum; 1070 char *model, *classname; 1071 1072 Log_Print("-- HL_LoadMapFromBSP --\n"); 1073 //loaded map type 1074 loadedmaptype = MAPTYPE_HALFLIFE; 1075 // 1076 qprintf("loading map from %s at %d\n", filename, offset); 1077 //load the Half-Life BSP file 1078 HL_LoadBSPFile(filename, offset, length); 1079 // 1080 hl_numclipbrushes = 0; 1081 //parse the entities from the BSP 1082 HL_ParseEntities(); 1083 //clear the map mins and maxs 1084 ClearBounds(map_mins, map_maxs); 1085 // 1086 qprintf("creating Half-Life brushes\n"); 1087 if (lessbrushes) qprintf("creating minimum number of brushes\n"); 1088 else qprintf("placing textures correctly\n"); 1089 // 1090 for (i = 0; i < num_entities; i++) 1091 { 1092 entities[i].firstbrush = nummapbrushes; 1093 entities[i].numbrushes = 0; 1094 // 1095 classname = ValueForKey(&entities[i], "classname"); 1096 if (classname && !strcmp(classname, "worldspawn")) 1097 { 1098 modelnum = 0; 1099 } //end if 1100 else 1101 { 1102 // 1103 model = ValueForKey(&entities[i], "model"); 1104 if (!model || *model != '*') continue; 1105 model++; 1106 modelnum = atoi(model); 1107 } //end else 1108 //create map brushes for the entity 1109 HL_CreateMapBrushes(&entities[i], modelnum); 1110 } //end for 1111 // 1112 qprintf("%5d map brushes\n", nummapbrushes); 1113 qprintf("%5d clip brushes\n", hl_numclipbrushes); 1114 } //end of the function HL_LoadMapFromBSP