From 9827218f4a5de4fd5f2c5ddf4ec7485a86118ccc Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 29 Jun 2025 12:41:54 +0100 Subject: [PATCH] chore: add tests for material dumpers --- .github/workflows/ci.yaml | 3 + premake5.lua | 2 + test/ObjCommonTestUtils/NormalizedJson.cpp | 11 + test/ObjCommonTestUtils/NormalizedJson.h | 5 + test/ObjWritingTests.lua | 58 ++ .../IW4/Material/DumperMaterialIW4Test.cpp | 552 ++++++++++++++++ .../IW5/Material/DumperMaterialIW5Test.cpp | 605 ++++++++++++++++++ .../Game/T6/Material/DumperMaterialT6Test.cpp | 484 ++++++++++++++ 8 files changed, 1720 insertions(+) create mode 100644 test/ObjCommonTestUtils/NormalizedJson.cpp create mode 100644 test/ObjCommonTestUtils/NormalizedJson.h create mode 100644 test/ObjWritingTests.lua create mode 100644 test/ObjWritingTests/Game/IW4/Material/DumperMaterialIW4Test.cpp create mode 100644 test/ObjWritingTests/Game/IW5/Material/DumperMaterialIW5Test.cpp create mode 100644 test/ObjWritingTests/Game/T6/Material/DumperMaterialT6Test.cpp diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 047661c3..1a4412a0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -46,6 +46,7 @@ jobs: ./ObjCommonTests ./ObjCompilingTests ./ObjLoadingTests + ./ObjWritingTests ./ParserTests ./ZoneCodeGeneratorLibTests ./ZoneCommonTests @@ -89,6 +90,8 @@ jobs: $combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE) ./ObjLoadingTests $combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE) + ./ObjWritingTests + $combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE) ./ParserTests $combinedExitCode = [System.Math]::max($combinedExitCode, $LASTEXITCODE) ./ZoneCodeGeneratorLibTests diff --git a/premake5.lua b/premake5.lua index 245f4a6e..4a0f4d8a 100644 --- a/premake5.lua +++ b/premake5.lua @@ -184,6 +184,7 @@ include "test/ObjCommonTestUtils.lua" include "test/ObjCommonTests.lua" include "test/ObjCompilingTests.lua" include "test/ObjLoadingTests.lua" +include "test/ObjWritingTests.lua" include "test/ParserTestUtils.lua" include "test/ParserTests.lua" include "test/ZoneCodeGeneratorLibTests.lua" @@ -196,6 +197,7 @@ group "Tests" ObjCommonTests:project() ObjCompilingTests:project() ObjLoadingTests:project() + ObjWritingTests:project() ParserTestUtils:project() ParserTests:project() ZoneCodeGeneratorLibTests:project() diff --git a/test/ObjCommonTestUtils/NormalizedJson.cpp b/test/ObjCommonTestUtils/NormalizedJson.cpp new file mode 100644 index 00000000..c06ffbb2 --- /dev/null +++ b/test/ObjCommonTestUtils/NormalizedJson.cpp @@ -0,0 +1,11 @@ +#include "NormalizedJson.h" + +#include + +using namespace nlohmann; + +std::string JsonNormalized(const std::string& str0) +{ + const json j0 = json::parse(str0); + return j0.dump(4); +} diff --git a/test/ObjCommonTestUtils/NormalizedJson.h b/test/ObjCommonTestUtils/NormalizedJson.h new file mode 100644 index 00000000..ad7a1df3 --- /dev/null +++ b/test/ObjCommonTestUtils/NormalizedJson.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +std::string JsonNormalized(const std::string& str0); diff --git a/test/ObjWritingTests.lua b/test/ObjWritingTests.lua new file mode 100644 index 00000000..8afcba6c --- /dev/null +++ b/test/ObjWritingTests.lua @@ -0,0 +1,58 @@ +ObjWritingTests = {} + +function ObjWritingTests:include(includes) + if includes:handle(self:name()) then + includedirs { + path.join(TestFolder(), "ObjWritingTests") + } + end +end + +function ObjWritingTests:link(links) + +end + +function ObjWritingTests:use() + +end + +function ObjWritingTests:name() + return "ObjWritingTests" +end + +function ObjWritingTests:project() + local folder = TestFolder() + local includes = Includes:create() + local links = Links:create() + + project(self:name()) + targetdir(TargetDirectoryTest) + location "%{wks.location}/test/%{prj.name}" + kind "ConsoleApp" + language "C++" + + files { + path.join(folder, "ObjWritingTests/**.h"), + path.join(folder, "ObjWritingTests/**.cpp") + } + + vpaths { + ["*"] = { + path.join(folder, "ObjWritingTests") + } + } + + self:include(includes) + Catch2Common:include(includes) + ObjCommonTestUtils:include(includes) + ParserTestUtils:include(includes) + ObjWriting:include(includes) + catch2:include(includes) + + links:linkto(ObjCommonTestUtils) + links:linkto(ParserTestUtils) + links:linkto(ObjWriting) + links:linkto(catch2) + links:linkto(Catch2Common) + links:linkall() +end diff --git a/test/ObjWritingTests/Game/IW4/Material/DumperMaterialIW4Test.cpp b/test/ObjWritingTests/Game/IW4/Material/DumperMaterialIW4Test.cpp new file mode 100644 index 00000000..2d33bd2d --- /dev/null +++ b/test/ObjWritingTests/Game/IW4/Material/DumperMaterialIW4Test.cpp @@ -0,0 +1,552 @@ +#include "Game/IW4/Material/DumperMaterialIW4.h" + +#include "Asset/AssetRegistration.h" +#include "Game/IW4/CommonIW4.h" +#include "Game/IW4/GameIW4.h" +#include "NormalizedJson.h" +#include "Pool/AssetPoolDynamic.h" +#include "SearchPath/MockOutputPath.h" +#include "SearchPath/MockSearchPath.h" +#include "Utils/MemoryManager.h" + +#include +#include +#include + +using namespace IW4; +using namespace Catch; +using namespace std::literals; + +namespace +{ + GfxImage* GivenImage(const std::string& name, MemoryManager& memory) + { + auto* image = memory.Alloc(); + image->name = memory.Dup(name.c_str()); + + return image; + } + + MaterialTechniqueSet* GivenTechset(const std::string& name, MemoryManager& memory) + { + auto* techset = memory.Alloc(); + techset->name = memory.Dup(name.c_str()); + + return techset; + } + + void GivenMaterial(const std::string& name, AssetPool& pool, MemoryManager& memory) + { + auto* material = memory.Alloc(); + material->info.name = memory.Dup(name.c_str()); + material->info.gameFlags = 0x50; + material->info.sortKey = 1; + material->info.textureAtlasRowCount = 1; + material->info.textureAtlasColumnCount = 1; + material->info.surfaceTypeBits = 0x10; + + constexpr int8_t stateBitsEntry[] = {0, 1, 2, 1, 3, -1, -1, -1, -1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, -1, -1, -1, -1, 5, -1, 3, 3}; + std::memcpy(material->stateBitsEntry, stateBitsEntry, sizeof(material->stateBitsEntry)); + + material->cameraRegion = CAMERA_REGION_LIT_OPAQUE; + material->stateFlags = 121; + material->techniqueSet = GivenTechset("mc_l_sm_r0c0n0s0", memory); + + material->textureCount = 3; + material->textureTable = memory.Alloc(3); + + auto& textureDef0 = material->textureTable[0]; + textureDef0.u.image = GivenImage("~ch_rubble02_spc-r-74g-74b-74~1eb1f0d0", memory); + textureDef0.nameHash = 0x34ecccb3; + textureDef0.nameStart = 's'; + textureDef0.nameEnd = 'p'; + textureDef0.samplerState.filter = TEXTURE_FILTER_ANISO2X; + textureDef0.samplerState.mipMap = TEXTURE_FILTER_NEAREST; + textureDef0.samplerState.clampU = 0; + textureDef0.samplerState.clampV = 0; + textureDef0.samplerState.clampW = 0; + textureDef0.semantic = TS_SPECULAR_MAP; + + auto& textureDef1 = material->textureTable[1]; + textureDef1.u.image = GivenImage("ch_rubble01_nml", memory); + textureDef1.nameHash = 0x59d30d0f; + textureDef1.nameStart = 'n'; + textureDef1.nameEnd = 'p'; + textureDef1.samplerState.filter = TEXTURE_FILTER_ANISO2X; + textureDef1.samplerState.mipMap = TEXTURE_FILTER_NEAREST; + textureDef1.samplerState.clampU = 0; + textureDef1.samplerState.clampV = 0; + textureDef1.samplerState.clampW = 0; + textureDef1.semantic = TS_NORMAL_MAP; + + auto& textureDef2 = material->textureTable[2]; + textureDef2.u.image = GivenImage("ch_rubble01_col", memory); + textureDef2.nameHash = 0xa0ab1041; + textureDef2.nameStart = 'c'; + textureDef2.nameEnd = 'p'; + textureDef2.samplerState.filter = TEXTURE_FILTER_ANISO2X; + textureDef2.samplerState.mipMap = TEXTURE_FILTER_NEAREST; + textureDef2.samplerState.clampU = 0; + textureDef2.samplerState.clampV = 0; + textureDef2.samplerState.clampW = 0; + textureDef2.semantic = TS_COLOR_MAP; + + material->constantCount = 2; + material->constantTable = memory.Alloc(2); + + auto& constantDef0 = material->constantTable[0]; + constantDef0.nameHash = 0x3d9994dc; + strncpy(constantDef0.name, "envMapParms", std::extent_v); + constantDef0.literal.x = 0.07f; + constantDef0.literal.y = 0.46f; + constantDef0.literal.z = 1.6f; + constantDef0.literal.w = 2.0f; + + auto& constantDef1 = material->constantTable[1]; + constantDef1.nameHash = 0xb60c3b3a; + strncpy(constantDef1.name, "colorTint", std::extent_v); + constantDef1.literal.x = 1.0f; + constantDef1.literal.y = 1.0f; + constantDef1.literal.z = 1.0f; + constantDef1.literal.w = 1.0f; + + material->stateBitsCount = 6; + material->stateBitsTable = memory.Alloc(6); + + auto& stateBits0 = material->stateBitsTable[0]; + stateBits0.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits0.loadBits.structured.dstBlendRgb = GFXS_BLEND_ZERO; + stateBits0.loadBits.structured.blendOpRgb = GFXS_BLENDOP_DISABLED; + stateBits0.loadBits.structured.alphaTestDisabled = 1; + stateBits0.loadBits.structured.alphaTest = 0; + stateBits0.loadBits.structured.cullFace = GFXS_CULL_BACK; + stateBits0.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits0.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits0.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits0.loadBits.structured.colorWriteRgb = 0; + stateBits0.loadBits.structured.colorWriteAlpha = 0; + stateBits0.loadBits.structured.gammaWrite = 0; + stateBits0.loadBits.structured.polymodeLine = 0; + stateBits0.loadBits.structured.depthWrite = 1; + stateBits0.loadBits.structured.depthTestDisabled = 0; + stateBits0.loadBits.structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL; + stateBits0.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_0; + stateBits0.loadBits.structured.stencilFrontEnabled = 0; + stateBits0.loadBits.structured.stencilFrontPass = 0; + stateBits0.loadBits.structured.stencilFrontFail = 0; + stateBits0.loadBits.structured.stencilFrontZFail = 0; + stateBits0.loadBits.structured.stencilFrontFunc = 0; + stateBits0.loadBits.structured.stencilBackEnabled = 0; + stateBits0.loadBits.structured.stencilBackPass = 0; + stateBits0.loadBits.structured.stencilBackFail = 0; + stateBits0.loadBits.structured.stencilBackZFail = 0; + stateBits0.loadBits.structured.stencilBackFunc = 0; + + auto& stateBits1 = material->stateBitsTable[1]; + stateBits1.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits1.loadBits.structured.dstBlendRgb = GFXS_BLEND_ZERO; + stateBits1.loadBits.structured.blendOpRgb = GFXS_BLENDOP_DISABLED; + stateBits1.loadBits.structured.alphaTestDisabled = 1; + stateBits1.loadBits.structured.alphaTest = 0; + stateBits1.loadBits.structured.cullFace = GFXS_CULL_BACK; + stateBits1.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits1.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits1.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits1.loadBits.structured.colorWriteRgb = 1; + stateBits1.loadBits.structured.colorWriteAlpha = 1; + stateBits1.loadBits.structured.gammaWrite = 0; + stateBits1.loadBits.structured.polymodeLine = 0; + stateBits1.loadBits.structured.depthWrite = 1; + stateBits1.loadBits.structured.depthTestDisabled = 0; + stateBits1.loadBits.structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL; + stateBits1.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_0; + stateBits1.loadBits.structured.stencilFrontEnabled = 0; + stateBits1.loadBits.structured.stencilFrontPass = 0; + stateBits1.loadBits.structured.stencilFrontFail = 0; + stateBits1.loadBits.structured.stencilFrontZFail = 0; + stateBits1.loadBits.structured.stencilFrontFunc = 0; + stateBits1.loadBits.structured.stencilBackEnabled = 0; + stateBits1.loadBits.structured.stencilBackPass = 0; + stateBits1.loadBits.structured.stencilBackFail = 0; + stateBits1.loadBits.structured.stencilBackZFail = 0; + stateBits1.loadBits.structured.stencilBackFunc = 0; + + auto& stateBits2 = material->stateBitsTable[2]; + stateBits2.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits2.loadBits.structured.dstBlendRgb = GFXS_BLEND_ZERO; + stateBits2.loadBits.structured.blendOpRgb = GFXS_BLENDOP_DISABLED; + stateBits2.loadBits.structured.alphaTestDisabled = 1; + stateBits2.loadBits.structured.alphaTest = 0; + stateBits2.loadBits.structured.cullFace = GFXS_CULL_BACK; + stateBits2.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits2.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits2.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits2.loadBits.structured.colorWriteRgb = 0; + stateBits2.loadBits.structured.colorWriteAlpha = 0; + stateBits2.loadBits.structured.gammaWrite = 0; + stateBits2.loadBits.structured.polymodeLine = 0; + stateBits2.loadBits.structured.depthWrite = 1; + stateBits2.loadBits.structured.depthTestDisabled = 0; + stateBits2.loadBits.structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL; + stateBits2.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_SHADOWMAP; + stateBits2.loadBits.structured.stencilFrontEnabled = 0; + stateBits2.loadBits.structured.stencilFrontPass = 0; + stateBits2.loadBits.structured.stencilFrontFail = 0; + stateBits2.loadBits.structured.stencilFrontZFail = 0; + stateBits2.loadBits.structured.stencilFrontFunc = 0; + stateBits2.loadBits.structured.stencilBackEnabled = 0; + stateBits2.loadBits.structured.stencilBackPass = 0; + stateBits2.loadBits.structured.stencilBackFail = 0; + stateBits2.loadBits.structured.stencilBackZFail = 0; + stateBits2.loadBits.structured.stencilBackFunc = 0; + + auto& stateBits3 = material->stateBitsTable[3]; + stateBits3.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits3.loadBits.structured.dstBlendRgb = GFXS_BLEND_ZERO; + stateBits3.loadBits.structured.blendOpRgb = GFXS_BLENDOP_DISABLED; + stateBits3.loadBits.structured.alphaTestDisabled = 1; + stateBits3.loadBits.structured.alphaTest = 0; + stateBits3.loadBits.structured.cullFace = GFXS_CULL_BACK; + stateBits3.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits3.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits3.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits3.loadBits.structured.colorWriteRgb = 1; + stateBits3.loadBits.structured.colorWriteAlpha = 1; + stateBits3.loadBits.structured.gammaWrite = 1; + stateBits3.loadBits.structured.polymodeLine = 0; + stateBits3.loadBits.structured.depthWrite = 1; + stateBits3.loadBits.structured.depthTestDisabled = 0; + stateBits3.loadBits.structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL; + stateBits3.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_0; + stateBits3.loadBits.structured.stencilFrontEnabled = 0; + stateBits3.loadBits.structured.stencilFrontPass = 0; + stateBits3.loadBits.structured.stencilFrontFail = 0; + stateBits3.loadBits.structured.stencilFrontZFail = 0; + stateBits3.loadBits.structured.stencilFrontFunc = 0; + stateBits3.loadBits.structured.stencilBackEnabled = 0; + stateBits3.loadBits.structured.stencilBackPass = 0; + stateBits3.loadBits.structured.stencilBackFail = 0; + stateBits3.loadBits.structured.stencilBackZFail = 0; + stateBits3.loadBits.structured.stencilBackFunc = 0; + + auto& stateBits4 = material->stateBitsTable[4]; + stateBits4.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits4.loadBits.structured.dstBlendRgb = GFXS_BLEND_ONE; + stateBits4.loadBits.structured.blendOpRgb = GFXS_BLENDOP_ADD; + stateBits4.loadBits.structured.alphaTestDisabled = 1; + stateBits4.loadBits.structured.alphaTest = 0; + stateBits4.loadBits.structured.cullFace = GFXS_CULL_BACK; + stateBits4.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits4.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits4.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits4.loadBits.structured.colorWriteRgb = 1; + stateBits4.loadBits.structured.colorWriteAlpha = 1; + stateBits4.loadBits.structured.gammaWrite = 1; + stateBits4.loadBits.structured.polymodeLine = 0; + stateBits4.loadBits.structured.depthWrite = 0; + stateBits4.loadBits.structured.depthTestDisabled = 0; + stateBits4.loadBits.structured.depthTest = GFXS_DEPTHTEST_EQUAL; + stateBits4.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_0; + stateBits4.loadBits.structured.stencilFrontEnabled = 1; + stateBits4.loadBits.structured.stencilFrontPass = GFXS_STENCILOP_KEEP; + stateBits4.loadBits.structured.stencilFrontFail = GFXS_STENCILOP_KEEP; + stateBits4.loadBits.structured.stencilFrontZFail = GFXS_STENCILOP_KEEP; + stateBits4.loadBits.structured.stencilFrontFunc = GFXS_STENCILFUNC_EQUAL; + stateBits4.loadBits.structured.stencilBackEnabled = 0; + stateBits4.loadBits.structured.stencilBackPass = 0; + stateBits4.loadBits.structured.stencilBackFail = 0; + stateBits4.loadBits.structured.stencilBackZFail = 0; + stateBits4.loadBits.structured.stencilBackFunc = 0; + + auto& stateBits5 = material->stateBitsTable[5]; + stateBits5.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits5.loadBits.structured.dstBlendRgb = GFXS_BLEND_ZERO; + stateBits5.loadBits.structured.blendOpRgb = GFXS_BLENDOP_DISABLED; + stateBits5.loadBits.structured.alphaTestDisabled = 1; + stateBits5.loadBits.structured.alphaTest = 0; + stateBits5.loadBits.structured.cullFace = GFXS_CULL_BACK; + stateBits5.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits5.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits5.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits5.loadBits.structured.colorWriteRgb = 1; + stateBits5.loadBits.structured.colorWriteAlpha = 0; + stateBits5.loadBits.structured.gammaWrite = 0; + stateBits5.loadBits.structured.polymodeLine = 1; + stateBits5.loadBits.structured.depthWrite = 0; + stateBits5.loadBits.structured.depthTestDisabled = 0; + stateBits5.loadBits.structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL; + stateBits5.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_2; + stateBits5.loadBits.structured.stencilFrontEnabled = 0; + stateBits5.loadBits.structured.stencilFrontPass = 0; + stateBits5.loadBits.structured.stencilFrontFail = 0; + stateBits5.loadBits.structured.stencilFrontZFail = 0; + stateBits5.loadBits.structured.stencilFrontFunc = 0; + stateBits5.loadBits.structured.stencilBackEnabled = 0; + stateBits5.loadBits.structured.stencilBackPass = 0; + stateBits5.loadBits.structured.stencilBackFail = 0; + stateBits5.loadBits.structured.stencilBackZFail = 0; + stateBits5.loadBits.structured.stencilBackFunc = 0; + + pool.AddAsset(std::make_unique>(ASSET_TYPE_MATERIAL, name, material)); + } + + TEST_CASE("DumperMaterial(IW4): Can dump material", "[iw4][material][assetdumper]") + { + std::string expected(R"MATERIAL( +{ + "_game": "iw4", + "_type": "material", + "_version": 1, + "cameraRegion": "litOpaque", + "constants": [ + { + "literal": [ + 0.07000000029802322, + 0.46000000834465027, + 1.600000023841858, + 2.0 + ], + "name": "envMapParms" + }, + { + "literal": [ + 1.0, + 1.0, + 1.0, + 1.0 + ], + "name": "colorTint" + } + ], + "gameFlags": [ + "10", + "40" + ], + "sortKey": 1, + "stateBits": [ + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "disabled", + "colorWriteAlpha": false, + "colorWriteRgb": false, + "cullFace": "back", + "depthTest": "less_equal", + "depthWrite": true, + "dstBlendAlpha": "zero", + "dstBlendRgb": "zero", + "gammaWrite": false, + "polygonOffset": "offset0", + "polymodeLine": false, + "srcBlendAlpha": "one", + "srcBlendRgb": "one" + }, + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "disabled", + "colorWriteAlpha": true, + "colorWriteRgb": true, + "cullFace": "back", + "depthTest": "less_equal", + "depthWrite": true, + "dstBlendAlpha": "zero", + "dstBlendRgb": "zero", + "gammaWrite": false, + "polygonOffset": "offset0", + "polymodeLine": false, + "srcBlendAlpha": "one", + "srcBlendRgb": "one" + }, + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "disabled", + "colorWriteAlpha": false, + "colorWriteRgb": false, + "cullFace": "back", + "depthTest": "less_equal", + "depthWrite": true, + "dstBlendAlpha": "zero", + "dstBlendRgb": "zero", + "gammaWrite": false, + "polygonOffset": "offsetShadowmap", + "polymodeLine": false, + "srcBlendAlpha": "one", + "srcBlendRgb": "one" + }, + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "disabled", + "colorWriteAlpha": true, + "colorWriteRgb": true, + "cullFace": "back", + "depthTest": "less_equal", + "depthWrite": true, + "dstBlendAlpha": "zero", + "dstBlendRgb": "zero", + "gammaWrite": true, + "polygonOffset": "offset0", + "polymodeLine": false, + "srcBlendAlpha": "one", + "srcBlendRgb": "one" + }, + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "add", + "colorWriteAlpha": true, + "colorWriteRgb": true, + "cullFace": "back", + "depthTest": "equal", + "depthWrite": false, + "dstBlendAlpha": "zero", + "dstBlendRgb": "one", + "gammaWrite": true, + "polygonOffset": "offset0", + "polymodeLine": false, + "srcBlendAlpha": "one", + "srcBlendRgb": "one", + "stencilFront": { + "fail": "keep", + "func": "equal", + "pass": "keep", + "zfail": "keep" + } + }, + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "disabled", + "colorWriteAlpha": false, + "colorWriteRgb": true, + "cullFace": "back", + "depthTest": "less_equal", + "depthWrite": false, + "dstBlendAlpha": "zero", + "dstBlendRgb": "zero", + "gammaWrite": false, + "polygonOffset": "offset2", + "polymodeLine": true, + "srcBlendAlpha": "one", + "srcBlendRgb": "one" + } + ], + "stateBitsEntry": [ + 0, + 1, + 2, + 1, + 3, + -1, + -1, + -1, + -1, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 3, + 4, + 4, + 4, + -1, + -1, + -1, + -1, + 5, + -1, + 3, + 3 + ], + "stateFlags": 121, + "surfaceTypeBits": 16, + "techniqueSet": "mc_l_sm_r0c0n0s0", + "textureAtlas": { + "columns": 1, + "rows": 1 + }, + "textures": [ + { + "image": "~ch_rubble02_spc-r-74g-74b-74~1eb1f0d0", + "name": "specularMap", + "samplerState": { + "clampU": false, + "clampV": false, + "clampW": false, + "filter": "aniso2x", + "mipMap": "nearest" + }, + "semantic": "specularMap" + }, + { + "image": "ch_rubble01_nml", + "name": "normalMap", + "samplerState": { + "clampU": false, + "clampV": false, + "clampW": false, + "filter": "aniso2x", + "mipMap": "nearest" + }, + "semantic": "normalMap" + }, + { + "image": "ch_rubble01_col", + "name": "colorMap", + "samplerState": { + "clampU": false, + "clampV": false, + "clampW": false, + "filter": "aniso2x", + "mipMap": "nearest" + }, + "semantic": "colorMap" + } + ] +})MATERIAL"); + + Zone zone("MockZone", 0, IGame::GetGameById(GameId::IW4)); + + MemoryManager memory; + MockSearchPath mockObjPath; + MockOutputPath mockOutput; + AssetDumpingContext context(zone, "", mockOutput, mockObjPath); + + AssetPoolDynamic materialPool(0); + + GivenMaterial("mc/ch_rubble01", materialPool, memory); + + AssetDumperMaterial dumper; + dumper.DumpPool(context, &materialPool); + + const auto* file = mockOutput.GetMockedFile("materials/mc/ch_rubble01.json"); + REQUIRE(file); + REQUIRE(JsonNormalized(file->AsString()) == JsonNormalized(expected)); + } +} // namespace diff --git a/test/ObjWritingTests/Game/IW5/Material/DumperMaterialIW5Test.cpp b/test/ObjWritingTests/Game/IW5/Material/DumperMaterialIW5Test.cpp new file mode 100644 index 00000000..cf545055 --- /dev/null +++ b/test/ObjWritingTests/Game/IW5/Material/DumperMaterialIW5Test.cpp @@ -0,0 +1,605 @@ +#include "Game/IW5/Material/DumperMaterialIW5.h" + +#include "Asset/AssetRegistration.h" +#include "Game/IW5/CommonIW5.h" +#include "Game/IW5/GameIW5.h" +#include "NormalizedJson.h" +#include "Pool/AssetPoolDynamic.h" +#include "SearchPath/MockOutputPath.h" +#include "SearchPath/MockSearchPath.h" +#include "Utils/MemoryManager.h" + +#include +#include +#include + +using namespace IW5; +using namespace Catch; +using namespace std::literals; + +namespace +{ + GfxImage* GivenImage(const std::string& name, MemoryManager& memory) + { + auto* image = memory.Alloc(); + image->name = memory.Dup(name.c_str()); + + return image; + } + + MaterialTechniqueSet* GivenTechset(const std::string& name, MemoryManager& memory) + { + auto* techset = memory.Alloc(); + techset->name = memory.Dup(name.c_str()); + + return techset; + } + + void GivenMaterial(const std::string& name, AssetPool& pool, MemoryManager& memory) + { + auto* material = memory.Alloc(); + material->info.name = memory.Dup(name.c_str()); + material->info.gameFlags = 0x52; + material->info.sortKey = 1; + material->info.textureAtlasRowCount = 1; + material->info.textureAtlasColumnCount = 1; + material->info.surfaceTypeBits = 0x1000; + + constexpr int8_t stateBitsEntry[] = {0, 1, 2, 3, 4, -1, -1, -1, -1, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 5, 5, 5, 5, -1, -1, -1, -1, 6, -1, -1, 4, -1}; + std::memcpy(material->stateBitsEntry, stateBitsEntry, sizeof(material->stateBitsEntry)); + + material->cameraRegion = CAMERA_REGION_LIT_OPAQUE; + material->stateFlags = 59; + material->techniqueSet = GivenTechset("wc_l_sm_r0c0n0s0", memory); + + material->textureCount = 3; + material->textureTable = memory.Alloc(3); + + auto& textureDef0 = material->textureTable[0]; + textureDef0.u.image = GivenImage("~me_metal_rusty02_spc-rgb&me_~927de80f", memory); + textureDef0.nameHash = 0x34ecccb3; + textureDef0.nameStart = 's'; + textureDef0.nameEnd = 'p'; + textureDef0.samplerState.filter = TEXTURE_FILTER_ANISO2X; + textureDef0.samplerState.mipMap = TEXTURE_FILTER_NEAREST; + textureDef0.samplerState.clampU = 0; + textureDef0.samplerState.clampV = 0; + textureDef0.samplerState.clampW = 0; + textureDef0.semantic = TS_SPECULAR_MAP; + + auto& textureDef1 = material->textureTable[1]; + textureDef1.u.image = GivenImage("me_metal_rusty02_nml", memory); + textureDef1.nameHash = 0x59d30d0f; + textureDef1.nameStart = 'n'; + textureDef1.nameEnd = 'p'; + textureDef1.samplerState.filter = TEXTURE_FILTER_ANISO2X; + textureDef1.samplerState.mipMap = TEXTURE_FILTER_LINEAR; + textureDef1.samplerState.clampU = 0; + textureDef1.samplerState.clampV = 0; + textureDef1.samplerState.clampW = 0; + textureDef1.semantic = TS_NORMAL_MAP; + + auto& textureDef2 = material->textureTable[2]; + textureDef2.u.image = GivenImage("me_metal_rusty02_col", memory); + textureDef2.nameHash = 0xa0ab1041; + textureDef2.nameStart = 'c'; + textureDef2.nameEnd = 'p'; + textureDef2.samplerState.filter = TEXTURE_FILTER_ANISO2X; + textureDef2.samplerState.mipMap = TEXTURE_FILTER_LINEAR; + textureDef2.samplerState.clampU = 0; + textureDef2.samplerState.clampV = 0; + textureDef2.samplerState.clampW = 0; + textureDef2.semantic = TS_COLOR_MAP; + + material->constantCount = 2; + material->constantTable = memory.Alloc(2); + + auto& constantDef0 = material->constantTable[0]; + constantDef0.nameHash = 0x3d9994dc; + strncpy(constantDef0.name, "envMapParms", std::extent_v); + constantDef0.literal.x = 0.07f; + constantDef0.literal.y = 0.33f; + constantDef0.literal.z = 1.4f; + constantDef0.literal.w = 2.0f; + + auto& constantDef1 = material->constantTable[1]; + constantDef1.nameHash = 0xb60c3b3a; + strncpy(constantDef1.name, "colorTint", std::extent_v); + constantDef1.literal.x = 1.0f; + constantDef1.literal.y = 1.0f; + constantDef1.literal.z = 1.0f; + constantDef1.literal.w = 1.0f; + + material->stateBitsCount = 7; + material->stateBitsTable = memory.Alloc(7); + + auto& stateBits0 = material->stateBitsTable[0]; + stateBits0.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits0.loadBits.structured.dstBlendRgb = GFXS_BLEND_ZERO; + stateBits0.loadBits.structured.blendOpRgb = GFXS_BLENDOP_DISABLED; + stateBits0.loadBits.structured.alphaTestDisabled = 1; + stateBits0.loadBits.structured.alphaTest = 0; + stateBits0.loadBits.structured.cullFace = GFXS_CULL_BACK; + stateBits0.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits0.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits0.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits0.loadBits.structured.colorWriteRgb = 0; + stateBits0.loadBits.structured.colorWriteAlpha = 0; + stateBits0.loadBits.structured.gammaWrite = 0; + stateBits0.loadBits.structured.polymodeLine = 0; + stateBits0.loadBits.structured.depthWrite = 1; + stateBits0.loadBits.structured.depthTestDisabled = 0; + stateBits0.loadBits.structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL; + stateBits0.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_0; + stateBits0.loadBits.structured.stencilFrontEnabled = 0; + stateBits0.loadBits.structured.stencilFrontPass = 0; + stateBits0.loadBits.structured.stencilFrontFail = 0; + stateBits0.loadBits.structured.stencilFrontZFail = 0; + stateBits0.loadBits.structured.stencilFrontFunc = 0; + stateBits0.loadBits.structured.stencilBackEnabled = 0; + stateBits0.loadBits.structured.stencilBackPass = 0; + stateBits0.loadBits.structured.stencilBackFail = 0; + stateBits0.loadBits.structured.stencilBackZFail = 0; + stateBits0.loadBits.structured.stencilBackFunc = 0; + + auto& stateBits1 = material->stateBitsTable[1]; + stateBits1.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits1.loadBits.structured.dstBlendRgb = GFXS_BLEND_ZERO; + stateBits1.loadBits.structured.blendOpRgb = GFXS_BLENDOP_DISABLED; + stateBits1.loadBits.structured.alphaTestDisabled = 1; + stateBits1.loadBits.structured.alphaTest = 0; + stateBits1.loadBits.structured.cullFace = GFXS_CULL_BACK; + stateBits1.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits1.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits1.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits1.loadBits.structured.colorWriteRgb = 1; + stateBits1.loadBits.structured.colorWriteAlpha = 1; + stateBits1.loadBits.structured.gammaWrite = 0; + stateBits1.loadBits.structured.polymodeLine = 0; + stateBits1.loadBits.structured.depthWrite = 1; + stateBits1.loadBits.structured.depthTestDisabled = 0; + stateBits1.loadBits.structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL; + stateBits1.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_0; + stateBits1.loadBits.structured.stencilFrontEnabled = 0; + stateBits1.loadBits.structured.stencilFrontPass = 0; + stateBits1.loadBits.structured.stencilFrontFail = 0; + stateBits1.loadBits.structured.stencilFrontZFail = 0; + stateBits1.loadBits.structured.stencilFrontFunc = 0; + stateBits1.loadBits.structured.stencilBackEnabled = 0; + stateBits1.loadBits.structured.stencilBackPass = 0; + stateBits1.loadBits.structured.stencilBackFail = 0; + stateBits1.loadBits.structured.stencilBackZFail = 0; + stateBits1.loadBits.structured.stencilBackFunc = 0; + + auto& stateBits2 = material->stateBitsTable[2]; + stateBits2.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits2.loadBits.structured.dstBlendRgb = GFXS_BLEND_ZERO; + stateBits2.loadBits.structured.blendOpRgb = GFXS_BLENDOP_DISABLED; + stateBits2.loadBits.structured.alphaTestDisabled = 1; + stateBits2.loadBits.structured.alphaTest = 0; + stateBits2.loadBits.structured.cullFace = GFXS_CULL_NONE; + stateBits2.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits2.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits2.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits2.loadBits.structured.colorWriteRgb = 0; + stateBits2.loadBits.structured.colorWriteAlpha = 0; + stateBits2.loadBits.structured.gammaWrite = 0; + stateBits2.loadBits.structured.polymodeLine = 0; + stateBits2.loadBits.structured.depthWrite = 1; + stateBits2.loadBits.structured.depthTestDisabled = 0; + stateBits2.loadBits.structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL; + stateBits2.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_SHADOWMAP; + stateBits2.loadBits.structured.stencilFrontEnabled = 0; + stateBits2.loadBits.structured.stencilFrontPass = 0; + stateBits2.loadBits.structured.stencilFrontFail = 0; + stateBits2.loadBits.structured.stencilFrontZFail = 0; + stateBits2.loadBits.structured.stencilFrontFunc = 0; + stateBits2.loadBits.structured.stencilBackEnabled = 0; + stateBits2.loadBits.structured.stencilBackPass = 0; + stateBits2.loadBits.structured.stencilBackFail = 0; + stateBits2.loadBits.structured.stencilBackZFail = 0; + stateBits2.loadBits.structured.stencilBackFunc = 0; + + auto& stateBits3 = material->stateBitsTable[3]; + stateBits3.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits3.loadBits.structured.dstBlendRgb = GFXS_BLEND_ZERO; + stateBits3.loadBits.structured.blendOpRgb = GFXS_BLENDOP_DISABLED; + stateBits3.loadBits.structured.alphaTestDisabled = 1; + stateBits3.loadBits.structured.alphaTest = 0; + stateBits3.loadBits.structured.cullFace = GFXS_CULL_NONE; + stateBits3.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits3.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits3.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits3.loadBits.structured.colorWriteRgb = 1; + stateBits3.loadBits.structured.colorWriteAlpha = 1; + stateBits3.loadBits.structured.gammaWrite = 0; + stateBits3.loadBits.structured.polymodeLine = 0; + stateBits3.loadBits.structured.depthWrite = 1; + stateBits3.loadBits.structured.depthTestDisabled = 0; + stateBits3.loadBits.structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL; + stateBits3.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_0; + stateBits3.loadBits.structured.stencilFrontEnabled = 0; + stateBits3.loadBits.structured.stencilFrontPass = 0; + stateBits3.loadBits.structured.stencilFrontFail = 0; + stateBits3.loadBits.structured.stencilFrontZFail = 0; + stateBits3.loadBits.structured.stencilFrontFunc = 0; + stateBits3.loadBits.structured.stencilBackEnabled = 0; + stateBits3.loadBits.structured.stencilBackPass = 0; + stateBits3.loadBits.structured.stencilBackFail = 0; + stateBits3.loadBits.structured.stencilBackZFail = 0; + stateBits3.loadBits.structured.stencilBackFunc = 0; + + auto& stateBits4 = material->stateBitsTable[4]; + stateBits4.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits4.loadBits.structured.dstBlendRgb = GFXS_BLEND_ZERO; + stateBits4.loadBits.structured.blendOpRgb = GFXS_BLENDOP_DISABLED; + stateBits4.loadBits.structured.alphaTestDisabled = 1; + stateBits4.loadBits.structured.alphaTest = 0; + stateBits4.loadBits.structured.cullFace = GFXS_CULL_BACK; + stateBits4.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits4.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits4.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits4.loadBits.structured.colorWriteRgb = 1; + stateBits4.loadBits.structured.colorWriteAlpha = 1; + stateBits4.loadBits.structured.gammaWrite = 1; + stateBits4.loadBits.structured.polymodeLine = 0; + stateBits4.loadBits.structured.depthWrite = 1; + stateBits4.loadBits.structured.depthTestDisabled = 0; + stateBits4.loadBits.structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL; + stateBits4.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_0; + stateBits4.loadBits.structured.stencilFrontEnabled = 0; + stateBits4.loadBits.structured.stencilFrontPass = 0; + stateBits4.loadBits.structured.stencilFrontFail = 0; + stateBits4.loadBits.structured.stencilFrontZFail = 0; + stateBits4.loadBits.structured.stencilFrontFunc = 0; + stateBits4.loadBits.structured.stencilBackEnabled = 0; + stateBits4.loadBits.structured.stencilBackPass = 0; + stateBits4.loadBits.structured.stencilBackFail = 0; + stateBits4.loadBits.structured.stencilBackZFail = 0; + stateBits4.loadBits.structured.stencilBackFunc = 0; + + auto& stateBits5 = material->stateBitsTable[5]; + stateBits5.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits5.loadBits.structured.dstBlendRgb = GFXS_BLEND_ONE; + stateBits5.loadBits.structured.blendOpRgb = GFXS_BLENDOP_ADD; + stateBits5.loadBits.structured.alphaTestDisabled = 1; + stateBits5.loadBits.structured.alphaTest = 0; + stateBits5.loadBits.structured.cullFace = GFXS_CULL_BACK; + stateBits5.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits5.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits5.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits5.loadBits.structured.colorWriteRgb = 1; + stateBits5.loadBits.structured.colorWriteAlpha = 1; + stateBits5.loadBits.structured.gammaWrite = 1; + stateBits5.loadBits.structured.polymodeLine = 0; + stateBits5.loadBits.structured.depthWrite = 0; + stateBits5.loadBits.structured.depthTestDisabled = 0; + stateBits5.loadBits.structured.depthTest = GFXS_DEPTHTEST_EQUAL; + stateBits5.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_0; + stateBits5.loadBits.structured.stencilFrontEnabled = 1; + stateBits5.loadBits.structured.stencilFrontPass = GFXS_STENCILOP_KEEP; + stateBits5.loadBits.structured.stencilFrontFail = GFXS_STENCILOP_KEEP; + stateBits5.loadBits.structured.stencilFrontZFail = GFXS_STENCILOP_KEEP; + stateBits5.loadBits.structured.stencilFrontFunc = GFXS_STENCILFUNC_EQUAL; + stateBits5.loadBits.structured.stencilBackEnabled = 0; + stateBits5.loadBits.structured.stencilBackPass = 0; + stateBits5.loadBits.structured.stencilBackFail = 0; + stateBits5.loadBits.structured.stencilBackZFail = 0; + stateBits5.loadBits.structured.stencilBackFunc = 0; + + auto& stateBits6 = material->stateBitsTable[6]; + stateBits6.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits6.loadBits.structured.dstBlendRgb = GFXS_BLEND_ZERO; + stateBits6.loadBits.structured.blendOpRgb = GFXS_BLENDOP_DISABLED; + stateBits6.loadBits.structured.alphaTestDisabled = 1; + stateBits6.loadBits.structured.alphaTest = 0; + stateBits6.loadBits.structured.cullFace = GFXS_CULL_BACK; + stateBits6.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits6.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits6.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits6.loadBits.structured.colorWriteRgb = 1; + stateBits6.loadBits.structured.colorWriteAlpha = 0; + stateBits6.loadBits.structured.gammaWrite = 0; + stateBits6.loadBits.structured.polymodeLine = 1; + stateBits6.loadBits.structured.depthWrite = 0; + stateBits6.loadBits.structured.depthTestDisabled = 0; + stateBits6.loadBits.structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL; + stateBits6.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_2; + stateBits6.loadBits.structured.stencilFrontEnabled = 0; + stateBits6.loadBits.structured.stencilFrontPass = 0; + stateBits6.loadBits.structured.stencilFrontFail = 0; + stateBits6.loadBits.structured.stencilFrontZFail = 0; + stateBits6.loadBits.structured.stencilFrontFunc = 0; + stateBits6.loadBits.structured.stencilBackEnabled = 0; + stateBits6.loadBits.structured.stencilBackPass = 0; + stateBits6.loadBits.structured.stencilBackFail = 0; + stateBits6.loadBits.structured.stencilBackZFail = 0; + stateBits6.loadBits.structured.stencilBackFunc = 0; + + pool.AddAsset(std::make_unique>(ASSET_TYPE_MATERIAL, name, material)); + } + + TEST_CASE("DumperMaterial(IW5): Can dump material", "[iw5][material][assetdumper]") + { + std::string expected(R"MATERIAL( +{ + "_game": "iw5", + "_type": "material", + "_version": 1, + "cameraRegion": "litOpaque", + "constants": [ + { + "literal": [ + 0.07000000029802322, + 0.33000001311302185, + 1.399999976158142, + 2.0 + ], + "name": "envMapParms" + }, + { + "literal": [ + 1.0, + 1.0, + 1.0, + 1.0 + ], + "name": "colorTint" + } + ], + "gameFlags": [ + "2", + "10", + "40" + ], + "sortKey": 1, + "stateBits": [ + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "disabled", + "colorWriteAlpha": false, + "colorWriteRgb": false, + "cullFace": "back", + "depthTest": "less_equal", + "depthWrite": true, + "dstBlendAlpha": "zero", + "dstBlendRgb": "zero", + "gammaWrite": false, + "polygonOffset": "offset0", + "polymodeLine": false, + "srcBlendAlpha": "one", + "srcBlendRgb": "one" + }, + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "disabled", + "colorWriteAlpha": true, + "colorWriteRgb": true, + "cullFace": "back", + "depthTest": "less_equal", + "depthWrite": true, + "dstBlendAlpha": "zero", + "dstBlendRgb": "zero", + "gammaWrite": false, + "polygonOffset": "offset0", + "polymodeLine": false, + "srcBlendAlpha": "one", + "srcBlendRgb": "one" + }, + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "disabled", + "colorWriteAlpha": false, + "colorWriteRgb": false, + "cullFace": "none", + "depthTest": "less_equal", + "depthWrite": true, + "dstBlendAlpha": "zero", + "dstBlendRgb": "zero", + "gammaWrite": false, + "polygonOffset": "offsetShadowmap", + "polymodeLine": false, + "srcBlendAlpha": "one", + "srcBlendRgb": "one" + }, + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "disabled", + "colorWriteAlpha": true, + "colorWriteRgb": true, + "cullFace": "none", + "depthTest": "less_equal", + "depthWrite": true, + "dstBlendAlpha": "zero", + "dstBlendRgb": "zero", + "gammaWrite": false, + "polygonOffset": "offset0", + "polymodeLine": false, + "srcBlendAlpha": "one", + "srcBlendRgb": "one" + }, + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "disabled", + "colorWriteAlpha": true, + "colorWriteRgb": true, + "cullFace": "back", + "depthTest": "less_equal", + "depthWrite": true, + "dstBlendAlpha": "zero", + "dstBlendRgb": "zero", + "gammaWrite": true, + "polygonOffset": "offset0", + "polymodeLine": false, + "srcBlendAlpha": "one", + "srcBlendRgb": "one" + }, + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "add", + "colorWriteAlpha": true, + "colorWriteRgb": true, + "cullFace": "back", + "depthTest": "equal", + "depthWrite": false, + "dstBlendAlpha": "zero", + "dstBlendRgb": "one", + "gammaWrite": true, + "polygonOffset": "offset0", + "polymodeLine": false, + "srcBlendAlpha": "one", + "srcBlendRgb": "one", + "stencilFront": { + "fail": "keep", + "func": "equal", + "pass": "keep", + "zfail": "keep" + } + }, + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "disabled", + "colorWriteAlpha": false, + "colorWriteRgb": true, + "cullFace": "back", + "depthTest": "less_equal", + "depthWrite": false, + "dstBlendAlpha": "zero", + "dstBlendRgb": "zero", + "gammaWrite": false, + "polygonOffset": "offset2", + "polymodeLine": true, + "srcBlendAlpha": "one", + "srcBlendRgb": "one" + } + ], + "stateBitsEntry": [ + 0, + 1, + 2, + 3, + 4, + -1, + -1, + -1, + -1, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + 4, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + -1, + 5, + 5, + 5, + 5, + -1, + -1, + -1, + -1, + 6, + -1, + -1, + 4, + -1 + ], + "stateFlags": 59, + "surfaceTypeBits": 4096, + "techniqueSet": "wc_l_sm_r0c0n0s0", + "textureAtlas": { + "columns": 1, + "rows": 1 + }, + "textures": [ + { + "image": "~me_metal_rusty02_spc-rgb&me_~927de80f", + "name": "specularMap", + "samplerState": { + "clampU": false, + "clampV": false, + "clampW": false, + "filter": "aniso2x", + "mipMap": "nearest" + }, + "semantic": "specularMap" + }, + { + "image": "me_metal_rusty02_nml", + "name": "normalMap", + "samplerState": { + "clampU": false, + "clampV": false, + "clampW": false, + "filter": "aniso2x", + "mipMap": "linear" + }, + "semantic": "normalMap" + }, + { + "image": "me_metal_rusty02_col", + "name": "colorMap", + "samplerState": { + "clampU": false, + "clampV": false, + "clampW": false, + "filter": "aniso2x", + "mipMap": "linear" + }, + "semantic": "colorMap" + } + ] +})MATERIAL"); + + Zone zone("MockZone", 0, IGame::GetGameById(GameId::IW5)); + + MemoryManager memory; + MockSearchPath mockObjPath; + MockOutputPath mockOutput; + AssetDumpingContext context(zone, "", mockOutput, mockObjPath); + + AssetPoolDynamic materialPool(0); + + GivenMaterial("wc/me_metal_rust_02", materialPool, memory); + + AssetDumperMaterial dumper; + dumper.DumpPool(context, &materialPool); + + const auto* file = mockOutput.GetMockedFile("materials/wc/me_metal_rust_02.json"); + REQUIRE(file); + REQUIRE(JsonNormalized(file->AsString()) == JsonNormalized(expected)); + } +} // namespace diff --git a/test/ObjWritingTests/Game/T6/Material/DumperMaterialT6Test.cpp b/test/ObjWritingTests/Game/T6/Material/DumperMaterialT6Test.cpp new file mode 100644 index 00000000..4c6e5f50 --- /dev/null +++ b/test/ObjWritingTests/Game/T6/Material/DumperMaterialT6Test.cpp @@ -0,0 +1,484 @@ +#include "Game/T6/Material/DumperMaterialT6.h" + +#include "Asset/AssetRegistration.h" +#include "Game/T6/CommonT6.h" +#include "Game/T6/GameT6.h" +#include "NormalizedJson.h" +#include "Pool/AssetPoolDynamic.h" +#include "SearchPath/MockOutputPath.h" +#include "SearchPath/MockSearchPath.h" +#include "Utils/MemoryManager.h" + +#include +#include +#include + +using namespace T6; +using namespace Catch; +using namespace std::literals; + +namespace +{ + GfxImage* GivenImage(const std::string& name, MemoryManager& memory) + { + auto* image = memory.Alloc(); + image->name = memory.Dup(name.c_str()); + + return image; + } + + MaterialTechniqueSet* GivenTechset(const std::string& name, MemoryManager& memory) + { + auto* techset = memory.Alloc(); + techset->name = memory.Dup(name.c_str()); + + return techset; + } + + void GivenMaterial(const std::string& name, AssetPool& pool, MemoryManager& memory) + { + auto* material = memory.Alloc(); + material->info.name = memory.Dup(name.c_str()); + material->info.gameFlags = 0x52; + material->info.sortKey = 4; + material->info.textureAtlasRowCount = 1; + material->info.textureAtlasColumnCount = 1; + material->info.surfaceTypeBits = 0x1000; + material->info.layeredSurfaceTypes = 0x2000000Du; + material->info.surfaceFlags = 0xD00000u; + material->info.contents = 1; + + constexpr int8_t stateBitsEntry[] = {0, 1, 2, -1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, -1, -1, -1, -1, -1, -1, 3, -1, 2, 4}; + std::memcpy(material->stateBitsEntry, stateBitsEntry, sizeof(material->stateBitsEntry)); + + material->cameraRegion = CAMERA_REGION_LIT_OPAQUE; + material->stateFlags = 121; + material->techniqueSet = GivenTechset("wpc_lit_sm_r0c0n0s0_1zzj1138", memory); + + material->textureCount = 3; + material->textureTable = memory.Alloc(3); + + auto& textureDef0 = material->textureTable[0]; + textureDef0.image = GivenImage("~~-gmetal_ac_duct_s-rgb&~-rme~0a5a2e6f", memory); + textureDef0.nameHash = 0x34ecccb3; + textureDef0.nameStart = 's'; + textureDef0.nameEnd = 'p'; + textureDef0.samplerState.filter = TEXTURE_FILTER_ANISO4X; + textureDef0.samplerState.mipMap = SAMPLER_MIPMAP_ENUM_LINEAR; + textureDef0.samplerState.clampU = 0; + textureDef0.samplerState.clampV = 0; + textureDef0.samplerState.clampW = 0; + textureDef0.semantic = TS_SPECULAR_MAP; + textureDef0.isMatureContent = false; + + auto& textureDef1 = material->textureTable[1]; + textureDef1.image = GivenImage("metal_ac_duct_n", memory); + textureDef1.nameHash = 0x59d30d0f; + textureDef1.nameStart = 'n'; + textureDef1.nameEnd = 'p'; + textureDef1.samplerState.filter = TEXTURE_FILTER_ANISO4X; + textureDef1.samplerState.mipMap = SAMPLER_MIPMAP_ENUM_LINEAR; + textureDef1.samplerState.clampU = 0; + textureDef1.samplerState.clampV = 0; + textureDef1.samplerState.clampW = 0; + textureDef1.semantic = TS_NORMAL_MAP; + textureDef1.isMatureContent = false; + + auto& textureDef2 = material->textureTable[2]; + textureDef2.image = GivenImage("~-gmetal_ac_duct_c", memory); + textureDef2.nameHash = 0xa0ab1041; + textureDef2.nameStart = 'c'; + textureDef2.nameEnd = 'p'; + textureDef2.samplerState.filter = TEXTURE_FILTER_ANISO4X; + textureDef2.samplerState.mipMap = SAMPLER_MIPMAP_ENUM_LINEAR; + textureDef2.samplerState.clampU = 0; + textureDef2.samplerState.clampV = 0; + textureDef2.samplerState.clampW = 0; + textureDef2.semantic = TS_COLOR_MAP; + textureDef2.isMatureContent = false; + + material->constantCount = 1; + material->constantTable = memory.Alloc(1); + + auto& constantDef0 = material->constantTable[0]; + constantDef0.nameHash = 0x9027e5c1; + strncpy(constantDef0.name, "occlusionAmount", std::extent_v); + constantDef0.literal.x = 1.0f; + constantDef0.literal.y = 1.0f; + constantDef0.literal.z = 1.0f; + constantDef0.literal.w = 1.0f; + + material->stateBitsCount = 5; + material->stateBitsTable = memory.Alloc(5); + + auto& stateBits0 = material->stateBitsTable[0]; + stateBits0.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits0.loadBits.structured.dstBlendRgb = GFXS_BLEND_ZERO; + stateBits0.loadBits.structured.blendOpRgb = GFXS_BLENDOP_DISABLED; + stateBits0.loadBits.structured.alphaTestDisabled = 1; + stateBits0.loadBits.structured.alphaTest = 0; + stateBits0.loadBits.structured.cullFace = GFXS_CULL_BACK; + stateBits0.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits0.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits0.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits0.loadBits.structured.colorWriteRgb = 0; + stateBits0.loadBits.structured.colorWriteAlpha = 0; + stateBits0.loadBits.structured.polymodeLine = 0; + stateBits0.loadBits.structured.depthWrite = 1; + stateBits0.loadBits.structured.depthTestDisabled = 0; + stateBits0.loadBits.structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL; + stateBits0.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_0; + stateBits0.loadBits.structured.stencilFrontEnabled = 1; + stateBits0.loadBits.structured.stencilFrontPass = GFXS_STENCILOP_KEEP; + stateBits0.loadBits.structured.stencilFrontFail = GFXS_STENCILOP_KEEP; + stateBits0.loadBits.structured.stencilFrontZFail = GFXS_STENCILOP_KEEP; + stateBits0.loadBits.structured.stencilFrontFunc = GFXS_STENCILFUNC_EQUAL; + stateBits0.loadBits.structured.stencilBackEnabled = 0; + stateBits0.loadBits.structured.stencilBackPass = 0; + stateBits0.loadBits.structured.stencilBackFail = 0; + stateBits0.loadBits.structured.stencilBackZFail = 0; + stateBits0.loadBits.structured.stencilBackFunc = 0; + + auto& stateBits1 = material->stateBitsTable[1]; + stateBits1.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits1.loadBits.structured.dstBlendRgb = GFXS_BLEND_ZERO; + stateBits1.loadBits.structured.blendOpRgb = GFXS_BLENDOP_DISABLED; + stateBits1.loadBits.structured.alphaTestDisabled = 1; + stateBits1.loadBits.structured.alphaTest = 0; + stateBits1.loadBits.structured.cullFace = GFXS_CULL_BACK; + stateBits1.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits1.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits1.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits1.loadBits.structured.colorWriteRgb = 0; + stateBits1.loadBits.structured.colorWriteAlpha = 0; + stateBits1.loadBits.structured.polymodeLine = 0; + stateBits1.loadBits.structured.depthWrite = 1; + stateBits1.loadBits.structured.depthTestDisabled = 0; + stateBits1.loadBits.structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL; + stateBits1.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_SHADOWMAP; + stateBits1.loadBits.structured.stencilFrontEnabled = 0; + stateBits1.loadBits.structured.stencilFrontPass = 0; + stateBits1.loadBits.structured.stencilFrontFail = 0; + stateBits1.loadBits.structured.stencilFrontZFail = 0; + stateBits1.loadBits.structured.stencilFrontFunc = 0; + stateBits1.loadBits.structured.stencilBackEnabled = 0; + stateBits1.loadBits.structured.stencilBackPass = 0; + stateBits1.loadBits.structured.stencilBackFail = 0; + stateBits1.loadBits.structured.stencilBackZFail = 0; + stateBits1.loadBits.structured.stencilBackFunc = 0; + + auto& stateBits2 = material->stateBitsTable[2]; + stateBits2.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits2.loadBits.structured.dstBlendRgb = GFXS_BLEND_ZERO; + stateBits2.loadBits.structured.blendOpRgb = GFXS_BLENDOP_DISABLED; + stateBits2.loadBits.structured.alphaTestDisabled = 1; + stateBits2.loadBits.structured.alphaTest = 0; + stateBits2.loadBits.structured.cullFace = GFXS_CULL_BACK; + stateBits2.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits2.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits2.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits2.loadBits.structured.colorWriteRgb = 1; + stateBits2.loadBits.structured.colorWriteAlpha = 1; + stateBits2.loadBits.structured.polymodeLine = 0; + stateBits2.loadBits.structured.depthWrite = 1; + stateBits2.loadBits.structured.depthTestDisabled = 0; + stateBits2.loadBits.structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL; + stateBits2.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_0; + stateBits2.loadBits.structured.stencilFrontEnabled = 0; + stateBits2.loadBits.structured.stencilFrontPass = 0; + stateBits2.loadBits.structured.stencilFrontFail = 0; + stateBits2.loadBits.structured.stencilFrontZFail = 0; + stateBits2.loadBits.structured.stencilFrontFunc = 0; + stateBits2.loadBits.structured.stencilBackEnabled = 0; + stateBits2.loadBits.structured.stencilBackPass = 0; + stateBits2.loadBits.structured.stencilBackFail = 0; + stateBits2.loadBits.structured.stencilBackZFail = 0; + stateBits2.loadBits.structured.stencilBackFunc = 0; + + auto& stateBits3 = material->stateBitsTable[3]; + stateBits3.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits3.loadBits.structured.dstBlendRgb = GFXS_BLEND_ZERO; + stateBits3.loadBits.structured.blendOpRgb = GFXS_BLENDOP_DISABLED; + stateBits3.loadBits.structured.alphaTestDisabled = 1; + stateBits3.loadBits.structured.alphaTest = 0; + stateBits3.loadBits.structured.cullFace = GFXS_CULL_BACK; + stateBits3.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits3.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits3.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits3.loadBits.structured.colorWriteRgb = 1; + stateBits3.loadBits.structured.colorWriteAlpha = 0; + stateBits3.loadBits.structured.polymodeLine = 1; + stateBits3.loadBits.structured.depthWrite = 0; + stateBits3.loadBits.structured.depthTestDisabled = 0; + stateBits3.loadBits.structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL; + stateBits3.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_2; + stateBits3.loadBits.structured.stencilFrontEnabled = 0; + stateBits3.loadBits.structured.stencilFrontPass = 0; + stateBits3.loadBits.structured.stencilFrontFail = 0; + stateBits3.loadBits.structured.stencilFrontZFail = 0; + stateBits3.loadBits.structured.stencilFrontFunc = 0; + stateBits3.loadBits.structured.stencilBackEnabled = 0; + stateBits3.loadBits.structured.stencilBackPass = 0; + stateBits3.loadBits.structured.stencilBackFail = 0; + stateBits3.loadBits.structured.stencilBackZFail = 0; + stateBits3.loadBits.structured.stencilBackFunc = 0; + + auto& stateBits4 = material->stateBitsTable[4]; + stateBits4.loadBits.structured.srcBlendRgb = GFXS_BLEND_ONE; + stateBits4.loadBits.structured.dstBlendRgb = GFXS_BLEND_ONE; + stateBits4.loadBits.structured.blendOpRgb = GFXS_BLENDOP_ADD; + stateBits4.loadBits.structured.alphaTestDisabled = 1; + stateBits4.loadBits.structured.alphaTest = 0; + stateBits4.loadBits.structured.cullFace = GFXS_CULL_BACK; + stateBits4.loadBits.structured.srcBlendAlpha = GFXS_BLEND_ONE; + stateBits4.loadBits.structured.dstBlendAlpha = GFXS_BLEND_ZERO; + stateBits4.loadBits.structured.blendOpAlpha = GFXS_BLENDOP_DISABLED; + stateBits4.loadBits.structured.colorWriteRgb = 1; + stateBits4.loadBits.structured.colorWriteAlpha = 1; + stateBits4.loadBits.structured.polymodeLine = 0; + stateBits4.loadBits.structured.depthWrite = 1; + stateBits4.loadBits.structured.depthTestDisabled = 0; + stateBits4.loadBits.structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL; + stateBits4.loadBits.structured.polygonOffset = GFXS_POLYGON_OFFSET_1; + stateBits4.loadBits.structured.stencilFrontEnabled = 0; + stateBits4.loadBits.structured.stencilFrontPass = 0; + stateBits4.loadBits.structured.stencilFrontFail = 0; + stateBits4.loadBits.structured.stencilFrontZFail = 0; + stateBits4.loadBits.structured.stencilFrontFunc = 0; + stateBits4.loadBits.structured.stencilBackEnabled = 0; + stateBits4.loadBits.structured.stencilBackPass = 0; + stateBits4.loadBits.structured.stencilBackFail = 0; + stateBits4.loadBits.structured.stencilBackZFail = 0; + stateBits4.loadBits.structured.stencilBackFunc = 0; + + material->thermalMaterial = nullptr; + + pool.AddAsset(std::make_unique>(ASSET_TYPE_MATERIAL, name, material)); + } + + TEST_CASE("DumperMaterial(T6): Can dump material", "[t6][material][assetdumper]") + { + std::string expected(R"MATERIAL( +{ + "_game": "t6", + "_type": "material", + "_version": 1, + "cameraRegion": "litOpaque", + "constants": [ + { + "literal": [ + 1.0, + 1.0, + 1.0, + 1.0 + ], + "name": "occlusionAmount" + } + ], + "contents": 1, + "gameFlags": [ + "2", + "10", + "CASTS_SHADOW" + ], + "hashIndex": 0, + "layeredSurfaceTypes": 536870925, + "probeMipBits": 0, + "sortKey": 4, + "stateBits": [ + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "disabled", + "colorWriteAlpha": false, + "colorWriteRgb": false, + "cullFace": "back", + "depthTest": "less_equal", + "depthWrite": true, + "dstBlendAlpha": "zero", + "dstBlendRgb": "zero", + "polygonOffset": "offset0", + "polymodeLine": false, + "srcBlendAlpha": "one", + "srcBlendRgb": "one", + "stencilFront": { + "fail": "keep", + "func": "equal", + "pass": "keep", + "zfail": "keep" + } + }, + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "disabled", + "colorWriteAlpha": false, + "colorWriteRgb": false, + "cullFace": "back", + "depthTest": "less_equal", + "depthWrite": true, + "dstBlendAlpha": "zero", + "dstBlendRgb": "zero", + "polygonOffset": "offsetShadowmap", + "polymodeLine": false, + "srcBlendAlpha": "one", + "srcBlendRgb": "one" + }, + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "disabled", + "colorWriteAlpha": true, + "colorWriteRgb": true, + "cullFace": "back", + "depthTest": "less_equal", + "depthWrite": true, + "dstBlendAlpha": "zero", + "dstBlendRgb": "zero", + "polygonOffset": "offset0", + "polymodeLine": false, + "srcBlendAlpha": "one", + "srcBlendRgb": "one" + }, + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "disabled", + "colorWriteAlpha": false, + "colorWriteRgb": true, + "cullFace": "back", + "depthTest": "less_equal", + "depthWrite": false, + "dstBlendAlpha": "zero", + "dstBlendRgb": "zero", + "polygonOffset": "offset2", + "polymodeLine": true, + "srcBlendAlpha": "one", + "srcBlendRgb": "one" + }, + { + "alphaTest": "disabled", + "blendOpAlpha": "disabled", + "blendOpRgb": "add", + "colorWriteAlpha": true, + "colorWriteRgb": true, + "cullFace": "back", + "depthTest": "less_equal", + "depthWrite": true, + "dstBlendAlpha": "zero", + "dstBlendRgb": "one", + "polygonOffset": "offset1", + "polymodeLine": false, + "srcBlendAlpha": "one", + "srcBlendRgb": "one" + } + ], + "stateBitsEntry": [ + 0, + 1, + 2, + -1, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + -1, + -1, + -1, + -1, + -1, + -1, + 3, + -1, + 2, + 4 + ], + "stateFlags": 121, + "surfaceFlags": 13631488, + "surfaceTypeBits": 4096, + "techniqueSet": "wpc_lit_sm_r0c0n0s0_1zzj1138", + "textureAtlas": { + "columns": 1, + "rows": 1 + }, + "textures": [ + { + "image": "~~-gmetal_ac_duct_s-rgb&~-rme~0a5a2e6f", + "isMatureContent": false, + "name": "specularMap", + "samplerState": { + "clampU": false, + "clampV": false, + "clampW": false, + "filter": "aniso4x", + "mipMap": "linear" + }, + "semantic": "specularMap" + }, + { + "image": "metal_ac_duct_n", + "isMatureContent": false, + "name": "normalMap", + "samplerState": { + "clampU": false, + "clampV": false, + "clampW": false, + "filter": "aniso4x", + "mipMap": "linear" + }, + "semantic": "normalMap" + }, + { + "image": "~-gmetal_ac_duct_c", + "isMatureContent": false, + "name": "colorMap", + "samplerState": { + "clampU": false, + "clampV": false, + "clampW": false, + "filter": "aniso4x", + "mipMap": "linear" + }, + "semantic": "colorMap" + } + ] +})MATERIAL"); + + Zone zone("MockZone", 0, IGame::GetGameById(GameId::T6)); + + MemoryManager memory; + MockSearchPath mockObjPath; + MockOutputPath mockOutput; + AssetDumpingContext context(zone, "", mockOutput, mockObjPath); + + AssetPoolDynamic materialPool(0); + + GivenMaterial("wpc/metal_ac_duct", materialPool, memory); + + AssetDumperMaterial dumper; + dumper.DumpPool(context, &materialPool); + + const auto* file = mockOutput.GetMockedFile("materials/wpc/metal_ac_duct.json"); + REQUIRE(file); + REQUIRE(JsonNormalized(file->AsString()) == JsonNormalized(expected)); + } +} // namespace