UFO: Alien Invasion
Loading...
Searching...
No Matches
portals.cpp
Go to the documentation of this file.
1
7
8/*
9Copyright (C) 1997-2001 Id Software, Inc.
10
11This program is free software; you can redistribute it and/or
12modify it under the terms of the GNU General Public License
13as published by the Free Software Foundation; either version 2
14of the License, or (at your option) any later version.
15
16This program is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19
20See the GNU General Public License for more details.
21
22You should have received a copy of the GNU General Public License
23along with this program; if not, write to the Free Software
24Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25
26*/
27
28
29#include "bsp.h"
30
31
32static int c_active_portals = 0;
33static int c_peak_portals = 0;
34static int c_tinyportals = 0;
35
39static portal_t* AllocPortal (void)
40{
41 if (threadstate.numthreads == 1)
45
46 return Mem_AllocType(portal_t);
47}
48
53{
54 if (p->winding)
56 if (threadstate.numthreads == 1)
58 Mem_Free(p);
59}
60
64uint32_t VisibleContents (uint32_t contentFlags)
65{
66 uint32_t i;
67
68 for (i = 1; i <= LAST_VISIBLE_CONTENTS; i <<= 1)
69 if (contentFlags & i)
70 return i;
71
72 return 0;
73}
74
82static void AddPortalToNodes (portal_t* p, node_t* front, node_t* back)
83{
84 if (p->nodes[0] || p->nodes[1])
85 Sys_Error("AddPortalToNodes: already included");
86
87 p->nodes[0] = front;
88 p->next[0] = front->portals;
89 front->portals = p;
90
91 p->nodes[1] = back;
92 p->next[1] = back->portals;
93 back->portals = p;
94}
95
103{
104 portal_t** pp;
105
106 /* remove reference to the current portal */
107 pp = &l->portals;
108 while (1) {
109 portal_t* t = *pp;
110 if (!t)
111 Sys_Error("RemovePortalFromNode: portal not in leaf");
112
113 if (t == portal)
114 break;
115
116 if (t->nodes[0] == l)
117 pp = &t->next[0];
118 else if (t->nodes[1] == l)
119 pp = &t->next[1];
120 else
121 Sys_Error("RemovePortalFromNode: portal not bounding leaf");
122 }
123
124 if (portal->nodes[0] == l) {
125 *pp = portal->next[0];
126 portal->nodes[0] = nullptr;
127 } else if (portal->nodes[1] == l) {
128 *pp = portal->next[1];
129 portal->nodes[1] = nullptr;
130 }
131}
132
133#define SIDESPACE 8
137static void MakeHeadnodePortals (tree_t* tree)
138{
139 vec3_t bounds[2];
140 int i, j;
141 portal_t* portals[6];
142 plane_t bplanes[6];
143 node_t* node = tree->headnode;
144
145 /* pad with some space so there will never be null volume leafs */
146 for (i = 0; i < 3; i++) {
147 bounds[0][i] = tree->aabb.mins[i] - SIDESPACE;
148 bounds[1][i] = tree->aabb.maxs[i] + SIDESPACE;
149 }
150
151 tree->outside_node.planenum = PLANENUM_LEAF;
152 tree->outside_node.brushlist = nullptr;
153 tree->outside_node.portals = nullptr;
154 tree->outside_node.contentFlags = 0;
155
156 for (i = 0; i < 3; i++)
157 for (j = 0; j < 2; j++) {
158 const int n = j * 3 + i;
159 portal_t* p = AllocPortal();
160 plane_t* pl = &bplanes[n];
161
162 OBJZERO(*pl);
163 portals[n] = p;
164
165 if (j) {
166 pl->normal[i] = -1;
167 pl->dist = -bounds[j][i];
168 } else {
169 pl->normal[i] = 1;
170 pl->dist = bounds[j][i];
171 }
172 p->plane = *pl;
173 p->winding = BaseWindingForPlane(pl->normal, pl->dist);
174 AddPortalToNodes(p, node, &tree->outside_node);
175 }
176
177 /* clip the basewindings by all the other planes */
178 for (i = 0; i < 6; i++) {
179 for (j = 0; j < 6; j++) {
180 if (j == i)
181 continue;
182 ChopWindingInPlace(&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON);
183 }
184 }
185}
186
187#define BASE_WINDING_EPSILON 0.001
188#define SPLIT_WINDING_EPSILON 0.001
189
191{
192 node_t* n;
193 winding_t* w;
194
195 w = BaseWindingForPlane(mapplanes[node->planenum].normal
196 , mapplanes[node->planenum].dist);
197
198 /* clip by all the parents */
199 for (n = node->parent; n && w;) {
200 const plane_t* plane = &mapplanes[n->planenum];
201
202 if (n->children[0] == node) { /* take front */
204 } else { /* take back */
205 const vec_t dist = -plane->dist;
206 vec3_t normal;
207 VectorSubtract(vec3_origin, plane->normal, normal);
208 ChopWindingInPlace(&w, normal, dist, BASE_WINDING_EPSILON);
209 }
210 node = n;
211 n = n->parent;
212 }
213
214 return w;
215}
216
217/*============================================================ */
218
223static void MakeNodePortal (node_t* node)
224{
225 portal_t* new_portal, *p;
226 winding_t* w;
227 vec3_t normal;
228 float dist = 0.0f;
229 int side = 0;
230
231 w = BaseWindingForNode(node);
232
233 /* clip the portal by all the other portals in the node */
234 for (p = node->portals; p && w; p = p->next[side]) {
235 if (p->nodes[0] == node) {
236 side = 0;
237 VectorCopy(p->plane.normal, normal);
238 dist = p->plane.dist;
239 } else if (p->nodes[1] == node) {
240 side = 1;
242 dist = -p->plane.dist;
243 } else
244 Sys_Error("CutNodePortals_r: mislinked portal");
245
246 ChopWindingInPlace(&w, normal, dist, 0.1);
247 }
248
249 if (!w)
250 return;
251
252 if (WindingIsTiny(w)) {
254 FreeWinding(w);
255 return;
256 }
257
258 new_portal = AllocPortal();
259 new_portal->plane = mapplanes[node->planenum];
260 new_portal->onnode = node;
261 new_portal->winding = w;
262 AddPortalToNodes(new_portal, node->children[0], node->children[1]);
263}
264
265
270static void SplitNodePortals (node_t* node)
271{
272 portal_t* p, *next_portal, *new_portal;
273 node_t* f, *b;
274 int side = 0;
275 plane_t* plane;
276 winding_t* frontwinding, *backwinding;
277
278 plane = &mapplanes[node->planenum];
279 f = node->children[0];
280 b = node->children[1];
281
282 for (p = node->portals; p; p = next_portal) {
283 if (p->nodes[0] == node)
284 side = 0;
285 else if (p->nodes[1] == node)
286 side = 1;
287 else
288 Sys_Error("SplitNodePortals: mislinked portal");
289 next_portal = p->next[side];
290
291 node_t* other_node = p->nodes[!side];
292 RemovePortalFromNode(p, p->nodes[0]);
293 RemovePortalFromNode(p, p->nodes[1]);
294
295 /* cut the portal into two portals, one on each side of the cut plane */
296 ClipWindingEpsilon(p->winding, plane->normal, plane->dist,
297 SPLIT_WINDING_EPSILON, &frontwinding, &backwinding);
298
299 if (frontwinding && WindingIsTiny(frontwinding)) {
300 FreeWinding(frontwinding);
301 frontwinding = nullptr;
303 }
304
305 if (backwinding && WindingIsTiny(backwinding)) {
306 FreeWinding(backwinding);
307 backwinding = nullptr;
309 }
310
311 if (!frontwinding && !backwinding) { /* tiny windings on both sides */
312 continue;
313 }
314
315 if (!frontwinding) {
316 FreeWinding(backwinding);
317 if (side == 0)
318 AddPortalToNodes(p, b, other_node);
319 else
320 AddPortalToNodes(p, other_node, b);
321 continue;
322 }
323 if (!backwinding) {
324 FreeWinding(frontwinding);
325 if (side == 0)
326 AddPortalToNodes(p, f, other_node);
327 else
328 AddPortalToNodes(p, other_node, f);
329 continue;
330 }
331
332 /* the winding is split */
333 new_portal = AllocPortal();
334 *new_portal = *p;
335 new_portal->winding = backwinding;
337 p->winding = frontwinding;
338
339 if (side == 0) {
340 AddPortalToNodes(p, f, other_node);
341 AddPortalToNodes(new_portal, b, other_node);
342 } else {
343 AddPortalToNodes(p, other_node, f);
344 AddPortalToNodes(new_portal, other_node, b);
345 }
346 }
347
348 node->portals = nullptr;
349}
350
351
352static void CalcNodeBounds (node_t* node)
353{
354 int s;
355
356 /* calc mins/maxs for both leafs and nodes */
357 node->nBox.setNegativeVolume();
358 for (portal_t* p = node->portals; p; p = p->next[s]) {
359 s = (p->nodes[1] == node);
360 if (!p->winding)
361 continue;
362 for (int i = 0; i < p->winding->numpoints; i++)
363 node->nBox.add(p->winding->p[i]);
364 }
365}
366
367
368static void MakeTreePortals_r (node_t* node)
369{
370 CalcNodeBounds(node);
371 if (node->nBox.mins[0] >= node->nBox.maxs[0]) {
372 Com_Printf("WARNING: node without a volume\n");
373 }
374
375 for (int i = 0; i < 3; i++) {
376 if (node->nBox.mins[i] < -MAX_WORLD_WIDTH || node->nBox.maxs[i] > MAX_WORLD_WIDTH) {
377 Com_Printf("WARNING: node with unbounded volume %i\n", (int)node->nBox.mins[i]);
378 break;
379 }
380 }
381 if (node->planenum == PLANENUM_LEAF)
382 return;
383
384 MakeNodePortal(node);
385 SplitNodePortals(node);
386
387 MakeTreePortals_r(node->children[0]);
388 MakeTreePortals_r(node->children[1]);
389}
390
392{
395}
396
400static void FindPortalSide (portal_t* p)
401{
402 /* decide which content change is strongest
403 * solid > water, etc */
404 uint32_t viscontents = VisibleContents(p->nodes[0]->contentFlags ^ p->nodes[1]->contentFlags);
405 if (!viscontents)
406 return;
407
408 int planenum = p->onnode->planenum;
409 side_t* bestside = nullptr;
410 float bestdot = 0;
411
412 for (int j = 0; j < 2; j++) {
413 const node_t* n = p->nodes[j];
414 const plane_t* p1 = &mapplanes[p->onnode->planenum];
415 for (bspbrush_t* bb = n->brushlist; bb; bb = bb->next) {
416 const mapbrush_t* brush = bb->original;
417
418 if (!(brush->contentFlags & viscontents))
419 continue;
420 for (int i = 0; i < brush->numsides; i++) {
421 side_t* side = &brush->original_sides[i];
422 float dot;
423 const plane_t* p2;
424
425 if (side->bevel)
426 continue;
427 /* non-visible */
428 if (side->texinfo == TEXINFO_NODE)
429 continue;
430 /* exact match */
431 if ((side->planenum &~ 1) == planenum) {
432 bestside = &brush->original_sides[i];
433 goto gotit;
434 }
435 /* see how close the match is */
436 p2 = &mapplanes[side->planenum &~ 1];
437 dot = DotProduct(p1->normal, p2->normal);
438 if (dot > bestdot) {
439 bestdot = dot;
440 bestside = side;
441 }
442 }
443 }
444 }
445
446gotit:
447 if (!bestside)
448 Verb_Printf(VERB_EXTRA, "WARNING: side not found for portal\n");
449
450 p->sidefound = true;
451 p->side = bestside;
452}
453
454
455static void MarkVisibleSides_r (node_t* node)
456{
457 portal_t* p;
458 int s;
459
460 if (node->planenum != PLANENUM_LEAF) {
463 return;
464 }
465
466 /* empty leafs are never boundary leafs */
467 if (!node->contentFlags)
468 return;
469
470 /* see if there is a visible face */
471 for (p = node->portals; p; p = p->next[!s]) {
472 s = (p->nodes[0] == node);
473 if (!p->onnode)
474 continue; /* edge of world */
475 if (!p->sidefound)
477 if (p->side)
478 p->side->visible = true;
479 }
480}
481
482void MarkVisibleSides (tree_t* tree, int startbrush, int endbrush)
483{
484 Verb_Printf(VERB_EXTRA, "--- MarkVisibleSides ---\n");
485
486 /* clear all the visible flags */
487 for (int i = startbrush; i < endbrush; i++) {
488 mapbrush_t* mb = &mapbrushes[i];
489 const int numsides = mb->numsides;
490 for (int j = 0; j < numsides; j++)
491 mb->original_sides[j].visible = false;
492 }
493
494 /* set visible flags on the sides that are used by portals */
496}
plane_t mapplanes[MAX_MAP_PLANES]
Definition map.cpp:43
mapbrush_t mapbrushes[MAX_MAP_BRUSHES]
Definition map.cpp:34
vec3_t maxs
Definition aabb.h:258
void setNegativeVolume()
Sets mins and maxs to their starting points before using addPoint.
Definition aabb.h:98
vec3_t mins
Definition aabb.h:257
void add(const vec3_t point)
If the point is outside the box, expand the box to accommodate it.
Definition aabb.cpp:57
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
#define ON_EPSILON
Definition defines.h:374
#define LAST_VISIBLE_CONTENTS
Definition defines.h:230
#define TEXINFO_NODE
Definition defines.h:48
#define PLANENUM_LEAF
Definition defines.h:45
#define MAX_WORLD_WIDTH
-MAX_WORLD_WIDTH up tp +MAX_WORLD_WIDTH
Definition defines.h:288
void Sys_Error(const char *error,...)
Definition g_main.cpp:421
const vec3_t vec3_origin
Definition mathlib.cpp:35
#define Mem_Free(ptr)
Definition mem.h:35
#define Mem_AllocType(type)
Definition mem.h:39
void FreeWinding(winding_t *w)
Definition polylib.cpp:46
void ChopWindingInPlace(winding_t **inout, const vec3_t normal, const vec_t dist, const vec_t epsilon)
Definition polylib.cpp:299
bool WindingIsTiny(winding_t *w)
Returns true if the winding would be crunched out of existance by the vertex snapping.
Definition polylib.cpp:407
winding_t * BaseWindingForPlane(const vec3_t normal, const vec_t dist)
Definition polylib.cpp:116
void ClipWindingEpsilon(const winding_t *in, const vec3_t normal, const vec_t dist, const vec_t epsilon, winding_t **front, winding_t **back)
Definition polylib.cpp:204
static void MakeNodePortal(node_t *node)
Create the new portal by taking the full plane winding for the cutting plane and clipping it by all o...
Definition portals.cpp:223
static void MakeTreePortals_r(node_t *node)
Definition portals.cpp:368
void FreePortal(portal_t *p)
Definition portals.cpp:52
static winding_t * BaseWindingForNode(node_t *node)
Definition portals.cpp:190
void RemovePortalFromNode(portal_t *portal, node_t *l)
Removes references to the given portal from the given node.
Definition portals.cpp:102
static int c_active_portals
Definition portals.cpp:32
static void FindPortalSide(portal_t *p)
Finds a brush side to use for texturing the given portal.
Definition portals.cpp:400
static void MakeHeadnodePortals(tree_t *tree)
The created portals will face the global outside_node.
Definition portals.cpp:137
static void AddPortalToNodes(portal_t *p, node_t *front, node_t *back)
Links a portal into the given back and front nodes.
Definition portals.cpp:82
static void MarkVisibleSides_r(node_t *node)
Definition portals.cpp:455
#define BASE_WINDING_EPSILON
Definition portals.cpp:187
void MakeTreePortals(tree_t *tree)
Definition portals.cpp:391
static int c_peak_portals
Definition portals.cpp:33
static portal_t * AllocPortal(void)
Definition portals.cpp:39
#define SIDESPACE
Definition portals.cpp:133
static void CalcNodeBounds(node_t *node)
Definition portals.cpp:352
void MarkVisibleSides(tree_t *tree, int startbrush, int endbrush)
Definition portals.cpp:482
static int c_tinyportals
Definition portals.cpp:34
uint32_t VisibleContents(uint32_t contentFlags)
Returns the single content bit of the strongest visible content present.
Definition portals.cpp:64
#define SPLIT_WINDING_EPSILON
Definition portals.cpp:188
static void SplitNodePortals(node_t *node)
Move or split the portals that bound node so that the node's children have portals instead of node.
Definition portals.cpp:270
QGL_EXTERN GLfloat f
Definition r_gl.h:114
QGL_EXTERN GLint i
Definition r_gl.h:113
#define OBJZERO(obj)
Definition shared.h:178
struct bspbrush_s * next
Definition bspbrush.h:36
struct side_s * original_sides
Definition map.h:84
int numsides
Definition map.h:83
uint32_t contentFlags
Definition map.h:79
Definition bsp.h:42
int32_t planenum
Definition bsp.h:44
AABB nBox
Definition bsp.h:46
struct node_s * parent
Definition bsp.h:45
int32_t contentFlags
Definition bsp.h:56
bspbrush_t * brushlist
Definition bsp.h:55
struct portal_s * portals
Definition bsp.h:58
struct node_s * children[2]
Definition bsp.h:51
Definition map.h:98
vec_t dist
Definition map.h:100
vec3_t normal
Definition map.h:99
struct node_s * nodes[2]
Definition map.h:113
bool sidefound
Definition map.h:117
struct side_s * side
Definition map.h:118
winding_t * winding
Definition map.h:115
struct node_s * onnode
Definition map.h:112
plane_t plane
Definition map.h:111
struct portal_s * next[2]
Definition map.h:114
Definition map.h:60
uint16_t planenum
Definition map.h:61
int texinfo
Definition map.h:62
bool bevel
Definition map.h:69
Definition bsp.h:61
struct node_s * headnode
Definition bsp.h:62
struct node_s outside_node
Definition bsp.h:63
AABB aabb
Definition bsp.h:64
for storing the vertices of the side of a brush or other polygon
Definition polylib.h:30
void Verb_Printf(const verbosityLevel_t importance, const char *format,...) __attribute__((format(__printf__
@ VERB_EXTRA
Definition shared.h:46
threadstate_t threadstate
Definition threads.cpp:32
float vec_t
Definition ufotypes.h:37
vec_t vec3_t[3]
Definition ufotypes.h:39
#define VectorSubtract(a, b, dest)
Definition vector.h:45
#define VectorCopy(src, dest)
Definition vector.h:51
#define DotProduct(x, y)
Returns the distance between two 3-dimensional vectors.
Definition vector.h:44