From a42102f706cf587d30cb2eec071605bf2a0e3847 Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Fri, 7 Feb 2025 22:05:54 +0300 Subject: [PATCH] ref: gl: add r_dlight_virtual_radius. It potentially fixes ugly dlight cut off on largely scaled textures (or at least allows to tune it) It also adds a fix found in JoeQuake to exactly calculate whether the light hits the surface, so we don't wrongly enable lighting on a surface by an increased radius. --- ref/gl/gl_local.h | 3 ++- ref/gl/gl_opengl.c | 2 ++ ref/gl/gl_rlight.c | 63 +++++++++++++++++++++++++++++++++------------- 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/ref/gl/gl_local.h b/ref/gl/gl_local.h index 7a00f9b70..9acb1058d 100644 --- a/ref/gl/gl_local.h +++ b/ref/gl/gl_local.h @@ -388,7 +388,7 @@ void R_TextureReplacementReport( const char *modelname, int gl_texturenum, const void CL_RunLightStyles( lightstyle_t *ls ); void R_PushDlights( void ); void R_GetLightSpot( vec3_t lightspot ); -void R_MarkLights( dlight_t *light, int bit, mnode_t *node ); +void R_MarkLights( const dlight_t *light, int bit, const mnode_t *node ); colorVec R_LightVec( const vec3_t start, const vec3_t end, vec3_t lightspot, vec3_t lightvec ); colorVec R_LightPoint( const vec3_t p0 ); @@ -812,6 +812,7 @@ extern convar_t r_ripple; extern convar_t r_ripple_updatetime; extern convar_t r_ripple_spawntime; extern convar_t r_large_lightmaps; +extern convar_t r_dlight_virtual_radius; // // engine shared convars diff --git a/ref/gl/gl_opengl.c b/ref/gl/gl_opengl.c index 9b9b4558b..b992d544f 100644 --- a/ref/gl/gl_opengl.c +++ b/ref/gl/gl_opengl.c @@ -38,6 +38,7 @@ CVAR_DEFINE_AUTO( r_ripple, "0", FCVAR_GLCONFIG, "enable software-like water tex CVAR_DEFINE_AUTO( r_ripple_updatetime, "0.05", FCVAR_GLCONFIG, "how fast ripple simulation is" ); CVAR_DEFINE_AUTO( r_ripple_spawntime, "0.1", FCVAR_GLCONFIG, "how fast new ripples spawn" ); CVAR_DEFINE_AUTO( r_large_lightmaps, "0", FCVAR_GLCONFIG|FCVAR_LATCH, "enable larger lightmap atlas textures (might break custom renderer mods)" ); +CVAR_DEFINE_AUTO( r_dlight_virtual_radius, "3", FCVAR_GLCONFIG, "increase dlight radius virtually by this amount, should help against ugly cut off dlights on highly scaled textures" ); DEFINE_ENGINE_SHARED_CVAR_LIST() @@ -1155,6 +1156,7 @@ static void GL_InitCommands( void ) gEngfuncs.Cvar_RegisterVariable( &r_vbo_overbrightmode ); gEngfuncs.Cvar_RegisterVariable( &r_vbo_detail ); gEngfuncs.Cvar_RegisterVariable( &r_large_lightmaps ); + gEngfuncs.Cvar_RegisterVariable( &r_dlight_virtual_radius ); gEngfuncs.Cvar_RegisterVariable( &gl_extensions ); gEngfuncs.Cvar_RegisterVariable( &gl_texture_nearest ); diff --git a/ref/gl/gl_rlight.c b/ref/gl/gl_rlight.c index 40c082503..6b481acfa 100644 --- a/ref/gl/gl_rlight.c +++ b/ref/gl/gl_rlight.c @@ -99,48 +99,75 @@ void CL_RunLightStyles( lightstyle_t *ls ) R_MarkLights ============= */ -void R_MarkLights( dlight_t *light, int bit, mnode_t *node ) +void R_MarkLights( const dlight_t *light, int bit, const mnode_t *node ) { - float dist; - msurface_t *surf; - int i; + const float virtual_radius = light->radius * Q_max( 1.0f, r_dlight_virtual_radius.value ); + const float maxdist = light->radius * light->radius; + float dist; + int i; mnode_t *children[2]; int firstsurface, numsurfaces; +start: + if( !node || node->contents < 0 ) return; dist = PlaneDiff( light->origin, node->plane ); node_children( children, node, RI.currentmodel ); - firstsurface = node_firstsurface( node, RI.currentmodel ); - numsurfaces = node_numsurfaces( node, RI.currentmodel ); - if( dist > light->radius ) + if( dist > virtual_radius ) { - R_MarkLights( light, bit, children[0] ); - return; + node = children[0]; + goto start; } - if( dist < -light->radius ) + + if( dist < -virtual_radius ) { - R_MarkLights( light, bit, children[1] ); - return; + node = children[1]; + goto start; } // mark the polygons - surf = RI.currentmodel->surfaces + firstsurface; + firstsurface = node_firstsurface( node, RI.currentmodel ); + numsurfaces = node_numsurfaces( node, RI.currentmodel ); - for( i = 0; i < numsurfaces; i++, surf++ ) + for( i = 0; i < numsurfaces; i++ ) { - if( !BoundsAndSphereIntersect( surf->info->mins, surf->info->maxs, light->origin, light->radius )) - continue; // no intersection + vec3_t impact; + float s, t, l; + msurface_t *surf = &RI.currentmodel->surfaces[firstsurface + i]; + const mextrasurf_t *info = surf->info; + + if( surf->plane->type < 3 ) + { + VectorCopy( light->origin, impact ); + impact[surf->plane->type] -= dist; + } + else VectorMA( light->origin, -dist, surf->plane->normal, impact ); + + // a1ba: taken from JoeQuake, but it's probably originated in FitzQuake + // clamp center of light to corner and check brightness + l = DotProduct( impact, info->lmvecs[0] ) + info->lmvecs[0][3] - info->lightmapmins[0]; + s = l + 0.5; + s = bound( 0, s, info->lightextents[0] ); + s = l - s; + + l = DotProduct( impact, info->lmvecs[1] ) + info->lmvecs[1][3] - info->lightmapmins[1]; + t = l + 0.5; + t = bound( 0, t, info->lightextents[1] ); + t = l - t; + + if( s * s + t * t + dist * dist >= maxdist ) + continue; if( surf->dlightframe != tr.dlightframecount ) { - surf->dlightbits = 0; + surf->dlightbits = bit; surf->dlightframe = tr.dlightframecount; } - surf->dlightbits |= bit; + else surf->dlightbits |= bit; } R_MarkLights( light, bit, children[0] );