/*
Original Lua/TIC-80 source was live-coded in
25 minutes by exoticorn during a 256-byte battle
at outlinedemoparty.nl 2021-05-15

function TIC()t=time()/1e3
for i=0,32639 do
x=i%240-120
y=i//240-68
z=20/(x*x+y*y)^.5+t
q=z%9<6 and z-z%9+6 or z
w=9/y+t
c=y>0 and w<q and
(((x*(w-t))^2<99 and 14 or 6)+w%2)or
(-y*(q-t)<99/((x*(q-t)/50)^2+1)and(q==z and z%2 or 3)or 12-y/20)
poke4(i,c)
end
end
*/

#include <FastLED.h>

const uint8_t kHalfWidth = 8;
const uint8_t kHalfHeight = 8;
#define NUM_LEDS (4 * kHalfWidth * kHalfHeight)
CRGB leds[NUM_LEDS];

void setup() {
  FastLED.addLeds<NEOPIXEL,3>(leds, NUM_LEDS);
  Serial.begin(115200);
}

// https://github.com/nesbox/TIC-80/wiki/palette
CRGBPalette16 palette = {0x1a1c2c, 0x5d275d, 0xb13e53, 0xef7d57,
  0xffcd75, 0xa7f070, 0x38b764, 0x257179, 0x29366f, 0x3b5dc9,
  0x41a6f6, 0x73eff7, 0xf4f4f4, 0x94b0c2, 0x566c86, 0x333c57};

#pragma GCC push_options
#pragma GCC optimize "-Ofast"
void loop() {
  CRGB *led = leds;
  byte c;
  float t = (millis() % (21*200*2)) / 200.f, z, q, w;
  for (int8_t y = -kHalfHeight-kHalfHeight/8; y < kHalfHeight-kHalfHeight/8; y++) {
    for (int8_t x = -kHalfWidth; x <= 0; x++) {
      z = 20.0f / sqrtf(x*x + y*y) + t;
      q = (fmod(z, 21) < 15) ? z - fmod(z, 21) + 15 : z;
      w = 9.0f / y + t;
      if (y > 0 && w < q)
        c = (powf(x*(w-t), 2) < 39 ? 14 : 6) + fmod(w, 2);
      else
        if (-y*(q-t) < 99.f / (powf(x*(q-t) / 50.f, 2)+1))
          c = (q==z) ? fmod(z, 2) : 3;
        else
          c = 9 - y/3 - ((0x2 >> (-y%3)) & 1);
      *led++ = palette[c];
    }
    CRGB *src = led-1;
    for (uint8_t x = 1; x < kHalfWidth; x++)
      *led++ = *--src;
  }
  FastLED.show();

  // print frames per second
  uint16_t sample_frames = 50;
  static uint16_t frame;
  static uint32_t last_ms;
  if (++frame == sample_frames) {
    frame = 0;
    Serial.print(sample_frames * 1000.0 / (millis() - last_ms));
    Serial.println(" FPS");
    last_ms = millis();
  }
}
#pragma GCC pop_options