diff --git a/src.cmake b/src.cmake index 7430a577b9..078d111a43 100644 --- a/src.cmake +++ b/src.cmake @@ -108,7 +108,6 @@ set(GLSL_EMBED_LIST blur_fp.glsl cameraEffects_fp.glsl contrast_fp.glsl - fogGlobal_fp.glsl fxaa_fp.glsl fxaa3_11_fp.glsl motionblur_fp.glsl @@ -130,6 +129,8 @@ set(GLSL_EMBED_LIST vertexSkinning_vp.glsl # Regular shaders + fogGlobal_vp.glsl + fogGlobal_fp.glsl fogQuake3_vp.glsl fogQuake3_fp.glsl generic_vp.glsl diff --git a/src/engine/renderer/GeometryOptimiser.h b/src/engine/renderer/GeometryOptimiser.h index 3a24a972d9..cfce0db7e1 100644 --- a/src/engine/renderer/GeometryOptimiser.h +++ b/src/engine/renderer/GeometryOptimiser.h @@ -87,7 +87,6 @@ void MarkShaderBuildScreen( const shaderStage_t* pStage ); void MarkShaderBuildPortal( const shaderStage_t* pStage ); void MarkShaderBuildHeatHaze( const shaderStage_t* pStage ); void MarkShaderBuildLiquid( const shaderStage_t* pStage ); -void MarkShaderBuildFog( const shaderStage_t* pStage ); void MarkShaderBuildIQM( const IQModel_t* model ); void MarkShaderBuildMDV( const mdvModel_t* model ); diff --git a/src/engine/renderer/Material.cpp b/src/engine/renderer/Material.cpp index a091109746..ce0bacf776 100644 --- a/src/engine/renderer/Material.cpp +++ b/src/engine/renderer/Material.cpp @@ -1114,11 +1114,11 @@ void BindShaderFog( Material* material ) { // since fognum is grouped with the GL state stuff, segregating each fognum in a separate draw call. gl_fogQuake3ShaderMaterial->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin ); - gl_fogQuake3ShaderMaterial->SetUniform_FogDensity( fog->tcScale ); + gl_fogQuake3ShaderMaterial->SetUniform_FogDensity( 1.0f / fog->shader->fogParms.depthForOpaque ); gl_fogQuake3ShaderMaterial->SetUniform_FogDepthVector( fogDepthVector ); gl_fogQuake3ShaderMaterial->SetUniform_FogEyeT( eyeT ); - gl_fogQuake3ShaderMaterial->SetUniform_ColorGlobal_Uint( fog->color ); + gl_fogQuake3ShaderMaterial->SetUniform_ColorGlobal_Uint( fog->shader->fogParms.color ); gl_fogQuake3ShaderMaterial->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); gl_fogQuake3ShaderMaterial->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[glState.stackIndex] ); @@ -2096,7 +2096,7 @@ void MaterialSystem::RenderMaterial( Material& material, const uint32_t viewID ) } if( material.shaderBinder == BindShaderFog ) { - if ( r_noFog->integer || !r_wolfFog->integer || ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) { + if ( r_noFog->integer || ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) { return; } } diff --git a/src/engine/renderer/gl_shader.cpp b/src/engine/renderer/gl_shader.cpp index 0526d2c5aa..0184a01bca 100644 --- a/src/engine/renderer/gl_shader.cpp +++ b/src/engine/renderer/gl_shader.cpp @@ -2719,10 +2719,12 @@ GLShader_fogQuake3Material::GLShader_fogQuake3Material() : GLDeformStage( this ) { } +// TODO: rename GLShader_fogGlobal::GLShader_fogGlobal() : GLShader( "fogGlobal", ATTR_POSITION, - false, "screenSpace", "fogGlobal" ), + false, "fogGlobal", "fogGlobal" ), u_DepthMap( this ), + u_ModelViewProjectionMatrix( this ), u_UnprojectMatrix( this ), u_Color_Float( this ), u_Color_Uint( this ), diff --git a/src/engine/renderer/gl_shader.h b/src/engine/renderer/gl_shader.h index 8a62521d5f..5a17271bb7 100644 --- a/src/engine/renderer/gl_shader.h +++ b/src/engine/renderer/gl_shader.h @@ -3194,6 +3194,7 @@ class GLShader_fogQuake3Material : class GLShader_fogGlobal : public GLShader, public u_DepthMap, + public u_ModelViewProjectionMatrix, public u_UnprojectMatrix, public u_Color_Float, public u_Color_Uint, diff --git a/src/engine/renderer/glsl_source/fogGlobal_fp.glsl b/src/engine/renderer/glsl_source/fogGlobal_fp.glsl index 6097825900..b8e636af09 100644 --- a/src/engine/renderer/glsl_source/fogGlobal_fp.glsl +++ b/src/engine/renderer/glsl_source/fogGlobal_fp.glsl @@ -27,6 +27,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define DEPTHMAP_GLSL +IN(smooth) vec3 var_Position; + uniform sampler2D u_DepthMap; uniform colorPack u_Color; @@ -37,6 +39,7 @@ uniform mat4 u_UnprojectMatrix; DECLARE_OUTPUT(vec4) +// This shader can be used to draw a fog volume the viewer is inside of. void main() { #insert material_fp @@ -50,7 +53,9 @@ void main() P.xyz /= P.w; // calculate the length in fog (t is always 1 if eye is in fog) - float s = distance(u_ViewOrigin, P.xyz) * u_FogDensity; + float depthDist = distance(u_ViewOrigin, P.xyz); + float fogBoundaryDist = distance(u_ViewOrigin, var_Position); + float s = min(depthDist, fogBoundaryDist) * u_FogDensity; vec4 color = vec4(1, 1, 1, GetFogAlpha(s, 1.0)); diff --git a/src/engine/renderer/glsl_source/fogGlobal_vp.glsl b/src/engine/renderer/glsl_source/fogGlobal_vp.glsl new file mode 100644 index 0000000000..ea81f2ea94 --- /dev/null +++ b/src/engine/renderer/glsl_source/fogGlobal_vp.glsl @@ -0,0 +1,46 @@ +/* +=========================================================================== + +Daemon BSD Source Code +Copyright (c) 2026 Daemon Developers +All rights reserved. + +This file is part of the Daemon BSD Source Code (Daemon Source Code). + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Daemon developers nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL DAEMON DEVELOPERS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=========================================================================== +*/ + +uniform mat4 u_ModelViewProjectionMatrix; + +IN vec3 attr_Position; + +OUT(smooth) vec3 var_Position; + +void main() +{ + vec4 position = vec4(attr_Position, 1.0); + gl_Position = u_ModelViewProjectionMatrix * position; + var_Position = attr_Position; +} diff --git a/src/engine/renderer/tr_backend.cpp b/src/engine/renderer/tr_backend.cpp index 18795fec41..f8722e44b5 100644 --- a/src/engine/renderer/tr_backend.cpp +++ b/src/engine/renderer/tr_backend.cpp @@ -1423,46 +1423,36 @@ void RB_RenderPostDepthLightTile() GL_CheckErrors(); } -void RB_RenderGlobalFog() +// TODO: move with other Render_ functions +void Render_fogGlobal( shaderStage_t *stage ) { - if ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) - { - return; - } - if ( r_noFog->integer ) { return; } - if ( !tr.world || tr.world->globalFog < 0 ) - { - return; - } - GLIMP_LOGCOMMENT( "--- RB_RenderGlobalFog ---" ); RB_PrepareForSamplingDepthMap(); - GL_Cull( cullType_t::CT_TWO_SIDED ); + GL_Cull( cullType_t::CT_FRONT_SIDED ); gl_fogGlobalShader->BindProgram(); - // go back to the world modelview matrix - backEnd.orientation = backEnd.viewParms.world; - { - fog_t* fog = &tr.world->fogs[ tr.world->globalFog ]; - - GLIMP_LOGCOMMENT( "--- RB_RenderGlobalFog( fogNum = %i ) ---", tr.world->globalFog ); - GL_State( GLS_DEPTHTEST_DISABLE | GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - gl_fogGlobalShader->SetUniform_FogDensity( fog->tcScale ); + gl_fogGlobalShader->SetUniform_FogDensity( 1.0f / stage->shader->fogParms.depthForOpaque ); gl_fogGlobalShader->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin ); - SetUniform_Color( gl_fogGlobalShader, fog->color ); + SetUniform_Color( gl_fogGlobalShader, stage->shader->fogParms.color ); } + // It's important to avoid far plane clipping + matrix_t projection, mvp; + MatrixPerspectiveProjectionFovXYInfiniteRH( projection, tr.refdef.fov_x, tr.refdef.fov_y, 1.0f ); + MatrixMultiply( projection, glState.modelViewMatrix[ glState.stackIndex ], mvp ); + + gl_fogGlobalShader->SetUniform_ModelViewProjectionMatrix( mvp ); gl_fogGlobalShader->SetUniform_UnprojectMatrix( backEnd.viewParms.unprojectionMatrix ); // bind u_DepthMap @@ -1470,7 +1460,9 @@ void RB_RenderGlobalFog() GL_BindToTMU( 1, tr.depthSamplerImage ) ); - Tess_InstantScreenSpaceQuad(); + gl_fogGlobalShader->SetRequiredVertexPointers(); + + Tess_DrawElements(); GL_CheckErrors(); } @@ -2801,9 +2793,6 @@ static void RB_RenderView( bool depthPass ) RB_RenderSSAO(); - // render global fog post process effect - RB_RenderGlobalFog(); - TransitionMainToMSAA( GL_COLOR_BUFFER_BIT ); // draw everything that is translucent diff --git a/src/engine/renderer/tr_bsp.cpp b/src/engine/renderer/tr_bsp.cpp index d03844d401..9ae13ce473 100644 --- a/src/engine/renderer/tr_bsp.cpp +++ b/src/engine/renderer/tr_bsp.cpp @@ -3217,8 +3217,6 @@ static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) int count, brushesCount, sidesCount; int sideNum; int planeNum; - shader_t *shader; - float d; int firstSide = 0; Log::Debug("...loading fogs" ); @@ -3264,6 +3262,9 @@ static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) sidesCount = sidesLump->filelen / sizeof( *sides ); + std::vector> fogVerts(8 * count); + std::vector fogIndexes(6 * 6 * count); + for ( i = 0; i < count; i++, fogs++ ) { out->originalBrushNumber = LittleLong( fogs->brushNum ); @@ -3316,26 +3317,28 @@ static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) out->bounds[ 1 ][ 2 ] = s_worldData.planes[ planeNum ].dist; } - // get information from the shader for fog parameters - // it says RSF_3D but if there is no shader text found it should probably just error instead - // of trying to create an implicit shader from an image... - shader = R_FindShader( fogs->shader, RSF_3D ); - - out->fogParms = shader->fogParms; - - out->color = Color::Adapt( shader->fogParms.color ); - - if ( tr.worldLinearizeTexture ) + // add faces of fog brush for drawing fog from inside + for ( int p = 0; p < 8; p++ ) { - out->color = out->color.ConvertFromSRGB(); + fogVerts[ i * 8 + p ][ 0 ] = out->bounds[ p & 1 ][ 0 ]; + fogVerts[ i * 8 + p ][ 1 ] = out->bounds[ ( p >> 1 ) & 1 ][ 1 ]; + fogVerts[ i * 8 + p ][ 2 ] = out->bounds[ p >> 2 ][ 2 ]; + } + constexpr int box[ 36 ] = { 2, 3, 0, 0, 3, 1, 0, 1, 4, 4, 1, 5, 2, 0, 6, 6, 0, 4, + 1, 3, 5, 5, 3, 7, 3, 2, 7, 7, 2, 6, 7, 6, 5, 5, 6, 4 }; + for ( int p = 0; p < 36; p++ ) + { + fogIndexes[ 36 * i + p ] = 8 * i + box[ p ]; } - out->color *= tr.identityLight; - - out->color.SetAlpha( 1 ); + // add draw surf for fog brush faces + out->surf.firstIndex = 36 * i; + out->surf.numTriangles = 12; + out->surf.surfaceType = surfaceType_t::SF_TRIANGLES; - d = shader->fogParms.depthForOpaque < 1 ? 1 : shader->fogParms.depthForOpaque; - out->tcScale = 1.0f / d; + // it says RSF_3D but if there is no shader text found it should probably just error instead + // of trying to create an implicit shader from an image... + out->shader = R_FindShader( fogs->shader, RSF_3D ); // ydnar: global fog sets clearcolor/zfar if ( out->originalBrushNumber == -1 ) @@ -3362,6 +3365,20 @@ static void R_LoadFogs( lump_t *l, lump_t *brushesLump, lump_t *sidesLump ) out++; } + vertexAttributeSpec_t attributes[] { + { ATTR_INDEX_POSITION, GL_FLOAT, GL_FLOAT, &fogVerts[ 0 ], 3, sizeof( fogVerts[ 0 ] ), 0 }, + }; + VBO_t *fogVBO = R_CreateStaticVBO( + "fogs VBO", std::begin( attributes ), std::end( attributes ), fogVerts.size() ); + IBO_t *fogIBO = R_CreateStaticIBO( "fogs IBO", &fogIndexes[ 0 ], fogIndexes.size() ); + SetupVAOBuffers( fogVBO, fogIBO, ATTR_POSITION, &fogVBO->VAO ); + + for ( int j = 1; j < s_worldData.numFogs; j++ ) + { + s_worldData.fogs[ j ].surf.vbo = fogVBO; + s_worldData.fogs[ j ].surf.ibo = fogIBO; + } + Log::Debug("%i fog volumes loaded", s_worldData.numFogs ); } diff --git a/src/engine/renderer/tr_init.cpp b/src/engine/renderer/tr_init.cpp index e0cae98d2e..c1e121004e 100644 --- a/src/engine/renderer/tr_init.cpp +++ b/src/engine/renderer/tr_init.cpp @@ -222,7 +222,6 @@ Cvar::Cvar r_rendererAPI( "r_rendererAPI", "Renderer API: 0: OpenGL, 1: Vul cvar_t *r_showImages; - cvar_t *r_wolfFog; cvar_t *r_noFog; Cvar::Range> r_forceAmbient( "r_forceAmbient", "Minimal light amount in lightGrid; -1 to use map value", @@ -1157,7 +1156,6 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p r_heatHaze = Cvar_Get( "r_heatHaze", "1", CVAR_LATCH | CVAR_ARCHIVE ); r_noMarksOnTrisurfs = Cvar_Get( "r_noMarksOnTrisurfs", "1", CVAR_CHEAT ); - r_wolfFog = Cvar_Get( "r_wolfFog", "1", CVAR_CHEAT ); r_noFog = Cvar_Get( "r_noFog", "0", CVAR_CHEAT ); Cvar::Latch( r_forceAmbient ); @@ -1543,6 +1541,8 @@ ScreenshotCmd screenshotPNGRegistration("screenshotPNG", ssFormat_t::SSF_PNG, "p gl_fogQuake3Shader->SetDeform( 0 ); gl_fogQuake3Shader->MarkProgramForBuilding(); } + + gl_fogGlobalShader->MarkProgramForBuilding(); } for ( int i = 0; i < tr.numModels; i++ ) { diff --git a/src/engine/renderer/tr_local.h b/src/engine/renderer/tr_local.h index bc54905438..488ac16943 100644 --- a/src/engine/renderer/tr_local.h +++ b/src/engine/renderer/tr_local.h @@ -940,6 +940,7 @@ enum ST_HEATHAZEMAP, // heatHaze post process effect ST_LIQUIDMAP, ST_FOGMAP, + ST_FOGMAP_INNER, // a fog seen from inside ST_LIGHTMAP, ST_STYLELIGHTMAP, ST_STYLECOLORMAP, @@ -1116,13 +1117,15 @@ enum struct fogParms_t { - vec3_t color; + Color::Color color; float depthForOpaque; }; struct shader_t { - char name[ MAX_QPATH ]; // game path, including extension + // max name length is MAX_QPATH - 1 but with room for automatically added suffixes + char name[ MAX_QPATH + 8 ]; + int registerFlags; // RSF_ int index; // this shader == tr.shaders[index] @@ -1192,6 +1195,7 @@ enum struct shader_t *depthShader; struct shader_t *fogShader; + struct shader_t *fogInnerShader; struct shader_t *next; }; @@ -1335,20 +1339,6 @@ enum //================================================================================= - struct fog_t - { - int originalBrushNumber; - vec3_t bounds[ 2 ]; - - Color::Color color; // in packed byte format - float tcScale; // texture coordinate vector scales - fogParms_t fogParms; - - // for clipping distance in fog when outside - bool hasSurface; - float surface[ 4 ]; - }; - struct viewParms_t { orientationr_t orientation; @@ -1619,6 +1609,20 @@ enum IBO_t *ibo; }; + struct fog_t + { + int originalBrushNumber; + vec3_t bounds[ 2 ]; + + shader_t *shader; // has the fog parms + + // for clipping distance in fog when outside + bool hasSurface; + float surface[ 4 ]; + + srfGeneric_t surf; + }; + extern void ( *rb_surfaceTable[Util::ordinal(surfaceType_t::SF_NUM_SURFACE_TYPES)] )(void * ); void ValidateVertex( srfVert_t* vertex, int vertexID, shader_t* shader ); @@ -2634,7 +2638,6 @@ enum extern cvar_t *r_lodBias; // push/pull LOD transitions extern cvar_t *r_lodScale; - extern cvar_t *r_wolfFog; extern cvar_t *r_noFog; extern Cvar::Range> r_forceAmbient; @@ -3251,6 +3254,7 @@ void GLimp_LogComment_( std::string comment ); void Render_heatHaze( shaderStage_t *pStage ); void Render_liquid( shaderStage_t *pStage ); void Render_fog( shaderStage_t* pStage ); + void Render_fogGlobal( shaderStage_t *pStage ); /* ============================================================ @@ -3342,6 +3346,9 @@ void GLimp_LogComment_( std::string comment ); void RE_AddPolyToSceneET( qhandle_t hShader, int numVerts, const polyVert_t *verts ); void RE_AddPolysToScene( qhandle_t hShader, int numVerts, const polyVert_t *verts, int numPolys ); + bool R_InsideFog( const vec3_t origin, int fognum ); + void R_AddInnerFogSurfaces(); + void RE_AddDynamicLightToSceneET( const vec3_t org, float radius, float intensity, float r, float g, float b, qhandle_t hShader, int flags ); void RE_AddDynamicLightToSceneQ3A( const vec3_t org, float intensity, float r, float g, float b ); diff --git a/src/engine/renderer/tr_main.cpp b/src/engine/renderer/tr_main.cpp index 8937479b04..f05e74c149 100644 --- a/src/engine/renderer/tr_main.cpp +++ b/src/engine/renderer/tr_main.cpp @@ -1731,11 +1731,12 @@ void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader, int lightmapNum, i R_AddDrawSurf( surface, shader->depthShader, 0, 0, bspSurface ); } - // don't draw the global fog twice on opaque surfaces - // allow global fog with the fogLE shader although drawing the global fog with the - // volumetric (fogQuake3) shader looks kind of buggy + bool usingMaterial = glConfig.usingMaterialSystem && !r_materialSystemSkip.Get(); + + // don't fog surfaces that already were covered by globalFog if ( !shader->noFog && fogNum >= 1 && - ( fogNum != tr.world->globalFog || shader->fogPass == fogPass_t::FP_LE ) ) { + !( usingMaterial ? fogNum == tr.world->globalFog : R_InsideFog( backEnd.viewParms.orientation.origin, fogNum ) ) ) + { R_AddDrawSurf( surface, shader->fogShader, 0, fogNum, bspSurface ); } } @@ -2085,6 +2086,8 @@ void R_RenderView( viewParms_t *parms ) // set camera frustum planes in world space again, but this time including the far plane tr.orientation = tr.viewParms.world; + R_AddInnerFogSurfaces(); + R_AddEntitySurfaces(); // Transform the blur vector in view space, FIXME for some we need reason invert its Z component diff --git a/src/engine/renderer/tr_scene.cpp b/src/engine/renderer/tr_scene.cpp index e14632ef18..831b240ae5 100644 --- a/src/engine/renderer/tr_scene.cpp +++ b/src/engine/renderer/tr_scene.cpp @@ -248,6 +248,45 @@ void RE_AddPolysToScene( qhandle_t hShader, int numVerts, const polyVert_t *vert //================================================================================= +bool R_InsideFog( const vec3_t origin, int fognum ) +{ + const auto &bounds = tr.world->fogs[ fognum ].bounds; + + for ( int i = 0; i < 3; i++ ) + { + if ( origin[ i ] < bounds[ 0 ][ i ] || origin[ i ] > bounds[ 1 ][ i ] ) + { + return false; + } + } + + return true; +} + +void R_AddInnerFogSurfaces() +{ + if ( glConfig.usingMaterialSystem && !r_materialSystemSkip.Get() ) + { + if ( tr.world->globalFog > 0 ) + { + const fog_t &fog = tr.world->fogs[ tr.world->globalFog ]; + R_AddDrawSurf( ( surfaceType_t *)&fog.surf, fog.shader->fogInnerShader, -1, 0 ); + } + } + else + { + for ( int i = 1; i < tr.world->numFogs; i++ ) + { + // TODO: with portals this should use the point at the view frustum instead + if ( R_InsideFog( backEnd.viewParms.orientation.origin, i ) ) + { + const fog_t &fog = tr.world->fogs[ i ]; + R_AddDrawSurf( ( surfaceType_t *)&fog.surf, fog.shader->fogInnerShader, -1, 0 ); + } + } + } +} + /* ===================== RE_AddRefEntityToScene diff --git a/src/engine/renderer/tr_shade.cpp b/src/engine/renderer/tr_shade.cpp index 713934f9d1..7a2f447575 100644 --- a/src/engine/renderer/tr_shade.cpp +++ b/src/engine/renderer/tr_shade.cpp @@ -310,8 +310,6 @@ static void GLSL_InitGPUShadersOrError() // global fog post process effect gl_shaderManager.LoadShader( gl_fogGlobalShader ); - - gl_fogGlobalShader->MarkProgramForBuilding(); } if ( r_heatHaze->integer ) @@ -1615,7 +1613,7 @@ void Render_liquid( shaderStage_t *pStage ) void Render_fog( shaderStage_t* pStage ) { - if ( r_noFog->integer || !r_wolfFog->integer || ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) + if ( r_noFog->integer || ( backEnd.refdef.rdflags & RDF_NOWORLDMODEL ) ) { return; } @@ -1646,12 +1644,12 @@ void Render_fog( shaderStage_t* pStage ) gl_fogQuake3Shader->BindProgram(); gl_fogQuake3Shader->SetUniform_ViewOrigin( backEnd.viewParms.orientation.origin ); - gl_fogQuake3Shader->SetUniform_FogDensity( fog->tcScale ); + gl_fogQuake3Shader->SetUniform_FogDensity( 1.0f / fog->shader->fogParms.depthForOpaque ); gl_fogQuake3Shader->SetUniform_FogDepthVector( fogDepthVector ); gl_fogQuake3Shader->SetUniform_FogEyeT( eyeT ); // u_Color - SetUniform_ColorGlobal( gl_fogQuake3Shader, fog->color ); + SetUniform_ColorGlobal( gl_fogQuake3Shader, fog->shader->fogParms.color ); gl_fogQuake3Shader->SetUniform_ModelMatrix( backEnd.orientation.transformMatrix ); gl_fogQuake3Shader->SetUniform_ModelViewProjectionMatrix( glState.modelViewProjectionMatrix[ glState.stackIndex ] ); diff --git a/src/engine/renderer/tr_shader.cpp b/src/engine/renderer/tr_shader.cpp index 647eae66c6..43d24df473 100644 --- a/src/engine/renderer/tr_shader.cpp +++ b/src/engine/renderer/tr_shader.cpp @@ -4398,17 +4398,23 @@ static bool ParseShader( const char *_text ) // fogParms else if ( !Q_stricmp( token, "fogParms" ) ) { - /* - Log::Warn("fogParms keyword not supported in shader '%s'", shader.name); - SkipRestOfLine(text); + vec3_t fogColor; - */ - - if ( !ParseVector( text, 3, shader.fogParms.color ) ) + if ( !ParseVector( text, 3, fogColor ) ) { return false; } + shader.fogParms.color = Color::Adapt( fogColor ); + + if ( tr.worldLinearizeTexture ) + { + shader.fogParms.color = shader.fogParms.color.ConvertFromSRGB(); + } + + shader.fogParms.color *= tr.identityLight; + shader.fogParms.color.SetAlpha( 1 ); + token = COM_ParseExt2( text, false ); if ( !token[ 0 ] ) @@ -4417,7 +4423,7 @@ static bool ParseShader( const char *_text ) continue; } - shader.fogParms.depthForOpaque = atof( token ); + shader.fogParms.depthForOpaque = std::max( 1.0, atof( token ) ); shader.sort = Util::ordinal(shaderSort_t::SS_FOG); @@ -5430,6 +5436,12 @@ static void SetStagesRenderers() &UpdateSurfaceDataFog, &BindShaderFog, &ProcessMaterialFog, }; break; + case stageType_t::ST_FOGMAP_INNER: + stageRendererOptions = { + &Render_fogGlobal, &MarkShaderBuildNOP, + &UpdateSurfaceDataNOP, &BindShaderNOP, &ProcessMaterialNOP, + }; + break; default: Log::Warn( "Missing renderer for stage type %d in shader %s, stage %d", Util::ordinal(stage->type), shader.name, s ); @@ -5592,17 +5604,6 @@ static void GeneratePermanentShaderTable( const float *values, int numValues ) shaderTableHashTable[ hash ] = newTable; } -bool CheckShaderNameLength( const char* func_err, const char* name, const char* suffix ) -{ - if ( strlen( name ) + strlen( suffix ) >= MAX_QPATH ) - { - Log::Warn("%s Shader name %s%s length longer than MAX_QPATH %d", func_err, name, suffix, MAX_QPATH ); - return false; - } - - return true; -} - static void ValidateStage( shaderStage_t *pStage ) { struct stageCheck_t { @@ -5624,6 +5625,7 @@ static void ValidateStage( shaderStage_t *pStage ) { stageType_t::ST_HEATHAZEMAP, { true, true, false, "heatHazeMap" } }, { stageType_t::ST_LIQUIDMAP, { true, true, false, "liquidMap" } }, { stageType_t::ST_FOGMAP, { true, false, false, "fogMap" } }, + { stageType_t::ST_FOGMAP_INNER, { true, false, false, "fogMapInner" } }, // The lightmap is fetched at render time. { stageType_t::ST_LIGHTMAP, { true, false, false, "light map" } }, // The lightmap is fetched at render time. @@ -5833,6 +5835,8 @@ static shader_t *FinishShader() } } + size_t nameLength = strlen( shader.name ); + // generate depth-only shader if necessary if( r_depthShaders.Get() && !shader.isSky && @@ -5847,24 +5851,7 @@ static shader_t *FinishShader() shader.noFog = true; shader.fogShader = nullptr; - const char* depthShaderSuffix = "$depth"; - - if ( !CheckShaderNameLength( "FinishShader", shader.name, depthShaderSuffix ) ) - { - ret->depthShader = nullptr; - - if ( glConfig.usingMaterialSystem && !tr.worldLoaded ) { - uint8_t maxStages = ret->lastStage - ret->stages; - - // Add 1 for potential fog stages - maxStages = PAD( maxStages + 1, 4 ); // Aligned to 4 components - materialSystem.maxStages = std::max( maxStages, materialSystem.maxStages ); - } - - return ret; - } - - strcat( shader.name, depthShaderSuffix ); + Q_strcat( shader.name, sizeof( shader.name ), "$depth" ); if( stages[0].stateBits & GLS_ATEST_BITS ) { // alpha test requires a custom depth shader @@ -5911,6 +5898,19 @@ static shader_t *FinishShader() ret->depthShader = nullptr; } + if ( ret->fogParms.depthForOpaque != 0 ) + { + shader.name[ nameLength ] = '\0'; + Q_strcat( shader.name, sizeof( shader.name ), "$fogIn" ); + stages[1].active = false; + numStages = 1; + ResetStruct( stages[ 0 ] ); + stages[ 0 ].active = true; + stages[ 0 ].type = stageType_t::ST_FOGMAP_INNER; + SetStagesRenderers(); + ret->fogInnerShader = MakeShaderPermanent(); + } + if ( glConfig.usingMaterialSystem && !tr.worldLoaded ) { uint8_t maxStages = ret->lastStage - ret->stages; @@ -6053,6 +6053,7 @@ shader_t *R_FindShader( const char *name, int flags ) ClearGlobalShader(); Q_strncpyz( shader.name, strippedName, sizeof( shader.name ) ); + ASSERT_LT( strlen( shader.name ), MAX_QPATH ); shader.registerFlags = flags; for ( i = 0; i < MAX_SHADER_STAGES; i++ ) @@ -6243,8 +6244,9 @@ qhandle_t RE_RegisterShader( const char *name, int flags ) { shader_t *sh; - if ( !CheckShaderNameLength( "RE_RegisterShader", name, "" ) ) + if ( strlen( name ) >= MAX_QPATH ) { + Log::Warn( "RE_RegisterShader: name '%s' is too long", name ); return 0; }