From dbb42e741d29ab213f2a51fc8d9568c02f844647 Mon Sep 17 00:00:00 2001 From: fschildt Date: Sat, 27 Sep 2025 12:40:31 +0200 Subject: add font glyph drawing --- src/common/Font.cpp | 117 ++++++++++++++++++++++++++++++++++ src/common/Font.hpp | 43 +++++++++++++ src/games/minesweeper/Minesweeper.cpp | 13 +++- src/games/minesweeper/Minesweeper.hpp | 9 +++ 4 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 src/common/Font.cpp create mode 100644 src/common/Font.hpp (limited to 'src') diff --git a/src/common/Font.cpp b/src/common/Font.cpp new file mode 100644 index 0000000..31a6720 --- /dev/null +++ b/src/common/Font.cpp @@ -0,0 +1,117 @@ +#include + +#include +#include + + +Font::~Font() +{ + Deinit(); +} + + +bool +Font::Init(const char* path, int font_size) +{ + std::ifstream file(path, std::ios::in|std::ios::binary|std::ios::ate); + if (!file.is_open()) { + return false; + } + + + std::streampos end = file.tellg(); + size_t size = static_cast(end); + char *content = new char[size + 1]; + + file.seekg(0, std::ios::beg); + file.read(content, end); + file.close(); + content[size] = '\0'; + + + // set font info + if (!stbtt_InitFont(&m_font_info, (unsigned char*)content, 0)) + { + std::cout << "stbtt_InitFont failed.\n"; + printf("stbtt_InitFont failed\n"); + delete[] content; + return false; + } + + + // font settings (scale + vmetrics) + float scale = stbtt_ScaleForPixelHeight(&m_font_info, (float)font_size); + int baseline, ascent, descent, line_gap; + stbtt_GetFontVMetrics(&m_font_info, &ascent, &descent, &line_gap); + baseline = int(scale * (float)-descent); + ascent = int(scale * (float)ascent); + descent = int(scale * (float)descent); + line_gap = int(scale * (float)line_gap); + + + m_font_scale = scale; + m_font_baseline = baseline; + m_font_yadvance = ascent - descent + line_gap; + m_file_content = content; + + + return true; +} + + +void +Font::LoadGlyph(Glyph& glyph, uint32_t codepoint) +{ + int bbx0, bby0, bbx1, bby1; + stbtt_GetCodepointBitmapBox(&m_font_info, (int)codepoint, m_font_scale, m_font_scale, &bbx0, &bby0, &bbx1, &bby1); + int width = bbx1 - bbx0; + int height = bby1 - bby0; + + + size_t size = size_t(width * height); + uint8_t* bitmap_flipped = new uint8_t[size]; + uint8_t* bitmap_correct = new uint8_t[size]; + + + stbtt_MakeCodepointBitmap(&m_font_info, bitmap_flipped, width, height, width, m_font_scale, m_font_scale, (int)codepoint); + + uint8_t* dest = bitmap_correct; + for (int y = 0; y < height; ++y) + { + uint8_t* src = bitmap_flipped + size_t((height-1-y)*width); + for (int x = 0; x < width; ++x) + { + *dest++ = *src++; + } + } + delete[] bitmap_flipped; + + glyph.bitmap.width = width; + glyph.bitmap.height = height; + glyph.bitmap.pixels = std::unique_ptr(bitmap_correct); + + + int xadvance; + int left_side_bearing; + stbtt_GetCodepointHMetrics(&m_font_info, (int)codepoint, &xadvance, &left_side_bearing); + xadvance = (int)(m_font_scale * (float)xadvance); + left_side_bearing = (int)(m_font_scale * (float)left_side_bearing); + + + glyph.xoff = static_cast(m_font_scale * (float)bbx0) + left_side_bearing; + glyph.yoff = -bby1; + glyph.xadvance = xadvance; + +} + + +void +Font::Deinit() +{ + if (m_file_content) { + delete[] m_file_content; + m_file_content = nullptr; + } +} + + diff --git a/src/common/Font.hpp b/src/common/Font.hpp new file mode 100644 index 0000000..a594add --- /dev/null +++ b/src/common/Font.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include +#include + + +struct MonoBitmap { + int32_t width; + int32_t height; + std::unique_ptr pixels; +}; + + +struct Glyph { + int32_t xoff; + int32_t yoff; + int32_t xadvance; + MonoBitmap bitmap; +}; + + +class Font { +public: + ~Font(); + + bool Init(const char* path, int font_size); + void Deinit(); + + void LoadGlyph(Glyph& glyph, uint32_t codepoint); + + +private: + const char* m_file_content = nullptr; + + float m_font_scale; + int m_font_baseline; + int m_font_yadvance; + + stbtt_fontinfo m_font_info; + Glyph m_glyphs['~' - ' ' + 1]; +}; + + diff --git a/src/games/minesweeper/Minesweeper.cpp b/src/games/minesweeper/Minesweeper.cpp index 6dc77a4..abb9515 100644 --- a/src/games/minesweeper/Minesweeper.cpp +++ b/src/games/minesweeper/Minesweeper.cpp @@ -25,8 +25,11 @@ Minesweeper::Minesweeper() m_CellOuterViewSize = {cell_size, cell_size}; m_CellInnerViewSize = {cell_size_without_border, cell_size_without_border}; + m_Font.Init("fonts/dejavu_ttf/DejaVuSansMono.ttf", 32); + for (uint32_t i = 0; i < m_DigitGlyphs.size(); ++i) { + m_Font.LoadGlyph(m_DigitGlyphs[i], i + '0'); + } - // Todo: assert various stuff Reinit(); } @@ -278,6 +281,14 @@ void Minesweeper::DrawBoard(RenderGroup &render_group) { }; + // Temporary: Drawing Glyph Test + render_group.PushBitmap( + {100.0f, 100.0f, 10.0f}, + m_DigitGlyphs[1].bitmap.width, + m_DigitGlyphs[1].bitmap.height, + m_DigitGlyphs[1].bitmap.pixels.get()); + + for (int32_t y = 0; y < m_MapHeight; y++) { for (int32_t x = 0; x < m_MapWidth; x++) { V2F32 world_pos = { diff --git a/src/games/minesweeper/Minesweeper.hpp b/src/games/minesweeper/Minesweeper.hpp index 4906464..b081806 100644 --- a/src/games/minesweeper/Minesweeper.hpp +++ b/src/games/minesweeper/Minesweeper.hpp @@ -1,6 +1,10 @@ #pragma once #include +#include + +#include + namespace std { template <> @@ -13,6 +17,7 @@ namespace std { }; } + enum class MinesweeperRunState { Resume, Pause, @@ -21,6 +26,7 @@ enum class MinesweeperRunState { Exit }; + class Minesweeper : public Game { public: Minesweeper(); @@ -76,6 +82,9 @@ class Minesweeper : public Game { uint32_t m_IsFlaggedBitmap[MAX_MAP_HEIGHT] {}; uint32_t m_IsMineBitmap[MAX_MAP_HEIGHT] {}; int32_t m_AdjacentMineCounters[MAX_MAP_WIDTH * MAX_MAP_HEIGHT] {}; + + Font m_Font; + std::array m_DigitGlyphs; }; -- cgit v1.2.3