A game framework written with osu! in mind.
at master 129 lines 4.0 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using osu.Framework.Graphics.Containers; 6using osu.Framework.Graphics.Shapes; 7using osu.Framework.Graphics.Sprites; 8using osu.Framework.Statistics; 9using osu.Framework.Timing; 10using osu.Framework.Utils; 11using osuTK; 12using osuTK.Graphics; 13 14namespace osu.Framework.Graphics.Performance 15{ 16 internal class FrameTimeDisplay : Container 17 { 18 private readonly SpriteText counter; 19 20 private readonly ThrottledFrameClock clock; 21 22 public bool Counting = true; 23 24 public FrameTimeDisplay(ThrottledFrameClock clock) 25 { 26 this.clock = clock; 27 28 Masking = true; 29 CornerRadius = 5; 30 31 AddRange(new Drawable[] 32 { 33 new Box 34 { 35 RelativeSizeAxes = Axes.Both, 36 Colour = Color4.Black, 37 Alpha = 0.75f 38 }, 39 counter = new CounterText 40 { 41 Anchor = Anchor.TopRight, 42 Origin = Anchor.TopRight, 43 Spacing = new Vector2(-1, 0), 44 Text = @"...", 45 } 46 }); 47 } 48 49 private float aimWidth; 50 51 private double displayFps; 52 53 private double rollingElapsed; 54 55 private int framesSinceLastUpdate; 56 57 private double elapsedSinceLastUpdate; 58 private double lastUpdateLocalTime; 59 private double lastFrameFramesPerSecond; 60 61 private const int updates_per_second = 10; 62 63 protected override void Update() 64 { 65 base.Update(); 66 67 if (!Precision.AlmostEquals(counter.DrawWidth, aimWidth)) 68 { 69 ClearTransforms(); 70 71 if (aimWidth == 0) 72 Size = counter.DrawSize; 73 else if (Precision.AlmostBigger(counter.DrawWidth, aimWidth)) 74 this.ResizeTo(counter.DrawSize, 200, Easing.OutQuint); 75 else 76 this.Delay(500).ResizeTo(counter.DrawSize, 200, Easing.InOutSine); 77 78 aimWidth = counter.DrawWidth; 79 } 80 81 if (Clock.CurrentTime - lastUpdateLocalTime > 1000.0 / updates_per_second) 82 updateDisplay(); 83 } 84 85 private void updateDisplay() 86 { 87 double dampRate = Math.Max(Clock.CurrentTime - lastUpdateLocalTime, 0) / 1000; 88 89 displayFps = Interpolation.Damp(displayFps, lastFrameFramesPerSecond, 0.01, dampRate); 90 91 if (framesSinceLastUpdate > 0) 92 { 93 rollingElapsed = Interpolation.Damp(rollingElapsed, elapsedSinceLastUpdate / framesSinceLastUpdate, 0.01, dampRate); 94 } 95 96 lastUpdateLocalTime = Clock.CurrentTime; 97 98 framesSinceLastUpdate = 0; 99 elapsedSinceLastUpdate = 0; 100 101 counter.Text = $"{displayFps:0}fps ({rollingElapsed:0.00}ms)" 102 + (clock.Throttling ? $"{(clock.MaximumUpdateHz > 0 && clock.MaximumUpdateHz < 10000 ? clock.MaximumUpdateHz.ToString("0") : "").PadLeft(4)}hz" : string.Empty); 103 } 104 105 private class CounterText : SpriteText 106 { 107 public CounterText() 108 { 109 Font = FrameworkFont.Regular.With(fixedWidth: true); 110 } 111 112 protected override char[] FixedWidthExcludeCharacters { get; } = { ',', '.', ' ' }; 113 } 114 115 public void NewFrame(FrameStatistics frame) 116 { 117 if (!Counting) return; 118 119 foreach (var pair in frame.CollectedTimes) 120 { 121 if (pair.Key != PerformanceCollectionType.Sleep) 122 elapsedSinceLastUpdate += pair.Value; 123 } 124 125 framesSinceLastUpdate++; 126 lastFrameFramesPerSecond = frame.FramesPerSecond; 127 } 128 } 129}