diff --git a/osu.Framework.Font.Tests/Visual/Shaders/TestSceneDefaultKaraokeLyricShader.cs b/osu.Framework.Font.Tests/Visual/Shaders/TestSceneDefaultKaraokeLyricShader.cs new file mode 100644 index 0000000..0481740 --- /dev/null +++ b/osu.Framework.Font.Tests/Visual/Shaders/TestSceneDefaultKaraokeLyricShader.cs @@ -0,0 +1,36 @@ +// Copyright (c) karaoke.dev . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Extensions; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics.Shaders; +using osuTK; + +namespace osu.Framework.Font.Tests.Visual.Shaders +{ + public class TestSceneDefaultKaraokeLyricShader : TestSceneInternalShader + { + [TestCase("#FFFFFF", 10, "#0000FF")] // White text with blue outline + [TestCase("#FF0000", 5, "#FFFFFF")] // Red text with white outline + [TestCase("#FF0000", 0, "#FFFFFF")] // Red text with no outline + public void TestOutline(string colour, int radius, string outlineColour) + { + AddStep("Apply shader", () => + { + ShaderContainer.Shaders = new[] + { + GetShaderByType().With(s => + { + s.Colour = Color4Extensions.FromHex(colour); + s.Radius = radius; + s.OutlineColour = Color4Extensions.FromHex(outlineColour); + + s.ShadowSigma = 200; + s.ShadowOffset = new Vector2(0, 1); + }) + }; + }); + } + } +} diff --git a/osu.Framework.Font/Graphics/Shaders/DefaultKaraokeLyricShader.cs b/osu.Framework.Font/Graphics/Shaders/DefaultKaraokeLyricShader.cs new file mode 100644 index 0000000..cb737d9 --- /dev/null +++ b/osu.Framework.Font/Graphics/Shaders/DefaultKaraokeLyricShader.cs @@ -0,0 +1,52 @@ +// Copyright (c) karaoke.dev . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics.OpenGL.Buffers; +using osuTK; +using osuTK.Graphics; + +namespace osu.Framework.Graphics.Shaders +{ + public class DefaultKaraokeLyricShader : InternalShader + { + public override string ShaderName => "DefaultKaraokeLyric"; + + public Color4 Colour { get; set; } + + public int Radius { get; set; } + + public Color4 OutlineColour { get; set; } + + public Vector2 ShadowOffset { get; set; } + + public int ShadowSize { get; set; } + + public float ShadowSigma { get; set; } + + public Vector2 ShadowColour { get; set; } + + public override void ApplyValue(FrameBuffer current) + { + // outline effect + var colourMatrix = new Vector4(Colour.R, Colour.G, Colour.B, Colour.A); + GetUniform(@"g_Colour").UpdateValue(ref colourMatrix); + + var radius = Radius; + GetUniform(@"g_Radius").UpdateValue(ref radius); + + var outlineColourMatrix = new Vector4(OutlineColour.R, OutlineColour.G, OutlineColour.B, OutlineColour.A); + GetUniform(@"g_OutlineColour").UpdateValue(ref outlineColourMatrix); + + // shadow effect + var shadowOffset = ShadowOffset; + GetUniform(@"g_BlurDirection").UpdateValue(ref shadowOffset); + + var shadowSigma = ShadowSigma; + GetUniform(@"g_Sigma").UpdateValue(ref shadowSigma); + + // common property. + var size = current.Size; + GetUniform(@"g_TexSize").UpdateValue(ref size); + } + } +} diff --git a/osu.Framework.Font/Resources/Shaders/sh_DefaultKaraokeLyric.fs b/osu.Framework.Font/Resources/Shaders/sh_DefaultKaraokeLyric.fs new file mode 100644 index 0000000..2176b2e --- /dev/null +++ b/osu.Framework.Font/Resources/Shaders/sh_DefaultKaraokeLyric.fs @@ -0,0 +1,59 @@ +#include "sh_Utils.h" + +#define INV_SQRT_2PI 0.39894 + +varying mediump vec2 v_TexCoord; + +uniform lowp sampler2D m_Sampler; + +uniform mediump vec2 g_TexSize; + +// outline effect +uniform vec4 g_Colour; +uniform int g_Radius; +uniform vec4 g_OutlineColour; + +// shadow effect +uniform mediump float g_Sigma; + +mediump float computeGauss(in mediump float x, in mediump float sigma) +{ + return INV_SQRT_2PI * exp(-0.5*x*x / (sigma*sigma)) / sigma; +} + +lowp vec4 blur(sampler2D tex, int radius, highp vec2 direction, mediump vec2 texCoord, mediump vec2 texSize, mediump float sigma) +{ + mediump float factor = computeGauss(0.0, sigma); + mediump vec4 sum = texture2D(tex, texCoord) * factor; + + mediump float totalFactor = factor; + + for (int i = 2; i <= 200; i += 2) + { + mediump float x = float(i) - 0.5; + factor = computeGauss(x, sigma) * 2.0; + totalFactor += 2.0 * factor; + sum += texture2D(tex, texCoord + direction * x / texSize) * factor; + sum += texture2D(tex, texCoord - direction * x / texSize) * factor; + if (i >= radius) + break; + } + + return toSRGB(sum / totalFactor); +} + +lowp vec4 outline() +{ + return blur(m_Sampler, g_Radius, highp vec2(1, 0), v_TexCoord, g_TexSize, g_Sigma) + + blur(m_Sampler, g_Radius, highp vec2(0, -1), v_TexCoord, g_TexSize, g_Sigma); +} + +void main(void) +{ + mediump vec4 originTexture = texture2D(m_Sampler, v_TexCoord).a * g_Colour; + lowp vec4 outline = outline().a * g_OutlineColour; + lowp vec4 shadow = blur(m_Sampler, g_Radius, highp vec2(0, 1), v_TexCoord, g_TexSize, g_Sigma); + + + gl_FragColor = blur(m_Sampler, g_Radius, highp vec2(0, -1), v_TexCoord, g_TexSize, g_Sigma); +} \ No newline at end of file