map.c (35826B)
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 "l_bsp_q1.h" 26 #include "l_bsp_q2.h" 27 #include "l_bsp_q3.h" 28 #include "l_bsp_sin.h" 29 #include "l_mem.h" 30 #include "../botlib/aasfile.h" //aas_bbox_t 31 #include "aas_store.h" //AAS_MAX_BBOXES 32 #include "aas_cfg.h" 33 34 #define Sign(x) (x < 0 ? 1 : 0) 35 36 int nummapbrushes; 37 mapbrush_t mapbrushes[MAX_MAPFILE_BRUSHES]; 38 39 int nummapbrushsides; 40 side_t brushsides[MAX_MAPFILE_BRUSHSIDES]; 41 brush_texture_t side_brushtextures[MAX_MAPFILE_BRUSHSIDES]; 42 43 int nummapplanes; 44 plane_t mapplanes[MAX_MAPFILE_PLANES]; 45 int mapplaneusers[MAX_MAPFILE_PLANES]; 46 47 #define PLANE_HASHES 1024 48 plane_t *planehash[PLANE_HASHES]; 49 vec3_t map_mins, map_maxs; 50 51 #ifdef SIN 52 textureref_t side_newrefs[MAX_MAPFILE_BRUSHSIDES]; 53 #endif 54 55 map_texinfo_t map_texinfo[MAX_MAPFILE_TEXINFO]; 56 int map_numtexinfo; 57 int loadedmaptype; //loaded map type 58 59 // undefine to make plane finding use linear sort 60 #define USE_HASHING 61 62 int c_boxbevels; 63 int c_edgebevels; 64 int c_areaportals; 65 int c_clipbrushes; 66 int c_squattbrushes; 67 int c_writtenbrushes; 68 69 /* 70 ============================================================================= 71 72 PLANE FINDING 73 74 ============================================================================= 75 */ 76 77 78 //=========================================================================== 79 // 80 // Parameter: - 81 // Returns: - 82 // Changes Globals: - 83 //=========================================================================== 84 int PlaneSignBits(vec3_t normal) 85 { 86 int i, signbits; 87 88 signbits = 0; 89 for (i = 2; i >= 0; i--) 90 { 91 signbits = (signbits << 1) + Sign(normal[i]); 92 } //end for 93 return signbits; 94 } //end of the function PlaneSignBits 95 //=========================================================================== 96 // 97 // Parameter: - 98 // Returns: - 99 // Changes Globals: - 100 //=========================================================================== 101 int PlaneTypeForNormal(vec3_t normal) 102 { 103 vec_t ax, ay, az; 104 105 // NOTE: should these have an epsilon around 1.0? 106 if (normal[0] == 1.0 || normal[0] == -1.0) 107 return PLANE_X; 108 if (normal[1] == 1.0 || normal[1] == -1.0) 109 return PLANE_Y; 110 if (normal[2] == 1.0 || normal[2] == -1.0) 111 return PLANE_Z; 112 113 ax = fabs(normal[0]); 114 ay = fabs(normal[1]); 115 az = fabs(normal[2]); 116 117 if (ax >= ay && ax >= az) 118 return PLANE_ANYX; 119 if (ay >= ax && ay >= az) 120 return PLANE_ANYY; 121 return PLANE_ANYZ; 122 } //end of the function PlaneTypeForNormal 123 //=========================================================================== 124 // 125 // Parameter: - 126 // Returns: - 127 // Changes Globals: - 128 //=========================================================================== 129 //ME NOTE: changed from 0.00001 130 #define NORMAL_EPSILON 0.0001 131 //ME NOTE: changed from 0.01 132 #define DIST_EPSILON 0.02 133 qboolean PlaneEqual(plane_t *p, vec3_t normal, vec_t dist) 134 { 135 #if 1 136 if ( 137 fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON 138 && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON 139 && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON 140 && fabs(p->dist - dist) < DIST_EPSILON ) 141 return true; 142 #else 143 if (p->normal[0] == normal[0] 144 && p->normal[1] == normal[1] 145 && p->normal[2] == normal[2] 146 && p->dist == dist) 147 return true; 148 #endif 149 return false; 150 } //end of the function PlaneEqual 151 //=========================================================================== 152 // 153 // Parameter: - 154 // Returns: - 155 // Changes Globals: - 156 //=========================================================================== 157 void AddPlaneToHash(plane_t *p) 158 { 159 int hash; 160 161 hash = (int)fabs(p->dist) / 8; 162 hash &= (PLANE_HASHES-1); 163 164 p->hash_chain = planehash[hash]; 165 planehash[hash] = p; 166 } //end of the function AddPlaneToHash 167 //=========================================================================== 168 // 169 // Parameter: - 170 // Returns: - 171 // Changes Globals: - 172 //=========================================================================== 173 int CreateNewFloatPlane (vec3_t normal, vec_t dist) 174 { 175 plane_t *p, temp; 176 177 if (VectorLength(normal) < 0.5) 178 Error ("FloatPlane: bad normal"); 179 // create a new plane 180 if (nummapplanes+2 > MAX_MAPFILE_PLANES) 181 Error ("MAX_MAPFILE_PLANES"); 182 183 p = &mapplanes[nummapplanes]; 184 VectorCopy (normal, p->normal); 185 p->dist = dist; 186 p->type = (p+1)->type = PlaneTypeForNormal (p->normal); 187 p->signbits = PlaneSignBits(p->normal); 188 189 VectorSubtract (vec3_origin, normal, (p+1)->normal); 190 (p+1)->dist = -dist; 191 (p+1)->signbits = PlaneSignBits((p+1)->normal); 192 193 nummapplanes += 2; 194 195 // allways put axial planes facing positive first 196 if (p->type < 3) 197 { 198 if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0) 199 { 200 // flip order 201 temp = *p; 202 *p = *(p+1); 203 *(p+1) = temp; 204 205 AddPlaneToHash (p); 206 AddPlaneToHash (p+1); 207 return nummapplanes - 1; 208 } 209 } 210 211 AddPlaneToHash (p); 212 AddPlaneToHash (p+1); 213 return nummapplanes - 2; 214 } //end of the function CreateNewFloatPlane 215 //=========================================================================== 216 // 217 // Parameter: - 218 // Returns: - 219 // Changes Globals: - 220 //=========================================================================== 221 void SnapVector(vec3_t normal) 222 { 223 int i; 224 225 for (i=0 ; i<3 ; i++) 226 { 227 if ( fabs(normal[i] - 1) < NORMAL_EPSILON ) 228 { 229 VectorClear (normal); 230 normal[i] = 1; 231 break; 232 } 233 if ( fabs(normal[i] - -1) < NORMAL_EPSILON ) 234 { 235 VectorClear (normal); 236 normal[i] = -1; 237 break; 238 } 239 } 240 } //end of the function SnapVector 241 //=========================================================================== 242 // 243 // Parameter: - 244 // Returns: - 245 // Changes Globals: - 246 //=========================================================================== 247 void SnapPlane(vec3_t normal, vec_t *dist) 248 { 249 SnapVector(normal); 250 251 if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON) 252 *dist = Q_rint(*dist); 253 } //end of the function SnapPlane 254 //=========================================================================== 255 // 256 // Parameter: - 257 // Returns: - 258 // Changes Globals: - 259 //=========================================================================== 260 #ifndef USE_HASHING 261 int FindFloatPlane(vec3_t normal, vec_t dist) 262 { 263 int i; 264 plane_t *p; 265 266 SnapPlane(normal, &dist); 267 for (i = 0, p = mapplanes; i < nummapplanes; i++, p++) 268 { 269 if (PlaneEqual (p, normal, dist)) 270 { 271 mapplaneusers[i]++; 272 return i; 273 } //end if 274 } //end for 275 i = CreateNewFloatPlane (normal, dist); 276 mapplaneusers[i]++; 277 return i; 278 } //end of the function FindFloatPlane 279 #else 280 int FindFloatPlane (vec3_t normal, vec_t dist) 281 { 282 int i; 283 plane_t *p; 284 int hash, h; 285 286 SnapPlane (normal, &dist); 287 hash = (int)fabs(dist) / 8; 288 hash &= (PLANE_HASHES-1); 289 290 // search the border bins as well 291 for (i = -1; i <= 1; i++) 292 { 293 h = (hash+i)&(PLANE_HASHES-1); 294 for (p = planehash[h]; p; p = p->hash_chain) 295 { 296 if (PlaneEqual(p, normal, dist)) 297 { 298 mapplaneusers[p-mapplanes]++; 299 return p - mapplanes; 300 } //end if 301 } //end for 302 } //end for 303 i = CreateNewFloatPlane (normal, dist); 304 mapplaneusers[i]++; 305 return i; 306 } //end of the function FindFloatPlane 307 #endif 308 //=========================================================================== 309 // 310 // Parameter: - 311 // Returns: - 312 // Changes Globals: - 313 //=========================================================================== 314 int PlaneFromPoints (int *p0, int *p1, int *p2) 315 { 316 vec3_t t1, t2, normal; 317 vec_t dist; 318 319 VectorSubtract (p0, p1, t1); 320 VectorSubtract (p2, p1, t2); 321 CrossProduct (t1, t2, normal); 322 VectorNormalize (normal); 323 324 dist = DotProduct (p0, normal); 325 326 return FindFloatPlane (normal, dist); 327 } //end of the function PlaneFromPoints 328 //=========================================================================== 329 // Adds any additional planes necessary to allow the brush to be expanded 330 // against axial bounding boxes 331 // 332 // Parameter: - 333 // Returns: - 334 // Changes Globals: - 335 //=========================================================================== 336 void AddBrushBevels (mapbrush_t *b) 337 { 338 int axis, dir; 339 int i, j, k, l, order; 340 side_t sidetemp; 341 brush_texture_t tdtemp; 342 #ifdef SIN 343 textureref_t trtemp; 344 #endif 345 side_t *s, *s2; 346 vec3_t normal; 347 float dist; 348 winding_t *w, *w2; 349 vec3_t vec, vec2; 350 float d; 351 352 // 353 // add the axial planes 354 // 355 order = 0; 356 for (axis=0 ; axis <3 ; axis++) 357 { 358 for (dir=-1 ; dir <= 1 ; dir+=2, order++) 359 { 360 // see if the plane is allready present 361 for (i=0, s=b->original_sides ; i<b->numsides ; i++,s++) 362 { 363 if (mapplanes[s->planenum].normal[axis] == dir) 364 break; 365 } 366 367 if (i == b->numsides) 368 { // add a new side 369 if (nummapbrushsides == MAX_MAP_BRUSHSIDES) 370 Error ("MAX_MAP_BRUSHSIDES"); 371 nummapbrushsides++; 372 b->numsides++; 373 VectorClear (normal); 374 normal[axis] = dir; 375 if (dir == 1) 376 dist = b->maxs[axis]; 377 else 378 dist = -b->mins[axis]; 379 s->planenum = FindFloatPlane (normal, dist); 380 s->texinfo = b->original_sides[0].texinfo; 381 #ifdef SIN 382 s->lightinfo = b->original_sides[0].lightinfo; 383 #endif 384 s->contents = b->original_sides[0].contents; 385 s->flags |= SFL_BEVEL; 386 c_boxbevels++; 387 } 388 389 // if the plane is not in it canonical order, swap it 390 if (i != order) 391 { 392 sidetemp = b->original_sides[order]; 393 b->original_sides[order] = b->original_sides[i]; 394 b->original_sides[i] = sidetemp; 395 396 j = b->original_sides - brushsides; 397 tdtemp = side_brushtextures[j+order]; 398 side_brushtextures[j+order] = side_brushtextures[j+i]; 399 side_brushtextures[j+i] = tdtemp; 400 401 #ifdef SIN 402 trtemp = side_newrefs[j+order]; 403 side_newrefs[j+order] = side_newrefs[j+i]; 404 side_newrefs[j+i] = trtemp; 405 #endif 406 } 407 } 408 } 409 410 // 411 // add the edge bevels 412 // 413 if (b->numsides == 6) 414 return; // pure axial 415 416 // test the non-axial plane edges 417 for (i=6 ; i<b->numsides ; i++) 418 { 419 s = b->original_sides + i; 420 w = s->winding; 421 if (!w) 422 continue; 423 for (j=0 ; j<w->numpoints ; j++) 424 { 425 k = (j+1)%w->numpoints; 426 VectorSubtract (w->p[j], w->p[k], vec); 427 if (VectorNormalize (vec) < 0.5) 428 continue; 429 SnapVector (vec); 430 for (k=0 ; k<3 ; k++) 431 if ( vec[k] == -1 || vec[k] == 1) 432 break; // axial 433 if (k != 3) 434 continue; // only test non-axial edges 435 436 // try the six possible slanted axials from this edge 437 for (axis=0 ; axis <3 ; axis++) 438 { 439 for (dir=-1 ; dir <= 1 ; dir+=2) 440 { 441 // construct a plane 442 VectorClear (vec2); 443 vec2[axis] = dir; 444 CrossProduct (vec, vec2, normal); 445 if (VectorNormalize (normal) < 0.5) 446 continue; 447 dist = DotProduct (w->p[j], normal); 448 449 // if all the points on all the sides are 450 // behind this plane, it is a proper edge bevel 451 for (k=0 ; k<b->numsides ; k++) 452 { 453 // if this plane has allready been used, skip it 454 if (PlaneEqual (&mapplanes[b->original_sides[k].planenum] 455 , normal, dist) ) 456 break; 457 458 w2 = b->original_sides[k].winding; 459 if (!w2) 460 continue; 461 for (l=0 ; l<w2->numpoints ; l++) 462 { 463 d = DotProduct (w2->p[l], normal) - dist; 464 if (d > 0.1) 465 break; // point in front 466 } 467 if (l != w2->numpoints) 468 break; 469 } 470 471 if (k != b->numsides) 472 continue; // wasn't part of the outer hull 473 // add this plane 474 if (nummapbrushsides == MAX_MAP_BRUSHSIDES) 475 Error ("MAX_MAP_BRUSHSIDES"); 476 nummapbrushsides++; 477 s2 = &b->original_sides[b->numsides]; 478 s2->planenum = FindFloatPlane (normal, dist); 479 s2->texinfo = b->original_sides[0].texinfo; 480 #ifdef SIN 481 s2->lightinfo = b->original_sides[0].lightinfo; 482 #endif 483 s2->contents = b->original_sides[0].contents; 484 s2->flags |= SFL_BEVEL; 485 c_edgebevels++; 486 b->numsides++; 487 } 488 } 489 } 490 } 491 } //end of the function AddBrushBevels 492 //=========================================================================== 493 // creates windigs for sides and mins / maxs for the brush 494 // 495 // Parameter: - 496 // Returns: - 497 // Changes Globals: - 498 //=========================================================================== 499 qboolean MakeBrushWindings(mapbrush_t *ob) 500 { 501 int i, j; 502 winding_t *w; 503 side_t *side; 504 plane_t *plane; 505 506 ClearBounds (ob->mins, ob->maxs); 507 508 for (i = 0; i < ob->numsides; i++) 509 { 510 plane = &mapplanes[ob->original_sides[i].planenum]; 511 w = BaseWindingForPlane(plane->normal, plane->dist); 512 for (j = 0; j <ob->numsides && w; j++) 513 { 514 if (i == j) continue; 515 if (ob->original_sides[j].flags & SFL_BEVEL) continue; 516 plane = &mapplanes[ob->original_sides[j].planenum^1]; 517 ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); 518 } 519 520 side = &ob->original_sides[i]; 521 side->winding = w; 522 if (w) 523 { 524 side->flags |= SFL_VISIBLE; 525 for (j = 0; j < w->numpoints; j++) 526 AddPointToBounds (w->p[j], ob->mins, ob->maxs); 527 } 528 } 529 530 for (i = 0; i < 3; i++) 531 { 532 //IDBUG: all the indexes into the mins and maxs were zero (not using i) 533 if (ob->mins[i] < -MAX_MAP_BOUNDS || ob->maxs[i] > MAX_MAP_BOUNDS) 534 { 535 Log_Print("entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum); 536 ob->numsides = 0; //remove the brush 537 break; 538 } //end if 539 if (ob->mins[i] > MAX_MAP_BOUNDS || ob->maxs[i] < -MAX_MAP_BOUNDS) 540 { 541 Log_Print("entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum); 542 ob->numsides = 0; //remove the brush 543 break; 544 } //end if 545 } //end for 546 return true; 547 } //end of the function MakeBrushWindings 548 //=========================================================================== 549 // FIXME: currently doesn't mark all bevels 550 // NOTE: when one brush bevel is found the remaining sides of the brush 551 // are bevels as well (when the brush isn't expanded for AAS :)) 552 // 553 // Parameter: - 554 // Returns: - 555 // Changes Globals: - 556 //=========================================================================== 557 void MarkBrushBevels(mapbrush_t *brush) 558 { 559 int i; 560 int we; 561 side_t *s; 562 563 //check all the sides of the brush 564 for (i = 0; i < brush->numsides; i++) 565 { 566 s = brush->original_sides + i; 567 //if the side has no winding 568 if (!s->winding) 569 { 570 Log_Write("MarkBrushBevels: brush %d no winding", brush->brushnum); 571 s->flags |= SFL_BEVEL; 572 } //end if 573 //if the winding is tiny 574 else if (WindingIsTiny(s->winding)) 575 { 576 s->flags |= SFL_BEVEL; 577 Log_Write("MarkBrushBevels: brush %d tiny winding", brush->brushnum); 578 } //end else if 579 //if the winding has errors 580 else 581 { 582 we = WindingError(s->winding); 583 if (we == WE_NOTENOUGHPOINTS 584 || we == WE_SMALLAREA 585 || we == WE_POINTBOGUSRANGE 586 // || we == WE_NONCONVEX 587 ) 588 { 589 Log_Write("MarkBrushBevels: brush %d %s", brush->brushnum, WindingErrorString()); 590 s->flags |= SFL_BEVEL; 591 } //end else if 592 } //end else 593 if (s->flags & SFL_BEVEL) 594 { 595 s->flags &= ~SFL_VISIBLE; 596 //if the side has a valid plane 597 if (s->planenum > 0 && s->planenum < nummapplanes) 598 { 599 //if it is an axial plane 600 if (mapplanes[s->planenum].type < 3) c_boxbevels++; 601 else c_edgebevels++; 602 } //end if 603 } //end if 604 } //end for 605 } //end of the function MarkBrushBevels 606 //=========================================================================== 607 // returns true if the map brush already exists 608 // 609 // Parameter: - 610 // Returns: - 611 // Changes Globals: - 612 //=========================================================================== 613 int BrushExists(mapbrush_t *brush) 614 { 615 int i, s1, s2; 616 side_t *side1, *side2; 617 mapbrush_t *brush1, *brush2; 618 619 for (i = 0; i < nummapbrushes; i++) 620 { 621 brush1 = brush; 622 brush2 = &mapbrushes[i]; 623 //compare the brushes 624 if (brush1->entitynum != brush2->entitynum) continue; 625 //if (brush1->contents != brush2->contents) continue; 626 if (brush1->numsides != brush2->numsides) continue; 627 for (s1 = 0; s1 < brush1->numsides; s1++) 628 { 629 side1 = brush1->original_sides + s1; 630 // 631 for (s2 = 0; s2 < brush2->numsides; s2++) 632 { 633 side2 = brush2->original_sides + s2; 634 // 635 if ((side1->planenum & ~1) == (side2->planenum & ~1) 636 // && side1->texinfo == side2->texinfo 637 // && side1->contents == side2->contents 638 // && side1->surf == side2->surf 639 ) break; 640 } //end if 641 if (s2 >= brush2->numsides) break; 642 } //end for 643 if (s1 >= brush1->numsides) return true; 644 } //end for 645 return false; 646 } //end of the function BrushExists 647 //=========================================================================== 648 // 649 // Parameter: - 650 // Returns: - 651 // Changes Globals: - 652 //=========================================================================== 653 qboolean WriteMapBrush(FILE *fp, mapbrush_t *brush, vec3_t origin) 654 { 655 int sn, rotate, shift[2], sv, tv, planenum, p1, i, j; 656 float scale[2], originshift[2], ang1, ang2, newdist; 657 vec3_t vecs[2], axis[2]; 658 map_texinfo_t *ti; 659 winding_t *w; 660 side_t *s; 661 plane_t *plane; 662 663 if (noliquids) 664 { 665 if (brush->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) 666 { 667 return true; 668 } //end if 669 } //end if 670 //if the brush has no contents 671 if (!brush->contents) return true; 672 //print the leading { 673 if (fprintf(fp, " { //brush %d\n", brush->brushnum) < 0) return false; 674 //write brush sides 675 for (sn = 0; sn < brush->numsides; sn++) 676 { 677 s = brush->original_sides + sn; 678 //don't write out bevels 679 if (!(s->flags & SFL_BEVEL)) 680 { 681 //if the entity has an origin set 682 if (origin[0] || origin[1] || origin[2]) 683 { 684 newdist = mapplanes[s->planenum].dist + 685 DotProduct(mapplanes[s->planenum].normal, origin); 686 planenum = FindFloatPlane(mapplanes[s->planenum].normal, newdist); 687 } //end if 688 else 689 { 690 planenum = s->planenum; 691 } //end else 692 //always take the first plane, then flip the points if necesary 693 plane = &mapplanes[planenum & ~1]; 694 w = BaseWindingForPlane(plane->normal, plane->dist); 695 // 696 for (i = 0; i < 3; i++) 697 { 698 for (j = 0; j < 3; j++) 699 { 700 if (fabs(w->p[i][j]) < 0.2) w->p[i][j] = 0; 701 else if (fabs((int)w->p[i][j] - w->p[i][j]) < 0.3) w->p[i][j] = (int) w->p[i][j]; 702 //w->p[i][j] = (int) (w->p[i][j] + 0.2); 703 } //end for 704 } //end for 705 //three non-colinear points to define the plane 706 if (planenum & 1) p1 = 1; 707 else p1 = 0; 708 if (fprintf(fp," ( %5i %5i %5i ) ", (int)w->p[p1][0], (int)w->p[p1][1], (int)w->p[p1][2]) < 0) return false; 709 if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[!p1][0], (int)w->p[!p1][1], (int)w->p[!p1][2]) < 0) return false; 710 if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]) < 0) return false; 711 //free the winding 712 FreeWinding(w); 713 // 714 if (s->texinfo == TEXINFO_NODE) 715 { 716 if (brush->contents & CONTENTS_PLAYERCLIP) 717 { 718 //player clip 719 if (loadedmaptype == MAPTYPE_SIN) 720 { 721 if (fprintf(fp, "generic/misc/clip 0 0 0 1 1") < 0) return false; 722 } //end if 723 else if (loadedmaptype == MAPTYPE_QUAKE2) 724 { //FIXME: don't always use e1u1 725 if (fprintf(fp, "e1u1/clip 0 0 0 1 1") < 0) return false; 726 } //end else 727 else if (loadedmaptype == MAPTYPE_QUAKE3) 728 { 729 if (fprintf(fp, "e1u1/clip 0 0 0 1 1") < 0) return false; 730 } //end else if 731 else 732 { 733 if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false; 734 } //end else 735 } //end if 736 else if (brush->contents == CONTENTS_MONSTERCLIP) 737 { 738 //monster clip 739 if (loadedmaptype == MAPTYPE_SIN) 740 { 741 if (fprintf(fp, "generic/misc/monster 0 0 0 1 1") < 0) return false; 742 } //end if 743 else if (loadedmaptype == MAPTYPE_QUAKE2) 744 { 745 if (fprintf(fp, "e1u1/clip_mon 0 0 0 1 1") < 0) return false; 746 } //end else 747 else 748 { 749 if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false; 750 } //end else 751 } //end else 752 else 753 { 754 if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false; 755 Log_Write("brush->contents = %d\n", brush->contents); 756 } //end else 757 } //end if 758 else if (loadedmaptype == MAPTYPE_SIN && s->texinfo == 0) 759 { 760 if (brush->contents & CONTENTS_DUMMYFENCE) 761 { 762 if (fprintf(fp, "generic/misc/fence 0 0 0 1 1") < 0) return false; 763 } //end if 764 else if (brush->contents & CONTENTS_MIST) 765 { 766 if (fprintf(fp, "generic/misc/volumetric_base 0 0 0 1 1") < 0) return false; 767 } //end if 768 else //unknown so far 769 { 770 if (fprintf(fp, "generic/misc/red 0 0 0 1 1") < 0) return false; 771 } //end else 772 } //end if 773 else if (loadedmaptype == MAPTYPE_QUAKE3) 774 { 775 //always use the same texture 776 if (fprintf(fp, "e2u3/floor1_2 0 0 0 1 1 1 0 0") < 0) return false; 777 } //end else if 778 else 779 { 780 //* 781 ti = &map_texinfo[s->texinfo]; 782 //the scaling of the texture 783 scale[0] = 1 / VectorNormalize2(ti->vecs[0], vecs[0]); 784 scale[1] = 1 / VectorNormalize2(ti->vecs[1], vecs[1]); 785 // 786 TextureAxisFromPlane(plane, axis[0], axis[1]); 787 //calculate texture shift done by entity origin 788 originshift[0] = DotProduct(origin, axis[0]); 789 originshift[1] = DotProduct(origin, axis[1]); 790 //the texture shift without origin shift 791 shift[0] = ti->vecs[0][3] - originshift[0]; 792 shift[1] = ti->vecs[1][3] - originshift[1]; 793 // 794 if (axis[0][0]) sv = 0; 795 else if (axis[0][1]) sv = 1; 796 else sv = 2; 797 if (axis[1][0]) tv = 0; 798 else if (axis[1][1]) tv = 1; 799 else tv = 2; 800 //calculate rotation of texture 801 if (vecs[0][tv] == 0) ang1 = vecs[0][sv] > 0 ? 90.0 : -90.0; 802 else ang1 = atan2(vecs[0][sv], vecs[0][tv]) * 180 / Q_PI; 803 if (ang1 < 0) ang1 += 360; 804 if (ang1 >= 360) ang1 -= 360; 805 if (axis[0][tv] == 0) ang2 = axis[0][sv] > 0 ? 90.0 : -90.0; 806 else ang2 = atan2(axis[0][sv], axis[0][tv]) * 180 / Q_PI; 807 if (ang2 < 0) ang2 += 360; 808 if (ang2 >= 360) ang2 -= 360; 809 rotate = ang2 - ang1; 810 if (rotate < 0) rotate += 360; 811 if (rotate >= 360) rotate -= 360; 812 //write the texture info 813 if (fprintf(fp, "%s %d %d %d", ti->texture, shift[0], shift[1], rotate) < 0) return false; 814 if (fabs(scale[0] - ((int) scale[0])) < 0.001) 815 { 816 if (fprintf(fp, " %d", (int) scale[0]) < 0) return false; 817 } //end if 818 else 819 { 820 if (fprintf(fp, " %4f", scale[0]) < 0) return false; 821 } //end if 822 if (fabs(scale[1] - ((int) scale[1])) < 0.001) 823 { 824 if (fprintf(fp, " %d", (int) scale[1]) < 0) return false; 825 } //end if 826 else 827 { 828 if (fprintf(fp, " %4f", scale[1]) < 0) return false; 829 } //end else 830 //write the extra brush side info 831 if (loadedmaptype == MAPTYPE_QUAKE2) 832 { 833 if (fprintf(fp, " %ld %ld %ld", s->contents, ti->flags, ti->value) < 0) return false; 834 } //end if 835 //*/ 836 } //end else 837 if (fprintf(fp, "\n") < 0) return false; 838 } //end if 839 } //end if 840 if (fprintf(fp, " }\n") < 0) return false; 841 c_writtenbrushes++; 842 return true; 843 } //end of the function WriteMapBrush 844 //=========================================================================== 845 // 846 // Parameter: - 847 // Returns: - 848 // Changes Globals: - 849 //=========================================================================== 850 qboolean WriteOriginBrush(FILE *fp, vec3_t origin) 851 { 852 vec3_t normal; 853 float dist; 854 int i, s; 855 winding_t *w; 856 857 if (fprintf(fp, " {\n") < 0) return false; 858 // 859 for (i = 0; i < 3; i++) 860 { 861 for (s = -1; s <= 1; s += 2) 862 { 863 // 864 VectorClear(normal); 865 normal[i] = s; 866 dist = origin[i] * s + 16; 867 // 868 w = BaseWindingForPlane(normal, dist); 869 //three non-colinear points to define the plane 870 if (fprintf(fp," ( %5i %5i %5i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]) < 0) return false; 871 if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]) < 0) return false; 872 if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]) < 0) return false; 873 //free the winding 874 FreeWinding(w); 875 //write origin texture: 876 // CONTENTS_ORIGIN = 16777216 877 // SURF_NODRAW = 128 878 if (loadedmaptype == MAPTYPE_SIN) 879 { 880 if (fprintf(fp, "generic/misc/origin 0 0 0 1 1") < 0) return false; 881 } //end if 882 else if (loadedmaptype == MAPTYPE_HALFLIFE) 883 { 884 if (fprintf(fp, "origin 0 0 0 1 1") < 0) return false; 885 } //end if 886 else 887 { 888 if (fprintf(fp, "e1u1/origin 0 0 0 1 1") < 0) return false; 889 } //end else 890 //Quake2 extra brush side info 891 if (loadedmaptype == MAPTYPE_QUAKE2) 892 { 893 //if (fprintf(fp, " 16777216 128 0") < 0) return false; 894 } //end if 895 if (fprintf(fp, "\n") < 0) return false; 896 } //end for 897 } //end for 898 if (fprintf(fp, " }\n") < 0) return false; 899 c_writtenbrushes++; 900 return true; 901 } //end of the function WriteOriginBrush 902 //=========================================================================== 903 // 904 // Parameter: - 905 // Returns: - 906 // Changes Globals: - 907 //=========================================================================== 908 mapbrush_t *GetAreaPortalBrush(entity_t *mapent) 909 { 910 int portalnum, bn; 911 mapbrush_t *brush; 912 913 //the area portal number 914 portalnum = mapent->areaportalnum; 915 //find the area portal brush in the world brushes 916 for (bn = 0; bn < nummapbrushes && portalnum; bn++) 917 { 918 brush = &mapbrushes[bn]; 919 //must be in world entity 920 if (brush->entitynum == 0) 921 { 922 if (brush->contents & CONTENTS_AREAPORTAL) 923 { 924 portalnum--; 925 } //end if 926 } //end if 927 } //end for 928 if (bn < nummapbrushes) 929 { 930 return brush; 931 } //end if 932 else 933 { 934 Log_Print("area portal %d brush not found\n", mapent->areaportalnum); 935 return NULL; 936 } //end else 937 } //end of the function GetAreaPortalBrush 938 //=========================================================================== 939 // 940 // Parameter: - 941 // Returns: - 942 // Changes Globals: - 943 //=========================================================================== 944 qboolean WriteMapFileSafe(FILE *fp) 945 { 946 char key[1024], value[1024]; 947 int i, bn, entitybrushes; 948 epair_t *ep; 949 mapbrush_t *brush; 950 entity_t *mapent; 951 //vec3_t vec_origin = {0, 0, 0}; 952 953 // 954 if (fprintf(fp,"//=====================================================\n" 955 "//\n" 956 "// map file created with BSPC "BSPC_VERSION"\n" 957 "//\n" 958 "// BSPC is designed to decompile material in which you own the copyright\n" 959 "// or have obtained permission to decompile from the copyright owner. Unless\n" 960 "// you own the copyright or have permission to decompile from the copyright\n" 961 "// owner, you may be violating copyright law and be subject to payment of\n" 962 "// damages and other remedies. If you are uncertain about your rights, contact\n" 963 "// your legal advisor.\n" 964 "//\n") < 0) return false; 965 if (loadedmaptype == MAPTYPE_SIN) 966 { 967 if (fprintf(fp, 968 "// generic/misc/red is used for unknown textures\n") < 0) return false; 969 } //end if 970 if (fprintf(fp,"//\n" 971 "//=====================================================\n") < 0) return false; 972 //write out all the entities 973 for (i = 0; i < num_entities; i++) 974 { 975 mapent = &entities[i]; 976 if (!mapent->epairs) 977 { 978 continue; 979 } //end if 980 if (fprintf(fp, "{\n") < 0) return false; 981 // 982 if (loadedmaptype == MAPTYPE_QUAKE3) 983 { 984 if (!stricmp(ValueForKey(mapent, "classname"), "light")) 985 { 986 SetKeyValue(mapent, "light", "10000"); 987 } //end if 988 } //end if 989 //write epairs 990 for (ep = mapent->epairs; ep; ep = ep->next) 991 { 992 strcpy(key, ep->key); 993 StripTrailing (key); 994 strcpy(value, ep->value); 995 StripTrailing(value); 996 // 997 if (loadedmaptype == MAPTYPE_QUAKE2 || 998 loadedmaptype == MAPTYPE_SIN) 999 { 1000 //don't write an origin for BSP models 1001 if (mapent->modelnum >= 0 && !strcmp(key, "origin")) continue; 1002 } //end if 1003 //don't write BSP model numbers 1004 if (mapent->modelnum >= 0 && !strcmp(key, "model") && value[0] == '*') continue; 1005 // 1006 if (fprintf(fp, " \"%s\" \"%s\"\n", key, value) < 0) return false; 1007 } //end for 1008 // 1009 if (ValueForKey(mapent, "origin")) GetVectorForKey(mapent, "origin", mapent->origin); 1010 else mapent->origin[0] = mapent->origin[1] = mapent->origin[2] = 0; 1011 //if this is an area portal entity 1012 if (!strcmp("func_areaportal", ValueForKey(mapent, "classname"))) 1013 { 1014 brush = GetAreaPortalBrush(mapent); 1015 if (!brush) return false; 1016 if (!WriteMapBrush(fp, brush, mapent->origin)) return false; 1017 } //end if 1018 else 1019 { 1020 entitybrushes = false; 1021 //write brushes 1022 for (bn = 0; bn < nummapbrushes; bn++) 1023 { 1024 brush = &mapbrushes[bn]; 1025 //if the brush is part of this entity 1026 if (brush->entitynum == i) 1027 { 1028 //don't write out area portal brushes in the world 1029 if (!((brush->contents & CONTENTS_AREAPORTAL) && brush->entitynum == 0)) 1030 { 1031 /* 1032 if (!strcmp("func_door_rotating", ValueForKey(mapent, "classname"))) 1033 { 1034 AAS_PositionFuncRotatingBrush(mapent, brush); 1035 if (!WriteMapBrush(fp, brush, vec_origin)) return false; 1036 } //end if 1037 else //*/ 1038 { 1039 if (!WriteMapBrush(fp, brush, mapent->origin)) return false; 1040 } //end else 1041 entitybrushes = true; 1042 } //end if 1043 } //end if 1044 } //end for 1045 //if the entity had brushes 1046 if (entitybrushes) 1047 { 1048 //if the entity has an origin set 1049 if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2]) 1050 { 1051 if (!WriteOriginBrush(fp, mapent->origin)) return false; 1052 } //end if 1053 } //end if 1054 } //end else 1055 if (fprintf(fp, "}\n") < 0) return false; 1056 } //end for 1057 if (fprintf(fp, "//total of %d brushes\n", c_writtenbrushes) < 0) return false; 1058 return true; 1059 } //end of the function WriteMapFileSafe 1060 //=========================================================================== 1061 // 1062 // Parameter: - 1063 // Returns: - 1064 // Changes Globals: - 1065 //=========================================================================== 1066 void WriteMapFile(char *filename) 1067 { 1068 FILE *fp; 1069 double start_time; 1070 1071 c_writtenbrushes = 0; 1072 //the time started 1073 start_time = I_FloatTime(); 1074 // 1075 Log_Print("writing %s\n", filename); 1076 fp = fopen(filename, "wb"); 1077 if (!fp) 1078 { 1079 Log_Print("can't open %s\n", filename); 1080 return; 1081 } //end if 1082 if (!WriteMapFileSafe(fp)) 1083 { 1084 fclose(fp); 1085 Log_Print("error writing map file %s\n", filename); 1086 return; 1087 } //end if 1088 fclose(fp); 1089 //display creation time 1090 Log_Print("written %d brushes\n", c_writtenbrushes); 1091 Log_Print("map file written in %5.0f seconds\n", I_FloatTime() - start_time); 1092 } //end of the function WriteMapFile 1093 //=========================================================================== 1094 // 1095 // Parameter: - 1096 // Returns: - 1097 // Changes Globals: - 1098 //=========================================================================== 1099 void PrintMapInfo(void) 1100 { 1101 Log_Print("\n"); 1102 Log_Print("%6i brushes\n", nummapbrushes); 1103 Log_Print("%6i brush sides\n", nummapbrushsides); 1104 // Log_Print("%6i clipbrushes\n", c_clipbrushes); 1105 // Log_Print("%6i total sides\n", nummapbrushsides); 1106 // Log_Print("%6i boxbevels\n", c_boxbevels); 1107 // Log_Print("%6i edgebevels\n", c_edgebevels); 1108 // Log_Print("%6i entities\n", num_entities); 1109 // Log_Print("%6i planes\n", nummapplanes); 1110 // Log_Print("%6i areaportals\n", c_areaportals); 1111 // Log_Print("%6i squatt brushes\n", c_squattbrushes); 1112 // Log_Print("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2], 1113 // map_maxs[0],map_maxs[1],map_maxs[2]); 1114 } //end of the function PrintMapInfo 1115 //=========================================================================== 1116 // 1117 // Parameter: - 1118 // Returns: - 1119 // Changes Globals: - 1120 //=========================================================================== 1121 void ResetMapLoading(void) 1122 { 1123 int i; 1124 epair_t *ep, *nextep; 1125 1126 Q2_ResetMapLoading(); 1127 Sin_ResetMapLoading(); 1128 1129 //free all map brush side windings 1130 for (i = 0; i < nummapbrushsides; i++) 1131 { 1132 if (brushsides[i].winding) 1133 { 1134 FreeWinding(brushsides[i].winding); 1135 } //end for 1136 } //end for 1137 1138 //reset regular stuff 1139 nummapbrushes = 0; 1140 memset(mapbrushes, 0, MAX_MAPFILE_BRUSHES * sizeof(mapbrush_t)); 1141 // 1142 nummapbrushsides = 0; 1143 memset(brushsides, 0, MAX_MAPFILE_BRUSHSIDES * sizeof(side_t)); 1144 memset(side_brushtextures, 0, MAX_MAPFILE_BRUSHSIDES * sizeof(brush_texture_t)); 1145 // 1146 nummapplanes = 0; 1147 memset(mapplanes, 0, MAX_MAPFILE_PLANES * sizeof(plane_t)); 1148 // 1149 memset(planehash, 0, PLANE_HASHES * sizeof(plane_t *)); 1150 // 1151 memset(map_texinfo, 0, MAX_MAPFILE_TEXINFO * sizeof(map_texinfo_t)); 1152 map_numtexinfo = 0; 1153 // 1154 VectorClear(map_mins); 1155 VectorClear(map_maxs); 1156 // 1157 c_boxbevels = 0; 1158 c_edgebevels = 0; 1159 c_areaportals = 0; 1160 c_clipbrushes = 0; 1161 c_writtenbrushes = 0; 1162 //clear the entities 1163 for (i = 0; i < num_entities; i++) 1164 { 1165 for (ep = entities[i].epairs; ep; ep = nextep) 1166 { 1167 nextep = ep->next; 1168 FreeMemory(ep->key); 1169 FreeMemory(ep->value); 1170 FreeMemory(ep); 1171 } //end for 1172 } //end for 1173 num_entities = 0; 1174 memset(entities, 0, MAX_MAP_ENTITIES * sizeof(entity_t)); 1175 } //end of the function ResetMapLoading 1176 //=========================================================================== 1177 // 1178 // Parameter: - 1179 // Returns: - 1180 // Changes Globals: - 1181 //=========================================================================== 1182 #ifndef Q1_BSPVERSION 1183 #define Q1_BSPVERSION 29 1184 #endif 1185 #ifndef HL_BSPVERSION 1186 #define HL_BSPVERSION 30 1187 #endif 1188 1189 #define Q2_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') //IBSP 1190 #define Q2_BSPVERSION 38 1191 1192 #define SINGAME_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'R') //RBSP 1193 #define SINGAME_BSPVERSION 1 1194 1195 #define SIN_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') //IBSP 1196 #define SIN_BSPVERSION 41 1197 1198 typedef struct 1199 { 1200 int ident; 1201 int version; 1202 } idheader_t; 1203 1204 int LoadMapFromBSP(struct quakefile_s *qf) 1205 { 1206 idheader_t idheader; 1207 1208 if (ReadQuakeFile(qf, &idheader, 0, sizeof(idheader_t)) != sizeof(idheader_t)) 1209 { 1210 return false; 1211 } //end if 1212 1213 idheader.ident = LittleLong(idheader.ident); 1214 idheader.version = LittleLong(idheader.version); 1215 //Quake3 BSP file 1216 if (idheader.ident == Q3_BSP_IDENT && idheader.version == Q3_BSP_VERSION) 1217 { 1218 ResetMapLoading(); 1219 Q3_LoadMapFromBSP(qf); 1220 Q3_FreeMaxBSP(); 1221 } //end if 1222 //Quake2 BSP file 1223 else if (idheader.ident == Q2_BSPHEADER && idheader.version == Q2_BSPVERSION) 1224 { 1225 ResetMapLoading(); 1226 Q2_AllocMaxBSP(); 1227 Q2_LoadMapFromBSP(qf->filename, qf->offset, qf->length); 1228 Q2_FreeMaxBSP(); 1229 } //endif 1230 //Sin BSP file 1231 else if ((idheader.ident == SIN_BSPHEADER && idheader.version == SIN_BSPVERSION) || 1232 //the dorks gave the same format another ident and verions 1233 (idheader.ident == SINGAME_BSPHEADER && idheader.version == SINGAME_BSPVERSION)) 1234 { 1235 ResetMapLoading(); 1236 Sin_AllocMaxBSP(); 1237 Sin_LoadMapFromBSP(qf->filename, qf->offset, qf->length); 1238 Sin_FreeMaxBSP(); 1239 } //end if 1240 //the Quake1 bsp files don't have a ident only a version 1241 else if (idheader.ident == Q1_BSPVERSION) 1242 { 1243 ResetMapLoading(); 1244 Q1_AllocMaxBSP(); 1245 Q1_LoadMapFromBSP(qf->filename, qf->offset, qf->length); 1246 Q1_FreeMaxBSP(); 1247 } //end if 1248 //Half-Life also only uses a version number 1249 else if (idheader.ident == HL_BSPVERSION) 1250 { 1251 ResetMapLoading(); 1252 HL_AllocMaxBSP(); 1253 HL_LoadMapFromBSP(qf->filename, qf->offset, qf->length); 1254 HL_FreeMaxBSP(); 1255 } //end if 1256 else 1257 { 1258 Error("unknown BSP format %c%c%c%c, version %d\n", 1259 (idheader.ident & 0xFF), 1260 ((idheader.ident >> 8) & 0xFF), 1261 ((idheader.ident >> 16) & 0xFF), 1262 ((idheader.ident >> 24) & 0xFF), idheader.version); 1263 return false; 1264 } //end if 1265 // 1266 return true; 1267 } //end of the function LoadMapFromBSP