|
|
@@ -3,38 +3,119 @@
|
|
|
#include "config.h"
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
-// Startup logo rendered via TFT_eSPI sprites.
|
|
|
-// Replace drawLogo() with custom artwork stored in PROGMEM if required.
|
|
|
+// Logo polygon data — design canvas 107 × 125 units
|
|
|
// ---------------------------------------------------------------------------
|
|
|
+static const int kGreenPts[][2] = {
|
|
|
+ {19, 92}, {19, 39}, {54, 66}, {107, 24},
|
|
|
+ {107, 1}, {54, 42}, { 1, 2}, { 1, 107}
|
|
|
+};
|
|
|
|
|
|
+static const int kBluePts[][2] = {
|
|
|
+ { 1, 125}, {31, 125}, {89, 79}, { 89, 107},
|
|
|
+ { 76, 107}, {76, 125}, {107, 125}, {107, 42}
|
|
|
+};
|
|
|
+
|
|
|
+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 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); }
|
|
|
+
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+// RGB565 colour helpers
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+static inline uint16_t rgb565(uint8_t r, uint8_t g, uint8_t b) {
|
|
|
+ return ((uint16_t)(r & 0xF8) << 8) |
|
|
|
+ ((uint16_t)(g & 0xFC) << 3) |
|
|
|
+ (b >> 3);
|
|
|
+}
|
|
|
+
|
|
|
+static inline uint16_t logoGreenAt(float t) {
|
|
|
+ return rgb565(0, (uint8_t)(191.0f * t), (uint8_t)(99.0f * t));
|
|
|
+}
|
|
|
+
|
|
|
+static inline uint16_t logoBlueAt(float t) {
|
|
|
+ return rgb565((uint8_t)(17.0f * t), (uint8_t)(67.0f * t), (uint8_t)(120.0f * t));
|
|
|
+}
|
|
|
+
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+// Scanline polygon fill — operates in screen coordinates
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+static void fillPolygon(TFT_eSPI &tft, int pts[][2], int n, uint16_t colour) {
|
|
|
+ int yMin = pts[0][1], yMax = pts[0][1];
|
|
|
+ for (int i = 1; i < n; i++) {
|
|
|
+ if (pts[i][1] < yMin) yMin = 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
|
|
|
+
|
|
|
+ for (int y = yMin; y <= yMax; y++) {
|
|
|
+ int nodes = 0;
|
|
|
+ int j = n - 1;
|
|
|
+ for (int i = 0; i < n; i++) {
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ j = i;
|
|
|
+ }
|
|
|
+ // Insertion sort
|
|
|
+ for (int a = 1; a < nodes; a++) {
|
|
|
+ int key = nodeX[a], b = a - 1;
|
|
|
+ while (b >= 0 && nodeX[b] > key) { nodeX[b + 1] = nodeX[b--]; }
|
|
|
+ nodeX[b + 1] = key;
|
|
|
+ }
|
|
|
+ for (int a = 0; a + 1 < nodes; a += 2) {
|
|
|
+ tft.drawFastHLine(nodeX[a], y, nodeX[a + 1] - nodeX[a] + 1, colour);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// Scale design-space polygon into screen-space once
|
|
|
+static void buildScaledLogo(int greenOut[][2], int blueOut[][2]) {
|
|
|
+ for (int i = 0; i < LOGO_N; i++) {
|
|
|
+ greenOut[i][0] = lsx(kGreenPts[i][0]);
|
|
|
+ greenOut[i][1] = lsy(kGreenPts[i][1]);
|
|
|
+ blueOut[i][0] = lsx(kBluePts[i][0]);
|
|
|
+ blueOut[i][1] = lsy(kBluePts[i][1]);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
+// Animated logo — total duration ~10 s
|
|
|
+// 0.0 – 1.0 s green shape fades in
|
|
|
+// 1.0 – 2.0 s blue shape fades in, green holds solid
|
|
|
+// 2.0 – 10.0 s logo remains on screen
|
|
|
+// ---------------------------------------------------------------------------
|
|
|
inline void drawLogo(TFT_eSPI &tft) {
|
|
|
- // Use a full-screen sprite to eliminate flicker during render
|
|
|
- TFT_eSprite spr = TFT_eSprite(&tft);
|
|
|
- spr.createSprite(DISPLAY_W, DISPLAY_H);
|
|
|
- spr.fillSprite(COL_BG_LOGO);
|
|
|
-
|
|
|
- // Triple gold outer ring
|
|
|
- spr.drawCircle(DISPLAY_CX, DISPLAY_CY, DISPLAY_RADIUS, COL_LOGO_ACCENT);
|
|
|
- spr.drawCircle(DISPLAY_CX, DISPLAY_CY, DISPLAY_RADIUS - 2, COL_LOGO_ACCENT);
|
|
|
- spr.drawCircle(DISPLAY_CX, DISPLAY_CY, DISPLAY_RADIUS - 4, COL_LOGO_ACCENT);
|
|
|
-
|
|
|
- // Inner separator ring
|
|
|
- spr.drawCircle(DISPLAY_CX, DISPLAY_CY, 88, COL_LOGO_ACCENT);
|
|
|
-
|
|
|
- // Horizontal separator lines (clipped inside outer ring)
|
|
|
- spr.drawFastHLine(DISPLAY_CX - 82, DISPLAY_CY - 25, 164, COL_LOGO_ACCENT);
|
|
|
- spr.drawFastHLine(DISPLAY_CX - 82, DISPLAY_CY + 30, 164, COL_LOGO_ACCENT);
|
|
|
-
|
|
|
- // Primary brand text
|
|
|
- spr.setTextDatum(MC_DATUM);
|
|
|
- spr.setTextColor(COL_LOGO_ACCENT, COL_BG_LOGO);
|
|
|
- spr.drawString("MMC", DISPLAY_CX, DISPLAY_CY - 50, 6);
|
|
|
-
|
|
|
- // Sub-label text
|
|
|
- spr.setTextColor(TFT_WHITE, COL_BG_LOGO);
|
|
|
- spr.drawString("RACK", DISPLAY_CX, DISPLAY_CY + 3, 4);
|
|
|
- spr.drawString("SYSTEM", DISPLAY_CX, DISPLAY_CY + 33, 4);
|
|
|
-
|
|
|
- spr.pushSprite(0, 0);
|
|
|
- spr.deleteSprite();
|
|
|
+ static int sGreen[LOGO_N][2];
|
|
|
+ static int sBlue[LOGO_N][2];
|
|
|
+ static bool scaled = false;
|
|
|
+
|
|
|
+ if (!scaled) {
|
|
|
+ buildScaledLogo(sGreen, sBlue);
|
|
|
+ scaled = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ tft.fillScreen(TFT_BLACK);
|
|
|
+
|
|
|
+ // Phase 1: green fade-in
|
|
|
+ for (int i = 0; i <= LOGO_FADE_STEPS; i++) {
|
|
|
+ fillPolygon(tft, sGreen, LOGO_N, logoGreenAt(i / (float)LOGO_FADE_STEPS));
|
|
|
+ delay(LOGO_FADE_STEP_MS);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Phase 2: blue fade-in (green redrawn solid to prevent bleed-through)
|
|
|
+ for (int i = 0; i <= LOGO_FADE_STEPS; i++) {
|
|
|
+ fillPolygon(tft, sGreen, LOGO_N, logoGreenAt(1.0f));
|
|
|
+ fillPolygon(tft, sBlue, LOGO_N, logoBlueAt(i / (float)LOGO_FADE_STEPS));
|
|
|
+ delay(LOGO_FADE_STEP_MS);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Phase 3: static hold
|
|
|
+ delay(LOGO_STATIC_MS);
|
|
|
}
|