From 2b3f680d485378e6e1326c0193e51c48fde73a68 Mon Sep 17 00:00:00 2001 From: njohnson Date: Thu, 30 Apr 2026 19:27:49 -0400 Subject: [PATCH] feat: add t6 gfxlight dumper and loader --- docs/SupportedAssetTypes.md | 2 +- .../Game/T6/LightDef/LightDefLoaderT6.cpp | 77 +++++++++++++++++++ .../Game/T6/LightDef/LightDefLoaderT6.h | 13 ++++ src/ObjLoading/Game/T6/ObjLoaderT6.cpp | 3 +- .../Game/T6/LightDef/LightDefDumperT6.cpp | 25 ++++++ .../Game/T6/LightDef/LightDefDumperT6.h | 13 ++++ src/ObjWriting/Game/T6/ObjWriterT6.cpp | 3 +- 7 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 src/ObjLoading/Game/T6/LightDef/LightDefLoaderT6.cpp create mode 100644 src/ObjLoading/Game/T6/LightDef/LightDefLoaderT6.h create mode 100644 src/ObjWriting/Game/T6/LightDef/LightDefDumperT6.cpp create mode 100644 src/ObjWriting/Game/T6/LightDef/LightDefDumperT6.h diff --git a/docs/SupportedAssetTypes.md b/docs/SupportedAssetTypes.md index ac186e48..f2d9e404 100644 --- a/docs/SupportedAssetTypes.md +++ b/docs/SupportedAssetTypes.md @@ -179,7 +179,7 @@ The following section specify which assets are supported to be dumped to disk (u | GameWorldMp | ❌ | ❌ | | | MapEnts | ✅ | ❌ | | | GfxWorld | ❌ | ❌ | | -| GfxLightDef | ❌ | ❌ | | +| GfxLightDef | ✅ | ✅ | | | Font_s | ❌ | ❌ | | | FontIcon | ✅ | ✅ | | | MenuList | ❌ | ❌ | | diff --git a/src/ObjLoading/Game/T6/LightDef/LightDefLoaderT6.cpp b/src/ObjLoading/Game/T6/LightDef/LightDefLoaderT6.cpp new file mode 100644 index 00000000..a0a5e0ed --- /dev/null +++ b/src/ObjLoading/Game/T6/LightDef/LightDefLoaderT6.cpp @@ -0,0 +1,77 @@ +#include "LightDefLoaderT6.h" + +#include "Game/T6/T6.h" +#include "LightDef/LightDefCommon.h" +#include "Utils/Logging/Log.h" + +#include +#include +#include + +using namespace T6; + +namespace +{ + constexpr auto MAX_IMAGE_NAME_SIZE = 0x800; + + class LoaderLightDef final : public AssetCreator + { + public: + LoaderLightDef(MemoryManager& memory, ISearchPath& searchPath) + : m_memory(memory), + m_search_path(searchPath) + { + } + + AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override + { + const auto filename = light_def::GetFileNameForAsset(assetName); + const auto file = m_search_path.Open(filename); + if (!file.IsOpen()) + return AssetCreationResult::NoAction(); + + const auto imageNameSize = file.m_length - sizeof(char) - sizeof(char); + if (imageNameSize < 0 || imageNameSize > MAX_IMAGE_NAME_SIZE) + return AssetCreationResult::Failure(); + + auto* lightDef = m_memory.Alloc(); + lightDef->name = m_memory.Dup(assetName.c_str()); + + AssetRegistration registration(assetName, lightDef); + + std::string imageName(static_cast(imageNameSize), '\0'); + + int8_t samplerState; + int8_t lmapLookupStart; + file.m_stream->read(reinterpret_cast(&samplerState), sizeof(int8_t)); + file.m_stream->read(&imageName[0], static_cast(imageNameSize)); + file.m_stream->read(reinterpret_cast(&lmapLookupStart), sizeof(int8_t)); + + auto* imageDependency = context.LoadDependency(imageName); + if (!imageDependency) + { + con::error("Could not load GfxLightDef \"{}\" due to missing image \"{}\"", assetName, imageName); + return AssetCreationResult::Failure(); + } + registration.AddDependency(imageDependency); + + lightDef->attenuation.samplerState = samplerState; + lightDef->attenuation.image = imageDependency->Asset(); + lightDef->lmapLookupStart = static_cast(static_cast(lmapLookupStart)); + + return AssetCreationResult::Success(context.AddAsset(std::move(registration))); + } + + private: + MemoryManager& m_memory; + ISearchPath& m_search_path; + }; +} // namespace + +namespace light_def +{ + std::unique_ptr> CreateLoaderT6(MemoryManager& memory, ISearchPath& searchPath) + { + return std::make_unique(memory, searchPath); + } +} // namespace light_def diff --git a/src/ObjLoading/Game/T6/LightDef/LightDefLoaderT6.h b/src/ObjLoading/Game/T6/LightDef/LightDefLoaderT6.h new file mode 100644 index 00000000..b4377299 --- /dev/null +++ b/src/ObjLoading/Game/T6/LightDef/LightDefLoaderT6.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Game/T6/T6.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +namespace light_def +{ + std::unique_ptr> CreateLoaderT6(MemoryManager& memory, ISearchPath& searchPath); +} // namespace light_def diff --git a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp index 97c9128b..0721c573 100644 --- a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp +++ b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp @@ -17,6 +17,7 @@ #include "Image/IwiTypes.h" #include "Image/Texture.h" #include "Leaderboard/JsonLoaderLeaderboardT6.h" +#include "LightDef/LightDefLoaderT6.h" #include "Localize/LocalizeLoaderT6.h" #include "Material/LoaderMaterialT6.h" #include "ObjContainer/IPak/IPak.h" @@ -399,7 +400,7 @@ namespace T6 // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); - // collection.AddAssetCreator(std::make_unique(memory)); + collection.AddAssetCreator(light_def::CreateLoaderT6(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); collection.AddAssetCreator(font_icon::CreateCsvLoaderT6(memory, searchPath)); collection.AddAssetCreator(font_icon::CreateJsonLoaderT6(memory, searchPath)); diff --git a/src/ObjWriting/Game/T6/LightDef/LightDefDumperT6.cpp b/src/ObjWriting/Game/T6/LightDef/LightDefDumperT6.cpp new file mode 100644 index 00000000..f748e408 --- /dev/null +++ b/src/ObjWriting/Game/T6/LightDef/LightDefDumperT6.cpp @@ -0,0 +1,25 @@ +#include "LightDefDumperT6.h" + +#include "LightDef/LightDefCommon.h" + +using namespace T6; + +namespace light_def +{ + void DumperT6::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) + { + const auto* lightDef = asset.Asset(); + const auto assetFile = context.OpenAssetFile(GetFileNameForAsset(asset.m_name)); + + if (!assetFile || lightDef->attenuation.image == nullptr || lightDef->attenuation.image->name == nullptr) + return; + + auto& stream = *assetFile; + + const auto* imageName = lightDef->attenuation.image->name; + if (imageName[0] == ',') + imageName = &imageName[1]; + + stream << lightDef->attenuation.samplerState << imageName << static_cast(lightDef->lmapLookupStart); + } +} // namespace light_def diff --git a/src/ObjWriting/Game/T6/LightDef/LightDefDumperT6.h b/src/ObjWriting/Game/T6/LightDef/LightDefDumperT6.h new file mode 100644 index 00000000..eddd5289 --- /dev/null +++ b/src/ObjWriting/Game/T6/LightDef/LightDefDumperT6.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/T6/T6.h" + +namespace light_def +{ + class DumperT6 final : public AbstractAssetDumper + { + protected: + void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; + }; +} // namespace light_def diff --git a/src/ObjWriting/Game/T6/ObjWriterT6.cpp b/src/ObjWriting/Game/T6/ObjWriterT6.cpp index f4d09da2..aa3cb9b1 100644 --- a/src/ObjWriting/Game/T6/ObjWriterT6.cpp +++ b/src/ObjWriting/Game/T6/ObjWriterT6.cpp @@ -6,6 +6,7 @@ #include "Game/T6/XModel/XModelDumperT6.h" #include "Image/ImageDumperT6.h" #include "Leaderboard/LeaderboardJsonDumperT6.h" +#include "LightDef/LightDefDumperT6.h" #include "Localize/LocalizeDumperT6.h" #include "Maps/MapEntsDumperT6.h" #include "PhysConstraints/PhysConstraintsInfoStringDumperT6.h" @@ -51,7 +52,7 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context) // REGISTER_DUMPER(AssetDumperGameWorldMp, m_game_world_mp) RegisterAssetDumper(std::make_unique()); // REGISTER_DUMPER(AssetDumperGfxWorld, m_gfx_world) - // REGISTER_DUMPER(AssetDumperGfxLightDef, m_gfx_light_def) + RegisterAssetDumper(std::make_unique()); // REGISTER_DUMPER(AssetDumperFont, m_font) RegisterAssetDumper(font_icon::CreateDumperT6()); // REGISTER_DUMPER(AssetDumperMenuList, m_menu_list)