#include "FastLED.h"
// Matrix size
#define WIDTH 16
#define HEIGHT 16
#define NUM_LEDS HEIGHT * WIDTH
#define MATRIX_TYPE 1
// LEDs pin
#define DATA_PIN 3
// LED brightness
#define BRIGHTNESS 255
// Define the array of leds
CRGB leds[NUM_LEDS];
byte effect = 1;
const int SPARKS_AM = HEIGHT * 4;
float FADE_KOEF = .6;
float SpeedK = 2;
float SpeedDecX = .1;
float SpeedDecY = 0;
int sparksPos[2][SPARKS_AM];
float sparksSpeed[2][SPARKS_AM];
float sparksFade[SPARKS_AM];
byte sparksColor[SPARKS_AM];
float sparksSat[SPARKS_AM];
static byte period = 10;
int genPos[2];
int gravityPos[2];
bool run = true;
bool loadingFlag = true;
void reg(byte id) {
sparksPos[0][id] = (genPos[0] == -1205)? random(0, WIDTH * 10) : genPos[0];
sparksPos[1][id] = (genPos[1] == -1205)? random(0,HEIGHT * 10) : genPos[1];
byte al = random8();
sparksSpeed[0][id] = random(-10, 10);
sparksSpeed[1][id] = random(-5, 20);
sparksColor[id] = random();
sparksFade[id] = 255;
}
void phisics(byte id) {
if (SpeedK) {
if (gravityPos[0] != -1205) {
if (gravityPos[0] < sparksPos[0][id])
sparksSpeed[0][id] -= SpeedK;
else
sparksSpeed[0][id] += SpeedK;
}
if (gravityPos[1] != -1205) {
if (gravityPos[1] < sparksPos[1][id])
sparksSpeed[1][id] -= SpeedK;
else
sparksSpeed[1][id] += SpeedK;
}
}
sparksFade[id] -= (255. / float(HEIGHT * FADE_KOEF));
sparksSat[id] += (255. / (float)((WIDTH + WIDTH) * (FADE_KOEF - 0.2)));
if (SpeedDecX && sparksSpeed[0][id]) {
if (sparksSpeed[0][id] > 0)
sparksSpeed[0][id] -= SpeedDecX;
else
sparksSpeed[0][id] += SpeedDecX;
if (abs(sparksSpeed[0][id]) <= SpeedDecX)
sparksSpeed[0][id] = 0;
}
if (SpeedDecY && sparksSpeed[1][id]) {
if (sparksSpeed[1][id] > 0)
sparksSpeed[1][id] -= SpeedDecY;
else
sparksSpeed[1][id] += SpeedDecY;
if (abs(sparksSpeed[1][id]) <= SpeedDecY)
sparksSpeed[1][id] = 0;
}
sparksPos[0][id] += sparksSpeed[0][id];
sparksPos[1][id] += sparksSpeed[1][id];
}
void wu_pixel(uint32_t x, uint32_t y, CRGB * col) { //awesome wu_pixel procedure by reddit u/sutaburosu
// extract the fractional parts and derive their inverses
uint8_t xx = x & 0xff, yy = y & 0xff, ix = 255 - xx, iy = 255 - yy;
// calculate the intensities for each affected pixel
#define WU_WEIGHT(a, b)((uint8_t)(((a) * (b) + (a) + (b)) >> 8))
uint8_t wu[4] = {
WU_WEIGHT(ix, iy),
WU_WEIGHT(xx, iy),
WU_WEIGHT(ix, yy),
WU_WEIGHT(xx, yy)
};
// multiply the intensities by the colour, and saturating-add them to the pixels
for (uint8_t i = 0; i < 4; i++) {
uint16_t xy = XY((x >> 8) + (i & 1), (y >> 8) + ((i >> 1) & 1));
leds[xy].r = qadd8(leds[xy].r, col -> r * wu[i] >> 8);
leds[xy].g = qadd8(leds[xy].g, col -> g * wu[i] >> 8);
leds[xy].b = qadd8(leds[xy].b, col -> b * wu[i] >> 8);
}
}
void render(byte id, CRGB Col) {
phisics(id);
if (sparksPos[1][id] < ((HEIGHT - 1) * 10) and sparksPos[1][id] >= 0)
if (sparksPos[0][id] < ((WIDTH - 1) * 10) and sparksPos[0][id] >= 0) {
CRGB color = Col;
wu_pixel(sparksPos[0][id] * 25.6, sparksPos[1][id] * 25.6, & color);
}
}
void setGenPos(int x, int y) {
genPos[0] = x;
genPos[1] = y;
}
void setGravityPos(int x, int y) {
gravityPos[0] = x;
gravityPos[1] = y;
}
void setRegenRule(byte id, bool b) {
if (b) reg(id);
}
void start() {
for (byte i = 0; i < SPARKS_AM; i++) {
reg(i);
for (byte a = 0; a < i; a++) {
setRegenRule(a, (sparksPos[0][a] <= 0 || sparksPos[0][a] >= (WIDTH - 1) * 10 || sparksPos[1][a] < 0 || sparksPos[1][a] >= (HEIGHT - 1) * 10 || sparksFade[a] < 20) ? 1 : 0);
phisics(a);
}
}
}
void drawFire() {
setGenPos(WIDTH * 5, HEIGHT * 1);
byte noise = inoise8(millis() / 10);
setGravityPos(map(noise, 0, 255, WIDTH * 4, WIDTH * 6), map(abs(128 - noise), 0, 127, HEIGHT * 6, HEIGHT * 9));
if (loadingFlag) {
start();
loadingFlag = false;
}
//FastLED.clear();
//fadeToBlackBy(leds, NUM_LEDS, 20);
for (byte i = 0; i < SPARKS_AM; i++) {
setRegenRule(i, (sparksPos[0][i] <= 0 || sparksPos[0][i] >= (WIDTH - 1) * 10 || sparksPos[1][i] < 0 || sparksPos[1][i] >= (HEIGHT - 1) * 10 || sparksFade[i] < 20) ? 1 : 0);
render(i, ColorFromPalette(HeatColors_p, sparksFade[i]));
}
blur2d(leds, WIDTH, HEIGHT, 32);
delay(16);
}
void drawGravityDemo() {
fadeToBlackBy(leds, NUM_LEDS, 20);
setGenPos(beatsin16(10, 0, WIDTH * 10), beatsin16(10, 0, HEIGHT * 10, 0, 16384));
setGravityPos((WIDTH / 2) * 10, (HEIGHT / 2) * 10);
for (byte i = 0; i < SPARKS_AM; i++) {
setRegenRule(i, (sparksPos[0][i] <= 0 || sparksPos[0][i] >= (WIDTH - 1) * 10 || sparksPos[1][i] < 0 || sparksPos[1][i] >= (HEIGHT - 1) * 10 || sparksFade[i] <= 35) ? 1 : 0);
render(i, CHSV(sparksColor[i], 255, constrain(sparksFade[i], 32, 255)));
}
delay(16);
}
void drawBengalFire() {
fadeToBlackBy(leds, NUM_LEDS, beatsin8(5, 20, 100));
setGenPos(WIDTH * 5, HEIGHT * 5);
setGravityPos(-1205, 0);
for (byte i = 0; i < SPARKS_AM; i++) {
setRegenRule(i, (sparksPos[0][i] <= 0 || sparksPos[0][i] >= (WIDTH - 1) * 10 || sparksPos[1][i] < 0) ? 1 : 0);
render(i, CHSV(sparksColor[i], constrain(sparksSat[i], 5, 255), constrain(sparksFade[i], 32, 255)));
EVERY_N_SECONDS(period) {
for (byte i = 0; i < SPARKS_AM; i++) reg(i);
period = random(10, 60);
}
}
delay(16);
}
void drawWind() {
setGenPos(0,-1205);
byte noise = inoise8(millis() / 10);
setGravityPos(WIDTH * 11, map(abs(128 - noise), 0, 127, HEIGHT, HEIGHT * 9));
if (loadingFlag) {
start();
loadingFlag = false;
}
//FastLED.clear();
fadeToBlackBy(leds, NUM_LEDS, 20);
for (byte i = 0; i < SPARKS_AM; i++) {
setRegenRule(i, (sparksPos[0][i] >= (WIDTH - 1) * 10 || sparksPos[1][i] < 0 || sparksPos[1][i] >= (HEIGHT - 1) * 10 || sparksFade[i] < 20) ? 1 : 0);
render(i, CHSV(0,0,sparksFade[i]));
}
//blur2d(leds, LED_COLS, LED_ROWS, 32);
delay(16);
}
void setup() {
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
FastLED.setBrightness(BRIGHTNESS);
}
void loop() {
EVERY_N_SECONDS(10) {(effect== 3) ? effect = 0 : effect++; FastLED.clear(); }
switch (effect) {
case 0: drawFire(); break;
case 1: drawGravityDemo(); break;
case 2: drawBengalFire(); break;
case 3: drawWind(); break;
}
FastLED.show();
} //loop
uint16_t XY (uint8_t x, uint8_t y) {
if ((y % 2 == 0) || MATRIX_TYPE) // если чётная строка
{
return ((uint32_t)y * WIDTH + x) % (WIDTH * HEIGHT);
}
else // если нечётная строка
{
return ((uint32_t)y * WIDTH + WIDTH - x - 1) % (WIDTH * HEIGHT);
}
}