1 /**
2 * @file
3 * @note some faces will be removed before saving, but still form nodes:
4 * meeting planes of different water current volumes
5 */
6
7 /*
8 Copyright (C) 1997-2001 Id Software, Inc.
9
10 This program is free software; you can redistribute it and/or
11 modify it under the terms of the GNU General Public License
12 as published by the Free Software Foundation; either version 2
13 of the License, or (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18
19 See the GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25 */
26
27
28 #include "bsp.h"
29
30 #define INTEGRAL_EPSILON 0.01
31 #define POINT_EPSILON 0.0625
32 #define OFF_EPSILON 0.5
33
34 static int c_merge, c_subdivide, c_totalverts, c_uniqueverts, c_degenerate, c_tjunctions, c_faceoverflows, c_facecollapse, c_badstartverts, c_faces;
35
36 #define MAX_SUPERVERTS 512
37 static int superverts[MAX_SUPERVERTS];
38 static int numsuperverts;
39
40 static const face_t* edgefaces[MAX_MAP_EDGES][2];
41 int firstmodeledge = 1;
42
43 static vec3_t edge_dir;
44 static vec3_t edge_start;
45
46 static int num_edge_verts;
47 static int edge_verts[MAX_MAP_VERTS];
48
49 #define HASH_SIZE 64
50
51 static int vertexchain[MAX_MAP_VERTS]; /* the next vertex in a hash chain */
52 static int hashverts[HASH_SIZE * HASH_SIZE]; /* a vertex number, or 0 for no verts */
53
54 /**
55 * @todo Fix this to support the full bsp level bounds
56 */
HashVec(const vec3_t vec)57 static unsigned HashVec (const vec3_t vec)
58 {
59 const int x = (4096 + (int)(vec[0] + 0.5)) >> 7;
60 const int y = (4096 + (int)(vec[1] + 0.5)) >> 7;
61
62 if (x < 0 || x >= HASH_SIZE || y < 0 || y >= HASH_SIZE)
63 Sys_Error("HashVec: point outside valid range");
64
65 return y * HASH_SIZE + x;
66 }
67
68 /**
69 * @brief Returns the number of an existing vertex or allocates a new one
70 * @note Uses hashing
71 */
GetVertexnum(const vec3_t in)72 static int GetVertexnum (const vec3_t in)
73 {
74 int h, i, vnum;
75 vec3_t vert;
76
77 c_totalverts++;
78
79 for (i = 0; i < 3; i++) {
80 if (fabs(in[i] - Q_rint(in[i])) < INTEGRAL_EPSILON)
81 vert[i] = Q_rint(in[i]);
82 else
83 vert[i] = in[i];
84 }
85
86 h = HashVec(vert);
87
88 for (vnum = hashverts[h]; vnum; vnum = vertexchain[vnum]) {
89 const float* p = curTile->vertexes[vnum].point;
90 if (fabs(p[0] - vert[0]) < POINT_EPSILON
91 && fabs(p[1] - vert[1]) < POINT_EPSILON
92 && fabs(p[2] - vert[2]) < POINT_EPSILON)
93 return vnum;
94 }
95
96 /* emit a vertex */
97 if (curTile->numvertexes == MAX_MAP_VERTS)
98 Sys_Error("numvertexes == MAX_MAP_VERTS");
99
100 curTile->vertexes[curTile->numvertexes].point[0] = vert[0];
101 curTile->vertexes[curTile->numvertexes].point[1] = vert[1];
102 curTile->vertexes[curTile->numvertexes].point[2] = vert[2];
103
104 vertexchain[curTile->numvertexes] = hashverts[h];
105 hashverts[h] = curTile->numvertexes;
106
107 c_uniqueverts++;
108
109 curTile->numvertexes++;
110 curTile->numnormals++;
111
112 return curTile->numvertexes - 1;
113 }
114
AllocFace(void)115 static face_t* AllocFace (void)
116 {
117 c_faces++;
118
119 return Mem_AllocType(face_t);
120 }
121
NewFaceFromFace(const face_t * f)122 static face_t* NewFaceFromFace (const face_t* f)
123 {
124 face_t *newf;
125
126 newf = AllocFace();
127 *newf = *f;
128 newf->merged = nullptr;
129 newf->split[0] = newf->split[1] = nullptr;
130 newf->w = nullptr;
131 return newf;
132 }
133
FreeFace(face_t * f)134 void FreeFace (face_t* f)
135 {
136 if (f->w)
137 FreeWinding(f->w);
138 Mem_Free(f);
139 c_faces--;
140 }
141
142 /**
143 * @brief The faces vertexes have been added to the superverts[] array,
144 * and there may be more there than can be held in a face (MAXEDGES).
145 *
146 * If less, the faces vertexnums[] will be filled in, otherwise
147 * face will reference a tree of split[] faces until all of the
148 * vertexnums can be added.
149 *
150 * @note superverts[base] will become face->vertexnums[0], and the others
151 * will be circularly filled in.
152 */
FaceFromSuperverts(node_t * node,face_t * f,int base)153 static void FaceFromSuperverts (node_t* node, face_t* f, int base)
154 {
155 int i, remaining;
156
157 remaining = numsuperverts;
158 /* must split into two faces, because of vertex overload */
159 while (remaining > MAXEDGES) {
160 c_faceoverflows++;
161
162 face_t* newf = f->split[0] = NewFaceFromFace(f);
163 newf->next = node->faces;
164 node->faces = newf;
165
166 newf->numpoints = MAXEDGES;
167 for (i = 0; i < MAXEDGES; i++)
168 newf->vertexnums[i] = superverts[(i + base) % numsuperverts];
169
170 f->split[1] = NewFaceFromFace(f);
171 f = f->split[1];
172 f->next = node->faces;
173 node->faces = f;
174
175 remaining -= (MAXEDGES - 2);
176 base = (base + MAXEDGES - 1) % numsuperverts;
177 }
178
179 /* copy the vertexes back to the face */
180 f->numpoints = remaining;
181 for (i = 0; i < remaining; i++)
182 f->vertexnums[i] = superverts[(i + base) % numsuperverts];
183 }
184
EmitFaceVertexes(node_t * node,face_t * f)185 static void EmitFaceVertexes (node_t* node, face_t* f)
186 {
187 winding_t* w;
188 int i;
189
190 if (f->merged || f->split[0] || f->split[1])
191 return;
192
193 w = f->w;
194 for (i = 0; i < w->numpoints; i++) {
195 /* make every point unique */
196 if (config.noweld) {
197 if (curTile->numvertexes == MAX_MAP_VERTS)
198 Sys_Error("MAX_MAP_VERTS (%i)", curTile->numvertexes);
199 superverts[i] = curTile->numvertexes;
200 VectorCopy(w->p[i], curTile->vertexes[curTile->numvertexes].point);
201 curTile->numvertexes++;
202 curTile->numnormals++;
203 c_uniqueverts++;
204 c_totalverts++;
205 } else
206 superverts[i] = GetVertexnum(w->p[i]);
207 }
208 numsuperverts = w->numpoints;
209
210 /* this may fragment the face if > MAXEDGES */
211 FaceFromSuperverts(node, f, 0);
212 }
213
EmitVertexes_r(node_t * node)214 static void EmitVertexes_r (node_t* node)
215 {
216 int i;
217 face_t* f;
218
219 if (node->planenum == PLANENUM_LEAF)
220 return;
221
222 for (f = node->faces; f; f = f->next)
223 EmitFaceVertexes(node, f);
224
225 for (i = 0; i < 2; i++)
226 EmitVertexes_r(node->children[i]);
227 }
228
229
230 /**
231 * @brief Uses the hash tables to cut down to a small number
232 */
FindEdgeVerts(const vec3_t v1,const vec3_t v2)233 static void FindEdgeVerts (const vec3_t v1, const vec3_t v2)
234 {
235 int x1, x2, y1, y2, t;
236 int x, y, vnum;
237
238 x1 = (MAX_WORLD_WIDTH + (int)(v1[0] + 0.5)) >> 7;
239 y1 = (MAX_WORLD_WIDTH + (int)(v1[1] + 0.5)) >> 7;
240 x2 = (MAX_WORLD_WIDTH + (int)(v2[0] + 0.5)) >> 7;
241 y2 = (MAX_WORLD_WIDTH + (int)(v2[1] + 0.5)) >> 7;
242
243 if (x1 > x2) {
244 t = x1;
245 x1 = x2;
246 x2 = t;
247 }
248 if (y1 > y2) {
249 t = y1;
250 y1 = y2;
251 y2 = t;
252 }
253 num_edge_verts = 0;
254 for (x = x1; x <= x2; x++)
255 for (y = y1; y <= y2; y++)
256 for (vnum = hashverts[y * HASH_SIZE + x]; vnum; vnum = vertexchain[vnum])
257 edge_verts[num_edge_verts++] = vnum;
258 }
259
260 /**
261 * @note Can be recursively reentered
262 */
TestEdge(vec_t start,vec_t end,int p1,int p2,int startvert)263 static void TestEdge (vec_t start, vec_t end, int p1, int p2, int startvert)
264 {
265 int k;
266 vec_t dist, error;
267 vec3_t delta, exact, off, p;
268
269 if (p1 == p2) {
270 c_degenerate++;
271 return; /* degenerate edge */
272 }
273
274 for (k = startvert; k < num_edge_verts; k++) {
275 const int j = edge_verts[k];
276 if (j == p1 || j == p2)
277 continue;
278
279 VectorCopy(curTile->vertexes[j].point, p);
280
281 VectorSubtract(p, edge_start, delta);
282 dist = DotProduct(delta, edge_dir);
283 if (dist <= start || dist >= end)
284 continue; /* off an end */
285 VectorMA(edge_start, dist, edge_dir, exact);
286 VectorSubtract(p, exact, off);
287 error = VectorLength(off);
288
289 if (fabs(error) > OFF_EPSILON)
290 continue; /* not on the edge */
291
292 /* break the edge */
293 c_tjunctions++;
294 TestEdge(start, dist, p1, j, k + 1);
295 TestEdge(dist, end, j, p2, k + 1);
296 return;
297 }
298
299 /* the edge p1 to p2 is now free of tjunctions */
300 if (numsuperverts >= MAX_SUPERVERTS)
301 Sys_Error("MAX_SUPERVERTS (%i)", numsuperverts);
302 superverts[numsuperverts] = p1;
303 numsuperverts++;
304 }
305
FixFaceEdges(node_t * node,face_t * f)306 static void FixFaceEdges (node_t* node, face_t* f)
307 {
308 int i, base;
309 vec3_t e2;
310 int count[MAX_SUPERVERTS], start[MAX_SUPERVERTS];
311
312 if (f->merged || f->split[0] || f->split[1])
313 return;
314
315 numsuperverts = 0;
316
317 for (i = 0; i < f->numpoints; i++) {
318 const int p1 = f->vertexnums[i];
319 const int p2 = f->vertexnums[(i + 1) % f->numpoints];
320
321 VectorCopy(curTile->vertexes[p1].point, edge_start);
322 VectorCopy(curTile->vertexes[p2].point, e2);
323
324 FindEdgeVerts(edge_start, e2);
325
326 VectorSubtract(e2, edge_start, edge_dir);
327 vec_t len = VectorNormalize(edge_dir);
328
329 start[i] = numsuperverts;
330 TestEdge(0, len, p1, p2, 0);
331
332 count[i] = numsuperverts - start[i];
333 }
334
335 /* entire face collapsed */
336 if (numsuperverts < 3) {
337 f->numpoints = 0;
338 c_facecollapse++;
339 return;
340 }
341
342 /* we want to pick a vertex that doesn't have tjunctions
343 * on either side, which can cause artifacts on trifans,
344 * especially underwater */
345 for (i = 0; i < f->numpoints; i++) {
346 if (count[i] == 1 && count[(i + f->numpoints - 1) % f->numpoints] == 1)
347 break;
348 }
349 if (i == f->numpoints) {
350 c_badstartverts++;
351 base = 0;
352 } else {
353 /* rotate the vertex order */
354 base = start[i];
355 }
356
357 /* this may fragment the face if > MAXEDGES */
358 FaceFromSuperverts(node, f, base);
359 }
360
FixEdges_r(node_t * node)361 static void FixEdges_r (node_t* node)
362 {
363 int i;
364 face_t* f;
365
366 if (node->planenum == PLANENUM_LEAF)
367 return;
368
369 for (f = node->faces; f; f = f->next)
370 FixFaceEdges(node, f);
371
372 for (i = 0; i < 2; i++)
373 FixEdges_r(node->children[i]);
374 }
375
376 /**
377 * @sa ProcessSubModel
378 * @sa ConstructLevelNodes_r
379 */
FixTjuncs(node_t * headnode)380 void FixTjuncs (node_t* headnode)
381 {
382 /* snap and merge all vertexes */
383 Verb_Printf(VERB_EXTRA, "---- snap verts ----\n");
384 OBJZERO(hashverts);
385 c_totalverts = 0;
386 c_uniqueverts = 0;
387 c_faceoverflows = 0;
388 EmitVertexes_r(headnode);
389 Verb_Printf(VERB_EXTRA, "%i unique from %i\n", c_uniqueverts, c_totalverts);
390
391 /* break edges on tjunctions */
392 Verb_Printf(VERB_EXTRA, "---- tjunc ----\n");
393 c_degenerate = 0;
394 c_facecollapse = 0;
395 c_tjunctions = 0;
396 if (!config.notjunc)
397 FixEdges_r(headnode);
398 Verb_Printf(VERB_EXTRA, "%5i edges degenerated\n", c_degenerate);
399 Verb_Printf(VERB_EXTRA, "%5i faces degenerated\n", c_facecollapse);
400 Verb_Printf(VERB_EXTRA, "%5i edges added by tjunctions\n", c_tjunctions);
401 Verb_Printf(VERB_EXTRA, "%5i faces added by tjunctions\n", c_faceoverflows);
402 Verb_Printf(VERB_EXTRA, "%5i bad start verts\n", c_badstartverts);
403 }
404
405 /**
406 * @sa EmitFace.
407 * @note Don't allow four way edges
408 */
GetEdge(int v1,int v2,const face_t * f)409 int GetEdge (int v1, int v2, const face_t* f)
410 {
411 dBspEdge_t* edge;
412
413 if (!config.noshare) {
414 int i;
415 for (i = firstmodeledge; i < curTile->numedges; i++) {
416 edge = &curTile->edges[i];
417 if (v1 == edge->v[1] && v2 == edge->v[0]
418 && edgefaces[i][0]->contentFlags == f->contentFlags) {
419 if (edgefaces[i][1])
420 continue;
421 edgefaces[i][1] = f;
422 return -i;
423 }
424 }
425 }
426
427 /* emit an edge */
428 if (curTile->numedges >= MAX_MAP_EDGES)
429 Sys_Error("numedges >= MAX_MAP_EDGES (%i)", curTile->numedges);
430 edge = &curTile->edges[curTile->numedges];
431 edge->v[0] = v1;
432 edge->v[1] = v2;
433 edgefaces[curTile->numedges][0] = f;
434 curTile->numedges++;
435
436 return curTile->numedges - 1;
437 }
438
439 /*
440 ===========================================================================
441 FACE MERGING
442 ===========================================================================
443 */
444
445 #define CONTINUOUS_EPSILON 0.001
446
447 /**
448 * @brief If two polygons share a common edge and the edges that meet at the
449 * common points are both inside the other polygons, merge them
450 * @return nullptr if the faces couldn't be merged, or the new winding.
451 * @note The originals will NOT be freed.
452 */
TryMergeWinding(winding_t * f1,winding_t * f2,const vec3_t planenormal)453 static winding_t* TryMergeWinding (winding_t* f1, winding_t* f2, const vec3_t planenormal)
454 {
455 vec_t* p1, *p2, *back;
456 winding_t* newf;
457 int i, j, k, l;
458 vec3_t normal, delta;
459 vec_t dot;
460 bool keep1, keep2;
461
462 p1 = p2 = nullptr;
463 j = 0;
464
465 /* find a common edge */
466 for (i = 0; i < f1->numpoints; i++) {
467 p1 = f1->p[i];
468 p2 = f1->p[(i + 1) % f1->numpoints];
469 for (j = 0; j < f2->numpoints; j++) {
470 const vec_t* p3 = f2->p[j];
471 const vec_t* p4 = f2->p[(j + 1) % f2->numpoints];
472 for (k = 0; k < 3; k++) {
473 if (fabs(p1[k] - p4[k]) > EQUAL_EPSILON)
474 break;
475 if (fabs(p2[k] - p3[k]) > EQUAL_EPSILON)
476 break;
477 }
478 if (k == 3)
479 break;
480 }
481 if (j < f2->numpoints)
482 break;
483 }
484
485 /* no matching edges */
486 if (i == f1->numpoints)
487 return nullptr;
488
489 /* check slope of connected lines */
490 /* if the slopes are colinear, the point can be removed */
491 back = f1->p[(i + f1->numpoints - 1) % f1->numpoints];
492 VectorSubtract(p1, back, delta);
493 CrossProduct(planenormal, delta, normal);
494 VectorNormalize(normal);
495
496 back = f2->p[(j + 2) % f2->numpoints];
497 VectorSubtract(back, p1, delta);
498 dot = DotProduct(delta, normal);
499 /* not a convex polygon */
500 if (dot > CONTINUOUS_EPSILON)
501 return nullptr;
502 keep1 = (bool)(dot < -CONTINUOUS_EPSILON);
503
504 back = f1->p[(i + 2) % f1->numpoints];
505 VectorSubtract(back, p2, delta);
506 CrossProduct(planenormal, delta, normal);
507 VectorNormalize(normal);
508
509 back = f2->p[(j + f2->numpoints - 1) % f2->numpoints];
510 VectorSubtract(back, p2, delta);
511 dot = DotProduct(delta, normal);
512 /* not a convex polygon */
513 if (dot > CONTINUOUS_EPSILON)
514 return nullptr;
515 keep2 = (bool)(dot < -CONTINUOUS_EPSILON);
516
517 /* build the new polygon */
518 newf = AllocWinding(f1->numpoints + f2->numpoints);
519
520 /* copy first polygon */
521 for (k = (i + 1) % f1->numpoints; k != i; k = (k + 1) % f1->numpoints) {
522 if (k == (i + 1) % f1->numpoints && !keep2)
523 continue;
524
525 VectorCopy(f1->p[k], newf->p[newf->numpoints]);
526 newf->numpoints++;
527 }
528
529 /* copy second polygon */
530 for (l = (j + 1) % f2->numpoints; l != j; l = (l + 1) % f2->numpoints) {
531 if (l == (j + 1) % f2->numpoints && !keep1)
532 continue;
533 VectorCopy(f2->p[l], newf->p[newf->numpoints]);
534 newf->numpoints++;
535 }
536
537 return newf;
538 }
539
540 /**
541 * @brief If two polygons share a common edge and the edges that meet at the
542 * common points are both inside the other polygons, merge them
543 *
544 * @return nullptr if the faces couldn't be merged, or the new face.
545 * @note The originals will NOT be freed.
546 */
TryMerge(face_t * f1,face_t * f2,const vec3_t planenormal)547 static face_t* TryMerge (face_t* f1, face_t* f2, const vec3_t planenormal)
548 {
549 face_t* newf;
550 winding_t* nw;
551
552 if (!f1->w || !f2->w)
553 return nullptr;
554 if (f1->texinfo != f2->texinfo)
555 return nullptr;
556 if (f1->planenum != f2->planenum) /* on front and back sides */
557 return nullptr;
558 if (f1->contentFlags != f2->contentFlags)
559 return nullptr;
560
561 nw = TryMergeWinding(f1->w, f2->w, planenormal);
562 if (!nw)
563 return nullptr;
564
565 c_merge++;
566 newf = NewFaceFromFace(f1);
567 newf->w = nw;
568
569 f1->merged = newf;
570 f2->merged = newf;
571
572 return newf;
573 }
574
MergeNodeFaces(node_t * node)575 static void MergeNodeFaces (node_t* node)
576 {
577 face_t* f1;
578
579 for (f1 = node->faces; f1; f1 = f1->next) {
580 face_t* f2;
581 if (f1->merged || f1->split[0] || f1->split[1])
582 continue;
583 for (f2 = node->faces; f2 != f1; f2 = f2->next) {
584 const plane_t* plane = &mapplanes[node->planenum];
585 face_t* merged;
586 face_t* end;
587
588 if (f2->merged || f2->split[0] || f2->split[1])
589 continue;
590
591 merged = TryMerge(f1, f2, plane->normal);
592 if (!merged)
593 continue;
594
595 /* add merged to the end of the node face list
596 * so it will be checked against all the faces again */
597 for (end = node->faces; end->next; end = end->next);
598
599 merged->next = nullptr;
600 end->next = merged;
601 break;
602 }
603 }
604 }
605
606 /*===================================================================== */
607
608 /**
609 * @brief Chop up faces that are larger than we want in the surface cache
610 */
SubdivideFace(node_t * node,face_t * f)611 static void SubdivideFace (node_t* node, face_t* f)
612 {
613 int axis, i;
614 const dBspTexinfo_t* tex;
615 vec3_t temp;
616 vec_t dist;
617
618 if (f->merged)
619 return;
620
621 /* special (non-surface cached) faces don't need subdivision */
622 tex = &curTile->texinfo[f->texinfo];
623 if (tex->surfaceFlags & SURF_WARP)
624 return;
625
626 for (axis = 0; axis < 2; axis++) {
627 while (1) {
628 const winding_t* w = f->w;
629 winding_t* frontw, *backw;
630 float mins = 999999;
631 float maxs = -999999;
632 vec_t v;
633
634 VectorCopy(tex->vecs[axis], temp);
635 for (i = 0; i < w->numpoints; i++) {
636 v = DotProduct(w->p[i], temp);
637 if (v < mins)
638 mins = v;
639 if (v > maxs)
640 maxs = v;
641 }
642
643 /* no bsp subdivide for this winding? */
644 if (maxs - mins <= config.subdivideSize)
645 break;
646
647 /* split it */
648 c_subdivide++;
649
650 v = VectorNormalize(temp);
651
652 dist = (mins + config.subdivideSize - 16) / v;
653
654 ClipWindingEpsilon(w, temp, dist, ON_EPSILON, &frontw, &backw);
655 if (!frontw || !backw)
656 Sys_Error("SubdivideFace: didn't split the polygon (texture: '%s')",
657 tex->texture);
658
659 f->split[0] = NewFaceFromFace(f);
660 f->split[0]->w = frontw;
661 f->split[0]->next = node->faces;
662 node->faces = f->split[0];
663
664 f->split[1] = NewFaceFromFace(f);
665 f->split[1]->w = backw;
666 f->split[1]->next = node->faces;
667 node->faces = f->split[1];
668
669 SubdivideFace(node, f->split[0]);
670 SubdivideFace(node, f->split[1]);
671 return;
672 }
673 }
674 }
675
SubdivideNodeFaces(node_t * node)676 static void SubdivideNodeFaces (node_t* node)
677 {
678 face_t* f;
679
680 for (f = node->faces; f; f = f->next)
681 SubdivideFace(node, f);
682 }
683
684 static int c_nodefaces;
685
FaceFromPortal(portal_t * p,bool pside)686 static face_t* FaceFromPortal (portal_t* p, bool pside)
687 {
688 face_t* f;
689 side_t* side = p->side;
690
691 /* portal does not bridge different visible contents */
692 if (!side)
693 return nullptr;
694
695 /* nodraw/caulk faces */
696 if (side->surfaceFlags & SURF_NODRAW)
697 return nullptr;
698
699 f = AllocFace();
700
701 f->texinfo = side->texinfo;
702 f->planenum = (side->planenum & ~1) | pside;
703 f->portal = p;
704
705 if ((p->nodes[pside]->contentFlags & CONTENTS_WINDOW)
706 && VisibleContents(p->nodes[!pside]->contentFlags ^ p->nodes[pside]->contentFlags) == CONTENTS_WINDOW)
707 return nullptr; /* don't show insides of windows */
708
709 /* do back-clipping */
710 if (!config.nobackclip && mapplanes[f->planenum].normal[2] < -0.9) {
711 /* this face is not visible from birds view - optimize away
712 * but only if it's not light emitting surface */
713 const entity_t* e = &entities[side->brush->entitynum];
714 if (!Q_streq(ValueForKey(e, "classname"), "func_rotating")) {
715 if (!(curTile->texinfo[f->texinfo].surfaceFlags & SURF_LIGHT)) {
716 /* e.g. water surfaces are removed if we set the surfaceFlags
717 * to SURF_NODRAW for this side */
718 /*side->surfaceFlags |= SURF_NODRAW;*/
719 return nullptr;
720 }
721 }
722 }
723
724 if (pside) {
725 f->w = ReverseWinding(p->winding);
726 f->contentFlags = p->nodes[1]->contentFlags;
727 } else {
728 f->w = CopyWinding(p->winding);
729 f->contentFlags = p->nodes[0]->contentFlags;
730 }
731 return f;
732 }
733
734
735 /**
736 * @brief If a portal will make a visible face, mark the side that originally created it
737 * - solid / empty : solid
738 * - solid / water : solid
739 * - water / empty : water
740 * - water / water : none
741 */
MakeFaces_r(node_t * node)742 static void MakeFaces_r (node_t* node)
743 {
744 portal_t* p;
745
746 /* recurse down to leafs */
747 if (node->planenum != PLANENUM_LEAF) {
748 MakeFaces_r(node->children[0]);
749 MakeFaces_r(node->children[1]);
750
751 /* merge together all visible faces on the node */
752 if (!config.nomerge)
753 MergeNodeFaces(node);
754 if (!config.nosubdiv)
755 SubdivideNodeFaces(node);
756
757 return;
758 }
759
760 /* solid leafs never have visible faces */
761 if (node->contentFlags & CONTENTS_SOLID)
762 return;
763
764 /* see which portals are valid */
765 for (p = node->portals; p;) {
766 const int pside = (p->nodes[1] == node);
767
768 p->face[pside] = FaceFromPortal(p, pside);
769 if (p->face[pside]) {
770 c_nodefaces++;
771 p->face[pside]->next = p->onnode->faces;
772 p->onnode->faces = p->face[pside];
773 }
774 p = p->next[pside];
775 }
776 }
777
MakeFaces(node_t * node)778 void MakeFaces (node_t* node)
779 {
780 Verb_Printf(VERB_EXTRA, "--- MakeFaces ---\n");
781 c_merge = 0;
782 c_subdivide = 0;
783 c_nodefaces = 0;
784
785 MakeFaces_r(node);
786
787 Verb_Printf(VERB_EXTRA, "%5i makefaces\n", c_nodefaces);
788 Verb_Printf(VERB_EXTRA, "%5i merged\n", c_merge);
789 Verb_Printf(VERB_EXTRA, "%5i subdivided\n", c_subdivide);
790 }
791