#include <FastLED.h>

#define LED_PIN         3
#define MATRIX_WIDTH    40
#define MATRIX_HEIGHT   12
#define VIRTUAL_MATRIX_WIDTH = MATRIX_WIDTH << 1;
#define VIRTUAL_MATRIX_HEIGHT = MATRIX_HEIGHT << 1;
#define NUM_LEDS        (MATRIX_WIDTH * MATRIX_HEIGHT)


CRGB leds[NUM_LEDS];

struct Line {
  int x1, y1, x2, y2;
  CRGB color;
};

#define NUM_LINES 8 // Number of lines for the snowflake

Line lines[NUM_LINES]; // Array to hold the lines for the snowflake

void setup() {
  Serial.begin(9600);
  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);

 // Load lines for the snowflake into the array (Snowflake 1)
  // lines[0] = {18,  2, 28, 12, CRGB::White};
  // lines[1] = {20,  9, 25,  4, CRGB::White};
  // lines[2] = {38,  2, 28, 12, CRGB::White};
  // lines[3] = {31,  4, 36,  9, CRGB::White};
  // lines[4] = {38, 22, 28, 12, CRGB::White};
  // lines[5] = {31, 20, 36, 15, CRGB::White};
  // lines[6] = {18, 22, 28, 12, CRGB::White};
  // lines[7] = {20, 15, 25, 20, CRGB::White};

//   // Load lines for the snowflake into the array
//   lines[0] = {18,  2, 28, 12, CRGB::White};
//   lines[1] = {18,  8, 24,  2, CRGB::White};
//   lines[2] = {38,  2, 28, 12, CRGB::White};
//   lines[3] = {32,  2, 38,  8, CRGB::White};
//   lines[4] = {38, 22, 28, 12, CRGB::White};
//   lines[5] = {32, 22, 38, 16, CRGB::White};
//   lines[6] = {18, 22, 28, 12, CRGB::White};
//   lines[7] = {18, 16, 24, 22, CRGB::White};

  // Load lines for the snowflake into the array
  lines[0] = {18,  2, 28, 12, CRGB::White};
  lines[1] = {19,  9, 25,  3, CRGB::White};
  lines[2] = {38,  2, 28, 12, CRGB::White};
  lines[3] = {31,  3, 37,  9, CRGB::White};
  lines[4] = {38, 22, 28, 12, CRGB::White};
  lines[5] = {31, 21, 37, 15, CRGB::White};
  lines[6] = {18, 22, 28, 12, CRGB::White};
  lines[7] = {19, 15, 25, 21, CRGB::White};


}

void loop() {
  // Iterate over all the elements in the lines array
  for (int i = 0; i < NUM_LINES; i++) {
    draw_line(lines[i]); // Draw each line in the lines array
  }
  FastLED.show();
  delay(1000); // Adjust delay time as needed
  FastLED.clear();
}

int XY(int x, int y) {
  return y * MATRIX_WIDTH + ((y % 2 == 0) ? x : MATRIX_WIDTH - 1 - x);
}

void wu_pixel(uint32_t x, uint32_t y, CRGB *col) {
  uint8_t xx = x & 0xff, yy = y & 0xff, ix = 255 - xx, iy = 255 - yy;
  uint8_t wu[4] = {((ix * iy) + ix + iy) >> 8, ((xx * iy) + xx) >> 8,
                   ((ix * yy) + ix + yy) >> 8, ((xx * yy) + xx) >> 8
                  };

  for (uint8_t i = 0; i < 4; i++) {
    uint16_t xy = XY((x >> 8) + (i & 1), (y >> 8) + ((i >> 1) & 1));
    CRGB *led = &leds[xy];
    led->r = qadd8(led->r, col->r * wu[i] >> 8);
    led->g = qadd8(led->g, col->g * wu[i] >> 8);
    led->b = qadd8(led->b, col->b * wu[i] >> 8);
  }
}

void draw_line(Line &line) {
  int x1 = line.x1;
  int y1 = line.y1;
  int x2 = line.x2;
  int y2 = line.y2;
  CRGB color = line.color;

  int dx = abs(x2 - x1);
  int dy = abs(y2 - y1);
  int sx = x1 < x2 ? 1 : -1;
  int sy = y1 < y2 ? 1 : -1;
  int err = dx - dy;
  int x = x1;
  int y = y1;

  while (true) {
    wu_pixel(x << 7, y << 7, &color);

    if (x == x2 && y == y2)
      break;
    int e2 = 2 * err;
    if (e2 > -dy) {
      err -= dy;
      x += sx;
    }
    if (e2 < dx) {
      err += dx;
      y += sy;
    }
  }
}