From: Ben Morrow Date: Tue, 20 Aug 2013 05:26:42 +0000 (-0700) Subject: Merge branch 'master' of github.com:sugarcubes/SugarCubes into integration X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=bd33a0f155de19be679b13e02737b7a44956ed03;hp=f8ebf5d090a0dbe1e236fba5ea5de490ccc61492;p=SugarCubes.git Merge branch 'master' of github.com:sugarcubes/SugarCubes into integration --- diff --git a/BenMorrow.pde b/BenMorrow.pde new file mode 100644 index 0000000..e610155 --- /dev/null +++ b/BenMorrow.pde @@ -0,0 +1,186 @@ +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); + + super.addParams(); + } + + public void onParameterChanged(LXParameter p) { + if(p == mode) + { + if(interactive()) + { + copyValuesToKnobs(); + }else{ + copyKnobsToValues(); + } + } + } + + void copyValuesToKnobs() + { + xd.setValue(x.getValue()/200); + yd.setValue(y.getValue()/115); + zd.setValue(z.getValue()/100); + } + + void copyKnobsToValues() + { + x.setValue(xd.getValue()*200); + y.setValue(yd.getValue()*115); + z.setValue(zd.getValue()*100); + } + + boolean interactive() + { + return Math.round(mode.getValuef())>0.5; + } + + public void updateXYZVals() + { + if(interactive()) + { + xv = xd.getValuef()*200; + yv = yd.getValuef()*115; + zv = zd.getValuef()*100; + }else{ + super.updateXYZVals(); + copyValuesToKnobs(); + } + } + +} \ No newline at end of file diff --git a/GranimPattern.pde b/GranimPattern.pde new file mode 100644 index 0000000..6c3088f --- /dev/null +++ b/GranimPattern.pde @@ -0,0 +1,236 @@ +import java.util.LinkedHashMap; +class Graphic +{ + public boolean changed = false; + public int position = 0; + public ArrayList graphicBuffer; + Graphic() + { + graphicBuffer = new ArrayList(); + } + public int width() + { + return graphicBuffer.size(); + } + + +}; +class Granim extends Graphic +{ + HashMap displayList; + + Granim() + { + displayList = new HashMap(); + } + 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 displayList; + + GranimPattern(GLucose glucose) + { + super(glucose); + displayList = new HashMap(); + } + + 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 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)); + } + int colorLid=0; + public Graphic makeGraphic(int len) + { + + int[] colors= new int[len]; + for(int i =0;i 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); } } } diff --git a/SugarCubes.pde b/SugarCubes.pde index 615b3bd..0f7be33 100644 --- a/SugarCubes.pde +++ b/SugarCubes.pde @@ -25,7 +25,7 @@ LXPattern[] patterns(GLucose glucose) { return new LXPattern[] { - new HelixPattern(glucose), + new ShiftingPlane(glucose), new AskewPlanes(glucose), new Swarm(glucose), @@ -44,13 +44,18 @@ LXPattern[] patterns(GLucose glucose) { new SoundSpikes(glucose), new FaceSync(glucose), + new TimPlanes(glucose), new TimPinwheels(glucose), new TimRaindrops(glucose), new TimCubes(glucose), -// new TimTrace(glucose), + //new TimTrace(glucose), new TimSpheres(glucose), + //Ben + new DriveableCrossSections(glucose), + new GranimTestPattern2(glucose), + // Basic test patterns for reference, not art new TestCubePattern(glucose), new TestTowerPattern(glucose), @@ -60,6 +65,8 @@ LXPattern[] patterns(GLucose glucose) { // new TestYPattern(glucose), // new TestZPattern(glucose), + //slow for now, relegated to the bottom until faster! + new HelixPattern(glucose), }; } diff --git a/TestPatterns.pde b/TestPatterns.pde index 38ea229..14572a2 100644 --- a/TestPatterns.pde +++ b/TestPatterns.pde @@ -1,8 +1,15 @@ +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); } @@ -19,7 +26,7 @@ class TestHuePattern extends SCPattern { /** * 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); @@ -41,7 +48,7 @@ class TestXPattern extends SCPattern { /** * 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); @@ -59,7 +66,7 @@ class TestYPattern extends SCPattern { /** * 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); @@ -77,7 +84,7 @@ class TestZPattern extends SCPattern { /** * 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) { @@ -119,7 +126,7 @@ class TestTowerPattern extends SCPattern { * 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); @@ -161,7 +168,7 @@ class TestProjectionPattern extends SCPattern { } } -class TestCubePattern extends SCPattern { +class TestCubePattern extends TestPattern { private SawLFO index = new SawLFO(0, Cube.POINTS_PER_CUBE, Cube.POINTS_PER_CUBE*60); @@ -185,7 +192,7 @@ class TestCubePattern extends SCPattern { } } -class MappingTool extends SCPattern { +class MappingTool extends TestPattern { private int cubeIndex = 0; private int stripIndex = 0; diff --git a/_Mappings.pde b/_Mappings.pde index b049bf7..967048f 100644 --- a/_Mappings.pde +++ b/_Mappings.pde @@ -38,149 +38,153 @@ public Model buildModel() { // 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}, }), }; @@ -189,16 +193,25 @@ public Model buildModel() { ArrayList 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(); - 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)); } diff --git a/_Overlay.pde b/_Overlay.pde index 29e2353..a02aa12 100644 --- a/_Overlay.pde +++ b/_Overlay.pde @@ -33,6 +33,7 @@ abstract class OverlayUI { protected final int scrollWidth = 14; protected final color lightBlue = #666699; protected final color lightGreen = #669966; + protected final int toggleButtonSize = 10; private PImage logo; @@ -45,6 +46,8 @@ abstract class OverlayUI { protected final int pandaHeight = 13; protected final int pandaTop = height-16; + protected int eligibleLeft; + protected OverlayUI() { leftPos = width - w; leftTextPos = leftPos + 4; @@ -110,6 +113,17 @@ abstract class OverlayUI { 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); @@ -117,6 +131,7 @@ abstract class OverlayUI { textAlign(LEFT); text(title, leftTextPos, yPos += lineHeight); if (items != null) { + boolean hasScroll = (scrollPos > 0) || (scrollLength < items.length); textFont(itemFont); color textColor; boolean even = true; @@ -143,12 +158,18 @@ abstract class OverlayUI { 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)); @@ -214,6 +235,9 @@ class ControlUI extends OverlayUI { private int firstEffectY; private int firstEffectKnobY; + private int autoRotateX; + private int autoRotateY; + private final int PATTERN_LIST_LENGTH = 8; private int patternScrollPos = 0; @@ -240,6 +264,11 @@ class ControlUI extends OverlayUI { 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; @@ -396,6 +425,20 @@ class ControlUI extends OverlayUI { 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(); @@ -430,7 +473,11 @@ class ControlUI extends OverlayUI { } 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); + } } } } diff --git a/_PandaDriver.pde b/_PandaDriver.pde index e62cfff..ef86dbe 100644 --- a/_PandaDriver.pde +++ b/_PandaDriver.pde @@ -62,6 +62,13 @@ public class PandaDriver { } 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) { @@ -74,10 +81,14 @@ public class PandaDriver { 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; diff --git a/code/GLucose.jar b/code/GLucose.jar index 3525e18..54b4b70 100644 Binary files a/code/GLucose.jar and b/code/GLucose.jar differ