/* vim:setf c:
 * Scheiben aus pNoise schneiden - Peter Chiochetti, Mai 2013
 * gcc -DSIM -x c slicer32.ino -o slicer32 -lm -Wall
 * Farbe: "xterm +cm" && xterm patchlevel >= 282! oder Konsole
 */

// Hier schreibt das IDE:
// Das muss zuerst kommen und
// hier muss ein Ausdruck stehen.
#ifndef SIM // Blinkenwall
#include "tlc_config.h"
#include "Tlc5940.h"
#include "BlinkenWall.h"
BlinkenWall blinkenWall(50, 0x000000);
#define bclear blinkenWall.clear
#define bsetup blinkenWall.setup
#define bupdate blinkenWall.update
#define bpoint blinkenWall.drawPoint
#endif // Blinkenwall

#ifdef SIM // Simulator...
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#define byte unsigned char
void loop();
#endif // ...Simulator

/*
 * Ken Perlins improved noise   -  http://mrl.nyu.edu/~perlin/noise/
 * C-port:  http://www.fundza.com/c4serious/noise/perlin/perlin.html
 * by Malcolm Kesson;   arduino port by Peter Chiochetti,  Sep 2007:
 * -  make permutation constant byte, obsoletes init(), lookup % 256
 */

#include <math.h>

// begin perlin noise
static const byte p[] = {   151,160,137,91,90, 15,131, 13,201,95,96,
53,194,233, 7,225,140,36,103,30,69,142, 8,99,37,240,21,10,23,190, 6,
148,247,120,234,75, 0,26,197,62,94,252,219,203,117, 35,11,32,57,177,
33,88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71,134,139,
48,27,166, 77,146,158,231,83,111,229,122, 60,211,133,230,220,105,92,
41,55,46,245,40,244,102,143,54,65,25,63,161, 1,216,80,73,209,76,132,
187,208, 89, 18,169,200,196,135,130,116,188,159, 86,164,100,109,198,
173,186, 3,64,52,217,226,250,124,123,5,202,38,147,118,126,255,82,85,
212,207,206, 59,227, 47,16,58,17,182,189, 28,42,223,183,170,213,119,
248,152,2,44,154,163,70,221,153,101,155,167,43,172, 9,129,22,39,253,
19,98,108,110,79,113,224,232,178,185,112,104,218,246, 97,228,251,34,
242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,
150,254,138,236,205, 93,222,114, 67,29,24, 72,243,141,128,195,78,66,
215,61,156,180 };

double fade(double t){ return t * t * t * (t * (t * 6 - 15) + 10); }
double lerp(double t, double a, double b){ return a + t * (b - a); }
double grad(uint8_t hash, double x, double y, double z)
{
uint8_t h = hash & 15;          /* CONVERT LO 4 BITS OF HASH CODE */
double  u = h < 8 ? x : y,      /* INTO 12 GRADIENT DIRECTIONS.   */
        v = h < 4 ? y : h==12||h==14 ? x : z;
return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v);
}

#define P(x) p[(x) & 255]

double pnoise(double x, double y, double z)
{
uint8_t  X = (uint32_t)floor(x) & 255,     /* FIND UNIT CUBE THAT */
         Y = (uint32_t)floor(y) & 255,     /* CONTAINS POINT.     */
         Z = (uint32_t)floor(z) & 255;
x -= floor(x);                             /* FIND RELATIVE X,Y,Z */
y -= floor(y);                             /* OF POINT IN CUBE.   */
z -= floor(z);
double  u = fade(x),                       /* COMPUTE FADE CURVES */
        v = fade(y),                       /* FOR EACH OF X,Y,Z.  */
        w = fade(z);
uint16_t  A  = P(X)+Y,
          AA = P(A)+Z,
          AB = P(A+1)+Z,                   /* HASH COORDINATES OF */
          B  = P(X+1)+Y,
          BA = P(B)+Z,
          BB = P(B+1)+Z;                   /* THE 8 CUBE CORNERS, */

return lerp(w,lerp(v,lerp(u,grad(P(AA  ),x,y,z),       /* AND ADD */
                            grad(P(BA  ),x-1,y,z)),    /* BLENDED */
                     lerp(u,grad(P(AB  ),x,y-1,z),     /* RESULTS */
                            grad(P(BB  ),x-1,y-1,z))), /* FROM  8 */
              lerp(v,lerp(u,grad(P(AA+1),x,y,z-1),     /* CORNERS */
                            grad(P(BA+1),x-1,y,z-1)),  /* OF CUBE */
                     lerp(u,grad(P(AB+1),x,y-1,z-1),
                            grad(P(BB+1),x-1,y-1,z-1))));
}
// end perlin noise

// B L I N K E N
#define w  8 // wird unten dann
#define h 12 // um 90° gedreht
#define step 0.0005

#ifdef SIM // Simulator...
uint32_t panel[w * h];

void bpoint(uint8_t x, uint8_t y, uint8_t z, uint32_t c)
{
  panel[x + y * w] = c;
}

void bupdate()
{
  uint8_t x, y, r, g, b;
  uint32_t c;
  printf("\e[;H");
  for(x = 0; x < w; x++) {
    for(y = 0; y < h; y++) {
      c = panel[x + y * w];
      r = (c >> 16) & 255;
      g =  (c >> 8) & 255;
      b =         c & 255;
      printf("\e[48:2:%d:%d:%dm  \e[0m", r, g, b);
      //printf("%2X %2X %2X ", r, g, b);
    }
    printf("\n");
  }
  printf("%*s", h*2, "slicer");
}

void bclear()
{
  printf("\e[2J\e[;H");
}

void bsetup()
{
  bclear();
}

int main(void)
{
  bsetup();
  for(;;) { loop(); usleep(100000); }
}
#endif // ...Simulator

void setup()
{
  bsetup();
}

/* Halbton finden */
uint8_t comp(double a, double b)
{
  double c;
  static double i;
  c = pnoise(a, b, i += step) + 0.5;
  c = c > 1 ? 1 : c < 0 ? 0 : c;
  return (uint8_t)(c * 255);
}

/* (a b c) Koordinatenpaare rechnen */
void loop()
{
  uint8_t a, b, c;
  for(a = 0; a < w; a++) {
    for(b = 0; b < h; b++) {
      c = comp((double)a/w, (double)b/h);
      bpoint(a, b, 0, c << 16 | c << 8 | c);
    }
  }
  bupdate();
}
// end BLINKEN