mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2026-07-19 14:30:37 +00:00
feat: font loading and dumping (#866)
* feat: font loading and dumping * chore: make font properties unsigned if possible * chore: use merge_patch to dump json font * chore: font material is required * chore: move static methods from font loader and dumper to anonymous namespace * chore: make sure loaded fonts have their glyphs sorted * chore: add macros for json NLOHMANN_TO_JSON_METHOD and NLOHMANN_FROM_JSON_METHOD * feat: encode printable letters as string in json Co-authored-by: hindercanrun <[email protected]> * chore: omit redundant glyph count from jsons --------- Co-authored-by: Jan Laupetin <[email protected]> Co-authored-by: hindercanrun <[email protected]> Co-authored-by: MrIkso <[email protected]>
This commit is contained in:
co-authored by
Jan Laupetin
hindercanrun
MrIkso
parent
fb4b00398c
commit
3fb8b2bb17
@@ -28,7 +28,7 @@ using `Linker`):
|
||||
| MapEnts | ✅ | ❌ | |
|
||||
| GfxWorld | ❌ | ❌ | |
|
||||
| GfxLightDef | ✅ | ✅ | |
|
||||
| Font_s | ❌ | ❌ | |
|
||||
| Font_s | ✅ | ✅ | |
|
||||
| MenuList | ❌ | ❌ | |
|
||||
| menuDef_t | ❌ | ❌ | |
|
||||
| LocalizeEntry | ✅ | ✅ | |
|
||||
@@ -63,7 +63,7 @@ using `Linker`):
|
||||
| FxWorld | ❌ | ❌ | |
|
||||
| GfxWorld | ❌ | ❌ | |
|
||||
| GfxLightDef | ✅ | ✅ | |
|
||||
| Font_s | ❌ | ❌ | |
|
||||
| Font_s | ✅ | ✅ | |
|
||||
| MenuList | ✅ | ✅ | The output is decompiled. The result will not be the same as the input. |
|
||||
| menuDef_t | ✅ | ✅ | See menulist. |
|
||||
| LocalizeEntry | ✅ | ✅ | |
|
||||
@@ -105,7 +105,7 @@ using `Linker`):
|
||||
| FxWorld | ❌ | ❌ | |
|
||||
| GfxWorld | ❌ | ❌ | |
|
||||
| GfxLightDef | ✅ | ✅ | |
|
||||
| Font_s | ❌ | ❌ | |
|
||||
| Font_s | ✅ | ✅ | |
|
||||
| MenuList | ✅ | ✅ | The output is decompiled. The result will not be the same as the input. |
|
||||
| menuDef_t | ✅ | ✅ | See menulist. |
|
||||
| LocalizeEntry | ✅ | ✅ | |
|
||||
@@ -145,7 +145,7 @@ using `Linker`):
|
||||
| MapEnts | ✅ | ✅ | |
|
||||
| GfxWorld | ❌ | ❌ | |
|
||||
| GfxLightDef | ❌ | ❌ | |
|
||||
| Font_s | ❌ | ❌ | |
|
||||
| Font_s | ✅ | ✅ | |
|
||||
| MenuList | ❌ | ❌ | |
|
||||
| menuDef_t | ❌ | ❌ | |
|
||||
| LocalizeEntry | ✅ | ✅ | |
|
||||
@@ -177,7 +177,7 @@ using `Linker`):
|
||||
| MapEnts | ❌ | ❌ | |
|
||||
| GfxWorld | ❌ | ❌ | |
|
||||
| GfxLightDef | ✅ | ✅ | |
|
||||
| Font_s | ❌ | ❌ | |
|
||||
| Font_s | ✅ | ✅ | |
|
||||
| MenuList | ❌ | ❌ | |
|
||||
| menuDef_t | ❌ | ❌ | |
|
||||
| LocalizeEntry | ✅ | ✅ | |
|
||||
|
||||
@@ -2455,9 +2455,9 @@ namespace IW3
|
||||
uint16_t letter;
|
||||
char x0;
|
||||
char y0;
|
||||
char dx;
|
||||
char pixelWidth;
|
||||
char pixelHeight;
|
||||
unsigned char dx;
|
||||
unsigned char pixelWidth;
|
||||
unsigned char pixelHeight;
|
||||
float s0;
|
||||
float t0;
|
||||
float s1;
|
||||
|
||||
@@ -2676,9 +2676,9 @@ namespace IW4
|
||||
uint16_t letter;
|
||||
char x0;
|
||||
char y0;
|
||||
char dx;
|
||||
char pixelWidth;
|
||||
char pixelHeight;
|
||||
unsigned char dx;
|
||||
unsigned char pixelWidth;
|
||||
unsigned char pixelHeight;
|
||||
float s0;
|
||||
float t0;
|
||||
float s1;
|
||||
|
||||
@@ -2713,9 +2713,9 @@ namespace T4
|
||||
uint16_t letter;
|
||||
char x0;
|
||||
char y0;
|
||||
char dx;
|
||||
char pixelWidth;
|
||||
char pixelHeight;
|
||||
unsigned char dx;
|
||||
unsigned char pixelWidth;
|
||||
unsigned char pixelHeight;
|
||||
float s0;
|
||||
float t0;
|
||||
float s1;
|
||||
|
||||
@@ -3310,9 +3310,9 @@ namespace T5
|
||||
uint16_t letter;
|
||||
char x0;
|
||||
char y0;
|
||||
char dx;
|
||||
char pixelWidth;
|
||||
char pixelHeight;
|
||||
unsigned char dx;
|
||||
unsigned char pixelWidth;
|
||||
unsigned char pixelHeight;
|
||||
float s0;
|
||||
float t0;
|
||||
float s1;
|
||||
|
||||
@@ -3997,9 +3997,9 @@ namespace T6
|
||||
uint16_t letter;
|
||||
char x0;
|
||||
char y0;
|
||||
char dx;
|
||||
char pixelWidth;
|
||||
char pixelHeight;
|
||||
unsigned char dx;
|
||||
unsigned char pixelWidth;
|
||||
unsigned char pixelHeight;
|
||||
float s0;
|
||||
float t0;
|
||||
float s1;
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
#include "FontCommon.h"
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
namespace font
|
||||
{
|
||||
std::string GetJsonFileNameForAssetName(const std::string& assetName)
|
||||
{
|
||||
fs::path path(assetName);
|
||||
path.replace_extension(".json");
|
||||
return path.string();
|
||||
}
|
||||
|
||||
bool IsPrintableLetter(const unsigned letter)
|
||||
{
|
||||
// Control characters
|
||||
if (letter < 0x20)
|
||||
return false;
|
||||
|
||||
// Printable ascii characters
|
||||
if (letter < 0x7F)
|
||||
return true;
|
||||
|
||||
// There are characters after this point that are printable as well
|
||||
// But they don't seem to play a role in cod fonts
|
||||
if (letter > 0xFF)
|
||||
return false;
|
||||
|
||||
switch (letter)
|
||||
{
|
||||
case 0x7F:
|
||||
case 0x81:
|
||||
case 0x8D:
|
||||
case 0x8F:
|
||||
case 0x90:
|
||||
case 0x9D:
|
||||
case 0xA0:
|
||||
case 0xAD:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
std::string LetterToString(const unsigned letter)
|
||||
{
|
||||
// UTF-8 => 1 byte
|
||||
if (letter < 0x80)
|
||||
return std::string(1, static_cast<char>(letter));
|
||||
|
||||
if (letter < 0x800)
|
||||
{
|
||||
// UTF-8 => 2 bytes
|
||||
std::string s(2, '\0');
|
||||
s[0] = static_cast<char>(0xC0 | (letter >> 6u));
|
||||
s[1] = static_cast<char>(0x80 | (letter & 0x3F));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// UTF-8 => 3 bytes
|
||||
std::string s(3, '\0');
|
||||
s[0] = static_cast<char>(0xE0 | (letter >> 12u));
|
||||
s[1] = static_cast<char>(0x80 | ((letter >> 6u) & 0x3F));
|
||||
s[2] = static_cast<char>(0x80 | (letter & 0x3F));
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
unsigned StringToLetter(const std::string& str)
|
||||
{
|
||||
const auto strSize = str.size();
|
||||
if (strSize < 1)
|
||||
return 0;
|
||||
|
||||
const auto firstByte = static_cast<unsigned char>(str[0]);
|
||||
|
||||
// UTF-8 => 1 byte
|
||||
if ((firstByte & 0x80) == 0)
|
||||
return firstByte;
|
||||
|
||||
if (strSize < 2)
|
||||
return 0;
|
||||
const auto secondByte = static_cast<unsigned char>(str[1]);
|
||||
|
||||
if ((firstByte & 0xE0) == 0xC0 && (secondByte & 0xC0) == 0x80)
|
||||
{
|
||||
// UTF-8 => 2 bytes
|
||||
return ((firstByte & 0x1F) << 6u) | (secondByte & 0x3F);
|
||||
}
|
||||
|
||||
if (strSize < 3)
|
||||
return 0;
|
||||
const auto thirdByte = static_cast<unsigned char>(str[2]);
|
||||
|
||||
if ((firstByte & 0xF0) == 0xE0 && (secondByte & 0xC0) == 0x80 && (thirdByte & 0xC0) == 0x80)
|
||||
{
|
||||
// UTF-8 => 3 bytes
|
||||
return ((firstByte & 0x0F) << 12u) | ((secondByte & 0x3F) << 6u) | (thirdByte & 0x3F);
|
||||
}
|
||||
|
||||
// Unsupported
|
||||
return 0;
|
||||
}
|
||||
} // namespace font
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace font
|
||||
{
|
||||
std::string GetJsonFileNameForAssetName(const std::string& assetName);
|
||||
|
||||
bool IsPrintableLetter(unsigned letter);
|
||||
|
||||
std::string LetterToString(unsigned letter);
|
||||
unsigned StringToLetter(const std::string& str);
|
||||
} // namespace font
|
||||
@@ -0,0 +1,67 @@
|
||||
#options GAME (IW3, IW4, IW5, T4, T5)
|
||||
|
||||
#filename "Game/" + GAME + "/Font/JsonFont" + GAME + ".h"
|
||||
|
||||
// This file was templated.
|
||||
// See JsonFont.h.template.
|
||||
// Do not modify, changes will be lost.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Json/JsonExtension.h"
|
||||
#include "Font/FontCommon.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace GAME
|
||||
{
|
||||
class JsonGlyph
|
||||
{
|
||||
public:
|
||||
unsigned letter;
|
||||
int x0;
|
||||
int y0;
|
||||
unsigned dx;
|
||||
unsigned pixelWidth;
|
||||
unsigned pixelHeight;
|
||||
float s0;
|
||||
float t0;
|
||||
float s1;
|
||||
float t1;
|
||||
};
|
||||
|
||||
NLOHMANN_TO_JSON_METHOD(JsonGlyph)
|
||||
{
|
||||
if (font::IsPrintableLetter(nlohmann_json_t.letter))
|
||||
extended_to_json("letter", nlohmann_json_j, font::LetterToString(nlohmann_json_t.letter));
|
||||
else
|
||||
extended_to_json("letter", nlohmann_json_j, nlohmann_json_t.letter);
|
||||
|
||||
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(EXTEND_JSON_TO, x0, y0, dx, pixelWidth, pixelHeight, s0, t0, s1, t1))
|
||||
}
|
||||
|
||||
NLOHMANN_FROM_JSON_METHOD(JsonGlyph)
|
||||
{
|
||||
const auto jLetter = nlohmann_json_j.at("letter");
|
||||
if (jLetter.type() == BasicJsonType::value_t::string)
|
||||
nlohmann_json_t.letter = font::StringToLetter(jLetter.template get<std::string>());
|
||||
else
|
||||
nlohmann_json_t.letter = jLetter.template get<unsigned>();
|
||||
|
||||
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(EXTEND_JSON_FROM, x0, y0, dx, pixelWidth, pixelHeight, s0, t0, s1, t1))
|
||||
}
|
||||
|
||||
class JsonFont
|
||||
{
|
||||
public:
|
||||
unsigned pixelHeight;
|
||||
std::string material;
|
||||
std::optional<std::string> glowMaterial;
|
||||
std::vector<JsonGlyph> glyphs;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonFont, pixelHeight, material, glowMaterial, glyphs);
|
||||
} // namespace GAME
|
||||
@@ -0,0 +1,254 @@
|
||||
#options GAME (IW3, IW4, IW5, T4, T5)
|
||||
|
||||
#filename "Game/" + GAME + "/Font/FontLoader" + GAME + ".cpp"
|
||||
|
||||
#if GAME == "IW3"
|
||||
#define GAME_LOWER "iw3"
|
||||
#elif GAME == "IW4"
|
||||
#define GAME_LOWER "iw4"
|
||||
#elif GAME == "IW5"
|
||||
#define GAME_LOWER "iw5"
|
||||
#elif GAME == "T4"
|
||||
#define GAME_LOWER "t4"
|
||||
#elif GAME == "T5"
|
||||
#define GAME_LOWER "t5"
|
||||
#endif
|
||||
|
||||
// This file was templated.
|
||||
// See FontLoader.cpp.template.
|
||||
// Do not modify, changes will be lost.
|
||||
|
||||
#set LOADER_HEADER "\"FontLoader" + GAME + ".h\""
|
||||
#include LOADER_HEADER
|
||||
|
||||
#include "Font/FontCommon.h"
|
||||
#set JSON_HEADER "\"Game/" + GAME + "/Font/JsonFont" + GAME + ".h\""
|
||||
#include JSON_HEADER
|
||||
#include "Utils/Logging/Log.h"
|
||||
|
||||
#include <format>
|
||||
#include <limits>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using namespace nlohmann;
|
||||
using namespace GAME;
|
||||
|
||||
namespace
|
||||
{
|
||||
void PrintError(const Font_s& font, const std::string& message)
|
||||
{
|
||||
con::error("Cannot load font \"{}\": {}", font.fontName, message);
|
||||
}
|
||||
|
||||
template<typename FieldType, typename ValueType>
|
||||
bool AssignIntegerField(FieldType& field, const ValueType value, const Font_s& font, const char* fieldName)
|
||||
{
|
||||
const auto minValue = static_cast<ValueType>(std::numeric_limits<FieldType>::min());
|
||||
const auto maxValue = static_cast<ValueType>(std::numeric_limits<FieldType>::max());
|
||||
|
||||
if (value < minValue || value > maxValue)
|
||||
{
|
||||
PrintError(font, std::format("{} value {} is outside allowed range {}..{}", fieldName, value, minValue, maxValue));
|
||||
return false;
|
||||
}
|
||||
|
||||
field = static_cast<FieldType>(value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateMaterialDependency(const std::string& materialName,
|
||||
Material*& material,
|
||||
AssetRegistration<AssetFont>& registration,
|
||||
AssetCreationContext& context,
|
||||
const Font_s& font,
|
||||
const char* fieldName)
|
||||
{
|
||||
auto* materialDependency = context.LoadDependency<AssetMaterial>(materialName);
|
||||
if (!materialDependency)
|
||||
{
|
||||
PrintError(font, std::format("Could not find {} material \"{}\"", fieldName, materialName));
|
||||
return false;
|
||||
}
|
||||
|
||||
registration.AddDependency(materialDependency);
|
||||
material = materialDependency->Asset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateGlyphFromJson(const JsonGlyph& jGlyph, Glyph& glyph, const Font_s& font)
|
||||
{
|
||||
if (!AssignIntegerField(glyph.letter, jGlyph.letter, font, "glyph.letter"))
|
||||
return false;
|
||||
if (!AssignIntegerField(glyph.x0, jGlyph.x0, font, "glyph.x0"))
|
||||
return false;
|
||||
if (!AssignIntegerField(glyph.y0, jGlyph.y0, font, "glyph.y0"))
|
||||
return false;
|
||||
if (!AssignIntegerField(glyph.dx, jGlyph.dx, font, "glyph.dx"))
|
||||
return false;
|
||||
if (!AssignIntegerField(glyph.pixelWidth, jGlyph.pixelWidth, font, "glyph.pixelWidth"))
|
||||
return false;
|
||||
if (!AssignIntegerField(glyph.pixelHeight, jGlyph.pixelHeight, font, "glyph.pixelHeight"))
|
||||
return false;
|
||||
|
||||
glyph.s0 = jGlyph.s0;
|
||||
glyph.t0 = jGlyph.t0;
|
||||
glyph.s1 = jGlyph.s1;
|
||||
glyph.t1 = jGlyph.t1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr auto REQUIRED_GLYPH_START = 0x20;
|
||||
constexpr auto REQUIRED_GLYPH_END_INCLUSIVE = 0x7F;
|
||||
constexpr unsigned REQUIRED_GLYPH_COUNT = REQUIRED_GLYPH_END_INCLUSIVE + 1 - REQUIRED_GLYPH_START;
|
||||
constexpr bool IsRequiredGlyph(const unsigned letter)
|
||||
{
|
||||
return letter >= REQUIRED_GLYPH_START && letter <= REQUIRED_GLYPH_END_INCLUSIVE;
|
||||
}
|
||||
|
||||
void SortGlyphs(const Font_s& font)
|
||||
{
|
||||
std::sort(&font.glyphs[0], &font.glyphs[font.glyphCount], [](const Glyph& a, const Glyph& b)
|
||||
{
|
||||
const auto aRequired = IsRequiredGlyph(a.letter);
|
||||
const auto bRequired = IsRequiredGlyph(b.letter);
|
||||
if (aRequired != bRequired)
|
||||
return aRequired;
|
||||
|
||||
return a.letter < b.letter;
|
||||
});
|
||||
}
|
||||
|
||||
bool EnsureFontContainsAllRequiredGlyphs(const Font_s& font)
|
||||
{
|
||||
if (static_cast<unsigned>(font.glyphCount) < REQUIRED_GLYPH_COUNT)
|
||||
{
|
||||
con::error("Font {} must contain all {} required letters", font.fontName, REQUIRED_GLYPH_COUNT);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < REQUIRED_GLYPH_COUNT; i++)
|
||||
{
|
||||
const unsigned requiredGlyphLetter = REQUIRED_GLYPH_START + i;
|
||||
if (font.glyphs[i].letter != requiredGlyphLetter)
|
||||
{
|
||||
con::error("Font {} is missing required letter {} ('{}')", font.fontName, requiredGlyphLetter, static_cast<char>(requiredGlyphLetter));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class FontLoader final : public AssetCreator<AssetFont>
|
||||
{
|
||||
public:
|
||||
FontLoader(MemoryManager& memory, ISearchPath& searchPath)
|
||||
: m_memory(memory),
|
||||
m_search_path(searchPath)
|
||||
{
|
||||
}
|
||||
|
||||
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
||||
{
|
||||
const auto file = m_search_path.Open(font::GetJsonFileNameForAssetName(assetName));
|
||||
if (!file.IsOpen())
|
||||
return AssetCreationResult::NoAction();
|
||||
|
||||
auto* font = m_memory.Alloc<Font_s>();
|
||||
font->fontName = m_memory.Dup(assetName.c_str());
|
||||
AssetRegistration<AssetFont> registration(assetName, font);
|
||||
|
||||
try
|
||||
{
|
||||
const auto jRoot = json::parse(*file.m_stream);
|
||||
std::string type;
|
||||
unsigned version;
|
||||
|
||||
jRoot.at("_type").get_to(type);
|
||||
jRoot.at("_version").get_to(version);
|
||||
|
||||
if (type != "font" || version != 1u)
|
||||
{
|
||||
con::error(R"(Tried to load font "{}" but did not find expected type font of version 1)", assetName);
|
||||
return AssetCreationResult::Failure();
|
||||
}
|
||||
|
||||
std::string game;
|
||||
jRoot.at("_game").get_to(game);
|
||||
if (game != GAME_LOWER)
|
||||
{
|
||||
con::error(R"(Tried to load font "{}" but "_game" did not have expected value {})", assetName, GAME_LOWER);
|
||||
return AssetCreationResult::Failure();
|
||||
}
|
||||
|
||||
const auto jFont = jRoot.get<JsonFont>();
|
||||
if (CreateFontFromJson(jFont, *font, registration, context))
|
||||
return AssetCreationResult::Success(context.AddAsset(std::move(registration)));
|
||||
}
|
||||
catch (const json::exception& e)
|
||||
{
|
||||
con::error("Failed to parse json of font: {}", e.what());
|
||||
}
|
||||
|
||||
return AssetCreationResult::Failure();
|
||||
}
|
||||
|
||||
private:
|
||||
bool CreateFontFromJson(const JsonFont& jFont, Font_s& font, AssetRegistration<AssetFont>& registration, AssetCreationContext& context) const
|
||||
{
|
||||
font.pixelHeight = static_cast<decltype(Font_s::pixelHeight)>(jFont.pixelHeight);
|
||||
|
||||
if (!CreateMaterialDependency(jFont.material, font.material, registration, context, font, "font"))
|
||||
return false;
|
||||
|
||||
if (jFont.glowMaterial)
|
||||
{
|
||||
if (!CreateMaterialDependency(*jFont.glowMaterial, font.glowMaterial, registration, context, font, "glow"))
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr auto MAX_GLYPH_COUNT = std::numeric_limits<decltype(Font_s::glyphCount)>::max();
|
||||
if (jFont.glyphs.size() > static_cast<size_t>(MAX_GLYPH_COUNT))
|
||||
{
|
||||
PrintError(font, std::format("glyph count {} exceeds maximum {}", jFont.glyphs.size(), MAX_GLYPH_COUNT));
|
||||
return false;
|
||||
}
|
||||
|
||||
font.glyphCount = static_cast<decltype(Font_s::glyphCount)>(jFont.glyphs.size());;
|
||||
if (font.glyphCount <= 0)
|
||||
{
|
||||
font.glyphs = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
font.glyphs = m_memory.Alloc<Glyph>(font.glyphCount);
|
||||
for (auto i = 0; i < font.glyphCount; i++)
|
||||
{
|
||||
if (!CreateGlyphFromJson(jFont.glyphs[i], font.glyphs[i], font))
|
||||
return false;
|
||||
}
|
||||
|
||||
SortGlyphs(font);
|
||||
|
||||
if (!EnsureFontContainsAllRequiredGlyphs(font))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MemoryManager& m_memory;
|
||||
ISearchPath& m_search_path;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace font
|
||||
{
|
||||
#set CREATE_LOADER_METHOD "CreateLoader" + GAME
|
||||
std::unique_ptr<AssetCreator<AssetFont>> CREATE_LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath)
|
||||
{
|
||||
return std::make_unique<FontLoader>(memory, searchPath);
|
||||
}
|
||||
} // namespace font
|
||||
@@ -0,0 +1,23 @@
|
||||
#options GAME (IW3, IW4, IW5, T4, T5)
|
||||
|
||||
#filename "Game/" + GAME + "/Font/FontLoader" + GAME + ".h"
|
||||
|
||||
// This file was templated.
|
||||
// See FontLoader.h.template.
|
||||
// Do not modify, changes will be lost.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Asset/IAssetCreator.h"
|
||||
#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\""
|
||||
#include GAME_HEADER
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace font
|
||||
{
|
||||
#set CREATE_LOADER_METHOD "CreateLoader" + GAME
|
||||
std::unique_ptr<AssetCreator<GAME::AssetFont>> CREATE_LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath);
|
||||
} // namespace font
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Asset/GlobalAssetPoolsLoader.h"
|
||||
#include "Game/IW3/AssetMarkerIW3.h"
|
||||
#include "Game/IW3/Font/FontLoaderIW3.h"
|
||||
#include "Game/IW3/GameIW3.h"
|
||||
#include "Game/IW3/IW3.h"
|
||||
#include "Game/IW3/Image/ImageLoaderEmbeddedIW3.h"
|
||||
@@ -119,7 +120,7 @@ namespace
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderMapEnts>(memory));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderGfxWorld>(memory));
|
||||
collection.AddAssetCreator(light_def::CreateLoaderIW3(memory, searchPath));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderFont>(memory));
|
||||
collection.AddAssetCreator(font::CreateLoaderIW3(memory, searchPath));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderMenuList>(memory));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderMenu>(memory));
|
||||
collection.AddAssetCreator(localize::CreateLoaderIW3(memory, searchPath, zone));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Asset/GlobalAssetPoolsLoader.h"
|
||||
#include "Game/IW4/AssetMarkerIW4.h"
|
||||
#include "Game/IW4/Font/FontLoaderIW4.h"
|
||||
#include "Game/IW4/GameIW4.h"
|
||||
#include "Game/IW4/IW4.h"
|
||||
#include "Game/IW4/Image/ImageLoaderEmbeddedIW4.h"
|
||||
@@ -146,7 +147,7 @@ namespace
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderFxWorld>(memory));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderGfxWorld>(memory));
|
||||
collection.AddAssetCreator(light_def::CreateLoaderIW4(memory, searchPath));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderFont>(memory));
|
||||
collection.AddAssetCreator(font::CreateLoaderIW4(memory, searchPath));
|
||||
collection.AddAssetCreator(menu::CreateMenuListLoaderIW4(memory, searchPath));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderMenu>(memory));
|
||||
collection.AddAssetCreator(localize::CreateLoaderIW4(memory, searchPath, zone));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Asset/GlobalAssetPoolsLoader.h"
|
||||
#include "Game/IW5/AssetMarkerIW5.h"
|
||||
#include "Game/IW5/Font/FontLoaderIW5.h"
|
||||
#include "Game/IW5/GameIW5.h"
|
||||
#include "Game/IW5/IW5.h"
|
||||
#include "Game/IW5/Image/ImageLoaderEmbeddedIW5.h"
|
||||
@@ -154,7 +155,7 @@ namespace
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderFxWorld>(memory));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderGfxWorld>(memory));
|
||||
collection.AddAssetCreator(light_def::CreateLoaderIW5(memory, searchPath));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderFont>(memory));
|
||||
collection.AddAssetCreator(font::CreateLoaderIW5(memory, searchPath));
|
||||
collection.AddAssetCreator(menu::CreateMenuListLoaderIW5(memory, searchPath));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderMenu>(memory));
|
||||
collection.AddAssetCreator(localize::CreateLoaderIW5(memory, searchPath, zone));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Asset/GlobalAssetPoolsLoader.h"
|
||||
#include "Game/T4/AssetMarkerT4.h"
|
||||
#include "Game/T4/Font/FontLoaderT4.h"
|
||||
#include "Game/T4/T4.h"
|
||||
#include "Game/T4/Weapon/AccuracyGraphLoaderT4.h"
|
||||
#include "Game/T4/XAnim/XAnimLoaderT4.h"
|
||||
@@ -93,6 +94,7 @@ namespace
|
||||
auto& memory = zone.Memory();
|
||||
|
||||
collection.AddAssetCreator(xanim::CreateLoaderT4(memory, searchPath, zone));
|
||||
collection.AddAssetCreator(font::CreateLoaderT4(memory, searchPath));
|
||||
collection.AddAssetCreator(localize::CreateLoaderT4(memory, searchPath, zone));
|
||||
collection.AddAssetCreator(map_ents::CreateLoaderT4(memory, searchPath));
|
||||
collection.AddAssetCreator(raw_file::CreateLoaderT4(memory, searchPath));
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Asset/GlobalAssetPoolsLoader.h"
|
||||
#include "Game/T5/AssetMarkerT5.h"
|
||||
#include "Game/T5/Font/FontLoaderT5.h"
|
||||
#include "Game/T5/GameT5.h"
|
||||
#include "Game/T5/Image/ImageLoaderEmbeddedT5.h"
|
||||
#include "Game/T5/Image/ImageLoaderExternalT5.h"
|
||||
@@ -132,7 +133,7 @@ namespace
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderMapEnts>(memory));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderGfxWorld>(memory));
|
||||
collection.AddAssetCreator(light_def::CreateLoaderT5(memory, searchPath));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderFont>(memory));
|
||||
collection.AddAssetCreator(font::CreateLoaderT5(memory, searchPath));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderMenuList>(memory));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderMenu>(memory));
|
||||
collection.AddAssetCreator(localize::CreateLoaderT5(memory, searchPath, zone));
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
#options GAME (IW3, IW4, IW5, T4, T5)
|
||||
|
||||
#filename "Game/" + GAME + "/Font/FontDumper" + GAME + ".cpp"
|
||||
|
||||
#if GAME == "IW3"
|
||||
#define GAME_LOWER "iw3"
|
||||
#elif GAME == "IW4"
|
||||
#define GAME_LOWER "iw4"
|
||||
#elif GAME == "IW5"
|
||||
#define GAME_LOWER "iw5"
|
||||
#elif GAME == "T4"
|
||||
#define GAME_LOWER "t4"
|
||||
#elif GAME == "T5"
|
||||
#define GAME_LOWER "t5"
|
||||
#endif
|
||||
|
||||
// This file was templated.
|
||||
// See FontDumper.cpp.template.
|
||||
// Do not modify, changes will be lost.
|
||||
|
||||
#set DUMPER_HEADER "\"FontDumper" + GAME + ".h\""
|
||||
#include DUMPER_HEADER
|
||||
|
||||
#include "Font/FontCommon.h"
|
||||
#set JSON_HEADER "\"Game/" + GAME + "/Font/JsonFont" + GAME + ".h\""
|
||||
#include JSON_HEADER
|
||||
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using namespace nlohmann;
|
||||
using namespace GAME;
|
||||
|
||||
#set CLASS_NAME "JsonDumper" + GAME
|
||||
|
||||
namespace
|
||||
{
|
||||
const char* AssetName(const char* input)
|
||||
{
|
||||
if (input && input[0] == ',')
|
||||
return &input[1];
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
void CreateJsonGlyph(JsonGlyph& jGlyph, const Glyph& glyph)
|
||||
{
|
||||
jGlyph.letter = glyph.letter;
|
||||
jGlyph.x0 = glyph.x0;
|
||||
jGlyph.y0 = glyph.y0;
|
||||
jGlyph.dx = glyph.dx;
|
||||
jGlyph.pixelWidth = glyph.pixelWidth;
|
||||
jGlyph.pixelHeight = glyph.pixelHeight;
|
||||
jGlyph.s0 = glyph.s0;
|
||||
jGlyph.t0 = glyph.t0;
|
||||
jGlyph.s1 = glyph.s1;
|
||||
jGlyph.t1 = glyph.t1;
|
||||
}
|
||||
|
||||
void CreateJsonFont(JsonFont& jFont, const Font_s& font)
|
||||
{
|
||||
jFont.pixelHeight = font.pixelHeight;
|
||||
|
||||
if (font.material && font.material->info.name)
|
||||
jFont.material = AssetName(font.material->info.name);
|
||||
|
||||
if (font.glowMaterial && font.glowMaterial->info.name)
|
||||
jFont.glowMaterial = AssetName(font.glowMaterial->info.name);
|
||||
|
||||
if (font.glyphs == nullptr || font.glyphCount <= 0)
|
||||
return;
|
||||
|
||||
jFont.glyphs.resize(font.glyphCount);
|
||||
for (auto i = 0; i < font.glyphCount; i++)
|
||||
CreateJsonGlyph(jFont.glyphs[i], font.glyphs[i]);
|
||||
}
|
||||
|
||||
class Dumper
|
||||
{
|
||||
public:
|
||||
explicit Dumper(std::ostream& stream)
|
||||
: m_stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
void Dump(const Font_s& font) const
|
||||
{
|
||||
JsonFont jFont;
|
||||
CreateJsonFont(jFont, font);
|
||||
|
||||
ordered_json jRoot;
|
||||
jRoot["$schema"] = "http://openassettools.dev/schema/font.v1.json";
|
||||
jRoot["_type"] = "font";
|
||||
jRoot["_version"] = 1;
|
||||
jRoot["_game"] = GAME_LOWER;
|
||||
|
||||
jRoot.merge_patch(jFont);
|
||||
|
||||
m_stream << std::setw(4) << jRoot << "\n";
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream& m_stream;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace font
|
||||
{
|
||||
void CLASS_NAME::DumpAsset(AssetDumpingContext& context, const XAssetInfo<AssetFont::Type>& asset)
|
||||
{
|
||||
const auto assetFile = context.OpenAssetFile(GetJsonFileNameForAssetName(asset.m_name));
|
||||
|
||||
if (!assetFile)
|
||||
return;
|
||||
|
||||
Dumper dumper(*assetFile);
|
||||
dumper.Dump(*asset.Asset());
|
||||
}
|
||||
} // namespace font
|
||||
@@ -0,0 +1,25 @@
|
||||
#options GAME (IW3, IW4, IW5, T4, T5)
|
||||
|
||||
#filename "Game/" + GAME + "/Font/FontDumper" + GAME + ".h"
|
||||
|
||||
// This file was templated.
|
||||
// See FontDumper.h.template.
|
||||
// Do not modify, changes will be lost.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Dumping/AbstractAssetDumper.h"
|
||||
#include "Dumping/AssetDumpingContext.h"
|
||||
#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\""
|
||||
#include GAME_HEADER
|
||||
|
||||
#set CLASS_NAME "JsonDumper" + GAME
|
||||
|
||||
namespace font
|
||||
{
|
||||
class CLASS_NAME final : public AbstractAssetDumper<GAME::AssetFont>
|
||||
{
|
||||
protected:
|
||||
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<GAME::AssetFont::Type>& asset) override;
|
||||
};
|
||||
} // namespace font
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "ObjWriterIW3.h"
|
||||
|
||||
#include "Game/IW3/Font/FontDumperIW3.h"
|
||||
#include "Game/IW3/Image/ImageDumperIW3.h"
|
||||
#include "Game/IW3/Material/MaterialJsonDumperIW3.h"
|
||||
#include "Game/IW3/Techset/TechsetDumperIW3.h"
|
||||
@@ -41,7 +42,7 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context)
|
||||
RegisterAssetDumper(std::make_unique<map_ents::DumperIW3>());
|
||||
// REGISTER_DUMPER(AssetDumperGfxWorld)
|
||||
RegisterAssetDumper(std::make_unique<light_def::DumperIW3>());
|
||||
// REGISTER_DUMPER(AssetDumperFont_s)
|
||||
RegisterAssetDumper(std::make_unique<font::JsonDumperIW3>());
|
||||
// REGISTER_DUMPER(AssetDumperMenuList)
|
||||
// REGISTER_DUMPER(AssetDumpermenuDef_t)
|
||||
RegisterAssetDumper(std::make_unique<localize::DumperIW3>());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "ObjWriterIW4.h"
|
||||
|
||||
#include "Game/IW4/Font/FontDumperIW4.h"
|
||||
#include "Game/IW4/Image/ImageDumperIW4.h"
|
||||
#include "Game/IW4/Material/MaterialJsonDumperIW4.h"
|
||||
#include "Game/IW4/Techset/PixelShaderDumperIW4.h"
|
||||
@@ -58,7 +59,7 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context)
|
||||
// REGISTER_DUMPER(AssetDumperFxWorld)
|
||||
// REGISTER_DUMPER(AssetDumperGfxWorld)
|
||||
RegisterAssetDumper(std::make_unique<light_def::DumperIW4>());
|
||||
// REGISTER_DUMPER(AssetDumperFont_s)
|
||||
RegisterAssetDumper(std::make_unique<font::JsonDumperIW4>());
|
||||
RegisterAssetDumper(std::make_unique<menu::MenuListDumperIW4>());
|
||||
RegisterAssetDumper(std::make_unique<menu::MenuDumperIW4>());
|
||||
RegisterAssetDumper(std::make_unique<localize::DumperIW4>());
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "ObjWriterIW5.h"
|
||||
|
||||
#include "Game/IW4/XAnim/XAnimDumperIW4.h"
|
||||
#include "Game/IW5/Font/FontDumperIW5.h"
|
||||
#include "Game/IW5/Image/ImageDumperIW5.h"
|
||||
#include "Game/IW5/Material/MaterialJsonDumperIW5.h"
|
||||
#include "Game/IW5/Techset/PixelShaderDumperIW5.h"
|
||||
@@ -53,7 +54,7 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context)
|
||||
// REGISTER_DUMPER(AssetDumperFxWorld)
|
||||
// REGISTER_DUMPER(AssetDumperGfxWorld)
|
||||
RegisterAssetDumper(std::make_unique<light_def::DumperIW5>());
|
||||
// REGISTER_DUMPER(AssetDumperFont_s)
|
||||
RegisterAssetDumper(std::make_unique<font::JsonDumperIW5>());
|
||||
RegisterAssetDumper(std::make_unique<menu::MenuListDumperIW5>());
|
||||
RegisterAssetDumper(std::make_unique<menu::MenuDumperIW5>());
|
||||
RegisterAssetDumper(std::make_unique<localize::DumperIW5>());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "ObjWriterT4.h"
|
||||
|
||||
#include "Game/T4/Font/FontDumperT4.h"
|
||||
#include "Game/T4/Image/ImageDumperT4.h"
|
||||
#include "Game/T4/XAnim/XAnimDumperT4.h"
|
||||
#include "Game/T4/XModel/XModelDumperT4.h"
|
||||
@@ -19,6 +20,7 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context)
|
||||
RegisterAssetDumper(std::make_unique<image::DumperT4>());
|
||||
RegisterAssetDumper(std::make_unique<sound::LoadedSoundDumperT4>());
|
||||
RegisterAssetDumper(std::make_unique<map_ents::DumperT4>());
|
||||
RegisterAssetDumper(std::make_unique<font::JsonDumperT4>());
|
||||
RegisterAssetDumper(std::make_unique<localize::DumperT4>());
|
||||
RegisterAssetDumper(std::make_unique<weapon::DumperT4>());
|
||||
RegisterAssetDumper(std::make_unique<raw_file::DumperT4>());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "ObjWriterT5.h"
|
||||
|
||||
#include "Game/T5/Font/FontDumperT5.h"
|
||||
#include "Game/T5/Image/ImageDumperT5.h"
|
||||
#include "Game/T5/Material/MaterialJsonDumperT5.h"
|
||||
#include "Game/T5/Techset/TechsetDumperT5.h"
|
||||
@@ -39,7 +40,7 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context)
|
||||
// REGISTER_DUMPER(AssetDumperMapEnts, m_map_ents)
|
||||
// REGISTER_DUMPER(AssetDumperGfxWorld, m_gfx_world)
|
||||
RegisterAssetDumper(std::make_unique<light_def::DumperT5>());
|
||||
// REGISTER_DUMPER(AssetDumperFont, m_font)
|
||||
RegisterAssetDumper(std::make_unique<font::JsonDumperT5>());
|
||||
// REGISTER_DUMPER(AssetDumperMenuList, m_menu_list)
|
||||
// REGISTER_DUMPER(AssetDumperMenuDef, m_menu_def)
|
||||
RegisterAssetDumper(std::make_unique<localize::DumperT5>());
|
||||
|
||||
@@ -53,17 +53,21 @@ namespace nlohmann
|
||||
}
|
||||
} // namespace nlohmann
|
||||
|
||||
#define NLOHMANN_TO_JSON_METHOD(Type) \
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
inline void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t)
|
||||
|
||||
#define NLOHMANN_FROM_JSON_METHOD(Type) \
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
inline void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t)
|
||||
|
||||
#define EXTEND_JSON_TO(v1) extended_to_json(#v1, nlohmann_json_j, nlohmann_json_t.v1);
|
||||
#define EXTEND_JSON_FROM(v1) extended_from_json(#v1, nlohmann_json_j, nlohmann_json_t.v1);
|
||||
|
||||
#define NLOHMANN_DEFINE_TYPE_EXTENSION(Type, ...) \
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
inline void to_json(BasicJsonType& nlohmann_json_j, const Type& nlohmann_json_t) \
|
||||
{ \
|
||||
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(EXTEND_JSON_TO, __VA_ARGS__)) \
|
||||
} \
|
||||
template<typename BasicJsonType, nlohmann::detail::enable_if_t<nlohmann::detail::is_basic_json<BasicJsonType>::value, int> = 0> \
|
||||
inline void from_json(const BasicJsonType& nlohmann_json_j, Type& nlohmann_json_t) \
|
||||
NLOHMANN_TO_JSON_METHOD(Type){NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(EXTEND_JSON_TO, __VA_ARGS__))} \
|
||||
\
|
||||
NLOHMANN_FROM_JSON_METHOD(Type) \
|
||||
{ \
|
||||
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(EXTEND_JSON_FROM, __VA_ARGS__)) \
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user