Custom font support

This commit is contained in:
Federico Cecchetto 2022-03-18 00:56:03 +01:00
parent 3471ae9dd8
commit 6044326356
4 changed files with 133 additions and 0 deletions

View File

@ -0,0 +1,116 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "fonts.hpp"
#include "console.hpp"
#include "game/game.hpp"
#include "game/dvars.hpp"
#include <utils/hook.hpp>
#include <utils/memory.hpp>
#include <utils/io.hpp>
#include <utils/string.hpp>
#include <utils/image.hpp>
#include <utils/concurrency.hpp>
namespace fonts
{
namespace
{
struct font_data_t
{
std::unordered_map<std::string, game::TTF*> fonts;
std::unordered_map<std::string, std::string> raw_fonts;
};
utils::concurrency::container<font_data_t> font_data;
game::TTF* create_font(const std::string& name, const std::string& data)
{
const auto font = utils::memory::get_allocator()->allocate<game::TTF>();
font->name = utils::memory::get_allocator()->duplicate_string(name);
font->buffer = utils::memory::get_allocator()->duplicate_string(data);
font->len = static_cast<int>(data.size());
font->fontFace = 0;
return font;
}
game::TTF* load_font(const std::string& name)
{
return font_data.access<game::TTF*>([&](font_data_t& data_) -> game::TTF*
{
if (const auto i = data_.fonts.find(name); i != data_.fonts.end())
{
return i->second;
}
std::string data{};
if (const auto i = data_.raw_fonts.find(name); i != data_.raw_fonts.end())
{
data = i->second;
}
if (data.empty()
&& !utils::io::read_file(utils::string::va("h1-mod/%s", name.data()), &data)
&& !utils::io::read_file(utils::string::va("data/%s", name.data()), &data))
{
return nullptr;
}
const auto material = create_font(name, data);
data_.fonts[name] = material;
return material;
});
}
game::TTF* try_load_font(const std::string& name)
{
try
{
return load_font(name);
}
catch (const std::exception& e)
{
console::error("Failed to load font %s: %s\n", name.data(), e.what());
}
return nullptr;
}
game::TTF* db_find_xasset_header_stub(game::XAssetType type, const char* name, int create_default)
{
auto result = try_load_font(name);
if (result == nullptr)
{
result = game::DB_FindXAssetHeader(type, name, create_default).ttf;
}
return result;
}
}
void add(const std::string& name, const std::string& data)
{
font_data.access([&](font_data_t& data_)
{
data_.raw_fonts[name] = data;
});
}
class component final : public component_interface
{
public:
void post_unpack() override
{
if (game::environment::is_dedi())
{
return;
}
utils::hook::call(SELECT_VALUE(0x1404D41B6, 0x1405D9296), db_find_xasset_header_stub);
}
};
}
REGISTER_COMPONENT(fonts::component)

View File

@ -0,0 +1,6 @@
#pragma once
namespace fonts
{
void add(const std::string& name, const std::string& data);
}

View File

@ -1316,6 +1316,14 @@ namespace game
const char* buffer; const char* buffer;
}; };
struct TTF
{
const char* name;
int len;
const char* buffer;
int fontFace;
};
struct GfxImageLoadDef struct GfxImageLoadDef
{ {
char levelCount; char levelCount;
@ -1387,6 +1395,7 @@ namespace game
StringTable* stringTable; StringTable* stringTable;
LuaFile* luaFile; LuaFile* luaFile;
GfxImage* image; GfxImage* image;
TTF* ttf;
}; };
struct XAsset struct XAsset

View File

@ -143,6 +143,8 @@ namespace game
DB_EnumXAssets_Internal{0x1401C9C10, 0x1402BA830}; DB_EnumXAssets_Internal{0x1401C9C10, 0x1402BA830};
WEAK symbol<const char*(const XAsset* asset)> DB_GetXAssetName{0x14019A390, 0x14028BE50}; WEAK symbol<const char*(const XAsset* asset)> DB_GetXAssetName{0x14019A390, 0x14028BE50};
WEAK symbol<int(XAssetType type)> DB_GetXAssetTypeSize{0x14019A3B0, 0x14028BE70}; WEAK symbol<int(XAssetType type)> DB_GetXAssetTypeSize{0x14019A3B0, 0x14028BE70};
WEAK symbol<XAssetHeader(XAssetType type, const char* name,
int createDefault)> DB_FindXAssetHeader{0x1401CA150, 0x1402BAC70};
WEAK symbol<void(int clientNum, const char* menu, WEAK symbol<void(int clientNum, const char* menu,
int a3, int a4, unsigned int a5)> LUI_OpenMenu{0x14039D5F0, 0x1404CD210}; int a3, int a4, unsigned int a5)> LUI_OpenMenu{0x14039D5F0, 0x1404CD210};