Commit | Line | Data |
---|---|---|
6c1a9e53 MS |
1 | abstract class TestPattern extends SCPattern { |
2 | public TestPattern(GLucose glucose) { | |
3 | super(glucose); | |
4 | setEligible(false); | |
5 | } | |
6 | } | |
7 | ||
254fbb68 MS |
8 | class TestStripPattern extends TestPattern { |
9 | public TestStripPattern(GLucose glucose) { | |
10 | super(glucose); | |
11 | } | |
12 | ||
13 | public void run(int deltaMs) { | |
14 | for (Strip s : model.strips) { | |
15 | for (Point p : s.points) { | |
16 | colors[p.index] = color( | |
17 | lx.getBaseHuef(), | |
18 | 100, | |
19 | max(0, 100 - 10*dist(p.x, p.y, s.cx, s.cy)) | |
20 | ); | |
21 | } | |
22 | } | |
23 | } | |
24 | } | |
25 | ||
7ef61b89 MS |
26 | /** |
27 | * Simplest demonstration of using the rotating master hue. | |
28 | * All pixels are full-on the same color. | |
29 | */ | |
6c1a9e53 | 30 | class TestHuePattern extends TestPattern { |
49815cc0 MS |
31 | public TestHuePattern(GLucose glucose) { |
32 | super(glucose); | |
33 | } | |
7ef61b89 | 34 | |
49815cc0 | 35 | public void run(int deltaMs) { |
7ef61b89 MS |
36 | // Access the core master hue via this method call |
37 | float hv = lx.getBaseHuef(); | |
49815cc0 | 38 | for (int i = 0; i < colors.length; ++i) { |
7ef61b89 | 39 | colors[i] = color(hv, 100, 100); |
49815cc0 MS |
40 | } |
41 | } | |
42 | } | |
43 | ||
7ef61b89 MS |
44 | /** |
45 | * Test of a wave moving across the X axis. | |
46 | */ | |
6c1a9e53 | 47 | class TestXPattern extends TestPattern { |
7ef61b89 | 48 | private final SinLFO xPos = new SinLFO(0, model.xMax, 4000); |
49815cc0 MS |
49 | public TestXPattern(GLucose glucose) { |
50 | super(glucose); | |
51 | addModulator(xPos).trigger(); | |
52 | } | |
53 | public void run(int deltaMs) { | |
7ef61b89 | 54 | float hv = lx.getBaseHuef(); |
87f6fa39 | 55 | for (Point p : model.points) { |
7ef61b89 MS |
56 | // This is a common technique for modulating brightness. |
57 | // You can use abs() to determine the distance between two | |
58 | // values. The further away this point is from an exact | |
59 | // point, the more we decrease its brightness | |
60 | float bv = max(0, 100 - abs(p.fx - xPos.getValuef())); | |
61 | colors[p.index] = color(hv, 100, bv); | |
49815cc0 MS |
62 | } |
63 | } | |
64 | } | |
65 | ||
7ef61b89 MS |
66 | /** |
67 | * Test of a wave on the Y axis. | |
68 | */ | |
6c1a9e53 | 69 | class TestYPattern extends TestPattern { |
7ef61b89 | 70 | private final SinLFO yPos = new SinLFO(0, model.yMax, 4000); |
49815cc0 MS |
71 | public TestYPattern(GLucose glucose) { |
72 | super(glucose); | |
73 | addModulator(yPos).trigger(); | |
74 | } | |
75 | public void run(int deltaMs) { | |
7ef61b89 | 76 | float hv = lx.getBaseHuef(); |
87f6fa39 | 77 | for (Point p : model.points) { |
7ef61b89 MS |
78 | float bv = max(0, 100 - abs(p.fy - yPos.getValuef())); |
79 | colors[p.index] = color(hv, 100, bv); | |
49815cc0 MS |
80 | } |
81 | } | |
82 | } | |
83 | ||
7ef61b89 MS |
84 | /** |
85 | * Test of a wave on the Z axis. | |
86 | */ | |
6c1a9e53 | 87 | class TestZPattern extends TestPattern { |
7ef61b89 | 88 | private final SinLFO zPos = new SinLFO(0, model.zMax, 4000); |
49815cc0 MS |
89 | public TestZPattern(GLucose glucose) { |
90 | super(glucose); | |
91 | addModulator(zPos).trigger(); | |
92 | } | |
93 | public void run(int deltaMs) { | |
7ef61b89 | 94 | float hv = lx.getBaseHuef(); |
87f6fa39 | 95 | for (Point p : model.points) { |
7ef61b89 MS |
96 | float bv = max(0, 100 - abs(p.fz - zPos.getValuef())); |
97 | colors[p.index] = color(hv, 100, bv); | |
49815cc0 MS |
98 | } |
99 | } | |
100 | } | |
f3f5a876 | 101 | |
186bc4d3 MS |
102 | /** |
103 | * This shows how to iterate over towers, enumerated in the model. | |
104 | */ | |
6c1a9e53 | 105 | class TestTowerPattern extends TestPattern { |
186bc4d3 MS |
106 | private final SawLFO towerIndex = new SawLFO(0, model.towers.size(), 1000*model.towers.size()); |
107 | ||
108 | public TestTowerPattern(GLucose glucose) { | |
109 | super(glucose); | |
110 | addModulator(towerIndex).trigger(); | |
186bc4d3 MS |
111 | } |
112 | ||
113 | public void run(int deltaMs) { | |
186bc4d3 MS |
114 | int ti = 0; |
115 | for (Tower t : model.towers) { | |
116 | for (Point p : t.points) { | |
117 | colors[p.index] = color( | |
118 | lx.getBaseHuef(), | |
119 | 100, | |
92341dd9 | 120 | max(0, 100 - 80*LXUtils.wrapdistf(ti, towerIndex.getValuef(), model.towers.size())) |
186bc4d3 MS |
121 | ); |
122 | } | |
123 | ++ti; | |
124 | } | |
125 | } | |
126 | ||
127 | } | |
128 | ||
7ef61b89 MS |
129 | /** |
130 | * This is a demonstration of how to use the projection library. A projection | |
131 | * creates a mutation of the coordinates of all the points in the model, creating | |
132 | * virtual x,y,z coordinates. In effect, this is like virtually rotating the entire | |
133 | * art car. However, since in reality the car does not move, the result is that | |
134 | * it appears that the object we are drawing on the car is actually moving. | |
135 | * | |
136 | * Keep in mind that what we are creating a projection of is the view coordinates. | |
137 | * Depending on your intuition, some operations may feel backwards. For instance, | |
138 | * if you translate the view to the right, it will make it seem that the object | |
139 | * you are drawing has moved to the left. If you scale the view up 2x, objects | |
140 | * drawn with the same absolute values will seem to be half the size. | |
141 | * | |
142 | * If this feels counterintuitive at first, don't worry. Just remember that you | |
143 | * are moving the pixels, not the structure. We're dealing with a finite set | |
144 | * of sparse, non-uniformly spaced pixels. Mutating the structure would move | |
145 | * things to a space where there are no pixels in 99% of the cases. | |
146 | */ | |
6c1a9e53 | 147 | class TestProjectionPattern extends TestPattern { |
f3f5a876 | 148 | |
7ef61b89 MS |
149 | private final Projection projection; |
150 | private final SawLFO angle = new SawLFO(0, TWO_PI, 9000); | |
151 | private final SinLFO yPos = new SinLFO(-20, 40, 5000); | |
f3f5a876 | 152 | |
7ef61b89 | 153 | public TestProjectionPattern(GLucose glucose) { |
f3f5a876 MS |
154 | super(glucose); |
155 | projection = new Projection(model); | |
156 | addModulator(angle).trigger(); | |
157 | addModulator(yPos).trigger(); | |
158 | } | |
159 | ||
160 | public void run(int deltaMs) { | |
7ef61b89 MS |
161 | // For the same reasons described above, it may logically feel to you that |
162 | // some of these operations are in reverse order. Again, just keep in mind that | |
163 | // the car itself is what's moving, not the object | |
f3f5a876 | 164 | projection.reset(model) |
7ef61b89 MS |
165 | |
166 | // Translate so the center of the car is the origin, offset by yPos | |
e0cea600 | 167 | .translateCenter(model, 0, yPos.getValuef(), 0) |
7ef61b89 MS |
168 | |
169 | // Rotate around the origin (now the center of the car) about an X-vector | |
f3f5a876 | 170 | .rotate(angle.getValuef(), 1, 0, 0) |
7ef61b89 MS |
171 | |
172 | // Scale up the Y axis (objects will look smaller in that access) | |
f3f5a876 MS |
173 | .scale(1, 1.5, 1); |
174 | ||
7ef61b89 | 175 | float hv = lx.getBaseHuef(); |
f3f5a876 MS |
176 | for (Coord c : projection) { |
177 | float d = sqrt(c.x*c.x + c.y*c.y + c.z*c.z); // distance from origin | |
178 | // d = abs(d-60) + max(0, abs(c.z) - 20); // life saver / ring thing | |
179 | d = max(0, abs(c.y) - 10 + .3*abs(c.z) + .08*abs(c.x)); // plane / spear thing | |
180 | colors[c.index] = color( | |
7ef61b89 | 181 | (hv + .6*abs(c.x) + abs(c.z)) % 360, |
f3f5a876 MS |
182 | 100, |
183 | constrain(140 - 10*d, 0, 100) | |
184 | ); | |
185 | } | |
186 | } | |
187 | } | |
bf551144 | 188 | |
6c1a9e53 | 189 | class TestCubePattern extends TestPattern { |
254d34c0 | 190 | |
cdb88d5d | 191 | private SawLFO index = new SawLFO(0, Cube.POINTS_PER_CUBE, Cube.POINTS_PER_CUBE*60); |
254d34c0 MS |
192 | |
193 | TestCubePattern(GLucose glucose) { | |
194 | super(glucose); | |
195 | addModulator(index).start(); | |
196 | } | |
197 | ||
198 | public void run(int deltaMs) { | |
199 | for (Cube c : model.cubes) { | |
200 | int i = 0; | |
201 | for (Point p : c.points) { | |
202 | colors[p.index] = color( | |
203 | lx.getBaseHuef(), | |
204 | 100, | |
205 | max(0, 100 - 80.*abs(i - index.getValuef())) | |
206 | ); | |
207 | ++i; | |
208 | } | |
209 | } | |
210 | } | |
211 | } | |
212 | ||
6c1a9e53 | 213 | class MappingTool extends TestPattern { |
bf551144 MS |
214 | |
215 | private int cubeIndex = 0; | |
216 | private int stripIndex = 0; | |
2bae07c9 | 217 | private int channelIndex = 0; |
bf551144 | 218 | |
2bae07c9 MS |
219 | public final int MAPPING_MODE_ALL = 0; |
220 | public final int MAPPING_MODE_CHANNEL = 1; | |
221 | public final int MAPPING_MODE_SINGLE_CUBE = 2; | |
222 | public int mappingMode = MAPPING_MODE_ALL; | |
bf551144 MS |
223 | |
224 | public final int CUBE_MODE_ALL = 0; | |
225 | public final int CUBE_MODE_SINGLE_STRIP = 1; | |
226 | public final int CUBE_MODE_STRIP_PATTERN = 2; | |
227 | public int cubeMode = CUBE_MODE_ALL; | |
228 | ||
229 | public boolean channelModeRed = true; | |
230 | public boolean channelModeGreen = false; | |
231 | public boolean channelModeBlue = false; | |
232 | ||
45f43cc2 | 233 | private final int numChannels; |
2bae07c9 | 234 | |
45f43cc2 MS |
235 | private final PandaMapping[] pandaMappings; |
236 | private PandaMapping activeMapping; | |
237 | private int mappingChannelIndex; | |
2bae07c9 | 238 | |
45f43cc2 | 239 | MappingTool(GLucose glucose, PandaMapping[] pandaMappings) { |
bf551144 | 240 | super(glucose); |
45f43cc2 | 241 | this.pandaMappings = pandaMappings; |
1685dc84 | 242 | numChannels = pandaMappings.length * PandaMapping.CHANNELS_PER_BOARD; |
2bae07c9 MS |
243 | setChannel(); |
244 | } | |
245 | ||
246 | private void setChannel() { | |
1685dc84 MS |
247 | mappingChannelIndex = channelIndex % PandaMapping.CHANNELS_PER_BOARD; |
248 | activeMapping = pandaMappings[channelIndex / PandaMapping.CHANNELS_PER_BOARD]; | |
2bae07c9 MS |
249 | } |
250 | ||
251 | private int cubeInChannel(Cube c) { | |
252 | int i = 1; | |
45f43cc2 | 253 | for (int index : activeMapping.channelList[mappingChannelIndex]) { |
2bae07c9 MS |
254 | if (c == model.getCubeByRawIndex(index)) { |
255 | return i; | |
256 | } | |
257 | ++i; | |
258 | } | |
259 | return 0; | |
bf551144 MS |
260 | } |
261 | ||
262 | private void printInfo() { | |
263 | println("Cube:" + cubeIndex + " Strip:" + (stripIndex+1)); | |
264 | } | |
265 | ||
266 | public void cube(int delta) { | |
267 | int len = model.cubes.size(); | |
268 | cubeIndex = (len + cubeIndex + delta) % len; | |
269 | printInfo(); | |
270 | } | |
271 | ||
272 | public void strip(int delta) { | |
45f43cc2 | 273 | int len = Cube.STRIPS_PER_CUBE; |
bf551144 MS |
274 | stripIndex = (len + stripIndex + delta) % len; |
275 | printInfo(); | |
276 | } | |
277 | ||
278 | public void run(int deltaMs) { | |
279 | color off = color(0, 0, 0); | |
280 | color c = off; | |
281 | color r = #FF0000; | |
282 | color g = #00FF00; | |
283 | color b = #0000FF; | |
284 | if (channelModeRed) c |= r; | |
285 | if (channelModeGreen) c |= g; | |
286 | if (channelModeBlue) c |= b; | |
287 | ||
288 | int ci = 0; | |
289 | for (Cube cube : model.cubes) { | |
2bae07c9 MS |
290 | boolean cubeOn = false; |
291 | int channelIndex = cubeInChannel(cube); | |
292 | switch (mappingMode) { | |
293 | case MAPPING_MODE_ALL: cubeOn = true; break; | |
294 | case MAPPING_MODE_SINGLE_CUBE: cubeOn = (cubeIndex == ci); break; | |
295 | case MAPPING_MODE_CHANNEL: cubeOn = (channelIndex > 0); break; | |
296 | } | |
297 | if (cubeOn) { | |
298 | if (mappingMode == MAPPING_MODE_CHANNEL) { | |
299 | color cc = off; | |
300 | switch (channelIndex) { | |
301 | case 1: cc = r; break; | |
302 | case 2: cc = r|g; break; | |
303 | case 3: cc = g; break; | |
304 | case 4: cc = b; break; | |
305 | case 5: cc = r|b; break; | |
306 | } | |
307 | setColor(cube, cc); | |
308 | } else if (cubeMode == CUBE_MODE_STRIP_PATTERN) { | |
bf551144 MS |
309 | int si = 0; |
310 | color sc = off; | |
311 | for (Strip strip : cube.strips) { | |
a797d019 MS |
312 | int faceI = si / Face.STRIPS_PER_FACE; |
313 | switch (faceI) { | |
bf551144 MS |
314 | case 0: sc = r; break; |
315 | case 1: sc = g; break; | |
316 | case 2: sc = b; break; | |
317 | case 3: sc = r|g|b; break; | |
318 | } | |
a797d019 | 319 | if (si % Face.STRIPS_PER_FACE == 2) { |
bf551144 MS |
320 | sc = r|g; |
321 | } | |
322 | setColor(strip, sc); | |
323 | ++si; | |
324 | } | |
325 | } else if (cubeMode == CUBE_MODE_SINGLE_STRIP) { | |
326 | setColor(cube, off); | |
327 | setColor(cube.strips.get(stripIndex), c); | |
328 | } else { | |
329 | setColor(cube, c); | |
330 | } | |
331 | } else { | |
332 | setColor(cube, off); | |
333 | } | |
334 | ++ci; | |
335 | } | |
336 | ||
337 | } | |
338 | ||
339 | public void incCube() { | |
340 | cubeIndex = (cubeIndex + 1) % model.cubes.size(); | |
341 | } | |
342 | ||
343 | public void decCube() { | |
344 | --cubeIndex; | |
345 | if (cubeIndex < 0) { | |
346 | cubeIndex += model.cubes.size(); | |
347 | } | |
348 | } | |
2bae07c9 MS |
349 | |
350 | public void incChannel() { | |
45f43cc2 | 351 | channelIndex = (channelIndex + 1) % numChannels; |
2bae07c9 MS |
352 | setChannel(); |
353 | } | |
354 | ||
355 | public void decChannel() { | |
356 | --channelIndex; | |
357 | if (channelIndex < 0) { | |
45f43cc2 | 358 | channelIndex += numChannels; |
2bae07c9 MS |
359 | } |
360 | setChannel(); | |
361 | } | |
bf551144 MS |
362 | |
363 | public void incStrip() { | |
92c06c97 | 364 | stripIndex = (stripIndex + 1) % Cube.STRIPS_PER_CUBE; |
bf551144 MS |
365 | } |
366 | ||
367 | public void decStrip() { | |
bf551144 MS |
368 | --stripIndex; |
369 | if (stripIndex < 0) { | |
92c06c97 | 370 | stripIndex += Cube.STRIPS_PER_CUBE; |
bf551144 MS |
371 | } |
372 | } | |
373 | ||
374 | public void keyPressed() { | |
375 | switch (keyCode) { | |
2bae07c9 MS |
376 | case UP: if (mappingMode == MAPPING_MODE_CHANNEL) incChannel(); else incCube(); break; |
377 | case DOWN: if (mappingMode == MAPPING_MODE_CHANNEL) decChannel(); else decCube(); break; | |
bf551144 MS |
378 | case LEFT: decStrip(); break; |
379 | case RIGHT: incStrip(); break; | |
380 | } | |
381 | switch (key) { | |
382 | case 'r': channelModeRed = !channelModeRed; break; | |
383 | case 'g': channelModeGreen = !channelModeGreen; break; | |
384 | case 'b': channelModeBlue = !channelModeBlue; break; | |
385 | } | |
386 | } | |
387 | } |