From ee82919293fb825909a16f35d18442c63e1eacbd Mon Sep 17 00:00:00 2001 From: Georg Hagen Date: Sun, 2 Mar 2025 18:35:36 +0100 Subject: [PATCH] Update to FontAtlasFactory for more eficent loading --- .../Scene/Text/BitmapFontAtlasGenerator.cpp | 18 ++-- .../Scene/Text/FontAtlasFactory.cpp | 88 ++++++++++--------- .../Scene/Text/FontAtlasFactory.hpp | 9 +- .../Scene/Text/SdfFontAtlasGenerator.cpp | 8 +- openVulkanoCpp/Scene/Text/SubpixelLayout.hpp | 2 +- 5 files changed, 69 insertions(+), 56 deletions(-) diff --git a/openVulkanoCpp/Scene/Text/BitmapFontAtlasGenerator.cpp b/openVulkanoCpp/Scene/Text/BitmapFontAtlasGenerator.cpp index ccb027a..9afc6ce 100644 --- a/openVulkanoCpp/Scene/Text/BitmapFontAtlasGenerator.cpp +++ b/openVulkanoCpp/Scene/Text/BitmapFontAtlasGenerator.cpp @@ -24,16 +24,18 @@ namespace OpenVulkano::Scene } void BitmapFontAtlasGenerator::Generate(const std::span& fontData, - const std::set& chset, + const std::set& inCs, const std::optional& pngOutput) { - if (chset.empty()) - { - Logger::APP->info("Charset is empty. Nothing to generate."); - return; - } - const auto& [lib, face] = FontAtlasGeneratorBase::InitFreetype(fontData); + + std::set fallback; + if (inCs.empty()) + { + FontAtlasGeneratorBase::LoadAllGlyphs(fallback, face); + } + const auto& charset = inCs.empty() ? fallback : inCs; + FT_Set_Pixel_Sizes(face.get(), 0, m_pixelSizeConfig.CalculatePixelSize()); if (m_subpixelLayout != SubpixelLayout::UNKNOWN) { @@ -46,7 +48,7 @@ namespace OpenVulkano::Scene } } - auto [allGlyphs, atlasWidth] = InitGlyphsForPacking(chset, face); + auto [allGlyphs, atlasWidth] = InitGlyphsForPacking(charset, face); std::vector shelves = Shelf::CreateShelves(atlasWidth, allGlyphs, face.get(), m_channelsCount); uint32_t atlasHeight = 0; std::for_each(shelves.begin(), shelves.end(), [&](const Shelf& shelf) { atlasHeight += shelf.GetHeight(); }); diff --git a/openVulkanoCpp/Scene/Text/FontAtlasFactory.cpp b/openVulkanoCpp/Scene/Text/FontAtlasFactory.cpp index 7b4ad01..cf7439a 100644 --- a/openVulkanoCpp/Scene/Text/FontAtlasFactory.cpp +++ b/openVulkanoCpp/Scene/Text/FontAtlasFactory.cpp @@ -16,57 +16,72 @@ namespace OpenVulkano::Scene { FontAtlasFactory FontAtlasFactory::INSTANCE = FontAtlasFactory(); // Global factory - FontAtlasFactory::FontIdentifier::FontIdentifier(const std::string& font_, const std::set& charset, - SubpixelLayout subpixelLayout_, float ptSize_, - FontAtlasType atlasType_) - : font(font_), subpixelLayout(subpixelLayout_), ptSize(ptSize_), atlasType(atlasType_) - { - std::for_each(charset.begin(), charset.end(), [&](uint32_t c) { charsetHash ^= c; }); - } - bool FontAtlasFactory::FontIdentifier::FontIdentifier::operator<(const FontIdentifier& other) const { - return std::tie(atlasType, charsetHash, ptSize, subpixelLayout, font) - < std::tie(other.atlasType, other.charsetHash, other.ptSize, other.subpixelLayout, other.font); + if (atlasType < other.atlasType) return true; + if (atlasType > other.atlasType) return false; + if (atlasType.IsSDF()) + { + return font < other.font; + } + return std::tie(ptSize, subpixelLayout, font) < std::tie(other.ptSize, other.subpixelLayout, other.font); } - FontAtlas::Ptr FontAtlasFactory::GetFontAtlasScalable(const std::string& fontIdentifier, bool msdf, - const std::set& charset) const + FontAtlas::Ptr FontAtlasFactory::GetFontAtlasScalable(const std::string& fontIdentifier, bool msdf, const std::set& charset) const { - const auto& fontData = FindFont(fontIdentifier); - if (fontData.Empty()) - { - Logger::DATA->warn("Could not find font {}", fontIdentifier); - return nullptr; - } - - std::set fallback; - if (charset.empty()) FontAtlasGeneratorBase::LoadAllGlyphs(fallback, fontData.AsBytes()); - const std::set& setRef = (charset.empty() ? fallback : charset); - FontIdentifier id(fontIdentifier, setRef, SubpixelLayout::UNKNOWN, 0, - msdf ? FontAtlasType::MSDF : FontAtlasType::SDF); + FontIdentifier id(fontIdentifier, msdf ? FontAtlasType::MSDF : FontAtlasType::SDF); auto it = m_atlasesCache.find(id); if (it != m_atlasesCache.end()) { return it->second; } + + Array ovFontData = ResourceLoader::GetInstance().GetResource(fontIdentifier + ".ovfont"); + if (!ovFontData.Empty()) + { + auto atlas = std::make_shared(ovFontData); + m_atlasesCache[FontIdentifier(fontIdentifier, atlas->GetAtlasType())] = atlas; + return atlas; + } + const auto& fontData = FindFont(fontIdentifier); + if (fontData.Empty()) + { + Logger::DATA->warn("Could not find font {}", fontIdentifier); + return nullptr; + } + + FontAtlas::Ptr atlas; if (msdf) { MsdfFontAtlasGenerator msdfGen; msdfGen.GenerateAtlas(fontData, charset); - return m_atlasesCache.insert({ id, msdfGen.GetAtlas() }).first->second; + atlas = msdfGen.GetAtlas(); } - SdfFontAtlasGenerator sdfGen; - sdfGen.GenerateAtlas(fontData, charset); - return m_atlasesCache.insert({ id, sdfGen.GetAtlas() }).first->second; + else + { + SdfFontAtlasGenerator sdfGen; + sdfGen.GenerateAtlas(fontData, charset); + atlas = sdfGen.GetAtlas(); + } + if (charset.empty()) m_atlasesCache.emplace(id, atlas); + return atlas; } FontAtlas::Ptr FontAtlasFactory::GetFontAtlas(const std::string& fontIdentifier, float ptSize, SubpixelLayout subpixelLayout, const std::set& charset) const { + + FontIdentifier id(fontIdentifier, subpixelLayout ? FontAtlasType::BITMAP_SUBPIXEL : FontAtlasType::BITMAP, subpixelLayout, ptSize); + + auto it = m_atlasesCache.find(id); + if (it != m_atlasesCache.end()) + { + return it->second; + } + const auto& fontData = FindFont(fontIdentifier); if (fontData.Empty()) { @@ -74,22 +89,11 @@ namespace OpenVulkano::Scene return nullptr; } - std::set fallback; - if (charset.empty()) FontAtlasGeneratorBase::LoadAllGlyphs(fallback, fontData.AsBytes()); - const std::set& setRef = (charset.empty() ? fallback : charset); - FontIdentifier id(fontIdentifier, setRef, subpixelLayout, ptSize, - subpixelLayout ? FontAtlasType::BITMAP_SUBPIXEL : FontAtlasType::BITMAP); - - auto it = m_atlasesCache.find(id); - if (it != m_atlasesCache.end()) - { - return it->second; - } - FontPixelSizeConfig cfg(ptSize); BitmapFontAtlasGenerator bitmapGen(cfg, subpixelLayout); - bitmapGen.GenerateAtlas(fontData, setRef); - return m_atlasesCache.insert({ id, bitmapGen.GetAtlas() }).first->second; + bitmapGen.GenerateAtlas(fontData, charset); + if (charset.empty()) m_atlasesCache.emplace(id, bitmapGen.GetAtlas()); + return bitmapGen.GetAtlas(); } Array FontAtlasFactory::FindFont(const std::string& fontIdentifier) const diff --git a/openVulkanoCpp/Scene/Text/FontAtlasFactory.hpp b/openVulkanoCpp/Scene/Text/FontAtlasFactory.hpp index 6ea11c2..5c1fd32 100644 --- a/openVulkanoCpp/Scene/Text/FontAtlasFactory.hpp +++ b/openVulkanoCpp/Scene/Text/FontAtlasFactory.hpp @@ -16,15 +16,16 @@ namespace OpenVulkano::Scene { struct FontIdentifier { - FontIdentifier(const std::string& font_, const std::set& charset, SubpixelLayout subpixelLayout_, - float ptSize_, FontAtlasType atlasType_); + FontIdentifier(const std::string_view& font, FontAtlasType atlasType) : font(font), atlasType(atlasType) { assert(atlasType.IsSDF()); } + FontIdentifier(const std::string_view& font, FontAtlasType atlasType, SubpixelLayout subpixelLayout, float ptSize) + : font(font), atlasType(atlasType), subpixelLayout(subpixelLayout), ptSize(ptSize) {} + bool operator<(const FontIdentifier& other) const; std::string font; - uint32_t charsetHash = 0; + FontAtlasType atlasType; SubpixelLayout subpixelLayout = SubpixelLayout::UNKNOWN; float ptSize = 0; - FontAtlasType atlasType; }; static FontAtlasFactory INSTANCE; diff --git a/openVulkanoCpp/Scene/Text/SdfFontAtlasGenerator.cpp b/openVulkanoCpp/Scene/Text/SdfFontAtlasGenerator.cpp index 4e66f3c..807dddb 100644 --- a/openVulkanoCpp/Scene/Text/SdfFontAtlasGenerator.cpp +++ b/openVulkanoCpp/Scene/Text/SdfFontAtlasGenerator.cpp @@ -36,13 +36,19 @@ namespace OpenVulkano::Scene } template - void SdfFontAtlasGeneratorGeneric::GenerateAtlas(const Array& fontData, const std::set& charset, + void SdfFontAtlasGeneratorGeneric::GenerateAtlas(const Array& fontData, const std::set& inCs, const std::optional& pngOutput) { msdfgen::FreetypeHandle* ft; msdfgen::FontHandle* font; InitFreetypeFromBuffer(ft, font, (const msdfgen::byte*)(fontData.Data()), fontData.Size()); msdf_atlas::Charset s; + std::set fallback; + if (inCs.empty()) + { + FontAtlasGeneratorBase::LoadAllGlyphs(fallback, fontData.AsBytes()); + } + const auto& charset = inCs.empty() ? fallback : inCs; std::for_each(charset.begin(), charset.end(), [&](uint32_t unicode) { s.add(unicode); }); Generate(ft, font, s, pngOutput); } diff --git a/openVulkanoCpp/Scene/Text/SubpixelLayout.hpp b/openVulkanoCpp/Scene/Text/SubpixelLayout.hpp index 394e9b5..9771508 100644 --- a/openVulkanoCpp/Scene/Text/SubpixelLayout.hpp +++ b/openVulkanoCpp/Scene/Text/SubpixelLayout.hpp @@ -16,7 +16,7 @@ namespace OpenVulkano class SubpixelLayout { public: - enum Layout : uint32_t + enum Layout : uint16_t { RGB, BGR,