#include <FastLED.h>

#define DATA_PIN     3
#define LED_COLS 15          // resolution for cilindrical lookup table
#define LED_ROWS 16          // resolution for cinindrical lookup table
#define NUM_LEDS    256
#define LED_TYPE    WS2812B          //leds type
#define COLOR_ORDER GRB              //color order of leds
#define petals 6

byte XY_angle[LED_COLS][LED_ROWS];
byte XY_radius[LED_COLS][LED_ROWS];

bool setupm = 1;
const uint8_t C_X = LED_COLS / 2;
const uint8_t C_Y = LED_ROWS / 2;
const uint8_t mapp = 255 / LED_COLS;
struct{
  uint8_t angle;
  uint8_t radius;
} 
   xMap[NUM_LEDS];
   
CRGB leds[NUM_LEDS+1]; 


uint8_t gCurrentPatternNumber =0; // Index number of which pattern is current
uint8_t InitNeeded = 1;           //global variable for effects initial needed
byte BRIGHTNESS = 255;             // for me good bright about 100-120, don't turn leds in full brightness long time! it may overheat




#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
// List of patterns to cycle through.  Each is defined as a separate function below.
typedef void (*SimplePatternList[])();
 


//_____________________________________ effects for cilindrical layout
//system procedures_____________________________________

void Flower() {

  LEDS.show();
 // FastLED.clear();
  if (setupm) {
    setupm = 1;
    for (int8_t x = -C_X; x < C_X + (LED_COLS % 2); x++) {
      for (int8_t y = -C_Y; y < C_Y + (LED_ROWS % 2); y++) {
        // XY_angle[x + C_X][y + C_Y] = atan2(y, x) * (180. / 2. / PI) * LED_COLS;
        XY_angle[x + C_X][y + C_Y] = (atan2(x, y) / PI) * 128 + 127; //thanks ldirko 
        XY_radius[x + C_X][y + C_Y] = hypot(x, y); //thanks Sutaburosu
      }
    }
  }
  
  static byte speed = 1;
  static uint32_t t;
  t += speed;
  for (uint8_t x = 0; x < LED_COLS; x++) {
    for (uint8_t y = 0; y < LED_ROWS; y++) {
      byte angle = XY_angle[x][y];
      byte radius = XY_radius[x][y];
      leds[XY(x, y)] = CHSV(t + radius * (255 / LED_COLS), 255, sin8(sin8(t+angle*5+( radius * (255 / LED_COLS)))+t * 4 + sin8(t * 4 - radius * (255 / LED_COLS)) + angle * 5));
    }
  }
  delay(16);
}





//CilindricalSwirl_____________________________________

void STAR() {



//+++++++++
static byte speed = 2;

LEDS.show();
//+++++++++++++++++++++++++++
 // FastLED.clear();
  if (setupm) {
    setupm = 0;
    for (int8_t x = -C_X; x < C_X + (LED_COLS % 2); x++) {
      for (int8_t y = -C_Y; y < C_Y + (LED_ROWS % 2); y++) {
       uint16_t coord = XY(x + C_X, y + C_Y);

        xMap[coord].angle = 128 * (atan2(y, x) / PI);
        xMap[coord].radius = hypot(x, y) * mapp; //thanks Sutaburosu
      }
    }
  }

  
  static uint32_t t;
  t += speed;
  for (uint8_t x = 0; x < LED_COLS; x++) {
    for (uint8_t y = 0; y < LED_ROWS; y++) {

      uint16_t coord = XY(x,y);
      byte angle = xMap[coord].angle;
      byte radius = xMap[coord].radius;
      leds[XY(x, y)] = CHSV(255,181,sin8(t-radius+sin8(t - angle*petals)/5));

    }
  }
  delay(20);

//+++++++++++++++++++++++++




}
//+++++++++++++++++++++++++






void Stepko() {
 // FastLED.clear();

static byte speed = 6;
 LEDS.show();
  if (setupm) {
    setupm = 0;
    for (int8_t x = -C_X; x < C_X + (LED_COLS % 2); x++) {
      for (int8_t y = -C_Y; y < C_Y + (LED_ROWS % 2); y++) {
        uint16_t coord = XY(x + C_X, y + C_Y);
        xMap[coord].angle = 128 * (atan2(y, x) / PI);
        xMap[coord].radius = hypot(x, y) * mapp; //thanks Sutaburosu
      }
    }
  }
  
 // static byte speed = 2;
  static uint16_t t;
  t += speed;
  uint16_t t1 = t / 2;
  for (uint8_t x = 0; x < LED_COLS; x++) {
    for (uint8_t y = 0; y < LED_ROWS; y++) {
      uint16_t coord = XY(x,y);
      uint8_t angle = sin8(t1 / 2 + xMap[coord].angle * 5);
      uint8_t radius = (xMap[coord].radius) * 2 - t;
      uint8_t noise[3] = { inoise8(angle, radius, t1), inoise8(angle, 12032 + t1, radius), inoise8(radius, 120021 + t1, angle) };
      for(uint8_t i = 0; i <3; i++){
        noise[i] = (noise[i] < 128) ? 0 : constrain((noise[i] - 128) * 3,0,255);
      }
      leds[coord] = CRGB(noise[0], noise[1], noise[2]);
    }
  }
  delay(16);
}
uint16_t XY (uint8_t x, uint8_t y) { return (y * LED_COLS + x);}

//DiagonalPatternCilindr_____________________________________





SimplePatternList gPatterns =     // this is list of patterns
{

Flower,
STAR,

Stepko
 
};



void FadeOut (byte steps){
for (byte i=0; i<=steps; i++) {
gPatterns[gCurrentPatternNumber]();
byte fadeOut = lerp8by8 (BRIGHTNESS, 0, 255*i/steps);

FastLED.setBrightness(fadeOut);
FastLED.show();  
}
}

void FadeIn (byte steps){
byte fadeOut  ;
for (byte i=steps+1; i--; i>=0) {
gPatterns[gCurrentPatternNumber]();
 fadeOut = lerp8by8 (BRIGHTNESS , 0, 255*i/steps);
FastLED.setBrightness(fadeOut);
FastLED.show();  
}
}
void setup() {
  
  FastLED.setBrightness(BRIGHTNESS);
  FastLED.clear();
  FadeIn (50); 

 FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS)

 .setCorrection( TypicalLEDStrip );

   
 
  FastLED.clear();



}

void loop() {
EVERY_N_SECONDS( 5 ) // speed of change patterns periodically
{
FadeOut (50);        // fade out current effect
gCurrentPatternNumber = (gCurrentPatternNumber + 1) % ARRAY_SIZE(gPatterns); //next effect
InitNeeded=100; //flag if init something need
FadeIn (50);        // fade in current effect
} 

gPatterns[gCurrentPatternNumber]();

//FastLED.show();  
}