252 lines
6.7 KiB
HLSL
252 lines
6.7 KiB
HLSL
|
// 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;
|
||
|
}
|
||
|
|