ba9498b57598321b9a4f3ddb843b4cf420228ca6
[SugarCubes.git] / JR.pde
1 color BLACK = #000000;
2
3 class Gimbal extends SCPattern {
4
5 private final boolean DEBUG_MANUAL_ABG = false;
6 private final int MAXIMUM_BEATS_PER_REVOLUTION = 100;
7
8 private boolean first_run = true;
9 private final LXProjection projection;
10 private final BasicParameter beatsPerRevolutionParam = new BasicParameter("SLOW", 20./MAXIMUM_BEATS_PER_REVOLUTION);
11 private final BasicParameter hueDeltaParam = new BasicParameter("HUED", 60./360);
12 private final BasicParameter fadeFromCoreParam = new BasicParameter("FADE", 1);
13 private final BasicParameter girthParam = new BasicParameter("GRTH", .18);
14 private final BasicParameter ringExtendParam = new BasicParameter("XTND", 1);
15 private final BasicParameter relativeSpeedParam = new BasicParameter("RLSP", .83);
16 private final BasicParameter sizeParam = new BasicParameter("SIZE", .9);
17
18 private final BasicParameter aP = new BasicParameter("a", 0);
19 private final BasicParameter bP = new BasicParameter("b", 0);
20 private final BasicParameter gP = new BasicParameter("g", 0);
21
22 Gimbal(GLucose glucose) {
23 super(glucose);
24 projection = new LXProjection(model);
25 addParameter(beatsPerRevolutionParam);
26 addParameter(hueDeltaParam);
27 addParameter(fadeFromCoreParam);
28 addParameter(girthParam);
29 addParameter(ringExtendParam);
30 addParameter(relativeSpeedParam);
31 addParameter(sizeParam);
32
33 if (DEBUG_MANUAL_ABG) {
34 addParameter(aP);
35 addParameter(bP);
36 addParameter(gP);
37 }
38 }
39
40 float a = 0, b = 0, g = 0;
41
42 public void run(double deltaMs) {
43
44 if (DEBUG_MANUAL_ABG) {
45 a = aP.getValuef() * (2 * PI);
46 b = bP.getValuef() * (2 * PI);
47 g = gP.getValuef() * (2 * PI);
48 } else {
49 float relativeSpeed = relativeSpeedParam.getValuef();
50 float time = millis() / 1000.f;
51
52 int beatsPerRevolution = (int) (beatsPerRevolutionParam.getValuef() * MAXIMUM_BEATS_PER_REVOLUTION) + 1;
53 float radiansPerMs = 2 * PI // radians / revolution
54 / beatsPerRevolution // beats / revolution
55 * lx.tempo.bpmf() // BPM beats / min
56 / 60 // sec / min
57 / 1000; // ms / sec
58
59 a += deltaMs * radiansPerMs * pow(relativeSpeed, 0);
60 b += deltaMs * radiansPerMs * pow(relativeSpeed, 1);
61 g += deltaMs * radiansPerMs * pow(relativeSpeed, 2);
62 a %= 2 * PI;
63 b %= 2 * PI;
64 g %= 2 * PI;
65 }
66
67 float hue = lx.getBaseHuef();
68 float hue_delta = hueDeltaParam.getValuef() * 360;
69
70 float radius1 = model.xMax / 2 * sizeParam.getValuef();
71 float radius2 = ((model.xMax + model.yMax) / 2) / 2 * sizeParam.getValuef();
72 float radius3 = model.yMax / 2 * sizeParam.getValuef();
73 float girth = model.xMax * girthParam.getValuef();
74 Ring ring1 = new Ring((hue + hue_delta * 0) % 360, radius1, girth);
75 Ring ring2 = new Ring((hue + hue_delta * 1) % 360, radius2, girth);
76 Ring ring3 = new Ring((hue + hue_delta * 2) % 360, radius3, girth);
77
78 projection.reset()
79 // Translate so the center of the car is the origin
80 .center();
81
82 for (LXVector c : projection) {
83 //if (first_run) println(c.x + "," + c.y + "," + c.z);
84
85 rotate3d(c, a, 0, 0);
86 rotate3d(c, PI/4, PI/4, PI/4);
87 color color1 = ring1.colorFor(c);
88
89 rotate3d(c, 0, b, 0);
90 color color2 = ring2.colorFor(c);
91
92 rotate3d(c, 0, 0, g);
93 color color3 = ring3.colorFor(c);
94
95 colors[c.index] = specialBlend(color1, color2, color3);
96 }
97
98 first_run = false;
99 }
100
101 class Ring {
102
103 float hue;
104 float radius, girth;
105
106 public Ring(float hue, float radius, float girth) {
107 this.hue = hue;
108 this.radius = radius;
109 this.girth = girth;
110 }
111
112 public color colorFor(LXVector c) {
113 float theta = atan2(c.y, c.x);
114 float nearest_circle_x = cos(theta) * radius;
115 float nearest_circle_y = sin(theta) * radius;
116 float nearest_circle_z = 0;
117
118 float distance_to_circle
119 = sqrt(pow(nearest_circle_x - c.x, 2)
120 + pow(nearest_circle_y - c.y, 2)
121 + pow(nearest_circle_z - c.z * ringExtendParam.getValuef(), 2));
122
123 float xy_distance = sqrt(c.x*c.x + c.y*c.y);
124 return lx.hsb(this.hue, 100, (1 - distance_to_circle / girth * fadeFromCoreParam.getValuef()) * 100);
125 }
126
127 }
128
129 }
130
131
132
133
134
135
136 class Zebra extends SCPattern {
137
138 private final LXProjection projection;
139 SinLFO angleM = new SinLFO(0, PI * 2, 30000);
140
141 /*
142 SinLFO x, y, z, dx, dy, dz;
143 float cRad;
144 _P size;
145 */
146
147 Zebra(GLucose glucose) {
148 super(glucose);
149 projection = new LXProjection(model);
150
151 addModulator(angleM).trigger();
152 }
153
154 color colorFor(LXVector c) {
155 float hue = lx.getBaseHuef();
156
157
158
159
160 /* SLIDE ALONG
161 c.x = c.x + millis() / 100.f;
162 */
163
164
165
166 int stripe_count = 12;
167 float stripe_width = model.xMax / (float)stripe_count;
168 if (Math.floor((c.x) / stripe_width) % 2 == 0) {
169 return lx.hsb(hue, 100, 100);
170 } else {
171 return lx.hsb((hue + 90) % 360, 100, 100);
172 }
173
174
175 /* OCTANTS
176
177 if ((isPositiveBit(c.x) + isPositiveBit(c.y) + isPositiveBit(c.z)) % 2 == 0) {
178 return lx.hsb(lx.getBaseHuef(), 100, 100);
179 } else {
180 return lx.hsb(0, 0, 0);
181 }
182 */
183 }
184
185 int isPositiveBit(float f) {
186 return f > 0 ? 1 : 0;
187 }
188
189 public void run(double deltaMs) {
190 float a = (millis() / 1000.f) % (2 * PI);
191 float b = (millis() / 1200.f) % (2 * PI);
192 float g = (millis() / 1600.f) % (2 * PI);
193
194 projection.reset()
195 // Translate so the center of the car is the origin
196 .center();
197
198 for (LXVector c : projection) {
199 // rotate3d(c, a, b, g);
200 colors[c.index] = colorFor(c);
201 }
202
203 first_run = false;
204 }
205
206
207 // Utility!
208 boolean first_run = true;
209 private void log(String s) {
210 if (first_run) {
211 println(s);
212 }
213 }
214
215
216 }
217
218 void rotate3d(LXVector c, float a /* roll */, float b /* pitch */, float g /* yaw */) {
219 float cosa = cos(a);
220 float cosb = cos(b);
221 float cosg = cos(g);
222 float sina = sin(a);
223 float sinb = sin(b);
224 float sing = sin(g);
225
226 float a1 = cosa*cosb;
227 float a2 = cosa*sinb*sing - sina*cosg;
228 float a3 = cosa*sinb*cosg + sina*sing;
229 float b1 = sina*cosb;
230 float b2 = sina*sinb*sing + cosa*cosg;
231 float b3 = sina*sinb*cosg - cosa*sing;
232 float c1 = -sinb;
233 float c2 = cosb*sing;
234 float c3 = cosb*cosg;
235
236 float[] cArray = { c.x, c.y, c.z };
237 c.x = dotProduct(new float[] {a1, a2, a3}, cArray);
238 c.y = dotProduct(new float[] {b1, b2, b3}, cArray);
239 c.z = dotProduct(new float[] {c1, c2, c3}, cArray);
240 }
241
242 float dotProduct(float[] a, float[] b) {
243 float ret = 0;
244 for (int i = 0 ; i < a.length; ++i) {
245 ret += a[i] * b[i];
246 }
247 return ret;
248 }
249
250 color specialBlend(color c1, color c2, color c3) {
251 float h1 = hue(c1);
252 float h2 = hue(c2);
253 float h3 = hue(c3);
254
255 // force h1 < h2 < h3
256 while (h2 < h1) {
257 h2 += 360;
258 }
259 while (h3 < h2) {
260 h3 += 360;
261 }
262
263 float s1 = saturation(c1);
264 float s2 = saturation(c2);
265 float s3 = saturation(c3);
266
267 float b1 = brightness(c1);
268 float b2 = brightness(c2);
269 float b3 = brightness(c3);
270 float relative_b1 = b1 / (b1 + b2 + b3);
271 float relative_b2 = b2 / (b1 + b2 + b3);
272 float relative_b3 = b3 / (b1 + b2 + b3);
273
274 return lx.hsb(
275 (h1 * relative_b1 + h2 * relative_b1 + h3 * relative_b3) % 360,
276 s1 * relative_b1 + s2 * relative_b2 + s3 * relative_b3,
277 max(max(b1, b2), b3)
278 );
279 }
280