//WIP 241 led rings demo reel
//ldirko_Yaroslaw Turbin 17-06-2021
//https://twitter.com/ldir_ko
//https://vk.com/ldirko
//https://www.youtube.com/c/ldirldir
//https://www.reddit.com/user/ldirko/  

// 17-06-2021 added planar map, distorsion waves effec, sliders for speed and bright
//11-08-2021 added cilindrical map, spirals effect, pallettes blend, palletes

#include <FastLED.h>
#include "palletes.h"

#define DATA_PIN    3                //set your datapin
#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 NUM_COLS_PLANAR 17            // resolution for planar lookup table
#define NUM_ROWS_PLANAR 17            // resolution for planar lookup table
#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    WS2812
#define COLOR_ORDER GRB

CRGB leds[NUM_LEDS+1];
byte potpin = 0;  // analog pin used to connect the potentiometer1
byte potpin1 = 1; // analog pin used to connect the potentiometer2
byte BRIGHTNESS = 255;  
uint8_t gCurrentPatternNumber =0; // Index number of which pattern is current
uint8_t InitNeeded = 1;           //global variable for effects initial needed

const uint8_t exp_gamma[256] PROGMEM = {
 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
};

const uint8_t cos_wave[256] = {
 0,   0,   0,   0,   1,   1,   1,   2,   2,   3,   4,   5,   6,   6,   8,
 9,   10,  11,  12,  14,  15,  17,  18,  20,  22,  23,  25,  27,  29,  31,
 33,  35,  38,  40,  42,  45,  47,  49,  52,  54,  57,  60,  62,  65,  68,
 71,  73,  76,  79,  82,  85,  88,  91,  94,  97,  100, 103, 106, 109, 113,
 116, 119, 122, 125, 128, 131, 135, 138, 141, 144, 147, 150, 153, 156, 159,
 162, 165, 168, 171, 174, 177, 180, 183, 186, 189, 191, 194, 197, 199, 202,
 204, 207, 209, 212, 214, 216, 218, 221, 223, 225, 227, 229, 231, 232, 234,
 236, 238, 239, 241, 242, 243, 245, 246, 247, 248, 249, 250, 251, 252, 252,
 253, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 254, 254, 253,
 253, 252, 252, 251, 250, 249, 248, 247, 246, 245, 243, 242, 241, 239, 238,
 236, 234, 232, 231, 229, 227, 225, 223, 221, 218, 216, 214, 212, 209, 207,
 204, 202, 199, 197, 194, 191, 189, 186, 183, 180, 177, 174, 171, 168, 165,
 162, 159, 156, 153, 150, 147, 144, 141, 138, 135, 131, 128, 125, 122, 119,
 116, 113, 109, 106, 103, 100, 97,  94,  91,  88,  85,  82,  79,  76,  73,
 71,  68,  65,  62,  60,  57,  54,  52,  49,  47,  45,  42,  40,  38,  35,
 33,  31,  29,  27,  25,  23,  22,  20,  18,  17,  15,  14,  12,  11,  10,
 9,   8,   6,   6,   5,   4,   3,   2,   2,   1,   1,   1,   0,   0,   0, 0
};

void setup() {
  FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS)
  // .setCorrection( TypicalLEDStrip )
  ;
//   FastLED.setMaxPowerInVoltsAndMilliamps( 5, MAX_POWER_MILLIAMPS);   
  Check_bright();

  // FastLED.setBrightness(BRIGHTNESS);
  FastLED.clear();
  FadeIn (50);
} 

#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[])();
SimplePatternList gPatterns =     // this is list of patterns
{
  Distortion_Waves, Spiral,
}; 

#define SECONDS_PER_PALETTE 10

// Forward declarations of an array of cpt-city gradient palettes, and 
// a count of how many there are.  The actual color palette definitions
// are at the bottom of this file.
extern const TProgmemRGBGradientPalettePtr gGradientPalettes[];
extern const uint8_t gGradientPaletteCount;

// Current palette number from the 'playlist' of color palettes
uint8_t gCurrentPaletteNumber = 0;

CRGBPalette16 gCurrentPalette( CRGB::Black);
CRGBPalette16 gTargetPalette( gGradientPalettes[0] );

void loop () {

   EVERY_N_SECONDS( SECONDS_PER_PALETTE ) {
    gCurrentPaletteNumber = addmod8( gCurrentPaletteNumber, 1, gGradientPaletteCount);
    gTargetPalette = gGradientPalettes[ gCurrentPaletteNumber ];
  }

  EVERY_N_MILLISECONDS(40) {
    nblendPaletteTowardPalette( gCurrentPalette, gTargetPalette, 16);
  }


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

  gPatterns[gCurrentPatternNumber]();

  FastLED.show();  
  Check_bright();

}


//_________________________planar effects

//Distorsion waves
//rgb led matrix demo
//Yaroslaw Turbin 07-06-2021
//https://twitter.com/ldir_ko
//https://vk.com/ldirko
//https://www.youtube.com/c/ldirldir
//https://www.reddit.com/user/ldirko/ 

void Distortion_Waves() {
  byte speed = 5; 
  uint8_t w = 2;
  uint8_t scale = 4;

  uint16_t a=(speed_slider()*millis())>>9;
  uint16_t a2=a/2;
  uint16_t a3=a/3;

  uint16_t cx =  beatsin8 (10-speed,0,NUM_COLS_PLANAR)*scale;
  uint16_t cy =  beatsin8 (12-speed,0,NUM_ROWS_PLANAR)*scale;
  uint16_t cx1 = beatsin8 (13-speed,0,NUM_COLS_PLANAR)*scale;
  uint16_t cy1 = beatsin8 (15-speed,0,NUM_ROWS_PLANAR)*scale;
  uint16_t cx2 = beatsin8 (17-speed,0,NUM_COLS_PLANAR)*scale;
  uint16_t cy2 = beatsin8 (14-speed,0,NUM_ROWS_PLANAR)*scale;
  
  uint16_t xoffs=0;

  for (int x = 0; x < NUM_COLS_PLANAR; x++) {

    xoffs += scale;
    uint16_t yoffs = 0;

    for (int y = 0; y < NUM_ROWS_PLANAR; y++) {
      uint16_t index = XY_PLANAR(x, y);
      if (index==241) continue;     //for skip unused cells in lookup table. add some fps )). may be delete

      yoffs += scale;

      // byte rdistort = cos_wave [((x+y)*8+a2)&255]>>1; 
      // byte gdistort = cos_wave [((x+y)*8+a3+32)&255]>>1;
      // byte bdistort = cos_wave [((x+y)*8+a+64)&255]>>1;

      byte rdistort = cos_wave [(cos_wave[((x<<3)+a )&255]+cos_wave[((y<<3)-a2)&255]+a3   )&255]>>1; 
      byte gdistort = cos_wave [(cos_wave[((x<<3)-a2)&255]+cos_wave[((y<<3)+a3)&255]+a+32 )&255]>>1; 
      byte bdistort = cos_wave [(cos_wave[((x<<3)+a3)&255]+cos_wave[((y<<3)-a) &255]+a2+64)&255]>>1; 

      byte valueR = rdistort+ w*  (a- ( ((xoffs - cx) *  (xoffs - cx) +  (yoffs - cy) *   (yoffs - cy))>>7  ));
      byte valueG = gdistort+ w*  (a2-( ((xoffs - cx1) * (xoffs - cx1) + (yoffs - cy1) *  (yoffs - cy1))>>7 ));
      byte valueB = bdistort+ w*  (a3-( ((xoffs - cx2) * (xoffs - cx2) + (yoffs - cy2) *  (yoffs - cy2))>>7 ));

      valueR = cos_wave [valueR];
      valueG = cos_wave [valueG];
      valueB = cos_wave [valueB];
     
      leds[index].setRGB (valueR,valueG,valueB); 
      // CRGB newcolor = CRGB (valueR, valueG, valueB);
      // nblend( leds[index], newcolor, 128);
    }
  }

 GammaCorrection();
}

//_________________________cilindrical effects


// Spirals_Swirl_WithPalettes _________________________

//Yaroslaw Turbin 03-08-2021
//https://vk.com/ldirko
//https://www.reddit.com/user/ldirko/
//https://twitter.com/ldir_ko

void Spiral () {
 int a=(speed_slider()*millis())>>8;
 float scale = (sin(a/32*PI/180)+1)*12-16;  //-16..8
 float scale1 =0;
  for (int i = 0; i < NUM_COLS_CILINDR; i++) {
    for (int j = 0; j < NUM_ROWS_CILINDR; j++) {
      uint16_t index = XY_CILINDR(i,j);  
      if (index==241) continue;
      CRGB newcolor = ColorFromPalette( gCurrentPalette, (i*255/(NUM_COLS_CILINDR-1)+j*255/(NUM_ROWS_CILINDR-1))+(int)scale1+a+sin16(a)/16384, 255);
      nblend( leds[index], newcolor, 32);
    }
    scale1 += scale;
  }
}



//_______________________system function

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

byte XY_CILINDR (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);
}



void GammaCorrection(){   //gamma correction function 
 byte r,g,b;
  for (uint16_t i=0; i<NUM_LEDS; i++){
    r=leds[i].r;
    g=leds[i].g;
    b=leds[i].b;
    leds[i].r = pgm_read_byte(exp_gamma + r);
    leds[i].g = pgm_read_byte(exp_gamma + g);
    leds[i].b = pgm_read_byte(exp_gamma + b);
  }
}

byte speed_slider(){
  int val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)
  val = map(val, 0, 1023, 0, 255);         // map value between 0 and 255
  return (val);
}

byte bright_slider(){
  int val = analogRead(potpin1);            // reads the value of the potentiometer (value between 0 and 1023)
  val = map(val, 0, 1023, 0, 255);         // map value between 0 and 255
  return (255-val);
}

void Check_bright (){
 static byte oldBright=BRIGHTNESS;

 byte newbright = bright_slider();

  if (newbright!=oldBright) {
   oldBright = newbright; 
   BRIGHTNESS = newbright;
   FastLED.setBrightness(newbright);
  }

}

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();  
  }
}
FPS: 0
Power: 0.00W