//Hipnotic_RGB
//241 LED ring cilindrical map 
//Fastled rgb led demo
//Yaroslaw Turbin, 25-03-2021 
//https://vk.com/ldirko 
//https://www.reddit.com/user/ldirko/ 
//https://twitter.com/ldir_ko


#include <FastLED.h>

#define DATA_PIN     3
#define NUM_COLS_CILINDR 60           // resolution for cilindrical lookup table
#define NUM_ROWS_CILINDR 9           // resolution for cinindrical lookup table
#define NUM_LEDS    241

#define LED_TYPE    WS2812B          //leds type
#define COLOR_ORDER GRB              //color order of leds
#define MAX_POWER_MILLIAMPS 800  //write here your power in milliamps. default i set 800 mA for safety
#define BRIGHTNESS 255

CRGB leds[NUM_LEDS+1];  //one safe pixel in bottom. its index 241 

const uint8_t exp_gamma[256] = {
0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   1,   1,
1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,   1,
1,   2,   2,   2,   2,   2,   2,   2,   2,   2,   3,   3,   3,   3,   3,
4,   4,   4,   4,   4,   5,   5,   5,   5,   5,   6,   6,   6,   7,   7,
7,   7,   8,   8,   8,   9,   9,   9,   10,  10,  10,  11,  11,  12,  12,
12,  13,  13,  14,  14,  14,  15,  15,  16,  16,  17,  17,  18,  18,  19,
19,  20,  20,  21,  21,  22,  23,  23,  24,  24,  25,  26,  26,  27,  28,
28,  29,  30,  30,  31,  32,  32,  33,  34,  35,  35,  36,  37,  38,  39,
39,  40,  41,  42,  43,  44,  44,  45,  46,  47,  48,  49,  50,  51,  52,
53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,
68,  70,  71,  72,  73,  74,  75,  77,  78,  79,  80,  82,  83,  84,  85,
87,  89,  91,  92,  93,  95,  96,  98,  99,  100, 101, 102, 105, 106, 108,
109, 111, 112, 114, 115, 117, 118, 120, 121, 123, 125, 126, 128, 130, 131,
133, 135, 136, 138, 140, 142, 143, 145, 147, 149, 151, 152, 154, 156, 158,
160, 162, 164, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187,
190, 192, 194, 196, 198, 200, 202, 204, 207, 209, 211, 213, 216, 218, 220,
222, 225, 227, 229, 232, 234, 236, 239, 241, 244, 246, 249, 251, 253, 254, 255};

void setup() {
  FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS)
  .setCorrection( TypicalLEDStrip );
//   FastLED.setMaxPowerInVoltsAndMilliamps( 5, MAX_POWER_MILLIAMPS);   
  FastLED.setBrightness(BRIGHTNESS);
  FastLED.clear();
} 
void loop() {
static byte speed;
EVERY_N_MILLISECONDS (50) {speed++;}

uint16_t  a = millis()/4;
for (int j = 0; j < NUM_ROWS_CILINDR; j++) {
for (int i = 0; i < NUM_COLS_CILINDR; i++) {

byte index = XY_cilindrical(i,j);

if (index!=241) {
leds[index].b=exp_gamma [sin8((i/2-16)*cos8((j+20)*4)/4+a)];
leds[index].g=exp_gamma [(sin8(i*16+a/3)+cos8(j*8+a/2))/2];
leds[index].r=exp_gamma [sin8(cos8(i*8+a/3)+sin8(j*8+a/4)+a)];}

//  if (index!=241) leds[index].setHue (i*16+(sin8((j<<3)+a))>>1); 

    // if (index!=241) leds[index].setHue (i*255/(NUM_COLS_CILINDR-1)*3+j*32+a/2); //full moving rainbow
    
    // if (index!=241) leds[index]= HeatColor(inoise8(i*70+a,j*60+a*2)); //red tonnel

}} //end cycles 
LEDS.show();
}

byte XY_cilindrical (byte x, byte y) {
static const byte CilindricalLookTable [] = {   //1/4 of full table for reduce memory size. little bit tricky to calculate index )) 
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
60, 61, 241, 62, 63, 64, 65, 241, 66, 67, 68, 69, 241, 70, 71,
108, 241, 109, 110, 241, 111, 112, 241, 113, 114, 241, 115, 116, 241, 117,
148, 241, 149, 241, 150, 241, 151, 241, 152, 153, 241, 154, 241, 155, 241,
180, 241, 241, 181, 241, 182, 241, 241, 183, 241, 184, 241, 241, 185, 241,
204, 241, 241, 241, 205, 241, 241, 241, 206, 241, 241, 207, 241, 241, 241,
220, 241, 241, 241, 241, 221, 241, 241, 241, 241, 222, 241, 241, 241, 241,
232, 241, 241, 241, 241, 241, 241, 241, 233, 241, 241, 241, 241, 241, 241,
240, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241};

static const byte offs [] = {15, 12, 10, 8, 6, 4, 3, 2, 0};

byte index = CilindricalLookTable [y*15+x%15] ;
if (index!=241) {index+= (x/15)*offs[y];}

return (index);
}