From 3209d4ed23ecf3ca6d7feaa5aef8c829a8d444e2 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 20 Dec 2019 16:05:00 +0100 Subject: [PATCH] - added a few more texture coloring options to the shader. Aside from adding an additive component it can now also do: - desaturation (not limited to the range of 0..1 so it can also be used for oversaturation by applying a negative number or negative saturation by going above 1.0. - invert the texture - apply a blend, including 3 special mode taken from EDuke32. Currently only the implementation is done, it is not exposed to UDMF yet. --- src/rendering/gl/renderer/gl_renderstate.cpp | 5 ++ src/rendering/gl/shaders/gl_shader.cpp | 12 +++ src/rendering/gl/shaders/gl_shader.h | 6 ++ .../hwrenderer/scene/hw_renderstate.h | 35 ++++++++ src/rendering/hwrenderer/scene/hw_walls.cpp | 4 + src/rendering/vulkan/shaders/vk_shader.cpp | 5 ++ wadsrc/static/shaders/glsl/main.fp | 81 +++++++++++++++++-- 7 files changed, 142 insertions(+), 6 deletions(-) diff --git a/src/rendering/gl/renderer/gl_renderstate.cpp b/src/rendering/gl/renderer/gl_renderstate.cpp index 29883afc8..7a11a60f5 100644 --- a/src/rendering/gl/renderer/gl_renderstate.cpp +++ b/src/rendering/gl/renderer/gl_renderstate.cpp @@ -138,6 +138,11 @@ bool FGLRenderState::ApplyShader() activeShader->muClipSplit.Set(mClipSplit); activeShader->muSpecularMaterial.Set(mGlossiness, mSpecularLevel); activeShader->muAddColor.Set(mStreamData.uAddColor); + activeShader->muBlendColor.Set(mStreamData.uBlendColor); + activeShader->muObjectBlendMode.Set(mStreamData.uObjectBlendMode); + activeShader->muObjectColorizeFactor.Set(mStreamData.uObjectColorizeFactor); + activeShader->muObjectDesaturationFactor.Set(mStreamData.uObjectDesaturationFactor); + activeShader->muObjectInvertColor.Set(mStreamData.uObjectInvertColor); if (mGlowEnabled || activeShader->currentglowstate) { diff --git a/src/rendering/gl/shaders/gl_shader.cpp b/src/rendering/gl/shaders/gl_shader.cpp index 0a06e56c0..a2d73ceb6 100644 --- a/src/rendering/gl/shaders/gl_shader.cpp +++ b/src/rendering/gl/shaders/gl_shader.cpp @@ -242,10 +242,17 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * i_data += "uniform vec4 uObjectColor2;\n"; i_data += "uniform vec4 uDynLightColor;\n"; i_data += "uniform vec4 uAddColor;\n"; + i_data += "uniform vec4 uBlendColor;\n"; i_data += "uniform vec4 uFogColor;\n"; i_data += "uniform float uDesaturationFactor;\n"; i_data += "uniform float uInterpolationFactor;\n"; + i_data += "uniform float uObjectDesaturationFactor;\n"; + i_data += "uniform float uObjectColorizeFactor;\n"; + i_data += "uniform int uObjectBlendMode;\n"; + i_data += "uniform int uObjectInvertColor;\n"; + + // Glowing walls stuff i_data += "uniform vec4 uGlowTopPlane;\n"; i_data += "uniform vec4 uGlowTopColor;\n"; @@ -536,6 +543,11 @@ bool FShader::Load(const char * name, const char * vert_prog_lump, const char * muAlphaThreshold.Init(hShader, "uAlphaThreshold"); muSpecularMaterial.Init(hShader, "uSpecularMaterial"); muAddColor.Init(hShader, "uAddColor"); + muBlendColor.Init(hShader, "uBlendColor"); + muObjectDesaturationFactor.Init(hShader, "uObjectDesaturationFactor"); + muObjectColorizeFactor.Init(hShader, "uObjectColorizeFactor"); + muObjectBlendMode.Init(hShader, "uObjectBlendMode"); + muObjectInvertColor.Init(hShader, "uObjectInvertColor"); muTimer.Init(hShader, "timer"); lights_index = glGetUniformLocation(hShader, "lights"); diff --git a/src/rendering/gl/shaders/gl_shader.h b/src/rendering/gl/shaders/gl_shader.h index 2a3097097..ea3c36479 100644 --- a/src/rendering/gl/shaders/gl_shader.h +++ b/src/rendering/gl/shaders/gl_shader.h @@ -246,6 +246,7 @@ class FShader FBufferedUniformPE muObjectColor; FBufferedUniformPE muObjectColor2; FBufferedUniformPE muAddColor; + FBufferedUniformPE muBlendColor; FUniform4f muGlowBottomColor; FUniform4f muGlowTopColor; FUniform4f muGlowBottomPlane; @@ -259,6 +260,11 @@ class FShader FBufferedUniform2f muSpecularMaterial; FBufferedUniform1f muTimer; + FBufferedUniform1f muObjectDesaturationFactor; + FBufferedUniform1f muObjectColorizeFactor; + FBufferedUniform1i muObjectBlendMode; + FBufferedUniform1i muObjectInvertColor; + int lights_index; int modelmatrix_index; int normalmodelmatrix_index; diff --git a/src/rendering/hwrenderer/scene/hw_renderstate.h b/src/rendering/hwrenderer/scene/hw_renderstate.h index b09d6e9e0..4f1d97019 100644 --- a/src/rendering/hwrenderer/scene/hw_renderstate.h +++ b/src/rendering/hwrenderer/scene/hw_renderstate.h @@ -158,11 +158,16 @@ struct StreamData FVector4PalEntry uObjectColor2; FVector4 uDynLightColor; FVector4PalEntry uAddColor; + FVector4PalEntry uBlendColor; FVector4PalEntry uFogColor; float uDesaturationFactor; float uInterpolationFactor; float timer; int useVertexData; + float uObjectDesaturationFactor; + float uObjectColorizeFactor; + int uObjectBlendMode; + int uObjectInvertColor; FVector4 uVertexColor; FVector4 uVertexNormal; @@ -236,6 +241,11 @@ public: mStreamData.uAddColor = 0; mStreamData.uObjectColor = 0xffffffff; mStreamData.uObjectColor2 = 0; + mStreamData.uBlendColor = 0; + mStreamData.uObjectDesaturationFactor = 0; + mStreamData.uObjectBlendMode = 0; + mStreamData.uObjectColorizeFactor = 1; + mStreamData.uObjectInvertColor = 0; mSoftLight = 0; mLightParms[0] = mLightParms[1] = mLightParms[2] = 0.0f; mLightParms[3] = -1.f; @@ -445,6 +455,31 @@ public: mStreamData.uAddColor = pe; } + void SetBlendColor(PalEntry pe) + { + mStreamData.uBlendColor = pe; + } + + void SetColorizeFactor(float f) + { + mStreamData.uObjectColorizeFactor = f; + } + + void SetObjectDesaturateFactor(float f) + { + mStreamData.uObjectDesaturationFactor = f; + } + + void SetObjectInvert(bool on) + { + mStreamData.uObjectInvertColor = on; + } + + void SetObjectBlendMode(int b) + { + mStreamData.uObjectBlendMode = b; + } + void SetFog(PalEntry c, float d) { const float LOG2E = 1.442692f; // = 1/log(2) diff --git a/src/rendering/hwrenderer/scene/hw_walls.cpp b/src/rendering/hwrenderer/scene/hw_walls.cpp index 9f1b4aab0..d8efc7346 100644 --- a/src/rendering/hwrenderer/scene/hw_walls.cpp +++ b/src/rendering/hwrenderer/scene/hw_walls.cpp @@ -175,6 +175,7 @@ void HWWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) state.SetObjectColor(color1); state.SetObjectColor2((color1 != color2) ? color2 : PalEntry(0)); state.SetAddColor(side->GetAdditiveColor(tierndx, frontsector)); + if (color1 != color2) { // Do gradient setup only if there actually is a gradient. @@ -243,6 +244,9 @@ void HWWall::RenderTexturedWall(HWDrawInfo *di, FRenderState &state, int rflags) state.SetTextureMode(tmode); state.EnableGlow(false); state.EnableGradient(false); + state.SetObjectDesaturateFactor(0); + state.SetObjectInvert(false); + state.SetObjectBlendMode(0); } //========================================================================== diff --git a/src/rendering/vulkan/shaders/vk_shader.cpp b/src/rendering/vulkan/shaders/vk_shader.cpp index 12f501db7..0c06944ae 100644 --- a/src/rendering/vulkan/shaders/vk_shader.cpp +++ b/src/rendering/vulkan/shaders/vk_shader.cpp @@ -118,11 +118,16 @@ static const char *shaderBindings = R"( vec4 uObjectColor2; vec4 uDynLightColor; vec4 uAddColor; + vec4 uBlendColor; vec4 uFogColor; float uDesaturationFactor; float uInterpolationFactor; float timer; // timer data for material shaders int useVertexData; + float uObjectDesaturationFactor; + float uObjectColorizeFactor; + int uObjectBlendMode; + int uObjectInvertColor; vec4 uVertexColor; vec4 uVertexNormal; diff --git a/wadsrc/static/shaders/glsl/main.fp b/wadsrc/static/shaders/glsl/main.fp index c3a08ad99..c8757ad1b 100644 --- a/wadsrc/static/shaders/glsl/main.fp +++ b/wadsrc/static/shaders/glsl/main.fp @@ -54,12 +54,12 @@ float grayscale(vec4 color) // //=========================================================================== -vec4 desaturate(vec4 texel) +vec4 dodesaturate(vec4 texel, float factor) { - if (uDesaturationFactor > 0.0) + if (factor != 0.0) { float gray = grayscale(texel); - return mix (texel, vec4(gray,gray,gray,texel.a), uDesaturationFactor); + return mix (texel, vec4(gray,gray,gray,texel.a), factor); } else { @@ -67,6 +67,28 @@ vec4 desaturate(vec4 texel) } } +//=========================================================================== +// +// Desaturate a color +// +//=========================================================================== + +vec4 desaturate(vec4 texel) +{ + return dodesaturate(texel, uDesaturationFactor); +} + +//=========================================================================== +// +// Texture tinting code originally from JFDuke. +// +//=========================================================================== + +const int Tex_Blend_Alpha = 1; +const int Tex_Blend_Screen = 2; +const int Tex_Blend_Overlay = 3; +const int Tex_Blend_Hardlight = 4; + //=========================================================================== // // This function is common for all (non-special-effect) fragment shaders @@ -116,11 +138,58 @@ vec4 getTexel(vec2 st) return texel; } - + + // Step 1: desaturate according to the material's desaturation factor. + texel = dodesaturate(texel, uObjectDesaturationFactor); + + // Step 2: Invert if requested + if (uObjectInvertColor != 0) + { + texel.rgb = vec3(1.0 - texel.r, 1.0 - texel.g, 1.0 - texel.b); + } + + // Step 3: Apply additive color texel.rgb += uAddColor.rgb; + + // Step 4: Colorization, including gradient if set. + if (uObjectColor2.a == 0.0) + texel.rgb = clamp(texel.rgb * uObjectColor.rgb * uObjectColorizeFactor, 0.0, 1.0); + else + texel.rgb *= clamp(texel.rgb * mix(uObjectColor.rgb, uObjectColor2.rgb, gradientdist.z) * uObjectColorizeFactor, 0.0, 1.0); + texel.a *= uObjectColor.a; // note that the ObjectColor can have an alpha component. + + // Step 5: Apply a blend. This may just be a translucent overlay or one of the blend modes present in current Build engines. + if (uObjectBlendMode != 0) + { + vec3 tcol = texel.rgb * 255.0; // * 255.0 to make it easier to reuse the integer math. + vec4 tint = uBlendColor * 255.0; - if (uObjectColor2.a == 0.0) texel *= uObjectColor; - else texel *= mix(uObjectColor, uObjectColor2, gradientdist.z); + switch (uObjectBlendMode) + { + default: + tcol.b = tcol.b * (1.0 - uBlendColor.a) + tint.b * uBlendColor.a; + tcol.g = tcol.g * (1.0 - uBlendColor.a) + tint.g * uBlendColor.a; + tcol.r = tcol.r * (1.0 - uBlendColor.a) + tint.r * uBlendColor.a; + break; + // The following 3 are taken 1:1 from the Build engine + case Tex_Blend_Screen: + tcol.b = 255.0 - (((255.0 - tcol.b) * (255.0 - tint.r)) / 256.0); + tcol.g = 255.0 - (((255.0 - tcol.g) * (255.0 - tint.g)) / 256.0); + tcol.r = 255.0 - (((255.0 - tcol.r) * (255.0 - tint.b)) / 256.0); + break; + case Tex_Blend_Overlay: + tcol.b = tcol.b < 128.0? (tcol.b * tint.b) / 128.0 : 255.0 - (((255.0 - tcol.b) * (255.0 - tint.b)) / 128.0); + tcol.g = tcol.g < 128.0? (tcol.g * tint.g) / 128.0 : 255.0 - (((255.0 - tcol.g) * (255.0 - tint.g)) / 128.0); + tcol.r = tcol.r < 128.0? (tcol.r * tint.r) / 128.0 : 255.0 - (((255.0 - tcol.r) * (255.0 - tint.r)) / 128.0); + break; + case Tex_Blend_Hardlight: + tcol.b = tint.b < 128.0 ? (tcol.b * tint.b) / 128.0 : 255.0 - (((255.0 - tcol.b) * (255.0 - tint.b)) / 128.0); + tcol.g = tint.g < 128.0 ? (tcol.g * tint.g) / 128.0 : 255.0 - (((255.0 - tcol.g) * (255.0 - tint.g)) / 128.0); + tcol.r = tint.r < 128.0 ? (tcol.r * tint.r) / 128.0 : 255.0 - (((255.0 - tcol.r) * (255.0 - tint.r)) / 128.0); + break; + } + texel.rgb = tcol / 255.0; + } return desaturate(texel); }