private final SinLFO a;
private final SinLFO b;
private final SinLFO c;
- float av;
- float bv;
- float cv;
- float denom;
+ float av = 1;
+ float bv = 1;
+ float cv = 1;
+ float denom = 0.1;
Plane(int i) {
addModulator(a = new SinLFO(-1, 1, 4000 + 1029*i)).trigger();
planes[i] = new Plane(i);
}
}
-
- private final float denoms[] = new float[NUM_PLANES];
public void run(int deltaMs) {
float huev = lx.getBaseHuef();
- int i = 0;
- for (Plane p : planes) {
- p.run(deltaMs);
- }
+
+ // This is super fucking bizarre. But if this is a for loop, the framerate
+ // tanks to like 30FPS, instead of 60. Call them manually and it works fine.
+ // Doesn't make ANY sense... there must be some weird side effect going on
+ // with the Processing internals perhaps?
+// for (Plane plane : planes) {
+// plane.run(deltaMs);
+// }
+ planes[0].run(deltaMs);
+ planes[1].run(deltaMs);
+ planes[2].run(deltaMs);
+
for (Point p : model.points) {
- float d = MAX_FLOAT;
- for (Plane plane : planes) {
- d = min(d, abs(plane.av*(p.fx-model.xMax/2.) + plane.bv*(p.fy-model.yMax/2.) + plane.cv) / plane.denom);
- }
- colors[p.index] = color(
- (lx.getBaseHuef() + abs(p.fx-model.xMax/2.)*.3 + p.fy*.8) % 360,
- max(0, 100 - .8*abs(p.fx - model.xMax/2.)),
- constrain(140 - 10.*d, 0, 100)
- );
+ float d = MAX_FLOAT;
+ for (Plane plane : planes) {
+ if (plane.denom != 0) {
+ d = min(d, abs(plane.av*(p.fx-model.cx) + plane.bv*(p.fy-model.cy) + plane.cv) / plane.denom);
+ }
+ }
+ colors[p.index] = color(
+ (huev + abs(p.fx-model.cx)*.3 + p.fy*.8) % 360,
+ max(0, 100 - .8*abs(p.fx - model.cx)),
+ constrain(140 - 10.*d, 0, 100)
+ );
}
}
}
float dv = d.getValuef();
float denom = sqrt(av*av + bv*bv + cv*cv);
for (Point p : model.points) {
- float d = abs(av*(p.fx-model.xMax/2.) + bv*(p.fy-model.yMax/2.) + cv*(p.fz-model.zMax/2.) + dv) / denom;
+ float d = abs(av*(p.fx-model.cx) + bv*(p.fy-model.cy) + cv*(p.fz-model.cz) + dv) / denom;
colors[p.index] = color(
- (hv + abs(p.fx-model.xMax/2.)*.6 + abs(p.fy-model.yMax/2)*.9 + abs(p.fz - model.zMax/2.)) % 360,
+ (hv + abs(p.fx-model.cx)*.6 + abs(p.fy-model.cy)*.9 + abs(p.fz - model.cz)) % 360,
constrain(110 - d*6, 0, 100),
constrain(130 - 7*d, 0, 100)
);
new GlitchPlasma(glucose),
new FireEffect(glucose),
new StripBounce(glucose),
- new SoundCubes(glucose),
+ new SoundRain(glucose),
+ new SoundSpikes(glucose),
+ new FaceSync(glucose),
// Basic test patterns for reference, not art
new TestCubePattern(glucose),
+abstract class TestPattern extends SCPattern {
+ public TestPattern(GLucose glucose) {
+ super(glucose);
+ setEligible(false);
+ }
+}
+
/**
* Simplest demonstration of using the rotating master hue.
* All pixels are full-on the same color.
*/
-class TestHuePattern extends SCPattern {
+class TestHuePattern extends TestPattern {
public TestHuePattern(GLucose glucose) {
super(glucose);
}
/**
* Test of a wave moving across the X axis.
*/
-class TestXPattern extends SCPattern {
+class TestXPattern extends TestPattern {
private final SinLFO xPos = new SinLFO(0, model.xMax, 4000);
public TestXPattern(GLucose glucose) {
super(glucose);
/**
* Test of a wave on the Y axis.
*/
-class TestYPattern extends SCPattern {
+class TestYPattern extends TestPattern {
private final SinLFO yPos = new SinLFO(0, model.yMax, 4000);
public TestYPattern(GLucose glucose) {
super(glucose);
/**
* Test of a wave on the Z axis.
*/
-class TestZPattern extends SCPattern {
+class TestZPattern extends TestPattern {
private final SinLFO zPos = new SinLFO(0, model.zMax, 4000);
public TestZPattern(GLucose glucose) {
super(glucose);
/**
* This shows how to iterate over towers, enumerated in the model.
*/
-class TestTowerPattern extends SCPattern {
+class TestTowerPattern extends TestPattern {
private final SawLFO towerIndex = new SawLFO(0, model.towers.size(), 1000*model.towers.size());
public TestTowerPattern(GLucose glucose) {
* of sparse, non-uniformly spaced pixels. Mutating the structure would move
* things to a space where there are no pixels in 99% of the cases.
*/
-class TestProjectionPattern extends SCPattern {
+class TestProjectionPattern extends TestPattern {
private final Projection projection;
private final SawLFO angle = new SawLFO(0, TWO_PI, 9000);
}
}
-class TestCubePattern extends SCPattern {
+class TestCubePattern extends TestPattern {
private SawLFO index = new SawLFO(0, Cube.POINTS_PER_CUBE, Cube.POINTS_PER_CUBE*60);
}
}
-class MappingTool extends SCPattern {
+class MappingTool extends TestPattern {
private int cubeIndex = 0;
private int stripIndex = 0;
+ sin(dist(p.fx, p.fy + pos / 7, 192.0, 64.0) / 7.0)
+ sin(dist(p.fx, p.fz + pos, 192.0, 100.0) / 8.0);
float bv = 100;
- colors[p.index] = color((hv+2)*25, satu, bv);
+ colors[p.index] = color((hv+2)*50, satu, bv);
}
if (random(1.0)<glitch/20) {
pos=pos-int(random(10,30));
addModulator(fX[i]).trigger();
addModulator(fY[i]).trigger();
addModulator(fZ[i]).trigger();
- colorOffset[i]=random(0,100);
+ colorOffset[i]=random(0,256);
}
}
float avgdist=0.0;
avgdist = dist(strip.points.get(8).fx,strip.points.get(8).fy,strip.points.get(8).fz,fX[i].getValuef(),fY[i].getValuef(),fZ[i].getValuef());
boolean on = avgdist<30;
- float hv = (lx.getBaseHuef()+colorOffset[i])%100;
+ float hv = (lx.getBaseHuef()+colorOffset[i])%360;
float br = max(0,100-avgdist*4);
for (Point p : strip.points) {
if (on && br>bright[p.index]) {
}
}
-class SoundCubes extends SCPattern {
+class SoundRain extends SCPattern {
private FFT fft = null;
private LinearEnvelope[] bandVals = null;
+ private float[] lightVals = null;
private int avgSize;
-
- public SoundCubes(GLucose glucose) {
+ private float gain = 25;
+ SawLFO pos = new SawLFO(0, 9, 8000);
+ SinLFO col1 = new SinLFO(0, model.xMax, 5000);
+ BasicParameter gainParameter = new BasicParameter("GAIN", 0.5);
+
+ public SoundRain(GLucose glucose) {
super(glucose);
+ addModulator(pos).trigger();
+ addModulator(col1).trigger();
+ addParameter(gainParameter);
}
+ public void onParameterChanged(LXParameter parameter) {
+ if (parameter == gainParameter) {
+ gain = 50*parameter.getValuef();
+ }
+ }
protected void onActive() {
if (this.fft == null) {
this.fft = new FFT(lx.audioInput().bufferSize(), lx.audioInput().sampleRate());
for (int i = 0; i < this.bandVals.length; ++i) {
this.addModulator(this.bandVals[i] = (new LinearEnvelope(0, 0, 700+i*4))).trigger();
}
+ lightVals = new float[avgSize];
}
}
public void run(int deltaMs) {
this.fft.forward(this.lx.audioInput().mix);
+ for (int i = 0; i < avgSize; ++i) {
+ float value = this.fft.getAvg(i);
+ this.bandVals[i].setEndVal(value,40).trigger();
+ float lv = min(value*gain,100);
+ if (lv>lightVals[i]) {
+ lightVals[i]=min(lightVals[i]+15,lv,100);
+ } else {
+ lightVals[i]=max(lv,lightVals[i]-5,0);
+ }
+ }
+ for (Cube c : model.cubes) {
+ for (int j=0; j<c.strips.size(); j++) {
+ Strip s = c.strips.get(j);
+ if (j%4!=0 && j%4!=2) {
+ for (Point p : s.points) {
+ int seq = int(p.fy*avgSize/model.yMax+pos.getValuef()+sin(p.fx+p.fz)*2)%avgSize;
+ seq=min(abs(seq-(avgSize/2)),avgSize-1);
+ colors[p.index] = color(200,max(0,100-abs(p.fx-col1.getValuef())/2),lightVals[seq]);
+ }
+ }
+ }
+ }
+ }
+}
+
+class FaceSync extends SCPattern {
+ SinLFO xosc = new SinLFO(-10, 10, 3000);
+ SinLFO zosc = new SinLFO(-10, 10, 3000);
+ SinLFO col1 = new SinLFO(0, model.xMax, 5000);
+ SinLFO col2 = new SinLFO(0, model.xMax, 4000);
+
+ public FaceSync(GLucose glucose) {
+ super(glucose);
+ addModulator(xosc).trigger();
+ addModulator(zosc).trigger();
+ zosc.setValue(0);
+ addModulator(col1).trigger();
+ addModulator(col2).trigger();
+ col2.setValue(model.xMax);
+ }
+
+ public void run(int deltaMs) {
+ int i=0;
+ for (Cube c : model.cubes) {
+ i++;
+ for (Point p : c.points) {
+ float dx, dz;
+ if (i%2==0) {
+ dx = p.fx - (c.cx+xosc.getValuef());
+ dz = p.fz - (c.cz+zosc.getValuef());
+ } else {
+ dx = p.fx - (c.cx+zosc.getValuef());
+ dz = p.fz - (c.cz+xosc.getValuef());
+ }
+ //println(dx);
+ float a1=max(0,100-abs(p.fx-col1.getValuef()));
+ float a2=max(0,100-abs(p.fx-col2.getValuef()));
+ float sat = max(a1,a2);
+ float h = (359*a1+200*a2) / (a1+a2);
+ colors[p.index] = color(h,sat,100-abs(dx*5)-abs(dz*5));
+ }
+ }
+ }
+}
+
+class SoundSpikes extends SCPattern {
+ private FFT fft = null;
+ private LinearEnvelope[] bandVals = null;
+ private float[] lightVals = null;
+ private int avgSize;
+ private float gain = 25;
+ BasicParameter gainParameter = new BasicParameter("GAIN", 0.5);
+ SawLFO pos = new SawLFO(0, model.xMax, 8000);
+
+ public SoundSpikes(GLucose glucose) {
+ super(glucose);
+ addParameter(gainParameter);
+ addModulator(pos).trigger();
+ }
+ public void onParameterChanged(LXParameter parameter) {
+ if (parameter == gainParameter) {
+ gain = 50*parameter.getValuef();
+ }
+ }
+ protected void onActive() {
+ if (this.fft == null) {
+ this.fft = new FFT(lx.audioInput().bufferSize(), lx.audioInput().sampleRate());
+ this.fft.window(FFT.HAMMING);
+ this.fft.logAverages(40, 1);
+ this.avgSize = this.fft.avgSize();
+ this.bandVals = new LinearEnvelope[this.avgSize];
+ for (int i = 0; i < this.bandVals.length; ++i) {
+ this.addModulator(this.bandVals[i] = (new LinearEnvelope(0, 0, 700+i*4))).trigger();
+ }
+ lightVals = new float[avgSize];
+ }
+ }
+
+ public void run(int deltaMs) {
+ this.fft.forward(this.lx.audioInput().mix);
for (int i = 0; i < avgSize; ++i) {
float value = this.fft.getAvg(i);
this.bandVals[i].setEndVal(value,40).trigger();
+ float lv = min(value*gain,model.yMax+10);
+ if (lv>lightVals[i]) {
+ lightVals[i]=min(lightVals[i]+30,lv,model.yMax+10);
+ } else {
+ lightVals[i]=max(lv,lightVals[i]-10,0);
+ }
}
- for (Point p : model.points) {
- colors[p.index] = color(100,0,bandVals[1].getValuef()*25 );
+ int i = 0;
+ for (Cube c : model.cubes) {
+ for (int j=0; j<c.strips.size(); j++) {
+ Strip s = c.strips.get(j);
+ if (j%4!=0 && j%4!=2) {
+ for (Point p : s.points) {
+ float dis = (abs(p.fx-model.xMax/2)+pos.getValuef())%model.xMax/2;
+ int seq = int((dis*avgSize*2)/model.xMax);
+ if (seq>avgSize) seq=avgSize-seq;
+ seq=constrain(seq,0,avgSize-1);
+ float br=max(0, lightVals[seq]-p.fy);
+ colors[p.index] = color((dis*avgSize*65)/model.xMax,90,br);
+ }
+ }
+ }
}
}
}
+
// y-axis.
//
// The cubes automatically increment their y-position by Cube.EDGE_HEIGHT.
+
+ final float STACKED_RELATIVE = 1;
+ final float STACKED_REL_SPIN = 2;
+
TowerMapping[] mapping = new TowerMapping[] {
new TowerMapping(0, 0, 0, new float[][] {
- {0, 0},
- {5, -10, 20},
- {0, -6},
- {-5, -2, -20},
+ {STACKED_RELATIVE, 0, 0},
+ {STACKED_RELATIVE, 5, -10, 20},
+ {STACKED_RELATIVE, 0, -6},
+ {STACKED_RELATIVE, -5, -2, -20},
}),
new TowerMapping(Cube.EDGE_WIDTH + 2, 0, 0, new float[][] {
- {0, 0},
- {0, 5, 10},
- {0, 2, 20},
- {0, 0, 30},
+ {STACKED_RELATIVE, 0, 0},
+ {STACKED_RELATIVE, 0, 5, 10},
+ {STACKED_RELATIVE, 0, 2, 20},
+ {STACKED_RELATIVE, 0, 0, 30},
}),
// Back Cubes behind DJ platform (in order of increasing x)
new TowerMapping(50, 5, BASS_DEPTH, new float[][] {
- {0, 0},
- {2, 0, 20},
- {-2, 10},
- {-5, 15, -20},
- {-2, 13},
+ {STACKED_RELATIVE, 0, 0},
+ {STACKED_RELATIVE, 2, 0, 20},
+ {STACKED_RELATIVE, -2, 10},
+ {STACKED_RELATIVE, -5, 15, -20},
+ {STACKED_RELATIVE, -2, 13},
}),
new TowerMapping(79, 5, BASS_DEPTH, new float[][] {
- {0, 0},
- {2, 0, 20},
- {4, 10},
- {2, 15, -20},
- {0, 13},
+ {STACKED_RELATIVE, 0, 0},
+ {STACKED_RELATIVE, 2, 0, 20},
+ {STACKED_RELATIVE, 4, 10},
+ {STACKED_RELATIVE, 2, 15, -20},
+ {STACKED_RELATIVE, 0, 13},
}),
new TowerMapping(107, 5, BASS_DEPTH, new float[][] {
- {0, 0},
- {4, 0, 20},
- {6, 10},
- {3, 15, -20},
- // {8, 13},
+ {STACKED_RELATIVE, 0, 0},
+ {STACKED_RELATIVE, 4, 0, 20},
+ {STACKED_RELATIVE, 6, 10},
+ {STACKED_RELATIVE, 3, 15, -20},
+ // {STACKED_RELATIVE, 8, 13},
}),
new TowerMapping(133, 5, BASS_DEPTH, new float[][] {
- {0, 0},
- {-2, 0, 20},
- {0, 10},
- {2, 15, -20},
- // {4, 13}
+ {STACKED_RELATIVE, 0, 0},
+ {STACKED_RELATIVE, -2, 0, 20},
+ {STACKED_RELATIVE, 0, 10},
+ {STACKED_RELATIVE, 2, 15, -20},
+ // {STACKED_RELATIVE, 4, 13}
}),
new TowerMapping(165, 5, BASS_DEPTH, new float[][] {
- {0, 0},
- {-1, 20},
- {2, 10},
- {-2, 15, -20},
- {3, 13},
+ {STACKED_RELATIVE, 0, 0},
+ {STACKED_RELATIVE, -1, 20},
+ {STACKED_RELATIVE, 2, 10},
+ {STACKED_RELATIVE, -2, 15, -20},
+ {STACKED_RELATIVE, 3, 13},
}),
// front DJ cubes
new TowerMapping((TRAILER_WIDTH - BASS_WIDTH)/2, BASS_HEIGHT, 10, new float[][] {
- {0, 0},
- {0, -10, 20},
+ {STACKED_RELATIVE, 0, 0},
+ {STACKED_RELATIVE, 0, -10, 20},
}),
new TowerMapping((TRAILER_WIDTH - BASS_WIDTH)/2 + Cube.EDGE_HEIGHT, BASS_HEIGHT, 10, new float[][] {
- {3, 0},
- {2, -10, 20},
+ {STACKED_RELATIVE, 3, 0},
+ {STACKED_RELATIVE, 2, -10, 20},
}),
new TowerMapping((TRAILER_WIDTH - BASS_WIDTH)/2 + 2*Cube.EDGE_HEIGHT + 5, BASS_HEIGHT, 10, new float[][] {
- {0, 0},
- {1, 0, 10},
+ {STACKED_RELATIVE, 0, 0},
+ {STACKED_RELATIVE, 1, 0, 10},
}),
new TowerMapping((TRAILER_WIDTH - BASS_WIDTH)/2 + 3*Cube.EDGE_HEIGHT + 9, BASS_HEIGHT, 10, new float[][] {
- {0, 0},
- {-1, 0},
+ {STACKED_RELATIVE, 0, 0},
+ {STACKED_RELATIVE, -1, 0},
}),
new TowerMapping((TRAILER_WIDTH - BASS_WIDTH)/2 + 4*Cube.EDGE_HEIGHT + 15, BASS_HEIGHT, 10, new float[][] {
- {0, 0},
- {-1, 0},
+ {STACKED_RELATIVE, 0, 0},
+ {STACKED_RELATIVE, -1, 0},
}),
// left dj cubes
new TowerMapping((TRAILER_WIDTH - BASS_WIDTH)/2, BASS_HEIGHT, Cube.EDGE_HEIGHT + 2, new float[][] {
- {0, 0},
- {0, 2, 20},
+ {STACKED_RELATIVE, 0, 0},
+ {STACKED_RELATIVE, 0, 2, 20},
}),
new TowerMapping((TRAILER_WIDTH - BASS_WIDTH)/2, BASS_HEIGHT, 2*Cube.EDGE_HEIGHT + 4, new float[][] {
- {0, 0},
- {0, 2, 20},
+ {STACKED_RELATIVE, 0, 0},
+ {STACKED_RELATIVE, 0, 2, 20},
}),
// right dj cubes
new TowerMapping((TRAILER_WIDTH - BASS_WIDTH)/2 + 4*Cube.EDGE_HEIGHT + 15, BASS_HEIGHT, Cube.EDGE_HEIGHT + 2, new float[][] {
- {0, 0},
- {0, 2, 20},
+ {STACKED_RELATIVE, 0, 0},
+ {STACKED_RELATIVE, 0, 2, 20},
}),
new TowerMapping((TRAILER_WIDTH - BASS_WIDTH)/2 + 4*Cube.EDGE_HEIGHT + 15, BASS_HEIGHT, 2*Cube.EDGE_HEIGHT + 4, new float[][] {
- {0, 0},
- {0, 2, 20},
+ {STACKED_RELATIVE, 0, 0},
+ {STACKED_RELATIVE, 0, 2, 20},
}),
new TowerMapping(200, 0, 0, new float[][] {
- {0, 10},
- {5, 0, 20},
- {0, 4},
- {-5, 8, -20},
- {0, 3},
+ {STACKED_RELATIVE, 0, 10},
+ {STACKED_RELATIVE, 5, 0, 20},
+ {STACKED_RELATIVE, 0, 4},
+ {STACKED_RELATIVE, -5, 8, -20},
+ {STACKED_RELATIVE, 0, 3},
}),
new TowerMapping(0, 0, Cube.EDGE_HEIGHT + 10, new float[][] {
- {10, 0, 40},
- {3, -2, 20},
- {0, 0, 40},
- {0, 0, 60},
- {0, 0, 40},
+ {STACKED_RELATIVE, 10, 0, 40},
+ {STACKED_RELATIVE, 3, -2, 20},
+ {STACKED_RELATIVE, 0, 0, 40},
+ {STACKED_RELATIVE, 0, 0, 60},
+ {STACKED_RELATIVE, 0, 0, 40},
}),
new TowerMapping(20, 0, 2*Cube.EDGE_HEIGHT + 18, new float[][] {
- {0, 0, 40},
- {10, 0, 20},
- {5, 0, 40},
- {10, 0, 60},
- {12, 0, 40},
+ {STACKED_RELATIVE, 0, 0, 40},
+ {STACKED_RELATIVE, 10, 0, 20},
+ {STACKED_RELATIVE, 5, 0, 40},
+ {STACKED_RELATIVE, 10, 0, 60},
+ {STACKED_RELATIVE, 12, 0, 40},
}),
new TowerMapping(210, 0, Cube.EDGE_HEIGHT + 15, new float[][] {
- {0, 0, 40},
- {5, 0, 20},
- {8, 0, 40},
- {3, 0, 60},
- {0, 0, 40},
+ {STACKED_RELATIVE, 0, 0, 40},
+ {STACKED_RELATIVE, 5, 0, 20},
+ {STACKED_RELATIVE, 8, 0, 40},
+ {STACKED_RELATIVE, 3, 0, 60},
+ {STACKED_RELATIVE, 0, 0, 40},
}),
new TowerMapping(210, 0, 2*Cube.EDGE_HEIGHT + 25, new float[][] {
- {0, 0, 40},
- {5, 0, 20},
- {2, 0, 40},
- {5, 0, 60},
- {0, 0, 40},
+ {STACKED_RELATIVE, 0, 0, 40},
+ {STACKED_RELATIVE, 5, 0, 20},
+ {STACKED_RELATIVE, 2, 0, 40},
+ {STACKED_RELATIVE, 5, 0, 60},
+ {STACKED_RELATIVE, 0, 0, 40},
}),
};
ArrayList<Cube> tower;
Cube[] cubes = new Cube[79];
int cubeIndex = 1;
- float x, y, z, ry;
+ float tx, ty, tz, px, pz, ny, dx, dz, ry;
for (TowerMapping tm : mapping) {
tower = new ArrayList<Cube>();
- x = tm.x;
- y = tm.y;
- z = tm.z;
+ px = tx = tm.x;
+ ny = ty = tm.y;
+ pz = tz = tm.z;
+ int ti = 0;
for (float[] cp : tm.cubePositions) {
- ry = (cp.length >= 3) ? cp[2] : 0;
- tower.add(cubes[cubeIndex++] = new Cube(x + cp[0], y, z + cp[1], 0, ry, 0));
- y += Cube.EDGE_HEIGHT;
+ float mode = cp[0];
+ if (mode == STACKED_RELATIVE) {
+ dx = cp[1];
+ dz = cp[2];
+ ry = (cp.length >= 4) ? cp[3] : 0;
+ tower.add(cubes[cubeIndex++] = new Cube(px = tx + dx, ny, pz = tz + dz, 0, ry, 0));
+ ny += Cube.EDGE_HEIGHT;
+ } else if (mode == STACKED_REL_SPIN) {
+ // Same as above but the front left of this cube is actually its back right for wiring
+ // TODO(mcslee): implement this
+ }
}
towerList.add(new Tower(tower));
}
protected final int scrollWidth = 14;
protected final color lightBlue = #666699;
protected final color lightGreen = #669966;
+ protected final int toggleButtonSize = 10;
private PImage logo;
protected final int pandaHeight = 13;
protected final int pandaTop = height-16;
+ protected int eligibleLeft;
+
protected OverlayUI() {
leftPos = width - w;
leftTextPos = leftPos + 4;
return drawObjectList(yPos, title, items, names, stateMethod, sz, 0);
}
+ protected void drawToggleButton(float x, float y, boolean eligible, color textColor) {
+ noFill();
+ stroke(textColor);
+ rect(x, y, toggleButtonSize, toggleButtonSize);
+ if (eligible) {
+ noStroke();
+ fill(textColor);
+ rect(x + 2, y + 2, toggleButtonSize - 4, toggleButtonSize - 4);
+ }
+ }
+
protected int drawObjectList(int yPos, String title, Object[] items, String[] names, Method stateMethod, int scrollLength, int scrollPos) {
noStroke();
fill(titleColor);
textAlign(LEFT);
text(title, leftTextPos, yPos += lineHeight);
if (items != null) {
+ boolean hasScroll = (scrollPos > 0) || (scrollLength < items.length);
textFont(itemFont);
color textColor;
boolean even = true;
fill(even ? #666666 : #777777);
break;
}
+ noStroke();
rect(leftPos, yPos+6, w, lineHeight);
fill(textColor);
text(names[i], leftTextPos, yPos += lineHeight);
+ if (lx.isAutoTransitionEnabled() && items[i] instanceof LXPattern) {
+ boolean eligible = ((LXPattern)items[i]).isEligible();
+ eligibleLeft = leftPos + w - (hasScroll ? scrollWidth : 0) - 15;
+ drawToggleButton(eligibleLeft, yPos-8, eligible, textColor);
+ }
even = !even;
}
- if ((scrollPos > 0) || (scrollLength < items.length)) {
+ if (hasScroll) {
int yHere = yPos+6;
noStroke();
fill(color(0, 0, 0, 50));
private int firstEffectY;
private int firstEffectKnobY;
+ private int autoRotateX;
+ private int autoRotateY;
+
private final int PATTERN_LIST_LENGTH = 8;
private int patternScrollPos = 0;
public void draw() {
drawLogoAndBackground();
int yPos = 0;
+ autoRotateX = leftPos + w - 29;
+ autoRotateY = yPos + 12;
+ drawToggleButton(autoRotateX, autoRotateY, lx.isAutoTransitionEnabled(), #999999);
+ fill(lx.isAutoTransitionEnabled() ? #222222: #999999);
+ text("A", autoRotateX + 2, autoRotateY + 9);
firstPatternY = yPos + lineHeight + 6;
yPos = drawObjectList(yPos, "PATTERN", patterns, patternNames, patternStateMethod, PATTERN_LIST_LENGTH, patternScrollPos);
yPos += controlSpacing;
return;
}
+ if ((mouseX >= autoRotateX) &&
+ (mouseX < autoRotateX + toggleButtonSize) &&
+ (mouseY >= autoRotateY) &&
+ (mouseY < autoRotateY + toggleButtonSize)) {
+ if (lx.isAutoTransitionEnabled()) {
+ lx.disableAutoTransition();
+ println("Auto pattern transition disabled");
+ } else {
+ lx.enableAutoTransition(60000);
+ println("Auto pattern transition enabled");
+ }
+ return;
+ }
+
if (mouseY > tempoY) {
if (mouseY - tempoY < tempoHeight) {
lx.tempo.tap();
} else {
int patternIndex = objectClickIndex(firstPatternY);
if (patternIndex < patterns.length) {
- lx.goIndex(patternIndex + patternScrollPos);
+ if (lx.isAutoTransitionEnabled() && (mouseX > eligibleLeft)) {
+ patterns[patternIndex + patternScrollPos].toggleEligible();
+ } else {
+ lx.goIndex(patternIndex + patternScrollPos);
+ }
}
}
}
}
private void buildPointList(Model model, PandaMapping pm) {
+ final int[][] stripOrderings = new int[][] {
+ { 2, 1, 0, 3, 13, 12, 15, 14, 4, 7, 6, 5, 11, 10, 9, 8 }, // FRONT_LEFT
+ { 6, 5, 4, 7, 1, 0, 3, 2, 8, 11, 10, 9, 15, 14, 13, 12 }, // FRONT_RIGHT
+ { 14, 13, 12, 15, 9, 8, 11, 10, 0, 3, 2, 1, 7, 6, 5, 4 }, // REAR_LEFT
+ { 10, 9, 8, 11, 5, 4, 7, 6, 12, 15, 14, 13, 3, 2, 1, 0 }, // REAR_RIGHT
+ };
+
int pi = 0;
for (int[] channel : pm.channelList) {
for (int cubeNumber : channel) {
if (cube == null) {
throw new RuntimeException("Non-zero, non-existing cube specified in channel mapping (" + cubeNumber + ")");
}
- final int[] stripOrder = new int[] {
- 2, 1, 0, 3, 13, 12, 15, 14, 4, 7, 6, 5, 11, 10, 9, 8
- };
- for (int stripIndex : stripOrder) {
+ int stripOrderIndex = 0;
+ switch (cube.wiring) {
+ case FRONT_LEFT: stripOrderIndex = 0; break;
+ case FRONT_RIGHT: stripOrderIndex = 1; break;
+ case REAR_LEFT: stripOrderIndex = 2; break;
+ case REAR_RIGHT: stripOrderIndex = 3; break;
+ }
+ for (int stripIndex : stripOrderings[stripOrderIndex]) {
Strip s = cube.strips.get(stripIndex);
for (int j = s.points.size() - 1; j >= 0; --j) {
points[pi++] = s.points.get(j).index;