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