//Stepko
#include "FastLED.h"

// Matrix size
#define LED_COLS 20
#define LED_ROWS 20
#define NUM_LEDS LED_ROWS * LED_COLS
// LEDs pin
#define DATA_PIN 3
// LED brightness
#define BRIGHTNESS 255
// Define the array of leds
CRGB leds[NUM_LEDS];

uint8_t Eff = 2;
bool isSetup = 1;

void setup() {
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  //FastLED.setMaxPowerInVoltsAndMilliamps(5,1000);
  FastLED.setBrightness(BRIGHTNESS);
  Serial.begin(9600);
}
uint8_t x , y, hue;
void SinusoidEff(){
  //FastLED.clear();
  //fadeToBlackBy(leds, NUM_LEDS, 32);
  x++; x%= LED_COLS;
  hue++;
  y = beatsin8(128, 0, LED_ROWS - 1);
  leds[XY(x,y)] = CHSV(hue,255,255);
  blur2d(leds, LED_COLS, LED_ROWS, 64);
}

void NoiseEff(){
  uint16_t t = millis() / 10;
  for(uint8_t x = 0; x < LED_COLS; x++){
    for(uint8_t y = 0; y < LED_ROWS; y++){
      leds[XY(x,y)] = ColorFromPalette(HeatColors_p, inoise8(x* 32,y * 32,t));
    }
  }
}
struct{
  uint16_t PosX;
  uint16_t PosY;
  int8_t SpeedX;
  int8_t SpeedY;
} fish[10];
void NewEff(){
  if(isSetup){
    for(uint8_t i = 0; i < 10; i++){
      fish[i].PosX = (random()%LED_COLS) << 8;
      fish[i].PosY = (random()%LED_ROWS) << 8;
      fish[i].SpeedX = random(- 100, 100);
      fish[i].SpeedY = random(- 100, 100);
    }
    isSetup = 0;
  }
  uint16_t t = millis() / 10;
  for(uint8_t x = 0; x < LED_COLS; x++){
    uint8_t noise_h = map(inoise8(x*32),0,255,0,LED_COLS - 1);
    for(uint8_t y = 0; y < LED_ROWS; y++){
      leds[XY(x,y)] = (y> noise_h)? CRGB(194, 178, 192) : CHSV(150, inoise8(x*20, y*20, t),255);
    }
  }
  for(uint8_t i = 0; i < 10; i++){
      fish[i].PosX += fish[i].SpeedX; fish[i].PosX %= (LED_COLS << 8);
      fish[i].PosY += fish[i].SpeedY; fish[i].PosY %= (LED_ROWS << 8);
      leds[XY(fish[i].PosX >> 8, fish[i].PosY >> 8)] = CHSV(50,192,255);
      leds[XY((fish[i].PosX + fish[i].SpeedX) >> 8, (fish[i].PosY + fish[i].SpeedY) >> 8)] = CHSV(50,192,255);
    }
}

void loop() {
  switch(Eff){
  case 1: NoiseEff(); break;
  case 2: NewEff(); break;
  default: SinusoidEff(); break;
  }
  FastLED.show();
}


uint16_t XY (uint8_t x, uint8_t y) {
  return (y * LED_COLS + x);
}