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