New ambient mode
authorTomas Wenström <tomas.wenstrom@gmail.com>
Mon, 24 Apr 2017 19:23:46 +0000 (21:23 +0200)
committerTomas Wenström <tomas.wenstrom@gmail.com>
Mon, 24 Apr 2017 19:23:46 +0000 (21:23 +0200)
src/kaka/cakelight/AmbientMode.java
src/kaka/cakelight/LedFrame.java
src/kaka/cakelight/Main.java
src/kaka/cakelight/util/SimplexNoise3D.java [new file with mode: 0644]

index 51cb1e6..a6ae8da 100644 (file)
@@ -1,8 +1,17 @@
 package kaka.cakelight;
 
+import kaka.cakelight.util.SimplexNoise3D;
+
 public class AmbientMode extends Mode { // TODO split into DynamicAmbient and StaticAmbient?
     private Thread thread; // TODO move to a dynamic sub class
     private Configuration config;
+    private int type = 0;
+
+    public AmbientMode(String[] args) {
+        if (args.length > 0) {
+            type = Integer.parseInt(args[0]);
+        }
+    }
 
     @Override
     public void enter(Configuration config) {
@@ -45,10 +54,20 @@ public class AmbientMode extends Mode { // TODO split into DynamicAmbient and St
      * @param count Goes from 0 to number of LEDs - 1
      */
     private void updateFrame(LedFrame frame, long time, int count) {
-        for (int i = 0; i < config.leds.getCount(); i++) {
-            double r = Math.sin(2 * i * Math.PI / config.leds.getCount() + time * 0.001) * 0.5 + 0.5;
-            double g = Math.cos(2 * i * Math.PI / config.leds.getCount() + time * 0.002) * 0.5 + 0.5;
-            frame.setLedColor(i, Color.rgb(r, g, 0));
+        if (type == 0) {
+            for (int i = 0; i < config.leds.getCount(); i++) {
+                double r = Math.sin(2 * i * Math.PI / config.leds.getCount() + time * 0.001) * 0.5 + 0.5;
+                double g = Math.cos(2 * i * Math.PI / config.leds.getCount() + time * 0.002) * 0.5 + 0.5;
+                frame.setLedColor(i, Color.rgb(r, g, 0));
+            }
+        } else if (type == 1) {
+            for (int i = 0; i < config.leds.getCount(); i++) {
+                double g = noise.getr(0, 0.5, 0.5, frame.xOf(i), frame.yOf(i), time / 5000.0);
+                double b = noise.getr(0, 1, 1, frame.xOf(i), frame.yOf(i), time / 7000.0);
+                frame.setLedColor(i, Color.rgb(0, g, b));
+            }
         }
     }
+
+    private SimplexNoise3D noise = new SimplexNoise3D(0);
 }
index 4d6b68a..9d95b0c 100644 (file)
@@ -1,11 +1,13 @@
 package kaka.cakelight;
 
 public class LedFrame {
+    private Configuration config;
     private byte[] bytes;
     private int roff = 0, goff = 2, boff = 1; // Color values are stored as RBG, which is what the LED list takes.
 
     public static LedFrame from(Configuration config) {
         LedFrame frame = new LedFrame();
+        frame.config = config;
         frame.bytes = new byte[config.leds.getCount() * 3];
         return frame;
     }
@@ -41,4 +43,21 @@ public class LedFrame {
     public byte[] getBytes() {
         return bytes;
     }
+
+    // TODO this needs to be improved
+    /** The x position of the led from 0.0-1.0. */
+    public double xOf(int led) {
+        /* left   */ if (led >= config.leds.cols * 2 + config.leds.rows) return 0;
+        /* top    */ if (led >= config.leds.cols + config.leds.rows) return 1 - (double)(led - config.leds.cols - config.leds.rows) / config.leds.cols;
+        /* right  */ if (led >= config.leds.cols) return 1;
+        /* bottom */ return (double)led / config.leds.cols;
+    }
+
+    /** The y position of the led from 0.0-1.0. */
+    public double yOf(int led) {
+        /* left   */ if (led >= config.leds.cols * 2 + config.leds.rows) return (double)(led - config.leds.cols * 2 - config.leds.rows) / config.leds.rows;
+        /* top    */ if (led >= config.leds.cols + config.leds.rows) return 0;
+        /* right  */ if (led >= config.leds.cols) return 1 - (double)(led - config.leds.cols) / config.leds.rows;
+        /* bottom */ return 1;
+    }
 }
index 52d3b61..59e03ff 100644 (file)
@@ -14,7 +14,7 @@ public class Main {
        log("Running with config:\n" + config);
 
        CakeLight cakelight = new CakeLight(config, new LedController(config));
-       cakelight.setMode(new AmbientMode());
+       cakelight.setMode(new AmbientMode(args));
        cakelight.startLoop();
        Runtime.getRuntime().addShutdownHook(new Thread(Main::printTimeStats));
     }
diff --git a/src/kaka/cakelight/util/SimplexNoise3D.java b/src/kaka/cakelight/util/SimplexNoise3D.java
new file mode 100644 (file)
index 0000000..7749acc
--- /dev/null
@@ -0,0 +1,97 @@
+package kaka.cakelight.util;
+
+import java.util.Random;
+
+import static java.lang.Math.*;
+
+public class SimplexNoise3D {
+    private final byte[] ptab = new byte[256];
+    private final double[][] gtab = {
+            { 1,  1,  0}, {-1,  1,  0}, { 1, -1,  0}, {-1, -1,  0},
+            { 1,  0,  1}, {-1,  0,  1}, { 1,  0, -1}, {-1,  0, -1},
+            { 0,  1,  1}, { 0, -1,  1}, { 0,  1, -1}, { 0, -1, -1},
+    };
+
+    public SimplexNoise3D(Random rnd) {
+        for(int i = 0; i < 256; i++)
+            ptab[i] = (byte)i;
+        for(int i = 0; i < 256; i++) {
+            int r = rnd.nextInt(256);
+            byte t = ptab[i]; ptab[i] = ptab[r]; ptab[r] = t;
+        }
+    }
+
+    public SimplexNoise3D(long seed) {
+        this(new Random(seed));
+    }
+
+    public SimplexNoise3D() {
+        this(new Random());
+    }
+
+    public double get(double r, double x, double y, double z) {
+        x /= r; y /= r; z /= r;
+
+        double i, j, k;
+        {
+            double s = (x + y + z) / 3;
+            i = floor(x + s);
+            j = floor(y + s);
+            k = floor(z + s);
+        }
+
+        double dx, dy, dz;
+        {
+            double s = (i + j + k) / 6;
+            dx = x - (i - s);
+            dy = y - (j - s);
+            dz = z - (k - s);
+        }
+
+        int i1, j1, k1, i2, j2, k2;
+        if((dx >= dy) && (dy >= dz)) {
+            i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0;
+        } else if((dx >= dz) && (dz >= dy)) {
+            i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1;
+        } else if((dz >= dx) && (dx >= dy)) {
+            i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1;
+        } else if((dz >= dy) && (dy >= dx)) {
+            i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1;
+        } else if((dy >= dz) && (dz >= dx)) {
+            i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1;
+        } else /* if((dy >= dx) && (dx >= dz)) */ {
+            i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0;
+        }
+
+        double x1 = dx - i1 + (1.0 / 6.0), y1 = dy - j1 + (1.0 / 6.0), z1 = dz - k1 + (1.0 / 6.0);
+        double x2 = dx - i2 + (1.0 / 3.0), y2 = dy - j2 + (1.0 / 3.0), z2 = dz - k2 + (1.0 / 3.0);
+        double x3 = dx - 0.5, y3 = dy - 0.5, z3 = dz - 0.5;
+
+        int ip = (int)i, jp = (int)j, kp = (int)k;
+        double[] g0 = gtab[((int)ptab[(int)(ip      + ptab[(int)(jp      + ptab[(int)kp        & 0xff]) & 0xff]) & 0xff] & 0xff) % 12];
+        double[] g1 = gtab[((int)ptab[(int)(ip + i1 + ptab[(int)(jp + j1 + ptab[(int)(kp + k1) & 0xff]) & 0xff]) & 0xff] & 0xff) % 12];
+        double[] g2 = gtab[((int)ptab[(int)(ip + i2 + ptab[(int)(jp + j2 + ptab[(int)(kp + k2) & 0xff]) & 0xff]) & 0xff] & 0xff) % 12];
+        double[] g3 = gtab[((int)ptab[(int)(ip +  1 + ptab[(int)(jp +  1 + ptab[(int)(kp +  1) & 0xff]) & 0xff]) & 0xff] & 0xff) % 12];
+
+        double n0 = 0.6 - (dx * dx) - (dy * dy) - (dz * dz);
+        double n1 = 0.6 - (x1 * x1) - (y1 * y1) - (z1 * z1);
+        double n2 = 0.6 - (x2 * x2) - (y2 * y2) - (z2 * z2);
+        double n3 = 0.6 - (x3 * x3) - (y3 * y3) - (z3 * z3);
+
+        double v = 0.0;
+        if(n0 > 0) v += n0 * n0 * n0 * n0 * ((g0[0] * dx) + (g0[1] * dy) + (g0[2] * dz));
+        if(n1 > 0) v += n1 * n1 * n1 * n1 * ((g1[0] * x1) + (g1[1] * y1) + (g1[2] * z1));
+        if(n2 > 0) v += n2 * n2 * n2 * n2 * ((g2[0] * x2) + (g2[1] * y2) + (g2[2] * z2));
+        if(n3 > 0) v += n3 * n3 * n3 * n3 * ((g3[0] * x3) + (g3[1] * y3) + (g3[2] * z3));
+
+        return(min(max(v * 32, -1.0), 1.0));
+    }
+
+    public double getr(double lo, double hi, double r, double x, double y, double z) {
+        return((((get(r, x, y, z) * 0.5) + 0.5) * (hi - lo)) + lo);
+    }
+
+    public int geti(int lo, int hi, double r, double x, double y, double z) {
+        return(min((int)(((get(r, x, y, z) * 0.5) + 0.5) * (hi - lo)), (int)((hi - lo) - 1)) + lo);
+    }
+}