From bb9dba41326a5c6a3d685cdf3437ef9ef2393088 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 6 Mar 2026 20:08:50 +0000 Subject: [PATCH 01/14] chore: add CommonCodeSourceInfos for IW4 --- src/Common/Game/T6/T6_Assets.h | 2 +- .../Game/IW4/Techset/TechsetConstantsIW4.h | 1494 ++++++++++++----- .../Game/T6/Techset/TechsetConstantsT6.h | 2 +- 3 files changed, 1067 insertions(+), 431 deletions(-) diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index d38ed38e..627e3b7d 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -6208,7 +6208,7 @@ namespace T6 MTL_ARG_MATERIAL_PIXEL_CONST = 0x6, MTL_ARG_LITERAL_PIXEL_CONST = 0x7, - MLT_ARG_COUNT, + MTL_ARG_COUNT, }; struct MaterialShaderArgument diff --git a/src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h b/src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h index 0881ff8c..37498377 100644 --- a/src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h +++ b/src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h @@ -2,6 +2,7 @@ #include "Game/IW4/CommonIW4.h" #include "Game/IW4/IW4.h" +#include "Techset/CommonTechnique.h" #include "Techset/CommonTechset.h" #include "Techset/StateMap/StateMapLayout.h" @@ -63,446 +64,1081 @@ namespace IW4 static_assert(std::extent_v == TECHNIQUE_COUNT); static inline techset::CommonTechniqueTypeNames commonTechniqueTypeNames(techniqueTypeNames, std::extent_v); - static inline const char* materialStreamDestinationNames[]{ - "position", - "normal", - "color[0]", - "color[1]", - "depth", - "texcoord[0]", - "texcoord[1]", - "texcoord[2]", - "texcoord[3]", - "texcoord[4]", - "texcoord[5]", - "texcoord[6]", - "texcoord[7]", + static inline techset::CommonStreamRoutingSourceInfo streamRoutingSources[]{ + { + .name = "position", + .abbreviation = "p", + .optional = false, + }, + { + .name = "color", + .abbreviation = "c", + .optional = false, + }, + { + .name = "texcoord[0]", + .abbreviation = "t0", + .optional = false, + }, + { + .name = "normal", + .abbreviation = "n", + .optional = false, + }, + { + .name = "tangent", + .abbreviation = "t", + .optional = false, + }, + { + .name = "texcoord[1]", + .abbreviation = "t1", + .optional = false, + }, + { + .name = "texcoord[2]", + .abbreviation = "t2", + .optional = true, + }, + { + .name = "normalTransform[0]", + .abbreviation = "n0", + .optional = true, + }, + { + .name = "normalTransform[1]", + .abbreviation = "n1", + .optional = true, + }, }; - static_assert(std::extent_v == STREAM_DST_COUNT); + static_assert(std::extent_v == STREAM_SRC_COUNT); - static inline const char* materialStreamDestinationAbbreviation[]{ - "p", - "n", - "c0", - "c1", - "d", - "t0", - "t1", - "t2", - "t3", - "t4", - "t5", - "t6", - "t7", + static inline techset::CommonStreamRoutingDestinationInfo streamRoutingDestinations[]{ + { + .name = "position", + .abbreviation = "p", + }, + { + .name = "normal", + .abbreviation = "n", + }, + { + .name = "color[0]", + .abbreviation = "c0", + }, + { + .name = "color[1]", + .abbreviation = "c1", + }, + { + .name = "depth", + .abbreviation = "d", + }, + { + .name = "texcoord[0]", + .abbreviation = "t0", + }, + { + .name = "texcoord[1]", + .abbreviation = "t1", + }, + { + .name = "texcoord[2]", + .abbreviation = "t2", + }, + { + .name = "texcoord[3]", + .abbreviation = "t3", + }, + { + .name = "texcoord[4]", + .abbreviation = "t4", + }, + { + .name = "texcoord[5]", + .abbreviation = "t5", + }, + { + .name = "texcoord[6]", + .abbreviation = "t6", + }, + { + .name = "texcoord[7]", + .abbreviation = "t7", + }, }; - static_assert(std::extent_v == STREAM_DST_COUNT); + static_assert(std::extent_v == STREAM_DST_COUNT); - static inline const char* materialStreamSourceNames[]{ - "position", - "color", - "texcoord[0]", - "normal", - "tangent", - "texcoord[1]", - "texcoord[2]", - "normalTransform[0]", - "normalTransform[1]", - }; - static_assert(std::extent_v == STREAM_SRC_COUNT); + static inline techset::CommonStreamRoutingInfos commonRoutingInfos(streamRoutingSources, + std::extent_v, + streamRoutingDestinations, + std::extent_v); - static inline const char* materialStreamSourceAbbreviation[]{ - "p", - "c", - "t0", - "n", - "t", - "t1", - "t2", - "n0", - "n1", - }; - static_assert(std::extent_v == STREAM_SRC_COUNT); - - static inline CodeSamplerSource s_lightmapSamplers[]{ - {"primary", TEXTURE_SRC_CODE_LIGHTMAP_PRIMARY, nullptr, 0, 0}, - {"secondary", TEXTURE_SRC_CODE_LIGHTMAP_SECONDARY, nullptr, 0, 0}, - {}, + static inline techset::CommonCodeConstSourceInfo commonCodeConstSources[]{ + { + .value = CONST_SRC_CODE_LIGHT_POSITION, + .accessor = "lightPosition", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_LIGHT_DIFFUSE, + .accessor = "lightDiffuse", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_LIGHT_SPECULAR, + .accessor = "lightSpecular", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_LIGHT_SPOTDIR, + .accessor = "lightSpotDir", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_LIGHT_SPOTFACTORS, + .accessor = "lightSpotFactors", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_LIGHT_FALLOFF_PLACEMENT, + .accessor = "lightFalloffPlacement", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_PARTICLE_CLOUD_COLOR, + .accessor = "particleCloudColor", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_GAMETIME, + .accessor = "gameTime", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_PIXEL_COST_FRACS, + .accessor = "pixelCostFracs", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_PIXEL_COST_DECODE, + .accessor = "pixelCostDecode", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_FILTER_TAP_0, + .accessor = "filterTap", + .arrayCount = 8, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_COLOR_MATRIX_R, + .accessor = "colorMatrixR", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_COLOR_MATRIX_G, + .accessor = "colorMatrixG", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_COLOR_MATRIX_B, + .accessor = "colorMatrixB", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_SHADOWMAP_POLYGON_OFFSET, + .accessor = "shadowmapPolygonOffset", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_RENDER_TARGET_SIZE, + .accessor = "renderTargetSize", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_DOF_EQUATION_VIEWMODEL_AND_FAR_BLUR, + .accessor = "dofEquationViewModelAndFarBlur", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_DOF_EQUATION_SCENE, + .accessor = "dofEquationScene", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_DOF_LERP_SCALE, + .accessor = "dofLerpScale", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_DOF_LERP_BIAS, + .accessor = "dofLerpBias", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_DOF_ROW_DELTA, + .accessor = "dofRowDelta", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_MOTION_MATRIX_X, + .accessor = "motionMatrixX", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_MOTION_MATRIX_Y, + .accessor = "motionMatrixY", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_MOTION_MATRIX_W, + .accessor = "motionMatrixW", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_SHADOWMAP_SWITCH_PARTITION, + .accessor = "shadowmapSwitchPartition", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_SHADOWMAP_SCALE, + .accessor = "shadowmapScale", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_ZNEAR, + .accessor = "zNear", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_LIGHTING_LOOKUP_SCALE, + .accessor = "lightingLookupScale", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_DEBUG_BUMPMAP, + .accessor = "debugBumpmap", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_MATERIAL_COLOR, + .accessor = "materialColor", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_FOG, + .accessor = "fogConsts", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_FOG_COLOR_LINEAR, + .accessor = "fogColorLinear", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_FOG_COLOR_GAMMA, + .accessor = "fogColorGamma", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_FOG_SUN_CONSTS, + .accessor = "fogSunConsts", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_FOG_SUN_COLOR_LINEAR, + .accessor = "fogSunColorLinear", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_FOG_SUN_COLOR_GAMMA, + .accessor = "fogSunColorGamma", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_FOG_SUN_DIR, + .accessor = "fogSunDir", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_GLOW_SETUP, + .accessor = "glowSetup", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_GLOW_APPLY, + .accessor = "glowApply", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_COLOR_BIAS, + .accessor = "colorBias", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_COLOR_TINT_BASE, + .accessor = "colorTintBase", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_COLOR_TINT_DELTA, + .accessor = "colorTintDelta", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_COLOR_TINT_QUADRATIC_DELTA, + .accessor = "colorTintQuadraticDelta", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_OUTDOOR_FEATHER_PARMS, + .accessor = "outdoorFeatherParms", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_ENVMAP_PARMS, + .accessor = "envMapParms", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_SUN_SHADOWMAP_PIXEL_ADJUST, + .accessor = "sunShadowmapPixelAdjust", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_SPOT_SHADOWMAP_PIXEL_ADJUST, + .accessor = "spotShadowmapPixelAdjust", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_COMPOSITE_FX_DISTORTION, + .accessor = "fullscreenDistortion", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_POSTFX_FADE_EFFECT, + .accessor = "fadeEffect", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_VIEWPORT_DIMENSIONS, + .accessor = "viewportDimensions", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_FRAMEBUFFER_READ, + .accessor = "framebufferRead", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_BASE_LIGHTING_COORDS, + .accessor = "baseLightingCoords", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + }, + { + .value = CONST_SRC_CODE_LIGHT_PROBE_AMBIENT, + .accessor = "lightprobeAmbient", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + }, + { + .value = CONST_SRC_CODE_NEARPLANE_ORG, + .accessor = "nearPlaneOrg", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_NEARPLANE_DX, + .accessor = "nearPlaneDx", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_NEARPLANE_DY, + .accessor = "nearPlaneDy", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_CLIP_SPACE_LOOKUP_SCALE, + .accessor = "clipSpaceLookupScale", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_CLIP_SPACE_LOOKUP_OFFSET, + .accessor = "clipSpaceLookupOffset", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX0, + .accessor = "particleCloudMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX1, + .accessor = "particleCloudMatrix1", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX2, + .accessor = "particleCloudMatrix2", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = CONST_SRC_CODE_PARTICLE_CLOUD_SPARK_COLOR0, + .accessor = "particleCloudSparkColor0", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = CONST_SRC_CODE_PARTICLE_CLOUD_SPARK_COLOR1, + .accessor = "particleCloudSparkColor1", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = CONST_SRC_CODE_PARTICLE_CLOUD_SPARK_COLOR2, + .accessor = "particleCloudSparkColor2", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = CONST_SRC_CODE_PARTICLE_FOUNTAIN_PARM0, + .accessor = "particleFountainParms0", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = CONST_SRC_CODE_PARTICLE_FOUNTAIN_PARM1, + .accessor = "particleFountainParms1", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = CONST_SRC_CODE_DEPTH_FROM_CLIP, + .accessor = "depthFromClip", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = CONST_SRC_CODE_CODE_MESH_ARG_0, + .accessor = "codeMeshArg", + .arrayCount = 2, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = CONST_SRC_CODE_VIEW_MATRIX, + .accessor = "viewMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_VIEW_MATRIX, + }, + { + .value = CONST_SRC_CODE_INVERSE_VIEW_MATRIX, + .accessor = "inverseViewMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_MATRIX, + }, + { + .value = CONST_SRC_CODE_TRANSPOSE_VIEW_MATRIX, + .accessor = "transposeViewMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .transposedMatrix = CONST_SRC_CODE_VIEW_MATRIX, + }, + { + .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_MATRIX, + .accessor = "inverseTransposeViewMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .transposedMatrix = CONST_SRC_CODE_INVERSE_VIEW_MATRIX, + }, + { + .value = CONST_SRC_CODE_PROJECTION_MATRIX, + .accessor = "projectionMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_PROJECTION_MATRIX, + }, + { + .value = CONST_SRC_CODE_INVERSE_PROJECTION_MATRIX, + .accessor = "inverseProjectionMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_PROJECTION_MATRIX, + }, + { + .value = CONST_SRC_CODE_TRANSPOSE_PROJECTION_MATRIX, + .accessor = "transposeProjectionMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .transposedMatrix = CONST_SRC_CODE_PROJECTION_MATRIX, + }, + { + .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_PROJECTION_MATRIX, + .accessor = "inverseTransposeProjectionMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .transposedMatrix = CONST_SRC_CODE_INVERSE_PROJECTION_MATRIX, + }, + { + .value = CONST_SRC_CODE_VIEW_PROJECTION_MATRIX, + .accessor = "viewProjectionMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_VIEW_PROJECTION_MATRIX, + }, + { + .value = CONST_SRC_CODE_INVERSE_VIEW_PROJECTION_MATRIX, + .accessor = "inverseViewProjectionMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_PROJECTION_MATRIX, + }, + { + .value = CONST_SRC_CODE_TRANSPOSE_VIEW_PROJECTION_MATRIX, + .accessor = "transposeViewProjectionMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .transposedMatrix = CONST_SRC_CODE_VIEW_PROJECTION_MATRIX, + }, + { + .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_PROJECTION_MATRIX, + .accessor = "inverseTransposeViewProjectionMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .transposedMatrix = CONST_SRC_CODE_INVERSE_VIEW_PROJECTION_MATRIX, + }, + { + .value = CONST_SRC_CODE_SHADOW_LOOKUP_MATRIX, + .accessor = "shadowLookupMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_SHADOW_LOOKUP_MATRIX, + }, + { + .value = CONST_SRC_CODE_INVERSE_SHADOW_LOOKUP_MATRIX, + .accessor = "inverseShadowLookupMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_SHADOW_LOOKUP_MATRIX, + }, + { + .value = CONST_SRC_CODE_TRANSPOSE_SHADOW_LOOKUP_MATRIX, + .accessor = "transposeShadowLookupMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .transposedMatrix = CONST_SRC_CODE_SHADOW_LOOKUP_MATRIX, + }, + { + .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_SHADOW_LOOKUP_MATRIX, + .accessor = "inverseTransposeShadowLookupMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .transposedMatrix = CONST_SRC_CODE_INVERSE_SHADOW_LOOKUP_MATRIX, + }, + { + .value = CONST_SRC_CODE_WORLD_OUTDOOR_LOOKUP_MATRIX, + .accessor = "worldOutdoorLookupMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX, + }, + { + .value = CONST_SRC_CODE_INVERSE_WORLD_OUTDOOR_LOOKUP_MATRIX, + .accessor = "inverseWorldOutdoorLookupMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX, + }, + { + .value = CONST_SRC_CODE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX, + .accessor = "transposeWorldOutdoorLookupMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_WORLD_OUTDOOR_LOOKUP_MATRIX, + }, + { + .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX, + .accessor = "inverseTransposeWorldOutdoorLookupMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_WORLD_OUTDOOR_LOOKUP_MATRIX, + }, + { + .value = CONST_SRC_CODE_WORLD_MATRIX0, + .accessor = "worldMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX0, + }, + { + .value = CONST_SRC_CODE_INVERSE_WORLD_MATRIX0, + .accessor = "inverseWorldMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX0, + }, + { + .value = CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX0, + .accessor = "transposeWorldMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_WORLD_MATRIX0, + }, + { + .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX0, + .accessor = "inverseTransposeWorldMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_WORLD_MATRIX0, + }, + { + .value = CONST_SRC_CODE_WORLD_VIEW_MATRIX0, + .accessor = "worldViewMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX0, + }, + { + .value = CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX0, + .accessor = "inverseWorldViewMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX0, + }, + { + .value = CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX0, + .accessor = "transposeWorldViewMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_WORLD_VIEW_MATRIX0, + }, + { + .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX0, + .accessor = "inverseTransposeWorldViewMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX0, + }, + { + .value = CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX0, + .accessor = "worldViewProjectionMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX0, + }, + { + .value = CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX0, + .accessor = "inverseWorldViewProjectionMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX0, + }, + { + .value = CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX0, + .accessor = "transposeWorldViewProjectionMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX0, + }, + { + .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX0, + .accessor = "inverseTransposeWorldViewProjectionMatrix", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX0, + }, + { + .value = CONST_SRC_CODE_WORLD_MATRIX1, + .accessor = "worldMatrix1", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX1, + }, + { + .value = CONST_SRC_CODE_INVERSE_WORLD_MATRIX1, + .accessor = "inverseWorldMatrix1", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX1, + }, + { + .value = CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX1, + .accessor = "transposeWorldMatrix1", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_WORLD_MATRIX1, + }, + { + .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX1, + .accessor = "inverseTransposeWorldMatrix1", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_WORLD_MATRIX1, + }, + { + .value = CONST_SRC_CODE_WORLD_VIEW_MATRIX1, + .accessor = "worldViewMatrix1", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX1, + }, + { + .value = CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX1, + .accessor = "inverseWorldViewMatrix1", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX1, + }, + { + .value = CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX1, + .accessor = "transposeWorldViewMatrix1", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_WORLD_VIEW_MATRIX1, + }, + { + .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX1, + .accessor = "inverseTransposeWorldViewMatrix1", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX1, + }, + { + .value = CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX1, + .accessor = "worldViewProjectionMatrix1", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX1, + }, + { + .value = CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX1, + .accessor = "inverseWorldViewProjectionMatrix1", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX1, + }, + { + .value = CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX1, + .accessor = "transposeWorldViewProjectionMatrix1", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX1, + }, + { + .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX1, + .accessor = "inverseTransposeWorldViewProjectionMatrix1", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX1, + }, + { + .value = CONST_SRC_CODE_WORLD_MATRIX2, + .accessor = "worldMatrix2", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX2, + }, + { + .value = CONST_SRC_CODE_INVERSE_WORLD_MATRIX2, + .accessor = "inverseWorldMatrix2", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX2, + }, + { + .value = CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX2, + .accessor = "transposeWorldMatrix2", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_WORLD_MATRIX2, + }, + { + .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX2, + .accessor = "inverseTransposeWorldMatrix2", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_WORLD_MATRIX2, + }, + { + .value = CONST_SRC_CODE_WORLD_VIEW_MATRIX2, + .accessor = "worldViewMatrix2", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX2, + }, + { + .value = CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX2, + .accessor = "inverseWorldViewMatrix2", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX2, + }, + { + .value = CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX2, + .accessor = "transposeWorldViewMatrix2", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_WORLD_VIEW_MATRIX2, + }, + { + .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX2, + .accessor = "inverseTransposeWorldViewMatrix2", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX2, + }, + { + .value = CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX2, + .accessor = "worldViewProjectionMatrix2", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX2, + }, + { + .value = CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX2, + .accessor = "inverseWorldViewProjectionMatrix2", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX2, + }, + { + .value = CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX2, + .accessor = "transposeWorldViewProjectionMatrix2", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX2, + }, + { + .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX2, + .accessor = "inverseTransposeWorldViewProjectionMatrix2", + .arrayCount = 0, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX2, + }, }; - static inline CodeSamplerSource s_lightSamplers[]{ - {"attenuation", TEXTURE_SRC_CODE_LIGHT_ATTENUATION, nullptr, 0, 0}, - {}, + static inline techset::CommonCodeSamplerSourceInfo commonCodeSamplerSources[]{ + { + .value = TEXTURE_SRC_CODE_BLACK, + .accessor = "black", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = TEXTURE_SRC_CODE_WHITE, + .accessor = "white", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = TEXTURE_SRC_CODE_IDENTITY_NORMAL_MAP, + .accessor = "identityNormalMap", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = TEXTURE_SRC_CODE_MODEL_LIGHTING, + .accessor = "modelLightingSampler", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = TEXTURE_SRC_CODE_LIGHTMAP_PRIMARY, + .accessor = "lightmapSamplerPrimary", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::CUSTOM, + .customSamplerIndex = CUSTOM_SAMPLER_LIGHTMAP_PRIMARY, + }, + { + .value = TEXTURE_SRC_CODE_LIGHTMAP_SECONDARY, + .accessor = "lightmapSamplerSecondary", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::CUSTOM, + .customSamplerIndex = CUSTOM_SAMPLER_LIGHTMAP_SECONDARY, + }, + { + .value = TEXTURE_SRC_CODE_SHADOWMAP_SUN, + .accessor = "shadowmapSamplerSun", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = TEXTURE_SRC_CODE_SHADOWMAP_SPOT, + .accessor = "shadowmapSamplerSpot", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = TEXTURE_SRC_CODE_FEEDBACK, + .accessor = "feedbackSampler", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = TEXTURE_SRC_CODE_RESOLVED_POST_SUN, + .accessor = "resolvedPostSun", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = TEXTURE_SRC_CODE_RESOLVED_SCENE, + .accessor = "resolvedScene", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = TEXTURE_SRC_CODE_POST_EFFECT_0, + .accessor = "postEffect0", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = TEXTURE_SRC_CODE_POST_EFFECT_1, + .accessor = "postEffect1", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = TEXTURE_SRC_CODE_LIGHT_ATTENUATION, + .accessor = "attenuationSampler", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = TEXTURE_SRC_CODE_OUTDOOR, + .accessor = "outdoor", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = TEXTURE_SRC_CODE_FLOATZ, + .accessor = "floatZSampler", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = TEXTURE_SRC_CODE_PROCESSED_FLOATZ, + .accessor = "processedFloatZSampler", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = TEXTURE_SRC_CODE_RAW_FLOATZ, + .accessor = "rawFloatZSampler", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = TEXTURE_SRC_CODE_HALF_PARTICLES, + .accessor = "halfParticleColorSampler", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = TEXTURE_SRC_CODE_HALF_PARTICLES_Z, + .accessor = "halfParticleDepthSampler", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, + { + .value = TEXTURE_SRC_CODE_CASE_TEXTURE, + .accessor = "caseTexture" /* ? */, + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = TEXTURE_SRC_CODE_CINEMATIC_Y, + .accessor = "cinematicYSampler", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = TEXTURE_SRC_CODE_CINEMATIC_CR, + .accessor = "cinematicCrSampler", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = TEXTURE_SRC_CODE_CINEMATIC_CB, + .accessor = "cinematicCbSampler", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = TEXTURE_SRC_CODE_CINEMATIC_A, + .accessor = "cinematicASampler", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + }, + { + .value = TEXTURE_SRC_CODE_REFLECTION_PROBE, + .accessor = "reflectionProbeSampler", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::CUSTOM, + .customSamplerIndex = CUSTOM_SAMPLER_REFLECTION_PROBE, + }, + { + .value = TEXTURE_SRC_CODE_ALTERNATE_SCENE, + .accessor = "alternateSceneSampler", + .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + }, }; - static inline CodeSamplerSource s_codeSamplers[]{ - {"white", TEXTURE_SRC_CODE_WHITE, nullptr, 0, 0}, - {"black", TEXTURE_SRC_CODE_BLACK, nullptr, 0, 0}, - {"identityNormalMap", TEXTURE_SRC_CODE_IDENTITY_NORMAL_MAP, nullptr, 0, 0}, - {"lightmap", TEXTURE_SRC_CODE_LIGHTMAP_PRIMARY, s_lightmapSamplers, 0, 0}, - {"outdoor", TEXTURE_SRC_CODE_OUTDOOR, nullptr, 0, 0}, - {"shadowmapSun", TEXTURE_SRC_CODE_SHADOWMAP_SUN, nullptr, 0, 0}, - {"shadowmapSpot", TEXTURE_SRC_CODE_SHADOWMAP_SPOT, nullptr, 0, 0}, - {"feedback", TEXTURE_SRC_CODE_FEEDBACK, nullptr, 0, 0}, - {"resolvedPostSun", TEXTURE_SRC_CODE_RESOLVED_POST_SUN, nullptr, 0, 0}, - {"resolvedScene", TEXTURE_SRC_CODE_RESOLVED_SCENE, nullptr, 0, 0}, - {"postEffect0", TEXTURE_SRC_CODE_POST_EFFECT_0, nullptr, 0, 0}, - {"postEffect1", TEXTURE_SRC_CODE_POST_EFFECT_1, nullptr, 0, 0}, - {"light", TEXTURE_SRC_CODE_LIGHT_ATTENUATION, s_lightSamplers, 0, 0}, - {"floatZ", TEXTURE_SRC_CODE_FLOATZ, nullptr, 0, 0}, - {"processedFloatZ", TEXTURE_SRC_CODE_PROCESSED_FLOATZ, nullptr, 0, 0}, - {"rawFloatZ", TEXTURE_SRC_CODE_RAW_FLOATZ, nullptr, 0, 0}, - {"halfParticleColorSampler", TEXTURE_SRC_CODE_HALF_PARTICLES, nullptr, 0, 0}, - {"halfParticleDepthSampler", TEXTURE_SRC_CODE_HALF_PARTICLES_Z, nullptr, 0, 0}, - {"alternateScene", TEXTURE_SRC_CODE_ALTERNATE_SCENE, nullptr, 0, 0}, - {}, + // See MaterialShaderArgumentType + static inline techset::CommonShaderArgumentType commonArgumentTypes[]{ + {.m_shader_type = techset::CommonTechniqueShaderType::VERTEX, .m_value_type = techset::CommonShaderValueType::MATERIAL_CONST }, + {.m_shader_type = techset::CommonTechniqueShaderType::VERTEX, .m_value_type = techset::CommonShaderValueType::LITERAL_CONST }, + {.m_shader_type = techset::CommonTechniqueShaderType::PIXEL, .m_value_type = techset::CommonShaderValueType::MATERIAL_SAMPLER}, + {.m_shader_type = techset::CommonTechniqueShaderType::VERTEX, .m_value_type = techset::CommonShaderValueType::CODE_CONST }, + {.m_shader_type = techset::CommonTechniqueShaderType::PIXEL, .m_value_type = techset::CommonShaderValueType::CODE_SAMPLER }, + {.m_shader_type = techset::CommonTechniqueShaderType::PIXEL, .m_value_type = techset::CommonShaderValueType::CODE_CONST }, + {.m_shader_type = techset::CommonTechniqueShaderType::PIXEL, .m_value_type = techset::CommonShaderValueType::MATERIAL_CONST }, + {.m_shader_type = techset::CommonTechniqueShaderType::PIXEL, .m_value_type = techset::CommonShaderValueType::LITERAL_CONST }, }; + static_assert(std::extent_v == MTL_ARG_COUNT); - static inline CodeSamplerSource s_defaultCodeSamplers[]{ - {"shadowmapSamplerSun", TEXTURE_SRC_CODE_SHADOWMAP_SUN, nullptr, 0, 0}, - {"shadowmapSamplerSpot", TEXTURE_SRC_CODE_SHADOWMAP_SPOT, nullptr, 0, 0}, - {"feedbackSampler", TEXTURE_SRC_CODE_FEEDBACK, nullptr, 0, 0}, - {"floatZSampler", TEXTURE_SRC_CODE_FLOATZ, nullptr, 0, 0}, - {"processedFloatZSampler", TEXTURE_SRC_CODE_PROCESSED_FLOATZ, nullptr, 0, 0}, - {"rawFloatZSampler", TEXTURE_SRC_CODE_RAW_FLOATZ, nullptr, 0, 0}, - {"halfParticleColorSampler", TEXTURE_SRC_CODE_HALF_PARTICLES, nullptr, 0, 0}, - {"halfParticleDepthSampler", TEXTURE_SRC_CODE_HALF_PARTICLES_Z, nullptr, 0, 0}, - {"attenuationSampler", TEXTURE_SRC_CODE_LIGHT_ATTENUATION, nullptr, 0, 0}, - {"lightmapSamplerPrimary", TEXTURE_SRC_CODE_LIGHTMAP_PRIMARY, nullptr, 0, 0}, - {"lightmapSamplerSecondary", TEXTURE_SRC_CODE_LIGHTMAP_SECONDARY, nullptr, 0, 0}, - {"modelLightingSampler", TEXTURE_SRC_CODE_MODEL_LIGHTING, nullptr, 0, 0}, - {"cinematicYSampler", TEXTURE_SRC_CODE_CINEMATIC_Y, nullptr, 0, 0}, - {"cinematicCrSampler", TEXTURE_SRC_CODE_CINEMATIC_CR, nullptr, 0, 0}, - {"cinematicCbSampler", TEXTURE_SRC_CODE_CINEMATIC_CB, nullptr, 0, 0}, - {"cinematicASampler", TEXTURE_SRC_CODE_CINEMATIC_A, nullptr, 0, 0}, - {"reflectionProbeSampler", TEXTURE_SRC_CODE_REFLECTION_PROBE, nullptr, 0, 0}, - {"alternateSceneSampler", TEXTURE_SRC_CODE_ALTERNATE_SCENE, nullptr, 0, 0}, - {}, - }; - - static inline CodeConstantSource s_sunConsts[]{ - {"position", CONST_SRC_CODE_LIGHT_POSITION, nullptr, 0, 0}, - {"diffuse", CONST_SRC_CODE_LIGHT_DIFFUSE, nullptr, 0, 0}, - {"specular", CONST_SRC_CODE_LIGHT_SPECULAR, nullptr, 0, 0}, - {"spotDir", CONST_SRC_CODE_LIGHT_SPOTDIR, nullptr, 0, 0}, - {"spotFactors", CONST_SRC_CODE_LIGHT_SPOTFACTORS, nullptr, 0, 0}, - {"falloffPlacement", CONST_SRC_CODE_LIGHT_FALLOFF_PLACEMENT, nullptr, 0, 0}, - {}, - }; - - static inline CodeConstantSource s_nearPlaneConsts[]{ - {"org", CONST_SRC_CODE_NEARPLANE_ORG, nullptr, 0, 0}, - {"dx", CONST_SRC_CODE_NEARPLANE_DX, nullptr, 0, 0}, - {"dy", CONST_SRC_CODE_NEARPLANE_DY, nullptr, 0, 0}, - {}, - }; - - static inline CodeConstantSource s_codeConsts[]{ - {"nearPlane", CONST_SRC_NONE, s_nearPlaneConsts, 0, 0}, - {"light", CONST_SRC_NONE, s_sunConsts, 0, 0}, - {"baseLightingCoords", CONST_SRC_CODE_BASE_LIGHTING_COORDS, nullptr, 0, 0}, - {"lightprobeAmbient", CONST_SRC_CODE_LIGHT_PROBE_AMBIENT, nullptr, 0, 0}, - {"fullscreenDistortion", CONST_SRC_CODE_COMPOSITE_FX_DISTORTION, nullptr, 0, 0}, - {"fadeEffect", CONST_SRC_CODE_POSTFX_FADE_EFFECT, nullptr, 0, 0}, - {"lightingLookupScale", CONST_SRC_CODE_LIGHTING_LOOKUP_SCALE, nullptr, 0, 0}, - {"debugBumpmap", CONST_SRC_CODE_DEBUG_BUMPMAP, nullptr, 0, 0}, - {"pixelCostFracs", CONST_SRC_CODE_PIXEL_COST_FRACS, nullptr, 0, 0}, - {"pixelCostDecode", CONST_SRC_CODE_PIXEL_COST_DECODE, nullptr, 0, 0}, - {"materialColor", CONST_SRC_CODE_MATERIAL_COLOR, nullptr, 0, 0}, - {"fogConsts", CONST_SRC_CODE_FOG, nullptr, 0, 0}, - {"fogColorLinear", CONST_SRC_CODE_FOG_COLOR_LINEAR, nullptr, 0, 0}, - {"fogColorGamma", CONST_SRC_CODE_FOG_COLOR_GAMMA, nullptr, 0, 0}, - {"fogSunConsts", CONST_SRC_CODE_FOG_SUN_CONSTS, nullptr, 0, 0}, - {"fogSunColorLinear", CONST_SRC_CODE_FOG_SUN_COLOR_LINEAR, nullptr, 0, 0}, - {"fogSunColorGamma", CONST_SRC_CODE_FOG_SUN_COLOR_GAMMA, nullptr, 0, 0}, - {"fogSunDir", CONST_SRC_CODE_FOG_SUN_DIR, nullptr, 0, 0}, - {"glowSetup", CONST_SRC_CODE_GLOW_SETUP, nullptr, 0, 0}, - {"glowApply", CONST_SRC_CODE_GLOW_APPLY, nullptr, 0, 0}, - {"filterTap", CONST_SRC_CODE_FILTER_TAP_0, nullptr, 8, 1}, - {"codeMeshArg", CONST_SRC_CODE_CODE_MESH_ARG_0, nullptr, 2, 1}, - {"renderTargetSize", CONST_SRC_CODE_RENDER_TARGET_SIZE, nullptr, 0, 0}, - {"shadowmapSwitchPartition", CONST_SRC_CODE_SHADOWMAP_SWITCH_PARTITION, nullptr, 0, 0}, - {"shadowmapScale", CONST_SRC_CODE_SHADOWMAP_SCALE, nullptr, 0, 0}, - {"shadowmapPolygonOffset", CONST_SRC_CODE_SHADOWMAP_POLYGON_OFFSET, nullptr, 0, 0}, - {"zNear", CONST_SRC_CODE_ZNEAR, nullptr, 0, 0}, - {"clipSpaceLookupScale", CONST_SRC_CODE_CLIP_SPACE_LOOKUP_SCALE, nullptr, 0, 0}, - {"clipSpaceLookupOffset", CONST_SRC_CODE_CLIP_SPACE_LOOKUP_OFFSET, nullptr, 0, 0}, - {"dofEquationViewModelAndFarBlur", CONST_SRC_CODE_DOF_EQUATION_VIEWMODEL_AND_FAR_BLUR, nullptr, 0, 0}, - {"dofEquationScene", CONST_SRC_CODE_DOF_EQUATION_SCENE, nullptr, 0, 0}, - {"dofLerpScale", CONST_SRC_CODE_DOF_LERP_SCALE, nullptr, 0, 0}, - {"dofLerpBias", CONST_SRC_CODE_DOF_LERP_BIAS, nullptr, 0, 0}, - {"dofRowDelta", CONST_SRC_CODE_DOF_ROW_DELTA, nullptr, 0, 0}, - {"depthFromClip", CONST_SRC_CODE_DEPTH_FROM_CLIP, nullptr, 0, 0}, - {"outdoorFeatherParms", CONST_SRC_CODE_OUTDOOR_FEATHER_PARMS, nullptr, 0, 0}, - {"envMapParms", CONST_SRC_CODE_ENVMAP_PARMS, nullptr, 0, 0}, - {"colorMatrixR", CONST_SRC_CODE_COLOR_MATRIX_R, nullptr, 0, 0}, - {"colorMatrixG", CONST_SRC_CODE_COLOR_MATRIX_G, nullptr, 0, 0}, - {"colorMatrixB", CONST_SRC_CODE_COLOR_MATRIX_B, nullptr, 0, 0}, - {"colorBias", CONST_SRC_CODE_COLOR_BIAS, nullptr, 0, 0}, - {"colorTintBase", CONST_SRC_CODE_COLOR_TINT_BASE, nullptr, 0, 0}, - {"colorTintDelta", CONST_SRC_CODE_COLOR_TINT_DELTA, nullptr, 0, 0}, - {"colorTintQuadraticDelta", CONST_SRC_CODE_COLOR_TINT_QUADRATIC_DELTA, nullptr, 0, 0}, - {"motionMatrixX", CONST_SRC_CODE_MOTION_MATRIX_X, nullptr, 0, 0}, - {"motionMatrixY", CONST_SRC_CODE_MOTION_MATRIX_Y, nullptr, 0, 0}, - {"motionMatrixW", CONST_SRC_CODE_MOTION_MATRIX_W, nullptr, 0, 0}, - {"gameTime", CONST_SRC_CODE_GAMETIME, nullptr, 0, 0}, - {"particleCloudColor", CONST_SRC_CODE_PARTICLE_CLOUD_COLOR, nullptr, 0, 0}, - {"particleCloudMatrix", CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX0, nullptr, 0, 0}, - {"particleCloudMatrix1", CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX1, nullptr, 0, 0}, - {"particleCloudMatrix2", CONST_SRC_CODE_PARTICLE_CLOUD_MATRIX2, nullptr, 0, 0}, - {"particleCloudSparkColor0", CONST_SRC_CODE_PARTICLE_CLOUD_SPARK_COLOR0, nullptr, 0, 0}, - {"particleCloudSparkColor1", CONST_SRC_CODE_PARTICLE_CLOUD_SPARK_COLOR1, nullptr, 0, 0}, - {"particleCloudSparkColor2", CONST_SRC_CODE_PARTICLE_CLOUD_SPARK_COLOR2, nullptr, 0, 0}, - {"particleFountainParms0", CONST_SRC_CODE_PARTICLE_FOUNTAIN_PARM0, nullptr, 0, 0}, - {"particleFountainParms1", CONST_SRC_CODE_PARTICLE_FOUNTAIN_PARM1, nullptr, 0, 0}, - {"viewportDimensions", CONST_SRC_CODE_VIEWPORT_DIMENSIONS, nullptr, 0, 0}, - {"framebufferRead", CONST_SRC_CODE_FRAMEBUFFER_READ, nullptr, 0, 0}, - {"viewMatrix", CONST_SRC_CODE_VIEW_MATRIX, nullptr, 0, 0}, - {"inverseViewMatrix", CONST_SRC_CODE_INVERSE_VIEW_MATRIX, nullptr, 0, 0}, - {"transposeViewMatrix", CONST_SRC_CODE_TRANSPOSE_VIEW_MATRIX, nullptr, 0, 0}, - {"inverseTransposeViewMatrix", CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_MATRIX, nullptr, 0, 0}, - {"projectionMatrix", CONST_SRC_CODE_PROJECTION_MATRIX, nullptr, 0, 0}, - {"inverseProjectionMatrix", CONST_SRC_CODE_INVERSE_PROJECTION_MATRIX, nullptr, 0, 0}, - {"transposeProjectionMatrix", CONST_SRC_CODE_TRANSPOSE_PROJECTION_MATRIX, nullptr, 0, 0}, - {"inverseTransposeProjectionMatrix", CONST_SRC_CODE_INVERSE_TRANSPOSE_PROJECTION_MATRIX, nullptr, 0, 0}, - {"viewProjectionMatrix", CONST_SRC_CODE_VIEW_PROJECTION_MATRIX, nullptr, 0, 0}, - {"inverseViewProjectionMatrix", CONST_SRC_CODE_INVERSE_VIEW_PROJECTION_MATRIX, nullptr, 0, 0}, - {"transposeViewProjectionMatrix", CONST_SRC_CODE_TRANSPOSE_VIEW_PROJECTION_MATRIX, nullptr, 0, 0}, - {"inverseTransposeViewProjectionMatrix", CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_PROJECTION_MATRIX, nullptr, 0, 0}, - {"shadowLookupMatrix", CONST_SRC_CODE_SHADOW_LOOKUP_MATRIX, nullptr, 0, 0}, - {"inverseShadowLookupMatrix", CONST_SRC_CODE_INVERSE_SHADOW_LOOKUP_MATRIX, nullptr, 0, 0}, - {"transposeShadowLookupMatrix", CONST_SRC_CODE_TRANSPOSE_SHADOW_LOOKUP_MATRIX, nullptr, 0, 0}, - {"inverseTransposeShadowLookupMatrix", CONST_SRC_CODE_INVERSE_TRANSPOSE_SHADOW_LOOKUP_MATRIX, nullptr, 0, 0}, - {"worldOutdoorLookupMatrix", CONST_SRC_CODE_WORLD_OUTDOOR_LOOKUP_MATRIX, nullptr, 0, 0}, - {"inverseWorldOutdoorLookupMatrix", CONST_SRC_CODE_INVERSE_WORLD_OUTDOOR_LOOKUP_MATRIX, nullptr, 0, 0}, - {"transposeWorldOutdoorLookupMatrix", CONST_SRC_CODE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX, nullptr, 0, 0}, - {"inverseTransposeWorldOutdoorLookupMatrix", CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX, nullptr, 0, 0}, - {"worldMatrix", CONST_SRC_CODE_WORLD_MATRIX0, nullptr, 0, 0}, - {"inverseWorldMatrix", CONST_SRC_CODE_INVERSE_WORLD_MATRIX0, nullptr, 0, 0}, - {"transposeWorldMatrix", CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX0, nullptr, 0, 0}, - {"inverseTransposeWorldMatrix", CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX0, nullptr, 0, 0}, - {"worldViewMatrix", CONST_SRC_CODE_WORLD_VIEW_MATRIX0, nullptr, 0, 0}, - {"inverseWorldViewMatrix", CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX0, nullptr, 0, 0}, - {"transposeWorldViewMatrix", CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX0, nullptr, 0, 0}, - {"inverseTransposeWorldViewMatrix", CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX0, nullptr, 0, 0}, - {"worldViewProjectionMatrix", CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX0, nullptr, 0, 0}, - {"inverseWorldViewProjectionMatrix", CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX0, nullptr, 0, 0}, - {"transposeWorldViewProjectionMatrix", CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX0, nullptr, 0, 0}, - {"inverseTransposeWorldViewProjectionMatrix", CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX0, nullptr, 0, 0}, - {"worldMatrix1", CONST_SRC_CODE_WORLD_MATRIX1, nullptr, 0, 0}, - {"inverseWorldMatrix1", CONST_SRC_CODE_INVERSE_WORLD_MATRIX1, nullptr, 0, 0}, - {"transposeWorldMatrix1", CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX1, nullptr, 0, 0}, - {"inverseTransposeWorldMatrix1", CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX1, nullptr, 0, 0}, - {"worldViewMatrix1", CONST_SRC_CODE_WORLD_VIEW_MATRIX1, nullptr, 0, 0}, - {"inverseWorldViewMatrix1", CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX1, nullptr, 0, 0}, - {"transposeWorldViewMatrix1", CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX1, nullptr, 0, 0}, - {"inverseTransposeWorldViewMatrix1", CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX1, nullptr, 0, 0}, - {"worldViewProjectionMatrix1", CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX1, nullptr, 0, 0}, - {"inverseWorldViewProjectionMatrix1", CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX1, nullptr, 0, 0}, - {"transposeWorldViewProjectionMatrix1", CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX1, nullptr, 0, 0}, - {"inverseTransposeWorldViewProjectionMatrix1", CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX1, nullptr, 0, 0}, - {"worldMatrix2", CONST_SRC_CODE_WORLD_MATRIX2, nullptr, 0, 0}, - {"inverseWorldMatrix2", CONST_SRC_CODE_INVERSE_WORLD_MATRIX2, nullptr, 0, 0}, - {"transposeWorldMatrix2", CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX2, nullptr, 0, 0}, - {"inverseTransposeWorldMatrix2", CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX2, nullptr, 0, 0}, - {"worldViewMatrix2", CONST_SRC_CODE_WORLD_VIEW_MATRIX2, nullptr, 0, 0}, - {"inverseWorldViewMatrix2", CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX2, nullptr, 0, 0}, - {"transposeWorldViewMatrix2", CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX2, nullptr, 0, 0}, - {"inverseTransposeWorldViewMatrix2", CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX2, nullptr, 0, 0}, - {"worldViewProjectionMatrix2", CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX2, nullptr, 0, 0}, - {"inverseWorldViewProjectionMatrix2", CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX2, nullptr, 0, 0}, - {"transposeWorldViewProjectionMatrix2", CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX2, nullptr, 0, 0}, - {"inverseTransposeWorldViewProjectionMatrix2", CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX2, nullptr, 0, 0}, - {}, - }; - - static inline CodeConstantSource s_defaultCodeConsts[]{ - {"nearPlaneOrg", CONST_SRC_CODE_NEARPLANE_ORG, nullptr, 0, 0}, - {"nearPlaneDx", CONST_SRC_CODE_NEARPLANE_DX, nullptr, 0, 0}, - {"nearPlaneDy", CONST_SRC_CODE_NEARPLANE_DY, nullptr, 0, 0}, - {"lightPosition", CONST_SRC_CODE_LIGHT_POSITION, nullptr, 0, 0}, - {"lightDiffuse", CONST_SRC_CODE_LIGHT_DIFFUSE, nullptr, 0, 0}, - {"lightSpecular", CONST_SRC_CODE_LIGHT_SPECULAR, nullptr, 0, 0}, - {"lightSpotDir", CONST_SRC_CODE_LIGHT_SPOTDIR, nullptr, 0, 0}, - {"lightSpotFactors", CONST_SRC_CODE_LIGHT_SPOTFACTORS, nullptr, 0, 0}, - {"lightFalloffPlacement", CONST_SRC_CODE_LIGHT_FALLOFF_PLACEMENT, nullptr, 0, 0}, - {"sunShadowmapPixelAdjust", CONST_SRC_CODE_SUN_SHADOWMAP_PIXEL_ADJUST, nullptr, 0, 0}, - {"spotShadowmapPixelAdjust", CONST_SRC_CODE_SPOT_SHADOWMAP_PIXEL_ADJUST, nullptr, 0, 0}, - {}, - }; - - static inline MaterialUpdateFrequency s_codeConstUpdateFreq[]{ - MTL_UPDATE_RARELY, // LIGHT_POSITION - MTL_UPDATE_RARELY, // LIGHT_DIFFUSE - MTL_UPDATE_RARELY, // LIGHT_SPECULAR - MTL_UPDATE_RARELY, // LIGHT_SPOTDIR - MTL_UPDATE_RARELY, // LIGHT_SPOTFACTORS - MTL_UPDATE_RARELY, // LIGHT_FALLOFF_PLACEMENT - MTL_UPDATE_RARELY, // PARTICLE_CLOUD_COLOR - MTL_UPDATE_RARELY, // GAMETIME - MTL_UPDATE_RARELY, // PIXEL_COST_FRACS - MTL_UPDATE_RARELY, // PIXEL_COST_DECODE - MTL_UPDATE_RARELY, // FILTER_TAP_0 - MTL_UPDATE_RARELY, // FILTER_TAP_1 - MTL_UPDATE_RARELY, // FILTER_TAP_2 - MTL_UPDATE_RARELY, // FILTER_TAP_3 - MTL_UPDATE_RARELY, // FILTER_TAP_4 - MTL_UPDATE_RARELY, // FILTER_TAP_5 - MTL_UPDATE_RARELY, // FILTER_TAP_6 - MTL_UPDATE_RARELY, // FILTER_TAP_7 - MTL_UPDATE_RARELY, // COLOR_MATRIX_R - MTL_UPDATE_RARELY, // COLOR_MATRIX_G - MTL_UPDATE_RARELY, // COLOR_MATRIX_B - MTL_UPDATE_RARELY, // SHADOWMAP_POLYGON_OFFSET - MTL_UPDATE_RARELY, // RENDER_TARGET_SIZE - MTL_UPDATE_RARELY, // DOF_EQUATION_VIEWMODEL_AND_FAR_BLUR - MTL_UPDATE_RARELY, // DOF_EQUATION_SCENE - MTL_UPDATE_RARELY, // DOF_LERP_SCALE - MTL_UPDATE_RARELY, // DOF_LERP_BIAS - MTL_UPDATE_RARELY, // DOF_ROW_DELTA - MTL_UPDATE_RARELY, // MOTION_MATRIX_X - MTL_UPDATE_RARELY, // MOTION_MATRIX_Y - MTL_UPDATE_RARELY, // MOTION_MATRIX_W - MTL_UPDATE_RARELY, // SHADOWMAP_SWITCH_PARTITION - MTL_UPDATE_RARELY, // SHADOWMAP_SCALE - MTL_UPDATE_RARELY, // ZNEAR - MTL_UPDATE_RARELY, // LIGHTING_LOOKUP_SCALE - MTL_UPDATE_RARELY, // DEBUG_BUMPMAP - MTL_UPDATE_RARELY, // MATERIAL_COLOR - MTL_UPDATE_RARELY, // FOG - MTL_UPDATE_RARELY, // FOG_COLOR_LINEAR - MTL_UPDATE_RARELY, // FOG_COLOR_GAMMA - MTL_UPDATE_RARELY, // FOG_SUN_CONSTS - MTL_UPDATE_RARELY, // FOG_SUN_COLOR_LINEAR - MTL_UPDATE_RARELY, // FOG_SUN_COLOR_GAMMA - MTL_UPDATE_RARELY, // FOG_SUN_DIR - MTL_UPDATE_RARELY, // GLOW_SETUP - MTL_UPDATE_RARELY, // GLOW_APPLY - MTL_UPDATE_RARELY, // COLOR_BIAS - MTL_UPDATE_RARELY, // COLOR_TINT_BASE - MTL_UPDATE_RARELY, // COLOR_TINT_DELTA - MTL_UPDATE_RARELY, // COLOR_TINT_QUADRATIC_DELTA - MTL_UPDATE_RARELY, // OUTDOOR_FEATHER_PARMS - MTL_UPDATE_RARELY, // ENVMAP_PARMS - MTL_UPDATE_RARELY, // SUN_SHADOWMAP_PIXEL_ADJUST - MTL_UPDATE_RARELY, // SPOT_SHADOWMAP_PIXEL_ADJUST - MTL_UPDATE_RARELY, // COMPOSITE_FX_DISTORTION - MTL_UPDATE_RARELY, // POSTFX_FADE_EFFECT - MTL_UPDATE_RARELY, // VIEWPORT_DIMENSIONS - MTL_UPDATE_RARELY, // FRAMEBUFFER_READ - MTL_UPDATE_PER_PRIM, // BASE_LIGHTING_COORDS - MTL_UPDATE_PER_PRIM, // LIGHT_PROBE_AMBIENT - MTL_UPDATE_RARELY, // NEARPLANE_ORG - MTL_UPDATE_RARELY, // NEARPLANE_DX - MTL_UPDATE_RARELY, // NEARPLANE_DY - MTL_UPDATE_RARELY, // CLIP_SPACE_LOOKUP_SCALE - MTL_UPDATE_RARELY, // CLIP_SPACE_LOOKUP_OFFSET - MTL_UPDATE_PER_OBJECT, // PARTICLE_CLOUD_MATRIX0 - MTL_UPDATE_PER_OBJECT, // PARTICLE_CLOUD_MATRIX1 - MTL_UPDATE_PER_OBJECT, // PARTICLE_CLOUD_MATRIX2 - MTL_UPDATE_PER_OBJECT, // PARTICLE_CLOUD_SPARK_COLOR0 - MTL_UPDATE_PER_OBJECT, // PARTICLE_CLOUD_SPARK_COLOR1 - MTL_UPDATE_PER_OBJECT, // PARTICLE_CLOUD_SPARK_COLOR2 - MTL_UPDATE_PER_OBJECT, // PARTICLE_FOUNTAIN_PARM0 - MTL_UPDATE_PER_OBJECT, // PARTICLE_FOUNTAIN_PARM1 - MTL_UPDATE_PER_OBJECT, // DEPTH_FROM_CLIP - MTL_UPDATE_PER_OBJECT, // CODE_MESH_ARG_0 - MTL_UPDATE_PER_OBJECT, // CODE_MESH_ARG_1 - MTL_UPDATE_PER_OBJECT, // VIEW_MATRIX - MTL_UPDATE_PER_OBJECT, // INVERSE_VIEW_MATRIX - MTL_UPDATE_PER_OBJECT, // TRANSPOSE_VIEW_MATRIX - MTL_UPDATE_PER_OBJECT, // INVERSE_TRANSPOSE_VIEW_MATRIX - MTL_UPDATE_PER_OBJECT, // PROJECTION_MATRIX - MTL_UPDATE_PER_OBJECT, // INVERSE_PROJECTION_MATRIX - MTL_UPDATE_PER_OBJECT, // TRANSPOSE_PROJECTION_MATRIX - MTL_UPDATE_PER_OBJECT, // INVERSE_TRANSPOSE_PROJECTION_MATRIX - MTL_UPDATE_PER_OBJECT, // VIEW_PROJECTION_MATRIX - MTL_UPDATE_PER_OBJECT, // INVERSE_VIEW_PROJECTION_MATRIX - MTL_UPDATE_PER_OBJECT, // TRANSPOSE_VIEW_PROJECTION_MATRIX - MTL_UPDATE_PER_OBJECT, // INVERSE_TRANSPOSE_VIEW_PROJECTION_MATRIX - MTL_UPDATE_PER_OBJECT, // SHADOW_LOOKUP_MATRIX - MTL_UPDATE_PER_OBJECT, // INVERSE_SHADOW_LOOKUP_MATRIX - MTL_UPDATE_PER_OBJECT, // TRANSPOSE_SHADOW_LOOKUP_MATRIX - MTL_UPDATE_PER_OBJECT, // INVERSE_TRANSPOSE_SHADOW_LOOKUP_MATRIX - MTL_UPDATE_PER_PRIM, // WORLD_OUTDOOR_LOOKUP_MATRIX - MTL_UPDATE_PER_PRIM, // INVERSE_WORLD_OUTDOOR_LOOKUP_MATRIX - MTL_UPDATE_PER_PRIM, // TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX - MTL_UPDATE_PER_PRIM, // INVERSE_TRANSPOSE_WORLD_OUTDOOR_LOOKUP_MATRIX - MTL_UPDATE_PER_PRIM, // WORLD_MATRIX0 - MTL_UPDATE_PER_PRIM, // INVERSE_WORLD_MATRIX0 - MTL_UPDATE_PER_PRIM, // TRANSPOSE_WORLD_MATRIX0 - MTL_UPDATE_PER_PRIM, // INVERSE_TRANSPOSE_WORLD_MATRIX0 - MTL_UPDATE_PER_PRIM, // WORLD_VIEW_MATRIX0 - MTL_UPDATE_PER_PRIM, // INVERSE_WORLD_VIEW_MATRIX0 - MTL_UPDATE_PER_PRIM, // TRANSPOSE_WORLD_VIEW_MATRIX0 - MTL_UPDATE_PER_PRIM, // INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX0 - MTL_UPDATE_PER_PRIM, // WORLD_VIEW_PROJECTION_MATRIX0 - MTL_UPDATE_PER_PRIM, // INVERSE_WORLD_VIEW_PROJECTION_MATRIX0 - MTL_UPDATE_PER_PRIM, // TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX0 - MTL_UPDATE_PER_PRIM, // INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX0 - MTL_UPDATE_PER_PRIM, // WORLD_MATRIX1 - MTL_UPDATE_PER_PRIM, // INVERSE_WORLD_MATRIX1 - MTL_UPDATE_PER_PRIM, // TRANSPOSE_WORLD_MATRIX1 - MTL_UPDATE_PER_PRIM, // INVERSE_TRANSPOSE_WORLD_MATRIX1 - MTL_UPDATE_PER_PRIM, // WORLD_VIEW_MATRIX1 - MTL_UPDATE_PER_PRIM, // INVERSE_WORLD_VIEW_MATRIX1 - MTL_UPDATE_PER_PRIM, // TRANSPOSE_WORLD_VIEW_MATRIX1 - MTL_UPDATE_PER_PRIM, // INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX1 - MTL_UPDATE_PER_PRIM, // WORLD_VIEW_PROJECTION_MATRIX1 - MTL_UPDATE_PER_PRIM, // INVERSE_WORLD_VIEW_PROJECTION_MATRIX1 - MTL_UPDATE_PER_PRIM, // TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX1 - MTL_UPDATE_PER_PRIM, // INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX1 - MTL_UPDATE_PER_PRIM, // WORLD_MATRIX2 - MTL_UPDATE_PER_PRIM, // INVERSE_WORLD_MATRIX2 - MTL_UPDATE_PER_PRIM, // TRANSPOSE_WORLD_MATRIX2 - MTL_UPDATE_PER_PRIM, // INVERSE_TRANSPOSE_WORLD_MATRIX2 - MTL_UPDATE_PER_PRIM, // WORLD_VIEW_MATRIX2 - MTL_UPDATE_PER_PRIM, // INVERSE_WORLD_VIEW_MATRIX2 - MTL_UPDATE_PER_PRIM, // TRANSPOSE_WORLD_VIEW_MATRIX2 - MTL_UPDATE_PER_PRIM, // INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX2 - MTL_UPDATE_PER_PRIM, // WORLD_VIEW_PROJECTION_MATRIX2 - MTL_UPDATE_PER_PRIM, // INVERSE_WORLD_VIEW_PROJECTION_MATRIX2 - MTL_UPDATE_PER_PRIM, // TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX2 - MTL_UPDATE_PER_PRIM, // INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX2 - }; - static_assert(std::extent_v == CONST_SRC_TOTAL_COUNT); - - static inline MaterialUpdateFrequency s_codeSamplerUpdateFreq[]{ - MTL_UPDATE_RARELY, // BLACK - MTL_UPDATE_RARELY, // WHITE - MTL_UPDATE_RARELY, // IDENTITY_NORMAL_MAP - MTL_UPDATE_RARELY, // MODEL_LIGHTING - MTL_UPDATE_CUSTOM, // LIGHTMAP_PRIMARY - MTL_UPDATE_CUSTOM, // LIGHTMAP_SECONDARY - MTL_UPDATE_RARELY, // SHADOWMAP_SUN - MTL_UPDATE_RARELY, // SHADOWMAP_SPOT - MTL_UPDATE_PER_OBJECT, // FEEDBACK - MTL_UPDATE_RARELY, // RESOLVED_POST_SUN - MTL_UPDATE_RARELY, // RESOLVED_SCENE - MTL_UPDATE_RARELY, // POST_EFFECT_0 - MTL_UPDATE_RARELY, // POST_EFFECT_1 - MTL_UPDATE_PER_OBJECT, // LIGHT_ATTENUATION - MTL_UPDATE_RARELY, // OUTDOOR - MTL_UPDATE_RARELY, // FLOATZ - MTL_UPDATE_RARELY, // PROCESSED_FLOATZ - MTL_UPDATE_RARELY, // RAW_FLOATZ - MTL_UPDATE_RARELY, // HALF_PARTICLES - MTL_UPDATE_RARELY, // HALF_PARTICLES_Z - MTL_UPDATE_PER_OBJECT, // CASE_TEXTURE - MTL_UPDATE_PER_OBJECT, // CINEMATIC_Y - MTL_UPDATE_PER_OBJECT, // CINEMATIC_CR - MTL_UPDATE_PER_OBJECT, // CINEMATIC_CB - MTL_UPDATE_PER_OBJECT, // CINEMATIC_A - MTL_UPDATE_CUSTOM, // REFLECTION_PROBE - MTL_UPDATE_RARELY, // ALTERNATE_SCENE - }; - static_assert(std::extent_v == TEXTURE_SRC_CODE_COUNT); - - static inline MaterialTextureSource g_customSamplerSrc[]{ - TEXTURE_SRC_CODE_REFLECTION_PROBE, // CUSTOM_SAMPLER_REFLECTION_PROBE - TEXTURE_SRC_CODE_LIGHTMAP_PRIMARY, // CUSTOM_SAMPLER_LIGHTMAP_PRIMARY - TEXTURE_SRC_CODE_LIGHTMAP_SECONDARY, // CUSTOM_SAMPLER_LIGHTMAP_SECONDARY - }; - static_assert(std::extent_v == CUSTOM_SAMPLER_COUNT); + static inline techset::CommonCodeSourceInfos commonCodeSourceInfos(commonCodeConstSources, + std::extent_v, + commonCodeSamplerSources, + std::extent_v, + nullptr, + 0, + commonArgumentTypes, + std::extent_v); static inline MaterialTypeInfo g_materialTypeInfo[]{ {"", "" }, diff --git a/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h b/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h index 84e6b48f..4251faa7 100644 --- a/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h +++ b/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h @@ -1848,7 +1848,7 @@ namespace T6 {.m_shader_type = techset::CommonTechniqueShaderType::PIXEL, .m_value_type = techset::CommonShaderValueType::MATERIAL_CONST }, {.m_shader_type = techset::CommonTechniqueShaderType::PIXEL, .m_value_type = techset::CommonShaderValueType::LITERAL_CONST }, }; - static_assert(std::extent_v == MLT_ARG_COUNT); + static_assert(std::extent_v == MTL_ARG_COUNT); static inline const char* commonIgnoredArgAccessors[]{ "combined_dlight", From eae57d9da0b30fe815225479ecd6eae303cb1b1e Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 6 Mar 2026 21:55:26 +0000 Subject: [PATCH 02/14] feat: template techset and shader dumping for IW4,T6 --- .../IW4/Techset/CompilerVertexDeclIW4.cpp | 78 +-- src/ObjWriting/Game/IW4/ObjWriterIW4.cpp | 18 +- .../Game/IW4/Shader/PixelShaderDumperIW4.cpp | 20 - .../Game/IW4/Shader/PixelShaderDumperIW4.h | 13 - .../Game/IW4/Shader/VertexShaderDumperIW4.cpp | 20 - .../Game/IW4/Shader/VertexShaderDumperIW4.h | 13 - .../Game/IW4/Techset/TechsetDumperIW4.cpp | 510 ------------------ .../Game/IW4/Techset/TechsetDumperIW4.h | 13 - src/ObjWriting/Game/T6/ObjWriterT6.cpp | 2 +- .../Game/T6/Techset/TechsetDumperT6.h | 21 - .../Techset/CommonTechniqueDumper.cpp | 2 +- .../Techset/PixelShaderDumper.cpp.template | 46 ++ .../Techset/PixelShaderDumper.h.template | 25 + .../TechsetDumper.cpp.template} | 118 +++- .../Techset/TechsetDumper.h.template | 33 ++ .../Techset/VertexShaderDumper.cpp.template | 46 ++ .../Techset/VertexShaderDumper.h.template | 25 + 17 files changed, 313 insertions(+), 690 deletions(-) delete mode 100644 src/ObjWriting/Game/IW4/Shader/PixelShaderDumperIW4.cpp delete mode 100644 src/ObjWriting/Game/IW4/Shader/PixelShaderDumperIW4.h delete mode 100644 src/ObjWriting/Game/IW4/Shader/VertexShaderDumperIW4.cpp delete mode 100644 src/ObjWriting/Game/IW4/Shader/VertexShaderDumperIW4.h delete mode 100644 src/ObjWriting/Game/IW4/Techset/TechsetDumperIW4.cpp delete mode 100644 src/ObjWriting/Game/IW4/Techset/TechsetDumperIW4.h delete mode 100644 src/ObjWriting/Game/T6/Techset/TechsetDumperT6.h create mode 100644 src/ObjWriting/Techset/PixelShaderDumper.cpp.template create mode 100644 src/ObjWriting/Techset/PixelShaderDumper.h.template rename src/ObjWriting/{Game/T6/Techset/TechsetDumperT6.cpp => Techset/TechsetDumper.cpp.template} (78%) create mode 100644 src/ObjWriting/Techset/TechsetDumper.h.template create mode 100644 src/ObjWriting/Techset/VertexShaderDumper.cpp.template create mode 100644 src/ObjWriting/Techset/VertexShaderDumper.h.template diff --git a/src/ObjCompiling/Game/IW4/Techset/CompilerVertexDeclIW4.cpp b/src/ObjCompiling/Game/IW4/Techset/CompilerVertexDeclIW4.cpp index 9bfdaedc..a2762d59 100644 --- a/src/ObjCompiling/Game/IW4/Techset/CompilerVertexDeclIW4.cpp +++ b/src/ObjCompiling/Game/IW4/Techset/CompilerVertexDeclIW4.cpp @@ -2,12 +2,9 @@ #include "Game/IW4/IW4.h" #include "Game/IW4/Techset/TechsetConstantsIW4.h" +#include "Techset/CommonVertexDeclCreator.h" #include "Utils/Logging/Log.h" -#include -#include -#include - using namespace IW4; namespace @@ -15,78 +12,37 @@ namespace class LoaderVertexDecl final : public AssetCreator { public: - LoaderVertexDecl(MemoryManager& memory) + explicit LoaderVertexDecl(MemoryManager& memory) : m_memory(memory) { } AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override { - auto* decl = m_memory.Alloc(); - decl->name = m_memory.Dup(assetName.c_str()); + const auto commonVertexDecl = techset::CreateVertexDeclFromName(assetName, commonRoutingInfos); + if (!commonVertexDecl) + return AssetCreationResult::Failure(); - size_t currentOffset = 0u; - - std::string sourceAbbreviation; - while (NextAbbreviation(assetName, sourceAbbreviation, currentOffset)) + if (commonVertexDecl->m_routing.size() > std::extent_v) { - if (decl->streamCount >= std::extent_v) - { - con::error("Failed to add vertex decl stream. Too many abbreviations: {}", assetName); - return AssetCreationResult::Failure(); - } - - std::string destinationAbbreviation; - if (!NextAbbreviation(assetName, destinationAbbreviation, currentOffset)) - { - con::error("Failed to detect vertex decl destination abbreviation: {}", assetName); - return AssetCreationResult::Failure(); - } - - const auto foundSourceAbbreviation = std::ranges::find(materialStreamSourceAbbreviation, sourceAbbreviation); - if (foundSourceAbbreviation == std::end(materialStreamSourceAbbreviation)) - { - con::error("Unknown vertex decl source abbreviation: {}", sourceAbbreviation); - return AssetCreationResult::Failure(); - } - - const auto foundDestinationAbbreviation = std::ranges::find(materialStreamDestinationAbbreviation, destinationAbbreviation); - if (foundDestinationAbbreviation == std::end(materialStreamDestinationAbbreviation)) - { - con::error("Unknown vertex decl destination abbreviation: {}", destinationAbbreviation); - return AssetCreationResult::Failure(); - } - - const auto sourceIndex = static_cast(foundSourceAbbreviation - std::begin(materialStreamSourceAbbreviation)); - const auto destinationIndex = - static_cast(foundDestinationAbbreviation - std::begin(materialStreamDestinationAbbreviation)); - - decl->routing.data[decl->streamCount].source = sourceIndex; - decl->routing.data[decl->streamCount].dest = destinationIndex; - decl->hasOptionalSource = decl->hasOptionalSource || sourceIndex >= STREAM_SRC_OPTIONAL_BEGIN; - decl->streamCount++; + con::error("Vertex declaration can only have up to {} routing entries", std::extent_v); + return AssetCreationResult::Failure(); } - return AssetCreationResult::Success(context.AddAsset(assetName, decl)); - } + auto* vertexDecl = m_memory.Alloc(); - static bool NextAbbreviation(const std::string& assetName, std::string& abbreviation, size_t& offset) - { - if (offset >= assetName.size()) - return false; + vertexDecl->name = m_memory.Dup(assetName.c_str()); - if (offset + 1 < assetName.size() && isdigit(assetName[offset + 1])) + for (const auto& commonRoutingEntry : commonVertexDecl->m_routing) { - abbreviation = std::string(assetName, offset, 2); - offset += 2; - } - else - { - abbreviation = std::string(assetName, offset, 1); - offset += 1; + vertexDecl->routing.data[vertexDecl->streamCount].source = commonRoutingEntry.m_source; + vertexDecl->routing.data[vertexDecl->streamCount].dest = commonRoutingEntry.m_destination; + vertexDecl->hasOptionalSource = vertexDecl->hasOptionalSource || commonRoutingEntry.m_source >= STREAM_SRC_OPTIONAL_BEGIN; + + vertexDecl->streamCount++; } - return true; + return AssetCreationResult::Success(context.AddAsset(AssetRegistration(assetName, vertexDecl))); } MemoryManager& m_memory; diff --git a/src/ObjWriting/Game/IW4/ObjWriterIW4.cpp b/src/ObjWriting/Game/IW4/ObjWriterIW4.cpp index 8ae26e8e..6004d5ea 100644 --- a/src/ObjWriting/Game/IW4/ObjWriterIW4.cpp +++ b/src/ObjWriting/Game/IW4/ObjWriterIW4.cpp @@ -1,6 +1,9 @@ #include "ObjWriterIW4.h" #include "Game/IW4/Material/MaterialJsonDumperIW4.h" +#include "Game/IW4/Techset/PixelShaderDumperIW4.h" +#include "Game/IW4/Techset/TechsetDumperIW4.h" +#include "Game/IW4/Techset/VertexShaderDumperIW4.h" #include "Game/IW4/XModel/XModelDumperIW4.h" #include "Image/ImageDumperIW4.h" #include "Leaderboard/LeaderboardJsonDumperIW4.h" @@ -13,13 +16,10 @@ #include "PhysCollmap/PhysCollmapDumperIW4.h" #include "PhysPreset/PhysPresetInfoStringDumperIW4.h" #include "RawFile/RawFileDumperIW4.h" -#include "Shader/PixelShaderDumperIW4.h" -#include "Shader/VertexShaderDumperIW4.h" #include "Sound/LoadedSoundDumperIW4.h" #include "Sound/SndCurveDumperIW4.h" #include "StringTable/StringTableDumperIW4.h" #include "StructuredDataDef/StructuredDataDefDumperIW4.h" -#include "Techset/TechsetDumperIW4.h" #include "Tracer/TracerDumperIW4.h" #include "Vehicle/VehicleDumperIW4.h" #include "Weapon/WeaponDumperIW4.h" @@ -36,9 +36,15 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context) #ifdef EXPERIMENTAL_MATERIAL_COMPILATION RegisterAssetDumper(std::make_unique()); #endif - RegisterAssetDumper(std::make_unique()); - RegisterAssetDumper(std::make_unique()); - RegisterAssetDumper(std::make_unique()); + RegisterAssetDumper(std::make_unique()); + RegisterAssetDumper(std::make_unique()); + RegisterAssetDumper(std::make_unique( +#ifdef TECHSET_DEBUG + true +#else + false +#endif + )); RegisterAssetDumper(std::make_unique()); // REGISTER_DUMPER(AssetDumpersnd_alias_list_t) RegisterAssetDumper(std::make_unique()); diff --git a/src/ObjWriting/Game/IW4/Shader/PixelShaderDumperIW4.cpp b/src/ObjWriting/Game/IW4/Shader/PixelShaderDumperIW4.cpp deleted file mode 100644 index 17a779ae..00000000 --- a/src/ObjWriting/Game/IW4/Shader/PixelShaderDumperIW4.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "PixelShaderDumperIW4.h" - -#include "Shader/ShaderCommon.h" - -using namespace IW4; - -namespace shader -{ - void PixelShaderDumperIW4::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) - { - const auto* pixelShader = asset.Asset(); - const auto shaderFile = context.OpenAssetFile(shader::GetFileNameForPixelShaderAssetName(asset.m_name)); - - if (!shaderFile) - return; - - shaderFile->write(reinterpret_cast(pixelShader->prog.loadDef.program), - static_cast(pixelShader->prog.loadDef.programSize) * 4u); - } -} // namespace shader diff --git a/src/ObjWriting/Game/IW4/Shader/PixelShaderDumperIW4.h b/src/ObjWriting/Game/IW4/Shader/PixelShaderDumperIW4.h deleted file mode 100644 index 5e91c95c..00000000 --- a/src/ObjWriting/Game/IW4/Shader/PixelShaderDumperIW4.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Dumping/AbstractAssetDumper.h" -#include "Game/IW4/IW4.h" - -namespace shader -{ - class PixelShaderDumperIW4 final : public AbstractAssetDumper - { - protected: - void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; - }; -} // namespace shader diff --git a/src/ObjWriting/Game/IW4/Shader/VertexShaderDumperIW4.cpp b/src/ObjWriting/Game/IW4/Shader/VertexShaderDumperIW4.cpp deleted file mode 100644 index 9531f0e6..00000000 --- a/src/ObjWriting/Game/IW4/Shader/VertexShaderDumperIW4.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "VertexShaderDumperIW4.h" - -#include "Shader/ShaderCommon.h" - -using namespace IW4; - -namespace shader -{ - void VertexShaderDumperIW4::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) - { - const auto* vertexShader = asset.Asset(); - const auto shaderFile = context.OpenAssetFile(shader::GetFileNameForVertexShaderAssetName(asset.m_name)); - - if (!shaderFile) - return; - - shaderFile->write(reinterpret_cast(vertexShader->prog.loadDef.program), - static_cast(vertexShader->prog.loadDef.programSize) * 4u); - } -} // namespace shader diff --git a/src/ObjWriting/Game/IW4/Shader/VertexShaderDumperIW4.h b/src/ObjWriting/Game/IW4/Shader/VertexShaderDumperIW4.h deleted file mode 100644 index 2b817b5d..00000000 --- a/src/ObjWriting/Game/IW4/Shader/VertexShaderDumperIW4.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Dumping/AbstractAssetDumper.h" -#include "Game/IW4/IW4.h" - -namespace shader -{ - class VertexShaderDumperIW4 final : public AbstractAssetDumper - { - protected: - void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; - }; -} // namespace shader diff --git a/src/ObjWriting/Game/IW4/Techset/TechsetDumperIW4.cpp b/src/ObjWriting/Game/IW4/Techset/TechsetDumperIW4.cpp deleted file mode 100644 index 1a3d8119..00000000 --- a/src/ObjWriting/Game/IW4/Techset/TechsetDumperIW4.cpp +++ /dev/null @@ -1,510 +0,0 @@ -#include "TechsetDumperIW4.h" - -#include "Dumping/AbstractTextDumper.h" -#include "Game/IW4/Techset/TechsetConstantsIW4.h" -#include "Pool/GlobalAssetPool.h" -#include "Shader/D3D9ShaderAnalyser.h" -#include "Techset/CommonTechset.h" -#include "Techset/CommonTechsetDumper.h" -#include "Techset/TechniqueDumpingZoneState.h" -#include "Techset/TechsetCommon.h" -#include "Utils/Logging/Log.h" - -#include -#include -#include -#include -#include -#include - -using namespace IW4; - -namespace -{ - class TechniqueFileWriter : public AbstractTextDumper - { - void DumpStateMap() const - { - Indent(); - // TODO: Actual statemap: Maybe find all materials using this techset and try to make out rules for the flags based on the statebitstable - m_stream << "stateMap \"passthrough\"; // TODO\n"; - } - - static bool FindCodeConstantSourceAccessor(const MaterialConstantSource sourceIndexToFind, - const CodeConstantSource* codeConstantTable, - std::string& codeSourceAccessor) - { - const auto* currentCodeConst = codeConstantTable; - while (currentCodeConst->name != nullptr) - { - if (currentCodeConst->subtable != nullptr) - { - std::string accessorInSubTable; - if (FindCodeConstantSourceAccessor(sourceIndexToFind, currentCodeConst->subtable, accessorInSubTable)) - { - std::ostringstream ss; - ss << currentCodeConst->name << '.' << accessorInSubTable; - codeSourceAccessor = ss.str(); - return true; - } - } - else if (currentCodeConst->arrayCount > 0) - { - if (currentCodeConst->source <= sourceIndexToFind - && static_cast(currentCodeConst->source) + currentCodeConst->arrayCount > static_cast(sourceIndexToFind)) - { - std::ostringstream ss; - ss << currentCodeConst->name << '[' << (static_cast(sourceIndexToFind) - static_cast(currentCodeConst->source)) - << ']'; - codeSourceAccessor = ss.str(); - return true; - } - } - else if (currentCodeConst->source == sourceIndexToFind) - { - codeSourceAccessor = currentCodeConst->name; - return true; - } - - currentCodeConst++; - } - - return false; - } - - static bool FindCodeSamplerSourceAccessor(const MaterialTextureSource sourceIndexToFind, - const CodeSamplerSource* codeSamplerTable, - std::string& codeSourceAccessor) - { - const auto* currentCodeConst = codeSamplerTable; - while (currentCodeConst->name != nullptr) - { - if (currentCodeConst->subtable != nullptr) - { - std::string accessorInSubTable; - if (FindCodeSamplerSourceAccessor(sourceIndexToFind, currentCodeConst->subtable, accessorInSubTable)) - { - std::ostringstream ss; - ss << currentCodeConst->name << '.' << accessorInSubTable; - codeSourceAccessor = ss.str(); - return true; - } - } - else if (currentCodeConst->arrayCount > 0) - { - if (currentCodeConst->source <= sourceIndexToFind - && static_cast(currentCodeConst->source) + currentCodeConst->arrayCount > static_cast(sourceIndexToFind)) - { - std::ostringstream ss; - ss << currentCodeConst->name << '[' << (static_cast(sourceIndexToFind) - static_cast(currentCodeConst->source)) - << ']'; - codeSourceAccessor = ss.str(); - return true; - } - } - else if (currentCodeConst->source == sourceIndexToFind) - { - codeSourceAccessor = currentCodeConst->name; - return true; - } - - currentCodeConst++; - } - - return false; - } - - void DumpShaderArg(const MaterialShaderArgument& arg, const d3d9::ShaderInfo& shaderInfo) const - { - const auto expectedRegisterSet = - arg.type == MTL_ARG_CODE_PIXEL_SAMPLER || arg.type == MTL_ARG_MATERIAL_PIXEL_SAMPLER ? d3d9::RegisterSet::SAMPLER : d3d9::RegisterSet::FLOAT_4; - const auto targetShaderArg = std::ranges::find_if(shaderInfo.m_constants, - [arg, expectedRegisterSet](const d3d9::ShaderConstant& constant) - { - return constant.m_register_set == expectedRegisterSet && constant.m_register_index <= arg.dest - && constant.m_register_index + constant.m_register_count > arg.dest; - }); - - assert(targetShaderArg != shaderInfo.m_constants.end()); - if (targetShaderArg == shaderInfo.m_constants.end()) - { - m_stream << "// Unrecognized arg dest:" << arg.dest << " type: " << arg.type << "\n"; - return; - } - - std::string codeDestAccessor; - if (targetShaderArg->m_type_elements > 1) - { - std::ostringstream ss; - ss << targetShaderArg->m_name << '[' << (arg.dest - targetShaderArg->m_register_index) << ']'; - codeDestAccessor = ss.str(); - } - else - codeDestAccessor = targetShaderArg->m_name; - - if (arg.type == MTL_ARG_CODE_VERTEX_CONST || arg.type == MTL_ARG_CODE_PIXEL_CONST) - { - const auto sourceIndex = static_cast(arg.u.codeConst.index); - std::string codeSourceAccessor; - if (FindCodeConstantSourceAccessor(sourceIndex, s_codeConsts, codeSourceAccessor) - || FindCodeConstantSourceAccessor(sourceIndex, s_defaultCodeConsts, codeSourceAccessor)) - { - if (codeDestAccessor != codeSourceAccessor) - { - Indent(); - m_stream << codeDestAccessor << " = constant." << codeSourceAccessor << ";\n"; - } - else - { -#ifdef TECHSET_DEBUG - Indent(); - m_stream << "// Omitted due to matching accessors: " << codeDestAccessor << " = constant." << codeSourceAccessor << ";\n"; -#endif - } - } - else - { - assert(false); - Indent(); - m_stream << codeDestAccessor << " = UNKNOWN;\n"; - } - } - else if (arg.type == MTL_ARG_CODE_PIXEL_SAMPLER) - { - const auto sourceIndex = static_cast(arg.u.codeSampler); - std::string codeSourceAccessor; - if (FindCodeSamplerSourceAccessor(sourceIndex, s_codeSamplers, codeSourceAccessor) - || FindCodeSamplerSourceAccessor(sourceIndex, s_defaultCodeSamplers, codeSourceAccessor)) - { - if (codeDestAccessor != codeSourceAccessor) - { - Indent(); - m_stream << codeDestAccessor << " = sampler." << codeSourceAccessor << ";\n"; - } - else - { -#ifdef TECHSET_DEBUG - Indent(); - m_stream << "// Omitted due to matching accessors: " << codeDestAccessor << " = sampler." << codeSourceAccessor << ";\n"; -#endif - } - } - else - { - assert(false); - Indent(); - m_stream << codeDestAccessor << " = UNKNOWN;\n"; - } - } - else if (arg.type == MTL_ARG_LITERAL_VERTEX_CONST || arg.type == MTL_ARG_LITERAL_PIXEL_CONST) - { - if (arg.u.literalConst) - { - Indent(); - m_stream << codeDestAccessor << " = float4( " << (*arg.u.literalConst)[0] << ", " << (*arg.u.literalConst)[1] << ", " - << (*arg.u.literalConst)[2] << ", " << (*arg.u.literalConst)[3] << " );\n"; - } - } - else if (arg.type == MTL_ARG_MATERIAL_PIXEL_CONST || arg.type == MTL_ARG_MATERIAL_VERTEX_CONST || arg.type == MTL_ARG_MATERIAL_PIXEL_SAMPLER) - { - Indent(); - m_stream << codeDestAccessor << " = material."; - - const auto knownConstantName = knownConstantNames.find(arg.u.nameHash); - if (knownConstantName != knownConstantNames.end()) - { - m_stream << knownConstantName->second; - } - else - { - const auto knownMaterialTextureName = knownTextureMaps.find(arg.u.nameHash); - - if (knownMaterialTextureName != knownTextureMaps.end()) - { - m_stream << knownMaterialTextureName->second.m_name; - } - else - { - const auto shaderArgNameHash = Common::R_HashString(targetShaderArg->m_name.c_str(), 0u); - if (shaderArgNameHash == arg.u.nameHash) - m_stream << targetShaderArg->m_name; - else - m_stream << "#0x" << std::hex << arg.u.nameHash; - } - } - - m_stream << ";\n"; - } - else - { - assert(false); - } - } - - void DumpVertexShader(const MaterialPass& pass) - { - auto vertexShader = pass.vertexShader; - - if (vertexShader == nullptr || vertexShader->name == nullptr) - return; - - if (vertexShader->name[0] == ',') - { - const auto loadedVertexShaderFromOtherZone = - GameGlobalAssetPools::GetGlobalPoolsForGame(GameId::IW4)->GetAsset(&vertexShader->name[1]); - - if (loadedVertexShaderFromOtherZone == nullptr) - { - // Cannot dump when shader is referenced due to unknown constant names and unknown version - Indent(); - con::error("Cannot dump vertex shader {} due to being a referenced asset", &vertexShader->name[1]); - m_stream << std::format("// Cannot dump vertex shader {} due to being a referenced asset\n", &vertexShader->name[1]); - return; - } - vertexShader = loadedVertexShaderFromOtherZone->Asset(); - } - - const auto vertexShaderInfo = - d3d9::ShaderAnalyser::GetShaderInfo(vertexShader->prog.loadDef.program, vertexShader->prog.loadDef.programSize * sizeof(uint32_t)); - assert(vertexShaderInfo); - if (!vertexShaderInfo) - return; - - m_stream << "\n"; - Indent(); - m_stream << "vertexShader " << vertexShaderInfo->m_version_major << "." << vertexShaderInfo->m_version_minor << " \"" << vertexShader->name - << "\"\n"; - Indent(); - m_stream << "{\n"; - IncIndent(); - - if (pass.args) - { - const auto totalArgCount = - static_cast(pass.perPrimArgCount) + static_cast(pass.perObjArgCount) + static_cast(pass.stableArgCount); - for (auto i = 0u; i < totalArgCount; i++) - { - const auto& arg = pass.args[i]; - if (arg.type == MTL_ARG_MATERIAL_VERTEX_CONST || arg.type == MTL_ARG_LITERAL_VERTEX_CONST || arg.type == MTL_ARG_CODE_VERTEX_CONST) - { - DumpShaderArg(arg, *vertexShaderInfo); - } - } - } - - DecIndent(); - Indent(); - m_stream << "}\n"; - } - - void DumpPixelShader(const MaterialPass& pass) - { - auto pixelShader = pass.pixelShader; - - if (pixelShader == nullptr || pixelShader->name == nullptr) - return; - - if (pixelShader->name[0] == ',') - { - const auto loadedPixelShaderFromOtherZone = - GameGlobalAssetPools::GetGlobalPoolsForGame(GameId::IW4)->GetAsset(&pixelShader->name[1]); - - if (loadedPixelShaderFromOtherZone == nullptr) - { - // Cannot dump when shader is referenced due to unknown constant names and unknown version - Indent(); - con::error("Cannot dump pixel shader {} due to being a referenced asset", &pixelShader->name[1]); - m_stream << std::format("// Cannot dump pixel shader {} due to being a referenced asset\n", &pixelShader->name[1]); - return; - } - pixelShader = loadedPixelShaderFromOtherZone->Asset(); - } - - const auto pixelShaderInfo = - d3d9::ShaderAnalyser::GetShaderInfo(pixelShader->prog.loadDef.program, pixelShader->prog.loadDef.programSize * sizeof(uint32_t)); - assert(pixelShaderInfo); - if (!pixelShaderInfo) - return; - - m_stream << "\n"; - Indent(); - m_stream << "pixelShader " << pixelShaderInfo->m_version_major << "." << pixelShaderInfo->m_version_minor << " \"" << pixelShader->name << "\"\n"; - Indent(); - m_stream << "{\n"; - IncIndent(); - - if (pass.args) - { - const auto totalArgCount = - static_cast(pass.perPrimArgCount) + static_cast(pass.perObjArgCount) + static_cast(pass.stableArgCount); - for (auto i = 0u; i < totalArgCount; i++) - { - const auto& arg = pass.args[i]; - if (arg.type == MTL_ARG_MATERIAL_PIXEL_SAMPLER || arg.type == MTL_ARG_CODE_PIXEL_SAMPLER || arg.type == MTL_ARG_CODE_PIXEL_CONST - || arg.type == MTL_ARG_MATERIAL_PIXEL_CONST || arg.type == MTL_ARG_LITERAL_PIXEL_CONST) - { - DumpShaderArg(arg, *pixelShaderInfo); - } - } - } - - DecIndent(); - Indent(); - m_stream << "}\n"; - } - - static const char* GetStreamDestinationString(const MaterialStreamDestination_e dst) - { - const auto dstIndex = static_cast(dst); - assert(dstIndex < std::extent_v); - if (dstIndex < std::extent_v) - return materialStreamDestinationNames[dstIndex]; - return ""; - } - - static const char* GetStreamSourceString(const MaterialStreamStreamSource_e src) - { - const auto srcIndex = static_cast(src); - assert(srcIndex < std::extent_v); - if (srcIndex < std::extent_v) - return materialStreamSourceNames[srcIndex]; - return ""; - } - - void DumpVertexDecl(const MaterialPass& pass) - { - const auto* vertexDecl = pass.vertexDecl; - if (vertexDecl == nullptr) - return; - - if (vertexDecl->name && vertexDecl->name[0] == ',') - { - const auto loadedVertexDeclFromOtherZone = - GameGlobalAssetPools::GetGlobalPoolsForGame(GameId::IW4)->GetAsset(&vertexDecl->name[1]); - - if (loadedVertexDeclFromOtherZone == nullptr) - { - // Cannot dump when shader is referenced due to unknown constant names and unknown version - Indent(); - con::error("Cannot dump vertex decl {} due to being a referenced asset", &vertexDecl->name[1]); - m_stream << std::format("// Cannot dump vertex decl {} due to being a referenced asset\n", &vertexDecl->name[1]); - return; - } - vertexDecl = loadedVertexDeclFromOtherZone->Asset(); - } - - m_stream << "\n"; - -#ifdef TECHSET_DEBUG - Indent(); - m_stream << "// Decl: " << vertexDecl->name << "\n"; -#endif - - const auto streamCount = std::min(static_cast(vertexDecl->streamCount), std::extent_v); - for (auto streamIndex = 0u; streamIndex < streamCount; streamIndex++) - { - const auto& stream = vertexDecl->routing.data[streamIndex]; - Indent(); - m_stream << "vertex." << GetStreamDestinationString(static_cast(stream.dest)) << " = code." - << GetStreamSourceString(static_cast(stream.source)) << ";\n"; - } - } - - void DumpPass(const MaterialPass& pass) - { - m_stream << "{\n"; - IncIndent(); - -#ifdef TECHSET_DEBUG - for (auto i = 0u; i < 8; i++) - { - const auto mask = 1u << i; - if (pass.customSamplerFlags & mask) - { - Indent(); - m_stream << "// CUSTOM SAMPLER FLAGS: 0x" << std::hex << mask << "\n"; - } - } -#endif - - DumpStateMap(); - DumpVertexShader(pass); - DumpPixelShader(pass); - DumpVertexDecl(pass); - - DecIndent(); - m_stream << "}\n"; - } - - public: - explicit TechniqueFileWriter(std::ostream& stream) - : AbstractTextDumper(stream) - { - } - - void DumpTechnique(const MaterialTechnique* technique) - { -#ifdef TECHSET_DEBUG - if (technique->flags) - { - for (auto i = 0u; i < 16; i++) - { - const auto mask = 1u << i; - if (technique->flags & mask) - { - Indent(); - m_stream << "// TECHNIQUE FLAGS: 0x" << std::hex << mask << "\n"; - } - } - } -#endif - for (auto i = 0u; i < technique->passCount; i++) - DumpPass(technique->passArray[i]); - } - }; - - techset::CommonTechset ConvertToCommonTechset(const MaterialTechniqueSet& techset) - { - std::vector techniqueNames(std::extent_v); - - for (auto techniqueIndex = 0u; techniqueIndex < std::extent_v; techniqueIndex++) - { - const auto* technique = techset.techniques[techniqueIndex]; - if (technique && technique->name) - techniqueNames[techniqueIndex] = technique->name; - } - - return techset::CommonTechset(techset.name, std::move(techniqueNames)); - } - - void DumpTechset(const AssetDumpingContext& context, const MaterialTechniqueSet& techset) - { - static techset::CommonTechniqueTypeNames commonNames(techniqueTypeNames, std::extent_v); - const auto commonTechset = ConvertToCommonTechset(techset); - - techset::DumpCommonTechset(commonNames, context, commonTechset); - } -} // namespace - -namespace techset -{ - void DumperIW4::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) - { - const auto* techniqueSet = asset.Asset(); - DumpTechset(context, *techniqueSet); - - auto* techniqueState = context.GetZoneAssetDumperState(); - for (const auto* technique : techniqueSet->techniques) - { - if (technique && techniqueState->ShouldDumpTechnique(technique)) - { - const auto techniqueFile = context.OpenAssetFile(GetFileNameForTechniqueName(technique->name)); - if (techniqueFile) - { - TechniqueFileWriter writer(*techniqueFile); - writer.DumpTechnique(technique); - } - } - } - } -} // namespace techset diff --git a/src/ObjWriting/Game/IW4/Techset/TechsetDumperIW4.h b/src/ObjWriting/Game/IW4/Techset/TechsetDumperIW4.h deleted file mode 100644 index 17daac8e..00000000 --- a/src/ObjWriting/Game/IW4/Techset/TechsetDumperIW4.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Dumping/AbstractAssetDumper.h" -#include "Game/IW4/IW4.h" - -namespace techset -{ - class DumperIW4 final : public AbstractAssetDumper - { - protected: - void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; - }; -} // namespace techset diff --git a/src/ObjWriting/Game/T6/ObjWriterT6.cpp b/src/ObjWriting/Game/T6/ObjWriterT6.cpp index b43d4947..f4d09da2 100644 --- a/src/ObjWriting/Game/T6/ObjWriterT6.cpp +++ b/src/ObjWriting/Game/T6/ObjWriterT6.cpp @@ -2,6 +2,7 @@ #include "FontIcon/FontIconDumperT6.h" #include "Game/T6/Material/MaterialJsonDumperT6.h" +#include "Game/T6/Techset/TechsetDumperT6.h" #include "Game/T6/XModel/XModelDumperT6.h" #include "Image/ImageDumperT6.h" #include "Leaderboard/LeaderboardJsonDumperT6.h" @@ -16,7 +17,6 @@ #include "Sound/SndBankDumperT6.h" #include "Sound/SndDriverGlobalsDumperT6.h" #include "StringTable/StringTableDumperT6.h" -#include "Techset/TechsetDumperT6.h" #include "Tracer/TracerDumperT6.h" #include "Vehicle/VehicleDumperT6.h" #include "Weapon/AttachmentDumperT6.h" diff --git a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.h b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.h deleted file mode 100644 index 913d1e85..00000000 --- a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "Dumping/AbstractAssetDumper.h" -#include "Game/T6/T6.h" - -namespace techset -{ - class DumperT6 final : public AbstractAssetDumper - { - public: - explicit DumperT6(bool debug); - - void Dump(AssetDumpingContext& context) override; - - protected: - void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; - - private: - bool m_debug; - }; -} // namespace techset diff --git a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp index e83bd777..31128e52 100644 --- a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp +++ b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp @@ -103,7 +103,7 @@ namespace if (!shader.m_name.empty()) { m_stream << std::format("// ERROR: Cannot dump shader {} as its data is not loaded\n", shader.m_name); - con::error("Technique {}: Cannot dump shader {} as its data is not loaded\n", technique.m_name, shader.m_name); + con::error("Technique {}: Cannot dump shader {} as its data is not loaded", technique.m_name, shader.m_name); } return; diff --git a/src/ObjWriting/Techset/PixelShaderDumper.cpp.template b/src/ObjWriting/Techset/PixelShaderDumper.cpp.template new file mode 100644 index 00000000..c7f95cd4 --- /dev/null +++ b/src/ObjWriting/Techset/PixelShaderDumper.cpp.template @@ -0,0 +1,46 @@ +#options GAME(IW4) + +#filename "Game/" + GAME + "/Techset/PixelShaderDumper" + GAME + ".cpp" + +#set DUMPER_HEADER "\"PixelShaderDumper" + GAME + ".h\"" + +#if GAME == "IW3" +#define FEATURE_IW3 +#define IS_DX9 +#elif GAME == "IW4" +#define FEATURE_IW4 +#define IS_DX9 +#elif GAME == "IW5" +#define FEATURE_IW5 +#define IS_DX9 +#endif + +// This file was templated. +// See PixelShaderDumper.cpp.template. +// Do not modify, changes will be lost. + +#include DUMPER_HEADER + +#include "Shader/ShaderCommon.h" + +#include + +using namespace GAME; + +#set CLASS_NAME "PixelShaderDumper" + GAME + +namespace techset +{ + void CLASS_NAME::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) + { + const auto& shader = *asset.Asset(); + const auto shaderFile = context.OpenAssetFile(shader::GetFileNameForPixelShaderAssetName(shader.name)); + + if (!shaderFile) + return; + + shaderFile->write(reinterpret_cast(shader.prog.loadDef.program), + static_cast(shader.prog.loadDef.programSize) + * sizeof(std::remove_pointer_t)); + } +} // namespace techset diff --git a/src/ObjWriting/Techset/PixelShaderDumper.h.template b/src/ObjWriting/Techset/PixelShaderDumper.h.template new file mode 100644 index 00000000..f0d7326a --- /dev/null +++ b/src/ObjWriting/Techset/PixelShaderDumper.h.template @@ -0,0 +1,25 @@ +#options GAME(IW4) + +#filename "Game/" + GAME + "/Techset/PixelShaderDumper" + GAME + ".h" + +#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" + +// This file was templated. +// See PixelShaderDumper.h.template. +// Do not modify, changes will be lost. + +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include GAME_HEADER + +#set CLASS_NAME "PixelShaderDumper" + GAME + +namespace techset +{ + class CLASS_NAME final : public AbstractAssetDumper + { + protected: + void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; + }; +} // namespace techset diff --git a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp b/src/ObjWriting/Techset/TechsetDumper.cpp.template similarity index 78% rename from src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp rename to src/ObjWriting/Techset/TechsetDumper.cpp.template index 63d2d4a0..fd017b9f 100644 --- a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp +++ b/src/ObjWriting/Techset/TechsetDumper.cpp.template @@ -1,19 +1,55 @@ -#include "TechsetDumperT6.h" +#options GAME(IW4, T6) + +#filename "Game/" + GAME + "/Techset/TechsetDumper" + GAME + ".cpp" + +#set DUMPER_HEADER "\"TechsetDumper" + GAME + ".h\"" +#set MATERIAL_CONSTANT_ZONE_STATE_HEADER "\"Game/" + GAME + "/Material/MaterialConstantZoneState" + GAME + ".h\"" +#set TECHSET_CONSTANTS_HEADER "\"Game/" + GAME + "/Techset/TechsetConstants" + GAME + ".h\"" + +#if GAME == "IW3" +#define FEATURE_IW3 +#define IS_DX9 +#elif GAME == "IW4" +#define FEATURE_IW4 +#define IS_DX9 +#elif GAME == "IW5" +#define FEATURE_IW5 +#define IS_DX9 +#elif GAME == "T5" +#define FEATURE_T5 +#define IS_DX9 +#elif GAME == "T6" +#define FEATURE_T6 +#define IS_DX11 +#define DUMP_SHADERS "1" +#endif + +// This file was templated. +// See TechsetDumper.cpp.template. +// Do not modify, changes will be lost. + +#include DUMPER_HEADER + +#include MATERIAL_CONSTANT_ZONE_STATE_HEADER +#include TECHSET_CONSTANTS_HEADER -#include "Game/T6/Material/MaterialConstantZoneStateT6.h" -#include "Game/T6/Techset/TechsetConstantsT6.h" -#include "Shader/ShaderCommon.h" #include "Techset/CommonTechniqueDumper.h" #include "Techset/CommonTechsetDumper.h" -#include "Techset/ShaderDumpingZoneState.h" +#include "Techset/CommonVertexDeclCreator.h" #include "Techset/TechniqueDumpingZoneState.h" +#if defined(DUMP_SHADERS) +#include "Shader/ShaderCommon.h" +#include "Techset/ShaderDumpingZoneState.h" +#endif #include +#include -using namespace T6; +using namespace GAME; namespace { +#if defined(DUMP_SHADERS) void DumpPixelShader(const AssetDumpingContext& context, const MaterialPixelShader& pixelShader) { const auto shaderFile = context.OpenAssetFile(shader::GetFileNameForPixelShaderAssetName(pixelShader.name)); @@ -21,7 +57,12 @@ namespace if (!shaderFile) return; +#if defined(FEATURE_T6) shaderFile->write(pixelShader.prog.loadDef.program, pixelShader.prog.loadDef.programSize); +#else + shaderFile->write(reinterpret_cast(pixelShader.prog.loadDef.program), + static_cast(pixelShader.prog.loadDef.programSize) * sizeof(GfxPixelShaderLoadDef::program)); +#endif } void DumpVertexShader(const AssetDumpingContext& context, const MaterialVertexShader& vertexShader) @@ -31,7 +72,12 @@ namespace if (!shaderFile) return; +#if defined(FEATURE_T6) shaderFile->write(vertexShader.prog.loadDef.program, vertexShader.prog.loadDef.programSize); +#else + shaderFile->write(reinterpret_cast(vertexShader.prog.loadDef.program), + static_cast(vertexShader.prog.loadDef.programSize) * sizeof(GfxVertexShaderLoadDef::program)); +#endif } void DumpShaders(AssetDumpingContext& context, const MaterialTechniqueSet& techset) @@ -55,12 +101,17 @@ namespace } } } +#endif techset::CommonVertexDeclaration ConvertToCommonVertexDeclaration(const MaterialVertexDeclaration* vertexDecl) { std::vector commonRouting; +#if defined(FEATURE_IW4) + if (vertexDecl && vertexDecl->name && vertexDecl->name[0] != ',') +#else if (vertexDecl) +#endif { const auto streamCount = std::min(static_cast(vertexDecl->streamCount), std::extent_v); for (auto streamIndex = 0u; streamIndex < streamCount; streamIndex++) @@ -70,12 +121,24 @@ namespace static_cast(routing.dest)); } } +#if defined(FEATURE_IW4) + else if (vertexDecl && vertexDecl->name) + { + auto result = techset::CreateVertexDeclFromName(&vertexDecl->name[1], commonRoutingInfos); + if (result.has_value()) + return std::move(*result); + } +#endif return techset::CommonVertexDeclaration(std::move(commonRouting)); } techset::CommonShaderArg ConvertToCommonArg(const MaterialShaderArgument& arg) { +#if defined(IS_DX9) + const techset::CommonShaderArgDestination destination = {.dx9 = {.m_destination_register = arg.dest}}; + +#endif switch (arg.type) { case MTL_ARG_CODE_VERTEX_CONST: @@ -87,6 +150,7 @@ namespace .m_row_count = arg.u.codeConst.rowCount, }; const techset::CommonShaderArgValue value{.code_const_source = codeConstValue}; +#if defined(IS_DX11) const techset::CommonShaderArgLocationDx11 location{ .constant_buffer_offset = arg.location.offset, }; @@ -97,6 +161,7 @@ namespace .m_buffer = arg.buffer, } }; +#endif return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); } @@ -107,6 +172,7 @@ namespace const techset::CommonShaderArgValue value{ .name_hash = arg.u.nameHash, }; +#if defined(IS_DX11) const techset::CommonShaderArgLocationDx11 location{ .constant_buffer_offset = arg.location.offset, }; @@ -117,6 +183,7 @@ namespace .m_buffer = arg.buffer, } }; +#endif return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); } @@ -126,6 +193,7 @@ namespace const techset::CommonShaderArgValue value{ .code_sampler_source = static_cast(arg.u.codeSampler), }; +#if defined(IS_DX11) const techset::CommonShaderArgLocationDx11 location{ .texture_index = arg.location.textureIndex, .sampler_index = arg.location.samplerIndex, @@ -137,6 +205,7 @@ namespace .m_buffer = arg.buffer, } }; +#endif return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); } @@ -146,6 +215,7 @@ namespace const techset::CommonShaderArgValue value{ .name_hash = arg.u.nameHash, }; +#if defined(IS_DX11) const techset::CommonShaderArgLocationDx11 location{ .texture_index = arg.location.textureIndex, .sampler_index = arg.location.samplerIndex, @@ -157,6 +227,7 @@ namespace .m_buffer = arg.buffer, } }; +#endif return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); } @@ -176,6 +247,7 @@ namespace }; } +#if defined(IS_DX11) const techset::CommonShaderArgLocationDx11 location{ .constant_buffer_offset = arg.location.offset, }; @@ -186,6 +258,7 @@ namespace .m_buffer = arg.buffer, } }; +#endif return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); } @@ -205,7 +278,11 @@ namespace { result.m_bin = techset::CommonTechniqueShaderBin{ .m_shader_bin = vertexShader->prog.loadDef.program, +#if defined(IS_DX9) + .m_shader_bin_size = vertexShader->prog.loadDef.programSize * sizeof(std::remove_pointer_t), +#else .m_shader_bin_size = vertexShader->prog.loadDef.programSize, +#endif }; } @@ -225,7 +302,11 @@ namespace { result.m_bin = techset::CommonTechniqueShaderBin{ .m_shader_bin = pixelShader->prog.loadDef.program, +#if defined(IS_DX9) + .m_shader_bin_size = pixelShader->prog.loadDef.programSize * sizeof(std::remove_pointer_t), +#else .m_shader_bin_size = pixelShader->prog.loadDef.programSize, +#endif }; } @@ -241,11 +322,13 @@ namespace const auto& pass = technique.passArray[passIndex]; std::string comment; +#ifdef FEATURE_T6 if (debug) { comment = std::format( "MaterialType: {}; PrecompiledIndex: {}", static_cast(pass.materialType), static_cast(pass.precompiledIndex)); } +#endif techset::CommonPass commonPass(pass.customSamplerFlags, // No clue what the actual state map was @@ -279,8 +362,17 @@ namespace { const auto commonTechnique = ConvertToCommonTechnique(*technique, debug); - techset::DumpCommonTechnique( - context, commonTechnique, techset::DxVersion::DX11, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState, debug); + techset::DumpCommonTechnique(context, + commonTechnique, +#if defined(IS_DX9) + techset::DxVersion::DX9, +#elif defined(IS_DX11) + techset::DxVersion::DX11, +#endif + commonCodeSourceInfos, + commonRoutingInfos, + *materialConstantState, + debug); } } } @@ -307,24 +399,28 @@ namespace } } // namespace +#set CLASS_NAME "Dumper" + GAME + namespace techset { - DumperT6::DumperT6(const bool debug) + CLASS_NAME::CLASS_NAME(const bool debug) : m_debug(debug) { } - void DumperT6::Dump(AssetDumpingContext& context) + void CLASS_NAME::Dump(AssetDumpingContext& context) { context.GetZoneAssetDumperState()->EnsureInitialized(); AbstractAssetDumper::Dump(context); } - void DumperT6::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) + void CLASS_NAME::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) { const auto* techniqueSet = asset.Asset(); DumpTechset(context, *techniqueSet); DumpTechniques(context, *techniqueSet, m_debug); +#if defined(DUMP_SHADERS) DumpShaders(context, *techniqueSet); +#endif } } // namespace techset diff --git a/src/ObjWriting/Techset/TechsetDumper.h.template b/src/ObjWriting/Techset/TechsetDumper.h.template new file mode 100644 index 00000000..fa1f0721 --- /dev/null +++ b/src/ObjWriting/Techset/TechsetDumper.h.template @@ -0,0 +1,33 @@ +#options GAME(IW4, T6) + +#filename "Game/" + GAME + "/Techset/TechsetDumper" + GAME + ".h" + +#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" + +// This file was templated. +// See TechsetDumper.h.template. +// Do not modify, changes will be lost. + +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include GAME_HEADER + +#set CLASS_NAME "Dumper" + GAME + +namespace techset +{ + class CLASS_NAME final : public AbstractAssetDumper + { + public: + explicit CLASS_NAME(bool debug); + + void Dump(AssetDumpingContext& context) override; + + protected: + void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; + + private: + bool m_debug; + }; +} // namespace techset diff --git a/src/ObjWriting/Techset/VertexShaderDumper.cpp.template b/src/ObjWriting/Techset/VertexShaderDumper.cpp.template new file mode 100644 index 00000000..cade44ba --- /dev/null +++ b/src/ObjWriting/Techset/VertexShaderDumper.cpp.template @@ -0,0 +1,46 @@ +#options GAME(IW4) + +#filename "Game/" + GAME + "/Techset/VertexShaderDumper" + GAME + ".cpp" + +#set DUMPER_HEADER "\"VertexShaderDumper" + GAME + ".h\"" + +#if GAME == "IW3" +#define FEATURE_IW3 +#define IS_DX9 +#elif GAME == "IW4" +#define FEATURE_IW4 +#define IS_DX9 +#elif GAME == "IW5" +#define FEATURE_IW5 +#define IS_DX9 +#endif + +// This file was templated. +// See VertexShaderDumper.cpp.template. +// Do not modify, changes will be lost. + +#include DUMPER_HEADER + +#include "Shader/ShaderCommon.h" + +#include + +using namespace GAME; + +#set CLASS_NAME "VertexShaderDumper" + GAME + +namespace techset +{ + void CLASS_NAME::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) + { + const auto& shader = *asset.Asset(); + const auto shaderFile = context.OpenAssetFile(shader::GetFileNameForVertexShaderAssetName(shader.name)); + + if (!shaderFile) + return; + + shaderFile->write(reinterpret_cast(shader.prog.loadDef.program), + static_cast(shader.prog.loadDef.programSize) + * sizeof(std::remove_pointer_t)); + } +} // namespace techset diff --git a/src/ObjWriting/Techset/VertexShaderDumper.h.template b/src/ObjWriting/Techset/VertexShaderDumper.h.template new file mode 100644 index 00000000..363bfb22 --- /dev/null +++ b/src/ObjWriting/Techset/VertexShaderDumper.h.template @@ -0,0 +1,25 @@ +#options GAME(IW4) + +#filename "Game/" + GAME + "/Techset/VertexShaderDumper" + GAME + ".h" + +#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" + +// This file was templated. +// See VertexShaderDumper.h.template. +// Do not modify, changes will be lost. + +#pragma once + +#include "Dumping/AbstractAssetDumper.h" +#include GAME_HEADER + +#set CLASS_NAME "VertexShaderDumper" + GAME + +namespace techset +{ + class CLASS_NAME final : public AbstractAssetDumper + { + protected: + void DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) override; + }; +} // namespace techset From 2f120927738e89f41e4c653beedae1bcd9bd39c1 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 6 Mar 2026 22:38:11 +0000 Subject: [PATCH 03/14] fix: indentation in shader dumping error message --- src/ObjWriting/Techset/CommonTechniqueDumper.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp index 31128e52..16283d2c 100644 --- a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp +++ b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp @@ -102,6 +102,7 @@ namespace { if (!shader.m_name.empty()) { + Indent(); m_stream << std::format("// ERROR: Cannot dump shader {} as its data is not loaded\n", shader.m_name); con::error("Technique {}: Cannot dump shader {} as its data is not loaded", technique.m_name, shader.m_name); } From 3aac05a516ec4c6d0eb778cf5af4d53170c5ed65 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 7 Mar 2026 00:33:27 +0100 Subject: [PATCH 04/14] fix: make sure matrix shader args with less than 4 rows are properly dumped and loaded --- .../Techset/CommonShaderArgCreator.cpp | 20 +++++++++++++------ .../Techset/CommonTechniqueDumper.cpp | 20 ++++++++++++------- .../Techset/TechsetDumper.cpp.template | 19 ++++++++++++++++++ 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp index 9f0c5c10..5e1497fd 100644 --- a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp +++ b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp @@ -58,8 +58,9 @@ namespace { techset::CommonShaderArgDestination commonDestination{}; bool isTransposed; + unsigned rowCount; std::string errorMessage; - if (!FindDestinationForConstant(commonDestination, isTransposed, errorMessage, destination)) + if (!FindDestinationForConstant(commonDestination, isTransposed, rowCount, errorMessage, destination)) { if (!errorMessage.empty()) return result::Unexpected(std::move(errorMessage)); @@ -67,7 +68,7 @@ namespace return result::Unexpected(std::format("Could not find constant shader input with name {}", destination.m_argument_name)); } - return AcceptShaderConstantArgument(commonDestination, isTransposed, codeConstSource, sourceIndex); + return AcceptShaderConstantArgument(commonDestination, isTransposed, rowCount, codeConstSource, sourceIndex); } result::Expected AcceptShaderSamplerArgument(const techset::CommonShaderArgCreatorDestination& destination, @@ -91,8 +92,9 @@ namespace { techset::CommonShaderArgDestination commonDestination{}; bool isTransposed; + unsigned rowCount; std::string errorMessage; - if (!FindDestinationForConstant(commonDestination, isTransposed, errorMessage, destination)) + if (!FindDestinationForConstant(commonDestination, isTransposed, rowCount, errorMessage, destination)) { if (!errorMessage.empty()) return result::Unexpected(std::move(errorMessage)); @@ -121,8 +123,9 @@ namespace techset::CommonShaderArgDestination commonDestination{}; bool isTransposed; + unsigned rowCount; std::string errorMessage; - if (!FindDestinationForConstant(commonDestination, isTransposed, errorMessage, destination)) + if (!FindDestinationForConstant(commonDestination, isTransposed, rowCount, errorMessage, destination)) { if (!errorMessage.empty()) return result::Unexpected(std::move(errorMessage)); @@ -191,6 +194,7 @@ namespace protected: result::Expected AcceptShaderConstantArgument(const techset::CommonShaderArgDestination& commonDestination, const bool isTransposed, + const unsigned rowCount, const techset::CommonCodeConstSource codeConstSource, const unsigned sourceIndex) { @@ -207,7 +211,7 @@ namespace techset::CommonShaderArgCodeConstValue value{ .m_index = 0, .m_first_row = 0, - .m_row_count = isMatrix ? 4u : 1u, + .m_row_count = isMatrix ? rowCount : 1u, }; if (isMatrix) @@ -260,6 +264,7 @@ namespace [[nodiscard]] virtual bool FindDestinationForConstant(techset::CommonShaderArgDestination& commonDestination, bool& isTransposed, + unsigned& rowCount, std::string& errorMessage, const techset::CommonShaderArgCreatorDestination& input) = 0; [[nodiscard]] virtual bool FindDestinationForSampler(techset::CommonShaderArgDestination& commonDestination, @@ -316,6 +321,7 @@ namespace [[nodiscard]] bool FindDestinationForConstant(techset::CommonShaderArgDestination& commonDestination, bool& isTransposed, + unsigned& rowCount, std::string& errorMessage, const techset::CommonShaderArgCreatorDestination& input) override { @@ -402,6 +408,7 @@ namespace [[nodiscard]] bool FindDestinationForConstant(techset::CommonShaderArgDestination& commonDestination, bool& isTransposed, + unsigned& rowCount, std::string& errorMessage, const techset::CommonShaderArgCreatorDestination& input) override { @@ -448,6 +455,7 @@ namespace commonDestination.dx11.m_size = variableElementSize; commonDestination.dx11.m_buffer = bufferBinding->m_bind_point; isTransposed = variableIterator->m_variable_class == d3d11::VariableClass::MATRIX_COLUMNS; + rowCount = variableIterator->m_row_count; m_const_arg_added[usedConstantIndex] = true; @@ -632,7 +640,7 @@ namespace for (auto elementIndex = 0u; elementIndex < variableElementCount; elementIndex++) { commonDestination.dx11.m_location.constant_buffer_offset = variable.m_offset + variableElementSize * elementIndex; - auto result = AcceptShaderConstantArgument(commonDestination, isTransposed, *maybeCodeConst, elementIndex); + auto result = AcceptShaderConstantArgument(commonDestination, isTransposed, variable.m_row_count, *maybeCodeConst, elementIndex); if (!result) return std::move(result); } diff --git a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp index 16283d2c..0be6f401 100644 --- a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp +++ b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp @@ -202,7 +202,7 @@ namespace codeDestAccessor = targetShaderArg->m_name; const auto isTransposed = targetShaderArg->m_class == d3d9::ParameterClass::MATRIX_COLUMNS; - DumpShaderArg(technique, arg, codeDestAccessor, isTransposed); + DumpShaderArg(technique, arg, codeDestAccessor, isTransposed, targetShaderArg->m_register_count); } void DumpShaderArgDx11(const CommonTechnique& technique, const CommonShaderArg& arg, const d3d11::ShaderInfo& shaderInfo) const @@ -284,7 +284,8 @@ namespace } const auto isTransposed = variable->m_variable_class == d3d11::VariableClass::MATRIX_COLUMNS; - DumpShaderArg(technique, arg, codeDestAccessor, isTransposed); + + DumpShaderArg(technique, arg, codeDestAccessor, isTransposed, variable->m_row_count); } else { @@ -315,11 +316,15 @@ namespace static_cast(arg.m_type.m_value_type)); return; } - DumpShaderArg(technique, arg, boundTextureResource->m_name, false); + DumpShaderArg(technique, arg, boundTextureResource->m_name, false, 0); } } - void DumpShaderArg(const CommonTechnique& technique, const CommonShaderArg& arg, std::string codeDestAccessor, const bool isTransposed) const + void DumpShaderArg(const CommonTechnique& technique, + const CommonShaderArg& arg, + std::string codeDestAccessor, + const bool isTransposed, + const size_t shaderRowCount) const { if (arg.m_type.m_value_type == CommonShaderValueType::CODE_CONST) { @@ -341,9 +346,10 @@ namespace else codeAccessor = std::format("{}[{}]", constSourceInfo->accessor, arg.m_value.code_const_source.m_index - constSourceInfo->value); - // Assert that the value uses 4 rows when matrix and 1 otherwise. - // If this is untrue, there must be more code handling the selected rows - assert((isMatrix && arg.m_value.code_const_source.m_row_count == 4) || arg.m_value.code_const_source.m_row_count == 1); + // Assert that when a code const is not a matrix, the game uses one row of it per arg + // If it is a matrix, the game uses as many rows as can be seen in the shader + assert(isMatrix || arg.m_value.code_const_source.m_row_count == 1); + assert(!isMatrix || arg.m_value.code_const_source.m_row_count == shaderRowCount); if (codeDestAccessor != codeAccessor) { diff --git a/src/ObjWriting/Techset/TechsetDumper.cpp.template b/src/ObjWriting/Techset/TechsetDumper.cpp.template index fd017b9f..c11f36bc 100644 --- a/src/ObjWriting/Techset/TechsetDumper.cpp.template +++ b/src/ObjWriting/Techset/TechsetDumper.cpp.template @@ -33,6 +33,7 @@ #include MATERIAL_CONSTANT_ZONE_STATE_HEADER #include TECHSET_CONSTANTS_HEADER +#include "Pool/GlobalAssetPool.h" #include "Techset/CommonTechniqueDumper.h" #include "Techset/CommonTechsetDumper.h" #include "Techset/CommonVertexDeclCreator.h" @@ -267,6 +268,15 @@ namespace techset::CommonTechniqueShader ConvertToCommonShader(const MaterialVertexShader* vertexShader) { +#if defined(FEATURE_IW4) + if (vertexShader && vertexShader->name && vertexShader->name[0] == ',') + { + auto* globalAsset = GameGlobalAssetPools::GetGlobalPoolsForGame(GameId::IW4)->GetAsset(&vertexShader->name[1]); + if (globalAsset) + vertexShader = globalAsset->Asset(); + } +#endif + techset::CommonTechniqueShader result(techset::CommonTechniqueShaderType::VERTEX, std::string()); if (!vertexShader) return result; @@ -291,6 +301,15 @@ namespace techset::CommonTechniqueShader ConvertToCommonShader(const MaterialPixelShader* pixelShader) { +#if defined(FEATURE_IW4) + if (pixelShader && pixelShader->name && pixelShader->name[0] == ',') + { + auto* globalAsset = GameGlobalAssetPools::GetGlobalPoolsForGame(GameId::IW4)->GetAsset(&pixelShader->name[1]); + if (globalAsset) + pixelShader = globalAsset->Asset(); + } +#endif + techset::CommonTechniqueShader result(techset::CommonTechniqueShaderType::PIXEL, std::string()); if (!pixelShader) return result; From 02a3394c2d95e1c3fc8ea32c75cf129ddcbd9a71 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 7 Mar 2026 09:21:34 +0000 Subject: [PATCH 05/14] fix: fix extraction of source templating games --- tools/scripts/source_templating.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/scripts/source_templating.lua b/tools/scripts/source_templating.lua index db6b7264..71dd9028 100644 --- a/tools/scripts/source_templating.lua +++ b/tools/scripts/source_templating.lua @@ -12,19 +12,19 @@ function useSourceTemplating(projectName) local resultExtension = path.getextension(relativeResultPath) local data = io.readfile(templateFile) - local gameOptionsStart, gameOptionsCount = string.find(data, "#options%s+GAME%s*%(") + local gameOptionsStart, gameOptionsEnd = string.find(data, "#options%s+GAME%s*%(") if gameOptionsStart == nil then error("Source template " .. relativeTemplatePath .. " must define an option called GAME") end - local gameOptionsPos, gameOptionsLenPlusOne = string.find(data, "[%a%d%s,]+%)", gameOptionsStart + gameOptionsCount) + local gameOptionsArgsStart, gameOptionsArgsEnd = string.find(data, "[%a%d%s,]+%)", gameOptionsEnd + 1) - if gameOptionsPos ~= gameOptionsStart + gameOptionsCount then + if gameOptionsArgsStart ~= gameOptionsEnd + 1 then error("Source template " .. relativeTemplatePath .. " must define an option called GAME") end - local gameOptions = string.sub(data, gameOptionsPos, gameOptionsLenPlusOne - 1) + local gameOptions = string.sub(data, gameOptionsArgsStart, gameOptionsArgsEnd - 1) local games = string.explode(gameOptions, ",%s*") files { From 5272b9060d4601da01028a6ae243fbfff5ba3de4 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 7 Mar 2026 09:42:57 +0000 Subject: [PATCH 06/14] chore: use templating for t6 techset compilation --- src/ObjCompiling.lua | 3 + src/ObjCompiling/Game/T6/ObjCompilerT6.cpp | 8 +- .../Game/T6/Techset/TechniqueCompilerT6.h | 12 --- .../Game/T6/Techset/TechsetCompilerT6.h | 12 --- .../Game/T6/Techset/VertexDeclCompilerT6.cpp | 57 ----------- .../Game/T6/Techset/VertexDeclCompilerT6.h | 11 --- .../Techset/CommonShaderArgCreator.cpp | 3 +- .../TechniqueCompiler.cpp.template} | 57 ++++++++--- .../Techset/TechniqueCompiler.h.template | 36 +++++++ .../TechsetCompiler.cpp.template} | 46 +++++++-- .../Techset/TechsetCompiler.h.template | 36 +++++++ .../Techset/VertexDeclCompiler.cpp.template | 97 +++++++++++++++++++ .../Techset/VertexDeclCompiler.h.template | 41 ++++++++ test/ObjCompilingTests.lua | 1 + .../Game/T6/Techset/TechsetCompilerT6Test.cpp | 2 +- 15 files changed, 301 insertions(+), 121 deletions(-) delete mode 100644 src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.h delete mode 100644 src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.h delete mode 100644 src/ObjCompiling/Game/T6/Techset/VertexDeclCompilerT6.cpp delete mode 100644 src/ObjCompiling/Game/T6/Techset/VertexDeclCompilerT6.h rename src/ObjCompiling/{Game/T6/Techset/TechniqueCompilerT6.cpp => Techset/TechniqueCompiler.cpp.template} (90%) create mode 100644 src/ObjCompiling/Techset/TechniqueCompiler.h.template rename src/ObjCompiling/{Game/T6/Techset/TechsetCompilerT6.cpp => Techset/TechsetCompiler.cpp.template} (79%) create mode 100644 src/ObjCompiling/Techset/TechsetCompiler.h.template create mode 100644 src/ObjCompiling/Techset/VertexDeclCompiler.cpp.template create mode 100644 src/ObjCompiling/Techset/VertexDeclCompiler.h.template diff --git a/src/ObjCompiling.lua b/src/ObjCompiling.lua index 38691e33..8070274d 100644 --- a/src/ObjCompiling.lua +++ b/src/ObjCompiling.lua @@ -50,6 +50,9 @@ function ObjCompiling:project() path.join(folder, "ObjCompiling") } } + + ObjCommon:use() + useSourceTemplating("ObjCompiling") self:include(includes) minilzo:include(includes) diff --git a/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp b/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp index 34e0cbb1..37ac9529 100644 --- a/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp +++ b/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp @@ -1,12 +1,12 @@ #include "ObjCompilerT6.h" #include "Game/T6/T6.h" +#include "Game/T6/Techset/TechniqueCompilerT6.h" +#include "Game/T6/Techset/TechsetCompilerT6.h" +#include "Game/T6/Techset/VertexDeclCompilerT6.h" #include "Image/ImageIPakPostProcessor.h" #include "Image/ImageIwdPostProcessor.h" #include "KeyValuePairs/KeyValuePairsCompilerT6.h" -#include "Techset/TechniqueCompilerT6.h" -#include "Techset/TechsetCompilerT6.h" -#include "Techset/VertexDeclCompilerT6.h" #include @@ -23,7 +23,7 @@ namespace auto& memory = zone.Memory(); collection.AddAssetCreator(key_value_pairs::CreateCompilerT6(memory, zone, zoneDefinition.m_zone_definition, zoneStates)); - collection.AddAssetCreator(techset::CreateCompilerT6(memory, searchPath)); + collection.AddAssetCreator(techset::CreateTechsetCompilerT6(memory, searchPath)); collection.AddSubAssetCreator(techset::CreateTechniqueCompilerT6(memory, zone, searchPath)); collection.AddSubAssetCreator(techset::CreateVertexDeclCompilerT6(memory)); diff --git a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.h b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.h deleted file mode 100644 index 869acca8..00000000 --- a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "Asset/IAssetCreator.h" -#include "SearchPath/ISearchPath.h" -#include "Utils/MemoryManager.h" - -#include - -namespace techset -{ - std::unique_ptr CreateTechniqueCompilerT6(MemoryManager& memory, Zone& zone, ISearchPath& searchPath); -} diff --git a/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.h b/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.h deleted file mode 100644 index 2af583f1..00000000 --- a/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "Asset/IAssetCreator.h" -#include "SearchPath/ISearchPath.h" -#include "Utils/MemoryManager.h" - -#include - -namespace techset -{ - std::unique_ptr CreateCompilerT6(MemoryManager& memory, ISearchPath& searchPath); -} // namespace techset diff --git a/src/ObjCompiling/Game/T6/Techset/VertexDeclCompilerT6.cpp b/src/ObjCompiling/Game/T6/Techset/VertexDeclCompilerT6.cpp deleted file mode 100644 index b01f2607..00000000 --- a/src/ObjCompiling/Game/T6/Techset/VertexDeclCompilerT6.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "VertexDeclCompilerT6.h" - -#include "Game/T6/T6.h" -#include "Game/T6/Techset/TechsetConstantsT6.h" -#include "Techset/CommonVertexDeclCreator.h" -#include "Utils/Logging/Log.h" - -using namespace T6; - -namespace -{ - class VertexDeclCompilerT6 final : public SubAssetCreator - { - public: - explicit VertexDeclCompilerT6(MemoryManager& memory) - : m_memory(memory) - { - } - - AssetCreationResult CreateSubAsset(const std::string& subAssetName, AssetCreationContext& context) override - { - const auto commonVertexDecl = techset::CreateVertexDeclFromName(subAssetName, commonRoutingInfos); - if (!commonVertexDecl) - return AssetCreationResult::Failure(); - - if (commonVertexDecl->m_routing.size() > std::extent_v) - { - con::error("Vertex declaration can only have up to {} routing entries", std::extent_v); - return AssetCreationResult::Failure(); - } - - auto* vertexDecl = m_memory.Alloc(); - - for (const auto& commonRoutingEntry : commonVertexDecl->m_routing) - { - vertexDecl->routing.data[vertexDecl->streamCount].source = commonRoutingEntry.m_source; - vertexDecl->routing.data[vertexDecl->streamCount].dest = commonRoutingEntry.m_destination; - vertexDecl->hasOptionalSource = vertexDecl->hasOptionalSource || commonRoutingEntry.m_source >= STREAM_SRC_OPTIONAL_BEGIN; - - vertexDecl->streamCount++; - } - - return AssetCreationResult::Success(context.AddSubAsset(AssetRegistration(subAssetName, vertexDecl))); - } - - private: - MemoryManager& m_memory; - }; -} // namespace - -namespace techset -{ - std::unique_ptr CreateVertexDeclCompilerT6(MemoryManager& memory) - { - return std::make_unique(memory); - } -} // namespace techset diff --git a/src/ObjCompiling/Game/T6/Techset/VertexDeclCompilerT6.h b/src/ObjCompiling/Game/T6/Techset/VertexDeclCompilerT6.h deleted file mode 100644 index 434e602f..00000000 --- a/src/ObjCompiling/Game/T6/Techset/VertexDeclCompilerT6.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "Asset/IAssetCreator.h" -#include "Utils/MemoryManager.h" - -#include - -namespace techset -{ - std::unique_ptr CreateVertexDeclCompilerT6(MemoryManager& memory); -} diff --git a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp index 5e1497fd..4fc8aba3 100644 --- a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp +++ b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp @@ -326,7 +326,7 @@ namespace const techset::CommonShaderArgCreatorDestination& input) override { assert(m_shader_info); - // TODO + return false; } @@ -577,7 +577,6 @@ namespace return std::move(result); } - // TODO return NoResult{}; } diff --git a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp b/src/ObjCompiling/Techset/TechniqueCompiler.cpp.template similarity index 90% rename from src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp rename to src/ObjCompiling/Techset/TechniqueCompiler.cpp.template index 6b61a657..4fff5f44 100644 --- a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp +++ b/src/ObjCompiling/Techset/TechniqueCompiler.cpp.template @@ -1,19 +1,50 @@ -#include "TechniqueCompilerT6.h" +#options GAME(T6) -#include "Game/T6/T6.h" -#include "Game/T6/Techset/TechsetConstantsT6.h" -#include "PrecompiledIndexT6.h" +#filename "Game/" + GAME + "/Techset/TechniqueCompiler" + GAME + ".cpp" + +#set COMPILER_HEADER "\"TechniqueCompiler" + GAME + ".h\"" +#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" +#set TECHSET_CONSTANTS_HEADER "\"Game/" + GAME + "/Techset/TechsetConstants" + GAME + ".h\"" + +#if GAME == "IW3" +#define FEATURE_IW3 +#elif GAME == "IW4" +#define FEATURE_IW4 +#elif GAME == "IW5" +#define FEATURE_IW5 +#elif GAME == "T5" +#define FEATURE_T5 +#elif GAME == "T6" +#define FEATURE_T6 +#endif + +// This file was templated. +// See TechniqueCompiler.cpp.template. +// Do not modify, changes will be lost. + +#include COMPILER_HEADER + +#include GAME_HEADER +#include TECHSET_CONSTANTS_HEADER #include "Techset/CommonShaderArgCreator.h" #include "Techset/CommonTechniqueLoader.h" #include "Techset/LiteralConstsZoneState.h" #include "Utils/StringUtils.h" +#if defined(FEATURE_T6) +#set PRECOMPILED_INDEX_HEADER "\"Game/" + GAME + "/Techset/PrecompiledIndex" + GAME + ".h\"" +#include PRECOMPILED_INDEX_HEADER +#endif + #include #include #include #include -using namespace T6; +using namespace GAME; + +#set SHADER_LOADER_CLASS_NAME "TechniqueShaderLoader" + GAME +#set COMPILER_CLASS_NAME "TechniqueCompiler" + GAME namespace { @@ -236,10 +267,10 @@ namespace } } - class TechniqueShaderLoaderT6 final : public techset::ITechniqueShaderLoader + class SHADER_LOADER_CLASS_NAME final : public techset::ITechniqueShaderLoader { public: - explicit TechniqueShaderLoaderT6(AssetCreationContext& context) + explicit SHADER_LOADER_CLASS_NAME(AssetCreationContext& context) : m_context(context) { } @@ -282,10 +313,10 @@ namespace AssetCreationContext& m_context; }; - class TechniqueCompilerT6 final : public SubAssetCreator + class COMPILER_CLASS_NAME final : public SubAssetCreator { public: - TechniqueCompilerT6(MemoryManager& memory, Zone& zone, ISearchPath& searchPath) + COMPILER_CLASS_NAME(MemoryManager& memory, Zone& zone, ISearchPath& searchPath) : m_memory(memory), m_zone(zone), m_search_path(searchPath) @@ -295,7 +326,7 @@ namespace AssetCreationResult CreateSubAsset(const std::string& subAssetName, AssetCreationContext& context) override { bool failure = false; - TechniqueShaderLoaderT6 shaderLoader(context); + SHADER_LOADER_CLASS_NAME shaderLoader(context); const auto commonShaderArgCreator = techset::CommonShaderArgCreator::CreateDx11(shaderLoader, context, commonCodeSourceInfos); const auto commonTechnique = @@ -336,10 +367,12 @@ namespace }; } // namespace +#set CREATE_COMPILER_METHOD "CreateTechniqueCompiler" + GAME + namespace techset { - std::unique_ptr CreateTechniqueCompilerT6(MemoryManager& memory, Zone& zone, ISearchPath& searchPath) + std::unique_ptr CREATE_COMPILER_METHOD(MemoryManager& memory, Zone& zone, ISearchPath& searchPath) { - return std::make_unique(memory, zone, searchPath); + return std::make_unique(memory, zone, searchPath); } } // namespace techset diff --git a/src/ObjCompiling/Techset/TechniqueCompiler.h.template b/src/ObjCompiling/Techset/TechniqueCompiler.h.template new file mode 100644 index 00000000..a1310e61 --- /dev/null +++ b/src/ObjCompiling/Techset/TechniqueCompiler.h.template @@ -0,0 +1,36 @@ +#options GAME(T6) + +#filename "Game/" + GAME + "/Techset/TechniqueCompiler" + GAME + ".h" + +#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" + +#if GAME == "IW3" +#define FEATURE_IW3 +#elif GAME == "IW4" +#define FEATURE_IW4 +#elif GAME == "IW5" +#define FEATURE_IW5 +#elif GAME == "T5" +#define FEATURE_T5 +#elif GAME == "T6" +#define FEATURE_T6 +#endif + +// This file was templated. +// See TechniqueCompiler.h.template. +// Do not modify, changes will be lost. + +#pragma once + +#include "Asset/IAssetCreator.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +#set CREATE_COMPILER_METHOD "CreateTechniqueCompiler" + GAME + +namespace techset +{ + std::unique_ptr CREATE_COMPILER_METHOD(MemoryManager& memory, Zone& zone, ISearchPath& searchPath); +} diff --git a/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.cpp b/src/ObjCompiling/Techset/TechsetCompiler.cpp.template similarity index 79% rename from src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.cpp rename to src/ObjCompiling/Techset/TechsetCompiler.cpp.template index b23280fc..b005610b 100644 --- a/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.cpp +++ b/src/ObjCompiling/Techset/TechsetCompiler.cpp.template @@ -1,11 +1,37 @@ -#include "TechsetCompilerT6.h" +#options GAME(T6) -#include "Game/T6/T6.h" -#include "Game/T6/Techset/TechsetConstantsT6.h" +#filename "Game/" + GAME + "/Techset/TechsetCompiler" + GAME + ".cpp" + +#set COMPILER_HEADER "\"TechsetCompiler" + GAME + ".h\"" +#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" +#set TECHSET_CONSTANTS_HEADER "\"Game/" + GAME + "/Techset/TechsetConstants" + GAME + ".h\"" + +#if GAME == "IW3" +#define FEATURE_IW3 +#elif GAME == "IW4" +#define FEATURE_IW4 +#elif GAME == "IW5" +#define FEATURE_IW5 +#elif GAME == "T5" +#define FEATURE_T5 +#elif GAME == "T6" +#define FEATURE_T6 +#endif + +// This file was templated. +// See TechsetCompiler.cpp.template. +// Do not modify, changes will be lost. + +#include COMPILER_HEADER + +#include GAME_HEADER +#include TECHSET_CONSTANTS_HEADER #include "Techset/CommonTechsetLoader.h" #include "Techset/TechsetCommon.h" -using namespace T6; +using namespace GAME; + +#set COMPILER_CLASS_NAME "TechsetCompiler" + GAME namespace { @@ -71,10 +97,10 @@ namespace return techset; } - class TechsetCompilerT6 final : public AssetCreator + class COMPILER_CLASS_NAME final : public AssetCreator { public: - TechsetCompilerT6(ISearchPath& searchPath, MemoryManager& memory) + COMPILER_CLASS_NAME(ISearchPath& searchPath, MemoryManager& memory) : m_search_path(searchPath), m_memory(memory) { @@ -106,8 +132,6 @@ namespace // but the game determines the material type by techset name. // So this may just be a constraint that cannot be changed. ApplyMaterialTypeToTechnique(*techset->techniques[techniqueIndex], materialType); - - // Precompiled index? } return AssetCreationResult::Success(context.AddAsset(AssetRegistration(assetName, techset))); @@ -119,10 +143,12 @@ namespace }; } // namespace +#set CREATE_COMPILER_METHOD "CreateTechsetCompiler" + GAME + namespace techset { - std::unique_ptr CreateCompilerT6(MemoryManager& memory, ISearchPath& searchPath) + std::unique_ptr CREATE_COMPILER_METHOD(MemoryManager& memory, ISearchPath& searchPath) { - return std::make_unique(searchPath, memory); + return std::make_unique(searchPath, memory); } } // namespace techset diff --git a/src/ObjCompiling/Techset/TechsetCompiler.h.template b/src/ObjCompiling/Techset/TechsetCompiler.h.template new file mode 100644 index 00000000..78ba580e --- /dev/null +++ b/src/ObjCompiling/Techset/TechsetCompiler.h.template @@ -0,0 +1,36 @@ +#options GAME(T6) + +#filename "Game/" + GAME + "/Techset/TechsetCompiler" + GAME + ".h" + +#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" + +#if GAME == "IW3" +#define FEATURE_IW3 +#elif GAME == "IW4" +#define FEATURE_IW4 +#elif GAME == "IW5" +#define FEATURE_IW5 +#elif GAME == "T5" +#define FEATURE_T5 +#elif GAME == "T6" +#define FEATURE_T6 +#endif + +// This file was templated. +// See TechsetCompiler.h.template. +// Do not modify, changes will be lost. + +#pragma once + +#include "Asset/IAssetCreator.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +#set CREATE_COMPILER_METHOD "CreateTechsetCompiler" + GAME + +namespace techset +{ + std::unique_ptr CREATE_COMPILER_METHOD(MemoryManager& memory, ISearchPath& searchPath); +} diff --git a/src/ObjCompiling/Techset/VertexDeclCompiler.cpp.template b/src/ObjCompiling/Techset/VertexDeclCompiler.cpp.template new file mode 100644 index 00000000..39e01cac --- /dev/null +++ b/src/ObjCompiling/Techset/VertexDeclCompiler.cpp.template @@ -0,0 +1,97 @@ +#options GAME(T6) + +#filename "Game/" + GAME + "/Techset/VertexDeclCompiler" + GAME + ".cpp" + +#set COMPILER_HEADER "\"VertexDeclCompiler" + GAME + ".h\"" +#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" +#set TECHSET_CONSTANTS_HEADER "\"Game/" + GAME + "/Techset/TechsetConstants" + GAME + ".h\"" + +#if GAME == "IW3" +#define FEATURE_IW3 +#elif GAME == "IW4" +#define FEATURE_IW4 +#elif GAME == "IW5" +#define FEATURE_IW5 +#elif GAME == "T5" +#define FEATURE_T5 +#elif GAME == "T6" +#define FEATURE_T6 +#endif + +// This file was templated. +// See VertexDeclCompiler.cpp.template. +// Do not modify, changes will be lost. + +#include COMPILER_HEADER + +#include GAME_HEADER +#include TECHSET_CONSTANTS_HEADER +#include "Techset/CommonVertexDeclCreator.h" +#include "Utils/Logging/Log.h" + +using namespace GAME; + +#set COMPILER_CLASS_NAME "VertexDeclCompiler" + GAME + +#if defined(FEATURE_T6) +#define ABSTRACT_CREATOR_NAME SubAssetCreator +#define OVERRIDEN_CREATOR_METHOD CreateSubAsset +#define ASSET_NAME SubAssetVertexDecl +#define INTERFACE_NAME ISubAssetCreator +#else +#define ABSTRACT_CREATOR_NAME AssetCreator +#define OVERRIDEN_CREATOR_METHOD CreateAsset +#define ASSET_NAME AssetVertexDecl +#define INTERFACE_NAME IAssetCreator +#endif + +namespace +{ + class COMPILER_CLASS_NAME final : public ABSTRACT_CREATOR_NAME + { + public: + explicit COMPILER_CLASS_NAME(MemoryManager& memory) + : m_memory(memory) + { + } + + AssetCreationResult OVERRIDEN_CREATOR_METHOD(const std::string& assetName, AssetCreationContext& context) override + { + const auto commonVertexDecl = techset::CreateVertexDeclFromName(assetName, commonRoutingInfos); + if (!commonVertexDecl) + return AssetCreationResult::Failure(); + + if (commonVertexDecl->m_routing.size() > std::extent_v) + { + con::error("Vertex declaration can only have up to {} routing entries", std::extent_v); + return AssetCreationResult::Failure(); + } + + auto* vertexDecl = m_memory.Alloc(); + + for (const auto& commonRoutingEntry : commonVertexDecl->m_routing) + { + vertexDecl->routing.data[vertexDecl->streamCount].source = commonRoutingEntry.m_source; + vertexDecl->routing.data[vertexDecl->streamCount].dest = commonRoutingEntry.m_destination; + vertexDecl->hasOptionalSource = vertexDecl->hasOptionalSource || commonRoutingEntry.m_source >= STREAM_SRC_OPTIONAL_BEGIN; + + vertexDecl->streamCount++; + } + + return AssetCreationResult::Success(context.AddSubAsset(AssetRegistration(assetName, vertexDecl))); + } + + private: + MemoryManager& m_memory; + }; +} // namespace + +#set CREATE_COMPILER_METHOD "CreateVertexDeclCompiler" + GAME + +namespace techset +{ + std::unique_ptr CREATE_COMPILER_METHOD(MemoryManager& memory) + { + return std::make_unique(memory); + } +} // namespace techset diff --git a/src/ObjCompiling/Techset/VertexDeclCompiler.h.template b/src/ObjCompiling/Techset/VertexDeclCompiler.h.template new file mode 100644 index 00000000..1d20878b --- /dev/null +++ b/src/ObjCompiling/Techset/VertexDeclCompiler.h.template @@ -0,0 +1,41 @@ +#options GAME(T6) + +#filename "Game/" + GAME + "/Techset/VertexDeclCompiler" + GAME + ".h" + +#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" + +#if GAME == "IW3" +#define FEATURE_IW3 +#elif GAME == "IW4" +#define FEATURE_IW4 +#elif GAME == "IW5" +#define FEATURE_IW5 +#elif GAME == "T5" +#define FEATURE_T5 +#elif GAME == "T6" +#define FEATURE_T6 +#endif + +// This file was templated. +// See VertexDeclCompiler.h.template. +// Do not modify, changes will be lost. + +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Utils/MemoryManager.h" + +#include + +#set CREATE_COMPILER_METHOD "CreateVertexDeclCompiler" + GAME + +#if defined(FEATURE_T6) +#define INTERFACE_NAME ISubAssetCreator +#else +#define INTERFACE_NAME IAssetCreator +#endif + +namespace techset +{ + std::unique_ptr CREATE_COMPILER_METHOD(MemoryManager& memory); +} diff --git a/test/ObjCompilingTests.lua b/test/ObjCompilingTests.lua index e521a743..1e382f12 100644 --- a/test/ObjCompilingTests.lua +++ b/test/ObjCompilingTests.lua @@ -3,6 +3,7 @@ ObjCompilingTests = {} function ObjCompilingTests:include(includes) if includes:handle(self:name()) then includedirs { + "%{wks.location}/src/ObjCompiling", path.join(TestFolder(), "ObjCompilingTests") } end diff --git a/test/ObjCompilingTests/Game/T6/Techset/TechsetCompilerT6Test.cpp b/test/ObjCompilingTests/Game/T6/Techset/TechsetCompilerT6Test.cpp index 4eb3a709..51a38425 100644 --- a/test/ObjCompilingTests/Game/T6/Techset/TechsetCompilerT6Test.cpp +++ b/test/ObjCompilingTests/Game/T6/Techset/TechsetCompilerT6Test.cpp @@ -34,7 +34,7 @@ TEST_CASE("TechsetCompilerT6", "[techset][t6][compiler]") AssetCreationContext context(zone, &creators, &ignoredAssets); MockSearchPath searchPath; TestMemoryManager memory; - const auto sut = techset::CreateCompilerT6(memory, searchPath); + const auto sut = techset::CreateTechsetCompilerT6(memory, searchPath); SECTION("Sets correct worldVertFormat") { From 3bb7f1aa05a51da5bb0898b194850aa6963007ba Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 7 Mar 2026 09:51:12 +0000 Subject: [PATCH 07/14] chore: use templated vertex decl compiler --- src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp | 4 +- .../IW4/Techset/CompilerVertexDeclIW4.cpp | 58 ------------------- .../Game/IW4/Techset/CompilerVertexDeclIW4.h | 13 ----- .../Techset/VertexDeclCompiler.cpp.template | 13 ++++- .../Techset/VertexDeclCompiler.h.template | 2 +- 5 files changed, 13 insertions(+), 77 deletions(-) delete mode 100644 src/ObjCompiling/Game/IW4/Techset/CompilerVertexDeclIW4.cpp delete mode 100644 src/ObjCompiling/Game/IW4/Techset/CompilerVertexDeclIW4.h diff --git a/src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp b/src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp index 3930a746..66f326d3 100644 --- a/src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp +++ b/src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp @@ -1,10 +1,10 @@ #include "ObjCompilerIW4.h" #include "Game/IW4/IW4.h" +#include "Game/IW4/Techset/VertexDeclCompilerIW4.h" #include "Image/ImageIwdPostProcessor.h" #include "Material/CompilerMaterialIW4.h" #include "Techset/CompilerTechsetIW4.h" -#include "Techset/CompilerVertexDeclIW4.h" #include @@ -20,7 +20,7 @@ namespace collection.AddAssetCreator(material::CreateCompilerIW4(memory, searchPath, gdt)); collection.AddAssetCreator(techset::CreateLoaderIW4(memory, searchPath)); #endif - collection.AddAssetCreator(vertex_decl::CreateLoaderIW4(memory)); + collection.AddAssetCreator(techset::CreateVertexDeclCompilerIW4(memory)); } void ConfigurePostProcessors(AssetCreatorCollection& collection, diff --git a/src/ObjCompiling/Game/IW4/Techset/CompilerVertexDeclIW4.cpp b/src/ObjCompiling/Game/IW4/Techset/CompilerVertexDeclIW4.cpp deleted file mode 100644 index a2762d59..00000000 --- a/src/ObjCompiling/Game/IW4/Techset/CompilerVertexDeclIW4.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "CompilerVertexDeclIW4.h" - -#include "Game/IW4/IW4.h" -#include "Game/IW4/Techset/TechsetConstantsIW4.h" -#include "Techset/CommonVertexDeclCreator.h" -#include "Utils/Logging/Log.h" - -using namespace IW4; - -namespace -{ - class LoaderVertexDecl final : public AssetCreator - { - public: - explicit LoaderVertexDecl(MemoryManager& memory) - : m_memory(memory) - { - } - - AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override - { - const auto commonVertexDecl = techset::CreateVertexDeclFromName(assetName, commonRoutingInfos); - if (!commonVertexDecl) - return AssetCreationResult::Failure(); - - if (commonVertexDecl->m_routing.size() > std::extent_v) - { - con::error("Vertex declaration can only have up to {} routing entries", std::extent_v); - return AssetCreationResult::Failure(); - } - - auto* vertexDecl = m_memory.Alloc(); - - vertexDecl->name = m_memory.Dup(assetName.c_str()); - - for (const auto& commonRoutingEntry : commonVertexDecl->m_routing) - { - vertexDecl->routing.data[vertexDecl->streamCount].source = commonRoutingEntry.m_source; - vertexDecl->routing.data[vertexDecl->streamCount].dest = commonRoutingEntry.m_destination; - vertexDecl->hasOptionalSource = vertexDecl->hasOptionalSource || commonRoutingEntry.m_source >= STREAM_SRC_OPTIONAL_BEGIN; - - vertexDecl->streamCount++; - } - - return AssetCreationResult::Success(context.AddAsset(AssetRegistration(assetName, vertexDecl))); - } - - MemoryManager& m_memory; - }; -} // namespace - -namespace vertex_decl -{ - std::unique_ptr> CreateLoaderIW4(MemoryManager& memory) - { - return std::make_unique(memory); - } -} // namespace vertex_decl diff --git a/src/ObjCompiling/Game/IW4/Techset/CompilerVertexDeclIW4.h b/src/ObjCompiling/Game/IW4/Techset/CompilerVertexDeclIW4.h deleted file mode 100644 index 4713a652..00000000 --- a/src/ObjCompiling/Game/IW4/Techset/CompilerVertexDeclIW4.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Asset/IAssetCreator.h" -#include "Game/IW4/IW4.h" -#include "SearchPath/ISearchPath.h" -#include "Utils/MemoryManager.h" - -#include - -namespace vertex_decl -{ - std::unique_ptr> CreateLoaderIW4(MemoryManager& memory); -} // namespace vertex_decl diff --git a/src/ObjCompiling/Techset/VertexDeclCompiler.cpp.template b/src/ObjCompiling/Techset/VertexDeclCompiler.cpp.template index 39e01cac..313f9ca3 100644 --- a/src/ObjCompiling/Techset/VertexDeclCompiler.cpp.template +++ b/src/ObjCompiling/Techset/VertexDeclCompiler.cpp.template @@ -1,4 +1,4 @@ -#options GAME(T6) +#options GAME(IW4, T6) #filename "Game/" + GAME + "/Techset/VertexDeclCompiler" + GAME + ".cpp" @@ -16,6 +16,7 @@ #define FEATURE_T5 #elif GAME == "T6" #define FEATURE_T6 +#define IS_SUB_ASSET #endif // This file was templated. @@ -33,14 +34,16 @@ using namespace GAME; #set COMPILER_CLASS_NAME "VertexDeclCompiler" + GAME -#if defined(FEATURE_T6) +#if defined(IS_SUB_ASSET) #define ABSTRACT_CREATOR_NAME SubAssetCreator #define OVERRIDEN_CREATOR_METHOD CreateSubAsset +#define ADD_ASSET_METHOD AddSubAsset #define ASSET_NAME SubAssetVertexDecl #define INTERFACE_NAME ISubAssetCreator #else #define ABSTRACT_CREATOR_NAME AssetCreator #define OVERRIDEN_CREATOR_METHOD CreateAsset +#define ADD_ASSET_METHOD AddAsset #define ASSET_NAME AssetVertexDecl #define INTERFACE_NAME IAssetCreator #endif @@ -69,6 +72,10 @@ namespace auto* vertexDecl = m_memory.Alloc(); +#ifndef IS_SUB_ASSET + vertexDecl->name = m_memory.Dup(assetName.c_str()); +#endif + for (const auto& commonRoutingEntry : commonVertexDecl->m_routing) { vertexDecl->routing.data[vertexDecl->streamCount].source = commonRoutingEntry.m_source; @@ -78,7 +85,7 @@ namespace vertexDecl->streamCount++; } - return AssetCreationResult::Success(context.AddSubAsset(AssetRegistration(assetName, vertexDecl))); + return AssetCreationResult::Success(context.ADD_ASSET_METHOD(AssetRegistration(assetName, vertexDecl))); } private: diff --git a/src/ObjCompiling/Techset/VertexDeclCompiler.h.template b/src/ObjCompiling/Techset/VertexDeclCompiler.h.template index 1d20878b..d236b706 100644 --- a/src/ObjCompiling/Techset/VertexDeclCompiler.h.template +++ b/src/ObjCompiling/Techset/VertexDeclCompiler.h.template @@ -1,4 +1,4 @@ -#options GAME(T6) +#options GAME(IW4, T6) #filename "Game/" + GAME + "/Techset/VertexDeclCompiler" + GAME + ".h" From dbe5cffb2f9a03e6a9e53d24ae864fb07b11f57d Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 7 Mar 2026 10:02:39 +0000 Subject: [PATCH 08/14] feat: use templated techset compiler for IW4 --- src/Common/Game/IW4/IW4.h | 2 ++ src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp | 4 ++-- src/ObjCompiling/Techset/TechsetCompiler.cpp.template | 8 +++++++- src/ObjCompiling/Techset/TechsetCompiler.h.template | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/Common/Game/IW4/IW4.h b/src/Common/Game/IW4/IW4.h index ac7400b2..d30ba9aa 100644 --- a/src/Common/Game/IW4/IW4.h +++ b/src/Common/Game/IW4/IW4.h @@ -223,6 +223,8 @@ namespace IW4 using AssetTracer = Asset; using AssetVehicle = Asset; using AssetAddonMapEnts = Asset; + + using SubAssetTechnique = SubAsset; } // namespace IW4 DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetPhysPreset, name); diff --git a/src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp b/src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp index 66f326d3..79a9723a 100644 --- a/src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp +++ b/src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp @@ -1,10 +1,10 @@ #include "ObjCompilerIW4.h" #include "Game/IW4/IW4.h" +#include "Game/IW4/Techset/TechsetCompilerIW4.h" #include "Game/IW4/Techset/VertexDeclCompilerIW4.h" #include "Image/ImageIwdPostProcessor.h" #include "Material/CompilerMaterialIW4.h" -#include "Techset/CompilerTechsetIW4.h" #include @@ -18,9 +18,9 @@ namespace #ifdef EXPERIMENTAL_MATERIAL_COMPILATION collection.AddAssetCreator(material::CreateCompilerIW4(memory, searchPath, gdt)); - collection.AddAssetCreator(techset::CreateLoaderIW4(memory, searchPath)); #endif collection.AddAssetCreator(techset::CreateVertexDeclCompilerIW4(memory)); + collection.AddAssetCreator(techset::CreateTechsetCompilerIW4(memory, searchPath)); } void ConfigurePostProcessors(AssetCreatorCollection& collection, diff --git a/src/ObjCompiling/Techset/TechsetCompiler.cpp.template b/src/ObjCompiling/Techset/TechsetCompiler.cpp.template index b005610b..38a4890f 100644 --- a/src/ObjCompiling/Techset/TechsetCompiler.cpp.template +++ b/src/ObjCompiling/Techset/TechsetCompiler.cpp.template @@ -1,4 +1,4 @@ -#options GAME(T6) +#options GAME(IW4, T6) #filename "Game/" + GAME + "/Techset/TechsetCompiler" + GAME + ".cpp" @@ -69,6 +69,7 @@ namespace return static_cast(0); } +#if defined(FEATURE_T6) MaterialType GetMaterialType(const std::string& name) { for (unsigned materialTypeIndex = MTL_TYPE_MODEL; materialTypeIndex < MTL_TYPE_COUNT; materialTypeIndex++) @@ -87,6 +88,7 @@ namespace technique.passArray[passIndex].materialType = materialType; } } +#endif MaterialTechniqueSet* ConvertTechniqueSet(const techset::CommonTechset& commonTechset, MemoryManager& memory) { @@ -114,7 +116,9 @@ namespace return failure ? AssetCreationResult::Failure() : AssetCreationResult::NoAction(); auto* techset = ConvertTechniqueSet(*commonTechset, m_memory); +#if defined(FEATURE_T6) const auto materialType = GetMaterialType(assetName); +#endif for (auto techniqueIndex = 0u; techniqueIndex < std::extent_v; techniqueIndex++) { @@ -128,10 +132,12 @@ namespace techset->techniques[techniqueIndex] = technique->Asset(); +#if defined(FEATURE_T6) // Another techset may override this for the technique // but the game determines the material type by techset name. // So this may just be a constraint that cannot be changed. ApplyMaterialTypeToTechnique(*techset->techniques[techniqueIndex], materialType); +#endif } return AssetCreationResult::Success(context.AddAsset(AssetRegistration(assetName, techset))); diff --git a/src/ObjCompiling/Techset/TechsetCompiler.h.template b/src/ObjCompiling/Techset/TechsetCompiler.h.template index 78ba580e..4bbdfc78 100644 --- a/src/ObjCompiling/Techset/TechsetCompiler.h.template +++ b/src/ObjCompiling/Techset/TechsetCompiler.h.template @@ -1,4 +1,4 @@ -#options GAME(T6) +#options GAME(IW4, T6) #filename "Game/" + GAME + "/Techset/TechsetCompiler" + GAME + ".h" From fbfd418e20ceb505f041aa6114ac99ea6c93a0c5 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 7 Mar 2026 10:32:53 +0000 Subject: [PATCH 09/14] feat: add templated technique compiler for IW4 --- src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp | 3 + .../Techset/TechniqueCompiler.cpp.template | 61 ++++++++++++++++++- .../Techset/TechniqueCompiler.h.template | 2 +- 3 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp b/src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp index 79a9723a..88457744 100644 --- a/src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp +++ b/src/ObjCompiling/Game/IW4/ObjCompilerIW4.cpp @@ -1,6 +1,7 @@ #include "ObjCompilerIW4.h" #include "Game/IW4/IW4.h" +#include "Game/IW4/Techset/TechniqueCompilerIW4.h" #include "Game/IW4/Techset/TechsetCompilerIW4.h" #include "Game/IW4/Techset/VertexDeclCompilerIW4.h" #include "Image/ImageIwdPostProcessor.h" @@ -21,6 +22,8 @@ namespace #endif collection.AddAssetCreator(techset::CreateVertexDeclCompilerIW4(memory)); collection.AddAssetCreator(techset::CreateTechsetCompilerIW4(memory, searchPath)); + + collection.AddSubAssetCreator(techset::CreateTechniqueCompilerIW4(memory, zone, searchPath)); } void ConfigurePostProcessors(AssetCreatorCollection& collection, diff --git a/src/ObjCompiling/Techset/TechniqueCompiler.cpp.template b/src/ObjCompiling/Techset/TechniqueCompiler.cpp.template index 4fff5f44..0bd9b10d 100644 --- a/src/ObjCompiling/Techset/TechniqueCompiler.cpp.template +++ b/src/ObjCompiling/Techset/TechniqueCompiler.cpp.template @@ -1,4 +1,4 @@ -#options GAME(T6) +#options GAME(IW4, T6) #filename "Game/" + GAME + "/Techset/TechniqueCompiler" + GAME + ".cpp" @@ -8,14 +8,21 @@ #if GAME == "IW3" #define FEATURE_IW3 +#define IS_DX9 #elif GAME == "IW4" #define FEATURE_IW4 +#define IS_DX9 #elif GAME == "IW5" #define FEATURE_IW5 +#define IS_DX9 #elif GAME == "T5" #define FEATURE_T5 +#define IS_DX9 +#define SHADERS_ARE_SUBASSETS #elif GAME == "T6" #define FEATURE_T6 +#define IS_DX11 +#define SHADERS_ARE_SUBASSETS #endif // This file was templated. @@ -131,6 +138,9 @@ namespace arg.type = static_cast(ConvertArgumentType(commonArg.m_type)); +#if defined(IS_DX9) + arg.dest = static_cast(commonArg.m_destination.dx9.m_destination_register); +#else arg.size = static_cast(commonArg.m_destination.dx11.m_size); arg.buffer = static_cast(commonArg.m_destination.dx11.m_buffer); @@ -146,6 +156,7 @@ namespace arg.location.samplerIndex = static_cast(commonArg.m_destination.dx11.m_location.sampler_index); } +#endif ConvertArgumentValue(arg.u, commonArg, memory, context); } @@ -161,7 +172,11 @@ namespace } const std::string declName(nameStream.str()); +#if defined(SHADERS_ARE_SUBASSETS) auto* vertexDeclAsset = context.LoadSubAsset(declName); +#else + auto* vertexDeclAsset = context.LoadDependency(declName); +#endif assert(vertexDeclAsset); pass.vertexDecl = vertexDeclAsset ? vertexDeclAsset->Asset() : nullptr; } @@ -172,14 +187,22 @@ namespace if (!commonPass.m_vertex_shader.m_name.empty()) { +#if defined(SHADERS_ARE_SUBASSETS) auto* vertexShaderAsset = context.LoadSubAsset(commonPass.m_vertex_shader.m_name); +#else + auto* vertexShaderAsset = context.LoadDependency(commonPass.m_vertex_shader.m_name); +#endif assert(vertexShaderAsset); pass.vertexShader = vertexShaderAsset ? vertexShaderAsset->Asset() : nullptr; } if (!commonPass.m_pixel_shader.m_name.empty()) { +#if defined(SHADERS_ARE_SUBASSETS) auto* pixelShaderAsset = context.LoadSubAsset(commonPass.m_pixel_shader.m_name); +#else + auto* pixelShaderAsset = context.LoadDependency(commonPass.m_pixel_shader.m_name); +#endif assert(pixelShaderAsset); pass.pixelShader = pixelShaderAsset ? pixelShaderAsset->Asset() : nullptr; } @@ -205,6 +228,9 @@ namespace void UpdateTechniqueFlags(MaterialTechnique& technique, const techset::CommonTechnique& commonTechnique) { +#if defined(FEATURE_IW4) + // TODO +#elif defined(FEATURE_T6) std::string lowerTechniqueName(commonTechnique.m_name); utils::MakeStringLowerCase(lowerTechniqueName); @@ -215,9 +241,14 @@ namespace { technique.flags |= TECHNIQUE_FLAG_4; } +#endif if (AnyDeclHasOptionalSource(technique)) +#if defined(FEATURE_IW4) + technique.flags |= TECHNIQUE_FLAG_20; +#elif defined(FEATURE_T6) technique.flags |= TECHNIQUE_FLAG_8; +#endif } MaterialTechnique* ConvertTechnique(const techset::CommonTechnique& commonTechnique, AssetCreationContext& context, MemoryManager& memory) @@ -241,6 +272,7 @@ namespace return technique; } +#if defined(FEATURE_T6) void ApplyTechFlagsFromMaterial(const Material& material, const Zone& zone) { if (!material.techniqueSet || !material.techniqueSet->name || !material.stateBitsTable) @@ -266,6 +298,7 @@ namespace technique->flags |= TECHNIQUE_FLAG_80; } } +#endif class SHADER_LOADER_CLASS_NAME final : public techset::ITechniqueShaderLoader { @@ -277,7 +310,11 @@ namespace std::optional LoadVertexShader(const std::string& name) override { +#if defined(SHADERS_ARE_SUBASSETS) auto* shaderAsset = m_context.LoadSubAsset(name); +#else + auto* shaderAsset = m_context.ForceLoadDependency(name); +#endif if (!shaderAsset) return std::nullopt; @@ -288,13 +325,22 @@ namespace return techset::CommonTechniqueShaderBin{ .m_shader_bin = shader->prog.loadDef.program, +#if defined(IS_DX9) + .m_shader_bin_size = + static_cast(shader->prog.loadDef.programSize) * sizeof(std::remove_pointer_t), +#else .m_shader_bin_size = shader->prog.loadDef.programSize, +#endif }; } std::optional LoadPixelShader(const std::string& name) override { +#if defined(SHADERS_ARE_SUBASSETS) auto* shaderAsset = m_context.LoadSubAsset(name); +#else + auto* shaderAsset = m_context.ForceLoadDependency(name); +#endif if (!shaderAsset) return std::nullopt; @@ -305,7 +351,12 @@ namespace return techset::CommonTechniqueShaderBin{ .m_shader_bin = shader->prog.loadDef.program, +#if defined(IS_DX9) + .m_shader_bin_size = + static_cast(shader->prog.loadDef.programSize) * sizeof(std::remove_pointer_t), +#else .m_shader_bin_size = shader->prog.loadDef.programSize, +#endif }; } @@ -327,7 +378,11 @@ namespace { bool failure = false; SHADER_LOADER_CLASS_NAME shaderLoader(context); +#if defined(IS_DX9) + const auto commonShaderArgCreator = techset::CommonShaderArgCreator::CreateDx9(shaderLoader, context, commonCodeSourceInfos); +#else const auto commonShaderArgCreator = techset::CommonShaderArgCreator::CreateDx11(shaderLoader, context, commonCodeSourceInfos); +#endif const auto commonTechnique = techset::LoadCommonTechnique(subAssetName, commonCodeSourceInfos, commonRoutingInfos, *commonShaderArgCreator, m_search_path, failure); @@ -343,6 +398,9 @@ namespace void FinalizeZone(AssetCreationContext& context) override { +#if defined(FEATURE_IW4) + // TODO +#elif defined(FEATURE_T6) const auto materials = m_zone.m_pools.PoolAssets(); for (auto* materialAsset : materials) { @@ -358,6 +416,7 @@ namespace ApplyPrecompiledIndex(technique.passArray[passIndex]); } } +#endif } private: diff --git a/src/ObjCompiling/Techset/TechniqueCompiler.h.template b/src/ObjCompiling/Techset/TechniqueCompiler.h.template index a1310e61..f858775d 100644 --- a/src/ObjCompiling/Techset/TechniqueCompiler.h.template +++ b/src/ObjCompiling/Techset/TechniqueCompiler.h.template @@ -1,4 +1,4 @@ -#options GAME(T6) +#options GAME(IW4, T6) #filename "Game/" + GAME + "/Techset/TechniqueCompiler" + GAME + ".h" From 6e19b94b9b912578cc16e6aab0f6360c4cbdd1a2 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 7 Mar 2026 11:11:53 +0000 Subject: [PATCH 10/14] chore: use templated loaders for shaders in IW4,T6 --- .../Game/IW4/Techset/CompilerTechsetIW4.cpp | 2 - .../Techset/TechniqueCompiler.h.template | 2 - .../Techset/TechsetCompiler.h.template | 2 - .../Techset/VertexDeclCompiler.cpp.template | 6 +- .../Techset/VertexDeclCompiler.h.template | 2 - src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp | 8 +- .../Game/IW4/Shader/LoaderPixelShaderIW4.cpp | 64 ---------- .../Game/IW4/Shader/LoaderPixelShaderIW4.h | 13 -- .../Game/IW4/Shader/LoaderVertexShaderIW4.cpp | 64 ---------- .../Game/IW4/Shader/LoaderVertexShaderIW4.h | 13 -- src/ObjLoading/Game/T6/ObjLoaderT6.cpp | 4 +- .../Game/T6/Techset/PixelShaderLoaderT6.cpp | 55 -------- .../Game/T6/Techset/PixelShaderLoaderT6.h | 13 -- .../Game/T6/Techset/VertexShaderLoaderT6.cpp | 55 -------- .../Game/T6/Techset/VertexShaderLoaderT6.h | 13 -- .../Techset/PixelShaderLoader.cpp.template | 117 +++++++++++++++++ .../Techset/PixelShaderLoader.h.template | 40 ++++++ .../Techset/VertexShaderLoader.cpp.template | 118 ++++++++++++++++++ .../Techset/VertexShaderLoader.h.template | 40 ++++++ test/ObjCompilingTests.lua | 1 + 20 files changed, 325 insertions(+), 307 deletions(-) delete mode 100644 src/ObjLoading/Game/IW4/Shader/LoaderPixelShaderIW4.cpp delete mode 100644 src/ObjLoading/Game/IW4/Shader/LoaderPixelShaderIW4.h delete mode 100644 src/ObjLoading/Game/IW4/Shader/LoaderVertexShaderIW4.cpp delete mode 100644 src/ObjLoading/Game/IW4/Shader/LoaderVertexShaderIW4.h delete mode 100644 src/ObjLoading/Game/T6/Techset/PixelShaderLoaderT6.cpp delete mode 100644 src/ObjLoading/Game/T6/Techset/PixelShaderLoaderT6.h delete mode 100644 src/ObjLoading/Game/T6/Techset/VertexShaderLoaderT6.cpp delete mode 100644 src/ObjLoading/Game/T6/Techset/VertexShaderLoaderT6.h create mode 100644 src/ObjLoading/Techset/PixelShaderLoader.cpp.template create mode 100644 src/ObjLoading/Techset/PixelShaderLoader.h.template create mode 100644 src/ObjLoading/Techset/VertexShaderLoader.cpp.template create mode 100644 src/ObjLoading/Techset/VertexShaderLoader.h.template diff --git a/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp b/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp index f3a4d0df..abe15d9d 100644 --- a/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp +++ b/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp @@ -1,8 +1,6 @@ #include "CompilerTechsetIW4.h" #include "Game/IW4/IW4.h" -#include "Game/IW4/Shader/LoaderPixelShaderIW4.h" -#include "Game/IW4/Shader/LoaderVertexShaderIW4.h" #include "Game/IW4/Techset/TechsetConstantsIW4.h" #include "Shader/D3D9ShaderAnalyser.h" #include "Shader/ShaderCommon.h" diff --git a/src/ObjCompiling/Techset/TechniqueCompiler.h.template b/src/ObjCompiling/Techset/TechniqueCompiler.h.template index f858775d..a1bbe9f0 100644 --- a/src/ObjCompiling/Techset/TechniqueCompiler.h.template +++ b/src/ObjCompiling/Techset/TechniqueCompiler.h.template @@ -2,8 +2,6 @@ #filename "Game/" + GAME + "/Techset/TechniqueCompiler" + GAME + ".h" -#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" - #if GAME == "IW3" #define FEATURE_IW3 #elif GAME == "IW4" diff --git a/src/ObjCompiling/Techset/TechsetCompiler.h.template b/src/ObjCompiling/Techset/TechsetCompiler.h.template index 4bbdfc78..6e6d8abd 100644 --- a/src/ObjCompiling/Techset/TechsetCompiler.h.template +++ b/src/ObjCompiling/Techset/TechsetCompiler.h.template @@ -2,8 +2,6 @@ #filename "Game/" + GAME + "/Techset/TechsetCompiler" + GAME + ".h" -#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" - #if GAME == "IW3" #define FEATURE_IW3 #elif GAME == "IW4" diff --git a/src/ObjCompiling/Techset/VertexDeclCompiler.cpp.template b/src/ObjCompiling/Techset/VertexDeclCompiler.cpp.template index 313f9ca3..b3a9ba17 100644 --- a/src/ObjCompiling/Techset/VertexDeclCompiler.cpp.template +++ b/src/ObjCompiling/Techset/VertexDeclCompiler.cpp.template @@ -36,13 +36,13 @@ using namespace GAME; #if defined(IS_SUB_ASSET) #define ABSTRACT_CREATOR_NAME SubAssetCreator -#define OVERRIDEN_CREATOR_METHOD CreateSubAsset +#define OVERRIDDEN_CREATOR_METHOD CreateSubAsset #define ADD_ASSET_METHOD AddSubAsset #define ASSET_NAME SubAssetVertexDecl #define INTERFACE_NAME ISubAssetCreator #else #define ABSTRACT_CREATOR_NAME AssetCreator -#define OVERRIDEN_CREATOR_METHOD CreateAsset +#define OVERRIDDEN_CREATOR_METHOD CreateAsset #define ADD_ASSET_METHOD AddAsset #define ASSET_NAME AssetVertexDecl #define INTERFACE_NAME IAssetCreator @@ -58,7 +58,7 @@ namespace { } - AssetCreationResult OVERRIDEN_CREATOR_METHOD(const std::string& assetName, AssetCreationContext& context) override + AssetCreationResult OVERRIDDEN_CREATOR_METHOD(const std::string& assetName, AssetCreationContext& context) override { const auto commonVertexDecl = techset::CreateVertexDeclFromName(assetName, commonRoutingInfos); if (!commonVertexDecl) diff --git a/src/ObjCompiling/Techset/VertexDeclCompiler.h.template b/src/ObjCompiling/Techset/VertexDeclCompiler.h.template index d236b706..c7c4b6a5 100644 --- a/src/ObjCompiling/Techset/VertexDeclCompiler.h.template +++ b/src/ObjCompiling/Techset/VertexDeclCompiler.h.template @@ -2,8 +2,6 @@ #filename "Game/" + GAME + "/Techset/VertexDeclCompiler" + GAME + ".h" -#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" - #if GAME == "IW3" #define FEATURE_IW3 #elif GAME == "IW4" diff --git a/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp b/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp index 8d5899a2..1bc7f913 100644 --- a/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp +++ b/src/ObjLoading/Game/IW4/ObjLoaderIW4.cpp @@ -6,6 +6,8 @@ #include "Game/IW4/IW4.h" #include "Game/IW4/Image/ImageLoaderEmbeddedIW4.h" #include "Game/IW4/Image/ImageLoaderExternalIW4.h" +#include "Game/IW4/Techset/PixelShaderLoaderIW4.h" +#include "Game/IW4/Techset/VertexShaderLoaderIW4.h" #include "Game/IW4/XModel/LoaderXModelIW4.h" #include "Leaderboard/LoaderLeaderboardIW4.h" #include "LightDef/LightDefLoaderIW4.h" @@ -16,8 +18,6 @@ #include "PhysPreset/GdtLoaderPhysPresetIW4.h" #include "PhysPreset/RawLoaderPhysPresetIW4.h" #include "RawFile/LoaderRawFileIW4.h" -#include "Shader/LoaderPixelShaderIW4.h" -#include "Shader/LoaderVertexShaderIW4.h" #include "Sound/LoaderSoundCurveIW4.h" #include "StringTable/LoaderStringTableIW4.h" #include "StructuredDataDef/LoaderStructuredDataDefIW4.h" @@ -129,8 +129,8 @@ namespace // collection.AddAssetCreator(std::make_unique(memory)); collection.AddAssetCreator(xmodel::CreateLoaderIW4(memory, searchPath, zone)); collection.AddAssetCreator(material::CreateLoaderIW4(memory, searchPath)); - collection.AddAssetCreator(shader::CreatePixelShaderLoaderIW4(memory, searchPath)); - collection.AddAssetCreator(shader::CreateVertexShaderLoaderIW4(memory, searchPath)); + collection.AddAssetCreator(techset::CreateVertexShaderLoaderIW4(memory, searchPath)); + collection.AddAssetCreator(techset::CreatePixelShaderLoaderIW4(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); collection.AddAssetCreator(image::CreateLoaderEmbeddedIW4(memory, searchPath)); collection.AddAssetCreator(image::CreateLoaderExternalIW4(memory, searchPath)); diff --git a/src/ObjLoading/Game/IW4/Shader/LoaderPixelShaderIW4.cpp b/src/ObjLoading/Game/IW4/Shader/LoaderPixelShaderIW4.cpp deleted file mode 100644 index 4450dc92..00000000 --- a/src/ObjLoading/Game/IW4/Shader/LoaderPixelShaderIW4.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "LoaderPixelShaderIW4.h" - -#include "Game/IW4/IW4.h" -#include "Shader/ShaderCommon.h" -#include "Utils/Logging/Log.h" - -#include -#include -#include - -using namespace IW4; - -namespace -{ - class PixelShaderLoader final : public AssetCreator - { - public: - PixelShaderLoader(MemoryManager& memory, ISearchPath& searchPath) - : m_memory(memory), - m_search_path(searchPath) - { - } - - AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override - { - const auto fileName = shader::GetFileNameForPixelShaderAssetName(assetName); - const auto file = m_search_path.Open(fileName); - if (!file.IsOpen()) - return AssetCreationResult::NoAction(); - - if (file.m_length % sizeof(uint32_t) != 0) - { - con::error("Invalid pixel shader \"{}\": Size must be dividable by {}", assetName, sizeof(uint32_t)); - return AssetCreationResult::Failure(); - } - - auto* pixelShader = m_memory.Alloc(); - pixelShader->name = m_memory.Dup(assetName.c_str()); - pixelShader->prog.loadDef.programSize = static_cast(static_cast(file.m_length) / sizeof(uint32_t)); - pixelShader->prog.loadDef.loadForRenderer = 0; - pixelShader->prog.ps = nullptr; - - auto* fileBuffer = m_memory.Alloc(pixelShader->prog.loadDef.programSize); - file.m_stream->read(reinterpret_cast(fileBuffer), static_cast(pixelShader->prog.loadDef.programSize) * sizeof(uint32_t)); - if (file.m_stream->gcount() != file.m_length) - return AssetCreationResult::Failure(); - - pixelShader->prog.loadDef.program = fileBuffer; - return AssetCreationResult::Success(context.AddAsset(assetName, pixelShader)); - } - - private: - MemoryManager& m_memory; - ISearchPath& m_search_path; - }; -} // namespace - -namespace shader -{ - std::unique_ptr> CreatePixelShaderLoaderIW4(MemoryManager& memory, ISearchPath& searchPath) - { - return std::make_unique(memory, searchPath); - } -} // namespace shader diff --git a/src/ObjLoading/Game/IW4/Shader/LoaderPixelShaderIW4.h b/src/ObjLoading/Game/IW4/Shader/LoaderPixelShaderIW4.h deleted file mode 100644 index 0bc212a5..00000000 --- a/src/ObjLoading/Game/IW4/Shader/LoaderPixelShaderIW4.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Asset/IAssetCreator.h" -#include "Game/IW4/IW4.h" -#include "SearchPath/ISearchPath.h" -#include "Utils/MemoryManager.h" - -#include - -namespace shader -{ - std::unique_ptr> CreatePixelShaderLoaderIW4(MemoryManager& memory, ISearchPath& searchPath); -} // namespace shader diff --git a/src/ObjLoading/Game/IW4/Shader/LoaderVertexShaderIW4.cpp b/src/ObjLoading/Game/IW4/Shader/LoaderVertexShaderIW4.cpp deleted file mode 100644 index 79fcff64..00000000 --- a/src/ObjLoading/Game/IW4/Shader/LoaderVertexShaderIW4.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "LoaderVertexShaderIW4.h" - -#include "Game/IW4/IW4.h" -#include "Shader/ShaderCommon.h" -#include "Utils/Logging/Log.h" - -#include -#include -#include - -using namespace IW4; - -namespace -{ - class VertexShaderLoader final : public AssetCreator - { - public: - VertexShaderLoader(MemoryManager& memory, ISearchPath& searchPath) - : m_memory(memory), - m_search_path(searchPath) - { - } - - AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override - { - const auto fileName = shader::GetFileNameForVertexShaderAssetName(assetName); - const auto file = m_search_path.Open(fileName); - if (!file.IsOpen()) - return AssetCreationResult::NoAction(); - - if (file.m_length % sizeof(uint32_t) != 0) - { - con::error("Invalid vertex shader \"{}\": Size must be dividable by {}", assetName, sizeof(uint32_t)); - return AssetCreationResult::Failure(); - } - - auto* vertexShader = m_memory.Alloc(); - vertexShader->name = m_memory.Dup(assetName.c_str()); - vertexShader->prog.loadDef.programSize = static_cast(static_cast(file.m_length) / sizeof(uint32_t)); - vertexShader->prog.loadDef.loadForRenderer = 0; - vertexShader->prog.vs = nullptr; - - auto* fileBuffer = m_memory.Alloc(vertexShader->prog.loadDef.programSize); - file.m_stream->read(reinterpret_cast(fileBuffer), static_cast(vertexShader->prog.loadDef.programSize) * sizeof(uint32_t)); - if (file.m_stream->gcount() != file.m_length) - return AssetCreationResult::Failure(); - - vertexShader->prog.loadDef.program = fileBuffer; - return AssetCreationResult::Success(context.AddAsset(assetName, vertexShader)); - } - - private: - MemoryManager& m_memory; - ISearchPath& m_search_path; - }; -} // namespace - -namespace shader -{ - std::unique_ptr> CreateVertexShaderLoaderIW4(MemoryManager& memory, ISearchPath& searchPath) - { - return std::make_unique(memory, searchPath); - } -} // namespace shader diff --git a/src/ObjLoading/Game/IW4/Shader/LoaderVertexShaderIW4.h b/src/ObjLoading/Game/IW4/Shader/LoaderVertexShaderIW4.h deleted file mode 100644 index 28076aaf..00000000 --- a/src/ObjLoading/Game/IW4/Shader/LoaderVertexShaderIW4.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Asset/IAssetCreator.h" -#include "Game/IW4/IW4.h" -#include "SearchPath/ISearchPath.h" -#include "Utils/MemoryManager.h" - -#include - -namespace shader -{ - std::unique_ptr> CreateVertexShaderLoaderIW4(MemoryManager& memory, ISearchPath& searchPath); -} // namespace shader diff --git a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp index 7f5fbc09..97c9128b 100644 --- a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp +++ b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp @@ -9,6 +9,8 @@ #include "Game/T6/Image/ImageLoaderEmbeddedT6.h" #include "Game/T6/Image/ImageLoaderExternalT6.h" #include "Game/T6/T6.h" +#include "Game/T6/Techset/PixelShaderLoaderT6.h" +#include "Game/T6/Techset/VertexShaderLoaderT6.h" #include "Game/T6/XModel/LoaderXModelT6.h" #include "Image/Dx12TextureLoader.h" #include "Image/IwiLoader.h" @@ -29,8 +31,6 @@ #include "Slug/LoaderSlugT6.h" #include "Sound/LoaderSoundBankT6.h" #include "StringTable/LoaderStringTableT6.h" -#include "Techset/PixelShaderLoaderT6.h" -#include "Techset/VertexShaderLoaderT6.h" #include "Tracer/GdtLoaderTracerT6.h" #include "Tracer/RawLoaderTracerT6.h" #include "Utils/Logging/Log.h" diff --git a/src/ObjLoading/Game/T6/Techset/PixelShaderLoaderT6.cpp b/src/ObjLoading/Game/T6/Techset/PixelShaderLoaderT6.cpp deleted file mode 100644 index acd67d55..00000000 --- a/src/ObjLoading/Game/T6/Techset/PixelShaderLoaderT6.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "PixelShaderLoaderT6.h" - -#include "Game/T6/T6.h" -#include "Shader/ShaderCommon.h" - -#include -#include - -using namespace T6; - -namespace -{ - class PixelShaderLoader final : public SubAssetCreator - { - public: - PixelShaderLoader(MemoryManager& memory, ISearchPath& searchPath) - : m_memory(memory), - m_search_path(searchPath) - { - } - - AssetCreationResult CreateSubAsset(const std::string& assetName, AssetCreationContext& context) override - { - const auto fileName = shader::GetFileNameForPixelShaderAssetName(assetName); - const auto file = m_search_path.Open(fileName); - if (!file.IsOpen()) - return AssetCreationResult::NoAction(); - - auto* pixelShader = m_memory.Alloc(); - pixelShader->name = m_memory.Dup(assetName.c_str()); - pixelShader->prog.loadDef.programSize = static_cast(file.m_length); - pixelShader->prog.ps = nullptr; - - auto* fileBuffer = m_memory.Alloc(pixelShader->prog.loadDef.programSize); - file.m_stream->read(fileBuffer, pixelShader->prog.loadDef.programSize); - if (file.m_stream->gcount() != file.m_length) - return AssetCreationResult::Failure(); - - pixelShader->prog.loadDef.program = fileBuffer; - return AssetCreationResult::Success(context.AddSubAsset(assetName, pixelShader)); - } - - private: - MemoryManager& m_memory; - ISearchPath& m_search_path; - }; -} // namespace - -namespace techset -{ - std::unique_ptr> CreatePixelShaderLoaderT6(MemoryManager& memory, ISearchPath& searchPath) - { - return std::make_unique(memory, searchPath); - } -} // namespace techset diff --git a/src/ObjLoading/Game/T6/Techset/PixelShaderLoaderT6.h b/src/ObjLoading/Game/T6/Techset/PixelShaderLoaderT6.h deleted file mode 100644 index 199960cf..00000000 --- a/src/ObjLoading/Game/T6/Techset/PixelShaderLoaderT6.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Asset/IAssetCreator.h" -#include "Game/T6/T6.h" -#include "SearchPath/ISearchPath.h" -#include "Utils/MemoryManager.h" - -#include - -namespace techset -{ - std::unique_ptr> CreatePixelShaderLoaderT6(MemoryManager& memory, ISearchPath& searchPath); -} // namespace techset diff --git a/src/ObjLoading/Game/T6/Techset/VertexShaderLoaderT6.cpp b/src/ObjLoading/Game/T6/Techset/VertexShaderLoaderT6.cpp deleted file mode 100644 index 8dd2fa06..00000000 --- a/src/ObjLoading/Game/T6/Techset/VertexShaderLoaderT6.cpp +++ /dev/null @@ -1,55 +0,0 @@ -#include "VertexShaderLoaderT6.h" - -#include "Game/T6/T6.h" -#include "Shader/ShaderCommon.h" - -#include -#include - -using namespace T6; - -namespace -{ - class VertexShaderLoader final : public SubAssetCreator - { - public: - VertexShaderLoader(MemoryManager& memory, ISearchPath& searchPath) - : m_memory(memory), - m_search_path(searchPath) - { - } - - AssetCreationResult CreateSubAsset(const std::string& assetName, AssetCreationContext& context) override - { - const auto fileName = shader::GetFileNameForVertexShaderAssetName(assetName); - const auto file = m_search_path.Open(fileName); - if (!file.IsOpen()) - return AssetCreationResult::NoAction(); - - auto* vertexShader = m_memory.Alloc(); - vertexShader->name = m_memory.Dup(assetName.c_str()); - vertexShader->prog.loadDef.programSize = static_cast(file.m_length); - vertexShader->prog.vs = nullptr; - - auto* fileBuffer = m_memory.Alloc(vertexShader->prog.loadDef.programSize); - file.m_stream->read(fileBuffer, vertexShader->prog.loadDef.programSize); - if (file.m_stream->gcount() != file.m_length) - return AssetCreationResult::Failure(); - - vertexShader->prog.loadDef.program = fileBuffer; - return AssetCreationResult::Success(context.AddSubAsset(assetName, vertexShader)); - } - - private: - MemoryManager& m_memory; - ISearchPath& m_search_path; - }; -} // namespace - -namespace techset -{ - std::unique_ptr> CreateVertexShaderLoaderT6(MemoryManager& memory, ISearchPath& searchPath) - { - return std::make_unique(memory, searchPath); - } -} // namespace techset diff --git a/src/ObjLoading/Game/T6/Techset/VertexShaderLoaderT6.h b/src/ObjLoading/Game/T6/Techset/VertexShaderLoaderT6.h deleted file mode 100644 index d0ae6c76..00000000 --- a/src/ObjLoading/Game/T6/Techset/VertexShaderLoaderT6.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include "Asset/IAssetCreator.h" -#include "Game/T6/T6.h" -#include "SearchPath/ISearchPath.h" -#include "Utils/MemoryManager.h" - -#include - -namespace techset -{ - std::unique_ptr> CreateVertexShaderLoaderT6(MemoryManager& memory, ISearchPath& searchPath); -} // namespace techset diff --git a/src/ObjLoading/Techset/PixelShaderLoader.cpp.template b/src/ObjLoading/Techset/PixelShaderLoader.cpp.template new file mode 100644 index 00000000..19de8f72 --- /dev/null +++ b/src/ObjLoading/Techset/PixelShaderLoader.cpp.template @@ -0,0 +1,117 @@ +#options GAME(IW4, T6) + +#filename "Game/" + GAME + "/Techset/PixelShaderLoader" + GAME + ".cpp" + +#set LOADER_HEADER "\"PixelShaderLoader" + GAME + ".h\"" +#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" + +#if GAME == "IW3" +#define FEATURE_IW3 +#define IS_DX9 +#elif GAME == "IW4" +#define FEATURE_IW4 +#define IS_DX9 +#elif GAME == "IW5" +#define FEATURE_IW5 +#define IS_DX9 +#elif GAME == "T5" +#define FEATURE_T5 +#define IS_DX9 +#elif GAME == "T6" +#define FEATURE_T6 +#define IS_DX11 +#define IS_SUB_ASSET +#endif + +#include LOADER_HEADER + +#include GAME_HEADER +#include "Shader/ShaderCommon.h" +#include "Utils/Logging/Log.h" + +#include +#include + +using namespace GAME; + +#set LOADER_CLASS_NAME "PixelShaderLoader" + GAME + +#if defined(IS_SUB_ASSET) +#define ABSTRACT_CREATOR_NAME SubAssetCreator +#define OVERRIDDEN_CREATOR_METHOD CreateSubAsset +#define ADD_ASSET_METHOD AddSubAsset +#define ASSET_NAME SubAssetPixelShader +#define INTERFACE_NAME ISubAssetCreator +#else +#define ABSTRACT_CREATOR_NAME AssetCreator +#define OVERRIDDEN_CREATOR_METHOD CreateAsset +#define ADD_ASSET_METHOD AddAsset +#define ASSET_NAME AssetPixelShader +#define INTERFACE_NAME IAssetCreator +#endif + +namespace +{ + class LOADER_CLASS_NAME final : public ABSTRACT_CREATOR_NAME + { + public: + LOADER_CLASS_NAME(MemoryManager& memory, ISearchPath& searchPath) + : m_memory(memory), + m_search_path(searchPath) + { + } + + AssetCreationResult OVERRIDDEN_CREATOR_METHOD(const std::string& assetName, AssetCreationContext& context) override + { + const auto fileName = shader::GetFileNameForPixelShaderAssetName(assetName); + const auto file = m_search_path.Open(fileName); + if (!file.IsOpen()) + return AssetCreationResult::NoAction(); + +#if defined(IS_DX9) + if (file.m_length % sizeof(uint32_t) != 0) + { + con::error("Invalid pixel shader \"{}\": Size must be dividable by {}", assetName, sizeof(uint32_t)); + return AssetCreationResult::Failure(); + } +#endif + + auto* pixelShader = m_memory.Alloc(); + pixelShader->name = m_memory.Dup(assetName.c_str()); + pixelShader->prog.loadDef.programSize = static_cast( +#if defined(IS_DX9) + file.m_length / sizeof(std::remove_pointer_t) +#else + file.m_length +#endif + ); + pixelShader->prog.ps = nullptr; + + auto* fileBuffer = m_memory.Alloc(static_cast(file.m_length)); + file.m_stream->read(fileBuffer, file.m_length); + if (file.m_stream->gcount() != file.m_length) + return AssetCreationResult::Failure(); + +#if defined(IS_DX9) + pixelShader->prog.loadDef.program = reinterpret_cast(fileBuffer); +#else + pixelShader->prog.loadDef.program = fileBuffer; +#endif + return AssetCreationResult::Success(context.ADD_ASSET_METHOD(assetName, pixelShader)); + } + + private: + MemoryManager& m_memory; + ISearchPath& m_search_path; + }; +} // namespace + +#set CREATE_LOADER_METHOD "CreatePixelShaderLoader" + GAME + +namespace techset +{ + std::unique_ptr CREATE_LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath) + { + return std::make_unique(memory, searchPath); + } +} // namespace techset diff --git a/src/ObjLoading/Techset/PixelShaderLoader.h.template b/src/ObjLoading/Techset/PixelShaderLoader.h.template new file mode 100644 index 00000000..05933dab --- /dev/null +++ b/src/ObjLoading/Techset/PixelShaderLoader.h.template @@ -0,0 +1,40 @@ +#options GAME(IW4, T6) + +#filename "Game/" + GAME + "/Techset/PixelShaderLoader" + GAME + ".h" + +#if GAME == "IW3" +#define FEATURE_IW3 +#elif GAME == "IW4" +#define FEATURE_IW4 +#elif GAME == "IW5" +#define FEATURE_IW5 +#elif GAME == "T5" +#define FEATURE_T5 +#elif GAME == "T6" +#define FEATURE_T6 +#endif + +// This file was templated. +// See PixelShaderLoader.h.template. +// Do not modify, changes will be lost. + +#pragma once + +#include "Asset/IAssetCreator.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +#set CREATE_LOADER_METHOD "CreatePixelShaderLoader" + GAME + +#if defined(FEATURE_T6) +#define INTERFACE_NAME ISubAssetCreator +#else +#define INTERFACE_NAME IAssetCreator +#endif + +namespace techset +{ + std::unique_ptr CREATE_LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath); +} // namespace techset diff --git a/src/ObjLoading/Techset/VertexShaderLoader.cpp.template b/src/ObjLoading/Techset/VertexShaderLoader.cpp.template new file mode 100644 index 00000000..fb68e435 --- /dev/null +++ b/src/ObjLoading/Techset/VertexShaderLoader.cpp.template @@ -0,0 +1,118 @@ +#options GAME(IW4, T6) + +#filename "Game/" + GAME + "/Techset/VertexShaderLoader" + GAME + ".cpp" + +#set LOADER_HEADER "\"VertexShaderLoader" + GAME + ".h\"" +#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\"" + +#if GAME == "IW3" +#define FEATURE_IW3 +#define IS_DX9 +#elif GAME == "IW4" +#define FEATURE_IW4 +#define IS_DX9 +#elif GAME == "IW5" +#define FEATURE_IW5 +#define IS_DX9 +#elif GAME == "T5" +#define FEATURE_T5 +#define IS_DX9 +#elif GAME == "T6" +#define FEATURE_T6 +#define IS_DX11 +#define IS_SUB_ASSET +#endif + +#include LOADER_HEADER + +#include GAME_HEADER +#include "Shader/ShaderCommon.h" +#include "Utils/Logging/Log.h" + +#include +#include + +using namespace GAME; + +#set LOADER_CLASS_NAME "VertexShaderLoader" + GAME + +#if defined(IS_SUB_ASSET) +#define ABSTRACT_CREATOR_NAME SubAssetCreator +#define OVERRIDDEN_CREATOR_METHOD CreateSubAsset +#define ADD_ASSET_METHOD AddSubAsset +#define ASSET_NAME SubAssetVertexShader +#define INTERFACE_NAME ISubAssetCreator +#else +#define ABSTRACT_CREATOR_NAME AssetCreator +#define OVERRIDDEN_CREATOR_METHOD CreateAsset +#define ADD_ASSET_METHOD AddAsset +#define ASSET_NAME AssetVertexShader +#define INTERFACE_NAME IAssetCreator +#endif + +namespace +{ + class LOADER_CLASS_NAME final : public ABSTRACT_CREATOR_NAME + { + public: + LOADER_CLASS_NAME(MemoryManager& memory, ISearchPath& searchPath) + : m_memory(memory), + m_search_path(searchPath) + { + } + + AssetCreationResult OVERRIDDEN_CREATOR_METHOD(const std::string& assetName, AssetCreationContext& context) override + { + const auto fileName = shader::GetFileNameForVertexShaderAssetName(assetName); + const auto file = m_search_path.Open(fileName); + if (!file.IsOpen()) + return AssetCreationResult::NoAction(); + +#if defined(IS_DX9) + if (file.m_length % sizeof(uint32_t) != 0) + { + con::error("Invalid vertex shader \"{}\": Size must be dividable by {}", assetName, sizeof(uint32_t)); + return AssetCreationResult::Failure(); + } +#endif + + auto* vertexShader = m_memory.Alloc(); + vertexShader->name = m_memory.Dup(assetName.c_str()); + vertexShader->prog.loadDef.programSize = static_cast( +#if defined(IS_DX9) + file.m_length / sizeof(std::remove_pointer_t) +#else + file.m_length +#endif + ); + vertexShader->prog.vs = nullptr; + + auto* fileBuffer = m_memory.Alloc(static_cast(file.m_length)); + file.m_stream->read(fileBuffer, file.m_length); + if (file.m_stream->gcount() != file.m_length) + return AssetCreationResult::Failure(); + +#if defined(IS_DX9) + vertexShader->prog.loadDef.program = reinterpret_cast(fileBuffer); +#else + vertexShader->prog.loadDef.program = fileBuffer; +#endif + + return AssetCreationResult::Success(context.ADD_ASSET_METHOD(assetName, vertexShader)); + } + + private: + MemoryManager& m_memory; + ISearchPath& m_search_path; + }; +} // namespace + +#set CREATE_LOADER_METHOD "CreateVertexShaderLoader" + GAME + +namespace techset +{ + std::unique_ptr CREATE_LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath) + { + return std::make_unique(memory, searchPath); + } +} // namespace techset diff --git a/src/ObjLoading/Techset/VertexShaderLoader.h.template b/src/ObjLoading/Techset/VertexShaderLoader.h.template new file mode 100644 index 00000000..b9e37b0d --- /dev/null +++ b/src/ObjLoading/Techset/VertexShaderLoader.h.template @@ -0,0 +1,40 @@ +#options GAME(IW4, T6) + +#filename "Game/" + GAME + "/Techset/VertexShaderLoader" + GAME + ".h" + +#if GAME == "IW3" +#define FEATURE_IW3 +#elif GAME == "IW4" +#define FEATURE_IW4 +#elif GAME == "IW5" +#define FEATURE_IW5 +#elif GAME == "T5" +#define FEATURE_T5 +#elif GAME == "T6" +#define FEATURE_T6 +#endif + +// This file was templated. +// See VertexShaderLoader.h.template. +// Do not modify, changes will be lost. + +#pragma once + +#include "Asset/IAssetCreator.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +#set CREATE_LOADER_METHOD "CreateVertexShaderLoader" + GAME + +#if defined(FEATURE_T6) +#define INTERFACE_NAME ISubAssetCreator +#else +#define INTERFACE_NAME IAssetCreator +#endif + +namespace techset +{ + std::unique_ptr CREATE_LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath); +} // namespace techset diff --git a/test/ObjCompilingTests.lua b/test/ObjCompilingTests.lua index 1e382f12..fa64961e 100644 --- a/test/ObjCompilingTests.lua +++ b/test/ObjCompilingTests.lua @@ -3,6 +3,7 @@ ObjCompilingTests = {} function ObjCompilingTests:include(includes) if includes:handle(self:name()) then includedirs { + "%{wks.location}/src/ObjLoading", "%{wks.location}/src/ObjCompiling", path.join(TestFolder(), "ObjCompilingTests") } From 503fe89251c575250e46df88deaa2b4dad02f8fe Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 7 Mar 2026 12:10:12 +0000 Subject: [PATCH 11/14] feat: load shader args for dx9 shaders --- .../Techset/CommonShaderArgCreator.cpp | 132 +++++++++++++++++- 1 file changed, 128 insertions(+), 4 deletions(-) diff --git a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp index 4fc8aba3..e2531448 100644 --- a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp +++ b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp @@ -3,6 +3,7 @@ #include "Shader/D3D11ShaderAnalyser.h" #include "Shader/D3D9ShaderAnalyser.h" #include "Utils/Djb2.h" +#include "Utils/Logging/Log.h" #include #include @@ -302,6 +303,8 @@ namespace if (!m_shader_info) return result::Unexpected(std::format("Failed to analyse dx9 shader {}", name)); + m_arg_added = std::vector(m_shader_info->m_constants.size(), false); + return NoResult{}; } @@ -327,7 +330,26 @@ namespace { assert(m_shader_info); - return false; + const auto foundConstant = + std::ranges::find_if(m_shader_info->m_constants, + [input](const d3d9::ShaderConstant& constant) + { + return constant.m_register_set == d3d9::RegisterSet::FLOAT_4 && constant.m_name == input.m_argument_name; + }); + + if (foundConstant == m_shader_info->m_constants.end()) + return false; + + const auto variableElementCount = std::max(foundConstant->m_register_count, 1); + + commonDestination.dx9.m_destination_register = foundConstant->m_register_index; + isTransposed = foundConstant->m_class == d3d9::ParameterClass::MATRIX_COLUMNS; + rowCount = foundConstant->m_register_count; + + const auto argIndex = static_cast(foundConstant - m_shader_info->m_constants.begin()); + m_arg_added[argIndex] = true; + + return true; } [[nodiscard]] bool FindDestinationForSampler(techset::CommonShaderArgDestination& commonDestination, @@ -335,18 +357,120 @@ namespace const techset::CommonShaderArgCreatorDestination& input) override { assert(m_shader_info); - // TODO - return false; + + const auto foundConstant = + std::ranges::find_if(m_shader_info->m_constants, + [input](const d3d9::ShaderConstant& constant) + { + return constant.m_register_set == d3d9::RegisterSet::SAMPLER && constant.m_name == input.m_argument_name; + }); + + if (foundConstant == m_shader_info->m_constants.end()) + return false; + + commonDestination.dx9.m_destination_register = foundConstant->m_register_index; + + const auto argIndex = static_cast(foundConstant - m_shader_info->m_constants.begin()); + m_arg_added[argIndex] = true; + + return true; } result::Expected AutoCreateMissingArgs() override { - // TODO + const auto argCount = m_shader_info->m_constants.size(); + for (size_t argIndex = 0; argIndex < argCount; argIndex++) + { + if (m_arg_added[argIndex]) + continue; + + const auto& shaderArg = m_shader_info->m_constants[argIndex]; + + if (shaderArg.m_register_set == d3d9::RegisterSet::FLOAT_4) + { + auto result = AutoCreateConstantArg(shaderArg); + if (!result) + return std::move(result); + } + else + { + assert(shaderArg.m_register_set == d3d9::RegisterSet::SAMPLER); + + auto result = AutoCreateSamplerArg(shaderArg); + if (!result) + return std::move(result); + } + } + return NoResult{}; } private: + result::Expected AutoCreateConstantArg(const d3d9::ShaderConstant& shaderArg) + { + const auto maybeCodeConst = m_common_code_source_infos.GetCodeConstSourceForAccessor(shaderArg.m_name); + if (!maybeCodeConst) + { + // Some variables are simply not added as args for some reason + if (m_common_code_source_infos.IsArgAccessorIgnored(shaderArg.m_name)) + return NoResult{}; + + return result::Unexpected(std::format("Missing assignment to shader constant {}", shaderArg.m_name)); + } + + const auto constInfo = m_common_code_source_infos.GetInfoForCodeConstSource(*maybeCodeConst); + if (!constInfo) + return result::Unexpected(std::format("Missing info for code const {}", shaderArg.m_name)); + + const auto variableElementCount = std::max(shaderArg.m_type_elements, 1); + const auto infoArrayCount = std::max(constInfo->arrayCount, 1); + if (variableElementCount > infoArrayCount) + { + return result::Unexpected(std::format("Could not auto create argument for constant {} as it has more elements ({}) than the code constant ({})", + shaderArg.m_name, + variableElementCount, + infoArrayCount)); + } + + techset::CommonShaderArgDestination commonDestination; + const auto isTransposed = shaderArg.m_class == d3d9::ParameterClass::MATRIX_COLUMNS; + for (auto elementIndex = 0u; elementIndex < variableElementCount; elementIndex++) + { + commonDestination.dx9.m_destination_register = shaderArg.m_register_index + elementIndex; + auto result = AcceptShaderConstantArgument(commonDestination, isTransposed, shaderArg.m_register_count, *maybeCodeConst, elementIndex); + if (!result) + return std::move(result); + } + + if (constInfo->techFlags) + m_tech_flags |= *constInfo->techFlags; + + return NoResult{}; + } + + result::Expected AutoCreateSamplerArg(const d3d9::ShaderConstant& shaderArg) + { + const auto maybeCodeSampler = m_common_code_source_infos.GetCodeSamplerSourceForAccessor(shaderArg.m_name); + if (!maybeCodeSampler) + return result::Unexpected(std::format("Missing assignment to shader texture {}", shaderArg.m_name)); + + const auto samplerInfo = m_common_code_source_infos.GetInfoForCodeSamplerSource(*maybeCodeSampler); + if (!samplerInfo) + return result::Unexpected(std::format("Missing info for code sampler {}", shaderArg.m_name)); + + techset::CommonShaderArgDestination commonDestination; + commonDestination.dx9.m_destination_register = shaderArg.m_register_index; + + if (samplerInfo->techFlags) + m_tech_flags |= *samplerInfo->techFlags; + if (samplerInfo->customSamplerIndex) + m_sampler_flags |= (1 << *samplerInfo->customSamplerIndex); + + return AcceptShaderSamplerArgument(commonDestination, *maybeCodeSampler); + } + std::unique_ptr m_shader_info; + std::vector m_arg_added; }; class CommonShaderArgCreatorDx11 final : public BaseCommonShaderArgCreator From 161ab4530697a09238236761ce206c77f3370edc Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Mon, 9 Mar 2026 00:01:35 +0100 Subject: [PATCH 12/14] 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; } From 629564073c4ac764c79c44e525b42fd446413f3f Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 14 Mar 2026 10:50:12 +0100 Subject: [PATCH 13/14] fix: auto creating dx9 shader args with too many elements --- .../Techset/CommonShaderArgCreator.cpp | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp index e2531448..43045cd7 100644 --- a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp +++ b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp @@ -2,6 +2,7 @@ #include "Shader/D3D11ShaderAnalyser.h" #include "Shader/D3D9ShaderAnalyser.h" +#include "Utils/Alignment.h" #include "Utils/Djb2.h" #include "Utils/Logging/Log.h" @@ -422,19 +423,20 @@ namespace if (!constInfo) return result::Unexpected(std::format("Missing info for code const {}", shaderArg.m_name)); - const auto variableElementCount = std::max(shaderArg.m_type_elements, 1); + const auto elementSize = ElementSizeForArg(shaderArg); + const auto elementCount = utils::Align(shaderArg.m_register_count, elementSize) / elementSize; const auto infoArrayCount = std::max(constInfo->arrayCount, 1); - if (variableElementCount > infoArrayCount) + if (elementCount > infoArrayCount) { return result::Unexpected(std::format("Could not auto create argument for constant {} as it has more elements ({}) than the code constant ({})", shaderArg.m_name, - variableElementCount, + elementCount, infoArrayCount)); } techset::CommonShaderArgDestination commonDestination; const auto isTransposed = shaderArg.m_class == d3d9::ParameterClass::MATRIX_COLUMNS; - for (auto elementIndex = 0u; elementIndex < variableElementCount; elementIndex++) + for (auto elementIndex = 0u; elementIndex < elementCount; elementIndex++) { commonDestination.dx9.m_destination_register = shaderArg.m_register_index + elementIndex; auto result = AcceptShaderConstantArgument(commonDestination, isTransposed, shaderArg.m_register_count, *maybeCodeConst, elementIndex); @@ -448,6 +450,18 @@ namespace return NoResult{}; } + [[nodiscard]] static unsigned ElementSizeForArg(const d3d9::ShaderConstant& arg) + { + switch (arg.m_class) + { + case d3d9::ParameterClass::MATRIX_COLUMNS: + case d3d9::ParameterClass::MATRIX_ROWS: + return 4; + default: + return 1; + } + } + result::Expected AutoCreateSamplerArg(const d3d9::ShaderConstant& shaderArg) { const auto maybeCodeSampler = m_common_code_source_infos.GetCodeSamplerSourceForAccessor(shaderArg.m_name); From 08a869f8c3d8a098090eeb6e744c2ea486a305aa Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 14 Mar 2026 13:35:42 +0100 Subject: [PATCH 14/14] chore: add cursed calculation for techflag 200 in iw4 --- .../Techset/TechniqueCompiler.cpp.template | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/ObjCompiling/Techset/TechniqueCompiler.cpp.template b/src/ObjCompiling/Techset/TechniqueCompiler.cpp.template index e036374e..9d5e194c 100644 --- a/src/ObjCompiling/Techset/TechniqueCompiler.cpp.template +++ b/src/ObjCompiling/Techset/TechniqueCompiler.cpp.template @@ -212,6 +212,42 @@ namespace pass.customSamplerFlags = static_cast(commonPass.m_sampler_flags); } +#ifdef FEATURE_IW4 + // Not sure if this is actually how this is calculated. + // It produces identical results at least though. + constexpr MaterialConstantSource ALLOWED_PIXEL_CONSTANTS_FOR_FLAG_200[]{ + CONST_SRC_CODE_RENDER_TARGET_SIZE, + CONST_SRC_CODE_VIEWPORT_DIMENSIONS, + }; + + bool ShouldApplyFlag200(const MaterialTechnique& technique) + { + for (auto passIndex = 0u; passIndex < technique.passCount; passIndex++) + { + const auto& pass = technique.passArray[passIndex]; + if (!pass.args) + continue; + + const unsigned argCount = pass.perPrimArgCount + pass.perObjArgCount + pass.stableArgCount; + for (auto argIndex = 0u; argIndex < argCount; argIndex++) + { + const auto& arg = pass.args[argIndex]; + if (arg.type == MTL_ARG_MATERIAL_VERTEX_CONST || arg.type == MTL_ARG_MATERIAL_PIXEL_SAMPLER || arg.type == MTL_ARG_MATERIAL_PIXEL_CONST) + return false; + + if (arg.type == MTL_ARG_CODE_PIXEL_CONST) + { + const auto foundAllowedConstant = std::ranges::find(ALLOWED_PIXEL_CONSTANTS_FOR_FLAG_200, arg.u.codeConst.index); + if (foundAllowedConstant == std::end(ALLOWED_PIXEL_CONSTANTS_FOR_FLAG_200)) + return false; + } + } + } + + return true; + } +#endif + bool AnyDeclHasOptionalSource(const MaterialTechnique& technique, AssetCreationContext& context) { for (auto passIndex = 0u; passIndex < technique.passCount; passIndex++) @@ -254,6 +290,9 @@ namespace if (technique.flags & MTL_TECHFLAG_USES_FLOATZ && lowerTechniqueName.starts_with("distortion_")) technique.flags = (technique.flags & ~MTL_TECHFLAG_USES_FLOATZ) | MTL_TECHFLAG_USES_DISTORTION_FLOATZ; + + if (ShouldApplyFlag200(technique)) + technique.flags |= TECHNIQUE_FLAG_200; #elif defined(FEATURE_T6) // Not a particularly cool way to do this but... // the game actually does this :shrug: