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;
5using System.Collections.Generic;
6using osu.Framework.Graphics;
7using osu.Framework.Graphics.Colour;
8using osu.Framework.Graphics.Containers;
9using osu.Framework.Graphics.Shapes;
10using osu.Framework.Graphics.Sprites;
11using osu.Framework.Graphics.UserInterface;
12using osu.Framework.Logging;
13using osuTK;
14using osuTK.Graphics;
15
16namespace osu.Framework.Tests.Visual.Drawables
17{
18 public class TestSceneComplexBlending : FrameworkTestScene
19 {
20 private readonly Dropdown<string> colourModeDropdown;
21 private readonly Dropdown<BlendingEquation> colourEquation;
22 private readonly Dropdown<BlendingEquation> alphaEquation;
23 private readonly BufferedContainer foregroundContainer;
24
25 private readonly FillFlowContainer blendingSrcContainer;
26 private readonly FillFlowContainer blendingDestContainer;
27 private readonly FillFlowContainer blendingAlphaSrcContainer;
28 private readonly FillFlowContainer blendingAlphaDestContainer;
29
30 private readonly Dropdown<BlendingType> blendingSrcDropdown;
31 private readonly Dropdown<BlendingType> blendingDestDropdown;
32 private readonly Dropdown<BlendingType> blendingAlphaSrcDropdown;
33 private readonly Dropdown<BlendingType> blendingAlphaDestDropdown;
34
35 private readonly FillFlowContainer settingsBox;
36
37 private readonly Dictionary<string, BlendingParameters> blendingModes = new Dictionary<string, BlendingParameters>
38 {
39 { "Inherit", BlendingParameters.Inherit },
40 { "Additive", BlendingParameters.Additive },
41 { "Mixture", BlendingParameters.Mixture },
42 { "Custom", BlendingParameters.Mixture },
43 };
44
45 private bool inCustomMode;
46
47 public TestSceneComplexBlending()
48 {
49 Children = new Drawable[]
50 {
51 settingsBox = new FillFlowContainer
52 {
53 Name = "Settings",
54 AutoSizeAxes = Axes.Both,
55 Y = 50,
56 Direction = FillDirection.Vertical,
57 Spacing = new Vector2(0, 20),
58 Children = new Drawable[]
59 {
60 new FillFlowContainer
61 {
62 AutoSizeAxes = Axes.Both,
63 Direction = FillDirection.Vertical,
64 Spacing = new Vector2(0, 5),
65 Children = new Drawable[]
66 {
67 new SpriteText { Text = "Blending mode" },
68 colourModeDropdown = new BasicDropdown<string> { Width = 200 }
69 }
70 },
71 new FillFlowContainer
72 {
73 AutoSizeAxes = Axes.Both,
74 Direction = FillDirection.Vertical,
75 Spacing = new Vector2(0, 5),
76 Children = new Drawable[]
77 {
78 new SpriteText { Text = "Blending equation (colour)" },
79 colourEquation = new BasicDropdown<BlendingEquation> { Width = 200 }
80 }
81 },
82 new FillFlowContainer
83 {
84 AutoSizeAxes = Axes.Both,
85 Direction = FillDirection.Vertical,
86 Spacing = new Vector2(0, 5),
87 Children = new Drawable[]
88 {
89 new SpriteText { Text = "Blending equation (alpha)" },
90 alphaEquation = new BasicDropdown<BlendingEquation> { Width = 200 }
91 }
92 }
93 }
94 },
95 new SpriteText
96 {
97 Anchor = Anchor.Centre,
98 Origin = Anchor.Centre,
99 Text = "Behind background"
100 },
101 new BufferedContainer
102 {
103 Name = "Background",
104 Anchor = Anchor.Centre,
105 Origin = Anchor.Centre,
106 RelativeSizeAxes = Axes.Both,
107 FillMode = FillMode.Fit,
108 Size = new Vector2(0.85f),
109 Masking = true,
110 Children = new Drawable[]
111 {
112 new GradientPart(0, Color4.Orange, Color4.Yellow),
113 new GradientPart(1, Color4.Yellow, Color4.Green),
114 new GradientPart(2, Color4.Green, Color4.Cyan),
115 new GradientPart(3, Color4.Cyan, Color4.Blue),
116 new GradientPart(4, Color4.Blue, Color4.Violet),
117 foregroundContainer = new BufferedContainer
118 {
119 Name = "Foreground",
120 Anchor = Anchor.Centre,
121 Origin = Anchor.Centre,
122 RelativeSizeAxes = Axes.Both,
123 Alpha = 0.8f,
124 Children = new[]
125 {
126 new Circle
127 {
128 Anchor = Anchor.Centre,
129 Origin = Anchor.Centre,
130 RelativePositionAxes = Axes.Both,
131 RelativeSizeAxes = Axes.Both,
132 Size = new Vector2(0.45f),
133 Y = -0.15f,
134 Colour = Color4.Cyan
135 },
136 new Circle
137 {
138 Anchor = Anchor.Centre,
139 Origin = Anchor.Centre,
140 RelativePositionAxes = Axes.Both,
141 RelativeSizeAxes = Axes.Both,
142 Size = new Vector2(0.45f),
143 X = -0.15f,
144 Colour = Color4.Magenta
145 },
146 new Circle
147 {
148 Anchor = Anchor.Centre,
149 Origin = Anchor.Centre,
150 RelativePositionAxes = Axes.Both,
151 RelativeSizeAxes = Axes.Both,
152 Size = new Vector2(0.45f),
153 X = 0.15f,
154 Colour = Color4.Yellow
155 },
156 }
157 },
158 }
159 },
160 };
161
162 blendingSrcContainer = new FillFlowContainer
163 {
164 AutoSizeAxes = Axes.Both,
165 Direction = FillDirection.Vertical,
166 Spacing = new Vector2(0, 5),
167 Children = new Drawable[]
168 {
169 new SpriteText { Text = "Custom: Source" },
170 blendingSrcDropdown = new BasicDropdown<BlendingType> { Width = 200 }
171 },
172 };
173
174 blendingDestContainer = new FillFlowContainer
175 {
176 AutoSizeAxes = Axes.Both,
177 Direction = FillDirection.Vertical,
178 Spacing = new Vector2(0, 5),
179 Children = new Drawable[]
180 {
181 new SpriteText { Text = "Custom: Destination" },
182 blendingDestDropdown = new BasicDropdown<BlendingType> { Width = 200 }
183 },
184 };
185
186 blendingAlphaSrcContainer = new FillFlowContainer
187 {
188 AutoSizeAxes = Axes.Both,
189 Direction = FillDirection.Vertical,
190 Spacing = new Vector2(0, 5),
191 Children = new Drawable[]
192 {
193 new SpriteText { Text = "Custom: Alpha Source" },
194 blendingAlphaSrcDropdown = new BasicDropdown<BlendingType> { Width = 200 }
195 },
196 };
197
198 blendingAlphaDestContainer = new FillFlowContainer
199 {
200 AutoSizeAxes = Axes.Both,
201 Direction = FillDirection.Vertical,
202 Spacing = new Vector2(0, 5),
203 Children = new Drawable[]
204 {
205 new SpriteText { Text = "Custom: Alpha Destination" },
206 blendingAlphaDestDropdown = new BasicDropdown<BlendingType> { Width = 200 }
207 },
208 };
209
210 colourModeDropdown.Items = blendingModes.Keys;
211 colourEquation.Items = (BlendingEquation[])Enum.GetValues(typeof(BlendingEquation));
212 alphaEquation.Items = (BlendingEquation[])Enum.GetValues(typeof(BlendingEquation));
213
214 blendingSrcDropdown.Items = (BlendingType[])Enum.GetValues(typeof(BlendingType));
215 blendingDestDropdown.Items = (BlendingType[])Enum.GetValues(typeof(BlendingType));
216 blendingAlphaSrcDropdown.Items = (BlendingType[])Enum.GetValues(typeof(BlendingType));
217 blendingAlphaDestDropdown.Items = (BlendingType[])Enum.GetValues(typeof(BlendingType));
218
219 colourModeDropdown.Current.Value = "Mixture";
220 colourEquation.Current.Value = foregroundContainer.Blending.RGBEquation;
221 alphaEquation.Current.Value = foregroundContainer.Blending.AlphaEquation;
222
223 blendingSrcDropdown.Current.Value = BlendingType.SrcAlpha;
224 blendingDestDropdown.Current.Value = BlendingType.OneMinusSrcAlpha;
225 blendingAlphaSrcDropdown.Current.Value = BlendingType.One;
226 blendingAlphaDestDropdown.Current.Value = BlendingType.One;
227
228 colourModeDropdown.Current.ValueChanged += v => updateBlending();
229 colourEquation.Current.ValueChanged += v => updateBlending();
230 alphaEquation.Current.ValueChanged += v => updateBlending();
231 blendingSrcDropdown.Current.ValueChanged += v => updateBlending();
232 blendingDestDropdown.Current.ValueChanged += v => updateBlending();
233 blendingAlphaSrcDropdown.Current.ValueChanged += v => updateBlending();
234 blendingAlphaDestDropdown.Current.ValueChanged += v => updateBlending();
235 }
236
237 private void switchToCustomBlending()
238 {
239 settingsBox.Add(blendingSrcContainer);
240 settingsBox.Add(blendingDestContainer);
241 settingsBox.Add(blendingAlphaSrcContainer);
242 settingsBox.Add(blendingAlphaDestContainer);
243 }
244
245 private void switchOffCustomBlending()
246 {
247 settingsBox.Remove(blendingSrcContainer);
248 settingsBox.Remove(blendingDestContainer);
249 settingsBox.Remove(blendingAlphaSrcContainer);
250 settingsBox.Remove(blendingAlphaDestContainer);
251 }
252
253 private void updateBlending()
254 {
255 if (colourModeDropdown.Current.Value == "Custom")
256 {
257 if (!inCustomMode)
258 switchToCustomBlending();
259
260 var blending = new BlendingParameters
261 {
262 Source = blendingSrcDropdown.Current.Value,
263 Destination = blendingDestDropdown.Current.Value,
264 SourceAlpha = blendingAlphaSrcDropdown.Current.Value,
265 DestinationAlpha = blendingAlphaDestDropdown.Current.Value,
266 RGBEquation = colourEquation.Current.Value,
267 AlphaEquation = alphaEquation.Current.Value
268 };
269
270 Logger.Log("Changed blending mode to: " + blending, LoggingTarget.Runtime, LogLevel.Debug);
271
272 foregroundContainer.Blending = blending;
273
274 inCustomMode = true;
275 }
276 else
277 {
278 if (inCustomMode)
279 switchOffCustomBlending();
280
281 var blending = blendingModes[colourModeDropdown.Current.Value];
282
283 blending.RGBEquation = colourEquation.Current.Value;
284 blending.AlphaEquation = alphaEquation.Current.Value;
285
286 Logger.Log("Changed blending mode to: " + blending, LoggingTarget.Runtime, LogLevel.Debug);
287
288 foregroundContainer.Blending = blending;
289
290 inCustomMode = false;
291 }
292 }
293
294 private class GradientPart : Box
295 {
296 public GradientPart(int index, Color4 start, Color4 end)
297 {
298 RelativeSizeAxes = Axes.Both;
299 RelativePositionAxes = Axes.Both;
300 Width = 1 / 5f; // Assume 5 gradients
301 X = 1 / 5f * index;
302
303 Colour = ColourInfo.GradientHorizontal(start, end);
304 }
305 }
306 }
307}