diff --git a/fluXis.Game/Graphics/Shaders/Bloom/BloomDrawNode.cs b/fluXis.Game/Graphics/Shaders/Bloom/BloomDrawNode.cs index 1e150442..bc201ae1 100644 --- a/fluXis.Game/Graphics/Shaders/Bloom/BloomDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/Bloom/BloomDrawNode.cs @@ -16,8 +16,8 @@ public partial class BloomContainer { private class BloomContainerDrawNode : ShaderDrawNode { - private IUniformBuffer blurParametersBuffer; private float strength; + private IUniformBuffer parametersBuffer; private int radius; @@ -52,7 +52,7 @@ protected override void PopulateContents(IRenderer renderer) private void drawFrameBuffer(IRenderer renderer, int kernelRadius, float sigma, int rotation) { - blurParametersBuffer ??= renderer.CreateUniformBuffer(); + parametersBuffer ??= renderer.CreateUniformBuffer(); IFrameBuffer current = SharedData.CurrentEffectBuffer; IFrameBuffer target = SharedData.GetNextEffectBuffer(); @@ -61,7 +61,7 @@ private void drawFrameBuffer(IRenderer renderer, int kernelRadius, float sigma, { float radians = float.DegreesToRadians(rotation); - blurParametersBuffer.Data = blurParametersBuffer.Data with + parametersBuffer.Data = parametersBuffer.Data with { Radius = kernelRadius, Sigma = sigma, @@ -69,13 +69,19 @@ private void drawFrameBuffer(IRenderer renderer, int kernelRadius, float sigma, Direction = new Vector2(MathF.Cos(radians), MathF.Sin(radians)) }; - Shader.BindUniformBlock("m_BlurParameters", blurParametersBuffer); + Shader.BindUniformBlock("m_BlurParameters", parametersBuffer); Shader.Bind(); renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); Shader.Unbind(); } } + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + parametersBuffer?.Dispose(); + } + [StructLayout(LayoutKind.Sequential, Pack = 1)] private record struct BlurParameters { diff --git a/fluXis.Game/Graphics/Shaders/Chromatic/ChromaticDrawNote.cs b/fluXis.Game/Graphics/Shaders/Chromatic/ChromaticDrawNote.cs index a5d0cc49..d65df1c8 100644 --- a/fluXis.Game/Graphics/Shaders/Chromatic/ChromaticDrawNote.cs +++ b/fluXis.Game/Graphics/Shaders/Chromatic/ChromaticDrawNote.cs @@ -13,7 +13,7 @@ public partial class ChromaticContainer private class ChromaticContainerDrawNode : ShaderDrawNode { private float strength; - private IUniformBuffer chromaticParametersBuffer; + private IUniformBuffer parametersBuffer; public ChromaticContainerDrawNode(ChromaticContainer source, BufferedDrawNodeSharedData sharedData) : base(source, sharedData) @@ -32,12 +32,12 @@ protected override void PopulateContents(IRenderer renderer) base.PopulateContents(renderer); if (strength > 0) - drawFrameBuffer(renderer, strength); + drawFrameBuffer(renderer); } - private void drawFrameBuffer(IRenderer renderer, float strength) + private void drawFrameBuffer(IRenderer renderer) { - chromaticParametersBuffer ??= renderer.CreateUniformBuffer(); + parametersBuffer ??= renderer.CreateUniformBuffer(); IFrameBuffer current = SharedData.CurrentEffectBuffer; IFrameBuffer target = SharedData.GetNextEffectBuffer(); @@ -46,13 +46,13 @@ private void drawFrameBuffer(IRenderer renderer, float strength) using (BindFrameBuffer(target)) { - chromaticParametersBuffer.Data = chromaticParametersBuffer.Data with + parametersBuffer.Data = parametersBuffer.Data with { TexSize = current.Size, Radius = strength }; - Shader.BindUniformBlock("m_ChromaticParameters", chromaticParametersBuffer); + Shader.BindUniformBlock("m_ChromaticParameters", parametersBuffer); Shader.Bind(); renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); Shader.Unbind(); @@ -62,7 +62,7 @@ private void drawFrameBuffer(IRenderer renderer, float strength) protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - chromaticParametersBuffer?.Dispose(); + parametersBuffer?.Dispose(); } [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -70,8 +70,7 @@ private record struct ChromaticParameters { public UniformVector2 TexSize; public UniformFloat Radius; - private readonly UniformPadding8 pad1; - private readonly UniformPadding12 pad2; + private readonly UniformPadding4 pad1; } } } diff --git a/fluXis.Game/Graphics/Shaders/Glitch/GlitchContainer.cs b/fluXis.Game/Graphics/Shaders/Glitch/GlitchContainer.cs new file mode 100644 index 00000000..38c4dfa2 --- /dev/null +++ b/fluXis.Game/Graphics/Shaders/Glitch/GlitchContainer.cs @@ -0,0 +1,11 @@ +using fluXis.Game.Map.Structures.Events; +using osu.Framework.Graphics; + +namespace fluXis.Game.Graphics.Shaders.Glitch; + +public partial class GlitchContainer : ShaderContainer +{ + protected override string FragmentShader => "Glitch"; + public override ShaderType Type => ShaderType.Glitch; + protected override DrawNode CreateShaderDrawNode() => new GlitchContainerDrawNode(this, SharedData); +} diff --git a/fluXis.Game/Graphics/Shaders/Glitch/GlitchDrawNode.cs b/fluXis.Game/Graphics/Shaders/Glitch/GlitchDrawNode.cs new file mode 100644 index 00000000..b1045839 --- /dev/null +++ b/fluXis.Game/Graphics/Shaders/Glitch/GlitchDrawNode.cs @@ -0,0 +1,86 @@ +using System.Runtime.InteropServices; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Shaders.Types; +using osuTK.Graphics; + +namespace fluXis.Game.Graphics.Shaders.Glitch; + +public partial class GlitchContainer +{ + private class GlitchContainerDrawNode : ShaderDrawNode + { + private float strength; // x strength + private float strength2; // y strength + private float strength3; // glitch block size + private IUniformBuffer parametersBuffer; + + public GlitchContainerDrawNode(GlitchContainer source, BufferedDrawNodeSharedData sharedData) + : base(source, sharedData) + { + } + + public override void ApplyState() + { + base.ApplyState(); + + strength = Source.Strength / 10f; + strength2 = Source.Strength2 / 10f; + strength3 = Source.Strength3; + } + + protected override void PopulateContents(IRenderer renderer) + { + base.PopulateContents(renderer); + + if (strength > 0 || strength2 > 0) + drawFrameBuffer(renderer); + } + + private void drawFrameBuffer(IRenderer renderer) + { + parametersBuffer ??= renderer.CreateUniformBuffer(); + + IFrameBuffer current = SharedData.CurrentEffectBuffer; + IFrameBuffer target = SharedData.GetNextEffectBuffer(); + + renderer.SetBlend(BlendingParameters.None); + + using (BindFrameBuffer(target)) + { + parametersBuffer.Data = parametersBuffer.Data with + { + TexSize = current.Size, + StrengthX = strength, + StrengthY = strength2, + BlockSize = strength3, + Time = (float)Source.Time.Current % 10000f + }; + + Shader.BindUniformBlock("m_GlitchParameters", parametersBuffer); + Shader.Bind(); + renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); + Shader.Unbind(); + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + parametersBuffer?.Dispose(); + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private record struct GlitchParameters + { + public UniformVector2 TexSize; + public UniformFloat StrengthX; + public UniformFloat StrengthY; + public UniformFloat BlockSize; + public UniformFloat Time; + private readonly UniformPadding8 pad1; + } + } +} diff --git a/fluXis.Game/Graphics/Shaders/Greyscale/GreyscaleDrawNode.cs b/fluXis.Game/Graphics/Shaders/Greyscale/GreyscaleDrawNode.cs index f63164d3..4c2fa98e 100644 --- a/fluXis.Game/Graphics/Shaders/Greyscale/GreyscaleDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/Greyscale/GreyscaleDrawNode.cs @@ -12,22 +12,32 @@ public partial class GreyscaleContainer { private class GreyscaleDrawNode : ShaderDrawNode { - private IUniformBuffer parameters; + private float strength; + private IUniformBuffer parametersBuffer; public GreyscaleDrawNode(ShaderContainer source, BufferedDrawNodeSharedData sharedData) : base(source, sharedData) { } + public override void ApplyState() + { + base.ApplyState(); + + strength = Source.Strength; + } + protected override void PopulateContents(IRenderer renderer) { base.PopulateContents(renderer); - drawFrameBuffer(renderer); + + if (strength > 0) + drawFrameBuffer(renderer); } private void drawFrameBuffer(IRenderer renderer) { - parameters ??= renderer.CreateUniformBuffer(); + parametersBuffer ??= renderer.CreateUniformBuffer(); IFrameBuffer current = SharedData.CurrentEffectBuffer; IFrameBuffer target = SharedData.GetNextEffectBuffer(); @@ -36,13 +46,13 @@ private void drawFrameBuffer(IRenderer renderer) using (BindFrameBuffer(target)) { - parameters.Data = parameters.Data with + parametersBuffer.Data = parametersBuffer.Data with { TexSize = current.Size, Strength = Source.Strength }; - Shader.BindUniformBlock("m_GreyscaleParameters", parameters); + Shader.BindUniformBlock("m_GreyscaleParameters", parametersBuffer); Shader.Bind(); renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); Shader.Unbind(); @@ -52,7 +62,7 @@ private void drawFrameBuffer(IRenderer renderer) protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - parameters?.Dispose(); + parametersBuffer?.Dispose(); } [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -61,8 +71,6 @@ private record struct GreyscaleParameters public UniformVector2 TexSize; public UniformFloat Strength; private readonly UniformPadding4 pad1; - private readonly UniformPadding4 pad2; - private readonly UniformPadding12 pad3; } } } diff --git a/fluXis.Game/Graphics/Shaders/HueShift/HueShiftContainer.cs b/fluXis.Game/Graphics/Shaders/HueShift/HueShiftContainer.cs new file mode 100644 index 00000000..99d04762 --- /dev/null +++ b/fluXis.Game/Graphics/Shaders/HueShift/HueShiftContainer.cs @@ -0,0 +1,11 @@ +using fluXis.Game.Map.Structures.Events; +using osu.Framework.Graphics; + +namespace fluXis.Game.Graphics.Shaders.HueShift; + +public partial class HueShiftContainer : ShaderContainer +{ + protected override string FragmentShader => "HueShift"; + public override ShaderType Type => ShaderType.HueShift; + protected override DrawNode CreateShaderDrawNode() => new HueShiftContainerDrawNode(this, SharedData); +} diff --git a/fluXis.Game/Graphics/Shaders/HueShift/HueShiftDrawNode.cs b/fluXis.Game/Graphics/Shaders/HueShift/HueShiftDrawNode.cs new file mode 100644 index 00000000..0305dcc7 --- /dev/null +++ b/fluXis.Game/Graphics/Shaders/HueShift/HueShiftDrawNode.cs @@ -0,0 +1,76 @@ +using System.Runtime.InteropServices; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Shaders.Types; +using osuTK.Graphics; + +namespace fluXis.Game.Graphics.Shaders.HueShift; + +public partial class HueShiftContainer +{ + private class HueShiftContainerDrawNode : ShaderDrawNode + { + private float strength; + private IUniformBuffer parametersBuffer; + + public HueShiftContainerDrawNode(HueShiftContainer source, BufferedDrawNodeSharedData sharedData) + : base(source, sharedData) + { + } + + public override void ApplyState() + { + base.ApplyState(); + + strength = Source.Strength; + } + + protected override void PopulateContents(IRenderer renderer) + { + base.PopulateContents(renderer); + + if (strength > 0) + drawFrameBuffer(renderer); + } + + private void drawFrameBuffer(IRenderer renderer) + { + parametersBuffer ??= renderer.CreateUniformBuffer(); + + IFrameBuffer current = SharedData.CurrentEffectBuffer; + IFrameBuffer target = SharedData.GetNextEffectBuffer(); + + renderer.SetBlend(BlendingParameters.None); + + using (BindFrameBuffer(target)) + { + parametersBuffer.Data = parametersBuffer.Data with + { + TexSize = current.Size, + Strength = strength + }; + + Shader.BindUniformBlock("m_HueShiftParameters", parametersBuffer); + Shader.Bind(); + renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); + Shader.Unbind(); + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + parametersBuffer?.Dispose(); + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private record struct HueShiftParameters + { + public UniformVector2 TexSize; + public UniformFloat Strength; + private readonly UniformPadding4 pad1; + } + } +} diff --git a/fluXis.Game/Graphics/Shaders/Invert/InvertDrawNode.cs b/fluXis.Game/Graphics/Shaders/Invert/InvertDrawNode.cs index 740b6f9f..eaa79733 100644 --- a/fluXis.Game/Graphics/Shaders/Invert/InvertDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/Invert/InvertDrawNode.cs @@ -32,10 +32,10 @@ protected override void PopulateContents(IRenderer renderer) base.PopulateContents(renderer); if (strength > 0) - drawFrameBuffer(renderer, strength); + drawFrameBuffer(renderer); } - private void drawFrameBuffer(IRenderer renderer, float strength) + private void drawFrameBuffer(IRenderer renderer) { invertParametersBuffer ??= renderer.CreateUniformBuffer(); @@ -70,8 +70,7 @@ private record struct InvertParameters { public UniformVector2 TexSize; public UniformFloat Strength; - private readonly UniformPadding8 pad1; - private readonly UniformPadding12 pad2; + private readonly UniformPadding4 pad1; } } } diff --git a/fluXis.Game/Graphics/Shaders/Mosaic/MosaicDrawNode.cs b/fluXis.Game/Graphics/Shaders/Mosaic/MosaicDrawNode.cs index 3f6b3d23..e6a1abe1 100644 --- a/fluXis.Game/Graphics/Shaders/Mosaic/MosaicDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/Mosaic/MosaicDrawNode.cs @@ -12,8 +12,8 @@ public partial class MosaicContainer { private class MosaicDrawNode : ShaderDrawNode { - private IUniformBuffer paramBuffer; private float strength; + private IUniformBuffer parametersBuffer; public MosaicDrawNode(MosaicContainer source, BufferedDrawNodeSharedData sharedData) : base(source, sharedData) @@ -37,7 +37,7 @@ protected override void PopulateContents(IRenderer renderer) private void drawFrameBuffer(IRenderer renderer) { - paramBuffer ??= renderer.CreateUniformBuffer(); + parametersBuffer ??= renderer.CreateUniformBuffer(); IFrameBuffer current = SharedData.CurrentEffectBuffer; IFrameBuffer target = SharedData.GetNextEffectBuffer(); @@ -46,9 +46,13 @@ private void drawFrameBuffer(IRenderer renderer) using (BindFrameBuffer(target)) { - paramBuffer.Data = new MosaicParameters { TexSize = current.Size, Strength = strength }; + parametersBuffer.Data = parametersBuffer.Data with + { + TexSize = current.Size, + Strength = strength + }; - Shader.BindUniformBlock("m_MosaicParameters", paramBuffer); + Shader.BindUniformBlock("m_MosaicParameters", parametersBuffer); Shader.Bind(); renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); Shader.Unbind(); @@ -58,7 +62,7 @@ private void drawFrameBuffer(IRenderer renderer) protected override void Dispose(bool isDisposing) { base.Dispose(isDisposing); - paramBuffer?.Dispose(); + parametersBuffer?.Dispose(); } [StructLayout(LayoutKind.Sequential, Pack = 1)] @@ -66,7 +70,7 @@ private record struct MosaicParameters { public UniformVector2 TexSize; public UniformFloat Strength; - public UniformPadding4 _padding; + private readonly UniformPadding4 pad1; } } } diff --git a/fluXis.Game/Graphics/Shaders/Noise/NoiseDrawNode.cs b/fluXis.Game/Graphics/Shaders/Noise/NoiseDrawNode.cs index 3dcb6737..e8d3efe9 100644 --- a/fluXis.Game/Graphics/Shaders/Noise/NoiseDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/Noise/NoiseDrawNode.cs @@ -32,10 +32,10 @@ protected override void PopulateContents(IRenderer renderer) base.PopulateContents(renderer); if (strength > 0) - drawFrameBuffer(renderer, strength); + drawFrameBuffer(renderer); } - private void drawFrameBuffer(IRenderer renderer, float strength) + private void drawFrameBuffer(IRenderer renderer) { parametersBuffer ??= renderer.CreateUniformBuffer(); diff --git a/fluXis.Game/Graphics/Shaders/Pixelate/PixelateContainer.cs b/fluXis.Game/Graphics/Shaders/Pixelate/PixelateContainer.cs new file mode 100644 index 00000000..3656a3b8 --- /dev/null +++ b/fluXis.Game/Graphics/Shaders/Pixelate/PixelateContainer.cs @@ -0,0 +1,11 @@ +using fluXis.Game.Map.Structures.Events; +using osu.Framework.Graphics; + +namespace fluXis.Game.Graphics.Shaders.Pixelate; + +public partial class PixelateContainer : ShaderContainer +{ + protected override string FragmentShader => "Pixelate"; + public override ShaderType Type => ShaderType.Pixelate; + protected override DrawNode CreateShaderDrawNode() => new PixelateContainerDrawNode(this, SharedData); +} diff --git a/fluXis.Game/Graphics/Shaders/Pixelate/PixelateDrawNode.cs b/fluXis.Game/Graphics/Shaders/Pixelate/PixelateDrawNode.cs new file mode 100644 index 00000000..e1119083 --- /dev/null +++ b/fluXis.Game/Graphics/Shaders/Pixelate/PixelateDrawNode.cs @@ -0,0 +1,76 @@ +using System.Runtime.InteropServices; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Shaders.Types; +using osuTK.Graphics; + +namespace fluXis.Game.Graphics.Shaders.Pixelate; + +public partial class PixelateContainer +{ + private class PixelateContainerDrawNode : ShaderDrawNode + { + private float strength; + private IUniformBuffer parametersBuffer; + + public PixelateContainerDrawNode(PixelateContainer source, BufferedDrawNodeSharedData sharedData) + : base(source, sharedData) + { + } + + public override void ApplyState() + { + base.ApplyState(); + + strength = Source.Strength; + } + + protected override void PopulateContents(IRenderer renderer) + { + base.PopulateContents(renderer); + + if (strength > 0) + drawFrameBuffer(renderer); + } + + private void drawFrameBuffer(IRenderer renderer) + { + parametersBuffer ??= renderer.CreateUniformBuffer(); + + IFrameBuffer current = SharedData.CurrentEffectBuffer; + IFrameBuffer target = SharedData.GetNextEffectBuffer(); + + renderer.SetBlend(BlendingParameters.None); + + using (BindFrameBuffer(target)) + { + parametersBuffer.Data = parametersBuffer.Data with + { + TexSize = current.Size, + Strength = strength + }; + + Shader.BindUniformBlock("m_PixelateParameters", parametersBuffer); + Shader.Bind(); + renderer.DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White)); + Shader.Unbind(); + } + } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + parametersBuffer?.Dispose(); + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private record struct PixelateParameters + { + public UniformVector2 TexSize; + public UniformFloat Strength; + private readonly UniformPadding4 pad1; + } + } +} diff --git a/fluXis.Game/Graphics/Shaders/Retro/RetroDrawNode.cs b/fluXis.Game/Graphics/Shaders/Retro/RetroDrawNode.cs index 0d727496..640f0fe5 100644 --- a/fluXis.Game/Graphics/Shaders/Retro/RetroDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/Retro/RetroDrawNode.cs @@ -32,10 +32,10 @@ protected override void PopulateContents(IRenderer renderer) base.PopulateContents(renderer); if (strength > 0) - drawFrameBuffer(renderer, strength); + drawFrameBuffer(renderer); } - private void drawFrameBuffer(IRenderer renderer, float strength) + private void drawFrameBuffer(IRenderer renderer) { parametersBuffer ??= renderer.CreateUniformBuffer(); @@ -70,7 +70,7 @@ private record struct RetroParameters { public UniformVector2 TexSize; public UniformFloat Strength; - public readonly UniformPadding4 Pad; + public readonly UniformPadding4 pad1; } } } diff --git a/fluXis.Game/Graphics/Shaders/ShaderContainer.cs b/fluXis.Game/Graphics/Shaders/ShaderContainer.cs index 8d9781ef..ac886d45 100644 --- a/fluXis.Game/Graphics/Shaders/ShaderContainer.cs +++ b/fluXis.Game/Graphics/Shaders/ShaderContainer.cs @@ -19,12 +19,9 @@ public abstract partial class ShaderContainer : Container, IBufferedDrawable protected abstract DrawNode CreateShaderDrawNode(); private float strength; + private float strength2; + private float strength3; - /// - /// The strength of the mosaic effect. From 0 to 1. - ///
- /// 0 means its full resolution, 1 means its 1x1 pixel. - ///
public float Strength { get => strength; @@ -38,6 +35,32 @@ public float Strength } } + public float Strength2 + { + get => strength2; + set + { + if (value == strength2) + return; + + strength2 = value; + Invalidate(Invalidation.DrawNode); + } + } + + public float Strength3 + { + get => strength3; + set + { + if (value == strength3) + return; + + strength3 = value; + Invalidate(Invalidation.DrawNode); + } + } + public bool DrawOriginal { get; set; } public ColourInfo EffectColour { get; set; } = Color4.White; public BlendingParameters EffectBlending { get; set; } = BlendingParameters.Inherit; diff --git a/fluXis.Game/Graphics/Shaders/Vignette/VignetteDrawNode.cs b/fluXis.Game/Graphics/Shaders/Vignette/VignetteDrawNode.cs index a17e5ac1..c1e9b60e 100644 --- a/fluXis.Game/Graphics/Shaders/Vignette/VignetteDrawNode.cs +++ b/fluXis.Game/Graphics/Shaders/Vignette/VignetteDrawNode.cs @@ -32,10 +32,10 @@ protected override void PopulateContents(IRenderer renderer) base.PopulateContents(renderer); if (strength > 0) - drawFrameBuffer(renderer, strength); + drawFrameBuffer(renderer); } - private void drawFrameBuffer(IRenderer renderer, float strength) + private void drawFrameBuffer(IRenderer renderer) { parametersBuffer ??= renderer.CreateUniformBuffer(); diff --git a/fluXis.Game/Map/Structures/Events/ShaderEvent.cs b/fluXis.Game/Map/Structures/Events/ShaderEvent.cs index 3b8cecca..7e876b8b 100644 --- a/fluXis.Game/Map/Structures/Events/ShaderEvent.cs +++ b/fluXis.Game/Map/Structures/Events/ShaderEvent.cs @@ -50,6 +50,12 @@ public class ShaderParameters { [JsonProperty("strength")] public float Strength { get; set; } + + [JsonProperty("strength2")] + public float Strength2 { get; set; } + + [JsonProperty("strength3")] + public float Strength3 { get; set; } } } @@ -62,5 +68,8 @@ public enum ShaderType Mosaic, Noise, Vignette, - Retro + Retro, + HueShift, + Pixelate, + Glitch } diff --git a/fluXis.Game/Screens/Edit/Tabs/Design/DesignContainer.cs b/fluXis.Game/Screens/Edit/Tabs/Design/DesignContainer.cs index 068470bb..936cf33e 100644 --- a/fluXis.Game/Screens/Edit/Tabs/Design/DesignContainer.cs +++ b/fluXis.Game/Screens/Edit/Tabs/Design/DesignContainer.cs @@ -4,12 +4,15 @@ using fluXis.Game.Graphics.Shaders; using fluXis.Game.Graphics.Shaders.Bloom; using fluXis.Game.Graphics.Shaders.Chromatic; +using fluXis.Game.Graphics.Shaders.Glitch; using fluXis.Game.Graphics.Shaders.Greyscale; using fluXis.Game.Graphics.Shaders.Invert; using fluXis.Game.Graphics.Shaders.Mosaic; using fluXis.Game.Graphics.Shaders.Noise; using fluXis.Game.Graphics.Shaders.Retro; using fluXis.Game.Graphics.Shaders.Vignette; +using fluXis.Game.Graphics.Shaders.HueShift; +using fluXis.Game.Graphics.Shaders.Pixelate; using fluXis.Game.Graphics.Sprites; using fluXis.Game.Map.Structures.Events; using fluXis.Game.Screens.Edit.Tabs.Design.Effects; @@ -108,6 +111,9 @@ private ShaderStackContainer createShaderStack() ShaderType.Noise => new NoiseContainer(), ShaderType.Vignette => new VignetteContainer(), ShaderType.Retro => new RetroContainer(), + ShaderType.HueShift => new HueShiftContainer(), + ShaderType.Pixelate => new PixelateContainer(), + ShaderType.Glitch => new GlitchContainer(), _ => null }; diff --git a/fluXis.Game/Screens/Edit/Tabs/Design/DesignShaderHandler.cs b/fluXis.Game/Screens/Edit/Tabs/Design/DesignShaderHandler.cs index 0484dba5..50cfe5b2 100644 --- a/fluXis.Game/Screens/Edit/Tabs/Design/DesignShaderHandler.cs +++ b/fluXis.Game/Screens/Edit/Tabs/Design/DesignShaderHandler.cs @@ -43,27 +43,39 @@ private void handleGroup(ShaderType type, IEnumerable events) if (current == null) { container.Strength = 0; + container.Strength2 = 0; + container.Strength3 = 0; return; } var progress = (clock.CurrentTime - current.Time) / current.Duration; - var end = current.EndParameters.Strength; + var endStrength = current.EndParameters.Strength; + var endStrength2 = current.EndParameters.Strength2; + var endStrength3 = current.EndParameters.Strength3; if (progress >= 1) { - container.Strength = end; + container.Strength = endStrength; + container.Strength2 = endStrength2; + container.Strength3 = endStrength3; return; } var previous = events.LastOrDefault(e => e.Time < current.Time); - var start = current.UseStartParams ? current.StartParameters.Strength : previous?.EndParameters.Strength ?? 0; + var startStrength = current.UseStartParams ? current.StartParameters.Strength : previous?.EndParameters.Strength ?? 0; + var startStrength2 = current.UseStartParams ? current.StartParameters.Strength2 : previous?.EndParameters.Strength2 ?? 0; + var startStrength3 = current.UseStartParams ? current.StartParameters.Strength3 : previous?.EndParameters.Strength3 ?? 0; if (progress < 0) { - container.Strength = start; + container.Strength = startStrength; + container.Strength2 = startStrength2; + container.Strength3 = startStrength3; return; } - container.Strength = Interpolation.ValueAt(clock.CurrentTime, start, end, current.Time, current.Time + current.Duration); + container.Strength = Interpolation.ValueAt(clock.CurrentTime, startStrength, endStrength, current.Time, current.Time + current.Duration); + container.Strength2 = Interpolation.ValueAt(clock.CurrentTime, startStrength2, endStrength2, current.Time, current.Time + current.Duration); + container.Strength3 = Interpolation.ValueAt(clock.CurrentTime, startStrength3, endStrength3, current.Time, current.Time + current.Duration); } } diff --git a/fluXis.Game/Screens/Edit/Tabs/Design/Points/Entries/ShaderEntry.cs b/fluXis.Game/Screens/Edit/Tabs/Design/Points/Entries/ShaderEntry.cs index e8462d7d..aa2301ad 100644 --- a/fluXis.Game/Screens/Edit/Tabs/Design/Points/Entries/ShaderEntry.cs +++ b/fluXis.Game/Screens/Edit/Tabs/Design/Points/Entries/ShaderEntry.cs @@ -31,6 +31,10 @@ private float maxStrength } } + private float maxStrength2 => 1f; + + private float maxStrength3 => 1f; + private float step { get @@ -57,11 +61,13 @@ public override ITimedObject CreateClone() UseStartParams = shader.UseStartParams, StartParameters = new ShaderEvent.ShaderParameters { - Strength = shader.StartParameters.Strength + Strength = shader.StartParameters.Strength, + Strength2 = shader.StartParameters.Strength2, }, EndParameters = new ShaderEvent.ShaderParameters { - Strength = shader.EndParameters.Strength + Strength = shader.EndParameters.Strength, + Strength2 = shader.EndParameters.Strength2 } }; } @@ -94,12 +100,14 @@ protected override IEnumerable CreateSettings() Bindable = new Bindable(shader.UseStartParams), OnStateChanged = enabled => { + RequestClose?.Invoke(); // until there is a way to refresh shader.UseStartParams = enabled; Map.Update(shader); + OpenSettings(); } }; - return base.CreateSettings().Concat(new Drawable[] + var settings = new List { new PointSettingsLength(Map, shader, BeatLength), new PointSettingsDropdown @@ -110,41 +118,170 @@ protected override IEnumerable CreateSettings() Items = Enum.GetValues().ToList(), OnValueChanged = value => { + RequestClose?.Invoke(); // until there is a way to refresh shader.Type = value; Map.Update(shader); + OpenSettings(); } }, - startValToggle, - new PointSettingsSlider + new PointSettingsToggle { - Enabled = startValToggle.Bindable, - Text = "Start Strength", - TooltipText = "The strength of the shader effect.", - CurrentValue = shader.StartParameters.Strength, - Min = 0, - Max = maxStrength, - Step = step, - OnValueChanged = value => + Text = "Use Start Value", + TooltipText = "Enables whether start values should be used.", + Bindable = new Bindable(shader.UseStartParams), + OnStateChanged = enabled => { - shader.StartParameters.Strength = value; + shader.UseStartParams = enabled; Map.Update(shader); } - }, - new PointSettingsSlider - { - Text = "End Strength", - TooltipText = "The strength of the shader effect.", - CurrentValue = shader.EndParameters.Strength, - Min = 0, - Max = maxStrength, - Step = step, - OnValueChanged = value => + } + }; + + // edge cases for shaders with extra/different parameter(s) + switch (shader.Type) + { + case ShaderType.Glitch: + settings.AddRange(new Drawable[] { - shader.EndParameters.Strength = value; - Map.Update(shader); - } - }, - new PointSettingsEasing(Map, shader) - }); + new PointSettingsSlider + { + Enabled = startValToggle.Bindable, + Text = "Start X Strength", + TooltipText = "The strength of the glitch effect on the x-axis.", + CurrentValue = shader.StartParameters.Strength, + Min = 0, + Max = maxStrength, + Step = step, + OnValueChanged = value => + { + shader.StartParameters.Strength = value; + Map.Update(shader); + } + }, + new PointSettingsSlider + { + Text = "End X Strength", + TooltipText = "The strength of the glitch effect on the x-axis.", + CurrentValue = shader.EndParameters.Strength, + Min = 0, + Max = maxStrength, + Step = step, + OnValueChanged = value => + { + shader.EndParameters.Strength = value; + Map.Update(shader); + } + }, + new PointSettingsSlider + { + Enabled = startValToggle.Bindable, + Text = "Start Y Strength", + TooltipText = "The strength of the glitch effect on the y-axis.", + CurrentValue = shader.StartParameters.Strength2, + Min = 0, + Max = maxStrength2, + Step = step, + OnValueChanged = value => + { + shader.StartParameters.Strength2 = value; + Map.Update(shader); + } + }, + new PointSettingsSlider + { + Text = "End Y Strength", + TooltipText = "The strength of the glitch effect on the y-axis.", + CurrentValue = shader.EndParameters.Strength2, + Min = 0, + Max = maxStrength2, + Step = step, + OnValueChanged = value => + { + shader.EndParameters.Strength2 = value; + Map.Update(shader); + } + }, + new PointSettingsSlider + { + Enabled = startValToggle.Bindable, + Text = "Start Block Size", + TooltipText = "The size of the glitch blocks.", + CurrentValue = shader.StartParameters.Strength3, + Min = 0, + Max = maxStrength3, + Step = step, + OnValueChanged = value => + { + shader.StartParameters.Strength3 = value; + Map.Update(shader); + } + }, + new PointSettingsSlider + { + Text = "End Block Size", + TooltipText = "The size of the glitch blocks.", + CurrentValue = shader.EndParameters.Strength3, + Min = 0, + Max = maxStrength3, + Step = step, + OnValueChanged = value => + { + shader.EndParameters.Strength3 = value; + Map.Update(shader); + } + } + }); + break; + + case ShaderType.Bloom: + case ShaderType.Greyscale: + case ShaderType.Invert: + case ShaderType.Chromatic: + case ShaderType.Mosaic: + case ShaderType.Noise: + case ShaderType.Vignette: + case ShaderType.Retro: + case ShaderType.HueShift: + case ShaderType.Pixelate: + default: // default shader settings + settings.AddRange(new Drawable[] + { + new PointSettingsSlider + { + Enabled = startValToggle.Bindable, + Text = "Start Strength", + TooltipText = "The strength of the shader effect.", + CurrentValue = shader.StartParameters.Strength, + Min = 0, + Max = maxStrength, + Step = step, + OnValueChanged = value => + { + shader.StartParameters.Strength = value; + Map.Update(shader); + } + }, + + new PointSettingsSlider + { + Text = "End Strength", + TooltipText = "The strength of the shader effect.", + CurrentValue = shader.EndParameters.Strength, + Min = 0, + Max = maxStrength, + Step = step, + OnValueChanged = value => + { + shader.EndParameters.Strength = value; + Map.Update(shader); + } + } + }); + break; + } + + settings.Add(new PointSettingsEasing(Map, shader)); + + return base.CreateSettings().Concat(settings); } } diff --git a/fluXis.Game/Screens/Gameplay/GameplayScreen.cs b/fluXis.Game/Screens/Gameplay/GameplayScreen.cs index bc715e09..81f20fe8 100644 --- a/fluXis.Game/Screens/Gameplay/GameplayScreen.cs +++ b/fluXis.Game/Screens/Gameplay/GameplayScreen.cs @@ -20,6 +20,9 @@ using fluXis.Game.Graphics.Shaders.Noise; using fluXis.Game.Graphics.Shaders.Retro; using fluXis.Game.Graphics.Shaders.Vignette; +using fluXis.Game.Graphics.Shaders.HueShift; +using fluXis.Game.Graphics.Shaders.Pixelate; +using fluXis.Game.Graphics.Shaders.Glitch; using fluXis.Game.Input; using fluXis.Game.Map; using fluXis.Game.Map.Structures.Events; @@ -329,6 +332,9 @@ private ShaderStackContainer buildShaders() ShaderType.Noise => new NoiseContainer(), ShaderType.Vignette => new VignetteContainer(), ShaderType.Retro => new RetroContainer(), + ShaderType.HueShift => new HueShiftContainer(), + ShaderType.Pixelate => new PixelateContainer(), + ShaderType.Glitch => new GlitchContainer(), _ => null }; diff --git a/fluXis.Game/Screens/Gameplay/ShaderEventHandler.cs b/fluXis.Game/Screens/Gameplay/ShaderEventHandler.cs index 8dcfc36f..813f38be 100644 --- a/fluXis.Game/Screens/Gameplay/ShaderEventHandler.cs +++ b/fluXis.Game/Screens/Gameplay/ShaderEventHandler.cs @@ -43,9 +43,15 @@ private void trigger(ShaderEvent ev) throw new Exception($"Handler with type {ev.ShaderName} is not in scene tree!"); if (ev.UseStartParams) + { handler.StrengthTo(ev.StartParameters.Strength); + handler.Strength2To(ev.StartParameters.Strength2); + handler.Strength3To(ev.StartParameters.Strength3); + } handler.StrengthTo(ev.EndParameters.Strength, ev.Duration, ev.Easing); + handler.Strength2To(ev.EndParameters.Strength2, ev.Duration, ev.Easing); + handler.Strength3To(ev.EndParameters.Strength3, ev.Duration, ev.Easing); } // the shader stack is outside the gameplay clock. @@ -61,6 +67,18 @@ private float strength set => container.Strength = value; } + private float strength2 + { + get => container.Strength2; + set => container.Strength2 = value; + } + + private float strength3 + { + get => container.Strength3; + set => container.Strength3 = value; + } + public TransformHandler(ShaderContainer container) { this.container = container; @@ -69,5 +87,11 @@ public TransformHandler(ShaderContainer container) public void StrengthTo(float str, double dur = 0, Easing ease = Easing.None) => this.TransformTo(nameof(strength), str, dur, ease); + + public void Strength2To(float str, double dur = 0, Easing ease = Easing.None) + => this.TransformTo(nameof(strength2), str, dur, ease); + + public void Strength3To(float str, double dur = 0, Easing ease = Easing.None) + => this.TransformTo(nameof(strength3), str, dur, ease); } } diff --git a/fluXis.Resources/Shaders/sh_Glitch.fs b/fluXis.Resources/Shaders/sh_Glitch.fs new file mode 100644 index 00000000..2fca3e73 --- /dev/null +++ b/fluXis.Resources/Shaders/sh_Glitch.fs @@ -0,0 +1,39 @@ +layout(std140, set = 0, binding = 0) uniform m_GlitchParameters +{ + vec2 g_TexSize; + float g_StrengthX; + float g_StrengthY; + float g_BlockSize; + float g_Time; +}; + +layout(set = 1, binding = 0) uniform texture2D m_Texture; +layout(set = 1, binding = 1) uniform sampler m_Sampler; + +layout(location = 0) out vec4 o_Colour; + +highp float random(highp vec2 st, float seed) +{ + return fract(sin(dot(st.xy, vec2(12.9898, 78.233) + seed)) * 43758.5453123); +} + + +void main(void) +{ + vec2 uv = gl_FragCoord.xy / g_TexSize; + + float blockSizeInPixels = mix(1.0, min(g_TexSize.x, g_TexSize.y), g_BlockSize); + + vec2 blockUV = floor(uv * blockSizeInPixels) / blockSizeInPixels; + + float randomShiftX = (random(blockUV, g_Time) - 0.5) * g_StrengthX; + float randomShiftY = (random(blockUV + vec2(5.0), g_Time) - 0.5) * g_StrengthY; + + vec2 fixedUV = uv; + fixedUV.x += randomShiftX; + fixedUV.y += randomShiftY; + + vec4 pixelColor = textureLod(sampler2D(m_Texture, m_Sampler), fixedUV, 0.0); + + o_Colour = pixelColor; +} \ No newline at end of file diff --git a/fluXis.Resources/Shaders/sh_HueShift.fs b/fluXis.Resources/Shaders/sh_HueShift.fs new file mode 100644 index 00000000..c2702dc7 --- /dev/null +++ b/fluXis.Resources/Shaders/sh_HueShift.fs @@ -0,0 +1,48 @@ +layout(std140, set = 0, binding = 0) uniform m_HueShiftParameters +{ + vec2 g_TexSize; + float g_Strength; +}; + +layout(set = 1, binding = 0) uniform texture2D m_Texture; +layout(set = 1, binding = 1) uniform sampler m_Sampler; + +layout(location = 0) out vec4 o_Colour; + +vec3 hueShift(vec3 color, float hueAdjust) { + const vec3 kRGBToYPrime = vec3(0.299, 0.587, 0.114); + const vec3 kRGBToI = vec3(0.596, -0.275, -0.321); + const vec3 kRGBToQ = vec3(0.212, -0.523, 0.311); + + const vec3 kYIQToR = vec3(1.0, 0.956, 0.621); + const vec3 kYIQToG = vec3(1.0, -0.272, -0.647); + const vec3 kYIQToB = vec3(1.0, -1.107, 1.704); + + float YPrime = dot(color, kRGBToYPrime); + float I = dot(color, kRGBToI); + float Q = dot(color, kRGBToQ); + float chroma = sqrt(I * I + Q * Q); + + if (chroma < 1e-5) { + return color; + } + + float hue = atan(Q, I); + hue += hueAdjust; + + Q = chroma * sin(hue); + I = chroma * cos(hue); + + vec3 yIQ = vec3(YPrime, I, Q); + + return vec3(dot(yIQ, kYIQToR), dot(yIQ, kYIQToG), dot(yIQ, kYIQToB)); +} + +void main(void) { + vec2 uv = gl_FragCoord.xy / g_TexSize; + vec4 colour = texture(sampler2D(m_Texture, m_Sampler), uv); + + vec3 shiftedColour = hueShift(colour.rgb, radians(g_Strength * 360.0)); + + o_Colour = vec4(shiftedColour, colour.a); +} diff --git a/fluXis.Resources/Shaders/sh_Pixelate.fs b/fluXis.Resources/Shaders/sh_Pixelate.fs new file mode 100644 index 00000000..20a0f1ad --- /dev/null +++ b/fluXis.Resources/Shaders/sh_Pixelate.fs @@ -0,0 +1,20 @@ +layout(std140, set = 0, binding = 0) uniform m_PixelateParameters +{ + vec2 g_TexSize; + float g_Strength; +}; + +layout(set = 1, binding = 0) uniform texture2D m_Texture; +layout(set = 1, binding = 1) uniform sampler m_Sampler; + +layout(location = 0) out vec4 o_Colour; + +void main(void) { + vec2 uv = gl_FragCoord.xy / g_TexSize; + + float pixelSizeFactor = mix(1.0, min(g_TexSize.x, g_TexSize.y), 1.0 - g_Strength); + vec2 pixelSize = vec2(pixelSizeFactor, pixelSizeFactor * (g_TexSize.y / g_TexSize.x)); + vec2 pixelatedUV = (floor(uv * pixelSize) + 0.5) / pixelSize; + + o_Colour = textureLod(sampler2D(m_Texture, m_Sampler), pixelatedUV, 0.0); +} diff --git a/fluXis.Resources/fluXis.Resources.csproj b/fluXis.Resources/fluXis.Resources.csproj index ad45af01..6e5f29ca 100644 --- a/fluXis.Resources/fluXis.Resources.csproj +++ b/fluXis.Resources/fluXis.Resources.csproj @@ -11,4 +11,6 @@ + +