1 /*
2 Copyright (C) 1996-2001 Id Software, Inc.
3 Copyright (C) 2002-2009 John Fitzgibbons and others
4 Copyright (C) 2010-2014 QuakeSpasm developers
5 
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10 
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 
15 See the GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 
21 */
22 // r_main.c
23 
24 #include "quakedef.h"
25 
26 qboolean	r_cache_thrash;		// compatability
27 
28 vec3_t		modelorg, r_entorigin;
29 entity_t	*currententity;
30 
31 int			r_visframecount;	// bumped when going to a new PVS
32 int			r_framecount;		// used for dlight push checking
33 
34 mplane_t	frustum[4];
35 
36 int			render_pass_index;
37 qboolean	render_warp;
38 int			render_scale;
39 
40 //johnfitz -- rendering statistics
41 unsigned int rs_brushpolys, rs_aliaspolys, rs_skypolys, rs_particles, rs_fogpolys;
42 unsigned int rs_dynamiclightmaps, rs_brushpasses, rs_aliaspasses, rs_skypasses;
43 float rs_megatexels;
44 
45 //
46 // view origin
47 //
48 vec3_t	vup;
49 vec3_t	vpn;
50 vec3_t	vright;
51 vec3_t	r_origin;
52 
53 float r_fovx, r_fovy; //johnfitz -- rendering fov may be different becuase of r_waterwarp
54 
55 //
56 // screen size info
57 //
58 refdef_t	r_refdef;
59 
60 mleaf_t		*r_viewleaf, *r_oldviewleaf;
61 
62 int		d_lightstylevalue[256];	// 8.8 fraction of base light value
63 
64 
65 cvar_t	r_drawentities = {"r_drawentities","1",CVAR_NONE};
66 cvar_t	r_drawviewmodel = {"r_drawviewmodel","1",CVAR_NONE};
67 cvar_t	r_speeds = {"r_speeds","0",CVAR_NONE};
68 cvar_t	r_pos = {"r_pos","0",CVAR_NONE};
69 cvar_t	r_fullbright = {"r_fullbright","0",CVAR_NONE};
70 cvar_t	r_lightmap = {"r_lightmap","0",CVAR_NONE};
71 cvar_t	r_wateralpha = {"r_wateralpha","1",CVAR_ARCHIVE};
72 cvar_t	r_dynamic = {"r_dynamic","1",CVAR_ARCHIVE};
73 cvar_t	r_novis = {"r_novis","0",CVAR_ARCHIVE};
74 #if defined(USE_SIMD)
75 cvar_t	r_simd = {"r_simd","1",CVAR_ARCHIVE};
76 #endif
77 
78 cvar_t	gl_finish = {"gl_finish","0",CVAR_NONE};
79 cvar_t	gl_polyblend = {"gl_polyblend","1",CVAR_NONE};
80 cvar_t	gl_nocolors = {"gl_nocolors","0",CVAR_NONE};
81 
82 //johnfitz -- new cvars
83 cvar_t	r_clearcolor = {"r_clearcolor","2",CVAR_ARCHIVE};
84 cvar_t	r_fastclear = {"r_fastclear","1",CVAR_ARCHIVE};
85 cvar_t	r_flatlightstyles = {"r_flatlightstyles", "0", CVAR_NONE};
86 cvar_t	gl_fullbrights = {"gl_fullbrights", "1", CVAR_ARCHIVE};
87 cvar_t	gl_farclip = {"gl_farclip", "16384", CVAR_ARCHIVE};
88 cvar_t	r_oldskyleaf = {"r_oldskyleaf", "0", CVAR_NONE};
89 cvar_t	r_drawworld = {"r_drawworld", "1", CVAR_NONE};
90 cvar_t	r_showtris = {"r_showtris", "0", CVAR_NONE};
91 cvar_t	r_showbboxes = {"r_showbboxes", "0", CVAR_NONE};
92 cvar_t	r_lerpmodels = {"r_lerpmodels", "1", CVAR_NONE};
93 cvar_t	r_lerpmove = {"r_lerpmove", "1", CVAR_NONE};
94 cvar_t	r_nolerp_list = {"r_nolerp_list", "progs/flame.mdl,progs/flame2.mdl,progs/braztall.mdl,progs/brazshrt.mdl,progs/longtrch.mdl,progs/flame_pyre.mdl,progs/v_saw.mdl,progs/v_xfist.mdl,progs/h2stuff/newfire.mdl", CVAR_NONE};
95 
96 extern cvar_t	r_vfog;
97 //johnfitz
98 
99 cvar_t	gl_zfix = {"gl_zfix", "1", CVAR_ARCHIVE}; // QuakeSpasm z-fighting fix
100 
101 cvar_t	r_lavaalpha = {"r_lavaalpha","0",CVAR_NONE};
102 cvar_t	r_telealpha = {"r_telealpha","0",CVAR_NONE};
103 cvar_t	r_slimealpha = {"r_slimealpha","0",CVAR_NONE};
104 
105 float	map_wateralpha, map_lavaalpha, map_telealpha, map_slimealpha;
106 float	map_fallbackalpha;
107 
108 qboolean r_drawworld_cheatsafe, r_fullbright_cheatsafe, r_lightmap_cheatsafe; //johnfitz
109 
110 cvar_t	r_scale = {"r_scale", "1", CVAR_ARCHIVE};
111 
112 /*
113 =================
114 R_CullBox -- johnfitz -- replaced with new function from lordhavoc
115 
116 Returns true if the box is completely outside the frustum
117 =================
118 */
R_CullBox(vec3_t emins,vec3_t emaxs)119 qboolean R_CullBox (vec3_t emins, vec3_t emaxs)
120 {
121 	int i;
122 	mplane_t *p;
123 	byte signbits;
124 	float vec[3];
125 	for (i = 0;i < 4;i++)
126 	{
127 		p = frustum + i;
128 		signbits = p->signbits;
129 		vec[0] = ((signbits % 2)<1) ? emaxs[0] : emins[0];
130 		vec[1] = ((signbits % 4)<2) ? emaxs[1] : emins[1];
131 		vec[2] = ((signbits % 8)<4) ? emaxs[2] : emins[2];
132 		if (p->normal[0]*vec[0] + p->normal[1]*vec[1] + p->normal[2]*vec[2] < p->dist)
133 			return true;
134 	}
135 	return false;
136 }
137 /*
138 ===============
139 R_CullModelForEntity -- johnfitz -- uses correct bounds based on rotation
140 ===============
141 */
R_CullModelForEntity(entity_t * e)142 qboolean R_CullModelForEntity (entity_t *e)
143 {
144 	vec3_t mins, maxs;
145 
146 	if (e->angles[0] || e->angles[2]) //pitch or roll
147 	{
148 		VectorAdd (e->origin, e->model->rmins, mins);
149 		VectorAdd (e->origin, e->model->rmaxs, maxs);
150 	}
151 	else if (e->angles[1]) //yaw
152 	{
153 		VectorAdd (e->origin, e->model->ymins, mins);
154 		VectorAdd (e->origin, e->model->ymaxs, maxs);
155 	}
156 	else //no rotation
157 	{
158 		VectorAdd (e->origin, e->model->mins, mins);
159 		VectorAdd (e->origin, e->model->maxs, maxs);
160 	}
161 
162 	return R_CullBox (mins, maxs);
163 }
164 
165 /*
166 ===============
167 R_RotateForEntity -- johnfitz -- modified to take origin and angles instead of pointer to entity
168 ===============
169 */
170 #define DEG2RAD( a ) ( (a) * M_PI_DIV_180 )
R_RotateForEntity(float matrix[16],vec3_t origin,vec3_t angles)171 void R_RotateForEntity (float matrix[16], vec3_t origin, vec3_t angles)
172 {
173 	float translation_matrix[16];
174 	TranslationMatrix (translation_matrix, origin[0], origin[1], origin[2]);
175 	MatrixMultiply (matrix, translation_matrix);
176 
177 	float rotation_matrix[16];
178 	RotationMatrix (rotation_matrix, DEG2RAD(angles[1]), 0, 0, 1);
179 	MatrixMultiply (matrix, rotation_matrix);
180 	RotationMatrix (rotation_matrix, DEG2RAD(-angles[0]), 0, 1, 0);
181 	MatrixMultiply (matrix, rotation_matrix);
182 	RotationMatrix (rotation_matrix, DEG2RAD(angles[2]), 1, 0, 0);
183 	MatrixMultiply (matrix, rotation_matrix);
184 }
185 
186 //==============================================================================
187 //
188 // SETUP FRAME
189 //
190 //==============================================================================
191 
SignbitsForPlane(mplane_t * out)192 int SignbitsForPlane (mplane_t *out)
193 {
194 	int	bits, j;
195 
196 	// for fast box on planeside test
197 
198 	bits = 0;
199 	for (j=0 ; j<3 ; j++)
200 	{
201 		if (out->normal[j] < 0)
202 			bits |= 1<<j;
203 	}
204 	return bits;
205 }
206 
207 /*
208 ===============
209 TurnVector -- johnfitz
210 
211 turn forward towards side on the plane defined by forward and side
212 if angle = 90, the result will be equal to side
213 assumes side and forward are perpendicular, and normalized
214 to turn away from side, use a negative angle
215 ===============
216 */
217 #define DEG2RAD( a ) ( (a) * M_PI_DIV_180 )
TurnVector(vec3_t out,const vec3_t forward,const vec3_t side,float angle)218 void TurnVector (vec3_t out, const vec3_t forward, const vec3_t side, float angle)
219 {
220 	float scale_forward, scale_side;
221 
222 	scale_forward = cos( DEG2RAD( angle ) );
223 	scale_side = sin( DEG2RAD( angle ) );
224 
225 	out[0] = scale_forward*forward[0] + scale_side*side[0];
226 	out[1] = scale_forward*forward[1] + scale_side*side[1];
227 	out[2] = scale_forward*forward[2] + scale_side*side[2];
228 }
229 
230 /*
231 ===============
232 R_SetFrustum -- johnfitz -- rewritten
233 ===============
234 */
R_SetFrustum(float fovx,float fovy)235 void R_SetFrustum (float fovx, float fovy)
236 {
237 	int		i;
238 
239 	TurnVector(frustum[0].normal, vpn, vright, fovx/2 - 90); //right plane
240 	TurnVector(frustum[1].normal, vpn, vright, 90 - fovx/2); //left plane
241 	TurnVector(frustum[2].normal, vpn, vup, 90 - fovy/2); //bottom plane
242 	TurnVector(frustum[3].normal, vpn, vup, fovy/2 - 90); //top plane
243 
244 	for (i=0 ; i<4 ; i++)
245 	{
246 		frustum[i].type = PLANE_ANYZ;
247 		frustum[i].dist = DotProduct (r_origin, frustum[i].normal); //FIXME: shouldn't this always be zero?
248 		frustum[i].signbits = SignbitsForPlane (&frustum[i]);
249 	}
250 }
251 
252 /*
253 =============
254 GL_FrustumMatrix
255 =============
256 */
257 #define NEARCLIP 4
GL_FrustumMatrix(float matrix[16],float fovx,float fovy)258 static void GL_FrustumMatrix(float matrix[16], float fovx, float fovy)
259 {
260 	const float w = 1.0f / tanf(fovx * 0.5f);
261 	const float h = 1.0f / tanf(fovy * 0.5f);
262 
263 	// reduce near clip distance at high FOV's to avoid seeing through walls
264 	const float d = 12.f * q_min(w, h);
265 	const float n = CLAMP(0.5f, d, NEARCLIP);
266 	const float f = gl_farclip.value;
267 
268 	memset(matrix, 0, 16 * sizeof(float));
269 
270 	// First column
271 	matrix[0*4 + 0] = w;
272 
273 	// Second column
274 	matrix[1*4 + 1] = -h;
275 
276 	// Third column
277 	matrix[2*4 + 2] = f / (f - n) - 1.0f;
278 	matrix[2*4 + 3] = -1.0f;
279 
280 	// Fourth column
281 	matrix[3*4 + 2] = (n * f) / (f - n);
282 }
283 
284 /*
285 =============
286 R_SetupMatrix
287 =============
288 */
R_SetupMatrix(void)289 void R_SetupMatrix (void)
290 {
291 	GL_Viewport(glx + r_refdef.vrect.x,
292 				gly + glheight - r_refdef.vrect.y - r_refdef.vrect.height,
293 				r_refdef.vrect.width,
294 				r_refdef.vrect.height,
295 				0.0f, 1.0f);
296 
297 	// Projection matrix
298 	GL_FrustumMatrix(vulkan_globals.projection_matrix, DEG2RAD(r_fovx), DEG2RAD(r_fovy));
299 
300 	// View matrix
301 	float rotation_matrix[16];
302 	RotationMatrix(vulkan_globals.view_matrix, -M_PI / 2.0f, 1.0f, 0.0f, 0.0f);
303 	RotationMatrix(rotation_matrix,  M_PI / 2.0f, 0.0f, 0.0f, 1.0f);
304 	MatrixMultiply(vulkan_globals.view_matrix, rotation_matrix);
305 	RotationMatrix(rotation_matrix, DEG2RAD(-r_refdef.viewangles[2]), 1.0f, 0.0f, 0.0f);
306 	MatrixMultiply(vulkan_globals.view_matrix, rotation_matrix);
307 	RotationMatrix(rotation_matrix, DEG2RAD(-r_refdef.viewangles[0]), 0.0f, 1.0f, 0.0f);
308 	MatrixMultiply(vulkan_globals.view_matrix, rotation_matrix);
309 	RotationMatrix(rotation_matrix, DEG2RAD(-r_refdef.viewangles[1]), 0.0f, 0.0f, 1.0f);
310 	MatrixMultiply(vulkan_globals.view_matrix, rotation_matrix);
311 
312 	float translation_matrix[16];
313 	TranslationMatrix(translation_matrix, -r_refdef.vieworg[0], -r_refdef.vieworg[1], -r_refdef.vieworg[2]);
314 	MatrixMultiply(vulkan_globals.view_matrix, translation_matrix);
315 
316 	// View projection matrix
317 	memcpy(vulkan_globals.view_projection_matrix, vulkan_globals.projection_matrix, 16 * sizeof(float));
318 	MatrixMultiply(vulkan_globals.view_projection_matrix, vulkan_globals.view_matrix);
319 
320 	R_BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_globals.basic_blend_pipeline[render_pass_index]);
321 	R_PushConstants(VK_SHADER_STAGE_ALL_GRAPHICS, 0, 16 * sizeof(float), vulkan_globals.view_projection_matrix);
322 }
323 
324 /*
325 ===============
326 R_SetupScene
327 ===============
328 */
R_SetupScene(void)329 void R_SetupScene (void)
330 {
331 	render_pass_index = 0;
332 	qboolean screen_effects = render_warp || (render_scale >= 2);
333 	vkCmdBeginRenderPass(vulkan_globals.command_buffer, &vulkan_globals.main_render_pass_begin_infos[screen_effects ? 1 : 0], VK_SUBPASS_CONTENTS_INLINE);
334 
335 	R_SetupMatrix ();
336 }
337 
338 /*
339 ===============
340 R_SetupView
341 ===============
342 */
R_SetupView(void)343 void R_SetupView (void)
344 {
345 	// Need to do those early because we now update dynamic light maps during R_MarkSurfaces
346 	R_PushDlights ();
347 	R_AnimateLight ();
348 	r_framecount++;
349 
350 	Fog_SetupFrame (); //johnfitz
351 
352 // build the transformation matrix for the given view angles
353 	VectorCopy (r_refdef.vieworg, r_origin);
354 	AngleVectors (r_refdef.viewangles, vpn, vright, vup);
355 
356 // current viewleaf
357 	r_oldviewleaf = r_viewleaf;
358 	r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);
359 
360 	V_SetContentsColor (r_viewleaf->contents);
361 	V_CalcBlend ();
362 
363 	r_cache_thrash = false;
364 
365 	//johnfitz -- calculate r_fovx and r_fovy here
366 	r_fovx = r_refdef.fov_x;
367 	r_fovy = r_refdef.fov_y;
368 	render_warp = false;
369 	render_scale = (int)r_scale.value;
370 
371 	if (r_waterwarp.value)
372 	{
373 		int contents = Mod_PointInLeaf (r_origin, cl.worldmodel)->contents;
374 		if (contents == CONTENTS_WATER || contents == CONTENTS_SLIME || contents == CONTENTS_LAVA)
375 		{
376 			if (r_waterwarp.value == 1)
377 				render_warp = true;
378 			else
379 			{
380 				//variance is a percentage of width, where width = 2 * tan(fov / 2) otherwise the effect is too dramatic at high FOV and too subtle at low FOV.  what a mess!
381 				r_fovx = atan(tan(DEG2RAD(r_refdef.fov_x) / 2) * (0.97 + sin(cl.time * 1.5) * 0.03)) * 2 / M_PI_DIV_180;
382 				r_fovy = atan(tan(DEG2RAD(r_refdef.fov_y) / 2) * (1.03 - sin(cl.time * 1.5) * 0.03)) * 2 / M_PI_DIV_180;
383 			}
384 		}
385 	}
386 	//johnfitz
387 
388 	R_SetFrustum (r_fovx, r_fovy); //johnfitz -- use r_fov* vars
389 
390 	R_MarkSurfaces (); //johnfitz -- create texture chains from PVS
391 
392 	R_UpdateWarpTextures (); //johnfitz -- do this before R_Clear
393 
394 	//johnfitz -- cheat-protect some draw modes
395 	r_fullbright_cheatsafe = false;
396 	r_lightmap_cheatsafe = false;
397 	r_drawworld_cheatsafe = true;
398 	if (cl.maxclients == 1)
399 	{
400 		if (!r_drawworld.value) r_drawworld_cheatsafe = false;
401 		if (r_fullbright.value) r_fullbright_cheatsafe = true;
402 		else if (r_lightmap.value) r_lightmap_cheatsafe = true;
403 	}
404 	//johnfitz
405 }
406 
407 //==============================================================================
408 //
409 // RENDER VIEW
410 //
411 //==============================================================================
412 
413 /*
414 =============
415 R_DrawEntitiesOnList
416 =============
417 */
R_DrawEntitiesOnList(qboolean alphapass)418 void R_DrawEntitiesOnList (qboolean alphapass) //johnfitz -- added parameter
419 {
420 	int		i;
421 
422 	if (!r_drawentities.value)
423 		return;
424 
425 	R_BeginDebugUtilsLabel (alphapass ? "Entities Alpha Pass" : "Entities" );
426 	//johnfitz -- sprites are not a special case
427 	for (i=0 ; i<cl_numvisedicts ; i++)
428 	{
429 		currententity = cl_visedicts[i];
430 
431 		//johnfitz -- if alphapass is true, draw only alpha entites this time
432 		//if alphapass is false, draw only nonalpha entities this time
433 		if ((ENTALPHA_DECODE(currententity->alpha) < 1 && !alphapass) ||
434 			(ENTALPHA_DECODE(currententity->alpha) == 1 && alphapass))
435 			continue;
436 
437 		//johnfitz -- chasecam
438 		if (currententity == &cl.entities[cl.viewentity])
439 			currententity->angles[0] *= 0.3;
440 		//johnfitz
441 
442 		//spike -- this would be more efficient elsewhere, but its more correct here.
443 		if (currententity->eflags & EFLAGS_EXTERIORMODEL)
444 			continue;
445 
446 		switch (currententity->model->type)
447 		{
448 			case mod_alias:
449 				R_DrawAliasModel (currententity);
450 				break;
451 			case mod_brush:
452 				R_DrawBrushModel (currententity);
453 				break;
454 			case mod_sprite:
455 				R_DrawSpriteModel (currententity);
456 				break;
457 		}
458 	}
459 	R_EndDebugUtilsLabel();
460 }
461 
462 /*
463 =============
464 R_DrawViewModel -- johnfitz -- gutted
465 =============
466 */
R_DrawViewModel(void)467 void R_DrawViewModel (void)
468 {
469 	if (!r_drawviewmodel.value || !r_drawentities.value || chase_active.value)
470 		return;
471 
472 	if (cl.items & IT_INVISIBILITY || cl.stats[STAT_HEALTH] <= 0)
473 		return;
474 
475 	currententity = &cl.viewent;
476 	if (!currententity->model)
477 		return;
478 
479 	//johnfitz -- this fixes a crash
480 	if (currententity->model->type != mod_alias)
481 		return;
482 	//johnfitz
483 
484 	R_BeginDebugUtilsLabel ("View Model");
485 
486 	// hack the depth range to prevent view model from poking into walls
487 	GL_Viewport(glx + r_refdef.vrect.x,
488 				gly + glheight - r_refdef.vrect.y - r_refdef.vrect.height,
489 				r_refdef.vrect.width,
490 				r_refdef.vrect.height,
491 				0.7f, 1.0f);
492 
493 	R_DrawAliasModel (currententity);
494 
495 	GL_Viewport(glx + r_refdef.vrect.x,
496 				gly + glheight - r_refdef.vrect.y - r_refdef.vrect.height,
497 				r_refdef.vrect.width,
498 				r_refdef.vrect.height,
499 				0.0f, 1.0f);
500 
501 	R_EndDebugUtilsLabel ();
502 }
503 
504 /*
505 ================
506 R_EmitWirePoint -- johnfitz -- draws a wireframe cross shape for point entities
507 ================
508 */
R_EmitWirePoint(vec3_t origin)509 void R_EmitWirePoint (vec3_t origin)
510 {
511 	VkBuffer vertex_buffer;
512 	VkDeviceSize vertex_buffer_offset;
513 	basicvertex_t * vertices = (basicvertex_t*)R_VertexAllocate(6 * sizeof(basicvertex_t), &vertex_buffer, &vertex_buffer_offset);
514 	int size=8;
515 
516 	vertices[0].position[0] = origin[0]-size;
517 	vertices[0].position[1] = origin[1];
518 	vertices[0].position[2] = origin[2];
519 	vertices[1].position[0] = origin[0]+size;
520 	vertices[1].position[1] = origin[1];
521 	vertices[1].position[2] = origin[2];
522 	vertices[2].position[0] = origin[0];
523 	vertices[2].position[1] = origin[1]-size;
524 	vertices[2].position[2] = origin[2];
525 	vertices[3].position[0] = origin[0];
526 	vertices[3].position[1] = origin[1]+size;
527 	vertices[3].position[2] = origin[2];
528 	vertices[4].position[0] = origin[0];
529 	vertices[4].position[1] = origin[1];
530 	vertices[4].position[2] = origin[2]-size;
531 	vertices[5].position[0] = origin[0];
532 	vertices[5].position[1] = origin[1];
533 	vertices[5].position[2] = origin[2]+size;
534 
535 	vulkan_globals.vk_cmd_bind_vertex_buffers(vulkan_globals.command_buffer, 0, 1, &vertex_buffer, &vertex_buffer_offset);
536 	vulkan_globals.vk_cmd_draw(vulkan_globals.command_buffer, 6, 1, 0, 0);
537 }
538 
539 /*
540 ================
541 R_EmitWireBox -- johnfitz -- draws one axis aligned bounding box
542 ================
543 */
R_EmitWireBox(vec3_t mins,vec3_t maxs,VkBuffer box_index_buffer,VkDeviceSize box_index_buffer_offset)544 void R_EmitWireBox (vec3_t mins, vec3_t maxs, VkBuffer box_index_buffer, VkDeviceSize box_index_buffer_offset)
545 {
546 	VkBuffer vertex_buffer;
547 	VkDeviceSize vertex_buffer_offset;
548 	basicvertex_t * vertices = (basicvertex_t*)R_VertexAllocate(8 * sizeof(basicvertex_t), &vertex_buffer, &vertex_buffer_offset);
549 
550 	for (int i = 0; i < 8; ++i)
551 	{
552 		vertices[i].position[0] = ((i % 2) < 1) ? mins[0] : maxs[0];
553 		vertices[i].position[1] = ((i % 4) < 2) ? mins[1] : maxs[1];
554 		vertices[i].position[2] = ((i % 8) < 4) ? mins[2] : maxs[2];
555 	}
556 
557 	vulkan_globals.vk_cmd_bind_index_buffer(vulkan_globals.command_buffer, box_index_buffer, box_index_buffer_offset, VK_INDEX_TYPE_UINT16);
558 	vulkan_globals.vk_cmd_bind_vertex_buffers(vulkan_globals.command_buffer, 0, 1, &vertex_buffer, &vertex_buffer_offset);
559 	vulkan_globals.vk_cmd_draw_indexed(vulkan_globals.command_buffer, 24, 1, 0, 0, 0);
560 }
561 
562 static uint16_t box_indices[24] =
563 {
564 	0, 1, 2, 3, 4, 5, 6, 7,
565 	0, 4, 1, 5, 2, 6, 3, 7,
566 	0, 2, 1, 3, 4, 6, 5, 7
567 };
568 
569 /*
570 ================
571 R_ShowBoundingBoxes -- johnfitz
572 
573 draw bounding boxes -- the server-side boxes, not the renderer cullboxes
574 ================
575 */
R_ShowBoundingBoxes(void)576 void R_ShowBoundingBoxes (void)
577 {
578 	extern		edict_t *sv_player;
579 	vec3_t		mins,maxs;
580 	edict_t		*ed;
581 	int			i;
582 
583 	if (!r_showbboxes.value || cl.maxclients > 1 || !r_drawentities.value || !sv.active)
584 		return;
585 
586 	R_BeginDebugUtilsLabel ("show bboxes");
587 	R_BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, vulkan_globals.showbboxes_pipeline);
588 
589 	VkBuffer box_index_buffer;
590 	VkDeviceSize box_index_buffer_offset;
591 	uint16_t * indices = (uint16_t *)R_IndexAllocate(24 * sizeof(uint16_t), &box_index_buffer, &box_index_buffer_offset);
592 	memcpy(indices, box_indices, 24 * sizeof(uint16_t));
593 
594 	PR_SwitchQCVM(&sv.qcvm);
595 	for (i=0, ed=NEXT_EDICT(qcvm->edicts) ; i<qcvm->num_edicts ; i++, ed=NEXT_EDICT(ed))
596 	{
597 		if (ed == sv_player)
598 			continue; //don't draw player's own bbox
599 
600 		if (ed->v.mins[0] == ed->v.maxs[0] && ed->v.mins[1] == ed->v.maxs[1] && ed->v.mins[2] == ed->v.maxs[2])
601 		{
602 			//point entity
603 			R_EmitWirePoint (ed->v.origin);
604 		}
605 		else
606 		{
607 			//box entity
608 			VectorAdd (ed->v.mins, ed->v.origin, mins);
609 			VectorAdd (ed->v.maxs, ed->v.origin, maxs);
610 			R_EmitWireBox (mins, maxs, box_index_buffer, box_index_buffer_offset);
611 		}
612 	}
613 	PR_SwitchQCVM(NULL);
614 
615 	Sbar_Changed (); //so we don't get dots collecting on the statusbar
616 	R_EndDebugUtilsLabel ();
617 }
618 
619 /*
620 ================
621 R_ShowTris -- johnfitz
622 ================
623 */
R_ShowTris(void)624 void R_ShowTris(void)
625 {
626 	extern cvar_t r_particles;
627 	int i;
628 
629 	if (r_showtris.value < 1 || r_showtris.value > 2 || cl.maxclients > 1 || !vulkan_globals.non_solid_fill)
630 		return;
631 
632 	R_BeginDebugUtilsLabel ("show tris");
633 	if (r_drawworld.value)
634 		R_DrawWorld_ShowTris();
635 
636 	if (r_drawentities.value)
637 	{
638 		for (i=0 ; i<cl_numvisedicts ; i++)
639 		{
640 			currententity = cl_visedicts[i];
641 
642 			if (currententity == &cl.entities[cl.viewentity]) // chasecam
643 				currententity->angles[0] *= 0.3;
644 
645 			switch (currententity->model->type)
646 			{
647 			case mod_brush:
648 				R_DrawBrushModel_ShowTris (currententity);
649 				break;
650 			case mod_alias:
651 				R_DrawAliasModel_ShowTris (currententity);
652 				break;
653 			case mod_sprite:
654 				R_DrawSpriteModel_ShowTris (currententity);
655 				break;
656 			default:
657 				break;
658 			}
659 		}
660 
661 		// viewmodel
662 		currententity = &cl.viewent;
663 		if (r_drawviewmodel.value
664 			&& !chase_active.value
665 			&& cl.stats[STAT_HEALTH] > 0
666 			&& !(cl.items & IT_INVISIBILITY)
667 			&& currententity->model
668 			&& currententity->model->type == mod_alias)
669 		{
670 			R_DrawAliasModel_ShowTris (currententity);
671 		}
672 	}
673 
674 	if (r_particles.value)
675 	{
676 		R_DrawParticles_ShowTris();
677 #ifdef PSET_SCRIPT
678 		PScript_DrawParticles_ShowTris();
679 #endif
680 	}
681 
682 	Sbar_Changed(); //so we don't get dots collecting on the statusbar
683 	R_EndDebugUtilsLabel ();
684 }
685 
686 /*
687 ================
688 R_RenderScene
689 ================
690 */
R_RenderScene(void)691 void R_RenderScene (void)
692 {
693 	static entity_t r_worldentity;	//so we can make sure currententity is valid
694 	currententity = &r_worldentity;
695 	R_SetupScene (); //johnfitz -- this does everything that should be done once per call to RenderScene
696 
697 	Fog_EnableGFog (); //johnfitz
698 
699 	R_DrawWorld ();
700 	currententity = NULL;
701 
702 	S_ExtraUpdate (); // don't let sound get messed up if going slow
703 
704 	R_DrawEntitiesOnList (false); //johnfitz -- false means this is the pass for nonalpha entities
705 
706 	Sky_DrawSky (); //johnfitz
707 
708 	R_DrawWorld_Water (); //johnfitz -- drawn here since they might have transparency
709 
710 	R_DrawEntitiesOnList (true); //johnfitz -- true means this is the pass for alpha entities
711 
712 	R_DrawParticles ();
713 #ifdef PSET_SCRIPT
714 	PScript_DrawParticles();
715 #endif
716 
717 	Fog_DisableGFog (); //johnfitz
718 
719 	R_DrawViewModel (); //johnfitz -- moved here from R_RenderView
720 
721 	R_ShowTris(); //johnfitz
722 
723 	R_ShowBoundingBoxes (); //johnfitz
724 }
725 
726 /*
727 ================
728 R_RenderView
729 ================
730 */
R_RenderView(void)731 void R_RenderView (void)
732 {
733 	double	time1, time2;
734 
735 	if (!cl.worldmodel)
736 		Sys_Error ("R_RenderView: NULL worldmodel");
737 
738 	time1 = 0; /* avoid compiler warning */
739 	if (r_speeds.value)
740 	{
741 		time1 = Sys_DoubleTime ();
742 
743 		//johnfitz -- rendering statistics
744 		rs_brushpolys = rs_aliaspolys = rs_skypolys = rs_particles = rs_fogpolys = rs_megatexels =
745 		rs_dynamiclightmaps = rs_aliaspasses = rs_skypasses = rs_brushpasses = 0;
746 	}
747 
748 	R_SetupView (); //johnfitz -- this does everything that should be done once per frame
749 
750 	R_RenderScene ();
751 
752 	//johnfitz
753 
754 	//johnfitz -- modified r_speeds output
755 	time2 = Sys_DoubleTime ();
756 	if (r_pos.value)
757 		Con_Printf ("x %i y %i z %i (pitch %i yaw %i roll %i)\n",
758 			(int)cl.entities[cl.viewentity].origin[0],
759 			(int)cl.entities[cl.viewentity].origin[1],
760 			(int)cl.entities[cl.viewentity].origin[2],
761 			(int)cl.viewangles[PITCH],
762 			(int)cl.viewangles[YAW],
763 			(int)cl.viewangles[ROLL]);
764 	else if (r_speeds.value == 2)
765 		Con_Printf ("%6.3f ms  %4u/%4u wpoly %4u/%4u epoly %3u lmap %4u/%4u sky\n",
766 					(time2-time1)*1000.0,
767 					rs_brushpolys,
768 					rs_brushpasses,
769 					rs_aliaspolys,
770 					rs_aliaspasses,
771 					rs_dynamiclightmaps,
772 					rs_skypolys,
773 					rs_skypasses);
774 	else if (r_speeds.value)
775 		Con_Printf ("%3i ms  %4i wpoly %4i epoly %3i lmap\n",
776 					(int)((time2-time1)*1000),
777 					rs_brushpolys,
778 					rs_aliaspolys,
779 					rs_dynamiclightmaps);
780 	//johnfitz
781 }
782 
783