aas_create.c (35954B)
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 "../botlib/aasfile.h" 25 #include "aas_create.h" 26 #include "aas_store.h" 27 #include "aas_gsubdiv.h" 28 #include "aas_facemerging.h" 29 #include "aas_areamerging.h" 30 #include "aas_edgemelting.h" 31 #include "aas_prunenodes.h" 32 #include "aas_cfg.h" 33 #include "../game/surfaceflags.h" 34 35 //#define AW_DEBUG 36 //#define L_DEBUG 37 38 #define AREAONFACESIDE(face, area) (face->frontarea != area) 39 40 tmp_aas_t tmpaasworld; 41 42 //=========================================================================== 43 // 44 // Parameter: - 45 // Returns: - 46 // Changes Globals: - 47 //=========================================================================== 48 void AAS_InitTmpAAS(void) 49 { 50 //tmp faces 51 tmpaasworld.numfaces = 0; 52 tmpaasworld.facenum = 0; 53 tmpaasworld.faces = NULL; 54 //tmp convex areas 55 tmpaasworld.numareas = 0; 56 tmpaasworld.areanum = 0; 57 tmpaasworld.areas = NULL; 58 //tmp nodes 59 tmpaasworld.numnodes = 0; 60 tmpaasworld.nodes = NULL; 61 // 62 tmpaasworld.nodebuffer = NULL; 63 } //end of the function AAS_InitTmpAAS 64 //=========================================================================== 65 // 66 // Parameter: - 67 // Returns: - 68 // Changes Globals: - 69 //=========================================================================== 70 void AAS_FreeTmpAAS(void) 71 { 72 tmp_face_t *f, *nextf; 73 tmp_area_t *a, *nexta; 74 tmp_nodebuf_t *nb, *nextnb; 75 76 //free all the faces 77 for (f = tmpaasworld.faces; f; f = nextf) 78 { 79 nextf = f->l_next; 80 if (f->winding) FreeWinding(f->winding); 81 FreeMemory(f); 82 } //end if 83 //free all tmp areas 84 for (a = tmpaasworld.areas; a; a = nexta) 85 { 86 nexta = a->l_next; 87 if (a->settings) FreeMemory(a->settings); 88 FreeMemory(a); 89 } //end for 90 //free all the tmp nodes 91 for (nb = tmpaasworld.nodebuffer; nb; nb = nextnb) 92 { 93 nextnb = nb->next; 94 FreeMemory(nb); 95 } //end for 96 } //end of the function AAS_FreeTmpAAS 97 //=========================================================================== 98 // 99 // Parameter: - 100 // Returns: - 101 // Changes Globals: - 102 //=========================================================================== 103 tmp_face_t *AAS_AllocTmpFace(void) 104 { 105 tmp_face_t *tmpface; 106 107 tmpface = (tmp_face_t *) GetClearedMemory(sizeof(tmp_face_t)); 108 tmpface->num = tmpaasworld.facenum++; 109 tmpface->l_prev = NULL; 110 tmpface->l_next = tmpaasworld.faces; 111 if (tmpaasworld.faces) tmpaasworld.faces->l_prev = tmpface; 112 tmpaasworld.faces = tmpface; 113 tmpaasworld.numfaces++; 114 return tmpface; 115 } //end of the function AAS_AllocTmpFace 116 //=========================================================================== 117 // 118 // Parameter: - 119 // Returns: - 120 // Changes Globals: - 121 //=========================================================================== 122 void AAS_FreeTmpFace(tmp_face_t *tmpface) 123 { 124 if (tmpface->l_next) tmpface->l_next->l_prev = tmpface->l_prev; 125 if (tmpface->l_prev) tmpface->l_prev->l_next = tmpface->l_next; 126 else tmpaasworld.faces = tmpface->l_next; 127 //free the winding 128 if (tmpface->winding) FreeWinding(tmpface->winding); 129 //free the face 130 FreeMemory(tmpface); 131 tmpaasworld.numfaces--; 132 } //end of the function AAS_FreeTmpFace 133 //=========================================================================== 134 // 135 // Parameter: - 136 // Returns: - 137 // Changes Globals: - 138 //=========================================================================== 139 tmp_area_t *AAS_AllocTmpArea(void) 140 { 141 tmp_area_t *tmparea; 142 143 tmparea = (tmp_area_t *) GetClearedMemory(sizeof(tmp_area_t)); 144 tmparea->areanum = tmpaasworld.areanum++; 145 tmparea->l_prev = NULL; 146 tmparea->l_next = tmpaasworld.areas; 147 if (tmpaasworld.areas) tmpaasworld.areas->l_prev = tmparea; 148 tmpaasworld.areas = tmparea; 149 tmpaasworld.numareas++; 150 return tmparea; 151 } //end of the function AAS_AllocTmpArea 152 //=========================================================================== 153 // 154 // Parameter: - 155 // Returns: - 156 // Changes Globals: - 157 //=========================================================================== 158 void AAS_FreeTmpArea(tmp_area_t *tmparea) 159 { 160 if (tmparea->l_next) tmparea->l_next->l_prev = tmparea->l_prev; 161 if (tmparea->l_prev) tmparea->l_prev->l_next = tmparea->l_next; 162 else tmpaasworld.areas = tmparea->l_next; 163 if (tmparea->settings) FreeMemory(tmparea->settings); 164 FreeMemory(tmparea); 165 tmpaasworld.numareas--; 166 } //end of the function AAS_FreeTmpArea 167 //=========================================================================== 168 // 169 // Parameter: - 170 // Returns: - 171 // Changes Globals: - 172 //=========================================================================== 173 tmp_node_t *AAS_AllocTmpNode(void) 174 { 175 tmp_nodebuf_t *nodebuf; 176 177 if (!tmpaasworld.nodebuffer || 178 tmpaasworld.nodebuffer->numnodes >= NODEBUF_SIZE) 179 { 180 nodebuf = (tmp_nodebuf_t *) GetClearedMemory(sizeof(tmp_nodebuf_t)); 181 nodebuf->next = tmpaasworld.nodebuffer; 182 nodebuf->numnodes = 0; 183 tmpaasworld.nodebuffer = nodebuf; 184 } //end if 185 tmpaasworld.numnodes++; 186 return &tmpaasworld.nodebuffer->nodes[tmpaasworld.nodebuffer->numnodes++]; 187 } //end of the function AAS_AllocTmpNode 188 //=========================================================================== 189 // 190 // Parameter: - 191 // Returns: - 192 // Changes Globals: - 193 //=========================================================================== 194 void AAS_FreeTmpNode(tmp_node_t *tmpnode) 195 { 196 tmpaasworld.numnodes--; 197 } //end of the function AAS_FreeTmpNode 198 //=========================================================================== 199 // returns true if the face is a gap from the given side 200 // 201 // Parameter: - 202 // Returns: - 203 // Changes Globals: - 204 //=========================================================================== 205 int AAS_GapFace(tmp_face_t *tmpface, int side) 206 { 207 vec3_t invgravity; 208 209 //if the face is a solid or ground face it can't be a gap 210 if (tmpface->faceflags & (FACE_GROUND | FACE_SOLID)) return 0; 211 212 VectorCopy(cfg.phys_gravitydirection, invgravity); 213 VectorInverse(invgravity); 214 215 return (DotProduct(invgravity, mapplanes[tmpface->planenum ^ side].normal) > cfg.phys_maxsteepness); 216 } //end of the function AAS_GapFace 217 //=========================================================================== 218 // returns true if the face is a ground face 219 // 220 // Parameter: - 221 // Returns: - 222 // Changes Globals: - 223 //=========================================================================== 224 int AAS_GroundFace(tmp_face_t *tmpface) 225 { 226 vec3_t invgravity; 227 228 //must be a solid face 229 if (!(tmpface->faceflags & FACE_SOLID)) return 0; 230 231 VectorCopy(cfg.phys_gravitydirection, invgravity); 232 VectorInverse(invgravity); 233 234 return (DotProduct(invgravity, mapplanes[tmpface->planenum].normal) > cfg.phys_maxsteepness); 235 } //end of the function AAS_GroundFace 236 //=========================================================================== 237 // adds the side of a face to an area 238 // 239 // side : 0 = front side 240 // 1 = back side 241 // 242 // Parameter: - 243 // Returns: - 244 // Changes Globals: - 245 //=========================================================================== 246 void AAS_AddFaceSideToArea(tmp_face_t *tmpface, int side, tmp_area_t *tmparea) 247 { 248 int tmpfaceside; 249 250 if (side) 251 { 252 if (tmpface->backarea) Error("AAS_AddFaceSideToArea: already a back area\n"); 253 } //end if 254 else 255 { 256 if (tmpface->frontarea) Error("AAS_AddFaceSideToArea: already a front area\n"); 257 } //end else 258 259 if (side) tmpface->backarea = tmparea; 260 else tmpface->frontarea = tmparea; 261 262 if (tmparea->tmpfaces) 263 { 264 tmpfaceside = tmparea->tmpfaces->frontarea != tmparea; 265 tmparea->tmpfaces->prev[tmpfaceside] = tmpface; 266 } //end if 267 tmpface->next[side] = tmparea->tmpfaces; 268 tmpface->prev[side] = NULL; 269 tmparea->tmpfaces = tmpface; 270 } //end of the function AAS_AddFaceSideToArea 271 //=========================================================================== 272 // remove (a side of) a face from an area 273 // 274 // Parameter: - 275 // Returns: - 276 // Changes Globals: - 277 //=========================================================================== 278 void AAS_RemoveFaceFromArea(tmp_face_t *tmpface, tmp_area_t *tmparea) 279 { 280 int side, prevside, nextside; 281 282 if (tmpface->frontarea != tmparea && 283 tmpface->backarea != tmparea) 284 { 285 Error("AAS_RemoveFaceFromArea: face not part of the area"); 286 } //end if 287 side = tmpface->frontarea != tmparea; 288 if (tmpface->prev[side]) 289 { 290 prevside = tmpface->prev[side]->frontarea != tmparea; 291 tmpface->prev[side]->next[prevside] = tmpface->next[side]; 292 } //end if 293 else 294 { 295 tmparea->tmpfaces = tmpface->next[side]; 296 } //end else 297 if (tmpface->next[side]) 298 { 299 nextside = tmpface->next[side]->frontarea != tmparea; 300 tmpface->next[side]->prev[nextside] = tmpface->prev[side]; 301 } //end if 302 //remove the area number from the face depending on the side 303 if (side) tmpface->backarea = NULL; 304 else tmpface->frontarea = NULL; 305 tmpface->prev[side] = NULL; 306 tmpface->next[side] = NULL; 307 } //end of the function AAS_RemoveFaceFromArea 308 //=========================================================================== 309 // 310 // Parameter: - 311 // Returns: - 312 // Changes Globals: - 313 //=========================================================================== 314 void AAS_CheckArea(tmp_area_t *tmparea) 315 { 316 int side; 317 tmp_face_t *face; 318 plane_t *plane; 319 vec3_t wcenter, acenter = {0, 0, 0}; 320 vec3_t normal; 321 float n, dist; 322 323 if (tmparea->invalid) Log_Print("AAS_CheckArea: invalid area\n"); 324 for (n = 0, face = tmparea->tmpfaces; face; face = face->next[side]) 325 { 326 //side of the face the area is on 327 side = face->frontarea != tmparea; 328 WindingCenter(face->winding, wcenter); 329 VectorAdd(acenter, wcenter, acenter); 330 n++; 331 } //end for 332 n = 1 / n; 333 VectorScale(acenter, n, acenter); 334 for (face = tmparea->tmpfaces; face; face = face->next[side]) 335 { 336 //side of the face the area is on 337 side = face->frontarea != tmparea; 338 339 #ifdef L_DEBUG 340 if (WindingError(face->winding)) 341 { 342 Log_Write("AAS_CheckArea: area %d face %d: %s\r\n", tmparea->areanum, 343 face->num, WindingErrorString()); 344 } //end if 345 #endif L_DEBUG 346 347 plane = &mapplanes[face->planenum ^ side]; 348 349 if (DotProduct(plane->normal, acenter) - plane->dist < 0) 350 { 351 Log_Print("AAS_CheckArea: area %d face %d is flipped\n", tmparea->areanum, face->num); 352 Log_Print("AAS_CheckArea: area %d center is %f %f %f\n", tmparea->areanum, acenter[0], acenter[1], acenter[2]); 353 } //end if 354 //check if the winding plane is the same as the face plane 355 WindingPlane(face->winding, normal, &dist); 356 plane = &mapplanes[face->planenum]; 357 #ifdef L_DEBUG 358 if (fabs(dist - plane->dist) > 0.4 || 359 fabs(normal[0] - plane->normal[0]) > 0.0001 || 360 fabs(normal[1] - plane->normal[1]) > 0.0001 || 361 fabs(normal[2] - plane->normal[2]) > 0.0001) 362 { 363 Log_Write("AAS_CheckArea: area %d face %d winding plane unequal to face plane\r\n", 364 tmparea->areanum, face->num); 365 } //end if 366 #endif L_DEBUG 367 } //end for 368 } //end of the function AAS_CheckArea 369 //=========================================================================== 370 // 371 // Parameter: - 372 // Returns: - 373 // Changes Globals: - 374 //=========================================================================== 375 void AAS_CheckFaceWindingPlane(tmp_face_t *face) 376 { 377 float dist, sign1, sign2; 378 vec3_t normal; 379 plane_t *plane; 380 winding_t *w; 381 382 //check if the winding plane is the same as the face plane 383 WindingPlane(face->winding, normal, &dist); 384 plane = &mapplanes[face->planenum]; 385 // 386 sign1 = DotProduct(plane->normal, normal); 387 // 388 if (fabs(dist - plane->dist) > 0.4 || 389 fabs(normal[0] - plane->normal[0]) > 0.0001 || 390 fabs(normal[1] - plane->normal[1]) > 0.0001 || 391 fabs(normal[2] - plane->normal[2]) > 0.0001) 392 { 393 VectorInverse(normal); 394 dist = -dist; 395 if (fabs(dist - plane->dist) > 0.4 || 396 fabs(normal[0] - plane->normal[0]) > 0.0001 || 397 fabs(normal[1] - plane->normal[1]) > 0.0001 || 398 fabs(normal[2] - plane->normal[2]) > 0.0001) 399 { 400 Log_Write("AAS_CheckFaceWindingPlane: face %d winding plane unequal to face plane\r\n", 401 face->num); 402 // 403 sign2 = DotProduct(plane->normal, normal); 404 if ((sign1 < 0 && sign2 > 0) || 405 (sign1 > 0 && sign2 < 0)) 406 { 407 Log_Write("AAS_CheckFaceWindingPlane: face %d winding reversed\r\n", 408 face->num); 409 w = face->winding; 410 face->winding = ReverseWinding(w); 411 FreeWinding(w); 412 } //end if 413 } //end if 414 else 415 { 416 Log_Write("AAS_CheckFaceWindingPlane: face %d winding reversed\r\n", 417 face->num); 418 w = face->winding; 419 face->winding = ReverseWinding(w); 420 FreeWinding(w); 421 } //end else 422 } //end if 423 } //end of the function AAS_CheckFaceWindingPlane 424 //=========================================================================== 425 // 426 // Parameter: - 427 // Returns: - 428 // Changes Globals: - 429 //=========================================================================== 430 void AAS_CheckAreaWindingPlanes(void) 431 { 432 int side; 433 tmp_area_t *tmparea; 434 tmp_face_t *face; 435 436 Log_Write("AAS_CheckAreaWindingPlanes:\r\n"); 437 for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next) 438 { 439 if (tmparea->invalid) continue; 440 for (face = tmparea->tmpfaces; face; face = face->next[side]) 441 { 442 side = face->frontarea != tmparea; 443 AAS_CheckFaceWindingPlane(face); 444 } //end for 445 } //end for 446 } //end of the function AAS_CheckAreaWindingPlanes 447 //=========================================================================== 448 // 449 // Parameter: - 450 // Returns: - 451 // Changes Globals: - 452 //=========================================================================== 453 void AAS_FlipAreaFaces(tmp_area_t *tmparea) 454 { 455 int side; 456 tmp_face_t *face; 457 plane_t *plane; 458 vec3_t wcenter, acenter = {0, 0, 0}; 459 //winding_t *w; 460 float n; 461 462 for (n = 0, face = tmparea->tmpfaces; face; face = face->next[side]) 463 { 464 if (!face->frontarea) Error("face %d has no front area\n", face->num); 465 //side of the face the area is on 466 side = face->frontarea != tmparea; 467 WindingCenter(face->winding, wcenter); 468 VectorAdd(acenter, wcenter, acenter); 469 n++; 470 } //end for 471 n = 1 / n; 472 VectorScale(acenter, n, acenter); 473 for (face = tmparea->tmpfaces; face; face = face->next[side]) 474 { 475 //side of the face the area is on 476 side = face->frontarea != tmparea; 477 478 plane = &mapplanes[face->planenum ^ side]; 479 480 if (DotProduct(plane->normal, acenter) - plane->dist < 0) 481 { 482 Log_Print("area %d face %d flipped: front area %d, back area %d\n", tmparea->areanum, face->num, 483 face->frontarea ? face->frontarea->areanum : 0, 484 face->backarea ? face->backarea->areanum : 0); 485 /* 486 face->planenum = face->planenum ^ 1; 487 w = face->winding; 488 face->winding = ReverseWinding(w); 489 FreeWinding(w); 490 */ 491 } //end if 492 #ifdef L_DEBUG 493 { 494 float dist; 495 vec3_t normal; 496 497 //check if the winding plane is the same as the face plane 498 WindingPlane(face->winding, normal, &dist); 499 plane = &mapplanes[face->planenum]; 500 if (fabs(dist - plane->dist) > 0.4 || 501 fabs(normal[0] - plane->normal[0]) > 0.0001 || 502 fabs(normal[1] - plane->normal[1]) > 0.0001 || 503 fabs(normal[2] - plane->normal[2]) > 0.0001) 504 { 505 Log_Write("area %d face %d winding plane unequal to face plane\r\n", 506 tmparea->areanum, face->num); 507 } //end if 508 } 509 #endif 510 } //end for 511 } //end of the function AAS_FlipAreaFaces 512 //=========================================================================== 513 // 514 // Parameter: - 515 // Returns: - 516 // Changes Globals: - 517 //=========================================================================== 518 void AAS_RemoveAreaFaceColinearPoints(void) 519 { 520 int side; 521 tmp_face_t *face; 522 tmp_area_t *tmparea; 523 524 //FIXME: loop over the faces instead of area->faces 525 for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next) 526 { 527 for (face = tmparea->tmpfaces; face; face = face->next[side]) 528 { 529 side = face->frontarea != tmparea; 530 RemoveColinearPoints(face->winding); 531 // RemoveEqualPoints(face->winding, 0.1); 532 } //end for 533 } //end for 534 } //end of the function AAS_RemoveAreaFaceColinearPoints 535 //=========================================================================== 536 // 537 // Parameter: - 538 // Returns: - 539 // Changes Globals: - 540 //=========================================================================== 541 void AAS_RemoveTinyFaces(void) 542 { 543 int side, num; 544 tmp_face_t *face, *nextface; 545 tmp_area_t *tmparea; 546 547 //FIXME: loop over the faces instead of area->faces 548 Log_Write("AAS_RemoveTinyFaces\r\n"); 549 num = 0; 550 for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next) 551 { 552 for (face = tmparea->tmpfaces; face; face = nextface) 553 { 554 side = face->frontarea != tmparea; 555 nextface = face->next[side]; 556 // 557 if (WindingArea(face->winding) < 1) 558 { 559 if (face->frontarea) AAS_RemoveFaceFromArea(face, face->frontarea); 560 if (face->backarea) AAS_RemoveFaceFromArea(face, face->backarea); 561 AAS_FreeTmpFace(face); 562 //Log_Write("area %d face %d is tiny\r\n", tmparea->areanum, face->num); 563 num++; 564 } //end if 565 } //end for 566 } //end for 567 Log_Write("%d tiny faces removed\r\n", num); 568 } //end of the function AAS_RemoveTinyFaces 569 //=========================================================================== 570 // 571 // Parameter: - 572 // Returns: - 573 // Changes Globals: - 574 //=========================================================================== 575 void AAS_CreateAreaSettings(void) 576 { 577 int i, flags, side, numgrounded, numladderareas, numliquidareas; 578 tmp_face_t *face; 579 tmp_area_t *tmparea; 580 581 numgrounded = 0; 582 numladderareas = 0; 583 numliquidareas = 0; 584 Log_Write("AAS_CreateAreaSettings\r\n"); 585 i = 0; 586 qprintf("%6d areas provided with settings", i); 587 for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next) 588 { 589 //if the area is invalid there no need to create settings for it 590 if (tmparea->invalid) continue; 591 592 tmparea->settings = (tmp_areasettings_t *) GetClearedMemory(sizeof(tmp_areasettings_t)); 593 tmparea->settings->contents = tmparea->contents; 594 tmparea->settings->modelnum = tmparea->modelnum; 595 flags = 0; 596 for (face = tmparea->tmpfaces; face; face = face->next[side]) 597 { 598 side = face->frontarea != tmparea; 599 flags |= face->faceflags; 600 } //end for 601 tmparea->settings->areaflags = 0; 602 if (flags & FACE_GROUND) 603 { 604 tmparea->settings->areaflags |= AREA_GROUNDED; 605 numgrounded++; 606 } //end if 607 if (flags & FACE_LADDER) 608 { 609 tmparea->settings->areaflags |= AREA_LADDER; 610 numladderareas++; 611 } //end if 612 if (tmparea->contents & (AREACONTENTS_WATER | 613 AREACONTENTS_SLIME | 614 AREACONTENTS_LAVA)) 615 { 616 tmparea->settings->areaflags |= AREA_LIQUID; 617 numliquidareas++; 618 } //end if 619 //presence type of the area 620 tmparea->settings->presencetype = tmparea->presencetype; 621 // 622 qprintf("\r%6d", ++i); 623 } //end for 624 qprintf("\n"); 625 #ifdef AASINFO 626 Log_Print("%6d grounded areas\n", numgrounded); 627 Log_Print("%6d ladder areas\n", numladderareas); 628 Log_Print("%6d liquid areas\n", numliquidareas); 629 #endif //AASINFO 630 } //end of the function AAS_CreateAreaSettings 631 //=========================================================================== 632 // create a tmp AAS area from a leaf node 633 // 634 // Parameter: - 635 // Returns: - 636 // Changes Globals: - 637 //=========================================================================== 638 tmp_node_t *AAS_CreateArea(node_t *node) 639 { 640 int pside; 641 int areafaceflags; 642 portal_t *p; 643 tmp_face_t *tmpface; 644 tmp_area_t *tmparea; 645 tmp_node_t *tmpnode; 646 vec3_t up = {0, 0, 1}; 647 648 //create an area from this leaf 649 tmparea = AAS_AllocTmpArea(); 650 tmparea->tmpfaces = NULL; 651 //clear the area face flags 652 areafaceflags = 0; 653 //make aas faces from the portals 654 for (p = node->portals; p; p = p->next[pside]) 655 { 656 pside = (p->nodes[1] == node); 657 //don't create faces from very small portals 658 // if (WindingArea(p->winding) < 1) continue; 659 //if there's already a face created for this portal 660 if (p->tmpface) 661 { 662 //add the back side of the face to the area 663 AAS_AddFaceSideToArea(p->tmpface, 1, tmparea); 664 } //end if 665 else 666 { 667 tmpface = AAS_AllocTmpFace(); 668 //set the face pointer at the portal so we can see from 669 //the portal there's a face created for it 670 p->tmpface = tmpface; 671 //FIXME: test this change 672 //tmpface->planenum = (p->planenum & ~1) | pside; 673 tmpface->planenum = p->planenum ^ pside; 674 if (pside) tmpface->winding = ReverseWinding(p->winding); 675 else tmpface->winding = CopyWinding(p->winding); 676 #ifdef L_DEBUG 677 // 678 AAS_CheckFaceWindingPlane(tmpface); 679 #endif //L_DEBUG 680 //if there's solid at the other side of the portal 681 if (p->nodes[!pside]->contents & (CONTENTS_SOLID | CONTENTS_PLAYERCLIP)) 682 { 683 tmpface->faceflags |= FACE_SOLID; 684 } //end if 685 //else there is no solid at the other side and if there 686 //is a liquid at this side 687 else if (node->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)) 688 { 689 tmpface->faceflags |= FACE_LIQUID; 690 //if there's no liquid at the other side 691 if (!(p->nodes[!pside]->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))) 692 { 693 tmpface->faceflags |= FACE_LIQUIDSURFACE; 694 } //end if 695 } //end else 696 //if there's ladder contents at other side of the portal 697 if ((p->nodes[pside]->contents & CONTENTS_LADDER) || 698 (p->nodes[!pside]->contents & CONTENTS_LADDER)) 699 { 700 701 //NOTE: doesn't have to be solid at the other side because 702 // when standing one can use a crouch area (which is not solid) 703 // as a ladder 704 // imagine a ladder one can walk underthrough, 705 // under the ladder against the ladder is a crouch area 706 // the (vertical) sides of this crouch area area also used as 707 // ladder sides when standing (not crouched) 708 tmpface->faceflags |= FACE_LADDER; 709 } //end if 710 //if it is possible to stand on the face 711 if (AAS_GroundFace(tmpface)) 712 { 713 tmpface->faceflags |= FACE_GROUND; 714 } //end if 715 // 716 areafaceflags |= tmpface->faceflags; 717 //no aas face number yet (zero is a dummy in the aasworld faces) 718 tmpface->aasfacenum = 0; 719 //add the front side of the face to the area 720 AAS_AddFaceSideToArea(tmpface, 0, tmparea); 721 } //end else 722 } //end for 723 qprintf("\r%6d", tmparea->areanum); 724 //presence type in the area 725 tmparea->presencetype = ~node->expansionbboxes & cfg.allpresencetypes; 726 // 727 tmparea->contents = 0; 728 if (node->contents & CONTENTS_CLUSTERPORTAL) tmparea->contents |= AREACONTENTS_CLUSTERPORTAL; 729 if (node->contents & CONTENTS_MOVER) tmparea->contents |= AREACONTENTS_MOVER; 730 if (node->contents & CONTENTS_TELEPORTER) tmparea->contents |= AREACONTENTS_TELEPORTER; 731 if (node->contents & CONTENTS_JUMPPAD) tmparea->contents |= AREACONTENTS_JUMPPAD; 732 if (node->contents & CONTENTS_DONOTENTER) tmparea->contents |= AREACONTENTS_DONOTENTER; 733 if (node->contents & CONTENTS_WATER) tmparea->contents |= AREACONTENTS_WATER; 734 if (node->contents & CONTENTS_LAVA) tmparea->contents |= AREACONTENTS_LAVA; 735 if (node->contents & CONTENTS_SLIME) tmparea->contents |= AREACONTENTS_SLIME; 736 if (node->contents & CONTENTS_NOTTEAM1) tmparea->contents |= AREACONTENTS_NOTTEAM1; 737 if (node->contents & CONTENTS_NOTTEAM2) tmparea->contents |= AREACONTENTS_NOTTEAM2; 738 739 //store the bsp model that's inside this node 740 tmparea->modelnum = node->modelnum; 741 //sorta check for flipped area faces (remove??) 742 AAS_FlipAreaFaces(tmparea); 743 //check if the area is ok (remove??) 744 AAS_CheckArea(tmparea); 745 // 746 tmpnode = AAS_AllocTmpNode(); 747 tmpnode->planenum = 0; 748 tmpnode->children[0] = 0; 749 tmpnode->children[1] = 0; 750 tmpnode->tmparea = tmparea; 751 // 752 return tmpnode; 753 } //end of the function AAS_CreateArea 754 //=========================================================================== 755 // 756 // Parameter: - 757 // Returns: - 758 // Changes Globals: - 759 //=========================================================================== 760 tmp_node_t *AAS_CreateAreas_r(node_t *node) 761 { 762 tmp_node_t *tmpnode; 763 764 //recurse down to leafs 765 if (node->planenum != PLANENUM_LEAF) 766 { 767 //the first tmp node is a dummy 768 tmpnode = AAS_AllocTmpNode(); 769 tmpnode->planenum = node->planenum; 770 tmpnode->children[0] = AAS_CreateAreas_r(node->children[0]); 771 tmpnode->children[1] = AAS_CreateAreas_r(node->children[1]); 772 return tmpnode; 773 } //end if 774 //areas won't be created for solid leafs 775 if (node->contents & CONTENTS_SOLID) 776 { 777 //just return zero for a solid leaf (in tmp AAS NULL is a solid leaf) 778 return NULL; 779 } //end if 780 781 return AAS_CreateArea(node); 782 } //end of the function AAS_CreateAreas_r 783 //=========================================================================== 784 // 785 // Parameter: - 786 // Returns: - 787 // Changes Globals: - 788 //=========================================================================== 789 void AAS_CreateAreas(node_t *node) 790 { 791 Log_Write("AAS_CreateAreas\r\n"); 792 qprintf("%6d areas created", 0); 793 tmpaasworld.nodes = AAS_CreateAreas_r(node); 794 qprintf("\n"); 795 Log_Write("%6d areas created\r\n", tmpaasworld.numareas); 796 } //end of the function AAS_CreateAreas 797 //=========================================================================== 798 // 799 // Parameter: - 800 // Returns: - 801 // Changes Globals: - 802 //=========================================================================== 803 void AAS_PrintNumGroundFaces(void) 804 { 805 tmp_face_t *tmpface; 806 int numgroundfaces = 0; 807 808 for (tmpface = tmpaasworld.faces; tmpface; tmpface = tmpface->l_next) 809 { 810 if (tmpface->faceflags & FACE_GROUND) 811 { 812 numgroundfaces++; 813 } //end if 814 } //end for 815 qprintf("%6d ground faces\n", numgroundfaces); 816 } //end of the function AAS_PrintNumGroundFaces 817 //=========================================================================== 818 // checks the number of shared faces between the given two areas 819 // since areas are convex they should only have ONE shared face 820 // however due to crappy face merging there are sometimes several 821 // shared faces 822 // 823 // Parameter: - 824 // Returns: - 825 // Changes Globals: - 826 //=========================================================================== 827 void AAS_CheckAreaSharedFaces(tmp_area_t *tmparea1, tmp_area_t *tmparea2) 828 { 829 int numsharedfaces, side; 830 tmp_face_t *face1, *sharedface; 831 832 if (tmparea1->invalid || tmparea2->invalid) return; 833 834 sharedface = NULL; 835 numsharedfaces = 0; 836 for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side]) 837 { 838 side = face1->frontarea != tmparea1; 839 if (face1->backarea == tmparea2 || face1->frontarea == tmparea2) 840 { 841 sharedface = face1; 842 numsharedfaces++; 843 } //end if 844 } //end if 845 if (!sharedface) return; 846 //the areas should only have one shared face 847 if (numsharedfaces > 1) 848 { 849 Log_Write("---- tmp area %d and %d have %d shared faces\r\n", 850 tmparea1->areanum, tmparea2->areanum, numsharedfaces); 851 for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side]) 852 { 853 side = face1->frontarea != tmparea1; 854 if (face1->backarea == tmparea2 || face1->frontarea == tmparea2) 855 { 856 Log_Write("face %d, planenum = %d, face->frontarea = %d face->backarea = %d\r\n", 857 face1->num, face1->planenum, face1->frontarea->areanum, face1->backarea->areanum); 858 } //end if 859 } //end if 860 } //end if 861 } //end of the function AAS_CheckAreaSharedFaces 862 //=========================================================================== 863 // 864 // Parameter: - 865 // Returns: - 866 // Changes Globals: - 867 //=========================================================================== 868 void AAS_CheckSharedFaces(void) 869 { 870 tmp_area_t *tmparea1, *tmparea2; 871 872 for (tmparea1 = tmpaasworld.areas; tmparea1; tmparea1 = tmparea1->l_next) 873 { 874 for (tmparea2 = tmpaasworld.areas; tmparea2; tmparea2 = tmparea2->l_next) 875 { 876 if (tmparea1 == tmparea2) continue; 877 AAS_CheckAreaSharedFaces(tmparea1, tmparea2); 878 } //end for 879 } //end for 880 } //end of the function AAS_CheckSharedFaces 881 //=========================================================================== 882 // 883 // Parameter: - 884 // Returns: - 885 // Changes Globals: - 886 //=========================================================================== 887 void AAS_FlipFace(tmp_face_t *face) 888 { 889 tmp_area_t *frontarea, *backarea; 890 winding_t *w; 891 892 frontarea = face->frontarea; 893 backarea = face->backarea; 894 //must have an area at both sides before flipping is allowed 895 if (!frontarea || !backarea) return; 896 //flip the face winding 897 w = face->winding; 898 face->winding = ReverseWinding(w); 899 FreeWinding(w); 900 //flip the face plane 901 face->planenum ^= 1; 902 //flip the face areas 903 AAS_RemoveFaceFromArea(face, frontarea); 904 AAS_RemoveFaceFromArea(face, backarea); 905 AAS_AddFaceSideToArea(face, 1, frontarea); 906 AAS_AddFaceSideToArea(face, 0, backarea); 907 } //end of the function AAS_FlipFace 908 //=========================================================================== 909 // 910 // Parameter: - 911 // Returns: - 912 // Changes Globals: - 913 //=========================================================================== 914 /* 915 void AAS_FlipAreaSharedFaces(tmp_area_t *tmparea1, tmp_area_t *tmparea2) 916 { 917 int numsharedfaces, side, area1facing, area2facing; 918 tmp_face_t *face1, *sharedface; 919 920 if (tmparea1->invalid || tmparea2->invalid) return; 921 922 sharedface = NULL; 923 numsharedfaces = 0; 924 area1facing = 0; //number of shared faces facing towards area 1 925 area2facing = 0; //number of shared faces facing towards area 2 926 for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side]) 927 { 928 side = face1->frontarea != tmparea1; 929 if (face1->backarea == tmparea2 || face1->frontarea == tmparea2) 930 { 931 sharedface = face1; 932 numsharedfaces++; 933 if (face1->frontarea == tmparea1) area1facing++; 934 else area2facing++; 935 } //end if 936 } //end if 937 if (!sharedface) return; 938 //if there's only one shared face 939 if (numsharedfaces <= 1) return; 940 //if all the shared faces are facing to the same area 941 if (numsharedfaces == area1facing || numsharedfaces == area2facing) return; 942 // 943 do 944 { 945 for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side]) 946 { 947 side = face1->frontarea != tmparea1; 948 if (face1->backarea == tmparea2 || face1->frontarea == tmparea2) 949 { 950 if (face1->frontarea != tmparea1) 951 { 952 AAS_FlipFace(face1); 953 break; 954 } //end if 955 } //end if 956 } //end for 957 } while(face1); 958 } //end of the function AAS_FlipAreaSharedFaces 959 //=========================================================================== 960 // 961 // Parameter: - 962 // Returns: - 963 // Changes Globals: - 964 //=========================================================================== 965 void AAS_FlipSharedFaces(void) 966 { 967 int i; 968 tmp_area_t *tmparea1, *tmparea2; 969 970 i = 0; 971 qprintf("%6d areas checked for shared face flipping", i); 972 for (tmparea1 = tmpaasworld.areas; tmparea1; tmparea1 = tmparea1->l_next) 973 { 974 if (tmparea1->invalid) continue; 975 for (tmparea2 = tmpaasworld.areas; tmparea2; tmparea2 = tmparea2->l_next) 976 { 977 if (tmparea2->invalid) continue; 978 if (tmparea1 == tmparea2) continue; 979 AAS_FlipAreaSharedFaces(tmparea1, tmparea2); 980 } //end for 981 qprintf("\r%6d", ++i); 982 } //end for 983 Log_Print("\r%6d areas checked for shared face flipping\n", i); 984 } //end of the function AAS_FlipSharedFaces 985 */ 986 //=========================================================================== 987 // 988 // Parameter: - 989 // Returns: - 990 // Changes Globals: - 991 //=========================================================================== 992 void AAS_FlipSharedFaces(void) 993 { 994 int i, side1, side2; 995 tmp_area_t *tmparea1; 996 tmp_face_t *face1, *face2; 997 998 i = 0; 999 qprintf("%6d areas checked for shared face flipping", i); 1000 for (tmparea1 = tmpaasworld.areas; tmparea1; tmparea1 = tmparea1->l_next) 1001 { 1002 if (tmparea1->invalid) continue; 1003 for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side1]) 1004 { 1005 side1 = face1->frontarea != tmparea1; 1006 if (!face1->frontarea || !face1->backarea) continue; 1007 // 1008 for (face2 = face1->next[side1]; face2; face2 = face2->next[side2]) 1009 { 1010 side2 = face2->frontarea != tmparea1; 1011 if (!face2->frontarea || !face2->backarea) continue; 1012 // 1013 if (face1->frontarea == face2->backarea && 1014 face1->backarea == face2->frontarea) 1015 { 1016 AAS_FlipFace(face2); 1017 } //end if 1018 //recheck side 1019 side2 = face2->frontarea != tmparea1; 1020 } //end for 1021 } //end for 1022 qprintf("\r%6d", ++i); 1023 } //end for 1024 qprintf("\n"); 1025 Log_Write("%6d areas checked for shared face flipping\r\n", i); 1026 } //end of the function AAS_FlipSharedFaces 1027 //=========================================================================== 1028 // creates an .AAS file with the given name 1029 // a MAP should be loaded before calling this 1030 // 1031 // Parameter: - 1032 // Returns: - 1033 // Changes Globals: - 1034 //=========================================================================== 1035 void AAS_Create(char *aasfile) 1036 { 1037 entity_t *e; 1038 tree_t *tree; 1039 double start_time; 1040 1041 //for a possible leak file 1042 strcpy(source, aasfile); 1043 StripExtension(source); 1044 //the time started 1045 start_time = I_FloatTime(); 1046 //set the default number of threads (depends on number of processors) 1047 ThreadSetDefault(); 1048 //set the global entity number to the world model 1049 entity_num = 0; 1050 //the world entity 1051 e = &entities[entity_num]; 1052 //process the whole world 1053 tree = ProcessWorldBrushes(e->firstbrush, e->firstbrush + e->numbrushes); 1054 //if the conversion is cancelled 1055 if (cancelconversion) 1056 { 1057 Tree_Free(tree); 1058 return; 1059 } //end if 1060 //display BSP tree creation time 1061 Log_Print("BSP tree created in %5.0f seconds\n", I_FloatTime() - start_time); 1062 //prune the bsp tree 1063 Tree_PruneNodes(tree->headnode); 1064 //if the conversion is cancelled 1065 if (cancelconversion) 1066 { 1067 Tree_Free(tree); 1068 return; 1069 } //end if 1070 //create the tree portals 1071 MakeTreePortals(tree); 1072 //if the conversion is cancelled 1073 if (cancelconversion) 1074 { 1075 Tree_Free(tree); 1076 return; 1077 } //end if 1078 //Marks all nodes that can be reached by entites 1079 if (FloodEntities(tree)) 1080 { 1081 //fill out nodes that can't be reached 1082 FillOutside(tree->headnode); 1083 } //end if 1084 else 1085 { 1086 LeakFile(tree); 1087 Error("**** leaked ****\n"); 1088 return; 1089 } //end else 1090 //create AAS from the BSP tree 1091 //========================================== 1092 //initialize tmp aas 1093 AAS_InitTmpAAS(); 1094 //create the convex areas from the leaves 1095 AAS_CreateAreas(tree->headnode); 1096 //free the BSP tree because it isn't used anymore 1097 if (freetree) Tree_Free(tree); 1098 //try to merge area faces 1099 AAS_MergeAreaFaces(); 1100 //do gravitational subdivision 1101 AAS_GravitationalSubdivision(); 1102 //merge faces if possible 1103 AAS_MergeAreaFaces(); 1104 AAS_RemoveAreaFaceColinearPoints(); 1105 //merge areas if possible 1106 AAS_MergeAreas(); 1107 //NOTE: prune nodes directly after area merging 1108 AAS_PruneNodes(); 1109 //flip shared faces so they are all facing to the same area 1110 AAS_FlipSharedFaces(); 1111 AAS_RemoveAreaFaceColinearPoints(); 1112 //merge faces if possible 1113 AAS_MergeAreaFaces(); 1114 //merge area faces in the same plane 1115 AAS_MergeAreaPlaneFaces(); 1116 //do ladder subdivision 1117 AAS_LadderSubdivision(); 1118 //FIXME: melting is buggy 1119 AAS_MeltAreaFaceWindings(); 1120 //remove tiny faces 1121 AAS_RemoveTinyFaces(); 1122 //create area settings 1123 AAS_CreateAreaSettings(); 1124 //check if the winding plane is equal to the face plane 1125 //AAS_CheckAreaWindingPlanes(); 1126 // 1127 //AAS_CheckSharedFaces(); 1128 //========================================== 1129 //if the conversion is cancelled 1130 if (cancelconversion) 1131 { 1132 Tree_Free(tree); 1133 AAS_FreeTmpAAS(); 1134 return; 1135 } //end if 1136 //store the created AAS stuff in the AAS file format and write the file 1137 AAS_StoreFile(aasfile); 1138 //free the temporary AAS memory 1139 AAS_FreeTmpAAS(); 1140 //display creation time 1141 Log_Print("\nAAS created in %5.0f seconds\n", I_FloatTime() - start_time); 1142 } //end of the function AAS_Create