Created
April 10, 2013 22:02
-
-
Save neophob/5358858 to your computer and use it in GitHub Desktop.
stripinvaders addon
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Fireplace and Perlin Noise colour effect for a WS2801 addressable RGB LED strip. | |
By Ruben VC | |
Swapped R and B to compensate LPD8066 vs WS2801 in Fireplace code. | |
Based on fast and smooth random colour patterns for a LPD8066 addressable RGB LED strip. | |
By happyinmotion ([email protected]) | |
Simplex noise code taken from Stephen Carmody's Java implementation at: | |
http://stephencarmody.wikispaces.com/Simplex+Noise | |
Perlin Noise code copyright 2007 Mike Edwards: | |
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1191768812 | |
*/ | |
// Strip variables: | |
const int LEDs_for_simplex = 8; | |
// Extra fake LED at the end, to avoid fencepost problem. | |
// It is used by simplex node and interpolation code. | |
float LED_array_blue[NR_OF_PIXELS+1]; | |
float LED_array_green[NR_OF_PIXELS+1]; | |
float LED_array_red[NR_OF_PIXELS+1]; | |
int node_spacing = NR_OF_PIXELS / LEDs_for_simplex; | |
// Perlin noise global variables: | |
float x1,y1,x2,y2; | |
// Set up Perlin globals: | |
// Simplex noise global variables: | |
int i, j, k, A[] = {0, 0, 0}; | |
float u, v, w, s; | |
static float onethird = 0.333333333; | |
static float onesixth = 0.166666667; | |
int T[] = {0x15, 0x38, 0x32, 0x2c, 0x0d, 0x13, 0x07, 0x2a}; | |
// Simplex noise variables: | |
// So that subsequent calls to SimplexNoisePattern produce similar outputs, this needs to be outside the scope of loop() | |
float yoffset = 0.0; | |
int perlinmode = 0; | |
// Simplex noise parameters: | |
// Useable values for time increment range from 0.005 (barely perceptible) to 0.2 (irritatingly flickery) | |
// 0.02 seems ideal for relaxed screensaver | |
float timeinc = 0.1; | |
// Useable values for space increment range from 0.8 (LEDS doing different things to their neighbours), to 0.02 (roughly one feature present in 15 LEDs). | |
// 0.05 seems ideal for relaxed screensaver | |
float spaceinc = 0.1; | |
void setupFire() { | |
delay(0.5); | |
perlinmode = 0; | |
timeinc = 0.1; | |
} | |
void setupPerlin() { | |
delay(0.5); | |
perlinmode = 1; | |
timeinc = 0.05; | |
} | |
void loopFire() { | |
// Simplex noise for whole strip of 64 LEDs. | |
// (Well, it's simplex noise for 24 LEDs and cubic interpolation between those nodes.) | |
SimplexNoisePatternInterpolated(spaceinc, timeinc, yoffset); | |
yoffset += timeinc; | |
AllOff(); | |
} | |
void loopPerlin() { | |
// Simplex noise for whole strip of 64 LEDs. | |
// (Well, it's simplex noise for 8 LEDs and cubic interpolation between those nodes.) | |
SimplexNoisePatternInterpolated( spaceinc, timeinc, yoffset); | |
yoffset += timeinc; | |
AllOff(); | |
} | |
void SimplexNoisePatternInterpolated( float spaceinc, float timeinc, float yoffset) { | |
// Calculate simplex noise for LEDs that are nodes: | |
// Store raw values from simplex function (-0.347 to 0.347) | |
float xoffset = 0.0; | |
for (int i=0; i<=NR_OF_PIXELS; i=i+node_spacing) { | |
xoffset += spaceinc; | |
LED_array_blue[i] = SimplexNoise(xoffset,yoffset,0); | |
LED_array_green[i] = SimplexNoise(xoffset,yoffset,1); | |
LED_array_blue[i] = SimplexNoise(xoffset,yoffset,2); | |
} | |
// Interpolate values for LEDs between nodes | |
for (int i=0; i<NR_OF_PIXELS; i++) { | |
int position_between_nodes = i % node_spacing; | |
int last_node, next_node; | |
// If at node, skip | |
if ( position_between_nodes == 0 ) { | |
// At node for simplex noise, do nothing but update which nodes we are between | |
last_node = i; | |
next_node = last_node + node_spacing; | |
} | |
// Else between two nodes, so identify those nodes | |
else { | |
// And interpolate between the values at those nodes for red and green | |
float t = float(position_between_nodes) / float(node_spacing); | |
float t_squaredx3 = 3*t*t; | |
float t_cubedx2 = 2*t*t*t; | |
LED_array_red[i] = LED_array_red[last_node] * ( t_cubedx2 - t_squaredx3 + 1.0 ) + LED_array_red[next_node] * ( -t_cubedx2 + t_squaredx3 ); | |
LED_array_blue[i] = LED_array_blue[last_node] * ( t_cubedx2 - t_squaredx3 + 1.0 ) + LED_array_blue[next_node] * ( -t_cubedx2 + t_squaredx3 ); | |
LED_array_green[i] = LED_array_green[last_node] * ( t_cubedx2 - t_squaredx3 + 1.0 ) + LED_array_green[next_node] * ( -t_cubedx2 + t_squaredx3 ); | |
} | |
} | |
// Convert values from raw noise to scaled r,g,b and feed to strip | |
// blue is not used, red is prime color and green is used for lighter orange colors. | |
if(perlinmode<1){ | |
for (int i=0; i<NR_OF_PIXELS; i++) { | |
int b = int(LED_array_blue[i]*403 + 16); | |
int g = int(LED_array_green[i]*403 + 16); | |
int r = int(0); | |
if ( g>75 ) { g=75; } | |
else if ( g<65 ) { g=65; } | |
if ( b>255 ) { b=255; } | |
else if ( b<175 ) { b=175; } | |
strip.setPixelColor(i, r, g, b); | |
} | |
} else { | |
for (int i=0; i<NR_OF_PIXELS; i++) { | |
int r = int(LED_array_red[i]*403 + 16); | |
int g = int(LED_array_green[i]*403 + 16); | |
int b = int(LED_array_blue[i]*403 + 16); | |
if ( r>127 ) { r=127; } | |
else if ( r<0 ) { r=0; } // Adds no time at all. Conclusion: constrain() sucks. | |
if ( g>127 ) { g=127; } | |
else if ( g<0 ) { g=0; } | |
if ( b>127 ) { b=127; } | |
else if ( b<0 ) { b=0; } | |
strip.setPixelColor(i, r, g, b); | |
} | |
} | |
} | |
/*****************************************************************************/ | |
// Simplex noise code: | |
// From an original algorythm by Ken Perlin. | |
// Returns a value in the range of about [-0.347 .. 0.347] | |
float SimplexNoise(float x, float y, float z) { | |
// Skew input space to relative coordinate in simplex cell | |
s = (x + y + z) * onethird; | |
i = fastfloor(x+s); | |
j = fastfloor(y+s); | |
k = fastfloor(z+s); | |
// Unskew cell origin back to (x, y , z) space | |
s = (i + j + k) * onesixth; | |
u = x - i + s; | |
v = y - j + s; | |
w = z - k + s;; | |
A[0] = A[1] = A[2] = 0; | |
// For 3D case, the simplex shape is a slightly irregular tetrahedron. | |
// Determine which simplex we're in | |
int hi = u >= w ? u >= v ? 0 : 1 : v >= w ? 1 : 2; | |
int lo = u < w ? u < v ? 0 : 1 : v < w ? 1 : 2; | |
return k_fn(hi) + k_fn(3 - hi - lo) + k_fn(lo) + k_fn(0); | |
} | |
int fastfloor(float n) { | |
return n > 0 ? (int) n : (int) n - 1; | |
} | |
float k_fn(int a) { | |
s = (A[0] + A[1] + A[2]) * onesixth; | |
float x = u - A[0] + s; | |
float y = v - A[1] + s; | |
float z = w - A[2] + s; | |
float t = 0.6f - x * x - y * y - z * z; | |
int h = shuffle(i + A[0], j + A[1], k + A[2]); | |
A[a]++; | |
if (t < 0) return 0; | |
int b5 = h >> 5 & 1; | |
int b4 = h >> 4 & 1; | |
int b3 = h >> 3 & 1; | |
int b2 = h >> 2 & 1; | |
int r = h & 3; | |
float p = r == 1 ? x : r == 2 ? y : z; | |
float q = r == 1 ? y : r == 2 ? z : x; | |
float b = r == 1 ? z : r == 2 ? x : y; | |
p = b5 == b3 ? -p : p; | |
q = b5 == b4 ? -q: q; | |
b = b5 != (b4^b3) ? -r : r; | |
t *= t; | |
return 8 * t * t * (p + (b == 0 ? q + b : b2 == 0 ? q : r)); | |
} | |
int shuffle(int i, int j, int k) { | |
return b(i, j, k, 0) + b(j, k, i, 1) + b(k, i, j, 2) + b(i, j, k, 3) + b(j, k, i, 4) + b(k, i, j, 5) + b(i, j, k, 6) + b(j, k, i, 7); | |
} | |
int b(int i, int j, int k, int B) { | |
return T[b(i, B) << 2 | b(j, B) << 1 | b(k, B)]; | |
} | |
int b(int N, int B) { | |
return N >> B & 1; | |
} | |
void AllOff() { | |
// Reset LED strip | |
strip.begin(); | |
strip.show(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment