From 495dd759f0e385c91dea50339230f46c26150950 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 30 Mar 2022 14:55:32 +0900 Subject: [PATCH] [renderer] Clean up FOV and viewport handling Viewport and FOV updates are now separate so updating one doesn't cause recalculations of the other. Also, perspective setup is now done directly from the tangents of the half angles for fov_x and fov_y making the renderers independent of fov/aspect mode. I imagine things are a bit of a mess with view size changes, and especially screen size changes (not supported yet anyway), and vulkan winds up updating its projection matrices every frame, but everything that's expected to work does (vulkan errors out for fisheye or warp due to frame buffer creation not being supported yet). --- include/QF/Vulkan/projection.h | 6 +- include/QF/Vulkan/qf_matrices.h | 1 - include/QF/plugin/vid_render.h | 3 +- include/QF/render.h | 2 - include/QF/screen.h | 1 + include/vid_gl.h | 4 + libs/video/renderer/gl/gl_fisheye.c | 2 - libs/video/renderer/gl/gl_rmain.c | 33 +----- libs/video/renderer/gl/gl_rmisc.c | 5 - libs/video/renderer/glsl/glsl_main.c | 29 +---- libs/video/renderer/r_cvar.c | 2 +- libs/video/renderer/r_screen.c | 27 ++--- libs/video/renderer/sw/sw_rmain.c | 108 ------------------ libs/video/renderer/vid_render_gl.c | 30 ++++- libs/video/renderer/vid_render_glsl.c | 30 ++++- libs/video/renderer/vid_render_sw.c | 112 ++++++++++++++++++- libs/video/renderer/vid_render_vulkan.c | 32 ++++-- libs/video/renderer/vulkan/projection.c | 18 +-- libs/video/renderer/vulkan/vulkan_lighting.c | 2 +- libs/video/renderer/vulkan/vulkan_matrices.c | 35 ------ 20 files changed, 224 insertions(+), 258 deletions(-) diff --git a/include/QF/Vulkan/projection.h b/include/QF/Vulkan/projection.h index 7a1dc96bd..7936008aa 100644 --- a/include/QF/Vulkan/projection.h +++ b/include/QF/Vulkan/projection.h @@ -5,8 +5,8 @@ void QFV_Orthographic (mat4f_t proj, float xmin, float xmax, float ymin, float ymax, float znear, float zfar); -void QFV_PerspectiveTan (mat4f_t proj, float fov, float aspect); -void QFV_PerspectiveCos (mat4f_t proj, float fov, float aspect); -void QFV_Perspective (mat4f_t proj, float fov, float aspect); +// fov_x and fov_y are tan(fov/2) for x and y respectively +void QFV_PerspectiveTan (mat4f_t proj, float fov_x, float fov_y); +void QFV_PerspectiveCos (mat4f_t proj, float fov); #endif//__QF_Vulkan_projection_h diff --git a/include/QF/Vulkan/qf_matrices.h b/include/QF/Vulkan/qf_matrices.h index 9a3df6f58..4a8d0e413 100644 --- a/include/QF/Vulkan/qf_matrices.h +++ b/include/QF/Vulkan/qf_matrices.h @@ -78,7 +78,6 @@ typedef struct matrixctx_s { struct vulkan_ctx_s; struct qfv_renderframe_s; -void Vulkan_CalcProjectionMatrices (struct vulkan_ctx_s *ctx); void Vulkan_CalcViewMatrix (struct vulkan_ctx_s *ctx); void Vulkan_SetViewMatrix (struct vulkan_ctx_s *ctx, mat4f_t view); void Vulkan_SetSkyMatrix (struct vulkan_ctx_s *ctx, mat4f_t sky); diff --git a/include/QF/plugin/vid_render.h b/include/QF/plugin/vid_render.h index 60fda8e3b..c0ad899c9 100644 --- a/include/QF/plugin/vid_render.h +++ b/include/QF/plugin/vid_render.h @@ -107,7 +107,6 @@ typedef struct vid_render_funcs_s { void (*R_LoadSkys) (const char *); void (*R_NewMap) (model_t *worldmodel, model_t **models, int num_models); void (*R_LineGraph) (int x, int y, int *h_vals, int count, int height); - void (*R_ViewChanged) (void); void (*begin_frame) (void); void (*render_view) (void); @@ -122,6 +121,8 @@ typedef struct vid_render_funcs_s { struct framebuffer_s *(*create_frame_buffer) (int width, int height); void (*bind_framebuffer) (struct framebuffer_s *framebuffer); void (*set_viewport) (const struct vrect_s *view); + // x and y are tan(f/2) for fov_x and fov_y + void (*set_fov) (float x, float y); vid_model_funcs_t *model_funcs; } vid_render_funcs_t; diff --git a/include/QF/render.h b/include/QF/render.h index 124e9ae0a..d989bd38b 100644 --- a/include/QF/render.h +++ b/include/QF/render.h @@ -166,8 +166,6 @@ typedef struct { int ambientlight; int drawflat; - float fov_x, fov_y; - struct model_s *worldmodel; struct mleaf_s *viewleaf; } refdef_t; diff --git a/include/QF/screen.h b/include/QF/screen.h index 892fd6cf3..11a591f87 100644 --- a/include/QF/screen.h +++ b/include/QF/screen.h @@ -42,6 +42,7 @@ typedef void (*SCR_Func)(void); // scr_funcs is a null terminated array void SCR_UpdateScreen (struct transform_s *camera, double realtime, SCR_Func *scr_funcs); +void SCR_SetFOV (float fov); // control whether the 3d viewport is user-controlled or always fullscreen void SCR_SetFullscreen (qboolean fullscreen); void SCR_SetBottomMargin (int lines); diff --git a/include/vid_gl.h b/include/vid_gl.h index 26d445770..6249790dd 100644 --- a/include/vid_gl.h +++ b/include/vid_gl.h @@ -1,6 +1,8 @@ #ifndef __vid_gl_h #define __vid_gl_h +#include "QF/simd/types.h" + // GL_context is a pointer to opaque data typedef struct GL_context *GL_context; @@ -13,6 +15,8 @@ typedef struct gl_ctx_s { void *(*get_proc_address) (const char *name, qboolean crit); void (*end_rendering) (void); + mat4f_t projection; + int begun; double start_time; int brush_polys; diff --git a/libs/video/renderer/gl/gl_fisheye.c b/libs/video/renderer/gl/gl_fisheye.c index edace6c55..bb0a34e21 100644 --- a/libs/video/renderer/gl/gl_fisheye.c +++ b/libs/video/renderer/gl/gl_fisheye.c @@ -166,8 +166,6 @@ gl_FisheyeScreen (framebuffer_t *fb) gl_framebuffer_t *buffer = fb->buffer; - qfglViewport (r_refdef.vrect.x, r_refdef.vrect.x, - r_refdef.vrect.width, r_refdef.vrect.height); qfglMatrixMode (GL_PROJECTION); qfglLoadIdentity (); qfglOrtho (0, r_refdef.vrect.width, r_refdef.vrect.height, 0, -9999, 9999); diff --git a/libs/video/renderer/gl/gl_rmain.c b/libs/video/renderer/gl/gl_rmain.c index a782abae0..19da42cbe 100644 --- a/libs/video/renderer/gl/gl_rmain.c +++ b/libs/video/renderer/gl/gl_rmain.c @@ -229,40 +229,11 @@ R_DrawViewModel (void) qfglDepthRange (gldepthmin, gldepthmax); } -static void -R_Perspective (void) -{ - float aspect = (float) r_refdef.vrect.width / r_refdef.vrect.height; - float f = 1 / tan (r_refdef.fov_y * M_PI / 360); - float neard, fard; - mat4f_t proj; - - neard = r_nearclip->value; - fard = r_farclip->value; - - // NOTE columns! - proj[0] = (vec4f_t) { f / aspect, 0, 0, 0 }; - proj[1] = (vec4f_t) { 0, f, 0, 0 }; - proj[2] = (vec4f_t) { 0, 0, (fard) / (fard - neard), 1 }; - proj[3] = (vec4f_t) { 0, 0, (fard * neard) / (neard - fard), 0 }; - - // convert 0..1 depth buffer range to -1..1 - static mat4f_t depth_range = { - { 1, 0, 0, 0}, - { 0, 1, 0, 0}, - { 0, 0, 2, 0}, - { 0, 0,-1, 1}, - }; - mmulf (proj, depth_range, proj); - - qfglMatrixMode (GL_PROJECTION); - qfglLoadMatrixf (&proj[0][0]); -} - static void R_SetupGL (void) { - R_Perspective (); + qfglMatrixMode (GL_PROJECTION); + qfglLoadMatrixf (&gl_ctx->projection[0][0]); qfglFrontFace (GL_CW); diff --git a/libs/video/renderer/gl/gl_rmisc.c b/libs/video/renderer/gl/gl_rmisc.c index f5f822dd6..fc72d7f96 100644 --- a/libs/video/renderer/gl/gl_rmisc.c +++ b/libs/video/renderer/gl/gl_rmisc.c @@ -200,8 +200,3 @@ gl_R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) register_textures (&models[i]->brush); } } - -void -gl_R_ViewChanged (void) -{ -} diff --git a/libs/video/renderer/glsl/glsl_main.c b/libs/video/renderer/glsl/glsl_main.c index c0195d394..892f8d235 100644 --- a/libs/video/renderer/glsl/glsl_main.c +++ b/libs/video/renderer/glsl/glsl_main.c @@ -68,33 +68,6 @@ mat4f_t glsl_projection; mat4f_t glsl_view; -void -glsl_R_ViewChanged (void) -{ - float aspect = (float) r_refdef.vrect.width / r_refdef.vrect.height; - float f = 1 / tan (r_refdef.fov_y * M_PI / 360); - float neard, fard; - vec4f_t *proj = glsl_projection; - - neard = r_nearclip->value; - fard = r_farclip->value; - - // NOTE columns! - proj[0] = (vec4f_t) { f / aspect, 0, 0, 0 }; - proj[1] = (vec4f_t) { 0, f, 0, 0 }; - proj[2] = (vec4f_t) { 0, 0, (fard) / (fard - neard), 1 }; - proj[3] = (vec4f_t) { 0, 0, (fard * neard) / (neard - fard), 0 }; - - // convert 0..1 depth buffer range to -1..1 - static mat4f_t depth_range = { - { 1, 0, 0, 0}, - { 0, 1, 0, 0}, - { 0, 0, 2, 0}, - { 0, 0,-1, 1}, - }; - mmulf (proj, depth_range, proj); -} - static void R_SetupView (void) { @@ -164,6 +137,8 @@ glsl_R_RenderView (void) return; } + memcpy (glsl_projection, glsl_ctx->projection, sizeof (mat4f_t)); + R_SetupView (); glsl_R_DrawWorld (); glsl_R_DrawSky (); diff --git a/libs/video/renderer/r_cvar.c b/libs/video/renderer/r_cvar.c index c7b96969c..83c5f1958 100644 --- a/libs/video/renderer/r_cvar.c +++ b/libs/video/renderer/r_cvar.c @@ -167,7 +167,7 @@ scr_fov_f (cvar_t *var) if (fov != var->value) { Cvar_SetValue (var, fov); } else { - r_data->vid->recalc_refdef = 1; + SCR_SetFOV (var->value); } } diff --git a/libs/video/renderer/r_screen.c b/libs/video/renderer/r_screen.c index 5de3b8184..cd8ff5102 100644 --- a/libs/video/renderer/r_screen.c +++ b/libs/video/renderer/r_screen.c @@ -69,6 +69,9 @@ static qpic_t *scr_turtle; static framebuffer_t *fisheye_cube_map; static framebuffer_t *warp_buffer; +static float fov_x, fov_y; +static float tan_fov_x, tan_fov_y; + static mat4f_t box_rotations[] = { [BOX_FRONT] = { { 1, 0, 0, 0}, // front @@ -146,8 +149,8 @@ R_SetVrect (const vrect_t *vrectin, vrect_t *vrect, int lineadj) set_vrect (vrectin, vrect, lineadj); } -static void -set_fov (float fov) +void +SCR_SetFOV (float fov) { refdef_t *refdef = r_data->refdef; @@ -158,8 +161,11 @@ set_fov (float fov) double w = refdef->vrect.width; double h = refdef->vrect.height; - refdef->fov_x = fov; - refdef->fov_y = 360 * atan2 (s * h, c * w) / M_PI; + fov_x = fov; + fov_y = 360 * atan2 (s * h, c * w) / M_PI; + tan_fov_x = s / c; + tan_fov_y = (s * h) / (c * w); + r_funcs->set_fov (tan_fov_x, tan_fov_y); } static void @@ -172,9 +178,6 @@ SCR_CalcRefdef (void) view_setgeometry (view, rect->x, rect->y, rect->width, rect->height); - // notify the refresh of the change - r_funcs->R_ViewChanged (); - // force a background redraw r_data->scr_fullupdate = 0; } @@ -210,10 +213,8 @@ render_side (int side) r_refdef.frame.mat[3] = r_refdef.camera[3]; refdef_t *refdef = r_data->refdef; - R_SetFrustum (refdef->frustum, &refdef->frame, - refdef->fov_x, refdef->fov_y); + R_SetFrustum (refdef->frustum, &refdef->frame, 90, 90); - r_data->refdef->fov_x = r_data->refdef->fov_y = 90; r_funcs->bind_framebuffer (&fisheye_cube_map[side]); render_scene (); @@ -256,8 +257,7 @@ SCR_UpdateScreen (transform_t *camera, double realtime, SCR_Func *scr_funcs) refdef->frame.mat[1] = refdef->camera[0]; refdef->frame.mat[2] = refdef->camera[2]; refdef->frame.mat[3] = refdef->camera[3]; - R_SetFrustum (refdef->frustum, &refdef->frame, - refdef->fov_x, refdef->fov_y); + R_SetFrustum (refdef->frustum, &refdef->frame, fov_x, fov_y); r_data->realtime = realtime; scr_copytop = r_data->scr_copyeverything = 0; @@ -292,6 +292,7 @@ SCR_UpdateScreen (transform_t *camera, double realtime, SCR_Func *scr_funcs) int side = fisheye_cube_map->width; vrect_t feye = { 0, 0, side, side }; r_funcs->set_viewport (&feye); + r_funcs->set_fov (1, 1); //FIXME shouldn't be every frame (2d stuff) switch (scr_fviews->int_val) { case 6: render_side (BOX_BEHIND); case 5: render_side (BOX_BOTTOM); @@ -335,7 +336,7 @@ update_vrect (void) vrect.height = r_data->vid->height; set_vrect (&vrect, &refdef->vrect, r_data->lineadj); - set_fov (scr_fov->value); + SCR_SetFOV (scr_fov->value); } void diff --git a/libs/video/renderer/sw/sw_rmain.c b/libs/video/renderer/sw/sw_rmain.c index 255da2ba6..74ad36338 100644 --- a/libs/video/renderer/sw/sw_rmain.c +++ b/libs/video/renderer/sw/sw_rmain.c @@ -67,7 +67,6 @@ qboolean r_drawculledpolys; qboolean r_worldpolysbacktofront; qboolean r_recursiveaffinetriangles = true; int r_pixbytes = 1; -float r_aliasuvscale = 1.0; int r_outofsurfaces; int r_outofedges; @@ -211,113 +210,6 @@ R_NewMap (model_t *worldmodel, struct model_s **models, int num_models) r_viewchanged = false; } -/* - R_ViewChanged - - Called every time the vid structure or r_refdef changes. - Guaranteed to be called before the first refresh -*/ -void -R_ViewChanged (void) -{ - int i; - float res_scale; - - r_viewchanged = true; - -#define SHIFT20(x) (((x) << 20) + (1 << 19) - 1) - r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width; - r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height; - r_refdef.vrectx_adj_shift20 = SHIFT20 (r_refdef.vrect.x); - r_refdef.vrectright_adj_shift20 = SHIFT20 (r_refdef.vrectright); - - r_refdef.fvrectx = (float) r_refdef.vrect.x; - r_refdef.fvrecty = (float) r_refdef.vrect.y; - r_refdef.fvrectright = (float) r_refdef.vrectright; - r_refdef.fvrectbottom = (float) r_refdef.vrectbottom; - - r_refdef.fvrectx_adj = (float) r_refdef.vrect.x - 0.5; - r_refdef.fvrecty_adj = (float) r_refdef.vrect.y - 0.5; - r_refdef.fvrectright_adj = (float) r_refdef.vrectright - 0.5; - r_refdef.fvrectbottom_adj = (float) r_refdef.vrectbottom - 0.5; - - int aleft = r_refdef.vrect.x * r_aliasuvscale; - int atop = r_refdef.vrect.y * r_aliasuvscale; - int awidth = r_refdef.vrect.width * r_aliasuvscale; - int aheight = r_refdef.vrect.height * r_aliasuvscale; - r_refdef.aliasvrectleft = aleft; - r_refdef.aliasvrecttop = atop; - r_refdef.aliasvrectright = aleft + awidth; - r_refdef.aliasvrectbottom = atop + aheight; - - // values for perspective projection - // if math were exact, the values would range from 0.5 to to range+0.5 - // hopefully they wll be in the 0.000001 to range+.999999 and truncate - // the polygon rasterization will never render in the first row or column - // but will definately render in the [range] row and column, so adjust the - // buffer origin to get an exact edge to edge fill - xcenter = r_refdef.vrect.width * XCENTERING + r_refdef.vrect.x - 0.5; - ycenter = r_refdef.vrect.height * YCENTERING + r_refdef.vrect.y - 0.5; - aliasxcenter = xcenter * r_aliasuvscale; - aliasycenter = ycenter * r_aliasuvscale; - - pixelAspect = 1;//FIXME vid.aspect; - - float aspect = r_refdef.vrect.width * pixelAspect / r_refdef.vrect.height; - // 320*200 1.0 pixelAspect = 1.6 aspect - // 320*240 1.0 pixelAspect = 1.3333 aspect - // proper 320*200 pixelAspect = 0.8333333 - - float hFOV = 2.0 * tan (r_refdef.fov_x / 360 * M_PI); - float vFOV = hFOV / aspect; - - // general perspective scaling - xscale = r_refdef.vrect.width / hFOV; - yscale = xscale * pixelAspect; - xscaleinv = 1.0 / xscale; - yscaleinv = 1.0 / yscale; - // perspective scaling for alias models - aliasxscale = xscale * r_aliasuvscale; - aliasyscale = yscale * r_aliasuvscale; - // perspective scaling for paricle position - xscaleshrink = (r_refdef.vrect.width - 6) / hFOV; - yscaleshrink = xscaleshrink * pixelAspect; - - // left side clip - screenedge[0].normal[0] = -1.0 / (XCENTERING * hFOV); - screenedge[0].normal[1] = 0; - screenedge[0].normal[2] = 1; - screenedge[0].type = PLANE_ANYZ; - - // right side clip - screenedge[1].normal[0] = 1.0 / ((1.0 - XCENTERING) * hFOV); - screenedge[1].normal[1] = 0; - screenedge[1].normal[2] = 1; - screenedge[1].type = PLANE_ANYZ; - - // top side clip - screenedge[2].normal[0] = 0; - screenedge[2].normal[1] = -1.0 / (YCENTERING * vFOV); - screenedge[2].normal[2] = 1; - screenedge[2].type = PLANE_ANYZ; - - // bottom side clip - screenedge[3].normal[0] = 0; - screenedge[3].normal[1] = 1.0 / ((1.0 - YCENTERING) * vFOV); - screenedge[3].normal[2] = 1; - screenedge[3].type = PLANE_ANYZ; - - for (i = 0; i < 4; i++) - VectorNormalize (screenedge[i].normal); - - res_scale = sqrt ((double) (r_refdef.vrect.width * r_refdef.vrect.height) / - (320.0 * 152.0)) * (2.0 / hFOV); - r_aliastransition = r_aliastransbase->value * res_scale; - r_resfudge = r_aliastransadj->value * res_scale; - - D_ViewChanged (); -} - void R_SetColormap (const byte *cmap) { diff --git a/libs/video/renderer/vid_render_gl.c b/libs/video/renderer/vid_render_gl.c index 7d31c65d2..687f8765e 100644 --- a/libs/video/renderer/vid_render_gl.c +++ b/libs/video/renderer/vid_render_gl.c @@ -421,19 +421,43 @@ gl_bind_framebuffer (framebuffer_t *framebuffer) vrect_t r = { 0, 0, width, height }; R_SetVrect (&r, &r_refdef.vrect, 0); - gl_R_ViewChanged (); } static void gl_set_viewport (const vrect_t *view) { int x = view->x; - int y = vid.height - (view->y + view->height);//FIXME vid.height + int y = vid.height - (view->y + view->height); //FIXME vid.height int w = view->width; int h = view->height; qfglViewport (x, y, w, h); } +static void +gl_set_fov (float x, float y) +{ + float neard, fard; + mat4f_t proj; + + neard = r_nearclip->value; + fard = r_farclip->value; + + // NOTE columns! + proj[0] = (vec4f_t) { 1/x, 0, 0, 0 }; + proj[1] = (vec4f_t) { 0, 1/y, 0, 0 }; + proj[2] = (vec4f_t) { 0, 0, (fard) / (fard - neard), 1 }; + proj[3] = (vec4f_t) { 0, 0, (fard * neard) / (neard - fard), 0 }; + + // convert 0..1 depth buffer range to -1..1 + static mat4f_t depth_range = { + { 1, 0, 0, 0}, + { 0, 1, 0, 0}, + { 0, 0, 2, 0}, + { 0, 0,-1, 1}, + }; + mmulf (gl_ctx->projection, depth_range, proj); +} + vid_render_funcs_t gl_vid_render_funcs = { gl_vid_render_init, gl_Draw_Character, @@ -465,7 +489,6 @@ vid_render_funcs_t gl_vid_render_funcs = { gl_R_LoadSkys, gl_R_NewMap, gl_R_LineGraph, - gl_R_ViewChanged, gl_begin_frame, gl_render_view, gl_R_RenderEntities, @@ -479,6 +502,7 @@ vid_render_funcs_t gl_vid_render_funcs = { gl_create_frame_buffer, gl_bind_framebuffer, gl_set_viewport, + gl_set_fov, &model_funcs }; diff --git a/libs/video/renderer/vid_render_glsl.c b/libs/video/renderer/vid_render_glsl.c index dcc8125ea..669cedab9 100644 --- a/libs/video/renderer/vid_render_glsl.c +++ b/libs/video/renderer/vid_render_glsl.c @@ -368,19 +368,43 @@ glsl_bind_framebuffer (framebuffer_t *framebuffer) vrect_t r = { 0, 0, width, height }; R_SetVrect (&r, &r_refdef.vrect, 0); - glsl_R_ViewChanged (); } static void glsl_set_viewport (const vrect_t *view) { int x = view->x; - int y = vid.height - (view->y + view->height);//FIXME vid.height + int y = vid.height - (view->y + view->height); //FIXME vid.height int w = view->width; int h = view->height; qfeglViewport (x, y, w, h); } +static void +glsl_set_fov (float x, float y) +{ + float neard, fard; + mat4f_t proj; + + neard = r_nearclip->value; + fard = r_farclip->value; + + // NOTE columns! + proj[0] = (vec4f_t) { 1/x, 0, 0, 0 }; + proj[1] = (vec4f_t) { 0, 1/y, 0, 0 }; + proj[2] = (vec4f_t) { 0, 0, (fard) / (fard - neard), 1 }; + proj[3] = (vec4f_t) { 0, 0, (fard * neard) / (neard - fard), 0 }; + + // convert 0..1 depth buffer range to -1..1 + static mat4f_t depth_range = { + { 1, 0, 0, 0}, + { 0, 1, 0, 0}, + { 0, 0, 2, 0}, + { 0, 0,-1, 1}, + }; + mmulf (glsl_ctx->projection, depth_range, proj); +} + vid_render_funcs_t glsl_vid_render_funcs = { glsl_vid_render_init, glsl_Draw_Character, @@ -412,7 +436,6 @@ vid_render_funcs_t glsl_vid_render_funcs = { glsl_R_LoadSkys, glsl_R_NewMap, glsl_R_LineGraph, - glsl_R_ViewChanged, glsl_begin_frame, glsl_render_view, glsl_R_RenderEntities, @@ -426,6 +449,7 @@ vid_render_funcs_t glsl_vid_render_funcs = { glsl_create_frame_buffer, glsl_bind_framebuffer, glsl_set_viewport, + glsl_set_fov, &model_funcs }; diff --git a/libs/video/renderer/vid_render_sw.c b/libs/video/renderer/vid_render_sw.c index bf3145b5c..23a920a36 100644 --- a/libs/video/renderer/vid_render_sw.c +++ b/libs/video/renderer/vid_render_sw.c @@ -45,6 +45,8 @@ sw_ctx_t *sw_ctx; +static float r_aliasuvscale = 1.0; + static void sw_vid_render_choose_visual (void *data) { @@ -258,6 +260,8 @@ sw_create_frame_buffer (int width, int height) return fb; } +static void sw_set_viewport (const vrect_t *view); + static void sw_bind_framebuffer (framebuffer_t *framebuffer) { @@ -295,14 +299,116 @@ sw_bind_framebuffer (framebuffer_t *framebuffer) if (changed) { vrect_t r = { 0, 0, framebuffer->width, framebuffer->height }; - R_SetVrect (&r, &r_refdef.vrect, 0); - R_ViewChanged (); + sw_set_viewport (&r); } } static void sw_set_viewport (const vrect_t *view) { +#define SHIFT20(x) (((x) << 20) + (1 << 19) - 1) + r_refdef.vrectright = view->x + view->width; + r_refdef.vrectbottom = view->y + view->height; + r_refdef.vrectx_adj_shift20 = SHIFT20 (view->x); + r_refdef.vrectright_adj_shift20 = SHIFT20 (r_refdef.vrectright); + + r_refdef.fvrectx = (float) view->x; + r_refdef.fvrecty = (float) view->y; + r_refdef.fvrectright = (float) r_refdef.vrectright; + r_refdef.fvrectbottom = (float) r_refdef.vrectbottom; + + r_refdef.fvrectx_adj = (float) view->x - 0.5; + r_refdef.fvrecty_adj = (float) view->y - 0.5; + r_refdef.fvrectright_adj = (float) r_refdef.vrectright - 0.5; + r_refdef.fvrectbottom_adj = (float) r_refdef.vrectbottom - 0.5; + + int aleft = view->x * r_aliasuvscale; + int atop = view->y * r_aliasuvscale; + int awidth = view->width * r_aliasuvscale; + int aheight = view->height * r_aliasuvscale; + r_refdef.aliasvrectleft = aleft; + r_refdef.aliasvrecttop = atop; + r_refdef.aliasvrectright = aleft + awidth; + r_refdef.aliasvrectbottom = atop + aheight; + + // values for perspective projection + // if math were exact, the values would range from 0.5 to to range+0.5 + // hopefully they wll be in the 0.000001 to range+.999999 and truncate + // the polygon rasterization will never render in the first row or column + // but will definately render in the [range] row and column, so adjust the + // buffer origin to get an exact edge to edge fill + xcenter = view->width * XCENTERING + view->x - 0.5; + ycenter = view->height * YCENTERING + view->y - 0.5; + aliasxcenter = xcenter * r_aliasuvscale; + aliasycenter = ycenter * r_aliasuvscale; + + r_refdef.vrect.x = view->x; + r_refdef.vrect.y = view->y; + r_refdef.vrect.width = view->width; + r_refdef.vrect.height = view->height; + + D_ViewChanged (); +} + +static void +sw_set_fov (float x, float y) +{ + int i; + float res_scale; + + r_viewchanged = true; + + // 320*200 1.0 pixelAspect = 1.6 aspect + // 320*240 1.0 pixelAspect = 1.3333 aspect + // proper 320*200 pixelAspect = 0.8333333 + pixelAspect = 1;//FIXME vid.aspect; + + float hFOV = 2 * x; + float vFOV = 2 * y * pixelAspect; + + // general perspective scaling + xscale = r_refdef.vrect.width / hFOV; + yscale = xscale * pixelAspect; + xscaleinv = 1.0 / xscale; + yscaleinv = 1.0 / yscale; + // perspective scaling for alias models + aliasxscale = xscale * r_aliasuvscale; + aliasyscale = yscale * r_aliasuvscale; + // perspective scaling for paricle position + xscaleshrink = (r_refdef.vrect.width - 6) / hFOV; + yscaleshrink = xscaleshrink * pixelAspect; + + // left side clip + screenedge[0].normal[0] = -1.0 / (XCENTERING * hFOV); + screenedge[0].normal[1] = 0; + screenedge[0].normal[2] = 1; + screenedge[0].type = PLANE_ANYZ; + + // right side clip + screenedge[1].normal[0] = 1.0 / ((1.0 - XCENTERING) * hFOV); + screenedge[1].normal[1] = 0; + screenedge[1].normal[2] = 1; + screenedge[1].type = PLANE_ANYZ; + + // top side clip + screenedge[2].normal[0] = 0; + screenedge[2].normal[1] = -1.0 / (YCENTERING * vFOV); + screenedge[2].normal[2] = 1; + screenedge[2].type = PLANE_ANYZ; + + // bottom side clip + screenedge[3].normal[0] = 0; + screenedge[3].normal[1] = 1.0 / ((1.0 - YCENTERING) * vFOV); + screenedge[3].normal[2] = 1; + screenedge[3].type = PLANE_ANYZ; + + for (i = 0; i < 4; i++) + VectorNormalize (screenedge[i].normal); + + res_scale = sqrt ((double) (r_refdef.vrect.width * r_refdef.vrect.height) / + (320.0 * 152.0)) * (2.0 / hFOV); + r_aliastransition = r_aliastransbase->value * res_scale; + r_resfudge = r_aliastransadj->value * res_scale; } vid_render_funcs_t sw_vid_render_funcs = { @@ -336,7 +442,6 @@ vid_render_funcs_t sw_vid_render_funcs = { R_LoadSkys, R_NewMap, R_LineGraph, - R_ViewChanged, sw_begin_frame, sw_render_view, R_DrawEntitiesOnList, @@ -350,6 +455,7 @@ vid_render_funcs_t sw_vid_render_funcs = { sw_create_frame_buffer, sw_bind_framebuffer, sw_set_viewport, + sw_set_fov, &model_funcs }; diff --git a/libs/video/renderer/vid_render_vulkan.c b/libs/video/renderer/vid_render_vulkan.c index 95fdb8642..7224dc2ef 100644 --- a/libs/video/renderer/vid_render_vulkan.c +++ b/libs/video/renderer/vid_render_vulkan.c @@ -57,6 +57,7 @@ #include "QF/Vulkan/device.h" #include "QF/Vulkan/image.h" #include "QF/Vulkan/instance.h" +#include "QF/Vulkan/projection.h" #include "QF/Vulkan/renderpass.h" #include "QF/Vulkan/swapchain.h" #include "QF/ui/view.h" @@ -247,12 +248,6 @@ vulkan_Draw_SubPic (int x, int y, qpic_t *pic, int srcx, int srcy, int width, in Vulkan_Draw_SubPic (x, y, pic, srcx, srcy, width, height, vulkan_ctx); } -static void -vulkan_R_ViewChanged (void) -{ - Vulkan_CalcProjectionMatrices (vulkan_ctx); -} - static void vulkan_begin_frame (void) { @@ -316,6 +311,15 @@ vulkan_post_process (framebuffer_t *src) static void vulkan_set_2d (int scaled) { + //FIXME this should not be done every frame + __auto_type mctx = vulkan_ctx->matrix_context; + __auto_type mat = &mctx->matrices; + + int width = vid.conview->xlen; //FIXME vid + int height = vid.conview->ylen; + QFV_Orthographic (mat->Projection2d, 0, width, 0, height, 0, 99999); + + mctx->dirty = mctx->frames.size; } static void @@ -445,6 +449,20 @@ vulkan_set_viewport (const vrect_t *view) { } +static void +vulkan_set_fov (float x, float y) +{ + if (!vulkan_ctx || !vulkan_ctx->matrix_context) { + return; + } + __auto_type mctx = vulkan_ctx->matrix_context; + __auto_type mat = &mctx->matrices; + + QFV_PerspectiveTan (mat->Projection3d, x, y); + + mctx->dirty = mctx->frames.size; +} + static int is_bgr (VkFormat format) { @@ -715,7 +733,6 @@ vid_render_funcs_t vulkan_vid_render_funcs = { vulkan_R_LoadSkys, vulkan_R_NewMap, vulkan_R_LineGraph, - vulkan_R_ViewChanged, vulkan_begin_frame, vulkan_render_view, vulkan_draw_entities, @@ -729,6 +746,7 @@ vid_render_funcs_t vulkan_vid_render_funcs = { vulkan_create_frame_buffer, vulkan_bind_framebuffer, vulkan_set_viewport, + vulkan_set_fov, &model_funcs }; diff --git a/libs/video/renderer/vulkan/projection.c b/libs/video/renderer/vulkan/projection.c index 1dda6a7b6..7102acb26 100644 --- a/libs/video/renderer/vulkan/projection.c +++ b/libs/video/renderer/vulkan/projection.c @@ -68,30 +68,24 @@ QFV_Orthographic (mat4f_t proj, float xmin, float xmax, float ymin, float ymax, } void -QFV_PerspectiveTan (mat4f_t proj, float fov, float aspect) +QFV_PerspectiveTan (mat4f_t proj, float fov_x, float fov_y) { - float f = 1 / fov; float neard, fard; neard = r_nearclip->value; fard = r_farclip->value; - proj[0] = (vec4f_t) { f / aspect, 0, 0, 0 }; - proj[1] = (vec4f_t) { 0, f, 0, 0 }; + proj[0] = (vec4f_t) { 1 / fov_x, 0, 0, 0 }; + proj[1] = (vec4f_t) { 0, 1 / fov_y, 0, 0 }; proj[2] = (vec4f_t) { 0, 0, fard / (fard - neard), 1 }; proj[3] = (vec4f_t) { 0, 0, (neard * fard) / (neard - fard), 0 }; } void -QFV_PerspectiveCos (mat4f_t proj, float fov, float aspect) +QFV_PerspectiveCos (mat4f_t proj, float fov) { // square first for auto-abs (no support for > 180 degree fov) fov = fov * fov; - QFV_PerspectiveTan (proj, sqrt ((1 - fov) / fov), aspect); -} - -void -QFV_Perspective (mat4f_t proj, float fov, float aspect) -{ - QFV_PerspectiveTan (proj, tan (fov * M_PI / 360), aspect); + float t = sqrt ((1 - fov) / fov); + QFV_PerspectiveTan (proj, t, t); } diff --git a/libs/video/renderer/vulkan/vulkan_lighting.c b/libs/video/renderer/vulkan/vulkan_lighting.c index d6578356d..b34d70e38 100644 --- a/libs/video/renderer/vulkan/vulkan_lighting.c +++ b/libs/video/renderer/vulkan/vulkan_lighting.c @@ -711,7 +711,7 @@ create_light_matrices (lightingctx_t *lctx) mat4fidentity (proj); break; case ST_PLANE: - QFV_PerspectiveCos (proj, light->cone, 1); + QFV_PerspectiveCos (proj, light->cone); break; } mmulf (lctx->lightmats.a[i], proj, view); diff --git a/libs/video/renderer/vulkan/vulkan_matrices.c b/libs/video/renderer/vulkan/vulkan_matrices.c index 79ca29906..5ad3a2ca6 100644 --- a/libs/video/renderer/vulkan/vulkan_matrices.c +++ b/libs/video/renderer/vulkan/vulkan_matrices.c @@ -169,41 +169,6 @@ Vulkan_Matrix_Draw (qfv_renderframe_t *rFrame) QFV_PacketSubmit (packet); } -void -Vulkan_CalcProjectionMatrices (vulkan_ctx_t *ctx) -{ - __auto_type mctx = ctx->matrix_context; - __auto_type mat = &mctx->matrices; - - int width = vid.conview->xlen; - int height = vid.conview->ylen; - QFV_Orthographic (mat->Projection2d, 0, width, 0, height, 0, 99999); - - float aspect = (float) r_refdef.vrect.width / r_refdef.vrect.height; - QFV_Perspective (mat->Projection3d, r_refdef.fov_y, aspect); -#if 0 - Sys_MaskPrintf (SYS_vulkan, "ortho:\n"); - Sys_MaskPrintf (SYS_vulkan, " [[%g, %g, %g, %g],\n", - QuatExpand (mat->Projection2d + 0)); - Sys_MaskPrintf (SYS_vulkan, " [%g, %g, %g, %g],\n", - QuatExpand (mat->Projection2d + 4)); - Sys_MaskPrintf (SYS_vulkan, " [%g, %g, %g, %g],\n", - QuatExpand (mat->Projection2d + 8)); - Sys_MaskPrintf (SYS_vulkan, " [%g, %g, %g, %g]]\n", - QuatExpand (mat->Projection2d + 12)); - Sys_MaskPrintf (SYS_vulkan, "presp:\n"); - Sys_MaskPrintf (SYS_vulkan, " [[%g, %g, %g, %g],\n", - QuatExpand (mat->Projection3d + 0)); - Sys_MaskPrintf (SYS_vulkan, " [%g, %g, %g, %g],\n", - QuatExpand (mat->Projection3d + 4)); - Sys_MaskPrintf (SYS_vulkan, " [%g, %g, %g, %g],\n", - QuatExpand (mat->Projection3d + 8)); - Sys_MaskPrintf (SYS_vulkan, " [%g, %g, %g, %g]]\n", - QuatExpand (mat->Projection3d + 12)); -#endif - mctx->dirty = mctx->frames.size; -} - void Vulkan_Matrix_Init (vulkan_ctx_t *ctx) {