From 161ab4530697a09238236761ce206c77f3370edc Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Mon, 9 Mar 2026 00:01:35 +0100 Subject: [PATCH] chore: handle iw4 technique flags --- src/Common/Game/IW4/IW4_Assets.h | 34 +++++++++------ src/Common/Game/T6/T6_Assets.h | 12 +++--- .../Game/IW4/Techset/TechsetConstantsIW4.h | 8 +++- .../Game/T6/Techset/TechsetConstantsT6.h | 12 +++--- .../Techset/CommonVertexDeclCreator.cpp | 28 ++++++++++++ .../Techset/CommonVertexDeclCreator.h | 3 +- .../Game/IW4/Techset/CompilerTechsetIW4.cpp | 26 +++++------ .../Techset/TechniqueCompiler.cpp.template | 43 +++++++++++++------ 8 files changed, 112 insertions(+), 54 deletions(-) diff --git a/src/Common/Game/IW4/IW4_Assets.h b/src/Common/Game/IW4/IW4_Assets.h index 7da63e1e..31e207ba 100644 --- a/src/Common/Game/IW4/IW4_Assets.h +++ b/src/Common/Game/IW4/IW4_Assets.h @@ -1207,9 +1207,13 @@ namespace IW4 STREAM_SRC_COLOR = 0x1, STREAM_SRC_TEXCOORD_0 = 0x2, STREAM_SRC_NORMAL = 0x3, - STREAM_SRC_TANGENT = 0x4, - STREAM_SRC_OPTIONAL_BEGIN = 0x5, + STREAM_SRC_PRE_OPTIONAL_BEGIN = 0x4, + + STREAM_SRC_TANGENT = 0x4, + + STREAM_SRC_OPTIONAL_BEGIN = 0x5, + STREAM_SRC_TEXCOORD_1 = 0x5, STREAM_SRC_TEXCOORD_2 = 0x6, STREAM_SRC_NORMAL_TRANSFORM_0 = 0x7, @@ -1586,18 +1590,20 @@ namespace IW4 enum TechniqueFlags { - // Guesses purely based on data analysis: - TECHNIQUE_FLAG_1 = 0x1, // uses resolvedPostSun code sampler // MTL_TECHFLAG_NEEDS_RESOLVED_POST_SUN - TECHNIQUE_FLAG_2 = 0x2, // uses resolvedScene code sampler MTL_TECHFLAG_NEEDS_RESOLVED_SCENE - TECHNIQUE_FLAG_4 = 0x4, // zprepass only - TECHNIQUE_FLAG_8 = 0x8, // build_floatz only - TECHNIQUE_FLAG_10 = 0x10, // build_shadowmap_depth + build_shadowmap_model only - TECHNIQUE_FLAG_20 = - 0x20, // techniques with _i_ in its name (all use texcoord[1] in decl -> other optional stream sources are not used at all so might be any optional) - TECHNIQUE_FLAG_40 = 0x40, // uses code constant light.spotDir or light.spotFactors - TECHNIQUE_FLAG_80 = 0x80, // uses floatZ sampler and does not have 0x100 flag - TECHNIQUE_FLAG_100 = 0x100, // distortion_scale_zfeather_dtex + distortion_scale_ua_zfeather + distortion_scale_zfeather - TECHNIQUE_FLAG_200 = 0x200, // ? + MTL_TECHFLAG_NEEDS_RESOLVED_POST_SUN = 0x1, + MTL_TECHFLAG_NEEDS_RESOLVED_SCENE = 0x2, + + // These 3 are set so rare, it seems like they are just based on name just like other games do + MTL_TECHFLAG_ZPREPASS = 0x4, + MTL_TECHFLAG_BUILD_FLOATZ = 0x8, + MTL_TECHFLAG_BUILD_SHADOW_MAP_DEPTH_OR_MODEL = 0x10, + + MTL_TECHFLAG_DECL_HAS_OPTIONAL_SOURCE = 0x20, + + MTL_TECHFLAG_USES_LIGHT_SPOT_FACTORS = 0x40, + MTL_TECHFLAG_USES_FLOATZ = 0x80, // uses floatZ sampler and does not have 0x100 flag + MTL_TECHFLAG_USES_DISTORTION_FLOATZ = 0x100, // distortion_scale_zfeather_dtex + distortion_scale_ua_zfeather + distortion_scale_zfeather + TECHNIQUE_FLAG_200 = 0x200, // ? }; struct MaterialTechnique diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 627e3b7d..8522c3fe 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -3045,16 +3045,16 @@ namespace T6 enum TechniqueFlags { - TECHNIQUE_FLAG_1 = 0x1, - TECHNIQUE_FLAG_2 = 0x2, - TECHNIQUE_FLAG_4 = 0x4, + MTL_TECHFLAG_NEEDS_RESOLVED_POST_SUN = 0x1, + MTL_TECHFLAG_NEEDS_RESOLVED_SCENE = 0x2, + MTL_TECHFLAG_ZPREPASS = 0x4, // Vertex decl has optional source - TECHNIQUE_FLAG_8 = 0x8, + MTL_TECHFLAG_DECL_HAS_OPTIONAL_SOURCE = 0x8, - TECHNIQUE_FLAG_10 = 0x10, + MTL_TECHFLAG_USES_LIGHT_SPOT_FACTORS = 0x10, TECHNIQUE_FLAG_20 = 0x20, - TECHNIQUE_FLAG_40 = 0x40, + MTL_TECHFLAG_USES_FLOATZ = 0x40, // Any material that has statebits according to any of the following sets this: // - GFXS1_DEPTHWRITE set diff --git a/src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h b/src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h index 37498377..4b5a4f8d 100644 --- a/src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h +++ b/src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h @@ -93,7 +93,7 @@ namespace IW4 { .name = "texcoord[1]", .abbreviation = "t1", - .optional = false, + .optional = true, }, { .name = "texcoord[2]", @@ -204,6 +204,7 @@ namespace IW4 .accessor = "lightSpotFactors", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .techFlags = MTL_TECHFLAG_USES_LIGHT_SPOT_FACTORS, }, { .value = CONST_SRC_CODE_LIGHT_FALLOFF_PLACEMENT, @@ -1029,11 +1030,13 @@ namespace IW4 .value = TEXTURE_SRC_CODE_RESOLVED_POST_SUN, .accessor = "resolvedPostSun", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .techFlags = MTL_TECHFLAG_NEEDS_RESOLVED_POST_SUN, }, { .value = TEXTURE_SRC_CODE_RESOLVED_SCENE, .accessor = "resolvedScene", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .techFlags = MTL_TECHFLAG_NEEDS_RESOLVED_SCENE, }, { .value = TEXTURE_SRC_CODE_POST_EFFECT_0, @@ -1059,16 +1062,19 @@ namespace IW4 .value = TEXTURE_SRC_CODE_FLOATZ, .accessor = "floatZSampler", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .techFlags = MTL_TECHFLAG_USES_FLOATZ, }, { .value = TEXTURE_SRC_CODE_PROCESSED_FLOATZ, .accessor = "processedFloatZSampler", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .techFlags = MTL_TECHFLAG_USES_FLOATZ, }, { .value = TEXTURE_SRC_CODE_RAW_FLOATZ, .accessor = "rawFloatZSampler", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .techFlags = MTL_TECHFLAG_USES_FLOATZ, }, { .value = TEXTURE_SRC_CODE_HALF_PARTICLES, diff --git a/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h b/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h index 4251faa7..b57c90f9 100644 --- a/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h +++ b/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h @@ -219,7 +219,7 @@ namespace T6 .accessor = "lightSpotFactors", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, - .techFlags = TECHNIQUE_FLAG_10, + .techFlags = MTL_TECHFLAG_USES_LIGHT_SPOT_FACTORS, }, { .value = CONST_SRC_CODE_LIGHT_ATTENUATION, @@ -1603,13 +1603,13 @@ namespace T6 .value = TEXTURE_SRC_CODE_RESOLVED_POST_SUN, .accessor = "resolvedPostSun", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, - .techFlags = TECHNIQUE_FLAG_1, + .techFlags = MTL_TECHFLAG_NEEDS_RESOLVED_POST_SUN, }, { .value = TEXTURE_SRC_CODE_RESOLVED_SCENE, .accessor = "resolvedScene", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, - .techFlags = TECHNIQUE_FLAG_2, + .techFlags = MTL_TECHFLAG_NEEDS_RESOLVED_SCENE, }, { .value = TEXTURE_SRC_CODE_POST_EFFECT_SRC, @@ -1650,19 +1650,19 @@ namespace T6 .value = TEXTURE_SRC_CODE_FLOATZ, .accessor = "floatZSampler", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, - .techFlags = TECHNIQUE_FLAG_40, + .techFlags = MTL_TECHFLAG_USES_FLOATZ, }, { .value = TEXTURE_SRC_CODE_PROCESSED_FLOATZ, .accessor = "processedFloatZSampler", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, - .techFlags = TECHNIQUE_FLAG_40, + .techFlags = MTL_TECHFLAG_USES_FLOATZ, }, { .value = TEXTURE_SRC_CODE_RAW_FLOATZ, .accessor = "rawFloatZSampler", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, - .techFlags = TECHNIQUE_FLAG_40, + .techFlags = MTL_TECHFLAG_USES_FLOATZ, }, { .value = TEXTURE_SRC_CODE_STENCIL, diff --git a/src/ObjCommon/Techset/CommonVertexDeclCreator.cpp b/src/ObjCommon/Techset/CommonVertexDeclCreator.cpp index ec100fe4..91f10213 100644 --- a/src/ObjCommon/Techset/CommonVertexDeclCreator.cpp +++ b/src/ObjCommon/Techset/CommonVertexDeclCreator.cpp @@ -24,6 +24,34 @@ namespace namespace techset { + std::optional HasOptionalSourceByName(const std::string& name, const CommonStreamRoutingInfos& routingInfos) + { + size_t currentOffset = 0u; + + std::string sourceAbbreviation; + while (NextAbbreviation(name, sourceAbbreviation, currentOffset)) + { + std::string destinationAbbreviation; + if (!NextAbbreviation(name, destinationAbbreviation, currentOffset)) + { + con::error("Failed to detect vertex decl destination abbreviation: {}", name); + return std::nullopt; + } + + const auto maybeSource = routingInfos.GetSourceByAbbreviation(sourceAbbreviation); + if (!maybeSource) + { + con::error("Unknown vertex decl source abbreviation: {}", sourceAbbreviation); + return std::nullopt; + } + + if (routingInfos.IsSourceOptional(*maybeSource)) + return true; + } + + return false; + } + std::optional CreateVertexDeclFromName(const std::string& name, const CommonStreamRoutingInfos& routingInfos) { CommonVertexDeclaration result; diff --git a/src/ObjCommon/Techset/CommonVertexDeclCreator.h b/src/ObjCommon/Techset/CommonVertexDeclCreator.h index a3e99b56..3fe80e9c 100644 --- a/src/ObjCommon/Techset/CommonVertexDeclCreator.h +++ b/src/ObjCommon/Techset/CommonVertexDeclCreator.h @@ -7,5 +7,6 @@ namespace techset { + std::optional HasOptionalSourceByName(const std::string& name, const CommonStreamRoutingInfos& routingInfos); std::optional CreateVertexDeclFromName(const std::string& name, const CommonStreamRoutingInfos& routingInfos); -} +} // namespace techset diff --git a/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp b/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp index abe15d9d..aa3a270c 100644 --- a/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp +++ b/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp @@ -1060,13 +1060,13 @@ namespace // The other ones might be handled by the game in the same fashion because there is not recognizable pattern that connects the shaders with the same // flags static std::unordered_map flagsByTechniqueName({ - {"zprepass", TECHNIQUE_FLAG_4 | TECHNIQUE_FLAG_200 }, - {"build_floatz", TECHNIQUE_FLAG_8 }, - {"build_shadowmap_depth", TECHNIQUE_FLAG_10 | TECHNIQUE_FLAG_200}, - {"build_shadowmap_model", TECHNIQUE_FLAG_10 | TECHNIQUE_FLAG_200}, - {"distortion_scale_ua_zfeather", TECHNIQUE_FLAG_100 }, - {"distortion_scale_zfeather", TECHNIQUE_FLAG_100 }, - {"distortion_scale_zfeather_dtex", TECHNIQUE_FLAG_100 }, + {"zprepass", MTL_TECHFLAG_ZPREPASS | TECHNIQUE_FLAG_200 }, + {"build_floatz", MTL_TECHFLAG_BUILD_FLOATZ }, + {"build_shadowmap_depth", MTL_TECHFLAG_BUILD_SHADOW_MAP_DEPTH_OR_MODEL | TECHNIQUE_FLAG_200}, + {"build_shadowmap_model", MTL_TECHFLAG_BUILD_SHADOW_MAP_DEPTH_OR_MODEL | TECHNIQUE_FLAG_200}, + {"distortion_scale_ua_zfeather", MTL_TECHFLAG_USES_DISTORTION_FLOATZ }, + {"distortion_scale_zfeather", MTL_TECHFLAG_USES_DISTORTION_FLOATZ }, + {"distortion_scale_zfeather_dtex", MTL_TECHFLAG_USES_DISTORTION_FLOATZ }, {"alternate_scene_overlay", TECHNIQUE_FLAG_200 }, {"blur_apply", TECHNIQUE_FLAG_200 }, {"build_floatz", TECHNIQUE_FLAG_200 }, @@ -1117,7 +1117,7 @@ namespace const auto& pass = technique.passArray[i]; if (pass.vertexDecl && pass.vertexDecl->hasOptionalSource) { - technique.flags |= TECHNIQUE_FLAG_20; + technique.flags |= MTL_TECHFLAG_DECL_HAS_OPTIONAL_SOURCE; break; } } @@ -1130,16 +1130,16 @@ namespace switch (arg.m_arg.u.codeSampler) { case TEXTURE_SRC_CODE_RESOLVED_POST_SUN: - techniqueFlags |= TECHNIQUE_FLAG_1; + techniqueFlags |= MTL_TECHFLAG_NEEDS_RESOLVED_POST_SUN; break; case TEXTURE_SRC_CODE_RESOLVED_SCENE: - techniqueFlags |= TECHNIQUE_FLAG_2; + techniqueFlags |= MTL_TECHFLAG_NEEDS_RESOLVED_SCENE; break; case TEXTURE_SRC_CODE_FLOATZ: case TEXTURE_SRC_CODE_PROCESSED_FLOATZ: case TEXTURE_SRC_CODE_RAW_FLOATZ: - if ((techniqueFlags & TECHNIQUE_FLAG_100) == 0) - techniqueFlags |= TECHNIQUE_FLAG_80; + if ((techniqueFlags & MTL_TECHFLAG_USES_DISTORTION_FLOATZ) == 0) + techniqueFlags |= MTL_TECHFLAG_USES_FLOATZ; break; default: break; @@ -1151,7 +1151,7 @@ namespace { case CONST_SRC_CODE_LIGHT_SPOTDIR: case CONST_SRC_CODE_LIGHT_SPOTFACTORS: - techniqueFlags |= TECHNIQUE_FLAG_40; + techniqueFlags |= MTL_TECHFLAG_USES_LIGHT_SPOT_FACTORS; break; default: break; diff --git a/src/ObjCompiling/Techset/TechniqueCompiler.cpp.template b/src/ObjCompiling/Techset/TechniqueCompiler.cpp.template index 0bd9b10d..e036374e 100644 --- a/src/ObjCompiling/Techset/TechniqueCompiler.cpp.template +++ b/src/ObjCompiling/Techset/TechniqueCompiler.cpp.template @@ -35,6 +35,7 @@ #include TECHSET_CONSTANTS_HEADER #include "Techset/CommonShaderArgCreator.h" #include "Techset/CommonTechniqueLoader.h" +#include "Techset/CommonVertexDeclCreator.h" #include "Techset/LiteralConstsZoneState.h" #include "Utils/StringUtils.h" @@ -211,7 +212,7 @@ namespace pass.customSamplerFlags = static_cast(commonPass.m_sampler_flags); } - bool AnyDeclHasOptionalSource(const MaterialTechnique& technique) + bool AnyDeclHasOptionalSource(const MaterialTechnique& technique, AssetCreationContext& context) { for (auto passIndex = 0u; passIndex < technique.passCount; passIndex++) { @@ -219,36 +220,52 @@ namespace if (!pass.vertexDecl) continue; +#if defined(SHADERS_ARE_SUBASSETS) if (pass.vertexDecl->hasOptionalSource) return true; +#else + if (pass.vertexDecl->name && pass.vertexDecl->name[0] == ',') + { + if (techset::HasOptionalSourceByName(&pass.vertexDecl->name[1], commonRoutingInfos).value_or(false)) + return true; + } + else if (pass.vertexDecl->hasOptionalSource) + return true; +#endif } return false; } - void UpdateTechniqueFlags(MaterialTechnique& technique, const techset::CommonTechnique& commonTechnique) + void UpdateTechniqueFlags(MaterialTechnique& technique, const techset::CommonTechnique& commonTechnique, AssetCreationContext& context) { -#if defined(FEATURE_IW4) - // TODO -#elif defined(FEATURE_T6) std::string lowerTechniqueName(commonTechnique.m_name); utils::MakeStringLowerCase(lowerTechniqueName); +#if defined(FEATURE_IW4) + // Not a particularly cool way to do this but... + // the game actually does this :shrug: + if (lowerTechniqueName == "zprepass") + technique.flags |= MTL_TECHFLAG_ZPREPASS; + else if (lowerTechniqueName == "build_floatz") + technique.flags |= MTL_TECHFLAG_BUILD_FLOATZ; + else if (lowerTechniqueName == "build_shadowmap_depth" || lowerTechniqueName == "build_shadowmap_model") + technique.flags |= MTL_TECHFLAG_BUILD_SHADOW_MAP_DEPTH_OR_MODEL; + + if (technique.flags & MTL_TECHFLAG_USES_FLOATZ && lowerTechniqueName.starts_with("distortion_")) + technique.flags = (technique.flags & ~MTL_TECHFLAG_USES_FLOATZ) | MTL_TECHFLAG_USES_DISTORTION_FLOATZ; +#elif defined(FEATURE_T6) // Not a particularly cool way to do this but... // the game actually does this :shrug: if (lowerTechniqueName == "zprepass" || lowerTechniqueName.starts_with("pimp_technique_zprepass_") || lowerTechniqueName.starts_with("pimp_technique_layer_zprepass_") || lowerTechniqueName.starts_with("pimp_technique_buildshadowmap_")) { - technique.flags |= TECHNIQUE_FLAG_4; + technique.flags |= MTL_TECHFLAG_ZPREPASS; } #endif - if (AnyDeclHasOptionalSource(technique)) -#if defined(FEATURE_IW4) - technique.flags |= TECHNIQUE_FLAG_20; -#elif defined(FEATURE_T6) - technique.flags |= TECHNIQUE_FLAG_8; -#endif + if (AnyDeclHasOptionalSource(technique, context)) + technique.flags |= MTL_TECHFLAG_DECL_HAS_OPTIONAL_SOURCE; } MaterialTechnique* ConvertTechnique(const techset::CommonTechnique& commonTechnique, AssetCreationContext& context, MemoryManager& memory) @@ -267,7 +284,7 @@ namespace // Take common flags and apply further logic technique->flags = static_cast(commonTechnique.m_flags); - UpdateTechniqueFlags(*technique, commonTechnique); + UpdateTechniqueFlags(*technique, commonTechnique, context); return technique; }