Created
May 25, 2015 17:18
-
-
Save jpro56/a98279acc78ec7bd2af5 to your computer and use it in GitHub Desktop.
My fireworks on a 16x25 Ws2812b array using Arduino MEGA 2560
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
#include "FastLED.h" | |
// Originaly designed for a 16x16 matrix by Mark Kriegsman, July 2013 | |
// Updated for a 16 strip X 25 WS2812b LED array with each strip driven by a separate pin | |
// Modified to have multiple shell launch and did some code clean-up wehe possible. | |
#define PIXEL_WIDTH 16 | |
#define PIXEL_HEIGHT 25 | |
CRGB leds[PIXEL_WIDTH][PIXEL_HEIGHT]; | |
CRGB overrun; | |
CRGB& XY( uint8_t x, uint8_t y) | |
{ | |
if( x < PIXEL_WIDTH && y < PIXEL_HEIGHT && x >= 0 && y >= 0) return leds[x][y]; | |
else return overrun; // In case pixel is outside the LED array, return the address of a dummy CRGB value | |
} | |
void screenscale( accum88 hor, accum88 ver, fract8& pixel, fract8& up, fract8& right, fract8& diag) // 3 Pointers to resulting fract8 variables | |
{ | |
fract8 x_fract = (hor >> 7) & 15; // Extracts only the fractional part (in 1/16th) of the pixel position | |
fract8 y_fract = (ver >> 7) & 15; | |
diag = x_fract * y_fract; // Returns a number representing the proportion (in 1/256th) for each of the 4 pixels | |
up = (16 - x_fract) * y_fract; | |
right = (16 - y_fract) * x_fract; | |
pixel = 256 - (16 * x_fract) - (16 * y_fract) + diag; | |
/* | |
Serial.print("Hor = "); | |
Serial.print(hor); | |
Serial.print(" , Ver = "); | |
Serial.print(ver); | |
Serial.print(" , x_fract = "); | |
Serial.print(x_fract); | |
Serial.print(" , y_fract = "); | |
Serial.print(y_fract); | |
Serial.print(" , diag = "); | |
Serial.print(diag); | |
Serial.print(" , up = "); | |
Serial.print(up); | |
Serial.print(" , right = "); | |
Serial.print(right); | |
Serial.print(" , pixel = "); | |
Serial.println(pixel); | |
*/ | |
} | |
uint8_t gGravity = 2; //11 | |
uint8_t gDrag = 1; | |
accum88 gBurstx; | |
accum88 gBursty; | |
saccum78 gBurstxv; | |
saccum78 gBurstyv; | |
CRGB gBurstcolor; | |
#define NONE 0 | |
#define SHELL 1 | |
#define SPARK 2 | |
#define EXPLODING 3 | |
#define BURSTING 4 | |
class Dot { | |
public: | |
int8_t show; | |
int8_t theType; | |
accum88 x; | |
accum88 y; | |
saccum78 xv; | |
saccum78 yv; | |
CRGB color; | |
Dot() // Constructor for the Dot class | |
{ | |
show = 0; | |
theType = 0; | |
x = 0; | |
y = 0; | |
xv = 0; | |
yv = 0; | |
color.setRGB( 0, 0, 0); | |
} | |
void Draw() | |
{ | |
fract8 p00, p01, p10, p11; // percentage of pixel spread to adjacent pixels | |
screenscale( x, y, p00, p01, p10, p11); | |
uint8_t x_pos = x >> 11; // Scaling to get x and y pixel positions | |
uint8_t y_pos = y >> 11; | |
if (yv > 0){ // In case of equal values, just adding 1 or 2 to any pixel's percentage | |
if (p00 == p01) p01++; // will ensure than only one pixel will have a higher percentage than | |
if (p10 == p11) p11++; // any of the other 3 | |
} | |
if (yv <0){ | |
if (p00 == p01) p00++; | |
if (p10 == p11) p10++; | |
} | |
if (xv > 0){ | |
if (p00 == p10) p10++; | |
if (p01 == p11) p11++; | |
} | |
if (xv <0){ | |
if (p00 == p10) p00++; | |
if (p01 == p11) p01++; | |
} | |
if( !show) return; | |
if ((p00 > p01) && (p00 > p10) && (p00 > p11)) XY(x_pos, y_pos) += color; | |
if ((p01 > p00) && (p01 > p10) && (p01 > p11)) XY(x_pos, y_pos + 1) += color; | |
if ((p10 > p00) && (p10 > p01) && (p10 > p11)) XY(x_pos + 1, y_pos) += color; | |
if ((p11 > p00) && (p11 > p01) && (p11 > p10)) XY(x_pos + 1, y_pos + 1) += color; | |
/* | |
XY(x_pos, y_pos) = CRGB(p00, p00, p00); // Modifies the color content of the base pixel | |
XY(x_pos, y_pos + 1) = CRGB(p01, p01, p01); // and the 3 immediate pixels on top, to the right and diagonal | |
XY(x_pos + 1, y_pos) = CRGB(p10, p10, p10); | |
XY(x_pos + 1, y_pos + 1) = CRGB(p11, p11, p11); | |
*/ | |
} // End of draw function | |
void Move() | |
{ | |
// if( !show) return; | |
if(((xv > 0) && (x+xv < xv)) || ((xv < 0) && (x+xv > xv))) show = 0; // Prevents pixels wraparounds from side to side | |
if(((yv > 0) && (y+yv < yv))) show = 0; // Prevents pixels wraparounds from top to bottom | |
if( yv < 0 && (y < (-yv)) ) show = 0; // If velocity is negative AND we are about to hit the ground | |
if (theType == EXPLODING) { // If the Shell has exploded... | |
show = 0; | |
theType = BURSTING; // prepare for a burst on next frame | |
// gBurstx = x; | |
// gBursty = y; | |
// gBurstxv = xv; | |
// gBurstyv = yv; | |
// hsv2rgb_rainbow( CHSV( random8(), 240, 200), gBurstcolor); | |
} | |
if ((yv < 0) && (theType == SHELL)) { // If velocity is negative AND it is a shell... | |
xv=0; // Stop further movements | |
yv=0; | |
color = CRGB(255, 255, 255); // Set full brightness white color | |
theType = EXPLODING; // explode the shell !! | |
} | |
x += xv; | |
y += yv; | |
yv -= gGravity; | |
if (xv>0) xv -= gDrag; | |
if (xv<0) xv += gDrag; | |
if (yv>0) yv -= gDrag; | |
if (yv<0) yv += gDrag; | |
} //End of the move function | |
void GroundLaunch() | |
{ | |
yv = 450 + random16(100); // Generates an unsigned int value between 450 and 550 (Nice height but always inside of frame) | |
xv = (int16_t)random16(350) - (int16_t) 175; // Generates a signed int value between +/- 175 (Nice width but always inside of frame) | |
y = 0; // Ground launch | |
x = 0x4000; // Horizontal middle of screen | |
color.setRGB(16,16,16); // Shells are white color' as a CRGB | |
theType = SHELL; | |
show = 1; | |
} //End of Groundlaunch function | |
void Skyburst( accum88 basex, accum88 basey, CRGB& basecolor) | |
{ | |
yv = random16(400) - 200; // Random number (Y-velocity) between -600 and +600 | |
xv = random16(400) - 200; // Random number (X-velocity) between -600 and +600 | |
y = basey; | |
x = basex; | |
color = basecolor; | |
color *= 8; | |
theType = SPARK; | |
show = 1; | |
} //End of Skyburst function | |
}; // End of Dot class definition | |
#define MAX_SHELLS 6 | |
#define MIN_SHELLS 2 | |
#define MAX_SPARKS 40 | |
#define MIN_SPARKS 30 | |
Dot gDot[MAX_SHELLS]; //Creates an object named gDot of type Dot class | |
Dot gSparks[MAX_SHELLS][MAX_SPARKS]; //Creates an array object named gSparks of type Dot class | |
void setup() | |
{ | |
Serial.begin(38400); | |
FastLED.setBrightness(128); | |
FastLED.addLeds<NEOPIXEL, 25>(leds[0], PIXEL_HEIGHT); | |
FastLED.addLeds<NEOPIXEL, 24>(leds[1], PIXEL_HEIGHT); | |
FastLED.addLeds<NEOPIXEL, 23>(leds[2], PIXEL_HEIGHT); | |
FastLED.addLeds<NEOPIXEL, 22>(leds[3], PIXEL_HEIGHT); | |
FastLED.addLeds<NEOPIXEL, 11>(leds[4], PIXEL_HEIGHT); | |
FastLED.addLeds<NEOPIXEL, 10>(leds[5], PIXEL_HEIGHT); | |
FastLED.addLeds<NEOPIXEL, 34>(leds[6], PIXEL_HEIGHT); | |
FastLED.addLeds<NEOPIXEL, 35>(leds[7], PIXEL_HEIGHT); | |
FastLED.addLeds<NEOPIXEL, 33>(leds[8], PIXEL_HEIGHT); | |
FastLED.addLeds<NEOPIXEL, 31>(leds[9], PIXEL_HEIGHT); | |
FastLED.addLeds<NEOPIXEL, 29>(leds[10], PIXEL_HEIGHT); | |
FastLED.addLeds<NEOPIXEL, 27>(leds[11], PIXEL_HEIGHT); | |
FastLED.addLeds<NEOPIXEL, 4>(leds[12], PIXEL_HEIGHT); | |
FastLED.addLeds<NEOPIXEL, 41>(leds[13], PIXEL_HEIGHT); | |
FastLED.addLeds<NEOPIXEL, 39>(leds[14], PIXEL_HEIGHT); | |
FastLED.addLeds<NEOPIXEL, 37>(leds[15], PIXEL_HEIGHT); | |
} | |
void loop() | |
{ | |
random16_add_entropy(analogRead(3)); // Somehow this mixes the random numbers even more !? | |
CRGB sky1(0,0,2); // Background sky color (will only work if brightness is set high 128 or up !!) | |
CRGB sky2(2,2,2); // Alternate sky color to create a star twinkle effect | |
for( int h = 0; h < PIXEL_WIDTH; h++) { // All leds will be set to 'sky1' (very dark blue) | |
for( int v = 0; v < PIXEL_HEIGHT; v++) { | |
leds[h][v] = sky1; | |
} | |
} | |
if( random8() < 32 ) leds[random16(PIXEL_WIDTH)][random16(PIXEL_HEIGHT)] = sky2; // Around once each 8 frames, a random pixel is set to 'sky2' | |
static uint8_t launchcountdown = 0; | |
static uint16_t re_launchcountdown = 0; | |
if(gDot[MAX_SHELLS-1].show == 0) { // If the last shell has exploded | |
re_launchcountdown --; // Count down for next re_launch | |
if (re_launchcountdown > 30000) re_launchcountdown = 0; | |
} | |
for( int a = 0; a < MAX_SHELLS; a++) // Always moves and draws the MAX number of sparks not the actual number of sparks (Wasteful!?) | |
{ | |
if(re_launchcountdown == 0){ | |
if(gDot[a].show == 0) { | |
if(launchcountdown == 0) { | |
gDot[a].GroundLaunch(); | |
launchcountdown = random16(50) + 10; | |
} | |
else { | |
launchcountdown --; | |
if (launchcountdown > 254) launchcountdown = 0; | |
} | |
} | |
} | |
if(gDot[MAX_SHELLS-1].show == 1) re_launchcountdown = random16(400) + 100; // Last SHELL has launched, restart the relaunch timer | |
// if( gDot[a].theType == EXPLODING) { | |
// gDot[a].color.setRGB(255,255,255); | |
// } | |
if( gDot[a].theType == BURSTING) { | |
hsv2rgb_rainbow( CHSV( random8(), 255, random8(64,254)), gBurstcolor); | |
gBurstx = gDot[a].x; | |
gBursty = gDot[a].y; | |
int nsparks = random8(MIN_SPARKS, MAX_SPARKS+1); | |
for( int b = 0; b < nsparks; b++) { | |
gSparks[a][b].Skyburst( gBurstx, gBursty, gBurstcolor); | |
} | |
gDot[a].theType = SPARK; | |
} | |
gDot[a].Move(); // Calculate the next position of the dots | |
gDot[a].Draw(); // Scale the position of the shell on the LED matrix | |
for( int b = 0; b < MAX_SPARKS; b++) { // Always moves and draws the MAX number of sparks not the actual number of sparks (Wasteful!?) | |
gSparks[a][b].Move(); | |
/* Serial.print("Before scaling: gSparks["); | |
Serial.print(a); | |
Serial.print("]["); | |
Serial.print(b); | |
Serial.print("].color.r = "); | |
Serial.print(gSparks[a][b].color.r); | |
Serial.print(" g = "); | |
Serial.print(gSparks[a][b].color.g); | |
Serial.print(" b = "); | |
Serial.println(gSparks[a][b].color.b); | |
*/ | |
gSparks[a][b].color.r = gSparks[a][b].color.r * 255 /256; | |
gSparks[a][b].color.g = gSparks[a][b].color.g * 255 /256; | |
gSparks[a][b].color.b = gSparks[a][b].color.b * 255 /256; | |
/* | |
Serial.print("After scaling: gSparks["); | |
Serial.print(a); | |
Serial.print("]["); | |
Serial.print(b); | |
Serial.print("].color.r = "); | |
Serial.print(gSparks[a][b].color.r); | |
Serial.print(" g = "); | |
Serial.print(gSparks[a][b].color.g); | |
Serial.print(" b = "); | |
Serial.println(gSparks[a][b].color.b); | |
*/ | |
gSparks[a][b].Draw(); | |
} | |
} | |
FastLED.show(); | |
//FastLED.delay(100); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment