Skip to content
74 changes: 74 additions & 0 deletions fluXis.Resources/Shaders/sh_Perspective.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
layout(std140, set = 0, binding = 0) uniform m_PerspectiveParameters
{
vec2 g_TexSize;
float g_Strength;
float g_Strength2;
float g_Strength3;
};

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;

// this is a port of a godot shader // saludos a mi compañero matias
// probably this one: https://godotshaders.com/shader/2d-perspective

bool cull_back = true;
float inset = 0.0;

const float PI = 3.14159;

mat3 getRotationMatrix(float yaw, float pitch) {
float sin_b = sin(yaw / 180.0 * PI);
float cos_b = cos(yaw / 180.0 * PI);
float sin_c = sin(pitch / 180.0 * PI);
float cos_c = cos(pitch / 180.0 * PI);

mat3 inv_rot_mat;
inv_rot_mat[0][0] = cos_b;
inv_rot_mat[0][1] = 0.0;
inv_rot_mat[0][2] = -sin_b;

inv_rot_mat[1][0] = sin_b * sin_c;
inv_rot_mat[1][1] = cos_c;
inv_rot_mat[1][2] = cos_b * sin_c;

inv_rot_mat[2][0] = sin_b * cos_c;
inv_rot_mat[2][1] = -sin_c;
inv_rot_mat[2][2] = cos_b * cos_c;

return inv_rot_mat;
}

void main(void) {
vec2 uv = (gl_FragCoord.xy / g_TexSize) - 0.5;

float x_rot = g_Strength2;
float y_rot = g_Strength;
float fov = g_Strength3 + 0.1;

mat3 inv_rot_mat = getRotationMatrix(x_rot, y_rot);

float t = tan(fov / 360.0 * PI);
vec3 ray_direction = inv_rot_mat * vec3(uv, 0.5 / t);
float v = (0.5 / t) + 0.5;

ray_direction.xy *= v * inv_rot_mat[2].z;
vec2 offset = v * inv_rot_mat[2].xy;

if (cull_back && ray_direction.z <= 0.0) {
o_Colour = vec4(0.0);
return;
}

vec2 tex_uv = (ray_direction.xy / ray_direction.z) - offset;
tex_uv += 0.5;

vec4 color = texture(sampler2D(m_Texture, m_Sampler), tex_uv);

float distance_from_center = max(abs(tex_uv.x - 0.5), abs(tex_uv.y - 0.5));
color.a *= step(distance_from_center, 0.5);

o_Colour = color;
}
11 changes: 11 additions & 0 deletions fluXis/Graphics/Shaders/Perspective/PerspectiveContainer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using fluXis.Map.Structures.Events;
using osu.Framework.Graphics;

namespace fluXis.Graphics.Shaders.Perspective;

public partial class PerspectiveContainer : ShaderContainer
{
protected override string FragmentShader => "Perspective";
public override ShaderType Type => ShaderType.Perspective;
protected override DrawNode CreateShaderDrawNode() => new PerspectiveContainerDrawNode(this, SharedData);
}
84 changes: 84 additions & 0 deletions fluXis/Graphics/Shaders/Perspective/PerspectiveDrawNode.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
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.Graphics.Shaders.Perspective;

public partial class PerspectiveContainer
{
private class PerspectiveContainerDrawNode : ShaderDrawNode<PerspectiveContainer>
{
private float strength;
private float strength2;
private float strength3;

private IUniformBuffer<PerspectiveParameters> parametersBuffer;

public PerspectiveContainerDrawNode(PerspectiveContainer source, BufferedDrawNodeSharedData sharedData)
: base(source, sharedData)
{
}

public override void ApplyState()
{
base.ApplyState();

strength = Source.Strength;
strength2 = Source.Strength2;
strength3 = Source.Strength3;
}

protected override void PopulateContents(IRenderer renderer)
{
base.PopulateContents(renderer);
if (strength != 0 || strength2 != 0 || strength3 != 0)
drawFrameBuffer(renderer);
}

private void drawFrameBuffer(IRenderer renderer)
{
parametersBuffer ??= renderer.CreateUniformBuffer<PerspectiveParameters>();

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,
Strength2 = strength2,
Strength3 = strength3,
};

Shader.BindUniformBlock("m_PerspectiveParameters", 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 PerspectiveParameters
{
public UniformVector2 TexSize;
public UniformFloat Strength;
public UniformFloat Strength2;
public UniformFloat Strength3;
private readonly UniformPadding12 pad1;
}
}
}
3 changes: 2 additions & 1 deletion fluXis/Map/Structures/Events/ShaderEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,6 @@ public enum ShaderType
Glitch,
SplitScreen,
FishEye,
Reflections
Reflections,
Perspective
}
7 changes: 5 additions & 2 deletions fluXis/Screens/Edit/Tabs/Design/DesignContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
using fluXis.Graphics.Shaders.SplitScreen;
using fluXis.Graphics.Shaders.FishEye;
using fluXis.Graphics.Shaders.Reflections;
using fluXis.Graphics.Shaders.Perspective;
using fluXis.Graphics.Sprites;
using fluXis.Map.Structures.Bases;
using fluXis.Map.Structures.Events;
Expand Down Expand Up @@ -79,14 +80,14 @@ public partial class DesignContainer : EditorTabContainer
private Bindable<float> userScrollSpeed;
private Bindable<float> rulesetScrollSpeed { get; } = new();

private BackgroundVideo backgroundVideo;

[BackgroundDependencyLoader]
private void load(FluXisConfig config)
{
userScrollSpeed = config.GetBindable<float>(FluXisSetting.ScrollSpeed);
}

private BackgroundVideo backgroundVideo;

protected override IEnumerable<Drawable> CreateContent()
{
drawSizePreserve = new DrawSizePreservingFillContainer
Expand Down Expand Up @@ -199,6 +200,7 @@ private RulesetContainer createRuleset()
var container = new ReplayRulesetContainer(auto.Generate(), Map.MapInfo, effects, new List<IMod> { new NoFailMod() });
container.ScrollSpeed = rulesetScrollSpeed;
container.ParentClock = EditorClock;

return container;
}

Expand All @@ -225,6 +227,7 @@ private ShaderStackContainer createShaderStack()
ShaderType.SplitScreen => new SplitScreenContainer(),
ShaderType.FishEye => new FishEyeContainer(),
ShaderType.Reflections => new ReflectionsContainer(),
ShaderType.Perspective => new PerspectiveContainer(),
_ => null
};

Expand Down
93 changes: 93 additions & 0 deletions fluXis/Screens/Edit/Tabs/Design/Points/Entries/ShaderEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,99 @@ protected override IEnumerable<Drawable> CreateSettings()
});
break;

case ShaderType.Perspective:
settings.AddRange(new Drawable[]
{
new PointSettingsSlider<float>
{
Enabled = startValToggle.Bindable,
Text = "Start X Rotation",
TooltipText = "X axis rotation.",
CurrentValue = shader.StartParameters.Strength,
Min = -90.0f,
Max = 90.0f,
Step = 1.0f,
OnValueChanged = value =>
{
shader.StartParameters.Strength = value;
Map.Update(shader);
}
},
new PointSettingsSlider<float>
{
Text = "End X Rotation",
TooltipText = "X axis rotation.",
CurrentValue = shader.EndParameters.Strength,
Min = -90.0f,
Max = 90.0f,
Step = 1.0f,
OnValueChanged = value =>
{
shader.EndParameters.Strength = value;
Map.Update(shader);
}
},
new PointSettingsSlider<float>
{
Enabled = startValToggle.Bindable,
Text = "Start Y Rotation",
TooltipText = "Y axis rotation.",
CurrentValue = shader.StartParameters.Strength2,
Min = -90.0f,
Max = 90.0f,
Step = 1.0f,
OnValueChanged = value =>
{
shader.StartParameters.Strength2 = value;
Map.Update(shader);
}
},
new PointSettingsSlider<float>
{
Text = "End Y Rotation",
TooltipText = "Y axis rotation.",
CurrentValue = shader.EndParameters.Strength2,
Min = -90.0f,
Max = 90.0f,
Step = 1.0f,
OnValueChanged = value =>
{
shader.EndParameters.Strength2 = value;
Map.Update(shader);
}
},
new PointSettingsSlider<float>
{
Enabled = startValToggle.Bindable,
Text = "Start FOV",
TooltipText = "FOV.",
CurrentValue = shader.StartParameters.Strength3,
Min = 0.0f,
Max = 100.0f,
Step = 1.0f,
OnValueChanged = value =>
{
shader.StartParameters.Strength3 = value;
Map.Update(shader);
}
},
new PointSettingsSlider<float>
{
Text = "End FOV",
TooltipText = "FOV.",
CurrentValue = shader.EndParameters.Strength3,
Min = 0.0f,
Max = 100.0f,
Step = 1.0f,
OnValueChanged = value =>
{
shader.EndParameters.Strength3 = value;
Map.Update(shader);
}
}
});
break;

case ShaderType.Bloom:
case ShaderType.Greyscale:
case ShaderType.Invert:
Expand Down
2 changes: 2 additions & 0 deletions fluXis/Screens/Gameplay/GameplayScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
using fluXis.Graphics.Shaders.SplitScreen;
using fluXis.Graphics.Shaders.FishEye;
using fluXis.Graphics.Shaders.Reflections;
using fluXis.Graphics.Shaders.Perspective;
using fluXis.Input;
using fluXis.Map;
using fluXis.Map.Structures.Bases;
Expand Down Expand Up @@ -379,6 +380,7 @@ private ShaderStackContainer buildShaders()
ShaderType.SplitScreen => new SplitScreenContainer(),
ShaderType.FishEye => new FishEyeContainer(),
ShaderType.Reflections => new ReflectionsContainer(),
ShaderType.Perspective => new PerspectiveContainer(),
_ => null
};

Expand Down