Finish dynamic load GetImGuiFont function

This commit is contained in:
Dan Paulat 2023-10-02 23:57:19 -05:00
parent aead8e7264
commit e4ab1e8c19
4 changed files with 59 additions and 35 deletions

View file

@ -30,16 +30,15 @@ struct FontRecord
std::string filename_ {}; std::string filename_ {};
}; };
typedef std::pair<FontRecord, units::font_size::pixels<int>> FontRecordPair;
template<class Key> template<class Key>
struct FontRecordHash; struct FontRecordHash;
template<class Key>
struct FontRecordKeyEqual;
template<> template<>
struct FontRecordHash<std::pair<FontRecord, int>> struct FontRecordHash<FontRecordPair>
{ {
size_t operator()(const std::pair<FontRecord, int>& x) const; size_t operator()(const FontRecordPair& x) const;
}; };
class FontManager::Impl class FontManager::Impl
@ -65,9 +64,9 @@ public:
std::shared_mutex imguiFontAtlasMutex_ {}; std::shared_mutex imguiFontAtlasMutex_ {};
boost::unordered_flat_map<std::pair<FontRecord, int>, boost::unordered_flat_map<FontRecordPair,
std::shared_ptr<types::ImGuiFont>, std::shared_ptr<types::ImGuiFont>,
FontRecordHash<std::pair<FontRecord, int>>> FontRecordHash<FontRecordPair>>
imguiFonts_ {}; imguiFonts_ {};
std::shared_mutex imguiFontsMutex_ {}; std::shared_mutex imguiFontsMutex_ {};
@ -88,7 +87,8 @@ std::shared_mutex& FontManager::imgui_font_atlas_mutex()
std::shared_ptr<types::ImGuiFont> std::shared_ptr<types::ImGuiFont>
FontManager::GetImGuiFont(const std::string& family, FontManager::GetImGuiFont(const std::string& family,
const std::vector<std::string>& styles, const std::vector<std::string>& styles,
units::font_size::points<double> size) units::font_size::points<double> size,
bool loadIfNotFound)
{ {
const std::string styleString = fmt::format("{}", fmt::join(styles, " ")); const std::string styleString = fmt::format("{}", fmt::join(styles, " "));
const std::string fontString = const std::string fontString =
@ -100,14 +100,16 @@ FontManager::GetImGuiFont(const std::string& family,
// Only allow whole pixels, and clamp to 6-72 pt // Only allow whole pixels, and clamp to 6-72 pt
units::font_size::pixels<double> pixels {size}; units::font_size::pixels<double> pixels {size};
int imFontSize = std::clamp(static_cast<int>(pixels.value()), 8, 96); units::font_size::pixels<int> imFontSize {
std::clamp(static_cast<int>(pixels.value()), 8, 96)};
auto imguiFontKey = std::make_pair(fontRecord, imFontSize);
// Search for a loaded ImGui font // Search for a loaded ImGui font
{ {
std::shared_lock imguiFontLock {p->imguiFontsMutex_}; std::shared_lock imguiFontLock {p->imguiFontsMutex_};
// Search for the associated ImGui font // Search for the associated ImGui font
auto it = p->imguiFonts_.find(std::make_pair(fontRecord, imFontSize)); auto it = p->imguiFonts_.find(imguiFontKey);
if (it != p->imguiFonts_.end()) if (it != p->imguiFonts_.end())
{ {
return it->second; return it->second;
@ -116,17 +118,38 @@ FontManager::GetImGuiFont(const std::string& family,
// No ImGui font was found, we need to create one // No ImGui font was found, we need to create one
} }
// No font was found, return an empty shared pointer if not loading
if (!loadIfNotFound)
{
return nullptr;
}
// Get raw font data // Get raw font data
const auto& rawFontData = p->GetRawFontData(fontRecord.filename_); const auto& rawFontData = p->GetRawFontData(fontRecord.filename_);
// TODO: Create an ImGui font // The font atlas mutex might already be locked within an ImGui render frame.
// TODO: imguiFontLock could be acquired during a render loop, when the font // Lock the font atlas mutex before the fonts mutex to prevent deadlock.
// atlas is already locked. Lock the font atlas first. Unless it's already std::unique_lock imguiFontAtlasLock {p->imguiFontAtlasMutex_};
// locked. It might need to be reentrant? std::unique_lock imguiFontsLock {p->imguiFontsMutex_};
// TODO: Search for font once more, to prevent loading the same font twice
Q_UNUSED(rawFontData);
return nullptr; // Search for the associated ImGui font again, to prevent loading the same
// font twice
auto it = p->imguiFonts_.find(imguiFontKey);
if (it != p->imguiFonts_.end())
{
return it->second;
}
// Create an ImGui font
std::shared_ptr<types::ImGuiFont> imguiFont =
std::make_shared<types::ImGuiFont>(
fontRecord.filename_, rawFontData, imFontSize);
// Store the ImGui font
p->imguiFonts_.insert_or_assign(imguiFontKey, imguiFont);
// Return the ImGui font
return imguiFont;
} }
const std::vector<std::uint8_t>& const std::vector<std::uint8_t>&
@ -311,14 +334,13 @@ FontManager& FontManager::Instance()
return instance_; return instance_;
} }
size_t FontRecordHash<std::pair<FontRecord, int>>::operator()( size_t FontRecordHash<FontRecordPair>::operator()(const FontRecordPair& x) const
const std::pair<FontRecord, int>& x) const
{ {
size_t seed = 0; size_t seed = 0;
boost::hash_combine(seed, x.first.family_); boost::hash_combine(seed, x.first.family_);
boost::hash_combine(seed, x.first.style_); boost::hash_combine(seed, x.first.style_);
boost::hash_combine(seed, x.first.filename_); boost::hash_combine(seed, x.first.filename_);
boost::hash_combine(seed, x.second); boost::hash_combine(seed, x.second.value());
return seed; return seed;
} }

View file

@ -26,7 +26,8 @@ public:
std::shared_ptr<types::ImGuiFont> std::shared_ptr<types::ImGuiFont>
GetImGuiFont(const std::string& family, GetImGuiFont(const std::string& family,
const std::vector<std::string>& styles, const std::vector<std::string>& styles,
units::font_size::points<double> size); units::font_size::points<double> size,
bool loadIfNotFound = false);
void LoadApplicationFont(const std::string& filename); void LoadApplicationFont(const std::string& filename);

View file

@ -24,8 +24,8 @@ class ImGuiFont::Impl
{ {
public: public:
explicit Impl(const std::string& fontName, explicit Impl(const std::string& fontName,
const std::string& fontData, const std::vector<std::uint8_t>& fontData,
units::pixels<double> size) : units::font_size::pixels<int> size) :
fontName_ {fontName}, size_ {size} fontName_ {fontName}, size_ {size}
{ {
CreateImGuiFont(fontData); CreateImGuiFont(fontData);
@ -33,23 +33,23 @@ public:
~Impl() {} ~Impl() {}
void CreateImGuiFont(const std::string& fontData); void CreateImGuiFont(const std::vector<std::uint8_t>& fontData);
const std::string fontName_; const std::string fontName_;
const units::pixels<double> size_; const units::font_size::pixels<int> size_;
ImFont* imFont_ {nullptr}; ImFont* imFont_ {nullptr};
}; };
ImGuiFont::ImGuiFont(const std::string& fontName, ImGuiFont::ImGuiFont(const std::string& fontName,
const std::string& fontData, const std::vector<std::uint8_t>& fontData,
units::pixels<double> size) : units::font_size::pixels<int> size) :
p(std::make_unique<Impl>(fontName, fontData, size)) p(std::make_unique<Impl>(fontName, fontData, size))
{ {
} }
ImGuiFont::~ImGuiFont() = default; ImGuiFont::~ImGuiFont() = default;
void ImGuiFont::Impl::CreateImGuiFont(const std::string& fontData) void ImGuiFont::Impl::CreateImGuiFont(const std::vector<std::uint8_t>& fontData)
{ {
logger_->debug("Creating Font: {}", fontName_); logger_->debug("Creating Font: {}", fontName_);
@ -66,7 +66,7 @@ void ImGuiFont::Impl::CreateImGuiFont(const std::string& fontData)
fontConfig.Name[sizeof(fontConfig.Name) - 1] = 0; fontConfig.Name[sizeof(fontConfig.Name) - 1] = 0;
imFont_ = fontAtlas->AddFontFromMemoryTTF( imFont_ = fontAtlas->AddFontFromMemoryTTF(
const_cast<void*>(static_cast<const void*>(fontData.c_str())), const_cast<void*>(static_cast<const void*>(fontData.data())),
static_cast<int>(std::clamp<std::size_t>( static_cast<int>(std::clamp<std::size_t>(
fontData.size(), 0, std::numeric_limits<int>::max())), fontData.size(), 0, std::numeric_limits<int>::max())),
sizePixels, sizePixels,

View file

@ -2,6 +2,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector>
#include <scwx/qt/types/font_types.hpp> #include <scwx/qt/types/font_types.hpp>
@ -18,8 +19,8 @@ class ImGuiFont
{ {
public: public:
explicit ImGuiFont(const std::string& fontName, explicit ImGuiFont(const std::string& fontName,
const std::string& fontData, const std::vector<std::uint8_t>& fontData,
units::pixels<double> size); units::font_size::pixels<int> size);
~ImGuiFont(); ~ImGuiFont();
ImGuiFont(const ImGuiFont&) = delete; ImGuiFont(const ImGuiFont&) = delete;