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 osu.Framework.Graphics;
6using osu.Framework.Graphics.Lines;
7using osu.Framework.Graphics.Sprites;
8using osu.Framework.Graphics.Textures;
9using osu.Framework.Input;
10using osu.Framework.Input.Events;
11using osu.Framework.Testing;
12using osuTK;
13using osuTK.Graphics;
14using SixLabors.ImageSharp;
15using SixLabors.ImageSharp.PixelFormats;
16
17namespace osu.Framework.Tests.Visual.Input
18{
19 [System.ComponentModel.Description("live path optimiastion")]
20 public class TestSceneInputResampler : GridTestScene
21 {
22 public TestSceneInputResampler()
23 : base(3, 3)
24 {
25 const int width = 2;
26 Texture gradientTexture = new Texture(width, 1, true);
27 var image = new Image<Rgba32>(width, 1);
28
29 for (int i = 0; i < width; ++i)
30 {
31 var brightnessByte = (byte)((float)i / (width - 1) * 255);
32 image[i, 0] = new Rgba32(brightnessByte, brightnessByte, brightnessByte);
33 }
34
35 gradientTexture.SetData(new TextureUpload(image));
36
37 SpriteText[] text = new SpriteText[6];
38
39 Cell(0, 0).AddRange(new Drawable[]
40 {
41 text[0] = createLabel("Raw"),
42 new ArcPath(true, true, new InputResampler(), gradientTexture, Color4.Green, text[0]),
43 });
44
45 Cell(0, 1).AddRange(new Drawable[]
46 {
47 text[1] = createLabel("Rounded (resembles mouse input)"),
48 new ArcPath(true, false, new InputResampler(), gradientTexture, Color4.Blue, text[1]),
49 });
50
51 Cell(0, 2).AddRange(new Drawable[]
52 {
53 text[2] = createLabel("Custom: Smoothed=0, Raw=0"),
54 new UserDrawnPath
55 {
56 DrawText = text[2],
57 Texture = gradientTexture,
58 Colour = Color4.White,
59 },
60 });
61
62 Cell(1, 0).AddRange(new Drawable[]
63 {
64 text[3] = createLabel("Smoothed raw"),
65 new ArcPath(false, true, new InputResampler(), gradientTexture, Color4.Green, text[3]),
66 });
67
68 Cell(1, 1).AddRange(new Drawable[]
69 {
70 text[4] = createLabel("Smoothed rounded"),
71 new ArcPath(false, false, new InputResampler(), gradientTexture, Color4.Blue, text[4]),
72 });
73
74 Cell(1, 2).AddRange(new Drawable[]
75 {
76 text[5] = createLabel("Smoothed custom: Smoothed=0, Raw=0"),
77 new SmoothedUserDrawnPath
78 {
79 DrawText = text[5],
80 Texture = gradientTexture,
81 Colour = Color4.White,
82 InputResampler = new InputResampler(),
83 },
84 });
85
86 Cell(2, 0).AddRange(new Drawable[]
87 {
88 text[3] = createLabel("Force-smoothed raw"),
89 new ArcPath(false, true, new InputResampler { ResampleRawInput = true }, gradientTexture, Color4.Green, text[3]),
90 });
91
92 Cell(2, 1).AddRange(new Drawable[]
93 {
94 text[4] = createLabel("Force-smoothed rounded"),
95 new ArcPath(false, false, new InputResampler { ResampleRawInput = true }, gradientTexture, Color4.Blue, text[4]),
96 });
97
98 Cell(2, 2).AddRange(new Drawable[]
99 {
100 text[5] = createLabel("Force-smoothed custom: Smoothed=0, Raw=0"),
101 new SmoothedUserDrawnPath
102 {
103 DrawText = text[5],
104 Texture = gradientTexture,
105 Colour = Color4.White,
106 InputResampler = new InputResampler
107 {
108 ResampleRawInput = true
109 },
110 },
111 });
112 }
113
114 private SpriteText createLabel(string text) => new SpriteText
115 {
116 Text = text,
117 Font = new FontUsage(size: 14),
118 Colour = Color4.White,
119 };
120
121 private class SmoothedPath : TexturedPath
122 {
123 protected SmoothedPath()
124 {
125 PathRadius = 2;
126 }
127
128 public InputResampler InputResampler { get; set; } = new InputResampler();
129
130 protected int NumVertices { get; set; }
131
132 protected int NumRaw { get; set; }
133
134 protected void AddRawVertex(Vector2 pos)
135 {
136 NumRaw++;
137 AddVertex(pos);
138 NumVertices++;
139 }
140
141 protected bool AddSmoothedVertex(Vector2 pos)
142 {
143 NumRaw++;
144 bool foundOne = false;
145
146 foreach (Vector2 relevant in InputResampler.AddPosition(pos))
147 {
148 AddVertex(relevant);
149 NumVertices++;
150 foundOne = true;
151 }
152
153 return foundOne;
154 }
155 }
156
157 private class ArcPath : SmoothedPath
158 {
159 public ArcPath(bool raw, bool keepFraction, InputResampler inputResampler, Texture texture, Color4 colour, SpriteText output)
160 {
161 InputResampler = inputResampler;
162
163 AutoSizeAxes = Axes.None;
164 RelativeSizeAxes = Axes.Both;
165 Texture = texture;
166 Colour = colour;
167
168 const float target_raw = 1024;
169
170 for (float i = 0; i < target_raw; i++)
171 {
172 float x = (MathF.Sin(i / target_raw * (MathF.PI * 0.5f)) * 200) + 50.5f;
173 float y = (MathF.Cos(i / target_raw * (MathF.PI * 0.5f)) * 200) + 50.5f;
174 Vector2 v = keepFraction ? new Vector2(x, y) : new Vector2((int)x, (int)y);
175 if (raw)
176 AddRawVertex(v);
177 else
178 AddSmoothedVertex(v);
179 }
180
181 output.Text += ": Smoothed=" + NumVertices + ", Raw=" + NumRaw;
182 }
183 }
184
185 private class UserDrawnPath : SmoothedPath
186 {
187 public SpriteText DrawText;
188
189 public UserDrawnPath()
190 {
191 AutoSizeAxes = Axes.None;
192 RelativeSizeAxes = Axes.Both;
193 }
194
195 protected virtual void AddUserVertex(Vector2 v) => AddRawVertex(v);
196
197 protected override bool OnDragStart(DragStartEvent e)
198 {
199 AddUserVertex(e.MousePosition);
200 DrawText.Text = "Custom Smoothed Drawn: Smoothed=" + NumVertices + ", Raw=" + NumRaw;
201 return true;
202 }
203
204 protected override void OnDrag(DragEvent e)
205 {
206 AddUserVertex(e.MousePosition);
207 DrawText.Text = "Custom Smoothed Drawn: Smoothed=" + NumVertices + ", Raw=" + NumRaw;
208 base.OnDrag(e);
209 }
210 }
211
212 private class SmoothedUserDrawnPath : UserDrawnPath
213 {
214 protected override void AddUserVertex(Vector2 v) => AddSmoothedVertex(v);
215 }
216 }
217}