From 47809b4024dd7cff33a4be167cc8fbc1334101f6 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 16 Feb 2026 01:42:48 +0300 Subject: [PATCH] feat: rendering pages on demand --- src/assets/assetload_funcs.cpp | 1 + src/coders/vector_fonts.cpp | 46 ++++++++++++++++----- src/coders/vector_fonts.hpp | 10 ++++- src/constants.hpp | 2 +- src/graphics/core/Font.cpp | 47 +++++++++++++++++----- src/graphics/core/Font.hpp | 29 +++++++------ src/graphics/render/TextsRenderer.cpp | 2 +- src/graphics/ui/elements/InventoryView.cpp | 6 +-- src/graphics/ui/elements/InventoryView.hpp | 2 +- 9 files changed, 106 insertions(+), 39 deletions(-) diff --git a/src/assets/assetload_funcs.cpp b/src/assets/assetload_funcs.cpp index 8a39d3934..09f244c34 100644 --- a/src/assets/assetload_funcs.cpp +++ b/src/assets/assetload_funcs.cpp @@ -208,6 +208,7 @@ assetload::postfunc assetload::font( logger.info() << "loading vector font " << util::quote(filename); return [=](auto assets) { auto font = vector_fonts::load_font(paths.find(filename).string()); + assets->store(font, filename); assets->store(font->createInstance(cfg ? cfg->size : 16), name); }; } diff --git a/src/coders/vector_fonts.cpp b/src/coders/vector_fonts.cpp index b308d5943..ad7706e6b 100644 --- a/src/coders/vector_fonts.cpp +++ b/src/coders/vector_fonts.cpp @@ -25,7 +25,8 @@ static const char* get_ft_error_message(FT_Error error) { } namespace { - class FTFontFile : public vector_fonts::FontFile { + class FTFontFile : public vector_fonts::FontFile, + public std::enable_shared_from_this { public: FTFontFile(FT_Face face, util::Buffer buffer) : face(std::move(face)), buffer(std::move(buffer)) { @@ -47,20 +48,42 @@ namespace { } std::vector> pages; - std::vector glyphs; + std::vector glyphs; int dstSize = size * 16; ImageData canvas(ImageFormat::RGBA8888, dstSize, dstSize); ImageData bitmapDst(ImageFormat::RGBA8888, size, size); - for (int pageid = 0; pageid < FONT_PAGES; pageid++) { + for (int pageid = 0; pageid < DEFAULT_PRE_RENDER_FONT_PAGES; pageid++) { renderPage(pageid, canvas, bitmapDst, glyphs); pages.push_back(Texture::from(&canvas)); } return std::make_unique( - std::move(pages), std::move(glyphs), size, size / 2 + std::move(pages), + std::move(glyphs), + size, + size / 2, + shared_from_this() ); } + + std::unique_ptr renderPage( + int pageid, std::vector& glyphs, int size + ) override { + if (FT_Error error = FT_Set_Pixel_Sizes(face, 0, size)) { + throw std::runtime_error( + "FT_Set_Pixel_Sizes error: " + + std::string(get_ft_error_message(error)) + ); + } + + int dstSize = size * 16; + ImageData canvas(ImageFormat::RGBA8888, dstSize, dstSize); + ImageData bitmapDst(ImageFormat::RGBA8888, size, size); + + renderPage(pageid, canvas, bitmapDst, glyphs); + return Texture::from(&canvas); + } private: FT_Face face; util::Buffer buffer; @@ -95,19 +118,19 @@ namespace { int pageid, ImageData& canvas, ImageData& bitmapDst, - std::vector& glyphs + std::vector& glyphs ) { int size = canvas.getWidth() / 16; for (int c = 0; c < 256; c++) { int codepoint = pageid << 8 | c; if (!renderGlyph(codepoint, bitmapDst)) { - glyphs.push_back(Font::Glyph {0, size / 2}); + glyphs.push_back(Glyph {0, size / 2}); continue; } canvas.blit(bitmapDst, (c % 16) * size, (c / 16) * size); - Font::Glyph glyph { + Glyph glyph { face->glyph->bitmap_top - size, static_cast(face->glyph->advance.x >> 6) }; @@ -133,11 +156,14 @@ void vector_fonts::initialize() { void vector_fonts::finalize() { if (FT_Error error = FT_Done_FreeType(library)) { - logger.error() << "error on FT_Done_FreeType: " << get_ft_error_message(error); + logger.error() << "error on FT_Done_FreeType: " + << get_ft_error_message(error); } } -std::unique_ptr vector_fonts::load_font(const std::string& filename) { +std::shared_ptr vector_fonts::load_font( + const std::string& filename +) { auto bytes = io::read_bytes_buffer(io::path(filename)); FT_Face face; @@ -150,5 +176,5 @@ std::unique_ptr vector_fonts::load_font(const std::strin ); } - return std::make_unique(std::move(face), std::move(bytes)); + return std::make_shared(std::move(face), std::move(bytes)); } diff --git a/src/coders/vector_fonts.hpp b/src/coders/vector_fonts.hpp index de73323c6..a28f3c5bf 100644 --- a/src/coders/vector_fonts.hpp +++ b/src/coders/vector_fonts.hpp @@ -2,8 +2,12 @@ #include #include +#include class Font; +struct Glyph; + +class Texture; namespace vector_fonts { class FontFile { @@ -11,10 +15,14 @@ namespace vector_fonts { virtual ~FontFile() {} virtual std::unique_ptr createInstance(int size) = 0; + + virtual std::unique_ptr renderPage( + int pageid, std::vector& glyphs, int size + ) = 0; }; void initialize(); void finalize(); - std::unique_ptr load_font(const std::string& filename); + std::shared_ptr load_font(const std::string& filename); } diff --git a/src/constants.hpp b/src/constants.hpp index d57f73669..501c5f62e 100644 --- a/src/constants.hpp +++ b/src/constants.hpp @@ -65,7 +65,7 @@ inline constexpr int ATLAS_EXTRUSION = 2; inline constexpr int DEFAULT_FONT_SIZE = 16; -inline constexpr int FONT_PAGES = 5; +inline constexpr int DEFAULT_PRE_RENDER_FONT_PAGES = 1; // must be at least 1 inline const std::string SHADERS_FOLDER = "shaders"; inline const std::string TEXTURES_FOLDER = "textures"; diff --git a/src/graphics/core/Font.cpp b/src/graphics/core/Font.cpp index 2b37d0db7..3f0b4b69b 100644 --- a/src/graphics/core/Font.cpp +++ b/src/graphics/core/Font.cpp @@ -1,11 +1,13 @@ #include "Font.hpp" +#include "Batch2D.hpp" +#include "Batch3D.hpp" +#include "coders/vector_fonts.hpp" +#include "Texture.hpp" +#include "window/Camera.hpp" + #include #include -#include "Texture.hpp" -#include "Batch2D.hpp" -#include "Batch3D.hpp" -#include "window/Camera.hpp" inline constexpr uint GLYPH_SIZE = 16; inline constexpr uint MAX_CODEPAGES = 10000; // idk ho many codepages unicode has @@ -15,13 +17,15 @@ Font::Font( std::vector> pages, std::vector glyphs, int lineHeight, - int yoffset + int yoffset, + std::optional> fontFile ) : lineHeight(lineHeight), yoffset(yoffset), glyphInterval(lineHeight / 2), pages(std::move(pages)), - glyphs(std::move(glyphs)) { + glyphs(std::move(glyphs)), + fontFile(std::move(fontFile)) { } Font::~Font() = default; @@ -139,7 +143,7 @@ static inline void draw_glyph( template static inline void draw_text( - const Font& font, + Font& font, Batch& batch, std::wstring_view text, const glm::vec3& pos, @@ -244,7 +248,7 @@ void Font::draw( const FontStylesScheme* styles, size_t styleMapOffset, float scale -) const { +) { draw_text( *this, batch, text, glm::vec3(x, y, 0), @@ -264,7 +268,7 @@ void Font::draw( const glm::vec3& pos, const glm::vec3& right, const glm::vec3& up -) const { +) { draw_text( *this, batch, text, pos, right * static_cast(glyphInterval), @@ -296,3 +300,28 @@ std::unique_ptr Font::createBitmapFont( } return std::make_unique(std::move(textures), std::move(glyphs), res, 4); } + +const Glyph* Font::getGlyph(int codepoint) { + if (codepoint < 0) { + return nullptr; + } + if (codepoint < glyphs.size()) { + return &glyphs.at(codepoint); + } + if (!this->fontFile.has_value() || this->fontFile->expired()) { + return nullptr; + } + int codepage = codepoint >> 8; + if (codepage >= 1024) { + return nullptr; + } + if (glyphs.size() < (codepage << 8)) { + glyphs.resize(codepage << 8); + } + auto fontFile = this->fontFile->lock(); + if (pages.size() <= codepage) { + pages.resize(codepage); + } + pages.push_back(fontFile->renderPage(codepage, glyphs, lineHeight)); + return &glyphs.at(codepoint); +} diff --git a/src/graphics/core/Font.hpp b/src/graphics/core/Font.hpp index 244e2e8a3..e23c45ba8 100644 --- a/src/graphics/core/Font.hpp +++ b/src/graphics/core/Font.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "typedefs.hpp" @@ -18,18 +19,23 @@ class ImageData; class Font; +namespace vector_fonts { + class FontFile; +} + +struct Glyph { + int yOffset; + int xAdvance; +}; + class Font { public: - struct Glyph { - int yOffset; - int xAdvance; - }; - Font( std::vector> pages, std::vector glyphs, int lineHeight, - int yoffset + int yoffset, + std::optional> fontFile = std::nullopt ); ~Font(); @@ -61,7 +67,7 @@ public: const FontStylesScheme* styles, size_t styleMapOffset, float scale = 1 - ) const; + ); void draw( Batch3D& batch, @@ -71,7 +77,7 @@ public: const glm::vec3& pos, const glm::vec3& right={1, 0, 0}, const glm::vec3& up={0, 1, 0} - ) const; + ); const Texture* getPage(int page) const; @@ -79,11 +85,7 @@ public: return {std::nullopt, lineHeight, yoffset, glyphInterval}; } - const Glyph* getGlyph(int codepoint) const { - return (codepoint < 0 || codepoint >= glyphs.size()) - ? nullptr - : &glyphs.at(codepoint); - } + const Glyph* getGlyph(int codepoint); static std::unique_ptr createBitmapFont( std::vector> pages @@ -94,4 +96,5 @@ private: int glyphInterval; std::vector> pages; std::vector glyphs; + std::optional> fontFile; }; diff --git a/src/graphics/render/TextsRenderer.cpp b/src/graphics/render/TextsRenderer.cpp index 4b905e138..0f9d32285 100644 --- a/src/graphics/render/TextsRenderer.cpp +++ b/src/graphics/render/TextsRenderer.cpp @@ -45,7 +45,7 @@ void TextsRenderer::renderNote( } opacity = preset.xrayOpacity; } - const auto& font = assets.require(FONT_DEFAULT); + auto& font = assets.require(FONT_DEFAULT); glm::vec3 xvec = note.getAxisX(); glm::vec3 yvec = note.getAxisY(); diff --git a/src/graphics/ui/elements/InventoryView.cpp b/src/graphics/ui/elements/InventoryView.cpp index 816f53474..49c8bd3b9 100644 --- a/src/graphics/ui/elements/InventoryView.cpp +++ b/src/graphics/ui/elements/InventoryView.cpp @@ -276,13 +276,13 @@ void SlotView::draw(const DrawContext& pctx, const Assets& assets) { drawItemIcon(batch, stack, item, assets, tint, pos); if (stack.getCount() > 1 || stack.getFields() != nullptr) { - const auto& font = assets.require(FONT_DEFAULT); + auto& font = assets.require(FONT_DEFAULT); drawItemInfo(batch, stack, item, font, pos); } } static void draw_shaded_text( - Batch2D& batch, const Font& font, const std::wstring& text, int x, int y + Batch2D& batch, Font& font, const std::wstring& text, int x, int y ) { batch.setColor({0, 0, 0, 1.0f}); font.draw(batch, text, x + 1, y + 1, nullptr, 0); @@ -294,7 +294,7 @@ void SlotView::drawItemInfo( Batch2D& batch, const ItemStack& stack, const ItemDef& item, - const Font& font, + Font& font, const glm::vec2& pos ) { const int SLOT_SIZE = InventoryView::SLOT_SIZE; diff --git a/src/graphics/ui/elements/InventoryView.hpp b/src/graphics/ui/elements/InventoryView.hpp index 9275a2daa..b77e7d684 100644 --- a/src/graphics/ui/elements/InventoryView.hpp +++ b/src/graphics/ui/elements/InventoryView.hpp @@ -81,7 +81,7 @@ namespace gui { Batch2D& batch, const ItemStack& stack, const ItemDef& item, - const Font& font, + Font& font, const glm::vec2& pos );