New Grizzly code using LXOutput framework
[SugarCubes.git] / JR.pde
CommitLineData
a41f334c 1color BLACK = #000000;
e28f168c
AG
2
3class Gimbal extends SCPattern {
4
58888c69
JR
5 private final PerfTimer perf = new PerfTimer();
6
e28f168c
AG
7 private final boolean DEBUG_MANUAL_ABG = false;
8 private final int MAXIMUM_BEATS_PER_REVOLUTION = 100;
9
10 private boolean first_run = true;
9fa29818 11 private final LXProjection projection;
58888c69 12 private final BasicParameter beatsPerRevolutionParam = new BasicParameter("SLOW", 25./MAXIMUM_BEATS_PER_REVOLUTION);
e28f168c
AG
13 private final BasicParameter hueDeltaParam = new BasicParameter("HUED", 60./360);
14 private final BasicParameter fadeFromCoreParam = new BasicParameter("FADE", 1);
15 private final BasicParameter girthParam = new BasicParameter("GRTH", .18);
16 private final BasicParameter ringExtendParam = new BasicParameter("XTND", 1);
17 private final BasicParameter relativeSpeedParam = new BasicParameter("RLSP", .83);
18 private final BasicParameter sizeParam = new BasicParameter("SIZE", .9);
19
20 private final BasicParameter aP = new BasicParameter("a", 0);
21 private final BasicParameter bP = new BasicParameter("b", 0);
22 private final BasicParameter gP = new BasicParameter("g", 0);
23
24 Gimbal(GLucose glucose) {
25 super(glucose);
9fa29818 26 projection = new LXProjection(model);
e28f168c
AG
27 addParameter(beatsPerRevolutionParam);
28 addParameter(hueDeltaParam);
29 addParameter(fadeFromCoreParam);
30 addParameter(girthParam);
31 addParameter(ringExtendParam);
32 addParameter(relativeSpeedParam);
33 addParameter(sizeParam);
34
35 if (DEBUG_MANUAL_ABG) {
36 addParameter(aP);
37 addParameter(bP);
38 addParameter(gP);
39 }
40 }
41
42 float a = 0, b = 0, g = 0;
43
34327c96 44 public void run(double deltaMs) {
e28f168c
AG
45
46 if (DEBUG_MANUAL_ABG) {
47 a = aP.getValuef() * (2 * PI);
48 b = bP.getValuef() * (2 * PI);
49 g = gP.getValuef() * (2 * PI);
50 } else {
51 float relativeSpeed = relativeSpeedParam.getValuef();
52 float time = millis() / 1000.f;
53
54 int beatsPerRevolution = (int) (beatsPerRevolutionParam.getValuef() * MAXIMUM_BEATS_PER_REVOLUTION) + 1;
55 float radiansPerMs = 2 * PI // radians / revolution
56 / beatsPerRevolution // beats / revolution
57 * lx.tempo.bpmf() // BPM beats / min
58 / 60 // sec / min
59 / 1000; // ms / sec
60
61 a += deltaMs * radiansPerMs * pow(relativeSpeed, 0);
62 b += deltaMs * radiansPerMs * pow(relativeSpeed, 1);
63 g += deltaMs * radiansPerMs * pow(relativeSpeed, 2);
64 a %= 2 * PI;
65 b %= 2 * PI;
66 g %= 2 * PI;
67 }
68
69 float hue = lx.getBaseHuef();
70 float hue_delta = hueDeltaParam.getValuef() * 360;
71
72 float radius1 = model.xMax / 2 * sizeParam.getValuef();
73 float radius2 = ((model.xMax + model.yMax) / 2) / 2 * sizeParam.getValuef();
74 float radius3 = model.yMax / 2 * sizeParam.getValuef();
75 float girth = model.xMax * girthParam.getValuef();
76 Ring ring1 = new Ring((hue + hue_delta * 0) % 360, radius1, girth);
77 Ring ring2 = new Ring((hue + hue_delta * 1) % 360, radius2, girth);
78 Ring ring3 = new Ring((hue + hue_delta * 2) % 360, radius3, girth);
79
2bb56822 80 projection.reset()
e28f168c 81 // Translate so the center of the car is the origin
2bb56822 82 .center();
e28f168c 83
9fa29818 84 for (LXVector c : projection) {
e28f168c
AG
85 //if (first_run) println(c.x + "," + c.y + "," + c.z);
86
58888c69
JR
87 rotate3dA(c, a);
88 rotate3dPiOver4(c);
e28f168c
AG
89 color color1 = ring1.colorFor(c);
90
58888c69 91 rotate3dB(c, b);
e28f168c
AG
92 color color2 = ring2.colorFor(c);
93
58888c69 94 rotate3dG(c, g);
e28f168c
AG
95 color color3 = ring3.colorFor(c);
96
97 colors[c.index] = specialBlend(color1, color2, color3);
98 }
99
58888c69 100 first_run = false;
e28f168c
AG
101 }
102
103 class Ring {
104
105 float hue;
106 float radius, girth;
58888c69 107 float _multiplier;
e28f168c
AG
108
109 public Ring(float hue, float radius, float girth) {
110 this.hue = hue;
111 this.radius = radius;
112 this.girth = girth;
58888c69 113 this._multiplier = 100. / girth * fadeFromCoreParam.getValuef();
e28f168c
AG
114 }
115
9fa29818 116 public color colorFor(LXVector c) {
58888c69
JR
117 float xy_distance_to_circle = sqrt(c.x * c.x + c.y * c.y) - radius;
118 float z_distance_to_circle = c.z * ringExtendParam.getValuef();
119
120 float distance_to_circle
121 = sqrt(xy_distance_to_circle * xy_distance_to_circle
122 + z_distance_to_circle * z_distance_to_circle);
123
124 return lx.hsb(this.hue, 100, 100. - distance_to_circle * _multiplier);
125
126 /* PRE-OPTIMIZED IMPLEMENTATION
e28f168c
AG
127 float theta = atan2(c.y, c.x);
128 float nearest_circle_x = cos(theta) * radius;
129 float nearest_circle_y = sin(theta) * radius;
130 float nearest_circle_z = 0;
131
132 float distance_to_circle
133 = sqrt(pow(nearest_circle_x - c.x, 2)
134 + pow(nearest_circle_y - c.y, 2)
135 + pow(nearest_circle_z - c.z * ringExtendParam.getValuef(), 2));
136
137 float xy_distance = sqrt(c.x*c.x + c.y*c.y);
a41f334c 138 return lx.hsb(this.hue, 100, (1 - distance_to_circle / girth * fadeFromCoreParam.getValuef()) * 100);
58888c69 139 */
e28f168c 140 }
58888c69 141
e28f168c
AG
142 }
143
144}
145
146
58888c69
JR
147class PerfTimer {
148
149 private final Map<String, Integer> m = new TreeMap<String, Integer>();
150 private String current_phase = null;
151 private int current_phase_start_time = 0;
152 private int total_time = 0;
153
154 public void start(String phase_name) {
155 if (current_phase != null) {
156 stop();
157 }
158 current_phase = phase_name;
159 current_phase_start_time = millis();
160 }
161
162 public void stop() {
163 int current_time = millis();
164
165 assert(current_phase != null);
166 assert(current_phase_start_time != 0);
167 int time_ellapsed = current_time - current_phase_start_time;
168 m.put(current_phase,
169 (m.containsKey(current_phase) ? m.get(current_phase) : 0)
170 + time_ellapsed);
171
172 current_phase = null;
173 current_phase_start_time = 0;
174 total_time += time_ellapsed;
175 }
176
177 public void report() {
178 if (random(0, 60 * 4) < 1) {
179 println("~~~~~~~~~~~~~~~~~~");
180 for (String phase_name : m.keySet()) {
181 print(phase_name);
182 for (int i = phase_name.length(); i < 30; ++i) {
183 print(" ");
184 }
185 println("" + (float) m.get(phase_name) / total_time);
186 }
187 }
188 }
189
190}
191
192
e28f168c
AG
193
194
195
196
197class Zebra extends SCPattern {
198
9fa29818 199 private final LXProjection projection;
e28f168c
AG
200 SinLFO angleM = new SinLFO(0, PI * 2, 30000);
201
202/*
203 SinLFO x, y, z, dx, dy, dz;
204 float cRad;
205 _P size;
206 */
207
208 Zebra(GLucose glucose) {
209 super(glucose);
9fa29818 210 projection = new LXProjection(model);
e28f168c
AG
211
212 addModulator(angleM).trigger();
213 }
214
9fa29818 215 color colorFor(LXVector c) {
e28f168c
AG
216 float hue = lx.getBaseHuef();
217
218
219
220
221/* SLIDE ALONG
222 c.x = c.x + millis() / 100.f;
223 */
224
225
226
227 int stripe_count = 12;
228 float stripe_width = model.xMax / (float)stripe_count;
229 if (Math.floor((c.x) / stripe_width) % 2 == 0) {
a41f334c 230 return lx.hsb(hue, 100, 100);
e28f168c 231 } else {
a41f334c 232 return lx.hsb((hue + 90) % 360, 100, 100);
e28f168c
AG
233 }
234
235
236 /* OCTANTS
237
238 if ((isPositiveBit(c.x) + isPositiveBit(c.y) + isPositiveBit(c.z)) % 2 == 0) {
a41f334c 239 return lx.hsb(lx.getBaseHuef(), 100, 100);
e28f168c 240 } else {
a41f334c 241 return lx.hsb(0, 0, 0);
e28f168c
AG
242 }
243 */
244 }
245
246 int isPositiveBit(float f) {
247 return f > 0 ? 1 : 0;
248 }
249
34327c96 250 public void run(double deltaMs) {
e28f168c
AG
251 float a = (millis() / 1000.f) % (2 * PI);
252 float b = (millis() / 1200.f) % (2 * PI);
253 float g = (millis() / 1600.f) % (2 * PI);
254
2bb56822 255 projection.reset()
e28f168c 256 // Translate so the center of the car is the origin
2bb56822 257 .center();
e28f168c 258
9fa29818 259 for (LXVector c : projection) {
e28f168c
AG
260// rotate3d(c, a, b, g);
261 colors[c.index] = colorFor(c);
262 }
263
264 first_run = false;
265 }
266
267
268 // Utility!
269 boolean first_run = true;
270 private void log(String s) {
271 if (first_run) {
272 println(s);
273 }
274 }
275
276
277}
278
58888c69
JR
279float HALF_OF_ONE_OVER_SQRT2_MINUS_1 = (1./sqrt(2) - 1) / 2;
280float HALF_OF_ONE_OVER_SQRT2_PLUS_1 = (1./sqrt(2) + 1) / 2;
281float SQRT2 = sqrt(2);
282
283/** Equivalent to rotate3d(c, a, 0, 0); */
284void rotate3dA(LXVector c, float a) {
285 float ox = c.x, oy = c.y;
286 float cosa = cos(a);
287 float sina = sin(a);
288 c.x = ox * cosa - oy * sina;
289 c.y = ox * sina + oy * cosa;
290}
291/** Equivalent to rotate3d(c, 0, b, 0); */
292void rotate3dB(LXVector c, float b) {
293 float ox = c.x, oz = c.z;
294 float cosb = cos(b);
295 float sinb = sin(b);
296 c.x = ox * cosb + oz * sinb;
297 c.z = oz * cosb - ox * sinb;
298}
299/** Equivalent to rotate3d(c, 0, 0, g); */
300void rotate3dG(LXVector c, float g) {
301 float oy = c.y, oz = c.z;
302 float cosg = cos(g);
303 float sing = sin(g);
304 c.y = oy * cosg - oz * sing;
305 c.z = oz * cosg + oy * sing;
306}
307/** Equivalent to rotate3d(c, PI/4, PI/4, PI/4); */
308void rotate3dPiOver4(LXVector c) {
309 float ox = c.x, oy = c.y, oz = c.z;
310 c.x = ox / 2 + oy * HALF_OF_ONE_OVER_SQRT2_MINUS_1 + oz * HALF_OF_ONE_OVER_SQRT2_PLUS_1;
311 c.y = ox / 2 + oy * HALF_OF_ONE_OVER_SQRT2_PLUS_1 + oz * HALF_OF_ONE_OVER_SQRT2_MINUS_1;
312 c.z = - ox / SQRT2 + oy / 2 + oz / 2;
313}
314
9fa29818 315void rotate3d(LXVector c, float a /* roll */, float b /* pitch */, float g /* yaw */) {
58888c69
JR
316 float ox = c.x, oy = c.y, oz = c.z;
317
e28f168c
AG
318 float cosa = cos(a);
319 float cosb = cos(b);
320 float cosg = cos(g);
321 float sina = sin(a);
322 float sinb = sin(b);
323 float sing = sin(g);
324
325 float a1 = cosa*cosb;
326 float a2 = cosa*sinb*sing - sina*cosg;
327 float a3 = cosa*sinb*cosg + sina*sing;
328 float b1 = sina*cosb;
329 float b2 = sina*sinb*sing + cosa*cosg;
330 float b3 = sina*sinb*cosg - cosa*sing;
331 float c1 = -sinb;
332 float c2 = cosb*sing;
333 float c3 = cosb*cosg;
58888c69
JR
334
335 c.x = ox * a1 + oy * a2 + oz * a3;
336 c.y = ox * b1 + oy * b2 + oz * b3;
337 c.z = ox * c1 + oy * c2 + oz * c3;
e28f168c
AG
338}
339
340float dotProduct(float[] a, float[] b) {
341 float ret = 0;
342 for (int i = 0 ; i < a.length; ++i) {
343 ret += a[i] * b[i];
344 }
345 return ret;
346}
347
348color specialBlend(color c1, color c2, color c3) {
349 float h1 = hue(c1);
350 float h2 = hue(c2);
351 float h3 = hue(c3);
352
353 // force h1 < h2 < h3
354 while (h2 < h1) {
355 h2 += 360;
356 }
357 while (h3 < h2) {
358 h3 += 360;
359 }
360
361 float s1 = saturation(c1);
362 float s2 = saturation(c2);
363 float s3 = saturation(c3);
364
365 float b1 = brightness(c1);
366 float b2 = brightness(c2);
367 float b3 = brightness(c3);
58888c69
JR
368 float b_denominator = b1 + b2 + b3;
369 float relative_b1 = b1 / b_denominator;
370 float relative_b2 = b2 / b_denominator;
371 float relative_b3 = b3 / b_denominator;
e28f168c 372
a41f334c 373 return lx.hsb(
e28f168c
AG
374 (h1 * relative_b1 + h2 * relative_b1 + h3 * relative_b3) % 360,
375 s1 * relative_b1 + s2 * relative_b2 + s3 * relative_b3,
376 max(max(b1, b2), b3)
377 );
378}
379