//240 LED ring cilindrical map swirl 
//Fastled rgb led demo
//Yaroslaw Turbin, 02.02.2021 
//https://vk.com/ldirko 
//https://www.reddit.com/user/ldirko/
//https://twitter.com/ldir_ko

//https://wokwi.com/arduino/projects/289422434310816264

#include <FastLED.h>

#define LED_PIN     3
#define NUM_COLS    60   
#define NUM_ROWS    8 
#define NUM_LEDS    240 
#define LED_TYPE    WS2812
#define COLOR_ORDER GRB
CRGB leds[241];
CRGB ledsbuff [NUM_COLS*NUM_ROWS];


void setup() {FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS);}
 
void loop() {
static int speed;
EVERY_N_MILLISECONDS(150) {speed++; }; //80 - speed of effect 

EVERY_N_MILLISECONDS(80) {  //80 - speed of effect 
fadeToBlackBy(ledsbuff, 480,40);

for (byte i=10; i<60; i+=12) {   

CRGB hue = CHSV (180+random8(15),255,255); 
randomWalk((i+speed)%60,0, hue); 

byte ind= i+random8(3); 
hue = CHSV (200+random8(10),255,255); 
if (ledsbuff[XY(ind,3)]) randomWalk((ind+speed)%60,3, hue);  

ind= i-random8(4); 
hue = CHSV (200+random8(10),255,255); 
if (ledsbuff[XY(ind,4)]) randomWalk((ind+speed)%60,4, hue); 

}
blur2d (ledsbuff, NUM_COLS,NUM_ROWS,48);
} 

ledsbuff_to_buff();
LEDS.show();
}

void ledsbuff_to_buff() {
int indexbuff=0;
for (byte j=0; j<NUM_ROWS;j++){
for (byte i=0; i<NUM_COLS;i++){
  byte index = XY_cilindrical(i,j);
if (index!=241) leds [index] =ledsbuff[indexbuff]; 
indexbuff++;
}}    
}

void randomWalk (int  x, byte y, CRGB hue) {
int a =millis();
for (byte i= y;i<NUM_ROWS;i++) {
byte xoffset = sin8(i*80+a)/250;

if ( random8(2)) ledsbuff[XY(x+=xoffset,i)]+= hue;
    else ledsbuff[XY(x-=xoffset,i)]+= hue; 
}
}

byte XY_cilindrical (byte x, byte y) {
static byte CilindricalLookTable [] = {             // this lookup table i made with illustrator and Indesign ))))
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
60, 61, 241, 62, 63, 64, 65, 66, 241, 67, 68, 69, 70, 241, 71, 72, 73, 241, 74, 75, 76, 77, 241, 78, 79, 80, 81, 241, 82, 83, 84, 85, 241, 86, 87, 88, 89, 241, 90, 91, 92, 93, 241, 94, 95, 96, 97, 241, 98, 99, 100, 101, 241, 102, 103, 104, 105, 241, 106, 107,
108, 241, 109, 110, 241, 111, 112, 241, 113, 114, 241, 115, 116, 241, 117, 118, 241, 119, 120, 241, 121, 122, 241, 123, 124, 241, 125, 126, 241, 127, 128, 241, 129, 130, 241, 131, 132, 241, 133, 134, 241, 135, 136, 241, 137, 138, 241, 139, 140, 241, 141, 142, 241, 143, 144, 241, 145, 241, 146, 147,
148, 241, 149, 241, 150, 241, 151, 241, 152, 241, 153, 154, 241, 155, 241, 156, 241, 157, 241, 158, 241, 159, 241, 160, 241, 161, 241, 162, 241, 163, 164, 241, 165, 241, 166, 241, 167, 241, 168, 241, 169, 241, 170, 241, 171, 241, 172, 241, 173, 174, 241, 175, 241, 176, 241, 177, 241, 178, 241, 179,
180, 241, 241, 181, 241, 182, 241, 241, 183, 241, 184, 241, 241, 185, 241, 186, 241, 241, 187, 241, 241, 188, 241, 189, 241, 241, 190, 241, 191, 241, 241, 192, 241, 193, 241, 241, 194, 241, 195, 241, 241, 196, 241, 241, 197, 241, 198, 241, 241, 199, 241, 200, 241, 241, 201, 241, 202, 241, 241, 203,
204, 241, 241, 241, 205, 241, 241, 241, 206, 241, 241, 241, 207, 241, 241, 241, 208, 241, 241, 241, 209, 241, 241, 241, 210, 241, 241, 241, 211, 241, 241, 212, 241, 241, 241, 213, 241, 241, 241, 214, 241, 241, 241, 215, 241, 241, 241, 216, 241, 241, 241, 217, 241, 241, 241, 218, 241, 241, 241, 219,
220, 241, 241, 241, 241, 221, 241, 241, 241, 241, 241, 222, 241, 241, 241, 241, 223, 241, 241, 241, 241, 224, 241, 241, 241, 241, 241, 225, 241, 241, 241, 241, 226, 241, 241, 241, 241, 227, 241, 241, 241, 241, 241, 228, 241, 241, 241, 241, 229, 241, 241, 241, 241, 241, 230, 241, 241, 241, 241, 231,
232, 241, 241, 241, 241, 241, 241, 241, 233, 241, 241, 241, 241, 241, 241, 241, 241, 234, 241, 241, 241, 241, 241, 241, 241, 235, 241, 241, 241, 241, 241, 241, 241, 241, 236, 241, 241, 241, 241, 241, 241, 241, 237, 241, 241, 241, 241, 241, 241, 241, 241, 238, 241, 241, 241, 241, 241, 241, 241, 239
};
return (CilindricalLookTable[y*NUM_COLS+x]);
}

uint16_t XY(uint8_t x, uint8_t y) {
  if (x >= NUM_COLS) x= NUM_COLS-1;
  if (y >= NUM_ROWS) y= NUM_ROWS-1;
  return y * NUM_COLS + x;
}