From 5b6a725f781cf9ae1ab1a63ea6a7fe39bdfe0a83 Mon Sep 17 00:00:00 2001 From: njohnson Date: Sat, 2 May 2026 14:26:17 +0200 Subject: [PATCH] feat: add t5 gfxlight dumper and loader --- docs/SupportedAssetTypes.md | 2 +- .../Game/T5/LightDef/LightDefLoaderT5.cpp | 77 +++++++++++++++++++ .../Game/T5/LightDef/LightDefLoaderT5.h | 13 ++++ src/ObjLoading/Game/T5/ObjLoaderT5.cpp | 3 +- .../Game/T5/LightDef/LightDefDumperT5.cpp | 25 ++++++ .../Game/T5/LightDef/LightDefDumperT5.h | 13 ++++ src/ObjWriting/Game/T5/ObjWriterT5.cpp | 3 +- 7 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 src/ObjLoading/Game/T5/LightDef/LightDefLoaderT5.cpp create mode 100644 src/ObjLoading/Game/T5/LightDef/LightDefLoaderT5.h create mode 100644 src/ObjWriting/Game/T5/LightDef/LightDefDumperT5.cpp create mode 100644 src/ObjWriting/Game/T5/LightDef/LightDefDumperT5.h diff --git a/docs/SupportedAssetTypes.md b/docs/SupportedAssetTypes.md index 0ee0b896..ac186e48 100644 --- a/docs/SupportedAssetTypes.md +++ b/docs/SupportedAssetTypes.md @@ -142,7 +142,7 @@ The following section specify which assets are supported to be dumped to disk (u | GameWorldMp | ❌ | ❌ | | | MapEnts | ❌ | ❌ | | | GfxWorld | ❌ | ❌ | | -| GfxLightDef | ❌ | ❌ | | +| GfxLightDef | ✅ | ✅ | | | Font_s | ❌ | ❌ | | | MenuList | ❌ | ❌ | | | menuDef_t | ❌ | ❌ | | diff --git a/src/ObjLoading/Game/T5/LightDef/LightDefLoaderT5.cpp b/src/ObjLoading/Game/T5/LightDef/LightDefLoaderT5.cpp new file mode 100644 index 00000000..0f484293 --- /dev/null +++ b/src/ObjLoading/Game/T5/LightDef/LightDefLoaderT5.cpp @@ -0,0 +1,77 @@ +#include "LightDefLoaderT5.h" + +#include "Game/T5/T5.h" +#include "LightDef/LightDefCommon.h" +#include "Utils/Logging/Log.h" + +#include +#include +#include + +using namespace T5; + +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> CreateLoaderT5(MemoryManager& memory, ISearchPath& searchPath) + { + return std::make_unique(memory, searchPath); + } +} // namespace light_def diff --git a/src/ObjLoading/Game/T5/LightDef/LightDefLoaderT5.h b/src/ObjLoading/Game/T5/LightDef/LightDefLoaderT5.h new file mode 100644 index 00000000..2583dd21 --- /dev/null +++ b/src/ObjLoading/Game/T5/LightDef/LightDefLoaderT5.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Game/T5/T5.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +namespace light_def +{ + std::unique_ptr> CreateLoaderT5(MemoryManager& memory, ISearchPath& searchPath); +} // namespace light_def diff --git a/src/ObjLoading/Game/T5/ObjLoaderT5.cpp b/src/ObjLoading/Game/T5/ObjLoaderT5.cpp index 2c72f5c1..e39247d5 100644 --- a/src/ObjLoading/Game/T5/ObjLoaderT5.cpp +++ b/src/ObjLoading/Game/T5/ObjLoaderT5.cpp @@ -9,6 +9,7 @@ #include "Game/T5/Techset/PixelShaderLoaderT5.h" #include "Game/T5/Techset/VertexShaderLoaderT5.h" #include "Game/T5/XModel/LoaderXModelT5.h" +#include "LightDef/LightDefLoaderT5.h" #include "Localize/LoaderLocalizeT5.h" #include "Material/LoaderMaterialT5.h" #include "ObjLoading.h" @@ -125,7 +126,7 @@ namespace // 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::CreateLoaderT5(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); diff --git a/src/ObjWriting/Game/T5/LightDef/LightDefDumperT5.cpp b/src/ObjWriting/Game/T5/LightDef/LightDefDumperT5.cpp new file mode 100644 index 00000000..386a7646 --- /dev/null +++ b/src/ObjWriting/Game/T5/LightDef/LightDefDumperT5.cpp @@ -0,0 +1,25 @@ +#include "LightDefDumperT5.h" + +#include "LightDef/LightDefCommon.h" + +using namespace T5; + +namespace light_def +{ + void DumperT5::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/T5/LightDef/LightDefDumperT5.h b/src/ObjWriting/Game/T5/LightDef/LightDefDumperT5.h new file mode 100644 index 00000000..0829d63d --- /dev/null +++ b/src/ObjWriting/Game/T5/LightDef/LightDefDumperT5.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/T5/T5.h" + +namespace light_def +{ + class DumperT5 final : public AbstractAssetDumper + { + protected: + void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; + }; +} // namespace light_def diff --git a/src/ObjWriting/Game/T5/ObjWriterT5.cpp b/src/ObjWriting/Game/T5/ObjWriterT5.cpp index 4e23d39d..9250df8a 100644 --- a/src/ObjWriting/Game/T5/ObjWriterT5.cpp +++ b/src/ObjWriting/Game/T5/ObjWriterT5.cpp @@ -4,6 +4,7 @@ #include "Game/T5/Techset/TechsetDumperT5.h" #include "Game/T5/XModel/XModelDumperT5.h" #include "Image/ImageDumperT5.h" +#include "LightDef/LightDefDumperT5.h" #include "Localize/LocalizeDumperT5.h" #include "PhysPreset/PhysPresetInfoStringDumperT5.h" #include "RawFile/RawFileDumperT5.h" @@ -35,7 +36,7 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context) // REGISTER_DUMPER(AssetDumperGameWorldMp, m_game_world_mp) // REGISTER_DUMPER(AssetDumperMapEnts, m_map_ents) // REGISTER_DUMPER(AssetDumperGfxWorld, m_gfx_world) - // REGISTER_DUMPER(AssetDumperGfxLightDef, m_gfx_light_def) + RegisterAssetDumper(std::make_unique()); // REGISTER_DUMPER(AssetDumperFont, m_font) // REGISTER_DUMPER(AssetDumperMenuList, m_menu_list) // REGISTER_DUMPER(AssetDumperMenuDef, m_menu_def)