Added more options to font loading.

This commit is contained in:
Patrick 2025-03-05 22:02:30 +01:00
parent 830fdd434b
commit 1d75400a2d
3 changed files with 71 additions and 17 deletions

View File

@ -4,7 +4,7 @@ Import('env')
public_dir = env.Dir('public') public_dir = env.Dir('public')
env.Append(CPPPATH = [public_dir]) env.Append(CPPPATH = [public_dir])
if env['BUILD_TYPE'] == 'release': if env['BUILD_TYPE'] == 'release':
cppdefines += ['RAID_RELEASE=1'] env.Append(CPPDEFINES = ['RAID_RELEASE'])
env = env.Module('private/raid/SModule') env = env.Module('private/raid/SModule')
LIB_CONFIG = { LIB_CONFIG = {

View File

@ -7,6 +7,7 @@
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
#include <mijin/debug/assert.hpp> #include <mijin/debug/assert.hpp>
#include <mijin/platform/folders.hpp> #include <mijin/platform/folders.hpp>
#include <mijin/util/iterators.hpp>
#include <mijin/util/scope_guard.hpp> #include <mijin/util/scope_guard.hpp>
#include <mijin/virtual_filesystem/mapping.hpp> #include <mijin/virtual_filesystem/mapping.hpp>
#include <mijin/virtual_filesystem/relative.hpp> #include <mijin/virtual_filesystem/relative.hpp>
@ -125,29 +126,55 @@ int Application::run(int argc, char** argv)
return 0; return 0;
} }
bool Application::loadFont(const fs::path& path)
bool Application::loadFonts(std::span<const FontConfig> fonts)
{ {
ImGuiIO& imguiIO = ImGui::GetIO(); ImGuiIO& imguiIO = ImGui::GetIO();
std::unique_ptr<mijin::Stream> fontFile; std::vector<mijin::TypelessBuffer> buffers;
if (const mijin::StreamError error = mFS.open(path, mijin::FileOpenMode::READ, fontFile); buffers.reserve(fonts.size());
error != mijin::StreamError::SUCCESS)
{
msgError("Error opening font file {}: {}.", path.generic_string(), mijin::errorName(error));
return false;
}
mijin::TypelessBuffer data; for (const FontConfig& font : fonts)
if (const mijin::StreamError readError = fontFile->readRest(data); readError != mijin::StreamError::SUCCESS)
{ {
msgError("Error reading font data from {}: {}.", path.generic_string(), mijin::errorName(readError)); std::unique_ptr<mijin::Stream> fontFile;
return false; if (const mijin::StreamError error = mFS.open(font.path, mijin::FileOpenMode::READ, fontFile);
error != mijin::StreamError::SUCCESS)
{
msgError("Error opening font file {}: {}.", font.path.generic_string(), mijin::errorName(error));
return false;
}
mijin::TypelessBuffer& data = buffers.emplace_back();
if (const mijin::StreamError readError = fontFile->readRest(data); readError != mijin::StreamError::SUCCESS)
{
msgError("Error reading font data from {}: {}.", font.path.generic_string(), mijin::errorName(readError));
return false;
}
} }
// by default ImGui takes ownership of the data, that's now what we want // by default ImGui takes ownership of the data, that's now what we want
ImFontConfig config; ImFontConfig config;
config.FontDataOwnedByAtlas = false; config.FontDataOwnedByAtlas = false;
imguiIO.Fonts->AddFontFromMemoryTTF(data.data(), static_cast<int>(data.byteSize()), 20, &config); std::vector<ImWchar> glyphRangesConverted;
for (const auto& [font, data] : mijin::zip(fonts, buffers))
{
ImWchar* glyphRanges = nullptr;
if (!font.glyphRanges.empty())
{
glyphRangesConverted.reserve(2 * font.glyphRanges.size() + 1);
glyphRangesConverted.clear();
for (const std::pair<ImWchar, ImWchar>& range : font.glyphRanges)
{
glyphRangesConverted.push_back(range.first);
glyphRangesConverted.push_back(range.second);
}
glyphRangesConverted.push_back(0);
glyphRanges = glyphRangesConverted.data();
}
config.PixelSnapH = font.flags.pixelSnapH;
imguiIO.Fonts->AddFontFromMemoryTTF(data.data(), static_cast<int>(data.byteSize()), font.size, &config, glyphRanges);
config.MergeMode = true; // for any more fonts
}
// but in that case Build() has to be run before the data gets deleted // but in that case Build() has to be run before the data gets deleted
imguiIO.Fonts->Build(); imguiIO.Fonts->Build();
@ -209,6 +236,13 @@ void Application::configureImgui()
imguiIO.ConfigViewportsNoAutoMerge = true; imguiIO.ConfigViewportsNoAutoMerge = true;
} }
std::vector<FontConfig> Application::getDefaultFonts()
{
return {{
.path = "/data/fonts/NotoSans-Regular.ttf"
}};
}
void Application::handleMessage(const Message& message) void Application::handleMessage(const Message& message)
{ {
switch (message.severity) switch (message.severity)
@ -452,8 +486,7 @@ bool Application::initImGui()
// init font // init font
if (imguiIO.Fonts->Fonts.empty()) if (imguiIO.Fonts->Fonts.empty())
{ {
static const char* const DEFAULT_FONT = "/data/fonts/NotoSans-Regular.ttf"; if (!loadFonts(getDefaultFonts()))
if (!loadFont(DEFAULT_FONT))
{ {
imguiIO.Fonts->AddFontDefault(); imguiIO.Fonts->AddFontDefault();
} }

View File

@ -9,6 +9,7 @@
#include <fmt/format.h> #include <fmt/format.h>
#include <imgui.h> #include <imgui.h>
#include <mijin/async/coroutine.hpp> #include <mijin/async/coroutine.hpp>
#include <mijin/util/bitflags.hpp>
#include <mijin/virtual_filesystem/stacked.hpp> #include <mijin/virtual_filesystem/stacked.hpp>
#include <SDL3/SDL.h> #include <SDL3/SDL.h>
@ -34,6 +35,19 @@ struct Message
const char* text; const char* text;
}; };
struct FontFlags : mijin::BitFlags<FontFlags>
{
bool pixelSnapH : 1 = false;
};
struct FontConfig
{
fs::path path;
std::vector<std::pair<ImWchar, ImWchar>> glyphRanges;
float size = 20.f;
FontFlags flags;
};
class Application class Application
{ {
private: private:
@ -90,7 +104,13 @@ public:
int run(int argc, char* argv[]); int run(int argc, char* argv[]);
[[nodiscard]] [[nodiscard]]
bool loadFont(const fs::path& path); bool loadFonts(std::span<const FontConfig> fonts);
[[nodiscard]]
bool loadFont(const FontConfig& font)
{
return loadFonts({&font, 1});
}
[[nodiscard]] [[nodiscard]]
ImTextureID getOrLoadTexture(fs::path path); ImTextureID getOrLoadTexture(fs::path path);
@ -100,6 +120,7 @@ protected:
virtual std::string getFolderName() = 0; virtual std::string getFolderName() = 0;
virtual std::string getWindowTitle() = 0; virtual std::string getWindowTitle() = 0;
virtual void configureImgui(); virtual void configureImgui();
virtual std::vector<FontConfig> getDefaultFonts();
virtual void handleMessage(const Message& message); virtual void handleMessage(const Message& message);
virtual void handleSDLEvent(const SDL_Event& event); virtual void handleSDLEvent(const SDL_Event& event);