From c385f50a0ec9336e06d3f133174850e0531a3e49 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Wed, 8 Jul 2026 22:50:22 +0200 Subject: [PATCH] feat: add support for t4 materials (#891) * feat: add support for t4 materials * fix: t4 material struct --- docs/SupportedAssetTypes.md | 2 +- src/Common/Game/T4/T4_Assets.h | 48 ++-- .../Material/JsonMaterial.h.template | 27 +- .../Game/T4/Material/LoaderMaterialT4.cpp | 55 ++++ .../Game/T4/Material/LoaderMaterialT4.h | 12 + src/ObjLoading/Game/T4/ObjLoaderT4.cpp | 2 + .../Material/JsonMaterialLoader.cpp.template | 14 +- .../Material/JsonMaterialLoader.h.template | 2 +- .../Material/MaterialConstantZoneStateT4.cpp | 249 ++++++++++++++++++ .../T4/Material/MaterialConstantZoneStateT4.h | 18 ++ src/ObjWriting/Game/T4/ObjWriterT4.cpp | 2 + .../Material/MaterialJsonDumper.cpp.template | 14 +- .../Material/MaterialJsonDumper.h.template | 2 +- 13 files changed, 402 insertions(+), 45 deletions(-) create mode 100644 src/ObjLoading/Game/T4/Material/LoaderMaterialT4.cpp create mode 100644 src/ObjLoading/Game/T4/Material/LoaderMaterialT4.h create mode 100644 src/ObjWriting/Game/T4/Material/MaterialConstantZoneStateT4.cpp create mode 100644 src/ObjWriting/Game/T4/Material/MaterialConstantZoneStateT4.h diff --git a/docs/SupportedAssetTypes.md b/docs/SupportedAssetTypes.md index ba68702d..fcd3ec1a 100644 --- a/docs/SupportedAssetTypes.md +++ b/docs/SupportedAssetTypes.md @@ -132,7 +132,7 @@ using `Linker`): | DestructibleDef | ❌ | ❌ | | | XAnimParts | ✅ | ✅ | | | XModel | ✅ | ❌ | Model data can be exported to `XMODEL_EXPORT/XMODEL_BIN`, `OBJ`, `GLB/GLTF`. | -| Material | ❌ | ❌ | | +| Material | ✅ | ✅ | | | MaterialTechniqueSet | ❌ | ❌ | | | GfxImage | ✅ | ✅ | A few special image encodings are not yet supported. | | snd_alias_list_t | ❌ | ❌ | | diff --git a/src/Common/Game/T4/T4_Assets.h b/src/Common/Game/T4/T4_Assets.h index 3f3d5161..064ade88 100644 --- a/src/Common/Game/T4/T4_Assets.h +++ b/src/Common/Game/T4/T4_Assets.h @@ -1046,6 +1046,7 @@ namespace T4 unsigned char textureAtlasColumnCount; GfxDrawSurf drawSurf; unsigned int surfaceTypeBits; + unsigned int layeredSurfaceTypes; uint16_t hashIndex; }; @@ -1074,7 +1075,7 @@ namespace T4 struct Material { MaterialInfo info; - char stateBitsEntry[67]; + char stateBitsEntry[59]; unsigned char textureCount; unsigned char constantCount; unsigned char stateBitsCount; @@ -1479,27 +1480,34 @@ namespace T4 TECHNIQUE_LIT_OMNI_FADE_CHARRED = 0x21, TECHNIQUE_LIT_OMNI_SHADOW_CHARRED = 0x22, TECHNIQUE_LIT_OMNI_SHADOW_FADE_CHARRED = 0x23, + TECHNIQUE_LIT_INSTANCED = 0x24, + TECHNIQUE_LIT_INSTANCED_SUN = 0x25, + TECHNIQUE_LIT_INSTANCED_SUN_SHADOW = 0x26, + TECHNIQUE_LIT_INSTANCED_SPOT = 0x27, + TECHNIQUE_LIT_INSTANCED_SPOT_SHADOW = 0x28, + TECHNIQUE_LIT_INSTANCED_OMNI = 0x29, + TECHNIQUE_LIT_INSTANCED_OMNI_SHADOW = 0x2A, - TECHNIQUE_LIT_END = 0x24, + TECHNIQUE_LIT_END = 0x2B, - TECHNIQUE_LIGHT_SPOT = 0x24, - TECHNIQUE_LIGHT_OMNI = 0x25, - TECHNIQUE_LIGHT_SPOT_SHADOW = 0x26, - TECHNIQUE_LIGHT_SPOT_CHARRED = 0x27, - TECHNIQUE_LIGHT_OMNI_CHARRED = 0x28, - TECHNIQUE_LIGHT_SPOT_SHADOW_CHARRED = 0x29, - TECHNIQUE_FAKELIGHT_NORMAL = 0x2A, - TECHNIQUE_FAKELIGHT_VIEW = 0x2B, - TECHNIQUE_SUNLIGHT_PREVIEW = 0x2C, - TECHNIQUE_CASE_TEXTURE = 0x2D, - TECHNIQUE_WIREFRAME_SOLID = 0x2E, - TECHNIQUE_WIREFRAME_SHADED = 0x2F, - TECHNIQUE_SHADOWCOOKIE_CASTER = 0x30, - TECHNIQUE_SHADOWCOOKIE_RECEIVER = 0x31, - TECHNIQUE_DEBUG_BUMPMAP = 0x32, - TECHNIQUE_COUNT = 0x33, - TECHNIQUE_TOTAL_COUNT = 0x34, - TECHNIQUE_NONE = 0x35, + TECHNIQUE_LIGHT_SPOT = 0x2B, + TECHNIQUE_LIGHT_OMNI = 0x2C, + TECHNIQUE_LIGHT_SPOT_SHADOW = 0x2D, + TECHNIQUE_LIGHT_SPOT_CHARRED = 0x2E, + TECHNIQUE_LIGHT_OMNI_CHARRED = 0x2F, + TECHNIQUE_LIGHT_SPOT_SHADOW_CHARRED = 0x30, + TECHNIQUE_FAKELIGHT_NORMAL = 0x31, + TECHNIQUE_FAKELIGHT_VIEW = 0x32, + TECHNIQUE_SUNLIGHT_PREVIEW = 0x33, + TECHNIQUE_CASE_TEXTURE = 0x34, + TECHNIQUE_WIREFRAME_SOLID = 0x35, + TECHNIQUE_WIREFRAME_SHADED = 0x36, + TECHNIQUE_SHADOWCOOKIE_CASTER = 0x37, + TECHNIQUE_SHADOWCOOKIE_RECEIVER = 0x38, + TECHNIQUE_DEBUG_BUMPMAP = 0x39, + TECHNIQUE_DEBUG_BUMPMAP_INSTANCED = 0x3A, + + TECHNIQUE_COUNT }; enum MaterialWorldVertexFormat : unsigned char diff --git a/src/ObjCommon/Material/JsonMaterial.h.template b/src/ObjCommon/Material/JsonMaterial.h.template index ee47aa99..3b91b2b0 100644 --- a/src/ObjCommon/Material/JsonMaterial.h.template +++ b/src/ObjCommon/Material/JsonMaterial.h.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T5, T6) +#options GAME (IW3, IW4, IW5, T4, T5, T6) #filename "Game/" + GAME + "/Material/JsonMaterial" + GAME + ".h" @@ -11,6 +11,9 @@ #elif GAME == "IW5" #define FEATURE_IW5 #define HAS_WATER +#elif GAME == "T4" +#define FEATURE_T4 +#define HAS_WATER #elif GAME == "T5" #define FEATURE_T5 #define HAS_WATER @@ -81,7 +84,7 @@ namespace GAME INVALID, DISABLED, GT0, -#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) +#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) || defined(FEATURE_T4) LT128, #elif defined(FEATURE_T5) GE255, @@ -93,7 +96,7 @@ namespace GAME {JsonAlphaTest::INVALID, nullptr }, {JsonAlphaTest::DISABLED, "disabled"}, {JsonAlphaTest::GT0, "gt0" }, -#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) +#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) || defined(FEATURE_T4) {JsonAlphaTest::LT128, "lt128" }, #elif defined(FEATURE_T5) {JsonAlphaTest::GE255, "ge255" }, @@ -328,7 +331,7 @@ namespace GAME {TS_2D, "2D" }, {TS_FUNCTION, "function" }, {TS_COLOR_MAP, "colorMap" }, -#if defined(FEATURE_IW3) || defined(FEATURE_T5) || defined(FEATURE_T6) +#if defined(FEATURE_IW3) || defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) {TS_UNUSED_1, "unused1" }, #else {TS_DETAIL_MAP, "detailMap" }, @@ -343,7 +346,7 @@ namespace GAME {TS_OCCLUSION_MAP, "occlusionMap" }, #endif {TS_UNUSED_6, "unused6" }, -#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) || defined(FEATURE_T5) +#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) || defined(FEATURE_T4) || defined(FEATURE_T5) {TS_WATER_MAP, "waterMap" }, #endif #ifdef FEATURE_IW5 @@ -378,7 +381,7 @@ namespace GAME std::optional nameStart; std::optional nameEnd; TextureSemantic semantic; -#if defined(FEATURE_T5) || defined(FEATURE_T6) +#if defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) bool isMatureContent; #endif JsonSamplerState samplerState; @@ -402,7 +405,7 @@ namespace GAME } out["semantic"] = in.semantic; -#if defined(FEATURE_T5) || defined(FEATURE_T6) +#if defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) out["isMatureContent"] = in.isMatureContent; #endif out["samplerState"] = in.samplerState; @@ -419,7 +422,7 @@ namespace GAME optional_from_json(in, "nameStart", out.nameStart); optional_from_json(in, "nameEnd", out.nameEnd); in.at("semantic").get_to(out.semantic); -#if defined(FEATURE_T5) || defined(FEATURE_T6) +#if defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) in.at("isMatureContent").get_to(out.isMatureContent); #endif in.at("samplerState").get_to(out.samplerState); @@ -454,14 +457,14 @@ namespace GAME {MTL_GAMEFLAG_8, "8" }, {MTL_GAMEFLAG_10, "10" }, {MTL_GAMEFLAG_20, "20" }, -#if defined(FEATURE_IW3) || defined(FEATURE_T5) || defined(FEATURE_T6) +#if defined(FEATURE_IW3) || defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) {MTL_GAMEFLAG_CASTS_SHADOW, "CASTS_SHADOW"}, {MTL_GAMEFLAG_CASTS_SHADOW, "40" }, #else {MTL_GAMEFLAG_40, "40" }, #endif {MTL_GAMEFLAG_80, "80" }, -#if defined(FEATURE_T5) || defined(FEATURE_T6) +#if defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) {MTL_GAMEFLAG_100, "100" }, {MTL_GAMEFLAG_200, "200" }, #if defined(FEATURE_T6) @@ -475,7 +478,7 @@ namespace GAME }); NLOHMANN_JSON_SERIALIZE_ENUM(GfxCameraRegionType, { -#if defined(FEATURE_IW3) || defined(FEATURE_T5) +#if defined(FEATURE_IW3) || defined(FEATURE_T4) || defined(FEATURE_T5) {CAMERA_REGION_LIT, "lit" }, {CAMERA_REGION_DECAL, "decal" }, {CAMERA_REGION_EMISSIVE, "emissive" }, @@ -506,7 +509,7 @@ namespace GAME class JsonMaterial { public: -#if defined(FEATURE_T5) || defined(FEATURE_T6) +#if defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) unsigned layeredSurfaceTypes; #if defined(FEATURE_T6) unsigned surfaceFlags; diff --git a/src/ObjLoading/Game/T4/Material/LoaderMaterialT4.cpp b/src/ObjLoading/Game/T4/Material/LoaderMaterialT4.cpp new file mode 100644 index 00000000..4f391ac1 --- /dev/null +++ b/src/ObjLoading/Game/T4/Material/LoaderMaterialT4.cpp @@ -0,0 +1,55 @@ +#include "LoaderMaterialT4.h" + +#include "Game/T4/Material/JsonMaterialLoaderT4.h" +#include "Game/T4/T4.h" +#include "Material/MaterialCommon.h" +#include "Utils/Logging/Log.h" + +#include +#include + +using namespace T4; + +namespace +{ + class MaterialLoader final : public AssetCreator + { + public: + MaterialLoader(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(material::GetFileNameForAssetName(assetName)); + if (!file.IsOpen()) + return AssetCreationResult::NoAction(); + + auto* material = m_memory.Alloc(); + material->info.name = m_memory.Dup(assetName.c_str()); + + AssetRegistration registration(assetName, material); + if (!LoadMaterialAsJson(*file.m_stream, *material, m_memory, context, registration)) + { + con::error("Failed to load material \"{}\"", assetName); + return AssetCreationResult::Failure(); + } + + return AssetCreationResult::Success(context.AddAsset(std::move(registration))); + } + + private: + MemoryManager& m_memory; + ISearchPath& m_search_path; + }; +} // namespace + +namespace material +{ + std::unique_ptr> CreateLoaderT4(MemoryManager& memory, ISearchPath& searchPath) + { + return std::make_unique(memory, searchPath); + } +} // namespace material diff --git a/src/ObjLoading/Game/T4/Material/LoaderMaterialT4.h b/src/ObjLoading/Game/T4/Material/LoaderMaterialT4.h new file mode 100644 index 00000000..c5745e88 --- /dev/null +++ b/src/ObjLoading/Game/T4/Material/LoaderMaterialT4.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Game/T4/T4.h" +#include "Gdt/IGdtQueryable.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +namespace material +{ + std::unique_ptr> CreateLoaderT4(MemoryManager& memory, ISearchPath& searchPath); +} // namespace material diff --git a/src/ObjLoading/Game/T4/ObjLoaderT4.cpp b/src/ObjLoading/Game/T4/ObjLoaderT4.cpp index 600a17d6..8740be9e 100644 --- a/src/ObjLoading/Game/T4/ObjLoaderT4.cpp +++ b/src/ObjLoading/Game/T4/ObjLoaderT4.cpp @@ -10,6 +10,7 @@ #include "Game/T4/XAnim/XAnimLoaderT4.h" #include "Localize/AssetLoaderLocalizeT4.h" #include "Maps/MapEntsLoaderT4.h" +#include "Material/LoaderMaterialT4.h" #include "RawFile/AssetLoaderRawFileT4.h" #include "Weapon/FlameTableLoaderT4.h" #include "Weapon/WeaponGdtLoaderT4.h" @@ -98,6 +99,7 @@ namespace collection.AddAssetCreator(xanim::CreateLoaderT4(memory, searchPath, zone)); collection.AddAssetCreator(image::CreateLoaderEmbeddedT4(memory, searchPath)); collection.AddAssetCreator(image::CreateLoaderExternalT4(memory, searchPath)); + collection.AddAssetCreator(material::CreateLoaderT4(memory, searchPath)); collection.AddAssetCreator(font::CreateLoaderT4(memory, searchPath)); collection.AddAssetCreator(localize::CreateLoaderT4(memory, searchPath, zone)); collection.AddAssetCreator(map_ents::CreateLoaderT4(memory, searchPath)); diff --git a/src/ObjLoading/Material/JsonMaterialLoader.cpp.template b/src/ObjLoading/Material/JsonMaterialLoader.cpp.template index 248d12cc..5d2cdbbe 100644 --- a/src/ObjLoading/Material/JsonMaterialLoader.cpp.template +++ b/src/ObjLoading/Material/JsonMaterialLoader.cpp.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T5, T6) +#options GAME (IW3, IW4, IW5, T4, T5, T6) #filename "Game/" + GAME + "/Material/JsonMaterialLoader" + GAME + ".cpp" @@ -14,6 +14,10 @@ #define FEATURE_IW5 #define HAS_WATER #define GAME_LOWER "iw5" +#elif GAME == "T4" +#define FEATURE_T4 +#define HAS_WATER +#define GAME_LOWER "t4" #elif GAME == "T5" #define FEATURE_T5 #define HAS_WATER @@ -104,7 +108,7 @@ namespace con::error("Cannot load material \"{}\": {}", material.info.name, message); } -#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) +#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) || defined(FEATURE_T4) static bool CreateGameFlagsFromJson(const JsonMaterial& jMaterial, unsigned char& gameFlags) #elif defined(FEATURE_T5) || defined(FEATURE_T6) static bool CreateGameFlagsFromJson(const JsonMaterial& jMaterial, unsigned& gameFlags) @@ -207,7 +211,7 @@ namespace CreateSamplerStateFromJson(jTexture.samplerState, textureDef.samplerState); textureDef.semantic = jTexture.semantic; -#if defined(FEATURE_T5) || defined(FEATURE_T6) +#if defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) textureDef.isMatureContent = jTexture.isMatureContent; #endif @@ -314,7 +318,7 @@ namespace structured.alphaTestDisabled = 0; structured.alphaTest = GFXS_ALPHA_TEST_GT_0; } -#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) +#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) || defined(FEATURE_T4) else if (jStateBitsTableEntry.alphaTest == JsonAlphaTest::LT128) { structured.alphaTestDisabled = 0; @@ -419,7 +423,7 @@ namespace } material.info.surfaceTypeBits = jMaterial.surfaceTypeBits; -#if defined(FEATURE_T5) || defined(FEATURE_T6) +#if defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) material.info.layeredSurfaceTypes = jMaterial.layeredSurfaceTypes; #endif #if defined(FEATURE_T6) diff --git a/src/ObjLoading/Material/JsonMaterialLoader.h.template b/src/ObjLoading/Material/JsonMaterialLoader.h.template index 04b768df..7bbf54d3 100644 --- a/src/ObjLoading/Material/JsonMaterialLoader.h.template +++ b/src/ObjLoading/Material/JsonMaterialLoader.h.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T5, T6) +#options GAME (IW3, IW4, IW5, T4, T5, T6) #filename "Game/" + GAME + "/Material/JsonMaterialLoader" + GAME + ".h" diff --git a/src/ObjWriting/Game/T4/Material/MaterialConstantZoneStateT4.cpp b/src/ObjWriting/Game/T4/Material/MaterialConstantZoneStateT4.cpp new file mode 100644 index 00000000..6cfd20e6 --- /dev/null +++ b/src/ObjWriting/Game/T4/Material/MaterialConstantZoneStateT4.cpp @@ -0,0 +1,249 @@ +#include "MaterialConstantZoneStateT4.h" + +#include "Game/T4/CommonT4.h" +#include "Game/T4/GameT4.h" +#include "ObjWriting.h" +#include "Zone/ZoneRegistry.h" + +namespace +{ + const char* KNOWN_CONSTANT_NAMES[]{ + "worldViewProjectionMatrix", + "worldViewMatrix2", + "worldViewMatrix1", + "worldViewMatrix", + "worldOutdoorLookupMatrix", + "worldMatrix", + "waterColor", + "viewportDimensions", + "viewProjectionMatrix", + "uvScale", + "uvAnimParms", + "thermalColorOffset", + "sunShadowmapPixelAdjust", + "ssaoParms", + "spotShadowmapPixelAdjust", + "shadowmapSwitchPartition", + "shadowmapScale", + "shadowmapPolygonOffset", + "shadowLookupMatrix", + "renderTargetSize", + "renderSourceSize", + "projectionMatrix", + "playlistPopulationParams", + "pixelCostFracs", + "pixelCostDecode", + "particleCloudSparkColor2", + "particleCloudSparkColor1", + "particleCloudSparkColor0", + "particleCloudMatrix2", + "particleCloudMatrix1", + "particleCloudMatrix", + "particleCloudColor", + "outdoorFeatherParms", + "oceanUVAnimParmPaintedFoam", + "oceanUVAnimParmOctave2", + "oceanUVAnimParmOctave1", + "oceanUVAnimParmOctave0", + "oceanUVAnimParmFoam", + "oceanUVAnimParmDetail1", + "oceanUVAnimParmDetail0", + "oceanScrollParms", + "oceanMiscParms", + "oceanFoamParms", + "oceanAmplitude", + "materialColor", + "lightprobeAmbient", + "lightingLookupScale", + "lightSpotFactors", + "lightSpotDir", + "lightSpecular", + "lightPosition", + "lightFalloffPlacement", + "lightDiffuse", + "inverseWorldViewMatrix", + "inverseViewProjectionMatrix", + "inverseTransposeWorldViewMatrix", + "heatMapDetail", + "glowSetup", + "glowApply", + "gameTime", + "fullscreenDistortion", + "fogSunDir", + "fogSunConsts", + "fogSunColorLinear", + "fogSunColorGamma", + "fogConsts", + "fogColorLinear", + "fogColorGamma", + "flagParms", + "filterTap", + "featherParms", + "falloffParms", + "falloffEndColor", + "falloffBeginColor", + "fadeEffect", + "eyeOffsetParms", + "eyeOffset", + "envMapParms", + "dustTint", + "dustParms", + "dustEyeParms", + "dofRowDelta", + "dofLerpScale", + "dofLerpBias", + "dofEquationViewModelAndFarBlur", + "dofEquationScene", + "distortionScale", + "detailScale", + "depthFromClip", + "debugBumpmap", + "colorTintQuadraticDelta", + "colorTintDelta", + "colorTintBase", + "colorSaturationR", + "colorSaturationG", + "colorSaturationB", + "colorObjMin", + "colorObjMax", + "colorMatrixR", + "colorMatrixG", + "colorMatrixB", + "colorBias", + "codeMeshArg", + "clipSpaceLookupScale", + "clipSpaceLookupOffset", + "baseLightingCoords", + }; + + const char* KNOWN_TEXTURE_DEF_NAMES[]{ + "attenuation", + "attenuationSampler", + "cinematicA", + "cinematicASampler", + "cinematicCb", + "cinematicCbSampler", + "cinematicCr", + "cinematicCrSampler", + "cinematicY", + "cinematicYSampler", + "colorMap", + "colorMap1", + "colorMap2", + "colorMapPostSun", + "colorMapPostSunSampler", + "colorMapSampler", + "colorMapSampler1", + "colorMapSampler2", + "cucoloris", + "cucolorisSampler", + "detailMap", + "detailMapSampler", + "dust", + "dustSampler", + "fadeMap", + "fadeMapSampler", + "floatZ", + "floatZSampler", + "grainMap", + "grainMapSampler", + "halfParticleColor", + "halfParticleColorSampler", + "halfParticleDepth", + "halfParticleDepthSampler", + "heatmap", + "heatmapSampler", + "lightmapPrimary", + "lightmapSamplerPrimary", + "lightmapSamplerSecondary", + "lightmapSecondary", + "lookupMap", + "lookupMapSampler", + "modelLighting", + "modelLightingSampler", + "normalMap", + "normalMapSampler", + "oceanColorRamp", + "oceanColorRampSampler", + "oceanDetailNormal", + "oceanDetailNormalSampler", + "oceanDisplacement", + "oceanDisplacementSampler", + "oceanEnv", + "oceanEnvSampler", + "oceanFoam", + "oceanFoamSampler", + "oceanHeightNormal", + "oceanHeightNormalSampler", + "oceanPaintedFoam", + "oceanPaintedFoamSampler", + "outdoorMap", + "outdoorMapSampler", + "population", + "populationSampler", + "reflectionProbe", + "reflectionProbeSampler", + "shadowmapSamplerSpot", + "shadowmapSamplerSun", + "shadowmapSpot", + "shadowmapSun", + "skyMap", + "skyMapSampler", + "specularMap", + "specularMapSampler", + "ssao", + "ssaoSampler", + "worldMap", + "worldMapSampler", + }; +} // namespace + +namespace T4 +{ + void MaterialConstantZoneState::ExtractNamesFromZoneInternal() + { + for (const auto* zone : ZoneRegistry::GetRegistryForGame(GameId::T4)->Zones()) + { + for (const auto* techniqueSetInfo : zone->m_pools.PoolAssets()) + { + const auto* techniqueSet = techniqueSetInfo->Asset(); + + for (const auto* technique : techniqueSet->techniques) + { + if (technique) + ExtractNamesFromTechnique(technique); + } + } + } + } + + unsigned MaterialConstantZoneState::HashString(const std::string& str) const + { + return Common::R_HashString(str.c_str()); + } + + void MaterialConstantZoneState::ExtractNamesFromTechnique(const MaterialTechnique* technique) + { + if (!ShouldDumpFromStruct(technique)) + return; + + for (auto passIndex = 0u; passIndex < technique->passCount; passIndex++) + { + const auto& pass = technique->passArray[passIndex]; + + if (pass.vertexShader && pass.vertexShader->prog.loadDef.program) + ExtractNamesFromShader(pass.vertexShader->prog.loadDef.program, pass.vertexShader->prog.loadDef.programSize); + + if (pass.pixelShader && pass.pixelShader->prog.loadDef.program) + ExtractNamesFromShader(pass.pixelShader->prog.loadDef.program, pass.pixelShader->prog.loadDef.programSize); + } + } + + void MaterialConstantZoneState::AddStaticKnownNames() + { + for (const auto* knownConstantName : KNOWN_CONSTANT_NAMES) + AddConstantName(knownConstantName); + for (const auto* knownTextureDefName : KNOWN_TEXTURE_DEF_NAMES) + AddTextureDefName(knownTextureDefName); + } +} // namespace T4 diff --git a/src/ObjWriting/Game/T4/Material/MaterialConstantZoneStateT4.h b/src/ObjWriting/Game/T4/Material/MaterialConstantZoneStateT4.h new file mode 100644 index 00000000..0106f665 --- /dev/null +++ b/src/ObjWriting/Game/T4/Material/MaterialConstantZoneStateT4.h @@ -0,0 +1,18 @@ +#pragma once + +#include "Game/T4/T4.h" +#include "Material/AbstractMaterialConstantZoneState.h" + +#include + +namespace T4 +{ + class MaterialConstantZoneState final : public AbstractMaterialConstantZoneStateDx9 + { + protected: + void ExtractNamesFromZoneInternal() override; + void ExtractNamesFromTechnique(const MaterialTechnique* technique); + void AddStaticKnownNames() override; + [[nodiscard]] unsigned HashString(const std::string& str) const override; + }; +} // namespace T4 diff --git a/src/ObjWriting/Game/T4/ObjWriterT4.cpp b/src/ObjWriting/Game/T4/ObjWriterT4.cpp index c964736a..408aab3d 100644 --- a/src/ObjWriting/Game/T4/ObjWriterT4.cpp +++ b/src/ObjWriting/Game/T4/ObjWriterT4.cpp @@ -2,6 +2,7 @@ #include "Game/T4/Font/FontDumperT4.h" #include "Game/T4/Image/ImageDumperT4.h" +#include "Game/T4/Material/MaterialJsonDumperT4.h" #include "Game/T4/XAnim/XAnimDumperT4.h" #include "Game/T4/XModel/XModelDumperT4.h" #include "Localize/LocalizeDumperT4.h" @@ -17,6 +18,7 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context) { RegisterAssetDumper(std::make_unique()); RegisterAssetDumper(std::make_unique()); + RegisterAssetDumper(std::make_unique()); RegisterAssetDumper(std::make_unique()); RegisterAssetDumper(std::make_unique()); RegisterAssetDumper(std::make_unique()); diff --git a/src/ObjWriting/Material/MaterialJsonDumper.cpp.template b/src/ObjWriting/Material/MaterialJsonDumper.cpp.template index 0e769bbc..592e20e3 100644 --- a/src/ObjWriting/Material/MaterialJsonDumper.cpp.template +++ b/src/ObjWriting/Material/MaterialJsonDumper.cpp.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T5, T6) +#options GAME (IW3, IW4, IW5, T4, T5, T6) #filename "Game/" + GAME + "/Material/MaterialJsonDumper" + GAME + ".cpp" @@ -14,6 +14,10 @@ #define FEATURE_IW5 #define HAS_WATER #define GAME_LOWER "iw5" +#elif GAME == "T4" +#define FEATURE_T4 +#define HAS_WATER +#define GAME_LOWER "t4" #elif GAME == "T5" #define FEATURE_T5 #define HAS_WATER @@ -153,7 +157,7 @@ namespace } jTextureDef.semantic = static_cast(textureDef.semantic); -#if defined(FEATURE_T5) || defined(FEATURE_T6) +#if defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) jTextureDef.isMatureContent = textureDef.isMatureContent; #endif @@ -231,7 +235,7 @@ namespace assert(structured.alphaTestDisabled || structured.alphaTest == GFXS_ALPHA_TEST_GT_0 -#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) +#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) || defined(FEATURE_T4) || structured.alphaTest == GFXS_ALPHA_TEST_LT_128 #elif defined(FEATURE_T5) || structured.alphaTest == GFXS_ALPHA_TEST_GE_255 @@ -241,7 +245,7 @@ namespace jStateBitsTableEntry.alphaTest = JsonAlphaTest::DISABLED; else if (structured.alphaTest == GFXS_ALPHA_TEST_GT_0) jStateBitsTableEntry.alphaTest = JsonAlphaTest::GT0; -#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) +#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) || defined(FEATURE_T4) else if (structured.alphaTest == GFXS_ALPHA_TEST_LT_128) jStateBitsTableEntry.alphaTest = JsonAlphaTest::LT128; #elif defined(FEATURE_T5) @@ -318,7 +322,7 @@ namespace jMaterial.textureAtlas->columns = material.info.textureAtlasColumnCount; jMaterial.surfaceTypeBits = material.info.surfaceTypeBits; -#if defined(FEATURE_T5) || defined(FEATURE_T6) +#if defined(FEATURE_T4) || defined(FEATURE_T5) || defined(FEATURE_T6) jMaterial.layeredSurfaceTypes = material.info.layeredSurfaceTypes; #endif #if defined(FEATURE_T6) diff --git a/src/ObjWriting/Material/MaterialJsonDumper.h.template b/src/ObjWriting/Material/MaterialJsonDumper.h.template index a089e691..5c7275f7 100644 --- a/src/ObjWriting/Material/MaterialJsonDumper.h.template +++ b/src/ObjWriting/Material/MaterialJsonDumper.h.template @@ -1,4 +1,4 @@ -#options GAME(IW3, IW4, IW5, T5, T6) +#options GAME(IW3, IW4, IW5, T4, T5, T6) #filename "Game/" + GAME + "/Material/MaterialJsonDumper" + GAME + ".h"