From b5cb0b9f10e7c5f3bcbade3a57fae1dd3831ae9e 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 (which traces back to FitzQuake, in which it is attributed to LadyHavoc, Darkplaces author) 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 | 64 +++++++++++++++++++++++++++++++++------------- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/ref/gl/gl_local.h b/ref/gl/gl_local.h index 7a00f9b7..9acb1058 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 9b9b4558..b992d544 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 40c08250..d776f783 100644 --- a/ref/gl/gl_rlight.c +++ b/ref/gl/gl_rlight.c @@ -99,48 +99,76 @@ 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: the fix was taken from JoeQuake, which traces back to FitzQuake, + // which attributes it to LadyHavoc (Darkplaces author) + // 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] );