mirror of
https://github.com/usatiuk/cardboy.git
synced 2025-10-28 23:27:49 +01:00
text
This commit is contained in:
@@ -102,49 +102,6 @@ void appendEmbeddedRoms(std::vector<RomEntry>& out) {
|
||||
}
|
||||
}
|
||||
|
||||
int measureVerticalText(std::string_view text, int scale = 1, int letterSpacing = 1) {
|
||||
if (text.empty())
|
||||
return 0;
|
||||
const int advance = (font16x8::kGlyphWidth + letterSpacing) * scale;
|
||||
return static_cast<int>(text.size()) * advance - letterSpacing * scale;
|
||||
}
|
||||
|
||||
void drawGlyphRotated(Framebuffer& fb, int x, int y, char ch, bool clockwise, int scale = 1, bool on = true) {
|
||||
const auto& rows = font16x8::glyphBitmap(ch);
|
||||
for (int row = 0; row < font16x8::kGlyphHeight; ++row) {
|
||||
const uint8_t rowBits = rows[row];
|
||||
for (int col = 0; col < font16x8::kGlyphWidth; ++col) {
|
||||
const uint8_t mask = static_cast<uint8_t>(1u << (font16x8::kGlyphWidth - 1 - col));
|
||||
if ((rowBits & mask) == 0)
|
||||
continue;
|
||||
for (int sx = 0; sx < scale; ++sx) {
|
||||
for (int sy = 0; sy < scale; ++sy) {
|
||||
int dstX;
|
||||
int dstY;
|
||||
if (clockwise) {
|
||||
dstX = x + row * scale + sx;
|
||||
dstY = y + (font16x8::kGlyphWidth - 1 - col) * scale + sy;
|
||||
} else {
|
||||
dstX = x + (font16x8::kGlyphHeight - 1 - row) * scale + sx;
|
||||
dstY = y + col * scale + sy;
|
||||
}
|
||||
fb.drawPixel(dstX, dstY, on);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void drawTextRotated(Framebuffer& fb, int x, int y, std::string_view text, bool clockwise, int scale = 1,
|
||||
bool on = true, int letterSpacing = 1) {
|
||||
int cursor = y;
|
||||
const int advance = (font16x8::kGlyphWidth + letterSpacing) * scale;
|
||||
for (char ch: text) {
|
||||
drawGlyphRotated(fb, x, cursor, ch, clockwise, scale, on);
|
||||
cursor += advance;
|
||||
}
|
||||
}
|
||||
|
||||
class GameboyApp final : public cardboy::sdk::IApp {
|
||||
public:
|
||||
explicit GameboyApp(AppContext& ctx) :
|
||||
@@ -1081,18 +1038,26 @@ private:
|
||||
|
||||
if (!activeRomName.empty()) {
|
||||
const std::string rotatedRomName(activeRomName.rbegin(), activeRomName.rend());
|
||||
const int textHeight = measureVerticalText(rotatedRomName, textScale);
|
||||
const auto textBounds =
|
||||
font16x8::measureTextBounds(rotatedRomName, textScale, 1,
|
||||
font16x8::Rotation::Clockwise90);
|
||||
const int textHeight = textBounds.height;
|
||||
const int maxOrigin = std::max(0, screenHeight - textHeight);
|
||||
int leftX = 8;
|
||||
int leftY = std::clamp((screenHeight - textHeight) / 2, 0, maxOrigin);
|
||||
drawTextRotated(framebuffer, leftX, leftY, rotatedRomName, true, textScale, true, 1);
|
||||
font16x8::drawText(framebuffer, leftX, leftY, rotatedRomName, textScale, true, 1,
|
||||
font16x8::Rotation::Clockwise90);
|
||||
if (!statusMessage.empty()) {
|
||||
const std::string rotatedStatusMessage(statusMessage.rbegin(), statusMessage.rend());
|
||||
const int textHeight = measureVerticalText(rotatedStatusMessage, textScale);
|
||||
const auto statusBounds =
|
||||
font16x8::measureTextBounds(rotatedStatusMessage, textScale, 1,
|
||||
font16x8::Rotation::Clockwise90);
|
||||
const int textHeight = statusBounds.height;
|
||||
const int maxOrigin = std::max(0, screenHeight - textHeight);
|
||||
leftX = leftX + 20;
|
||||
leftY = std::clamp((screenHeight - textHeight) / 2, 0, maxOrigin);
|
||||
drawTextRotated(framebuffer, leftX, leftY, rotatedStatusMessage, true, textScale, true, 1);
|
||||
font16x8::drawText(framebuffer, leftX, leftY, rotatedStatusMessage, textScale, true, 1,
|
||||
font16x8::Rotation::Clockwise90);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1110,7 +1075,10 @@ private:
|
||||
std::string rotated(text.rbegin(), text.rend());
|
||||
if (totalRightHeight > 0)
|
||||
totalRightHeight += gap;
|
||||
totalRightHeight += measureVerticalText(rotated, textScale);
|
||||
const auto bounds =
|
||||
font16x8::measureTextBounds(rotated, textScale, 1,
|
||||
font16x8::Rotation::Clockwise90);
|
||||
totalRightHeight += bounds.height;
|
||||
}
|
||||
|
||||
const int maxRightOrigin = std::max(0, screenHeight - totalRightHeight);
|
||||
@@ -1125,8 +1093,12 @@ private:
|
||||
if (text.empty())
|
||||
continue;
|
||||
std::string rotated(text.rbegin(), text.rend());
|
||||
rightY = screenHeight - measureVerticalText(rotated, textScale) - 8;
|
||||
drawTextRotated(framebuffer, rightX, rightY, rotated, true, textScale, true, 1);
|
||||
const auto bounds =
|
||||
font16x8::measureTextBounds(rotated, textScale, 1,
|
||||
font16x8::Rotation::Clockwise90);
|
||||
rightY = screenHeight - bounds.height - 8;
|
||||
font16x8::drawText(framebuffer, rightX, rightY, rotated, textScale, true, 1,
|
||||
font16x8::Rotation::Clockwise90);
|
||||
rightX -= 20;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,22 +26,69 @@ inline const std::array<uint8_t, kGlyphHeight>& glyphBitmap(char ch) {
|
||||
return fonts_Terminess_Powerline[uc];
|
||||
}
|
||||
|
||||
enum class Rotation {
|
||||
None,
|
||||
Clockwise90,
|
||||
CounterClockwise90,
|
||||
};
|
||||
|
||||
struct TextBounds {
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
};
|
||||
|
||||
template<typename Framebuffer>
|
||||
inline void drawGlyph(Framebuffer& fb, int x, int y, char ch, int scale = 1, bool on = true) {
|
||||
inline void drawGlyph(Framebuffer& fb, int x, int y, char ch, int scale = 1, bool on = true,
|
||||
Rotation rotation = Rotation::None) {
|
||||
const auto& rows = glyphBitmap(ch);
|
||||
for (int row = 0; row < kGlyphHeight; ++row) {
|
||||
const uint8_t rowBits = rows[row];
|
||||
for (int col = 0; col < kGlyphWidth; ++col) {
|
||||
const uint8_t mask = static_cast<uint8_t>(1u << (kGlyphWidth - 1 - col));
|
||||
if (rowBits & mask) {
|
||||
for (int sx = 0; sx < scale; ++sx)
|
||||
for (int sy = 0; sy < scale; ++sy)
|
||||
fb.drawPixel(x + col * scale + sx, y + row * scale + sy, on);
|
||||
if ((rowBits & mask) == 0)
|
||||
continue;
|
||||
for (int sx = 0; sx < scale; ++sx) {
|
||||
for (int sy = 0; sy < scale; ++sy) {
|
||||
int dstX = x;
|
||||
int dstY = y;
|
||||
switch (rotation) {
|
||||
case Rotation::None:
|
||||
dstX += col * scale + sx;
|
||||
dstY += row * scale + sy;
|
||||
break;
|
||||
case Rotation::Clockwise90:
|
||||
dstX += row * scale + sx;
|
||||
dstY += (kGlyphWidth - 1 - col) * scale + sy;
|
||||
break;
|
||||
case Rotation::CounterClockwise90:
|
||||
dstX += (kGlyphHeight - 1 - row) * scale + sx;
|
||||
dstY += col * scale + sy;
|
||||
break;
|
||||
}
|
||||
fb.drawPixel(dstX, dstY, on);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline TextBounds measureTextBounds(std::string_view text, int scale = 1, int letterSpacing = 1,
|
||||
Rotation rotation = Rotation::None) {
|
||||
if (text.empty())
|
||||
return {};
|
||||
const int advance = (kGlyphWidth + letterSpacing) * scale;
|
||||
const int extent = static_cast<int>(text.size()) * advance - letterSpacing * scale;
|
||||
const int height = kGlyphHeight * scale;
|
||||
switch (rotation) {
|
||||
case Rotation::None:
|
||||
return {extent, height};
|
||||
case Rotation::Clockwise90:
|
||||
case Rotation::CounterClockwise90:
|
||||
return {height, extent};
|
||||
}
|
||||
return {extent, height};
|
||||
}
|
||||
|
||||
inline int measureText(std::string_view text, int scale = 1, int letterSpacing = 1) {
|
||||
if (text.empty())
|
||||
return 0;
|
||||
@@ -51,11 +98,22 @@ inline int measureText(std::string_view text, int scale = 1, int letterSpacing =
|
||||
|
||||
template<typename Framebuffer>
|
||||
inline void drawText(Framebuffer& fb, int x, int y, std::string_view text, int scale = 1, bool on = true,
|
||||
int letterSpacing = 1) {
|
||||
int cursor = x;
|
||||
for (char ch: text) {
|
||||
drawGlyph(fb, cursor, y, ch, scale, on);
|
||||
cursor += (kGlyphWidth + letterSpacing) * scale;
|
||||
int letterSpacing = 1, Rotation rotation = Rotation::None) {
|
||||
if (text.empty())
|
||||
return;
|
||||
const int advance = (kGlyphWidth + letterSpacing) * scale;
|
||||
if (rotation == Rotation::None) {
|
||||
int cursor = x;
|
||||
for (char ch: text) {
|
||||
drawGlyph(fb, cursor, y, ch, scale, on, rotation);
|
||||
cursor += advance;
|
||||
}
|
||||
} else {
|
||||
int cursor = y;
|
||||
for (char ch: text) {
|
||||
drawGlyph(fb, x, cursor, ch, scale, on, rotation);
|
||||
cursor += advance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user