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