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
00025
00026 int c_active_portals;
00027 int c_peak_portals;
00028 int c_boundary;
00029 int c_boundary_sides;
00030
00031
00032
00033
00034
00035
00036 portal_t *AllocPortal (void)
00037 {
00038 portal_t *p;
00039
00040 if (numthreads == 1)
00041 c_active_portals++;
00042 if (c_active_portals > c_peak_portals)
00043 c_peak_portals = c_active_portals;
00044
00045 p = malloc (sizeof(portal_t));
00046 memset (p, 0, sizeof(portal_t));
00047
00048 return p;
00049 }
00050
00051 void FreePortal (portal_t *p)
00052 {
00053 if (p->winding)
00054 FreeWinding (p->winding);
00055 if (numthreads == 1)
00056 c_active_portals--;
00057 free (p);
00058 }
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 qboolean Portal_Passable(portal_t *p) {
00070 if (!p->onnode) {
00071 return qfalse;
00072 }
00073
00074 if (p->nodes[0]->planenum != PLANENUM_LEAF
00075 || p->nodes[1]->planenum != PLANENUM_LEAF) {
00076 Error ("Portal_EntityFlood: not a leaf");
00077 }
00078
00079 if ( !p->nodes[0]->opaque && !p->nodes[1]->opaque ) {
00080 return qtrue;
00081 }
00082
00083 return qfalse;
00084 }
00085
00086
00087
00088
00089 int c_tinyportals;
00090
00091
00092
00093
00094
00095
00096 void AddPortalToNodes (portal_t *p, node_t *front, node_t *back)
00097 {
00098 if (p->nodes[0] || p->nodes[1])
00099 Error ("AddPortalToNode: allready included");
00100
00101 p->nodes[0] = front;
00102 p->next[0] = front->portals;
00103 front->portals = p;
00104
00105 p->nodes[1] = back;
00106 p->next[1] = back->portals;
00107 back->portals = p;
00108 }
00109
00110
00111
00112
00113
00114
00115
00116 void RemovePortalFromNode (portal_t *portal, node_t *l)
00117 {
00118 portal_t **pp, *t;
00119
00120
00121 pp = &l->portals;
00122 while (1)
00123 {
00124 t = *pp;
00125 if (!t)
00126 Error ("RemovePortalFromNode: portal not in leaf");
00127
00128 if ( t == portal )
00129 break;
00130
00131 if (t->nodes[0] == l)
00132 pp = &t->next[0];
00133 else if (t->nodes[1] == l)
00134 pp = &t->next[1];
00135 else
00136 Error ("RemovePortalFromNode: portal not bounding leaf");
00137 }
00138
00139 if (portal->nodes[0] == l)
00140 {
00141 *pp = portal->next[0];
00142 portal->nodes[0] = NULL;
00143 }
00144 else if (portal->nodes[1] == l)
00145 {
00146 *pp = portal->next[1];
00147 portal->nodes[1] = NULL;
00148 }
00149 }
00150
00151
00152
00153 void PrintPortal (portal_t *p)
00154 {
00155 int i;
00156 winding_t *w;
00157
00158 w = p->winding;
00159 for (i=0 ; i<w->numpoints ; i++)
00160 _printf ("(%5.0f,%5.0f,%5.0f)\n",w->p[i][0]
00161 , w->p[i][1], w->p[i][2]);
00162 }
00163
00164
00165
00166
00167
00168
00169
00170
00171 #define SIDESPACE 8
00172 void MakeHeadnodePortals (tree_t *tree)
00173 {
00174 vec3_t bounds[2];
00175 int i, j, n;
00176 portal_t *p, *portals[6];
00177 plane_t bplanes[6], *pl;
00178 node_t *node;
00179
00180 node = tree->headnode;
00181
00182
00183 for (i=0 ; i<3 ; i++)
00184 {
00185 bounds[0][i] = tree->mins[i] - SIDESPACE;
00186 bounds[1][i] = tree->maxs[i] + SIDESPACE;
00187 if ( bounds[0][i] >= bounds[1][i] ) {
00188 Error( "Backwards tree volume" );
00189 }
00190 }
00191
00192 tree->outside_node.planenum = PLANENUM_LEAF;
00193 tree->outside_node.brushlist = NULL;
00194 tree->outside_node.portals = NULL;
00195 tree->outside_node.opaque = qfalse;
00196
00197 for (i=0 ; i<3 ; i++)
00198 for (j=0 ; j<2 ; j++)
00199 {
00200 n = j*3 + i;
00201
00202 p = AllocPortal ();
00203 portals[n] = p;
00204
00205 pl = &bplanes[n];
00206 memset (pl, 0, sizeof(*pl));
00207 if (j)
00208 {
00209 pl->normal[i] = -1;
00210 pl->dist = -bounds[j][i];
00211 }
00212 else
00213 {
00214 pl->normal[i] = 1;
00215 pl->dist = bounds[j][i];
00216 }
00217 p->plane = *pl;
00218 p->winding = BaseWindingForPlane (pl->normal, pl->dist);
00219 AddPortalToNodes (p, node, &tree->outside_node);
00220 }
00221
00222
00223 for (i=0 ; i<6 ; i++)
00224 {
00225 for (j=0 ; j<6 ; j++)
00226 {
00227 if (j == i)
00228 continue;
00229 ChopWindingInPlace (&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON);
00230 }
00231 }
00232 }
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242 #define BASE_WINDING_EPSILON 0.001
00243 #define SPLIT_WINDING_EPSILON 0.001
00244
00245 winding_t *BaseWindingForNode (node_t *node)
00246 {
00247 winding_t *w;
00248 node_t *n;
00249 plane_t *plane;
00250 vec3_t normal;
00251 vec_t dist;
00252
00253 w = BaseWindingForPlane (mapplanes[node->planenum].normal
00254 , mapplanes[node->planenum].dist);
00255
00256
00257 for (n=node->parent ; n && w ; )
00258 {
00259 plane = &mapplanes[n->planenum];
00260
00261 if (n->children[0] == node)
00262 {
00263 ChopWindingInPlace (&w, plane->normal, plane->dist, BASE_WINDING_EPSILON);
00264 }
00265 else
00266 {
00267 VectorSubtract (vec3_origin, plane->normal, normal);
00268 dist = -plane->dist;
00269 ChopWindingInPlace (&w, normal, dist, BASE_WINDING_EPSILON);
00270 }
00271 node = n;
00272 n = n->parent;
00273 }
00274
00275 return w;
00276 }
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 void MakeNodePortal (node_t *node)
00289 {
00290 portal_t *new_portal, *p;
00291 winding_t *w;
00292 vec3_t normal;
00293 float dist;
00294 int side;
00295
00296 w = BaseWindingForNode (node);
00297
00298
00299 for (p = node->portals ; p && w; p = p->next[side])
00300 {
00301 if (p->nodes[0] == node)
00302 {
00303 side = 0;
00304 VectorCopy (p->plane.normal, normal);
00305 dist = p->plane.dist;
00306 }
00307 else if (p->nodes[1] == node)
00308 {
00309 side = 1;
00310 VectorSubtract (vec3_origin, p->plane.normal, normal);
00311 dist = -p->plane.dist;
00312 }
00313 else
00314 Error ("CutNodePortals_r: mislinked portal");
00315
00316 ChopWindingInPlace (&w, normal, dist, CLIP_EPSILON);
00317 }
00318
00319 if (!w)
00320 {
00321 return;
00322 }
00323
00324 if (WindingIsTiny (w))
00325 {
00326 c_tinyportals++;
00327 FreeWinding (w);
00328 return;
00329 }
00330
00331 new_portal = AllocPortal ();
00332 new_portal->plane = mapplanes[node->planenum];
00333 new_portal->onnode = node;
00334 new_portal->winding = w;
00335 new_portal->hint = node->hint;
00336 AddPortalToNodes (new_portal, node->children[0], node->children[1]);
00337 }
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348 void SplitNodePortals (node_t *node)
00349 {
00350 portal_t *p, *next_portal, *new_portal;
00351 node_t *f, *b, *other_node;
00352 int side;
00353 plane_t *plane;
00354 winding_t *frontwinding, *backwinding;
00355
00356 plane = &mapplanes[node->planenum];
00357 f = node->children[0];
00358 b = node->children[1];
00359
00360 for (p = node->portals ; p ; p = next_portal)
00361 {
00362 if (p->nodes[0] == node)
00363 side = 0;
00364 else if (p->nodes[1] == node)
00365 side = 1;
00366 else
00367 Error ("SplitNodePortals: mislinked portal");
00368 next_portal = p->next[side];
00369
00370 other_node = p->nodes[!side];
00371 RemovePortalFromNode (p, p->nodes[0]);
00372 RemovePortalFromNode (p, p->nodes[1]);
00373
00374
00375
00376
00377 ClipWindingEpsilon (p->winding, plane->normal, plane->dist,
00378 SPLIT_WINDING_EPSILON, &frontwinding, &backwinding);
00379
00380 if (frontwinding && WindingIsTiny(frontwinding))
00381 {
00382 if (!f->tinyportals)
00383 VectorCopy(frontwinding->p[0], f->referencepoint);
00384 f->tinyportals++;
00385 if (!other_node->tinyportals)
00386 VectorCopy(frontwinding->p[0], other_node->referencepoint);
00387 other_node->tinyportals++;
00388
00389 FreeWinding (frontwinding);
00390 frontwinding = NULL;
00391 c_tinyportals++;
00392 }
00393
00394 if (backwinding && WindingIsTiny(backwinding))
00395 {
00396 if (!b->tinyportals)
00397 VectorCopy(backwinding->p[0], b->referencepoint);
00398 b->tinyportals++;
00399 if (!other_node->tinyportals)
00400 VectorCopy(backwinding->p[0], other_node->referencepoint);
00401 other_node->tinyportals++;
00402
00403 FreeWinding (backwinding);
00404 backwinding = NULL;
00405 c_tinyportals++;
00406 }
00407
00408 if (!frontwinding && !backwinding)
00409 {
00410 continue;
00411 }
00412
00413 if (!frontwinding)
00414 {
00415 FreeWinding (backwinding);
00416 if (side == 0)
00417 AddPortalToNodes (p, b, other_node);
00418 else
00419 AddPortalToNodes (p, other_node, b);
00420 continue;
00421 }
00422 if (!backwinding)
00423 {
00424 FreeWinding (frontwinding);
00425 if (side == 0)
00426 AddPortalToNodes (p, f, other_node);
00427 else
00428 AddPortalToNodes (p, other_node, f);
00429 continue;
00430 }
00431
00432
00433 new_portal = AllocPortal ();
00434 *new_portal = *p;
00435 new_portal->winding = backwinding;
00436 FreeWinding (p->winding);
00437 p->winding = frontwinding;
00438
00439 if (side == 0)
00440 {
00441 AddPortalToNodes (p, f, other_node);
00442 AddPortalToNodes (new_portal, b, other_node);
00443 }
00444 else
00445 {
00446 AddPortalToNodes (p, other_node, f);
00447 AddPortalToNodes (new_portal, other_node, b);
00448 }
00449 }
00450
00451 node->portals = NULL;
00452 }
00453
00454
00455
00456
00457
00458
00459
00460 void CalcNodeBounds (node_t *node)
00461 {
00462 portal_t *p;
00463 int s;
00464 int i;
00465
00466
00467 ClearBounds (node->mins, node->maxs);
00468 for (p = node->portals ; p ; p = p->next[s])
00469 {
00470 s = (p->nodes[1] == node);
00471 for (i=0 ; i<p->winding->numpoints ; i++)
00472 AddPointToBounds (p->winding->p[i], node->mins, node->maxs);
00473 }
00474 }
00475
00476
00477
00478
00479
00480
00481 void MakeTreePortals_r (node_t *node)
00482 {
00483 int i;
00484
00485 CalcNodeBounds (node);
00486 if (node->mins[0] >= node->maxs[0])
00487 {
00488 _printf ("WARNING: node without a volume\n");
00489 _printf("node has %d tiny portals\n", node->tinyportals);
00490 _printf("node reference point %1.2f %1.2f %1.2f\n", node->referencepoint[0],
00491 node->referencepoint[1],
00492 node->referencepoint[2]);
00493 }
00494
00495 for (i=0 ; i<3 ; i++)
00496 {
00497 if (node->mins[i] < MIN_WORLD_COORD || node->maxs[i] > MAX_WORLD_COORD)
00498 {
00499 _printf ("WARNING: node with unbounded volume\n");
00500 break;
00501 }
00502 }
00503 if (node->planenum == PLANENUM_LEAF)
00504 return;
00505
00506 MakeNodePortal (node);
00507 SplitNodePortals (node);
00508
00509 MakeTreePortals_r (node->children[0]);
00510 MakeTreePortals_r (node->children[1]);
00511 }
00512
00513
00514
00515
00516
00517
00518 void MakeTreePortals (tree_t *tree)
00519 {
00520 qprintf( "----- MakeTreePortals -----\n");
00521 MakeHeadnodePortals (tree);
00522 MakeTreePortals_r (tree->headnode);
00523 qprintf("%6d tiny portals\n", c_tinyportals);
00524 }
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534 int c_floodedleafs;
00535
00536
00537
00538
00539
00540
00541 void FloodPortals_r (node_t *node, int dist) {
00542 portal_t *p;
00543 int s;
00544
00545 if ( node->occupied ) {
00546 return;
00547 }
00548
00549 if ( node->opaque ) {
00550 return;
00551 }
00552
00553 c_floodedleafs++;
00554 node->occupied = dist;
00555
00556 for (p=node->portals ; p ; p = p->next[s]) {
00557 s = (p->nodes[1] == node);
00558 FloodPortals_r (p->nodes[!s], dist+1);
00559 }
00560 }
00561
00562
00563
00564
00565
00566
00567 qboolean PlaceOccupant (node_t *headnode, vec3_t origin, entity_t *occupant)
00568 {
00569 node_t *node;
00570 vec_t d;
00571 plane_t *plane;
00572
00573
00574 node = headnode;
00575 while (node->planenum != PLANENUM_LEAF)
00576 {
00577 plane = &mapplanes[node->planenum];
00578 d = DotProduct (origin, plane->normal) - plane->dist;
00579 if (d >= 0)
00580 node = node->children[0];
00581 else
00582 node = node->children[1];
00583 }
00584
00585 if ( node->opaque )
00586 return qfalse;
00587 node->occupant = occupant;
00588
00589 FloodPortals_r (node, 1);
00590
00591 return qtrue;
00592 }
00593
00594
00595
00596
00597
00598
00599
00600
00601 qboolean FloodEntities( tree_t *tree ) {
00602 int i;
00603 vec3_t origin;
00604 const char *cl;
00605 qboolean inside;
00606 node_t *headnode;
00607
00608 headnode = tree->headnode;
00609 qprintf ("--- FloodEntities ---\n");
00610 inside = qfalse;
00611 tree->outside_node.occupied = 0;
00612
00613 c_floodedleafs = 0;
00614 for (i=1 ; i<num_entities ; i++)
00615 {
00616 GetVectorForKey (&entities[i], "origin", origin);
00617 if (VectorCompare(origin, vec3_origin))
00618 continue;
00619
00620 cl = ValueForKey (&entities[i], "classname");
00621
00622 origin[2] += 1;
00623
00624 if (PlaceOccupant (headnode, origin, &entities[i]))
00625 inside = qtrue;
00626 }
00627
00628 qprintf("%5i flooded leafs\n", c_floodedleafs );
00629
00630 if (!inside)
00631 {
00632 qprintf ("no entities in open -- no filling\n");
00633 }
00634 else if (tree->outside_node.occupied)
00635 {
00636 qprintf ("entity reached from outside -- no filling\n");
00637 }
00638
00639 return (qboolean)(inside && !tree->outside_node.occupied);
00640 }
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650 int c_areas;
00651
00652
00653
00654
00655
00656
00657 void FloodAreas_r (node_t *node)
00658 {
00659 portal_t *p;
00660 int s;
00661 bspbrush_t *b;
00662
00663 if ( node->areaportal ) {
00664
00665 if ( node->area == -1 ) {
00666 node->area = c_areas;
00667 }
00668
00669 b = node->brushlist->original;
00670
00671
00672
00673 if (b->portalareas[0] == c_areas || b->portalareas[1] == c_areas)
00674 return;
00675
00676
00677 if (b->portalareas[1] != -1)
00678 {
00679 _printf ("WARNING: areaportal brush %i touches > 2 areas\n", b->brushnum );
00680 return;
00681 }
00682 if (b->portalareas[0] != -1) {
00683 b->portalareas[1] = c_areas;
00684 } else {
00685 b->portalareas[0] = c_areas;
00686 }
00687
00688 return;
00689 }
00690
00691 if (node->area != -1) {
00692 return;
00693 }
00694 if ( node->cluster == -1 ) {
00695 return;
00696 }
00697
00698 node->area = c_areas;
00699
00700 for (p=node->portals ; p ; p = p->next[s])
00701 {
00702 s = (p->nodes[1] == node);
00703
00704 if ( !Portal_Passable(p) )
00705 continue;
00706
00707 FloodAreas_r (p->nodes[!s]);
00708 }
00709 }
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720 void FindAreas_r (node_t *node)
00721 {
00722 if (node->planenum != PLANENUM_LEAF)
00723 {
00724 FindAreas_r (node->children[0]);
00725 FindAreas_r (node->children[1]);
00726 return;
00727 }
00728
00729 if (node->opaque)
00730 return;
00731
00732 if (node->areaportal)
00733 return;
00734
00735 if (node->area != -1)
00736 return;
00737
00738 FloodAreas_r (node);
00739 c_areas++;
00740 }
00741
00742
00743
00744
00745
00746
00747 void CheckAreas_r (node_t *node)
00748 {
00749 bspbrush_t *b;
00750
00751 if (node->planenum != PLANENUM_LEAF)
00752 {
00753 CheckAreas_r (node->children[0]);
00754 CheckAreas_r (node->children[1]);
00755 return;
00756 }
00757
00758 if (node->opaque)
00759 return;
00760
00761 if (node->cluster != -1)
00762 if (node->area == -1)
00763 _printf("WARNING: cluster %d has area set to -1\n", node->cluster);
00764 if (node->areaportal)
00765 {
00766 b = node->brushlist->original;
00767
00768
00769 if (b->portalareas[0] == -1 || b->portalareas[1] == -1)
00770 _printf ("WARNING: areaportal brush %i doesn't touch two areas\n", b->brushnum);
00771 }
00772 }
00773
00774
00775
00776
00777
00778
00779
00780
00781 void FloodAreas (tree_t *tree)
00782 {
00783 qprintf ("--- FloodAreas ---\n");
00784 FindAreas_r( tree->headnode );
00785
00786
00787 CheckAreas_r( tree->headnode );
00788
00789 qprintf ("%5i areas\n", c_areas);
00790 }
00791
00792
00793
00794 int c_outside;
00795 int c_inside;
00796 int c_solid;
00797
00798 void FillOutside_r (node_t *node)
00799 {
00800 if (node->planenum != PLANENUM_LEAF)
00801 {
00802 FillOutside_r (node->children[0]);
00803 FillOutside_r (node->children[1]);
00804 return;
00805 }
00806
00807
00808
00809 if (!node->occupied) {
00810 if ( !node->opaque ) {
00811 c_outside++;
00812 node->opaque = qtrue;
00813 } else {
00814 c_solid++;
00815 }
00816 } else {
00817 c_inside++;
00818 }
00819
00820 }
00821
00822
00823
00824
00825
00826
00827
00828
00829 void FillOutside (node_t *headnode)
00830 {
00831 c_outside = 0;
00832 c_inside = 0;
00833 c_solid = 0;
00834 qprintf ("--- FillOutside ---\n");
00835 FillOutside_r (headnode);
00836 qprintf ("%5i solid leafs\n", c_solid);
00837 qprintf ("%5i leafs filled\n", c_outside);
00838 qprintf ("%5i inside leafs\n", c_inside);
00839 }
00840
00841
00842
00843