1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 20:07:29 +08:00
osu-lazer/osu.Game/Graphics/UserInterface/BarGraph.cs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

265 lines
8.4 KiB
C#
Raw Normal View History

// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
2018-04-13 17:19:50 +08:00
2022-06-17 15:37:17 +08:00
#nullable disable
2018-11-20 15:51:59 +08:00
using osuTK;
2017-03-26 06:33:03 +08:00
using osu.Framework.Graphics;
using System.Collections.Generic;
using System.Linq;
2022-11-19 05:19:49 +08:00
using osu.Framework.Graphics.Rendering;
using osu.Framework.Graphics.Shaders;
using osu.Framework.Allocation;
using osu.Framework.Graphics.Textures;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Utils;
using System;
2018-04-13 17:19:50 +08:00
namespace osu.Game.Graphics.UserInterface
2017-03-26 06:33:03 +08:00
{
2022-11-19 05:19:49 +08:00
public class BarGraph : Drawable
{
2022-11-19 05:19:49 +08:00
private const int resize_duration = 250;
private const Easing easing = Easing.InOutCubic;
2017-04-10 22:42:23 +08:00
/// <summary>
/// Manually sets the max value, if null <see cref="Enumerable.Max(IEnumerable{float})"/> is instead used
/// </summary>
public float? MaxValue { get; set; }
2018-04-13 17:19:50 +08:00
2017-04-04 23:17:22 +08:00
private BarDirection direction = BarDirection.BottomToTop;
2019-02-28 12:31:40 +08:00
2022-11-19 05:19:49 +08:00
public BarDirection Direction
2017-04-04 23:17:22 +08:00
{
get => direction;
2017-04-04 23:17:22 +08:00
set
{
2022-11-19 05:19:49 +08:00
if (direction == value)
return;
2019-04-01 11:16:05 +08:00
2022-11-19 05:19:49 +08:00
direction = value;
Invalidate(Invalidation.DrawNode);
2017-04-04 23:17:22 +08:00
}
}
2018-04-13 17:19:50 +08:00
2022-11-20 10:14:07 +08:00
private readonly BarsInfo bars = new BarsInfo();
2022-11-19 05:19:49 +08:00
2017-04-10 22:42:23 +08:00
/// <summary>
/// A list of floats that defines the length of each <see cref="Bar"/>
/// </summary>
public IEnumerable<float> Values
{
set
{
2022-11-20 04:27:48 +08:00
if (!value.Any())
{
bars.Clear();
Invalidate(Invalidation.DrawNode);
return;
}
2022-11-19 05:19:49 +08:00
int newCount = value.Count();
2019-04-01 11:16:05 +08:00
2022-11-20 10:14:07 +08:00
bars.Breadth = 1.0f / newCount;
2022-11-19 05:19:49 +08:00
2022-11-20 04:27:48 +08:00
float maxLength = MaxValue ?? value.Max();
2022-11-19 15:16:58 +08:00
2022-11-20 04:29:50 +08:00
foreach (var bar in value.Select((length, index) => (Value: length, Index: index)))
{
2022-11-19 15:16:58 +08:00
float length = maxLength == 0 ? 0 : Math.Max(0f, bar.Value / maxLength);
2018-04-13 17:19:50 +08:00
2022-11-19 15:16:58 +08:00
if (bar.Index < bars.Count)
{
2022-11-20 06:20:57 +08:00
bars.UpdateLength(bar.Index, length);
2022-11-20 04:40:02 +08:00
continue;
}
2022-11-20 04:40:02 +08:00
2022-11-20 06:20:57 +08:00
bars.AddBar(length);
}
2019-02-28 12:31:40 +08:00
2022-11-19 15:16:58 +08:00
if (bars.Count > newCount)
bars.RemoveRange(newCount, bars.Count - newCount);
2022-11-19 05:19:49 +08:00
animationStartTime = Clock.CurrentTime;
animationComplete = false;
}
}
private double animationStartTime;
private bool animationComplete;
private IShader shader = null!;
private Texture texture = null!;
[BackgroundDependencyLoader]
private void load(IRenderer renderer, ShaderManager shaders)
{
texture = renderer.WhitePixel;
shader = shaders.Load(VertexShaderDescriptor.TEXTURE_2, FragmentShaderDescriptor.TEXTURE);
}
protected override void Update()
{
base.Update();
2022-11-20 06:20:57 +08:00
if (!bars.Any)
2022-11-19 05:19:49 +08:00
return;
double currentTime = Clock.CurrentTime;
if (currentTime < animationStartTime + resize_duration)
{
2022-11-20 06:20:57 +08:00
bars.Animate(animationStartTime, currentTime);
2022-11-19 05:19:49 +08:00
Invalidate(Invalidation.DrawNode);
}
else if (!animationComplete)
{
2022-11-20 06:20:57 +08:00
bars.FinishAnimation();
2022-11-19 05:19:49 +08:00
Invalidate(Invalidation.DrawNode);
animationComplete = true;
}
}
protected override DrawNode CreateDrawNode() => new BarGraphDrawNode(this);
private class BarGraphDrawNode : DrawNode
{
public new BarGraph Source => (BarGraph)base.Source;
public BarGraphDrawNode(BarGraph source)
: base(source)
{
}
private IShader shader = null!;
private Texture texture = null!;
private Vector2 drawSize;
private BarDirection direction;
2022-11-20 04:40:02 +08:00
private float barBreadth;
2022-11-20 10:14:07 +08:00
private readonly List<float> lengths = new List<float>();
2022-11-19 05:19:49 +08:00
public override void ApplyState()
{
base.ApplyState();
shader = Source.shader;
texture = Source.texture;
drawSize = Source.DrawSize;
direction = Source.direction;
2022-11-20 10:14:07 +08:00
barBreadth = Source.bars.Breadth;
lengths.Clear();
lengths.AddRange(Source.bars.InstantaneousLengths);
2022-11-19 05:19:49 +08:00
}
public override void Draw(IRenderer renderer)
{
base.Draw(renderer);
shader.Bind();
2022-11-20 10:14:07 +08:00
for (int i = 0; i < lengths.Count; i++)
2022-11-19 05:19:49 +08:00
{
2022-11-20 10:14:07 +08:00
float barHeight = drawSize.Y * ((direction == BarDirection.TopToBottom || direction == BarDirection.BottomToTop) ? lengths[i] : barBreadth);
float barWidth = drawSize.X * ((direction == BarDirection.LeftToRight || direction == BarDirection.RightToLeft) ? lengths[i] : barBreadth);
2022-11-19 05:19:49 +08:00
Vector2 topLeft;
switch (direction)
{
default:
case BarDirection.LeftToRight:
topLeft = new Vector2(0, i * barHeight);
break;
case BarDirection.RightToLeft:
topLeft = new Vector2(drawSize.X - barWidth, i * barHeight);
break;
case BarDirection.TopToBottom:
topLeft = new Vector2(i * barWidth, 0);
break;
case BarDirection.BottomToTop:
topLeft = new Vector2(i * barWidth, drawSize.Y - barHeight);
break;
}
2022-11-20 06:20:57 +08:00
renderer.DrawQuad(
texture,
new Quad(
Vector2Extensions.Transform(topLeft, DrawInfo.Matrix),
Vector2Extensions.Transform(topLeft + new Vector2(barWidth, 0), DrawInfo.Matrix),
Vector2Extensions.Transform(topLeft + new Vector2(0, barHeight), DrawInfo.Matrix),
Vector2Extensions.Transform(topLeft + new Vector2(barWidth, barHeight), DrawInfo.Matrix)
),
DrawColourInfo.Colour);
2022-11-19 05:19:49 +08:00
}
shader.Unbind();
}
}
2022-11-19 05:19:49 +08:00
2022-11-20 10:14:07 +08:00
private class BarsInfo
2022-11-19 05:19:49 +08:00
{
2022-11-20 10:14:07 +08:00
public bool Any => Count > 0;
2022-11-20 06:20:57 +08:00
2022-11-20 10:14:07 +08:00
public int Count { get; private set; }
2022-11-20 06:20:57 +08:00
2022-11-20 10:14:07 +08:00
public float Breadth { get; set; }
2022-11-20 06:20:57 +08:00
2022-11-20 10:14:07 +08:00
public List<float> InstantaneousLengths { get; } = new List<float>();
2022-11-20 06:20:57 +08:00
2022-11-20 10:14:07 +08:00
private readonly List<float> initialLengths = new List<float>();
private readonly List<float> finalLengths = new List<float>();
2022-11-20 06:20:57 +08:00
public void UpdateLength(int index, float newLength)
{
initialLengths[index] = finalLengths[index];
finalLengths[index] = newLength;
}
public void AddBar(float finalLength)
{
initialLengths.Add(0);
finalLengths.Add(finalLength);
2022-11-20 10:14:07 +08:00
InstantaneousLengths.Add(0);
Count++;
2022-11-20 06:20:57 +08:00
}
public void Clear()
{
initialLengths.Clear();
finalLengths.Clear();
2022-11-20 10:14:07 +08:00
InstantaneousLengths.Clear();
Count = 0;
2022-11-20 06:20:57 +08:00
}
public void RemoveRange(int index, int count)
{
initialLengths.RemoveRange(index, count);
finalLengths.RemoveRange(index, count);
2022-11-20 10:14:07 +08:00
InstantaneousLengths.RemoveRange(index, count);
Count -= count;
2022-11-20 06:20:57 +08:00
}
public void Animate(double animationStartTime, double currentTime)
{
for (int i = 0; i < Count; i++)
2022-11-20 10:14:07 +08:00
InstantaneousLengths[i] = Interpolation.ValueAt(currentTime, initialLengths[i], finalLengths[i], animationStartTime, animationStartTime + resize_duration, easing);
2022-11-20 06:20:57 +08:00
}
public void FinishAnimation()
{
for (int i = 0; i < Count; i++)
2022-11-20 10:14:07 +08:00
InstantaneousLengths[i] = finalLengths[i];
2022-11-20 06:20:57 +08:00
}
2022-11-19 05:19:49 +08:00
}
}
2018-01-05 19:21:19 +08:00
}