chore: replace material dumping with lib recommendation of serializing and deserializing json

This commit is contained in:
Jan 2024-02-25 21:34:46 +01:00
parent d3c3786d66
commit 1f6d0ab51a
No known key found for this signature in database
GPG Key ID: 44B581F78FF5C57C
12 changed files with 1367 additions and 1093 deletions

View File

@ -3,6 +3,7 @@ ObjCommon = {}
function ObjCommon:include(includes)
if includes:handle(self:name()) then
Common:include(includes)
json:include(includes)
minizip:include(includes)
includedirs {
path.join(ProjectFolder(), "ObjCommon")

View File

@ -0,0 +1,397 @@
#pragma once
#include "Game/T6/T6.h"
#include "Utils/JsonOptional.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_NON_INTRUSIVE(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_NON_INTRUSIVE(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())
{
out["name"] = in.name;
}
else
{
out["nameFragment"] = in.nameFragment;
out["nameHash"] = in.nameHash;
}
out["literal"] = in.literal;
}
inline void from_json(const nlohmann::json& in, JsonConstant& out)
{
in.at("name").get_to(out.name);
in.at("nameFragment").get_to(out.nameFragment);
in.at("nameHash").get_to(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_NON_INTRUSIVE(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())
{
out["name"] = in.name;
}
else
{
out["nameHash"] = in.nameHash;
out["nameStart"] = in.nameStart;
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)
{
in.at("name").get_to(out.name);
in.at("nameHash").get_to(out.nameHash);
in.at("nameStart").get_to(out.nameStart);
in.at("nameEnd").get_to(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_NON_INTRUSIVE(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_NON_INTRUSIVE(JsonMaterial,
gameFlags,
sortKey,
textureAtlas,
surfaceTypeBits,
layeredSurfaceTypes,
hashIndex,
surfaceFlags,
contents,
stateBitsEntry,
stateFlags,
cameraRegion,
probeMipBits,
techniqueSet,
textures,
constants,
stateBits,
thermalMaterial);
} // namespace T6

View File

@ -1,119 +0,0 @@
#pragma once
#include "Game/T6/CommonT6.h"
#include "Game/T6/T6.h"
namespace T6
{
inline const char* textureSemanticNames[]{
"2D", "function", "colorMap", "unused1", "unused2", "normalMap", "unused3", "unused4", "specularMap", "unused5",
"occlusionMap", "unused6", "color0Map", "color1Map", "color2Map", "color3Map", "color4Map", "color5Map", "color6Map", "color7Map",
"color8Map", "color9Map", "color10Map", "color11Map", "color12Map", "color13Map", "color14Map", "color15Map", "throwMap",
};
static_assert(std::extent_v<decltype(textureSemanticNames)> == TS_COUNT);
inline const char* cameraRegionNames[]{
"litOpaque",
"litTrans",
"litQuasiOpaque",
"emissiveOpaque",
"emissiveTrans",
"emissiveFx",
"lightMapOpaque",
"depthHack",
"unused",
"sonar",
"none",
};
static_assert(std::extent_v<decltype(cameraRegionNames)> == CAMERA_REGION_NONE + 1);
static const char* textureFilterNames[]{
"disabled",
"nearest",
"linear",
"aniso2x",
"aniso4x",
"compare",
};
static_assert(std::extent_v<decltype(textureFilterNames)> == TEXTURE_FILTER_COUNT);
static const char* samplerStateMipMapNames[]{
"disabled",
"nearest",
"linear",
};
static_assert(std::extent_v<decltype(samplerStateMipMapNames)> == SAMPLER_MIPMAP_ENUM_COUNT);
static const char* gameFlagNames[]{
"1",
"2",
"NO_MARKS",
"8",
"10",
"20",
"CASTS_SHADOW",
"80",
"100",
"200",
"400",
"800",
"1000",
};
inline const char* blendNames[]{
"disabled",
"zero",
"one",
"srccolor",
"invsrccolor",
"srcalpha",
"invsrcalpha",
"destalpha",
"invdestalpha",
"destcolor",
"invdestcolor",
};
static_assert(std::extent_v<decltype(blendNames)> == GFXS_BLEND_COUNT);
inline const char* blendOpNames[]{
"disabled",
"add",
"subtract",
"revsubtract",
"min",
"max",
};
static_assert(std::extent_v<decltype(blendOpNames)> == GFXS_BLENDOP_COUNT);
inline const char* polygonOffsetNames[]{
"offset0",
"offset1",
"offset2",
"offsetShadowmap",
};
static_assert(std::extent_v<decltype(polygonOffsetNames)> == GFXS_POLYGON_OFFSET_COUNT);
inline const char* stencilOpNames[]{
"keep",
"zero",
"replace",
"incrsat",
"decrsat",
"invert",
"incr",
"decr",
};
static_assert(std::extent_v<decltype(stencilOpNames)> == GFXS_STENCILOP_COUNT);
inline const char* stencilFuncNames[]{
"never",
"less",
"equal",
"lessequal",
"greater",
"notequal",
"greaterequal",
"always",
};
static_assert(std::extent_v<decltype(stencilFuncNames)> == GFXS_STENCILFUNC_COUNT);
} // namespace T6

View File

@ -0,0 +1,37 @@
#pragma once
#include <nlohmann/json.hpp>
#include <optional>
// partial specialization (full specialization works too)
namespace nlohmann
{
template<typename T> struct adl_serializer<std::optional<T>>
{
static void to_json(json& j, const std::optional<T>& opt)
{
if (!opt.has_value())
{
j = nullptr;
}
else
{
j = *opt; // this will call adl_serializer<T>::to_json which will
// find the free function to_json in T's namespace!
}
}
static void from_json(const json& j, std::optional<T>& opt)
{
if (j.is_null())
{
opt = std::nullopt;
}
else
{
opt = j.template get<T>(); // same as above, but with
// adl_serializer<T>::from_json
}
}
};
} // namespace nlohmann

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,245 @@
#include "JsonMaterialWriter.h"
#include "Game/T6/CommonT6.h"
#include "Game/T6/Material/JsonMaterial.h"
#include "MaterialConstantZoneState.h"
#include <iomanip>
#include <nlohmann/json.hpp>
using namespace nlohmann;
namespace T6
{
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;
};
void DumpMaterialAsJson(std::ostream& stream, const Material* material, AssetDumpingContext& context)
{
const JsonDumper dumper(context, stream);
dumper.Dump(material);
}
} // namespace T6

View File

@ -0,0 +1,11 @@
#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

View File

@ -0,0 +1,636 @@
#include "MaterialConstantZoneState.h"
#include "Game/T6/CommonT6.h"
#include "Game/T6/GameAssetPoolT6.h"
#include "Game/T6/GameT6.h"
#include "ObjWriting.h"
#include "Shader/D3D11ShaderAnalyser.h"
#include <chrono>
namespace T6
{
static constexpr const char* SAMPLER_STR = "Sampler";
static constexpr const char* GLOBALS_CBUFFER_NAME = "$Globals";
static constexpr const char* PER_OBJECT_CONSTS_CBUFFER_NAME = "PerObjectConsts";
const char* KNOWN_CONSTANT_NAMES[]{
"AngularVelocityScale",
"AnimSpeed",
"Background",
"BackgroundColor",
"BackgroundNoise",
"BakedLightingIntensity",
"BloodBrightness",
"BloodIntensity",
"BlurAmount",
"CapWidth",
"Char_Size",
"Char_Width",
"Coarseness",
"Color",
"ColorAmount",
"ColorBias",
"Color_Map_Noise",
"Color_Map_Scale",
"Color_Map_Size_Scale",
"DDXScale",
"DDYScale",
"DarkenAmount",
"DarkenPower",
"Detail_Amount",
"Detail_Normal_Tile",
"Diffuse_Normal_Height_Facing",
"Dimensions",
"DispersionAmount",
"Dolly",
"EdgeColor",
"EdgeHarshness",
"EdgeIntensity",
"EdgeMaxDist",
"EdgeMinDist",
"EdgeSize",
"Edge_Color_Multiplier",
"Emissive_Amount",
"EnemiesColor",
"Exposure",
"FPS",
"Fade_Distance",
"Fill_Direction",
"Fill_Direction2",
"FirstFrame",
"FlareIntensity",
"FlareScale",
"FlattenEdges",
"Flicker_Max",
"Flicker_Min",
"Flicker_Seed",
"Flicker_Speed",
"Font_Color",
"Gamma",
"GlossAmount",
"Gloss_Amount",
"Glow_Alt_Color",
"Glow_Color",
"Glow_Falloff",
"GradientColor",
"GradientMax",
"GradientMin",
"Grain_Amount",
"Grain_Color",
"Grid",
"Hardness",
"Heart_Rate_Offset",
"Heart_Rate_Scale",
"Highlight_1_Brightness",
"Highlight_1_Sharpness",
"Highlight_2_Brightness",
"Highlight_2_Sharpness",
"Highlight_2_Size",
"Hightlight_1_Size",
"Holo_Scale",
"LastFrame",
"Layer1Alpha",
"Layer1Depth",
"Layer1Offset",
"Layer1OffsetBobbleDelay",
"Layer1OffsetBobbleSpeedAndSize",
"Layer1Origin",
"Layer1Rotation",
"Layer1Scale",
"Layer1ScaleBobbleDelay",
"Layer1ScaleBobbleSpeedAndSize",
"Layer1Scroll",
"Layer2Alpha",
"Layer2Depth",
"Layer2Offset",
"Layer2OffsetBobbleDelay",
"Layer2OffsetBobbleSpeedAndSize",
"Layer2Origin",
"Layer2Rotation",
"Layer2Scale",
"Layer2ScaleBobbleDelay",
"Layer2ScaleBobbleSpeedAndSize",
"Layer2Scroll",
"Layer3Alpha",
"Layer3Depth",
"Layer3Offset",
"Layer3Origin",
"Layer3Rotation",
"Layer3Scale",
"Layer3Scroll",
"Layer4Alpha",
"Layer4Depth",
"Layer4Offset",
"Layer4Origin",
"Layer4Rotation",
"Layer4Scale",
"Layer4Scroll",
"LineColor",
"LineNoise",
"LineWidth",
"MaxDepth",
"MaxFlickerColor",
"MaxPulseDepth",
"MaxResolution",
"Max_Color",
"Maximum_Distance",
"Midlayer_Depth",
"MinDepth",
"MinFlickerColor",
"MinResolution",
"MinStatic",
"MinVelocityFraction",
"Min_Color",
"Min_Player_Intensity",
"MomentumColor",
"NegativeColor",
"NoisePower",
"Noise_Scale",
"NormalHeightMultiplier",
"Normal_Detail_Height",
"Normal_Detail_Scale",
"Normal_Map_Size_Scale",
"Normal_Variance_Scale",
"NumFrames",
"Outline_Lookup_Scale",
"OverallAmount",
"OverallBrightness",
"Overlay_Color",
"P1",
"P2",
"Padding",
"Player_Color_Multiplier",
"Player_Lookup_Scale",
"PositiveColor",
"Power",
"PulseColor",
"PulseInterval",
"PulseTime",
"Pulse_Color_Multiplier",
"Pulse_Lookup_Scale",
"Radius",
"ReflectionAmount",
"Reflection_Amount",
"Reflection_Blur",
"Reticle_Alt_Color",
"Reticle_Color",
"Row_Chars_",
"Scale",
"ScanlineColor",
"ScanlineIntensity",
"ScanlineOffset",
"ScanlinePower",
"ScanlineSpeed",
"ScatterAmount",
"ScatterSize",
"SceneNoise",
"SparkleBrightness",
"SparkleDensity",
"SparklePower",
"SparkleProbeAmount",
"SparkleScale",
"SparkleSpecAmount",
"SparkleWash",
"SpecGloss_Map_Size_Scale",
"SpecularAmount",
"SpecularColor",
"Specular_Amount",
"Specular_Decay_Threshold",
"Speed",
"StaticAmount",
"StaticLookupSpeed",
"StaticLookupX",
"StaticScale",
"Static_Size",
"Static_amount",
"TearLookupMaxX",
"TearLookupMinX",
"TearLookupSpeed",
"TearMultiplier",
"TearPower",
"Thickness",
"TickMarkColorAndHarshness",
"Tint",
"VelocityScale",
"VignetteMultiplier",
"VignettePower",
"WarpAmount",
"WarpHeight",
"WarpScale",
"WarpSpeed",
"WashOut",
"WashoutMultiply",
"WaterDirection",
"WaterHeight",
"WaterRefraction",
"WaterScale1",
"WaterScale2",
"WaterSpeed1",
"WaterSpeed2",
"Zoom",
"alphaDissolveParms",
"alphaRevealParms",
"alphaRevealParms1",
"alphaRevealParms2",
"alphaRevealParms3",
"alphaRevealParms4",
"clipSpaceLookupOffset",
"clipSpaceLookupScale",
"cloudsFeather",
"cloudsHeights",
"cloudsUVMad1",
"cloudsUVMad2",
"cloudsUVMul1",
"cloudsUVMul2",
"codeMeshArg",
"colorDetailScale",
"colorObjMax",
"colorObjMaxBaseBlend",
"colorObjMin",
"colorObjMinBaseBlend",
"colorTint",
"debugBumpmap",
"debugPerformance",
"detailScale",
"detailScale1",
"detailScale2",
"detailScale3",
"detailScale4",
"distortionScale",
"dofEquationScene",
"dofEquationViewModelAndFarBlur",
"dofLerpBias",
"dofLerpDownBias",
"dofLerpDownScale",
"dofLerpScale",
"dofLerpUpBias",
"dofLerpUpScale",
"dofRowDelta",
"eyeOffsetParms",
"falloffBeginColor",
"falloffEndColor",
"falloffParms",
"featherParms",
"flagParams",
"framebufferRead",
"gameTime",
"hdrAmount",
"inverseTransposeWorldMatrix",
"inverseTransposeWorldViewMatrix",
"inverseWorldMatrix",
"inverseWorldViewMatrix",
"motionblurDirectionAndMagnitude",
"occlusionAmount",
"occlusionAmount1",
"occlusionAmount2",
"occlusionAmount3",
"occlusionAmount4",
"particleCloudColor",
"particleCloudMatrix",
"particleCloudVelWorld",
"resizeParams1",
"resizeParams2",
"scaleRGB",
"scriptVector0",
"scriptVector1",
"scriptVector2",
"scriptVector3",
"scriptVector4",
"scriptVector5",
"scriptVector6",
"scriptVector7",
"skyBoxCloudWeights",
"skyBoxRotationSize",
"skyColorParms",
"spotLightWeight",
"treeCanopyLightingParms",
"treeCanopyScatterColor",
"treeCanopySwayParms",
"ui3dUVSetup0",
"ui3dUVSetup1",
"ui3dUVSetup2",
"ui3dUVSetup3",
"ui3dUVSetup4",
"ui3dUVSetup5",
"uvAnimParms",
"uvScroll",
"viewMatrix",
"weaponParam0",
"weaponParam1",
"weaponParam2",
"weaponParam3",
"weaponParam4",
"weaponParam5",
"weaponParam6",
"weaponParam7",
"weaponParam8",
"weaponParam9",
"worldViewMatrix",
"worldViewProjectionMatrix",
};
const char* KNOWN_TEXTURE_DEF_NAMES[]{
"AddMap",
"Blip_Mask",
"BlockNoise",
"CS_Z_buffer",
"Camo_Detail_Map",
"Color_Map",
"CompassMap",
"Detail_Map",
"Diffuse",
"Diffuse_Map",
"DpadTexture",
"FontTextutre",
"Grain_Map",
"GridTexture",
"GrimeMap",
"Heart_Rate_Image",
"Hologram_Diffuse",
"Image",
"Layer1Map",
"Layer2Map",
"Layer3Map",
"Layer4Map",
"Lookup",
"Lookup2",
"LookupMap",
"Mask",
"Noise",
"Noise_Texture",
"NormalDetailMap",
"Normal_Detail_Map",
"Normal_Map",
"Overlay_Map",
"Reflection_Mask",
"Reveal_Map",
"Rim_Color_Mask",
"Rim_Specular_Mask",
"Rim_Occlusion_Mask",
"Scanline",
"SparkleMap",
"SpecularAndGloss",
"SpecularAndGloss2",
"Specular_Color_Map",
"Specular_Gloss_Map",
"Specular_Map",
"SpotShadowSamplerState",
"SpotShadowState",
"SpriteMap",
"Static",
"StaticMap",
"Static_Noise_Map",
"SunShadowSamplerState",
"SunShadowState",
"Surface_Normal_Map",
"ThermalMapMask",
"Thermal_Gradient",
"Thermal_Map",
"TickMarkMaterial",
"Tile",
"WarpMap",
"WaterNormalMap",
"Weapon_Normal_Map",
"Weapon_Specular_Map",
"Wireframe",
"ZBuffer_Map",
"attenuation",
"attenuationSampler",
"baseLut2D",
"baseLut2DSampler",
"cinematicA",
"cinematicASampler",
"cinematicCb",
"cinematicCbSampler",
"cinematicCr",
"cinematicCrSampler",
"cinematicY",
"cinematicYSampler",
"codeTexture0",
"codeTexture1",
"codeTexture2",
"color",
"colorDetailMap",
"colorDetailMapSampler",
"colorMap",
"colorMap1",
"colorMap2",
"colorMap2D",
"colorMapPostSun",
"colorMapPostSunSampler",
"colorMapSampler",
"colorMapSampler1",
"colorMapSampler2",
"colorSampler",
"detailMap",
"detailMapSampler",
"dlightAttenuation",
"dlightAttenuationSampler",
"floatZ",
"floatZSampler",
"imageSampler",
"lightmapSamplerSecondary",
"lightmapSecondary",
"lut2D",
"lut2DSampler",
"lut3D",
"lut3DSampler",
"missileCam",
"missileCamSampler",
"modelLighting",
"modelLightingSampler",
"normalMap",
"normalMap1",
"normalMap2",
"normalMapSampler",
"normalMapSampler1",
"normalMapSampler2",
"occlusionMap",
"occlusionMapSampler",
"occMap",
"occMapSampler",
"outdoorMap",
"outdoorMapSampler",
"radiantDiffuseMap",
"rawFloatZ",
"rawFloatZSampler",
"reflectionProbe",
"reflectionProbeSampler",
"shadowmapSamplerSpot",
"shadowmapSamplerSun",
"shadowmapSpot",
"shadowmapSun",
"sonarColor",
"sonarColorSampler",
"sonarDepth",
"sonarDepthSampler",
"source",
"specularMap",
"specularMap1",
"specularMap2",
"specularMapSampler",
"specularMapSampler1",
"specularMapSampler2",
"stencil",
"stencilSampler",
"ui3d",
"ui3dSampler",
};
void MaterialConstantZoneState::ExtractNamesFromZone()
{
if (ObjWriting::Configuration.Verbose)
std::cout << "Building material constant name lookup...\n";
const auto begin = std::chrono::high_resolution_clock::now();
AddStaticKnownNames();
for (const auto* zone : g_GameT6.GetZones())
{
const auto* t6AssetPools = dynamic_cast<const GameAssetPoolT6*>(zone->m_pools.get());
if (!t6AssetPools)
return;
for (const auto* techniqueSetInfo : *t6AssetPools->m_technique_set)
{
const auto* techniqueSet = techniqueSetInfo->Asset();
for (const auto* technique : techniqueSet->techniques)
{
if (technique)
ExtractNamesFromTechnique(technique);
}
}
}
const auto end = std::chrono::high_resolution_clock::now();
if (ObjWriting::Configuration.Verbose)
{
const auto durationInMs = std::chrono::duration_cast<std::chrono::milliseconds>(end - begin);
std::cout << "Built material constant name lookup in " << durationInMs.count() << "ms: " << m_constant_names_from_shaders.size()
<< " constant names; " << m_texture_def_names_from_shaders.size() << " texture def names\n";
}
}
bool MaterialConstantZoneState::GetConstantName(const unsigned hash, std::string& constantName) const
{
const auto existingConstantName = m_constant_names_from_shaders.find(hash);
if (existingConstantName != m_constant_names_from_shaders.end())
{
constantName = existingConstantName->second;
return true;
}
return false;
}
bool MaterialConstantZoneState::GetTextureDefName(const unsigned hash, std::string& textureDefName) const
{
const auto existingTextureDefName = m_texture_def_names_from_shaders.find(hash);
if (existingTextureDefName != m_texture_def_names_from_shaders.end())
{
textureDefName = existingTextureDefName->second;
return true;
}
return false;
}
void MaterialConstantZoneState::ExtractNamesFromTechnique(const MaterialTechnique* technique)
{
const auto existingTechnique = m_dumped_techniques.find(technique);
if (existingTechnique != m_dumped_techniques.end())
return;
m_dumped_techniques.emplace(technique);
for (auto passIndex = 0u; passIndex < technique->passCount; passIndex++)
{
const auto& pass = technique->passArray[passIndex];
if (pass.vertexShader && pass.vertexShader->prog.loadDef.program)
ExtractNamesFromShader(pass.vertexShader->prog.loadDef.program, pass.vertexShader->prog.loadDef.programSize);
if (pass.pixelShader && pass.pixelShader->prog.loadDef.program)
ExtractNamesFromShader(pass.pixelShader->prog.loadDef.program, pass.pixelShader->prog.loadDef.programSize);
}
}
void MaterialConstantZoneState::ExtractNamesFromShader(const char* shader, const size_t shaderSize)
{
const auto shaderInfo = d3d11::ShaderAnalyser::GetShaderInfo(reinterpret_cast<const uint8_t*>(shader), shaderSize);
if (!shaderInfo)
return;
const auto globalsConstantBuffer = std::ranges::find_if(std::as_const(shaderInfo->m_constant_buffers),
[](const d3d11::ConstantBuffer& constantBuffer)
{
return constantBuffer.m_name == GLOBALS_CBUFFER_NAME;
});
const auto perObjectConsts = std::ranges::find_if(std::as_const(shaderInfo->m_constant_buffers),
[](const d3d11::ConstantBuffer& constantBuffer)
{
return constantBuffer.m_name == PER_OBJECT_CONSTS_CBUFFER_NAME;
});
if (globalsConstantBuffer != shaderInfo->m_constant_buffers.end())
{
for (const auto& variable : globalsConstantBuffer->m_variables)
AddConstantName(variable.m_name);
}
if (perObjectConsts != shaderInfo->m_constant_buffers.end())
{
for (const auto& variable : perObjectConsts->m_variables)
AddConstantName(variable.m_name);
}
for (const auto& boundResource : shaderInfo->m_bound_resources)
{
if (boundResource.m_type == d3d11::BoundResourceType::SAMPLER || boundResource.m_type == d3d11::BoundResourceType::TEXTURE)
{
if (AddTextureDefName(boundResource.m_name))
{
const auto samplerPos = boundResource.m_name.rfind(SAMPLER_STR);
if (samplerPos != std::string::npos)
{
auto nameWithoutSamplerStr = boundResource.m_name;
nameWithoutSamplerStr.erase(samplerPos, std::char_traits<char>::length(SAMPLER_STR));
AddTextureDefName(std::move(nameWithoutSamplerStr));
}
}
}
}
}
void MaterialConstantZoneState::AddStaticKnownNames()
{
for (const auto* knownConstantName : KNOWN_CONSTANT_NAMES)
AddConstantName(knownConstantName);
for (const auto* knownTextureDefName : KNOWN_TEXTURE_DEF_NAMES)
AddTextureDefName(knownTextureDefName);
}
void MaterialConstantZoneState::AddConstantName(std::string constantName)
{
const auto hash = Common::R_HashString(constantName.c_str(), 0);
if (m_constant_names_from_shaders.contains(hash))
return;
m_constant_names_from_shaders.emplace(hash, std::move(constantName));
}
bool MaterialConstantZoneState::AddTextureDefName(std::string textureDefName)
{
const auto hash = Common::R_HashString(textureDefName.c_str(), 0);
if (m_texture_def_names_from_shaders.contains(hash))
return false;
m_texture_def_names_from_shaders.emplace(hash, std::move(textureDefName));
return true;
}
} // namespace T6

View File

@ -0,0 +1,30 @@
#pragma once
#include "Dumping/IZoneAssetDumperState.h"
#include "Game/T6/T6.h"
#include <string>
#include <unordered_map>
#include <unordered_set>
namespace T6
{
class MaterialConstantZoneState final : public IZoneAssetDumperState
{
public:
void ExtractNamesFromZone();
bool GetConstantName(unsigned hash, std::string& constantName) const;
bool GetTextureDefName(unsigned hash, std::string& textureDefName) const;
private:
void ExtractNamesFromTechnique(const MaterialTechnique* technique);
void ExtractNamesFromShader(const char* shader, size_t shaderSize);
void AddStaticKnownNames();
void AddConstantName(std::string constantName);
bool AddTextureDefName(std::string textureDefName);
std::unordered_set<const MaterialTechnique*> m_dumped_techniques;
std::unordered_map<unsigned, std::string> m_constant_names_from_shaders;
std::unordered_map<unsigned, std::string> m_texture_def_names_from_shaders;
};
} // namespace T6