//source: https://editor.soulmatelights.com/gallery/475-tixy-land-pattern-viewer

#include "FastLED.h"
#define DATA_PIN 2
#define BRIGHTNESS 255
#define NUM_LEDS 256
#define LED_COLS 16
#define LED_ROWS 16
#define LED_TYPE    WS2812B
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];
//#define FRAMES_PER_SECOND 60
const uint8_t kMatrixWidth = 16;
const uint8_t kMatrixHeight = 16;

const bool    kMatrixSerpentineLayout = false;

float code(double t, double i, double x, double y) {
  //put  tixy.land formulas after return
  //use fmod() against C++ modulo %
  //float r = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);  // use against random()
  
  //some patterns from twitter https://twitter.com/search?q=tixy.land&s=09 & reddit. uncomment it

//____________________________
//float a = tan(-y/max(x-8,y-8,7-x,7-y)-t*4);   //http://maettig.com/code/canvas/tixy.land-hd.html?code=tan%28-y%2Fmax%28x-8%2Cy-8%2C7-x%2C7-y%29-t*4%29
//float a = max(x-8,y-8);                       //uncomment whole block, in arduino max() work only with 2 numbers instead javascript ( 
//a = max(a,7-x);
//a = max (a,7-y);
//a = tan(-y/a-t*4);
//return a;
//_____________________________________________
//return x/y*(hypot(x+cos(t)-8,y-7)-6);  // https://twitter.com/aemkei/status/1340044770257870851?s=20 // shady sphere// by @blu3_enjoy 
//return 0.1/(sin(y/4-t*6)-sin(x*2-t));  // OK //https://twitter.com/ntsutae/status/1336729037549436931?s=20

//return sin(t-sqrt((x-7.5)**2+(y-6)**2));
return sin(4*t-hypot(x-8,y-8)); // OK
//return sin(hypot(x-=8,y-=8)+t+atan2(y,x)); // OK // https://twitter.com/aemkei/status/1331340057727406081?s=20
 // return abs(cos(atan2(y+2,x-8)*6+t*2)); //https://twitter.com/mgmalheiros/status/1328456054049476611?s=20
 // return tan(cos(x)-t)*tan(sin(y)-t)/16; //https://twitter.com/SonezakiRinji/status/1328149756133052416?s=20
 // return sin(y*sin(t/2)*2+t+i*6); // OK
  //return abs(7-x)<4?cos(t+(x+y)*PI/8):0; //https://twitter.com/HiraginoYuki/status/1327166558955663362 
  //return !((int)(x+t*50/(fmod(y*y,5.9)+1))&15)/(fmod(y*y,5.9)+1); 
  //return sin(atan((y-7.5)/(x-7.5))+t*6);
 // return sin(atan((y)/(x))+t);
  //return 1-fmod(( (t+x+sin(t+x)/2) -y/30),1.0);
  //return (y-8)/3-tan(x/6+1.87)*sin(t*2);
  //return (y-8)/3-(sin(x/4+t*4));
 // return fmod(i,4) - fmod(y,4)+sin(t);  // OK
 // return sin(x) - sin(x/2-2*t) - y/1.2+6;
  //return -0.4/(hypot(x-fmod(t,10),y-fmod(t,8))-fmod(t,2)*9);  // OK
  //return sin(x/3*sin(t/3)*2)+cos(y/4*sin(t/2)*2);  
  //return cos(sin((x*t*.1))*PI)+cos(sin(y*t*.1+(sqrt(abs(cos(x*t*.1)))))*PI);
  //return x/t/sqrt(55-(x-=8)*x-(y-=8)*y); //https://twitter.com/XorDev/status/1327059496951291905 
 // return sin(x*x*3*i/1e4-y/2+t*9);
  //return min(7-y+sin(x+sin(y+t*8))*6,0); //fire https://twitter.com/davemakes/status/1324226447351803905
 // return x*y/64*sin(t+x*6-y*6);  //https://twitter.com/maettig/status/1326162655061696513
  //return 6-hypot(x-7.5,y-7.5)-sin(i/3-t); //https://twitter.com/maettig/status/1326162655061696513
  //return 1-abs((x-6)*cos(t)+(y-6)*sin(t)); //https://twitter.com/maettig/status/1326163017533419529
  //return atan((x-7.5)*(y-7.5))-2.5*sin(t); //https://twitter.com/maettig/status/1326163136559403015
  //return sin(3*atan2(y-7.5,x-7.5)+t);  // OK //https://twitter.com/aemkei/status/1326637631409676291
  //return sin(3 * atan2(y - 7.5 + sin(t) * 5, x - 7.5 + sin(t / 2) * 5) + t * 5); // OK //i add move for //https://twitter.com/aemkei/status/1326637631409676291
  //return sin(PI*2*atan((y-8)/(x-8))+5*t); 
  //return sin((t/16)*i+x/y);
  //return sin(x/y-y/x+t);
 // return sin(t-sqrt(x*x+y*y));  // OK
  //return sin(x+t)+sin(y+t)+sin(x+y+t)/3;
 // return 1-hypot(sin(t)*9-x,cos(t)*9-y)/9;
  //return 1-fmod((x*x-y+t*(fmod(1+x*x,5.0))*3.0),16.0)/16.0;
  
  //return x>7-(sin(t*5+y*3)*6)?1:.2;  // my DNA ))) https://twitter.com/ldir_ko/status/1326099121170771968  https://tixy.land/?code=x%3E7-%28sin%28t*5%2By*3%29*6%29%3F1%3A.2
  
  //_____________________
 // float r = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);  // my fire )) https://twitter.com/ldir_ko/status/1325720180262113281 https://tixy.land/?code=%7Ei%2F200*%28y%2F40%2Frandom%28%29%29
  //return -i/200*(y/40/r);   // my fire ))  
  //____________________________________
}

void setup() {
  FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS); //setCorrection(TypicalLEDStrip);
  //FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.setBrightness(BRIGHTNESS);
  Serial.begin(115200);
}

void processFrame(double t, double x, double y) {
  double i = (y * 16) + x;
  //double frame, xtemp, ytemp;
 double frame = constrain(code(t, i, x, y), -1, 1) * 255;
 // xtemp=x-7; ytemp=y-7;
 // frame = constrain(sin(sqrt(xtemp*xtemp+ytemp*ytemp)+t+atan2(y,x)), -1, 1) * 255;
 // frame = constrain(sin(hypot(xtemp,ytemp)+t+atan2(y,x)), -1, 1) * 255;
  //Serial.println(frame); 
 // if (frame >= 0) { leds[XY(x,y)].setRGB(frame, frame, frame); } //change to XY(x, y) for non rotate display
 // else { leds[XY(x,y)].setRGB(-frame, 0, 0); } //change to XY(x, y) for non rotate display

  if (frame >= 0) { leds[XY(x, (LED_ROWS - 1 - y))].setRGB(frame, frame, frame); } //change to XY(x, y) for non rotate display
  else { leds[XY(x, (LED_ROWS - 1 - y))].setRGB(-frame, 0, 0); } //change to XY(x, y) for non rotate display
}

void loop() 
{
  double t = millis() / 1000.0; // some formulas is hardcoded and fps get down. this speedup it

  //FastLED.delay(1000); 
  for (byte x = 0; x < LED_COLS; x++) {
    for (byte y = 0; y < LED_ROWS; y++) {
      processFrame(t, x, y);
    }
  }
      FastLED.show();

}
 
uint16_t XY( uint8_t x, uint8_t y)
{
  uint16_t i;
  if( kMatrixSerpentineLayout == false) {
    i = (y * kMatrixWidth) + x;
  }
  if( kMatrixSerpentineLayout == true) {
    if( y & 0x01) {
      // Odd rows run backwards
      uint8_t reverseX = (kMatrixWidth - 1) - x;
      i = (y * kMatrixWidth) + reverseX;
    } else {
      // Even rows run forwards
      i = (y * kMatrixWidth) + x;
    }
  }
  return i;
}