A game framework written with osu! in mind.
at master 478 lines 16 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 osu.Framework.Extensions.Color4Extensions; 5using osu.Framework.Graphics; 6using osu.Framework.Graphics.Containers; 7using osu.Framework.Graphics.Shapes; 8using osu.Framework.Graphics.Sprites; 9using osuTK; 10using osuTK.Graphics; 11 12namespace osu.Framework.Tests.Visual.Drawables 13{ 14 public class TestSceneProxyDrawables : FrameworkTestScene 15 { 16 public TestSceneProxyDrawables() 17 { 18 Child = new BasicScrollContainer 19 { 20 RelativeSizeAxes = Axes.Both, 21 Child = new FillFlowContainer 22 { 23 RelativeSizeAxes = Axes.X, 24 AutoSizeAxes = Axes.Y, 25 Children = new[] 26 { 27 generateProxyAboveAllPresentTest(1), 28 generateProxyBelowAllPresentTest(1), 29 generateProxyAboveAllPresentTest(6), 30 generateProxyBelowAllPresentTest(6), 31 generateProxyAboveOriginalMaskedAway(1), 32 generateProxyBelowOriginalMaskedAway(1), 33 generateProxyAboveOriginalMaskedAway(6), 34 generateProxyBelowOriginalMaskedAway(6), 35 generateProxyAboveBoxParentNotPresent(1), 36 generateProxyBelowBoxParentNotPresent(1), 37 generateProxyAboveBoxParentNotPresent(6), 38 generateProxyBelowBoxParentNotPresent(6), 39 generateProxyAboveBoxParentNotAlive(1), 40 generateProxyBelowBoxParentNotAlive(1), 41 generateProxyAboveBoxParentNotAlive(6), 42 generateProxyBelowBoxParentNotAlive(6), 43 generateProxyAboveParentOriginalIndirectlyMaskedAway(1), 44 generateProxyBelowParentOriginalIndirectlyMaskedAway(1), 45 generateProxyAboveParentOriginalIndirectlyMaskedAway(6), 46 generateProxyBelowParentOriginalIndirectlyMaskedAway(6), 47 generateOpaqueProxyAboveOpaqueBox(), 48 } 49 } 50 }; 51 } 52 53 private Drawable generateProxyAboveAllPresentTest(int proxyCount) 54 { 55 var box = new Box 56 { 57 Anchor = Anchor.Centre, 58 Origin = Anchor.Centre, 59 Size = new Vector2(50), 60 }; 61 62 var proxy = box.CreateProxy(); 63 for (int i = 1; i < proxyCount; i++) 64 proxy = proxy.CreateProxy(); 65 66 return new Visualiser($"{proxyCount} proxy(s) above, all present") 67 { 68 Children = new Drawable[] { box, new ProxyVisualiser(proxy, true) } 69 }; 70 } 71 72 private Drawable generateProxyBelowAllPresentTest(int proxyCount) 73 { 74 var box = new Box 75 { 76 Anchor = Anchor.Centre, 77 Origin = Anchor.Centre, 78 Size = new Vector2(50), 79 }; 80 81 var proxy = box.CreateProxy(); 82 for (int i = 1; i < proxyCount; i++) 83 proxy = proxy.CreateProxy(); 84 85 return new Visualiser($"{proxyCount} proxy(s) below, all present") 86 { 87 Children = new Drawable[] { new ProxyVisualiser(proxy, false), box } 88 }; 89 } 90 91 private Drawable generateProxyAboveOriginalMaskedAway(int proxyCount) 92 { 93 var box = new Box 94 { 95 RelativeSizeAxes = Axes.Both, 96 Position = new Vector2(60, 0) 97 }; 98 99 var boxMaskingContainer = new Container 100 { 101 Anchor = Anchor.Centre, 102 Origin = Anchor.Centre, 103 Size = new Vector2(50), 104 Masking = true, 105 BorderColour = Color4.Yellow, 106 BorderThickness = 2, 107 Children = new Drawable[] 108 { 109 new Box 110 { 111 RelativeSizeAxes = Axes.Both, 112 Alpha = 0, 113 AlwaysPresent = true 114 }, 115 box 116 } 117 }; 118 119 var proxy = box.CreateProxy(); 120 for (int i = 1; i < proxyCount; i++) 121 proxy = proxy.CreateProxy(); 122 123 return new Visualiser($"{proxyCount} proxy(s) above, original masked away") 124 { 125 Children = new Drawable[] { boxMaskingContainer, new ProxyVisualiser(proxy, true) } 126 }; 127 } 128 129 private Drawable generateProxyBelowOriginalMaskedAway(int proxyCount) 130 { 131 var box = new Box 132 { 133 RelativeSizeAxes = Axes.Both, 134 Position = new Vector2(60, 0) 135 }; 136 137 var boxMaskingContainer = new Container 138 { 139 Anchor = Anchor.Centre, 140 Origin = Anchor.Centre, 141 Size = new Vector2(50), 142 Masking = true, 143 BorderColour = Color4.Yellow, 144 BorderThickness = 2, 145 Children = new Drawable[] 146 { 147 new Box 148 { 149 RelativeSizeAxes = Axes.Both, 150 Alpha = 0, 151 AlwaysPresent = true 152 }, 153 box 154 } 155 }; 156 157 var proxy = box.CreateProxy(); 158 for (int i = 1; i < proxyCount; i++) 159 proxy = proxy.CreateProxy(); 160 161 return new Visualiser($"{proxyCount} proxy(s) below, original masked away") 162 { 163 Children = new Drawable[] { new ProxyVisualiser(proxy, false), boxMaskingContainer } 164 }; 165 } 166 167 private Drawable generateProxyAboveBoxParentNotPresent(int proxyCount) 168 { 169 var box = new Box { RelativeSizeAxes = Axes.Both }; 170 171 var invisibleContainer = new NonPresentContainer 172 { 173 Anchor = Anchor.Centre, 174 Origin = Anchor.Centre, 175 Size = new Vector2(50), 176 Child = new Container 177 { 178 RelativeSizeAxes = Axes.Both, 179 Child = box 180 } 181 }; 182 183 var proxy = box.CreateProxy(); 184 for (int i = 1; i < proxyCount; i++) 185 proxy = proxy.CreateProxy(); 186 187 return new Visualiser($"{proxyCount} proxy(s) above, original parent invisible") 188 { 189 Children = new Drawable[] { invisibleContainer, new ProxyVisualiser(proxy, true) } 190 }; 191 } 192 193 private Drawable generateProxyBelowBoxParentNotPresent(int proxyCount) 194 { 195 var box = new Box { RelativeSizeAxes = Axes.Both }; 196 197 var invisibleContainer = new NonPresentContainer 198 { 199 Anchor = Anchor.Centre, 200 Origin = Anchor.Centre, 201 Size = new Vector2(50), 202 Child = new Container 203 { 204 RelativeSizeAxes = Axes.Both, 205 Child = box 206 } 207 }; 208 209 var proxy = box.CreateProxy(); 210 for (int i = 1; i < proxyCount; i++) 211 proxy = proxy.CreateProxy(); 212 213 return new Visualiser($"{proxyCount} proxy(s) below, original parent invisible") 214 { 215 Children = new Drawable[] { new ProxyVisualiser(proxy, false), invisibleContainer } 216 }; 217 } 218 219 private Drawable generateProxyAboveBoxParentNotAlive(int proxyCount) 220 { 221 var box = new Box { RelativeSizeAxes = Axes.Both }; 222 223 var invisibleContainer = new NonAliveContainer 224 { 225 Anchor = Anchor.Centre, 226 Origin = Anchor.Centre, 227 Size = new Vector2(50), 228 Child = new Container 229 { 230 RelativeSizeAxes = Axes.Both, 231 Child = box 232 } 233 }; 234 235 var proxy = box.CreateProxy(); 236 for (int i = 1; i < proxyCount; i++) 237 proxy = proxy.CreateProxy(); 238 239 return new Visualiser($"{proxyCount} proxy(s) above, original parent not alive") 240 { 241 Children = new Drawable[] { invisibleContainer, new ProxyVisualiser(proxy, true) } 242 }; 243 } 244 245 private Drawable generateProxyBelowBoxParentNotAlive(int proxyCount) 246 { 247 var box = new Box { RelativeSizeAxes = Axes.Both }; 248 249 var invisibleContainer = new NonAliveContainer 250 { 251 Anchor = Anchor.Centre, 252 Origin = Anchor.Centre, 253 Size = new Vector2(50), 254 Child = new Container 255 { 256 RelativeSizeAxes = Axes.Both, 257 Child = box 258 } 259 }; 260 261 var proxy = box.CreateProxy(); 262 for (int i = 1; i < proxyCount; i++) 263 proxy = proxy.CreateProxy(); 264 265 return new Visualiser($"{proxyCount} proxy(s) below, original parent not alive") 266 { 267 Children = new Drawable[] { new ProxyVisualiser(proxy, false), invisibleContainer } 268 }; 269 } 270 271 private Drawable generateProxyAboveParentOriginalIndirectlyMaskedAway(int proxyCount) 272 { 273 var box = new Box 274 { 275 Size = new Vector2(50), 276 Anchor = Anchor.Centre, 277 Origin = Anchor.Centre, 278 Position = new Vector2(-50) 279 }; 280 281 var proxy = box.CreateProxy(); 282 for (int i = 1; i < proxyCount; i++) 283 proxy = proxy.CreateProxy(); 284 285 return new Visualiser($"{proxyCount} proxy(s) above, proxy masked") 286 { 287 Children = new Drawable[] 288 { 289 box, 290 new Container 291 { 292 Anchor = Anchor.Centre, 293 Origin = Anchor.Centre, 294 Size = new Vector2(100), 295 Masking = true, 296 CornerRadius = 20, 297 Children = new Drawable[] 298 { 299 new Box { RelativeSizeAxes = Axes.Both, Colour = Color4.Yellow.Opacity(0.2f) }, 300 new ProxyVisualiser(proxy, true) 301 } 302 } 303 } 304 }; 305 } 306 307 private Drawable generateProxyBelowParentOriginalIndirectlyMaskedAway(int proxyCount) 308 { 309 var box = new Box 310 { 311 Size = new Vector2(50), 312 Anchor = Anchor.Centre, 313 Origin = Anchor.Centre, 314 Position = new Vector2(-50) 315 }; 316 317 var proxy = box.CreateProxy(); 318 for (int i = 1; i < proxyCount; i++) 319 proxy = proxy.CreateProxy(); 320 321 return new Visualiser($"{proxyCount} proxy(s) below, proxy masked") 322 { 323 Children = new Drawable[] 324 { 325 new Container 326 { 327 Anchor = Anchor.Centre, 328 Origin = Anchor.Centre, 329 Size = new Vector2(100), 330 Masking = true, 331 CornerRadius = 20, 332 Children = new Drawable[] 333 { 334 new Box { RelativeSizeAxes = Axes.Both, Colour = Color4.Yellow.Opacity(0.2f) }, 335 new ProxyVisualiser(proxy, false) 336 } 337 }, 338 box 339 } 340 }; 341 } 342 343 private Drawable generateOpaqueProxyAboveOpaqueBox() 344 { 345 var box = new Box 346 { 347 Anchor = Anchor.Centre, 348 Origin = Anchor.Centre, 349 Size = new Vector2(50), 350 }; 351 352 var proxy = box.CreateProxy(); 353 354 return new Visualiser("proxy above opaque box") 355 { 356 Children = new Drawable[] 357 { 358 box, 359 new ProxyVisualiser(proxy, false, 1.0f) 360 } 361 }; 362 } 363 364 private class NonPresentContainer : Container 365 { 366 private bool isPresent = true; 367 public override bool IsPresent => isPresent; 368 369 public override bool UpdateSubTree() 370 { 371 // We want to be present for updates 372 isPresent = true; 373 374 var result = base.UpdateSubTree(); 375 if (!result) 376 return false; 377 378 // We want to not be present for draw 379 isPresent = false; 380 return true; 381 } 382 } 383 384 private class NonAliveContainer : Container 385 { 386 protected internal override bool ShouldBeAlive => false; 387 public override bool DisposeOnDeathRemoval => false; 388 } 389 390 private class Visualiser : Container 391 { 392 protected override Container<Drawable> Content => content; 393 private readonly Container content; 394 395 public Visualiser(string description) 396 { 397 Size = new Vector2(300); 398 399 InternalChildren = new Drawable[] 400 { 401 content = new Container { RelativeSizeAxes = Axes.Both }, 402 new Container 403 { 404 RelativeSizeAxes = Axes.Both, 405 Masking = true, 406 BorderColour = Color4.Gray, 407 BorderThickness = 2, 408 Child = new Box 409 { 410 RelativeSizeAxes = Axes.Both, 411 Alpha = 0, 412 AlwaysPresent = true 413 } 414 }, 415 new SpriteText 416 { 417 Anchor = Anchor.TopCentre, 418 Origin = Anchor.TopCentre, 419 Y = 10, 420 Text = description 421 } 422 }; 423 } 424 } 425 426 private class ProxyVisualiser : CompositeDrawable 427 { 428 private readonly Drawable original; 429 private readonly Drawable overlay; 430 431 public ProxyVisualiser(Drawable proxy, bool proxyIsBelow, float boxAlpha = 0.5f) 432 { 433 RelativeSizeAxes = Axes.Both; 434 435 original = proxy.Original; 436 437 while (original != (original = original.Original)) 438 { 439 } 440 441 if (proxyIsBelow) 442 AddInternal(proxy); 443 444 AddInternal(overlay = new Container 445 { 446 Colour = proxyIsBelow ? Color4.Red : Color4.Green, 447 Children = new Drawable[] 448 { 449 new Box 450 { 451 RelativeSizeAxes = Axes.Both, 452 Alpha = boxAlpha, 453 }, 454 new SpriteText 455 { 456 Anchor = Anchor.BottomCentre, 457 Origin = Anchor.BottomCentre, 458 Colour = Color4.Black, 459 Text = "proxy" 460 } 461 } 462 }); 463 464 if (!proxyIsBelow) 465 AddInternal(proxy); 466 } 467 468 protected override void Update() 469 { 470 base.Update(); 471 472 var aabb = ToLocalSpace(original.ScreenSpaceDrawQuad).AABBFloat.Inflate(15); 473 overlay.Position = aabb.Location; 474 overlay.Size = aabb.Size; 475 } 476 } 477 } 478}