diff --git a/src/Common/Game/T5/CommonT5.h b/src/Common/Game/T5/CommonT5.h index 9cb67e29..c5e4d762 100644 --- a/src/Common/Game/T5/CommonT5.h +++ b/src/Common/Game/T5/CommonT5.h @@ -11,6 +11,21 @@ namespace T5 static int Com_HashString(const char* str); static int Com_HashString(const char* str, int len); + static constexpr uint32_t R_HashString(const char* str, uint32_t hash) + { + for (const auto* pos = str; *pos; pos++) + { + hash = 33 * hash ^ (*pos | 0x20); + } + + return hash; + } + + static constexpr uint32_t R_HashString(const char* string) + { + return R_HashString(string, 0u); + } + static PackedTexCoords Vec2PackTexCoords(const float (&in)[2]); static PackedUnitVec Vec3PackUnitVec(const float (&in)[3]); static GfxColor Vec4PackGfxColor(const float (&in)[4]); diff --git a/src/Common/Game/T5/T5_Assets.h b/src/Common/Game/T5/T5_Assets.h index c1145466..865e2100 100644 --- a/src/Common/Game/T5/T5_Assets.h +++ b/src/Common/Game/T5/T5_Assets.h @@ -739,14 +739,30 @@ namespace T5 gcc_align32(8) uint64_t packed; }; + enum MaterialGameFlags + { + MTL_GAMEFLAG_1 = 0x1, + MTL_GAMEFLAG_2 = 0x2, + MTL_GAMEFLAG_4 = 0x4, + MTL_GAMEFLAG_8 = 0x8, + MTL_GAMEFLAG_10 = 0x10, + MTL_GAMEFLAG_20 = 0x20, + + // Probably, seems to be this in T5 + MTL_GAMEFLAG_CASTS_SHADOW = 0x40, + MTL_GAMEFLAG_80 = 0x80, + MTL_GAMEFLAG_100 = 0x100, + MTL_GAMEFLAG_200 = 0x200, + }; + struct MaterialInfo { const char* name; unsigned int gameFlags; char pad; - char sortKey; - char textureAtlasRowCount; - char textureAtlasColumnCount; + unsigned char sortKey; + unsigned char textureAtlasRowCount; + unsigned char textureAtlasColumnCount; GfxDrawSurf drawSurf; unsigned int surfaceTypeBits; unsigned int layeredSurfaceTypes; @@ -787,12 +803,45 @@ namespace T5 water_t* water; }; + enum TextureFilter + { + TEXTURE_FILTER_DISABLED = 0x0, + TEXTURE_FILTER_NEAREST = 0x1, + TEXTURE_FILTER_LINEAR = 0x2, + TEXTURE_FILTER_ANISO2X = 0x3, + TEXTURE_FILTER_ANISO4X = 0x4, + + TEXTURE_FILTER_COUNT + }; + + enum SamplerStateBitsMipMap_e + { + SAMPLER_MIPMAP_ENUM_DISABLED, + SAMPLER_MIPMAP_ENUM_NEAREST, + SAMPLER_MIPMAP_ENUM_LINEAR, + + SAMPLER_MIPMAP_ENUM_COUNT + }; + + struct MaterialTextureDefSamplerState + { + unsigned char filter : 3; + unsigned char mipMap : 2; + unsigned char clampU : 1; + unsigned char clampV : 1; + unsigned char clampW : 1; + }; + +#ifndef __zonecodegenerator + static_assert(sizeof(MaterialTextureDefSamplerState) == 1u); +#endif + struct MaterialTextureDef { unsigned int nameHash; char nameStart; char nameEnd; - char samplerState; + MaterialTextureDefSamplerState samplerState; unsigned char semantic; // TextureSemantic char isMatureContent; char pad[3]; @@ -803,7 +852,96 @@ namespace T5 { unsigned int nameHash; char name[12]; - float literal[4]; + vec4_t literal; + }; + + enum GfxBlend : unsigned int + { + GFXS_BLEND_DISABLED = 0x0, + GFXS_BLEND_ZERO = 0x1, + GFXS_BLEND_ONE = 0x2, + GFXS_BLEND_SRCCOLOR = 0x3, + GFXS_BLEND_INVSRCCOLOR = 0x4, + GFXS_BLEND_SRCALPHA = 0x5, + GFXS_BLEND_INVSRCALPHA = 0x6, + GFXS_BLEND_DESTALPHA = 0x7, + GFXS_BLEND_INVDESTALPHA = 0x8, + GFXS_BLEND_DESTCOLOR = 0x9, + GFXS_BLEND_INVDESTCOLOR = 0xA, + GFXS_BLEND_MASK = 0xF, + }; + + enum GfxBlendOp : unsigned int + { + GFXS_BLENDOP_DISABLED = 0x0, + GFXS_BLENDOP_ADD = 0x1, + GFXS_BLENDOP_SUBTRACT = 0x2, + GFXS_BLENDOP_REVSUBTRACT = 0x3, + GFXS_BLENDOP_MIN = 0x4, + GFXS_BLENDOP_MAX = 0x5, + GFXS_BLENDOP_MASK = 0x7, + }; + + enum GfxAlphaTest_e + { + GFXS_ALPHA_TEST_GT_0 = 1, + GFXS_ALPHA_TEST_GE_255 = 2, + GFXS_ALPHA_TEST_GE_128 = 3, + + GFXS_ALPHA_TEST_COUNT + }; + + enum GfxCullFace_e + { + GFXS_CULL_NONE = 1, + GFXS_CULL_BACK = 2, + GFXS_CULL_FRONT = 3, + }; + + enum GfxDepthTest_e + { + GFXS_DEPTHTEST_ALWAYS = 0, + GFXS_DEPTHTEST_LESS = 1, + GFXS_DEPTHTEST_EQUAL = 2, + GFXS_DEPTHTEST_LESSEQUAL = 3 + }; + + enum GfxPolygonOffset_e + { + GFXS_POLYGON_OFFSET_0 = 0, + GFXS_POLYGON_OFFSET_1 = 1, + GFXS_POLYGON_OFFSET_2 = 2, + GFXS_POLYGON_OFFSET_SHADOWMAP = 3 + }; + + enum GfxStencilOp : unsigned int + { + GFXS_STENCILOP_KEEP = 0x0, + GFXS_STENCILOP_ZERO = 0x1, + GFXS_STENCILOP_REPLACE = 0x2, + GFXS_STENCILOP_INCRSAT = 0x3, + GFXS_STENCILOP_DECRSAT = 0x4, + GFXS_STENCILOP_INVERT = 0x5, + GFXS_STENCILOP_INCR = 0x6, + GFXS_STENCILOP_DECR = 0x7, + + GFXS_STENCILOP_COUNT, + GFXS_STENCILOP_MASK = 0x7 + }; + + enum GfxStencilFunc : unsigned int + { + GFXS_STENCILFUNC_NEVER = 0x0, + GFXS_STENCILFUNC_LESS = 0x1, + GFXS_STENCILFUNC_EQUAL = 0x2, + GFXS_STENCILFUNC_LESSEQUAL = 0x3, + GFXS_STENCILFUNC_GREATER = 0x4, + GFXS_STENCILFUNC_NOTEQUAL = 0x5, + GFXS_STENCILFUNC_GREATEREQUAL = 0x6, + GFXS_STENCILFUNC_ALWAYS = 0x7, + + GFXS_STENCILFUNC_COUNT, + GFXS_STENCILFUNC_MASK = 0x7 }; enum GfxStateBitsEnum : unsigned int @@ -868,9 +1006,64 @@ namespace T5 GFXS1_STENCILOP_FRONTBACK_MASK = 0x1FF1FF00, }; + struct GfxStateBitsLoadBitsStructured + { + // Byte 0 + unsigned int srcBlendRgb : 4; // 0-3 + unsigned int dstBlendRgb : 4; // 4-7 + unsigned int blendOpRgb : 3; // 8-10 + unsigned int alphaTestDisabled : 1; // 11 + unsigned int alphaTest : 2; // 12-13 + unsigned int cullFace : 2; // 14-15 + unsigned int srcBlendAlpha : 4; // 16-19 + unsigned int dstBlendAlpha : 4; // 20-23 + unsigned int blendOpAlpha : 3; // 24-26 + unsigned int colorWriteRgb : 1; // 27 + unsigned int colorWriteAlpha : 1; // 28 + unsigned int unused0 : 2; // 29-30 + unsigned int polymodeLine : 1; // 31 + + // Byte 1 + unsigned int depthWrite : 1; // 0 + unsigned int depthTestDisabled : 1; // 1 + unsigned int depthTest : 2; // 2-3 + unsigned int polygonOffset : 2; // 4-5 + unsigned int stencilFrontEnabled : 1; // 6 + unsigned int stencilBackEnabled : 1; // 7 + unsigned int stencilFrontPass : 3; // 8-10 + unsigned int stencilFrontFail : 3; // 11-13 + unsigned int stencilFrontZFail : 3; // 14-16 + unsigned int stencilFrontFunc : 3; // 17-19 + unsigned int stencilBackPass : 3; // 20-22 + unsigned int stencilBackFail : 3; // 23-25 + unsigned int stencilBackZFail : 3; // 26-28 + unsigned int stencilBackFunc : 3; // 29-31 + }; + + union GfxStateBitsLoadBits + { + unsigned int raw[2]; + GfxStateBitsLoadBitsStructured structured; + }; + +#ifndef __zonecodegenerator + static_assert(sizeof(GfxStateBitsLoadBits) == 8); + static_assert(sizeof(GfxStateBitsLoadBitsStructured) == 8); +#endif + struct GfxStateBits { - unsigned int loadBits[2]; + GfxStateBitsLoadBits loadBits; + }; + + enum GfxCameraRegionType + { + CAMERA_REGION_LIT = 0x0, + CAMERA_REGION_DECAL = 0x1, + CAMERA_REGION_EMISSIVE = 0x2, + + CAMERA_REGION_COUNT, + CAMERA_REGION_NONE = CAMERA_REGION_COUNT, }; struct Material @@ -880,8 +1073,8 @@ namespace T5 unsigned char textureCount; unsigned char constantCount; unsigned char stateBitsCount; - char stateFlags; - char cameraRegion; + unsigned char stateFlags; + unsigned char cameraRegion; unsigned char maxStreamedMips; MaterialTechniqueSet* techniqueSet; MaterialTextureDef* textureTable; diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 62f3f300..28de10dc 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -700,6 +700,8 @@ namespace T6 MTL_GAMEFLAG_400 = 0x400, MTL_GAMEFLAG_800 = 0x800, MTL_GAMEFLAG_1000 = 0x1000, + MTL_GAMEFLAG_2000 = 0x2000, + MTL_GAMEFLAG_4000 = 0x4000, }; struct type_align32(8) MaterialInfo diff --git a/src/ObjCommon/Material/JsonMaterial.h.template b/src/ObjCommon/Material/JsonMaterial.h.template index 426bf449..f3fbb66f 100644 --- a/src/ObjCommon/Material/JsonMaterial.h.template +++ b/src/ObjCommon/Material/JsonMaterial.h.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T6) +#options GAME (IW3, IW4, IW5, T5, T6) #filename "Game/" + GAME + "/Material/JsonMaterial" + GAME + ".h" @@ -11,6 +11,9 @@ #elif GAME == "IW5" #define FEATURE_IW5 #define HAS_WATER +#elif GAME == "T5" +#define FEATURE_T5 +#define HAS_WATER #elif GAME == "T6" #define FEATURE_T6 #endif @@ -80,6 +83,8 @@ namespace GAME GT0, #if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) LT128, +#elif defined(FEATURE_T5) + GE255, #endif GE128 }; @@ -90,6 +95,8 @@ namespace GAME {JsonAlphaTest::GT0, "gt0" }, #if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) {JsonAlphaTest::LT128, "lt128" }, +#elif defined(FEATURE_T5) + {JsonAlphaTest::GE255, "ge255" }, #endif {JsonAlphaTest::GE128, "ge128" } }); @@ -321,7 +328,7 @@ namespace GAME {TS_2D, "2D" }, {TS_FUNCTION, "function" }, {TS_COLOR_MAP, "colorMap" }, -#if defined(FEATURE_IW3) || defined(FEATURE_T6) +#if defined(FEATURE_IW3) || defined(FEATURE_T5) || defined(FEATURE_T6) {TS_UNUSED_1, "unused1" }, #else {TS_DETAIL_MAP, "detailMap" }, @@ -332,15 +339,17 @@ namespace GAME {TS_UNUSED_4, "unused4" }, {TS_SPECULAR_MAP, "specularMap" }, {TS_UNUSED_5, "unused5" }, -#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) +#ifdef FEATURE_T6 + {TS_OCCLUSION_MAP, "occlusionMap" }, +#endif {TS_UNUSED_6, "unused6" }, +#if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) || defined(FEATURE_T5) {TS_WATER_MAP, "waterMap" }, +#endif #ifdef FEATURE_IW5 {TS_DISPLACEMENT_MAP, "displacementMap"}, #endif -#elif defined(FEATURE_T6) - {TS_OCCLUSION_MAP, "occlusionMap" }, - {TS_UNUSED_6, "unused6" }, +#if defined(FEATURE_T5) || defined(FEATURE_T6) {TS_COLOR0_MAP, "color0Map" }, {TS_COLOR1_MAP, "color1Map" }, {TS_COLOR2_MAP, "color2Map" }, @@ -369,7 +378,7 @@ namespace GAME std::optional nameStart; std::optional nameEnd; TextureSemantic semantic; -#ifdef FEATURE_T6 +#if defined(FEATURE_T5) || defined(FEATURE_T6) bool isMatureContent; #endif JsonSamplerState samplerState; @@ -393,7 +402,7 @@ namespace GAME } out["semantic"] = in.semantic; -#ifdef FEATURE_T6 +#if defined(FEATURE_T5) || defined(FEATURE_T6) out["isMatureContent"] = in.isMatureContent; #endif out["samplerState"] = in.samplerState; @@ -410,7 +419,7 @@ namespace GAME optional_from_json(in, "nameStart", out.nameStart); optional_from_json(in, "nameEnd", out.nameEnd); in.at("semantic").get_to(out.semantic); -#ifdef FEATURE_T6 +#if defined(FEATURE_T5) || defined(FEATURE_T6) in.at("isMatureContent").get_to(out.isMatureContent); #endif in.at("samplerState").get_to(out.samplerState); @@ -445,24 +454,28 @@ namespace GAME {MTL_GAMEFLAG_8, "8" }, {MTL_GAMEFLAG_10, "10" }, {MTL_GAMEFLAG_20, "20" }, -#if defined(FEATURE_IW3) || defined(FEATURE_T6) +#if defined(FEATURE_IW3) || 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" }, -#ifdef FEATURE_T6 +#if defined(FEATURE_T5) || defined(FEATURE_T6) {MTL_GAMEFLAG_100, "100" }, {MTL_GAMEFLAG_200, "200" }, +#if defined(FEATURE_T6) {MTL_GAMEFLAG_400, "400" }, {MTL_GAMEFLAG_800, "800" }, {MTL_GAMEFLAG_1000, "1000" }, + {MTL_GAMEFLAG_2000, "2000" }, + {MTL_GAMEFLAG_4000, "4000" }, +#endif #endif }); NLOHMANN_JSON_SERIALIZE_ENUM(GfxCameraRegionType, { -#if defined(FEATURE_IW3) +#if defined(FEATURE_IW3) || defined(FEATURE_T5) {CAMERA_REGION_LIT, "lit" }, {CAMERA_REGION_DECAL, "decal" }, {CAMERA_REGION_EMISSIVE, "emissive" }, @@ -492,7 +505,9 @@ namespace GAME class JsonMaterial { public: -#ifdef FEATURE_T6 +#ifdef FEATURE_T5 + uint8_t maxStreamedMips; +#elif defined(FEATURE_T6) unsigned layeredSurfaceTypes; unsigned hashIndex; unsigned surfaceFlags; @@ -515,7 +530,9 @@ namespace GAME NLOHMANN_DEFINE_TYPE_EXTENSION( JsonMaterial, -#ifdef FEATURE_T6 +#ifdef FEATURE_T5 + maxStreamedMips, +#elif defined(FEATURE_T6) layeredSurfaceTypes, hashIndex, surfaceFlags, diff --git a/src/ObjLoading/Game/T5/Material/LoaderMaterialT5.cpp b/src/ObjLoading/Game/T5/Material/LoaderMaterialT5.cpp new file mode 100644 index 00000000..a362e728 --- /dev/null +++ b/src/ObjLoading/Game/T5/Material/LoaderMaterialT5.cpp @@ -0,0 +1,54 @@ +#include "LoaderMaterialT5.h" + +#include "Game/T5/Material/JsonMaterialLoaderT5.h" +#include "Game/T5/T5.h" +#include "Material/MaterialCommon.h" + +#include +#include + +using namespace T5; + +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)) + { + std::cerr << std::format("Failed to load material \"{}\"\n", assetName); + return AssetCreationResult::Failure(); + } + + return AssetCreationResult::Success(context.AddAsset(std::move(registration))); + } + + private: + MemoryManager& m_memory; + ISearchPath& m_search_path; + }; +} // namespace + +namespace T5 +{ + std::unique_ptr> CreateMaterialLoader(MemoryManager& memory, ISearchPath& searchPath) + { + return std::make_unique(memory, searchPath); + } +} // namespace T5 diff --git a/src/ObjLoading/Game/T5/Material/LoaderMaterialT5.h b/src/ObjLoading/Game/T5/Material/LoaderMaterialT5.h new file mode 100644 index 00000000..22c337ff --- /dev/null +++ b/src/ObjLoading/Game/T5/Material/LoaderMaterialT5.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Game/T5/T5.h" +#include "Gdt/IGdtQueryable.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +namespace T5 +{ + std::unique_ptr> CreateMaterialLoader(MemoryManager& memory, ISearchPath& searchPath); +} // namespace T5 diff --git a/src/ObjLoading/Game/T5/ObjLoaderT5.cpp b/src/ObjLoading/Game/T5/ObjLoaderT5.cpp index 1f4d8132..f877d17c 100644 --- a/src/ObjLoading/Game/T5/ObjLoaderT5.cpp +++ b/src/ObjLoading/Game/T5/ObjLoaderT5.cpp @@ -5,6 +5,7 @@ #include "Game/T5/T5.h" #include "Game/T5/XModel/LoaderXModelT5.h" #include "Localize/LoaderLocalizeT5.h" +#include "Material/LoaderMaterialT5.h" #include "ObjLoading.h" #include "RawFile/LoaderRawFileT5.h" #include "StringTable/LoaderStringTableT5.h" @@ -104,7 +105,7 @@ namespace // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); collection.AddAssetCreator(CreateXModelLoader(memory, searchPath, zone)); - // collection.AddAssetCreator(std::make_unique(memory)); + collection.AddAssetCreator(CreateMaterialLoader(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); // collection.AddAssetCreator(std::make_unique(memory)); diff --git a/src/ObjLoading/Material/JsonMaterialLoader.cpp.template b/src/ObjLoading/Material/JsonMaterialLoader.cpp.template index 8db6cd37..21c32982 100644 --- a/src/ObjLoading/Material/JsonMaterialLoader.cpp.template +++ b/src/ObjLoading/Material/JsonMaterialLoader.cpp.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T6) +#options GAME (IW3, IW4, IW5, 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 == "T5" +#define FEATURE_T5 +#define HAS_WATER +#define GAME_LOWER "t5" #elif GAME == "T6" #define FEATURE_T6 #define GAME_LOWER "t6" @@ -29,6 +33,7 @@ #ifdef HAS_WATER #include "Base64.h" #endif + #set COMMON_HEADER "\"Game/" + GAME + "/Common" + GAME + ".h\"" #include COMMON_HEADER #set JSON_HEADER "\"Game/" + GAME + "/Material/JsonMaterial" + GAME + ".h\"" @@ -100,7 +105,7 @@ namespace #if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) static bool CreateGameFlagsFromJson(const JsonMaterial& jMaterial, unsigned char& gameFlags) -#elif defined(FEATURE_T6) +#elif defined(FEATURE_T5) || defined(FEATURE_T6) static bool CreateGameFlagsFromJson(const JsonMaterial& jMaterial, unsigned& gameFlags) #endif { @@ -201,7 +206,7 @@ namespace CreateSamplerStateFromJson(jTexture.samplerState, textureDef.samplerState); textureDef.semantic = jTexture.semantic; -#ifdef FEATURE_T6 +#if defined(FEATURE_T5) || defined(FEATURE_T6) textureDef.isMatureContent = jTexture.isMatureContent; #endif @@ -314,6 +319,12 @@ namespace structured.alphaTestDisabled = 0; structured.alphaTest = GFXS_ALPHA_TEST_LT_128; } +#elif defined(FEATURE_T5) + else if (jStateBitsTableEntry.alphaTest == JsonAlphaTest::GE255) + { + structured.alphaTestDisabled = 0; + structured.alphaTest = GFXS_ALPHA_TEST_GE_255; + } #endif else if (jStateBitsTableEntry.alphaTest == JsonAlphaTest::GE128) { @@ -424,7 +435,9 @@ namespace material.stateFlags = static_cast(jMaterial.stateFlags); material.cameraRegion = jMaterial.cameraRegion; -#ifdef FEATURE_T6 +#if defined(FEATURE_T5) + material.maxStreamedMips = jMaterial.maxStreamedMips; +#elif defined(FEATURE_T6) material.probeMipBits = jMaterial.probeMipBits; #endif diff --git a/src/ObjLoading/Material/JsonMaterialLoader.h.template b/src/ObjLoading/Material/JsonMaterialLoader.h.template index 49b8057d..04b768df 100644 --- a/src/ObjLoading/Material/JsonMaterialLoader.h.template +++ b/src/ObjLoading/Material/JsonMaterialLoader.h.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T6) +#options GAME (IW3, IW4, IW5, T5, T6) #filename "Game/" + GAME + "/Material/JsonMaterialLoader" + GAME + ".h" diff --git a/src/ObjWriting/Game/IW5/Material/DumperMaterialIW5.cpp b/src/ObjWriting/Game/IW5/Material/DumperMaterialIW5.cpp index 6b9f6e2c..b8e705cb 100644 --- a/src/ObjWriting/Game/IW5/Material/DumperMaterialIW5.cpp +++ b/src/ObjWriting/Game/IW5/Material/DumperMaterialIW5.cpp @@ -26,5 +26,6 @@ void AssetDumperMaterial::DumpAsset(AssetDumpingContext& context, XAssetInfoAsset(), context); + const auto* material = asset->Asset(); + DumpMaterialAsJson(*assetFile, *material, context); } diff --git a/src/ObjWriting/Game/T5/Material/DumperMaterialT5.cpp b/src/ObjWriting/Game/T5/Material/DumperMaterialT5.cpp new file mode 100644 index 00000000..2d687c0e --- /dev/null +++ b/src/ObjWriting/Game/T5/Material/DumperMaterialT5.cpp @@ -0,0 +1,34 @@ +#include "DumperMaterialT5.h" + +#include "Game/T5/Material/JsonMaterialWriterT5.h" +#include "Game/T5/Material/MaterialConstantZoneStateT5.h" +#include "Material/MaterialCommon.h" + +#include + +using namespace T5; + +void AssetDumperMaterial::DumpPool(AssetDumpingContext& context, AssetPool* pool) +{ + auto* materialConstantState = context.GetZoneAssetDumperState(); + materialConstantState->ExtractNamesFromZone(); + + AbstractAssetDumper::DumpPool(context, pool); +} + +bool AssetDumperMaterial::ShouldDump(XAssetInfo* asset) +{ + return true; +} + +void AssetDumperMaterial::DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) +{ + const auto assetFile = context.OpenAssetFile(material::GetFileNameForAssetName(asset->m_name)); + + if (!assetFile) + return; + + const auto* material = asset->Asset(); + assert(material->info.gameFlags < 0x400); + DumpMaterialAsJson(*assetFile, *material, context); +} diff --git a/src/ObjWriting/Game/T5/Material/DumperMaterialT5.h b/src/ObjWriting/Game/T5/Material/DumperMaterialT5.h new file mode 100644 index 00000000..bb13565c --- /dev/null +++ b/src/ObjWriting/Game/T5/Material/DumperMaterialT5.h @@ -0,0 +1,17 @@ +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include "Game/T5/T5.h" + +namespace T5 +{ + class AssetDumperMaterial final : public AbstractAssetDumper + { + public: + void DumpPool(AssetDumpingContext& context, AssetPool* pool) override; + + protected: + bool ShouldDump(XAssetInfo* asset) override; + void DumpAsset(AssetDumpingContext& context, XAssetInfo* asset) override; + }; +} // namespace T5 diff --git a/src/ObjWriting/Game/T5/Material/MaterialConstantZoneStateT5.cpp b/src/ObjWriting/Game/T5/Material/MaterialConstantZoneStateT5.cpp new file mode 100644 index 00000000..003d74cb --- /dev/null +++ b/src/ObjWriting/Game/T5/Material/MaterialConstantZoneStateT5.cpp @@ -0,0 +1,524 @@ +#include "MaterialConstantZoneStateT5.h" + +#include "Game/T5/CommonT5.h" +#include "Game/T5/GameAssetPoolT5.h" +#include "Game/T5/GameT5.h" +#include "ObjWriting.h" + +namespace T5 +{ + const char* KNOWN_CONSTANT_NAMES[]{ + "AngularVelocityScale", + "AnimSpeed", + "Background", + "BackgroundColor", + "BackgroundNoise", + "BakedLightingIntensity", + "BloodBrightness", + "BloodIntensity", + "BlurAmount", + "CapWidth", + "Char_Size", + "Char_Width", + "Coarseness", + "Color", + "ColorAmount", + "ColorBias", + "Color_Map_Noise", + "Color_Map_Scale", + "Color_Map_Size_Scale", + "DDXScale", + "DDYScale", + "DarkenAmount", + "DarkenPower", + "Detail_Amount", + "Detail_Normal_Tile", + "Diffuse_Normal_Height_Facing", + "Dimensions", + "DispersionAmount", + "Dolly", + "EdgeColor", + "EdgeHarshness", + "EdgeIntensity", + "EdgeMaxDist", + "EdgeMinDist", + "EdgeSize", + "Edge_Color_Multiplier", + "Emissive_Amount", + "EnemiesColor", + "Exposure", + "FPS", + "Fade_Distance", + "Fill_Direction", + "Fill_Direction2", + "FirstFrame", + "FlareIntensity", + "FlareScale", + "FlattenEdges", + "Flicker_Max", + "Flicker_Min", + "Flicker_Seed", + "Flicker_Speed", + "Font_Color", + "Gamma", + "GlossAmount", + "Gloss_Amount", + "Glow_Alt_Color", + "Glow_Color", + "Glow_Falloff", + "GradientColor", + "GradientMax", + "GradientMin", + "Grain_Amount", + "Grain_Color", + "Grid", + "Hardness", + "Heart_Rate_Offset", + "Heart_Rate_Scale", + "Highlight_1_Brightness", + "Highlight_1_Sharpness", + "Highlight_2_Brightness", + "Highlight_2_Sharpness", + "Highlight_2_Size", + "Hightlight_1_Size", + "Holo_Scale", + "LastFrame", + "Layer1Alpha", + "Layer1Depth", + "Layer1Offset", + "Layer1OffsetBobbleDelay", + "Layer1OffsetBobbleSpeedAndSize", + "Layer1Origin", + "Layer1Rotation", + "Layer1Scale", + "Layer1ScaleBobbleDelay", + "Layer1ScaleBobbleSpeedAndSize", + "Layer1Scroll", + "Layer2Alpha", + "Layer2Depth", + "Layer2Offset", + "Layer2OffsetBobbleDelay", + "Layer2OffsetBobbleSpeedAndSize", + "Layer2Origin", + "Layer2Rotation", + "Layer2Scale", + "Layer2ScaleBobbleDelay", + "Layer2ScaleBobbleSpeedAndSize", + "Layer2Scroll", + "Layer3Alpha", + "Layer3Depth", + "Layer3Offset", + "Layer3Origin", + "Layer3Rotation", + "Layer3Scale", + "Layer3Scroll", + "Layer4Alpha", + "Layer4Depth", + "Layer4Offset", + "Layer4Origin", + "Layer4Rotation", + "Layer4Scale", + "Layer4Scroll", + "LineColor", + "LineNoise", + "LineWidth", + "MaxDepth", + "MaxFlickerColor", + "MaxPulseDepth", + "MaxResolution", + "Max_Color", + "Maximum_Distance", + "Midlayer_Depth", + "MinDepth", + "MinFlickerColor", + "MinResolution", + "MinStatic", + "MinVelocityFraction", + "Min_Color", + "Min_Player_Intensity", + "MomentumColor", + "NegativeColor", + "NoisePower", + "Noise_Scale", + "NormalHeightMultiplier", + "Normal_Detail_Height", + "Normal_Detail_Scale", + "Normal_Map_Size_Scale", + "Normal_Variance_Scale", + "NumFrames", + "Outline_Lookup_Scale", + "OverallAmount", + "OverallBrightness", + "Overlay_Color", + "P1", + "P2", + "Padding", + "Player_Color_Multiplier", + "Player_Lookup_Scale", + "PositiveColor", + "Power", + "PulseColor", + "PulseInterval", + "PulseTime", + "Pulse_Color_Multiplier", + "Pulse_Lookup_Scale", + "Radius", + "ReflectionAmount", + "Reflection_Amount", + "Reflection_Blur", + "Reticle_Alt_Color", + "Reticle_Color", + "Row_Chars_", + "Scale", + "ScanlineColor", + "ScanlineIntensity", + "ScanlineOffset", + "ScanlinePower", + "ScanlineSpeed", + "ScatterAmount", + "ScatterSize", + "SceneNoise", + "SparkleBrightness", + "SparkleDensity", + "SparklePower", + "SparkleProbeAmount", + "SparkleScale", + "SparkleSpecAmount", + "SparkleWash", + "SpecGloss_Map_Size_Scale", + "SpecularAmount", + "SpecularColor", + "Specular_Amount", + "Specular_Decay_Threshold", + "Speed", + "StaticAmount", + "StaticLookupSpeed", + "StaticLookupX", + "StaticScale", + "Static_Size", + "Static_amount", + "TearLookupMaxX", + "TearLookupMinX", + "TearLookupSpeed", + "TearMultiplier", + "TearPower", + "Thickness", + "TickMarkColorAndHarshness", + "Tint", + "VelocityScale", + "VignetteMultiplier", + "VignettePower", + "WarpAmount", + "WarpHeight", + "WarpScale", + "WarpSpeed", + "WashOut", + "WashoutMultiply", + "WaterDirection", + "WaterHeight", + "WaterRefraction", + "WaterScale1", + "WaterScale2", + "WaterSpeed1", + "WaterSpeed2", + "Zoom", + "alphaDissolveParms", + "alphaRevealParms", + "alphaRevealParms1", + "alphaRevealParms2", + "alphaRevealParms3", + "alphaRevealParms4", + "clipSpaceLookupOffset", + "clipSpaceLookupScale", + "cloudsFeather", + "cloudsHeights", + "cloudsUVMad1", + "cloudsUVMad2", + "cloudsUVMul1", + "cloudsUVMul2", + "codeMeshArg", + "colorDetailScale", + "colorObjMax", + "colorObjMaxBaseBlend", + "colorObjMin", + "colorObjMinBaseBlend", + "colorTint", + "debugBumpmap", + "debugPerformance", + "detailScale", + "detailScale1", + "detailScale2", + "detailScale3", + "detailScale4", + "distortionScale", + "dofEquationScene", + "dofEquationViewModelAndFarBlur", + "dofLerpBias", + "dofLerpDownBias", + "dofLerpDownScale", + "dofLerpScale", + "dofLerpUpBias", + "dofLerpUpScale", + "dofRowDelta", + "eyeOffsetParms", + "falloffBeginColor", + "falloffEndColor", + "falloffParms", + "featherParms", + "flagParams", + "framebufferRead", + "gameTime", + "hdrAmount", + "inverseTransposeWorldMatrix", + "inverseTransposeWorldViewMatrix", + "inverseWorldMatrix", + "inverseWorldViewMatrix", + "motionblurDirectionAndMagnitude", + "occlusionAmount", + "occlusionAmount1", + "occlusionAmount2", + "occlusionAmount3", + "occlusionAmount4", + "particleCloudColor", + "particleCloudMatrix", + "particleCloudVelWorld", + "resizeParams1", + "resizeParams2", + "scaleRGB", + "scriptVector0", + "scriptVector1", + "scriptVector2", + "scriptVector3", + "scriptVector4", + "scriptVector5", + "scriptVector6", + "scriptVector7", + "skyBoxCloudWeights", + "skyBoxRotationSize", + "skyColorParms", + "spotLightWeight", + "treeCanopyLightingParms", + "treeCanopyScatterColor", + "treeCanopySwayParms", + "ui3dUVSetup0", + "ui3dUVSetup1", + "ui3dUVSetup2", + "ui3dUVSetup3", + "ui3dUVSetup4", + "ui3dUVSetup5", + "uvAnimParms", + "uvScroll", + "viewMatrix", + "weaponParam0", + "weaponParam1", + "weaponParam2", + "weaponParam3", + "weaponParam4", + "weaponParam5", + "weaponParam6", + "weaponParam7", + "weaponParam8", + "weaponParam9", + "worldViewMatrix", + "worldViewProjectionMatrix", + }; + + const char* KNOWN_TEXTURE_DEF_NAMES[]{ + "AddMap", + "Blip_Mask", + "BlockNoise", + "CS_Z_buffer", + "Camo_Detail_Map", + "Color_Map", + "CompassMap", + "Detail_Map", + "Diffuse", + "Diffuse_Map", + "DpadTexture", + "FontTextutre", + "Grain_Map", + "GridTexture", + "GrimeMap", + "Heart_Rate_Image", + "Hologram_Diffuse", + "Image", + "Layer1Map", + "Layer2Map", + "Layer3Map", + "Layer4Map", + "Lookup", + "Lookup2", + "LookupMap", + "Mask", + "Noise", + "Noise_Texture", + "NormalDetailMap", + "Normal_Detail_Map", + "Normal_Map", + "Overlay_Map", + "Reflection_Mask", + "Reveal_Map", + "Rim_Color_Mask", + "Rim_Specular_Mask", + "Rim_Occlusion_Mask", + "Scanline", + "SparkleMap", + "SpecularAndGloss", + "SpecularAndGloss2", + "Specular_Color_Map", + "Specular_Gloss_Map", + "Specular_Map", + "SpotShadowSamplerState", + "SpotShadowState", + "SpriteMap", + "Static", + "StaticMap", + "Static_Noise_Map", + "SunShadowSamplerState", + "SunShadowState", + "Surface_Normal_Map", + "ThermalMapMask", + "Thermal_Gradient", + "Thermal_Map", + "TickMarkMaterial", + "Tile", + "WarpMap", + "WaterNormalMap", + "Weapon_Normal_Map", + "Weapon_Specular_Map", + "Wireframe", + "ZBuffer_Map", + "attenuation", + "attenuationSampler", + "baseLut2D", + "baseLut2DSampler", + "cinematicA", + "cinematicASampler", + "cinematicCb", + "cinematicCbSampler", + "cinematicCr", + "cinematicCrSampler", + "cinematicY", + "cinematicYSampler", + "codeTexture0", + "codeTexture1", + "codeTexture2", + "color", + "colorDetailMap", + "colorDetailMapSampler", + "colorMap", + "colorMap1", + "colorMap2", + "colorMap2D", + "colorMapPostSun", + "colorMapPostSunSampler", + "colorMapSampler", + "colorMapSampler1", + "colorMapSampler2", + "colorSampler", + "detailMap", + "detailMapSampler", + "dlightAttenuation", + "dlightAttenuationSampler", + "floatZ", + "floatZSampler", + "imageSampler", + "lightmapSamplerSecondary", + "lightmapSecondary", + "lut2D", + "lut2DSampler", + "lut3D", + "lut3DSampler", + "missileCam", + "missileCamSampler", + "modelLighting", + "modelLightingSampler", + "normalMap", + "normalMap1", + "normalMap2", + "normalMapSampler", + "normalMapSampler1", + "normalMapSampler2", + "occlusionMap", + "occlusionMapSampler", + "occMap", + "occMapSampler", + "outdoorMap", + "outdoorMapSampler", + "radiantDiffuseMap", + "rawFloatZ", + "rawFloatZSampler", + "reflectionProbe", + "reflectionProbeSampler", + "shadowmapSamplerSpot", + "shadowmapSamplerSun", + "shadowmapSpot", + "shadowmapSun", + "sonarColor", + "sonarColorSampler", + "sonarDepth", + "sonarDepthSampler", + "source", + "specularMap", + "specularMap1", + "specularMap2", + "specularMapSampler", + "specularMapSampler1", + "specularMapSampler2", + "stencil", + "stencilSampler", + "ui3d", + "ui3dSampler", + }; + + void MaterialConstantZoneState::ExtractNamesFromZoneInternal() + { + for (const auto* zone : IGame::GetGameById(GameId::T6)->GetZones()) + { + const auto* assetPools = dynamic_cast(zone->m_pools.get()); + if (!assetPools) + return; + + for (const auto* techniqueSetInfo : *assetPools->m_technique_set) + { + const auto* techniqueSet = techniqueSetInfo->Asset(); + + for (const auto* technique : techniqueSet->techniques) + { + if (technique) + ExtractNamesFromTechnique(technique); + } + } + } + } + + unsigned MaterialConstantZoneState::HashString(const std::string& str) + { + 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 T5 diff --git a/src/ObjWriting/Game/T5/Material/MaterialConstantZoneStateT5.h b/src/ObjWriting/Game/T5/Material/MaterialConstantZoneStateT5.h new file mode 100644 index 00000000..f9c83922 --- /dev/null +++ b/src/ObjWriting/Game/T5/Material/MaterialConstantZoneStateT5.h @@ -0,0 +1,18 @@ +#pragma once + +#include "Game/T5/T5.h" +#include "Material/AbstractMaterialConstantZoneState.h" + +#include + +namespace T5 +{ + class MaterialConstantZoneState final : public AbstractMaterialConstantZoneStateDx11 + { + protected: + void ExtractNamesFromZoneInternal() override; + void ExtractNamesFromTechnique(const MaterialTechnique* technique); + void AddStaticKnownNames() override; + unsigned HashString(const std::string& str) override; + }; +} // namespace T5 diff --git a/src/ObjWriting/Game/T5/ObjWriterT5.cpp b/src/ObjWriting/Game/T5/ObjWriterT5.cpp index b1c06e2e..ce6dab53 100644 --- a/src/ObjWriting/Game/T5/ObjWriterT5.cpp +++ b/src/ObjWriting/Game/T5/ObjWriterT5.cpp @@ -10,6 +10,7 @@ #include "AssetDumpers/AssetDumperWeapon.h" #include "AssetDumpers/AssetDumperXModel.h" #include "Game/T5/GameAssetPoolT5.h" +#include "Material/DumperMaterialT5.h" #include "ObjWriting.h" using namespace T5; @@ -30,7 +31,7 @@ bool ObjWriter::DumpZone(AssetDumpingContext& context) const // DUMP_ASSET_POOL(AssetDumperDestructibleDef, m_destructible_def, ASSET_TYPE_DESTRUCTIBLEDEF) // DUMP_ASSET_POOL(AssetDumperXAnimParts, m_xanim_parts, ASSET_TYPE_XANIMPARTS) DUMP_ASSET_POOL(AssetDumperXModel, m_xmodel, ASSET_TYPE_XMODEL) - // DUMP_ASSET_POOL(AssetDumperMaterial, m_material, ASSET_TYPE_MATERIAL) + DUMP_ASSET_POOL(AssetDumperMaterial, m_material, ASSET_TYPE_MATERIAL) // DUMP_ASSET_POOL(AssetDumperTechniqueSet, m_technique_set, ASSET_TYPE_TECHNIQUE_SET) DUMP_ASSET_POOL(AssetDumperGfxImage, m_image, ASSET_TYPE_IMAGE) // DUMP_ASSET_POOL(AssetDumperSndBank, m_sound_bank, ASSET_TYPE_SOUND) diff --git a/src/ObjWriting/Game/T6/Material/DumperMaterialT6.cpp b/src/ObjWriting/Game/T6/Material/DumperMaterialT6.cpp index a245cc18..c90c2eb7 100644 --- a/src/ObjWriting/Game/T6/Material/DumperMaterialT6.cpp +++ b/src/ObjWriting/Game/T6/Material/DumperMaterialT6.cpp @@ -4,6 +4,8 @@ #include "Game/T6/Material/MaterialConstantZoneStateT6.h" #include "Material/MaterialCommon.h" +#include + using namespace T6; void AssetDumperMaterial::DumpPool(AssetDumpingContext& context, AssetPool* pool) @@ -26,5 +28,7 @@ void AssetDumperMaterial::DumpAsset(AssetDumpingContext& context, XAssetInfoAsset(), context); + const auto* material = asset->Asset(); + assert(material->info.gameFlags < 0x8000); + DumpMaterialAsJson(*assetFile, *material, context); } diff --git a/src/ObjWriting/Material/JsonMaterialWriter.cpp.template b/src/ObjWriting/Material/JsonMaterialWriter.cpp.template index f87ca242..00cc2b43 100644 --- a/src/ObjWriting/Material/JsonMaterialWriter.cpp.template +++ b/src/ObjWriting/Material/JsonMaterialWriter.cpp.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T6) +#options GAME (IW3, IW4, IW5, T5, T6) #filename "Game/" + GAME + "/Material/JsonMaterialWriter" + GAME + ".cpp" @@ -14,6 +14,10 @@ #define FEATURE_IW5 #define HAS_WATER #define GAME_LOWER "iw5" +#elif GAME == "T5" +#define FEATURE_T5 +#define HAS_WATER +#define GAME_LOWER "t5" #elif GAME == "T6" #define FEATURE_T6 #define GAME_LOWER "t6" @@ -144,7 +148,7 @@ namespace } jTextureDef.semantic = static_cast(textureDef.semantic); -#if defined(FEATURE_T6) +#if defined(FEATURE_T5) || defined(FEATURE_T6) jTextureDef.isMatureContent = textureDef.isMatureContent; #endif @@ -224,6 +228,8 @@ namespace || structured.alphaTest == GFXS_ALPHA_TEST_GT_0 #if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) || structured.alphaTest == GFXS_ALPHA_TEST_LT_128 +#elif defined(FEATURE_T5) + || structured.alphaTest == GFXS_ALPHA_TEST_GE_255 #endif || structured.alphaTest == GFXS_ALPHA_TEST_GE_128); if (structured.alphaTestDisabled) @@ -233,6 +239,9 @@ namespace #if defined(FEATURE_IW3) || defined(FEATURE_IW4) || defined(FEATURE_IW5) else if (structured.alphaTest == GFXS_ALPHA_TEST_LT_128) jStateBitsTableEntry.alphaTest = JsonAlphaTest::LT128; +#elif defined(FEATURE_T5) + else if (structured.alphaTest == GFXS_ALPHA_TEST_GE_255) + jStateBitsTableEntry.alphaTest = JsonAlphaTest::GE255; #endif else if (structured.alphaTest == GFXS_ALPHA_TEST_GE_128) jStateBitsTableEntry.alphaTest = JsonAlphaTest::GE128; @@ -317,7 +326,9 @@ namespace jMaterial.stateFlags = material.stateFlags; jMaterial.cameraRegion = static_cast(material.cameraRegion); -#ifdef FEATURE_T6 +#if defined(FEATURE_T5) + jMaterial.maxStreamedMips = material.maxStreamedMips; +#elif defined(FEATURE_T6) jMaterial.probeMipBits = material.probeMipBits; #endif diff --git a/src/ObjWriting/Material/JsonMaterialWriter.h.template b/src/ObjWriting/Material/JsonMaterialWriter.h.template index 82362d35..277c5420 100644 --- a/src/ObjWriting/Material/JsonMaterialWriter.h.template +++ b/src/ObjWriting/Material/JsonMaterialWriter.h.template @@ -1,4 +1,4 @@ -#options GAME (IW3, IW4, IW5, T6) +#options GAME (IW3, IW4, IW5, T5, T6) #filename "Game/" + GAME + "/Material/JsonMaterialWriter" + GAME + ".h"