--- /dev/null
+class Sandbox extends SCPattern
+{
+ int c=0;
+ int prevC=0;
+ int huerange=255;
+ int pointrange= model.points.size();
+ int striprange= model.strips.size();
+ int facerange= model.faces.size();
+ int cuberange = model.cubes.size();
+ int towerrange = model.towers.size();
+ int counter=0;
+
+ Sandbox(GLucose glucose) {
+ super(glucose);
+ println("points "+pointrange);
+ println("strips "+striprange);
+ println("faces "+facerange);
+ println("cubes "+cuberange);
+ println("towers "+towerrange);
+ }
+
+ public void run(int deltaMs) {
+
+
+ if(counter % 10 ==0)
+ {
+ doDraw(c,0);
+ c = (c + 1) % towerrange;
+ long col = color(Math.round(Math.random()*255),255,255) ;
+ doDraw(c,col);
+ }
+ counter++;
+
+ }
+
+ public void doDraw(int c,long col)
+ {
+ Tower t= model.towers.get((int) c);
+ for(Point p : t.points)
+ {
+ colors[p.index] = (int) col;
+ }
+ }
+};
+
+class GranimTestPattern extends GranimPattern
+{
+ GranimTestPattern(GLucose glucose)
+ {
+ super(glucose);
+ addGraphic("myReds",new RedsGraphic(100));
+ int[] dots = {0,128,0,128,0,128,0,128,0,128,0,128};
+ addGraphic("myOtherColors",new ColorDotsGraphic(dots));
+
+ getGraphicByName("myOtherColors").position=100;
+ }
+ int counter=0;
+ public void run(int deltaMs)
+ {
+ clearALL();
+ super.run(deltaMs);
+
+ if(counter % 3 ==0)
+ {
+ Graphic reds = getGraphicByName("myReds");
+ Graphic others = getGraphicByName("myOtherColors");
+ reds.position = reds.position + 1 % 19000;
+ others.position = others.position + 10 % 19000;
+ }
+ }
+ public void clearALL()
+ {
+ for(int i = 0; i < colors.length; i++)
+ {
+ colors[i] = 0;
+ }
+ }
+
+
+}
+
+class GranimTestPattern2 extends GranimPattern
+{
+ GranimTestPattern2(GLucose glucose)
+ {
+ super(glucose);
+ /*for(int i = 0;i < 100; i++)
+ {
+ Graphic g = addGraphic("myReds_"+i,new RedsGraphic(Math.round(Math.random() * 100)));
+
+ }*/
+ Graphic g = addGraphic("myRandoms",new RandomsGranim(50));
+ g.position = 200;
+
+ }
+ int counter=0;
+ float count=0;
+ public void run(int deltaMs)
+ {
+ clearALL();
+ super.run(deltaMs);
+ Graphic randomsGraphic = getGraphicByName("myRandoms");
+ randomsGraphic.position = Math.round(sin(count)*1000)+5000;
+ count+= 0.005;
+ }
+ public void clearALL()
+ {
+ for(Point p : model.points)
+ {
+ colors[p.index] = 0;
+ }
+ }
+
+
+};
+
+class DriveableCrossSections extends CrossSections
+{
+ BasicParameter xd;
+ BasicParameter yd;
+ BasicParameter zd;
+ BasicParameter mode;
+
+ DriveableCrossSections(GLucose glucose) {
+ super(glucose);
+ }
+
+ public void addParams()
+ {
+ mode = new BasicParameter("Mode", 0.0);
+ xd = new BasicParameter("XD", 0.0);
+ yd = new BasicParameter("YD", 0.0);
+ zd = new BasicParameter("ZD", 0.0);
+ addParameter(mode);
+ addParameter(xd);
+ addParameter(yd);
+ addParameter(zd);
+ addParameter(xr);
+ addParameter(yr);
+ addParameter(zr);
+ addParameter(xw);
+ addParameter(xl);
+ addParameter(yl);
+ addParameter(zl);
+ addParameter(yw);
+ addParameter(zw);
+ }
+
+ public void onParameterChanged(LXParameter p) {
+ if(p == mode)
+ {
+ if(interactive())
+ {
+ xd.setValue(x.getValue()/200);
+ yd.setValue(y.getValue()/200);
+ zd.setValue(z.getValue()/100);
+ }
+ }
+ }
+
+ boolean interactive()
+ {
+ return Math.round(mode.getValuef())>0.5;
+ }
+
+ public void updateXYZVals()
+ {
+ if(interactive())
+ {
+ xv = xd.getValuef()*200;
+ yv = yd.getValuef()*200;
+ zv = zd.getValuef()*100;
+ }else{
+ super.updateXYZVals();
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+import java.util.LinkedHashMap;
+class Graphic
+{
+ public boolean changed = false;
+ public int position = 0;
+ public ArrayList<Integer> graphicBuffer;
+ Graphic()
+ {
+ graphicBuffer = new ArrayList<Integer>();
+ }
+ public int width()
+ {
+ return graphicBuffer.size();
+ }
+
+
+};
+class Granim extends Graphic
+{
+ HashMap<String,Graphic> displayList;
+
+ Granim()
+ {
+ displayList = new HashMap<String,Graphic>();
+ }
+ public Graphic addGraphic(String name, Graphic g)
+ {
+ while(width()< g.position+1)
+ {
+ graphicBuffer.add(color(0,0,0));
+ }
+ drawAll();
+ displayList.put(name , g);
+ changed =true;
+ return g;
+ }
+
+ public Graphic getGraphicByName(String name)
+ {
+ return displayList.get(name);
+ }
+
+ public void update()
+ {
+
+ for(Graphic g : displayList.values())
+ {
+ if(g instanceof Granim)
+ {
+ ((Granim) g).update();
+
+ }
+ changed = changed || g.changed;
+ if(changed)
+ {
+ while(width()< g.position + g.width())
+ {
+ graphicBuffer.add(color(0,0,0));
+ }
+ if(g.changed)
+ {
+ drawOne(g);
+ g.changed =false;
+ }
+ }
+ }
+ changed = false;
+
+ }
+ public void drawOne(Graphic g)
+ {
+ graphicBuffer.addAll(g.position,g.graphicBuffer);
+ }
+ public void drawAll()
+ {
+ }
+};
+class GranimPattern extends SCPattern
+{
+ HashMap<String,Graphic> displayList;
+
+ GranimPattern(GLucose glucose)
+ {
+ super(glucose);
+ displayList = new HashMap<String,Graphic>();
+ }
+
+ public Graphic addGraphic(String name, Graphic g)
+ {
+ displayList.put(name,g);
+ return g;
+ }
+
+ public Graphic getGraphicByName(String name)
+ {
+ return displayList.get(name);
+ }
+
+ public void run(int deltaMs)
+ {
+ drawToPointList();
+ }
+ private Integer[] gbuffer;
+ public void drawToPointList()
+ {
+ for(Graphic g : displayList.values())
+ {
+ if(g instanceof Granim)
+ {
+ ((Granim) g).update();
+ }
+ List<Point> drawList = model.points.subList(Math.min(g.position,colors.length-1), Math.min(g.position + g.width(),colors.length-1));
+ //println("drawlistsize "+drawList.size());
+
+ gbuffer = g.graphicBuffer.toArray(new Integer[0]);
+
+ for (int i=0; i < drawList.size(); i++)
+ {
+ colors[drawList.get(i).index] = gbuffer[i];
+ }
+ g.changed =false;
+ }
+ }
+
+};
+
+class RedsGraphic extends Graphic
+{
+ RedsGraphic()
+ {
+ super();
+ drawit(10);
+ }
+ RedsGraphic(int len)
+ {
+ super();
+ drawit(len);
+
+ }
+ void drawit(int len)
+ {
+ for(int i = 0; i < len ;i++)
+ {
+ graphicBuffer.add(color(0,255,255));
+ }
+ }
+};
+
+class RedsGranim extends Granim
+{
+ RedsGranim()
+ {
+ super();
+ addGraphic("myreds", new RedsGraphic(10));
+ }
+ RedsGranim(int len)
+ {
+ super();
+ addGraphic("myreds", new RedsGraphic(len));
+ }
+ public float count = 0.0;
+ public void update()
+ {
+ Graphic g=getGraphicByName("myreds");
+ g.position = Math.round(sin(count)*20)+100;
+ count+= 0.1;
+ if(count>Math.PI*2)
+ {
+ count=0;
+ }
+ super.update();
+ }
+
+};
+
+class RandomsGranim extends Granim
+{
+ private int _len =0 ;
+ RandomsGranim()
+ {
+ super();
+ _len =100;
+ addGraphic("myrandoms", makeGraphic(_len));
+ }
+ RandomsGranim(int len)
+ {
+ super();
+ _len=len;
+ addGraphic("myrandoms", makeGraphic(len));
+ }
+ public Graphic makeGraphic(int len)
+ {
+ int[] colors= new int[len];
+ for(int i =0;i<len;i++)
+ {
+ colors[i]=(int) Math.round(Math.random()*255);
+ }
+ return new ColorDotsGraphic(colors);
+ }
+ private int count =1;
+ private int instanceCount =0;
+ public void update()
+ {
+ super.update();
+ if(instanceCount<50 && count % 20==0)
+ {
+ instanceCount++;
+ Graphic h=addGraphic("myrandoms_"+instanceCount, makeGraphic(_len));
+ h.position = instanceCount*(_len+100);
+ println("one more " + instanceCount+" at "+h.position);
+ count=0;
+ changed = true;
+ }
+ count++;
+
+ }
+
+};
+
+
+class ColorDotsGraphic extends Graphic
+{
+ ColorDotsGraphic(int[] colorSequence)
+ {
+ super();
+ for (int colorVal : colorSequence)
+ {
+ graphicBuffer.add(color(colorVal, 255, 255));
+ }
+ changed = true;
+ }
+};
addModulator(x).trigger();
addModulator(y).trigger();
addModulator(z).trigger();
+ addParams();
+ }
+
+ public void addParams()
+ {
addParameter(xr);
addParameter(yr);
addParameter(zr);
addParameter(yw);
addParameter(zw);
}
-
- void onParameterChanged(LXParameter p) {
+
+ public void onParameterChanged(LXParameter p) {
if (p == xr) {
x.setDuration(10000 - 8800*p.getValuef());
} else if (p == yr) {
}
}
+ float xv;
+ float yv;
+ float zv;
+
+ public void updateXYZVals()
+ {
+ xv = x.getValuef();
+ yv = y.getValuef();
+ zv = z.getValuef();
+ }
+
public void run(int deltaMs) {
- float xv = x.getValuef();
- float yv = y.getValuef();
- float zv = z.getValuef();
+ updateXYZVals();
float xlv = 100*xl.getValuef();
float ylv = 100*yl.getValuef();
float zlv = 100*zl.getValuef();
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)
);
private class Line {
private final PVector origin;
private final PVector vector;
-
+
Line(PVector pt, PVector v) {
origin = pt;
vector = v.get();
vector.normalize();
}
-
+
PVector getPoint() {
return origin;
}
-
+
PVector getVector() {
return vector;
}
-
- PVector getPointAt(float t) {
- PVector pt = PVector.mult(vector, t);
- pt.add(origin);
- return pt;
+
+ PVector getPointAt(final float t) {
+ return PVector.add(origin, PVector.mult(vector, t));
}
-
- boolean isColinear(PVector pt) {
- PVector projected = projected(pt);
+
+ boolean isColinear(final PVector pt) {
+ PVector projected = projectPoint(pt);
return projected.x==pt.x && projected.y==pt.y && projected.z==pt.z;
}
-
- float getTValue(PVector pt) {
+
+ float getTValue(final PVector pt) {
PVector subtraction = PVector.sub(pt, origin);
return subtraction.dot(vector);
- }
-
- PVector projected(PVector pt) {
+ }
+
+ PVector projectPoint(final PVector pt) {
return getPointAt(getTValue(pt));
}
-
- PVector rotatePoint(PVector pt, float rads) {
+
+ PVector rotatePoint(final PVector pt, final float rads) {
Vec3D axisVec3D = new Vec3D(vector.x, vector.y, vector.z);
- Matrix4x4 mat = new Matrix4x4();
- mat.rotateAroundAxis(axisVec3D, rads);
- Vec3D ptVec3D = new Vec3D(pt.x, pt.y, pt.z);
- Vec3D rotatedPt = mat.applyTo(ptVec3D);
+ Vec3D originVec3D = new Vec3D(origin.x, origin.y, origin.z);
+ Matrix4x4 mat = new Matrix4x4().identity()
+ .rotateAroundAxis(axisVec3D, rads);
+ Vec3D ptVec3D = new Vec3D(pt.x, pt.y, pt.z).sub(originVec3D);
+ Vec3D rotatedPt = mat.applyTo(ptVec3D).add(originVec3D);
return new PVector(rotatedPt.x, rotatedPt.y, rotatedPt.z);
}
}
private class Helix {
private final Line axis;
- private final float period;
- private final float rotationPeriod;
- private final float radius;
- private final float girth;
+ private final float period; // period of coil
+ private final float rotationPeriod; // animation period
+ private final float radius; // radius of coil
+ private final float girth; // girth of coil
private final PVector referencePoint;
private float phase;
private PVector phaseNormal;
}
this.referencePoint = pt;
- this.phase = phase;
- setPhaseNormalFromPhase();
- }
-
- private void setPhaseNormalFromPhase() {
- phaseNormal = axis.getVector().cross(axis.rotatePoint(referencePoint, phase));
+ // The normal is calculated by the cross product of the axis
+ // and a random point that is not colinear with it.
+ phaseNormal = axis.getVector().cross(referencePoint);
phaseNormal.normalize();
phaseNormal.mult(radius);
}
-
- private void setPhase(float phase) {
- this.phase = phase;
- setPhaseNormalFromPhase();
+
+ Line getAxis() {
+ return axis;
}
-
+
void step(int deltaMs) {
- setPhase(phase + (deltaMs / rotationPeriod) * TWO_PI);
+ // Rotate
+ if (rotationPeriod != 0) {
+ this.phase = (phase + ((float)deltaMs / (float)rotationPeriod) * TWO_PI);
+ }
}
-
+
PVector pointOnToroidalAxis(float t) {
PVector p = axis.getPointAt(t);
PVector middle = PVector.add(p, phaseNormal);
- return axis.rotatePoint(middle, (t / period) * TWO_PI);
+ return axis.rotatePoint(middle, (t / period) * TWO_PI + phase);
}
-
- color colorOfPoint(PVector p) {
- // Calculate the projection of this point to the axis.
- PVector projectedPoint = axis.projected(p);
-
+
+ color colorOfPoint(final PVector p) {
+ float t = axis.getTValue(p);
+
+ // For performance reasons, cut out points that are outside of
+ // the tube where the toroidal coil lives.
+ if (abs(PVector.dist(p, axis.getPointAt(t)) - radius) > girth*.5f) {
+ return color(0,0,0);
+ }
+
// Find the appropriate point for the current rotation
// of the helix.
- float t = axis.getTValue(projectedPoint);
PVector toroidPoint = pointOnToroidalAxis(t);
-
+
// The rotated point represents the middle of the girth of
// the helix. Figure out if the current point is inside that
// region.
float d = PVector.dist(p, toroidPoint);
- boolean inToroid = abs(d) < girth;
-
- return color((lx.getBaseHuef() + (360*(phase / TWO_PI)))%360, (inToroid ? 100 : 0), (inToroid ? 100 : 0));
+
+ // Soften edges by fading brightness.
+ float b = constrain(100*(1 - ((d-.5*girth)/(girth*.5))), 0, 100);
+ return color((lx.getBaseHuef() + (360*(phase / TWO_PI)))%360, 80, b);
}
}
private final Helix h1;
private final Helix h2;
-
+
private final BasicParameter helix1On = new BasicParameter("H1ON", 1);
private final BasicParameter helix2On = new BasicParameter("H2ON", 1);
-
+
+ private final BasicParameter basePairsOn = new BasicParameter("BPON", 1);
+ private final BasicParameter spokePeriodParam = new BasicParameter("SPPD", 0.40);
+ private final BasicParameter spokePhaseParam = new BasicParameter("SPPH", 0.25);
+
+ private static final float helixCoilPeriod = 100;
+ private static final float helixCoilRadius = 45;
+ private static final float helixCoilGirth = 20;
+ private static final float helixCoilRotationPeriod = 10000;
+
public HelixPattern(GLucose glucose) {
super(glucose);
-
+
addParameter(helix1On);
addParameter(helix2On);
-
+ addParameter(basePairsOn);
+ addParameter(spokePhaseParam);
+ addParameter(spokePeriodParam);
+
+ PVector origin = new PVector(100, 50, 45);
+ PVector axis = new PVector(1,0,0);
+
h1 = new Helix(
- new Line(new PVector(100, 50, 70), new PVector(1,0,0)),
- 700, // period
- 50, // radius
- 30, // girth
- 0, // phase
- 10000); // rotation period (ms)
+ new Line(origin, axis),
+ helixCoilPeriod,
+ helixCoilRadius,
+ helixCoilGirth,
+ 0,
+ helixCoilRotationPeriod);
h2 = new Helix(
- new Line(new PVector(100, 50, 70), new PVector(1,0,0)),
- 700,
- 50,
- 30,
+ new Line(origin, axis),
+ helixCoilPeriod,
+ helixCoilRadius,
+ helixCoilGirth,
PI,
- 10000);
-
- // TODO(shaheen) calculate line segments between
- // toroidal points selected by stepping the
- // parameterized t value. select base pairs and
- // associated colors. lerp between colors for each
- // base pair to produce a DNA effect.
+ helixCoilRotationPeriod);
}
-
+
void run(int deltaMs) {
boolean h1on = helix1On.getValue() > 0.5;
boolean h2on = helix2On.getValue() > 0.5;
-
+ boolean spokesOn = (float)basePairsOn.getValue() > 0.5;
+ float spokePeriod = (float)spokePeriodParam.getValue() * 100 + 1;
+ float spokeGirth = 10;
+ float spokePhase = (float)spokePhaseParam.getValue() * spokePeriod;
+ float spokeRadius = helixCoilRadius - helixCoilGirth*.5f;
+
h1.step(deltaMs);
h2.step(deltaMs);
-
+
for (Point p : model.points) {
- color h1c = color(0,0,0);
- color h2c = color(0,0,0);
-
- if (h1on) {
- h1c = h1.colorOfPoint(new PVector(p.x,p.y,p.z));
+ PVector pt = new PVector(p.x,p.y,p.z);
+ color h1c = h1.colorOfPoint(pt);
+ color h2c = h2.colorOfPoint(pt);
+
+ // Find the closest spoke's t-value and calculate its
+ // axis. Until everything animates in the model reference
+ // frame, this has to be calculated at every step because
+ // the helices rotate.
+ float t = h1.getAxis().getTValue(pt) + spokePhase;
+ float spokeAxisTValue = floor(((t + spokePeriod/2) / spokePeriod)) * spokePeriod;
+ PVector h1point = h1.pointOnToroidalAxis(spokeAxisTValue);
+ PVector h2point = h2.pointOnToroidalAxis(spokeAxisTValue);
+ PVector spokeVector = PVector.sub(h2point, h1point);
+ spokeVector.normalize();
+ Line spokeLine = new Line(h1point, spokeVector);
+ float spokeLength = PVector.dist(h1point, h2point);
+ // TODO(shaheen) investigate why h1.getAxis().getPointAt(spokeAxisTValue) doesn't quite
+ // have the same value.
+ PVector spokeCenter = PVector.add(h1point, PVector.mult(spokeVector, spokeLength/2.f));
+ PVector spokeStart = PVector.add(spokeCenter, PVector.mult(spokeLine.getVector(), -spokeRadius));
+ PVector spokeEnd = PVector.add(spokeCenter, PVector.mult(spokeLine.getVector(), spokeRadius));
+ float spokeStartTValue = spokeLine.getTValue(spokeStart);
+ float spokeEndTValue = spokeLine.getTValue(spokeEnd);
+ PVector pointOnSpoke = spokeLine.projectPoint(pt);
+ float projectedTValue = spokeLine.getTValue(pointOnSpoke);
+ float percentage = constrain(PVector.dist(pointOnSpoke, spokeStart) / spokeLength, 0.f, 1.f);
+ float b = ((PVector.dist(pt, pointOnSpoke) < spokeGirth) && (PVector.dist(pointOnSpoke, spokeCenter) < spokeRadius)) ? 100.f : 0.f;
+
+ color spokeColor;
+
+ if (spokeStartTValue < spokeEndTValue) {
+ spokeColor = lerpColor(h1c, h2c, percentage);
+ } else {
+ spokeColor = lerpColor(h2c, h1c, percentage);
+ }
+
+ spokeColor = color(hue(spokeColor), 80.f, b);
+
+ if (!h1on) {
+ h1c = color(0,0,0);
}
-
- if (h2on) {
- h2c = h2.colorOfPoint(new PVector(p.x,p.y,p.z));
+
+ if (!h2on) {
+ h2c = color(0,0,0);
}
-
+
+ if (!spokesOn) {
+ spokeColor = color(0,0,0);
+ }
+
// The helices are positioned to not overlap. If that changes,
// a better blending formula is probably needed.
- colors[p.index] = blendColor(h1c, h2c, ADD);
+ colors[p.index] = blendColor(blendColor(h1c, h2c, ADD), spokeColor, ADD);
}
}
}
+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;
// 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;