125 lines
4.2 KiB
C++
125 lines
4.2 KiB
C++
#include "Display_PNG.h"
|
|
|
|
static PNG png;
|
|
static File Image_file;
|
|
static int16_t xpos = 0;
|
|
static int16_t ypos = 0;
|
|
|
|
// ── PNG callbacks ─────────────────────────────────────────────────────────────
|
|
static void* pngOpen(const char* filePath, int32_t* size) {
|
|
Image_file = FFat.open(filePath);
|
|
if (!Image_file) { printf("PNG: failed to open %s\r\n", filePath); return nullptr; }
|
|
*size = Image_file.size();
|
|
return &Image_file;
|
|
}
|
|
|
|
static void pngClose(void* handle) {
|
|
File* fp = (File*)handle;
|
|
if (fp && *fp) fp->close();
|
|
}
|
|
|
|
static int32_t pngRead(PNGFILE* page, uint8_t* buffer, int32_t length) {
|
|
if (!Image_file) return 0;
|
|
return Image_file.read(buffer, length);
|
|
}
|
|
|
|
static int32_t pngSeek(PNGFILE* page, int32_t position) {
|
|
if (!Image_file) return 0;
|
|
return Image_file.seek(position);
|
|
}
|
|
|
|
static uint16_t lineBuffer[MAX_IMAGE_WIDTH];
|
|
static void pngDraw(PNGDRAW* pDraw) {
|
|
png.getLineAsRGB565(pDraw, lineBuffer, PNG_RGB565_BIG_ENDIAN, 0xffffffff);
|
|
uint32_t w = pDraw->iWidth;
|
|
for (size_t i = 0; i < w; i++) lineBuffer[i] = __builtin_bswap16(lineBuffer[i]);
|
|
LCD_addWindow(xpos, pDraw->y, xpos + w - 1, ypos + pDraw->y, lineBuffer);
|
|
}
|
|
|
|
// ── Screen fill ───────────────────────────────────────────────────────────────
|
|
static void clearScreen() {
|
|
static uint16_t blackLine[MAX_IMAGE_WIDTH];
|
|
memset(blackLine, 0, sizeof(blackLine));
|
|
for (int y = 0; y < LCD_HEIGHT; y++)
|
|
LCD_addWindow(0, y, LCD_WIDTH - 1, y, blackLine);
|
|
}
|
|
|
|
// ── Public API ────────────────────────────────────────────────────────────────
|
|
void Display_Image_From_SD(const char* fullPath) {
|
|
printf("PNG: loading %s\r\n", fullPath);
|
|
int16_t rc = png.open(fullPath, pngOpen, pngClose, pngRead, pngSeek, pngDraw);
|
|
if (rc != PNG_SUCCESS) {
|
|
printf("PNG: open failed, rc=%d\r\n", rc);
|
|
return;
|
|
}
|
|
if (png.getWidth() > MAX_IMAGE_WIDTH) {
|
|
printf("PNG: image too wide (%d px)\r\n", png.getWidth());
|
|
png.close();
|
|
return;
|
|
}
|
|
clearScreen();
|
|
png.decode(NULL, 0);
|
|
png.close();
|
|
}
|
|
|
|
void Display_Memory_Photo(int memoryIndex) {
|
|
if (memoryIndex < 0 || memoryIndex >= g_memoryCount) {
|
|
printf("PNG: invalid memory index %d\r\n", memoryIndex);
|
|
return;
|
|
}
|
|
char path[120];
|
|
snprintf(path, sizeof(path), "/photos/%s", g_memories[memoryIndex].photo);
|
|
Display_Image_From_SD(path);
|
|
}
|
|
|
|
void Draw_Candle_Body() {
|
|
clearScreen();
|
|
|
|
// Draw candle body (ivory column): x from 76 to 96 (width 21), y from 175 to 250 (height 75)
|
|
uint16_t body[21 * 75];
|
|
for (int i = 0; i < 21 * 75; i++) body[i] = 0xF7BE; // Warm Ivory / light cream
|
|
LCD_addWindow(76, 175, 96, 249, body);
|
|
|
|
// Draw candle wick: x = 86, y from 168 to 175
|
|
uint16_t wick[1 * 8];
|
|
for (int i = 0; i < 8; i++) wick[i] = 0x2104; // Dark gray
|
|
LCD_addWindow(86, 168, 86, 175, wick);
|
|
}
|
|
|
|
void Draw_Candle_Flicker() {
|
|
static uint32_t lastFlickerTime = 0;
|
|
static uint8_t flickerState = 0;
|
|
uint32_t now = millis();
|
|
if (now - lastFlickerTime < 180) return; // flicker every 180ms
|
|
lastFlickerTime = now;
|
|
flickerState = (flickerState + 1) % 4;
|
|
|
|
// Bounding box: width 31, height 43
|
|
static uint16_t canvas[31 * 43];
|
|
memset(canvas, 0, sizeof(canvas)); // fill black
|
|
|
|
int hOffset = (flickerState % 2 == 0) ? 0 : ((flickerState == 1) ? 1 : -1);
|
|
int vHeight = 22 + (flickerState % 3); // flame height varies
|
|
|
|
for (int y = 0; y < 43; y++) {
|
|
for (int x = 0; x < 31; x++) {
|
|
int dx = abs(x - 15 - hOffset);
|
|
int dy = 35 - y;
|
|
|
|
if (dy >= 0 && dy < vHeight) {
|
|
int maxWidth = (dy < 8) ? (dy * 1.2) : (vHeight - dy) * 0.4;
|
|
if (maxWidth < 1) maxWidth = 1;
|
|
if (dx <= maxWidth) {
|
|
if (dx <= maxWidth / 2 && dy < vHeight - 4) {
|
|
canvas[y * 31 + x] = 0xFFE0; // Yellow
|
|
} else {
|
|
canvas[y * 31 + x] = 0xFD20; // Orange
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LCD_addWindow(71, 125, 101, 167, canvas);
|
|
}
|