mirror of
https://github.com/ppy/osu.git
synced 2024-11-06 06:57:39 +08:00
Rework BarGraph to use Quads
This commit is contained in:
parent
e4fc14faee
commit
e8ca9f5dc5
@ -109,15 +109,11 @@ namespace osu.Game.Graphics.UserInterface
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum BarDirection
|
||||
{
|
||||
LeftToRight = 1,
|
||||
RightToLeft = 1 << 1,
|
||||
TopToBottom = 1 << 2,
|
||||
BottomToTop = 1 << 3,
|
||||
|
||||
Vertical = TopToBottom | BottomToTop,
|
||||
Horizontal = LeftToRight | RightToLeft,
|
||||
LeftToRight,
|
||||
RightToLeft,
|
||||
TopToBottom,
|
||||
BottomToTop
|
||||
}
|
||||
}
|
||||
|
@ -5,15 +5,23 @@
|
||||
|
||||
using osuTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions.EnumExtensions;
|
||||
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;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public class BarGraph : FillFlowContainer<Bar>
|
||||
public class BarGraph : Drawable
|
||||
{
|
||||
private const int resize_duration = 250;
|
||||
private const Easing easing = Easing.InOutCubic;
|
||||
|
||||
/// <summary>
|
||||
/// Manually sets the max value, if null <see cref="Enumerable.Max(IEnumerable{float})"/> is instead used
|
||||
/// </summary>
|
||||
@ -21,22 +29,21 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
private BarDirection direction = BarDirection.BottomToTop;
|
||||
|
||||
public new BarDirection Direction
|
||||
public BarDirection Direction
|
||||
{
|
||||
get => direction;
|
||||
set
|
||||
{
|
||||
direction = value;
|
||||
base.Direction = direction.HasFlagFast(BarDirection.Horizontal) ? FillDirection.Vertical : FillDirection.Horizontal;
|
||||
if (direction == value)
|
||||
return;
|
||||
|
||||
foreach (var bar in Children)
|
||||
{
|
||||
bar.Size = direction.HasFlagFast(BarDirection.Horizontal) ? new Vector2(1, 1.0f / Children.Count) : new Vector2(1.0f / Children.Count, 1);
|
||||
bar.Direction = direction;
|
||||
}
|
||||
direction = value;
|
||||
Invalidate(Invalidation.DrawNode);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<BarDescriptor> bars;
|
||||
|
||||
/// <summary>
|
||||
/// A list of floats that defines the length of each <see cref="Bar"/>
|
||||
/// </summary>
|
||||
@ -44,38 +51,188 @@ namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
set
|
||||
{
|
||||
List<Bar> bars = Children.ToList();
|
||||
List<BarDescriptor> newBars = bars?.ToList() ?? new List<BarDescriptor>();
|
||||
|
||||
foreach (var bar in value.Select((length, index) => new { Value = length, Bar = bars.Count > index ? bars[index] : null }))
|
||||
int newCount = value.Count();
|
||||
|
||||
float size = newCount;
|
||||
if (size != 0)
|
||||
size = 1.0f / size;
|
||||
|
||||
foreach (var bar in value.Select((length, index) => new { Value = length, Bar = newBars.Count > index ? newBars[index] : null }))
|
||||
{
|
||||
float length = MaxValue ?? value.Max();
|
||||
if (length != 0)
|
||||
length = bar.Value / length;
|
||||
|
||||
float size = value.Count();
|
||||
if (size != 0)
|
||||
size = 1.0f / size;
|
||||
length = Math.Max(0f, bar.Value / length);
|
||||
|
||||
if (bar.Bar != null)
|
||||
{
|
||||
bar.Bar.Length = length;
|
||||
bar.Bar.Size = direction.HasFlagFast(BarDirection.Horizontal) ? new Vector2(1, size) : new Vector2(size, 1);
|
||||
bar.Bar.OldValue = bar.Bar.Value;
|
||||
|
||||
bar.Bar.Value = length;
|
||||
bar.Bar.ShortSide = size;
|
||||
}
|
||||
else
|
||||
{
|
||||
Add(new Bar
|
||||
newBars.Add(new BarDescriptor
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Size = direction.HasFlagFast(BarDirection.Horizontal) ? new Vector2(1, size) : new Vector2(size, 1),
|
||||
Length = length,
|
||||
Direction = Direction,
|
||||
Value = length,
|
||||
ShortSide = size
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//I'm using ToList() here because Where() returns an Enumerable which can change it's elements afterwards
|
||||
RemoveRange(Children.Where((_, index) => index >= value.Count()).ToList(), true);
|
||||
if (newBars.Count > newCount)
|
||||
newBars.RemoveRange(newCount, newBars.Count - newCount);
|
||||
|
||||
bars = newBars;
|
||||
|
||||
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();
|
||||
|
||||
if (noBars)
|
||||
return;
|
||||
|
||||
double currentTime = Clock.CurrentTime;
|
||||
|
||||
if (currentTime < animationStartTime + resize_duration)
|
||||
{
|
||||
foreach (var bar in bars)
|
||||
bar.IntermediateValue = Interpolation.ValueAt(currentTime, bar.OldValue, bar.Value, animationStartTime, animationStartTime + resize_duration, easing);
|
||||
|
||||
Invalidate(Invalidation.DrawNode);
|
||||
return;
|
||||
}
|
||||
else if (!animationComplete)
|
||||
{
|
||||
foreach (var bar in bars)
|
||||
bar.IntermediateValue = bar.Value;
|
||||
|
||||
Invalidate(Invalidation.DrawNode);
|
||||
|
||||
animationComplete = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private bool noBars => bars?.Any() != 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;
|
||||
|
||||
private readonly List<BarDescriptor> bars = new List<BarDescriptor>();
|
||||
|
||||
public override void ApplyState()
|
||||
{
|
||||
base.ApplyState();
|
||||
|
||||
shader = Source.shader;
|
||||
texture = Source.texture;
|
||||
drawSize = Source.DrawSize;
|
||||
direction = Source.direction;
|
||||
|
||||
bars.Clear();
|
||||
|
||||
if (Source.noBars)
|
||||
return;
|
||||
|
||||
bars.AddRange(Source.bars);
|
||||
}
|
||||
|
||||
public override void Draw(IRenderer renderer)
|
||||
{
|
||||
base.Draw(renderer);
|
||||
|
||||
if (!bars.Any())
|
||||
return;
|
||||
|
||||
shader.Bind();
|
||||
|
||||
for (int i = 0; i < bars.Count; i++)
|
||||
{
|
||||
var bar = bars[i];
|
||||
|
||||
float barHeight = drawSize.Y * ((direction == BarDirection.TopToBottom || direction == BarDirection.BottomToTop) ? bar.IntermediateValue : bar.ShortSide);
|
||||
float barWidth = drawSize.X * ((direction == BarDirection.LeftToRight || direction == BarDirection.RightToLeft) ? bar.IntermediateValue : bar.ShortSide);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Vector2 topRight = topLeft + new Vector2(barWidth, 0);
|
||||
Vector2 bottomLeft = topLeft + new Vector2(0, barHeight);
|
||||
Vector2 bottomRight = bottomLeft + new Vector2(barWidth, 0);
|
||||
|
||||
var drawQuad = new Quad(
|
||||
Vector2Extensions.Transform(topLeft, DrawInfo.Matrix),
|
||||
Vector2Extensions.Transform(topRight, DrawInfo.Matrix),
|
||||
Vector2Extensions.Transform(bottomLeft, DrawInfo.Matrix),
|
||||
Vector2Extensions.Transform(bottomRight, DrawInfo.Matrix)
|
||||
);
|
||||
|
||||
renderer.DrawQuad(texture, drawQuad, DrawColourInfo.Colour);
|
||||
}
|
||||
|
||||
shader.Unbind();
|
||||
}
|
||||
}
|
||||
|
||||
private class BarDescriptor
|
||||
{
|
||||
public float OldValue { get; set; }
|
||||
public float Value { get; set; }
|
||||
public float IntermediateValue { get; set; }
|
||||
public float ShortSide { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user