diff --git a/osu.Game/Graphics/Cursor/CursorTrail.cs b/osu.Game/Graphics/Cursor/CursorTrail.cs new file mode 100644 index 0000000000..741fdbad73 --- /dev/null +++ b/osu.Game/Graphics/Cursor/CursorTrail.cs @@ -0,0 +1,155 @@ +//Copyright (c) 2007-2016 ppy Pty Ltd . +//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Batches; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shaders; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Textures; +using osu.Framework.Input; +using osu.Framework.MathUtils; +using OpenTK; + +namespace osu.Game.Graphics.Cursor +{ + class TrailSprite : Sprite + { + private Shader shader; + + public TrailSprite() + { + Origin = Anchor.Centre; + } + + protected override void ApplyDrawNode(DrawNode node) + { + base.ApplyDrawNode(node); + + SpriteDrawNode sNode = node as SpriteDrawNode; + sNode.RoundedTextureShader = sNode.TextureShader = shader; + } + + [BackgroundDependencyLoader] + private void load(ShaderManager shaders, TextureStore textures) + { + shader = shaders?.Load(@"CursorTrail", FragmentShaderDescriptor.Texture); + Texture = textures.Get(@"Cursor/cursortrail"); + } + } + + class CursorTrail : Container + { + public override bool Contains(Vector2 screenSpacePos) => true; + + int currentIndex; + + protected override bool CanBeFlattened => false; + + Shader shader; + + private double timeOffset; + + private float time; + + const int MAX_SPRITES = 2048; + + protected override DrawNode CreateDrawNode() => new TrailDrawNode(); + + protected override void ApplyDrawNode(DrawNode node) + { + base.ApplyDrawNode(node); + + TrailDrawNode tNode = node as TrailDrawNode; + tNode.Shader = shader; + tNode.Time = time; + } + + Vector2? last; + + protected override bool OnMouseMove(InputState state) + { + if (last == null) + { + last = state.Mouse.Position; + return base.OnMouseMove(state); + } + + Vector2 pos1 = last.Value; + Vector2 pos2 = state.Mouse.Position; + + Vector2 diff = (pos2 - pos1); + float distance = diff.Length; + Vector2 direction = diff / distance; + + float interval = this[0].DrawSize.X / 2; + + for (float d = interval; d < distance; d += interval) + { + last = pos1 + direction * d; + addPosition(last.Value); + } + + return base.OnMouseMove(state); + } + + private void addPosition(Vector2 pos) + { + var s = this[currentIndex]; + s.Position = pos; + s.Alpha = time + 1f; + + currentIndex = (currentIndex + 1) % MAX_SPRITES; + } + + public CursorTrail() + { + RelativeSizeAxes = Axes.Both; + + for (int i = 0; i < MAX_SPRITES; i++) + AddInternal(new TrailSprite()); + } + + [BackgroundDependencyLoader] + private void load(ShaderManager shaders) + { + shader = shaders?.Load(@"CursorTrail", FragmentShaderDescriptor.Texture); + } + + protected override void Update() + { + base.Update(); + + Invalidate(Invalidation.DrawNode); + + int fadeClockResetThreshold = 1000000; + + time = (float)(Time.Current - timeOffset) / 500f; + if (time > fadeClockResetThreshold) + ResetTime(); + } + + private void ResetTime() + { + foreach (var c in Children) + c.Alpha -= time; + + time = 0; + timeOffset = Time.Current; + } + + class TrailDrawNode : ContainerDrawNode + { + public Shader Shader; + public float Time; + + public override void Draw(IVertexBatch vertexBatch) + { + Shader.GetUniform("g_FadeClock").Value = Time; + base.Draw(vertexBatch); + } + } + } +} \ No newline at end of file diff --git a/osu.Game/Graphics/Cursor/OsuCursorContainer.cs b/osu.Game/Graphics/Cursor/OsuCursorContainer.cs index 081919feaf..bdf84e1d04 100644 --- a/osu.Game/Graphics/Cursor/OsuCursorContainer.cs +++ b/osu.Game/Graphics/Cursor/OsuCursorContainer.cs @@ -1,15 +1,22 @@ //Copyright (c) 2007-2016 ppy Pty Ltd . //Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; +using OpenTK; using osu.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Cursor; +using osu.Framework.Graphics.OpenGL; +using osu.Framework.Graphics.OpenGL.Buffers; +using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Transformations; using osu.Framework.Input; +using OpenTK.Graphics; +using OpenTK.Graphics.ES30; namespace osu.Game.Graphics.Cursor { @@ -17,9 +24,14 @@ namespace osu.Game.Graphics.Cursor { protected override Drawable CreateCursor() => new OsuCursor(); + public OsuCursorContainer() + { + Add(new CursorTrail { Depth = -1 }); + } + protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { - ActiveCursor.Scale = new OpenTK.Vector2(1); + ActiveCursor.Scale = new Vector2(1); ActiveCursor.ScaleTo(1.2f, 100, EasingTypes.OutQuad); return base.OnMouseDown(state, args); } @@ -52,5 +64,4 @@ namespace osu.Game.Graphics.Cursor } } } - } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 00c46a7ce3..c35bafb251 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -64,6 +64,7 @@ +