//simle rotozoomer procedure 
//fast led rgb matrix 16x16 demo
//Yaroslaw Turbin, 03.11.2020 
//https://vk.com/ldirko
//https://www.reddit.com/user/ldirko/

//how it's look in emulator: https://wokwi.com/arduino/projects/281176629596652040 
//                           https://editor.soulmatelights.com/gallery/457

#include "FastLED.h"
 
// Matrix size
#define NUM_ROWS 30
#define NUM_COLS 13
#define NUM_LEDS NUM_ROWS * NUM_COLS
struct pos_f{  float x; float y;};
struct pos_8{  uint8_t x; uint8_t y;};
//const uint8_t vHeight = NUM_COLS;
//const uint8_t vWidth = NUM_ROWS;

uint8_t vWidth = NUM_COLS;
  uint8_t vHeight = NUM_ROWS;
// LEDs pin 
#define DATA_PIN 3
 
// LED brightness
#define BRIGHTNESS 255
 
// Define the array of leds
CRGB leds[NUM_LEDS];
uint16_t ledPixelPos[NUM_LEDS][2];

DEFINE_GRADIENT_PALETTE( temperature_gp ) {
    0,   1, 27,105,
   14,   1, 40,127,
   28,   1, 70,168,
   42,   1, 92,197,
   56,   1,119,221,
   70,   3,130,151,
   84,  23,156,149,
   99,  67,182,112,
  113, 121,201, 52,
  127, 142,203, 11,
  141, 224,223,  1,
  155, 252,187,  2,
  170, 247,147,  1,
  184, 237, 87,  1,
  212, 229, 43,  1,
  226, 220, 15,  1,
  240, 171,  2,  2,
 // 255,  80,  3,  3};
 255,  1,  27,  105};
CRGBPalette16 myPal;


pos_f nextCenter = {6.0,15.0};
pos_f moveCenter = {0.0,0.0};
pos_f waveCenter = {6.0,15.0};
float hueSpeed = 40; // update hue delay


void setup() {
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  FastLED.setBrightness(BRIGHTNESS);
  Serial.begin(115200);
  setLedPxPos();
  myPal = temperature_gp;

}
  
void loop() {

 EVERY_N_MILLIS(10){ 
  // plasma();
  // movingWave();
 rotozum ();
 // rotationRainbow();
 showOnlyCenter();
  FastLED.show();
  }
EVERY_N_MILLIS(400){ 
  Serial.print(nextCenter.x);Serial.print('\t');Serial.print(nextCenter.y);;Serial.print('\t');
Serial.print(moveCenter.x);Serial.print('\t');Serial.print(moveCenter.y);Serial.print('\t');
Serial.print(waveCenter.x);Serial.print('\t');Serial.print(waveCenter.y);
//Serial.print();Serial.print('\t');
Serial.println(); 
}
}

void plasma(){
  uint8_t zoom = 30; // zoom 20 to 80
  float speed = 0.1;
  uint16_t ms = speed*millis();  
  for( int i = 0; i< NUM_LEDS; i++){
    uint8_t x = ledPixelPos[i][0];
    uint8_t y = ledPixelPos[i][1];
    byte noises =  inoise8 (y * zoom, x * zoom, ms);
    leds[XY(x,y)] = ColorFromPalette (myPal, noises, BRIGHTNESS );
  }
}

uint16_t XY (uint8_t x, uint8_t y) { return (y * NUM_COLS + x);}		//simple function to find led number in led matrix, 
																	//change this to your routine
																	//or generate XY function for your matrix there:
																	//https://macetech.github.io/FastLED-XY-Map-Generator/

void setLedPxPos(){
  for (int i = 0; i < NUM_LEDS; i++){
    ledPixelPos[i][0] = i % NUM_COLS;
    ledPixelPos[i][1] = i / NUM_COLS;
  }
}
void showOnlyCenter(){
 for( int x = 0; x < vWidth ; x++){
  for( int y = 0; y < vHeight ; y++){
     if(x != 6) leds[XY(x,y)] = nblend(leds[XY(x,y)],CRGB::Black,127); 
     //if(x != 6) leds[XY(x,y)] = CRGB::Black; 
  }
 }

}


pos_f getRandomPoint(){  return  {random( 0, vWidth), random( 0, vHeight)};}

//pos_f getStep(pos_f posCurrent, pos_f posTarget){ return {(posTarget.x - posCurrent.x) / 50 , (posTarget.y - posCurrent.y) / 50 };}
pos_f getStep(pos_f posCurrent, pos_f posTarget){ 
  pos_f deltaPos = {(posTarget.x - posCurrent.x) , (posTarget.y - posCurrent.y) };
  float dist = sqrt(sq(deltaPos.x)+sq(deltaPos.y)) / sqrt(sq(vWidth)+sq(vHeight)); // normalized distance
  return {deltaPos.x * dist / 30 , deltaPos.y * dist / 30 };
  }


void movingWave(){
  static uint16_t hueOffset  = 0; // counter for radial color wave motion
  static int plasVector = 0;// 0; // counter for orbiting plasma center

  static float zoom = 6; //0.7; // 0.5 is close and 10 is zoomed out
  static uint8_t yDelta = 128;
  static uint8_t yDeltaMax = NUM_LEDS/2 + 2;
   float xOffA = -waveCenter.x;
   float yOffA = -waveCenter.y;
   float xOffB = -nextCenter.x;
   float yOffB = -nextCenter.y;
  for( int i = 0; i < (NUM_LEDS); i++ ){
    int x = ledPixelPos[i][0];
    int y = ledPixelPos[i][1];
    byte color;

    float waveCenterDistA = sqrt(sq(((float)x + xOffA)*zoom) + sq(((float)y + yOffA )* zoom)) ;
    color = sin8(waveCenterDistA + hueOffset) ;
    leds[i] = ColorFromPalette(myPal, color, 255, LINEARBLEND);
  }
  EVERY_N_MILLIS(40){
    hueOffset-= 3;
    if((int)waveCenter.x != (int)nextCenter.x && (int)waveCenter.y != (int)nextCenter.y){
      waveCenter.x += moveCenter.x;
      waveCenter.y += moveCenter.y;
    }
    else if(waveCenter.x < 0 || waveCenter.y < 0 || waveCenter.x > vWidth || waveCenter.y > vHeight);}
    else{
      nextCenter = getRandomPoint();
      moveCenter = getStep(waveCenter,nextCenter);
      }
    }
//}




  
  
void rotationRainbow()  // ---- palettemix
{
    float zoom = 10;
    
    uint32_t ms = millis();
    //int32_t yHueDelta32 = ((int32_t)cos16( ms * (27/1) ) * (350 / vWidth));
    //int32_t xHueDelta32 = ((int32_t)sin16( ms * (39/1) ) * (310 / vHeight));
    int32_t yHueDelta32 = ((int32_t)cos16( (ms * (17.0/1.0)) + vWidth/2) * (35*zoom / vWidth));
    int32_t xHueDelta32 = ((int32_t)cos16( (ms * (29.0/1.0)) + vHeight/2) * (31*zoom / vHeight));
    DrawOneFrame( ms / 65536, yHueDelta32 / 32768, xHueDelta32 / 32768 + 3*zoom);
}
void DrawOneFrame( byte startHue8, int8_t yHueDelta8, int8_t xHueDelta8){
  Serial.print(startHue8 );Serial.print('\t');Serial.print(yHueDelta8);Serial.print('\t');Serial.println(xHueDelta8);
  for( int i = 0; i< NUM_LEDS; i++){
    uint8_t x = i % NUM_COLS;
    uint8_t y = i / NUM_COLS;

    byte pixelHue = (startHue8 + (yHueDelta8 * (y+1))) + (xHueDelta8 * (x+1));

        leds[XY(x, y)]  = CHSV( pixelHue, 255, 255);       
  }

}
uno:SCL
uno:SDA
uno:AREF
uno:GND.1
uno:13
uno:12
uno:11
uno:10
uno:9
uno:8
uno:7
uno:6
uno:5
uno:4
uno:3
uno:2
uno:1
uno:0
uno:14
uno:15
uno:16
uno:17
uno:18
uno:19
uno:20
uno:21
uno:5V.1
uno:5V.2
uno:22
uno:23
uno:24
uno:25
uno:26
uno:27
uno:28
uno:29
uno:30
uno:31
uno:32
uno:33
uno:34
uno:35
uno:36
uno:37
uno:38
uno:39
uno:40
uno:41
uno:42
uno:43
uno:44
uno:45
uno:46
uno:47
uno:48
uno:49
uno:50
uno:51
uno:52
uno:53
uno:GND.4
uno:GND.5
uno:IOREF
uno:RESET
uno:3.3V
uno:5V
uno:GND.2
uno:GND.3
uno:VIN
uno:A0
uno:A1
uno:A2
uno:A3
uno:A4
uno:A5
uno:A6
uno:A7
uno:A8
uno:A9
uno:A10
uno:A11
uno:A12
uno:A13
uno:A14
uno:A15
neopixels:DOUT
neopixels:VDD
neopixels:VSS
neopixels:DIN