1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-25 12:30:17 +08:00

Merge pull request #34280 from EVAST9919/editor-triangles-aa

Add antialiasing to triangles in `MarkerVisualisation`
This commit is contained in:
Dean Herbert
2025-07-19 00:44:08 +09:00
committed by GitHub
Unverified
3 changed files with 120 additions and 73 deletions
@@ -4,11 +4,9 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Framework.Threading;
using osu.Game.Overlays;
using osu.Game.Screens.Edit.Compose.Components.Timeline;
using osuTK;
namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
@@ -26,7 +24,14 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
[BackgroundDependencyLoader]
private void load()
{
Add(marker = new MarkerVisualisation());
Add(marker = new CentreMarker
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre,
RelativePositionAxes = Axes.X,
Width = 10,
TriangleHeightRatio = 0.5f
});
}
protected override bool OnDragStart(DragStartEvent e) => true;
@@ -68,44 +73,5 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
{
// block base call so we don't clear our marker (can be reused on beatmap change).
}
private partial class MarkerVisualisation : CompositeDrawable
{
public MarkerVisualisation()
{
Anchor = Anchor.CentreLeft;
Origin = Anchor.Centre;
RelativePositionAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
AutoSizeAxes = Axes.X;
InternalChildren = new Drawable[]
{
new Triangle
{
Anchor = Anchor.TopCentre,
Origin = Anchor.BottomCentre,
Scale = new Vector2(1, -1),
Size = new Vector2(10, 5),
},
new Triangle
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Size = new Vector2(10, 5),
},
new Box
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
Width = 1.4f,
EdgeSmoothness = new Vector2(1, 0)
}
};
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colours) => Colour = colours.Highlight1;
}
}
}
@@ -4,7 +4,10 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Overlays;
using osuTK;
@@ -12,47 +15,118 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
{
public partial class CentreMarker : CompositeDrawable
{
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colours)
public float TriangleHeightRatio
{
const float triangle_width = 8;
const float bar_width = 2f;
get => triangles.TriangleHeightRatio;
set => triangles.TriangleHeightRatio = value;
}
private readonly VerticalTriangles triangles;
public CentreMarker()
{
RelativeSizeAxes = Axes.Y;
Anchor = Anchor.TopCentre;
Origin = Anchor.TopCentre;
Size = new Vector2(triangle_width, 1);
Masking = true;
InternalChildren = new Drawable[]
{
new Circle
new Box
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
Width = bar_width,
Colour = colours.Colour2,
Width = 1.4f,
EdgeSmoothness = new Vector2(1, 0)
},
new Triangle
triangles = new VerticalTriangles
{
Anchor = Anchor.TopCentre,
Origin = Anchor.BottomCentre,
Size = new Vector2(triangle_width, triangle_width * 0.8f),
Scale = new Vector2(1, -1),
EdgeSmoothness = new Vector2(1, 0),
Colour = colours.Colour2,
},
new Triangle
{
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Size = new Vector2(triangle_width, triangle_width * 0.8f),
Scale = new Vector2(1, 1),
Colour = colours.Colour2,
},
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
EdgeSmoothness = Vector2.One
}
};
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colours) => Colour = colours.Highlight1;
/// <summary>
/// Triangles drawn at the top and bottom of <see cref="CentreMarker"/>.
/// </summary>
/// <remarks>
/// Since framework-side triangles don't support antialiasing we are using custom implementation involving rotated smoothened boxes to avoid
/// mismatch in antialiasing between top and bottom triangles when drawable moves across the screen.
/// To "trim" boxes we must enable masking at the top level.
/// </remarks>
private partial class VerticalTriangles : Sprite
{
private float triangleHeightRatio = 1f;
public float TriangleHeightRatio
{
get => triangleHeightRatio;
set
{
triangleHeightRatio = value;
Invalidate(Invalidation.DrawNode);
}
}
[BackgroundDependencyLoader]
private void load(IRenderer renderer)
{
Texture = renderer.WhitePixel;
}
protected override DrawNode CreateDrawNode() => new VerticalTrianglesDrawNode(this);
private class VerticalTrianglesDrawNode : SpriteDrawNode
{
public new VerticalTriangles Source => (VerticalTriangles)base.Source;
public VerticalTrianglesDrawNode(VerticalTriangles source)
: base(source)
{
}
private float triangleScreenSpaceHeight;
public override void ApplyState()
{
base.ApplyState();
triangleScreenSpaceHeight = ScreenSpaceDrawQuad.Width * Source.TriangleHeightRatio;
}
protected override void Blit(IRenderer renderer)
{
if (triangleScreenSpaceHeight == 0 || DrawRectangle.Width == 0 || DrawRectangle.Height == 0)
return;
Vector2 inflation = new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / (DrawRectangle.Width * Source.TriangleHeightRatio));
Quad topTriangle = new Quad
(
ScreenSpaceDrawQuad.TopLeft,
ScreenSpaceDrawQuad.TopLeft + new Vector2(ScreenSpaceDrawQuad.Width * 0.5f, -triangleScreenSpaceHeight),
ScreenSpaceDrawQuad.TopLeft + new Vector2(ScreenSpaceDrawQuad.Width * 0.5f, triangleScreenSpaceHeight),
ScreenSpaceDrawQuad.TopRight
);
Quad bottomTriangle = new Quad
(
ScreenSpaceDrawQuad.BottomLeft,
ScreenSpaceDrawQuad.BottomLeft + new Vector2(ScreenSpaceDrawQuad.Width * 0.5f, -triangleScreenSpaceHeight),
ScreenSpaceDrawQuad.BottomLeft + new Vector2(ScreenSpaceDrawQuad.Width * 0.5f, triangleScreenSpaceHeight),
ScreenSpaceDrawQuad.BottomRight
);
renderer.DrawQuad(Texture, topTriangle, DrawColourInfo.Colour, inflationPercentage: inflation);
renderer.DrawQuad(Texture, bottomTriangle, DrawColourInfo.Colour, inflationPercentage: inflation);
}
protected override bool CanDrawOpaqueInterior => false;
}
}
}
}
@@ -107,7 +107,14 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
CentreMarker centreMarker;
// We don't want the centre marker to scroll
AddInternal(centreMarker = new CentreMarker());
AddInternal(centreMarker = new CentreMarker
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Width = 8,
TriangleHeightRatio = 0.8f,
Colour = colourProvider.Colour2
});
AddRange(new Drawable[]
{