A game framework written with osu! in mind.
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 osu.Framework.Graphics;
6using osu.Framework.Graphics.Containers;
7using osu.Framework.Graphics.Shapes;
8using osu.Framework.Graphics.Sprites;
9using osu.Framework.Testing;
10using osuTK;
11using osuTK.Graphics;
12
13namespace osu.Framework.Tests.Visual.Containers
14{
15 public class TestSceneCachedBufferedContainer : GridTestScene
16 {
17 public TestSceneCachedBufferedContainer()
18 : base(5, 3)
19 {
20 string[] labels =
21 {
22 "uncached",
23 "cached",
24 "uncached with rotation",
25 "cached with rotation",
26 "uncached with movement",
27 "cached with movement",
28 "uncached with parent scale",
29 "cached with parent scale",
30 "uncached with parent scale&fade",
31 "cached with parent scale&fade",
32 "cached with no redraw on parent scale&fade",
33 };
34
35 var boxes = new List<ContainingBox>();
36
37 for (int i = 0; i < Rows * Cols; ++i)
38 {
39 if (i >= labels.Length)
40 break;
41
42 ContainingBox box;
43
44 Cell(i).AddRange(new Drawable[]
45 {
46 new SpriteText
47 {
48 Text = labels[i],
49 Font = new FontUsage(size: 20),
50 },
51 box = new ContainingBox(i >= 6, i >= 8)
52 {
53 Child = new CountingBox(i == 2 || i == 3, i == 4 || i == 5)
54 {
55 CacheDrawnFrameBuffer = i % 2 == 1 || i == 10,
56 RedrawOnScale = i != 10
57 },
58 }
59 });
60
61 boxes.Add(box);
62 }
63
64 AddWaitStep("wait for boxes", 5);
65
66 // ensure uncached is always updating children.
67 AddAssert("box 0 count > 0", () => boxes[0].Count > 0);
68 AddAssert("even box counts equal", () =>
69 boxes[0].Count == boxes[2].Count &&
70 boxes[2].Count == boxes[4].Count &&
71 boxes[4].Count == boxes[6].Count);
72
73 // ensure cached is never updating children.
74 AddAssert("box 1 count is 1", () => boxes[1].Count == 1);
75
76 // ensure rotation changes are invalidating cache (for now).
77 AddAssert("box 2 count > 0", () => boxes[2].Count > 0);
78 AddAssert("box 3 count is less than box 2 count", () => boxes[3].Count < boxes[2].Count);
79
80 // ensure cached with only translation is never updating children.
81 AddAssert("box 5 count is 1", () => boxes[1].Count == 1);
82
83 // ensure a parent scaling is invalidating cache.
84 AddAssert("box 5 count is less than box 6 count", () => boxes[5].Count < boxes[6].Count);
85
86 // ensure we don't break on colour invalidations (due to blanket invalidation logic in Drawable.Invalidate).
87 AddAssert("box 7 count equals box 8 count", () => boxes[7].Count == boxes[8].Count);
88
89 AddAssert("box 10 count is 1", () => boxes[10].Count == 1);
90 }
91
92 private class ContainingBox : Container<CountingBox>
93 {
94 public new int Count => Child.Count;
95
96 private readonly bool scaling;
97 private readonly bool fading;
98
99 public ContainingBox(bool scaling, bool fading)
100 {
101 this.scaling = scaling;
102 this.fading = fading;
103
104 RelativeSizeAxes = Axes.Both;
105 }
106
107 protected override void LoadComplete()
108 {
109 base.LoadComplete();
110 if (scaling) this.ScaleTo(1.2f, 1000).Then().ScaleTo(1, 1000).Loop();
111 if (fading) this.FadeTo(0.5f, 1000).Then().FadeTo(1, 1000).Loop();
112 }
113 }
114
115 private class CountingBox : BufferedContainer
116 {
117 public new int Count;
118
119 private readonly bool rotating;
120 private readonly bool moving;
121 private readonly SpriteText count;
122
123 public CountingBox(bool rotating = false, bool moving = false)
124 {
125 this.rotating = rotating;
126 this.moving = moving;
127 RelativeSizeAxes = Axes.Both;
128 Origin = Anchor.Centre;
129 Anchor = Anchor.Centre;
130
131 Scale = new Vector2(0.5f);
132
133 InternalChildren = new Drawable[]
134 {
135 new Box
136 {
137 RelativeSizeAxes = Axes.Both,
138 Origin = Anchor.Centre,
139 Anchor = Anchor.Centre,
140 Colour = Color4.NavajoWhite,
141 },
142 count = new SpriteText
143 {
144 Colour = Color4.Black,
145 Origin = Anchor.Centre,
146 Anchor = Anchor.Centre,
147 Font = new FontUsage(size: 80),
148 }
149 };
150 }
151
152 protected override void Update()
153 {
154 base.Update();
155
156 if (RequiresChildrenUpdate)
157 {
158 Count++;
159 count.Text = Count.ToString();
160 }
161 }
162
163 protected override void LoadComplete()
164 {
165 base.LoadComplete();
166 if (rotating) this.RotateTo(360, 1000).Loop();
167 if (moving) this.MoveTo(new Vector2(100, 0), 2000, Easing.InOutSine).Then().MoveTo(new Vector2(0, 0), 2000, Easing.InOutSine).Loop();
168 }
169 }
170 }
171}