diff --git a/src/Common/Game/IW4/IW4_Assets.h b/src/Common/Game/IW4/IW4_Assets.h index 4406002e..b2522c34 100644 --- a/src/Common/Game/IW4/IW4_Assets.h +++ b/src/Common/Game/IW4/IW4_Assets.h @@ -1878,6 +1878,29 @@ namespace IW4 FxElemDef* elemDefs; }; + enum SamplerStateBits_e + { + SAMPLER_FILTER_SHIFT = 0x0, + SAMPLER_FILTER_NEAREST = 0x1, + SAMPLER_FILTER_LINEAR = 0x2, + SAMPLER_FILTER_ANISO2X = 0x3, + SAMPLER_FILTER_ANISO4X = 0x4, + SAMPLER_FILTER_MASK = 0x7, + SAMPLER_MIPMAP_SHIFT = 0x3, + SAMPLER_MIPMAP_DISABLED = 0x0, + SAMPLER_MIPMAP_NEAREST = 0x8, + SAMPLER_MIPMAP_LINEAR = 0x10, + SAMPLER_MIPMAP_COUNT = 0x3, + SAMPLER_MIPMAP_MASK = 0x18, + SAMPLER_CLAMP_U_SHIFT = 0x5, + SAMPLER_CLAMP_V_SHIFT = 0x6, + SAMPLER_CLAMP_W_SHIFT = 0x7, + SAMPLER_CLAMP_U = 0x20, + SAMPLER_CLAMP_V = 0x40, + SAMPLER_CLAMP_W = 0x80, + SAMPLER_CLAMP_MASK = 0xE0, + }; + struct GfxLightImage { GfxImage* image; diff --git a/src/Common/Game/T5/T5_Assets.h b/src/Common/Game/T5/T5_Assets.h index 531104ce..35c9eba8 100644 --- a/src/Common/Game/T5/T5_Assets.h +++ b/src/Common/Game/T5/T5_Assets.h @@ -2428,6 +2428,43 @@ namespace T5 GfxHeroLightTree* heroLightTree; }; + enum SamplerStateBits_e + { + SAMPLER_FILTER_SHIFT = 0x0, + SAMPLER_FILTER_NEAREST = 0x1, + SAMPLER_FILTER_LINEAR = 0x2, + SAMPLER_FILTER_ANISO2X = 0x3, + SAMPLER_FILTER_ANISO4X = 0x4, + SAMPLER_FILTER_MASK = 0x7, + SAMPLER_MIPMAP_SHIFT = 0x3, + SAMPLER_MIPMAP_DISABLED = 0x0, + SAMPLER_MIPMAP_NEAREST = 0x8, + SAMPLER_MIPMAP_LINEAR = 0x10, + SAMPLER_MIPMAP_COUNT = 0x3, + SAMPLER_MIPMAP_MASK = 0x18, + SAMPLER_CLAMP_U_SHIFT = 0x5, + SAMPLER_CLAMP_V_SHIFT = 0x6, + SAMPLER_CLAMP_W_SHIFT = 0x7, + SAMPLER_CLAMP_U = 0x20, + SAMPLER_CLAMP_V = 0x40, + SAMPLER_CLAMP_W = 0x80, + SAMPLER_CLAMP_MASK = 0xE0, + SAMPLER_ANISO_SHIFT = 0x8, + SAMPLER_ANISO_1X = 0x0, + SAMPLER_ANISO_2X = 0x100, + SAMPLER_ANISO_4X = 0x200, + SAMPLER_ANISO_6X = 0x300, + SAMPLER_ANISO_8X = 0x400, + SAMPLER_ANISO_10X = 0x500, + SAMPLER_ANISO_12X = 0x600, + SAMPLER_ANISO_16X = 0x700, + SAMPLER_ANISO_MASK = 0x700, + SAMPLER_CONVOLUTION = 0x20000, + SAMPLER_GAMMA = 0x40000, + SAMPLER_UNNORMALIZED_UV = 0x80000, + SAMPLER_DIRECT_FILTER_UNNORMALIZED = 0x80000, + }; + struct GfxLightImage { GfxImage* image; diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderGfxLightDef.cpp b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderGfxLightDef.cpp index 2f16d842..aedfd2d9 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderGfxLightDef.cpp +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderGfxLightDef.cpp @@ -1,6 +1,8 @@ #include "AssetLoaderGfxLightDef.h" #include +#include +#include #include "ObjLoading.h" #include "Game/IW4/IW4.h" @@ -8,6 +10,15 @@ using namespace IW4; +std::string AssetLoaderGfxLightDef::GetAssetFilename(const std::string& assetName) +{ + std::ostringstream ss; + + ss << "lights/" << assetName; + + return ss.str(); +} + void* AssetLoaderGfxLightDef::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) { auto* lightDef = memory->Create(); @@ -15,3 +26,46 @@ void* AssetLoaderGfxLightDef::CreateEmptyAsset(const std::string& assetName, Mem lightDef->name = memory->Dup(assetName.c_str()); return lightDef; } + +bool AssetLoaderGfxLightDef::CanLoadFromRaw() const +{ + return true; +} + +bool AssetLoaderGfxLightDef::LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const +{ + const auto filename = GetAssetFilename(assetName); + const auto file = searchPath->Open(filename); + if (!file.IsOpen()) + return false; + + const auto imageNameSize = file.m_length - sizeof(char) - sizeof(char); + if (imageNameSize < 0 || imageNameSize > MAX_IMAGE_NAME_SIZE) + return false; + + 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 = reinterpret_cast*>(manager->LoadDependency(ASSET_TYPE_IMAGE, imageName)); + + if(!imageDependency) + { + std::cerr << "Could not load GfxLightDef \"" << assetName << "\" due to missing image \"" << imageName << "\"\n"; + return false; + } + + auto* lightDef = memory->Create(); + lightDef->name = memory->Dup(assetName.c_str()); + lightDef->attenuation.samplerState = samplerState; + lightDef->attenuation.image = imageDependency->Asset(); + lightDef->lmapLookupStart = static_cast(static_cast(lmapLookupStart)); + + manager->AddAsset(ASSET_TYPE_LIGHT_DEF, assetName, lightDef); + + return true; +} diff --git a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderGfxLightDef.h b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderGfxLightDef.h index 133f0d5d..e593fc3e 100644 --- a/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderGfxLightDef.h +++ b/src/ObjLoading/Game/IW4/AssetLoaders/AssetLoaderGfxLightDef.h @@ -8,7 +8,13 @@ namespace IW4 { class AssetLoaderGfxLightDef final : public BasicAssetLoader { + static constexpr auto MAX_IMAGE_NAME_SIZE = 0x800; + + static std::string GetAssetFilename(const std::string& assetName); + public: _NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override; + _NODISCARD bool CanLoadFromRaw() const override; + bool LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; }; } diff --git a/src/ObjLoading/Game/IW4/Menu/MenuConverterIW4.cpp b/src/ObjLoading/Game/IW4/Menu/MenuConverterIW4.cpp index e6b822cd..bda9bd69 100644 --- a/src/ObjLoading/Game/IW4/Menu/MenuConverterIW4.cpp +++ b/src/ObjLoading/Game/IW4/Menu/MenuConverterIW4.cpp @@ -648,6 +648,9 @@ namespace IW4 std::vector elements; ConvertEventHandlerElements(elements, eventHandlerSet, menu, item); + if (elements.empty()) + return nullptr; + auto* outputSet = static_cast(m_memory->Alloc(sizeof(MenuEventHandlerSet) + sizeof(void*) * elements.size())); auto* outputElements = reinterpret_cast(reinterpret_cast(outputSet) + sizeof(MenuEventHandlerSet)); memcpy(outputElements, &elements[0], sizeof(void*) * elements.size()); diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperGfxLightDef.cpp b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperGfxLightDef.cpp new file mode 100644 index 00000000..af05c62d --- /dev/null +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperGfxLightDef.cpp @@ -0,0 +1,36 @@ +#include "AssetDumperGfxLightDef.h" + +#include + +using namespace IW4; + +std::string AssetDumperGfxLightDef::GetAssetFilename(const std::string& assetName) +{ + std::ostringstream ss; + + ss << "lights/" << assetName; + + return ss.str(); +} + +bool AssetDumperGfxLightDef::ShouldDump(XAssetInfo* asset) +{ + return true; +} + +void AssetDumperGfxLightDef::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) +{ + const auto* lightDef = asset->Asset(); + const auto assetFile = context.OpenAssetFile(GetAssetFilename(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); +} diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperGfxLightDef.h b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperGfxLightDef.h new file mode 100644 index 00000000..9ac70751 --- /dev/null +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperGfxLightDef.h @@ -0,0 +1,16 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/IW4/IW4.h" + +namespace IW4 +{ + class AssetDumperGfxLightDef final : public AbstractAssetDumper + { + static std::string GetAssetFilename(const std::string& assetName); + + protected: + bool ShouldDump(XAssetInfo* asset) override; + void DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) override; + }; +} diff --git a/src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp b/src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp index 01b6fb76..52da4a6a 100644 --- a/src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp +++ b/src/ObjWriting/Game/IW4/ZoneDumperIW4.cpp @@ -6,6 +6,7 @@ #include "AssetDumpers/AssetDumperAddonMapEnts.h" #include "AssetDumpers/AssetDumperGfxImage.h" +#include "AssetDumpers/AssetDumperGfxLightDef.h" #include "AssetDumpers/AssetDumperLoadedSound.h" #include "AssetDumpers/AssetDumperLocalizeEntry.h" #include "AssetDumpers/AssetDumperMenuDef.h" @@ -56,7 +57,7 @@ bool ZoneDumper::DumpZone(AssetDumpingContext& context) const // DUMP_ASSET_POOL(AssetDumperMapEnts, m_map_ents, ASSET_TYPE_MAP_ENTS) // DUMP_ASSET_POOL(AssetDumperFxWorld, m_fx_world, ASSET_TYPE_FXWORLD) // DUMP_ASSET_POOL(AssetDumperGfxWorld, m_gfx_world, ASSET_TYPE_GFXWORLD) - // DUMP_ASSET_POOL(AssetDumperGfxLightDef, m_gfx_light_def, ASSET_TYPE_LIGHT_DEF) + DUMP_ASSET_POOL(AssetDumperGfxLightDef, m_gfx_light_def, ASSET_TYPE_LIGHT_DEF) // DUMP_ASSET_POOL(AssetDumperFont_s, m_font, ASSET_TYPE_FONT) DUMP_ASSET_POOL(AssetDumperMenuList, m_menu_list, ASSET_TYPE_MENULIST) DUMP_ASSET_POOL(AssetDumperMenuDef, m_menu_def, ASSET_TYPE_MENU)