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.OpenGL;
6using osu.Framework.Graphics.OpenGL.Buffers;
7using osuTK;
8using osuTK.Graphics;
9using osu.Framework.Graphics.Primitives;
10using osu.Framework.Graphics.Shaders;
11using System;
12using osu.Framework.Graphics.Colour;
13using osu.Framework.Utils;
14using osuTK.Graphics.ES30;
15
16namespace osu.Framework.Graphics.Containers
17{
18 public partial class BufferedContainer<T>
19 {
20 private class BufferedContainerDrawNode : BufferedDrawNode, ICompositeDrawNode
21 {
22 protected new BufferedContainer<T> Source => (BufferedContainer<T>)base.Source;
23
24 protected new CompositeDrawableDrawNode Child => (CompositeDrawableDrawNode)base.Child;
25
26 private bool drawOriginal;
27 private ColourInfo effectColour;
28 private BlendingParameters effectBlending;
29 private EffectPlacement effectPlacement;
30
31 private Vector2 blurSigma;
32 private Vector2I blurRadius;
33 private float blurRotation;
34
35 private long updateVersion;
36
37 private IShader blurShader;
38
39 public BufferedContainerDrawNode(BufferedContainer<T> source, BufferedContainerDrawNodeSharedData sharedData)
40 : base(source, new CompositeDrawableDrawNode(source), sharedData)
41 {
42 }
43
44 public override void ApplyState()
45 {
46 base.ApplyState();
47
48 updateVersion = Source.updateVersion;
49
50 effectColour = Source.EffectColour;
51 effectBlending = Source.DrawEffectBlending;
52 effectPlacement = Source.EffectPlacement;
53
54 drawOriginal = Source.DrawOriginal;
55 blurSigma = Source.BlurSigma;
56 blurRadius = new Vector2I(Blur.KernelSize(blurSigma.X), Blur.KernelSize(blurSigma.Y));
57 blurRotation = Source.BlurRotation;
58
59 blurShader = Source.blurShader;
60 }
61
62 protected override long GetDrawVersion() => updateVersion;
63
64 protected override void PopulateContents()
65 {
66 base.PopulateContents();
67
68 if (blurRadius.X > 0 || blurRadius.Y > 0)
69 {
70 GLWrapper.PushScissorState(false);
71
72 if (blurRadius.X > 0) drawBlurredFrameBuffer(blurRadius.X, blurSigma.X, blurRotation);
73 if (blurRadius.Y > 0) drawBlurredFrameBuffer(blurRadius.Y, blurSigma.Y, blurRotation + 90);
74
75 GLWrapper.PopScissorState();
76 }
77 }
78
79 protected override void DrawContents()
80 {
81 if (drawOriginal && effectPlacement == EffectPlacement.InFront)
82 base.DrawContents();
83
84 GLWrapper.SetBlend(effectBlending);
85
86 ColourInfo finalEffectColour = DrawColourInfo.Colour;
87 finalEffectColour.ApplyChild(effectColour);
88
89 DrawFrameBuffer(SharedData.CurrentEffectBuffer, DrawRectangle, finalEffectColour);
90
91 if (drawOriginal && effectPlacement == EffectPlacement.Behind)
92 base.DrawContents();
93 }
94
95 private void drawBlurredFrameBuffer(int kernelRadius, float sigma, float blurRotation)
96 {
97 FrameBuffer current = SharedData.CurrentEffectBuffer;
98 FrameBuffer target = SharedData.GetNextEffectBuffer();
99
100 GLWrapper.SetBlend(BlendingParameters.None);
101
102 using (BindFrameBuffer(target))
103 {
104 blurShader.GetUniform<int>(@"g_Radius").UpdateValue(ref kernelRadius);
105 blurShader.GetUniform<float>(@"g_Sigma").UpdateValue(ref sigma);
106
107 Vector2 size = current.Size;
108 blurShader.GetUniform<Vector2>(@"g_TexSize").UpdateValue(ref size);
109
110 float radians = -MathUtils.DegreesToRadians(blurRotation);
111 Vector2 blur = new Vector2(MathF.Cos(radians), MathF.Sin(radians));
112 blurShader.GetUniform<Vector2>(@"g_BlurDirection").UpdateValue(ref blur);
113
114 blurShader.Bind();
115 DrawFrameBuffer(current, new RectangleF(0, 0, current.Texture.Width, current.Texture.Height), ColourInfo.SingleColour(Color4.White));
116 blurShader.Unbind();
117 }
118 }
119
120 public List<DrawNode> Children
121 {
122 get => Child.Children;
123 set => Child.Children = value;
124 }
125
126 public bool AddChildDrawNodes => RequiresRedraw;
127 }
128
129 private class BufferedContainerDrawNodeSharedData : BufferedDrawNodeSharedData
130 {
131 public BufferedContainerDrawNodeSharedData(RenderbufferInternalFormat[] formats, bool pixelSnapping)
132 : base(2, formats, pixelSnapping)
133 {
134 }
135 }
136 }
137}