diff --git a/osu.Desktop.VisualTests/Tests/TestCaseSongProgress.cs b/osu.Desktop.VisualTests/Tests/TestCaseSongProgress.cs index 68391d9236..7c40d21512 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseSongProgress.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseSongProgress.cs @@ -16,6 +16,7 @@ namespace osu.Desktop.VisualTests.Tests public override string Description => @"With fake data"; private SongProgress progress; + private SongProgressGraph graph; public override void Reset() { @@ -29,6 +30,14 @@ namespace osu.Desktop.VisualTests.Tests Origin = Anchor.BottomLeft, }); + Add(graph = new SongProgressGraph + { + RelativeSizeAxes = Axes.X, + Height = 200, + Anchor = Anchor.TopLeft, + Origin = Anchor.TopLeft, + }); + AddStep("Toggle Bar", progress.ToggleBar); AddWaitStep(5); AddStep("Toggle Bar", progress.ToggleBar); @@ -45,6 +54,7 @@ namespace osu.Desktop.VisualTests.Tests objects.Add(new HitObject { StartTime = i }); progress.Objects = objects; + graph.Objects = objects; } } } diff --git a/osu.Game/Screens/Play/SongProgress.cs b/osu.Game/Screens/Play/SongProgress.cs index dd6ba67b2e..48f2ca14c0 100644 --- a/osu.Game/Screens/Play/SongProgress.cs +++ b/osu.Game/Screens/Play/SongProgress.cs @@ -41,25 +41,7 @@ namespace osu.Game.Screens.Play { set { - objects = value; - - const int granularity = 200; - - var interval = lastHitTime / granularity; - - var values = new int[granularity]; - - foreach (var h in objects) - { - IHasEndTime end = h as IHasEndTime; - - int startRange = (int)(h.StartTime / interval); - int endRange = (int)((end?.EndTime ?? h.StartTime) / interval); - for (int i = startRange; i <= endRange; i++) - values[i]++; - } - - graph.Values = values; + graph.Objects = objects = value; } } @@ -71,7 +53,7 @@ namespace osu.Game.Screens.Play public SongProgress() { - Height = bottom_bar_height + SongProgressGraph.Column.HEIGHT + handle_size.Y; + Height = bottom_bar_height + SquareGraph.Column.HEIGHT + handle_size.Y; Y = bottom_bar_height; Children = new Drawable[] @@ -81,10 +63,10 @@ namespace osu.Game.Screens.Play RelativeSizeAxes = Axes.X, Origin = Anchor.BottomLeft, Anchor = Anchor.BottomLeft, - Height = SongProgressGraph.Column.HEIGHT, + Height = SquareGraph.Column.HEIGHT, Margin = new MarginPadding { Bottom = bottom_bar_height }, }, - bar = new SongProgressBar(bottom_bar_height, SongProgressGraph.Column.HEIGHT, handle_size) + bar = new SongProgressBar(bottom_bar_height, SquareGraph.Column.HEIGHT, handle_size) { Alpha = 0, Anchor = Anchor.BottomLeft, @@ -138,7 +120,6 @@ namespace osu.Game.Screens.Play bar.UpdatePosition((float)progress); graph.Progress = (int)(graph.ColumnCount * progress); - } } } diff --git a/osu.Game/Screens/Play/SongProgressGraph.cs b/osu.Game/Screens/Play/SongProgressGraph.cs index 4f0cdbf67a..97f25e0a95 100644 --- a/osu.Game/Screens/Play/SongProgressGraph.cs +++ b/osu.Game/Screens/Play/SongProgressGraph.cs @@ -1,235 +1,43 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; -using OpenTK.Graphics; using System.Linq; using System.Collections.Generic; -using osu.Framework; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.Containers; -using osu.Framework.Extensions.Color4Extensions; +using osu.Game.Rulesets.Objects.Types; +using osu.Game.Rulesets.Objects; namespace osu.Game.Screens.Play { - public class SongProgressGraph : BufferedContainer + public class SongProgressGraph : SquareGraph { - private Column[] columns = { }; + private IEnumerable objects; - public int ColumnCount => columns.Length; - - public override bool HandleInput => false; - - private int progress; - public int Progress + public IEnumerable Objects { - get { return progress; } set { - if (value == progress) return; - progress = value; + objects = value; - redrawProgress(); - } - } + const int granularity = 200; - private int[] calculatedValues = { }; // values but adjusted to fit the amount of columns - private int[] values; - public int[] Values - { - get { return values; } - set - { - if (value == values) return; - values = value; - recreateGraph(); - } - } + var lastHit = ((objects.Last() as IHasEndTime)?.EndTime ?? objects.Last().StartTime) + 1; - private Color4 fillColour; - public Color4 FillColour - { - get { return fillColour; } - set - { - if (value == fillColour) return; - fillColour = value; + var interval = lastHit / granularity; - redrawFilled(); - } - } + var values = new int[granularity]; - public SongProgressGraph() - { - CacheDrawnFrameBuffer = true; - PixelSnapping = true; - } - - private float lastDrawWidth; - protected override void Update() - { - base.Update(); - - // todo: Recreating in update is probably not the best idea - if (DrawWidth == lastDrawWidth) return; - recreateGraph(); - lastDrawWidth = DrawWidth; - } - - /// - /// Redraws all the columns to match their lit/dimmed state. - /// - private void redrawProgress() - { - for (int i = 0; i < columns.Length; i++) - { - columns[i].State = i <= progress ? ColumnState.Lit : ColumnState.Dimmed; - } - - ForceRedraw(); - } - - /// - /// Redraws the filled amount of all the columns. - /// - private void redrawFilled() - { - for (int i = 0; i < ColumnCount; i++) - { - columns[i].Filled = calculatedValues.ElementAtOrDefault(i); - } - } - - /// - /// Takes and adjusts it to fit the amount of columns. - /// - private void recalculateValues() - { - var newValues = new List(); - - if (values == null) - { - for (float i = 0; i < ColumnCount; i++) - newValues.Add(0); - - return; - } - - float step = values.Length / (float)ColumnCount; - for (float i = 0; i < values.Length; i += step) - { - newValues.Add(values[(int)i]); - } - - calculatedValues = newValues.ToArray(); - } - - /// - /// Recreates the entire graph. - /// - private void recreateGraph() - { - var newColumns = new List(); - - for (float x = 0; x < DrawWidth; x += Column.WIDTH) - { - newColumns.Add(new Column(fillColour) + foreach (var h in objects) { - Anchor = Anchor.BottomLeft, - Origin = Anchor.BottomLeft, - Position = new Vector2(x, 0), - State = ColumnState.Dimmed, - }); - } + IHasEndTime end = h as IHasEndTime; - columns = newColumns.ToArray(); - Children = columns; - - recalculateValues(); - redrawFilled(); - redrawProgress(); - } - - public class Column : Container, IStateful - { - private readonly Color4 emptyColour = Color4.White.Opacity(100); - private readonly Color4 litColour; - private readonly Color4 dimmedColour = Color4.White.Opacity(175); - - private const float cube_count = 6; - private const float cube_size = 4; - private const float padding = 2; - public const float WIDTH = cube_size + padding; - public const float HEIGHT = cube_count * WIDTH + padding; - - private readonly List drawableRows = new List(); - - private int filled; - public int Filled - { - get { return filled; } - set - { - if (value == filled) return; - filled = value; - - fillActive(); - } - } - - private ColumnState state; - public ColumnState State - { - get { return state; } - set - { - if (value == state) return; - state = value; - - fillActive(); - } - } - - public Column(Color4 litColour) - { - Size = new Vector2(WIDTH, HEIGHT); - this.litColour = litColour; - - for (int r = 0; r < cube_count; r++) - { - drawableRows.Add(new Box - { - EdgeSmoothness = new Vector2(padding / 4), - Size = new Vector2(cube_size), - Position = new Vector2(0, r * WIDTH + padding), - }); + int startRange = (int)(h.StartTime / interval); + int endRange = (int)((end?.EndTime ?? h.StartTime) / interval); + for (int i = startRange; i <= endRange; i++) + values[i]++; } - Children = drawableRows; - - // Reverse drawableRows so when iterating through them they start at the bottom - drawableRows.Reverse(); + Values = values; } - - private void fillActive() - { - Color4 colour = State == ColumnState.Lit ? litColour : dimmedColour; - - for (int i = 0; i < drawableRows.Count; i++) - { - if (Filled == 0) // i <= Filled doesn't work for zero fill - drawableRows[i].Colour = emptyColour; - else - drawableRows[i].Colour = i <= Filled ? colour : emptyColour; - } - } - } - - public enum ColumnState - { - Lit, - Dimmed } } } diff --git a/osu.Game/Screens/Play/SquareGraph.cs b/osu.Game/Screens/Play/SquareGraph.cs new file mode 100644 index 0000000000..9afb1e063a --- /dev/null +++ b/osu.Game/Screens/Play/SquareGraph.cs @@ -0,0 +1,235 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using System.Linq; +using osu.Framework; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Screens.Play +{ + public class SquareGraph : BufferedContainer + { + private Column[] columns = { }; + + public int ColumnCount => columns.Length; + + public override bool HandleInput => false; + + private int progress; + public int Progress + { + get { return progress; } + set + { + if (value == progress) return; + progress = value; + + redrawProgress(); + } + } + + private int[] calculatedValues = { }; // values but adjusted to fit the amount of columns + private int[] values; + public int[] Values + { + get { return values; } + set + { + if (value == values) return; + values = value; + recreateGraph(); + } + } + + private Color4 fillColour; + public Color4 FillColour + { + get { return fillColour; } + set + { + if (value == fillColour) return; + fillColour = value; + + redrawFilled(); + } + } + + public SquareGraph() + { + CacheDrawnFrameBuffer = true; + PixelSnapping = true; + } + + private float lastDrawWidth; + protected override void Update() + { + base.Update(); + + // todo: Recreating in update is probably not the best idea + if (DrawWidth == lastDrawWidth) return; + recreateGraph(); + lastDrawWidth = DrawWidth; + } + + /// + /// Redraws all the columns to match their lit/dimmed state. + /// + private void redrawProgress() + { + for (int i = 0; i < columns.Length; i++) + { + columns[i].State = i <= progress ? ColumnState.Lit : ColumnState.Dimmed; + } + + ForceRedraw(); + } + + /// + /// Redraws the filled amount of all the columns. + /// + private void redrawFilled() + { + for (int i = 0; i < ColumnCount; i++) + { + columns[i].Filled = calculatedValues.ElementAtOrDefault(i); + } + } + + /// + /// Takes and adjusts it to fit the amount of columns. + /// + private void recalculateValues() + { + var newValues = new List(); + + if (values == null) + { + for (float i = 0; i < ColumnCount; i++) + newValues.Add(0); + + return; + } + + float step = values.Length / (float)ColumnCount; + for (float i = 0; i < values.Length; i += step) + { + newValues.Add(values[(int)i]); + } + + calculatedValues = newValues.ToArray(); + } + + /// + /// Recreates the entire graph. + /// + private void recreateGraph() + { + var newColumns = new List(); + + for (float x = 0; x < DrawWidth; x += Column.WIDTH) + { + newColumns.Add(new Column(fillColour) + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Position = new Vector2(x, 0), + State = ColumnState.Dimmed, + }); + } + + columns = newColumns.ToArray(); + Children = columns; + + recalculateValues(); + redrawFilled(); + redrawProgress(); + } + + public class Column : Container, IStateful + { + private readonly Color4 emptyColour = Color4.White.Opacity(100); + private readonly Color4 litColour; + private readonly Color4 dimmedColour = Color4.White.Opacity(175); + + private const float cube_count = 6; + private const float cube_size = 4; + private const float padding = 2; + public const float WIDTH = cube_size + padding; + public const float HEIGHT = cube_count * WIDTH + padding; + + private readonly List drawableRows = new List(); + + private int filled; + public int Filled + { + get { return filled; } + set + { + if (value == filled) return; + filled = value; + + fillActive(); + } + } + + private ColumnState state; + public ColumnState State + { + get { return state; } + set + { + if (value == state) return; + state = value; + + fillActive(); + } + } + + public Column(Color4 litColour) + { + Size = new Vector2(WIDTH, HEIGHT); + this.litColour = litColour; + + for (int r = 0; r < cube_count; r++) + { + drawableRows.Add(new Box + { + EdgeSmoothness = new Vector2(padding / 4), + Size = new Vector2(cube_size), + Position = new Vector2(0, r * WIDTH + padding), + }); + } + + Children = drawableRows; + + // Reverse drawableRows so when iterating through them they start at the bottom + drawableRows.Reverse(); + } + + private void fillActive() + { + Color4 colour = State == ColumnState.Lit ? litColour : dimmedColour; + + for (int i = 0; i < drawableRows.Count; i++) + { + if (Filled == 0) // i <= Filled doesn't work for zero fill + drawableRows[i].Colour = emptyColour; + else + drawableRows[i].Colour = i <= Filled ? colour : emptyColour; + } + } + } + + public enum ColumnState + { + Lit, + Dimmed + } + } +} \ No newline at end of file diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 5096323540..8421f89058 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -201,6 +201,7 @@ +