mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-12-25 01:39:23 +01:00
Added UiMetrics
This commit is contained in:
parent
55fae16768
commit
60dfbb1ec5
5 changed files with 164 additions and 8 deletions
|
@ -38,6 +38,7 @@ Additions
|
|||
- Added a multiline editing mode to TextField
|
||||
- Added a formatting code to allow for inline font changes
|
||||
- Added a SquishingGroup element
|
||||
- Added UiMetrics
|
||||
|
||||
Improvements
|
||||
- **Made Image ScaleToImage take ui scale into account**
|
||||
|
|
|
@ -18,6 +18,8 @@ namespace Demos {
|
|||
private double fpsTime;
|
||||
private int lastFps;
|
||||
private int fpsCounter;
|
||||
private UiMetrics cumulativeMetrics;
|
||||
private TimeSpan secondCounter;
|
||||
|
||||
static GameImpl() {
|
||||
Demos.Add("Ui", ("An in-depth demonstration of the MLEM.Ui package and its abilities", game => new UiDemo(game)));
|
||||
|
@ -29,6 +31,16 @@ namespace Demos {
|
|||
|
||||
public GameImpl() {
|
||||
this.IsMouseVisible = true;
|
||||
// print out ui metrics every second
|
||||
this.OnDraw += (g, time) => {
|
||||
this.cumulativeMetrics += this.UiSystem.Metrics;
|
||||
this.secondCounter += time.ElapsedGameTime;
|
||||
if (this.secondCounter.TotalSeconds >= 1) {
|
||||
this.secondCounter -= TimeSpan.FromSeconds(1);
|
||||
Console.WriteLine($"Metrics/s: {this.cumulativeMetrics}");
|
||||
this.cumulativeMetrics = new UiMetrics();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadContent() {
|
||||
|
|
|
@ -546,6 +546,7 @@ namespace MLEM.Ui.Elements {
|
|||
// which would cause our ForceUpdateArea code to be run twice, so we only update our parent instead
|
||||
if (this.Parent != null && this.Parent.UpdateAreaIfDirty())
|
||||
return;
|
||||
this.System.Stopwatch.Restart();
|
||||
|
||||
var parentArea = this.Parent != null ? this.Parent.ChildPaddedArea : (RectangleF) this.system.Viewport;
|
||||
var parentCenterX = parentArea.X + parentArea.Width / 2;
|
||||
|
@ -555,6 +556,10 @@ namespace MLEM.Ui.Elements {
|
|||
var recursion = 0;
|
||||
UpdateDisplayArea(actualSize);
|
||||
|
||||
this.System.Stopwatch.Stop();
|
||||
this.System.Metrics.ForceAreaUpdateTime += this.System.Stopwatch.Elapsed;
|
||||
this.System.Metrics.ForceAreaUpdates++;
|
||||
|
||||
void UpdateDisplayArea(Vector2 newSize) {
|
||||
var pos = new Vector2();
|
||||
switch (this.anchor) {
|
||||
|
@ -706,6 +711,7 @@ namespace MLEM.Ui.Elements {
|
|||
this.System.InvokeOnElementAreaUpdated(this);
|
||||
foreach (var child in this.Children)
|
||||
child.ForceUpdateArea();
|
||||
this.System.Metrics.ActualAreaUpdates++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -885,6 +891,8 @@ namespace MLEM.Ui.Elements {
|
|||
foreach (var child in this.GetRelevantChildren())
|
||||
if (child.System != null)
|
||||
child.Update(time);
|
||||
|
||||
this.System.Metrics.Updates++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -914,6 +922,7 @@ namespace MLEM.Ui.Elements {
|
|||
}
|
||||
// draw content in custom begin call
|
||||
this.Draw(time, batch, alpha, blendState, samplerState, depthStencilState, effect, mat);
|
||||
this.System.Metrics.Draws++;
|
||||
if (customDraw) {
|
||||
// end our draw
|
||||
batch.End();
|
||||
|
|
107
MLEM.Ui/UiMetrics.cs
Normal file
107
MLEM.Ui/UiMetrics.cs
Normal file
|
@ -0,0 +1,107 @@
|
|||
using System;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MLEM.Ui.Elements;
|
||||
|
||||
namespace MLEM.Ui {
|
||||
/// <summary>
|
||||
/// A snapshot of update and rendering statistics from <see cref="UiSystem.Metrics"/> to be used for runtime debugging and profiling.
|
||||
/// This metrics struct works similarly to <see cref="GraphicsMetrics"/>.
|
||||
/// </summary>
|
||||
public struct UiMetrics {
|
||||
|
||||
/// <summary>
|
||||
/// The amount of time that <see cref="Element.ForceUpdateArea"/> took.
|
||||
/// Can be divided by <see cref="ForceAreaUpdates"/> to get an average per area update.
|
||||
/// </summary>
|
||||
public TimeSpan ForceAreaUpdateTime { get; internal set; }
|
||||
/// <summary>
|
||||
/// The amount of time that <see cref="Element.Update"/> took.
|
||||
/// Can be divided by <see cref="Updates"/> to get an average per update.
|
||||
/// </summary>
|
||||
public TimeSpan UpdateTime { get; internal set; }
|
||||
/// <summary>
|
||||
/// The amount of times that <see cref="Element.ForceUpdateArea"/> was called.
|
||||
/// </summary>
|
||||
public uint ForceAreaUpdates { get; internal set; }
|
||||
/// <summary>
|
||||
/// The amount of times that <see cref="Element.SetAreaAndUpdateChildren"/> was called.
|
||||
/// </summary>
|
||||
public uint ActualAreaUpdates { get; internal set; }
|
||||
/// <summary>
|
||||
/// The amount of times that <see cref="Element.Update"/> was called.
|
||||
/// </summary>
|
||||
public uint Updates { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// The amount of time that <see cref="Element.Draw"/> took.
|
||||
/// Can be divided by <see cref="Draws"/> to get an average per draw.
|
||||
/// </summary>
|
||||
public TimeSpan DrawTime { get; internal set; }
|
||||
/// <summary>
|
||||
/// The amount of times that <see cref="Element.Draw"/> was called.
|
||||
/// </summary>
|
||||
public uint Draws { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Resets all update-related metrics to 0.
|
||||
/// </summary>
|
||||
public void ResetUpdates() {
|
||||
this.ForceAreaUpdateTime = TimeSpan.Zero;
|
||||
this.UpdateTime = TimeSpan.Zero;
|
||||
this.ForceAreaUpdates = 0;
|
||||
this.ActualAreaUpdates = 0;
|
||||
this.Updates = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets all rendering-related metrics to 0.
|
||||
/// </summary>
|
||||
public void ResetDraws() {
|
||||
this.DrawTime = TimeSpan.Zero;
|
||||
this.Draws = 0;
|
||||
}
|
||||
|
||||
/// <summary>Returns the fully qualified type name of this instance.</summary>
|
||||
/// <returns>The fully qualified type name.</returns>
|
||||
public override string ToString() {
|
||||
return $"{nameof(this.ForceAreaUpdateTime)}: {this.ForceAreaUpdateTime}, {nameof(this.UpdateTime)}: {this.UpdateTime}, {nameof(this.ForceAreaUpdates)}: {this.ForceAreaUpdates}, {nameof(this.ActualAreaUpdates)}: {this.ActualAreaUpdates}, {nameof(this.Updates)}: {this.Updates}, {nameof(this.DrawTime)}: {this.DrawTime}, {nameof(this.Draws)}: {this.Draws}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds two ui metrics together, causing all of their values to be combined.
|
||||
/// </summary>
|
||||
/// <param name="left">The left metrics</param>
|
||||
/// <param name="right">The right metrics</param>
|
||||
/// <returns>The sum of both metrics</returns>
|
||||
public static UiMetrics operator +(UiMetrics left, UiMetrics right) {
|
||||
return new UiMetrics {
|
||||
ForceAreaUpdateTime = left.ForceAreaUpdateTime + right.ForceAreaUpdateTime,
|
||||
UpdateTime = left.UpdateTime + right.UpdateTime,
|
||||
ForceAreaUpdates = left.ForceAreaUpdates + right.ForceAreaUpdates,
|
||||
ActualAreaUpdates = left.ActualAreaUpdates + right.ActualAreaUpdates,
|
||||
Updates = left.Updates + right.Updates,
|
||||
DrawTime = left.DrawTime + right.DrawTime,
|
||||
Draws = left.Draws + right.Draws
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Subtracts two ui metrics from each other, causing their values to be subtracted.
|
||||
/// </summary>
|
||||
/// <param name="left">The left metrics</param>
|
||||
/// <param name="right">The right metrics</param>
|
||||
/// <returns>The difference of both metrics</returns>
|
||||
public static UiMetrics operator -(UiMetrics left, UiMetrics right) {
|
||||
return new UiMetrics {
|
||||
ForceAreaUpdateTime = left.ForceAreaUpdateTime - right.ForceAreaUpdateTime,
|
||||
UpdateTime = left.UpdateTime - right.UpdateTime,
|
||||
ForceAreaUpdates = left.ForceAreaUpdates - right.ForceAreaUpdates,
|
||||
ActualAreaUpdates = left.ActualAreaUpdates - right.ActualAreaUpdates,
|
||||
Updates = left.Updates - right.Updates,
|
||||
DrawTime = left.DrawTime - right.DrawTime,
|
||||
Draws = left.Draws - right.Draws
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
@ -20,8 +21,6 @@ namespace MLEM.Ui {
|
|||
/// </summary>
|
||||
public class UiSystem : GameComponent {
|
||||
|
||||
private readonly List<RootElement> rootElements = new List<RootElement>();
|
||||
|
||||
/// <summary>
|
||||
/// The viewport that this ui system is rendering inside of.
|
||||
/// This is automatically updated during <see cref="GameWindow.ClientSizeChanged"/>
|
||||
|
@ -36,7 +35,6 @@ namespace MLEM.Ui {
|
|||
/// If <see cref="AutoScaleWithScreen"/> is true, this is used as the screen size that uses the default <see cref="GlobalScale"/>
|
||||
/// </summary>
|
||||
public Point AutoScaleReferenceSize;
|
||||
private float globalScale = 1;
|
||||
/// <summary>
|
||||
/// The global rendering scale of this ui system and all of its child elements.
|
||||
/// If <see cref="AutoScaleWithScreen"/> is true, this scale will be different based on the window size.
|
||||
|
@ -53,8 +51,6 @@ namespace MLEM.Ui {
|
|||
root.Element.ForceUpdateArea();
|
||||
}
|
||||
}
|
||||
|
||||
private UiStyle style;
|
||||
/// <summary>
|
||||
/// The style options that this ui system and all of its elements use.
|
||||
/// To set the default, untextured style, use <see cref="UntexturedStyle"/>.
|
||||
|
@ -102,6 +98,11 @@ namespace MLEM.Ui {
|
|||
/// The ui controls are also the place to change bindings for controller and keyboard input.
|
||||
/// </summary>
|
||||
public UiControls Controls;
|
||||
/// <summary>
|
||||
/// The update and rendering statistics to be used for runtime debugging and profiling.
|
||||
/// The metrics are reset accordingly every frame: <see cref="UiMetrics.ResetUpdates"/> is called at the start of <see cref="Update"/>, and <see cref="UiMetrics.ResetDraws"/> is called at the start of <see cref="DrawEarly"/>, or at the start of <see cref="Draw"/> if <see cref="DrawEarly"/> was not called.
|
||||
/// </summary>
|
||||
public UiMetrics Metrics;
|
||||
|
||||
/// <summary>
|
||||
/// Event that is invoked after an <see cref="Element"/> is drawn, but before its children are drawn.
|
||||
|
@ -172,6 +173,13 @@ namespace MLEM.Ui {
|
|||
/// </summary>
|
||||
public event RootCallback OnRootRemoved;
|
||||
|
||||
internal readonly Stopwatch Stopwatch = new Stopwatch();
|
||||
|
||||
private readonly List<RootElement> rootElements = new List<RootElement>();
|
||||
private float globalScale = 1;
|
||||
private bool drewEarly;
|
||||
private UiStyle style;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new ui system with the given settings.
|
||||
/// </summary>
|
||||
|
@ -232,11 +240,15 @@ namespace MLEM.Ui {
|
|||
/// </summary>
|
||||
/// <param name="time">The game's time</param>
|
||||
public override void Update(GameTime time) {
|
||||
this.Controls.Update();
|
||||
this.Metrics.ResetUpdates();
|
||||
this.Stopwatch.Restart();
|
||||
|
||||
for (var i = this.rootElements.Count - 1; i >= 0; i--) {
|
||||
this.Controls.Update();
|
||||
for (var i = this.rootElements.Count - 1; i >= 0; i--)
|
||||
this.rootElements[i].Element.Update(time);
|
||||
}
|
||||
|
||||
this.Stopwatch.Stop();
|
||||
this.Metrics.UpdateTime += this.Stopwatch.Elapsed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -246,10 +258,17 @@ namespace MLEM.Ui {
|
|||
/// <param name="time">The game's time</param>
|
||||
/// <param name="batch">The sprite batch to use for drawing</param>
|
||||
public void DrawEarly(GameTime time, SpriteBatch batch) {
|
||||
this.Metrics.ResetDraws();
|
||||
this.Stopwatch.Restart();
|
||||
|
||||
foreach (var root in this.rootElements) {
|
||||
if (!root.Element.IsHidden)
|
||||
root.Element.DrawEarly(time, batch, this.DrawAlpha * root.Element.DrawAlpha, this.BlendState, this.SamplerState, this.DepthStencilState, this.Effect, root.Transform);
|
||||
}
|
||||
|
||||
this.Stopwatch.Stop();
|
||||
this.Metrics.DrawTime += this.Stopwatch.Elapsed;
|
||||
this.drewEarly = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -259,6 +278,10 @@ namespace MLEM.Ui {
|
|||
/// <param name="time">The game's time</param>
|
||||
/// <param name="batch">The sprite batch to use for drawing</param>
|
||||
public void Draw(GameTime time, SpriteBatch batch) {
|
||||
if (!this.drewEarly)
|
||||
this.Metrics.ResetDraws();
|
||||
this.Stopwatch.Restart();
|
||||
|
||||
foreach (var root in this.rootElements) {
|
||||
if (root.Element.IsHidden)
|
||||
continue;
|
||||
|
@ -267,6 +290,10 @@ namespace MLEM.Ui {
|
|||
root.Element.DrawTransformed(time, batch, alpha, this.BlendState, this.SamplerState, this.DepthStencilState, this.Effect, root.Transform);
|
||||
batch.End();
|
||||
}
|
||||
|
||||
this.Stopwatch.Stop();
|
||||
this.Metrics.DrawTime += this.Stopwatch.Elapsed;
|
||||
this.drewEarly = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
Loading…
Reference in a new issue