00001
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "bsp.h"
00030
00031
00032 static int c_active_portals = 0;
00033 static int c_peak_portals = 0;
00034 static int c_tinyportals = 0;
00035
00039 static portal_t *AllocPortal (void)
00040 {
00041 if (threadstate.numthreads == 1)
00042 c_active_portals++;
00043 if (c_active_portals > c_peak_portals)
00044 c_peak_portals = c_active_portals;
00045
00046 return Mem_Alloc(sizeof(portal_t));
00047 }
00048
00052 void FreePortal (portal_t *p)
00053 {
00054 if (p->winding)
00055 FreeWinding(p->winding);
00056 if (threadstate.numthreads == 1)
00057 c_active_portals--;
00058 Mem_Free(p);
00059 }
00060
00064 int VisibleContents (int contentFlags)
00065 {
00066 int i;
00067
00068 for (i = 1; i <= LAST_VISIBLE_CONTENTS; i <<= 1)
00069 if (contentFlags & i)
00070 return i;
00071
00072 return 0;
00073 }
00074
00082 static void AddPortalToNodes (portal_t *p, node_t *front, node_t *back)
00083 {
00084 if (p->nodes[0] || p->nodes[1])
00085 Sys_Error("AddPortalToNodes: already included");
00086
00087 p->nodes[0] = front;
00088 p->next[0] = front->portals;
00089 front->portals = p;
00090
00091 p->nodes[1] = back;
00092 p->next[1] = back->portals;
00093 back->portals = p;
00094 }
00095
00102 void RemovePortalFromNode (portal_t *portal, node_t *l)
00103 {
00104 portal_t **pp;
00105
00106
00107 pp = &l->portals;
00108 while (1) {
00109 portal_t *t = *pp;
00110 if (!t)
00111 Sys_Error("RemovePortalFromNode: portal not in leaf");
00112
00113 if (t == portal)
00114 break;
00115
00116 if (t->nodes[0] == l)
00117 pp = &t->next[0];
00118 else if (t->nodes[1] == l)
00119 pp = &t->next[1];
00120 else
00121 Sys_Error("RemovePortalFromNode: portal not bounding leaf");
00122 }
00123
00124 if (portal->nodes[0] == l) {
00125 *pp = portal->next[0];
00126 portal->nodes[0] = NULL;
00127 } else if (portal->nodes[1] == l) {
00128 *pp = portal->next[1];
00129 portal->nodes[1] = NULL;
00130 }
00131 }
00132
00133 #define SIDESPACE 8
00134
00137 static void MakeHeadnodePortals (tree_t *tree)
00138 {
00139 vec3_t bounds[2];
00140 int i, j;
00141 portal_t *portals[6];
00142 plane_t bplanes[6];
00143 node_t *node;
00144
00145 node = tree->headnode;
00146
00147
00148 for (i = 0; i < 3; i++) {
00149 bounds[0][i] = tree->mins[i] - SIDESPACE;
00150 bounds[1][i] = tree->maxs[i] + SIDESPACE;
00151 }
00152
00153 tree->outside_node.planenum = PLANENUM_LEAF;
00154 tree->outside_node.brushlist = NULL;
00155 tree->outside_node.portals = NULL;
00156 tree->outside_node.contentFlags = 0;
00157
00158 for (i = 0; i < 3; i++)
00159 for (j = 0; j < 2; j++) {
00160 const int n = j * 3 + i;
00161 portal_t *p = AllocPortal();
00162 plane_t *pl = &bplanes[n];
00163
00164 memset(pl, 0, sizeof(*pl));
00165 portals[n] = p;
00166
00167 if (j) {
00168 pl->normal[i] = -1;
00169 pl->dist = -bounds[j][i];
00170 } else {
00171 pl->normal[i] = 1;
00172 pl->dist = bounds[j][i];
00173 }
00174 p->plane = *pl;
00175 p->winding = BaseWindingForPlane(pl->normal, pl->dist);
00176 AddPortalToNodes(p, node, &tree->outside_node);
00177 }
00178
00179
00180 for (i = 0; i < 6; i++) {
00181 for (j = 0; j < 6; j++) {
00182 if (j == i)
00183 continue;
00184 ChopWindingInPlace(&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON);
00185 }
00186 }
00187 }
00188
00189 #define BASE_WINDING_EPSILON 0.001
00190 #define SPLIT_WINDING_EPSILON 0.001
00191
00192 static winding_t *BaseWindingForNode (node_t *node)
00193 {
00194 node_t *n;
00195 winding_t *w;
00196
00197 w = BaseWindingForPlane(mapplanes[node->planenum].normal
00198 , mapplanes[node->planenum].dist);
00199
00200
00201 for (n = node->parent; n && w;) {
00202 const plane_t *plane = &mapplanes[n->planenum];
00203
00204 if (n->children[0] == node) {
00205 ChopWindingInPlace(&w, plane->normal, plane->dist, BASE_WINDING_EPSILON);
00206 } else {
00207 const vec_t dist = -plane->dist;
00208 vec3_t normal;
00209 VectorSubtract(vec3_origin, plane->normal, normal);
00210 ChopWindingInPlace(&w, normal, dist, BASE_WINDING_EPSILON);
00211 }
00212 node = n;
00213 n = n->parent;
00214 }
00215
00216 return w;
00217 }
00218
00219
00220
00225 static void MakeNodePortal (node_t *node)
00226 {
00227 portal_t *new_portal, *p;
00228 winding_t *w;
00229 vec3_t normal;
00230 float dist = 0.0f;
00231 int side = 0;
00232
00233 w = BaseWindingForNode(node);
00234
00235
00236 for (p = node->portals; p && w; p = p->next[side]) {
00237 if (p->nodes[0] == node) {
00238 side = 0;
00239 VectorCopy(p->plane.normal, normal);
00240 dist = p->plane.dist;
00241 } else if (p->nodes[1] == node) {
00242 side = 1;
00243 VectorSubtract(vec3_origin, p->plane.normal, normal);
00244 dist = -p->plane.dist;
00245 } else
00246 Sys_Error("CutNodePortals_r: mislinked portal");
00247
00248 ChopWindingInPlace(&w, normal, dist, 0.1);
00249 }
00250
00251 if (!w)
00252 return;
00253
00254 if (WindingIsTiny(w)) {
00255 c_tinyportals++;
00256 FreeWinding(w);
00257 return;
00258 }
00259
00260 new_portal = AllocPortal();
00261 new_portal->plane = mapplanes[node->planenum];
00262 new_portal->onnode = node;
00263 new_portal->winding = w;
00264 AddPortalToNodes(new_portal, node->children[0], node->children[1]);
00265 }
00266
00267
00272 static void SplitNodePortals (node_t *node)
00273 {
00274 portal_t *p, *next_portal, *new_portal;
00275 node_t *f, *b, *other_node;
00276 int side = 0;
00277 plane_t *plane;
00278 winding_t *frontwinding, *backwinding;
00279
00280 plane = &mapplanes[node->planenum];
00281 f = node->children[0];
00282 b = node->children[1];
00283
00284 for (p = node->portals; p; p = next_portal) {
00285 if (p->nodes[0] == node)
00286 side = 0;
00287 else if (p->nodes[1] == node)
00288 side = 1;
00289 else
00290 Sys_Error("CutNodePortals_r: mislinked portal");
00291 next_portal = p->next[side];
00292
00293 other_node = p->nodes[!side];
00294 RemovePortalFromNode(p, p->nodes[0]);
00295 RemovePortalFromNode(p, p->nodes[1]);
00296
00297
00298 ClipWindingEpsilon(p->winding, plane->normal, plane->dist,
00299 SPLIT_WINDING_EPSILON, &frontwinding, &backwinding);
00300
00301 if (frontwinding && WindingIsTiny(frontwinding)) {
00302 FreeWinding(frontwinding);
00303 frontwinding = NULL;
00304 c_tinyportals++;
00305 }
00306
00307 if (backwinding && WindingIsTiny(backwinding)) {
00308 FreeWinding(backwinding);
00309 backwinding = NULL;
00310 c_tinyportals++;
00311 }
00312
00313 if (!frontwinding && !backwinding) {
00314 continue;
00315 }
00316
00317 if (!frontwinding) {
00318 FreeWinding(backwinding);
00319 if (side == 0)
00320 AddPortalToNodes(p, b, other_node);
00321 else
00322 AddPortalToNodes(p, other_node, b);
00323 continue;
00324 }
00325 if (!backwinding) {
00326 FreeWinding(frontwinding);
00327 if (side == 0)
00328 AddPortalToNodes(p, f, other_node);
00329 else
00330 AddPortalToNodes(p, other_node, f);
00331 continue;
00332 }
00333
00334
00335 new_portal = AllocPortal();
00336 *new_portal = *p;
00337 new_portal->winding = backwinding;
00338 FreeWinding(p->winding);
00339 p->winding = frontwinding;
00340
00341 if (side == 0) {
00342 AddPortalToNodes(p, f, other_node);
00343 AddPortalToNodes(new_portal, b, other_node);
00344 } else {
00345 AddPortalToNodes(p, other_node, f);
00346 AddPortalToNodes(new_portal, other_node, b);
00347 }
00348 }
00349
00350 node->portals = NULL;
00351 }
00352
00353
00354 static void CalcNodeBounds (node_t *node)
00355 {
00356 portal_t *p;
00357 int s, i;
00358
00359
00360 ClearBounds(node->mins, node->maxs);
00361 for (p = node->portals; p; p = p->next[s]) {
00362 s = (p->nodes[1] == node);
00363 if (!p->winding)
00364 continue;
00365 for (i = 0; i < p->winding->numpoints; i++)
00366 AddPointToBounds(p->winding->p[i], node->mins, node->maxs);
00367 }
00368 }
00369
00370
00371 static void MakeTreePortals_r (node_t *node)
00372 {
00373 int i;
00374
00375 CalcNodeBounds(node);
00376 if (node->mins[0] >= node->maxs[0]) {
00377 Com_Printf("WARNING: node without a volume\n");
00378 }
00379
00380 for (i = 0; i < 3; i++) {
00381 if (node->mins[i] < -MAX_WORLD_WIDTH || node->maxs[i] > MAX_WORLD_WIDTH) {
00382 Com_Printf("WARNING: node with unbounded volume %i\n", (int)node->mins[i]);
00383 break;
00384 }
00385 }
00386 if (node->planenum == PLANENUM_LEAF)
00387 return;
00388
00389 MakeNodePortal(node);
00390 SplitNodePortals(node);
00391
00392 MakeTreePortals_r(node->children[0]);
00393 MakeTreePortals_r(node->children[1]);
00394 }
00395
00396 void MakeTreePortals (tree_t *tree)
00397 {
00398 MakeHeadnodePortals(tree);
00399 MakeTreePortals_r(tree->headnode);
00400 }
00401
00405 static void FindPortalSide (portal_t *p)
00406 {
00407 int viscontents;
00408 bspbrush_t *bb;
00409 int i, j, planenum;
00410 side_t *bestside;
00411 float bestdot;
00412
00413
00414
00415 viscontents = VisibleContents(p->nodes[0]->contentFlags ^ p->nodes[1]->contentFlags);
00416 if (!viscontents)
00417 return;
00418
00419 planenum = p->onnode->planenum;
00420 bestside = NULL;
00421 bestdot = 0;
00422
00423 for (j = 0; j < 2; j++) {
00424 const node_t *n = p->nodes[j];
00425 const plane_t *p1 = &mapplanes[p->onnode->planenum];
00426 for (bb = n->brushlist; bb; bb = bb->next) {
00427 const mapbrush_t *brush = bb->original;
00428
00429 if (!(brush->contentFlags & viscontents))
00430 continue;
00431 for (i = 0; i < brush->numsides; i++) {
00432 side_t *side = &brush->original_sides[i];
00433 float dot;
00434 plane_t *p2;
00435
00436 if (side->bevel)
00437 continue;
00438 if (side->texinfo == TEXINFO_NODE)
00439 continue;
00440 if ((side->planenum &~ 1) == planenum) {
00441 bestside = &brush->original_sides[i];
00442 goto gotit;
00443 }
00444
00445 p2 = &mapplanes[side->planenum &~ 1];
00446 dot = DotProduct(p1->normal, p2->normal);
00447 if (dot > bestdot) {
00448 bestdot = dot;
00449 bestside = side;
00450 }
00451 }
00452 }
00453 }
00454
00455 gotit:
00456 if (!bestside)
00457 Verb_Printf(VERB_EXTRA, "WARNING: side not found for portal\n");
00458
00459 p->sidefound = qtrue;
00460 p->side = bestside;
00461 }
00462
00463
00464 static void MarkVisibleSides_r (node_t *node)
00465 {
00466 portal_t *p;
00467 int s;
00468
00469 if (node->planenum != PLANENUM_LEAF) {
00470 MarkVisibleSides_r(node->children[0]);
00471 MarkVisibleSides_r(node->children[1]);
00472 return;
00473 }
00474
00475
00476 if (!node->contentFlags)
00477 return;
00478
00479
00480 for (p = node->portals; p; p = p->next[!s]) {
00481 s = (p->nodes[0] == node);
00482 if (!p->onnode)
00483 continue;
00484 if (!p->sidefound)
00485 FindPortalSide(p);
00486 if (p->side)
00487 p->side->visible = qtrue;
00488 }
00489 }
00490
00491 void MarkVisibleSides (tree_t *tree, int startbrush, int endbrush)
00492 {
00493 int i;
00494
00495 Verb_Printf(VERB_EXTRA, "--- MarkVisibleSides ---\n");
00496
00497
00498 for (i = startbrush; i < endbrush; i++) {
00499 mapbrush_t *mb = &mapbrushes[i];
00500 const int numsides = mb->numsides;
00501 int j;
00502
00503 for (j = 0; j < numsides; j++)
00504 mb->original_sides[j].visible = qfalse;
00505 }
00506
00507
00508 MarkVisibleSides_r(tree->headnode);
00509 }