From 1f6d0ab51ae3defbc056cd44519195562cf507d7 Mon Sep 17 00:00:00 2001 From: Jan Date: Sun, 25 Feb 2024 21:34:46 +0100 Subject: [PATCH 1/3] chore: replace material dumping with lib recommendation of serializing and deserializing json --- src/ObjCommon.lua | 1 + .../Game/T6/Material/JsonMaterial.cpp | 0 src/ObjCommon/Game/T6/Material/JsonMaterial.h | 397 +++++++ src/ObjCommon/Game/T6/MaterialConstantsT6.h | 119 --- src/ObjCommon/Utils/JsonOptional.h | 37 + .../Game/T6/Material/JsonMaterialLoader.cpp | 0 .../Game/T6/Material/JsonMaterialLoader.h | 0 .../T6/AssetDumpers/AssetDumperMaterial.cpp | 984 +----------------- .../Game/T6/Material/JsonMaterialWriter.cpp | 245 +++++ .../Game/T6/Material/JsonMaterialWriter.h | 11 + .../T6/Material/MaterialConstantZoneState.cpp | 636 +++++++++++ .../T6/Material/MaterialConstantZoneState.h | 30 + 12 files changed, 1367 insertions(+), 1093 deletions(-) create mode 100644 src/ObjCommon/Game/T6/Material/JsonMaterial.cpp create mode 100644 src/ObjCommon/Game/T6/Material/JsonMaterial.h delete mode 100644 src/ObjCommon/Game/T6/MaterialConstantsT6.h create mode 100644 src/ObjCommon/Utils/JsonOptional.h create mode 100644 src/ObjLoading/Game/T6/Material/JsonMaterialLoader.cpp create mode 100644 src/ObjLoading/Game/T6/Material/JsonMaterialLoader.h create mode 100644 src/ObjWriting/Game/T6/Material/JsonMaterialWriter.cpp create mode 100644 src/ObjWriting/Game/T6/Material/JsonMaterialWriter.h create mode 100644 src/ObjWriting/Game/T6/Material/MaterialConstantZoneState.cpp create mode 100644 src/ObjWriting/Game/T6/Material/MaterialConstantZoneState.h diff --git a/src/ObjCommon.lua b/src/ObjCommon.lua index 2d591bbef..df91eae8f 100644 --- a/src/ObjCommon.lua +++ b/src/ObjCommon.lua @@ -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") diff --git a/src/ObjCommon/Game/T6/Material/JsonMaterial.cpp b/src/ObjCommon/Game/T6/Material/JsonMaterial.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/src/ObjCommon/Game/T6/Material/JsonMaterial.h b/src/ObjCommon/Game/T6/Material/JsonMaterial.h new file mode 100644 index 000000000..a1f304707 --- /dev/null +++ b/src/ObjCommon/Game/T6/Material/JsonMaterial.h @@ -0,0 +1,397 @@ +#pragma once + +#include "Game/T6/T6.h" +#include "Utils/JsonOptional.h" + +#include +#include +#include +#include +#include + +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 stencilFront; + std::optional 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 name; + std::optional nameFragment; + std::optional nameHash; + std::vector 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 name; + std::optional nameHash; + std::optional nameStart; + std::optional 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 gameFlags; + unsigned sortKey; + std::optional textureAtlas; + unsigned surfaceTypeBits; + unsigned layeredSurfaceTypes; + unsigned hashIndex; + unsigned surfaceFlags; + unsigned contents; + std::vector stateBitsEntry; + unsigned stateFlags; + GfxCameraRegionType cameraRegion; + uint8_t probeMipBits; + std::string techniqueSet; + std::vector textures; + std::vector constants; + std::vector stateBits; + std::optional 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 diff --git a/src/ObjCommon/Game/T6/MaterialConstantsT6.h b/src/ObjCommon/Game/T6/MaterialConstantsT6.h deleted file mode 100644 index 393d51789..000000000 --- a/src/ObjCommon/Game/T6/MaterialConstantsT6.h +++ /dev/null @@ -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 == TS_COUNT); - - inline const char* cameraRegionNames[]{ - "litOpaque", - "litTrans", - "litQuasiOpaque", - "emissiveOpaque", - "emissiveTrans", - "emissiveFx", - "lightMapOpaque", - "depthHack", - "unused", - "sonar", - "none", - }; - static_assert(std::extent_v == CAMERA_REGION_NONE + 1); - - static const char* textureFilterNames[]{ - "disabled", - "nearest", - "linear", - "aniso2x", - "aniso4x", - "compare", - }; - static_assert(std::extent_v == TEXTURE_FILTER_COUNT); - - static const char* samplerStateMipMapNames[]{ - "disabled", - "nearest", - "linear", - }; - static_assert(std::extent_v == 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 == GFXS_BLEND_COUNT); - - inline const char* blendOpNames[]{ - "disabled", - "add", - "subtract", - "revsubtract", - "min", - "max", - }; - static_assert(std::extent_v == GFXS_BLENDOP_COUNT); - - inline const char* polygonOffsetNames[]{ - "offset0", - "offset1", - "offset2", - "offsetShadowmap", - }; - static_assert(std::extent_v == GFXS_POLYGON_OFFSET_COUNT); - - inline const char* stencilOpNames[]{ - "keep", - "zero", - "replace", - "incrsat", - "decrsat", - "invert", - "incr", - "decr", - }; - static_assert(std::extent_v == GFXS_STENCILOP_COUNT); - - inline const char* stencilFuncNames[]{ - "never", - "less", - "equal", - "lessequal", - "greater", - "notequal", - "greaterequal", - "always", - }; - static_assert(std::extent_v == GFXS_STENCILFUNC_COUNT); -} // namespace T6 diff --git a/src/ObjCommon/Utils/JsonOptional.h b/src/ObjCommon/Utils/JsonOptional.h new file mode 100644 index 000000000..df1cef8ae --- /dev/null +++ b/src/ObjCommon/Utils/JsonOptional.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +// partial specialization (full specialization works too) +namespace nlohmann +{ + template struct adl_serializer> + { + static void to_json(json& j, const std::optional& opt) + { + if (!opt.has_value()) + { + j = nullptr; + } + else + { + j = *opt; // this will call adl_serializer::to_json which will + // find the free function to_json in T's namespace! + } + } + + static void from_json(const json& j, std::optional& opt) + { + if (j.is_null()) + { + opt = std::nullopt; + } + else + { + opt = j.template get(); // same as above, but with + // adl_serializer::from_json + } + } + }; +} // namespace nlohmann diff --git a/src/ObjLoading/Game/T6/Material/JsonMaterialLoader.cpp b/src/ObjLoading/Game/T6/Material/JsonMaterialLoader.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/src/ObjLoading/Game/T6/Material/JsonMaterialLoader.h b/src/ObjLoading/Game/T6/Material/JsonMaterialLoader.h new file mode 100644 index 000000000..e69de29bb diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperMaterial.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperMaterial.cpp index 29b663e8a..b967a41ec 100644 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperMaterial.cpp +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperMaterial.cpp @@ -1,990 +1,27 @@ #include "AssetDumperMaterial.h" -#include "Game/T6/CommonT6.h" -#include "Game/T6/GameAssetPoolT6.h" -#include "Game/T6/GameT6.h" -#include "Game/T6/MaterialConstantsT6.h" -#include "Game/T6/TechsetConstantsT6.h" -#include "ObjWriting.h" -#include "Shader/D3D11ShaderAnalyser.h" +#include "Game/T6/Material/JsonMaterialWriter.h" +#include "Game/T6/Material/MaterialConstantZoneState.h" -#include -#include -#include -#include +#include +#include +#include using namespace T6; -using namespace nlohmann; - -namespace T6::material -{ -#define KNOWN_HASH(strValue) \ - { \ - Common::R_HashString(strValue, 0), strValue \ - } - - 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", - }; - - class MaterialConstantZoneState final : public IZoneAssetDumperState - { - public: - void 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(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(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 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 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; - } - - private: - void 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 ExtractNamesFromShader(const char* shader, const size_t shaderSize) - { - const auto shaderInfo = d3d11::ShaderAnalyser::GetShaderInfo(reinterpret_cast(shader), shaderSize); - if (!shaderInfo) - return; - - const auto globalsConstantBuffer = std::find_if(shaderInfo->m_constant_buffers.cbegin(), - shaderInfo->m_constant_buffers.cend(), - [](const d3d11::ConstantBuffer& constantBuffer) - { - return constantBuffer.m_name == GLOBALS_CBUFFER_NAME; - }); - - const auto perObjectConsts = std::find_if(shaderInfo->m_constant_buffers.cbegin(), - shaderInfo->m_constant_buffers.cend(), - [](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::length(SAMPLER_STR)); - AddTextureDefName(std::move(nameWithoutSamplerStr)); - } - } - } - } - } - - void AddStaticKnownNames() - { - for (const auto* knownConstantName : KNOWN_CONSTANT_NAMES) - AddConstantName(knownConstantName); - for (const auto* knownTextureDefName : KNOWN_TEXTURE_DEF_NAMES) - AddTextureDefName(knownTextureDefName); - } - - void AddConstantName(std::string constantName) - { - const auto hash = Common::R_HashString(constantName.c_str(), 0); - if (m_constant_names_from_shaders.find(hash) != m_constant_names_from_shaders.end()) - return; - - m_constant_names_from_shaders.emplace(hash, std::move(constantName)); - } - - bool AddTextureDefName(std::string textureDefName) - { - const auto hash = Common::R_HashString(textureDefName.c_str(), 0); - if (m_texture_def_names_from_shaders.find(hash) != m_texture_def_names_from_shaders.end()) - return false; - - m_texture_def_names_from_shaders.emplace(hash, std::move(textureDefName)); - return true; - } - - std::unordered_set m_dumped_techniques; - std::unordered_map m_constant_names_from_shaders; - std::unordered_map m_texture_def_names_from_shaders; - }; - - class JsonDumper - { - public: - explicit JsonDumper(AssetDumpingContext& context, std::ostream& stream) - : m_stream(stream), - m_material_constants(*context.GetZoneAssetDumperState()) - { - } - - void Dump(const Material* material) const - { - json jRoot; - - jRoot["_type"] = "material"; - jRoot["_version"] = 1; - - MaterialToJson(jRoot, material); - - m_stream << std::setw(4) << jRoot << "\n"; - } - - private: - template static void JsonEnumEntry(json& j, const char* key, const unsigned value, const char* (&enumValues)[SIZE]) - { - static_assert(SIZE > 0); - JsonEnumEntry(j, key, value, enumValues, SIZE); - } - - static void JsonEnumEntry(json& j, const char* key, const unsigned value, const char** enumValues, const size_t enumValueCount) - { - assert(value < enumValueCount); - - if (value < enumValueCount) - j[key] = enumValues[value]; - else - j[key] = nullptr; - } - - void MaterialToJson(json& jRoot, const Material* material) const - { - - MaterialInfoToJson(jRoot, material); - StateBitsEntryToJson(jRoot, material); - jRoot["stateFlags"] = material->stateFlags; - JsonEnumEntry(jRoot, "cameraRegion", material->cameraRegion, cameraRegionNames); - jRoot["probeMipBits"] = material->probeMipBits; - TechniqueSetToJson(jRoot, material->techniqueSet); - TextureTableToJson(jRoot, material); - ConstantTableToJson(jRoot, material); - StateBitsTableToJson(jRoot, material); - ThermalMaterialToJson(jRoot, material->thermalMaterial); - } - - static void MaterialInfoToJson(json& jRoot, const Material* material) - { - const auto& info = material->info; - - json jGameFlags = json::array(); - for (auto bitIndex = 0u; bitIndex < sizeof(info.gameFlags) * 8u; bitIndex++) - { - if (info.gameFlags & (1 << bitIndex)) - { - if (bitIndex >= std::extent_v) - { - std::ostringstream ss; - ss << std::hex << (1 << bitIndex); - jGameFlags.push_back(ss.str()); - } - else - jGameFlags.push_back(gameFlagNames[bitIndex]); - } - } - jRoot["gameFlags"] = std::move(jGameFlags); - - jRoot["sortKey"] = info.sortKey; - - json jTextureAtlas; - jTextureAtlas["rows"] = info.textureAtlasRowCount; - jTextureAtlas["columns"] = info.textureAtlasColumnCount; - jRoot["textureAtlas"] = std::move(jTextureAtlas); - - jRoot["surfaceTypeBits"] = info.surfaceTypeBits; - jRoot["layeredSurfaceTypes"] = info.layeredSurfaceTypes; - jRoot["hashIndex"] = info.hashIndex; - jRoot["surfaceFlags"] = info.surfaceFlags; - jRoot["contents"] = info.contents; - } - - static void StateBitsEntryToJson(json& jRoot, const Material* material) - { - json jStateBitsEntry = json::array(); - - for (const char c : material->stateBitsEntry) - jStateBitsEntry.push_back(static_cast(c)); - - jRoot["stateBitsEntry"] = std::move(jStateBitsEntry); - } - - static void TechniqueSetToJson(json& jRoot, const MaterialTechniqueSet* techniqueSet) - { - if (techniqueSet && techniqueSet->name) - jRoot["techniqueSet"] = AssetName(techniqueSet->name); - else - jRoot["techniqueSet"] = nullptr; - } - - void TextureTableToJson(json& jRoot, const Material* material) const - { - json jTextures = json::array(); - if (material->textureTable) - { - for (auto textureIndex = 0u; textureIndex < material->textureCount; textureIndex++) - { - json jTexture; - TextureDefToJson(jTexture, &material->textureTable[textureIndex]); - jTextures.emplace_back(std::move(jTexture)); - } - } - jRoot["textures"] = std::move(jTextures); - } - - void TextureDefToJson(json& jTexture, const MaterialTextureDef* textureDef) const - { - std::string textureDefName; - if (m_material_constants.GetTextureDefName(textureDef->nameHash, textureDefName)) - { - jTexture["name"] = textureDefName; - } - else - { - jTexture["nameHash"] = textureDef->nameHash; - jTexture["nameStart"] = std::string(1u, textureDef->nameStart); - jTexture["nameEnd"] = std::string(1u, textureDef->nameEnd); - } - - JsonEnumEntry(jTexture, "semantic", textureDef->semantic, textureSemanticNames); - jTexture["isMatureContent"] = textureDef->isMatureContent; - - json jSamplerState; - SamplerStateToJson(jSamplerState, textureDef->samplerState); - jTexture["samplerState"] = std::move(jSamplerState); - - if (textureDef->image && textureDef->image->name) - jTexture["image"] = AssetName(textureDef->image->name); - else - jTexture["image"] = nullptr; - } - - static void SamplerStateToJson(json& jSamplerState, const MaterialTextureDefSamplerState& samplerState) - { - JsonEnumEntry(jSamplerState, "filter", samplerState.filter, textureFilterNames); - JsonEnumEntry(jSamplerState, "mipMap", samplerState.mipMap, samplerStateMipMapNames); - jSamplerState["clampU"] = samplerState.clampU ? true : false; - jSamplerState["clampV"] = samplerState.clampV ? true : false; - jSamplerState["clampW"] = samplerState.clampW ? true : false; - } - - void ConstantTableToJson(json& jRoot, const Material* material) const - { - json jConstants = json::array(); - if (material->constantTable) - { - for (auto constantIndex = 0u; constantIndex < material->constantCount; constantIndex++) - { - json jConstant; - ConstantDefToJson(jConstant, &material->constantTable[constantIndex]); - jConstants.emplace_back(std::move(jConstant)); - } - } - jRoot["constants"] = std::move(jConstants); - } - - void ConstantDefToJson(json& jConstant, const MaterialConstantDef* constantDef) const - { - const auto fragmentLength = strnlen(constantDef->name, std::extent_v); - const std::string nameFragment(constantDef->name, fragmentLength); - std::string knownConstantName; - - if (fragmentLength < std::extent_v || Common::R_HashString(nameFragment.c_str(), 0) == constantDef->nameHash) - { - jConstant["name"] = nameFragment; - } - else if (m_material_constants.GetConstantName(constantDef->nameHash, knownConstantName)) - { - jConstant["name"] = knownConstantName; - } - else - { - jConstant["nameHash"] = constantDef->nameHash; - jConstant["nameFragment"] = nameFragment; - } - - json jLiteral; - jLiteral.push_back(constantDef->literal.v[0]); - jLiteral.push_back(constantDef->literal.v[1]); - jLiteral.push_back(constantDef->literal.v[2]); - jLiteral.push_back(constantDef->literal.v[3]); - jConstant["literal"] = std::move(jLiteral); - } - - static void StateBitsTableToJson(json& jRoot, const Material* material) - { - json jStateBits = json::array(); - if (material->stateBitsTable) - { - for (auto stateBitsEntryIndex = 0u; stateBitsEntryIndex < material->stateBitsCount; stateBitsEntryIndex++) - { - json jStateBitsEntry; - StateBitsEntryToJson(jStateBitsEntry, &material->stateBitsTable[stateBitsEntryIndex].loadBits.structured); - jStateBits.emplace_back(std::move(jStateBitsEntry)); - } - } - jRoot["stateBits"] = std::move(jStateBits); - } - - static void StateBitsEntryToJson(json& jStateBitsEntry, const GfxStateBitsLoadBitsStructured* structured) - { - JsonEnumEntry(jStateBitsEntry, "srcBlendRgb", std::min(structured->srcBlendRgb, std::extent_v - 1u), blendNames); - JsonEnumEntry(jStateBitsEntry, "dstBlendRgb", std::min(structured->dstBlendRgb, std::extent_v - 1u), blendNames); - JsonEnumEntry(jStateBitsEntry, "blendOpRgb", std::min(structured->blendOpRgb, std::extent_v - 1u), blendOpNames); - - assert(structured->alphaTestDisabled || structured->alphaTest == GFXS_ALPHA_TEST_GT_0 || structured->alphaTest == GFXS_ALPHA_TEST_GE_128); - if (structured->alphaTestDisabled) - jStateBitsEntry["alphaTest"] = "disabled"; - else if (structured->alphaTest == GFXS_ALPHA_TEST_GT_0) - jStateBitsEntry["alphaTest"] = "gt0"; - else if (structured->alphaTest == GFXS_ALPHA_TEST_GE_128) - jStateBitsEntry["alphaTest"] = "ge128"; - - assert(structured->cullFace == GFXS0_CULL_NONE || structured->cullFace == GFXS0_CULL_BACK || structured->cullFace == GFXS0_CULL_FRONT); - if (structured->cullFace == GFXS0_CULL_NONE) - jStateBitsEntry["cullFace"] = "none"; - else if (structured->cullFace == GFXS0_CULL_BACK) - jStateBitsEntry["cullFace"] = "back"; - else if (structured->cullFace == GFXS0_CULL_FRONT) - jStateBitsEntry["cullFace"] = "front"; - - JsonEnumEntry(jStateBitsEntry, "srcBlendRgb", std::min(structured->srcBlendAlpha, std::extent_v - 1u), blendNames); - JsonEnumEntry(jStateBitsEntry, "dstBlendRgb", std::min(structured->dstBlendAlpha, std::extent_v - 1u), blendNames); - JsonEnumEntry(jStateBitsEntry, "blendOpRgb", std::min(structured->blendOpAlpha, std::extent_v - 1u), blendOpNames); - jStateBitsEntry["colorWriteRgb"] = static_cast(structured->colorWriteRgb); - jStateBitsEntry["colorWriteAlpha"] = static_cast(structured->colorWriteAlpha); - jStateBitsEntry["polymodeLine"] = static_cast(structured->polymodeLine); - jStateBitsEntry["depthWrite"] = static_cast(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) - jStateBitsEntry["depthTest"] = "disabled"; - else if (structured->depthTest == GFXS_DEPTHTEST_ALWAYS) - jStateBitsEntry["depthTest"] = "always"; - else if (structured->depthTest == GFXS_DEPTHTEST_LESS) - jStateBitsEntry["depthTest"] = "less"; - else if (structured->depthTest == GFXS_DEPTHTEST_EQUAL) - jStateBitsEntry["depthTest"] = "equal"; - else if (structured->depthTest == GFXS_DEPTHTEST_LESSEQUAL) - jStateBitsEntry["depthTest"] = "lessequal"; - - JsonEnumEntry( - jStateBitsEntry, "polygonOffset", std::min(structured->polygonOffset, std::extent_v - 1u), polygonOffsetNames); - - if (structured->stencilFrontEnabled) - { - json jStencilFront; - StencilToJson( - jStencilFront, structured->stencilFrontPass, structured->stencilFrontFail, structured->stencilFrontZFail, structured->stencilFrontFunc); - jStateBitsEntry["stencilFront"] = std::move(jStencilFront); - } - else - jStateBitsEntry["stencilFront"] = json(); - - if (structured->stencilBackEnabled) - { - json jStencilBack; - StencilToJson( - jStencilBack, structured->stencilBackPass, structured->stencilBackFail, structured->stencilBackZFail, structured->stencilBackFunc); - jStateBitsEntry["stencilBack"] = std::move(jStencilBack); - } - else - jStateBitsEntry["stencilBack"] = json(); - } - - static void StencilToJson(json& jStencil, const unsigned pass, const unsigned fail, const unsigned zFail, const unsigned func) - { - JsonEnumEntry(jStencil, "pass", std::min(pass, std::extent_v - 1u), stencilOpNames); - JsonEnumEntry(jStencil, "fail", std::min(fail, std::extent_v - 1u), stencilOpNames); - JsonEnumEntry(jStencil, "zfail", std::min(zFail, std::extent_v - 1u), stencilOpNames); - JsonEnumEntry(jStencil, "func", std::min(func, std::extent_v - 1u), stencilFuncNames); - } - - static void ThermalMaterialToJson(json& jRoot, const Material* thermalMaterial) - { - if (thermalMaterial && thermalMaterial->info.name) - jRoot["thermalMaterial"] = AssetName(thermalMaterial->info.name); - else - jRoot["thermalMaterial"] = nullptr; - } - - static const char* AssetName(const char* input) - { - if (input && input[0] == ',') - return &input[1]; - - return input; - } - - std::ostream& m_stream; - const MaterialConstantZoneState& m_material_constants; - }; -} // namespace T6::material std::string AssetDumperMaterial::GetFileNameForAsset(const std::string& assetName) { std::string sanitizedFileName(assetName); if (sanitizedFileName[0] == '*') { - std::replace(sanitizedFileName.begin(), sanitizedFileName.end(), '*', '_'); + std::ranges::replace(sanitizedFileName, '*', '_'); const auto parenthesisPos = sanitizedFileName.find('('); if (parenthesisPos != std::string::npos) sanitizedFileName.erase(parenthesisPos); sanitizedFileName = "generated/" + sanitizedFileName; } - std::ostringstream ss; - ss << "materials/" << sanitizedFileName << ".json"; - - return ss.str(); + return std::format("materials/{}.json", sanitizedFileName); } bool AssetDumperMaterial::ShouldDump(XAssetInfo* asset) @@ -999,14 +36,13 @@ void AssetDumperMaterial::DumpAsset(AssetDumpingContext& context, XAssetInfoAsset()); + DumpMaterialAsJson(*assetFile, asset->Asset(), context); } void AssetDumperMaterial::DumpPool(AssetDumpingContext& context, AssetPool* pool) { - auto* materialConstantState = context.GetZoneAssetDumperState(); + auto* materialConstantState = context.GetZoneAssetDumperState(); materialConstantState->ExtractNamesFromZone(); - AbstractAssetDumper::DumpPool(context, pool); + AbstractAssetDumper::DumpPool(context, pool); } diff --git a/src/ObjWriting/Game/T6/Material/JsonMaterialWriter.cpp b/src/ObjWriting/Game/T6/Material/JsonMaterialWriter.cpp new file mode 100644 index 000000000..c31b075c9 --- /dev/null +++ b/src/ObjWriting/Game/T6/Material/JsonMaterialWriter.cpp @@ -0,0 +1,245 @@ +#include "JsonMaterialWriter.h" + +#include "Game/T6/CommonT6.h" +#include "Game/T6/Material/JsonMaterial.h" +#include "MaterialConstantZoneState.h" + +#include +#include + +using namespace nlohmann; + +namespace T6 +{ + class JsonDumper + { + public: + JsonDumper(AssetDumpingContext& context, std::ostream& stream) + : m_stream(stream), + m_material_constants(*context.GetZoneAssetDumperState()) + { + } + + 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(1 << i); + + if (gameFlags & flag) + jMaterial.gameFlags.emplace_back(flag); + } + } + + static void CreateJsonSamplerState(JsonSamplerState& jSamplerState, const MaterialTextureDefSamplerState& samplerState) + { + jSamplerState.filter = static_cast(samplerState.filter); + jSamplerState.mipMap = static_cast(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(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); + const std::string nameFragment(constantDef.name, fragmentLength); + std::string knownConstantName; + + if (fragmentLength < std::extent_v || 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(pass); + jStencil.fail = static_cast(fail); + jStencil.zfail = static_cast(zFail); + jStencil.func = static_cast(func); + } + + static void CreateJsonStateBitsTableEntry(JsonStateBitsTableEntry& jStateBitsTableEntry, const GfxStateBitsTable& stateBitsTableEntry) + { + const auto& structured = stateBitsTableEntry.loadBits.structured; + + jStateBitsTableEntry.srcBlendRgb = static_cast(structured.srcBlendRgb); + jStateBitsTableEntry.dstBlendRgb = static_cast(structured.dstBlendRgb); + jStateBitsTableEntry.blendOpRgb = static_cast(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(structured.srcBlendAlpha); + jStateBitsTableEntry.dstBlendAlpha = static_cast(structured.dstBlendAlpha); + jStateBitsTableEntry.blendOpAlpha = static_cast(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(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); + for (auto i = 0u; i < std::extent_v; i++) + jMaterial.stateBitsEntry[i] = material.stateBitsEntry[i]; + + jMaterial.stateFlags = material.stateFlags; + jMaterial.cameraRegion = static_cast(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 diff --git a/src/ObjWriting/Game/T6/Material/JsonMaterialWriter.h b/src/ObjWriting/Game/T6/Material/JsonMaterialWriter.h new file mode 100644 index 000000000..ac012e4ff --- /dev/null +++ b/src/ObjWriting/Game/T6/Material/JsonMaterialWriter.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Dumping/AssetDumpingContext.h" +#include "Game/T6/T6.h" + +#include + +namespace T6 +{ + void DumpMaterialAsJson(std::ostream& stream, const Material* material, AssetDumpingContext& context); +} // namespace T6 diff --git a/src/ObjWriting/Game/T6/Material/MaterialConstantZoneState.cpp b/src/ObjWriting/Game/T6/Material/MaterialConstantZoneState.cpp new file mode 100644 index 000000000..f92b37833 --- /dev/null +++ b/src/ObjWriting/Game/T6/Material/MaterialConstantZoneState.cpp @@ -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 + +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(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(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(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::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 diff --git a/src/ObjWriting/Game/T6/Material/MaterialConstantZoneState.h b/src/ObjWriting/Game/T6/Material/MaterialConstantZoneState.h new file mode 100644 index 000000000..27f3f49e3 --- /dev/null +++ b/src/ObjWriting/Game/T6/Material/MaterialConstantZoneState.h @@ -0,0 +1,30 @@ +#pragma once + +#include "Dumping/IZoneAssetDumperState.h" +#include "Game/T6/T6.h" + +#include +#include +#include + +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 m_dumped_techniques; + std::unordered_map m_constant_names_from_shaders; + std::unordered_map m_texture_def_names_from_shaders; + }; +} // namespace T6 From 0bb17a33bd2d270cfc98e7ef21b2a570bc8abe48 Mon Sep 17 00:00:00 2001 From: Jan Date: Sat, 24 Feb 2024 20:33:26 +0100 Subject: [PATCH 2/3] feat: load materials from json --- src/Common/Game/T6/T6_Assets.h | 12 +- src/ObjCommon/Game/T6/Material/JsonMaterial.h | 14 +- .../AssetLoading/IAssetLoadingManager.h | 5 + .../T6/AssetLoaders/AssetLoaderMaterial.cpp | 59 +++ .../T6/AssetLoaders/AssetLoaderMaterial.h | 19 + .../Game/T6/Material/JsonMaterialLoader.cpp | 372 ++++++++++++++++++ .../Game/T6/Material/JsonMaterialLoader.h | 13 + src/ObjLoading/Game/T6/ObjLoaderT6.cpp | 4 +- 8 files changed, 481 insertions(+), 17 deletions(-) create mode 100644 src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderMaterial.cpp create mode 100644 src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderMaterial.h diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 854e31fc7..3cc64a640 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -2913,9 +2913,7 @@ namespace T6 GFXS_POLYGON_OFFSET_0 = 0, GFXS_POLYGON_OFFSET_1 = 1, GFXS_POLYGON_OFFSET_2 = 2, - GFXS_POLYGON_OFFSET_SHADOWMAP = 3, - - GFXS_POLYGON_OFFSET_COUNT + GFXS_POLYGON_OFFSET_SHADOWMAP = 3 }; enum GfxStencilOp @@ -2927,9 +2925,7 @@ namespace T6 GFXS_STENCILOP_DECRSAT = 0x4, GFXS_STENCILOP_INVERT = 0x5, GFXS_STENCILOP_INCR = 0x6, - GFXS_STENCILOP_DECR = 0x7, - - GFXS_STENCILOP_COUNT, + GFXS_STENCILOP_DECR = 0x7 }; enum GfxStencilFunc @@ -2941,9 +2937,7 @@ namespace T6 GFXS_STENCILFUNC_GREATER = 0x4, GFXS_STENCILFUNC_NOTEQUAL = 0x5, GFXS_STENCILFUNC_GREATEREQUAL = 0x6, - GFXS_STENCILFUNC_ALWAYS = 0x7, - - GFXS_STENCILFUNC_COUNT, + GFXS_STENCILFUNC_ALWAYS = 0x7 }; struct GfxStateBitsLoadBitsStructured diff --git a/src/ObjCommon/Game/T6/Material/JsonMaterial.h b/src/ObjCommon/Game/T6/Material/JsonMaterial.h index a1f304707..b5fd2ae9c 100644 --- a/src/ObjCommon/Game/T6/Material/JsonMaterial.h +++ b/src/ObjCommon/Game/T6/Material/JsonMaterial.h @@ -199,9 +199,9 @@ namespace T6 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.value("name", nlohmann::json()).get_to(out.name); + in.value("nameFragment", nlohmann::json()).get_to(out.nameFragment); + in.value("nameHash", nlohmann::json()).get_to(out.nameHash); in.at("literal").get_to(out.literal); }; @@ -301,10 +301,10 @@ namespace T6 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.value("name", nlohmann::json()).get_to(out.name); + in.value("nameHash", nlohmann::json()).get_to(out.nameHash); + in.value("nameStart", nlohmann::json()).get_to(out.nameStart); + in.value("nameEnd", nlohmann::json()).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); diff --git a/src/ObjLoading/AssetLoading/IAssetLoadingManager.h b/src/ObjLoading/AssetLoading/IAssetLoadingManager.h index aa6f1dcb5..0d90a6f24 100644 --- a/src/ObjLoading/AssetLoading/IAssetLoadingManager.h +++ b/src/ObjLoading/AssetLoading/IAssetLoadingManager.h @@ -36,6 +36,11 @@ class IAssetLoadingManager return AddAsset(assetType, assetName, asset, std::vector(), std::vector()); } + XAssetInfoGeneric* AddAsset(const asset_type_t assetType, const std::string& assetName, void* asset, std::vector dependencies) + { + return AddAsset(assetType, assetName, asset, std::move(dependencies), std::vector()); + } + virtual XAssetInfoGeneric* LoadDependency(asset_type_t assetType, const std::string& assetName) = 0; virtual IndirectAssetReference LoadIndirectAssetReference(asset_type_t assetType, const std::string& assetName) = 0; }; diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderMaterial.cpp b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderMaterial.cpp new file mode 100644 index 000000000..028120e26 --- /dev/null +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderMaterial.cpp @@ -0,0 +1,59 @@ +#include "AssetLoaderMaterial.h" + +#include "Game/T6/Material/JsonMaterialLoader.h" +#include "Game/T6/T6.h" +#include "Pool/GlobalAssetPool.h" + +#include +#include + +using namespace T6; + +void* AssetLoaderMaterial::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) +{ + auto* material = memory->Create(); + memset(material, 0, sizeof(Material)); + material->info.name = memory->Dup(assetName.c_str()); + + return material; +} + +bool AssetLoaderMaterial::CanLoadFromRaw() const +{ + return true; +} + +std::string AssetLoaderMaterial::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 AssetLoaderMaterial::LoadFromRaw( + const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const +{ + const auto file = searchPath->Open(GetFileNameForAsset(assetName)); + if (!file.IsOpen()) + return false; + + auto* material = static_cast(memory->Alloc(sizeof(Material))); + memset(material, 0, sizeof(Material)); + material->info.name = memory->Dup(assetName.c_str()); + + std::vector dependencies; + if (LoadMaterialAsJson(*file.m_stream, *material, memory, manager, dependencies)) + manager->AddAsset(ASSET_TYPE_MATERIAL, assetName, material, std::move(dependencies)); + else + std::cerr << "Failed to load material \"" << assetName << "\"\n"; + + return true; +} diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderMaterial.h b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderMaterial.h new file mode 100644 index 000000000..c47c026b8 --- /dev/null +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderMaterial.h @@ -0,0 +1,19 @@ +#pragma once +#include "AssetLoading/BasicAssetLoader.h" +#include "AssetLoading/IAssetLoadingManager.h" +#include "Game/T6/T6.h" +#include "SearchPath/ISearchPath.h" + +namespace T6 +{ + class AssetLoaderMaterial final : public BasicAssetLoader + { + static std::string GetFileNameForAsset(const std::string& assetName); + + public: + _NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override; + _NODISCARD bool CanLoadFromRaw() const override; + bool + LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; + }; +} // namespace T6 diff --git a/src/ObjLoading/Game/T6/Material/JsonMaterialLoader.cpp b/src/ObjLoading/Game/T6/Material/JsonMaterialLoader.cpp index e69de29bb..c0d8bb86f 100644 --- a/src/ObjLoading/Game/T6/Material/JsonMaterialLoader.cpp +++ b/src/ObjLoading/Game/T6/Material/JsonMaterialLoader.cpp @@ -0,0 +1,372 @@ +#include "JsonMaterialLoader.h" + +#include "Game/T6/CommonT6.h" +#include "Game/T6/Material/JsonMaterial.h" + +#include +#include +#include + +using namespace nlohmann; + +namespace T6 +{ + class JsonLoader + { + public: + JsonLoader(std::istream& stream, MemoryManager& memory, IAssetLoadingManager& manager, std::vector& dependencies) + : m_stream(stream), + m_memory(memory), + m_manager(manager), + m_dependencies(dependencies) + + { + } + + 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 << "Tried to load material \"" << material.info.name << "\" but did not find expected type material of version 1\n"; + return false; + } + + const auto jMaterial = jRoot.get(); + return CreateMaterialFromJson(jMaterial, material); + } + + private: + static void PrintError(const Material& material, const std::string& message) + { + std::cerr << "Cannot load material \"" << material.info.name << "\": " << message << "\n"; + } + + 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 = static_cast*>(m_manager.LoadDependency(ASSET_TYPE_IMAGE, jTexture.image)); + if (!image) + { + PrintError(material, std::format("Could not find textureDef image: {}", jTexture.image)); + return false; + } + m_dependencies.push_back(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); + strncpy(constantDef.name, jConstant.name->c_str(), copyCount); + if (copyCount < std::extent_v) + memset(&constantDef.name[copyCount], 0, std::extent_v - 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); + strncpy(constantDef.name, jConstant.nameFragment->c_str(), copyCount); + if (copyCount < std::extent_v) + memset(&constantDef.name[copyCount], 0, std::extent_v - 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(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(jMaterial.hashIndex); + material.info.surfaceFlags = jMaterial.surfaceFlags; + material.info.contents = jMaterial.contents; + + if (jMaterial.stateBitsEntry.size() != std::extent_v) + { + PrintError(material, std::format("StateBitsEntry size is not {}", jMaterial.stateBitsEntry.size())); + return false; + } + for (auto i = 0u; i < std::extent_v; i++) + material.stateBitsEntry[i] = jMaterial.stateBitsEntry[i]; + + material.stateFlags = static_cast(jMaterial.stateFlags); + material.cameraRegion = jMaterial.cameraRegion; + material.probeMipBits = jMaterial.probeMipBits; + + auto* techniqueSet = static_cast*>(m_manager.LoadDependency(ASSET_TYPE_TECHNIQUE_SET, jMaterial.techniqueSet)); + if (!techniqueSet) + { + PrintError(material, "Could not find technique set"); + return false; + } + m_dependencies.push_back(techniqueSet); + material.techniqueSet = techniqueSet->Asset(); + + if (!jMaterial.textures.empty()) + { + material.textureCount = static_cast(jMaterial.textures.size()); + material.textureTable = static_cast(m_memory.Alloc(sizeof(MaterialTextureDef) * material.textureCount)); + memset(material.textureTable, 0, sizeof(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(jMaterial.constants.size()); + material.constantTable = static_cast(m_memory.Alloc(sizeof(MaterialConstantDef) * material.constantCount)); + memset(material.constantTable, 0, sizeof(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(jMaterial.stateBits.size()); + material.stateBitsTable = static_cast(m_memory.Alloc(sizeof(GfxStateBitsTable) * material.stateBitsCount)); + memset(material.stateBitsTable, 0, sizeof(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 = static_cast*>(m_manager.LoadDependency(ASSET_TYPE_MATERIAL, jMaterial.thermalMaterial.value())); + if (!thermalMaterial) + { + PrintError(material, "Could not find thermal material"); + return false; + } + m_dependencies.push_back(thermalMaterial); + material.thermalMaterial = thermalMaterial->Asset(); + } + else + { + material.thermalMaterial = nullptr; + } + + return true; + } + + std::istream& m_stream; + MemoryManager& m_memory; + IAssetLoadingManager& m_manager; + std::vector& m_dependencies; + }; + + bool LoadMaterialAsJson( + std::istream& stream, Material& material, MemoryManager* memory, IAssetLoadingManager* manager, std::vector& dependencies) + { + const JsonLoader loader(stream, *memory, *manager, dependencies); + + return loader.Load(material); + } +} // namespace T6 diff --git a/src/ObjLoading/Game/T6/Material/JsonMaterialLoader.h b/src/ObjLoading/Game/T6/Material/JsonMaterialLoader.h index e69de29bb..5e502e909 100644 --- a/src/ObjLoading/Game/T6/Material/JsonMaterialLoader.h +++ b/src/ObjLoading/Game/T6/Material/JsonMaterialLoader.h @@ -0,0 +1,13 @@ +#pragma once + +#include "AssetLoading/IAssetLoadingManager.h" +#include "Game/T6/T6.h" +#include "Utils/MemoryManager.h" + +#include + +namespace T6 +{ + bool LoadMaterialAsJson( + std::istream& stream, Material& material, MemoryManager* memory, IAssetLoadingManager* manager, std::vector& dependencies); +} // namespace T6 diff --git a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp index dcff00e55..667e70ab0 100644 --- a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp +++ b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp @@ -3,6 +3,7 @@ #include "AssetLoaders/AssetLoaderFontIcon.h" #include "AssetLoaders/AssetLoaderGfxImage.h" #include "AssetLoaders/AssetLoaderLocalizeEntry.h" +#include "AssetLoaders/AssetLoaderMaterial.h" #include "AssetLoaders/AssetLoaderPhysConstraints.h" #include "AssetLoaders/AssetLoaderPhysPreset.h" #include "AssetLoaders/AssetLoaderQdb.h" @@ -49,7 +50,8 @@ namespace T6 REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_DESTRUCTIBLEDEF, DestructibleDef)) REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_XANIMPARTS, XAnimParts)) REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_XMODEL, XModel)) - REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_MATERIAL, Material)) + // REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_MATERIAL, Material)) + REGISTER_ASSET_LOADER(AssetLoaderMaterial) REGISTER_ASSET_LOADER(BASIC_LOADER(ASSET_TYPE_TECHNIQUE_SET, MaterialTechniqueSet)) REGISTER_ASSET_LOADER(AssetLoaderGfxImage) REGISTER_ASSET_LOADER(AssetLoaderSoundBank) From a0a420f7f19a097d3617c99cb6b5781ac2b5e56b Mon Sep 17 00:00:00 2001 From: Jan Date: Thu, 29 Feb 2024 12:45:37 +0100 Subject: [PATCH 3/3] fix: build on linux --- src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderMaterial.cpp | 1 + src/ObjLoading/Game/T6/Material/JsonMaterialLoader.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderMaterial.cpp b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderMaterial.cpp index 028120e26..f73f6d2fc 100644 --- a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderMaterial.cpp +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderMaterial.cpp @@ -4,6 +4,7 @@ #include "Game/T6/T6.h" #include "Pool/GlobalAssetPool.h" +#include #include #include diff --git a/src/ObjLoading/Game/T6/Material/JsonMaterialLoader.cpp b/src/ObjLoading/Game/T6/Material/JsonMaterialLoader.cpp index c0d8bb86f..16975cd83 100644 --- a/src/ObjLoading/Game/T6/Material/JsonMaterialLoader.cpp +++ b/src/ObjLoading/Game/T6/Material/JsonMaterialLoader.cpp @@ -3,6 +3,7 @@ #include "Game/T6/CommonT6.h" #include "Game/T6/Material/JsonMaterial.h" +#include #include #include #include