feat: Overhaul font format into CrossPoint font
This commit is contained in:
@@ -2,7 +2,34 @@
|
||||
|
||||
#include <Utf8.h>
|
||||
|
||||
void GfxRenderer::insertFont(const int fontId, EpdFontFamily font) { fontMap.insert({fontId, font}); }
|
||||
#include "Group5/g5dec.inl"
|
||||
|
||||
// TODO: Build this into the format
|
||||
#define FONT_SCALE 2
|
||||
|
||||
namespace {
|
||||
// Number of set bits from 0->15
|
||||
uint8_t bitCount[] = {
|
||||
0, // 0b0000,
|
||||
1, // 0b0001,
|
||||
1, // 0b0010,
|
||||
2, // 0b0011,
|
||||
1, // 0b0100,
|
||||
2, // 0b0101,
|
||||
2, // 0b0110,
|
||||
3, // 0b0111,
|
||||
1, // 0b1000,
|
||||
2, // 0b1001,
|
||||
2, // 0b1010,
|
||||
3, // 0b1011,
|
||||
2, // 0b1100,
|
||||
3, // 0b1101,
|
||||
3, // 0b1110,
|
||||
4, // 0b1111,
|
||||
};
|
||||
} // namespace
|
||||
|
||||
void GfxRenderer::insertFont(const int fontId, CrossPointFont font) { fontMap.insert({fontId, font}); }
|
||||
|
||||
void GfxRenderer::rotateCoordinates(const int x, const int y, int* rotatedX, int* rotatedY) const {
|
||||
switch (orientation) {
|
||||
@@ -65,28 +92,25 @@ 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 {
|
||||
int GfxRenderer::getTextWidth(const int fontId, const char* text, const CrossPointFont::Style style) const {
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int w = 0, h = 0;
|
||||
fontMap.at(fontId).getTextDimensions(text, &w, &h, style);
|
||||
fontMap.at(fontId).getTextDimensions(text, style, &w, &h);
|
||||
return w;
|
||||
}
|
||||
|
||||
void GfxRenderer::drawCenteredText(const int fontId, const int y, const char* text, const bool black,
|
||||
const EpdFontFamily::Style style) const {
|
||||
const CrossPointFont::Style style) {
|
||||
const int x = (getScreenWidth() - getTextWidth(fontId, text, style)) / 2;
|
||||
drawText(fontId, x, y, text, black, style);
|
||||
}
|
||||
|
||||
void GfxRenderer::drawText(const int fontId, const int x, const int y, const char* text, const bool black,
|
||||
const EpdFontFamily::Style style) const {
|
||||
const int yPos = y + getFontAscenderSize(fontId);
|
||||
int xpos = x;
|
||||
|
||||
const CrossPointFont::Style style) {
|
||||
// cannot draw a NULL / empty string
|
||||
if (text == nullptr || *text == '\0') {
|
||||
return;
|
||||
@@ -96,16 +120,15 @@ void GfxRenderer::drawText(const int fontId, const int x, const int y, const cha
|
||||
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
|
||||
return;
|
||||
}
|
||||
const auto font = fontMap.at(fontId);
|
||||
const auto cpFont = fontMap.at(fontId);
|
||||
|
||||
// no printable characters
|
||||
if (!font.hasPrintableChars(text, style)) {
|
||||
return;
|
||||
}
|
||||
// TODO: REPLACE FONT_SCALE
|
||||
int xpos = x;
|
||||
const int yPos = y + cpFont.data.header.ascender / FONT_SCALE;
|
||||
|
||||
uint32_t cp;
|
||||
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&text)))) {
|
||||
renderChar(font, cp, &xpos, &yPos, black, style);
|
||||
renderChar(cpFont, cp, &xpos, yPos, black, style);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,7 +437,7 @@ void GfxRenderer::invertScreen() const {
|
||||
void GfxRenderer::displayBuffer(const HalDisplay::RefreshMode refreshMode) const { display.displayBuffer(refreshMode); }
|
||||
|
||||
std::string GfxRenderer::truncatedText(const int fontId, const char* text, const int maxWidth,
|
||||
const EpdFontFamily::Style style) const {
|
||||
const CrossPointFont::Style style) const {
|
||||
std::string item = text;
|
||||
int itemWidth = getTextWidth(fontId, item.c_str(), style);
|
||||
while (itemWidth > maxWidth && item.length() > 8) {
|
||||
@@ -459,7 +482,7 @@ int GfxRenderer::getSpaceWidth(const int fontId) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fontMap.at(fontId).getGlyph(' ', EpdFontFamily::REGULAR)->advanceX;
|
||||
return fontMap.at(fontId).getGlyph(' ', CrossPointFont::Style::REGULAR)->xAdvance / FONT_SCALE;
|
||||
}
|
||||
|
||||
int GfxRenderer::getFontAscenderSize(const int fontId) const {
|
||||
@@ -468,7 +491,7 @@ int GfxRenderer::getFontAscenderSize(const int fontId) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fontMap.at(fontId).getData(EpdFontFamily::REGULAR)->ascender;
|
||||
return fontMap.at(fontId).data.header.ascender / FONT_SCALE;
|
||||
}
|
||||
|
||||
int GfxRenderer::getLineHeight(const int fontId) const {
|
||||
@@ -477,7 +500,7 @@ int GfxRenderer::getLineHeight(const int fontId) const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return fontMap.at(fontId).getData(EpdFontFamily::REGULAR)->advanceY;
|
||||
return fontMap.at(fontId).data.header.height / FONT_SCALE;
|
||||
}
|
||||
|
||||
void GfxRenderer::drawButtonHints(const int fontId, const char* btn1, const char* btn2, const char* btn3,
|
||||
@@ -508,7 +531,7 @@ void GfxRenderer::drawButtonHints(const int fontId, const char* btn1, const char
|
||||
setOrientation(orig_orientation);
|
||||
}
|
||||
|
||||
void GfxRenderer::drawSideButtonHints(const int fontId, const char* topBtn, const char* bottomBtn) const {
|
||||
void GfxRenderer::drawSideButtonHints(const int fontId, const char* topBtn, const char* bottomBtn) {
|
||||
const int screenWidth = getScreenWidth();
|
||||
constexpr int buttonWidth = 40; // Width on screen (height when rotated)
|
||||
constexpr int buttonHeight = 80; // Height on screen (width when rotated)
|
||||
@@ -564,99 +587,19 @@ int GfxRenderer::getTextHeight(const int fontId) const {
|
||||
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
|
||||
return 0;
|
||||
}
|
||||
return fontMap.at(fontId).getData(EpdFontFamily::REGULAR)->ascender;
|
||||
return fontMap.at(fontId).data.header.ascender / FONT_SCALE;
|
||||
}
|
||||
|
||||
void GfxRenderer::drawTextRotated90CW(const int fontId, const int x, const int y, const char* text, const bool black,
|
||||
const EpdFontFamily::Style style) const {
|
||||
// Cannot draw a NULL / empty string
|
||||
if (text == nullptr || *text == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (fontMap.count(fontId) == 0) {
|
||||
Serial.printf("[%lu] [GFX] Font %d not found\n", millis(), fontId);
|
||||
return;
|
||||
}
|
||||
const auto font = fontMap.at(fontId);
|
||||
|
||||
// No printable characters
|
||||
if (!font.hasPrintableChars(text, style)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For 90° clockwise rotation:
|
||||
// Original (glyphX, glyphY) -> Rotated (glyphY, -glyphX)
|
||||
// Text reads from bottom to top
|
||||
|
||||
int yPos = y; // Current Y position (decreases as we draw characters)
|
||||
|
||||
uint32_t cp;
|
||||
while ((cp = utf8NextCodepoint(reinterpret_cast<const uint8_t**>(&text)))) {
|
||||
const EpdGlyph* glyph = font.getGlyph(cp, style);
|
||||
if (!glyph) {
|
||||
glyph = font.getGlyph(REPLACEMENT_GLYPH, style);
|
||||
}
|
||||
if (!glyph) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int is2Bit = font.getData(style)->is2Bit;
|
||||
const uint32_t offset = glyph->dataOffset;
|
||||
const uint8_t width = glyph->width;
|
||||
const uint8_t height = glyph->height;
|
||||
const int left = glyph->left;
|
||||
const int top = glyph->top;
|
||||
|
||||
const uint8_t* bitmap = &font.getData(style)->bitmap[offset];
|
||||
|
||||
if (bitmap != nullptr) {
|
||||
for (int glyphY = 0; glyphY < height; glyphY++) {
|
||||
for (int glyphX = 0; glyphX < width; glyphX++) {
|
||||
const int pixelPosition = glyphY * width + glyphX;
|
||||
|
||||
// 90° clockwise rotation transformation:
|
||||
// screenX = x + (ascender - top + glyphY)
|
||||
// screenY = yPos - (left + glyphX)
|
||||
const int screenX = x + (font.getData(style)->ascender - top + glyphY);
|
||||
const int screenY = yPos - left - glyphX;
|
||||
|
||||
if (is2Bit) {
|
||||
const uint8_t byte = bitmap[pixelPosition / 4];
|
||||
const uint8_t bit_index = (3 - pixelPosition % 4) * 2;
|
||||
const uint8_t bmpVal = 3 - (byte >> bit_index) & 0x3;
|
||||
|
||||
if (renderMode == BW && bmpVal < 3) {
|
||||
drawPixel(screenX, screenY, black);
|
||||
} else if (renderMode == GRAYSCALE_MSB && (bmpVal == 1 || bmpVal == 2)) {
|
||||
drawPixel(screenX, screenY, false);
|
||||
} else if (renderMode == GRAYSCALE_LSB && bmpVal == 1) {
|
||||
drawPixel(screenX, screenY, false);
|
||||
}
|
||||
} else {
|
||||
const uint8_t byte = bitmap[pixelPosition / 8];
|
||||
const uint8_t bit_index = 7 - (pixelPosition % 8);
|
||||
|
||||
if ((byte >> bit_index) & 1) {
|
||||
drawPixel(screenX, screenY, black);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Move to next character position (going up, so decrease Y)
|
||||
yPos -= glyph->advanceX;
|
||||
}
|
||||
const CrossPointFont::Style style) {
|
||||
// Stubbed
|
||||
// TODO: Set orientation, draw text, set orientation back
|
||||
}
|
||||
|
||||
uint8_t* GfxRenderer::getFrameBuffer() const { return display.getFrameBuffer(); }
|
||||
|
||||
size_t GfxRenderer::getBufferSize() { return HalDisplay::BUFFER_SIZE; }
|
||||
|
||||
// unused
|
||||
// void GfxRenderer::grayscaleRevert() const { display.grayscaleRevert(); }
|
||||
|
||||
void GfxRenderer::copyGrayscaleLsbBuffers() const { display.copyGrayscaleLsbBuffers(display.getFrameBuffer()); }
|
||||
|
||||
void GfxRenderer::copyGrayscaleMsbBuffers() const { display.copyGrayscaleMsbBuffers(display.getFrameBuffer()); }
|
||||
@@ -764,75 +707,107 @@ void GfxRenderer::restoreBwBuffer() {
|
||||
* Use this when BW buffer was re-rendered instead of stored/restored.
|
||||
*/
|
||||
void GfxRenderer::cleanupGrayscaleWithFrameBuffer() const {
|
||||
uint8_t* frameBuffer = display.getFrameBuffer();
|
||||
const uint8_t* frameBuffer = display.getFrameBuffer();
|
||||
if (frameBuffer) {
|
||||
display.cleanupGrayscaleBuffers(frameBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void GfxRenderer::renderChar(const EpdFontFamily& fontFamily, const uint32_t cp, int* x, const int* y,
|
||||
const bool pixelState, const EpdFontFamily::Style style) const {
|
||||
const EpdGlyph* glyph = fontFamily.getGlyph(cp, style);
|
||||
if (!glyph) {
|
||||
glyph = fontFamily.getGlyph(REPLACEMENT_GLYPH, style);
|
||||
void GfxRenderer::renderChar(const CrossPointFont& cpFont, const uint32_t cp, int* x, const int y,
|
||||
const bool pixelState, const CrossPointFont::Style style) {
|
||||
int rc, end_y, dx, dy, ty, tw;
|
||||
uint8_t* s;
|
||||
|
||||
const CrossPointFontGlyph* pGlyph = cpFont.getGlyph(cp, style);
|
||||
|
||||
if (!pGlyph) {
|
||||
pGlyph = cpFont.getGlyph(REPLACEMENT_GLYPH, style);
|
||||
}
|
||||
|
||||
// no glyph?
|
||||
if (!glyph) {
|
||||
Serial.printf("[%lu] [GFX] No glyph for codepoint %d\n", millis(), cp);
|
||||
int w = pGlyph->width;
|
||||
int h = pGlyph->height;
|
||||
uint32_t bitmapOffet = pGlyph->bitmapOffset;
|
||||
uint32_t xAdvance = pGlyph->xAdvance / FONT_SCALE;
|
||||
int16_t xOffset = pGlyph->xOffset / FONT_SCALE;
|
||||
int16_t yOffset = pGlyph->yOffset / FONT_SCALE;
|
||||
|
||||
// skip if drawing a space
|
||||
if (w <= 1) {
|
||||
*x += xAdvance;
|
||||
return;
|
||||
}
|
||||
|
||||
const int is2Bit = fontFamily.getData(style)->is2Bit;
|
||||
const uint32_t offset = glyph->dataOffset;
|
||||
const uint8_t width = glyph->width;
|
||||
const uint8_t height = glyph->height;
|
||||
const int left = glyph->left;
|
||||
s = cpFont.data.bitmap + bitmapOffet;
|
||||
|
||||
const uint8_t* bitmap = nullptr;
|
||||
bitmap = &fontFamily.getData(style)->bitmap[offset];
|
||||
dx = *x + xOffset;
|
||||
dy = y - yOffset;
|
||||
end_y = dy + h / FONT_SCALE;
|
||||
ty = pGlyph[1].bitmapOffset - bitmapOffet;
|
||||
|
||||
if (bitmap != nullptr) {
|
||||
for (int glyphY = 0; glyphY < height; glyphY++) {
|
||||
const int screenY = *y - glyph->top + glyphY;
|
||||
for (int glyphX = 0; glyphX < width; glyphX++) {
|
||||
const int pixelPosition = glyphY * width + glyphX;
|
||||
const int screenX = *x + left + glyphX;
|
||||
if (ty < 0 || ty > 4096) {
|
||||
Serial.printf("[%lu] [GFX] Invalid glyph compressed size: %d\n", millis(), ty);
|
||||
return;
|
||||
}
|
||||
rc = g5_decode_init(&g5dec, w, h, s, ty);
|
||||
if (rc != G5_SUCCESS) {
|
||||
return; // corrupt data?
|
||||
}
|
||||
tw = w / FONT_SCALE;
|
||||
|
||||
if (is2Bit) {
|
||||
const uint8_t byte = bitmap[pixelPosition / 4];
|
||||
const uint8_t bit_index = (3 - pixelPosition % 4) * 2;
|
||||
// the direct bit from the font is 0 -> white, 1 -> light gray, 2 -> dark gray, 3 -> black
|
||||
// we swap this to better match the way images and screen think about colors:
|
||||
// 0 -> black, 1 -> dark grey, 2 -> light grey, 3 -> white
|
||||
const uint8_t bmpVal = 3 - (byte >> bit_index) & 0x3;
|
||||
static_assert(FONT_SCALE == 2, "All this code depends on FONT_SCALE being 2");
|
||||
for (ty = dy; ty < end_y; ty++) {
|
||||
g5_decode_line(&g5dec, u8Cache);
|
||||
s = u8Cache;
|
||||
uint8_t u8 = *s++;
|
||||
g5_decode_line(&g5dec, u8Cache2);
|
||||
uint8_t* s2 = u8Cache2;
|
||||
uint8_t u82 = *s2++;
|
||||
uint8_t u8Count = 8;
|
||||
if (ty >= 0) {
|
||||
uint8_t bmpVal;
|
||||
for (int tx = dx; tx < dx + tw; tx++) {
|
||||
const uint8_t blkCnt = bitCount[(u8 & 0xC0 | (u82 & 0xC0) >> 2) >> 4];
|
||||
u8 <<= FONT_SCALE;
|
||||
u82 <<= FONT_SCALE;
|
||||
u8Count -= FONT_SCALE;
|
||||
|
||||
if (renderMode == BW && bmpVal < 3) {
|
||||
// Black (also paints over the grays in BW mode)
|
||||
drawPixel(screenX, screenY, pixelState);
|
||||
} else if (renderMode == GRAYSCALE_MSB && (bmpVal == 1 || bmpVal == 2)) {
|
||||
// Light gray (also mark the MSB if it's going to be a dark gray too)
|
||||
// We have to flag pixels in reverse for the gray buffers, as 0 leave alone, 1 update
|
||||
drawPixel(screenX, screenY, false);
|
||||
} else if (renderMode == GRAYSCALE_LSB && bmpVal == 1) {
|
||||
// Dark gray
|
||||
drawPixel(screenX, screenY, false);
|
||||
}
|
||||
} else {
|
||||
const uint8_t byte = bitmap[pixelPosition / 8];
|
||||
const uint8_t bit_index = 7 - (pixelPosition % 8);
|
||||
// 0 -> black, 1 -> dark grey, 2 -> light grey, 3 -> white
|
||||
// We're mapping from 0 = white to 4 = black, from 5 states to 4 states
|
||||
if (blkCnt == 4)
|
||||
bmpVal = 0;
|
||||
else if (blkCnt == 3 || blkCnt == 2)
|
||||
bmpVal = 1;
|
||||
else if (blkCnt == 1)
|
||||
bmpVal = 2;
|
||||
else
|
||||
bmpVal = 3;
|
||||
|
||||
if ((byte >> bit_index) & 1) {
|
||||
drawPixel(screenX, screenY, pixelState);
|
||||
}
|
||||
if (renderMode == BW && bmpVal < 3) {
|
||||
// Black (also paints over the grays in BW mode)
|
||||
drawPixel(tx, ty, pixelState);
|
||||
} else if (renderMode == GRAYSCALE_MSB && (bmpVal == 1 || bmpVal == 2)) {
|
||||
// Light gray (also mark the MSB if it's going to be a dark gray too)
|
||||
// We have to flag pixels in reverse for the gray buffers, as 0 leave alone, 1 update
|
||||
drawPixel(tx, ty, false);
|
||||
} else if (renderMode == GRAYSCALE_LSB && bmpVal == 1) {
|
||||
// Dark gray
|
||||
drawPixel(tx, ty, false);
|
||||
}
|
||||
|
||||
if (u8Count == 0) {
|
||||
u8Count = 8;
|
||||
u8 = *s++;
|
||||
u82 = *s2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*x += glyph->advanceX;
|
||||
*x += xAdvance; // width of this character
|
||||
}
|
||||
|
||||
inline unsigned short readWord(const void* data) { return *static_cast<const unsigned short*>(data); }
|
||||
|
||||
void GfxRenderer::getOrientedViewableTRBL(int* outTop, int* outRight, int* outBottom, int* outLeft) const {
|
||||
switch (orientation) {
|
||||
case Portrait:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <EpdFontFamily.h>
|
||||
#include <CrossPointFont.h>
|
||||
#include <HalDisplay.h>
|
||||
|
||||
#include <map>
|
||||
@@ -20,18 +20,23 @@ class GfxRenderer {
|
||||
};
|
||||
|
||||
private:
|
||||
// TODO: Cleanup?
|
||||
G5DECIMAGE g5dec;
|
||||
static constexpr size_t BW_BUFFER_CHUNK_SIZE = 8000; // 8KB chunks to allow for non-contiguous memory
|
||||
static constexpr size_t BW_BUFFER_NUM_CHUNKS = HalDisplay::BUFFER_SIZE / BW_BUFFER_CHUNK_SIZE;
|
||||
static_assert(BW_BUFFER_CHUNK_SIZE * BW_BUFFER_NUM_CHUNKS == HalDisplay::BUFFER_SIZE,
|
||||
"BW buffer chunking does not line up with display buffer size");
|
||||
|
||||
// TODO: Cleanup?
|
||||
uint8_t u8Cache[128];
|
||||
uint8_t u8Cache2[128];
|
||||
HalDisplay& display;
|
||||
RenderMode renderMode;
|
||||
Orientation orientation;
|
||||
uint8_t* bwBufferChunks[BW_BUFFER_NUM_CHUNKS] = {nullptr};
|
||||
std::map<int, EpdFontFamily> fontMap;
|
||||
void renderChar(const EpdFontFamily& fontFamily, uint32_t cp, int* x, const int* y, bool pixelState,
|
||||
EpdFontFamily::Style style) const;
|
||||
std::map<int, CrossPointFont> fontMap;
|
||||
void renderChar(const CrossPointFont& cpFont, uint32_t cp, int* x, int y, bool pixelState,
|
||||
CrossPointFont::Style style);
|
||||
void freeBwBufferChunks();
|
||||
void rotateCoordinates(int x, int y, int* rotatedX, int* rotatedY) const;
|
||||
|
||||
@@ -45,7 +50,7 @@ class GfxRenderer {
|
||||
static constexpr int VIEWABLE_MARGIN_LEFT = 3;
|
||||
|
||||
// Setup
|
||||
void insertFont(int fontId, EpdFontFamily font);
|
||||
void insertFont(int fontId, CrossPointFont font);
|
||||
|
||||
// Orientation control (affects logical width/height and coordinate transforms)
|
||||
void setOrientation(const Orientation o) { orientation = o; }
|
||||
@@ -72,25 +77,25 @@ class GfxRenderer {
|
||||
void fillPolygon(const int* xPoints, const int* yPoints, int numPoints, bool state = true) const;
|
||||
|
||||
// Text
|
||||
int getTextWidth(int fontId, const char* text, EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
|
||||
int getTextWidth(int fontId, const char* text, CrossPointFont::Style style = CrossPointFont::Style::REGULAR) const;
|
||||
void drawCenteredText(int fontId, int y, const char* text, bool black = true,
|
||||
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
|
||||
CrossPointFont::Style style = CrossPointFont::Style::REGULAR);
|
||||
void drawText(int fontId, int x, int y, const char* text, bool black = true,
|
||||
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
|
||||
CrossPointFont::Style style = CrossPointFont::Style::REGULAR);
|
||||
int getSpaceWidth(int fontId) const;
|
||||
int getFontAscenderSize(int fontId) const;
|
||||
int getLineHeight(int fontId) const;
|
||||
std::string truncatedText(int fontId, const char* text, int maxWidth,
|
||||
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
|
||||
CrossPointFont::Style style = CrossPointFont::Style::REGULAR) const;
|
||||
|
||||
// UI Components
|
||||
void drawButtonHints(int fontId, const char* btn1, const char* btn2, const char* btn3, const char* btn4);
|
||||
void drawSideButtonHints(int fontId, const char* topBtn, const char* bottomBtn) const;
|
||||
void drawSideButtonHints(int fontId, const char* topBtn, const char* bottomBtn);
|
||||
|
||||
private:
|
||||
// Helper for drawing rotated text (90 degrees clockwise, for side buttons)
|
||||
void drawTextRotated90CW(int fontId, int x, int y, const char* text, bool black = true,
|
||||
EpdFontFamily::Style style = EpdFontFamily::REGULAR) const;
|
||||
CrossPointFont::Style style = CrossPointFont::Style::REGULAR);
|
||||
int getTextHeight(int fontId) const;
|
||||
|
||||
public:
|
||||
@@ -106,6 +111,5 @@ class GfxRenderer {
|
||||
// Low level functions
|
||||
uint8_t* getFrameBuffer() const;
|
||||
static size_t getBufferSize();
|
||||
void grayscaleRevert() const;
|
||||
void getOrientedViewableTRBL(int* outTop, int* outRight, int* outBottom, int* outLeft) const;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user