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