Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/SupportedAssetTypes.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The following section specify which assets are supported to be dumped to disk (u
| MapEnts | ✅ | ❌ | |
| GfxWorld | ❌ | ❌ | |
| GfxLightDef | ❌ | ❌ | |
| Font_s | | | |
| Font_s | | | |
| MenuList | ❌ | ❌ | |
| menuDef_t | ❌ | ❌ | |
| LocalizeEntry | ✅ | ✅ | |
Expand Down Expand Up @@ -62,7 +62,7 @@ The following section specify which assets are supported to be dumped to disk (u
| 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 | ✅ | ✅ | |
Expand Down Expand Up @@ -104,7 +104,7 @@ The following section specify which assets are supported to be dumped to disk (u
| 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 | ✅ | ✅ | |
Expand Down Expand Up @@ -143,7 +143,7 @@ The following section specify which assets are supported to be dumped to disk (u
| MapEnts | ❌ | ❌ | |
| GfxWorld | ❌ | ❌ | |
| GfxLightDef | ❌ | ❌ | |
| Font_s | | | |
| Font_s | | | |
| MenuList | ❌ | ❌ | |
| menuDef_t | ❌ | ❌ | |
| LocalizeEntry | ✅ | ✅ | |
Expand Down
134 changes: 134 additions & 0 deletions src/ObjLoading/Game/IW3/Font/AssetLoaderFontIW3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#include "AssetLoaderFontIW3.h"
#include "Game/IW3/IW3.h"
Comment on lines +1 to +2

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The project uses clang-format for formatting. You should be able to configure clang-format as formatter in most IDEs.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay i'm try add it formatter in visual studio, vs always used own standard 🤣

#include "Utils/Logging/Log.h"

#include <nlohmann/json.hpp>
#include <cstring>
#include <format>

using namespace IW3;

namespace
{
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(std::format("{}.json", assetName));

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What other assets do is having a "common" file in the "ObjCommon" component that returns the file name for an asset, e.g. MaterialCommon.h.

This makes it possible to have a single source of truth for the filename pattern that is shared between dumpers and loaders.

if (!file.IsOpen())
return AssetCreationResult::NoAction();

auto* font = m_memory.Alloc<Font_s>();
std::memset(font, 0, sizeof(Font_s));

AssetRegistration<AssetFont> registration(assetName, font);

if (!LoadFromJson(*file.m_stream, *font, context, registration))
{
con::error("Failed to load font \"{}\"", assetName);
return AssetCreationResult::Failure();
}

return AssetCreationResult::Success(context.AddAsset(std::move(registration)));
}

private:
bool LoadFromJson(std::istream& jsonStream, Font_s& font, AssetCreationContext& context, AssetRegistration<AssetFont>& registration)
{
try
{
const auto jRoot = nlohmann::json::parse(jsonStream);

std::string type;
jRoot.at("_type").get_to(type);

if (type != "font")
{
con::error("Tried to load font but did not find expected type 'font'");
return false;
}

font.pixelHeight = jRoot.value("pixelHeight", 0);
font.glyphCount = jRoot.value("glyphCount", 0);
Comment on lines +58 to +59

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This project uses the arbitrary type conversions feature of nlohmann json, e.g. see JsonLeaderboardDef.h for the types and JsonLoaderFontIconT6.cpp on them getting used.

Makes the loading code less verbose, prone to errors and makes the target format clearer in code imo.

Would be nice to not have this be an outlier in what style it uses😅

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like your usage of ordered_json and i noticed that the extensions for arbitrary type conversions for nlohmann json i defined only support the normal json and not ordered_json. I got to fix that i guess 😅

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did this here: #746 if you wanna use ordered_json still with arbitrary type conversions, feel free to rebase on main when its merged


std::string fontName = jRoot.value("name", "");

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name part of the font asset should be taken from the input arguments of the loader (and the "name" should not be part of the json).

Otherwise you could try to load a font asset with one name and get an entirely different name (potentially by accident because you renamed the file but not the value in it)

font.fontName = m_memory.Dup(fontName.c_str());

if (jRoot.contains("material") && !jRoot["material"].is_null())
{
std::string matName = jRoot["material"];
auto* matInfo = context.LoadDependency<AssetMaterial>(matName);
if (!matInfo)
{
con::error("Font \"{}\" missing dependency material \"{}\"", font.fontName, matName);
return false;
}
registration.AddDependency(matInfo);
font.material = matInfo->Asset();
}

if (jRoot.contains("glowMaterial") && !jRoot["glowMaterial"].is_null())
{
std::string glowMatName = jRoot["glowMaterial"];
auto* glowMatInfo = context.LoadDependency<AssetMaterial>(glowMatName);
if (glowMatInfo)
{
registration.AddDependency(glowMatInfo);
font.glowMaterial = glowMatInfo->Asset();
}
}

if (font.glyphCount > 0 && jRoot.contains("glyphs"))
{
const auto& jGlyphs = jRoot["glyphs"];
font.glyphs = m_memory.Alloc<Glyph>(font.glyphCount);

for (int i = 0; i < font.glyphCount; ++i)
{
const auto& jG = jGlyphs[i];
auto& g = font.glyphs[i];

g.letter = jG.value("letter", 0);

g.x0 = static_cast<char>(jG.value("x0", 0));
g.y0 = static_cast<char>(jG.value("y0", 0));
g.dx = static_cast<char>(jG.value("dx", 0));
g.pixelWidth = static_cast<char>(jG.value("width", 0));
g.pixelHeight = static_cast<char>(jG.value("height", 0));
Comment on lines +102 to +104

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made a mistake on the game types here, dx, width and height should be unsigned char (applies to all games).


g.s0 = jG.value("s0", 0.0f);
g.t0 = jG.value("t0", 0.0f);
g.s1 = jG.value("s1", 0.0f);
g.t1 = jG.value("t1", 0.0f);
}
}

return true;
}
catch (const nlohmann::json::exception& e)
{
con::error("Failed to parse json of font: {}", e.what());
}

return false;
}

MemoryManager& m_memory;
ISearchPath& m_search_path;
};
} // namespace

namespace font
{
std::unique_ptr<AssetCreator<AssetFont>> CreateLoaderIW3(MemoryManager& memory, ISearchPath& searchPath)
{
return std::make_unique<FontLoader>(memory, searchPath);
}
} // namespace font
13 changes: 13 additions & 0 deletions src/ObjLoading/Game/IW3/Font/AssetLoaderFontIW3.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include "Asset/IAssetCreator.h"
#include "Game/IW3/IW3.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"

#include <memory>

namespace font
{
std::unique_ptr<AssetCreator<IW3::AssetFont>> CreateLoaderIW3(MemoryManager& memory, ISearchPath& searchPath);
} // namespace font
3 changes: 2 additions & 1 deletion src/ObjLoading/Game/IW3/ObjLoaderIW3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "ObjLoading.h"
#include "RawFile/AssetLoaderRawFileIW3.h"
#include "StringTable/AssetLoaderStringTableIW3.h"
#include "Font/AssetLoaderFontIW3.h"

#include <memory>

Expand Down Expand Up @@ -110,7 +111,7 @@ namespace
// collection.AddAssetCreator(std::make_unique<AssetLoaderMapEnts>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderGfxWorld>(memory));
// collection.AddAssetCreator(std::make_unique<AssetLoaderLightDef>(memory));
// 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));
Expand Down
134 changes: 134 additions & 0 deletions src/ObjLoading/Game/IW4/Font/AssetLoaderFontIW4.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
#include "AssetLoaderFontIW4.h"
#include "Game/IW4/IW4.h"
#include "Utils/Logging/Log.h"

#include <nlohmann/json.hpp>
#include <cstring>
#include <format>

using namespace IW4;

namespace
{
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(std::format("{}.json", assetName));
if (!file.IsOpen())
return AssetCreationResult::NoAction();

auto* font = m_memory.Alloc<Font_s>();
std::memset(font, 0, sizeof(Font_s));

AssetRegistration<AssetFont> registration(assetName, font);

if (!LoadFromJson(*file.m_stream, *font, context, registration))
{
con::error("Failed to load font \"{}\"", assetName);
return AssetCreationResult::Failure();
}

return AssetCreationResult::Success(context.AddAsset(std::move(registration)));
}

private:
bool LoadFromJson(std::istream& jsonStream, Font_s& font, AssetCreationContext& context, AssetRegistration<AssetFont>& registration)
{
try
{
const auto jRoot = nlohmann::json::parse(jsonStream);

std::string type;
jRoot.at("_type").get_to(type);

if (type != "font")
{
con::error("Tried to load font but did not find expected type 'font'");
return false;
}

font.pixelHeight = jRoot.value("pixelHeight", 0);
font.glyphCount = jRoot.value("glyphCount", 0);

std::string fontName = jRoot.value("name", "");
font.fontName = m_memory.Dup(fontName.c_str());

if (jRoot.contains("material") && !jRoot["material"].is_null())
{
std::string matName = jRoot["material"];
auto* matInfo = context.LoadDependency<AssetMaterial>(matName);
if (!matInfo)
{
con::error("Font \"{}\" missing dependency material \"{}\"", font.fontName, matName);
return false;
}
registration.AddDependency(matInfo);
font.material = matInfo->Asset();
}

if (jRoot.contains("glowMaterial") && !jRoot["glowMaterial"].is_null())
{
std::string glowMatName = jRoot["glowMaterial"];
auto* glowMatInfo = context.LoadDependency<AssetMaterial>(glowMatName);
if (glowMatInfo)
{
registration.AddDependency(glowMatInfo);
font.glowMaterial = glowMatInfo->Asset();
}
}

if (font.glyphCount > 0 && jRoot.contains("glyphs"))
{
const auto& jGlyphs = jRoot["glyphs"];
font.glyphs = m_memory.Alloc<Glyph>(font.glyphCount);

for (int i = 0; i < font.glyphCount; ++i)
{
const auto& jG = jGlyphs[i];
auto& g = font.glyphs[i];

g.letter = jG.value("letter", 0);

g.x0 = static_cast<char>(jG.value("x0", 0));
g.y0 = static_cast<char>(jG.value("y0", 0));
g.dx = static_cast<char>(jG.value("dx", 0));
g.pixelWidth = static_cast<char>(jG.value("width", 0));
g.pixelHeight = static_cast<char>(jG.value("height", 0));

g.s0 = jG.value("s0", 0.0f);
g.t0 = jG.value("t0", 0.0f);
g.s1 = jG.value("s1", 0.0f);
g.t1 = jG.value("t1", 0.0f);
}
}

return true;
}
catch (const nlohmann::json::exception& e)
{
con::error("Failed to parse json of font: {}", e.what());
}

return false;
}

MemoryManager& m_memory;
ISearchPath& m_search_path;
};
} // namespace

namespace font
{
std::unique_ptr<AssetCreator<AssetFont>> CreateLoaderIW4(MemoryManager& memory, ISearchPath& searchPath)
{
return std::make_unique<FontLoader>(memory, searchPath);
}
} // namespace font
13 changes: 13 additions & 0 deletions src/ObjLoading/Game/IW4/Font/AssetLoaderFontIW4.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once

#include "Asset/IAssetCreator.h"
#include "Game/IW4/IW4.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"

#include <memory>

namespace font
{
std::unique_ptr<AssetCreator<IW4::AssetFont>> CreateLoaderIW4(MemoryManager& memory, ISearchPath& searchPath);
} // namespace font
3 changes: 2 additions & 1 deletion src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "StructuredDataDef/LoaderStructuredDataDefIW4.h"
#include "Weapon/GdtLoaderWeaponIW4.h"
#include "Weapon/RawLoaderWeaponIW4.h"
#include "Font/AssetLoaderFontIW4.h"

#include <memory>

Expand Down Expand Up @@ -145,7 +146,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));
Expand Down
Loading
Loading