#include "FastLED.h"

// Matrix size
#define HEIGHT 16
#define WIDTH 16
#define NUM_LEDS WIDTH * HEIGHT
#define MATRIX_TYPE 1
// LEDs pin
#define DATA_PIN 3
// LED brightness
#define BRIGHTNESS 255
// Define the array of leds
CRGB leds[NUM_LEDS];

//// ----------------------------- Sinusoid ------------------------------
//(c)Stefan Petrick https://gist.github.com/StefanPetrick/dc666c1b4851d5fb8139b73719b70149
//https://editor.soulmatelights.com/gallery/587
//upd by Stepko
bool loadingFlag = true;

uint8_t speed = 15;
uint8_t scale = 55;
uint8_t amplitude = 255;
int8_t type = 0; //0-3 original/>3 other versions

static float fmap(const float x, const float in_min, const float in_max, const float out_min, const float out_max) {
  return (out_max - out_min) * (x - in_min) / (in_max - in_min) + out_min;
}
const int8_t semiHeightMajor  =  HEIGHT / 2 + (HEIGHT % 2);
const int8_t semiWidthMajor = WIDTH / 2  + (WIDTH % 2);
float e_s3_speed = 0.004 * speed + 0.015; // speed of the movement along the Lissajous curves
float e_s3_size = fmap(amplitude, 1, 255, 3, 9); // amplitude of the curves
uint8_t _scale = map8(scale, 50, 150);
void Sinusoid() {
  float time_shift = millis();
  struct {
    float shiftX;
    float shiftY;
  } sshft[3];
  sshft[0].shiftX = float(e_s3_size * (sin16(e_s3_speed * 98.301 * time_shift))) / 32767.0;
  sshft[0].shiftY = float(e_s3_size * (sin16(e_s3_speed * 72.0874 * time_shift))) / 32767.0;
  sshft[1].shiftX = float(e_s3_size * (sin16(e_s3_speed * 134.3447 * time_shift))) / 32767.0;
  sshft[1].shiftY = float(e_s3_size * (sin16(e_s3_speed * 170.3884 * time_shift))) / 32767.0;
  sshft[2].shiftX = float(e_s3_size * (sin16(e_s3_speed * 68.8107 * time_shift))) / 32767.0;
  sshft[2].shiftY = float(e_s3_size * (sin16(e_s3_speed * 65.534 * time_shift))) / 32767.0;
  switch (type) {
    case 0: //Sinusoid I
      for (uint8_t y = 0; y < HEIGHT; y++) {
        for (uint8_t x = 0; x < WIDTH; x++) {
          CRGB color;
          float cx = (y - semiHeightMajor) + sshft[0].shiftX; // the 8 centers the middle on a 16x16
          float cy = (x - semiWidthMajor) + sshft[0].shiftY;
          int8_t v = sin8((_scale/2) * sqrt((((float) cx * cx) + ((float) cy * cy))));
          color.r = ~v;

          cx = (y - semiHeightMajor) + sshft[1].shiftX;
          cy = (x - semiWidthMajor) + sshft[1].shiftY;
          v = sin8((_scale/2) * sqrt((((float) cx * cx) + ((float) cy * cy))));
          color.b = ~v;
          leds[XY(x,y)]=color;

        }
      }
      break;
    case 1: //it's not sinusoid II
      for (uint8_t y = 0; y < HEIGHT; y++) {
        for (uint8_t x = 0; x < WIDTH; x++) {
          CRGB color;
          int8_t change = time_shift * 0.1 * e_s3_speed;
          float cx = (y - semiHeightMajor) + sshft[0].shiftX; // the 8 centers the middle on a 16x16
          float cy = (x - semiWidthMajor) + sshft[0].shiftY;
          int8_t v = change + sin8((_scale/2) * sqrt((((float) cx * cx) + ((float) cy * cy))));
          color.r = ~v;
          change = time_shift * 0.09 * e_s3_speed;
          cx = (y - semiHeightMajor) + sshft[1].shiftX;
          cy = (x - semiWidthMajor) + sshft[1].shiftY;
          v = change + sin8((_scale/2) * sqrt((((float) cx * cx) + ((float) cy * cy))));
          color.r = (uint8_t(~v) > color.r) ? ~v : color.r;
          color.g = uint8_t(~v) >> 1;
          leds[XY(x, y)] = color;
        }
      }
      break;
    case 2: //Sinusoid III
      for (uint8_t y = 0; y < HEIGHT; y++) {
        for (uint8_t x = 0; x < WIDTH; x++) {

          float cx = (y - semiHeightMajor) + sshft[0].shiftX; // the 8 centers the middle on a 16x16
          float cy = (x - semiWidthMajor) + sshft[0].shiftY;
          int8_t v = sin8((_scale/2) * sqrt((((float) cx * cx) + ((float) cy * cy))));
          leds[XY(x, y)].r = ~v;

          cx = (y - semiHeightMajor) + sshft[1].shiftX;
          cy = (x - semiWidthMajor) + sshft[1].shiftY;
          v = sin8((_scale/2) * sqrt((((float) cx * cx) + ((float) cy * cy))));
          leds[XY(x, y)].g = ~v;

          cx = (y - semiHeightMajor) + sshft[2].shiftX;
          cy = (x - semiWidthMajor) + sshft[2].shiftX;
          v = sin8((_scale/2) * sqrt((((float) cx * cx) + ((float) cy * cy))));
          leds[XY(x, y)].b = ~v;

        }
      }
      break;
    case 3: //Sinusoid IV
      for (uint8_t y = 0; y < HEIGHT; y++) {
        for (uint8_t x = 0; x < WIDTH; x++) {

          float cx = (y - semiHeightMajor) + sshft[0].shiftX; // the 8 centers the middle on a 16x16
          float cy = (x - semiWidthMajor) + sshft[0].shiftY;
          int8_t v = sin8((_scale/2) * sqrt((((float) cx * cx) + ((float) cy * cy)))+(time_shift * e_s3_speed));
          leds[XY(x, y)].r = ~v;

          cx = (y - semiHeightMajor) + sshft[1].shiftX;
          cy = (x - semiWidthMajor) + sshft[1].shiftY;
          v =sin8((_scale/2) * sqrt((((float) cx * cx) + ((float) cy * cy)))+(time_shift * e_s3_speed));
          leds[XY(x, y)].g = ~v;

          cx = (y - semiHeightMajor) + sshft[2].shiftX;
          cy = (x - semiWidthMajor); sshft[2].shiftY;
          v = sin8((_scale/2) * sqrt((((float) cx * cx) + ((float) cy * cy)))+(time_shift * e_s3_speed));
          leds[XY(x, y)].b = ~v;

        }
      }
      break;
    case 4: //changed by stepko //anaglyph sinusoid
      for (uint8_t y = 0; y < HEIGHT; y++) {
        for (uint8_t x = 0; x < WIDTH; x++) {

          float cx = (y - semiHeightMajor) + sshft[0].shiftX; // the 8 centers the middle on a 16x16
          float cy = (x - semiWidthMajor) + sshft[0].shiftY;
          int8_t v = 127 * (1 + sin16(127 * _scale * sqrt((((float) cx * cx) + ((float) cy * cy))) + (time_shift * e_s3_speed * 10)) / 32767.0);
          leds[XY(x, y)].r = ~v;

          v = 127 * (1 + sin16(127 * _scale * sqrt((((float) cx * cx) + ((float) cy * cy))) + (time_shift * e_s3_speed * 1)) / 32767.0);
          leds[XY(x, y)].b = ~v;

          v = 127 * (1 + sin16(127 * _scale * sqrt((((float) cx * cx) + ((float) cy * cy))) + (time_shift * e_s3_speed * 1)) / 32767.0);
          leds[XY(x, y)].g = ~v;

        }
      }
      break;
    case 5: //changed by stepko //colored sinusoid
      for (uint8_t y = 0; y < HEIGHT; y++) {
        for (uint8_t x = 0; x < WIDTH; x++) {

          float cx = (y - semiHeightMajor) + sshft[0].shiftX; // the 8 centers the middle on a 16x16
          float cy = (x - semiWidthMajor) + sshft[0].shiftY;
          int8_t v = 127 * (1 + sin16(127 * _scale * sqrt((((float) cx * cx) + ((float) cy * cy))) + (time_shift * e_s3_speed * 5)) / 32767.0);
          leds[XY(x, y)].r = v;

          v = 127 * (1 + sin16(127 * _scale * sqrt((((float) cx * cx) + ((float) cy * cy))) + (time_shift * e_s3_speed * 10)) / 32767.0);
          leds[XY(x, y)].b = v;

          v = 127 * (1 + sin16(127 * _scale * sqrt((((float) cx * cx) + ((float) cy * cy))) + (time_shift * e_s3_speed * 50)) / 32767.0);
          leds[XY(x, y)].g = v;

        }
      }
      break;
    case 6: //changed by stepko //sinusoid in net
      for (uint8_t y = 0; y < HEIGHT; y++) {
        for (uint8_t x = 0; x < WIDTH; x++) {

          float cx = (y - semiHeightMajor) + sshft[0].shiftX; // the 8 centers the middle on a 16x16
          float cy = (x - semiWidthMajor) + sshft[0].shiftY;
          int8_t v = 127 * (1 + sin16(127 * _scale * sqrt((((float) cx * cx) + ((float) cy * cy))) + (time_shift * e_s3_speed * 5)) / 32767.0);
          leds[XY(x, y)].g = ~v;

          v = 127 * (1 + sinf(_scale * x * 10 + float(0.01 * time_shift * e_s3_speed)));
          leds[XY(x, y)].b = ~v;

          v = 127 * (1 + sinf(_scale * y * 10 + float(0.011 * time_shift * e_s3_speed)));
          leds[XY(x, y)].r = ~v;

        }
      }
      break;
    case 7: //idea by stepko //spiral
      for (uint8_t y = 0; y < HEIGHT; y++) {
        for (uint8_t x = 0; x < WIDTH; x++) {
          float cx = (y - semiHeightMajor) + sshft[0].shiftX; // the 8 centers the middle on a 16x16
          float cy = (x - semiWidthMajor) + sshft[0].shiftY;
          uint8_t v = 127 * (1 + sin16(127 * _scale * (2 * atan2(cy, cx) + hypot(cy, cx)) + (time_shift * e_s3_speed * 5)) / 32767.0);
          leds[XY(x, y)].r = v;

          cx = (y - semiHeightMajor) + sshft[1].shiftX;
          cy = (x - semiWidthMajor) + sshft[1].shiftY;
          v = 127 * (1 + sin16(127 * _scale * (2 * atan2(cy, cx) + hypot(cy, cx)) + (time_shift * e_s3_speed * 5)) / 32767.0);
          leds[XY(x, y)].b = v;

          cx = (y - semiHeightMajor) + sshft[2].shiftX;
          cy = (x - semiWidthMajor) + sshft[2].shiftX;
          v = 127 * (1 + sin16(127 * _scale * (2 * atan2(cy, cx) + hypot(cy, cx)) + (time_shift * e_s3_speed * 5)) / 32767.0);;
          leds[XY(x, y)].g = v;

        }
      }
      break;
    case 8: //idea by stepko //blobs
      for (uint8_t y = 0; y < HEIGHT; y++) {
        for (uint8_t x = 0; x < WIDTH; x++) {
          float cx = (y - semiHeightMajor) + sshft[0].shiftX; // the 8 centers the middle on a 16x16
          float cy = (x - semiWidthMajor) + sshft[0].shiftY;
          uint8_t v = 30 * (max(0, -hypot(cx, cy) + float(_scale * 0.07)));
          leds[XY(x, y)].r = v;

          cx = (y - semiHeightMajor) + sshft[1].shiftX;
          cy = (x - semiWidthMajor) + sshft[1].shiftY;
          v = 30 * (max(0, -hypot(cx, cy) + float(_scale * 0.07)));
          leds[XY(x, y)].b = v;
          cx = (y - semiHeightMajor) + sshft[2].shiftX;
          cy = (x - semiWidthMajor) + sshft[2].shiftX;
          v = 30 * (max(0, -hypot(cx, cy) + float(_scale * 0.07)));
          leds[XY(x, y)].g = v;

        }
      }
      break;
  }
}


void setup() {
  //Serial.begin(250000);
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  FastLED.setBrightness(BRIGHTNESS);
  pinMode(2, INPUT_PULLUP);
}

void loop() {
  bool buttonPressed = digitalRead(2) == LOW;
  Sinusoid();
  if (buttonPressed) {
    if (type >= 8) {
      type = 0;
    } else {
      type += 1;
    }
    FastLED.clear();
    delay(100);
  } else {
    FastLED.show();
  }
} //loop


uint16_t XY (uint8_t x, uint8_t y) {
  return (y * WIDTH + x);
}
FPS: 0
Power: 0.00W