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 osuTK;
5using System;
6using osu.Framework.Graphics.OpenGL.Vertices;
7using osu.Framework.Graphics.Primitives;
8using osu.Framework.Graphics.Textures;
9using osu.Framework.Graphics.OpenGL;
10using osu.Framework.Graphics.OpenGL.Textures;
11
12namespace osu.Framework.Graphics.Sprites
13{
14 /// <summary>
15 /// Draw node containing all necessary information to draw a <see cref="Sprite"/>.
16 /// </summary>
17 public class SpriteDrawNode : TexturedShaderDrawNode
18 {
19 protected Texture Texture { get; private set; }
20 protected Quad ScreenSpaceDrawQuad { get; private set; }
21
22 protected RectangleF DrawRectangle { get; private set; }
23 protected Vector2 InflationAmount { get; private set; }
24
25 protected RectangleF TextureCoords { get; private set; }
26
27 protected new Sprite Source => (Sprite)base.Source;
28
29 protected Quad ConservativeScreenSpaceDrawQuad;
30
31 private bool hasOpaqueInterior;
32
33 public SpriteDrawNode(Sprite source)
34 : base(source)
35 {
36 }
37
38 public override void ApplyState()
39 {
40 base.ApplyState();
41
42 Texture = Source.Texture;
43 ScreenSpaceDrawQuad = Source.ScreenSpaceDrawQuad;
44 DrawRectangle = Source.DrawRectangle;
45 InflationAmount = Source.InflationAmount;
46
47 TextureCoords = Source.DrawRectangle.RelativeIn(Source.DrawTextureRectangle);
48 if (Texture != null)
49 TextureCoords *= new Vector2(Texture.DisplayWidth, Texture.DisplayHeight);
50
51 hasOpaqueInterior = DrawColourInfo.Colour.MinAlpha == 1
52 && DrawColourInfo.Blending == BlendingParameters.Mixture
53 && DrawColourInfo.Colour.HasSingleColour;
54
55 if (CanDrawOpaqueInterior)
56 ConservativeScreenSpaceDrawQuad = Source.ConservativeScreenSpaceDrawQuad;
57 }
58
59 protected virtual void Blit(Action<TexturedVertex2D> vertexAction)
60 {
61 DrawQuad(Texture, ScreenSpaceDrawQuad, DrawColourInfo.Colour, null, vertexAction,
62 new Vector2(InflationAmount.X / DrawRectangle.Width, InflationAmount.Y / DrawRectangle.Height),
63 null, TextureCoords);
64 }
65
66 protected virtual void BlitOpaqueInterior(Action<TexturedVertex2D> vertexAction)
67 {
68 if (GLWrapper.IsMaskingActive)
69 DrawClipped(ref ConservativeScreenSpaceDrawQuad, Texture, DrawColourInfo.Colour, vertexAction: vertexAction);
70 else
71 DrawQuad(Texture, ConservativeScreenSpaceDrawQuad, DrawColourInfo.Colour, vertexAction: vertexAction, textureCoords: TextureCoords);
72 }
73
74 public override void Draw(Action<TexturedVertex2D> vertexAction)
75 {
76 base.Draw(vertexAction);
77
78 if (Texture?.Available != true)
79 return;
80
81 Shader.Bind();
82
83 Blit(vertexAction);
84
85 Shader.Unbind();
86 }
87
88 protected override bool RequiresRoundedShader => base.RequiresRoundedShader || InflationAmount != Vector2.Zero;
89
90 protected override void DrawOpaqueInterior(Action<TexturedVertex2D> vertexAction)
91 {
92 base.DrawOpaqueInterior(vertexAction);
93
94 if (Texture?.Available != true)
95 return;
96
97 TextureShader.Bind();
98
99 BlitOpaqueInterior(vertexAction);
100
101 TextureShader.Unbind();
102 }
103
104 protected internal override bool CanDrawOpaqueInterior => Texture?.Available == true && Texture.Opacity == Opacity.Opaque && hasOpaqueInterior;
105 }
106}