// Projection stuff
private final LXProjection projection;
- SawLFO rotation = new SawLFO(0, TWO_PI, 19000);
- SinLFO yPos = new SinLFO(-25, 25, 12323);
- final BasicParameter xAngle = new BasicParameter("XANG", 0.9);
- final BasicParameter yAngle = new BasicParameter("YANG", 0.3);
- final BasicParameter zAngle = new BasicParameter("ZANG", 0.3);
+ SinLFO rotationX = new SinLFO(-PI/16, PI/8, 9000);
+ SinLFO rotationY = new SinLFO(-PI/8, PI/8, 7000);
+ SinLFO rotationZ = new SinLFO(-PI/8, PI/16, 11000);
+ SinLFO yPos = new SinLFO(-1, 1, 13234);
+ SinLFO sineHeight = new SinLFO(1, 2.5, 13234);
+ SawLFO phaseLFO = new SawLFO(0, 2 * PI, 15000 - 13000 * 0.5);
+ final BasicParameter phaseParam = new BasicParameter("Spd", 0.5);
+ final BasicParameter crazyParam = new BasicParameter("Crzy", 0.5);
final BasicParameter hueScale = new BasicParameter("HUE", 0.3);
public Swim(GLucose glucose) {
super(glucose);
projection = new LXProjection(model);
-
- addParameter(xAngle);
- addParameter(yAngle);
- addParameter(zAngle);
addParameter(hueScale);
+ addParameter(crazyParam);
+ addParameter(phaseParam);
- addModulator(rotation).trigger();
+ addModulator(rotationX).trigger();
+ addModulator(rotationY).trigger();
+ addModulator(rotationZ).trigger();
addModulator(yPos).trigger();
+ addModulator(phaseLFO).trigger();
+ }
+
+ public void onParameterChanged(LXParameter parameter) {
+ if (parameter == phaseParam) {
+ phaseLFO.setDuration(5000 - 4500 * parameter.getValuef());
+ }
}
-
int beat = 0;
float prevRamp = 0;
void run(double deltaMs) {
- // Sync to the beat
- float ramp = (float)lx.tempo.ramp();
- if (ramp < prevRamp) {
- beat = (beat + 1) % 4;
- }
- prevRamp = ramp;
- float phase = (beat+ramp) / 2.0 * 2 * PI;
-
- float denominator = max(xAngle.getValuef() + yAngle.getValuef() + zAngle.getValuef(), 1);
+ float phase = phaseLFO.getValuef();
+
+ float up_down_range = (model.yMax - model.yMin) / 4;
+ // Swim around the world
+ float crazy_factor = crazyParam.getValuef() / 0.2;
projection.reset()
- // Swim around the world
- .rotate(rotation.getValuef(), xAngle.getValuef() / denominator, yAngle.getValuef() / denominator, zAngle.getValuef() / denominator)
- .translateCenter(0, 50 + yPos.getValuef(), 0);
+ .rotate(rotationZ.getValuef() * crazy_factor, 0, 1, 0)
+ .rotate(rotationX.getValuef() * crazy_factor, 0, 0, 1)
+ .rotate(rotationY.getValuef() * crazy_factor, 0, 1, 0)
+ .translate(0, up_down_range * yPos.getValuef(), 0);
+
float model_height = model.yMax - model.yMin;
float model_width = model.xMax - model.xMin;
for (LXVector p : projection) {
float x_percentage = (p.x - model.xMin)/model_width;
- // Multiply by 1.4 to shrink the size of the sin wave to be less than the height of the cubes.
- float y_in_range = 1.4 * (2*p.y - model.yMax - model.yMin) / model_height;
+ // Multiply by sineHeight to shrink the size of the sin wave to be less than the height of the cubes.
+ float y_in_range = sineHeight.getValuef() * (2*p.y - model.yMax - model.yMin) / model_height;
float sin_x = sin(phase + 2 * PI * x_percentage);
- // Color fade near the top of the sin wave
- float v1 = sin_x > y_in_range ? (100 + 100*(y_in_range - sin_x)) : 0;
+ float size_of_sin_wave = 0.4;
+
+ float v1 = (abs(y_in_range - sin_x) > size_of_sin_wave) ? 0 : abs((y_in_range - sin_x + size_of_sin_wave) / size_of_sin_wave / 2 * 100);
+
float hue_color = (lx.getBaseHuef() + hueScale.getValuef() * (abs(p.x-model.xMax/2.)*.3 + abs(p.y-model.yMax/2)*.9 + abs(p.z - model.zMax/2.))) % 360;
- colors[p.index] = lx.hsb(hue_color, 70, v1);
+ colors[p.index] = lx.hsb(hue_color, 100, v1);
}
}
}
LXPattern[] patterns(GLucose glucose) {
return new LXPattern[] {
-
- new SineSphere(glucose),
+
+ new SineSphere(glucose),
//new CubeCurl(glucose),
// Slee
// Alex G
// Tim
+ new TimMetronome(glucose),
new TimPlanes(glucose),
new TimPinwheels(glucose),
new TimRaindrops(glucose),
new TimCubes(glucose),
// new TimTrace(glucose),
new TimSpheres(glucose),
+
+
// Jackie
new JackieSquares(glucose),
new JackieDots(glucose),
+
+ // Vincent
+ new VSTowers(glucose),
// Toby
new GlitchPlasma(glucose),
*/
class TimSpheres extends SCPattern {
private BasicParameter hueParameter = new BasicParameter("RAD", 1.0);
+ private BasicParameter periodParameter = new BasicParameter("PERIOD", 4000.0, 200.0, 10000.0);
private final SawLFO lfo = new SawLFO(0, 1, 10000);
- private final SinLFO sinLfo = new SinLFO(0, 1, 4000);
+ private final SinLFO sinLfo = new SinLFO(0, 1, periodParameter);
private final float centerX, centerY, centerZ;
class Sphere {
public TimSpheres(GLucose glucose) {
super(glucose);
addParameter(hueParameter);
+ addParameter(periodParameter);
addModulator(lfo).trigger();
addModulator(sinLfo).trigger();
centerX = (model.xMax + model.xMin) / 2;
}
}
}
+
+class TimMetronome extends SCPattern {
+ private BasicParameter clickyParameter = new BasicParameter("CLICK", 0, 0, 10.0);
+ private BasicParameter derezParameter = new BasicParameter("DREZ", 0.5, 0, 1.0);
+ private BasicParameter driftParameter = new BasicParameter("DRIFT", 0, 0, 1.0);
+ private BasicParameter fadeParameter = new BasicParameter("FADE", 0.05, 0, 0.2);
+ private float modelWidth;
+ private int beatNum;
+ private float prevTempoRamp;
+ private LXProjection projection;
+ private float[] values;
+ private float[] hues;
+
+ TimMetronome(GLucose glucose) {
+ super(glucose);
+ addParameter(clickyParameter);
+ addParameter(derezParameter);
+ addParameter(driftParameter);
+ addParameter(fadeParameter);
+ modelWidth = model.xMax - model.xMin;
+ projection = new LXProjection(model);
+ beatNum = 0;
+ prevTempoRamp = 0;
+ values = new float[model.points.size()];
+ hues = new float[model.points.size()];
+ }
+
+ public void run(double deltaMs) {
+ float tempoRamp = lx.tempo.rampf();
+ if (tempoRamp < prevTempoRamp) {
+ beatNum = (beatNum + 1) % 1000;
+ }
+ prevTempoRamp = tempoRamp;
+
+ float phase = beatNum + pow(tempoRamp, 1.0 + clickyParameter.getValuef());
+
+ projection.reset();
+ projection.translateCenter(model.xMin, model.yMin, model.cz);
+ projection.rotate(phase * 0.5 * PI, 0, 0, 1);
+
+ projection.translate(driftParameter.getValuef() * tempoRamp * modelWidth * 0.5, 0, 0);
+
+ float derezCutoff = derezParameter.getValuef();
+
+ float fadeMultiplier = (1.0 - fadeParameter.getValuef());
+
+ float armRadius = modelWidth * 0.1;
+ for (LXVector p : projection) {
+ boolean onArm = false;
+ if (abs(p.x) < armRadius) {
+ onArm = (p.y > 0) || (sqrt(pow(p.x, 2) + pow(p.y, 2)) < armRadius);
+ }
+ if (onArm) {
+ values[p.index] = 1.0;
+ hues[p.index] = (floor(phase / 4) * 90) % 360;
+ } else {
+ values[p.index] *= fadeMultiplier;
+ }
+
+ float saturation = pow(1 - values[p.index], 0.5) * 0.7 + 0.3;
+ float brightness = values[p.index];
+
+ if (random(1.0) > derezCutoff) {
+ colors[p.index] = lx.hsb(hues[p.index], saturation * 100, brightness * 100);
+ }
+ }
+ }
+}
+
--- /dev/null
+class VSTowers extends SCPattern {
+ private BasicParameter saturationParameter = new BasicParameter("SAT", 80, 0, 100);
+ private BasicParameter attackParameter = new BasicParameter("ATTK", 0.96, 0.1, 1.0);
+ private BasicParameter decayParameter = new BasicParameter("DECAY", 0.7, 0.1, 1.0);
+ private SawLFO hueLfo = new SawLFO(0, 360, 20000);
+
+ private Map<Tower, Boolean> towerOn;
+
+ class TowerFlash {
+ Tower t;
+ float value;
+ float maxVal;
+ float hue;
+ boolean hasPeaked;
+
+ TowerFlash() {
+ do {
+ t = model.towers.get(floor(random(model.towers.size())));
+ } while (towerOn.get(t));
+ towerOn.put(t, true);
+ hue = (hueLfo.getValuef() + 50*(random(2)-1.0f)) % 360;
+ value = 0.0;
+ maxVal = random(0.4) + 0.6;
+ }
+
+ boolean run(double deltaMs) {
+ if (!hasPeaked) {
+ float atk = attackParameter.getValuef();
+ float atkDuration = 10000 * (1/sqrt(atk) - 1.0f);
+ value = value + (float)deltaMs / atkDuration;
+ if (value >= maxVal) {
+ value = maxVal;
+ hasPeaked = true;
+ }
+ return false;
+ } else {
+ float dec = decayParameter.getValuef();
+ float decDuration = 10000 * (1/sqrt(dec) - 1.0f);
+ value = value - (float)deltaMs / decDuration;
+ return value <= 0;
+ }
+ }
+ }
+
+ public VSTowers(GLucose glucose) {
+ super(glucose);
+ addParameter(saturationParameter);
+ addParameter(attackParameter);
+ addParameter(decayParameter);
+ addModulator(hueLfo).trigger();
+ flashes = new LinkedList<TowerFlash>();
+ towerOn = new HashMap();
+ for (Tower t : model.towers) {
+ towerOn.put(t, false);
+ }
+ }
+
+ private List<TowerFlash> flashes;
+ private float accDelta = 0;
+
+ public void run(double deltaMs) {
+ accDelta += deltaMs;
+ float rate = lx.tempo.rampf();
+ float msPerFlash = 5000 * (1/sqrt(rate) - 1.0f);
+ if (accDelta >= msPerFlash) {
+ accDelta -= msPerFlash;
+ if (flashes.size() < model.towers.size()) {
+ flashes.add(new TowerFlash());
+ }
+ }
+ for (LXPoint p : model.points) {
+ if (random(1) < 0.2) {
+ colors[p.index] = 0;
+ }
+ }
+ for (TowerFlash tf : flashes) {
+ for (LXPoint p : tf.t.points) {
+ float towerHeight = model.yMin + tf.value * (model.yMax - model.yMin);
+ if (p.y <= towerHeight) {
+ colors[p.index] = lx.hsb(
+ (tf.hue + tf.value*50 - p.y/2) % 360,
+ saturationParameter.getValuef(),
+ tf.value*100);
+ }
+ }
+ if (tf.hasPeaked) {
+ float towerMaxHeight = model.yMin + tf.maxVal * (model.yMax - model.yMin);
+ Cube top = tf.t.cubes.get(tf.t.cubes.size()-1);
+ for (int i = tf.t.cubes.size()-1; i >= 0; --i) {
+ Cube c = tf.t.cubes.get(i);
+ float maxY = c.points.get(0).y;
+ for (LXPoint p : c.points) {
+ maxY = max(maxY, p.y);
+ }
+ if (towerMaxHeight < maxY) {
+ top = c;
+ }
+ }
+ for (LXPoint p : top.points) {
+ if (tf.value > 0.5) {
+ colors[p.index] = lx.hsb(0, 0, tf.value*100);
+ } else if (random(1) < 0.2) {
+ colors[p.index] = 0;
+ }
+ }
+ }
+ }
+ // Run flashes and remove completed ones
+ Iterator<TowerFlash> it = flashes.iterator();
+ while (it.hasNext()) {
+ TowerFlash flash = it.next();
+ if (flash.run(deltaMs)) {
+ towerOn.put(flash.t, false);
+ it.remove();
+ }
+ }
+ }
+}
+