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