diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs
index 21b3b38388..afe14de3ea 100644
--- a/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs
+++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/Parts/MarkerPart.cs
@@ -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;
- }
}
}
diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/CentreMarker.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/CentreMarker.cs
index c63dfdfb55..145049e1dd 100644
--- a/osu.Game/Screens/Edit/Compose/Components/Timeline/CentreMarker.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/CentreMarker.cs
@@ -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;
+
+ ///
+ /// Triangles drawn at the top and bottom of .
+ ///
+ ///
+ /// 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.
+ ///
+ 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;
+ }
+ }
}
}
diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs
index cbf49e62e7..cbafea7600 100644
--- a/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/Timeline.cs
@@ -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[]
{