1 /**
2  * @file
3  * @brief BSP model code
4  */
5 
6 /*
7 Copyright (C) 1997-2001 Id Software, Inc.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23 
24 */
25 
26 #include "r_local.h"
27 #include "r_lightmap.h"
28 #include "r_material.h"
29 #include "r_light.h"
30 #include "r_draw.h"
31 
32 /*
33 =============================================================
34 BRUSH MODELS
35 =============================================================
36 */
37 
38 #define BACKFACE_EPSILON 0.01
39 
40 #define MAX_BSPS_TO_RENDER 1024
41 
42 typedef struct bspRenderRef_s {
43 	const mBspModel_t* bsp;
44 	vec3_t origin;
45 	vec3_t angles;
46 } bspRenderRef_t;
47 
48 static bspRenderRef_t bspRRefs[MAX_BSPS_TO_RENDER];
49 static int numBspRRefs;
50 
51 /**
52  * @brief Returns whether if the specified bounding box is completely culled by the
53  * view frustum (PSIDE_BACK), completely not culled (PSIDE_FRONT) or split by it (PSIDE_BOTH)
54  * @param[in] mins The mins of the bounding box
55  * @param[in] maxs The maxs of the bounding box
56  */
R_CullBox(const vec3_t mins,const vec3_t maxs)57 static int R_CullBox (const vec3_t mins, const vec3_t maxs)
58 {
59 	int i;
60 	int cullState = 0;
61 
62 	if (r_nocull->integer)
63 		return PSIDE_FRONT;
64 
65 	for (i = lengthof(r_locals.frustum) - 1; i >= 0; i--) {
66 		int planeSide = TR_BoxOnPlaneSide(mins, maxs, &r_locals.frustum[i]);
67 		if (planeSide == PSIDE_BACK)
68 			return PSIDE_BACK; /* completely culled away */
69 		cullState |= planeSide;
70 	}
71 
72 	return cullState;
73 }
74 
75 
76 /**
77  * @brief Performs a spherical frustum check
78  * @param[in] centre The world coordinate that is the center of the sphere
79  * @param[in] radius The radius of the sphere to check the frustum for
80  * @param[in] clipflags Can be used to skip sides of the frustum planes
81  * @return @c true if the sphere is completely outside the frustum, @c false otherwise
82  */
R_CullSphere(const vec3_t centre,const float radius,const unsigned int clipflags)83 bool R_CullSphere (const vec3_t centre, const float radius, const unsigned int clipflags)
84 {
85 	unsigned int i;
86 	unsigned int bit;
87 	const cBspPlane_t* p;
88 
89 	if (r_nocull->integer)
90 		return false;
91 
92 	for (i = lengthof(r_locals.frustum), bit = 1, p = r_locals.frustum; i > 0; i--, bit <<= 1, p++) {
93 		if (!(clipflags & bit))
94 			continue;
95 		if (DotProduct(centre, p->normal) - p->dist <= -radius)
96 			return true;
97 	}
98 
99 	return false;
100 }
101 
102 /**
103  * @brief Returns true if the specified entity is completely culled by the view
104  * frustum, false otherwise.
105  * @param[in] e The entity to check
106  * @sa R_CullBox
107  */
R_CullBspModel(const entity_t * e)108 bool R_CullBspModel (const entity_t* e)
109 {
110 	vec3_t mins, maxs;
111 
112 	/* no surfaces */
113 	if (!e->model->bsp.nummodelsurfaces)
114 		return true;
115 
116 	if (e->isOriginBrushModel) {
117 		int i;
118 		for (i = 0; i < 3; i++) {
119 			mins[i] = e->origin[i] - e->model->radius;
120 			maxs[i] = e->origin[i] + e->model->radius;
121 		}
122 	} else {
123 		VectorAdd(e->origin, e->model->mins, mins);
124 		VectorAdd(e->origin, e->model->maxs, maxs);
125 	}
126 
127 	return R_CullBox(mins, maxs) == PSIDE_BACK;
128 }
129 
130 /*
131 =============================================================
132 WORLD MODEL
133 =============================================================
134 */
135 
136 /**
137  * @brief Developer tool for viewing BSP vertex normals. Only Phong interpolated
138  * surfaces show their normals when r_shownormals > 1.
139  */
R_DrawBspNormals(int tile)140 void R_DrawBspNormals (int tile)
141 {
142 	int i, j, k;
143 	const mBspSurface_t* surf;
144 	const mBspModel_t* bsp;
145 	const vec4_t color = {1.0, 0.0, 0.0, 1.0};
146 
147 	if (!r_shownormals->integer)
148 		return;
149 
150 	R_EnableTexture(&texunit_diffuse, false);
151 
152 	R_ResetArrayState();  /* default arrays */
153 
154 	R_Color(color);
155 
156 	k = 0;
157 	bsp = &r_mapTiles[tile]->bsp;
158 	surf = bsp->surfaces;
159 	for (i = 0; i < bsp->numsurfaces; i++, surf++) {
160 		if (surf->frame != r_locals.frame)
161 			continue; /* not visible */
162 
163 		if (surf->texinfo->flags & SURF_WARP)
164 			continue;  /* don't care */
165 
166 		if (r_shownormals->integer > 1 && !(surf->texinfo->flags & SURF_PHONG))
167 			continue;  /* don't care */
168 
169 		/* avoid overflows, draw in batches */
170 		if (k > r_state.array_size - 512) {
171 			glDrawArrays(GL_LINES, 0, k / 3);
172 			k = 0;
173 
174 			refdef.batchCount++;
175 		}
176 
177 		for (j = 0; j < surf->numedges; j++) {
178 			vec3_t end;
179 			const GLfloat* vertex = &bsp->verts[(surf->index + j) * 3];
180 			const GLfloat* normal = &bsp->normals[(surf->index + j) * 3];
181 
182 			VectorMA(vertex, 12.0, normal, end);
183 
184 			memcpy(&r_state.vertex_array_3d[k], vertex, sizeof(vec3_t));
185 			memcpy(&r_state.vertex_array_3d[k + 3], end, sizeof(vec3_t));
186 			k += sizeof(vec3_t) / sizeof(vec_t) * 2;
187 			R_ReallocateStateArrays(k);
188 		}
189 	}
190 
191 	glDrawArrays(GL_LINES, 0, k / 3);
192 
193 	refdef.batchCount++;
194 
195 	R_EnableTexture(&texunit_diffuse, true);
196 
197 	R_Color(nullptr);
198 }
199 
200 /**
201  * @brief Recurse down the bsp tree and mark all surfaces as visible
202  * for being rendered
203  * @sa R_DrawWorld
204  * @sa R_RecurseWorld
205  * @sa R_RecursiveWorldNode
206  * @param[in] node The bsp node to mark
207  * @param[in] tile The maptile (map assembly)
208  */
R_RecursiveVisibleWorldNode(const mBspNode_t * node,int tile)209 static void R_RecursiveVisibleWorldNode (const mBspNode_t* node, int tile)
210 {
211 	/* if a leaf node, nothing to mark */
212 	if (node->contents > CONTENTS_NODE)
213 		return;
214 
215 	/* pathfinding nodes are invalid here */
216 	assert(node->plane);
217 
218 	mBspSurface_t* surf = r_mapTiles[tile]->bsp.surfaces + node->firstsurface;
219 	for (int i = 0; i < node->numsurfaces; i++, surf++)
220 		surf->frame = r_locals.frame;
221 
222 	/* recurse down the children */
223 	R_RecursiveVisibleWorldNode(node->children[0], tile);
224 	R_RecursiveVisibleWorldNode(node->children[1], tile);
225 }
226 
227 /**
228  * @brief Recurse down the bsp tree and mark surfaces that are visible (not culled)
229  * for being rendered
230  * @sa R_DrawWorld
231  * @sa R_RecurseWorld
232  * @sa R_RecursiveVisibleWorldNode
233  * @param[in] node The bsp node to check
234  * @param[in] tile The maptile (map assembly)
235  */
R_RecursiveWorldNode(const mBspNode_t * node,int tile)236 static void R_RecursiveWorldNode (const mBspNode_t* node, int tile)
237 {
238 	int i;
239 	int cullState;
240 	mBspSurface_t* surf;
241 
242 	/* if a leaf node, nothing to mark */
243 	if (node->contents > CONTENTS_NODE)
244 		return;
245 
246 	cullState = R_CullBox(node->minmaxs, node->minmaxs + 3);
247 
248 	if (cullState == PSIDE_BACK)
249 		return;					/* culled out */
250 
251 	/* pathfinding nodes are invalid here */
252 	assert(node->plane);
253 
254 	surf = r_mapTiles[tile]->bsp.surfaces + node->firstsurface;
255 	for (i = 0; i < node->numsurfaces; i++, surf++)
256 		surf->frame = r_locals.frame;
257 
258 	/* recurse down the children */
259 	/** @todo avoid being too precise, it's a waste of CPU time; possibly, granularity of 256x256x256 should be enough */
260 	if (cullState == PSIDE_FRONT) {
261 		/* completely inside the frustum - no need to do any further checks */
262 		R_RecursiveVisibleWorldNode(node->children[0], tile);
263 		R_RecursiveVisibleWorldNode(node->children[1], tile);
264 	} else {
265 		/* partially clipped by frustum - recurse to do finer checks */
266 		R_RecursiveWorldNode(node->children[0], tile);
267 		R_RecursiveWorldNode(node->children[1], tile);
268 	}
269 }
270 
271 /**
272  * @brief Wrapper that recurses the bsp nodes but skip the pathfinding nodes
273  * @sa R_GetLevelSurfaceLists
274  * @param[in] node The bsp node to check
275  * @param[in] tile The maptile (map assembly)
276  * @sa R_ModLoadNodes about pathfinding nodes
277  */
R_RecurseWorld(const mBspNode_t * node,int tile)278 static void R_RecurseWorld (const mBspNode_t* node, int tile)
279 {
280 	/* skip special pathfinding nodes */
281 	if (node->contents == CONTENTS_PATHFINDING_NODE) {
282 		R_RecurseWorld(node->children[0], tile);
283 		R_RecurseWorld(node->children[1], tile);
284 	} else {
285 		R_RecursiveWorldNode(node, tile);
286 	}
287 }
288 
289 
290 /**
291  * @brief Fills the surface chains for the current worldlevel and hide other levels
292  * @sa cvar cl_worldlevel
293  */
R_GetLevelSurfaceLists(void)294 void R_GetLevelSurfaceLists (void)
295 {
296 	if (!r_drawworld->integer)
297 		return;
298 
299 	const int mask = 1 << refdef.worldlevel;
300 
301 	for (int tile = 0; tile < r_numMapTiles; tile++) {
302 		/* don't draw weaponclip, actorclip and stepon */
303 		for (int i = 0; i <= LEVEL_LASTVISIBLE; i++) {
304 			/* check the worldlevel flags */
305 			if (i && !(i & mask))
306 				continue;
307 
308 			mBspModel_t* bspModel = &r_mapTiles[tile]->bsp;
309 			mBspHeader_t* header = &bspModel->submodels[i];
310 			if (!header->numfaces)
311 				continue;
312 
313 			R_RecurseWorld(bspModel->nodes + header->headnode, tile);
314 		}
315 	}
316 }
317 
318 /*
319 =============================================================
320 Deferred rendering
321 =============================================================
322 */
323 
R_ClearBspRRefs(void)324 void R_ClearBspRRefs (void)
325 {
326 	numBspRRefs = 0;
327 }
328 
329 /**
330  * @brief Adds bsp render references
331  * @note If forceVisibility is set, will mark the surfaces of the given bsp model as visible for this frame.
332  * @param[in] model The bsp model to add to the render chain
333  * @param[in] origin
334  * @param[in] angles
335  * @param[in] forceVisibility force model to be fully visible
336  */
R_AddBspRRef(const mBspModel_t * model,const vec3_t origin,const vec3_t angles,const bool forceVisibility)337 void R_AddBspRRef (const mBspModel_t* model, const vec3_t origin, const vec3_t angles, const bool forceVisibility)
338 {
339 	if (numBspRRefs >= MAX_BSPS_TO_RENDER) {
340 		Com_Printf("Cannot add BSP model rendering reference: MAX_BSPS_TO_RENDER exceeded\n");
341 		return;
342 	}
343 
344 	if (!model) {
345 		Com_Printf("R_AddBspRRef: null model!\n");
346 		return;
347 	}
348 
349 	bspRenderRef_t* bspRR = &bspRRefs[numBspRRefs++];
350 	bspRR->bsp = model;
351 	VectorCopy(origin, bspRR->origin);
352 	VectorCopy(angles, bspRR->angles);
353 
354 	if (!forceVisibility)
355 		return;
356 
357 	mBspSurface_t* surf = &model->surfaces[model->firstmodelsurface];
358 	for (int i = 0; i < model->nummodelsurfaces; i++, surf++) {
359 		/* visible flag for rendering */
360 		surf->frame = r_locals.frame;
361 	}
362 }
363 
364 typedef void (*drawSurfaceFunc)(const mBspSurfaces_t* surfs, glElementIndex_t* indexPtr);
365 
366 /**
367  * @param[in] drawFunc The function pointer to the surface draw function
368  */
R_RenderBspRRefs(drawSurfaceFunc drawFunc,surfaceArrayType_t surfType)369 static void R_RenderBspRRefs (drawSurfaceFunc drawFunc, surfaceArrayType_t surfType)
370 {
371 	glEnable(GL_CULL_FACE);
372 	glCullFace(GL_FRONT); /* our triangles are backwards to what OpenGL expects, so tell it to render only back faces */
373 
374 	for (int i = 0; i < numBspRRefs; i++) {
375 		const bspRenderRef_t* const bspRR = &bspRRefs[i];
376 		const mBspModel_t* const bsp = bspRR->bsp;
377 		const mBspModel_t* const tile = &r_mapTiles[bsp->maptile]->bsp; /* This is required to find the tile (world) bsp model to which arrays belong (submodels do not own arrays, but use world model ones) */
378 		glElementIndex_t* indexPtr;
379 
380 		if (!bsp->sorted_surfaces[surfType]->count)
381 			continue;
382 
383 		R_SetArrayState(tile);
384 
385 		/* Vertex buffers are nullptr-based, arrays are not */
386 		if (qglBindBuffer && r_vertexbuffers->integer)
387 			indexPtr = nullptr;
388 		else
389 			indexPtr = tile->indexes;
390 
391 		glPushMatrix();
392 
393 		glTranslatef(bspRR->origin[0], bspRR->origin[1], bspRR->origin[2]);
394 		glRotatef(bspRR->angles[YAW], 0, 0, 1);
395 		glRotatef(bspRR->angles[PITCH], 0, 1, 0);
396 		glRotatef(bspRR->angles[ROLL], 1, 0, 0);
397 
398 		drawFunc(bsp->sorted_surfaces[surfType], indexPtr);
399 
400 		/** @todo make it work again; also reimplement r_showbox 2 */
401 #if 0
402 		/* show model bounding box */
403 		if (r_showbox->integer) {
404 			const model_t* model = bspRR->bsp;
405 			R_DrawBoundingBox(model->mins, model->maxs);
406 		}
407 #endif
408 
409 		glPopMatrix();
410 	}
411 
412 	/* and restore array pointers */
413 	R_ResetArrayState();
414 
415 	glCullFace(GL_BACK);
416 	glDisable(GL_CULL_FACE);
417 }
418 
419 /**
420  * @brief Draw all simple opaque bsp surfaces with multitexture enabled and light enabled
421  */
R_RenderOpaqueBspRRefs(void)422 void R_RenderOpaqueBspRRefs (void)
423 {
424 	R_EnableTexture(&texunit_lightmap, true);
425 	R_EnableLighting(r_state.world_program, true);
426 	R_EnableWorldLights();
427 
428 	R_RenderBspRRefs(R_DrawSurfaces, S_OPAQUE);
429 
430 	R_EnableLighting(nullptr, false);
431 	R_EnableGlowMap(nullptr);
432 	R_EnableTexture(&texunit_lightmap, false);
433 }
434 
435 /**
436  * @brief Draw all warped opaque bsp surfaces via warp shader
437  */
R_RenderOpaqueWarpBspRRefs(void)438 void R_RenderOpaqueWarpBspRRefs (void)
439 {
440 	R_EnableWarp(r_state.warp_program, true);
441 
442 	R_RenderBspRRefs(R_DrawSurfaces, S_OPAQUE_WARP);
443 
444 	R_EnableWarp(nullptr, false);
445 	R_EnableGlowMap(nullptr);
446 }
447 
R_RenderAlphaTestBspRRefs(void)448 void R_RenderAlphaTestBspRRefs (void)
449 {
450 	R_EnableAlphaTest(true);
451 	R_EnableLighting(r_state.world_program, true);
452 	R_EnableWorldLights();
453 
454 	R_RenderBspRRefs(R_DrawSurfaces, S_ALPHA_TEST);
455 
456 	R_EnableLighting(nullptr, false);
457 	R_EnableGlowMap(nullptr);
458 	R_EnableAlphaTest(false);
459 }
460 
R_RenderMaterialBspRRefs(void)461 void R_RenderMaterialBspRRefs (void)
462 {
463 	R_RenderBspRRefs(R_DrawMaterialSurfaces, S_MATERIAL);
464 }
465 
R_RenderFlareBspRRefs(void)466 void R_RenderFlareBspRRefs (void)
467 {
468 	R_RenderBspRRefs(R_DrawFlareSurfaces, S_FLARE);
469 }
470 
471 /**
472  * @brief Draw all translucent bsp surfaces with multitexture enabled and blend enabled
473  */
R_RenderBlendBspRRefs(void)474 void R_RenderBlendBspRRefs (void)
475 {
476 	assert(r_state.blend_enabled);
477 	R_EnableTexture(&texunit_lightmap, true);
478 
479 	R_RenderBspRRefs(R_DrawSurfaces, S_BLEND);
480 
481 	R_EnableTexture(&texunit_lightmap, false);
482 }
483 
484 /**
485  * @brief Draw all warped translucent bsp surfaces via warp shader and with blend enabled
486  */
R_RenderBlendWarpBspRRefs(void)487 void R_RenderBlendWarpBspRRefs (void)
488 {
489 	assert(r_state.blend_enabled);
490 	R_EnableWarp(r_state.warp_program, true);
491 
492 	R_RenderBspRRefs(R_DrawSurfaces, S_BLEND_WARP);
493 
494 	R_EnableWarp(nullptr, false);
495 	R_EnableGlowMap(nullptr);
496 }
497