00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "qbsp.h"
00024 #include "../botlib/aasfile.h"
00025 #include "aas_create.h"
00026 #include "aas_store.h"
00027 #include "aas_cfg.h"
00028
00029 #define FACECLIP_EPSILON 0.2
00030 #define FACE_EPSILON 1.0
00031
00032 int numgravitationalsubdivisions = 0;
00033 int numladdersubdivisions = 0;
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 void AAS_SplitFace(tmp_face_t *face, vec3_t normal, float dist,
00046 tmp_face_t **frontface, tmp_face_t **backface)
00047 {
00048 winding_t *frontw, *backw;
00049
00050
00051 *frontface = *backface = NULL;
00052
00053 ClipWindingEpsilon(face->winding, normal, dist, FACECLIP_EPSILON, &frontw, &backw);
00054
00055 #ifdef DEBUG
00056
00057 if (frontw)
00058 {
00059 if (WindingIsTiny(frontw))
00060 {
00061 Log_Write("AAS_SplitFace: tiny back face\r\n");
00062 FreeWinding(frontw);
00063 frontw = NULL;
00064 }
00065 }
00066 if (backw)
00067 {
00068 if (WindingIsTiny(backw))
00069 {
00070 Log_Write("AAS_SplitFace: tiny back face\r\n");
00071 FreeWinding(backw);
00072 backw = NULL;
00073 }
00074 }
00075 #endif //DEBUG
00076
00077 if (frontw)
00078 {
00079
00080 (*frontface) = AAS_AllocTmpFace();
00081 (*frontface)->planenum = face->planenum;
00082 (*frontface)->winding = frontw;
00083 (*frontface)->faceflags = face->faceflags;
00084 }
00085 if (backw)
00086 {
00087
00088 (*backface) = AAS_AllocTmpFace();
00089 (*backface)->planenum = face->planenum;
00090 (*backface)->winding = backw;
00091 (*backface)->faceflags = face->faceflags;
00092 }
00093 }
00094
00095
00096
00097
00098
00099
00100 winding_t *AAS_SplitWinding(tmp_area_t *tmparea, int planenum)
00101 {
00102 tmp_face_t *face;
00103 plane_t *plane;
00104 int side;
00105 winding_t *splitwinding;
00106
00107
00108 plane = &mapplanes[planenum];
00109
00110 splitwinding = BaseWindingForPlane(plane->normal, plane->dist);
00111
00112 for (face = tmparea->tmpfaces; face && splitwinding; face = face->next[side])
00113 {
00114
00115 side = face->frontarea != tmparea;
00116 plane = &mapplanes[face->planenum ^ side];
00117 ChopWindingInPlace(&splitwinding, plane->normal, plane->dist, 0);
00118 }
00119 return splitwinding;
00120 }
00121
00122
00123
00124
00125
00126
00127 int AAS_TestSplitPlane(tmp_area_t *tmparea, vec3_t normal, float dist,
00128 int *facesplits, int *groundsplits, int *epsilonfaces)
00129 {
00130 int j, side, front, back, planenum;
00131 float d, d_front, d_back;
00132 tmp_face_t *face;
00133 winding_t *w;
00134
00135 *facesplits = *groundsplits = *epsilonfaces = 0;
00136
00137 planenum = FindFloatPlane(normal, dist);
00138
00139 w = AAS_SplitWinding(tmparea, planenum);
00140 if (!w) return false;
00141 FreeWinding(w);
00142
00143 for (face = tmparea->tmpfaces; face; face = face->next[side])
00144 {
00145
00146 side = face->frontarea != tmparea;
00147
00148 if ((face->planenum & ~1) == (planenum & ~1))
00149 {
00150 Log_Print("AAS_TestSplitPlane: tried face plane as splitter\n");
00151 return false;
00152 }
00153 w = face->winding;
00154
00155 d_front = d_back = 0;
00156
00157 front = back = 0;
00158 for (j = 0; j < w->numpoints; j++)
00159 {
00160 d = DotProduct(w->p[j], normal) - dist;
00161 if (d > d_front) d_front = d;
00162 if (d < d_back) d_back = d;
00163
00164 if (d > 0.4)
00165 front = 1;
00166 if (d < -0.4)
00167 back = 1;
00168 }
00169
00170 if ( (d_front > FACECLIP_EPSILON && d_front < FACE_EPSILON)
00171 || (d_back < -FACECLIP_EPSILON && d_back > -FACE_EPSILON) )
00172 {
00173 (*epsilonfaces)++;
00174 }
00175
00176 if (front && back)
00177 {
00178 (*facesplits)++;
00179 if (face->faceflags & FACE_GROUND)
00180 {
00181 (*groundsplits)++;
00182 }
00183 }
00184 }
00185 return true;
00186 }
00187
00188
00189
00190
00191
00192
00193 void AAS_SplitArea(tmp_area_t *tmparea, int planenum, tmp_area_t **frontarea, tmp_area_t **backarea)
00194 {
00195 int side;
00196 tmp_area_t *facefrontarea, *facebackarea, *faceotherarea;
00197 tmp_face_t *face, *frontface, *backface, *splitface, *nextface;
00198 winding_t *splitwinding;
00199 plane_t *splitplane;
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 AAS_FlipAreaFaces(tmparea);
00215 AAS_CheckArea(tmparea);
00216
00217 splitplane = &mapplanes[planenum];
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228 splitwinding = AAS_SplitWinding(tmparea, planenum);
00229 if (!splitwinding)
00230 {
00231
00232
00233
00234
00235
00236
00237
00238 Error("AAS_SplitArea: no split winding when splitting area %d\n", tmparea->areanum);
00239 }
00240
00241 splitface = AAS_AllocTmpFace();
00242
00243 splitface->planenum = planenum;
00244
00245 splitface->winding = splitwinding;
00246
00247 (*frontarea) = AAS_AllocTmpArea();
00248 (*frontarea)->presencetype = tmparea->presencetype;
00249 (*frontarea)->contents = tmparea->contents;
00250 (*frontarea)->modelnum = tmparea->modelnum;
00251 (*frontarea)->tmpfaces = NULL;
00252
00253 (*backarea) = AAS_AllocTmpArea();
00254 (*backarea)->presencetype = tmparea->presencetype;
00255 (*backarea)->contents = tmparea->contents;
00256 (*backarea)->modelnum = tmparea->modelnum;
00257 (*backarea)->tmpfaces = NULL;
00258
00259 AAS_AddFaceSideToArea(splitface, 0, (*frontarea));
00260 AAS_AddFaceSideToArea(splitface, 1, (*backarea));
00261
00262
00263 for (face = tmparea->tmpfaces; face; face = nextface)
00264 {
00265
00266 side = face->frontarea != tmparea;
00267
00268 nextface = face->next[side];
00269
00270 facefrontarea = face->frontarea;
00271
00272 facebackarea = face->backarea;
00273
00274 if (facefrontarea) AAS_RemoveFaceFromArea(face, facefrontarea);
00275 if (facebackarea) AAS_RemoveFaceFromArea(face, facebackarea);
00276
00277 AAS_SplitFace(face, splitplane->normal, splitplane->dist, &frontface, &backface);
00278
00279 AAS_FreeTmpFace(face);
00280
00281 if (side) faceotherarea = facefrontarea;
00282 else faceotherarea = facebackarea;
00283
00284 if (faceotherarea)
00285 {
00286 if (frontface) AAS_AddFaceSideToArea(frontface, !side, faceotherarea);
00287 if (backface) AAS_AddFaceSideToArea(backface, !side, faceotherarea);
00288 }
00289
00290 if (frontface) AAS_AddFaceSideToArea(frontface, side, (*frontarea));
00291 if (backface) AAS_AddFaceSideToArea(backface, side, (*backarea));
00292 }
00293
00294 if (!(*frontarea)->tmpfaces) Log_Print("AAS_SplitArea: front area without faces\n");
00295 if (!(*backarea)->tmpfaces) Log_Print("AAS_SplitArea: back area without faces\n");
00296
00297 tmparea->invalid = true;
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315 AAS_FlipAreaFaces((*frontarea));
00316 AAS_FlipAreaFaces((*backarea));
00317
00318 AAS_CheckArea((*frontarea));
00319 AAS_CheckArea((*backarea));
00320 }
00321
00322
00323
00324
00325
00326
00327 int AAS_FindBestAreaSplitPlane(tmp_area_t *tmparea, vec3_t normal, float *dist)
00328 {
00329 int side1, side2;
00330 int foundsplitter, facesplits, groundsplits, epsilonfaces, bestepsilonfaces;
00331 float bestvalue, value;
00332 tmp_face_t *face1, *face2;
00333 vec3_t tmpnormal, invgravity;
00334 float tmpdist;
00335
00336
00337 VectorCopy(cfg.phys_gravitydirection, invgravity);
00338 VectorInverse(invgravity);
00339
00340 foundsplitter = false;
00341 bestvalue = -999999;
00342 bestepsilonfaces = 0;
00343
00344 #ifdef AW_DEBUG
00345 Log_Print("finding split plane for area %d\n", tmparea->areanum);
00346 #endif //AW_DEBUG
00347 for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
00348 {
00349
00350 side1 = face1->frontarea != tmparea;
00351
00352 if (WindingIsTiny(face1->winding))
00353 {
00354 Log_Write("gsubdiv: area %d has a tiny winding\r\n", tmparea->areanum);
00355 continue;
00356 }
00357
00358 if (!(face1->faceflags & FACE_GROUND) && !AAS_GapFace(face1, side1)) continue;
00359
00360 for (face2 = face1->next[side1]; face2; face2 = face2->next[side2])
00361 {
00362
00363 side2 = face2->frontarea != tmparea;
00364
00365 if (WindingIsTiny(face1->winding))
00366 {
00367 Log_Write("gsubdiv: area %d has a tiny winding\r\n", tmparea->areanum);
00368 continue;
00369 }
00370
00371 if (!(face2->faceflags & FACE_GROUND) && !AAS_GapFace(face2, side2)) continue;
00372
00373 if (!(((face1->faceflags & FACE_GROUND) && AAS_GapFace(face2, side2)) ||
00374 ((face2->faceflags & FACE_GROUND) && AAS_GapFace(face1, side1)))) continue;
00375
00376 if (!FindPlaneSeperatingWindings(face1->winding, face2->winding, invgravity,
00377 tmpnormal, &tmpdist)) continue;
00378 #ifdef AW_DEBUG
00379 Log_Print("normal = \'%f %f %f\', dist = %f\n",
00380 tmpnormal[0], tmpnormal[1], tmpnormal[2], tmpdist);
00381 #endif //AW_DEBUG
00382
00383 if (!AAS_TestSplitPlane(tmparea, tmpnormal, tmpdist,
00384 &facesplits, &groundsplits, &epsilonfaces))
00385 {
00386 continue;
00387 }
00388 #ifdef AW_DEBUG
00389 Log_Print("face splits = %d\nground splits = %d\n",
00390 facesplits, groundsplits);
00391 #endif //AW_DEBUG
00392 value = 100 - facesplits - 2 * groundsplits;
00393
00394 value += epsilonfaces * -1000;
00395 if (value > bestvalue)
00396 {
00397 VectorCopy(tmpnormal, normal);
00398 *dist = tmpdist;
00399 bestvalue = value;
00400 bestepsilonfaces = epsilonfaces;
00401 foundsplitter = true;
00402 }
00403 }
00404 }
00405 if (bestepsilonfaces)
00406 {
00407 Log_Write("found %d epsilon faces trying to split area %d\r\n",
00408 epsilonfaces, tmparea->areanum);
00409 }
00410 return foundsplitter;
00411 }
00412
00413
00414
00415
00416
00417
00418 tmp_node_t *AAS_SubdivideArea_r(tmp_node_t *tmpnode)
00419 {
00420 int planenum;
00421 tmp_area_t *frontarea, *backarea;
00422 tmp_node_t *tmpnode1, *tmpnode2;
00423 vec3_t normal;
00424 float dist;
00425
00426 if (AAS_FindBestAreaSplitPlane(tmpnode->tmparea, normal, &dist))
00427 {
00428 qprintf("\r%6d", ++numgravitationalsubdivisions);
00429
00430 planenum = FindFloatPlane(normal, dist);
00431
00432 AAS_SplitArea(tmpnode->tmparea, planenum, &frontarea, &backarea);
00433
00434 tmpnode->tmparea = NULL;
00435 tmpnode->planenum = FindFloatPlane(normal, dist);
00436
00437 tmpnode1 = AAS_AllocTmpNode();
00438 tmpnode1->planenum = 0;
00439 tmpnode1->tmparea = frontarea;
00440
00441 tmpnode2 = AAS_AllocTmpNode();
00442 tmpnode2->planenum = 0;
00443 tmpnode2->tmparea = backarea;
00444
00445 tmpnode->children[0] = AAS_SubdivideArea_r(tmpnode1);
00446 tmpnode->children[1] = AAS_SubdivideArea_r(tmpnode2);
00447 }
00448 return tmpnode;
00449 }
00450
00451
00452
00453
00454
00455
00456 tmp_node_t *AAS_GravitationalSubdivision_r(tmp_node_t *tmpnode)
00457 {
00458
00459 if (!tmpnode) return NULL;
00460
00461 if (tmpnode->tmparea) return AAS_SubdivideArea_r(tmpnode);
00462
00463 tmpnode->children[0] = AAS_GravitationalSubdivision_r(tmpnode->children[0]);
00464 tmpnode->children[1] = AAS_GravitationalSubdivision_r(tmpnode->children[1]);
00465 return tmpnode;
00466 }
00467
00468
00469
00470
00471
00472
00473
00474 void AAS_GravitationalSubdivision(void)
00475 {
00476 Log_Write("AAS_GravitationalSubdivision\r\n");
00477 numgravitationalsubdivisions = 0;
00478 qprintf("%6i gravitational subdivisions", numgravitationalsubdivisions);
00479
00480 AAS_GravitationalSubdivision_r(tmpaasworld.nodes);
00481 qprintf("\n");
00482 Log_Write("%6i gravitational subdivisions\r\n", numgravitationalsubdivisions);
00483 }
00484
00485
00486
00487
00488
00489
00490 tmp_node_t *AAS_RefreshLadderSubdividedTree_r(tmp_node_t *tmpnode, tmp_area_t *tmparea,
00491 tmp_node_t *tmpnode1, tmp_node_t *tmpnode2, int planenum)
00492 {
00493
00494 if (!tmpnode) return NULL;
00495
00496 if (tmpnode->tmparea)
00497 {
00498 if (tmpnode->tmparea == tmparea)
00499 {
00500 tmpnode->tmparea = NULL;
00501 tmpnode->planenum = planenum;
00502 tmpnode->children[0] = tmpnode1;
00503 tmpnode->children[1] = tmpnode2;
00504 }
00505 return tmpnode;
00506 }
00507
00508 tmpnode->children[0] = AAS_RefreshLadderSubdividedTree_r(tmpnode->children[0],
00509 tmparea, tmpnode1, tmpnode2, planenum);
00510 tmpnode->children[1] = AAS_RefreshLadderSubdividedTree_r(tmpnode->children[1],
00511 tmparea, tmpnode1, tmpnode2, planenum);
00512 return tmpnode;
00513 }
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523 tmp_node_t *AAS_LadderSubdivideArea_r(tmp_node_t *tmpnode)
00524 {
00525 int side1, i, planenum;
00526 int foundladderface, foundgroundface;
00527 float dist;
00528 tmp_area_t *tmparea, *frontarea, *backarea;
00529 tmp_face_t *face1;
00530 tmp_node_t *tmpnode1, *tmpnode2;
00531 vec3_t lowestpoint, normal = {0, 0, 1};
00532 plane_t *plane;
00533 winding_t *w;
00534
00535 tmparea = tmpnode->tmparea;
00536
00537 if (tmparea->contents & (AREACONTENTS_WATER
00538 | AREACONTENTS_LAVA
00539 | AREACONTENTS_SLIME)) return tmpnode;
00540
00541 if (!(tmparea->presencetype & PRESENCE_NORMAL)) return tmpnode;
00542
00543 foundladderface = false;
00544 foundgroundface = false;
00545 lowestpoint[2] = 99999;
00546
00547 for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
00548 {
00549
00550 side1 = face1->frontarea != tmparea;
00551
00552 if (face1->faceflags & FACE_LADDER)
00553 {
00554 plane = &mapplanes[face1->planenum];
00555
00556 if (DotProduct(plane->normal, normal) > -0.1)
00557 {
00558 foundladderface = true;
00559
00560 for (i = 0; i < face1->winding->numpoints; i++)
00561 {
00562 if (face1->winding->p[i][2] < lowestpoint[2])
00563 {
00564 VectorCopy(face1->winding->p[i], lowestpoint);
00565 }
00566 }
00567 }
00568 }
00569 else if (face1->faceflags & FACE_GROUND)
00570 {
00571 foundgroundface = true;
00572 }
00573 }
00574
00575 if ((!foundladderface) || (!foundgroundface)) return tmpnode;
00576
00577 for (face1 = tmparea->tmpfaces; face1; face1 = face1->next[side1])
00578 {
00579
00580 side1 = face1->frontarea != tmparea;
00581
00582 if (!(face1->faceflags & FACE_GROUND)) continue;
00583
00584 plane = &mapplanes[face1->planenum];
00585
00586 dist = DotProduct(plane->normal, lowestpoint) - plane->dist;
00587
00588 if (dist > -1 && dist < 1)
00589 {
00590 return tmpnode;
00591 }
00592 }
00593
00594 dist = DotProduct(normal, lowestpoint);
00595 planenum = FindFloatPlane(normal, dist);
00596
00597 w = AAS_SplitWinding(tmparea, planenum);
00598 if (!w) return tmpnode;
00599 FreeWinding(w);
00600
00601 qprintf("\r%6d", ++numladdersubdivisions);
00602
00603 AAS_SplitArea(tmparea, planenum, &frontarea, &backarea);
00604
00605 tmpnode->tmparea = NULL;
00606 tmpnode->planenum = planenum;
00607
00608 tmpnode1 = AAS_AllocTmpNode();
00609 tmpnode1->planenum = 0;
00610 tmpnode1->tmparea = frontarea;
00611
00612 tmpnode2 = AAS_AllocTmpNode();
00613 tmpnode2->planenum = 0;
00614 tmpnode2->tmparea = backarea;
00615
00616 tmpnode->children[0] = AAS_LadderSubdivideArea_r(tmpnode1);
00617 tmpnode->children[1] = AAS_LadderSubdivideArea_r(tmpnode2);
00618
00619 AAS_RefreshLadderSubdividedTree_r(tmpaasworld.nodes, tmparea, tmpnode1, tmpnode2, planenum);
00620
00621 return tmpnode;
00622 }
00623
00624
00625
00626
00627
00628
00629 tmp_node_t *AAS_LadderSubdivision_r(tmp_node_t *tmpnode)
00630 {
00631
00632 if (!tmpnode) return 0;
00633
00634 if (tmpnode->tmparea) return AAS_LadderSubdivideArea_r(tmpnode);
00635
00636 tmpnode->children[0] = AAS_LadderSubdivision_r(tmpnode->children[0]);
00637 tmpnode->children[1] = AAS_LadderSubdivision_r(tmpnode->children[1]);
00638 return tmpnode;
00639 }
00640
00641
00642
00643
00644
00645
00646 void AAS_LadderSubdivision(void)
00647 {
00648 Log_Write("AAS_LadderSubdivision\r\n");
00649 numladdersubdivisions = 0;
00650 qprintf("%6i ladder subdivisions", numladdersubdivisions);
00651
00652 AAS_LadderSubdivision_r(tmpaasworld.nodes);
00653
00654 qprintf("\n");
00655 Log_Write("%6i ladder subdivisions\r\n", numladdersubdivisions);
00656 }