ITR2_ASSET/Engine/Shaders/StandaloneRenderer/OpenGL/SlateElementPixelShader.glsl
2024-11-19 13:27:19 -08:00

351 lines
8.8 KiB
GLSL

// Copyright Epic Games, Inc. All Rights Reserved.
// handle differences between ES and full GL shaders
#if PLATFORM_USES_GLES
precision highp float;
#else
// #version 120 at the beginning is added in FSlateOpenGLShader::CompileShader()
#extension GL_EXT_gpu_shader4 : enable
#endif
#ifndef USE_709
#define USE_709 0
#endif // USE_709
// Shader types
#define ST_Default 0
#define ST_Border 1
#define ST_GrayscaleFont 2
#define ST_ColorFont 3
#define ST_Line 4
#define ST_RoundedBox 7
#define USE_LEGACY_DISABLED_EFFECT 0
/** Display gamma x:gamma curve adjustment, y:inverse gamma (1/GEngine->DisplayGamma) */
uniform vec2 GammaValues = vec2(1, 1/2.2);
// Draw effects
uniform bool EffectsDisabled;
uniform bool IgnoreTextureAlpha;
uniform vec4 ShaderParams;
uniform vec4 ShaderParams2;
uniform int ShaderType;
uniform sampler2D ElementTexture;
#if PLATFORM_MAC
// GL_TEXTURE_RECTANGLE_ARB support, used by the web surface on macOS
uniform bool UseTextureRectangle;
uniform sampler2DRect ElementRectTexture;
uniform vec2 Size;
#endif
varying vec4 Position;
varying vec4 TexCoords;
varying vec4 Color;
varying vec4 SecondaryColor;
vec3 maxWithScalar(float test, vec3 values)
{
return vec3(max(test, values.x), max(test, values.y), max(test, values.z));
}
vec3 powScalar(vec3 values, float power)
{
return vec3(pow(values.x, power), pow(values.y, power), pow(values.z, power));
}
vec3 LinearTo709Branchless(vec3 lin)
{
lin = maxWithScalar(6.10352e-5, lin); // minimum positive non-denormal (fixes black problem on DX11 AMD and NV)
return min(lin * 4.5, powScalar(maxWithScalar(0.018, lin), 0.45) * 1.099 - 0.099);
}
vec3 LinearToSrgbBranchless(vec3 lin)
{
lin = maxWithScalar(6.10352e-5, lin); // minimum positive non-denormal (fixes black problem on DX11 AMD and NV)
return min(lin * 12.92, powScalar(maxWithScalar(0.00313067, lin), 1.0/2.4) * 1.055 - 0.055);
// Possible that mobile GPUs might have native pow() function?
//return min(lin * 12.92, exp2(log2(max(lin, 0.00313067)) * (1.0/2.4) + log2(1.055)) - 0.055);
}
float LinearToSrgbBranchingChannel(float lin)
{
if(lin < 0.00313067) return lin * 12.92;
return pow(lin, (1.0/2.4)) * 1.055 - 0.055;
}
vec3 LinearToSrgbBranching(vec3 lin)
{
return vec3(
LinearToSrgbBranchingChannel(lin.r),
LinearToSrgbBranchingChannel(lin.g),
LinearToSrgbBranchingChannel(lin.b));
}
float sRGBToLinearChannel( float ColorChannel )
{
return ColorChannel > 0.04045 ? pow( ColorChannel * (1.0 / 1.055) + 0.0521327, 2.4 ) : ColorChannel * (1.0 / 12.92);
}
vec3 sRGBToLinear( vec3 Color )
{
return vec3(sRGBToLinearChannel(Color.r),
sRGBToLinearChannel(Color.g),
sRGBToLinearChannel(Color.b));
}
/**
* @param GammaCurveRatio The curve ratio compared to a 2.2 standard gamma, e.g. 2.2 / DisplayGamma. So normally the value is 1.
*/
vec3 ApplyGammaCorrection(vec3 LinearColor, float GammaCurveRatio)
{
// Apply "gamma" curve adjustment.
vec3 CorrectedColor = powScalar(LinearColor, GammaCurveRatio);
#if PLATFORM_MAC
// Note, MacOSX native output is raw gamma 2.2 not sRGB!
//CorrectedColor = pow(CorrectedColor, 1.0/2.2);
CorrectedColor = LinearToSrgbBranching(CorrectedColor);
#else
#if USE_709
// Didn't profile yet if the branching version would be faster (different linear segment).
CorrectedColor = LinearTo709Branchless(CorrectedColor);
#else
CorrectedColor = LinearToSrgbBranching(CorrectedColor);
#endif
#endif
return CorrectedColor;
}
vec3 GammaCorrect(vec3 InColor)
{
vec3 CorrectedColor = InColor;
// gamma correct
//#if PLATFORM_USES_GLES
// OutColor.rgb = sqrt( OutColor.rgb );
//#else
// OutColor.rgb = pow(OutColor.rgb, vec3(1.0/2.2));
//#endif
#if !PLATFORM_USES_GLES
if( GammaValues.y != 1.0f )
{
CorrectedColor = ApplyGammaCorrection(CorrectedColor, GammaValues.x);
}
#endif
return CorrectedColor;
}
vec4 GetGrayscaleFontElementColor()
{
vec4 OutColor = Color;
#if PLATFORM_LINUX
OutColor.a *= texture2D(ElementTexture, TexCoords.xy).r; // OpenGL 3.2+ uses Red for single channel textures
#else
OutColor.a *= texture2D(ElementTexture, TexCoords.xy).a;
#endif
return OutColor;
}
vec4 GetColorFontElementColor()
{
vec4 OutColor = Color;
OutColor *= texture2D(ElementTexture, TexCoords.xy);
return OutColor;
}
vec4 GetDefaultElementColor()
{
vec4 OutColor = Color;
vec4 TextureColor;
#if PLATFORM_MAC
if ( UseTextureRectangle )
{
TextureColor = texture2DRect(ElementRectTexture, TexCoords.xy*TexCoords.zw*Size).bgra;
}
else
#endif
{
TextureColor = texture2D(ElementTexture, TexCoords.xy*TexCoords.zw);
}
if( IgnoreTextureAlpha )
{
TextureColor.a = 1.0;
}
OutColor *= TextureColor;
return OutColor;
}
vec4 GetBorderElementColor()
{
vec4 OutColor = Color;
vec4 InTexCoords = TexCoords;
vec2 NewUV;
if( InTexCoords.z == 0.0 && InTexCoords.w == 0.0 )
{
NewUV = InTexCoords.xy;
}
else
{
vec2 MinUV;
vec2 MaxUV;
if( InTexCoords.z > 0.0 )
{
MinUV = vec2(ShaderParams.x,0.0);
MaxUV = vec2(ShaderParams.y,1.0);
InTexCoords.w = 1.0;
}
else
{
MinUV = vec2(0.0,ShaderParams.z);
MaxUV = vec2(1.0,ShaderParams.w);
InTexCoords.z = 1.0;
}
NewUV = InTexCoords.xy*InTexCoords.zw;
NewUV = fract(NewUV);
NewUV = mix(MinUV,MaxUV,NewUV);
}
vec4 TextureColor = texture2D(ElementTexture, NewUV);
if( IgnoreTextureAlpha )
{
TextureColor.a = 1.0;
}
OutColor *= TextureColor;
return OutColor;
}
float GetRoundedBoxDistance(vec2 pos, vec2 center, float radius, float inset)
{
// distance from center
pos = abs(pos - center);
// distance from the inner corner
pos = pos - (center - vec2(radius + inset, radius + inset));
// use distance to nearest edge when not in quadrant with radius
// this handles an edge case when radius is very close to thickness
// otherwise we're in the quadrant with the radius,
// just use the analytic signed distance function
return mix( length(pos) - radius,
max(pos.x - radius, pos.y - radius),
float(pos.x <= 0 || pos.y <=0) );
}
vec4 GetRoundedBoxElementColor()
{
vec2 size = ShaderParams.zw;
vec2 pos = size * TexCoords.xy;
vec2 center = size / 2.0;
//X = Top Left, Y = Top Right, Z = Bottom Right, W = Bottom Left */
vec4 cornerRadii = ShaderParams2;
// figure out which radius to use based on which quadrant we're in
vec2 quadrant = step(TexCoords.xy, vec2(.5,.5));
float left = mix(cornerRadii.y, cornerRadii.x, quadrant.x);
float right = mix(cornerRadii.z, cornerRadii.w, quadrant.x);
float radius = mix(right, left, quadrant.y);
float thickness = ShaderParams.y;
// Compute the distances internal and external to the border outline
float dext = GetRoundedBoxDistance(pos, center, radius, 0.0);
float din = GetRoundedBoxDistance(pos, center, max(radius - thickness, 0), thickness);
// Compute the border intensity and fill intensity with a smooth transition
float spread = 0.5;
float bi = smoothstep(spread, -spread, dext);
float fi = smoothstep(spread, -spread, din);
// alpha blend the external color
vec4 fill = GetDefaultElementColor();
vec4 border = SecondaryColor;
vec4 OutColor = mix(border, fill, float(thickness > radius));
OutColor.a = 0.0;
// blend in the border and fill colors
OutColor = mix(OutColor, border, bi);
OutColor = mix(OutColor, fill, fi);
return OutColor;
}
vec4 GetLineSegmentElementColor()
{
vec2 Gradient = TexCoords.xy;
vec2 OutsideFilterUV = vec2(1.0, 1.0);
vec2 InsideFilterUV = vec2(ShaderParams.x, 0.0);
vec2 LineCoverage = smoothstep(OutsideFilterUV, InsideFilterUV, abs(Gradient));
vec4 OutColor = Color;
OutColor.a *= LineCoverage.x * LineCoverage.y;
return OutColor;
}
void main()
{
vec4 OutColor;
if( ShaderType == ST_Default )
{
OutColor = GetDefaultElementColor();
}
else if( ShaderType == ST_RoundedBox )
{
OutColor = GetRoundedBoxElementColor();
}
else if( ShaderType == ST_Border )
{
OutColor = GetBorderElementColor();
}
else if( ShaderType == ST_GrayscaleFont )
{
OutColor = GetGrayscaleFontElementColor();
}
else if( ShaderType == ST_ColorFont )
{
OutColor = GetColorFontElementColor();
}
else
{
OutColor = GetLineSegmentElementColor();
}
// gamma correct
OutColor.rgb = GammaCorrect(OutColor.rgb);
if( EffectsDisabled )
{
#if USE_LEGACY_DISABLED_EFFECT
//desaturate
vec3 LumCoeffs = vec3( 0.3, 0.59, .11 );
float Lum = dot( LumCoeffs, OutColor.rgb );
OutColor.rgb = mix( OutColor.rgb, vec3(Lum,Lum,Lum), .8 );
vec3 Grayish = vec3(0.4, 0.4, 0.4);
OutColor.rgb = mix( OutColor.rgb, Grayish, clamp( distance( OutColor.rgb, Grayish ), 0.0, 0.8) );
#else
OutColor.a *= .45f;
#endif
}
gl_FragColor = OutColor.bgra;
}