From cc2f0ca487a16107919c0f437725e48108129421 Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 2 May 2022 21:11:51 +0200 Subject: [PATCH] Write Statebits data to gdt materials --- src/Common/Game/IW4/IW4_Assets.h | 6 +- src/ObjCommon/Game/IW4/MaterialConstantsIW4.h | 195 ++++++++++++++++ .../IW4/AssetDumpers/AssetDumperMaterial.cpp | 216 +++++++++++------- 3 files changed, 337 insertions(+), 80 deletions(-) diff --git a/src/Common/Game/IW4/IW4_Assets.h b/src/Common/Game/IW4/IW4_Assets.h index f3b4f058..59ce5b3b 100644 --- a/src/Common/Game/IW4/IW4_Assets.h +++ b/src/Common/Game/IW4/IW4_Assets.h @@ -729,10 +729,10 @@ namespace IW4 GFXS0_ATEST_GE_128 = 0x3000, GFXS0_ATEST_MASK = 0x3000, - GFXS0_CULL_SHIFT = 0xE, GFXS0_CULL_NONE = 0x4000, GFXS0_CULL_BACK = 0x8000, GFXS0_CULL_FRONT = 0xC000, + GFXS0_CULL_SHIFT = 0xE, GFXS0_CULL_MASK = 0xC000, GFXS0_SRCBLEND_ALPHA_SHIFT = 0x10, @@ -752,18 +752,18 @@ namespace IW4 GFXS1_DEPTHWRITE = 0x1, GFXS1_DEPTHTEST_DISABLE = 0x2, - GFXS1_DEPTHTEST_SHIFT = 0x2, GFXS1_DEPTHTEST_ALWAYS = 0x0, GFXS1_DEPTHTEST_LESS = 0x4, GFXS1_DEPTHTEST_EQUAL = 0x8, GFXS1_DEPTHTEST_LESSEQUAL = 0xC, + GFXS1_DEPTHTEST_SHIFT = 0x2, GFXS1_DEPTHTEST_MASK = 0xC, - GFXS1_POLYGON_OFFSET_SHIFT = 0x4, GFXS1_POLYGON_OFFSET_0 = 0x0, GFXS1_POLYGON_OFFSET_1 = 0x10, GFXS1_POLYGON_OFFSET_2 = 0x20, GFXS1_POLYGON_OFFSET_SHADOWMAP = 0x30, + GFXS1_POLYGON_OFFSET_SHIFT = 0x4, GFXS1_POLYGON_OFFSET_MASK = 0x30, GFXS1_STENCIL_FRONT_ENABLE = 0x40, diff --git a/src/ObjCommon/Game/IW4/MaterialConstantsIW4.h b/src/ObjCommon/Game/IW4/MaterialConstantsIW4.h index 3b808120..907ded7e 100644 --- a/src/ObjCommon/Game/IW4/MaterialConstantsIW4.h +++ b/src/ObjCommon/Game/IW4/MaterialConstantsIW4.h @@ -108,4 +108,199 @@ namespace IW4 "slush" }; static_assert(std::extent_v == SURF_TYPE_NUM); + + + enum class BlendFunc_e + { + UNKNOWN, + CUSTOM, + REPLACE, + BLEND, + ADD, + MULTIPLY, + SCREEN_ADD, + + COUNT + }; + + inline const char* GdtBlendFuncNames[] + { + "", + "Custom", + "Replace*", + "Blend", + "Add", + "Multiply", + "Screen Add" + }; + static_assert(std::extent_v == static_cast(BlendFunc_e::COUNT)); + + enum class BlendOp_e + { + UNKNOWN, + DISABLE, + ADD, + SUBTRACT, + REV_SUBTRACT, + MIN, + MAX, + + COUNT + }; + + inline const char* GdtBlendOpNames[] + { + "", + "Disable", + "Add*", + "Subtract", + "RevSubtract", + "Min", + "Max" + }; + static_assert(std::extent_v == static_cast(BlendOp_e::COUNT)); + + enum class CustomBlendFunc_e + { + UNKNOWN, + DISABLED, + ZERO, + ONE, + SRC_COLOR, + INV_SRC_COLOR, + SRC_ALPHA, + INV_SRC_ALPHA, + DST_ALPHA, + INV_DST_ALPHA, + DEST_COLOR, + INV_DST_COLOR, + + COUNT + }; + + inline const char* GdtCustomBlendFuncNames[] + { + "", + "Disable", + "Zero", + "One*", + "SrcColor", + "InvSrcColor", + "SrcAlpha", + "InvSrcAlpha", + "DestAlpha", + "InvDestAlpha", + "DestColor", + "InvDestColor" + }; + static_assert(std::extent_v == static_cast(CustomBlendFunc_e::COUNT)); + + enum class AlphaTest_e + { + UNKNOWN, + ALWAYS, + GT0, + LT128, + GE128, + + COUNT + }; + + inline const char* GdtAlphaTestNames[] + { + "", + "Always*", + "GT0", + "LT128", + "GE128" + }; + static_assert(std::extent_v == static_cast(AlphaTest_e::COUNT)); + + enum class DepthTest_e + { + UNKNOWN, + LESS_EQUAL, + LESS, + EQUAL, + ALWAYS, + DISABLE, + + COUNT + }; + + inline const char* GdtDepthTestNames[] + { + "", + "LessEqual*", + "Less", + "Equal", + "Always", + "Disable" + }; + static_assert(std::extent_v == static_cast(DepthTest_e::COUNT)); + + enum class StateBitsEnabledStatus_e + { + UNKNOWN, + ENABLED, + DISABLED, + + COUNT + }; + + inline const char* GdtStateBitsEnabledStatusNames[] + { + "", + "Enable", + "Disable" + }; + static_assert(std::extent_v == static_cast(StateBitsEnabledStatus_e::COUNT)); + + inline const char* GdtStateBitsOnOffStatusNames[] + { + "", + "On", + "Off" + }; + static_assert(std::extent_v == static_cast(StateBitsEnabledStatus_e::COUNT)); + + enum class CullFace_e + { + UNKNOWN, + NONE, + BACK, + FRONT, + + COUNT + }; + + inline const char* GdtCullFaceNames[] + { + "", + "None", + "Back*", + "Front" + }; + static_assert(std::extent_v == static_cast(CullFace_e::COUNT)); + + enum class PolygonOffset_e + { + UNKNOWN, + OFFSET_0, + OFFSET_1, + OFFSET_2, + OFFSET_SHADOW_MAP, + + COUNT + }; + + inline const char* GdtPolygonOffsetNames[] + { + "", + "0", + "1", + "2", + "shadowMap" + }; + static_assert(std::extent_v == static_cast(PolygonOffset_e::COUNT)); } diff --git a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperMaterial.cpp b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperMaterial.cpp index 446957c4..b0fc9efa 100644 --- a/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperMaterial.cpp +++ b/src/ObjWriting/Game/IW4/AssetDumpers/AssetDumperMaterial.cpp @@ -540,82 +540,6 @@ namespace IW4 bool m_color_o_flag = false; }; - enum class BlendFunc_e - { - UNKNOWN, - CUSTOM, - REPLACE, - BLEND, - ADD, - MULTIPLY, - SCREEN_ADD - }; - - enum class BlendOp_e - { - UNKNOWN, - ADD, - SUBTRACT, - REV_SUBTRACT, - MIN, - MAX, - DISABLE - }; - - enum class CustomBlendFunc_e - { - UNKNOWN, - ONE, - ZERO, - SRC_COLOR, - INV_SRC_COLOR, - SRC_ALPHA, - INV_SRC_ALPHA, - DST_ALPHA, - INV_DST_ALPHA, - DEST_COLOR, - INV_DST_COLOR - }; - - enum class AlphaTest_e - { - UNKNOWN, - ALWAYS, - GE128 - }; - - enum class DepthTest_e - { - UNKNOWN, - LESS_EQUAL, - LESS, - EQUAL, - ALWAYS, - DISABLE - }; - - enum class StateBitsEnabledStatus_e - { - UNKNOWN, - ENABLED, - DISABLED - }; - - enum class CullFace_e - { - UNKNOWN, - FRONT, - BACK, - NONE - }; - - enum class PolygonOffset - { - UNKNOWN, - STATIC_DECAL, - WEAPON_IMPACT - }; - class StateBitsInfo { public: @@ -630,7 +554,7 @@ namespace IW4 DepthTest_e m_depth_test = DepthTest_e::UNKNOWN; StateBitsEnabledStatus_e m_depth_write = StateBitsEnabledStatus_e::UNKNOWN; CullFace_e m_cull_face = CullFace_e::UNKNOWN; - PolygonOffset m_polygon_offset = PolygonOffset::UNKNOWN; + PolygonOffset_e m_polygon_offset = PolygonOffset_e::UNKNOWN; StateBitsEnabledStatus_e m_color_write_rgb = StateBitsEnabledStatus_e::UNKNOWN; StateBitsEnabledStatus_e m_color_write_alpha = StateBitsEnabledStatus_e::UNKNOWN; }; @@ -645,6 +569,11 @@ namespace IW4 const Material* m_material; GdtEntry m_entry; + void SetValue(const std::string& key, const char* value) + { + m_entry.m_properties.emplace(std::make_pair(key, value)); + } + void SetValue(const std::string& key, std::string value) { m_entry.m_properties.emplace(std::make_pair(key, std::move(value))); @@ -657,6 +586,11 @@ namespace IW4 m_entry.m_properties.emplace(std::make_pair(key, ss.str())); } + void SetValue(const std::string& key, const bool value) + { + m_entry.m_properties.emplace(std::make_pair(key, value ? "1" : "0")); + } + template , T>> void SetValue(const std::string& key, T value) @@ -959,12 +893,140 @@ namespace IW4 } } + template + T StateBitsToEnum(const unsigned input, const size_t mask, const size_t shift) + { + const unsigned value = (input & mask) >> shift; + return value >= (static_cast(T::COUNT) - 1) ? T::UNKNOWN : static_cast(value + 1); + } + + void ExamineStateBitsInfo() + { + if (!m_material->stateBitsTable || m_material->stateBitsCount == 0) + return; + + // This assumes the statemap of these techniques is passthrough which it is most likely not + // This should still not produce any wrong values + GfxStateBits stateBits{}; + if (m_material->stateBitsEntry[TECHNIQUE_LIT] < m_material->stateBitsCount) + stateBits = m_material->stateBitsTable[m_material->stateBitsEntry[TECHNIQUE_LIT]]; + else if (m_material->stateBitsEntry[TECHNIQUE_EMISSIVE] < m_material->stateBitsCount) + stateBits = m_material->stateBitsTable[m_material->stateBitsEntry[TECHNIQUE_EMISSIVE]]; + else if (m_material->stateBitsEntry[TECHNIQUE_UNLIT] < m_material->stateBitsCount) + stateBits = m_material->stateBitsTable[m_material->stateBitsEntry[TECHNIQUE_UNLIT]]; + else if (m_material->stateBitsEntry[TECHNIQUE_DEPTH_PREPASS] < m_material->stateBitsCount) + stateBits = m_material->stateBitsTable[m_material->stateBitsEntry[TECHNIQUE_DEPTH_PREPASS]]; + else + { + assert(false); + return; + } + + if (m_state_bits_info.m_custom_blend_op_rgb == BlendOp_e::UNKNOWN) + m_state_bits_info.m_custom_blend_op_rgb = StateBitsToEnum(stateBits.loadBits[0], GFXS0_BLENDOP_RGB_MASK, GFXS0_BLENDOP_RGB_SHIFT); + + if (m_state_bits_info.m_custom_blend_op_alpha == BlendOp_e::UNKNOWN) + m_state_bits_info.m_custom_blend_op_alpha = StateBitsToEnum(stateBits.loadBits[0], GFXS0_BLENDOP_ALPHA_MASK, GFXS0_BLENDOP_ALPHA_SHIFT); + + if (m_state_bits_info.m_custom_src_blend_func == CustomBlendFunc_e::UNKNOWN) + m_state_bits_info.m_custom_src_blend_func = StateBitsToEnum(stateBits.loadBits[0], GFXS0_SRCBLEND_RGB_MASK, GFXS0_SRCBLEND_RGB_SHIFT); + + if (m_state_bits_info.m_custom_dst_blend_func == CustomBlendFunc_e::UNKNOWN) + m_state_bits_info.m_custom_dst_blend_func = StateBitsToEnum(stateBits.loadBits[0], GFXS0_DSTBLEND_RGB_MASK, GFXS0_DSTBLEND_RGB_SHIFT); + + if (m_state_bits_info.m_custom_src_blend_func_alpha == CustomBlendFunc_e::UNKNOWN) + m_state_bits_info.m_custom_src_blend_func_alpha = StateBitsToEnum(stateBits.loadBits[0], GFXS0_SRCBLEND_ALPHA_MASK, GFXS0_SRCBLEND_ALPHA_SHIFT); + + if (m_state_bits_info.m_custom_dst_blend_func_alpha == CustomBlendFunc_e::UNKNOWN) + m_state_bits_info.m_custom_dst_blend_func_alpha = StateBitsToEnum(stateBits.loadBits[0], GFXS0_DSTBLEND_ALPHA_MASK, GFXS0_DSTBLEND_ALPHA_SHIFT); + + if (m_state_bits_info.m_alpha_test == AlphaTest_e::UNKNOWN) + { + if (stateBits.loadBits[0] & GFXS0_ATEST_DISABLE) + m_state_bits_info.m_alpha_test = AlphaTest_e::ALWAYS; + else if (stateBits.loadBits[0] & GFXS0_ATEST_GE_128) + m_state_bits_info.m_alpha_test = AlphaTest_e::GE128; + else if (stateBits.loadBits[0] & GFXS0_ATEST_GT_0) + m_state_bits_info.m_alpha_test = AlphaTest_e::GT0; + else if (stateBits.loadBits[0] & GFXS0_ATEST_LT_128) + m_state_bits_info.m_alpha_test = AlphaTest_e::LT128; + else + assert(false); + } + + if (m_state_bits_info.m_depth_test == DepthTest_e::UNKNOWN) + { + if (stateBits.loadBits[1] & GFXS1_DEPTHTEST_DISABLE) + m_state_bits_info.m_depth_test = DepthTest_e::DISABLE; + else if (stateBits.loadBits[1] & GFXS1_DEPTHTEST_LESSEQUAL) + m_state_bits_info.m_depth_test = DepthTest_e::LESS_EQUAL; + else if (stateBits.loadBits[1] & GFXS1_DEPTHTEST_LESS) + m_state_bits_info.m_depth_test = DepthTest_e::LESS; + else if (stateBits.loadBits[1] & GFXS1_DEPTHTEST_EQUAL) + m_state_bits_info.m_depth_test = DepthTest_e::EQUAL; + else + m_state_bits_info.m_depth_test = DepthTest_e::ALWAYS; + } + + if (m_state_bits_info.m_depth_write == StateBitsEnabledStatus_e::UNKNOWN) + m_state_bits_info.m_depth_write = (stateBits.loadBits[1] & GFXS1_DEPTHWRITE) ? StateBitsEnabledStatus_e::ENABLED : StateBitsEnabledStatus_e::DISABLED; + + if (m_state_bits_info.m_cull_face == CullFace_e::UNKNOWN) + { + if (stateBits.loadBits[0] & GFXS0_CULL_NONE) + m_state_bits_info.m_cull_face = CullFace_e::NONE; + else if (stateBits.loadBits[0] & GFXS0_CULL_BACK) + m_state_bits_info.m_cull_face = CullFace_e::BACK; + else if (stateBits.loadBits[0] & GFXS0_CULL_FRONT) + m_state_bits_info.m_cull_face = CullFace_e::FRONT; + else + assert(false); + } + + if (m_state_bits_info.m_polygon_offset == PolygonOffset_e::UNKNOWN) + m_state_bits_info.m_polygon_offset = StateBitsToEnum(stateBits.loadBits[1], GFXS1_POLYGON_OFFSET_MASK, GFXS1_POLYGON_OFFSET_SHIFT); + + if (m_state_bits_info.m_color_write_rgb == StateBitsEnabledStatus_e::UNKNOWN) + m_state_bits_info.m_color_write_rgb = (stateBits.loadBits[0] & GFXS0_COLORWRITE_RGB) ? StateBitsEnabledStatus_e::ENABLED : StateBitsEnabledStatus_e::DISABLED; + + if (m_state_bits_info.m_color_write_alpha == StateBitsEnabledStatus_e::UNKNOWN) + m_state_bits_info.m_color_write_alpha = (stateBits.loadBits[0] & GFXS0_COLORWRITE_ALPHA) ? StateBitsEnabledStatus_e::ENABLED : StateBitsEnabledStatus_e::DISABLED; + } + void SetMaterialTypeValues() { ExamineTechsetInfo(); + ExamineStateBitsInfo(); + SetValue("materialType", GdtMaterialTypeNames[static_cast(m_techset_info.m_gdt_material_type)]); SetValue("customTemplate", GdtCustomMaterialTypeNames[static_cast(m_techset_info.m_gdt_custom_material_type)]); SetValue("customString", m_techset_info.m_gdt_custom_string); + SetValue("noCastShadow", m_techset_info.m_no_cast_shadow); + SetValue("noReceiveDynamicShadow", m_techset_info.m_no_receive_dynamic_shadow); + SetValue("noFog", m_techset_info.m_no_fog); + SetValue("texScroll", m_techset_info.m_tex_scroll); + SetValue("uvAnim", m_techset_info.m_uv_anim); + + // TODO: These are not good names, change when known what they do + SetValue("specularP", m_techset_info.m_specular_p_flag); + SetValue("colorO", m_techset_info.m_color_o_flag); + + SetValue("blendFunc", GdtBlendFuncNames[static_cast(m_state_bits_info.m_blend_func)]); + SetValue("customBlendOpRgb", GdtBlendOpNames[static_cast(m_state_bits_info.m_custom_blend_op_rgb)]); + SetValue("customBlendOpAlpha", GdtBlendOpNames[static_cast(m_state_bits_info.m_custom_blend_op_alpha)]); + SetValue("srcCustomBlendFunc", GdtCustomBlendFuncNames[static_cast(m_state_bits_info.m_custom_src_blend_func)]); + SetValue("destCustomBlendFunc", GdtCustomBlendFuncNames[static_cast(m_state_bits_info.m_custom_dst_blend_func)]); + SetValue("srcCustomBlendFuncAlpha", GdtCustomBlendFuncNames[static_cast(m_state_bits_info.m_custom_src_blend_func_alpha)]); + SetValue("destCustomBlendFuncAlpha", GdtCustomBlendFuncNames[static_cast(m_state_bits_info.m_custom_dst_blend_func_alpha)]); + SetValue("alphaTest", GdtAlphaTestNames[static_cast(m_state_bits_info.m_alpha_test)]); + SetValue("depthTest", GdtDepthTestNames[static_cast(m_state_bits_info.m_depth_test)]); + SetValue("depthWrite", GdtStateBitsOnOffStatusNames[static_cast(m_state_bits_info.m_depth_write)]); + SetValue("cullFace", GdtCullFaceNames[static_cast(m_state_bits_info.m_cull_face)]); + SetValue("polygonOffset", GdtPolygonOffsetNames[static_cast(m_state_bits_info.m_polygon_offset)]); + SetValue("colorWriteRed", GdtStateBitsEnabledStatusNames[static_cast(m_state_bits_info.m_color_write_rgb)]); + SetValue("colorWriteGreen", GdtStateBitsEnabledStatusNames[static_cast(m_state_bits_info.m_color_write_rgb)]); + SetValue("colorWriteBlue", GdtStateBitsEnabledStatusNames[static_cast(m_state_bits_info.m_color_write_rgb)]); + SetValue("colorWriteAlpha", GdtStateBitsEnabledStatusNames[static_cast(m_state_bits_info.m_color_write_alpha)]); } void SetTextureTableValues()