|
@@ -6,19 +6,26 @@
|
|
|
// Logo polygon data — design canvas 107 × 125 units
|
|
// Logo polygon data — design canvas 107 × 125 units
|
|
|
// ---------------------------------------------------------------------------
|
|
// ---------------------------------------------------------------------------
|
|
|
static const int kGreenPts[][2] = {
|
|
static const int kGreenPts[][2] = {
|
|
|
- {19, 92}, {19, 39}, {54, 66}, {107, 24},
|
|
|
|
|
- {107, 1}, {54, 42}, { 1, 2}, { 1, 107}
|
|
|
|
|
|
|
+ { 20, 92}, // left leg inner, mid-height
|
|
|
|
|
+ { 20, 39}, // left leg inner, upper
|
|
|
|
|
+ { 54, 66}, // centre V, bottom
|
|
|
|
|
+ {107, 24}, // right leg, upper
|
|
|
|
|
+ {107, 1}, // right leg, top
|
|
|
|
|
+ { 54, 42}, // centre V, top peak
|
|
|
|
|
+ { 1, 2}, // left leg, top-left
|
|
|
|
|
+ { 1, 107}, // left leg, bottom-left
|
|
|
|
|
+ // Z closes back to {20, 92}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
static const int kBluePts[][2] = {
|
|
static const int kBluePts[][2] = {
|
|
|
- { 1, 125}, {31, 125}, {89, 79}, { 89, 107},
|
|
|
|
|
- { 76, 107}, {76, 125}, {107, 125}, {107, 42}
|
|
|
|
|
|
|
+ { 1, 125}, { 31, 125}, { 89, 79}, { 89, 107},
|
|
|
|
|
+ { 76, 107}, { 76, 125}, {107, 125}, {107, 42}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
static constexpr int LOGO_N = 8;
|
|
static constexpr int LOGO_N = 8;
|
|
|
-static constexpr float LOGO_SCALE = 1.6f;
|
|
|
|
|
-static constexpr int LOGO_X_OFF = 34;
|
|
|
|
|
-static constexpr int LOGO_Y_OFF = 20;
|
|
|
|
|
|
|
+static constexpr float LOGO_SCALE = 1.2f;
|
|
|
|
|
+static constexpr int LOGO_X_OFF = 55;
|
|
|
|
|
+static constexpr int LOGO_Y_OFF = 45;
|
|
|
|
|
|
|
|
static inline int lsx(int x) { return LOGO_X_OFF + (int)(x * LOGO_SCALE); }
|
|
static inline int lsx(int x) { return LOGO_X_OFF + (int)(x * LOGO_SCALE); }
|
|
|
static inline int lsy(int y) { return LOGO_Y_OFF + (int)(y * LOGO_SCALE); }
|
|
static inline int lsy(int y) { return LOGO_Y_OFF + (int)(y * LOGO_SCALE); }
|
|
@@ -43,6 +50,13 @@ static inline uint16_t logoBlueAt(float t) {
|
|
|
// ---------------------------------------------------------------------------
|
|
// ---------------------------------------------------------------------------
|
|
|
// Scanline polygon fill — operates in screen coordinates
|
|
// Scanline polygon fill — operates in screen coordinates
|
|
|
// ---------------------------------------------------------------------------
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
+static void outlinePolygon(TFT_eSPI &tft, int pts[][2], int n, uint16_t colour) {
|
|
|
|
|
+ for (int i = 0; i < n; i++) {
|
|
|
|
|
+ int j = (i + 1) % n;
|
|
|
|
|
+ tft.drawLine(pts[i][0], pts[i][1], pts[j][0], pts[j][1], colour);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static void fillPolygon(TFT_eSPI &tft, int pts[][2], int n, uint16_t colour) {
|
|
static void fillPolygon(TFT_eSPI &tft, int pts[][2], int n, uint16_t colour) {
|
|
|
int yMin = pts[0][1], yMax = pts[0][1];
|
|
int yMin = pts[0][1], yMax = pts[0][1];
|
|
|
for (int i = 1; i < n; i++) {
|
|
for (int i = 1; i < n; i++) {
|
|
@@ -50,16 +64,19 @@ static void fillPolygon(TFT_eSPI &tft, int pts[][2], int n, uint16_t colour) {
|
|
|
if (pts[i][1] > yMax) yMax = pts[i][1];
|
|
if (pts[i][1] > yMax) yMax = pts[i][1];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- int nodeX[16]; // 8-point polygon produces at most 8 intersections per line
|
|
|
|
|
|
|
+ int nodeX[16];
|
|
|
|
|
|
|
|
for (int y = yMin; y <= yMax; y++) {
|
|
for (int y = yMin; y <= yMax; y++) {
|
|
|
int nodes = 0;
|
|
int nodes = 0;
|
|
|
int j = n - 1;
|
|
int j = n - 1;
|
|
|
for (int i = 0; i < n; i++) {
|
|
for (int i = 0; i < n; i++) {
|
|
|
int yi = pts[i][1], yj = pts[j][1];
|
|
int yi = pts[i][1], yj = pts[j][1];
|
|
|
- if ((yi < y && yj >= y) || (yj < y && yi >= y)) {
|
|
|
|
|
- int dy = yj - yi;
|
|
|
|
|
- nodeX[nodes++] = pts[i][0] + (y - yi) * (pts[j][0] - pts[i][0]) / dy;
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // Key fix: use strictly-one-side rule to avoid double-counting vertices
|
|
|
|
|
+ if ((yi <= y && yj > y) || (yj <= y && yi > y)) {
|
|
|
|
|
+ long num = (long)(y - yi) * (pts[j][0] - pts[i][0]);
|
|
|
|
|
+ long dy = yj - yi;
|
|
|
|
|
+ nodeX[nodes++] = pts[i][0] + (int)(num / dy);
|
|
|
}
|
|
}
|
|
|
j = i;
|
|
j = i;
|
|
|
}
|
|
}
|
|
@@ -105,13 +122,13 @@ inline void drawLogo(TFT_eSPI &tft) {
|
|
|
|
|
|
|
|
// Phase 1: green fade-in
|
|
// Phase 1: green fade-in
|
|
|
for (int i = 0; i <= LOGO_FADE_STEPS; i++) {
|
|
for (int i = 0; i <= LOGO_FADE_STEPS; i++) {
|
|
|
- fillPolygon(tft, sGreen, LOGO_N, logoGreenAt(i / (float)LOGO_FADE_STEPS));
|
|
|
|
|
|
|
+ outlinePolygon(tft, sGreen, LOGO_N, logoGreenAt(i / (float)LOGO_FADE_STEPS));
|
|
|
delay(LOGO_FADE_STEP_MS);
|
|
delay(LOGO_FADE_STEP_MS);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Phase 2: blue fade-in (green redrawn solid to prevent bleed-through)
|
|
// Phase 2: blue fade-in (green redrawn solid to prevent bleed-through)
|
|
|
for (int i = 0; i <= LOGO_FADE_STEPS; i++) {
|
|
for (int i = 0; i <= LOGO_FADE_STEPS; i++) {
|
|
|
- fillPolygon(tft, sGreen, LOGO_N, logoGreenAt(1.0f));
|
|
|
|
|
|
|
+ outlinePolygon(tft, sGreen, LOGO_N, logoGreenAt(1.0f));
|
|
|
fillPolygon(tft, sBlue, LOGO_N, logoBlueAt(i / (float)LOGO_FADE_STEPS));
|
|
fillPolygon(tft, sBlue, LOGO_N, logoBlueAt(i / (float)LOGO_FADE_STEPS));
|
|
|
delay(LOGO_FADE_STEP_MS);
|
|
delay(LOGO_FADE_STEP_MS);
|
|
|
}
|
|
}
|