// source https://editor.soulmatelights.com/gallery/1097-fire-comets

#include "FastLED.h"
#define DATA_PIN 2
#define BRIGHTNESS 255
#define NUM_LEDS 256
#define NUM_COLS 16
#define NUM_ROWS 16
#define LED_TYPE    WS2812B
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];
//#define FRAMES_PER_SECOND 60
const uint8_t kMatrixWidth = 16;
const uint8_t kMatrixHeight = 16;

const bool    kMatrixSerpentineLayout = false;

byte buff[(NUM_COLS+2)*(NUM_ROWS+2)];

DEFINE_GRADIENT_PALETTE(firepal_YE) { // define fire palette
  0,  0,  0,  0, //black
  50, 0,0,0,
  64,  255,  0,  0, // red
  100,  255,  255,  0, //yellow
  255,  255,  255,  255, // white
};

uint16_t buffXY (byte x, byte y){
return (y*(NUM_COLS+2)+x);
}

void fadecenter(){
uint16_t sum;
for (byte x = 1; x < NUM_COLS+1; x++) {
  for (byte y = 1; y < NUM_ROWS+1; y++) {

     sum = buff [buffXY(x,y)]; 
     sum += buff [buffXY(x+1,y)]; 
     sum += buff [buffXY(x-1,y)];
     sum += buff [buffXY(x,y+1)]; 
     sum += buff [buffXY(x,y-1)];
     sum /=5;
     buff [buffXY(x,y)]=sum;
}}
}

void balls (){
byte speed = 15;
byte bright = 200;  
byte x  = beatsin8 (10+speed,1,NUM_COLS-1);
byte y  = beatsin8 (15+speed,1,NUM_ROWS);
byte x1 = beatsin8 (11+speed,1,NUM_COLS-1);
byte y1 = beatsin8 (9+speed,1,NUM_ROWS);
byte x2 = beatsin8 (15+speed,1,NUM_COLS-1);
byte y2 = beatsin8 (11+speed,1,NUM_ROWS);

buff [buffXY(x,y)]   = bright;
buff [buffXY(x+1,y)] = bright;

buff [buffXY(x1,y1)] = bright;
buff [buffXY(x1+1,y1)] = bright;

buff [buffXY(x2,y2)] = bright;
buff [buffXY(x2+1,y2)] = bright;
}

void toLeds (){
  CRGBPalette256 myPal = firepal_YE;

  uint16_t buffIndex = (NUM_COLS+3);
  for (int y = 0; y < NUM_ROWS; y++) {
   for (int x = 0; x < NUM_COLS; x++) {
      int index = XY(x, (NUM_ROWS-1)-y);
      leds[index] = ColorFromPalette (myPal, buff [buffIndex],255);
      buffIndex++;
    }
  buffIndex+=2; 
  } 
}

void setup() {
  FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS); //setCorrection(TypicalLEDStrip);
  //FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.setBrightness(BRIGHTNESS);
// Serial.begin(115200);
}

void loop() 
{
  balls ();
  fadecenter(); 
  toLeds();
  delay(10);
  FastLED.show();
 //Serial.print(buff);
}
 
uint16_t XY( uint8_t x, uint8_t y)
{
  uint16_t i;
  if( kMatrixSerpentineLayout == false) {
    i = (y * kMatrixWidth) + x;
  }
  if( kMatrixSerpentineLayout == true) {
    if( y & 0x01) {
      // Odd NUM_ROWS run backwards
      uint8_t reverseX = (kMatrixWidth - 1) - x;
      i = (y * kMatrixWidth) + reverseX;
    } else {
      // Even NUM_ROWS run forwards
      i = (y * kMatrixWidth) + x;
    }
  }
  return i;
}