#include <FastLED.h>
const uint8_t XRES = 32;
const uint8_t YRES = 8;
const uint16_t NUM_LEDS = XRES * YRES;
const uint8_t BRIGHTNESS = 255;
const uint8_t LED_PIN = 6;
// FLARES
const uint8_t FLARE_ROWS = 2; // number of rows (from bottom) allowed to flare
const uint8_t FLARE_MAX = 8; // max number of simultaneous flares
const uint8_t FLARE_CHANCE = 50; // chance (%) of a new flare
const uint8_t FLARE_DECAY = 14; // decay rate of flare radiation
CRGB leds[NUM_LEDS];
// map x, y to pixel index
uint16_t pixel(uint8_t x, uint8_t y) {
return 224 - (y * XRES) + x;
}
/* This is the map of colors from coolest (black) to hottest. Want blue flames? Go for it! */
const uint32_t FIRE_COLORS[] = {
0x000000,
0x100000,
0x300000,
0x600000,
0x800000,
0xA00000,
0xC02000,
0xC04000,
0xC06000,
0xC08000,
0x807080
};
const uint8_t NUM_COLORS = (sizeof(FIRE_COLORS)/sizeof(FIRE_COLORS[0]));
uint8_t fire[XRES][YRES];
uint8_t flareIndex = 0;
uint32_t flare[FLARE_MAX];
// set pixels to intensity around flare
void glow(int16_t col, int16_t row, int16_t heat) {
int16_t b = heat * 10 / FLARE_DECAY + 1;
for (int16_t y = (row - b); y < (row + b); y++) {
for (int16_t x = (col - b); x < (col + b); x++) {
if (y >=0 && x >= 0 && y < YRES && x < XRES) {
int16_t d = (FLARE_DECAY * sqrt16((col - x) * (col - x) + (row - y) * (row - y)) + 5) / 10;
uint8_t n = 0;
if (heat > d) n = heat - d;
if (n > fire[x][y] ) { // can only get brighter
fire[x][y] = n;
}
}
}
}
}
void displayFire() {
uint8_t x;
uint8_t y;
// move all existing heat points up the display and fade
for (y = YRES - 1; y > 0; y--) {
for (x = 0; x < XRES; x++) {
uint8_t n = 0;
if (fire[x][y - 1] > 0) {
n = fire[x][y - 1] - 1;
}
fire[x][y] = n;
}
}
// heat the bottom row
for (x = 0; x < XRES; x++) {
y = fire[x][0];
if (y > 0) {
fire[x][0] = random(NUM_COLORS - 6, NUM_COLORS - 2);
}
}
// flare
for (y = 0; y < flareIndex; y++) {
int16_t col = flare[y] & 0xff;
int16_t row = (flare[y] >> 8) & 0xff;
int16_t heat = (flare[y] >> 16) & 0xff;
glow(col, row, heat);
if (heat > 1 ) {
flare[y] = (flare[y] & 0xffff) | ((heat - 1) << 16);
} else {
// flare is out
for (x = y + 1; x < flareIndex; x++) {
flare[x - 1] = flare[x];
}
flareIndex--;
}
}
// new flare
if (flareIndex < FLARE_MAX && random(1, 101) <= FLARE_CHANCE) {
int16_t col = random(0, XRES);
int16_t row = random(0, FLARE_ROWS);
int16_t heat = NUM_COLORS - 1;
flare[flareIndex++] = (heat << 16) | (row << 8) | (col & 0xff);
glow(col, row, heat);
}
// output to leds
for (y = 0; y < YRES; y++) {
for (x = 0; x < XRES; x++) {
leds[pixel(x, y)] = FIRE_COLORS[fire[x][y]];
}
}
FastLED.show();
}
void initFire() {
for (uint8_t y = 0; y < YRES; y++) {
for (uint8_t x = 0; x < XRES; x++) {
fire[x][y] = (y == 0) ? NUM_COLORS - 1 : 0;
}
}
}
void setup() {
initFire();
FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS);
FastLED.clear();
FastLED.show();
}
void loop() {
displayFire();
delay(10);
}