// Copyright Epic Games, Inc. All Rights Reserved. #include "GammaCorrectionCommon.hlsl" // Shader types #define ESlateShader::Default 0 #define ESlateShader::Border 1 #define ESlateShader::GrayscaleFont 2 #define ESlateShader::ColorFont 3 #define ESlateShader::LineSegment 4 #define ESlateShader::RoundedBox 7 #define USE_LEGACY_DISABLED_EFFECT 0 Texture2D ElementTexture; SamplerState ElementTextureSampler; cbuffer PerFramePSConstants { /** Display gamma x:gamma curve adjustment, y:inverse gamma (1/GEngine->DisplayGamma) */ float2 GammaValues; }; cbuffer PerElementPSConstants { float4 ShaderParams; // 16 bytes float4 ShaderParams2; // 16 bytes uint ShaderType; // 4 bytes uint IgnoreTextureAlpha; // 4 bytes uint DisableEffect; // 4 bytes uint UNUSED[1]; // 4 bytes }; struct VertexOut { float4 Position : SV_POSITION; float4 Color : COLOR0; float4 SecondaryColor : COLOR1; float4 TextureCoordinates : TEXCOORD0; }; float3 Hue( float H ) { float R = abs(H * 6 - 3) - 1; float G = 2 - abs(H * 6 - 2); float B = 2 - abs(H * 6 - 4); return saturate( float3(R,G,B) ); } float3 GammaCorrect(float3 InColor) { float3 CorrectedColor = InColor; if ( GammaValues.y != 1.0f ) { CorrectedColor = ApplyGammaCorrection(CorrectedColor, GammaValues.x); } return CorrectedColor; } float4 GetGrayscaleFontElementColor( VertexOut InVertex ) { float4 OutColor = InVertex.Color; OutColor.a *= ElementTexture.Sample(ElementTextureSampler, InVertex.TextureCoordinates.xy).a; return OutColor; } float4 GetColorFontElementColor(VertexOut InVertex) { float4 OutColor = InVertex.Color; OutColor *= ElementTexture.Sample(ElementTextureSampler, InVertex.TextureCoordinates.xy); return OutColor; } float4 GetColor( VertexOut InVertex, float2 UV ) { float4 FinalColor; float4 BaseColor = ElementTexture.Sample(ElementTextureSampler, UV ); if( IgnoreTextureAlpha != 0 ) { BaseColor.a = 1.0f; } FinalColor = BaseColor*InVertex.Color; return FinalColor; } float4 GetDefaultElementColor( VertexOut InVertex ) { return GetColor( InVertex, InVertex.TextureCoordinates.xy*InVertex.TextureCoordinates.zw ); } float4 GetBorderElementColor( VertexOut InVertex ) { float2 NewUV; if( InVertex.TextureCoordinates.z == 0.0f && InVertex.TextureCoordinates.w == 0.0f ) { NewUV = InVertex.TextureCoordinates.xy; } else { float2 MinUV; float2 MaxUV; if( InVertex.TextureCoordinates.z > 0 ) { MinUV = float2(ShaderParams.x,0); MaxUV = float2(ShaderParams.y,1); InVertex.TextureCoordinates.w = 1.0f; } else { MinUV = float2(0,ShaderParams.z); MaxUV = float2(1,ShaderParams.w); InVertex.TextureCoordinates.z = 1.0f; } NewUV = InVertex.TextureCoordinates.xy*InVertex.TextureCoordinates.zw; NewUV = frac(NewUV); NewUV = lerp(MinUV,MaxUV,NewUV); } return GetColor( InVertex, NewUV ); } float GetRoundedBoxDistance(float2 pos, float2 center, float radius, float inset) { // distance from center pos = abs(pos - center); // distance from the inner corner pos = pos - (center - float2(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 lerp( length(pos) - radius, max(pos.x - radius, pos.y - radius), float(pos.x <= 0 || pos.y <=0) ); } float4 GetRoundedBoxElementColor( VertexOut InVertex ) { const float2 size = ShaderParams.zw; float2 pos = size * InVertex.TextureCoordinates.xy; float2 center = size / 2.0; //X = Top Left, Y = Top Right, Z = Bottom Right, W = Bottom Left */ float4 cornerRadii = ShaderParams2; // figure out which radius to use based on which quadrant we're in float2 quadrant = step(InVertex.TextureCoordinates.xy, float2(.5,.5)); float left = lerp(cornerRadii.y, cornerRadii.x, quadrant.x); float right = lerp(cornerRadii.z, cornerRadii.w, quadrant.x); float radius = lerp(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 float4 fill = GetColor(InVertex, InVertex.TextureCoordinates.xy * InVertex.TextureCoordinates.zw); float4 border = InVertex.SecondaryColor; float4 OutColor = lerp(border, fill, float(thickness > radius)); OutColor.a = 0.0; // blend in the border and fill colors OutColor = lerp(OutColor, border, bi); OutColor = lerp(OutColor, fill, fi); return OutColor; } float4 GetLineSegmentElementColor( VertexOut InVertex ) { const float2 Gradient = InVertex.TextureCoordinates; const float2 OutsideFilterUV = float2(1.0f, 1.0f); const float2 InsideFilterUV = float2(ShaderParams.x, 0.0f); const float2 LineCoverage = smoothstep(OutsideFilterUV, InsideFilterUV, abs(Gradient)); float4 Color = InVertex.Color; Color.a *= LineCoverage.x * LineCoverage.y; return Color; } float4 Main( VertexOut InVertex ) : SV_Target { float4 OutColor; if( ShaderType == ESlateShader::Default ) { OutColor = GetDefaultElementColor( InVertex ); } else if( ShaderType == ESlateShader::RoundedBox) { OutColor = GetRoundedBoxElementColor( InVertex ); } else if( ShaderType == ESlateShader::Border ) { OutColor = GetBorderElementColor( InVertex ); } else if( ShaderType == ESlateShader::GrayscaleFont ) { OutColor = GetGrayscaleFontElementColor( InVertex ); } else if (ShaderType == ESlateShader::ColorFont) { OutColor = GetColorFontElementColor(InVertex); } else { OutColor = GetLineSegmentElementColor( InVertex ); } // gamma correct OutColor.rgb = GammaCorrect(OutColor.rgb); if (DisableEffect) { #if USE_LEGACY_DISABLED_EFFECT //desaturate float3 LumCoeffs = float3( 0.3, 0.59, .11 ); float Lum = dot( LumCoeffs, OutColor.rgb ); OutColor.rgb = lerp( OutColor.rgb, float3(Lum,Lum,Lum), .8 ); float3 Grayish = {.4, .4, .4}; // lerp between desaturated color and gray color based on distance from the desaturated color to the gray OutColor.rgb = lerp( OutColor.rgb, Grayish, clamp( distance( OutColor.rgb, Grayish ), 0, .8) ); #else OutColor.a *= .45f; #endif } return OutColor; }