A game framework written with osu! in mind.
at master 3.5 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.Collections.Generic; 5using JetBrains.Annotations; 6using osu.Framework.Allocation; 7using osu.Framework.Bindables; 8using osu.Framework.Graphics; 9using osu.Framework.Graphics.Containers; 10 11namespace osu.Framework.Testing 12{ 13 internal class DrawFrameRecordingContainer : Container 14 { 15 private readonly Bindable<RecordState> recordState = new Bindable<RecordState>(); 16 private readonly BindableInt currentFrame = new BindableInt(); 17 private readonly List<DrawNode> recordedFrames = new List<DrawNode>(); 18 19 protected override Container<Drawable> Content => content; 20 21 private readonly Container content; 22 23 public DrawFrameRecordingContainer() 24 { 25 InternalChildren = new Drawable[] 26 { 27 new InputCapturingDrawable { RelativeSizeAxes = Axes.Both }, 28 content = new Container { RelativeSizeAxes = Axes.Both } 29 }; 30 } 31 32 [BackgroundDependencyLoader(true)] 33 private void load([CanBeNull] TestBrowser browser) 34 { 35 if (browser != null) 36 { 37 recordState.BindTo(browser.RecordState); 38 currentFrame.BindTo(browser.CurrentFrame); 39 } 40 } 41 42 protected override bool CanBeFlattened => false; 43 44 internal override DrawNode GenerateDrawNodeSubtree(ulong frame, int treeIndex, bool forceNewDrawNode) 45 { 46 switch (recordState.Value) 47 { 48 default: 49 case RecordState.Normal: 50 foreach (var drawNode in recordedFrames) 51 disposeRecursively(drawNode); 52 53 recordedFrames.Clear(); 54 55 currentFrame.Value = currentFrame.MaxValue = 0; 56 57 return base.GenerateDrawNodeSubtree(frame, treeIndex, forceNewDrawNode); 58 59 case RecordState.Recording: 60 var node = base.GenerateDrawNodeSubtree(frame, treeIndex, true); 61 62 referenceRecursively(node); 63 64 recordedFrames.Add(node); 65 currentFrame.Value = currentFrame.MaxValue = recordedFrames.Count - 1; 66 67 return node; 68 69 case RecordState.Stopped: 70 return recordedFrames[currentFrame.Value]; 71 } 72 } 73 74 private void referenceRecursively(DrawNode drawNode) 75 { 76 drawNode.Reference(); 77 78 if (!(drawNode is ICompositeDrawNode composite)) 79 return; 80 81 foreach (var child in composite.Children) 82 referenceRecursively(child); 83 } 84 85 private void disposeRecursively(DrawNode drawNode) 86 { 87 drawNode.Dispose(); 88 89 if (!(drawNode is ICompositeDrawNode composite)) 90 return; 91 92 foreach (var child in composite.Children) 93 disposeRecursively(child); 94 } 95 96 // An empty drawable which captures DrawVisualiser input in this container 97 private class InputCapturingDrawable : Drawable 98 { 99 // Required for the DrawVisualiser to not treat this Drawable as an overlay input receptor 100 // ReSharper disable once RedundantOverriddenMember 101 protected override DrawNode CreateDrawNode() => base.CreateDrawNode(); 102 } 103 } 104}