mirror of
https://github.com/Laupetin/OpenAssetTools.git
synced 2025-07-02 09:11:49 +00:00
Merge pull request #460 from Laupetin/refactor/iw4-json-materials
refactor: add templated material json loading for iw4
This commit is contained in:
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
# All .sh files should be lf line endings
|
||||
*.sh text eol=cl
|
||||
|
2
.github/workflows/check-formatting.yaml
vendored
2
.github/workflows/check-formatting.yaml
vendored
@ -15,7 +15,7 @@ jobs:
|
||||
- name: Install LLVM and Clang
|
||||
uses: KyleMayes/install-llvm-action@v2
|
||||
with:
|
||||
version: "17.0"
|
||||
version: "20.1"
|
||||
|
||||
- name: Test formatting for all files
|
||||
working-directory: ${{ github.workspace }}
|
||||
|
3
.github/workflows/ci.yaml
vendored
3
.github/workflows/ci.yaml
vendored
@ -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
|
||||
|
@ -84,6 +84,9 @@ workspace "OpenAssetTools"
|
||||
filter "options:debug-techset"
|
||||
defines { "TECHSET_DEBUG" }
|
||||
filter {}
|
||||
filter "options:experimental-material-compilation"
|
||||
defines { "EXPERIMENTAL_MATERIAL_COMPILATION" }
|
||||
filter {}
|
||||
|
||||
-- ========================
|
||||
-- ThirdParty
|
||||
@ -181,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"
|
||||
@ -193,6 +197,7 @@ group "Tests"
|
||||
ObjCommonTests:project()
|
||||
ObjCompilingTests:project()
|
||||
ObjLoadingTests:project()
|
||||
ObjWritingTests:project()
|
||||
ParserTestUtils:project()
|
||||
ParserTests:project()
|
||||
ZoneCodeGeneratorLibTests:project()
|
||||
|
@ -674,7 +674,7 @@ namespace IW4
|
||||
water_t* water;
|
||||
};
|
||||
|
||||
enum MaterialTextureFilter
|
||||
enum TextureFilter
|
||||
{
|
||||
TEXTURE_FILTER_DISABLED = 0x0,
|
||||
TEXTURE_FILTER_NEAREST = 0x1,
|
||||
@ -685,6 +685,15 @@ namespace IW4
|
||||
TEXTURE_FILTER_COUNT
|
||||
};
|
||||
|
||||
enum SamplerStateBitsMipMap_e
|
||||
{
|
||||
SAMPLER_MIPMAP_ENUM_DISABLED,
|
||||
SAMPLER_MIPMAP_ENUM_NEAREST,
|
||||
SAMPLER_MIPMAP_ENUM_LINEAR,
|
||||
|
||||
SAMPLER_MIPMAP_ENUM_COUNT
|
||||
};
|
||||
|
||||
enum SamplerStateBits_e
|
||||
{
|
||||
SAMPLER_FILTER_SHIFT = 0x0,
|
||||
@ -710,13 +719,26 @@ namespace IW4
|
||||
SAMPLER_CLAMP_MASK = 0xE0,
|
||||
};
|
||||
|
||||
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;
|
||||
unsigned char samplerState; // SamplerStateBits_e
|
||||
unsigned char semantic; // TextureSemantic
|
||||
MaterialTextureDefSamplerState samplerState; // SamplerStateBits_e
|
||||
unsigned char semantic; // TextureSemantic
|
||||
MaterialTextureDefInfo u;
|
||||
};
|
||||
|
||||
@ -724,7 +746,7 @@ namespace IW4
|
||||
{
|
||||
unsigned int nameHash;
|
||||
char name[12];
|
||||
float literal[4];
|
||||
vec4_t literal;
|
||||
};
|
||||
|
||||
enum GfxBlend : unsigned int
|
||||
@ -754,19 +776,36 @@ namespace IW4
|
||||
GFXS_BLENDOP_MASK = 0x7,
|
||||
};
|
||||
|
||||
enum GfxStencilFunc : unsigned int
|
||||
enum GfxAlphaTest_e
|
||||
{
|
||||
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_ALPHA_TEST_GT_0 = 1,
|
||||
GFXS_ALPHA_TEST_LT_128 = 2,
|
||||
GFXS_ALPHA_TEST_GE_128 = 3,
|
||||
|
||||
GFXS_STENCILFUNC_COUNT,
|
||||
GFXS_STENCILFUNC_MASK = 0x7
|
||||
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
|
||||
@ -784,6 +823,21 @@ namespace IW4
|
||||
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
|
||||
{
|
||||
GFXS0_SRCBLEND_RGB_SHIFT = 0x0,
|
||||
@ -876,9 +930,55 @@ namespace IW4
|
||||
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 : 1; // 29
|
||||
unsigned int gammaWrite : 1; // 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;
|
||||
};
|
||||
|
||||
struct infoParm_t
|
||||
@ -1028,7 +1128,7 @@ namespace IW4
|
||||
struct Material
|
||||
{
|
||||
MaterialInfo info;
|
||||
unsigned char stateBitsEntry[48];
|
||||
char stateBitsEntry[48];
|
||||
unsigned char textureCount;
|
||||
unsigned char constantCount;
|
||||
unsigned char stateBitsCount;
|
||||
|
@ -691,11 +691,6 @@ namespace IW5
|
||||
MTL_GAMEFLAG_20 = 0x20,
|
||||
MTL_GAMEFLAG_40 = 0x40,
|
||||
MTL_GAMEFLAG_80 = 0x80,
|
||||
MTL_GAMEFLAG_100 = 0x100,
|
||||
MTL_GAMEFLAG_200 = 0x200,
|
||||
MTL_GAMEFLAG_400 = 0x400,
|
||||
MTL_GAMEFLAG_800 = 0x800,
|
||||
MTL_GAMEFLAG_1000 = 0x1000,
|
||||
};
|
||||
|
||||
struct MaterialInfo
|
||||
@ -991,7 +986,7 @@ namespace IW5
|
||||
unsigned char constantCount;
|
||||
unsigned char stateBitsCount;
|
||||
unsigned char stateFlags;
|
||||
unsigned char cameraRegion;
|
||||
unsigned char cameraRegion; // GfxCameraRegionType
|
||||
MaterialTechniqueSet* techniqueSet;
|
||||
MaterialTextureDef* textureTable;
|
||||
MaterialConstantDef* constantTable;
|
||||
|
@ -2929,9 +2929,9 @@ namespace T6
|
||||
|
||||
enum GfxCullFace_e
|
||||
{
|
||||
GFXS0_CULL_NONE = 1,
|
||||
GFXS0_CULL_BACK = 2,
|
||||
GFXS0_CULL_FRONT = 3,
|
||||
GFXS_CULL_NONE = 1,
|
||||
GFXS_CULL_BACK = 2,
|
||||
GFXS_CULL_FRONT = 3,
|
||||
};
|
||||
|
||||
enum GfxDepthTest_e
|
||||
|
@ -7,7 +7,8 @@ function ObjCommon:include(includes)
|
||||
minizip:include(includes)
|
||||
Parser:include(includes)
|
||||
includedirs {
|
||||
path.join(ProjectFolder(), "ObjCommon")
|
||||
path.join(ProjectFolder(), "ObjCommon"),
|
||||
"%{wks.location}/src/ObjCommon"
|
||||
}
|
||||
end
|
||||
end
|
||||
@ -21,7 +22,7 @@ function ObjCommon:link(links)
|
||||
end
|
||||
|
||||
function ObjCommon:use()
|
||||
|
||||
dependson(self:name())
|
||||
end
|
||||
|
||||
function ObjCommon:name()
|
||||
@ -48,6 +49,8 @@ function ObjCommon:project()
|
||||
path.join(folder, "ObjCommon")
|
||||
}
|
||||
}
|
||||
|
||||
useSourceTemplating("ObjCommon")
|
||||
|
||||
self:include(includes)
|
||||
Utils:include(includes)
|
||||
|
@ -818,5 +818,5 @@ namespace IW4
|
||||
}},
|
||||
});
|
||||
|
||||
inline state_map::StateMapLayout stateMapLayout(std::extent_v<decltype(GfxStateBits::loadBits)>, stateMapEntryLayout, stateMapVarLayout);
|
||||
inline state_map::StateMapLayout stateMapLayout(std::extent_v<decltype(GfxStateBits::loadBits.raw)>, stateMapEntryLayout, stateMapVarLayout);
|
||||
} // namespace IW4
|
||||
|
@ -1,391 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Game/IW5/IW5.h"
|
||||
|
||||
#include "Json/JsonExtension.h"
|
||||
#include <memory>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace IW5
|
||||
{
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxStencilOp,
|
||||
{
|
||||
{GFXS_STENCILOP_KEEP, "keep" },
|
||||
{GFXS_STENCILOP_ZERO, "zero" },
|
||||
{GFXS_STENCILOP_REPLACE, "replace"},
|
||||
{GFXS_STENCILOP_INCRSAT, "incrsat"},
|
||||
{GFXS_STENCILOP_DECRSAT, "decrsat"},
|
||||
{GFXS_STENCILOP_INVERT, "invert" },
|
||||
{GFXS_STENCILOP_INCR, "incr" },
|
||||
{GFXS_STENCILOP_DECR, "decr" },
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxStencilFunc,
|
||||
{
|
||||
{GFXS_STENCILFUNC_NEVER, "never" },
|
||||
{GFXS_STENCILFUNC_LESS, "less" },
|
||||
{GFXS_STENCILFUNC_EQUAL, "equal" },
|
||||
{GFXS_STENCILFUNC_LESSEQUAL, "lessequal" },
|
||||
{GFXS_STENCILFUNC_GREATER, "greater" },
|
||||
{GFXS_STENCILFUNC_NOTEQUAL, "notequal" },
|
||||
{GFXS_STENCILFUNC_GREATEREQUAL, "greaterequal"},
|
||||
{GFXS_STENCILFUNC_ALWAYS, "always" },
|
||||
});
|
||||
|
||||
class JsonStencil
|
||||
{
|
||||
public:
|
||||
GfxStencilOp pass;
|
||||
GfxStencilOp fail;
|
||||
GfxStencilOp zfail;
|
||||
GfxStencilFunc func;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonStencil, pass, fail, zfail, func);
|
||||
|
||||
enum class JsonAlphaTest
|
||||
{
|
||||
INVALID,
|
||||
DISABLED,
|
||||
GT0,
|
||||
LT128,
|
||||
GE128
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(JsonAlphaTest,
|
||||
{
|
||||
{JsonAlphaTest::INVALID, nullptr },
|
||||
{JsonAlphaTest::DISABLED, "disabled"},
|
||||
{JsonAlphaTest::GT0, "gt0" },
|
||||
{JsonAlphaTest::LT128, "lt128" },
|
||||
{JsonAlphaTest::GE128, "ge128" }
|
||||
});
|
||||
|
||||
enum class JsonCullFace
|
||||
{
|
||||
INVALID,
|
||||
NONE,
|
||||
BACK,
|
||||
FRONT
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(
|
||||
JsonCullFace,
|
||||
{
|
||||
{JsonCullFace::INVALID, nullptr},
|
||||
{JsonCullFace::NONE, "none" },
|
||||
{JsonCullFace::BACK, "back" },
|
||||
{JsonCullFace::FRONT, "front"}
|
||||
});
|
||||
|
||||
enum class JsonDepthTest
|
||||
{
|
||||
INVALID,
|
||||
DISABLED,
|
||||
ALWAYS,
|
||||
LESS,
|
||||
EQUAL,
|
||||
LESS_EQUAL
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(JsonDepthTest,
|
||||
{
|
||||
{JsonDepthTest::INVALID, nullptr },
|
||||
{JsonDepthTest::DISABLED, "disabled" },
|
||||
{JsonDepthTest::ALWAYS, "always" },
|
||||
{JsonDepthTest::LESS, "less" },
|
||||
{JsonDepthTest::EQUAL, "equal" },
|
||||
{JsonDepthTest::LESS_EQUAL, "less_equal"}
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxBlend,
|
||||
{
|
||||
{GFXS_BLEND_DISABLED, "disabled" },
|
||||
{GFXS_BLEND_ZERO, "zero" },
|
||||
{GFXS_BLEND_ONE, "one" },
|
||||
{GFXS_BLEND_SRCCOLOR, "srccolor" },
|
||||
{GFXS_BLEND_INVSRCCOLOR, "invsrccolor" },
|
||||
{GFXS_BLEND_SRCALPHA, "srcalpha" },
|
||||
{GFXS_BLEND_INVSRCALPHA, "invsrcalpha" },
|
||||
{GFXS_BLEND_DESTALPHA, "destalpha" },
|
||||
{GFXS_BLEND_INVDESTALPHA, "invdestalpha"},
|
||||
{GFXS_BLEND_DESTCOLOR, "destcolor" },
|
||||
{GFXS_BLEND_INVDESTCOLOR, "invdestcolor"},
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxBlendOp,
|
||||
{
|
||||
{GFXS_BLENDOP_DISABLED, "disabled" },
|
||||
{GFXS_BLENDOP_ADD, "add" },
|
||||
{GFXS_BLENDOP_SUBTRACT, "subtract" },
|
||||
{GFXS_BLENDOP_REVSUBTRACT, "revsubtract"},
|
||||
{GFXS_BLENDOP_MIN, "min" },
|
||||
{GFXS_BLENDOP_MAX, "max" },
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxPolygonOffset_e,
|
||||
{
|
||||
{GFXS_POLYGON_OFFSET_0, "offset0" },
|
||||
{GFXS_POLYGON_OFFSET_1, "offset1" },
|
||||
{GFXS_POLYGON_OFFSET_2, "offset2" },
|
||||
{GFXS_POLYGON_OFFSET_SHADOWMAP, "offsetShadowmap"},
|
||||
});
|
||||
|
||||
class JsonStateBitsTableEntry
|
||||
{
|
||||
public:
|
||||
GfxBlend srcBlendRgb;
|
||||
GfxBlend dstBlendRgb;
|
||||
GfxBlendOp blendOpRgb;
|
||||
JsonAlphaTest alphaTest;
|
||||
JsonCullFace cullFace;
|
||||
GfxBlend srcBlendAlpha;
|
||||
GfxBlend dstBlendAlpha;
|
||||
GfxBlendOp blendOpAlpha;
|
||||
bool colorWriteRgb;
|
||||
bool colorWriteAlpha;
|
||||
bool gammaWrite;
|
||||
bool polymodeLine;
|
||||
bool depthWrite;
|
||||
JsonDepthTest depthTest;
|
||||
GfxPolygonOffset_e polygonOffset;
|
||||
std::optional<JsonStencil> stencilFront;
|
||||
std::optional<JsonStencil> stencilBack;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonStateBitsTableEntry,
|
||||
srcBlendRgb,
|
||||
dstBlendRgb,
|
||||
blendOpRgb,
|
||||
alphaTest,
|
||||
cullFace,
|
||||
srcBlendAlpha,
|
||||
dstBlendAlpha,
|
||||
blendOpAlpha,
|
||||
colorWriteRgb,
|
||||
colorWriteAlpha,
|
||||
polymodeLine,
|
||||
depthWrite,
|
||||
depthWrite,
|
||||
depthTest,
|
||||
polygonOffset,
|
||||
stencilFront,
|
||||
stencilBack);
|
||||
|
||||
class JsonConstant
|
||||
{
|
||||
public:
|
||||
std::optional<std::string> name;
|
||||
std::optional<std::string> nameFragment;
|
||||
std::optional<unsigned> nameHash;
|
||||
std::vector<float> literal;
|
||||
};
|
||||
|
||||
inline void to_json(nlohmann::json& out, const JsonConstant& in)
|
||||
{
|
||||
if (in.name.has_value())
|
||||
{
|
||||
optional_to_json(out, "name", in.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
optional_to_json(out, "nameFragment", in.nameFragment);
|
||||
optional_to_json(out, "nameHash", in.nameHash);
|
||||
}
|
||||
|
||||
out["literal"] = in.literal;
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& in, JsonConstant& out)
|
||||
{
|
||||
optional_from_json(in, "name", out.name);
|
||||
optional_from_json(in, "nameFragment", out.nameFragment);
|
||||
optional_from_json(in, "nameHash", out.nameHash);
|
||||
in.at("literal").get_to(out.literal);
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(TextureFilter,
|
||||
{
|
||||
{TEXTURE_FILTER_DISABLED, "disabled"},
|
||||
{TEXTURE_FILTER_NEAREST, "nearest" },
|
||||
{TEXTURE_FILTER_LINEAR, "linear" },
|
||||
{TEXTURE_FILTER_ANISO2X, "aniso2x" },
|
||||
{TEXTURE_FILTER_ANISO4X, "aniso4x" },
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(SamplerStateBitsMipMap_e,
|
||||
{
|
||||
{SAMPLER_MIPMAP_ENUM_DISABLED, "disabled"},
|
||||
{SAMPLER_MIPMAP_ENUM_NEAREST, "nearest" },
|
||||
{SAMPLER_MIPMAP_ENUM_LINEAR, "linear" },
|
||||
});
|
||||
|
||||
class JsonSamplerState
|
||||
{
|
||||
public:
|
||||
TextureFilter filter;
|
||||
SamplerStateBitsMipMap_e mipMap;
|
||||
bool clampU;
|
||||
bool clampV;
|
||||
bool clampW;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonSamplerState, filter, mipMap, clampU, clampV, clampW);
|
||||
|
||||
class JsonComplex
|
||||
{
|
||||
public:
|
||||
float real;
|
||||
float imag;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonComplex, real, imag);
|
||||
|
||||
class JsonWater
|
||||
{
|
||||
public:
|
||||
float floatTime;
|
||||
int m;
|
||||
int n;
|
||||
std::string h0;
|
||||
std::string wTerm;
|
||||
float lx;
|
||||
float lz;
|
||||
float gravity;
|
||||
float windvel;
|
||||
std::array<float, 2> winddir;
|
||||
float amplitude;
|
||||
std::array<float, 4> codeConstant;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonWater, floatTime, m, n, h0, wTerm, lx, lz, gravity, windvel, winddir, amplitude, codeConstant);
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(TextureSemantic,
|
||||
{
|
||||
{TS_2D, "2D" },
|
||||
{TS_FUNCTION, "function" },
|
||||
{TS_COLOR_MAP, "colorMap" },
|
||||
{TS_DETAIL_MAP, "detailMap" },
|
||||
{TS_UNUSED_2, "unused2" },
|
||||
{TS_NORMAL_MAP, "normalMap" },
|
||||
{TS_UNUSED_3, "unused3" },
|
||||
{TS_UNUSED_4, "unused4" },
|
||||
{TS_SPECULAR_MAP, "specularMap" },
|
||||
{TS_UNUSED_5, "unused5" },
|
||||
{TS_UNUSED_6, "unused6" },
|
||||
{TS_WATER_MAP, "waterMap" },
|
||||
{TS_DISPLACEMENT_MAP, "displacementMap"},
|
||||
});
|
||||
|
||||
class JsonTexture
|
||||
{
|
||||
public:
|
||||
std::optional<std::string> name;
|
||||
std::optional<unsigned> nameHash;
|
||||
std::optional<std::string> nameStart;
|
||||
std::optional<std::string> nameEnd;
|
||||
TextureSemantic semantic;
|
||||
JsonSamplerState samplerState;
|
||||
std::string image;
|
||||
std::optional<JsonWater> water;
|
||||
};
|
||||
|
||||
inline void to_json(nlohmann::json& out, const JsonTexture& in)
|
||||
{
|
||||
if (in.name.has_value())
|
||||
{
|
||||
optional_to_json(out, "name", in.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
optional_to_json(out, "nameHash", in.nameHash);
|
||||
optional_to_json(out, "nameStart", in.nameStart);
|
||||
optional_to_json(out, "nameEnd", in.nameEnd);
|
||||
}
|
||||
|
||||
out["semantic"] = in.semantic;
|
||||
out["samplerState"] = in.samplerState;
|
||||
out["image"] = in.image;
|
||||
optional_to_json(out, "water", in.water);
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& in, JsonTexture& out)
|
||||
{
|
||||
optional_from_json(in, "name", out.name);
|
||||
optional_from_json(in, "nameHash", out.nameHash);
|
||||
optional_from_json(in, "nameStart", out.nameStart);
|
||||
optional_from_json(in, "nameEnd", out.nameEnd);
|
||||
in.at("semantic").get_to(out.semantic);
|
||||
in.at("samplerState").get_to(out.samplerState);
|
||||
in.at("image").get_to(out.image);
|
||||
optional_from_json(in, "water", out.water);
|
||||
};
|
||||
|
||||
class JsonTextureAtlas
|
||||
{
|
||||
public:
|
||||
uint8_t rows;
|
||||
uint8_t columns;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonTextureAtlas, rows, columns);
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(MaterialGameFlags,
|
||||
{
|
||||
{MTL_GAMEFLAG_1, "1" },
|
||||
{MTL_GAMEFLAG_2, "2" },
|
||||
{MTL_GAMEFLAG_4, "4" },
|
||||
{MTL_GAMEFLAG_8, "8" },
|
||||
{MTL_GAMEFLAG_10, "10" },
|
||||
{MTL_GAMEFLAG_20, "20" },
|
||||
{MTL_GAMEFLAG_40, "40" },
|
||||
{MTL_GAMEFLAG_80, "80" },
|
||||
{MTL_GAMEFLAG_100, "100" },
|
||||
{MTL_GAMEFLAG_200, "200" },
|
||||
{MTL_GAMEFLAG_400, "400" },
|
||||
{MTL_GAMEFLAG_800, "800" },
|
||||
{MTL_GAMEFLAG_1000, "1000"},
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxCameraRegionType,
|
||||
{
|
||||
{CAMERA_REGION_LIT_OPAQUE, "litOpaque" },
|
||||
{CAMERA_REGION_LIT_TRANS, "litTrans" },
|
||||
{CAMERA_REGION_EMISSIVE, "emissive" },
|
||||
{CAMERA_REGION_DEPTH_HACK, "depthHack" },
|
||||
{CAMERA_REGION_LIGHT_MAP_OPAQUE, "lightMapOpaque"},
|
||||
{CAMERA_REGION_NONE, "none" },
|
||||
});
|
||||
|
||||
class JsonMaterial
|
||||
{
|
||||
public:
|
||||
std::vector<MaterialGameFlags> gameFlags;
|
||||
unsigned sortKey;
|
||||
std::optional<JsonTextureAtlas> textureAtlas;
|
||||
unsigned surfaceTypeBits;
|
||||
std::vector<int8_t> stateBitsEntry;
|
||||
unsigned stateFlags;
|
||||
GfxCameraRegionType cameraRegion;
|
||||
std::string techniqueSet;
|
||||
std::vector<JsonTexture> textures;
|
||||
std::vector<JsonConstant> constants;
|
||||
std::vector<JsonStateBitsTableEntry> stateBits;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonMaterial,
|
||||
gameFlags,
|
||||
sortKey,
|
||||
textureAtlas,
|
||||
surfaceTypeBits,
|
||||
stateBitsEntry,
|
||||
stateFlags,
|
||||
cameraRegion,
|
||||
techniqueSet,
|
||||
textures,
|
||||
constants,
|
||||
stateBits);
|
||||
} // namespace IW5
|
@ -1,397 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Game/T6/T6.h"
|
||||
|
||||
#include "Json/JsonExtension.h"
|
||||
#include <memory>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace T6
|
||||
{
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxStencilOp,
|
||||
{
|
||||
{GFXS_STENCILOP_KEEP, "keep" },
|
||||
{GFXS_STENCILOP_ZERO, "zero" },
|
||||
{GFXS_STENCILOP_REPLACE, "replace"},
|
||||
{GFXS_STENCILOP_INCRSAT, "incrsat"},
|
||||
{GFXS_STENCILOP_DECRSAT, "decrsat"},
|
||||
{GFXS_STENCILOP_INVERT, "invert" },
|
||||
{GFXS_STENCILOP_INCR, "incr" },
|
||||
{GFXS_STENCILOP_DECR, "decr" },
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxStencilFunc,
|
||||
{
|
||||
{GFXS_STENCILFUNC_NEVER, "never" },
|
||||
{GFXS_STENCILFUNC_LESS, "less" },
|
||||
{GFXS_STENCILFUNC_EQUAL, "equal" },
|
||||
{GFXS_STENCILFUNC_LESSEQUAL, "lessequal" },
|
||||
{GFXS_STENCILFUNC_GREATER, "greater" },
|
||||
{GFXS_STENCILFUNC_NOTEQUAL, "notequal" },
|
||||
{GFXS_STENCILFUNC_GREATEREQUAL, "greaterequal"},
|
||||
{GFXS_STENCILFUNC_ALWAYS, "always" },
|
||||
});
|
||||
|
||||
class JsonStencil
|
||||
{
|
||||
public:
|
||||
GfxStencilOp pass;
|
||||
GfxStencilOp fail;
|
||||
GfxStencilOp zfail;
|
||||
GfxStencilFunc func;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonStencil, pass, fail, zfail, func);
|
||||
|
||||
enum class JsonAlphaTest
|
||||
{
|
||||
INVALID,
|
||||
DISABLED,
|
||||
GT0,
|
||||
GE128
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(
|
||||
JsonAlphaTest,
|
||||
{
|
||||
{JsonAlphaTest::INVALID, nullptr },
|
||||
{JsonAlphaTest::DISABLED, "disabled"},
|
||||
{JsonAlphaTest::GT0, "gt0" },
|
||||
{JsonAlphaTest::GE128, "ge128" }
|
||||
});
|
||||
|
||||
enum class JsonCullFace
|
||||
{
|
||||
INVALID,
|
||||
NONE,
|
||||
BACK,
|
||||
FRONT
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(
|
||||
JsonCullFace,
|
||||
{
|
||||
{JsonCullFace::INVALID, nullptr},
|
||||
{JsonCullFace::NONE, "none" },
|
||||
{JsonCullFace::BACK, "back" },
|
||||
{JsonCullFace::FRONT, "front"}
|
||||
});
|
||||
|
||||
enum class JsonDepthTest
|
||||
{
|
||||
INVALID,
|
||||
DISABLED,
|
||||
ALWAYS,
|
||||
LESS,
|
||||
EQUAL,
|
||||
LESS_EQUAL
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(JsonDepthTest,
|
||||
{
|
||||
{JsonDepthTest::INVALID, nullptr },
|
||||
{JsonDepthTest::DISABLED, "disabled" },
|
||||
{JsonDepthTest::ALWAYS, "always" },
|
||||
{JsonDepthTest::LESS, "less" },
|
||||
{JsonDepthTest::EQUAL, "equal" },
|
||||
{JsonDepthTest::LESS_EQUAL, "less_equal"}
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxBlend,
|
||||
{
|
||||
{GFXS_BLEND_DISABLED, "disabled" },
|
||||
{GFXS_BLEND_ZERO, "zero" },
|
||||
{GFXS_BLEND_ONE, "one" },
|
||||
{GFXS_BLEND_SRCCOLOR, "srccolor" },
|
||||
{GFXS_BLEND_INVSRCCOLOR, "invsrccolor" },
|
||||
{GFXS_BLEND_SRCALPHA, "srcalpha" },
|
||||
{GFXS_BLEND_INVSRCALPHA, "invsrcalpha" },
|
||||
{GFXS_BLEND_DESTALPHA, "destalpha" },
|
||||
{GFXS_BLEND_INVDESTALPHA, "invdestalpha"},
|
||||
{GFXS_BLEND_DESTCOLOR, "destcolor" },
|
||||
{GFXS_BLEND_INVDESTCOLOR, "invdestcolor"},
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxBlendOp,
|
||||
{
|
||||
{GFXS_BLENDOP_DISABLED, "disabled" },
|
||||
{GFXS_BLENDOP_ADD, "add" },
|
||||
{GFXS_BLENDOP_SUBTRACT, "subtract" },
|
||||
{GFXS_BLENDOP_REVSUBTRACT, "revsubtract"},
|
||||
{GFXS_BLENDOP_MIN, "min" },
|
||||
{GFXS_BLENDOP_MAX, "max" },
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxPolygonOffset_e,
|
||||
{
|
||||
{GFXS_POLYGON_OFFSET_0, "offset0" },
|
||||
{GFXS_POLYGON_OFFSET_1, "offset1" },
|
||||
{GFXS_POLYGON_OFFSET_2, "offset2" },
|
||||
{GFXS_POLYGON_OFFSET_SHADOWMAP, "offsetShadowmap"},
|
||||
});
|
||||
|
||||
class JsonStateBitsTableEntry
|
||||
{
|
||||
public:
|
||||
GfxBlend srcBlendRgb;
|
||||
GfxBlend dstBlendRgb;
|
||||
GfxBlendOp blendOpRgb;
|
||||
JsonAlphaTest alphaTest;
|
||||
JsonCullFace cullFace;
|
||||
GfxBlend srcBlendAlpha;
|
||||
GfxBlend dstBlendAlpha;
|
||||
GfxBlendOp blendOpAlpha;
|
||||
bool colorWriteRgb;
|
||||
bool colorWriteAlpha;
|
||||
bool polymodeLine;
|
||||
bool depthWrite;
|
||||
JsonDepthTest depthTest;
|
||||
GfxPolygonOffset_e polygonOffset;
|
||||
std::optional<JsonStencil> stencilFront;
|
||||
std::optional<JsonStencil> stencilBack;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonStateBitsTableEntry,
|
||||
srcBlendRgb,
|
||||
dstBlendRgb,
|
||||
blendOpRgb,
|
||||
alphaTest,
|
||||
cullFace,
|
||||
srcBlendAlpha,
|
||||
dstBlendAlpha,
|
||||
blendOpAlpha,
|
||||
colorWriteRgb,
|
||||
colorWriteAlpha,
|
||||
polymodeLine,
|
||||
depthWrite,
|
||||
depthWrite,
|
||||
depthTest,
|
||||
polygonOffset,
|
||||
stencilFront,
|
||||
stencilBack);
|
||||
|
||||
class JsonConstant
|
||||
{
|
||||
public:
|
||||
std::optional<std::string> name;
|
||||
std::optional<std::string> nameFragment;
|
||||
std::optional<unsigned> nameHash;
|
||||
std::vector<float> literal;
|
||||
};
|
||||
|
||||
inline void to_json(nlohmann::json& out, const JsonConstant& in)
|
||||
{
|
||||
if (in.name.has_value())
|
||||
{
|
||||
optional_to_json(out, "name", in.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
optional_to_json(out, "nameFragment", in.nameFragment);
|
||||
optional_to_json(out, "nameHash", in.nameHash);
|
||||
}
|
||||
|
||||
out["literal"] = in.literal;
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& in, JsonConstant& out)
|
||||
{
|
||||
optional_from_json(in, "name", out.name);
|
||||
optional_from_json(in, "nameFragment", out.nameFragment);
|
||||
optional_from_json(in, "nameHash", out.nameHash);
|
||||
in.at("literal").get_to(out.literal);
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(TextureFilter,
|
||||
{
|
||||
{TEXTURE_FILTER_DISABLED, "disabled"},
|
||||
{TEXTURE_FILTER_NEAREST, "nearest" },
|
||||
{TEXTURE_FILTER_LINEAR, "linear" },
|
||||
{TEXTURE_FILTER_ANISO2X, "aniso2x" },
|
||||
{TEXTURE_FILTER_ANISO4X, "aniso4x" },
|
||||
{TEXTURE_FILTER_COMPARE, "compare" },
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(SamplerStateBitsMipMap_e,
|
||||
{
|
||||
{SAMPLER_MIPMAP_ENUM_DISABLED, "disabled"},
|
||||
{SAMPLER_MIPMAP_ENUM_NEAREST, "nearest" },
|
||||
{SAMPLER_MIPMAP_ENUM_LINEAR, "linear" },
|
||||
});
|
||||
|
||||
class JsonSamplerState
|
||||
{
|
||||
public:
|
||||
TextureFilter filter;
|
||||
SamplerStateBitsMipMap_e mipMap;
|
||||
bool clampU;
|
||||
bool clampV;
|
||||
bool clampW;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonSamplerState, filter, mipMap, clampU, clampV, clampW);
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(TextureSemantic,
|
||||
{
|
||||
{TS_2D, "2D" },
|
||||
{TS_FUNCTION, "function" },
|
||||
{TS_COLOR_MAP, "colorMap" },
|
||||
{TS_UNUSED_1, "unused1" },
|
||||
{TS_UNUSED_2, "unused2" },
|
||||
{TS_NORMAL_MAP, "normalMap" },
|
||||
{TS_UNUSED_3, "unused3" },
|
||||
{TS_UNUSED_4, "unused4" },
|
||||
{TS_SPECULAR_MAP, "specularMap" },
|
||||
{TS_UNUSED_5, "unused5" },
|
||||
{TS_OCCLUSION_MAP, "occlusionMap"},
|
||||
{TS_UNUSED_6, "unused6" },
|
||||
{TS_COLOR0_MAP, "color0Map" },
|
||||
{TS_COLOR1_MAP, "color1Map" },
|
||||
{TS_COLOR2_MAP, "color2Map" },
|
||||
{TS_COLOR3_MAP, "color3Map" },
|
||||
{TS_COLOR4_MAP, "color4Map" },
|
||||
{TS_COLOR5_MAP, "color5Map" },
|
||||
{TS_COLOR6_MAP, "color6Map" },
|
||||
{TS_COLOR7_MAP, "color7Map" },
|
||||
{TS_COLOR8_MAP, "color8Map" },
|
||||
{TS_COLOR9_MAP, "color9Map" },
|
||||
{TS_COLOR10_MAP, "color10Map" },
|
||||
{TS_COLOR11_MAP, "color11Map" },
|
||||
{TS_COLOR12_MAP, "color12Map" },
|
||||
{TS_COLOR13_MAP, "color13Map" },
|
||||
{TS_COLOR14_MAP, "color14Map" },
|
||||
{TS_COLOR15_MAP, "color15Map" },
|
||||
{TS_THROW_MAP, "throwMap" },
|
||||
});
|
||||
|
||||
class JsonTexture
|
||||
{
|
||||
public:
|
||||
std::optional<std::string> name;
|
||||
std::optional<unsigned> nameHash;
|
||||
std::optional<std::string> nameStart;
|
||||
std::optional<std::string> nameEnd;
|
||||
TextureSemantic semantic;
|
||||
bool isMatureContent;
|
||||
JsonSamplerState samplerState;
|
||||
std::string image;
|
||||
};
|
||||
|
||||
inline void to_json(nlohmann::json& out, const JsonTexture& in)
|
||||
{
|
||||
if (in.name.has_value())
|
||||
{
|
||||
optional_to_json(out, "name", in.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
optional_to_json(out, "nameHash", in.nameHash);
|
||||
optional_to_json(out, "nameStart", in.nameStart);
|
||||
optional_to_json(out, "nameEnd", in.nameEnd);
|
||||
}
|
||||
|
||||
out["semantic"] = in.semantic;
|
||||
out["isMatureContent"] = in.isMatureContent;
|
||||
out["samplerState"] = in.samplerState;
|
||||
out["image"] = in.image;
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& in, JsonTexture& out)
|
||||
{
|
||||
optional_from_json(in, "name", out.name);
|
||||
optional_from_json(in, "nameHash", out.nameHash);
|
||||
optional_from_json(in, "nameStart", out.nameStart);
|
||||
optional_from_json(in, "nameEnd", out.nameEnd);
|
||||
in.at("semantic").get_to(out.semantic);
|
||||
in.at("isMatureContent").get_to(out.isMatureContent);
|
||||
in.at("samplerState").get_to(out.samplerState);
|
||||
in.at("image").get_to(out.image);
|
||||
};
|
||||
|
||||
class JsonTextureAtlas
|
||||
{
|
||||
public:
|
||||
uint8_t rows;
|
||||
uint8_t columns;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonTextureAtlas, rows, columns);
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(MaterialGameFlags,
|
||||
{
|
||||
{MTL_GAMEFLAG_1, "1" },
|
||||
{MTL_GAMEFLAG_2, "2" },
|
||||
{MTL_GAMEFLAG_NO_MARKS, "NO_MARKS" },
|
||||
{MTL_GAMEFLAG_NO_MARKS, "4" },
|
||||
{MTL_GAMEFLAG_8, "8" },
|
||||
{MTL_GAMEFLAG_10, "10" },
|
||||
{MTL_GAMEFLAG_20, "20" },
|
||||
{MTL_GAMEFLAG_CASTS_SHADOW, "CASTS_SHADOW"},
|
||||
{MTL_GAMEFLAG_CASTS_SHADOW, "40" },
|
||||
{MTL_GAMEFLAG_80, "80" },
|
||||
{MTL_GAMEFLAG_100, "100" },
|
||||
{MTL_GAMEFLAG_200, "200" },
|
||||
{MTL_GAMEFLAG_400, "400" },
|
||||
{MTL_GAMEFLAG_800, "800" },
|
||||
{MTL_GAMEFLAG_1000, "1000" },
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxCameraRegionType,
|
||||
{
|
||||
{CAMERA_REGION_LIT_OPAQUE, "litOpaque" },
|
||||
{CAMERA_REGION_LIT_TRANS, "litTrans" },
|
||||
{CAMERA_REGION_LIT_QUASI_OPAQUE, "litQuasiOpaque"},
|
||||
{CAMERA_REGION_EMISSIVE_OPAQUE, "emissiveOpaque"},
|
||||
{CAMERA_REGION_EMISSIVE_TRANS, "emissiveTrans" },
|
||||
{CAMERA_REGION_EMISSIVE_FX, "emissiveFx" },
|
||||
{CAMERA_REGION_LIGHT_MAP_OPAQUE, "lightMapOpaque"},
|
||||
{CAMERA_REGION_DEPTH_HACK, "depthHack" },
|
||||
{CAMERA_REGION_UNUSED, "unused" },
|
||||
{CAMERA_REGION_SONAR, "sonar" },
|
||||
{CAMERA_REGION_NONE, "none" },
|
||||
});
|
||||
|
||||
class JsonMaterial
|
||||
{
|
||||
public:
|
||||
std::vector<MaterialGameFlags> gameFlags;
|
||||
unsigned sortKey;
|
||||
std::optional<JsonTextureAtlas> textureAtlas;
|
||||
unsigned surfaceTypeBits;
|
||||
unsigned layeredSurfaceTypes;
|
||||
unsigned hashIndex;
|
||||
unsigned surfaceFlags;
|
||||
unsigned contents;
|
||||
std::vector<int8_t> stateBitsEntry;
|
||||
unsigned stateFlags;
|
||||
GfxCameraRegionType cameraRegion;
|
||||
uint8_t probeMipBits;
|
||||
std::string techniqueSet;
|
||||
std::vector<JsonTexture> textures;
|
||||
std::vector<JsonConstant> constants;
|
||||
std::vector<JsonStateBitsTableEntry> stateBits;
|
||||
std::optional<std::string> thermalMaterial;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonMaterial,
|
||||
gameFlags,
|
||||
sortKey,
|
||||
textureAtlas,
|
||||
surfaceTypeBits,
|
||||
layeredSurfaceTypes,
|
||||
hashIndex,
|
||||
surfaceFlags,
|
||||
contents,
|
||||
stateBitsEntry,
|
||||
stateFlags,
|
||||
cameraRegion,
|
||||
probeMipBits,
|
||||
techniqueSet,
|
||||
textures,
|
||||
constants,
|
||||
stateBits,
|
||||
thermalMaterial);
|
||||
} // namespace T6
|
539
src/ObjCommon/Material/JsonMaterial.h.template
Normal file
539
src/ObjCommon/Material/JsonMaterial.h.template
Normal file
@ -0,0 +1,539 @@
|
||||
#options GAME (IW4, IW5, T6)
|
||||
|
||||
#filename "Game/" + GAME + "/Material/JsonMaterial" + GAME + ".h"
|
||||
|
||||
#if GAME == "IW4"
|
||||
#define FEATURE_IW4
|
||||
#define HAS_WATER
|
||||
#elif GAME == "IW5"
|
||||
#define FEATURE_IW5
|
||||
#define HAS_WATER
|
||||
#elif GAME == "T6"
|
||||
#define FEATURE_T6
|
||||
#endif
|
||||
|
||||
// This file was templated.
|
||||
// See JsonMaterialWriter.h.template.
|
||||
// Do not modify, changes will be lost.
|
||||
|
||||
#pragma once
|
||||
|
||||
#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\""
|
||||
#include GAME_HEADER
|
||||
|
||||
#include "Json/JsonExtension.h"
|
||||
|
||||
#include <memory>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace GAME
|
||||
{
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxStencilOp, {
|
||||
{GFXS_STENCILOP_KEEP, "keep" },
|
||||
{GFXS_STENCILOP_ZERO, "zero" },
|
||||
{GFXS_STENCILOP_REPLACE, "replace"},
|
||||
{GFXS_STENCILOP_INCRSAT, "incrsat"},
|
||||
{GFXS_STENCILOP_DECRSAT, "decrsat"},
|
||||
{GFXS_STENCILOP_INVERT, "invert" },
|
||||
{GFXS_STENCILOP_INCR, "incr" },
|
||||
{GFXS_STENCILOP_DECR, "decr" },
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxStencilFunc, {
|
||||
{GFXS_STENCILFUNC_NEVER, "never" },
|
||||
{GFXS_STENCILFUNC_LESS, "less" },
|
||||
{GFXS_STENCILFUNC_EQUAL, "equal" },
|
||||
{GFXS_STENCILFUNC_LESSEQUAL, "lessequal" },
|
||||
{GFXS_STENCILFUNC_GREATER, "greater" },
|
||||
{GFXS_STENCILFUNC_NOTEQUAL, "notequal" },
|
||||
{GFXS_STENCILFUNC_GREATEREQUAL, "greaterequal"},
|
||||
{GFXS_STENCILFUNC_ALWAYS, "always" },
|
||||
});
|
||||
|
||||
class JsonStencil
|
||||
{
|
||||
public:
|
||||
GfxStencilOp pass;
|
||||
GfxStencilOp fail;
|
||||
GfxStencilOp zfail;
|
||||
GfxStencilFunc func;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(
|
||||
JsonStencil,
|
||||
pass,
|
||||
fail,
|
||||
zfail,
|
||||
func
|
||||
);
|
||||
|
||||
enum class JsonAlphaTest
|
||||
{
|
||||
INVALID,
|
||||
DISABLED,
|
||||
GT0,
|
||||
#if defined(FEATURE_IW4) || defined(FEATURE_IW5)
|
||||
LT128,
|
||||
#endif
|
||||
GE128
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(JsonAlphaTest, {
|
||||
{JsonAlphaTest::INVALID, nullptr },
|
||||
{JsonAlphaTest::DISABLED, "disabled"},
|
||||
{JsonAlphaTest::GT0, "gt0" },
|
||||
#if defined(FEATURE_IW4) || defined(FEATURE_IW5)
|
||||
{JsonAlphaTest::LT128, "lt128" },
|
||||
#endif
|
||||
{JsonAlphaTest::GE128, "ge128" }
|
||||
});
|
||||
|
||||
enum class JsonCullFace
|
||||
{
|
||||
INVALID,
|
||||
NONE,
|
||||
BACK,
|
||||
FRONT
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(JsonCullFace, {
|
||||
{JsonCullFace::INVALID, nullptr},
|
||||
{JsonCullFace::NONE, "none" },
|
||||
{JsonCullFace::BACK, "back" },
|
||||
{JsonCullFace::FRONT, "front"}
|
||||
});
|
||||
|
||||
enum class JsonDepthTest
|
||||
{
|
||||
INVALID,
|
||||
DISABLED,
|
||||
ALWAYS,
|
||||
LESS,
|
||||
EQUAL,
|
||||
LESS_EQUAL
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(JsonDepthTest, {
|
||||
{JsonDepthTest::INVALID, nullptr },
|
||||
{JsonDepthTest::DISABLED, "disabled" },
|
||||
{JsonDepthTest::ALWAYS, "always" },
|
||||
{JsonDepthTest::LESS, "less" },
|
||||
{JsonDepthTest::EQUAL, "equal" },
|
||||
{JsonDepthTest::LESS_EQUAL, "less_equal"}
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxBlend, {
|
||||
{GFXS_BLEND_DISABLED, "disabled" },
|
||||
{GFXS_BLEND_ZERO, "zero" },
|
||||
{GFXS_BLEND_ONE, "one" },
|
||||
{GFXS_BLEND_SRCCOLOR, "srccolor" },
|
||||
{GFXS_BLEND_INVSRCCOLOR, "invsrccolor" },
|
||||
{GFXS_BLEND_SRCALPHA, "srcalpha" },
|
||||
{GFXS_BLEND_INVSRCALPHA, "invsrcalpha" },
|
||||
{GFXS_BLEND_DESTALPHA, "destalpha" },
|
||||
{GFXS_BLEND_INVDESTALPHA, "invdestalpha"},
|
||||
{GFXS_BLEND_DESTCOLOR, "destcolor" },
|
||||
{GFXS_BLEND_INVDESTCOLOR, "invdestcolor"},
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxBlendOp, {
|
||||
{GFXS_BLENDOP_DISABLED, "disabled" },
|
||||
{GFXS_BLENDOP_ADD, "add" },
|
||||
{GFXS_BLENDOP_SUBTRACT, "subtract" },
|
||||
{GFXS_BLENDOP_REVSUBTRACT, "revsubtract"},
|
||||
{GFXS_BLENDOP_MIN, "min" },
|
||||
{GFXS_BLENDOP_MAX, "max" },
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxPolygonOffset_e, {
|
||||
{GFXS_POLYGON_OFFSET_0, "offset0" },
|
||||
{GFXS_POLYGON_OFFSET_1, "offset1" },
|
||||
{GFXS_POLYGON_OFFSET_2, "offset2" },
|
||||
{GFXS_POLYGON_OFFSET_SHADOWMAP, "offsetShadowmap"},
|
||||
});
|
||||
|
||||
class JsonStateBitsTableEntry
|
||||
{
|
||||
public:
|
||||
GfxBlend srcBlendRgb;
|
||||
GfxBlend dstBlendRgb;
|
||||
GfxBlendOp blendOpRgb;
|
||||
JsonAlphaTest alphaTest;
|
||||
JsonCullFace cullFace;
|
||||
GfxBlend srcBlendAlpha;
|
||||
GfxBlend dstBlendAlpha;
|
||||
GfxBlendOp blendOpAlpha;
|
||||
bool colorWriteRgb;
|
||||
bool colorWriteAlpha;
|
||||
#if defined(FEATURE_IW4) || defined(FEATURE_IW5)
|
||||
bool gammaWrite;
|
||||
#endif
|
||||
bool polymodeLine;
|
||||
bool depthWrite;
|
||||
JsonDepthTest depthTest;
|
||||
GfxPolygonOffset_e polygonOffset;
|
||||
std::optional<JsonStencil> stencilFront;
|
||||
std::optional<JsonStencil> stencilBack;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonStateBitsTableEntry,
|
||||
srcBlendRgb,
|
||||
dstBlendRgb,
|
||||
blendOpRgb,
|
||||
alphaTest,
|
||||
cullFace,
|
||||
srcBlendAlpha,
|
||||
dstBlendAlpha,
|
||||
blendOpAlpha,
|
||||
colorWriteRgb,
|
||||
colorWriteAlpha,
|
||||
#if defined(FEATURE_IW4) || defined(FEATURE_IW5)
|
||||
gammaWrite,
|
||||
#endif
|
||||
polymodeLine,
|
||||
depthWrite,
|
||||
depthWrite,
|
||||
depthTest,
|
||||
polygonOffset,
|
||||
stencilFront,
|
||||
stencilBack
|
||||
);
|
||||
|
||||
class JsonConstant
|
||||
{
|
||||
public:
|
||||
std::optional<std::string> name;
|
||||
std::optional<std::string> nameFragment;
|
||||
std::optional<unsigned> nameHash;
|
||||
std::vector<float> literal;
|
||||
};
|
||||
|
||||
inline void to_json(nlohmann::json& out, const JsonConstant& in)
|
||||
{
|
||||
if (in.name.has_value())
|
||||
{
|
||||
optional_to_json(out, "name", in.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
optional_to_json(out, "nameFragment", in.nameFragment);
|
||||
optional_to_json(out, "nameHash", in.nameHash);
|
||||
}
|
||||
|
||||
out["literal"] = in.literal;
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& in, JsonConstant& out)
|
||||
{
|
||||
optional_from_json(in, "name", out.name);
|
||||
optional_from_json(in, "nameFragment", out.nameFragment);
|
||||
optional_from_json(in, "nameHash", out.nameHash);
|
||||
in.at("literal").get_to(out.literal);
|
||||
};
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(TextureFilter, {
|
||||
{TEXTURE_FILTER_DISABLED, "disabled"},
|
||||
{TEXTURE_FILTER_NEAREST, "nearest" },
|
||||
{TEXTURE_FILTER_LINEAR, "linear" },
|
||||
{TEXTURE_FILTER_ANISO2X, "aniso2x" },
|
||||
{TEXTURE_FILTER_ANISO4X, "aniso4x" },
|
||||
#ifdef FEATURE_T6
|
||||
{TEXTURE_FILTER_COMPARE, "compare" },
|
||||
#endif
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(SamplerStateBitsMipMap_e, {
|
||||
{SAMPLER_MIPMAP_ENUM_DISABLED, "disabled"},
|
||||
{SAMPLER_MIPMAP_ENUM_NEAREST, "nearest" },
|
||||
{SAMPLER_MIPMAP_ENUM_LINEAR, "linear" },
|
||||
});
|
||||
|
||||
class JsonSamplerState
|
||||
{
|
||||
public:
|
||||
TextureFilter filter;
|
||||
SamplerStateBitsMipMap_e mipMap;
|
||||
bool clampU;
|
||||
bool clampV;
|
||||
bool clampW;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(
|
||||
JsonSamplerState,
|
||||
filter,
|
||||
mipMap,
|
||||
clampU,
|
||||
clampV,
|
||||
clampW
|
||||
);
|
||||
|
||||
#ifdef HAS_WATER
|
||||
class JsonComplex
|
||||
{
|
||||
public:
|
||||
float real;
|
||||
float imag;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(JsonComplex, real, imag);
|
||||
|
||||
class JsonWater
|
||||
{
|
||||
public:
|
||||
float floatTime;
|
||||
int m;
|
||||
int n;
|
||||
std::string h0;
|
||||
std::string wTerm;
|
||||
float lx;
|
||||
float lz;
|
||||
float gravity;
|
||||
float windvel;
|
||||
std::array<float, 2> winddir;
|
||||
float amplitude;
|
||||
std::array<float, 4> codeConstant;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(
|
||||
JsonWater,
|
||||
floatTime,
|
||||
m,
|
||||
n,
|
||||
h0,
|
||||
wTerm,
|
||||
lx,
|
||||
lz,
|
||||
gravity,
|
||||
windvel,
|
||||
winddir,
|
||||
amplitude,
|
||||
codeConstant
|
||||
);
|
||||
#endif
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(TextureSemantic, {
|
||||
#if defined(FEATURE_IW4) || defined(FEATURE_IW5)
|
||||
{TS_2D, "2D" },
|
||||
{TS_FUNCTION, "function" },
|
||||
{TS_COLOR_MAP, "colorMap" },
|
||||
{TS_DETAIL_MAP, "detailMap" },
|
||||
{TS_UNUSED_2, "unused2" },
|
||||
{TS_NORMAL_MAP, "normalMap" },
|
||||
{TS_UNUSED_3, "unused3" },
|
||||
{TS_UNUSED_4, "unused4" },
|
||||
{TS_SPECULAR_MAP, "specularMap" },
|
||||
{TS_UNUSED_5, "unused5" },
|
||||
{TS_UNUSED_6, "unused6" },
|
||||
{TS_WATER_MAP, "waterMap" },
|
||||
#ifdef FEATURE_IW5
|
||||
{TS_DISPLACEMENT_MAP, "displacementMap"},
|
||||
#endif
|
||||
#elif defined(FEATURE_T6)
|
||||
{TS_2D, "2D" },
|
||||
{TS_FUNCTION, "function" },
|
||||
{TS_COLOR_MAP, "colorMap" },
|
||||
{TS_UNUSED_1, "unused1" },
|
||||
{TS_UNUSED_2, "unused2" },
|
||||
{TS_NORMAL_MAP, "normalMap" },
|
||||
{TS_UNUSED_3, "unused3" },
|
||||
{TS_UNUSED_4, "unused4" },
|
||||
{TS_SPECULAR_MAP, "specularMap" },
|
||||
{TS_UNUSED_5, "unused5" },
|
||||
{TS_OCCLUSION_MAP, "occlusionMap"},
|
||||
{TS_UNUSED_6, "unused6" },
|
||||
{TS_COLOR0_MAP, "color0Map" },
|
||||
{TS_COLOR1_MAP, "color1Map" },
|
||||
{TS_COLOR2_MAP, "color2Map" },
|
||||
{TS_COLOR3_MAP, "color3Map" },
|
||||
{TS_COLOR4_MAP, "color4Map" },
|
||||
{TS_COLOR5_MAP, "color5Map" },
|
||||
{TS_COLOR6_MAP, "color6Map" },
|
||||
{TS_COLOR7_MAP, "color7Map" },
|
||||
{TS_COLOR8_MAP, "color8Map" },
|
||||
{TS_COLOR9_MAP, "color9Map" },
|
||||
{TS_COLOR10_MAP, "color10Map" },
|
||||
{TS_COLOR11_MAP, "color11Map" },
|
||||
{TS_COLOR12_MAP, "color12Map" },
|
||||
{TS_COLOR13_MAP, "color13Map" },
|
||||
{TS_COLOR14_MAP, "color14Map" },
|
||||
{TS_COLOR15_MAP, "color15Map" },
|
||||
{TS_THROW_MAP, "throwMap" },
|
||||
#endif
|
||||
});
|
||||
|
||||
class JsonTexture
|
||||
{
|
||||
public:
|
||||
std::optional<std::string> name;
|
||||
std::optional<unsigned> nameHash;
|
||||
std::optional<std::string> nameStart;
|
||||
std::optional<std::string> nameEnd;
|
||||
TextureSemantic semantic;
|
||||
#ifdef FEATURE_T6
|
||||
bool isMatureContent;
|
||||
#endif
|
||||
JsonSamplerState samplerState;
|
||||
std::string image;
|
||||
#ifdef HAS_WATER
|
||||
std::optional<JsonWater> water;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline void to_json(nlohmann::json& out, const JsonTexture& in)
|
||||
{
|
||||
if (in.name.has_value())
|
||||
{
|
||||
optional_to_json(out, "name", in.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
optional_to_json(out, "nameHash", in.nameHash);
|
||||
optional_to_json(out, "nameStart", in.nameStart);
|
||||
optional_to_json(out, "nameEnd", in.nameEnd);
|
||||
}
|
||||
|
||||
out["semantic"] = in.semantic;
|
||||
#ifdef FEATURE_T6
|
||||
out["isMatureContent"] = in.isMatureContent;
|
||||
#endif
|
||||
out["samplerState"] = in.samplerState;
|
||||
out["image"] = in.image;
|
||||
#ifdef HAS_WATER
|
||||
optional_to_json(out, "water", in.water);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void from_json(const nlohmann::json& in, JsonTexture& out)
|
||||
{
|
||||
optional_from_json(in, "name", out.name);
|
||||
optional_from_json(in, "nameHash", out.nameHash);
|
||||
optional_from_json(in, "nameStart", out.nameStart);
|
||||
optional_from_json(in, "nameEnd", out.nameEnd);
|
||||
in.at("semantic").get_to(out.semantic);
|
||||
#ifdef FEATURE_T6
|
||||
in.at("isMatureContent").get_to(out.isMatureContent);
|
||||
#endif
|
||||
in.at("samplerState").get_to(out.samplerState);
|
||||
in.at("image").get_to(out.image);
|
||||
#ifdef HAS_WATER
|
||||
optional_from_json(in, "water", out.water);
|
||||
#endif
|
||||
};
|
||||
|
||||
class JsonTextureAtlas
|
||||
{
|
||||
public:
|
||||
uint8_t rows;
|
||||
uint8_t columns;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(
|
||||
JsonTextureAtlas,
|
||||
rows,
|
||||
columns
|
||||
);
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(MaterialGameFlags, {
|
||||
#if defined(FEATURE_IW4) || defined(FEATURE_IW5)
|
||||
{MTL_GAMEFLAG_1, "1" },
|
||||
{MTL_GAMEFLAG_2, "2" },
|
||||
{MTL_GAMEFLAG_4, "4" },
|
||||
{MTL_GAMEFLAG_8, "8" },
|
||||
{MTL_GAMEFLAG_10, "10" },
|
||||
{MTL_GAMEFLAG_20, "20" },
|
||||
{MTL_GAMEFLAG_40, "40" },
|
||||
{MTL_GAMEFLAG_80, "80" },
|
||||
#elif defined(FEATURE_T6)
|
||||
{MTL_GAMEFLAG_1, "1" },
|
||||
{MTL_GAMEFLAG_2, "2" },
|
||||
{MTL_GAMEFLAG_NO_MARKS, "NO_MARKS" },
|
||||
{MTL_GAMEFLAG_NO_MARKS, "4" },
|
||||
{MTL_GAMEFLAG_8, "8" },
|
||||
{MTL_GAMEFLAG_10, "10" },
|
||||
{MTL_GAMEFLAG_20, "20" },
|
||||
{MTL_GAMEFLAG_CASTS_SHADOW, "CASTS_SHADOW"},
|
||||
{MTL_GAMEFLAG_CASTS_SHADOW, "40" },
|
||||
{MTL_GAMEFLAG_80, "80" },
|
||||
{MTL_GAMEFLAG_100, "100" },
|
||||
{MTL_GAMEFLAG_200, "200" },
|
||||
{MTL_GAMEFLAG_400, "400" },
|
||||
{MTL_GAMEFLAG_800, "800" },
|
||||
{MTL_GAMEFLAG_1000, "1000" },
|
||||
#endif
|
||||
});
|
||||
|
||||
NLOHMANN_JSON_SERIALIZE_ENUM(GfxCameraRegionType, {
|
||||
#if defined(FEATURE_IW4) || defined(FEATURE_IW5)
|
||||
{CAMERA_REGION_LIT_OPAQUE, "litOpaque" },
|
||||
{CAMERA_REGION_LIT_TRANS, "litTrans" },
|
||||
{CAMERA_REGION_EMISSIVE, "emissive" },
|
||||
{CAMERA_REGION_DEPTH_HACK, "depthHack" },
|
||||
#ifdef FEATURE_IW5
|
||||
{CAMERA_REGION_LIGHT_MAP_OPAQUE, "lightMapOpaque"},
|
||||
#endif
|
||||
{CAMERA_REGION_NONE, "none" },
|
||||
#elif defined(FEATURE_T6)
|
||||
{CAMERA_REGION_LIT_OPAQUE, "litOpaque" },
|
||||
{CAMERA_REGION_LIT_TRANS, "litTrans" },
|
||||
{CAMERA_REGION_LIT_QUASI_OPAQUE, "litQuasiOpaque"},
|
||||
{CAMERA_REGION_EMISSIVE_OPAQUE, "emissiveOpaque"},
|
||||
{CAMERA_REGION_EMISSIVE_TRANS, "emissiveTrans" },
|
||||
{CAMERA_REGION_EMISSIVE_FX, "emissiveFx" },
|
||||
{CAMERA_REGION_LIGHT_MAP_OPAQUE, "lightMapOpaque"},
|
||||
{CAMERA_REGION_DEPTH_HACK, "depthHack" },
|
||||
{CAMERA_REGION_UNUSED, "unused" },
|
||||
{CAMERA_REGION_SONAR, "sonar" },
|
||||
{CAMERA_REGION_NONE, "none" },
|
||||
#endif
|
||||
});
|
||||
|
||||
class JsonMaterial
|
||||
{
|
||||
public:
|
||||
#ifdef FEATURE_T6
|
||||
unsigned layeredSurfaceTypes;
|
||||
unsigned hashIndex;
|
||||
unsigned surfaceFlags;
|
||||
unsigned contents;
|
||||
uint8_t probeMipBits;
|
||||
std::optional<std::string> thermalMaterial;
|
||||
#endif
|
||||
std::vector<MaterialGameFlags> gameFlags;
|
||||
unsigned sortKey;
|
||||
std::optional<JsonTextureAtlas> textureAtlas;
|
||||
unsigned surfaceTypeBits;
|
||||
std::vector<int8_t> stateBitsEntry;
|
||||
unsigned stateFlags;
|
||||
GfxCameraRegionType cameraRegion;
|
||||
std::string techniqueSet;
|
||||
std::vector<JsonTexture> textures;
|
||||
std::vector<JsonConstant> constants;
|
||||
std::vector<JsonStateBitsTableEntry> stateBits;
|
||||
};
|
||||
|
||||
NLOHMANN_DEFINE_TYPE_EXTENSION(
|
||||
JsonMaterial,
|
||||
#ifdef FEATURE_T6
|
||||
layeredSurfaceTypes,
|
||||
hashIndex,
|
||||
surfaceFlags,
|
||||
contents,
|
||||
probeMipBits,
|
||||
thermalMaterial,
|
||||
#endif
|
||||
gameFlags,
|
||||
sortKey,
|
||||
textureAtlas,
|
||||
surfaceTypeBits,
|
||||
stateBitsEntry,
|
||||
stateFlags,
|
||||
cameraRegion,
|
||||
techniqueSet,
|
||||
textures,
|
||||
constants,
|
||||
stateBits
|
||||
);
|
||||
} // namespace GAME
|
22
src/ObjCommon/Material/MaterialCommon.cpp
Normal file
22
src/ObjCommon/Material/MaterialCommon.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "MaterialCommon.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <format>
|
||||
|
||||
namespace material
|
||||
{
|
||||
std::string GetFileNameForAssetName(const std::string& assetName)
|
||||
{
|
||||
std::string sanitizedFileName(assetName);
|
||||
if (sanitizedFileName[0] == '*')
|
||||
{
|
||||
std::ranges::replace(sanitizedFileName, '*', '_');
|
||||
const auto parenthesisPos = sanitizedFileName.find('(');
|
||||
if (parenthesisPos != std::string::npos)
|
||||
sanitizedFileName.erase(parenthesisPos);
|
||||
sanitizedFileName = std::format("generated/{}", sanitizedFileName);
|
||||
}
|
||||
|
||||
return std::format("materials/{}.json", sanitizedFileName);
|
||||
}
|
||||
} // namespace material
|
8
src/ObjCommon/Material/MaterialCommon.h
Normal file
8
src/ObjCommon/Material/MaterialCommon.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace material
|
||||
{
|
||||
std::string GetFileNameForAssetName(const std::string& assetName);
|
||||
}
|
1383
src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.cpp
Normal file
1383
src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.cpp
Normal file
File diff suppressed because it is too large
Load Diff
12
src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.h
Normal file
12
src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "Asset/IAssetCreator.h"
|
||||
#include "Game/IW4/IW4.h"
|
||||
#include "Gdt/IGdtQueryable.h"
|
||||
#include "SearchPath/ISearchPath.h"
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
namespace IW4
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetMaterial>> CreateMaterialCompiler(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt);
|
||||
} // namespace IW4
|
@ -2,6 +2,9 @@
|
||||
|
||||
#include "Game/IW4/IW4.h"
|
||||
#include "Image/ImageIwdPostProcessor.h"
|
||||
#include "Material/CompilerMaterialIW4.h"
|
||||
#include "Techset/CompilerTechsetIW4.h"
|
||||
#include "Techset/CompilerVertexDeclIW4.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
@ -9,11 +12,15 @@ using namespace IW4;
|
||||
|
||||
namespace
|
||||
{
|
||||
void ConfigureCompilers(AssetCreatorCollection& collection, Zone& zone, ISearchPath& searchPath)
|
||||
void ConfigureCompilers(AssetCreatorCollection& collection, Zone& zone, ISearchPath& searchPath, IGdtQueryable& gdt)
|
||||
{
|
||||
auto& memory = zone.Memory();
|
||||
|
||||
// No compilers yet
|
||||
#ifdef EXPERIMENTAL_MATERIAL_COMPILATION
|
||||
collection.AddAssetCreator(CreateMaterialCompiler(memory, searchPath, gdt));
|
||||
collection.AddAssetCreator(CreateTechsetLoader(memory, searchPath));
|
||||
#endif
|
||||
collection.AddAssetCreator(CreateVertexDeclLoader(memory));
|
||||
}
|
||||
|
||||
void ConfigurePostProcessors(AssetCreatorCollection& collection,
|
||||
@ -39,5 +46,6 @@ void ObjCompiler::ConfigureCreatorCollection(AssetCreatorCollection& collection,
|
||||
IOutputPath& outDir,
|
||||
IOutputPath& cacheDir) const
|
||||
{
|
||||
ConfigureCompilers(collection, zone, searchPath, gdt);
|
||||
ConfigurePostProcessors(collection, zone, zoneDefinition, searchPath, zoneStates, outDir);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "LoaderTechsetIW4.h"
|
||||
#include "CompilerTechsetIW4.h"
|
||||
|
||||
#include "Game/IW4/IW4.h"
|
||||
#include "Game/IW4/Shader/LoaderPixelShaderIW4.h"
|
@ -1,4 +1,4 @@
|
||||
#include "LoaderVertexDeclIW4.h"
|
||||
#include "CompilerVertexDeclIW4.h"
|
||||
|
||||
#include "Game/IW4/IW4.h"
|
||||
#include "Game/IW4/TechsetConstantsIW4.h"
|
@ -52,6 +52,7 @@ function ObjLoading:project()
|
||||
}
|
||||
}
|
||||
|
||||
ObjCommon:use()
|
||||
useSourceTemplating("ObjLoading")
|
||||
|
||||
self:include(includes)
|
||||
|
@ -25,7 +25,7 @@ public:
|
||||
|
||||
[[nodiscard]] virtual std::optional<asset_type_t> GetHandlingAssetType() const = 0;
|
||||
virtual AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) = 0;
|
||||
virtual void FinalizeZone(AssetCreationContext& context){};
|
||||
virtual void FinalizeZone(AssetCreationContext& context) {};
|
||||
};
|
||||
|
||||
template<typename AssetType> class AssetCreator : public IAssetCreator
|
||||
|
@ -25,5 +25,5 @@ public:
|
||||
|
||||
[[nodiscard]] virtual asset_type_t GetHandlingAssetType() const = 0;
|
||||
virtual void PostProcessAsset(XAssetInfoGeneric& assetInfo, AssetCreationContext& context) = 0;
|
||||
virtual void FinalizeZone(AssetCreationContext& context){};
|
||||
virtual void FinalizeZone(AssetCreationContext& context) {};
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -8,5 +8,5 @@
|
||||
|
||||
namespace IW4
|
||||
{
|
||||
std::unique_ptr<AssetCreator<AssetMaterial>> CreateMaterialLoader(MemoryManager& memory, ISearchPath& searchPath, IGdtQueryable& gdt);
|
||||
std::unique_ptr<AssetCreator<AssetMaterial>> CreateMaterialLoader(MemoryManager& memory, ISearchPath& searchPath);
|
||||
} // namespace IW4
|
||||
|
@ -17,8 +17,6 @@
|
||||
#include "Sound/LoaderSoundCurveIW4.h"
|
||||
#include "StringTable/LoaderStringTableIW4.h"
|
||||
#include "StructuredDataDef/LoaderStructuredDataDefIW4.h"
|
||||
#include "Techset/LoaderTechsetIW4.h"
|
||||
#include "Techset/LoaderVertexDeclIW4.h"
|
||||
#include "Weapon/GdtLoaderWeaponIW4.h"
|
||||
#include "Weapon/RawLoaderWeaponIW4.h"
|
||||
|
||||
@ -126,11 +124,10 @@ namespace
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderXAnim>(memory));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderXModelSurfs>(memory));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderXModel>(memory));
|
||||
collection.AddAssetCreator(CreateMaterialLoader(memory, searchPath, gdt));
|
||||
collection.AddAssetCreator(CreateMaterialLoader(memory, searchPath));
|
||||
collection.AddAssetCreator(CreatePixelShaderLoader(memory, searchPath));
|
||||
collection.AddAssetCreator(CreateVertexShaderLoader(memory, searchPath));
|
||||
collection.AddAssetCreator(CreateVertexDeclLoader(memory));
|
||||
collection.AddAssetCreator(CreateTechsetLoader(memory, searchPath));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderTechset>(memory));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderImage>(memory));
|
||||
// collection.AddAssetCreator(std::make_unique<AssetLoaderSound>(memory));
|
||||
collection.AddAssetCreator(CreateSoundCurveLoader(memory, searchPath));
|
||||
|
@ -1,10 +1,9 @@
|
||||
#include "LoaderMaterialIW5.h"
|
||||
|
||||
#include "Game/IW5/IW5.h"
|
||||
#include "JsonMaterialLoader.h"
|
||||
#include "Game/IW5/Material/JsonMaterialLoaderIW5.h"
|
||||
#include "Material/MaterialCommon.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
|
||||
@ -23,7 +22,7 @@ namespace
|
||||
|
||||
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
||||
{
|
||||
const auto file = m_search_path.Open(GetFileNameForAsset(assetName));
|
||||
const auto file = m_search_path.Open(material::GetFileNameForAssetName(assetName));
|
||||
if (!file.IsOpen())
|
||||
return AssetCreationResult::NoAction();
|
||||
|
||||
@ -41,21 +40,6 @@ namespace
|
||||
}
|
||||
|
||||
private:
|
||||
std::string GetFileNameForAsset(const std::string& assetName)
|
||||
{
|
||||
std::string sanitizedFileName(assetName);
|
||||
if (sanitizedFileName[0] == '*')
|
||||
{
|
||||
std::ranges::replace(sanitizedFileName, '*', '_');
|
||||
const auto parenthesisPos = sanitizedFileName.find('(');
|
||||
if (parenthesisPos != std::string::npos)
|
||||
sanitizedFileName.erase(parenthesisPos);
|
||||
sanitizedFileName = std::format("generated/{}", sanitizedFileName);
|
||||
}
|
||||
|
||||
return std::format("materials/{}.json", sanitizedFileName);
|
||||
}
|
||||
|
||||
MemoryManager& m_memory;
|
||||
ISearchPath& m_search_path;
|
||||
};
|
||||
|
@ -1,382 +0,0 @@
|
||||
#include "JsonMaterialLoader.h"
|
||||
|
||||
#include "Game/T6/CommonT6.h"
|
||||
#include "Game/T6/Json/JsonMaterial.h"
|
||||
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using namespace nlohmann;
|
||||
using namespace T6;
|
||||
|
||||
namespace
|
||||
{
|
||||
class JsonLoader
|
||||
{
|
||||
public:
|
||||
JsonLoader(std::istream& stream, MemoryManager& memory, AssetCreationContext& context, AssetRegistration<AssetMaterial>& registration)
|
||||
: m_stream(stream),
|
||||
m_memory(memory),
|
||||
m_context(context),
|
||||
m_registration(registration)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
bool Load(Material& material) const
|
||||
{
|
||||
const auto jRoot = json::parse(m_stream);
|
||||
std::string type;
|
||||
unsigned version;
|
||||
|
||||
jRoot.at("_type").get_to(type);
|
||||
jRoot.at("_version").get_to(version);
|
||||
|
||||
if (type != "material" || version != 1u)
|
||||
{
|
||||
std::cerr << std::format("Tried to load material \"{}\" but did not find expected type material of version 1\n", material.info.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
const auto jMaterial = jRoot.get<JsonMaterial>();
|
||||
return CreateMaterialFromJson(jMaterial, material);
|
||||
}
|
||||
catch (const json::exception& e)
|
||||
{
|
||||
std::cerr << std::format("Failed to parse json of material: {}\n", e.what());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
static void PrintError(const Material& material, const std::string& message)
|
||||
{
|
||||
std::cerr << std::format("Cannot load material \"{}\": {}\n", material.info.name, message);
|
||||
}
|
||||
|
||||
static bool CreateGameFlagsFromJson(const JsonMaterial& jMaterial, unsigned& gameFlags)
|
||||
{
|
||||
for (const auto gameFlag : jMaterial.gameFlags)
|
||||
gameFlags |= gameFlag;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateTextureDefFromJson(const JsonTexture& jTexture, MaterialTextureDef& textureDef, const Material& material) const
|
||||
{
|
||||
if (jTexture.name)
|
||||
{
|
||||
if (jTexture.name->empty())
|
||||
{
|
||||
PrintError(material, "textureDef name cannot be empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
textureDef.nameStart = jTexture.name.value()[0];
|
||||
textureDef.nameEnd = jTexture.name.value()[jTexture.name->size() - 1];
|
||||
textureDef.nameHash = Common::R_HashString(jTexture.name.value().c_str(), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!jTexture.nameStart || !jTexture.nameEnd || !jTexture.nameHash)
|
||||
{
|
||||
PrintError(material, "textureDefs without name must have nameStart, nameEnd and nameHash");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (jTexture.nameStart->size() != 1 || jTexture.nameEnd->size() != 1)
|
||||
{
|
||||
PrintError(material, "nameStart and nameEnd must be a string of exactly one character");
|
||||
return false;
|
||||
}
|
||||
|
||||
textureDef.nameStart = jTexture.nameStart.value()[0];
|
||||
textureDef.nameEnd = jTexture.nameEnd.value()[0];
|
||||
textureDef.nameHash = jTexture.nameHash.value();
|
||||
}
|
||||
|
||||
textureDef.samplerState.filter = jTexture.samplerState.filter;
|
||||
textureDef.samplerState.mipMap = jTexture.samplerState.mipMap;
|
||||
textureDef.samplerState.clampU = jTexture.samplerState.clampU;
|
||||
textureDef.samplerState.clampV = jTexture.samplerState.clampV;
|
||||
textureDef.samplerState.clampW = jTexture.samplerState.clampW;
|
||||
|
||||
textureDef.semantic = jTexture.semantic;
|
||||
textureDef.isMatureContent = jTexture.isMatureContent;
|
||||
|
||||
auto* image = m_context.LoadDependency<AssetImage>(jTexture.image);
|
||||
if (!image)
|
||||
{
|
||||
PrintError(material, std::format("Could not find textureDef image: {}", jTexture.image));
|
||||
return false;
|
||||
}
|
||||
m_registration.AddDependency(image);
|
||||
textureDef.image = image->Asset();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CreateConstantDefFromJson(const JsonConstant& jConstant, MaterialConstantDef& constantDef, const Material& material)
|
||||
{
|
||||
if (jConstant.name)
|
||||
{
|
||||
const auto copyCount = std::min(jConstant.name->size() + 1, std::extent_v<decltype(MaterialConstantDef::name)>);
|
||||
strncpy(constantDef.name, jConstant.name->c_str(), copyCount);
|
||||
if (copyCount < std::extent_v<decltype(MaterialConstantDef::name)>)
|
||||
memset(&constantDef.name[copyCount], 0, std::extent_v<decltype(MaterialConstantDef::name)> - copyCount);
|
||||
constantDef.nameHash = Common::R_HashString(jConstant.name->c_str(), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!jConstant.nameFragment || !jConstant.nameHash)
|
||||
{
|
||||
PrintError(material, "constantDefs without name must have nameFragment and nameHash");
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto copyCount = std::min(jConstant.nameFragment->size() + 1, std::extent_v<decltype(MaterialConstantDef::name)>);
|
||||
strncpy(constantDef.name, jConstant.nameFragment->c_str(), copyCount);
|
||||
if (copyCount < std::extent_v<decltype(MaterialConstantDef::name)>)
|
||||
memset(&constantDef.name[copyCount], 0, std::extent_v<decltype(MaterialConstantDef::name)> - copyCount);
|
||||
constantDef.nameHash = jConstant.nameHash.value();
|
||||
}
|
||||
|
||||
if (jConstant.literal.size() != 4)
|
||||
{
|
||||
PrintError(material, "constantDef literal must be array of size 4");
|
||||
return false;
|
||||
}
|
||||
|
||||
constantDef.literal.x = jConstant.literal[0];
|
||||
constantDef.literal.y = jConstant.literal[1];
|
||||
constantDef.literal.z = jConstant.literal[2];
|
||||
constantDef.literal.w = jConstant.literal[3];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
CreateStateBitsTableEntryFromJson(const JsonStateBitsTableEntry& jStateBitsTableEntry, GfxStateBits& stateBitsTableEntry, const Material& material)
|
||||
{
|
||||
auto& structured = stateBitsTableEntry.loadBits.structured;
|
||||
|
||||
structured.srcBlendRgb = jStateBitsTableEntry.srcBlendRgb;
|
||||
structured.dstBlendRgb = jStateBitsTableEntry.dstBlendRgb;
|
||||
structured.blendOpRgb = jStateBitsTableEntry.blendOpRgb;
|
||||
|
||||
if (jStateBitsTableEntry.alphaTest == JsonAlphaTest::DISABLED)
|
||||
{
|
||||
structured.alphaTestDisabled = 1;
|
||||
structured.alphaTest = 0;
|
||||
}
|
||||
else if (jStateBitsTableEntry.alphaTest == JsonAlphaTest::GT0)
|
||||
{
|
||||
structured.alphaTestDisabled = 0;
|
||||
structured.alphaTest = GFXS_ALPHA_TEST_GT_0;
|
||||
}
|
||||
else if (jStateBitsTableEntry.alphaTest == JsonAlphaTest::GE128)
|
||||
{
|
||||
structured.alphaTestDisabled = 0;
|
||||
structured.alphaTest = GFXS_ALPHA_TEST_GE_128;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintError(material, "Invalid value for alphaTest");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (jStateBitsTableEntry.cullFace == JsonCullFace::NONE)
|
||||
structured.cullFace = GFXS0_CULL_NONE;
|
||||
else if (jStateBitsTableEntry.cullFace == JsonCullFace::BACK)
|
||||
structured.cullFace = GFXS0_CULL_BACK;
|
||||
else if (jStateBitsTableEntry.cullFace == JsonCullFace::FRONT)
|
||||
structured.cullFace = GFXS0_CULL_FRONT;
|
||||
else
|
||||
{
|
||||
PrintError(material, "Invalid value for cull face");
|
||||
return false;
|
||||
}
|
||||
|
||||
structured.srcBlendAlpha = jStateBitsTableEntry.srcBlendAlpha;
|
||||
structured.dstBlendAlpha = jStateBitsTableEntry.dstBlendAlpha;
|
||||
structured.blendOpAlpha = jStateBitsTableEntry.blendOpAlpha;
|
||||
structured.colorWriteRgb = jStateBitsTableEntry.colorWriteRgb;
|
||||
structured.colorWriteAlpha = jStateBitsTableEntry.colorWriteAlpha;
|
||||
structured.polymodeLine = jStateBitsTableEntry.polymodeLine;
|
||||
structured.depthWrite = jStateBitsTableEntry.depthWrite;
|
||||
|
||||
if (jStateBitsTableEntry.depthTest == JsonDepthTest::DISABLED)
|
||||
structured.depthTestDisabled = 1;
|
||||
else if (jStateBitsTableEntry.depthTest == JsonDepthTest::ALWAYS)
|
||||
structured.depthTest = GFXS_DEPTHTEST_ALWAYS;
|
||||
else if (jStateBitsTableEntry.depthTest == JsonDepthTest::LESS)
|
||||
structured.depthTest = GFXS_DEPTHTEST_LESS;
|
||||
else if (jStateBitsTableEntry.depthTest == JsonDepthTest::EQUAL)
|
||||
structured.depthTest = GFXS_DEPTHTEST_EQUAL;
|
||||
else if (jStateBitsTableEntry.depthTest == JsonDepthTest::LESS_EQUAL)
|
||||
structured.depthTest = GFXS_DEPTHTEST_LESSEQUAL;
|
||||
else
|
||||
{
|
||||
PrintError(material, "Invalid value for depth test");
|
||||
return false;
|
||||
}
|
||||
|
||||
structured.polygonOffset = jStateBitsTableEntry.polygonOffset;
|
||||
|
||||
if (jStateBitsTableEntry.stencilFront)
|
||||
{
|
||||
structured.stencilFrontEnabled = 1;
|
||||
structured.stencilFrontPass = jStateBitsTableEntry.stencilFront->pass;
|
||||
structured.stencilFrontFail = jStateBitsTableEntry.stencilFront->fail;
|
||||
structured.stencilFrontZFail = jStateBitsTableEntry.stencilFront->zfail;
|
||||
structured.stencilFrontFunc = jStateBitsTableEntry.stencilFront->func;
|
||||
}
|
||||
|
||||
if (jStateBitsTableEntry.stencilBack)
|
||||
{
|
||||
structured.stencilBackEnabled = 1;
|
||||
structured.stencilBackPass = jStateBitsTableEntry.stencilBack->pass;
|
||||
structured.stencilBackFail = jStateBitsTableEntry.stencilBack->fail;
|
||||
structured.stencilBackZFail = jStateBitsTableEntry.stencilBack->zfail;
|
||||
structured.stencilBackFunc = jStateBitsTableEntry.stencilBack->func;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateMaterialFromJson(const JsonMaterial& jMaterial, Material& material) const
|
||||
{
|
||||
if (!CreateGameFlagsFromJson(jMaterial, material.info.gameFlags))
|
||||
return false;
|
||||
|
||||
material.info.sortKey = static_cast<unsigned char>(jMaterial.sortKey);
|
||||
|
||||
if (jMaterial.textureAtlas)
|
||||
{
|
||||
material.info.textureAtlasRowCount = jMaterial.textureAtlas->rows;
|
||||
material.info.textureAtlasColumnCount = jMaterial.textureAtlas->columns;
|
||||
}
|
||||
else
|
||||
{
|
||||
material.info.textureAtlasRowCount = 0;
|
||||
material.info.textureAtlasColumnCount = 0;
|
||||
}
|
||||
|
||||
material.info.surfaceTypeBits = jMaterial.surfaceTypeBits;
|
||||
material.info.layeredSurfaceTypes = jMaterial.layeredSurfaceTypes;
|
||||
material.info.hashIndex = static_cast<uint16_t>(jMaterial.hashIndex);
|
||||
material.info.surfaceFlags = jMaterial.surfaceFlags;
|
||||
material.info.contents = jMaterial.contents;
|
||||
|
||||
if (jMaterial.stateBitsEntry.size() != std::extent_v<decltype(Material::stateBitsEntry)>)
|
||||
{
|
||||
PrintError(material, std::format("StateBitsEntry size is not {}", jMaterial.stateBitsEntry.size()));
|
||||
return false;
|
||||
}
|
||||
for (auto i = 0u; i < std::extent_v<decltype(Material::stateBitsEntry)>; i++)
|
||||
material.stateBitsEntry[i] = jMaterial.stateBitsEntry[i];
|
||||
|
||||
material.stateFlags = static_cast<unsigned char>(jMaterial.stateFlags);
|
||||
material.cameraRegion = jMaterial.cameraRegion;
|
||||
material.probeMipBits = jMaterial.probeMipBits;
|
||||
|
||||
auto* techniqueSet = m_context.LoadDependency<AssetTechniqueSet>(jMaterial.techniqueSet);
|
||||
if (!techniqueSet)
|
||||
{
|
||||
PrintError(material, "Could not find technique set");
|
||||
return false;
|
||||
}
|
||||
m_registration.AddDependency(techniqueSet);
|
||||
material.techniqueSet = techniqueSet->Asset();
|
||||
|
||||
if (!jMaterial.textures.empty())
|
||||
{
|
||||
material.textureCount = static_cast<unsigned char>(jMaterial.textures.size());
|
||||
material.textureTable = m_memory.Alloc<MaterialTextureDef>(material.textureCount);
|
||||
|
||||
for (auto i = 0u; i < material.textureCount; i++)
|
||||
{
|
||||
if (!CreateTextureDefFromJson(jMaterial.textures[i], material.textureTable[i], material))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
material.textureCount = 0;
|
||||
material.textureTable = nullptr;
|
||||
}
|
||||
|
||||
if (!jMaterial.constants.empty())
|
||||
{
|
||||
material.constantCount = static_cast<unsigned char>(jMaterial.constants.size());
|
||||
material.constantTable = m_memory.Alloc<MaterialConstantDef>(material.constantCount);
|
||||
|
||||
for (auto i = 0u; i < material.constantCount; i++)
|
||||
{
|
||||
if (!CreateConstantDefFromJson(jMaterial.constants[i], material.constantTable[i], material))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
material.constantCount = 0;
|
||||
material.constantTable = nullptr;
|
||||
}
|
||||
|
||||
if (!jMaterial.stateBits.empty())
|
||||
{
|
||||
material.stateBitsCount = static_cast<unsigned char>(jMaterial.stateBits.size());
|
||||
material.stateBitsTable = m_memory.Alloc<GfxStateBitsTable>(material.stateBitsCount);
|
||||
|
||||
for (auto i = 0u; i < material.stateBitsCount; i++)
|
||||
{
|
||||
if (!CreateStateBitsTableEntryFromJson(jMaterial.stateBits[i], material.stateBitsTable[i], material))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
material.stateBitsCount = 0;
|
||||
material.stateBitsTable = nullptr;
|
||||
}
|
||||
|
||||
if (jMaterial.thermalMaterial)
|
||||
{
|
||||
auto* thermalMaterial = m_context.LoadDependency<AssetMaterial>(jMaterial.thermalMaterial.value());
|
||||
if (!thermalMaterial)
|
||||
{
|
||||
PrintError(material, "Could not find thermal material");
|
||||
return false;
|
||||
}
|
||||
m_registration.AddDependency(thermalMaterial);
|
||||
material.thermalMaterial = thermalMaterial->Asset();
|
||||
}
|
||||
else
|
||||
{
|
||||
material.thermalMaterial = nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::istream& m_stream;
|
||||
MemoryManager& m_memory;
|
||||
AssetCreationContext& m_context;
|
||||
AssetRegistration<AssetMaterial>& m_registration;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace T6
|
||||
{
|
||||
bool LoadMaterialAsJson(
|
||||
std::istream& stream, Material& material, MemoryManager& memory, AssetCreationContext& context, AssetRegistration<AssetMaterial>& registration)
|
||||
{
|
||||
const JsonLoader loader(stream, memory, context, registration);
|
||||
|
||||
return loader.Load(material);
|
||||
}
|
||||
} // namespace T6
|
@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Asset/AssetCreationContext.h"
|
||||
#include "Asset/AssetRegistration.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <istream>
|
||||
|
||||
namespace T6
|
||||
{
|
||||
bool LoadMaterialAsJson(
|
||||
std::istream& stream, Material& material, MemoryManager& memory, AssetCreationContext& context, AssetRegistration<AssetMaterial>& registration);
|
||||
} // namespace T6
|
@ -1,10 +1,9 @@
|
||||
#include "LoaderMaterialT6.h"
|
||||
|
||||
#include "Game/T6/Material/JsonMaterialLoader.h"
|
||||
#include "Game/T6/Material/JsonMaterialLoaderT6.h"
|
||||
#include "Game/T6/T6.h"
|
||||
#include "Material/MaterialCommon.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
|
||||
@ -23,7 +22,7 @@ namespace
|
||||
|
||||
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
|
||||
{
|
||||
const auto file = m_search_path.Open(GetFileNameForAsset(assetName));
|
||||
const auto file = m_search_path.Open(material::GetFileNameForAssetName(assetName));
|
||||
if (!file.IsOpen())
|
||||
return AssetCreationResult::NoAction();
|
||||
|
||||
@ -41,21 +40,6 @@ namespace
|
||||
}
|
||||
|
||||
private:
|
||||
static std::string GetFileNameForAsset(const std::string& assetName)
|
||||
{
|
||||
std::string sanitizedFileName(assetName);
|
||||
if (sanitizedFileName[0] == '*')
|
||||
{
|
||||
std::ranges::replace(sanitizedFileName, '*', '_');
|
||||
const auto parenthesisPos = sanitizedFileName.find('(');
|
||||
if (parenthesisPos != std::string::npos)
|
||||
sanitizedFileName.erase(parenthesisPos);
|
||||
sanitizedFileName = "generated/" + sanitizedFileName;
|
||||
}
|
||||
|
||||
return std::format("materials/{}.json", sanitizedFileName);
|
||||
}
|
||||
|
||||
MemoryManager& m_memory;
|
||||
ISearchPath& m_search_path;
|
||||
};
|
||||
|
@ -1,15 +1,41 @@
|
||||
#include "JsonMaterialLoader.h"
|
||||
#options GAME (IW4, IW5, T6)
|
||||
|
||||
#filename "Game/" + GAME + "/Material/JsonMaterialLoader" + GAME + ".cpp"
|
||||
|
||||
#if GAME == "IW4"
|
||||
#define FEATURE_IW4
|
||||
#define HAS_WATER
|
||||
#define GAME_LOWER "iw4"
|
||||
#elif GAME == "IW5"
|
||||
#define FEATURE_IW5
|
||||
#define HAS_WATER
|
||||
#define GAME_LOWER "iw5"
|
||||
#elif GAME == "T6"
|
||||
#define FEATURE_T6
|
||||
#define GAME_LOWER "t6"
|
||||
#endif
|
||||
|
||||
// This file was templated.
|
||||
// See JsonMaterialLoader.cpp.template.
|
||||
// Do not modify, changes will be lost.
|
||||
|
||||
#set LOADER_HEADER "\"JsonMaterialLoader" + GAME + ".h\""
|
||||
#include LOADER_HEADER
|
||||
|
||||
#ifdef HAS_WATER
|
||||
#include "Base64.h"
|
||||
#include "Game/IW5/CommonIW5.h"
|
||||
#include "Game/IW5/Material/JsonMaterial.h"
|
||||
#endif
|
||||
#set COMMON_HEADER "\"Game/" + GAME + "/Common" + GAME + ".h\""
|
||||
#include COMMON_HEADER
|
||||
#set JSON_HEADER "\"Game/" + GAME + "/Material/JsonMaterial" + GAME + ".h\""
|
||||
#include JSON_HEADER
|
||||
|
||||
#include <format>
|
||||
#include <iostream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using namespace nlohmann;
|
||||
using namespace IW5;
|
||||
using namespace GAME;
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -27,19 +53,27 @@ namespace
|
||||
bool Load(Material& material) const
|
||||
{
|
||||
const auto jRoot = json::parse(m_stream);
|
||||
std::string game;
|
||||
std::string type;
|
||||
unsigned version;
|
||||
|
||||
jRoot.at("_type").get_to(type);
|
||||
jRoot.at("_game").get_to(game);
|
||||
jRoot.at("_version").get_to(version);
|
||||
|
||||
if (type != "material" || version != 1u || game != "iw5")
|
||||
if (type != "material" || version != 1u)
|
||||
{
|
||||
std::cerr << std::format("Tried to load material \"{}\" but did not find expected type material of version 1\n", material.info.name);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef FEATURE_T6 // T6 did not have this check in version 1, so to stay backwards compatible, let it stay that way
|
||||
std::string game;
|
||||
jRoot.at("_game").get_to(game);
|
||||
if (game != GAME_LOWER)
|
||||
{
|
||||
std::cerr << std::format("Tried to load material \"{}\" but \"_game\" did not find expected type value {}\n", material.info.name, GAME_LOWER);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
@ -60,7 +94,11 @@ namespace
|
||||
std::cerr << std::format("Cannot load material \"{}\": {}\n", material.info.name, message);
|
||||
}
|
||||
|
||||
#if defined(FEATURE_IW4) || defined(FEATURE_IW5)
|
||||
static bool CreateGameFlagsFromJson(const JsonMaterial& jMaterial, unsigned char& gameFlags)
|
||||
#elif defined(FEATURE_T6)
|
||||
static bool CreateGameFlagsFromJson(const JsonMaterial& jMaterial, unsigned& gameFlags)
|
||||
#endif
|
||||
{
|
||||
for (const auto gameFlag : jMaterial.gameFlags)
|
||||
gameFlags |= gameFlag;
|
||||
@ -77,6 +115,7 @@ namespace
|
||||
samplerState.clampW = jSamplerState.clampW;
|
||||
}
|
||||
|
||||
#ifdef HAS_WATER
|
||||
bool CreateWaterFromJson(const JsonWater& jWater, water_t& water, const Material& material) const
|
||||
{
|
||||
water.writable.floatTime = jWater.floatTime;
|
||||
@ -120,6 +159,7 @@ namespace
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool CreateTextureDefFromJson(const JsonTexture& jTexture, MaterialTextureDef& textureDef, const Material& material) const
|
||||
{
|
||||
@ -157,6 +197,9 @@ namespace
|
||||
CreateSamplerStateFromJson(jTexture.samplerState, textureDef.samplerState);
|
||||
|
||||
textureDef.semantic = jTexture.semantic;
|
||||
#ifdef FEATURE_T6
|
||||
textureDef.isMatureContent = jTexture.isMatureContent;
|
||||
#endif
|
||||
|
||||
auto* imageAsset = m_context.LoadDependency<AssetImage>(jTexture.image);
|
||||
if (!imageAsset)
|
||||
@ -166,6 +209,7 @@ namespace
|
||||
}
|
||||
m_registration.AddDependency(imageAsset);
|
||||
|
||||
#ifdef HAS_WATER
|
||||
if (jTexture.water)
|
||||
{
|
||||
if (jTexture.semantic != TS_WATER_MAP)
|
||||
@ -195,6 +239,9 @@ namespace
|
||||
}
|
||||
else
|
||||
textureDef.u.image = imageAsset->Asset();
|
||||
#else
|
||||
textureDef.image = imageAsset->Asset();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -257,11 +304,13 @@ namespace
|
||||
structured.alphaTestDisabled = 0;
|
||||
structured.alphaTest = GFXS_ALPHA_TEST_GT_0;
|
||||
}
|
||||
#if defined(FEATURE_IW4) || defined(FEATURE_IW5)
|
||||
else if (jStateBitsTableEntry.alphaTest == JsonAlphaTest::LT128)
|
||||
{
|
||||
structured.alphaTestDisabled = 0;
|
||||
structured.alphaTest = GFXS_ALPHA_TEST_LT_128;
|
||||
}
|
||||
#endif
|
||||
else if (jStateBitsTableEntry.alphaTest == JsonAlphaTest::GE128)
|
||||
{
|
||||
structured.alphaTestDisabled = 0;
|
||||
@ -290,7 +339,9 @@ namespace
|
||||
structured.blendOpAlpha = jStateBitsTableEntry.blendOpAlpha;
|
||||
structured.colorWriteRgb = jStateBitsTableEntry.colorWriteRgb;
|
||||
structured.colorWriteAlpha = jStateBitsTableEntry.colorWriteAlpha;
|
||||
#if defined(FEATURE_IW4) || defined(FEATURE_IW5)
|
||||
structured.gammaWrite = jStateBitsTableEntry.gammaWrite;
|
||||
#endif
|
||||
structured.polymodeLine = jStateBitsTableEntry.polymodeLine;
|
||||
structured.depthWrite = jStateBitsTableEntry.depthWrite;
|
||||
|
||||
@ -352,6 +403,12 @@ namespace
|
||||
}
|
||||
|
||||
material.info.surfaceTypeBits = jMaterial.surfaceTypeBits;
|
||||
#ifdef FEATURE_T6
|
||||
material.info.layeredSurfaceTypes = jMaterial.layeredSurfaceTypes;
|
||||
material.info.hashIndex = static_cast<uint16_t>(jMaterial.hashIndex);
|
||||
material.info.surfaceFlags = jMaterial.surfaceFlags;
|
||||
material.info.contents = jMaterial.contents;
|
||||
#endif
|
||||
|
||||
if (jMaterial.stateBitsEntry.size() != std::extent_v<decltype(Material::stateBitsEntry)>)
|
||||
{
|
||||
@ -363,6 +420,9 @@ namespace
|
||||
|
||||
material.stateFlags = static_cast<unsigned char>(jMaterial.stateFlags);
|
||||
material.cameraRegion = jMaterial.cameraRegion;
|
||||
#ifdef FEATURE_T6
|
||||
material.probeMipBits = jMaterial.probeMipBits;
|
||||
#endif
|
||||
|
||||
auto* techniqueSet = m_context.LoadDependency<AssetTechniqueSet>(jMaterial.techniqueSet);
|
||||
if (!techniqueSet)
|
||||
@ -424,6 +484,24 @@ namespace
|
||||
material.stateBitsTable = nullptr;
|
||||
}
|
||||
|
||||
#ifdef FEATURE_T6
|
||||
if (jMaterial.thermalMaterial)
|
||||
{
|
||||
auto* thermalMaterial = m_context.LoadDependency<AssetMaterial>(jMaterial.thermalMaterial.value());
|
||||
if (!thermalMaterial)
|
||||
{
|
||||
PrintError(material, "Could not find thermal material");
|
||||
return false;
|
||||
}
|
||||
m_registration.AddDependency(thermalMaterial);
|
||||
material.thermalMaterial = thermalMaterial->Asset();
|
||||
}
|
||||
else
|
||||
{
|
||||
material.thermalMaterial = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -434,7 +512,7 @@ namespace
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace IW5
|
||||
namespace GAME
|
||||
{
|
||||
bool LoadMaterialAsJson(
|
||||
std::istream& stream, Material& material, MemoryManager& memory, AssetCreationContext& context, AssetRegistration<AssetMaterial>& registration)
|
||||
@ -443,4 +521,4 @@ namespace IW5
|
||||
|
||||
return loader.Load(material);
|
||||
}
|
||||
} // namespace IW5
|
||||
} // namespace GAME
|
@ -1,14 +1,23 @@
|
||||
#options GAME (IW4, IW5, T6)
|
||||
|
||||
#filename "Game/" + GAME + "/Material/JsonMaterialLoader" + GAME + ".h"
|
||||
|
||||
// This file was templated.
|
||||
// See JsonMaterialLoader.h.template.
|
||||
// Do not modify, changes will be lost.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Asset/AssetCreationContext.h"
|
||||
#include "Asset/AssetRegistration.h"
|
||||
#include "Game/IW5/IW5.h"
|
||||
#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\""
|
||||
#include GAME_HEADER
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <istream>
|
||||
|
||||
namespace IW5
|
||||
namespace GAME
|
||||
{
|
||||
bool LoadMaterialAsJson(
|
||||
std::istream& stream, Material& material, MemoryManager& memory, AssetCreationContext& context, AssetRegistration<AssetMaterial>& registration);
|
||||
} // namespace IW5
|
||||
} // namespace GAME
|
@ -28,7 +28,7 @@ namespace tangent_space
|
||||
|
||||
void SetVec3(void* dest, const size_t index, const size_t stride, const tvec3& data)
|
||||
{
|
||||
auto* out = reinterpret_cast<float(*)[3]>(static_cast<char*>(dest) + stride * index);
|
||||
auto* out = reinterpret_cast<float (*)[3]>(static_cast<char*>(dest) + stride * index);
|
||||
(*out)[0] = data[0];
|
||||
(*out)[1] = data[1];
|
||||
(*out)[2] = data[2];
|
||||
|
@ -53,6 +53,7 @@ function ObjWriting:project()
|
||||
}
|
||||
}
|
||||
|
||||
ObjCommon:use()
|
||||
useSourceTemplating("ObjWriting")
|
||||
|
||||
self:include(includes)
|
||||
|
@ -28,6 +28,7 @@ namespace
|
||||
|
||||
jRoot["_type"] = "leaderboard";
|
||||
jRoot["_version"] = 1;
|
||||
jRoot["_game"] = "iw4";
|
||||
|
||||
m_stream << std::setw(4) << jRoot << "\n";
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "Dumping/AssetDumpingContext.h"
|
||||
#include "Game/IW4/IW4.h"
|
||||
#include "Obj/Gdt/GdtStream.h"
|
||||
|
||||
namespace IW4
|
||||
{
|
||||
void DecompileMaterialToGdt(GdtOutputStream& out, const Material& material, AssetDumpingContext& context);
|
||||
} // namespace IW4
|
38
src/ObjWriting/Game/IW4/Material/DumperMaterialIW4.cpp
Normal file
38
src/ObjWriting/Game/IW4/Material/DumperMaterialIW4.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include "DumperMaterialIW4.h"
|
||||
|
||||
#include "DecompilingMaterialDumperIW4.h"
|
||||
#include "Game/IW4/Material/JsonMaterialWriterIW4.h"
|
||||
#include "Game/IW4/Material/MaterialConstantZoneStateIW4.h"
|
||||
#include "Material/MaterialCommon.h"
|
||||
|
||||
using namespace IW4;
|
||||
|
||||
void AssetDumperMaterial::DumpPool(AssetDumpingContext& context, AssetPool<Material>* pool)
|
||||
{
|
||||
auto* materialConstantState = context.GetZoneAssetDumperState<MaterialConstantZoneState>();
|
||||
materialConstantState->ExtractNamesFromZone();
|
||||
|
||||
AbstractAssetDumper::DumpPool(context, pool);
|
||||
}
|
||||
|
||||
bool AssetDumperMaterial::ShouldDump(XAssetInfo<Material>* asset)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssetDumperMaterial::DumpAsset(AssetDumpingContext& context, XAssetInfo<Material>* asset)
|
||||
{
|
||||
#ifdef EXPERIMENTAL_MATERIAL_COMPILATION
|
||||
if (context.m_gdt)
|
||||
{
|
||||
DecompileMaterialToGdt(*context.m_gdt, *asset->Asset(), context);
|
||||
}
|
||||
#else
|
||||
const auto assetFile = context.OpenAssetFile(material::GetFileNameForAssetName(asset->m_name));
|
||||
|
||||
if (!assetFile)
|
||||
return;
|
||||
|
||||
DumpMaterialAsJson(*assetFile, *asset->Asset(), context);
|
||||
#endif
|
||||
}
|
@ -7,6 +7,9 @@ namespace IW4
|
||||
{
|
||||
class AssetDumperMaterial final : public AbstractAssetDumper<Material>
|
||||
{
|
||||
public:
|
||||
void DumpPool(AssetDumpingContext& context, AssetPool<Material>* pool) override;
|
||||
|
||||
protected:
|
||||
bool ShouldDump(XAssetInfo<Material>* asset) override;
|
||||
void DumpAsset(AssetDumpingContext& context, XAssetInfo<Material>* asset) override;
|
@ -0,0 +1,236 @@
|
||||
#include "MaterialConstantZoneStateIW4.h"
|
||||
|
||||
#include "Game/IW4/CommonIW4.h"
|
||||
#include "Game/IW4/GameAssetPoolIW4.h"
|
||||
#include "Game/IW4/GameIW4.h"
|
||||
#include "ObjWriting.h"
|
||||
|
||||
namespace IW4
|
||||
{
|
||||
const char* KNOWN_CONSTANT_NAMES[]{
|
||||
"worldViewProjectionMatrix",
|
||||
"worldViewMatrix2",
|
||||
"worldViewMatrix1",
|
||||
"worldViewMatrix",
|
||||
"worldOutdoorLookupMatrix",
|
||||
"worldMatrix",
|
||||
"waterColor",
|
||||
"viewportDimensions",
|
||||
"viewProjectionMatrix",
|
||||
"uvScale",
|
||||
"uvAnimParms",
|
||||
"thermalColorOffset",
|
||||
"sunShadowmapPixelAdjust",
|
||||
"ssaoParms",
|
||||
"spotShadowmapPixelAdjust",
|
||||
"shadowmapSwitchPartition",
|
||||
"shadowmapScale",
|
||||
"shadowmapPolygonOffset",
|
||||
"shadowLookupMatrix",
|
||||
"renderTargetSize",
|
||||
"renderSourceSize",
|
||||
"projectionMatrix",
|
||||
"playlistPopulationParams",
|
||||
"pixelCostFracs",
|
||||
"pixelCostDecode",
|
||||
"particleCloudSparkColor2",
|
||||
"particleCloudSparkColor1",
|
||||
"particleCloudSparkColor0",
|
||||
"particleCloudMatrix2",
|
||||
"particleCloudMatrix1",
|
||||
"particleCloudMatrix",
|
||||
"particleCloudColor",
|
||||
"outdoorFeatherParms",
|
||||
"oceanUVAnimParmPaintedFoam",
|
||||
"oceanUVAnimParmOctave2",
|
||||
"oceanUVAnimParmOctave1",
|
||||
"oceanUVAnimParmOctave0",
|
||||
"oceanUVAnimParmFoam",
|
||||
"oceanUVAnimParmDetail1",
|
||||
"oceanUVAnimParmDetail0",
|
||||
"oceanScrollParms",
|
||||
"oceanMiscParms",
|
||||
"oceanFoamParms",
|
||||
"oceanAmplitude",
|
||||
"materialColor",
|
||||
"lightprobeAmbient",
|
||||
"lightingLookupScale",
|
||||
"lightSpotFactors",
|
||||
"lightSpotDir",
|
||||
"lightSpecular",
|
||||
"lightPosition",
|
||||
"lightFalloffPlacement",
|
||||
"lightDiffuse",
|
||||
"inverseWorldViewMatrix",
|
||||
"inverseViewProjectionMatrix",
|
||||
"inverseTransposeWorldViewMatrix",
|
||||
"heatMapDetail",
|
||||
"glowSetup",
|
||||
"glowApply",
|
||||
"gameTime",
|
||||
"fullscreenDistortion",
|
||||
"fogSunDir",
|
||||
"fogSunConsts",
|
||||
"fogSunColorLinear",
|
||||
"fogSunColorGamma",
|
||||
"fogConsts",
|
||||
"fogColorLinear",
|
||||
"fogColorGamma",
|
||||
"flagParms",
|
||||
"filterTap",
|
||||
"featherParms",
|
||||
"falloffParms",
|
||||
"falloffEndColor",
|
||||
"falloffBeginColor",
|
||||
"fadeEffect",
|
||||
"eyeOffsetParms",
|
||||
"eyeOffset",
|
||||
"envMapParms",
|
||||
"dustTint",
|
||||
"dustParms",
|
||||
"dustEyeParms",
|
||||
"dofRowDelta",
|
||||
"dofLerpScale",
|
||||
"dofLerpBias",
|
||||
"dofEquationViewModelAndFarBlur",
|
||||
"dofEquationScene",
|
||||
"distortionScale",
|
||||
"detailScale",
|
||||
"depthFromClip",
|
||||
"debugBumpmap",
|
||||
"colorTintQuadraticDelta",
|
||||
"colorTintDelta",
|
||||
"colorTintBase",
|
||||
"colorSaturationR",
|
||||
"colorSaturationG",
|
||||
"colorSaturationB",
|
||||
"colorObjMin",
|
||||
"colorObjMax",
|
||||
"colorMatrixR",
|
||||
"colorMatrixG",
|
||||
"colorMatrixB",
|
||||
"colorBias",
|
||||
"codeMeshArg",
|
||||
"clipSpaceLookupScale",
|
||||
"clipSpaceLookupOffset",
|
||||
"baseLightingCoords",
|
||||
};
|
||||
|
||||
const char* KNOWN_TEXTURE_DEF_NAMES[]{
|
||||
"attenuation",
|
||||
"attenuationSampler",
|
||||
"cinematicA",
|
||||
"cinematicASampler",
|
||||
"cinematicCb",
|
||||
"cinematicCbSampler",
|
||||
"cinematicCr",
|
||||
"cinematicCrSampler",
|
||||
"cinematicY",
|
||||
"cinematicYSampler",
|
||||
"colorMap",
|
||||
"colorMap1",
|
||||
"colorMap2",
|
||||
"colorMapPostSun",
|
||||
"colorMapPostSunSampler",
|
||||
"colorMapSampler",
|
||||
"colorMapSampler1",
|
||||
"colorMapSampler2",
|
||||
"cucoloris",
|
||||
"cucolorisSampler",
|
||||
"detailMap",
|
||||
"detailMapSampler",
|
||||
"dust",
|
||||
"dustSampler",
|
||||
"fadeMap",
|
||||
"fadeMapSampler",
|
||||
"floatZ",
|
||||
"floatZSampler",
|
||||
"grainMap",
|
||||
"grainMapSampler",
|
||||
"halfParticleColor",
|
||||
"halfParticleColorSampler",
|
||||
"halfParticleDepth",
|
||||
"halfParticleDepthSampler",
|
||||
"heatmap",
|
||||
"heatmapSampler",
|
||||
"lightmapPrimary",
|
||||
"lightmapSamplerPrimary",
|
||||
"lightmapSamplerSecondary",
|
||||
"lightmapSecondary",
|
||||
"lookupMap",
|
||||
"lookupMapSampler",
|
||||
"modelLighting",
|
||||
"modelLightingSampler",
|
||||
"normalMap",
|
||||
"normalMapSampler",
|
||||
"oceanColorRamp",
|
||||
"oceanColorRampSampler",
|
||||
"oceanDetailNormal",
|
||||
"oceanDetailNormalSampler",
|
||||
"oceanDisplacement",
|
||||
"oceanDisplacementSampler",
|
||||
"oceanEnv",
|
||||
"oceanEnvSampler",
|
||||
"oceanFoam",
|
||||
"oceanFoamSampler",
|
||||
"oceanHeightNormal",
|
||||
"oceanHeightNormalSampler",
|
||||
"oceanPaintedFoam",
|
||||
"oceanPaintedFoamSampler",
|
||||
"outdoorMap",
|
||||
"outdoorMapSampler",
|
||||
"population",
|
||||
"populationSampler",
|
||||
"reflectionProbe",
|
||||
"reflectionProbeSampler",
|
||||
"shadowmapSamplerSpot",
|
||||
"shadowmapSamplerSun",
|
||||
"shadowmapSpot",
|
||||
"shadowmapSun",
|
||||
"skyMap",
|
||||
"skyMapSampler",
|
||||
"specularMap",
|
||||
"specularMapSampler",
|
||||
"ssao",
|
||||
"ssaoSampler",
|
||||
"worldMap",
|
||||
"worldMapSampler",
|
||||
};
|
||||
|
||||
void MaterialConstantZoneState::ExtractNamesFromZoneInternal()
|
||||
{
|
||||
for (const auto* zone : IGame::GetGameById(GameId::IW5)->GetZones())
|
||||
{
|
||||
const auto* iw5AssetPools = dynamic_cast<const GameAssetPoolIW4*>(zone->m_pools.get());
|
||||
if (!iw5AssetPools)
|
||||
return;
|
||||
|
||||
for (const auto* vertexShaderAsset : *iw5AssetPools->m_material_vertex_shader)
|
||||
{
|
||||
const auto* vertexShader = vertexShaderAsset->Asset();
|
||||
if (ShouldDumpFromStruct(vertexShader))
|
||||
ExtractNamesFromShader(vertexShader->prog.loadDef.program, static_cast<size_t>(vertexShader->prog.loadDef.programSize) * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
for (const auto* pixelShaderAsset : *iw5AssetPools->m_material_pixel_shader)
|
||||
{
|
||||
const auto* pixelShader = pixelShaderAsset->Asset();
|
||||
if (ShouldDumpFromStruct(pixelShader))
|
||||
ExtractNamesFromShader(pixelShader->prog.loadDef.program, static_cast<size_t>(pixelShader->prog.loadDef.programSize) * sizeof(uint32_t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MaterialConstantZoneState::AddStaticKnownNames()
|
||||
{
|
||||
for (const auto* knownConstantName : KNOWN_CONSTANT_NAMES)
|
||||
AddConstantName(knownConstantName);
|
||||
for (const auto* knownTextureDefName : KNOWN_TEXTURE_DEF_NAMES)
|
||||
AddTextureDefName(knownTextureDefName);
|
||||
}
|
||||
|
||||
unsigned MaterialConstantZoneState::HashString(const std::string& str)
|
||||
{
|
||||
return Common::R_HashString(str.c_str());
|
||||
}
|
||||
} // namespace IW4
|
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "Material/AbstractMaterialConstantZoneState.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace IW4
|
||||
{
|
||||
class MaterialConstantZoneState final : public AbstractMaterialConstantZoneStateDx9
|
||||
{
|
||||
protected:
|
||||
void ExtractNamesFromZoneInternal() override;
|
||||
void AddStaticKnownNames() override;
|
||||
unsigned HashString(const std::string& str) override;
|
||||
};
|
||||
} // namespace IW4
|
@ -6,7 +6,6 @@
|
||||
#include "AssetDumpers/AssetDumperLeaderboardDef.h"
|
||||
#include "AssetDumpers/AssetDumperLoadedSound.h"
|
||||
#include "AssetDumpers/AssetDumperLocalizeEntry.h"
|
||||
#include "AssetDumpers/AssetDumperMaterial.h"
|
||||
#include "AssetDumpers/AssetDumperMenuDef.h"
|
||||
#include "AssetDumpers/AssetDumperMenuList.h"
|
||||
#include "AssetDumpers/AssetDumperPhysCollmap.h"
|
||||
@ -23,6 +22,7 @@
|
||||
#include "AssetDumpers/AssetDumperWeapon.h"
|
||||
#include "AssetDumpers/AssetDumperXModel.h"
|
||||
#include "Game/IW4/GameAssetPoolIW4.h"
|
||||
#include "Material/DumperMaterialIW4.h"
|
||||
#include "ObjWriting.h"
|
||||
|
||||
using namespace IW4;
|
||||
|
@ -1,48 +0,0 @@
|
||||
#include "AssetDumperMaterial.h"
|
||||
|
||||
#include "Game/IW5/Material/JsonMaterialWriter.h"
|
||||
#include "Game/IW5/Material/MaterialConstantZoneState.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <format>
|
||||
#include <ranges>
|
||||
|
||||
using namespace IW5;
|
||||
|
||||
std::string AssetDumperMaterial::GetFileNameForAsset(const std::string& assetName)
|
||||
{
|
||||
std::string sanitizedFileName(assetName);
|
||||
if (sanitizedFileName[0] == '*')
|
||||
{
|
||||
std::ranges::replace(sanitizedFileName, '*', '_');
|
||||
const auto parenthesisPos = sanitizedFileName.find('(');
|
||||
if (parenthesisPos != std::string::npos)
|
||||
sanitizedFileName.erase(parenthesisPos);
|
||||
sanitizedFileName = "generated/" + sanitizedFileName;
|
||||
}
|
||||
|
||||
return std::format("materials/{}.json", sanitizedFileName);
|
||||
}
|
||||
|
||||
bool AssetDumperMaterial::ShouldDump(XAssetInfo<Material>* asset)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssetDumperMaterial::DumpAsset(AssetDumpingContext& context, XAssetInfo<Material>* asset)
|
||||
{
|
||||
const auto assetFile = context.OpenAssetFile(GetFileNameForAsset(asset->m_name));
|
||||
|
||||
if (!assetFile)
|
||||
return;
|
||||
|
||||
DumpMaterialAsJson(*assetFile, asset->Asset(), context);
|
||||
}
|
||||
|
||||
void AssetDumperMaterial::DumpPool(AssetDumpingContext& context, AssetPool<Material>* pool)
|
||||
{
|
||||
auto* materialConstantState = context.GetZoneAssetDumperState<MaterialConstantZoneState>();
|
||||
materialConstantState->ExtractNamesFromZone();
|
||||
|
||||
AbstractAssetDumper::DumpPool(context, pool);
|
||||
}
|
@ -28,6 +28,7 @@ namespace
|
||||
|
||||
jRoot["_type"] = "leaderboard";
|
||||
jRoot["_version"] = 1;
|
||||
jRoot["_game"] = "iw5";
|
||||
|
||||
m_stream << std::setw(4) << jRoot << "\n";
|
||||
}
|
||||
|
30
src/ObjWriting/Game/IW5/Material/DumperMaterialIW5.cpp
Normal file
30
src/ObjWriting/Game/IW5/Material/DumperMaterialIW5.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#include "DumperMaterialIW5.h"
|
||||
|
||||
#include "Game/IW5/Material/JsonMaterialWriterIW5.h"
|
||||
#include "Game/IW5/Material/MaterialConstantZoneStateIW5.h"
|
||||
#include "Material/MaterialCommon.h"
|
||||
|
||||
using namespace IW5;
|
||||
|
||||
void AssetDumperMaterial::DumpPool(AssetDumpingContext& context, AssetPool<Material>* pool)
|
||||
{
|
||||
auto* materialConstantState = context.GetZoneAssetDumperState<MaterialConstantZoneState>();
|
||||
materialConstantState->ExtractNamesFromZone();
|
||||
|
||||
AbstractAssetDumper::DumpPool(context, pool);
|
||||
}
|
||||
|
||||
bool AssetDumperMaterial::ShouldDump(XAssetInfo<Material>* asset)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssetDumperMaterial::DumpAsset(AssetDumpingContext& context, XAssetInfo<Material>* asset)
|
||||
{
|
||||
const auto assetFile = context.OpenAssetFile(material::GetFileNameForAssetName(asset->m_name));
|
||||
|
||||
if (!assetFile)
|
||||
return;
|
||||
|
||||
DumpMaterialAsJson(*assetFile, *asset->Asset(), context);
|
||||
}
|
@ -3,19 +3,15 @@
|
||||
#include "Dumping/AbstractAssetDumper.h"
|
||||
#include "Game/IW5/IW5.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace IW5
|
||||
{
|
||||
class AssetDumperMaterial final : public AbstractAssetDumper<Material>
|
||||
{
|
||||
static std::string GetFileNameForAsset(const std::string& assetName);
|
||||
public:
|
||||
void DumpPool(AssetDumpingContext& context, AssetPool<Material>* pool) override;
|
||||
|
||||
protected:
|
||||
bool ShouldDump(XAssetInfo<Material>* asset) override;
|
||||
void DumpAsset(AssetDumpingContext& context, XAssetInfo<Material>* asset) override;
|
||||
|
||||
public:
|
||||
void DumpPool(AssetDumpingContext& context, AssetPool<Material>* pool) override;
|
||||
};
|
||||
} // namespace IW5
|
@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Dumping/AssetDumpingContext.h"
|
||||
#include "Game/IW5/IW5.h"
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace IW5
|
||||
{
|
||||
void DumpMaterialAsJson(std::ostream& stream, const Material* material, AssetDumpingContext& context);
|
||||
} // namespace IW5
|
@ -1,4 +1,4 @@
|
||||
#include "MaterialConstantZoneState.h"
|
||||
#include "MaterialConstantZoneStateIW5.h"
|
||||
|
||||
#include "Game/IW5/CommonIW5.h"
|
||||
#include "Game/IW5/GameAssetPoolIW5.h"
|
@ -5,7 +5,6 @@
|
||||
#include "AssetDumpers/AssetDumperLeaderboardDef.h"
|
||||
#include "AssetDumpers/AssetDumperLoadedSound.h"
|
||||
#include "AssetDumpers/AssetDumperLocalizeEntry.h"
|
||||
#include "AssetDumpers/AssetDumperMaterial.h"
|
||||
#include "AssetDumpers/AssetDumperMenuDef.h"
|
||||
#include "AssetDumpers/AssetDumperMenuList.h"
|
||||
#include "AssetDumpers/AssetDumperRawFile.h"
|
||||
@ -15,6 +14,7 @@
|
||||
#include "AssetDumpers/AssetDumperWeaponAttachment.h"
|
||||
#include "AssetDumpers/AssetDumperXModel.h"
|
||||
#include "Game/IW5/GameAssetPoolIW5.h"
|
||||
#include "Material/DumperMaterialIW5.h"
|
||||
#include "ObjWriting.h"
|
||||
|
||||
using namespace IW5;
|
||||
|
@ -27,6 +27,7 @@ namespace
|
||||
|
||||
jRoot["_type"] = "attachment";
|
||||
jRoot["_version"] = 1;
|
||||
jRoot["_game"] = "iw5";
|
||||
|
||||
m_stream << std::setw(4) << jRoot << "\n";
|
||||
}
|
||||
|
@ -1,48 +0,0 @@
|
||||
#include "AssetDumperMaterial.h"
|
||||
|
||||
#include "Game/T6/Material/JsonMaterialWriter.h"
|
||||
#include "Game/T6/Material/MaterialConstantZoneState.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <format>
|
||||
#include <ranges>
|
||||
|
||||
using namespace T6;
|
||||
|
||||
std::string AssetDumperMaterial::GetFileNameForAsset(const std::string& assetName)
|
||||
{
|
||||
std::string sanitizedFileName(assetName);
|
||||
if (sanitizedFileName[0] == '*')
|
||||
{
|
||||
std::ranges::replace(sanitizedFileName, '*', '_');
|
||||
const auto parenthesisPos = sanitizedFileName.find('(');
|
||||
if (parenthesisPos != std::string::npos)
|
||||
sanitizedFileName.erase(parenthesisPos);
|
||||
sanitizedFileName = "generated/" + sanitizedFileName;
|
||||
}
|
||||
|
||||
return std::format("materials/{}.json", sanitizedFileName);
|
||||
}
|
||||
|
||||
bool AssetDumperMaterial::ShouldDump(XAssetInfo<Material>* asset)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssetDumperMaterial::DumpAsset(AssetDumpingContext& context, XAssetInfo<Material>* asset)
|
||||
{
|
||||
const auto assetFile = context.OpenAssetFile(GetFileNameForAsset(asset->m_name));
|
||||
|
||||
if (!assetFile)
|
||||
return;
|
||||
|
||||
DumpMaterialAsJson(*assetFile, asset->Asset(), context);
|
||||
}
|
||||
|
||||
void AssetDumperMaterial::DumpPool(AssetDumpingContext& context, AssetPool<Material>* pool)
|
||||
{
|
||||
auto* materialConstantState = context.GetZoneAssetDumperState<MaterialConstantZoneState>();
|
||||
materialConstantState->ExtractNamesFromZone();
|
||||
|
||||
AbstractAssetDumper::DumpPool(context, pool);
|
||||
}
|
@ -28,6 +28,7 @@ namespace
|
||||
|
||||
jRoot["_type"] = "leaderboard";
|
||||
jRoot["_version"] = 1;
|
||||
jRoot["_game"] = "t6";
|
||||
|
||||
m_stream << std::setw(4) << jRoot << "\n";
|
||||
}
|
||||
|
30
src/ObjWriting/Game/T6/Material/DumperMaterialT6.cpp
Normal file
30
src/ObjWriting/Game/T6/Material/DumperMaterialT6.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#include "DumperMaterialT6.h"
|
||||
|
||||
#include "Game/T6/Material/JsonMaterialWriterT6.h"
|
||||
#include "Game/T6/Material/MaterialConstantZoneStateT6.h"
|
||||
#include "Material/MaterialCommon.h"
|
||||
|
||||
using namespace T6;
|
||||
|
||||
void AssetDumperMaterial::DumpPool(AssetDumpingContext& context, AssetPool<Material>* pool)
|
||||
{
|
||||
auto* materialConstantState = context.GetZoneAssetDumperState<MaterialConstantZoneState>();
|
||||
materialConstantState->ExtractNamesFromZone();
|
||||
|
||||
AbstractAssetDumper::DumpPool(context, pool);
|
||||
}
|
||||
|
||||
bool AssetDumperMaterial::ShouldDump(XAssetInfo<Material>* asset)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void AssetDumperMaterial::DumpAsset(AssetDumpingContext& context, XAssetInfo<Material>* asset)
|
||||
{
|
||||
const auto assetFile = context.OpenAssetFile(material::GetFileNameForAssetName(asset->m_name));
|
||||
|
||||
if (!assetFile)
|
||||
return;
|
||||
|
||||
DumpMaterialAsJson(*assetFile, *asset->Asset(), context);
|
||||
}
|
@ -3,19 +3,15 @@
|
||||
#include "Dumping/AbstractAssetDumper.h"
|
||||
#include "Game/T6/T6.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace T6
|
||||
{
|
||||
class AssetDumperMaterial final : public AbstractAssetDumper<Material>
|
||||
{
|
||||
static std::string GetFileNameForAsset(const std::string& assetName);
|
||||
public:
|
||||
void DumpPool(AssetDumpingContext& context, AssetPool<Material>* pool) override;
|
||||
|
||||
protected:
|
||||
bool ShouldDump(XAssetInfo<Material>* asset) override;
|
||||
void DumpAsset(AssetDumpingContext& context, XAssetInfo<Material>* asset) override;
|
||||
|
||||
public:
|
||||
void DumpPool(AssetDumpingContext& context, AssetPool<Material>* pool) override;
|
||||
};
|
||||
} // namespace T6
|
@ -1,249 +0,0 @@
|
||||
#include "JsonMaterialWriter.h"
|
||||
|
||||
#include "Game/T6/CommonT6.h"
|
||||
#include "Game/T6/Json/JsonMaterial.h"
|
||||
#include "MaterialConstantZoneState.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using namespace nlohmann;
|
||||
using namespace T6;
|
||||
|
||||
namespace
|
||||
{
|
||||
class JsonDumper
|
||||
{
|
||||
public:
|
||||
JsonDumper(AssetDumpingContext& context, std::ostream& stream)
|
||||
: m_stream(stream),
|
||||
m_material_constants(*context.GetZoneAssetDumperState<MaterialConstantZoneState>())
|
||||
{
|
||||
}
|
||||
|
||||
void Dump(const Material* material) const
|
||||
{
|
||||
JsonMaterial jsonMaterial;
|
||||
CreateJsonMaterial(jsonMaterial, *material);
|
||||
json jRoot = jsonMaterial;
|
||||
|
||||
jRoot["_type"] = "material";
|
||||
jRoot["_version"] = 1;
|
||||
|
||||
m_stream << std::setw(4) << jRoot << "\n";
|
||||
}
|
||||
|
||||
private:
|
||||
static const char* AssetName(const char* input)
|
||||
{
|
||||
if (input && input[0] == ',')
|
||||
return &input[1];
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
static void CreateJsonGameFlags(JsonMaterial& jMaterial, const unsigned gameFlags)
|
||||
{
|
||||
jMaterial.gameFlags.clear();
|
||||
for (auto i = 0u; i < sizeof(gameFlags) * 8u; i++)
|
||||
{
|
||||
const auto flag = static_cast<MaterialGameFlags>(1 << i);
|
||||
|
||||
if (gameFlags & flag)
|
||||
jMaterial.gameFlags.emplace_back(flag);
|
||||
}
|
||||
}
|
||||
|
||||
static void CreateJsonSamplerState(JsonSamplerState& jSamplerState, const MaterialTextureDefSamplerState& samplerState)
|
||||
{
|
||||
jSamplerState.filter = static_cast<TextureFilter>(samplerState.filter);
|
||||
jSamplerState.mipMap = static_cast<SamplerStateBitsMipMap_e>(samplerState.mipMap);
|
||||
jSamplerState.clampU = samplerState.clampU;
|
||||
jSamplerState.clampV = samplerState.clampV;
|
||||
jSamplerState.clampW = samplerState.clampW;
|
||||
}
|
||||
|
||||
void CreateJsonTexture(JsonTexture& jTextureDef, const MaterialTextureDef& textureDef) const
|
||||
{
|
||||
std::string textureDefName;
|
||||
if (m_material_constants.GetTextureDefName(textureDef.nameHash, textureDefName))
|
||||
{
|
||||
jTextureDef.name = textureDefName;
|
||||
}
|
||||
else
|
||||
{
|
||||
jTextureDef.nameHash = textureDef.nameHash;
|
||||
jTextureDef.nameStart = std::string(1u, textureDef.nameStart);
|
||||
jTextureDef.nameEnd = std::string(1u, textureDef.nameEnd);
|
||||
}
|
||||
|
||||
jTextureDef.semantic = static_cast<TextureSemantic>(textureDef.semantic);
|
||||
jTextureDef.isMatureContent = textureDef.isMatureContent;
|
||||
|
||||
CreateJsonSamplerState(jTextureDef.samplerState, textureDef.samplerState);
|
||||
|
||||
if (textureDef.image && textureDef.image->name)
|
||||
jTextureDef.image = AssetName(textureDef.image->name);
|
||||
}
|
||||
|
||||
void CreateJsonConstant(JsonConstant& jConstantDef, const MaterialConstantDef& constantDef) const
|
||||
{
|
||||
const auto fragmentLength = strnlen(constantDef.name, std::extent_v<decltype(MaterialConstantDef::name)>);
|
||||
const std::string nameFragment(constantDef.name, fragmentLength);
|
||||
std::string knownConstantName;
|
||||
|
||||
if (fragmentLength < std::extent_v<decltype(MaterialConstantDef::name)> || Common::R_HashString(nameFragment.c_str(), 0) == constantDef.nameHash)
|
||||
{
|
||||
jConstantDef.name = nameFragment;
|
||||
}
|
||||
else if (m_material_constants.GetConstantName(constantDef.nameHash, knownConstantName))
|
||||
{
|
||||
jConstantDef.name = knownConstantName;
|
||||
}
|
||||
else
|
||||
{
|
||||
jConstantDef.nameHash = constantDef.nameHash;
|
||||
jConstantDef.nameFragment = nameFragment;
|
||||
}
|
||||
|
||||
jConstantDef.literal = std::vector({
|
||||
constantDef.literal.x,
|
||||
constantDef.literal.y,
|
||||
constantDef.literal.z,
|
||||
constantDef.literal.w,
|
||||
});
|
||||
}
|
||||
|
||||
static void CreateJsonStencil(JsonStencil& jStencil, const unsigned pass, const unsigned fail, const unsigned zFail, const unsigned func)
|
||||
{
|
||||
jStencil.pass = static_cast<GfxStencilOp>(pass);
|
||||
jStencil.fail = static_cast<GfxStencilOp>(fail);
|
||||
jStencil.zfail = static_cast<GfxStencilOp>(zFail);
|
||||
jStencil.func = static_cast<GfxStencilFunc>(func);
|
||||
}
|
||||
|
||||
static void CreateJsonStateBitsTableEntry(JsonStateBitsTableEntry& jStateBitsTableEntry, const GfxStateBitsTable& stateBitsTableEntry)
|
||||
{
|
||||
const auto& structured = stateBitsTableEntry.loadBits.structured;
|
||||
|
||||
jStateBitsTableEntry.srcBlendRgb = static_cast<GfxBlend>(structured.srcBlendRgb);
|
||||
jStateBitsTableEntry.dstBlendRgb = static_cast<GfxBlend>(structured.dstBlendRgb);
|
||||
jStateBitsTableEntry.blendOpRgb = static_cast<GfxBlendOp>(structured.blendOpRgb);
|
||||
|
||||
assert(structured.alphaTestDisabled || structured.alphaTest == GFXS_ALPHA_TEST_GT_0 || structured.alphaTest == GFXS_ALPHA_TEST_GE_128);
|
||||
if (structured.alphaTestDisabled)
|
||||
jStateBitsTableEntry.alphaTest = JsonAlphaTest::DISABLED;
|
||||
else if (structured.alphaTest == GFXS_ALPHA_TEST_GT_0)
|
||||
jStateBitsTableEntry.alphaTest = JsonAlphaTest::GT0;
|
||||
else if (structured.alphaTest == GFXS_ALPHA_TEST_GE_128)
|
||||
jStateBitsTableEntry.alphaTest = JsonAlphaTest::GE128;
|
||||
else
|
||||
jStateBitsTableEntry.alphaTest = JsonAlphaTest::INVALID;
|
||||
|
||||
assert(structured.cullFace == GFXS0_CULL_NONE || structured.cullFace == GFXS0_CULL_BACK || structured.cullFace == GFXS0_CULL_FRONT);
|
||||
if (structured.cullFace == GFXS0_CULL_NONE)
|
||||
jStateBitsTableEntry.cullFace = JsonCullFace::NONE;
|
||||
else if (structured.cullFace == GFXS0_CULL_BACK)
|
||||
jStateBitsTableEntry.cullFace = JsonCullFace::BACK;
|
||||
else if (structured.cullFace == GFXS0_CULL_FRONT)
|
||||
jStateBitsTableEntry.cullFace = JsonCullFace::FRONT;
|
||||
else
|
||||
jStateBitsTableEntry.cullFace = JsonCullFace::INVALID;
|
||||
|
||||
jStateBitsTableEntry.srcBlendAlpha = static_cast<GfxBlend>(structured.srcBlendAlpha);
|
||||
jStateBitsTableEntry.dstBlendAlpha = static_cast<GfxBlend>(structured.dstBlendAlpha);
|
||||
jStateBitsTableEntry.blendOpAlpha = static_cast<GfxBlendOp>(structured.blendOpAlpha);
|
||||
jStateBitsTableEntry.colorWriteRgb = structured.colorWriteRgb;
|
||||
jStateBitsTableEntry.colorWriteAlpha = structured.colorWriteAlpha;
|
||||
jStateBitsTableEntry.polymodeLine = structured.polymodeLine;
|
||||
jStateBitsTableEntry.depthWrite = structured.depthWrite;
|
||||
|
||||
assert(structured.depthTestDisabled || structured.depthTest == GFXS_DEPTHTEST_ALWAYS || structured.depthTest == GFXS_DEPTHTEST_LESS
|
||||
|| structured.depthTest == GFXS_DEPTHTEST_EQUAL || structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
if (structured.depthTestDisabled)
|
||||
jStateBitsTableEntry.depthTest = JsonDepthTest::DISABLED;
|
||||
else if (structured.depthTest == GFXS_DEPTHTEST_ALWAYS)
|
||||
jStateBitsTableEntry.depthTest = JsonDepthTest::ALWAYS;
|
||||
else if (structured.depthTest == GFXS_DEPTHTEST_LESS)
|
||||
jStateBitsTableEntry.depthTest = JsonDepthTest::LESS;
|
||||
else if (structured.depthTest == GFXS_DEPTHTEST_EQUAL)
|
||||
jStateBitsTableEntry.depthTest = JsonDepthTest::EQUAL;
|
||||
else if (structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL)
|
||||
jStateBitsTableEntry.depthTest = JsonDepthTest::LESS_EQUAL;
|
||||
else
|
||||
jStateBitsTableEntry.depthTest = JsonDepthTest::INVALID;
|
||||
|
||||
jStateBitsTableEntry.polygonOffset = static_cast<GfxPolygonOffset_e>(structured.polygonOffset);
|
||||
|
||||
if (structured.stencilFrontEnabled)
|
||||
{
|
||||
JsonStencil jStencilFront;
|
||||
CreateJsonStencil(
|
||||
jStencilFront, structured.stencilFrontPass, structured.stencilFrontFail, structured.stencilFrontZFail, structured.stencilFrontFunc);
|
||||
jStateBitsTableEntry.stencilFront = jStencilFront;
|
||||
}
|
||||
|
||||
if (structured.stencilBackEnabled)
|
||||
{
|
||||
JsonStencil jStencilBack;
|
||||
CreateJsonStencil(
|
||||
jStencilBack, structured.stencilBackPass, structured.stencilBackFail, structured.stencilBackZFail, structured.stencilBackFunc);
|
||||
jStateBitsTableEntry.stencilBack = jStencilBack;
|
||||
}
|
||||
}
|
||||
|
||||
void CreateJsonMaterial(JsonMaterial& jMaterial, const Material& material) const
|
||||
{
|
||||
CreateJsonGameFlags(jMaterial, material.info.gameFlags);
|
||||
jMaterial.sortKey = material.info.sortKey;
|
||||
|
||||
jMaterial.textureAtlas = JsonTextureAtlas();
|
||||
jMaterial.textureAtlas->rows = material.info.textureAtlasRowCount;
|
||||
jMaterial.textureAtlas->columns = material.info.textureAtlasColumnCount;
|
||||
|
||||
jMaterial.surfaceTypeBits = material.info.surfaceTypeBits;
|
||||
jMaterial.layeredSurfaceTypes = material.info.layeredSurfaceTypes;
|
||||
jMaterial.hashIndex = material.info.hashIndex;
|
||||
jMaterial.surfaceFlags = material.info.surfaceFlags;
|
||||
jMaterial.contents = material.info.contents;
|
||||
|
||||
jMaterial.stateBitsEntry.resize(std::extent_v<decltype(Material::stateBitsEntry)>);
|
||||
for (auto i = 0u; i < std::extent_v<decltype(Material::stateBitsEntry)>; i++)
|
||||
jMaterial.stateBitsEntry[i] = material.stateBitsEntry[i];
|
||||
|
||||
jMaterial.stateFlags = material.stateFlags;
|
||||
jMaterial.cameraRegion = static_cast<GfxCameraRegionType>(material.cameraRegion);
|
||||
jMaterial.probeMipBits = material.probeMipBits;
|
||||
|
||||
if (material.techniqueSet && material.techniqueSet->name)
|
||||
jMaterial.techniqueSet = AssetName(material.techniqueSet->name);
|
||||
|
||||
jMaterial.textures.resize(material.textureCount);
|
||||
for (auto i = 0u; i < material.textureCount; i++)
|
||||
CreateJsonTexture(jMaterial.textures[i], material.textureTable[i]);
|
||||
|
||||
jMaterial.constants.resize(material.constantCount);
|
||||
for (auto i = 0u; i < material.constantCount; i++)
|
||||
CreateJsonConstant(jMaterial.constants[i], material.constantTable[i]);
|
||||
|
||||
jMaterial.stateBits.resize(material.stateBitsCount);
|
||||
for (auto i = 0u; i < material.stateBitsCount; i++)
|
||||
CreateJsonStateBitsTableEntry(jMaterial.stateBits[i], material.stateBitsTable[i]);
|
||||
|
||||
if (material.thermalMaterial && material.thermalMaterial->info.name)
|
||||
jMaterial.thermalMaterial = AssetName(material.thermalMaterial->info.name);
|
||||
}
|
||||
|
||||
std::ostream& m_stream;
|
||||
const MaterialConstantZoneState& m_material_constants;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace T6
|
||||
{
|
||||
void DumpMaterialAsJson(std::ostream& stream, const Material* material, AssetDumpingContext& context)
|
||||
{
|
||||
const JsonDumper dumper(context, stream);
|
||||
dumper.Dump(material);
|
||||
}
|
||||
} // namespace T6
|
@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "Dumping/AssetDumpingContext.h"
|
||||
#include "Game/T6/T6.h"
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace T6
|
||||
{
|
||||
void DumpMaterialAsJson(std::ostream& stream, const Material* material, AssetDumpingContext& context);
|
||||
} // namespace T6
|
@ -1,4 +1,4 @@
|
||||
#include "MaterialConstantZoneState.h"
|
||||
#include "MaterialConstantZoneStateT6.h"
|
||||
|
||||
#include "Game/T6/CommonT6.h"
|
||||
#include "Game/T6/GameAssetPoolT6.h"
|
@ -5,7 +5,6 @@
|
||||
#include "AssetDumpers/AssetDumperLeaderboardDef.h"
|
||||
#include "AssetDumpers/AssetDumperLocalizeEntry.h"
|
||||
#include "AssetDumpers/AssetDumperMapEnts.h"
|
||||
#include "AssetDumpers/AssetDumperMaterial.h"
|
||||
#include "AssetDumpers/AssetDumperPhysConstraints.h"
|
||||
#include "AssetDumpers/AssetDumperPhysPreset.h"
|
||||
#include "AssetDumpers/AssetDumperQdb.h"
|
||||
@ -25,6 +24,7 @@
|
||||
#include "AssetDumpers/AssetDumperXModel.h"
|
||||
#include "AssetDumpers/AssetDumperZBarrier.h"
|
||||
#include "Game/T6/GameAssetPoolT6.h"
|
||||
#include "Material/DumperMaterialT6.h"
|
||||
#include "ObjWriting.h"
|
||||
|
||||
using namespace T6;
|
||||
|
@ -27,6 +27,7 @@ namespace
|
||||
|
||||
jRoot["_type"] = "weaponCamo";
|
||||
jRoot["_version"] = 1;
|
||||
jRoot["_game"] = "t6";
|
||||
|
||||
m_stream << std::setw(4) << jRoot << "\n";
|
||||
}
|
||||
|
@ -1,15 +1,43 @@
|
||||
#include "JsonMaterialWriter.h"
|
||||
#options GAME (IW4, IW5, T6)
|
||||
|
||||
#filename "Game/" + GAME + "/Material/JsonMaterialWriter" + GAME + ".cpp"
|
||||
|
||||
#if GAME == "IW4"
|
||||
#define FEATURE_IW4
|
||||
#define HAS_WATER
|
||||
#define GAME_LOWER "iw4"
|
||||
#elif GAME == "IW5"
|
||||
#define FEATURE_IW5
|
||||
#define HAS_WATER
|
||||
#define GAME_LOWER "iw5"
|
||||
#elif GAME == "T6"
|
||||
#define FEATURE_T6
|
||||
#define GAME_LOWER "t6"
|
||||
#endif
|
||||
|
||||
// This file was templated.
|
||||
// See JsonMaterialWriter.cpp.template.
|
||||
// Do not modify, changes will be lost.
|
||||
|
||||
#set WRITER_HEADER "\"JsonMaterialWriter" + GAME + ".h\""
|
||||
#include WRITER_HEADER
|
||||
|
||||
#ifdef HAS_WATER
|
||||
#include "Base64.h"
|
||||
#include "Game/IW5/CommonIW5.h"
|
||||
#include "Game/IW5/Material/JsonMaterial.h"
|
||||
#include "MaterialConstantZoneState.h"
|
||||
#endif
|
||||
|
||||
#set COMMON_HEADER "\"Game/" + GAME + "/Common" + GAME + ".h\""
|
||||
#include COMMON_HEADER
|
||||
#set JSON_HEADER "\"Game/" + GAME + "/Material/JsonMaterial" + GAME + ".h\""
|
||||
#include JSON_HEADER
|
||||
#set CONSTANTS_HEADER "\"Game/" + GAME + "/Material/MaterialConstantZoneState" + GAME + ".h\""
|
||||
#include CONSTANTS_HEADER
|
||||
|
||||
#include <iomanip>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using namespace nlohmann;
|
||||
using namespace IW5;
|
||||
using namespace GAME;
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -22,15 +50,15 @@ namespace
|
||||
{
|
||||
}
|
||||
|
||||
void Dump(const Material* material) const
|
||||
void Dump(const Material& material) const
|
||||
{
|
||||
JsonMaterial jsonMaterial;
|
||||
CreateJsonMaterial(jsonMaterial, *material);
|
||||
CreateJsonMaterial(jsonMaterial, material);
|
||||
json jRoot = jsonMaterial;
|
||||
|
||||
jRoot["_type"] = "material";
|
||||
jRoot["_game"] = "iw5";
|
||||
jRoot["_version"] = 1;
|
||||
jRoot["_game"] = GAME_LOWER;
|
||||
|
||||
m_stream << std::setw(4) << jRoot << "\n";
|
||||
}
|
||||
@ -65,6 +93,7 @@ namespace
|
||||
jSamplerState.clampW = samplerState.clampW;
|
||||
}
|
||||
|
||||
#ifdef HAS_WATER
|
||||
static void CreateJsonWater(JsonWater& jWater, const water_t& water)
|
||||
{
|
||||
jWater.floatTime = water.writable.floatTime;
|
||||
@ -94,6 +123,7 @@ namespace
|
||||
jWater.wTerm = base64::EncodeBase64(water.wTerm, sizeof(float) * count);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void CreateJsonTexture(JsonTexture& jTextureDef, const MaterialTextureDef& textureDef) const
|
||||
{
|
||||
@ -110,9 +140,13 @@ namespace
|
||||
}
|
||||
|
||||
jTextureDef.semantic = static_cast<TextureSemantic>(textureDef.semantic);
|
||||
#if defined(FEATURE_T6)
|
||||
jTextureDef.isMatureContent = textureDef.isMatureContent;
|
||||
#endif
|
||||
|
||||
CreateJsonSamplerState(jTextureDef.samplerState, textureDef.samplerState);
|
||||
|
||||
#ifdef HAS_WATER
|
||||
if (textureDef.semantic == TS_WATER_MAP)
|
||||
{
|
||||
if (textureDef.u.water)
|
||||
@ -132,6 +166,10 @@ namespace
|
||||
if (textureDef.u.image && textureDef.u.image->name)
|
||||
jTextureDef.image = AssetName(textureDef.u.image->name);
|
||||
}
|
||||
#else
|
||||
if (textureDef.image && textureDef.image->name)
|
||||
jTextureDef.image = AssetName(textureDef.image->name);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CreateJsonConstant(JsonConstant& jConstantDef, const MaterialConstantDef& constantDef) const
|
||||
@ -178,14 +216,20 @@ namespace
|
||||
jStateBitsTableEntry.dstBlendRgb = static_cast<GfxBlend>(structured.dstBlendRgb);
|
||||
jStateBitsTableEntry.blendOpRgb = static_cast<GfxBlendOp>(structured.blendOpRgb);
|
||||
|
||||
assert(structured.alphaTestDisabled || structured.alphaTest == GFXS_ALPHA_TEST_GT_0 || structured.alphaTest == GFXS_ALPHA_TEST_LT_128
|
||||
|| structured.alphaTest == GFXS_ALPHA_TEST_GE_128);
|
||||
assert(structured.alphaTestDisabled
|
||||
|| structured.alphaTest == GFXS_ALPHA_TEST_GT_0
|
||||
#if defined(FEATURE_IW4) || defined(FEATURE_IW5)
|
||||
|| structured.alphaTest == GFXS_ALPHA_TEST_LT_128
|
||||
#endif
|
||||
|| structured.alphaTest == GFXS_ALPHA_TEST_GE_128);
|
||||
if (structured.alphaTestDisabled)
|
||||
jStateBitsTableEntry.alphaTest = JsonAlphaTest::DISABLED;
|
||||
else if (structured.alphaTest == GFXS_ALPHA_TEST_GT_0)
|
||||
jStateBitsTableEntry.alphaTest = JsonAlphaTest::GT0;
|
||||
#if defined(FEATURE_IW4) || defined(FEATURE_IW5)
|
||||
else if (structured.alphaTest == GFXS_ALPHA_TEST_LT_128)
|
||||
jStateBitsTableEntry.alphaTest = JsonAlphaTest::LT128;
|
||||
#endif
|
||||
else if (structured.alphaTest == GFXS_ALPHA_TEST_GE_128)
|
||||
jStateBitsTableEntry.alphaTest = JsonAlphaTest::GE128;
|
||||
else
|
||||
@ -206,7 +250,9 @@ namespace
|
||||
jStateBitsTableEntry.blendOpAlpha = static_cast<GfxBlendOp>(structured.blendOpAlpha);
|
||||
jStateBitsTableEntry.colorWriteRgb = structured.colorWriteRgb;
|
||||
jStateBitsTableEntry.colorWriteAlpha = structured.colorWriteAlpha;
|
||||
#if defined(FEATURE_IW4) || defined(FEATURE_IW5)
|
||||
jStateBitsTableEntry.gammaWrite = structured.gammaWrite;
|
||||
#endif
|
||||
jStateBitsTableEntry.polymodeLine = structured.polymodeLine;
|
||||
jStateBitsTableEntry.depthWrite = structured.depthWrite;
|
||||
|
||||
@ -254,6 +300,12 @@ namespace
|
||||
jMaterial.textureAtlas->columns = material.info.textureAtlasColumnCount;
|
||||
|
||||
jMaterial.surfaceTypeBits = material.info.surfaceTypeBits;
|
||||
#ifdef FEATURE_T6
|
||||
jMaterial.layeredSurfaceTypes = material.info.layeredSurfaceTypes;
|
||||
jMaterial.hashIndex = material.info.hashIndex;
|
||||
jMaterial.surfaceFlags = material.info.surfaceFlags;
|
||||
jMaterial.contents = material.info.contents;
|
||||
#endif
|
||||
|
||||
jMaterial.stateBitsEntry.resize(std::extent_v<decltype(Material::stateBitsEntry)>);
|
||||
for (auto i = 0u; i < std::extent_v<decltype(Material::stateBitsEntry)>; i++)
|
||||
@ -261,6 +313,9 @@ namespace
|
||||
|
||||
jMaterial.stateFlags = material.stateFlags;
|
||||
jMaterial.cameraRegion = static_cast<GfxCameraRegionType>(material.cameraRegion);
|
||||
#ifdef FEATURE_T6
|
||||
jMaterial.probeMipBits = material.probeMipBits;
|
||||
#endif
|
||||
|
||||
if (material.techniqueSet && material.techniqueSet->name)
|
||||
jMaterial.techniqueSet = AssetName(material.techniqueSet->name);
|
||||
@ -276,6 +331,11 @@ namespace
|
||||
jMaterial.stateBits.resize(material.stateBitsCount);
|
||||
for (auto i = 0u; i < material.stateBitsCount; i++)
|
||||
CreateJsonStateBitsTableEntry(jMaterial.stateBits[i], material.stateBitsTable[i]);
|
||||
|
||||
#ifdef FEATURE_T6
|
||||
if (material.thermalMaterial && material.thermalMaterial->info.name)
|
||||
jMaterial.thermalMaterial = AssetName(material.thermalMaterial->info.name);
|
||||
#endif
|
||||
}
|
||||
|
||||
std::ostream& m_stream;
|
||||
@ -283,11 +343,11 @@ namespace
|
||||
};
|
||||
} // namespace
|
||||
|
||||
namespace IW5
|
||||
namespace GAME
|
||||
{
|
||||
void DumpMaterialAsJson(std::ostream& stream, const Material* material, AssetDumpingContext& context)
|
||||
void DumpMaterialAsJson(std::ostream& stream, const Material& material, AssetDumpingContext& context)
|
||||
{
|
||||
const JsonDumper dumper(context, stream);
|
||||
dumper.Dump(material);
|
||||
}
|
||||
} // namespace IW5
|
||||
} // namespace GAME
|
20
src/ObjWriting/Material/JsonMaterialWriter.h.template
Normal file
20
src/ObjWriting/Material/JsonMaterialWriter.h.template
Normal file
@ -0,0 +1,20 @@
|
||||
#options GAME (IW4, IW5, T6)
|
||||
|
||||
#filename "Game/" + GAME + "/Material/JsonMaterialWriter" + GAME + ".h"
|
||||
|
||||
// This file was templated.
|
||||
// See JsonMaterialWriter.h.template.
|
||||
// Do not modify, changes will be lost.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Dumping/AssetDumpingContext.h"
|
||||
#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\""
|
||||
#include GAME_HEADER
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace GAME
|
||||
{
|
||||
void DumpMaterialAsJson(std::ostream& stream, const Material& material, AssetDumpingContext& context);
|
||||
} // namespace GAME
|
@ -1,687 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef GAME_NAMESPACE
|
||||
#error Must define GAME_NAMESPACE
|
||||
#endif
|
||||
|
||||
#include "Game/T6/CommonT6.h"
|
||||
#include "ObjWriting.h"
|
||||
#include "Utils/DistinctMapper.h"
|
||||
#include "Utils/QuatInt16.h"
|
||||
#include "XModel/Export/XModelExportWriter.h"
|
||||
#include "XModel/Gltf/GltfBinOutput.h"
|
||||
#include "XModel/Gltf/GltfTextOutput.h"
|
||||
#include "XModel/Gltf/GltfWriter.h"
|
||||
#include "XModel/Obj/ObjWriter.h"
|
||||
#include "XModel/XModelWriter.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <format>
|
||||
|
||||
namespace GAME_NAMESPACE
|
||||
{
|
||||
inline std::string GetFileNameForLod(const std::string& modelName, const unsigned lod, const std::string& extension)
|
||||
{
|
||||
return std::format("model_export/{}_lod{}{}", modelName, lod, extension);
|
||||
}
|
||||
|
||||
inline GfxImage* GetImageFromTextureDef(const MaterialTextureDef& textureDef)
|
||||
{
|
||||
#ifdef FEATURE_T6
|
||||
return textureDef.image;
|
||||
#else
|
||||
return textureDef.u.image;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline GfxImage* GetMaterialColorMap(const Material* material)
|
||||
{
|
||||
std::vector<MaterialTextureDef*> potentialTextureDefs;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
{
|
||||
MaterialTextureDef* def = &material->textureTable[textureIndex];
|
||||
|
||||
if (def->semantic == TS_COLOR_MAP || def->semantic >= TS_COLOR0_MAP && def->semantic <= TS_COLOR15_MAP)
|
||||
potentialTextureDefs.push_back(def);
|
||||
}
|
||||
|
||||
if (potentialTextureDefs.empty())
|
||||
return nullptr;
|
||||
if (potentialTextureDefs.size() == 1)
|
||||
return GetImageFromTextureDef(*potentialTextureDefs[0]);
|
||||
|
||||
for (const auto* def : potentialTextureDefs)
|
||||
{
|
||||
if (tolower(def->nameStart) == 'c' && tolower(def->nameEnd) == 'p')
|
||||
return GetImageFromTextureDef(*def);
|
||||
}
|
||||
|
||||
for (const auto* def : potentialTextureDefs)
|
||||
{
|
||||
if (tolower(def->nameStart) == 'r' && tolower(def->nameEnd) == 'k')
|
||||
return GetImageFromTextureDef(*def);
|
||||
}
|
||||
|
||||
for (const auto* def : potentialTextureDefs)
|
||||
{
|
||||
if (tolower(def->nameStart) == 'd' && tolower(def->nameEnd) == 'p')
|
||||
return GetImageFromTextureDef(*def);
|
||||
}
|
||||
|
||||
return GetImageFromTextureDef(*potentialTextureDefs[0]);
|
||||
}
|
||||
|
||||
inline GfxImage* GetMaterialNormalMap(const Material* material)
|
||||
{
|
||||
std::vector<MaterialTextureDef*> potentialTextureDefs;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
{
|
||||
MaterialTextureDef* def = &material->textureTable[textureIndex];
|
||||
|
||||
if (def->semantic == TS_NORMAL_MAP)
|
||||
potentialTextureDefs.push_back(def);
|
||||
}
|
||||
|
||||
if (potentialTextureDefs.empty())
|
||||
return nullptr;
|
||||
if (potentialTextureDefs.size() == 1)
|
||||
return GetImageFromTextureDef(*potentialTextureDefs[0]);
|
||||
|
||||
for (const auto* def : potentialTextureDefs)
|
||||
{
|
||||
if (def->nameStart == 'n' && def->nameEnd == 'p')
|
||||
return GetImageFromTextureDef(*def);
|
||||
}
|
||||
|
||||
return GetImageFromTextureDef(*potentialTextureDefs[0]);
|
||||
}
|
||||
|
||||
inline GfxImage* GetMaterialSpecularMap(const Material* material)
|
||||
{
|
||||
std::vector<MaterialTextureDef*> potentialTextureDefs;
|
||||
|
||||
for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++)
|
||||
{
|
||||
MaterialTextureDef* def = &material->textureTable[textureIndex];
|
||||
|
||||
if (def->semantic == TS_SPECULAR_MAP)
|
||||
potentialTextureDefs.push_back(def);
|
||||
}
|
||||
|
||||
if (potentialTextureDefs.empty())
|
||||
return nullptr;
|
||||
if (potentialTextureDefs.size() == 1)
|
||||
return GetImageFromTextureDef(*potentialTextureDefs[0]);
|
||||
|
||||
for (const auto* def : potentialTextureDefs)
|
||||
{
|
||||
if (def->nameStart == 's' && def->nameEnd == 'p')
|
||||
return GetImageFromTextureDef(*def);
|
||||
}
|
||||
|
||||
return GetImageFromTextureDef(*potentialTextureDefs[0]);
|
||||
}
|
||||
|
||||
inline bool HasDefaultArmature(const XModel* model, const unsigned lod)
|
||||
{
|
||||
if (model->numRootBones != 1 || model->numBones != 1)
|
||||
return false;
|
||||
|
||||
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
|
||||
const auto surfCount = model->lodInfo[lod].numsurfs;
|
||||
|
||||
if (!surfs)
|
||||
return true;
|
||||
|
||||
for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++)
|
||||
{
|
||||
const auto& surface = surfs[surfIndex];
|
||||
|
||||
if (surface.vertListCount != 1 || surface.vertInfo.vertsBlend)
|
||||
return false;
|
||||
|
||||
const auto& vertList = surface.vertList[0];
|
||||
if (vertList.boneOffset != 0 || vertList.triOffset != 0 || vertList.triCount != surface.triCount || vertList.vertCount != surface.vertCount)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void OmitDefaultArmature(XModelCommon& common)
|
||||
{
|
||||
common.m_bones.clear();
|
||||
common.m_bone_weight_data.weights.clear();
|
||||
common.m_vertex_bone_weights.resize(common.m_vertices.size());
|
||||
for (auto& vertexWeights : common.m_vertex_bone_weights)
|
||||
{
|
||||
vertexWeights.weightOffset = 0u;
|
||||
vertexWeights.weightCount = 0u;
|
||||
}
|
||||
}
|
||||
|
||||
inline void AddXModelBones(XModelCommon& out, const AssetDumpingContext& context, const XModel* model)
|
||||
{
|
||||
for (auto boneNum = 0u; boneNum < model->numBones; boneNum++)
|
||||
{
|
||||
XModelBone bone;
|
||||
if (model->boneNames[boneNum] < context.m_zone->m_script_strings.Count())
|
||||
bone.name = context.m_zone->m_script_strings[model->boneNames[boneNum]];
|
||||
else
|
||||
bone.name = "INVALID_BONE_NAME";
|
||||
|
||||
if (boneNum >= model->numRootBones)
|
||||
bone.parentIndex = static_cast<int>(boneNum - static_cast<unsigned int>(model->parentList[boneNum - model->numRootBones]));
|
||||
else
|
||||
bone.parentIndex = std::nullopt;
|
||||
|
||||
bone.scale[0] = 1.0f;
|
||||
bone.scale[1] = 1.0f;
|
||||
bone.scale[2] = 1.0f;
|
||||
|
||||
const auto& baseMat = model->baseMat[boneNum];
|
||||
bone.globalOffset[0] = baseMat.trans.x;
|
||||
bone.globalOffset[1] = baseMat.trans.y;
|
||||
bone.globalOffset[2] = baseMat.trans.z;
|
||||
bone.globalRotation = {
|
||||
baseMat.quat.x,
|
||||
baseMat.quat.y,
|
||||
baseMat.quat.z,
|
||||
baseMat.quat.w,
|
||||
};
|
||||
|
||||
if (boneNum < model->numRootBones)
|
||||
{
|
||||
bone.localOffset[0] = 0;
|
||||
bone.localOffset[1] = 0;
|
||||
bone.localOffset[2] = 0;
|
||||
bone.localRotation = {0, 0, 0, 1};
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto* trans = &model->trans[(boneNum - model->numRootBones) * 3];
|
||||
bone.localOffset[0] = trans[0];
|
||||
bone.localOffset[1] = trans[1];
|
||||
bone.localOffset[2] = trans[2];
|
||||
|
||||
const auto& quat = model->quats[boneNum - model->numRootBones];
|
||||
bone.localRotation = {
|
||||
QuatInt16::ToFloat(quat.v[0]),
|
||||
QuatInt16::ToFloat(quat.v[1]),
|
||||
QuatInt16::ToFloat(quat.v[2]),
|
||||
QuatInt16::ToFloat(quat.v[3]),
|
||||
};
|
||||
}
|
||||
|
||||
out.m_bones.emplace_back(std::move(bone));
|
||||
}
|
||||
}
|
||||
|
||||
inline const char* AssetName(const char* input)
|
||||
{
|
||||
if (input && input[0] == ',')
|
||||
return &input[1];
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
inline void AddXModelMaterials(XModelCommon& out, DistinctMapper<Material*>& materialMapper, const XModel* model)
|
||||
{
|
||||
for (auto surfaceMaterialNum = 0; surfaceMaterialNum < model->numsurfs; surfaceMaterialNum++)
|
||||
{
|
||||
Material* material = model->materialHandles[surfaceMaterialNum];
|
||||
if (materialMapper.Add(material))
|
||||
{
|
||||
XModelMaterial xMaterial;
|
||||
xMaterial.ApplyDefaults();
|
||||
|
||||
xMaterial.name = AssetName(material->info.name);
|
||||
const auto* colorMap = GetMaterialColorMap(material);
|
||||
if (colorMap)
|
||||
xMaterial.colorMapName = AssetName(colorMap->name);
|
||||
|
||||
const auto* normalMap = GetMaterialNormalMap(material);
|
||||
if (normalMap)
|
||||
xMaterial.normalMapName = AssetName(normalMap->name);
|
||||
|
||||
const auto* specularMap = GetMaterialSpecularMap(material);
|
||||
if (specularMap)
|
||||
xMaterial.specularMapName = AssetName(specularMap->name);
|
||||
|
||||
out.m_materials.emplace_back(std::move(xMaterial));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void AddXModelObjects(XModelCommon& out, const XModel* model, const unsigned lod, const DistinctMapper<Material*>& materialMapper)
|
||||
{
|
||||
const auto surfCount = model->lodInfo[lod].numsurfs;
|
||||
const auto baseSurfaceIndex = model->lodInfo[lod].surfIndex;
|
||||
|
||||
for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++)
|
||||
{
|
||||
XModelObject object;
|
||||
object.name = std::format("surf{}", surfIndex);
|
||||
object.materialIndex = static_cast<int>(materialMapper.GetDistinctPositionByInputPosition(surfIndex + baseSurfaceIndex));
|
||||
|
||||
out.m_objects.emplace_back(std::move(object));
|
||||
}
|
||||
}
|
||||
|
||||
inline void AddXModelVertices(XModelCommon& out, const XModel* model, const unsigned lod)
|
||||
{
|
||||
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
|
||||
const auto surfCount = model->lodInfo[lod].numsurfs;
|
||||
|
||||
if (!surfs)
|
||||
return;
|
||||
|
||||
for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++)
|
||||
{
|
||||
const auto& surface = surfs[surfIndex];
|
||||
|
||||
for (auto vertexIndex = 0u; vertexIndex < surface.vertCount; vertexIndex++)
|
||||
{
|
||||
const auto& v = surface.verts0[vertexIndex];
|
||||
|
||||
XModelVertex vertex{};
|
||||
vertex.coordinates[0] = v.xyz.x;
|
||||
vertex.coordinates[1] = v.xyz.y;
|
||||
vertex.coordinates[2] = v.xyz.z;
|
||||
Common::Vec3UnpackUnitVec(v.normal, vertex.normal);
|
||||
Common::Vec4UnpackGfxColor(v.color, vertex.color);
|
||||
Common::Vec2UnpackTexCoords(v.texCoord, vertex.uv);
|
||||
|
||||
out.m_vertices.emplace_back(vertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void AllocateXModelBoneWeights(const XModel* model, const unsigned lod, XModelVertexBoneWeightCollection& weightCollection)
|
||||
{
|
||||
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
|
||||
const auto surfCount = model->lodInfo[lod].numsurfs;
|
||||
|
||||
if (!surfs)
|
||||
return;
|
||||
|
||||
auto totalWeightCount = 0u;
|
||||
for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++)
|
||||
{
|
||||
const auto& surface = surfs[surfIndex];
|
||||
|
||||
if (surface.vertList)
|
||||
{
|
||||
totalWeightCount += surface.vertListCount;
|
||||
}
|
||||
|
||||
if (surface.vertInfo.vertsBlend)
|
||||
{
|
||||
totalWeightCount += surface.vertInfo.vertCount[0] * 1;
|
||||
totalWeightCount += surface.vertInfo.vertCount[1] * 2;
|
||||
totalWeightCount += surface.vertInfo.vertCount[2] * 3;
|
||||
totalWeightCount += surface.vertInfo.vertCount[3] * 4;
|
||||
}
|
||||
}
|
||||
|
||||
weightCollection.weights.resize(totalWeightCount);
|
||||
}
|
||||
|
||||
inline float BoneWeight16(const uint16_t value)
|
||||
{
|
||||
return static_cast<float>(value) / static_cast<float>(std::numeric_limits<uint16_t>::max());
|
||||
}
|
||||
|
||||
inline void AddXModelVertexBoneWeights(XModelCommon& out, const XModel* model, const unsigned lod)
|
||||
{
|
||||
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
|
||||
const auto surfCount = model->lodInfo[lod].numsurfs;
|
||||
auto& weightCollection = out.m_bone_weight_data;
|
||||
|
||||
if (!surfs)
|
||||
return;
|
||||
|
||||
auto weightOffset = 0u;
|
||||
|
||||
for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++)
|
||||
{
|
||||
const auto& surface = surfs[surfIndex];
|
||||
auto handledVertices = 0u;
|
||||
|
||||
if (surface.vertList)
|
||||
{
|
||||
for (auto vertListIndex = 0u; vertListIndex < surface.vertListCount; vertListIndex++)
|
||||
{
|
||||
const auto& vertList = surface.vertList[vertListIndex];
|
||||
const auto boneWeightOffset = weightOffset;
|
||||
|
||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{vertList.boneOffset / sizeof(DObjSkelMat), 1.0f};
|
||||
|
||||
for (auto vertListVertexOffset = 0u; vertListVertexOffset < vertList.vertCount; vertListVertexOffset++)
|
||||
{
|
||||
out.m_vertex_bone_weights.emplace_back(boneWeightOffset, 1);
|
||||
}
|
||||
handledVertices += vertList.vertCount;
|
||||
}
|
||||
}
|
||||
|
||||
auto vertsBlendOffset = 0u;
|
||||
if (surface.vertInfo.vertsBlend)
|
||||
{
|
||||
// 1 bone weight
|
||||
for (auto vertIndex = 0; vertIndex < surface.vertInfo.vertCount[0]; vertIndex++)
|
||||
{
|
||||
const auto boneWeightOffset = weightOffset;
|
||||
const auto boneIndex0 = surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat);
|
||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex0, 1.0f};
|
||||
|
||||
vertsBlendOffset += 1;
|
||||
|
||||
out.m_vertex_bone_weights.emplace_back(boneWeightOffset, 1);
|
||||
}
|
||||
|
||||
// 2 bone weights
|
||||
for (auto vertIndex = 0; vertIndex < surface.vertInfo.vertCount[1]; vertIndex++)
|
||||
{
|
||||
const auto boneWeightOffset = weightOffset;
|
||||
const auto boneIndex0 = surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat);
|
||||
const auto boneIndex1 = surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat);
|
||||
const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]);
|
||||
const auto boneWeight0 = 1.0f - boneWeight1;
|
||||
|
||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex0, boneWeight0};
|
||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex1, boneWeight1};
|
||||
|
||||
vertsBlendOffset += 3;
|
||||
|
||||
out.m_vertex_bone_weights.emplace_back(boneWeightOffset, 2);
|
||||
}
|
||||
|
||||
// 3 bone weights
|
||||
for (auto vertIndex = 0; vertIndex < surface.vertInfo.vertCount[2]; vertIndex++)
|
||||
{
|
||||
const auto boneWeightOffset = weightOffset;
|
||||
const auto boneIndex0 = surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat);
|
||||
const auto boneIndex1 = surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat);
|
||||
const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]);
|
||||
const auto boneIndex2 = surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat);
|
||||
const auto boneWeight2 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]);
|
||||
const auto boneWeight0 = 1.0f - boneWeight1 - boneWeight2;
|
||||
|
||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex0, boneWeight0};
|
||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex1, boneWeight1};
|
||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex2, boneWeight2};
|
||||
|
||||
vertsBlendOffset += 5;
|
||||
|
||||
out.m_vertex_bone_weights.emplace_back(boneWeightOffset, 3);
|
||||
}
|
||||
|
||||
// 4 bone weights
|
||||
for (auto vertIndex = 0; vertIndex < surface.vertInfo.vertCount[3]; vertIndex++)
|
||||
{
|
||||
const auto boneWeightOffset = weightOffset;
|
||||
const auto boneIndex0 = surface.vertInfo.vertsBlend[vertsBlendOffset + 0] / sizeof(DObjSkelMat);
|
||||
const auto boneIndex1 = surface.vertInfo.vertsBlend[vertsBlendOffset + 1] / sizeof(DObjSkelMat);
|
||||
const auto boneWeight1 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 2]);
|
||||
const auto boneIndex2 = surface.vertInfo.vertsBlend[vertsBlendOffset + 3] / sizeof(DObjSkelMat);
|
||||
const auto boneWeight2 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 4]);
|
||||
const auto boneIndex3 = surface.vertInfo.vertsBlend[vertsBlendOffset + 5] / sizeof(DObjSkelMat);
|
||||
const auto boneWeight3 = BoneWeight16(surface.vertInfo.vertsBlend[vertsBlendOffset + 6]);
|
||||
const auto boneWeight0 = 1.0f - boneWeight1 - boneWeight2 - boneWeight3;
|
||||
|
||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex0, boneWeight0};
|
||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex1, boneWeight1};
|
||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex2, boneWeight2};
|
||||
weightCollection.weights[weightOffset++] = XModelBoneWeight{boneIndex3, boneWeight3};
|
||||
|
||||
vertsBlendOffset += 7;
|
||||
|
||||
out.m_vertex_bone_weights.emplace_back(boneWeightOffset, 4);
|
||||
}
|
||||
|
||||
handledVertices +=
|
||||
surface.vertInfo.vertCount[0] + surface.vertInfo.vertCount[1] + surface.vertInfo.vertCount[2] + surface.vertInfo.vertCount[3];
|
||||
}
|
||||
|
||||
for (; handledVertices < surface.vertCount; handledVertices++)
|
||||
{
|
||||
out.m_vertex_bone_weights.emplace_back(0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void AddXModelFaces(XModelCommon& out, const XModel* model, const unsigned lod)
|
||||
{
|
||||
const auto* surfs = &model->surfs[model->lodInfo[lod].surfIndex];
|
||||
const auto surfCount = model->lodInfo[lod].numsurfs;
|
||||
|
||||
if (!surfs)
|
||||
return;
|
||||
|
||||
for (auto surfIndex = 0u; surfIndex < surfCount; surfIndex++)
|
||||
{
|
||||
const auto& surface = surfs[surfIndex];
|
||||
auto& object = out.m_objects[surfIndex];
|
||||
object.m_faces.reserve(surface.triCount);
|
||||
|
||||
for (auto triIndex = 0u; triIndex < surface.triCount; triIndex++)
|
||||
{
|
||||
const auto& tri = surface.triIndices[triIndex];
|
||||
|
||||
XModelFace face{};
|
||||
face.vertexIndex[0] = tri.i[0] + surface.baseVertIndex;
|
||||
face.vertexIndex[1] = tri.i[1] + surface.baseVertIndex;
|
||||
face.vertexIndex[2] = tri.i[2] + surface.baseVertIndex;
|
||||
object.m_faces.emplace_back(face);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void PopulateXModelWriter(XModelCommon& out, const AssetDumpingContext& context, const unsigned lod, const XModel* model)
|
||||
{
|
||||
DistinctMapper<Material*> materialMapper(model->numsurfs);
|
||||
AllocateXModelBoneWeights(model, lod, out.m_bone_weight_data);
|
||||
|
||||
out.m_name = std::format("{}_lod{}", model->name, lod);
|
||||
AddXModelMaterials(out, materialMapper, model);
|
||||
AddXModelObjects(out, model, lod, materialMapper);
|
||||
AddXModelVertices(out, model, lod);
|
||||
AddXModelFaces(out, model, lod);
|
||||
|
||||
if (!HasDefaultArmature(model, lod))
|
||||
{
|
||||
AddXModelBones(out, context, model);
|
||||
AddXModelVertexBoneWeights(out, model, lod);
|
||||
}
|
||||
else
|
||||
{
|
||||
OmitDefaultArmature(out);
|
||||
}
|
||||
}
|
||||
|
||||
inline void DumpObjMtl(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo<XModel>* asset)
|
||||
{
|
||||
const auto* model = asset->Asset();
|
||||
const auto mtlFile = context.OpenAssetFile(std::format("model_export/{}.mtl", model->name));
|
||||
|
||||
if (!mtlFile)
|
||||
return;
|
||||
|
||||
const auto writer = obj::CreateMtlWriter(*mtlFile, context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
|
||||
DistinctMapper<Material*> materialMapper(model->numsurfs);
|
||||
|
||||
writer->Write(common);
|
||||
}
|
||||
|
||||
inline void DumpObjLod(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod)
|
||||
{
|
||||
const auto* model = asset->Asset();
|
||||
const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".obj"));
|
||||
|
||||
if (!assetFile)
|
||||
return;
|
||||
|
||||
const auto writer =
|
||||
obj::CreateObjWriter(*assetFile, std::format("{}.mtl", model->name), context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
|
||||
DistinctMapper<Material*> materialMapper(model->numsurfs);
|
||||
|
||||
writer->Write(common);
|
||||
}
|
||||
|
||||
inline void DumpXModelExportLod(const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod)
|
||||
{
|
||||
const auto* model = asset->Asset();
|
||||
const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, ".XMODEL_EXPORT"));
|
||||
|
||||
if (!assetFile)
|
||||
return;
|
||||
|
||||
const auto writer = xmodel_export::CreateWriterForVersion6(*assetFile, context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
|
||||
writer->Write(common);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void DumpGltfLod(
|
||||
const XModelCommon& common, const AssetDumpingContext& context, const XAssetInfo<XModel>* asset, const unsigned lod, const std::string& extension)
|
||||
{
|
||||
const auto* model = asset->Asset();
|
||||
const auto assetFile = context.OpenAssetFile(GetFileNameForLod(model->name, lod, extension));
|
||||
|
||||
if (!assetFile)
|
||||
return;
|
||||
|
||||
const auto output = std::make_unique<T>(*assetFile);
|
||||
const auto writer = gltf::Writer::CreateWriter(output.get(), context.m_zone->m_game->GetShortName(), context.m_zone->m_name);
|
||||
|
||||
writer->Write(common);
|
||||
}
|
||||
|
||||
inline void DumpXModelSurfs(const AssetDumpingContext& context, const XAssetInfo<XModel>* asset)
|
||||
{
|
||||
const auto* model = asset->Asset();
|
||||
|
||||
for (auto currentLod = 0u; currentLod < model->numLods; currentLod++)
|
||||
{
|
||||
XModelCommon common;
|
||||
PopulateXModelWriter(common, context, currentLod, asset->Asset());
|
||||
|
||||
switch (ObjWriting::Configuration.ModelOutputFormat)
|
||||
{
|
||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ:
|
||||
DumpObjLod(common, context, asset, currentLod);
|
||||
if (currentLod == 0u)
|
||||
DumpObjMtl(common, context, asset);
|
||||
break;
|
||||
|
||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT:
|
||||
DumpXModelExportLod(common, context, asset, currentLod);
|
||||
break;
|
||||
|
||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLTF:
|
||||
DumpGltfLod<gltf::TextOutput>(common, context, asset, currentLod, ".gltf");
|
||||
break;
|
||||
|
||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLB:
|
||||
DumpGltfLod<gltf::BinOutput>(common, context, asset, currentLod, ".glb");
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class JsonDumper
|
||||
{
|
||||
public:
|
||||
JsonDumper(AssetDumpingContext& context, std::ostream& stream)
|
||||
: m_stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
void Dump(const XModel* xmodel) const
|
||||
{
|
||||
JsonXModel jsonXModel;
|
||||
CreateJsonXModel(jsonXModel, *xmodel);
|
||||
nlohmann::json jRoot = jsonXModel;
|
||||
|
||||
jRoot["_type"] = "xmodel";
|
||||
jRoot["_version"] = 1;
|
||||
|
||||
m_stream << std::setw(4) << jRoot << "\n";
|
||||
}
|
||||
|
||||
private:
|
||||
static const char* AssetName(const char* input)
|
||||
{
|
||||
if (input && input[0] == ',')
|
||||
return &input[1];
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
static const char* GetExtensionForModelByConfig()
|
||||
{
|
||||
switch (ObjWriting::Configuration.ModelOutputFormat)
|
||||
{
|
||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::XMODEL_EXPORT:
|
||||
return ".XMODEL_EXPORT";
|
||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::OBJ:
|
||||
return ".OBJ";
|
||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLTF:
|
||||
return ".GLTF";
|
||||
case ObjWriting::Configuration_t::ModelOutputFormat_e::GLB:
|
||||
return ".GLB";
|
||||
default:
|
||||
assert(false);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
static void CreateJsonXModel(JsonXModel& jXModel, const XModel& xmodel)
|
||||
{
|
||||
if (xmodel.collLod >= 0)
|
||||
jXModel.collLod = xmodel.collLod;
|
||||
|
||||
for (auto lodNumber = 0u; lodNumber < xmodel.numLods; lodNumber++)
|
||||
{
|
||||
JsonXModelLod lod;
|
||||
lod.file = std::format("model_export/{}_lod{}{}", xmodel.name, lodNumber, GetExtensionForModelByConfig());
|
||||
lod.distance = xmodel.lodInfo[lodNumber].dist;
|
||||
|
||||
jXModel.lods.emplace_back(std::move(lod));
|
||||
}
|
||||
|
||||
if (xmodel.physPreset && xmodel.physPreset->name)
|
||||
jXModel.physPreset = AssetName(xmodel.physPreset->name);
|
||||
|
||||
if (xmodel.physConstraints && xmodel.physConstraints->name)
|
||||
jXModel.physConstraints = AssetName(xmodel.physConstraints->name);
|
||||
|
||||
jXModel.flags = xmodel.flags;
|
||||
|
||||
#ifdef FEATURE_T6
|
||||
jXModel.lightingOriginOffset.x = xmodel.lightingOriginOffset.x;
|
||||
jXModel.lightingOriginOffset.y = xmodel.lightingOriginOffset.y;
|
||||
jXModel.lightingOriginOffset.z = xmodel.lightingOriginOffset.z;
|
||||
jXModel.lightingOriginRange = xmodel.lightingOriginRange;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::ostream& m_stream;
|
||||
};
|
||||
|
||||
inline void DumpXModelJson(AssetDumpingContext& context, XAssetInfo<XModel>* asset)
|
||||
{
|
||||
const auto assetFile = context.OpenAssetFile(std::format("xmodel/{}.json", asset->m_name));
|
||||
if (!assetFile)
|
||||
return;
|
||||
|
||||
const JsonDumper dumper(context, *assetFile);
|
||||
dumper.Dump(asset->Asset());
|
||||
}
|
||||
} // namespace GAME_NAMESPACE
|
@ -8,12 +8,19 @@
|
||||
|
||||
#if GAME == "IW5"
|
||||
#define FEATURE_IW5
|
||||
#define GAME_LOWER "iw5"
|
||||
#elif GAME == "T5"
|
||||
#define FEATURE_T5
|
||||
#define GAME_LOWER "t5"
|
||||
#elif GAME == "T6"
|
||||
#define FEATURE_T6
|
||||
#define GAME_LOWER "t6"
|
||||
#endif
|
||||
|
||||
// This file was templated.
|
||||
// See XModelDumper.cpp.template.
|
||||
// Do not modify, changes will be lost.
|
||||
|
||||
#include DUMPER_HEADER
|
||||
|
||||
#include COMMON_HEADER
|
||||
@ -664,6 +671,7 @@ namespace
|
||||
|
||||
jRoot["_type"] = "xmodel";
|
||||
jRoot["_version"] = 1;
|
||||
jRoot["_game"] = GAME_LOWER;
|
||||
|
||||
m_stream << std::setw(4) << jRoot << "\n";
|
||||
}
|
||||
|
@ -4,6 +4,10 @@
|
||||
|
||||
#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\""
|
||||
|
||||
// This file was templated.
|
||||
// See XModelDumper.h.template.
|
||||
// Do not modify, changes will be lost.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Dumping/AssetDumpingContext.h"
|
||||
|
@ -49,7 +49,7 @@ DefinesStreamProxy::DefineParameterPosition::DefineParameterPosition(const unsig
|
||||
}
|
||||
|
||||
DefinesStreamProxy::Define::Define()
|
||||
: m_contains_token_pasting_operators(false){};
|
||||
: m_contains_token_pasting_operators(false) {};
|
||||
|
||||
DefinesStreamProxy::Define::Define(std::string name, std::string value)
|
||||
: m_name(std::move(name)),
|
||||
|
@ -89,7 +89,7 @@ public:
|
||||
std::vector<scr_string_t> usedScriptStrings,
|
||||
std::vector<IndirectAssetReference> indirectAssetReferences)
|
||||
: XAssetInfoGeneric(
|
||||
type, std::move(name), static_cast<void*>(ptr), std::move(dependencies), std::move(usedScriptStrings), std::move(indirectAssetReferences))
|
||||
type, std::move(name), static_cast<void*>(ptr), std::move(dependencies), std::move(usedScriptStrings), std::move(indirectAssetReferences))
|
||||
{
|
||||
}
|
||||
|
||||
@ -101,7 +101,7 @@ public:
|
||||
std::vector<IndirectAssetReference> indirectAssetReferences,
|
||||
Zone* zone)
|
||||
: XAssetInfoGeneric(
|
||||
type, std::move(name), static_cast<void*>(ptr), std::move(dependencies), std::move(usedScriptStrings), std::move(indirectAssetReferences), zone)
|
||||
type, std::move(name), static_cast<void*>(ptr), std::move(dependencies), std::move(usedScriptStrings), std::move(indirectAssetReferences), zone)
|
||||
{
|
||||
}
|
||||
|
||||
|
11
test/ObjCommonTestUtils/NormalizedJson.cpp
Normal file
11
test/ObjCommonTestUtils/NormalizedJson.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "NormalizedJson.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using namespace nlohmann;
|
||||
|
||||
std::string JsonNormalized(const std::string& str0)
|
||||
{
|
||||
const json j0 = json::parse(str0);
|
||||
return j0.dump(4);
|
||||
}
|
5
test/ObjCommonTestUtils/NormalizedJson.h
Normal file
5
test/ObjCommonTestUtils/NormalizedJson.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string JsonNormalized(const std::string& str0);
|
558
test/ObjLoadingTests/Game/IW4/Material/LoaderMaterialIW4Test.cpp
Normal file
558
test/ObjLoadingTests/Game/IW4/Material/LoaderMaterialIW4Test.cpp
Normal file
@ -0,0 +1,558 @@
|
||||
#include "Game/IW4/Material/LoaderMaterialIW4.h"
|
||||
|
||||
#include "Game/IW4/CommonIW4.h"
|
||||
#include "Game/IW4/GameIW4.h"
|
||||
#include "SearchPath/MockSearchPath.h"
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <string>
|
||||
|
||||
using namespace IW4;
|
||||
using namespace Catch;
|
||||
using namespace std::literals;
|
||||
|
||||
namespace
|
||||
{
|
||||
void GivenImage(const std::string& name, AssetCreationContext& context, MemoryManager& memory)
|
||||
{
|
||||
auto* image = memory.Alloc<GfxImage>();
|
||||
image->name = memory.Dup(name.c_str());
|
||||
|
||||
AssetRegistration<AssetImage> registration(name);
|
||||
registration.SetAsset(image);
|
||||
context.AddAsset(std::move(registration));
|
||||
}
|
||||
|
||||
void GivenTechset(const std::string& name, AssetCreationContext& context, MemoryManager& memory)
|
||||
{
|
||||
auto* techset = memory.Alloc<MaterialTechniqueSet>();
|
||||
techset->name = memory.Dup(name.c_str());
|
||||
|
||||
AssetRegistration<AssetTechniqueSet> registration(name);
|
||||
registration.SetAsset(techset);
|
||||
context.AddAsset(std::move(registration));
|
||||
}
|
||||
|
||||
TEST_CASE("LoaderMaterial(IW4): Can parse material", "[iw4][material][assetloader]")
|
||||
{
|
||||
MockSearchPath searchPath;
|
||||
searchPath.AddFileData("materials/mc/ch_rubble01.json",
|
||||
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;
|
||||
AssetCreatorCollection creatorCollection(zone);
|
||||
IgnoredAssetLookup ignoredAssetLookup;
|
||||
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
|
||||
|
||||
GivenImage("~ch_rubble02_spc-r-74g-74b-74~1eb1f0d0", context, memory);
|
||||
GivenImage("ch_rubble01_nml", context, memory);
|
||||
GivenImage("ch_rubble01_col", context, memory);
|
||||
GivenTechset("mc_l_sm_r0c0n0s0", context, memory);
|
||||
|
||||
auto loader = CreateMaterialLoader(memory, searchPath);
|
||||
auto result = loader->CreateAsset("mc/ch_rubble01", context);
|
||||
REQUIRE(result.HasBeenSuccessful());
|
||||
|
||||
const auto* assetInfo = reinterpret_cast<XAssetInfo<Material>*>(result.GetAssetInfo());
|
||||
const auto* material = assetInfo->Asset();
|
||||
|
||||
REQUIRE(material->info.name == "mc/ch_rubble01"s);
|
||||
REQUIRE(material->info.gameFlags == 0x50);
|
||||
REQUIRE(material->info.sortKey == 1);
|
||||
REQUIRE(material->info.textureAtlasRowCount == 1);
|
||||
REQUIRE(material->info.textureAtlasColumnCount == 1);
|
||||
REQUIRE(material->info.surfaceTypeBits == 16);
|
||||
|
||||
constexpr int8_t expectedStateBitsEntry[]{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};
|
||||
REQUIRE(std::memcmp(material->stateBitsEntry, expectedStateBitsEntry, sizeof(expectedStateBitsEntry)) == 0);
|
||||
|
||||
REQUIRE(material->stateFlags == 121);
|
||||
REQUIRE(material->cameraRegion == CAMERA_REGION_LIT_OPAQUE);
|
||||
|
||||
REQUIRE(material->techniqueSet != nullptr);
|
||||
REQUIRE(material->techniqueSet->name != nullptr);
|
||||
REQUIRE(material->techniqueSet->name == "mc_l_sm_r0c0n0s0"s);
|
||||
|
||||
REQUIRE(material->textureCount == 3);
|
||||
REQUIRE(material->textureTable);
|
||||
|
||||
const auto& textureDef0 = material->textureTable[0];
|
||||
REQUIRE(textureDef0.nameHash == 0x34ecccb3);
|
||||
REQUIRE(textureDef0.nameStart == 's');
|
||||
REQUIRE(textureDef0.nameEnd == 'p');
|
||||
REQUIRE(textureDef0.samplerState.filter == TEXTURE_FILTER_ANISO2X);
|
||||
REQUIRE(textureDef0.samplerState.mipMap == SAMPLER_MIPMAP_ENUM_NEAREST);
|
||||
REQUIRE(textureDef0.samplerState.clampU == 0);
|
||||
REQUIRE(textureDef0.samplerState.clampV == 0);
|
||||
REQUIRE(textureDef0.samplerState.clampW == 0);
|
||||
REQUIRE(textureDef0.semantic == TS_SPECULAR_MAP);
|
||||
REQUIRE(textureDef0.u.image);
|
||||
REQUIRE(textureDef0.u.image->name);
|
||||
REQUIRE(textureDef0.u.image->name == "~ch_rubble02_spc-r-74g-74b-74~1eb1f0d0"s);
|
||||
|
||||
const auto& textureDef1 = material->textureTable[1];
|
||||
REQUIRE(textureDef1.nameHash == 0x59d30d0f);
|
||||
REQUIRE(textureDef1.nameStart == 'n');
|
||||
REQUIRE(textureDef1.nameEnd == 'p');
|
||||
REQUIRE(textureDef1.samplerState.filter == TEXTURE_FILTER_ANISO2X);
|
||||
REQUIRE(textureDef1.samplerState.mipMap == SAMPLER_MIPMAP_ENUM_NEAREST);
|
||||
REQUIRE(textureDef1.samplerState.clampU == 0);
|
||||
REQUIRE(textureDef1.samplerState.clampV == 0);
|
||||
REQUIRE(textureDef1.samplerState.clampW == 0);
|
||||
REQUIRE(textureDef1.semantic == TS_NORMAL_MAP);
|
||||
REQUIRE(textureDef1.u.image);
|
||||
REQUIRE(textureDef1.u.image->name);
|
||||
REQUIRE(textureDef1.u.image->name == "ch_rubble01_nml"s);
|
||||
|
||||
const auto& textureDef2 = material->textureTable[2];
|
||||
REQUIRE(textureDef2.nameHash == 0xa0ab1041);
|
||||
REQUIRE(textureDef2.nameStart == 'c');
|
||||
REQUIRE(textureDef2.nameEnd == 'p');
|
||||
REQUIRE(textureDef2.samplerState.filter == TEXTURE_FILTER_ANISO2X);
|
||||
REQUIRE(textureDef2.samplerState.mipMap == SAMPLER_MIPMAP_ENUM_NEAREST);
|
||||
REQUIRE(textureDef2.samplerState.clampU == 0);
|
||||
REQUIRE(textureDef2.samplerState.clampV == 0);
|
||||
REQUIRE(textureDef2.samplerState.clampW == 0);
|
||||
REQUIRE(textureDef2.semantic == TS_COLOR_MAP);
|
||||
REQUIRE(textureDef2.u.image);
|
||||
REQUIRE(textureDef2.u.image->name);
|
||||
REQUIRE(textureDef2.u.image->name == "ch_rubble01_col"s);
|
||||
|
||||
REQUIRE(material->constantCount == 2);
|
||||
REQUIRE(material->constantTable);
|
||||
|
||||
const auto& constantDef0 = material->constantTable[0];
|
||||
REQUIRE(constantDef0.nameHash == 0x3d9994dc);
|
||||
REQUIRE(strncmp(constantDef0.name, "envMapParms", std::extent_v<decltype(MaterialConstantDef::name)>) == 0);
|
||||
REQUIRE(constantDef0.literal.x == Approx(0.07f));
|
||||
REQUIRE(constantDef0.literal.y == Approx(0.46f));
|
||||
REQUIRE(constantDef0.literal.z == Approx(1.6f));
|
||||
REQUIRE(constantDef0.literal.w == Approx(2.0f));
|
||||
|
||||
const auto& constantDef1 = material->constantTable[1];
|
||||
REQUIRE(constantDef1.nameHash == 0xb60c3b3a);
|
||||
REQUIRE(strncmp(constantDef1.name, "colorTint", std::extent_v<decltype(MaterialConstantDef::name)>) == 0);
|
||||
REQUIRE(constantDef1.literal.x == Approx(1.0f));
|
||||
REQUIRE(constantDef1.literal.y == Approx(1.0f));
|
||||
REQUIRE(constantDef1.literal.z == Approx(1.0f));
|
||||
REQUIRE(constantDef1.literal.w == Approx(1.0f));
|
||||
|
||||
REQUIRE(material->stateBitsCount == 6);
|
||||
REQUIRE(material->stateBitsTable);
|
||||
|
||||
const auto& stateBits0 = material->stateBitsTable[0];
|
||||
REQUIRE(stateBits0.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits0.loadBits.structured.dstBlendRgb == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits0.loadBits.structured.blendOpRgb == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits0.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits0.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.cullFace == GFXS_CULL_BACK);
|
||||
REQUIRE(stateBits0.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits0.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits0.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits0.loadBits.structured.colorWriteRgb == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.colorWriteAlpha == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.gammaWrite == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.polymodeLine == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.depthWrite == 1);
|
||||
REQUIRE(stateBits0.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
REQUIRE(stateBits0.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilFrontEnabled == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilFrontPass == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilFrontFail == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilFrontZFail == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilFrontFunc == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilBackFunc == 0);
|
||||
|
||||
const auto& stateBits1 = material->stateBitsTable[1];
|
||||
REQUIRE(stateBits1.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits1.loadBits.structured.dstBlendRgb == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits1.loadBits.structured.blendOpRgb == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits1.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits1.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.cullFace == GFXS_CULL_BACK);
|
||||
REQUIRE(stateBits1.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits1.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits1.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits1.loadBits.structured.colorWriteRgb == 1);
|
||||
REQUIRE(stateBits1.loadBits.structured.colorWriteAlpha == 1);
|
||||
REQUIRE(stateBits1.loadBits.structured.gammaWrite == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.polymodeLine == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.depthWrite == 1);
|
||||
REQUIRE(stateBits1.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
REQUIRE(stateBits1.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilFrontEnabled == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilFrontPass == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilFrontFail == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilFrontZFail == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilFrontFunc == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilBackFunc == 0);
|
||||
|
||||
const auto& stateBits2 = material->stateBitsTable[2];
|
||||
REQUIRE(stateBits2.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits2.loadBits.structured.dstBlendRgb == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits2.loadBits.structured.blendOpRgb == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits2.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits2.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.cullFace == GFXS_CULL_BACK);
|
||||
REQUIRE(stateBits2.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits2.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits2.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits2.loadBits.structured.colorWriteRgb == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.colorWriteAlpha == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.gammaWrite == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.polymodeLine == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.depthWrite == 1);
|
||||
REQUIRE(stateBits2.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
REQUIRE(stateBits2.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_SHADOWMAP);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilFrontEnabled == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilFrontPass == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilFrontFail == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilFrontZFail == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilFrontFunc == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilBackFunc == 0);
|
||||
|
||||
const auto& stateBits3 = material->stateBitsTable[3];
|
||||
REQUIRE(stateBits3.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits3.loadBits.structured.dstBlendRgb == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits3.loadBits.structured.blendOpRgb == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits3.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits3.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.cullFace == GFXS_CULL_BACK);
|
||||
REQUIRE(stateBits3.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits3.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits3.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits3.loadBits.structured.colorWriteRgb == 1);
|
||||
REQUIRE(stateBits3.loadBits.structured.colorWriteAlpha == 1);
|
||||
REQUIRE(stateBits3.loadBits.structured.gammaWrite == 1);
|
||||
REQUIRE(stateBits3.loadBits.structured.polymodeLine == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.depthWrite == 1);
|
||||
REQUIRE(stateBits3.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
REQUIRE(stateBits3.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilFrontEnabled == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilFrontPass == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilFrontFail == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilFrontZFail == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilFrontFunc == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilBackFunc == 0);
|
||||
|
||||
const auto& stateBits4 = material->stateBitsTable[4];
|
||||
REQUIRE(stateBits4.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits4.loadBits.structured.dstBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits4.loadBits.structured.blendOpRgb == GFXS_BLENDOP_ADD);
|
||||
REQUIRE(stateBits4.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits4.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.cullFace == GFXS_CULL_BACK);
|
||||
REQUIRE(stateBits4.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits4.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits4.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits4.loadBits.structured.colorWriteRgb == 1);
|
||||
REQUIRE(stateBits4.loadBits.structured.colorWriteAlpha == 1);
|
||||
REQUIRE(stateBits4.loadBits.structured.gammaWrite == 1);
|
||||
REQUIRE(stateBits4.loadBits.structured.polymodeLine == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.depthWrite == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.depthTest == GFXS_DEPTHTEST_EQUAL);
|
||||
REQUIRE(stateBits4.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilFrontEnabled == 1);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilFrontPass == GFXS_STENCILOP_KEEP);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilFrontFail == GFXS_STENCILOP_KEEP);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilFrontZFail == GFXS_STENCILOP_KEEP);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilFrontFunc == GFXS_STENCILFUNC_EQUAL);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilBackFunc == 0);
|
||||
|
||||
const auto& stateBits5 = material->stateBitsTable[5];
|
||||
REQUIRE(stateBits5.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits5.loadBits.structured.dstBlendRgb == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits5.loadBits.structured.blendOpRgb == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits5.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits5.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.cullFace == GFXS_CULL_BACK);
|
||||
REQUIRE(stateBits5.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits5.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits5.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits5.loadBits.structured.colorWriteRgb == 1);
|
||||
REQUIRE(stateBits5.loadBits.structured.colorWriteAlpha == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.gammaWrite == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.polymodeLine == 1);
|
||||
REQUIRE(stateBits5.loadBits.structured.depthWrite == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
REQUIRE(stateBits5.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_2);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilFrontEnabled == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilFrontPass == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilFrontFail == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilFrontZFail == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilFrontFunc == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilBackFunc == 0);
|
||||
}
|
||||
} // namespace
|
611
test/ObjLoadingTests/Game/IW5/Material/LoaderMaterialIW5Test.cpp
Normal file
611
test/ObjLoadingTests/Game/IW5/Material/LoaderMaterialIW5Test.cpp
Normal file
@ -0,0 +1,611 @@
|
||||
#include "Game/IW5/Material/LoaderMaterialIW5.h"
|
||||
|
||||
#include "Game/IW5/CommonIW5.h"
|
||||
#include "Game/IW5/GameIW5.h"
|
||||
#include "SearchPath/MockSearchPath.h"
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <string>
|
||||
|
||||
using namespace IW5;
|
||||
using namespace Catch;
|
||||
using namespace std::literals;
|
||||
|
||||
namespace
|
||||
{
|
||||
void GivenImage(const std::string& name, AssetCreationContext& context, MemoryManager& memory)
|
||||
{
|
||||
auto* image = memory.Alloc<GfxImage>();
|
||||
image->name = memory.Dup(name.c_str());
|
||||
|
||||
AssetRegistration<AssetImage> registration(name);
|
||||
registration.SetAsset(image);
|
||||
context.AddAsset(std::move(registration));
|
||||
}
|
||||
|
||||
void GivenTechset(const std::string& name, AssetCreationContext& context, MemoryManager& memory)
|
||||
{
|
||||
auto* techset = memory.Alloc<MaterialTechniqueSet>();
|
||||
techset->name = memory.Dup(name.c_str());
|
||||
|
||||
AssetRegistration<AssetTechniqueSet> registration(name);
|
||||
registration.SetAsset(techset);
|
||||
context.AddAsset(std::move(registration));
|
||||
}
|
||||
|
||||
TEST_CASE("LoaderMaterial(IW5): Can parse material", "[iw5][material][assetloader]")
|
||||
{
|
||||
MockSearchPath searchPath;
|
||||
searchPath.AddFileData("materials/wc/me_metal_rust_02.json",
|
||||
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;
|
||||
AssetCreatorCollection creatorCollection(zone);
|
||||
IgnoredAssetLookup ignoredAssetLookup;
|
||||
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
|
||||
|
||||
GivenImage("~me_metal_rusty02_spc-rgb&me_~927de80f", context, memory);
|
||||
GivenImage("me_metal_rusty02_nml", context, memory);
|
||||
GivenImage("me_metal_rusty02_col", context, memory);
|
||||
GivenTechset("wc_l_sm_r0c0n0s0", context, memory);
|
||||
|
||||
auto loader = CreateMaterialLoader(memory, searchPath);
|
||||
auto result = loader->CreateAsset("wc/me_metal_rust_02", context);
|
||||
REQUIRE(result.HasBeenSuccessful());
|
||||
|
||||
const auto* assetInfo = reinterpret_cast<XAssetInfo<Material>*>(result.GetAssetInfo());
|
||||
const auto* material = assetInfo->Asset();
|
||||
|
||||
REQUIRE(material->info.name == "wc/me_metal_rust_02"s);
|
||||
REQUIRE(material->info.gameFlags == 0x52);
|
||||
REQUIRE(material->info.sortKey == 1);
|
||||
REQUIRE(material->info.textureAtlasRowCount == 1);
|
||||
REQUIRE(material->info.textureAtlasColumnCount == 1);
|
||||
REQUIRE(material->info.surfaceTypeBits == 4096);
|
||||
|
||||
constexpr int8_t expectedStateBitsEntry[]{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};
|
||||
REQUIRE(std::memcmp(material->stateBitsEntry, expectedStateBitsEntry, sizeof(expectedStateBitsEntry)) == 0);
|
||||
|
||||
REQUIRE(material->stateFlags == 59);
|
||||
REQUIRE(material->cameraRegion == CAMERA_REGION_LIT_OPAQUE);
|
||||
|
||||
REQUIRE(material->techniqueSet != nullptr);
|
||||
REQUIRE(material->techniqueSet->name != nullptr);
|
||||
REQUIRE(material->techniqueSet->name == "wc_l_sm_r0c0n0s0"s);
|
||||
|
||||
REQUIRE(material->textureCount == 3);
|
||||
REQUIRE(material->textureTable);
|
||||
|
||||
const auto& textureDef0 = material->textureTable[0];
|
||||
REQUIRE(textureDef0.nameHash == 0x34ecccb3);
|
||||
REQUIRE(textureDef0.nameStart == 's');
|
||||
REQUIRE(textureDef0.nameEnd == 'p');
|
||||
REQUIRE(textureDef0.samplerState.filter == TEXTURE_FILTER_ANISO2X);
|
||||
REQUIRE(textureDef0.samplerState.mipMap == SAMPLER_MIPMAP_ENUM_NEAREST);
|
||||
REQUIRE(textureDef0.samplerState.clampU == 0);
|
||||
REQUIRE(textureDef0.samplerState.clampV == 0);
|
||||
REQUIRE(textureDef0.samplerState.clampW == 0);
|
||||
REQUIRE(textureDef0.semantic == TS_SPECULAR_MAP);
|
||||
REQUIRE(textureDef0.u.image);
|
||||
REQUIRE(textureDef0.u.image->name);
|
||||
REQUIRE(textureDef0.u.image->name == "~me_metal_rusty02_spc-rgb&me_~927de80f"s);
|
||||
|
||||
const auto& textureDef1 = material->textureTable[1];
|
||||
REQUIRE(textureDef1.nameHash == 0x59d30d0f);
|
||||
REQUIRE(textureDef1.nameStart == 'n');
|
||||
REQUIRE(textureDef1.nameEnd == 'p');
|
||||
REQUIRE(textureDef1.samplerState.filter == TEXTURE_FILTER_ANISO2X);
|
||||
REQUIRE(textureDef1.samplerState.mipMap == SAMPLER_MIPMAP_ENUM_LINEAR);
|
||||
REQUIRE(textureDef1.samplerState.clampU == 0);
|
||||
REQUIRE(textureDef1.samplerState.clampV == 0);
|
||||
REQUIRE(textureDef1.samplerState.clampW == 0);
|
||||
REQUIRE(textureDef1.semantic == TS_NORMAL_MAP);
|
||||
REQUIRE(textureDef1.u.image);
|
||||
REQUIRE(textureDef1.u.image->name);
|
||||
REQUIRE(textureDef1.u.image->name == "me_metal_rusty02_nml"s);
|
||||
|
||||
const auto& textureDef2 = material->textureTable[2];
|
||||
REQUIRE(textureDef2.nameHash == 0xa0ab1041);
|
||||
REQUIRE(textureDef2.nameStart == 'c');
|
||||
REQUIRE(textureDef2.nameEnd == 'p');
|
||||
REQUIRE(textureDef2.samplerState.filter == TEXTURE_FILTER_ANISO2X);
|
||||
REQUIRE(textureDef2.samplerState.mipMap == SAMPLER_MIPMAP_ENUM_LINEAR);
|
||||
REQUIRE(textureDef2.samplerState.clampU == 0);
|
||||
REQUIRE(textureDef2.samplerState.clampV == 0);
|
||||
REQUIRE(textureDef2.samplerState.clampW == 0);
|
||||
REQUIRE(textureDef2.semantic == TS_COLOR_MAP);
|
||||
REQUIRE(textureDef2.u.image);
|
||||
REQUIRE(textureDef2.u.image->name);
|
||||
REQUIRE(textureDef2.u.image->name == "me_metal_rusty02_col"s);
|
||||
|
||||
REQUIRE(material->constantCount == 2);
|
||||
REQUIRE(material->constantTable);
|
||||
|
||||
const auto& constantDef0 = material->constantTable[0];
|
||||
REQUIRE(constantDef0.nameHash == 0x3d9994dc);
|
||||
REQUIRE(strncmp(constantDef0.name, "envMapParms", std::extent_v<decltype(MaterialConstantDef::name)>) == 0);
|
||||
REQUIRE(constantDef0.literal.x == Approx(0.07f));
|
||||
REQUIRE(constantDef0.literal.y == Approx(0.33f));
|
||||
REQUIRE(constantDef0.literal.z == Approx(1.4f));
|
||||
REQUIRE(constantDef0.literal.w == Approx(2.0f));
|
||||
|
||||
const auto& constantDef1 = material->constantTable[1];
|
||||
REQUIRE(constantDef1.nameHash == 0xb60c3b3a);
|
||||
REQUIRE(strncmp(constantDef1.name, "colorTint", std::extent_v<decltype(MaterialConstantDef::name)>) == 0);
|
||||
REQUIRE(constantDef1.literal.x == Approx(1.0f));
|
||||
REQUIRE(constantDef1.literal.y == Approx(1.0f));
|
||||
REQUIRE(constantDef1.literal.z == Approx(1.0f));
|
||||
REQUIRE(constantDef1.literal.w == Approx(1.0f));
|
||||
|
||||
REQUIRE(material->stateBitsCount == 7);
|
||||
REQUIRE(material->stateBitsTable);
|
||||
|
||||
const auto& stateBits0 = material->stateBitsTable[0];
|
||||
REQUIRE(stateBits0.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits0.loadBits.structured.dstBlendRgb == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits0.loadBits.structured.blendOpRgb == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits0.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits0.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.cullFace == GFXS_CULL_BACK);
|
||||
REQUIRE(stateBits0.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits0.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits0.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits0.loadBits.structured.colorWriteRgb == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.colorWriteAlpha == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.gammaWrite == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.polymodeLine == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.depthWrite == 1);
|
||||
REQUIRE(stateBits0.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
REQUIRE(stateBits0.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilFrontEnabled == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilFrontPass == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilFrontFail == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilFrontZFail == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilFrontFunc == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilBackFunc == 0);
|
||||
|
||||
const auto& stateBits1 = material->stateBitsTable[1];
|
||||
REQUIRE(stateBits1.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits1.loadBits.structured.dstBlendRgb == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits1.loadBits.structured.blendOpRgb == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits1.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits1.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.cullFace == GFXS_CULL_BACK);
|
||||
REQUIRE(stateBits1.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits1.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits1.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits1.loadBits.structured.colorWriteRgb == 1);
|
||||
REQUIRE(stateBits1.loadBits.structured.colorWriteAlpha == 1);
|
||||
REQUIRE(stateBits1.loadBits.structured.gammaWrite == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.polymodeLine == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.depthWrite == 1);
|
||||
REQUIRE(stateBits1.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
REQUIRE(stateBits1.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilFrontEnabled == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilFrontPass == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilFrontFail == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilFrontZFail == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilFrontFunc == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilBackFunc == 0);
|
||||
|
||||
const auto& stateBits2 = material->stateBitsTable[2];
|
||||
REQUIRE(stateBits2.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits2.loadBits.structured.dstBlendRgb == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits2.loadBits.structured.blendOpRgb == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits2.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits2.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.cullFace == GFXS_CULL_NONE);
|
||||
REQUIRE(stateBits2.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits2.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits2.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits2.loadBits.structured.colorWriteRgb == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.colorWriteAlpha == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.gammaWrite == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.polymodeLine == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.depthWrite == 1);
|
||||
REQUIRE(stateBits2.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
REQUIRE(stateBits2.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_SHADOWMAP);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilFrontEnabled == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilFrontPass == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilFrontFail == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilFrontZFail == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilFrontFunc == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilBackFunc == 0);
|
||||
|
||||
const auto& stateBits3 = material->stateBitsTable[3];
|
||||
REQUIRE(stateBits3.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits3.loadBits.structured.dstBlendRgb == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits3.loadBits.structured.blendOpRgb == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits3.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits3.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.cullFace == GFXS_CULL_NONE);
|
||||
REQUIRE(stateBits3.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits3.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits3.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits3.loadBits.structured.colorWriteRgb == 1);
|
||||
REQUIRE(stateBits3.loadBits.structured.colorWriteAlpha == 1);
|
||||
REQUIRE(stateBits3.loadBits.structured.gammaWrite == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.polymodeLine == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.depthWrite == 1);
|
||||
REQUIRE(stateBits3.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
REQUIRE(stateBits3.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilFrontEnabled == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilFrontPass == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilFrontFail == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilFrontZFail == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilFrontFunc == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilBackFunc == 0);
|
||||
|
||||
const auto& stateBits4 = material->stateBitsTable[4];
|
||||
REQUIRE(stateBits4.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits4.loadBits.structured.dstBlendRgb == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits4.loadBits.structured.blendOpRgb == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits4.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits4.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.cullFace == GFXS_CULL_BACK);
|
||||
REQUIRE(stateBits4.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits4.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits4.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits4.loadBits.structured.colorWriteRgb == 1);
|
||||
REQUIRE(stateBits4.loadBits.structured.colorWriteAlpha == 1);
|
||||
REQUIRE(stateBits4.loadBits.structured.gammaWrite == 1);
|
||||
REQUIRE(stateBits4.loadBits.structured.polymodeLine == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.depthWrite == 1);
|
||||
REQUIRE(stateBits4.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
REQUIRE(stateBits4.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilFrontEnabled == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilFrontPass == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilFrontFail == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilFrontZFail == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilFrontFunc == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilBackFunc == 0);
|
||||
|
||||
const auto& stateBits5 = material->stateBitsTable[5];
|
||||
REQUIRE(stateBits5.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits5.loadBits.structured.dstBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits5.loadBits.structured.blendOpRgb == GFXS_BLENDOP_ADD);
|
||||
REQUIRE(stateBits5.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits5.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.cullFace == GFXS_CULL_BACK);
|
||||
REQUIRE(stateBits5.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits5.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits5.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits5.loadBits.structured.colorWriteRgb == 1);
|
||||
REQUIRE(stateBits5.loadBits.structured.colorWriteAlpha == 1);
|
||||
REQUIRE(stateBits5.loadBits.structured.gammaWrite == 1);
|
||||
REQUIRE(stateBits5.loadBits.structured.polymodeLine == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.depthWrite == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.depthTest == GFXS_DEPTHTEST_EQUAL);
|
||||
REQUIRE(stateBits5.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_0);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilFrontEnabled == 1);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilFrontPass == GFXS_STENCILOP_KEEP);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilFrontFail == GFXS_STENCILOP_KEEP);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilFrontZFail == GFXS_STENCILOP_KEEP);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilFrontFunc == GFXS_STENCILFUNC_EQUAL);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits5.loadBits.structured.stencilBackFunc == 0);
|
||||
|
||||
const auto& stateBits6 = material->stateBitsTable[6];
|
||||
REQUIRE(stateBits6.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits6.loadBits.structured.dstBlendRgb == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits6.loadBits.structured.blendOpRgb == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits6.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits6.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits6.loadBits.structured.cullFace == GFXS_CULL_BACK);
|
||||
REQUIRE(stateBits6.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits6.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits6.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits6.loadBits.structured.colorWriteRgb == 1);
|
||||
REQUIRE(stateBits6.loadBits.structured.colorWriteAlpha == 0);
|
||||
REQUIRE(stateBits6.loadBits.structured.gammaWrite == 0);
|
||||
REQUIRE(stateBits6.loadBits.structured.polymodeLine == 1);
|
||||
REQUIRE(stateBits6.loadBits.structured.depthWrite == 0);
|
||||
REQUIRE(stateBits6.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits6.loadBits.structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
REQUIRE(stateBits6.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_2);
|
||||
REQUIRE(stateBits6.loadBits.structured.stencilFrontEnabled == 0);
|
||||
REQUIRE(stateBits6.loadBits.structured.stencilFrontPass == 0);
|
||||
REQUIRE(stateBits6.loadBits.structured.stencilFrontFail == 0);
|
||||
REQUIRE(stateBits6.loadBits.structured.stencilFrontZFail == 0);
|
||||
REQUIRE(stateBits6.loadBits.structured.stencilFrontFunc == 0);
|
||||
REQUIRE(stateBits6.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits6.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits6.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits6.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits6.loadBits.structured.stencilBackFunc == 0);
|
||||
}
|
||||
} // namespace
|
491
test/ObjLoadingTests/Game/T6/Material/LoaderMaterialT6Test.cpp
Normal file
491
test/ObjLoadingTests/Game/T6/Material/LoaderMaterialT6Test.cpp
Normal file
@ -0,0 +1,491 @@
|
||||
#include "Game/T6/Material/LoaderMaterialT6.h"
|
||||
|
||||
#include "Game/T6/CommonT6.h"
|
||||
#include "Game/T6/GameT6.h"
|
||||
#include "SearchPath/MockSearchPath.h"
|
||||
#include "Utils/MemoryManager.h"
|
||||
|
||||
#include <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <string>
|
||||
|
||||
using namespace T6;
|
||||
using namespace Catch;
|
||||
using namespace std::literals;
|
||||
|
||||
namespace
|
||||
{
|
||||
void GivenImage(const std::string& name, AssetCreationContext& context, MemoryManager& memory)
|
||||
{
|
||||
auto* image = memory.Alloc<GfxImage>();
|
||||
image->name = memory.Dup(name.c_str());
|
||||
|
||||
AssetRegistration<AssetImage> registration(name);
|
||||
registration.SetAsset(image);
|
||||
context.AddAsset(std::move(registration));
|
||||
}
|
||||
|
||||
void GivenTechset(const std::string& name, AssetCreationContext& context, MemoryManager& memory)
|
||||
{
|
||||
auto* techset = memory.Alloc<MaterialTechniqueSet>();
|
||||
techset->name = memory.Dup(name.c_str());
|
||||
|
||||
AssetRegistration<AssetTechniqueSet> registration(name);
|
||||
registration.SetAsset(techset);
|
||||
context.AddAsset(std::move(registration));
|
||||
}
|
||||
|
||||
TEST_CASE("LoaderMaterial(T6): Can parse material", "[t6][material][assetloader]")
|
||||
{
|
||||
MockSearchPath searchPath;
|
||||
searchPath.AddFileData("materials/wpc/metal_ac_duct.json",
|
||||
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;
|
||||
AssetCreatorCollection creatorCollection(zone);
|
||||
IgnoredAssetLookup ignoredAssetLookup;
|
||||
AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup);
|
||||
|
||||
GivenImage("~~-gmetal_ac_duct_s-rgb&~-rme~0a5a2e6f", context, memory);
|
||||
GivenImage("metal_ac_duct_n", context, memory);
|
||||
GivenImage("~-gmetal_ac_duct_c", context, memory);
|
||||
GivenTechset("wpc_lit_sm_r0c0n0s0_1zzj1138", context, memory);
|
||||
|
||||
auto loader = CreateMaterialLoader(memory, searchPath);
|
||||
auto result = loader->CreateAsset("wpc/metal_ac_duct", context);
|
||||
REQUIRE(result.HasBeenSuccessful());
|
||||
|
||||
const auto* assetInfo = reinterpret_cast<XAssetInfo<Material>*>(result.GetAssetInfo());
|
||||
const auto* material = assetInfo->Asset();
|
||||
|
||||
REQUIRE(material->info.name == "wpc/metal_ac_duct"s);
|
||||
REQUIRE(material->info.gameFlags == 0x52);
|
||||
REQUIRE(material->info.sortKey == 4);
|
||||
REQUIRE(material->info.textureAtlasRowCount == 1);
|
||||
REQUIRE(material->info.textureAtlasColumnCount == 1);
|
||||
REQUIRE(material->info.surfaceTypeBits == 4096);
|
||||
REQUIRE(material->info.layeredSurfaceTypes == 0x2000000Du);
|
||||
REQUIRE(material->info.surfaceFlags == 0xD00000u);
|
||||
REQUIRE(material->info.contents == 1);
|
||||
|
||||
constexpr int8_t expectedStateBitsEntry[]{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};
|
||||
REQUIRE(std::memcmp(material->stateBitsEntry, expectedStateBitsEntry, sizeof(expectedStateBitsEntry)) == 0);
|
||||
|
||||
REQUIRE(material->stateFlags == 121);
|
||||
REQUIRE(material->cameraRegion == CAMERA_REGION_LIT_OPAQUE);
|
||||
REQUIRE(material->probeMipBits == 0);
|
||||
|
||||
REQUIRE(material->techniqueSet != nullptr);
|
||||
REQUIRE(material->techniqueSet->name != nullptr);
|
||||
REQUIRE(material->techniqueSet->name == "wpc_lit_sm_r0c0n0s0_1zzj1138"s);
|
||||
|
||||
REQUIRE(material->textureCount == 3);
|
||||
REQUIRE(material->textureTable);
|
||||
|
||||
const auto& textureDef0 = material->textureTable[0];
|
||||
REQUIRE(textureDef0.nameHash == 0x34ecccb3);
|
||||
REQUIRE(textureDef0.nameStart == 's');
|
||||
REQUIRE(textureDef0.nameEnd == 'p');
|
||||
REQUIRE(textureDef0.samplerState.filter == TEXTURE_FILTER_ANISO4X);
|
||||
REQUIRE(textureDef0.samplerState.mipMap == SAMPLER_MIPMAP_ENUM_LINEAR);
|
||||
REQUIRE(textureDef0.samplerState.clampU == 0);
|
||||
REQUIRE(textureDef0.samplerState.clampV == 0);
|
||||
REQUIRE(textureDef0.samplerState.clampW == 0);
|
||||
REQUIRE(textureDef0.semantic == TS_SPECULAR_MAP);
|
||||
REQUIRE(textureDef0.isMatureContent == false);
|
||||
REQUIRE(textureDef0.image);
|
||||
REQUIRE(textureDef0.image->name);
|
||||
REQUIRE(textureDef0.image->name == "~~-gmetal_ac_duct_s-rgb&~-rme~0a5a2e6f"s);
|
||||
|
||||
const auto& textureDef1 = material->textureTable[1];
|
||||
REQUIRE(textureDef1.nameHash == 0x59d30d0f);
|
||||
REQUIRE(textureDef1.nameStart == 'n');
|
||||
REQUIRE(textureDef1.nameEnd == 'p');
|
||||
REQUIRE(textureDef1.samplerState.filter == TEXTURE_FILTER_ANISO4X);
|
||||
REQUIRE(textureDef1.samplerState.mipMap == SAMPLER_MIPMAP_ENUM_LINEAR);
|
||||
REQUIRE(textureDef1.samplerState.clampU == 0);
|
||||
REQUIRE(textureDef1.samplerState.clampV == 0);
|
||||
REQUIRE(textureDef1.samplerState.clampW == 0);
|
||||
REQUIRE(textureDef1.semantic == TS_NORMAL_MAP);
|
||||
REQUIRE(textureDef1.isMatureContent == false);
|
||||
REQUIRE(textureDef1.image);
|
||||
REQUIRE(textureDef1.image->name);
|
||||
REQUIRE(textureDef1.image->name == "metal_ac_duct_n"s);
|
||||
|
||||
const auto& textureDef2 = material->textureTable[2];
|
||||
REQUIRE(textureDef2.nameHash == 0xa0ab1041);
|
||||
REQUIRE(textureDef2.nameStart == 'c');
|
||||
REQUIRE(textureDef2.nameEnd == 'p');
|
||||
REQUIRE(textureDef2.samplerState.filter == TEXTURE_FILTER_ANISO4X);
|
||||
REQUIRE(textureDef2.samplerState.mipMap == SAMPLER_MIPMAP_ENUM_LINEAR);
|
||||
REQUIRE(textureDef2.samplerState.clampU == 0);
|
||||
REQUIRE(textureDef2.samplerState.clampV == 0);
|
||||
REQUIRE(textureDef2.samplerState.clampW == 0);
|
||||
REQUIRE(textureDef2.semantic == TS_COLOR_MAP);
|
||||
REQUIRE(textureDef2.isMatureContent == false);
|
||||
REQUIRE(textureDef2.image);
|
||||
REQUIRE(textureDef2.image->name);
|
||||
REQUIRE(textureDef2.image->name == "~-gmetal_ac_duct_c"s);
|
||||
|
||||
REQUIRE(material->constantCount == 1);
|
||||
REQUIRE(material->constantTable);
|
||||
|
||||
const auto& constantDef0 = material->constantTable[0];
|
||||
REQUIRE(constantDef0.nameHash == 0x9027e5c1);
|
||||
REQUIRE(strncmp(constantDef0.name, "occlusionAmount", std::extent_v<decltype(MaterialConstantDef::name)>) == 0);
|
||||
REQUIRE(constantDef0.literal.x == Approx(1.0f));
|
||||
REQUIRE(constantDef0.literal.y == Approx(1.0f));
|
||||
REQUIRE(constantDef0.literal.z == Approx(1.0f));
|
||||
REQUIRE(constantDef0.literal.w == Approx(1.0f));
|
||||
|
||||
REQUIRE(material->stateBitsCount == 5);
|
||||
REQUIRE(material->stateBitsTable);
|
||||
|
||||
const auto& stateBits0 = material->stateBitsTable[0];
|
||||
REQUIRE(stateBits0.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits0.loadBits.structured.dstBlendRgb == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits0.loadBits.structured.blendOpRgb == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits0.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits0.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.cullFace == GFXS_CULL_BACK);
|
||||
REQUIRE(stateBits0.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits0.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits0.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits0.loadBits.structured.colorWriteRgb == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.colorWriteAlpha == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.polymodeLine == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.depthWrite == 1);
|
||||
REQUIRE(stateBits0.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
REQUIRE(stateBits0.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilFrontEnabled == 1);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilFrontPass == GFXS_STENCILOP_KEEP);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilFrontFail == GFXS_STENCILOP_KEEP);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilFrontZFail == GFXS_STENCILOP_KEEP);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilFrontFunc == GFXS_STENCILFUNC_EQUAL);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits0.loadBits.structured.stencilBackFunc == 0);
|
||||
|
||||
const auto& stateBits1 = material->stateBitsTable[1];
|
||||
REQUIRE(stateBits1.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits1.loadBits.structured.dstBlendRgb == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits1.loadBits.structured.blendOpRgb == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits1.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits1.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.cullFace == GFXS_CULL_BACK);
|
||||
REQUIRE(stateBits1.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits1.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits1.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits1.loadBits.structured.colorWriteRgb == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.colorWriteAlpha == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.polymodeLine == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.depthWrite == 1);
|
||||
REQUIRE(stateBits1.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
REQUIRE(stateBits1.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_SHADOWMAP);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilFrontEnabled == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilFrontPass == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilFrontFail == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilFrontZFail == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilFrontFunc == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits1.loadBits.structured.stencilBackFunc == 0);
|
||||
|
||||
const auto& stateBits2 = material->stateBitsTable[2];
|
||||
REQUIRE(stateBits2.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits2.loadBits.structured.dstBlendRgb == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits2.loadBits.structured.blendOpRgb == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits2.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits2.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.cullFace == GFXS_CULL_BACK);
|
||||
REQUIRE(stateBits2.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits2.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits2.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits2.loadBits.structured.colorWriteRgb == 1);
|
||||
REQUIRE(stateBits2.loadBits.structured.colorWriteAlpha == 1);
|
||||
REQUIRE(stateBits2.loadBits.structured.polymodeLine == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.depthWrite == 1);
|
||||
REQUIRE(stateBits2.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
REQUIRE(stateBits2.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilFrontEnabled == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilFrontPass == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilFrontFail == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilFrontZFail == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilFrontFunc == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits2.loadBits.structured.stencilBackFunc == 0);
|
||||
|
||||
const auto& stateBits3 = material->stateBitsTable[3];
|
||||
REQUIRE(stateBits3.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits3.loadBits.structured.dstBlendRgb == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits3.loadBits.structured.blendOpRgb == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits3.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits3.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.cullFace == GFXS_CULL_BACK);
|
||||
REQUIRE(stateBits3.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits3.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits3.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits3.loadBits.structured.colorWriteRgb == 1);
|
||||
REQUIRE(stateBits3.loadBits.structured.colorWriteAlpha == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.polymodeLine == 1);
|
||||
REQUIRE(stateBits3.loadBits.structured.depthWrite == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
REQUIRE(stateBits3.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_2);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilFrontEnabled == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilFrontPass == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilFrontFail == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilFrontZFail == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilFrontFunc == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits3.loadBits.structured.stencilBackFunc == 0);
|
||||
|
||||
const auto& stateBits4 = material->stateBitsTable[4];
|
||||
REQUIRE(stateBits4.loadBits.structured.srcBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits4.loadBits.structured.dstBlendRgb == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits4.loadBits.structured.blendOpRgb == GFXS_BLENDOP_ADD);
|
||||
REQUIRE(stateBits4.loadBits.structured.alphaTestDisabled == 1);
|
||||
REQUIRE(stateBits4.loadBits.structured.alphaTest == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.cullFace == GFXS_CULL_BACK);
|
||||
REQUIRE(stateBits4.loadBits.structured.srcBlendAlpha == GFXS_BLEND_ONE);
|
||||
REQUIRE(stateBits4.loadBits.structured.dstBlendAlpha == GFXS_BLEND_ZERO);
|
||||
REQUIRE(stateBits4.loadBits.structured.blendOpAlpha == GFXS_BLENDOP_DISABLED);
|
||||
REQUIRE(stateBits4.loadBits.structured.colorWriteRgb == 1);
|
||||
REQUIRE(stateBits4.loadBits.structured.colorWriteAlpha == 1);
|
||||
REQUIRE(stateBits4.loadBits.structured.polymodeLine == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.depthWrite == 1);
|
||||
REQUIRE(stateBits4.loadBits.structured.depthTestDisabled == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.depthTest == GFXS_DEPTHTEST_LESSEQUAL);
|
||||
REQUIRE(stateBits4.loadBits.structured.polygonOffset == GFXS_POLYGON_OFFSET_1);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilFrontEnabled == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilFrontPass == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilFrontFail == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilFrontZFail == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilFrontFunc == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilBackEnabled == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilBackPass == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilBackFail == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilBackZFail == 0);
|
||||
REQUIRE(stateBits4.loadBits.structured.stencilBackFunc == 0);
|
||||
|
||||
REQUIRE(material->thermalMaterial == nullptr);
|
||||
}
|
||||
} // namespace
|
58
test/ObjWritingTests.lua
Normal file
58
test/ObjWritingTests.lua
Normal file
@ -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
|
552
test/ObjWritingTests/Game/IW4/Material/DumperMaterialIW4Test.cpp
Normal file
552
test/ObjWritingTests/Game/IW4/Material/DumperMaterialIW4Test.cpp
Normal file
@ -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 <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <string>
|
||||
|
||||
using namespace IW4;
|
||||
using namespace Catch;
|
||||
using namespace std::literals;
|
||||
|
||||
namespace
|
||||
{
|
||||
GfxImage* GivenImage(const std::string& name, MemoryManager& memory)
|
||||
{
|
||||
auto* image = memory.Alloc<GfxImage>();
|
||||
image->name = memory.Dup(name.c_str());
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
MaterialTechniqueSet* GivenTechset(const std::string& name, MemoryManager& memory)
|
||||
{
|
||||
auto* techset = memory.Alloc<MaterialTechniqueSet>();
|
||||
techset->name = memory.Dup(name.c_str());
|
||||
|
||||
return techset;
|
||||
}
|
||||
|
||||
void GivenMaterial(const std::string& name, AssetPool<Material>& pool, MemoryManager& memory)
|
||||
{
|
||||
auto* material = memory.Alloc<Material>();
|
||||
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<MaterialTextureDef>(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<MaterialConstantDef>(2);
|
||||
|
||||
auto& constantDef0 = material->constantTable[0];
|
||||
constantDef0.nameHash = 0x3d9994dc;
|
||||
strncpy(constantDef0.name, "envMapParms", std::extent_v<decltype(MaterialConstantDef::name)>);
|
||||
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<decltype(MaterialConstantDef::name)>);
|
||||
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<GfxStateBits>(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<XAssetInfo<Material>>(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<Material> 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
|
605
test/ObjWritingTests/Game/IW5/Material/DumperMaterialIW5Test.cpp
Normal file
605
test/ObjWritingTests/Game/IW5/Material/DumperMaterialIW5Test.cpp
Normal file
@ -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 <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <string>
|
||||
|
||||
using namespace IW5;
|
||||
using namespace Catch;
|
||||
using namespace std::literals;
|
||||
|
||||
namespace
|
||||
{
|
||||
GfxImage* GivenImage(const std::string& name, MemoryManager& memory)
|
||||
{
|
||||
auto* image = memory.Alloc<GfxImage>();
|
||||
image->name = memory.Dup(name.c_str());
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
MaterialTechniqueSet* GivenTechset(const std::string& name, MemoryManager& memory)
|
||||
{
|
||||
auto* techset = memory.Alloc<MaterialTechniqueSet>();
|
||||
techset->name = memory.Dup(name.c_str());
|
||||
|
||||
return techset;
|
||||
}
|
||||
|
||||
void GivenMaterial(const std::string& name, AssetPool<Material>& pool, MemoryManager& memory)
|
||||
{
|
||||
auto* material = memory.Alloc<Material>();
|
||||
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<MaterialTextureDef>(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<MaterialConstantDef>(2);
|
||||
|
||||
auto& constantDef0 = material->constantTable[0];
|
||||
constantDef0.nameHash = 0x3d9994dc;
|
||||
strncpy(constantDef0.name, "envMapParms", std::extent_v<decltype(MaterialConstantDef::name)>);
|
||||
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<decltype(MaterialConstantDef::name)>);
|
||||
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<GfxStateBits>(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<XAssetInfo<Material>>(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<Material> 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
|
484
test/ObjWritingTests/Game/T6/Material/DumperMaterialT6Test.cpp
Normal file
484
test/ObjWritingTests/Game/T6/Material/DumperMaterialT6Test.cpp
Normal file
@ -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 <catch2/catch_approx.hpp>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <string>
|
||||
|
||||
using namespace T6;
|
||||
using namespace Catch;
|
||||
using namespace std::literals;
|
||||
|
||||
namespace
|
||||
{
|
||||
GfxImage* GivenImage(const std::string& name, MemoryManager& memory)
|
||||
{
|
||||
auto* image = memory.Alloc<GfxImage>();
|
||||
image->name = memory.Dup(name.c_str());
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
MaterialTechniqueSet* GivenTechset(const std::string& name, MemoryManager& memory)
|
||||
{
|
||||
auto* techset = memory.Alloc<MaterialTechniqueSet>();
|
||||
techset->name = memory.Dup(name.c_str());
|
||||
|
||||
return techset;
|
||||
}
|
||||
|
||||
void GivenMaterial(const std::string& name, AssetPool<Material>& pool, MemoryManager& memory)
|
||||
{
|
||||
auto* material = memory.Alloc<Material>();
|
||||
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<MaterialTextureDef>(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<MaterialConstantDef>(1);
|
||||
|
||||
auto& constantDef0 = material->constantTable[0];
|
||||
constantDef0.nameHash = 0x9027e5c1;
|
||||
strncpy(constantDef0.name, "occlusionAmount", std::extent_v<decltype(MaterialConstantDef::name)>);
|
||||
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<GfxStateBits>(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<XAssetInfo<Material>>(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<Material> 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
|
@ -5,4 +5,8 @@ newoption {
|
||||
newoption {
|
||||
trigger = "debug-techset",
|
||||
description = "Activate additional debugging logic for Techset assets"
|
||||
}
|
||||
}
|
||||
newoption {
|
||||
trigger = "experimental-material-compilation",
|
||||
description = "Activate experimental material compilation support"
|
||||
}
|
||||
|
Reference in New Issue
Block a user