#include <FastLED.h>

#define LED_PIN  3
#define COLOR_ORDER       GRB
#define CHIPSET           WS2812B
#define kMatrixWidth      20
#define kMatrixHeight     20
#define kMatrixSerpentine true
#define kMatrixRowMajor   true
#define kMatrixFlipMajor  true
#define kMatrixFlipMinor  false
#define NUM_LEDS          ((kMatrixWidth) * (kMatrixHeight))
#define kHalfWidth        (kMatrixWidth / 2)
#define kHalfHeight       (kMatrixHeight / 2)

CRGB leds_plus_safety_pixel[NUM_LEDS + 1];
CRGB* const leds(leds_plus_safety_pixel + 1);

float XY_angle[kMatrixWidth][kMatrixHeight];
float XY_radius[kMatrixWidth][kMatrixHeight];

void setup() {
  FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(UncorrectedColor);
  for (int8_t x = -kHalfWidth; x < kHalfWidth; x++) {
    for (int8_t y = -kHalfHeight; y < kHalfHeight; y++) {
      XY_angle[x + kHalfWidth][y + kHalfHeight] = atan2(y, x) * (360. / 2. / PI) * kHalfWidth;
      XY_radius[x + kHalfWidth][y + kHalfHeight] = hypotf(x, y);
    }
  }
}


void loop() {
  drawFrame();
  FastLED.show();
}


void drawFrame() {
  static byte scale = 16;
  static byte speed = 48;
  static uint32_t t;
  t += speed;
  for (uint8_t x = 0; x < kMatrixWidth; x++) {
    for (uint8_t y = 0; y < kMatrixHeight; y++) {
      float angle = XY_angle[x][y];
      float radius = XY_radius[x][y];
      int16_t Bri = inoise8(angle, radius * scale - t) - radius * kMatrixHeight;
      byte Col = Bri;
       if (Bri < 0) Bri = 0; if(Bri != 0) Bri = 256 - (Bri * 0.2);
      nblend(leds[XY(x, y)], ColorFromPalette(HeatColors_p, Col, Bri), speed);}
  }
}


int16_t XY(int8_t x, int8_t y) {
  uint8_t major, minor, sz_major, sz_minor;
  if (x >= kMatrixWidth || y >= kMatrixHeight || x < 0 || y < 0) return -1;
  if (kMatrixRowMajor)
    major = x, minor = y, sz_major = kMatrixWidth,  sz_minor = kMatrixHeight;
  else
    major = y, minor = x, sz_major = kMatrixHeight, sz_minor = kMatrixWidth;
  if (kMatrixFlipMajor ^ (minor & 1 && kMatrixSerpentine))
    major = sz_major - 1 - major;
  if (kMatrixFlipMinor)
    minor = sz_minor - 1 - minor;
  return (uint16_t) minor * sz_major + major;
}