From 42c01f0ced7c4975fd8b7fd07818f3f84e45cf6c Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 19 May 2024 00:59:58 +0300 Subject: [PATCH 01/17] Implement FastCircle --- .../TestSceneFastCirclePerformance.cs | 13 ++++++ osu.Framework/Graphics/Shapes/FastCircle.cs | 41 +++++++++++++++++++ .../Resources/Shaders/sh_FastCircle.fs | 22 ++++++++++ 3 files changed, 76 insertions(+) create mode 100644 osu.Framework.Tests/Visual/Performance/TestSceneFastCirclePerformance.cs create mode 100644 osu.Framework/Graphics/Shapes/FastCircle.cs create mode 100644 osu.Framework/Resources/Shaders/sh_FastCircle.fs diff --git a/osu.Framework.Tests/Visual/Performance/TestSceneFastCirclePerformance.cs b/osu.Framework.Tests/Visual/Performance/TestSceneFastCirclePerformance.cs new file mode 100644 index 0000000000..3e4bd26c0d --- /dev/null +++ b/osu.Framework.Tests/Visual/Performance/TestSceneFastCirclePerformance.cs @@ -0,0 +1,13 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; + +namespace osu.Framework.Tests.Visual.Performance +{ + public sealed partial class TestSceneFastCirclePerformance : RepeatedDrawablePerformanceTestScene + { + protected override Drawable CreateDrawable() => new FastCircle(); + } +} diff --git a/osu.Framework/Graphics/Shapes/FastCircle.cs b/osu.Framework/Graphics/Shapes/FastCircle.cs new file mode 100644 index 0000000000..12bd269352 --- /dev/null +++ b/osu.Framework/Graphics/Shapes/FastCircle.cs @@ -0,0 +1,41 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Shaders; +using osu.Framework.Graphics.Sprites; +using osuTK; + +namespace osu.Framework.Graphics.Shapes +{ + public partial class FastCircle : Sprite + { + [BackgroundDependencyLoader] + private void load(ShaderManager shaders, IRenderer renderer) + { + TextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, "FastCircle"); + Texture = renderer.WhitePixel; + } + + protected override DrawNode CreateDrawNode() => new FastCircleDrawNode(this); + + private class FastCircleDrawNode : SpriteDrawNode + { + public FastCircleDrawNode(FastCircle source) + : base(source) + { + } + + protected override void Blit(IRenderer renderer) + { + if (DrawRectangle.Width == 0 || DrawRectangle.Height == 0) + return; + + renderer.DrawQuad(Texture, ScreenSpaceDrawQuad, DrawColourInfo.Colour, null, null, + new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height), + null, TextureCoords); + } + } + } +} diff --git a/osu.Framework/Resources/Shaders/sh_FastCircle.fs b/osu.Framework/Resources/Shaders/sh_FastCircle.fs new file mode 100644 index 0000000000..faa0d5347f --- /dev/null +++ b/osu.Framework/Resources/Shaders/sh_FastCircle.fs @@ -0,0 +1,22 @@ +#ifndef FAST_CIRCLE_FS +#define FAST_CIRCLE_FS + +#undef HIGH_PRECISION_VERTEX +#define HIGH_PRECISION_VERTEX + +#include "sh_Utils.h" +#include "sh_Masking.h" + +layout(location = 2) in highp vec2 v_TexCoord; + +layout(location = 0) out vec4 o_Colour; + +void main(void) +{ + highp vec2 resolution = v_TexRect.zw - v_TexRect.xy; + highp vec2 pixelPos = v_TexCoord / resolution; + + o_Colour = getRoundedColor(distance(pixelPos, vec2(0.5)) < 0.5 ? vec4(1.0) : vec4(vec3(1.0), 0.0), v_TexCoord); +} + +#endif From 0a76264e92be9bb7438b5780296d1e4687495e2f Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 19 May 2024 01:51:31 +0300 Subject: [PATCH 02/17] Add antialiasing --- osu.Framework/Graphics/Shapes/FastCircle.cs | 49 +++++++++++++++++-- .../Resources/Shaders/sh_FastCircle.fs | 8 +-- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/osu.Framework/Graphics/Shapes/FastCircle.cs b/osu.Framework/Graphics/Shapes/FastCircle.cs index 12bd269352..f6c102c8dc 100644 --- a/osu.Framework/Graphics/Shapes/FastCircle.cs +++ b/osu.Framework/Graphics/Shapes/FastCircle.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics.Rendering; +using osu.Framework.Graphics.Rendering.Vertices; using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Sprites; using osuTK; @@ -27,14 +28,56 @@ public FastCircleDrawNode(FastCircle source) { } + private Vector2 drawSize; + + public override void ApplyState() + { + base.ApplyState(); + drawSize = Source.DrawSize; + } + protected override void Blit(IRenderer renderer) { if (DrawRectangle.Width == 0 || DrawRectangle.Height == 0) return; - renderer.DrawQuad(Texture, ScreenSpaceDrawQuad, DrawColourInfo.Colour, null, null, - new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height), - null, TextureCoords); + if (!renderer.BindTexture(Texture)) + return; + + var vertexAction = renderer.DefaultQuadBatch.AddAction; + + vertexAction(new TexturedVertex2D(renderer) + { + Position = ScreenSpaceDrawQuad.BottomLeft, + TexturePosition = new Vector2(0, drawSize.Y), + TextureRect = new Vector4(0, 0, drawSize.X, drawSize.Y), + BlendRange = Vector2.Zero, + Colour = DrawColourInfo.Colour.BottomLeft.SRGB, + }); + vertexAction(new TexturedVertex2D(renderer) + { + Position = ScreenSpaceDrawQuad.BottomRight, + TexturePosition = new Vector2(drawSize.X, drawSize.Y), + TextureRect = new Vector4(0, 0, drawSize.X, drawSize.Y), + BlendRange = Vector2.Zero, + Colour = DrawColourInfo.Colour.BottomRight.SRGB, + }); + vertexAction(new TexturedVertex2D(renderer) + { + Position = ScreenSpaceDrawQuad.TopRight, + TexturePosition = new Vector2(drawSize.X, 0), + TextureRect = new Vector4(0, 0, drawSize.X, drawSize.Y), + BlendRange = Vector2.Zero, + Colour = DrawColourInfo.Colour.TopRight.SRGB, + }); + vertexAction(new TexturedVertex2D(renderer) + { + Position = ScreenSpaceDrawQuad.TopLeft, + TexturePosition = new Vector2(0, 0), + TextureRect = new Vector4(0, 0, drawSize.X, drawSize.Y), + BlendRange = Vector2.Zero, + Colour = DrawColourInfo.Colour.TopLeft.SRGB, + }); } } } diff --git a/osu.Framework/Resources/Shaders/sh_FastCircle.fs b/osu.Framework/Resources/Shaders/sh_FastCircle.fs index faa0d5347f..180f87148f 100644 --- a/osu.Framework/Resources/Shaders/sh_FastCircle.fs +++ b/osu.Framework/Resources/Shaders/sh_FastCircle.fs @@ -13,10 +13,12 @@ layout(location = 0) out vec4 o_Colour; void main(void) { - highp vec2 resolution = v_TexRect.zw - v_TexRect.xy; - highp vec2 pixelPos = v_TexCoord / resolution; + highp vec2 pixelPos = v_TexCoord / v_TexRect.zw; + highp vec2 pixelSize = vec2(1.5) / v_TexRect.zw; - o_Colour = getRoundedColor(distance(pixelPos, vec2(0.5)) < 0.5 ? vec4(1.0) : vec4(vec3(1.0), 0.0), v_TexCoord); + highp float alpha = smoothstep(0.5, 0.5 - min(max(pixelSize.x, pixelSize.y), 0.1), distance(pixelPos, vec2(0.5))); + + o_Colour = getRoundedColor(vec4(vec3(1.0), alpha), vec2(0.0)); } #endif From cd051478183acf0d38fc00c745f0dceb35df9c0c Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 19 May 2024 02:26:01 +0300 Subject: [PATCH 03/17] Add TestSceneCircle --- .../Visual/Drawables/TestSceneCircle.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 osu.Framework.Tests/Visual/Drawables/TestSceneCircle.cs diff --git a/osu.Framework.Tests/Visual/Drawables/TestSceneCircle.cs b/osu.Framework.Tests/Visual/Drawables/TestSceneCircle.cs new file mode 100644 index 0000000000..0eebb57b1f --- /dev/null +++ b/osu.Framework.Tests/Visual/Drawables/TestSceneCircle.cs @@ -0,0 +1,32 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics; +using osuTK; + +namespace osu.Framework.Tests.Visual.Drawables +{ + public partial class TestSceneCircle : FrameworkTestScene + { + private readonly FastCircle circle; + + public TestSceneCircle() + { + Add(circle = new FastCircle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(100) + }); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + AddSliderStep("Width", 0, 400, 100, w => circle.Width = w); + AddSliderStep("Height", 0, 400, 100, h => circle.Height = h); + } + } +} From 8931d9894e9e64f36280e986403056a0ba3fcbec Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 19 May 2024 03:00:47 +0300 Subject: [PATCH 04/17] Make circle with uneven sides pill-shaped --- osu.Framework/Resources/Shaders/sh_FastCircle.fs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Framework/Resources/Shaders/sh_FastCircle.fs b/osu.Framework/Resources/Shaders/sh_FastCircle.fs index 180f87148f..60d86406b4 100644 --- a/osu.Framework/Resources/Shaders/sh_FastCircle.fs +++ b/osu.Framework/Resources/Shaders/sh_FastCircle.fs @@ -13,10 +13,14 @@ layout(location = 0) out vec4 o_Colour; void main(void) { - highp vec2 pixelPos = v_TexCoord / v_TexRect.zw; - highp vec2 pixelSize = vec2(1.5) / v_TexRect.zw; + const float smoothness = 1.5; // in screen-space - highp float alpha = smoothstep(0.5, 0.5 - min(max(pixelSize.x, pixelSize.y), 0.1), distance(pixelPos, vec2(0.5))); + highp vec2 pixelPos = v_TexRect.zw * 0.5 - abs(v_TexCoord - v_TexRect.zw * 0.5); + highp float radius = min(v_TexRect.z, v_TexRect.w) * 0.5; + + highp float dst = max(pixelPos.x, pixelPos.y) > radius ? radius - min(pixelPos.x, pixelPos.y) : distance(pixelPos, vec2(radius)); + + highp float alpha = smoothstep(radius, radius - smoothness, dst); o_Colour = getRoundedColor(vec4(vec3(1.0), alpha), vec2(0.0)); } From 73237d357c2370466623b715fd1d64bb8e5c235d Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 19 May 2024 03:19:39 +0300 Subject: [PATCH 05/17] Don't inherit Sprite --- osu.Framework/Graphics/Shapes/FastCircle.cs | 56 ++++++++++++--------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/osu.Framework/Graphics/Shapes/FastCircle.cs b/osu.Framework/Graphics/Shapes/FastCircle.cs index f6c102c8dc..cdbea73c37 100644 --- a/osu.Framework/Graphics/Shapes/FastCircle.cs +++ b/osu.Framework/Graphics/Shapes/FastCircle.cs @@ -2,82 +2,90 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Rendering; using osu.Framework.Graphics.Rendering.Vertices; using osu.Framework.Graphics.Shaders; -using osu.Framework.Graphics.Sprites; using osuTK; namespace osu.Framework.Graphics.Shapes { - public partial class FastCircle : Sprite + public partial class FastCircle : Drawable { + private IShader shader = null!; + [BackgroundDependencyLoader] - private void load(ShaderManager shaders, IRenderer renderer) + private void load(ShaderManager shaders) { - TextureShader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, "FastCircle"); - Texture = renderer.WhitePixel; + shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, "FastCircle"); } protected override DrawNode CreateDrawNode() => new FastCircleDrawNode(this); - private class FastCircleDrawNode : SpriteDrawNode + private class FastCircleDrawNode : DrawNode { + protected new FastCircle Source => (FastCircle)base.Source; + public FastCircleDrawNode(FastCircle source) : base(source) { } - private Vector2 drawSize; + private Quad screenSpaceDrawQuad; + private Vector4 drawRectangle; + private IShader shader = null!; public override void ApplyState() { base.ApplyState(); - drawSize = Source.DrawSize; + + screenSpaceDrawQuad = Source.ScreenSpaceDrawQuad; + drawRectangle = new Vector4(0, 0, screenSpaceDrawQuad.Width, screenSpaceDrawQuad.Height); + shader = Source.shader; } - protected override void Blit(IRenderer renderer) + protected override void Draw(IRenderer renderer) { - if (DrawRectangle.Width == 0 || DrawRectangle.Height == 0) - return; + base.Draw(renderer); - if (!renderer.BindTexture(Texture)) - return; + shader.Bind(); var vertexAction = renderer.DefaultQuadBatch.AddAction; vertexAction(new TexturedVertex2D(renderer) { - Position = ScreenSpaceDrawQuad.BottomLeft, - TexturePosition = new Vector2(0, drawSize.Y), - TextureRect = new Vector4(0, 0, drawSize.X, drawSize.Y), + Position = screenSpaceDrawQuad.BottomLeft, + TexturePosition = new Vector2(0, screenSpaceDrawQuad.Height), + TextureRect = drawRectangle, BlendRange = Vector2.Zero, Colour = DrawColourInfo.Colour.BottomLeft.SRGB, }); vertexAction(new TexturedVertex2D(renderer) { - Position = ScreenSpaceDrawQuad.BottomRight, - TexturePosition = new Vector2(drawSize.X, drawSize.Y), - TextureRect = new Vector4(0, 0, drawSize.X, drawSize.Y), + Position = screenSpaceDrawQuad.BottomRight, + TexturePosition = new Vector2(screenSpaceDrawQuad.Width, screenSpaceDrawQuad.Height), + TextureRect = drawRectangle, BlendRange = Vector2.Zero, Colour = DrawColourInfo.Colour.BottomRight.SRGB, }); vertexAction(new TexturedVertex2D(renderer) { - Position = ScreenSpaceDrawQuad.TopRight, - TexturePosition = new Vector2(drawSize.X, 0), - TextureRect = new Vector4(0, 0, drawSize.X, drawSize.Y), + Position = screenSpaceDrawQuad.TopRight, + TexturePosition = new Vector2(screenSpaceDrawQuad.Width, 0), + TextureRect = drawRectangle, BlendRange = Vector2.Zero, Colour = DrawColourInfo.Colour.TopRight.SRGB, }); vertexAction(new TexturedVertex2D(renderer) { - Position = ScreenSpaceDrawQuad.TopLeft, + Position = screenSpaceDrawQuad.TopLeft, TexturePosition = new Vector2(0, 0), - TextureRect = new Vector4(0, 0, drawSize.X, drawSize.Y), + TextureRect = drawRectangle, BlendRange = Vector2.Zero, Colour = DrawColourInfo.Colour.TopLeft.SRGB, }); + + shader.Unbind(); } } } From a0a4ccc7eb01d1fd4f4ac8b8a3663ca78311cc38 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 19 May 2024 10:21:58 +0300 Subject: [PATCH 06/17] Implement correct input handling --- .../Visual/Drawables/TestSceneCircle.cs | 32 -------- .../Visual/Drawables/TestSceneFastCircle.cs | 76 +++++++++++++++++++ osu.Framework/Graphics/Shapes/FastCircle.cs | 12 +++ 3 files changed, 88 insertions(+), 32 deletions(-) delete mode 100644 osu.Framework.Tests/Visual/Drawables/TestSceneCircle.cs create mode 100644 osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs diff --git a/osu.Framework.Tests/Visual/Drawables/TestSceneCircle.cs b/osu.Framework.Tests/Visual/Drawables/TestSceneCircle.cs deleted file mode 100644 index 0eebb57b1f..0000000000 --- a/osu.Framework.Tests/Visual/Drawables/TestSceneCircle.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics; -using osuTK; - -namespace osu.Framework.Tests.Visual.Drawables -{ - public partial class TestSceneCircle : FrameworkTestScene - { - private readonly FastCircle circle; - - public TestSceneCircle() - { - Add(circle = new FastCircle - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(100) - }); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - AddSliderStep("Width", 0, 400, 100, w => circle.Width = w); - AddSliderStep("Height", 0, 400, 100, h => circle.Height = h); - } - } -} diff --git a/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs b/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs new file mode 100644 index 0000000000..08b84fe41a --- /dev/null +++ b/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs @@ -0,0 +1,76 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using NUnit.Framework; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics; +using osu.Framework.Input.Events; +using osu.Framework.Testing; +using osuTK; +using osuTK.Input; + +namespace osu.Framework.Tests.Visual.Drawables +{ + public partial class TestSceneFastCircle : ManualInputManagerTestScene + { + private TestCircle circle = null!; + + [SetUp] + public void Setup() + { + Child = circle = new TestCircle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(100), + Clicked = onClick + }; + } + + [Test] + public void TestInput() + { + AddStep("Resize to 100x50", () => + { + circle.Size = new Vector2(100, 50); + }); + AddStep("Click outside the corner", () => clickNearCorner(Vector2.Zero)); + AddAssert("input not received", () => clicked == false); + AddStep("Click inside the corner", () => clickNearCorner(Vector2.One)); + AddAssert("input received", () => clicked); + + AddStep("Resize to 50x100", () => + { + circle.Size = new Vector2(50, 100); + }); + AddStep("Click outside the corner", () => clickNearCorner(Vector2.Zero)); + AddAssert("input not received", () => clicked == false); + AddStep("Click inside the corner", () => clickNearCorner(Vector2.One)); + AddAssert("input received", () => clicked); + } + + private void clickNearCorner(Vector2 offset) + { + clicked = false; + InputManager.MoveMouseTo(circle.ToScreenSpace(new Vector2(circle.Radius * (1f - MathF.Sqrt(0.5f))) + offset)); + InputManager.Click(MouseButton.Left); + } + + private bool clicked; + + private void onClick() => clicked = true; + + private partial class TestCircle : FastCircle + { + public Action? Clicked; + + protected override bool OnClick(ClickEvent e) + { + base.OnClick(e); + Clicked?.Invoke(); + return true; + } + } + } +} diff --git a/osu.Framework/Graphics/Shapes/FastCircle.cs b/osu.Framework/Graphics/Shapes/FastCircle.cs index cdbea73c37..c0e81d557b 100644 --- a/osu.Framework/Graphics/Shapes/FastCircle.cs +++ b/osu.Framework/Graphics/Shapes/FastCircle.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Allocation; using osu.Framework.Graphics.Primitives; using osu.Framework.Graphics.Rendering; @@ -20,6 +21,17 @@ private void load(ShaderManager shaders) shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, "FastCircle"); } + public float Radius => MathF.Min(DrawSize.X, DrawSize.Y) * 0.5f; + + public override bool Contains(Vector2 screenSpacePos) + { + if (!base.Contains(screenSpacePos)) + return false; + + float cRadius = Radius; + return DrawRectangle.Shrink(cRadius).DistanceExponentiated(ToLocalSpace(screenSpacePos), 2f) <= cRadius * cRadius; + } + protected override DrawNode CreateDrawNode() => new FastCircleDrawNode(this); private class FastCircleDrawNode : DrawNode From f0d3350303c539f4f6158004c9e2250632b6fcd9 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 19 May 2024 11:42:37 +0300 Subject: [PATCH 07/17] Implement EdgeSmoothness property --- .../Visual/Drawables/TestSceneFastCircle.cs | 8 ++++++ osu.Framework/Graphics/Shapes/FastCircle.cs | 27 ++++++++++++++++--- .../Resources/Shaders/sh_FastCircle.fs | 4 +-- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs b/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs index 08b84fe41a..def658a02a 100644 --- a/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs +++ b/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs @@ -50,6 +50,14 @@ public void TestInput() AddAssert("input received", () => clicked); } + [Test] + public void TestSmoothness() + { + AddStep("Change smoothness to 0", () => circle.EdgeSmoothness = 0); + AddStep("Change smoothness to 1", () => circle.EdgeSmoothness = 1); + AddStep("Change smoothness to 5", () => circle.EdgeSmoothness = 5); + } + private void clickNearCorner(Vector2 offset) { clicked = false; diff --git a/osu.Framework/Graphics/Shapes/FastCircle.cs b/osu.Framework/Graphics/Shapes/FastCircle.cs index c0e81d557b..6239034cdb 100644 --- a/osu.Framework/Graphics/Shapes/FastCircle.cs +++ b/osu.Framework/Graphics/Shapes/FastCircle.cs @@ -13,6 +13,23 @@ namespace osu.Framework.Graphics.Shapes { public partial class FastCircle : Drawable { + private float edgeSmoothness = 1f; + + public float EdgeSmoothness + { + get => edgeSmoothness; + set + { + if (edgeSmoothness == value) + return; + + edgeSmoothness = value; + + if (IsLoaded) + Invalidate(Invalidation.DrawNode); + } + } + private IShader shader = null!; [BackgroundDependencyLoader] @@ -45,6 +62,7 @@ public FastCircleDrawNode(FastCircle source) private Quad screenSpaceDrawQuad; private Vector4 drawRectangle; + private Vector2 edgeSmoothness; private IShader shader = null!; public override void ApplyState() @@ -54,6 +72,7 @@ public override void ApplyState() screenSpaceDrawQuad = Source.ScreenSpaceDrawQuad; drawRectangle = new Vector4(0, 0, screenSpaceDrawQuad.Width, screenSpaceDrawQuad.Height); shader = Source.shader; + edgeSmoothness = new Vector2(Source.edgeSmoothness); } protected override void Draw(IRenderer renderer) @@ -69,7 +88,7 @@ protected override void Draw(IRenderer renderer) Position = screenSpaceDrawQuad.BottomLeft, TexturePosition = new Vector2(0, screenSpaceDrawQuad.Height), TextureRect = drawRectangle, - BlendRange = Vector2.Zero, + BlendRange = edgeSmoothness, Colour = DrawColourInfo.Colour.BottomLeft.SRGB, }); vertexAction(new TexturedVertex2D(renderer) @@ -77,7 +96,7 @@ protected override void Draw(IRenderer renderer) Position = screenSpaceDrawQuad.BottomRight, TexturePosition = new Vector2(screenSpaceDrawQuad.Width, screenSpaceDrawQuad.Height), TextureRect = drawRectangle, - BlendRange = Vector2.Zero, + BlendRange = edgeSmoothness, Colour = DrawColourInfo.Colour.BottomRight.SRGB, }); vertexAction(new TexturedVertex2D(renderer) @@ -85,7 +104,7 @@ protected override void Draw(IRenderer renderer) Position = screenSpaceDrawQuad.TopRight, TexturePosition = new Vector2(screenSpaceDrawQuad.Width, 0), TextureRect = drawRectangle, - BlendRange = Vector2.Zero, + BlendRange = edgeSmoothness, Colour = DrawColourInfo.Colour.TopRight.SRGB, }); vertexAction(new TexturedVertex2D(renderer) @@ -93,7 +112,7 @@ protected override void Draw(IRenderer renderer) Position = screenSpaceDrawQuad.TopLeft, TexturePosition = new Vector2(0, 0), TextureRect = drawRectangle, - BlendRange = Vector2.Zero, + BlendRange = edgeSmoothness, Colour = DrawColourInfo.Colour.TopLeft.SRGB, }); diff --git a/osu.Framework/Resources/Shaders/sh_FastCircle.fs b/osu.Framework/Resources/Shaders/sh_FastCircle.fs index 60d86406b4..307f00a74c 100644 --- a/osu.Framework/Resources/Shaders/sh_FastCircle.fs +++ b/osu.Framework/Resources/Shaders/sh_FastCircle.fs @@ -13,14 +13,12 @@ layout(location = 0) out vec4 o_Colour; void main(void) { - const float smoothness = 1.5; // in screen-space - highp vec2 pixelPos = v_TexRect.zw * 0.5 - abs(v_TexCoord - v_TexRect.zw * 0.5); highp float radius = min(v_TexRect.z, v_TexRect.w) * 0.5; highp float dst = max(pixelPos.x, pixelPos.y) > radius ? radius - min(pixelPos.x, pixelPos.y) : distance(pixelPos, vec2(radius)); - highp float alpha = smoothstep(radius, radius - smoothness, dst); + highp float alpha = v_BlendRange.x == 0.0 ? float(dst < radius) : (clamp(radius - dst, 0.0, v_BlendRange.x) / v_BlendRange.x); o_Colour = getRoundedColor(vec4(vec3(1.0), alpha), vec2(0.0)); } From 6dd915c641c1a873ec0f6b334d40272415bf6c28 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 19 May 2024 12:33:39 +0300 Subject: [PATCH 08/17] Add Circle to the text scene for comparison --- .../Visual/Drawables/TestSceneFastCircle.cs | 68 +++++++++++++++---- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs b/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs index def658a02a..2cc67da373 100644 --- a/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs +++ b/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs @@ -5,6 +5,8 @@ using NUnit.Framework; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; using osu.Framework.Input.Events; using osu.Framework.Testing; using osuTK; @@ -14,17 +16,59 @@ namespace osu.Framework.Tests.Visual.Drawables { public partial class TestSceneFastCircle : ManualInputManagerTestScene { - private TestCircle circle = null!; + private TestCircle fastCircle = null!; + private Circle circle = null!; [SetUp] public void Setup() { - Child = circle = new TestCircle + Child = new GridContainer { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(100), - Clicked = onClick + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(GridSizeMode.Absolute, 100), + new Dimension(), + }, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.Relative, 0.5f), + new Dimension() + }, + Content = new[] + { + new Drawable[] + { + new SpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "FastCircle" + }, + new SpriteText + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Text = "Circle" + } + }, + new Drawable[] + { + fastCircle = new TestCircle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(100), + Clicked = onClick + }, + circle = new Circle + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(100) + } + } + } }; } @@ -33,7 +77,7 @@ public void TestInput() { AddStep("Resize to 100x50", () => { - circle.Size = new Vector2(100, 50); + fastCircle.Size = circle.Size = new Vector2(100, 50); }); AddStep("Click outside the corner", () => clickNearCorner(Vector2.Zero)); AddAssert("input not received", () => clicked == false); @@ -42,7 +86,7 @@ public void TestInput() AddStep("Resize to 50x100", () => { - circle.Size = new Vector2(50, 100); + fastCircle.Size = circle.Size = new Vector2(50, 100); }); AddStep("Click outside the corner", () => clickNearCorner(Vector2.Zero)); AddAssert("input not received", () => clicked == false); @@ -53,15 +97,15 @@ public void TestInput() [Test] public void TestSmoothness() { - AddStep("Change smoothness to 0", () => circle.EdgeSmoothness = 0); - AddStep("Change smoothness to 1", () => circle.EdgeSmoothness = 1); - AddStep("Change smoothness to 5", () => circle.EdgeSmoothness = 5); + AddStep("Change smoothness to 0", () => fastCircle.EdgeSmoothness = circle.MaskingSmoothness = 0); + AddStep("Change smoothness to 1", () => fastCircle.EdgeSmoothness = circle.MaskingSmoothness = 1); + AddStep("Change smoothness to 5", () => fastCircle.EdgeSmoothness = circle.MaskingSmoothness = 5); } private void clickNearCorner(Vector2 offset) { clicked = false; - InputManager.MoveMouseTo(circle.ToScreenSpace(new Vector2(circle.Radius * (1f - MathF.Sqrt(0.5f))) + offset)); + InputManager.MoveMouseTo(fastCircle.ToScreenSpace(new Vector2(fastCircle.Radius * (1f - MathF.Sqrt(0.5f))) + offset)); InputManager.Click(MouseButton.Left); } From 30dc846db93631f325ebc4d72d2f48cb9d7b6c30 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 19 May 2024 12:40:25 +0300 Subject: [PATCH 09/17] Improve input test --- .../Visual/Drawables/TestSceneFastCircle.cs | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs b/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs index 2cc67da373..8e44c0fda3 100644 --- a/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs +++ b/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs @@ -58,14 +58,14 @@ public void Setup() { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(100), + Size = new Vector2(200), Clicked = onClick }, circle = new Circle { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Size = new Vector2(100) + Size = new Vector2(200) } } } @@ -75,23 +75,9 @@ public void Setup() [Test] public void TestInput() { - AddStep("Resize to 100x50", () => - { - fastCircle.Size = circle.Size = new Vector2(100, 50); - }); - AddStep("Click outside the corner", () => clickNearCorner(Vector2.Zero)); - AddAssert("input not received", () => clicked == false); - AddStep("Click inside the corner", () => clickNearCorner(Vector2.One)); - AddAssert("input received", () => clicked); - - AddStep("Resize to 50x100", () => - { - fastCircle.Size = circle.Size = new Vector2(50, 100); - }); - AddStep("Click outside the corner", () => clickNearCorner(Vector2.Zero)); - AddAssert("input not received", () => clicked == false); - AddStep("Click inside the corner", () => clickNearCorner(Vector2.One)); - AddAssert("input received", () => clicked); + testInput(new Vector2(200, 100)); + testInput(new Vector2(100, 200)); + testInput(new Vector2(200, 200)); } [Test] @@ -102,6 +88,18 @@ public void TestSmoothness() AddStep("Change smoothness to 5", () => fastCircle.EdgeSmoothness = circle.MaskingSmoothness = 5); } + private void testInput(Vector2 size) + { + AddStep($"Resize to {size}", () => + { + fastCircle.Size = circle.Size = size; + }); + AddStep("Click outside the corner", () => clickNearCorner(-Vector2.One)); + AddAssert("input not received", () => clicked == false); + AddStep("Click inside the corner", () => clickNearCorner(Vector2.One)); + AddAssert("input received", () => clicked); + } + private void clickNearCorner(Vector2 offset) { clicked = false; From 58593b4f95f2db5b8a7ac180faaf8bf745a2e29e Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 19 May 2024 12:47:13 +0300 Subject: [PATCH 10/17] Add nested masking test --- .../Visual/Drawables/TestSceneFastCircle.cs | 34 +++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs b/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs index 8e44c0fda3..1448ded767 100644 --- a/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs +++ b/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs @@ -18,6 +18,8 @@ public partial class TestSceneFastCircle : ManualInputManagerTestScene { private TestCircle fastCircle = null!; private Circle circle = null!; + private CircularContainer fastCircleMask = null!; + private CircularContainer circleMask = null!; [SetUp] public void Setup() @@ -54,19 +56,31 @@ public void Setup() }, new Drawable[] { - fastCircle = new TestCircle + fastCircleMask = new CircularContainer { Anchor = Anchor.Centre, - Origin = Anchor.Centre, + Origin = Anchor.TopRight, Size = new Vector2(200), - Clicked = onClick + Child = fastCircle = new TestCircle + { + Anchor = Anchor.TopRight, + Origin = Anchor.Centre, + Size = new Vector2(200), + Clicked = onClick + } }, - circle = new Circle + circleMask = new CircularContainer { Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(200) - } + Origin = Anchor.TopRight, + Size = new Vector2(200), + Child = circle = new Circle + { + Anchor = Anchor.TopRight, + Origin = Anchor.Centre, + Size = new Vector2(200) + } + }, } } }; @@ -88,6 +102,12 @@ public void TestSmoothness() AddStep("Change smoothness to 5", () => fastCircle.EdgeSmoothness = circle.MaskingSmoothness = 5); } + [Test] + public void TestNestedMasking() + { + AddToggleStep("Toggle parent masking", m => fastCircleMask.Masking = circleMask.Masking = m); + } + private void testInput(Vector2 size) { AddStep($"Resize to {size}", () => From 88f9416899102810903036f90616e47372a025ae Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 19 May 2024 12:52:49 +0300 Subject: [PATCH 11/17] Bind texture just in case --- osu.Framework/Graphics/Shapes/FastCircle.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Framework/Graphics/Shapes/FastCircle.cs b/osu.Framework/Graphics/Shapes/FastCircle.cs index 6239034cdb..d0dd3c4282 100644 --- a/osu.Framework/Graphics/Shapes/FastCircle.cs +++ b/osu.Framework/Graphics/Shapes/FastCircle.cs @@ -79,6 +79,9 @@ protected override void Draw(IRenderer renderer) { base.Draw(renderer); + if (!renderer.BindTexture(renderer.WhitePixel)) + return; + shader.Bind(); var vertexAction = renderer.DefaultQuadBatch.AddAction; From 018fd4bcdc424defb435544c50d520c525a23644 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 19 May 2024 14:23:07 +0300 Subject: [PATCH 12/17] Schedule content loading in TestSceneFastCircle setup --- osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs b/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs index 1448ded767..3e4af909dd 100644 --- a/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs +++ b/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs @@ -22,7 +22,7 @@ public partial class TestSceneFastCircle : ManualInputManagerTestScene private CircularContainer circleMask = null!; [SetUp] - public void Setup() + public void Setup() => Schedule(() => { Child = new GridContainer { @@ -84,7 +84,7 @@ public void Setup() } } }; - } + }); [Test] public void TestInput() From ac3a224b95661b5fcab620f3ae33d42512de6d2b Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 19 May 2024 23:15:39 +0300 Subject: [PATCH 13/17] Add rotation test --- .../Visual/Drawables/TestSceneFastCircle.cs | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs b/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs index 3e4af909dd..51c9b4280c 100644 --- a/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs +++ b/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs @@ -108,18 +108,40 @@ public void TestNestedMasking() AddToggleStep("Toggle parent masking", m => fastCircleMask.Masking = circleMask.Masking = m); } - private void testInput(Vector2 size) + [Test] + public void TestRotation() { - AddStep($"Resize to {size}", () => + resize(new Vector2(200, 100)); + AddToggleStep("Toggle rotation", rotate => { - fastCircle.Size = circle.Size = size; + fastCircle.ClearTransforms(); + circle.ClearTransforms(); + + if (rotate) + { + fastCircle.Spin(2000, RotationDirection.Clockwise); + circle.Spin(2000, RotationDirection.Clockwise); + } }); + } + + private void testInput(Vector2 size) + { + resize(size); AddStep("Click outside the corner", () => clickNearCorner(-Vector2.One)); AddAssert("input not received", () => clicked == false); AddStep("Click inside the corner", () => clickNearCorner(Vector2.One)); AddAssert("input received", () => clicked); } + private void resize(Vector2 size) + { + AddStep($"Resize to {size}", () => + { + fastCircle.Size = circle.Size = size; + }); + } + private void clickNearCorner(Vector2 offset) { clicked = false; From 5f6716b66ae21be6840c450358eec82e22af3cc9 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Tue, 21 May 2024 19:24:24 +0300 Subject: [PATCH 14/17] Add performance test scenes for alternating drawables --- .../TestSceneCircleBoxAlternatePerformance.cs | 22 +++++++++++++++++++ ...tSceneFastCircleBoxAlternatePerformance.cs | 22 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 osu.Framework.Tests/Visual/Performance/TestSceneCircleBoxAlternatePerformance.cs create mode 100644 osu.Framework.Tests/Visual/Performance/TestSceneFastCircleBoxAlternatePerformance.cs diff --git a/osu.Framework.Tests/Visual/Performance/TestSceneCircleBoxAlternatePerformance.cs b/osu.Framework.Tests/Visual/Performance/TestSceneCircleBoxAlternatePerformance.cs new file mode 100644 index 0000000000..5f06e8c154 --- /dev/null +++ b/osu.Framework.Tests/Visual/Performance/TestSceneCircleBoxAlternatePerformance.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; + +namespace osu.Framework.Tests.Visual.Performance +{ + public sealed partial class TestSceneCircleBoxAlternatePerformance : RepeatedDrawablePerformanceTestScene + { + private int index; + + protected override Drawable CreateDrawable() + { + index++; + if (index % 2 == 0) + return new Circle(); + + return new Box(); + } + } +} diff --git a/osu.Framework.Tests/Visual/Performance/TestSceneFastCircleBoxAlternatePerformance.cs b/osu.Framework.Tests/Visual/Performance/TestSceneFastCircleBoxAlternatePerformance.cs new file mode 100644 index 0000000000..137cb6ca1d --- /dev/null +++ b/osu.Framework.Tests/Visual/Performance/TestSceneFastCircleBoxAlternatePerformance.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; + +namespace osu.Framework.Tests.Visual.Performance +{ + public sealed partial class TestSceneFastCircleBoxAlternatePerformance : RepeatedDrawablePerformanceTestScene + { + private int index; + + protected override Drawable CreateDrawable() + { + index++; + if (index % 2 == 0) + return new FastCircle(); + + return new Box(); + } + } +} From bcac4ac2e99d245ca9a03409debe019c26a17e82 Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Sun, 26 May 2024 09:43:25 +0300 Subject: [PATCH 15/17] Add shear and scale tests --- .../Visual/Drawables/TestSceneFastCircle.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs b/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs index 51c9b4280c..b0e464e289 100644 --- a/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs +++ b/osu.Framework.Tests/Visual/Drawables/TestSceneFastCircle.cs @@ -125,6 +125,26 @@ public void TestRotation() }); } + [Test] + public void TestShear() + { + resize(new Vector2(200, 100)); + AddToggleStep("Toggle shear", shear => + { + fastCircle.Shear = circle.Shear = shear ? new Vector2(0.5f, 0) : Vector2.Zero; + }); + } + + [Test] + public void TestScale() + { + resize(new Vector2(200, 100)); + AddToggleStep("Toggle scale", scale => + { + fastCircle.Scale = circle.Scale = scale ? new Vector2(2f, 1f) : Vector2.One; + }); + } + private void testInput(Vector2 size) { resize(size); From 0a75c426c17b52554783dd48e485b5b18610d1eb Mon Sep 17 00:00:00 2001 From: Andrei Zavatski Date: Wed, 28 Aug 2024 14:33:14 +0300 Subject: [PATCH 16/17] Fix incorrect scale handling --- osu.Framework/Graphics/Shapes/FastCircle.cs | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Framework/Graphics/Shapes/FastCircle.cs b/osu.Framework/Graphics/Shapes/FastCircle.cs index d0dd3c4282..c2b8ef3a27 100644 --- a/osu.Framework/Graphics/Shapes/FastCircle.cs +++ b/osu.Framework/Graphics/Shapes/FastCircle.cs @@ -62,7 +62,7 @@ public FastCircleDrawNode(FastCircle source) private Quad screenSpaceDrawQuad; private Vector4 drawRectangle; - private Vector2 edgeSmoothness; + private Vector2 blend; private IShader shader = null!; public override void ApplyState() @@ -70,9 +70,9 @@ public override void ApplyState() base.ApplyState(); screenSpaceDrawQuad = Source.ScreenSpaceDrawQuad; - drawRectangle = new Vector4(0, 0, screenSpaceDrawQuad.Width, screenSpaceDrawQuad.Height); + drawRectangle = new Vector4(0, 0, Source.DrawWidth, Source.DrawHeight); shader = Source.shader; - edgeSmoothness = new Vector2(Source.edgeSmoothness); + blend = new Vector2(Source.edgeSmoothness * Math.Min(Source.DrawWidth, Source.DrawHeight) / Math.Min(screenSpaceDrawQuad.Width, screenSpaceDrawQuad.Height)); } protected override void Draw(IRenderer renderer) @@ -89,33 +89,33 @@ protected override void Draw(IRenderer renderer) vertexAction(new TexturedVertex2D(renderer) { Position = screenSpaceDrawQuad.BottomLeft, - TexturePosition = new Vector2(0, screenSpaceDrawQuad.Height), + TexturePosition = new Vector2(0, drawRectangle.W), TextureRect = drawRectangle, - BlendRange = edgeSmoothness, + BlendRange = blend, Colour = DrawColourInfo.Colour.BottomLeft.SRGB, }); vertexAction(new TexturedVertex2D(renderer) { Position = screenSpaceDrawQuad.BottomRight, - TexturePosition = new Vector2(screenSpaceDrawQuad.Width, screenSpaceDrawQuad.Height), + TexturePosition = new Vector2(drawRectangle.Z, drawRectangle.W), TextureRect = drawRectangle, - BlendRange = edgeSmoothness, + BlendRange = blend, Colour = DrawColourInfo.Colour.BottomRight.SRGB, }); vertexAction(new TexturedVertex2D(renderer) { Position = screenSpaceDrawQuad.TopRight, - TexturePosition = new Vector2(screenSpaceDrawQuad.Width, 0), + TexturePosition = new Vector2(drawRectangle.Z, 0), TextureRect = drawRectangle, - BlendRange = edgeSmoothness, + BlendRange = blend, Colour = DrawColourInfo.Colour.TopRight.SRGB, }); vertexAction(new TexturedVertex2D(renderer) { Position = screenSpaceDrawQuad.TopLeft, - TexturePosition = new Vector2(0, 0), + TexturePosition = Vector2.Zero, TextureRect = drawRectangle, - BlendRange = edgeSmoothness, + BlendRange = blend, Colour = DrawColourInfo.Colour.TopLeft.SRGB, }); From 293767873fc06b4269976df45cc0ff382254afe4 Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 30 Aug 2024 16:57:27 +0900 Subject: [PATCH 17/17] Add xmldoc --- osu.Framework/Graphics/Shapes/FastCircle.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Framework/Graphics/Shapes/FastCircle.cs b/osu.Framework/Graphics/Shapes/FastCircle.cs index c2b8ef3a27..660239ad45 100644 --- a/osu.Framework/Graphics/Shapes/FastCircle.cs +++ b/osu.Framework/Graphics/Shapes/FastCircle.cs @@ -11,6 +11,11 @@ namespace osu.Framework.Graphics.Shapes { + /// + /// A circle that is rendered directly to the screen using a specialised shader. + /// This behaves slightly differently from but offers + /// higher performance in scenarios where many circles are drawn at once. + /// public partial class FastCircle : Drawable { private float edgeSmoothness = 1f;