From 563fb48299f453ecb3b81168079df8d30c0ac311 Mon Sep 17 00:00:00 2001 From: havoc Date: Sun, 15 Apr 2018 23:23:11 +0000 Subject: [PATCH] Reworked v_isometric code significantly, it now defaults to a proper isometric view and some maps are actually playable like this. Added R_Viewport_InitOrtho3D which more correctly implements the VF_PERSPECTIVE=0 case for CSQC, with correct camera orientation and all that. This may break existing mods that tried to use that feature but I doubt there are any as it was pretty broken before. Reworked how R_CanSeeBox (and other vis code) determine if the view is able to use vieworigin based culling or not, this is now a separate property (r_refdef.view.usevieworiginculling) and can be turned on or off for reflection views and such. This is also exposed as v_isometric_usevieworiginculling for the v_isometric case. git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@12398 d7cf8633-e32d-0410-b094-e92efae38249 --- cl_screen.c | 42 +++++++++++++++--------------------------- client.h | 6 ++++++ gl_backend.c | 42 ++++++++++++++++++++++++++++++++++++++++++ gl_backend.h | 1 + gl_rmain.c | 25 +++++++++++++++---------- gl_rsurf.c | 2 +- view.c | 51 +++++++++++++++++++++++++++++++++++++++++---------- 7 files changed, 121 insertions(+), 48 deletions(-) diff --git a/cl_screen.c b/cl_screen.c index 92137842..71a74c08 100644 --- a/cl_screen.c +++ b/cl_screen.c @@ -2135,33 +2135,21 @@ static void SCR_DrawScreen (void) r_refdef.view.z = 0; } - if (v_isometric.integer) - { - r_refdef.view.useperspective = false; - r_refdef.view.frustum_y = v_isometric_verticalfov.value * cl.viewzoom; - r_refdef.view.frustum_x = r_refdef.view.frustum_y * (float)r_refdef.view.width / (float)r_refdef.view.height / vid_pixelheight.value; - r_refdef.view.frustum_x *= r_refdef.frustumscale_x; - r_refdef.view.frustum_y *= r_refdef.frustumscale_y; - r_refdef.view.ortho_x = r_refdef.view.frustum_x; // used by VM_CL_R_SetView - r_refdef.view.ortho_y = r_refdef.view.frustum_y; // used by VM_CL_R_SetView - } - else - { - // LordHavoc: viewzoom (zoom in for sniper rifles, etc) - // LordHavoc: this is designed to produce widescreen fov values - // when the screen is wider than 4/3 width/height aspect, to do - // this it simply assumes the requested fov is the vertical fov - // for a 4x3 display, if the ratio is not 4x3 this makes the fov - // higher/lower according to the ratio - r_refdef.view.useperspective = true; - r_refdef.view.frustum_y = tan(scr_fov.value * M_PI / 360.0) * (3.0 / 4.0) * cl.viewzoom; - r_refdef.view.frustum_x = r_refdef.view.frustum_y * (float)r_refdef.view.width / (float)r_refdef.view.height / vid_pixelheight.value; - - r_refdef.view.frustum_x *= r_refdef.frustumscale_x; - r_refdef.view.frustum_y *= r_refdef.frustumscale_y; - r_refdef.view.ortho_x = atan(r_refdef.view.frustum_x) * (360.0 / M_PI); // abused as angle by VM_CL_R_SetView - r_refdef.view.ortho_y = atan(r_refdef.view.frustum_y) * (360.0 / M_PI); // abused as angle by VM_CL_R_SetView - } + // LordHavoc: viewzoom (zoom in for sniper rifles, etc) + // LordHavoc: this is designed to produce widescreen fov values + // when the screen is wider than 4/3 width/height aspect, to do + // this it simply assumes the requested fov is the vertical fov + // for a 4x3 display, if the ratio is not 4x3 this makes the fov + // higher/lower according to the ratio + r_refdef.view.useperspective = true; + r_refdef.view.frustum_y = tan(scr_fov.value * M_PI / 360.0) * (3.0 / 4.0) * cl.viewzoom; + r_refdef.view.frustum_x = r_refdef.view.frustum_y * (float)r_refdef.view.width / (float)r_refdef.view.height / vid_pixelheight.value; + + r_refdef.view.frustum_x *= r_refdef.frustumscale_x; + r_refdef.view.frustum_y *= r_refdef.frustumscale_y; + r_refdef.view.ortho_x = atan(r_refdef.view.frustum_x) * (360.0 / M_PI); // abused as angle by VM_CL_R_SetView + r_refdef.view.ortho_y = atan(r_refdef.view.frustum_y) * (360.0 / M_PI); // abused as angle by VM_CL_R_SetView + r_refdef.view.ismain = true; // if CSQC is loaded, it is required to provide the CSQC_UpdateView function, diff --git a/client.h b/client.h index cbc0fc02..67013ddf 100644 --- a/client.h +++ b/client.h @@ -1815,6 +1815,12 @@ typedef struct r_refdef_view_s vec3_t frustumcorner[4]; // if turned off it renders an ortho view int useperspective; + // allows visibility culling based on the view origin (e.g. pvs and R_CanSeeBox) + // this is turned off by: + // r_trippy + // !r_refdef.view.useperspective + // (sometimes) r_refdef.view.useclipplane + int usevieworiginculling; float ortho_x, ortho_y; // screen area to render in diff --git a/gl_backend.c b/gl_backend.c index fa8fc68a..d1455af6 100644 --- a/gl_backend.c +++ b/gl_backend.c @@ -914,6 +914,48 @@ void R_Viewport_InitOrtho(r_viewport_t *v, const matrix4x4_t *cameramatrix, int #endif } +void R_Viewport_InitOrtho3D(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float nearclip, float farclip, const float *nearplane) +{ + matrix4x4_t tempmatrix, basematrix; + float m[16]; + memset(v, 0, sizeof(*v)); + + v->type = R_VIEWPORTTYPE_PERSPECTIVE; + v->cameramatrix = *cameramatrix; + v->x = x; + v->y = y; + v->z = 0; + v->width = width; + v->height = height; + v->depth = 1; + memset(m, 0, sizeof(m)); + m[0] = 1.0 / frustumx; + m[5] = 1.0 / frustumy; + m[10] = -2 / (farclip - nearclip); + m[14] = -(farclip + nearclip) / (farclip - nearclip); + m[15] = 1; + v->screentodepth[0] = -farclip / (farclip - nearclip); + v->screentodepth[1] = farclip * nearclip / (farclip - nearclip); + + Matrix4x4_Invert_Full(&tempmatrix, &v->cameramatrix); + Matrix4x4_CreateRotate(&basematrix, -90, 1, 0, 0); + Matrix4x4_ConcatRotate(&basematrix, 90, 0, 0, 1); + Matrix4x4_Concat(&v->viewmatrix, &basematrix, &tempmatrix); + + if (nearplane) + R_Viewport_ApplyNearClipPlaneFloatGL(v, m, nearplane[0], nearplane[1], nearplane[2], nearplane[3]); + + if(v_flipped.integer) + { + m[0] = -m[0]; + m[4] = -m[4]; + m[8] = -m[8]; + m[12] = -m[12]; + } + + Matrix4x4_FromArrayFloatGL(&v->projectmatrix, m); +} + void R_Viewport_InitPerspective(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float nearclip, float farclip, const float *nearplane) { matrix4x4_t tempmatrix, basematrix; diff --git a/gl_backend.h b/gl_backend.h index b770d687..60953740 100644 --- a/gl_backend.h +++ b/gl_backend.h @@ -25,6 +25,7 @@ extern unsigned short quadelement3s[QUADELEMENTS_MAXQUADS*6]; void R_Viewport_TransformToScreen(const r_viewport_t *v, const vec4_t in, vec4_t out); qboolean R_ScissorForBBox(const float *mins, const float *maxs, int *scissor); void R_Viewport_InitOrtho(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float x1, float y1, float x2, float y2, float zNear, float zFar, const float *nearplane); +void R_Viewport_InitOrtho3D(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float nearclip, float farclip, const float *nearplane); void R_Viewport_InitPerspective(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float zNear, float zFar, const float *nearplane); void R_Viewport_InitPerspectiveInfinite(r_viewport_t *v, const matrix4x4_t *cameramatrix, int x, int y, int width, int height, float frustumx, float frustumy, float zNear, const float *nearplane); void R_Viewport_InitCubeSideView(r_viewport_t *v, const matrix4x4_t *cameramatrix, int side, int size, float nearclip, float farclip, const float *nearplane); diff --git a/gl_rmain.c b/gl_rmain.c index 1cfb0353..29021091 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -5057,7 +5057,7 @@ qboolean R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec_t return true; // view origin is not used for culling in portal/reflection/refraction renders or isometric views - if (r_refdef.view.useclipplane || !r_refdef.view.useperspective || r_trippy.integer) + if (!r_refdef.view.usevieworiginculling) return true; if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight)) @@ -5478,16 +5478,16 @@ static void R_View_SetFrustum(const int *scissor) } else { - VectorScale(forward, -1.0f, r_refdef.view.frustum[0].normal); - VectorScale(forward, 1.0f, r_refdef.view.frustum[1].normal); - VectorScale(left, -1.0f, r_refdef.view.frustum[2].normal); - VectorScale(left, 1.0f, r_refdef.view.frustum[3].normal); - VectorScale(up, -1.0f, r_refdef.view.frustum[4].normal); + VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal); + VectorScale(left, 1.0f, r_refdef.view.frustum[1].normal); + VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal); + VectorScale(up, 1.0f, r_refdef.view.frustum[3].normal); + VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal); r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x; r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x; r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y; r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y; - r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip; + r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip; } r_refdef.view.numfrustumplanes = 5; @@ -5534,7 +5534,7 @@ static void R_View_UpdateWithScissor(const int *myscissor) { R_Main_ResizeViewCache(); R_View_SetFrustum(myscissor); - R_View_WorldVisibility(r_refdef.view.useclipplane); + R_View_WorldVisibility(!r_refdef.view.usevieworiginculling); R_View_UpdateEntityVisible(); } @@ -5542,7 +5542,7 @@ static void R_View_Update(void) { R_Main_ResizeViewCache(); R_View_SetFrustum(NULL); - R_View_WorldVisibility(r_refdef.view.useclipplane); + R_View_WorldVisibility(!r_refdef.view.usevieworiginculling); R_View_UpdateEntityVisible(); } @@ -5579,7 +5579,7 @@ void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *view rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height; if (!r_refdef.view.useperspective) - R_Viewport_InitOrtho(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, -r_refdef.view.ortho_x, -r_refdef.view.ortho_y, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane); + R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane); else if (vid.stencil && r_useinfinitefarclip.integer) R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane); else @@ -6079,6 +6079,8 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t } r_refdef.view.clipplane = p->plane; + // reflected view origin may be in solid, so don't cull with it + r_refdef.view.usevieworiginculling = false; // reverse the cullface settings for this render r_refdef.view.cullface_front = GL_FRONT; r_refdef.view.cullface_back = GL_BACK; @@ -6207,6 +6209,8 @@ static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t // camera needs no clipplane r_refdef.view.useclipplane = false; + // TODO: is the camera origin always valid? if so we don't need to clear this + r_refdef.view.usevieworiginculling = false; PlaneClassify(&r_refdef.view.clipplane); @@ -6983,6 +6987,7 @@ void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, i return; } + r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective; if (v_isometric.integer && r_refdef.view.ismain) V_MakeViewIsometric(); diff --git a/gl_rsurf.c b/gl_rsurf.c index 84027b1d..cd4c08bb 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -487,7 +487,7 @@ void R_View_WorldVisibility(qboolean forcenovis) // if floating around in the void (no pvs data available, and no // portals available), simply use all on-screen leafs. - if (!viewleaf || viewleaf->clusterindex < 0 || forcenovis || r_trippy.integer || !r_refdef.view.useperspective) + if (!viewleaf || viewleaf->clusterindex < 0 || forcenovis || !r_refdef.view.usevieworiginculling) { // no visibility method: (used when floating around in the void) // simply cull each leaf to the frustum (view pyramid) diff --git a/view.c b/view.c index df73f194..77aed899 100644 --- a/view.c +++ b/view.c @@ -94,22 +94,27 @@ cvar_t v_idlescale = {0, "v_idlescale", "0", "how much of the quake 'drunken vie cvar_t v_isometric = {0, "v_isometric", "0", "changes view to isometric (non-perspective)"}; cvar_t v_isometric_verticalfov = { 0, "v_isometric_verticalfov", "512", "vertical field of view in game units (horizontal is computed using aspect ratio based on this)"}; -cvar_t v_isometric_xx = {0, "v_isometric_xx", "0", "camera matrix"}; -cvar_t v_isometric_xy = {0, "v_isometric_xy", "-1", "camera matrix"}; +cvar_t v_isometric_xx = {0, "v_isometric_xx", "1", "camera matrix"}; +cvar_t v_isometric_xy = {0, "v_isometric_xy", "0", "camera matrix"}; cvar_t v_isometric_xz = {0, "v_isometric_xz", "0", "camera matrix"}; -cvar_t v_isometric_yx = {0, "v_isometric_yx", "-1", "camera matrix"}; -cvar_t v_isometric_yy = {0, "v_isometric_yy", "0", "camera matrix"}; +cvar_t v_isometric_yx = {0, "v_isometric_yx", "0", "camera matrix"}; +cvar_t v_isometric_yy = {0, "v_isometric_yy", "1", "camera matrix"}; cvar_t v_isometric_yz = {0, "v_isometric_yz", "0", "camera matrix"}; cvar_t v_isometric_zx = {0, "v_isometric_zx", "0", "camera matrix"}; cvar_t v_isometric_zy = {0, "v_isometric_zy", "0", "camera matrix"}; cvar_t v_isometric_zz = {0, "v_isometric_zz", "1", "camera matrix"}; -cvar_t v_isometric_tx = {0, "v_isometric_tx", "1767", "camera position"}; -cvar_t v_isometric_ty = {0, "v_isometric_ty", "1767", "camera position"}; -cvar_t v_isometric_tz = {0, "v_isometric_tz", "1425", "camera position"}; -cvar_t v_isometric_rot_pitch = {0, "v_isometric_rot_pitch", "0", "camera rotation"}; -cvar_t v_isometric_rot_yaw = {0, "v_isometric_rot_yaw", "-45", "camera rotation"}; -cvar_t v_isometric_rot_roll = {0, "v_isometric_rot_roll", "-60", "camera rotation"}; +cvar_t v_isometric_tx = {0, "v_isometric_tx", "0", "camera position (player-relative)"}; +cvar_t v_isometric_ty = {0, "v_isometric_ty", "0", "camera position (player-relative)"}; +cvar_t v_isometric_tz = {0, "v_isometric_tz", "0", "camera position (player-relative)"}; +cvar_t v_isometric_rot_pitch = {0, "v_isometric_rot_pitch", "60", "camera rotation"}; +cvar_t v_isometric_rot_yaw = {0, "v_isometric_rot_yaw", "135", "camera rotation"}; +cvar_t v_isometric_rot_roll = {0, "v_isometric_rot_roll", "0", "camera rotation"}; +cvar_t v_isometric_relx = {0, "v_isometric_relx", "0", "camera position*forward"}; +cvar_t v_isometric_rely = {0, "v_isometric_rely", "0", "camera position*left"}; +cvar_t v_isometric_relz = {0, "v_isometric_relz", "0", "camera position*up"}; +cvar_t v_isometric_flipcullface = {0, "v_isometric_flipcullface", "0", "flips the backface culling"}; cvar_t v_isometric_locked_orientation = {0, "v_isometric_locked_orientation", "1", "camera rotation is fixed"}; +cvar_t v_isometric_usevieworiginculling = {0, "v_isometric_usevieworiginculling", "0", "check visibility to the player location (can look pretty weird)"}; cvar_t crosshair = {CVAR_SAVE, "crosshair", "0", "selects crosshair to use (0 is none)"}; @@ -968,7 +973,18 @@ void V_MakeViewIsometric(void) matrix4x4_t relative; matrix4x4_t modifiedview; matrix4x4_t modify; + vec3_t forward, left, up, org; float t[4][4]; + + r_refdef.view.useperspective = false; + r_refdef.view.usevieworiginculling = !r_trippy.value && v_isometric_usevieworiginculling.integer; + r_refdef.view.frustum_y = v_isometric_verticalfov.value * cl.viewzoom; + r_refdef.view.frustum_x = r_refdef.view.frustum_y * (float)r_refdef.view.width / (float)r_refdef.view.height / vid_pixelheight.value; + r_refdef.view.frustum_x *= r_refdef.frustumscale_x; + r_refdef.view.frustum_y *= r_refdef.frustumscale_y; + r_refdef.view.ortho_x = r_refdef.view.frustum_x; // used by VM_CL_R_SetView + r_refdef.view.ortho_y = r_refdef.view.frustum_y; // used by VM_CL_R_SetView + t[0][0] = v_isometric_xx.value; t[0][1] = v_isometric_xy.value; t[0][2] = v_isometric_xz.value; @@ -998,6 +1014,16 @@ void V_MakeViewIsometric(void) Matrix4x4_Concat(&modifiedview, &r_refdef.view.matrix, &modify); Matrix4x4_CreateFromQuakeEntity(&relative, v_isometric_tx.value, v_isometric_ty.value, v_isometric_tz.value, v_isometric_rot_pitch.value, v_isometric_rot_yaw.value, v_isometric_rot_roll.value, 1.0f); Matrix4x4_Concat(&r_refdef.view.matrix, &modifiedview, &relative); + Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, org); + VectorMAMAMAM(1.0f, org, v_isometric_relx.value, forward, v_isometric_rely.value, left, v_isometric_relz.value, up, org); + Matrix4x4_FromVectors(&r_refdef.view.matrix, forward, left, up, org); + + if (v_isometric_flipcullface.integer) + { + int a = r_refdef.view.cullface_front; + r_refdef.view.cullface_front = r_refdef.view.cullface_back; + r_refdef.view.cullface_back = a; + } } @@ -1200,7 +1226,12 @@ void V_Init (void) Cvar_RegisterVariable(&v_isometric_rot_pitch); Cvar_RegisterVariable(&v_isometric_rot_yaw); Cvar_RegisterVariable(&v_isometric_rot_roll); + Cvar_RegisterVariable(&v_isometric_relx); + Cvar_RegisterVariable(&v_isometric_rely); + Cvar_RegisterVariable(&v_isometric_relz); + Cvar_RegisterVariable(&v_isometric_flipcullface); Cvar_RegisterVariable(&v_isometric_locked_orientation); + Cvar_RegisterVariable(&v_isometric_usevieworiginculling); Cvar_RegisterVariable (&v_idlescale); Cvar_RegisterVariable (&crosshair); -- 2.39.2