Merge upstream/master into x3-support

This commit is contained in:
Justin Mitchell
2026-02-13 15:56:38 -05:00
55 changed files with 1167 additions and 749 deletions
+28 -29
View File
@@ -1,11 +1,12 @@
#include "GfxRenderer.h"
#include <Logging.h>
#include <Utf8.h>
void GfxRenderer::begin() {
frameBuffer = display.getFrameBuffer();
if (!frameBuffer) {
Serial.printf("[%lu] [GFX] !! No framebuffer\n", millis());
LOG_ERR("GFX", "!! No framebuffer");
assert(false);
}
panelWidth = display.getDisplayWidth();
@@ -60,9 +61,9 @@ void GfxRenderer::drawPixel(const int x, const int y, const bool state) const {
// Note: this call should be inlined for better performance
rotateCoordinates(orientation, x, y, &phyX, &phyY, panelWidth, panelHeight);
// Bounds checking against physical panel dimensions
// Bounds checking against runtime panel dimensions
if (phyX < 0 || phyX >= panelWidth || phyY < 0 || phyY >= panelHeight) {
Serial.printf("[%lu] [GFX] !! Outside range (%d, %d) -> (%d, %d)\n", millis(), x, y, phyX, phyY);
LOG_ERR("GFX", "!! Outside range (%d, %d) -> (%d, %d)", x, y, phyX, phyY);
return;
}
@@ -79,7 +80,7 @@ void GfxRenderer::drawPixel(const int x, const int y, const bool state) const {
int GfxRenderer::getTextWidth(const int fontId, const char* text, const EpdFontFamily::Style style) const {
if (fontMap.count(fontId) == 0) {
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
LOG_ERR("GFX", "Font %d not found", fontId);
return 0;
}
@@ -105,7 +106,7 @@ void GfxRenderer::drawText(const int fontId, const int x, const int y, const cha
}
if (fontMap.count(fontId) == 0) {
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
LOG_ERR("GFX", "Font %d not found", fontId);
return;
}
const auto font = fontMap.at(fontId);
@@ -138,7 +139,7 @@ void GfxRenderer::drawLine(int x1, int y1, int x2, int y2, const bool state) con
}
} else {
// TODO: Implement
Serial.printf("[%lu] [GFX] Line drawing not supported\n", millis());
LOG_ERR("GFX", "Line drawing not supported");
}
}
@@ -424,8 +425,8 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con
bool isScaled = false;
int cropPixX = std::floor(bitmap.getWidth() * cropX / 2.0f);
int cropPixY = std::floor(bitmap.getHeight() * cropY / 2.0f);
Serial.printf("[%lu] [GFX] Cropping %dx%d by %dx%d pix, is %s\n", millis(), bitmap.getWidth(), bitmap.getHeight(),
cropPixX, cropPixY, bitmap.isTopDown() ? "top-down" : "bottom-up");
LOG_DBG("GFX", "Cropping %dx%d by %dx%d pix, is %s", bitmap.getWidth(), bitmap.getHeight(), cropPixX, cropPixY,
bitmap.isTopDown() ? "top-down" : "bottom-up");
if (maxWidth > 0 && (1.0f - cropX) * bitmap.getWidth() > maxWidth) {
scale = static_cast<float>(maxWidth) / static_cast<float>((1.0f - cropX) * bitmap.getWidth());
@@ -435,7 +436,7 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con
scale = std::min(scale, static_cast<float>(maxHeight) / static_cast<float>((1.0f - cropY) * bitmap.getHeight()));
isScaled = true;
}
Serial.printf("[%lu] [GFX] Scaling by %f - %s\n", millis(), scale, isScaled ? "scaled" : "not scaled");
LOG_DBG("GFX", "Scaling by %f - %s", scale, isScaled ? "scaled" : "not scaled");
// Calculate output row size (2 bits per pixel, packed into bytes)
// IMPORTANT: Use int, not uint8_t, to avoid overflow for images > 1020 pixels wide
@@ -444,7 +445,7 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con
auto* rowBytes = static_cast<uint8_t*>(malloc(bitmap.getRowBytes()));
if (!outputRow || !rowBytes) {
Serial.printf("[%lu] [GFX] !! Failed to allocate BMP row buffers\n", millis());
LOG_ERR("GFX", "!! Failed to allocate BMP row buffers");
free(outputRow);
free(rowBytes);
return;
@@ -463,7 +464,7 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con
}
if (bitmap.readNextRow(outputRow, rowBytes) != BmpReaderError::Ok) {
Serial.printf("[%lu] [GFX] Failed to read row %d from bitmap\n", millis(), bmpY);
LOG_ERR("GFX", "Failed to read row %d from bitmap", bmpY);
free(outputRow);
free(rowBytes);
return;
@@ -526,7 +527,7 @@ void GfxRenderer::drawBitmap1Bit(const Bitmap& bitmap, const int x, const int y,
auto* rowBytes = static_cast<uint8_t*>(malloc(bitmap.getRowBytes()));
if (!outputRow || !rowBytes) {
Serial.printf("[%lu] [GFX] !! Failed to allocate 1-bit BMP row buffers\n", millis());
LOG_ERR("GFX", "!! Failed to allocate 1-bit BMP row buffers");
free(outputRow);
free(rowBytes);
return;
@@ -535,7 +536,7 @@ void GfxRenderer::drawBitmap1Bit(const Bitmap& bitmap, const int x, const int y,
for (int bmpY = 0; bmpY < bitmap.getHeight(); bmpY++) {
// Read rows sequentially using readNextRow
if (bitmap.readNextRow(outputRow, rowBytes) != BmpReaderError::Ok) {
Serial.printf("[%lu] [GFX] Failed to read row %d from 1-bit bitmap\n", millis(), bmpY);
LOG_ERR("GFX", "Failed to read row %d from 1-bit bitmap", bmpY);
free(outputRow);
free(rowBytes);
return;
@@ -593,7 +594,7 @@ void GfxRenderer::fillPolygon(const int* xPoints, const int* yPoints, int numPoi
// Allocate node buffer for scanline algorithm
auto* nodeX = static_cast<int*>(malloc(numPoints * sizeof(int)));
if (!nodeX) {
Serial.printf("[%lu] [GFX] !! Failed to allocate polygon node buffer\n", millis());
LOG_ERR("GFX", "!! Failed to allocate polygon node buffer");
return;
}
@@ -660,7 +661,7 @@ void GfxRenderer::invertScreen() const {
void GfxRenderer::displayBuffer(const HalDisplay::RefreshMode refreshMode) const {
auto elapsed = millis() - start_ms;
Serial.printf("[%lu] [GFX] Time = %lu ms from clearScreen to displayBuffer\n", millis(), elapsed);
LOG_DBG("GFX", "Time = %lu ms from clearScreen to displayBuffer", elapsed);
display.displayBuffer(refreshMode, fadingFix);
}
@@ -714,7 +715,7 @@ int GfxRenderer::getScreenHeight() const {
int GfxRenderer::getSpaceWidth(const int fontId) const {
if (fontMap.count(fontId) == 0) {
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
LOG_ERR("GFX", "Font %d not found", fontId);
return 0;
}
@@ -723,7 +724,7 @@ int GfxRenderer::getSpaceWidth(const int fontId) const {
int GfxRenderer::getTextAdvanceX(const int fontId, const char* text) const {
if (fontMap.count(fontId) == 0) {
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
LOG_ERR("GFX", "Font %d not found", fontId);
return 0;
}
@@ -737,7 +738,7 @@ int GfxRenderer::getTextAdvanceX(const int fontId, const char* text) const {
int GfxRenderer::getFontAscenderSize(const int fontId) const {
if (fontMap.count(fontId) == 0) {
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
LOG_ERR("GFX", "Font %d not found", fontId);
return 0;
}
@@ -746,7 +747,7 @@ int GfxRenderer::getFontAscenderSize(const int fontId) const {
int GfxRenderer::getLineHeight(const int fontId) const {
if (fontMap.count(fontId) == 0) {
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
LOG_ERR("GFX", "Font %d not found", fontId);
return 0;
}
@@ -755,7 +756,7 @@ int GfxRenderer::getLineHeight(const int fontId) const {
int GfxRenderer::getTextHeight(const int fontId) const {
if (fontMap.count(fontId) == 0) {
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
LOG_ERR("GFX", "Font %d not found", fontId);
return 0;
}
return fontMap.at(fontId).getData(EpdFontFamily::REGULAR)->ascender;
@@ -769,7 +770,7 @@ void GfxRenderer::drawTextRotated90CW(const int fontId, const int x, const int y
}
if (fontMap.count(fontId) == 0) {
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
LOG_ERR("GFX", "Font %d not found", fontId);
return;
}
const auto font = fontMap.at(fontId);
@@ -877,8 +878,7 @@ bool GfxRenderer::storeBwBuffer() {
for (size_t i = 0; i < bwBufferChunks.size(); i++) {
// Check if any chunks are already allocated
if (bwBufferChunks[i]) {
Serial.printf("[%lu] [GFX] !! BW buffer chunk %zu already stored - this is likely a bug, freeing chunk\n",
millis(), i);
LOG_ERR("GFX", "!! BW buffer chunk %zu already stored - this is likely a bug, freeing chunk", i);
free(bwBufferChunks[i]);
bwBufferChunks[i] = nullptr;
}
@@ -888,7 +888,7 @@ bool GfxRenderer::storeBwBuffer() {
bwBufferChunks[i] = static_cast<uint8_t*>(malloc(chunkSize));
if (!bwBufferChunks[i]) {
Serial.printf("[%lu] [GFX] !! Failed to allocate BW buffer chunk %zu (%zu bytes)\n", millis(), i, chunkSize);
LOG_ERR("GFX", "!! Failed to allocate BW buffer chunk %zu (%zu bytes)", i, chunkSize);
// Free previously allocated chunks
freeBwBufferChunks();
return false;
@@ -897,8 +897,7 @@ bool GfxRenderer::storeBwBuffer() {
memcpy(bwBufferChunks[i], frameBuffer + offset, chunkSize);
}
Serial.printf("[%lu] [GFX] Stored BW buffer in %zu chunks (%zu bytes each)\n", millis(), bwBufferChunks.size(),
BW_BUFFER_CHUNK_SIZE);
LOG_DBG("GFX", "Stored BW buffer in %zu chunks (%zu bytes each)", bwBufferChunks.size(), BW_BUFFER_CHUNK_SIZE);
return true;
}
@@ -925,7 +924,7 @@ void GfxRenderer::restoreBwBuffer() {
for (size_t i = 0; i < bwBufferChunks.size(); i++) {
// Check if chunk is missing
if (!bwBufferChunks[i]) {
Serial.printf("[%lu] [GFX] !! BW buffer chunks not stored - this is likely a bug\n", millis());
LOG_ERR("GFX", "!! BW buffer chunks not stored - this is likely a bug");
freeBwBufferChunks();
return;
}
@@ -938,7 +937,7 @@ void GfxRenderer::restoreBwBuffer() {
display.cleanupGrayscaleBuffers(frameBuffer);
freeBwBufferChunks();
Serial.printf("[%lu] [GFX] Restored and freed BW buffer chunks\n", millis());
LOG_DBG("GFX", "Restored and freed BW buffer chunks");
}
/**
@@ -960,7 +959,7 @@ void GfxRenderer::renderChar(const EpdFontFamily& fontFamily, const uint32_t cp,
// no glyph?
if (!glyph) {
Serial.printf("[%lu] [GFX] No glyph for codepoint %d\n", millis(), cp);
LOG_ERR("GFX", "No glyph for codepoint %d", cp);
return;
}