025d74f259cc0b95ecfd56695a3e7320fe563f6b
[SugarCubes.git] / JR.pde
1 color BLACK = #000000;
2
3 class Gimbal extends SCPattern {
4
5 private final PerfTimer perf = new PerfTimer();
6
7 private final boolean DEBUG_MANUAL_ABG = false;
8 private final int MAXIMUM_BEATS_PER_REVOLUTION = 100;
9
10 private boolean first_run = true;
11 private final LXProjection projection;
12 private final BasicParameter beatsPerRevolutionParam = new BasicParameter("SLOW", 25./MAXIMUM_BEATS_PER_REVOLUTION);
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);
26 projection = new LXProjection(model);
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
44 public void run(double deltaMs) {
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
80 projection.reset()
81 // Translate so the center of the car is the origin
82 .center();
83
84 for (LXVector c : projection) {
85 //if (first_run) println(c.x + "," + c.y + "," + c.z);
86
87 rotate3dA(c, a);
88 rotate3dPiOver4(c);
89 color color1 = ring1.colorFor(c);
90
91 rotate3dB(c, b);
92 color color2 = ring2.colorFor(c);
93
94 rotate3dG(c, g);
95 color color3 = ring3.colorFor(c);
96
97 colors[c.index] = specialBlend(color1, color2, color3);
98 }
99
100 first_run = false;
101 }
102
103 class Ring {
104
105 float hue;
106 float radius, girth;
107 float _multiplier;
108
109 public Ring(float hue, float radius, float girth) {
110 this.hue = hue;
111 this.radius = radius;
112 this.girth = girth;
113 this._multiplier = 100. / girth * fadeFromCoreParam.getValuef();
114 }
115
116 public color colorFor(LXVector c) {
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
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);
138 return lx.hsb(this.hue, 100, (1 - distance_to_circle / girth * fadeFromCoreParam.getValuef()) * 100);
139 */
140 }
141
142 }
143
144 }
145
146
147 class 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
193
194
195
196
197 class Zebra extends SCPattern {
198
199 private final LXProjection projection;
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);
210 projection = new LXProjection(model);
211
212 addModulator(angleM).trigger();
213 }
214
215 color colorFor(LXVector c) {
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) {
230 return lx.hsb(hue, 100, 100);
231 } else {
232 return lx.hsb((hue + 90) % 360, 100, 100);
233 }
234
235
236 /* OCTANTS
237
238 if ((isPositiveBit(c.x) + isPositiveBit(c.y) + isPositiveBit(c.z)) % 2 == 0) {
239 return lx.hsb(lx.getBaseHuef(), 100, 100);
240 } else {
241 return lx.hsb(0, 0, 0);
242 }
243 */
244 }
245
246 int isPositiveBit(float f) {
247 return f > 0 ? 1 : 0;
248 }
249
250 public void run(double deltaMs) {
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
255 projection.reset()
256 // Translate so the center of the car is the origin
257 .center();
258
259 for (LXVector c : projection) {
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
279 float HALF_OF_ONE_OVER_SQRT2_MINUS_1 = (1./sqrt(2) - 1) / 2;
280 float HALF_OF_ONE_OVER_SQRT2_PLUS_1 = (1./sqrt(2) + 1) / 2;
281 float SQRT2 = sqrt(2);
282
283 /** Equivalent to rotate3d(c, a, 0, 0); */
284 void 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); */
292 void 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); */
300 void 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); */
308 void 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
315 void rotate3d(LXVector c, float a /* roll */, float b /* pitch */, float g /* yaw */) {
316 float ox = c.x, oy = c.y, oz = c.z;
317
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;
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;
338 }
339
340 float 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
348 color 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);
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;
372
373 return lx.hsb(
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