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 "l_mem.h"
00025
00026 int c_active_portals;
00027 int c_peak_portals;
00028 int c_boundary;
00029 int c_boundary_sides;
00030 int c_portalmemory;
00031
00032
00033
00034
00035
00036
00037
00038
00039 portal_t *AllocPortal (void)
00040 {
00041 portal_t *p;
00042
00043 p = GetMemory(sizeof(portal_t));
00044 memset (p, 0, sizeof(portal_t));
00045
00046 if (numthreads == 1)
00047 {
00048 c_active_portals++;
00049 if (c_active_portals > c_peak_portals)
00050 {
00051 c_peak_portals = c_active_portals;
00052 }
00053 c_portalmemory += MemorySize(p);
00054 }
00055
00056
00057
00058
00059 return p;
00060 }
00061
00062
00063
00064
00065
00066
00067 void FreePortal (portal_t *p)
00068 {
00069 if (p->winding) FreeWinding(p->winding);
00070 if (numthreads == 1)
00071 {
00072 c_active_portals--;
00073 c_portalmemory -= MemorySize(p);
00074 }
00075 FreeMemory(p);
00076 }
00077
00078
00079
00080
00081
00082
00083
00084
00085 int VisibleContents (int contents)
00086 {
00087 int i;
00088
00089 for (i=1 ; i<=LAST_VISIBLE_CONTENTS ; i<<=1)
00090 if (contents & i )
00091 return i;
00092
00093 return 0;
00094 }
00095
00096
00097
00098
00099
00100
00101 int ClusterContents (node_t *node)
00102 {
00103 int c1, c2, c;
00104
00105 if (node->planenum == PLANENUM_LEAF)
00106 return node->contents;
00107
00108 c1 = ClusterContents(node->children[0]);
00109 c2 = ClusterContents(node->children[1]);
00110 c = c1|c2;
00111
00112
00113
00114 if ( ! (c1&CONTENTS_SOLID) || ! (c2&CONTENTS_SOLID) )
00115 c &= ~CONTENTS_SOLID;
00116 return c;
00117 }
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129 qboolean Portal_VisFlood (portal_t *p)
00130 {
00131 int c1, c2;
00132
00133 if (!p->onnode)
00134 return false;
00135
00136 c1 = ClusterContents(p->nodes[0]);
00137 c2 = ClusterContents(p->nodes[1]);
00138
00139 if (!VisibleContents (c1^c2))
00140 return true;
00141
00142 if (c1 & (CONTENTS_Q2TRANSLUCENT|CONTENTS_DETAIL))
00143 c1 = 0;
00144 if (c2 & (CONTENTS_Q2TRANSLUCENT|CONTENTS_DETAIL))
00145 c2 = 0;
00146
00147 if ( (c1|c2) & CONTENTS_SOLID )
00148 return false;
00149
00150 if (! (c1 ^ c2))
00151 return true;
00152
00153 if (!VisibleContents (c1^c2))
00154 return true;
00155 return false;
00156 }
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166 qboolean Portal_EntityFlood (portal_t *p, int s)
00167 {
00168 if (p->nodes[0]->planenum != PLANENUM_LEAF
00169 || p->nodes[1]->planenum != PLANENUM_LEAF)
00170 Error ("Portal_EntityFlood: not a leaf");
00171
00172
00173 if ( (p->nodes[0]->contents & CONTENTS_SOLID)
00174 || (p->nodes[1]->contents & CONTENTS_SOLID) )
00175 return false;
00176
00177
00178 return true;
00179 }
00180
00181
00182
00183
00184 int c_tinyportals;
00185
00186
00187
00188
00189
00190
00191
00192 void AddPortalToNodes (portal_t *p, node_t *front, node_t *back)
00193 {
00194 if (p->nodes[0] || p->nodes[1])
00195 Error ("AddPortalToNode: allready included");
00196
00197 p->nodes[0] = front;
00198 p->next[0] = front->portals;
00199 front->portals = p;
00200
00201 p->nodes[1] = back;
00202 p->next[1] = back->portals;
00203 back->portals = p;
00204 }
00205
00206
00207
00208
00209
00210
00211 void RemovePortalFromNode (portal_t *portal, node_t *l)
00212 {
00213 portal_t **pp, *t;
00214
00215 int s, i, n;
00216 portal_t *p;
00217 portal_t *portals[4096];
00218
00219
00220 pp = &l->portals;
00221 while (1)
00222 {
00223 t = *pp;
00224 if (!t)
00225 Error ("RemovePortalFromNode: portal not in leaf");
00226
00227 if ( t == portal )
00228 break;
00229
00230 if (t->nodes[0] == l)
00231 pp = &t->next[0];
00232 else if (t->nodes[1] == l)
00233 pp = &t->next[1];
00234 else
00235 Error ("RemovePortalFromNode: portal not bounding leaf");
00236 }
00237
00238 if (portal->nodes[0] == l)
00239 {
00240 *pp = portal->next[0];
00241 portal->nodes[0] = NULL;
00242 }
00243 else if (portal->nodes[1] == l)
00244 {
00245 *pp = portal->next[1];
00246 portal->nodes[1] = NULL;
00247 }
00248 else
00249 {
00250 Error("RemovePortalFromNode: mislinked portal");
00251 }
00252
00253 n = 0;
00254 for (p = l->portals; p; p = p->next[s])
00255 {
00256 for (i = 0; i < n; i++)
00257 {
00258 if (p == portals[i]) Error("RemovePortalFromNode: circular linked\n");
00259 }
00260 if (p->nodes[0] != l && p->nodes[1] != l)
00261 {
00262 Error("RemovePortalFromNodes: portal does not belong to node\n");
00263 }
00264 portals[n] = p;
00265 s = (p->nodes[1] == l);
00266
00267 }
00268
00269 }
00270
00271
00272
00273
00274
00275
00276 void PrintPortal (portal_t *p)
00277 {
00278 int i;
00279 winding_t *w;
00280
00281 w = p->winding;
00282 for (i=0 ; i<w->numpoints ; i++)
00283 printf ("(%5.0f,%5.0f,%5.0f)\n",w->p[i][0]
00284 , w->p[i][1], w->p[i][2]);
00285 }
00286
00287
00288
00289
00290
00291
00292
00293 #define SIDESPACE 8
00294
00295 void MakeHeadnodePortals (tree_t *tree)
00296 {
00297 vec3_t bounds[2];
00298 int i, j, n;
00299 portal_t *p, *portals[6];
00300 plane_t bplanes[6], *pl;
00301 node_t *node;
00302
00303 node = tree->headnode;
00304
00305
00306 for (i=0 ; i<3 ; i++)
00307 {
00308 bounds[0][i] = tree->mins[i] - SIDESPACE;
00309 bounds[1][i] = tree->maxs[i] + SIDESPACE;
00310 if ( bounds[0][i] > bounds[1][i] ) {
00311 Error("empty BSP tree");
00312 }
00313 }
00314
00315 tree->outside_node.planenum = PLANENUM_LEAF;
00316 tree->outside_node.brushlist = NULL;
00317 tree->outside_node.portals = NULL;
00318 tree->outside_node.contents = 0;
00319
00320 for (i=0 ; i<3 ; i++)
00321 for (j=0 ; j<2 ; j++)
00322 {
00323 n = j*3 + i;
00324
00325 p = AllocPortal ();
00326 portals[n] = p;
00327
00328 pl = &bplanes[n];
00329 memset (pl, 0, sizeof(*pl));
00330 if (j)
00331 {
00332 pl->normal[i] = -1;
00333 pl->dist = -bounds[j][i];
00334 }
00335 else
00336 {
00337 pl->normal[i] = 1;
00338 pl->dist = bounds[j][i];
00339 }
00340 p->plane = *pl;
00341 p->winding = BaseWindingForPlane (pl->normal, pl->dist);
00342 AddPortalToNodes (p, node, &tree->outside_node);
00343 }
00344
00345
00346 for (i=0 ; i<6 ; i++)
00347 {
00348 for (j=0 ; j<6 ; j++)
00349 {
00350 if (j == i) continue;
00351 ChopWindingInPlace (&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON);
00352 }
00353 }
00354 }
00355
00356
00357
00358
00359
00360
00361 #define BASE_WINDING_EPSILON 0.001
00362 #define SPLIT_WINDING_EPSILON 0.001
00363
00364 winding_t *BaseWindingForNode (node_t *node)
00365 {
00366 winding_t *w;
00367 node_t *n;
00368 plane_t *plane;
00369 vec3_t normal;
00370 vec_t dist;
00371
00372 w = BaseWindingForPlane (mapplanes[node->planenum].normal
00373 , mapplanes[node->planenum].dist);
00374
00375
00376 for (n=node->parent ; n && w ; )
00377 {
00378 plane = &mapplanes[n->planenum];
00379
00380 if (n->children[0] == node)
00381 {
00382 ChopWindingInPlace (&w, plane->normal, plane->dist, BASE_WINDING_EPSILON);
00383 }
00384 else
00385 {
00386 VectorSubtract (vec3_origin, plane->normal, normal);
00387 dist = -plane->dist;
00388 ChopWindingInPlace (&w, normal, dist, BASE_WINDING_EPSILON);
00389 }
00390 node = n;
00391 n = n->parent;
00392 }
00393
00394 return w;
00395 }
00396
00397
00398
00399
00400
00401
00402
00403
00404 qboolean WindingIsTiny (winding_t *w);
00405
00406 void MakeNodePortal (node_t *node)
00407 {
00408 portal_t *new_portal, *p;
00409 winding_t *w;
00410 vec3_t normal;
00411 float dist;
00412 int side;
00413
00414 w = BaseWindingForNode (node);
00415
00416
00417 for (p = node->portals; p && w; p = p->next[side])
00418 {
00419 if (p->nodes[0] == node)
00420 {
00421 side = 0;
00422 VectorCopy (p->plane.normal, normal);
00423 dist = p->plane.dist;
00424 }
00425 else if (p->nodes[1] == node)
00426 {
00427 side = 1;
00428 VectorSubtract (vec3_origin, p->plane.normal, normal);
00429 dist = -p->plane.dist;
00430 }
00431 else
00432 {
00433 Error ("MakeNodePortal: mislinked portal");
00434 }
00435 ChopWindingInPlace (&w, normal, dist, 0.1);
00436 }
00437
00438 if (!w)
00439 {
00440 return;
00441 }
00442
00443 if (WindingIsTiny (w))
00444 {
00445 c_tinyportals++;
00446 FreeWinding(w);
00447 return;
00448 }
00449
00450 #ifdef DEBUG
00451
00452
00453
00454
00455
00456
00457
00458
00459 #endif //DEBUG
00460
00461
00462 new_portal = AllocPortal();
00463 new_portal->plane = mapplanes[node->planenum];
00464
00465 #ifdef ME
00466 new_portal->planenum = node->planenum;
00467 #endif //ME
00468
00469 new_portal->onnode = node;
00470 new_portal->winding = w;
00471 AddPortalToNodes (new_portal, node->children[0], node->children[1]);
00472 }
00473
00474
00475
00476
00477
00478
00479
00480
00481 void SplitNodePortals (node_t *node)
00482 {
00483 portal_t *p, *next_portal, *new_portal;
00484 node_t *f, *b, *other_node;
00485 int side;
00486 plane_t *plane;
00487 winding_t *frontwinding, *backwinding;
00488
00489 plane = &mapplanes[node->planenum];
00490 f = node->children[0];
00491 b = node->children[1];
00492
00493 for (p = node->portals ; p ; p = next_portal)
00494 {
00495 if (p->nodes[0] == node) side = 0;
00496 else if (p->nodes[1] == node) side = 1;
00497 else Error ("SplitNodePortals: mislinked portal");
00498 next_portal = p->next[side];
00499
00500 other_node = p->nodes[!side];
00501 RemovePortalFromNode (p, p->nodes[0]);
00502 RemovePortalFromNode (p, p->nodes[1]);
00503
00504
00505
00506
00507 ClipWindingEpsilon (p->winding, plane->normal, plane->dist,
00508 SPLIT_WINDING_EPSILON, &frontwinding, &backwinding);
00509
00510 if (frontwinding && WindingIsTiny(frontwinding))
00511 {
00512 FreeWinding (frontwinding);
00513 frontwinding = NULL;
00514 c_tinyportals++;
00515 }
00516
00517 if (backwinding && WindingIsTiny(backwinding))
00518 {
00519 FreeWinding (backwinding);
00520 backwinding = NULL;
00521 c_tinyportals++;
00522 }
00523
00524 #ifdef DEBUG
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539 #endif //DEBUG
00540
00541 if (!frontwinding && !backwinding)
00542 {
00543 continue;
00544 }
00545
00546 if (!frontwinding)
00547 {
00548 FreeWinding (backwinding);
00549 if (side == 0) AddPortalToNodes (p, b, other_node);
00550 else AddPortalToNodes (p, other_node, b);
00551 continue;
00552 }
00553 if (!backwinding)
00554 {
00555 FreeWinding (frontwinding);
00556 if (side == 0) AddPortalToNodes (p, f, other_node);
00557 else AddPortalToNodes (p, other_node, f);
00558 continue;
00559 }
00560
00561
00562 new_portal = AllocPortal();
00563 *new_portal = *p;
00564 new_portal->winding = backwinding;
00565 FreeWinding (p->winding);
00566 p->winding = frontwinding;
00567
00568 if (side == 0)
00569 {
00570 AddPortalToNodes (p, f, other_node);
00571 AddPortalToNodes (new_portal, b, other_node);
00572 }
00573 else
00574 {
00575 AddPortalToNodes (p, other_node, f);
00576 AddPortalToNodes (new_portal, other_node, b);
00577 }
00578 }
00579
00580 node->portals = NULL;
00581 }
00582
00583
00584
00585
00586
00587
00588 void CalcNodeBounds (node_t *node)
00589 {
00590 portal_t *p;
00591 int s;
00592 int i;
00593
00594
00595 ClearBounds (node->mins, node->maxs);
00596 for (p = node->portals ; p ; p = p->next[s])
00597 {
00598 s = (p->nodes[1] == node);
00599 for (i=0 ; i<p->winding->numpoints ; i++)
00600 AddPointToBounds (p->winding->p[i], node->mins, node->maxs);
00601 }
00602 }
00603
00604
00605
00606
00607
00608
00609 int c_numportalizednodes;
00610
00611 void MakeTreePortals_r (node_t *node)
00612 {
00613 int i;
00614
00615 #ifdef ME
00616 qprintf("\r%6d", ++c_numportalizednodes);
00617 if (cancelconversion) return;
00618 #endif //ME
00619
00620 CalcNodeBounds (node);
00621 if (node->mins[0] >= node->maxs[0])
00622 {
00623 Log_Print("WARNING: node without a volume\n");
00624 }
00625
00626 for (i=0 ; i<3 ; i++)
00627 {
00628 if (node->mins[i] < -MAX_MAP_BOUNDS || node->maxs[i] > MAX_MAP_BOUNDS)
00629 {
00630 Log_Print("WARNING: node with unbounded volume\n");
00631 break;
00632 }
00633 }
00634 if (node->planenum == PLANENUM_LEAF)
00635 return;
00636
00637 MakeNodePortal (node);
00638 SplitNodePortals (node);
00639
00640 MakeTreePortals_r (node->children[0]);
00641 MakeTreePortals_r (node->children[1]);
00642 }
00643
00644
00645
00646
00647
00648
00649 void MakeTreePortals(tree_t *tree)
00650 {
00651
00652 #ifdef ME
00653 Log_Print("---- Node Portalization ----\n");
00654 c_numportalizednodes = 0;
00655 c_portalmemory = 0;
00656 qprintf("%6d nodes portalized", c_numportalizednodes);
00657 #endif //ME
00658
00659 MakeHeadnodePortals(tree);
00660 MakeTreePortals_r(tree->headnode);
00661
00662 #ifdef ME
00663 qprintf("\n");
00664 Log_Write("%6d nodes portalized\r\n", c_numportalizednodes);
00665 Log_Print("%6d tiny portals\r\n", c_tinyportals);
00666 Log_Print("%6d KB of portal memory\r\n", c_portalmemory >> 10);
00667 Log_Print("%6i KB of winding memory\r\n", WindingMemory() >> 10);
00668 #endif //ME
00669 }
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680 node_t *p_firstnode;
00681 node_t *p_lastnode;
00682
00683
00684
00685
00686
00687
00688
00689 #ifdef P_NODESTACK
00690 void P_AddNodeToList(node_t *node)
00691 {
00692 node->next = p_firstnode;
00693 p_firstnode = node;
00694 if (!p_lastnode) p_lastnode = node;
00695 }
00696 #else //it's a node queue
00697
00698 void P_AddNodeToList(node_t *node)
00699 {
00700 node->next = NULL;
00701 if (p_lastnode) p_lastnode->next = node;
00702 else p_firstnode = node;
00703 p_lastnode = node;
00704 }
00705 #endif //P_NODESTACK
00706
00707
00708
00709
00710
00711
00712
00713 node_t *P_NextNodeFromList(void)
00714 {
00715 node_t *node;
00716
00717 node = p_firstnode;
00718 if (p_firstnode) p_firstnode = p_firstnode->next;
00719 if (!p_firstnode) p_lastnode = NULL;
00720 return node;
00721 }
00722
00723
00724
00725
00726
00727
00728 void FloodPortals(node_t *firstnode)
00729 {
00730 node_t *node;
00731 portal_t *p;
00732 int s;
00733
00734 firstnode->occupied = 1;
00735 P_AddNodeToList(firstnode);
00736
00737 for (node = P_NextNodeFromList(); node; node = P_NextNodeFromList())
00738 {
00739 for (p = node->portals; p; p = p->next[s])
00740 {
00741 s = (p->nodes[1] == node);
00742
00743 if (p->nodes[!s]->occupied) continue;
00744
00745 if (!Portal_EntityFlood(p, s)) continue;
00746
00747 p->nodes[!s]->occupied = node->occupied + 1;
00748
00749 P_AddNodeToList(p->nodes[!s]);
00750 }
00751 }
00752 }
00753
00754
00755
00756
00757
00758
00759 int numrec;
00760
00761 void FloodPortals_r (node_t *node, int dist)
00762 {
00763 portal_t *p;
00764 int s;
00765
00766
00767 Log_Print("\r%6d", ++numrec);
00768
00769 if (node->occupied) Error("FloodPortals_r: node already occupied\n");
00770 if (!node)
00771 {
00772 Error("FloodPortals_r: NULL node\n");
00773 }
00774 node->occupied = dist;
00775
00776 for (p = node->portals; p; p = p->next[s])
00777 {
00778 s = (p->nodes[1] == node);
00779
00780 if (p->nodes[!s]->occupied) continue;
00781
00782 if (!Portal_EntityFlood(p, s)) continue;
00783
00784 FloodPortals_r(p->nodes[!s], dist+1);
00785 }
00786 Log_Print("\r%6d", --numrec);
00787 }
00788
00789
00790
00791
00792
00793
00794 qboolean PlaceOccupant (node_t *headnode, vec3_t origin, entity_t *occupant)
00795 {
00796 node_t *node;
00797 vec_t d;
00798 plane_t *plane;
00799
00800
00801 node = headnode;
00802 while(node->planenum != PLANENUM_LEAF)
00803 {
00804 if (node->planenum < 0 || node->planenum > nummapplanes)
00805 {
00806 Error("PlaceOccupant: invalid node->planenum\n");
00807 }
00808 plane = &mapplanes[node->planenum];
00809 d = DotProduct(origin, plane->normal) - plane->dist;
00810 if (d >= 0) node = node->children[0];
00811 else node = node->children[1];
00812 if (!node)
00813 {
00814 Error("PlaceOccupant: invalid child %d\n", d < 0);
00815 }
00816 }
00817
00818
00819
00820
00821 if (node->contents & CONTENTS_SOLID) return false;
00822
00823 if (node->occupied) return false;
00824
00825
00826 node->occupant = occupant;
00827
00828 numrec = 0;
00829
00830
00831
00832 FloodPortals(node);
00833
00834 return true;
00835 }
00836
00837
00838
00839
00840
00841
00842
00843 qboolean FloodEntities (tree_t *tree)
00844 {
00845 int i;
00846 int x, y;
00847 vec3_t origin;
00848 char *cl;
00849 qboolean inside;
00850 node_t *headnode;
00851
00852 headnode = tree->headnode;
00853 Log_Print("------ FloodEntities -------\n");
00854 inside = false;
00855 tree->outside_node.occupied = 0;
00856
00857
00858 for (i = 1; i < num_entities; i++)
00859 {
00860 GetVectorForKey(&entities[i], "origin", origin);
00861 if (VectorCompare(origin, vec3_origin)) continue;
00862
00863 cl = ValueForKey(&entities[i], "classname");
00864 origin[2] += 1;
00865
00866
00867
00868
00869 if (!strcmp(cl, "info_player_start"))
00870 {
00871 for (x = -16; x <= 16; x += 16)
00872 {
00873 for (y = -16; y <= 16; y += 16)
00874 {
00875 origin[0] += x;
00876 origin[1] += y;
00877 if (PlaceOccupant(headnode, origin, &entities[i]))
00878 {
00879 inside = true;
00880 x = 999;
00881 break;
00882 }
00883 origin[0] -= x;
00884 origin[1] -= y;
00885 }
00886 }
00887 }
00888 else
00889 {
00890 if (PlaceOccupant(headnode, origin, &entities[i]))
00891 {
00892 inside = true;
00893 }
00894 }
00895 }
00896
00897 if (!inside)
00898 {
00899 Log_Print("WARNING: no entities inside\n");
00900 }
00901 else if (tree->outside_node.occupied)
00902 {
00903 Log_Print("WARNING: entity reached from outside\n");
00904 }
00905
00906 return (qboolean)(inside && !tree->outside_node.occupied);
00907 }
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917 int c_outside;
00918 int c_inside;
00919 int c_solid;
00920
00921
00922
00923
00924
00925
00926
00927 void FillOutside_r (node_t *node)
00928 {
00929 if (node->planenum != PLANENUM_LEAF)
00930 {
00931 FillOutside_r (node->children[0]);
00932 FillOutside_r (node->children[1]);
00933 return;
00934 }
00935
00936
00937 if (!node->occupied)
00938 {
00939 if (!(node->contents & CONTENTS_SOLID))
00940 {
00941 c_outside++;
00942 node->contents |= CONTENTS_SOLID;
00943 }
00944 else
00945 {
00946 c_solid++;
00947 }
00948 }
00949 else
00950 {
00951 c_inside++;
00952 }
00953 }
00954
00955
00956
00957
00958
00959
00960
00961 void FillOutside (node_t *headnode)
00962 {
00963 c_outside = 0;
00964 c_inside = 0;
00965 c_solid = 0;
00966 Log_Print("------- FillOutside --------\n");
00967 FillOutside_r (headnode);
00968 Log_Print("%5i solid leaves\n", c_solid);
00969 Log_Print("%5i leaves filled\n", c_outside);
00970 Log_Print("%5i inside leaves\n", c_inside);
00971 }
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981 int c_areas;
00982
00983
00984
00985
00986
00987
00988
00989 void FloodAreas_r (node_t *node)
00990 {
00991 portal_t *p;
00992 int s;
00993 bspbrush_t *b;
00994 entity_t *e;
00995
00996 if (node->contents == CONTENTS_AREAPORTAL)
00997 {
00998
00999 b = node->brushlist;
01000 e = &entities[b->original->entitynum];
01001
01002
01003
01004 if (e->portalareas[0] == c_areas || e->portalareas[1] == c_areas)
01005 return;
01006
01007
01008 if (e->portalareas[1])
01009 {
01010 Log_Print("WARNING: areaportal entity %i touches > 2 areas\n", b->original->entitynum);
01011 return;
01012 }
01013 if (e->portalareas[0])
01014 e->portalareas[1] = c_areas;
01015 else
01016 e->portalareas[0] = c_areas;
01017
01018 return;
01019 }
01020
01021 if (node->area)
01022 return;
01023 node->area = c_areas;
01024
01025 for (p=node->portals ; p ; p = p->next[s])
01026 {
01027 s = (p->nodes[1] == node);
01028 #if 0
01029 if (p->nodes[!s]->occupied)
01030 continue;
01031 #endif
01032 if (!Portal_EntityFlood (p, s))
01033 continue;
01034
01035 FloodAreas_r (p->nodes[!s]);
01036 }
01037 }
01038
01039
01040
01041
01042
01043
01044
01045
01046 void FindAreas_r (node_t *node)
01047 {
01048 if (node->planenum != PLANENUM_LEAF)
01049 {
01050 FindAreas_r (node->children[0]);
01051 FindAreas_r (node->children[1]);
01052 return;
01053 }
01054
01055 if (node->area)
01056 return;
01057
01058 if (node->contents & CONTENTS_SOLID)
01059 return;
01060
01061 if (!node->occupied)
01062 return;
01063
01064
01065
01066 if (node->contents == CONTENTS_AREAPORTAL)
01067 return;
01068
01069 c_areas++;
01070 FloodAreas_r (node);
01071 }
01072
01073
01074
01075
01076
01077
01078
01079
01080 void SetAreaPortalAreas_r (node_t *node)
01081 {
01082 bspbrush_t *b;
01083 entity_t *e;
01084
01085 if (node->planenum != PLANENUM_LEAF)
01086 {
01087 SetAreaPortalAreas_r (node->children[0]);
01088 SetAreaPortalAreas_r (node->children[1]);
01089 return;
01090 }
01091
01092 if (node->contents == CONTENTS_AREAPORTAL)
01093 {
01094 if (node->area)
01095 return;
01096
01097 b = node->brushlist;
01098 e = &entities[b->original->entitynum];
01099 node->area = e->portalareas[0];
01100 if (!e->portalareas[1])
01101 {
01102 Log_Print("WARNING: areaportal entity %i doesn't touch two areas\n", b->original->entitynum);
01103 return;
01104 }
01105 }
01106 }
01107
01108
01109
01110
01111
01112
01113
01114
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161 void FloodAreas (tree_t *tree)
01162 {
01163 Log_Print("--- FloodAreas ---\n");
01164 FindAreas_r (tree->headnode);
01165 SetAreaPortalAreas_r (tree->headnode);
01166 Log_Print("%5i areas\n", c_areas);
01167 }
01168
01169
01170
01171
01172
01173
01174
01175 void FindPortalSide (portal_t *p)
01176 {
01177 int viscontents;
01178 bspbrush_t *bb;
01179 mapbrush_t *brush;
01180 node_t *n;
01181 int i,j;
01182 int planenum;
01183 side_t *side, *bestside;
01184 float dot, bestdot;
01185 plane_t *p1, *p2;
01186
01187
01188
01189 viscontents = VisibleContents (p->nodes[0]->contents ^ p->nodes[1]->contents);
01190 if (!viscontents)
01191 return;
01192
01193 planenum = p->onnode->planenum;
01194 bestside = NULL;
01195 bestdot = 0;
01196
01197 for (j=0 ; j<2 ; j++)
01198 {
01199 n = p->nodes[j];
01200 p1 = &mapplanes[p->onnode->planenum];
01201 for (bb=n->brushlist ; bb ; bb=bb->next)
01202 {
01203 brush = bb->original;
01204 if ( !(brush->contents & viscontents) )
01205 continue;
01206 for (i=0 ; i<brush->numsides ; i++)
01207 {
01208 side = &brush->original_sides[i];
01209 if (side->flags & SFL_BEVEL)
01210 continue;
01211 if (side->texinfo == TEXINFO_NODE)
01212 continue;
01213 if ((side->planenum&~1) == planenum)
01214 {
01215 bestside = &brush->original_sides[i];
01216 goto gotit;
01217 }
01218
01219 p2 = &mapplanes[side->planenum&~1];
01220 dot = DotProduct (p1->normal, p2->normal);
01221 if (dot > bestdot)
01222 {
01223 bestdot = dot;
01224 bestside = side;
01225 }
01226 }
01227 }
01228 }
01229
01230 gotit:
01231 if (!bestside)
01232 Log_Print("WARNING: side not found for portal\n");
01233
01234 p->sidefound = true;
01235 p->side = bestside;
01236 }
01237
01238
01239
01240
01241
01242
01243 void MarkVisibleSides_r (node_t *node)
01244 {
01245 portal_t *p;
01246 int s;
01247
01248 if (node->planenum != PLANENUM_LEAF)
01249 {
01250 MarkVisibleSides_r (node->children[0]);
01251 MarkVisibleSides_r (node->children[1]);
01252 return;
01253 }
01254
01255
01256 if (!node->contents) return;
01257
01258
01259 for (p=node->portals ; p ; p = p->next[!s])
01260 {
01261 s = (p->nodes[0] == node);
01262 if (!p->onnode)
01263 continue;
01264 if (!p->sidefound)
01265 FindPortalSide (p);
01266 if (p->side)
01267 p->side->flags |= SFL_VISIBLE;
01268 }
01269 }
01270
01271
01272
01273
01274
01275
01276 void MarkVisibleSides(tree_t *tree, int startbrush, int endbrush)
01277 {
01278 int i, j;
01279 mapbrush_t *mb;
01280 int numsides;
01281
01282 Log_Print("--- MarkVisibleSides ---\n");
01283
01284
01285 for (i=startbrush ; i<endbrush ; i++)
01286 {
01287 mb = &mapbrushes[i];
01288
01289 numsides = mb->numsides;
01290 for (j=0 ; j<numsides ; j++)
01291 mb->original_sides[j].flags &= ~SFL_VISIBLE;
01292 }
01293
01294
01295 MarkVisibleSides_r (tree->headnode);
01296 }
01297