#include <TFT_eSPI.h> // Graphics and font library for ILI9341 driver chip
#include <SPI.h>
TFT_eSPI tft = TFT_eSPI(); // Invoke library
struct Rectangle {
int line1_0x, line1_0y;
int line1_1x, line1_1y;
int line3_0x, line3_0y;
int line3_1x, line3_1y;
};
int line1[2][33] = {{0}};
int line2[2][33] = {{0}};
int line3[2][33] = {{0}};
int line4[2][33] = {{0}};
int line5[2][6] = {
{70, 61, 49, 34, 17, -5},
{250, 259, 271, 286, 303, 325}
};
int line_1x0[6], line_1y0[6], line_1x1[6], line_1y1[6];
int line_3x0[6], line_3y0[6], line_3x1[6], line_3y1[6];
int prev_1x0[6], prev_1y0[6], prev_1x1[6], prev_1y1[6];
int prev_3x0[6], prev_3y0[6], prev_3x1[6], prev_3y1[6];
uint8_t lines[6][6] = {
{ 0, 0, 1, 1, 2, 3 },
{ 0, 0, 0, 1, 2, 3 },
{ 3, 4, 5, 6, 7, 8 },
{8, 10, 12, 14, 16, 18 },
{18, 20, 23, 26, 30, 31 },
{0, 9, 12, 15, 18, 21 }
};
int leftLineX = 10;
int rightLineX = 310;
// Screen center coordinates
#define CENTER_X 160 // Adjust for your TFT resolution if needed
#define CENTER_Y 100 // Adjust for your TFT resolution if needed
char countdown[7] = "047100";
unsigned long lastUpdateTime = 0;
unsigned long lastRedLinesTime = 0;
int semiHeight = 5; // Initial height of the semi-rectangle
bool countdownFinished = false;
Rectangle rect[6];
Rectangle rectInit[6];
uint8_t rectIndex = 0;
// uint8_t lineIndex = 0;
void setup() {
Serial.begin(9600);
tft.begin();
tft.setRotation(1); // Set the screen rotation (1 = landscape)
tft.fillScreen(TFT_BLACK); // Clear the screen
rect[0] = { 156, 95, 156, 105, 164, 105, 164, 95 };
rect[1] = { 156, 95, 156, 105, 164, 105, 164, 95 };
rect[2] = { 150, 86, 150, 114, 170, 114, 170, 86 };
rect[3] = { 138, 71, 138, 129, 182, 129, 182, 71 };
rect[4] = { 113, 41, 113, 159, 207, 159, 207, 41 };
rect[5] = { 70, 3, 70, 198, 250, 198, 250, 3 };
rectInit[0] = { 156, 95, 156, 105, 164, 105, 164, 95 };
rectInit[1] = { 156, 95, 156, 105, 164, 105, 164, 95 };
rectInit[2] = { 150, 86, 150, 114, 170, 114, 170, 86 };
rectInit[3] = { 138, 71, 138, 129, 182, 129, 182, 71 };
rectInit[4] = { 113, 41, 113, 159, 207, 159, 207, 41 };
rectInit[5] = { 70, 3, 70, 198, 250, 198, 250, 3 };
drawRoundedRectangle();
drawGrid();
drawSemi();
drawCountdown();
calculatePoints();
}
void loop() {
updateAnimation();
if(countdownFinished) {
countdownFinished = false;
tft.drawLine(leftLineX, 4, leftLineX, 197, TFT_BLACK); // Clear previous lines
tft.drawLine(leftLineX + 1, 4, leftLineX + 1, 197, TFT_BLACK); // Clear previous lines
tft.drawLine(leftLineX + 2, 4, leftLineX + 2, 197, TFT_BLACK); // Clear previous lines
tft.drawLine(rightLineX, 4, rightLineX, 197, TFT_BLACK);
tft.drawLine(rightLineX - 1, 4, rightLineX - 1, 197, TFT_BLACK);
tft.drawLine(rightLineX - 2, 4, rightLineX - 2, 197, TFT_BLACK);
leftLineX = 10;
rightLineX = 310;
strcpy(countdown, "047100"); // Set countdown to default
drawCountdown();
}
}
void drawRoundedRectangle() {
tft.drawRoundRect(2, 0, 316, 200, 15, TFT_YELLOW);
tft.drawRoundRect(3, 1, 314, 198, 15, TFT_YELLOW);
}
void drawSemi(void) {
tft.drawRoundRect(70, 207, tft.width() - 132, 31, 15, TFT_YELLOW);
tft.drawRoundRect(71, 208, tft.width() - 133, 32, 15, TFT_YELLOW);
}
void drawRedLines() {
tft.drawLine(leftLineX, 4, leftLineX, 197, TFT_RED); // Draw updated lines
tft.drawLine(leftLineX + 1, 4, leftLineX + 1, 197, TFT_RED); // Draw updated lines
tft.drawLine(leftLineX + 2, 4, leftLineX + 2, 197, TFT_RED); // Draw updated lines
tft.drawLine(rightLineX, 4, rightLineX, 197, TFT_RED);
tft.drawLine(rightLineX - 1, 4, rightLineX - 1, 197, TFT_RED);
tft.drawLine(rightLineX - 2, 4, rightLineX - 2, 197, TFT_RED);
}
// Draw and update countdown
void drawCountdown() {
tft.setTextColor(TFT_RED, TFT_BLACK);
tft.setTextDatum(TC_DATUM); // Center alignment
tft.setTextSize(3);
tft.drawString(countdown, CENTER_X + 2, 213);
}
// Update countdown and animation
void updateCountdownAndAnimation() {
if (countdownFinished) return;
unsigned long currentTime = millis();
if (currentTime - lastUpdateTime < 10) return; // Update every 10ms
lastUpdateTime = currentTime;
updateRedLines();
// Update countdown logic
for (int i = 4; i >= 0; i--) {
if (countdown[i] > '0') {
countdown[i]--;
break;
} else {
countdown[i] = '9';
}
}
if (strcmp(countdown, "000000") == 0) {
countdownFinished = true;
}
drawCountdown(); // Update the countdown display
}
// Update red lines moving to the center
void updateRedLines() {
unsigned long redLinesTime = millis();
if (countdownFinished || redLinesTime - lastRedLinesTime < 510) return;
lastRedLinesTime = redLinesTime;
tft.drawLine(leftLineX, 4, leftLineX, 197, TFT_BLACK); // Clear previous lines
tft.drawLine(leftLineX + 1, 4, leftLineX + 1, 197, TFT_BLACK); // Clear previous lines
tft.drawLine(leftLineX + 2, 4, leftLineX + 2, 197, TFT_BLACK); // Clear previous lines
tft.drawLine(rightLineX, 4, rightLineX, 197, TFT_BLACK);
tft.drawLine(rightLineX - 1, 4, rightLineX - 1, 197, TFT_BLACK);
tft.drawLine(rightLineX - 2, 4, rightLineX - 2, 197, TFT_BLACK);
leftLineX++;
rightLineX--;
// Stop moving lines when they reach the center
if (leftLineX >= CENTER_X - 3) {
leftLineX = 157;
rightLineX = 163;
}
tft.drawLine(leftLineX, 4, leftLineX, 197, TFT_RED); // Draw updated lines
tft.drawLine(leftLineX + 1, 4, leftLineX + 1, 197, TFT_RED); // Draw updated lines
tft.drawLine(leftLineX + 2, 4, leftLineX + 2, 197, TFT_RED); // Draw updated lines
tft.drawLine(rightLineX, 4, rightLineX, 197, TFT_RED);
tft.drawLine(rightLineX - 1, 4, rightLineX - 1, 197, TFT_RED);
tft.drawLine(rightLineX - 2, 4, rightLineX - 2, 197, TFT_RED);
drawGrid();
}
void drawGrid(void) {
tft.drawLine(25, 2, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(26, 2, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(27, 2, CENTER_X - 1, CENTER_Y, TFT_YELLOW);
tft.drawLine(295, 2, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(294, 2, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(293, 2, CENTER_X + 1, CENTER_Y, TFT_YELLOW);
tft.drawLine(80, 2, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(81, 2, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(82, 2, CENTER_X - 1, CENTER_Y, TFT_YELLOW);
tft.drawLine(240, 2, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(239, 2, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(238, 2, CENTER_X + 1, CENTER_Y, TFT_YELLOW);
tft.drawLine(2, 60, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(2, 61, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(2, 62, CENTER_X - 1, CENTER_Y, TFT_YELLOW);
tft.drawLine(317, 60, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(317, 61, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(317, 62, CENTER_X + 1, CENTER_Y, TFT_YELLOW);
tft.drawLine(2, 130, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(2, 131, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(2, 132, CENTER_X - 1, CENTER_Y, TFT_YELLOW);
tft.drawLine(317, 130, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(317, 131, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(317, 132, CENTER_X + 1, CENTER_Y, TFT_YELLOW);
tft.drawLine(25, 199, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(26, 199, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(27, 199, CENTER_X - 1, CENTER_Y, TFT_YELLOW);
tft.drawLine(295, 199, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(294, 199, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(293, 199, CENTER_X + 1, CENTER_Y, TFT_YELLOW);
tft.drawLine(80, 199, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(81, 199, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(82, 199, CENTER_X - 1, CENTER_Y, TFT_YELLOW);
tft.drawLine(240, 199, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(239, 199, CENTER_X, CENTER_Y, TFT_YELLOW);
tft.drawLine(238, 199, CENTER_X + 1, CENTER_Y, TFT_YELLOW);
}
void calculatePoints(void) {
for(uint8_t counts = 0; counts < 32; counts++) {
line1[0][counts] = rect[0].line1_0x;
line1[1][counts] = rect[0].line1_0y;
line2[0][counts] = rect[0].line1_0x;
line2[1][counts] = rect[0].line1_1y;
line4[0][counts] = rect[0].line3_0x;
line4[1][counts] = rect[0].line1_0y;
line3[0][counts] = rect[0].line3_0x;
line3[1][counts] = rect[0].line1_1y;
limit(rect[0].line1_0x, rect[0].line1_0y, 80, 2, &line_1x0[0], &line_1y0[0]);
rect[0].line1_0x = line_1x0[0];
rect[0].line1_0y = line_1y0[0];
limit(rect[0].line1_1x, rect[0].line1_1y, 80, 199, &line_1x1[0], &line_1y1[0]);
rect[0].line1_1x = line_1x1[0];
rect[0].line1_1y = line_1y1[0];
limit(rect[0].line3_0x, rect[0].line3_0y, 240, 199, &line_3x0[0], &line_3y0[0]);
rect[0].line3_0x = line_3x0[0];
rect[0].line3_0y = line_3y0[0];
limit(rect[0].line3_1x, rect[0].line3_1y, 240, 2, &line_3x1[0], &line_3y1[0]);
rect[0].line3_1x = line_3x1[0];
rect[0].line3_1y = line_3y1[0];
}
for(uint8_t i=0; i<6; i++) {
rect[i].line1_0x = rectInit[i].line1_0x;
rect[i].line1_0y = rectInit[i].line1_0y;
rect[i].line1_1x = rectInit[i].line1_1x;
rect[i].line1_1y = rectInit[i].line1_1y;
rect[i].line3_0x = rectInit[i].line3_0x;
rect[i].line3_0y = rectInit[i].line3_0y;
rect[i].line3_1x = rectInit[i].line3_1x;
rect[i].line3_1y = rectInit[i].line3_1y;
}
line1[0][31] = 70;
line1[1][31] = 3;
line2[0][31] = 70;
line2[1][31] = 197;
line3[0][31] = 250;
line3[1][31] = 3;
line4[0][31] = 250;
line4[1][31] = 197;
}
void updateAnimation(void) {
for (uint8_t i = 0; i < 6; i++) {
updateCountdownAndAnimation();
if(i != 5) {
rect[i].line1_0x = line1[0][(lines[i][rectIndex])];
rect[i].line1_0y = line1[1][(lines[i][rectIndex])];
rect[i].line1_1x = line2[0][(lines[i][rectIndex])];
rect[i].line1_1y = line2[1][(lines[i][rectIndex])];
rect[i].line3_0x = line3[0][(lines[i][rectIndex])];
rect[i].line3_0y = line3[1][(lines[i][rectIndex])];
rect[i].line3_1x = line4[0][(lines[i][rectIndex])];
rect[i].line3_1y = line4[1][(lines[i][rectIndex])];
} else {
rect[i].line1_0x = line5[0][rectIndex];
rect[i].line1_0y = 3;
rect[i].line1_1x = line5[0][rectIndex];
rect[i].line1_1y = 197;
rect[i].line3_0x = line5[1][rectIndex];
rect[i].line3_0y = 3;
rect[i].line3_1x = line5[1][rectIndex];
rect[i].line3_1y = 197;
}
if (rectIndex < 3 && i == 1)
continue;
tft.drawLine(prev_1x0[i], prev_1y0[i], prev_1x1[i], prev_1y1[i], TFT_BLACK);
if(i!=5)
tft.drawLine(prev_1x1[i], prev_1y1[i], prev_3x0[i], prev_3y0[i], TFT_BLACK);
tft.drawLine(prev_3x0[i], prev_3y0[i], prev_3x1[i], prev_3y1[i], TFT_BLACK);
tft.drawLine(rect[i].line1_0x, rect[i].line1_0y, rect[i].line1_1x, rect[i].line1_1y, TFT_YELLOW);
if(i != 5)
tft.drawLine(rect[i].line1_1x, rect[i].line1_1y, rect[i].line3_0x, rect[i].line3_0y, (rectIndex > 3 && i == 4) ? TFT_BLACK : TFT_YELLOW);
tft.drawLine(rect[i].line3_0x, rect[i].line3_0y, rect[i].line3_1x, rect[i].line3_1y, TFT_YELLOW);
prev_1x0[i] = rect[i].line1_0x;
prev_1y0[i] = rect[i].line1_0y;
prev_1x1[i] = rect[i].line1_1x;
prev_1y1[i] = rect[i].line1_1y;
prev_3x0[i] = rect[i].line3_0x;
prev_3y0[i] = rect[i].line3_0y;
prev_3x1[i] = rect[i].line3_1x;
prev_3y1[i] = rect[i].line3_1y;
drawGrid();
drawRedLines();
}
rectIndex = (rectIndex + 1) % 5;
}
void limit(int x0, int y0, int x1, int y1, int *xr, int *yr) { //Bresenham's Algorithm
int dx = abs(x1 - x0);
int dy = abs(y1 - y0);
int sx = (x0 < x1) ? 1 : -1;
int sy = (y0 < y1) ? 1 : -1;
int err = dx - dy;
for (uint8_t i = 0; i < 3; i++) { //increment the semi rectangle by 5 points
int e2 = 2 * err;
if (e2 > -dy) {
err -= dy;
x0 += sx;
}
if (e2 < dx) {
err += dx;
y0 += sy;
}
}
*xr = x0;
*yr = y0;
}