From e61ec8582a096da875242c0372b23538204cf395 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Mon, 19 Jan 2026 22:13:12 +0000 Subject: [PATCH 01/27] chore: use CommonTechset instead of TechsetDefinition --- .../Game/IW4/Techset/TechsetConstantsIW4.h | 46 ++++++++------- .../Game/T6/Techset/TechsetConstantsT6.h | 14 +++-- src/ObjCommon/Techset/CommonTechset.cpp | 55 ++++++++++++----- src/ObjCommon/Techset/CommonTechset.h | 8 +++ .../Game/IW4/Material/CompilerMaterialIW4.cpp | 16 ++--- .../Game/IW4/Techset/CompilerTechsetIW4.cpp | 22 +++---- .../Game/IW4/Techset/CompilerTechsetIW4.h | 4 +- src/ObjCompiling/Game/T6/ObjCompilerT6.cpp | 2 + .../Game/T6/Techset/TechsetCompilerT6.cpp | 23 ++++++++ .../Game/T6/Techset/TechsetCompilerT6.h | 12 ++++ .../Techset/CommonTechniqueLoader.cpp | 1 + .../Techset/CommonTechniqueLoader.h | 12 ++++ .../Techset/CommonTechsetLoader.cpp | 49 +++++++++++++++ .../Techset/CommonTechsetLoader.h | 12 ++++ .../Sequence/TechniqueNoScopeSequences.cpp | 0 .../Sequence/TechniqueNoScopeSequences.h | 0 .../Sequence/TechniquePassScopeSequences.cpp | 0 .../Sequence/TechniquePassScopeSequences.h | 0 .../TechniqueShaderScopeSequences.cpp | 0 .../Sequence/TechniqueShaderScopeSequences.h | 0 .../Techset/Parsing/TechniqueFileParser.cpp | 0 .../Techset/Parsing/TechniqueFileParser.h | 0 .../Parsing/TechniqueFileParserState.cpp | 0 .../Parsing/TechniqueFileParserState.h | 4 +- .../Techset/Parsing/TechsetFileParser.cpp | 59 ++++++++++--------- .../Techset/Parsing/TechsetFileParser.h | 10 ++-- .../Parsing/TechsetFileParserState.cpp | 10 ++++ .../Techset/Parsing/TechsetFileParserState.h | 20 +++++++ ...nitionCache.cpp => CommonTechsetCache.cpp} | 6 +- src/ObjLoading/Techset/CommonTechsetCache.h | 21 +++++++ .../Parsing/TechsetFileParserState.cpp | 25 -------- .../Techset/Parsing/TechsetFileParserState.h | 22 ------- src/ObjLoading/Techset/TechsetDefinition.cpp | 31 ---------- src/ObjLoading/Techset/TechsetDefinition.h | 18 ------ .../Techset/TechsetDefinitionCache.h | 22 ------- src/ObjLoading/Techset/TechsetFileReader.cpp | 40 ------------- src/ObjLoading/Techset/TechsetFileReader.h | 25 -------- .../Game/IW4/Techset/TechsetDumperIW4.cpp | 5 +- .../Game/T5/Techset/TechsetDumperT5.cpp | 5 +- .../Game/T6/Techset/TechsetDumperT6.cpp | 8 +-- 40 files changed, 306 insertions(+), 301 deletions(-) create mode 100644 src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.cpp create mode 100644 src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.h create mode 100644 src/ObjCompiling/Techset/CommonTechniqueLoader.cpp create mode 100644 src/ObjCompiling/Techset/CommonTechniqueLoader.h create mode 100644 src/ObjCompiling/Techset/CommonTechsetLoader.cpp create mode 100644 src/ObjCompiling/Techset/CommonTechsetLoader.h rename src/{ObjLoading => ObjCompiling}/Techset/Parsing/Sequence/TechniqueNoScopeSequences.cpp (100%) rename src/{ObjLoading => ObjCompiling}/Techset/Parsing/Sequence/TechniqueNoScopeSequences.h (100%) rename src/{ObjLoading => ObjCompiling}/Techset/Parsing/Sequence/TechniquePassScopeSequences.cpp (100%) rename src/{ObjLoading => ObjCompiling}/Techset/Parsing/Sequence/TechniquePassScopeSequences.h (100%) rename src/{ObjLoading => ObjCompiling}/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.cpp (100%) rename src/{ObjLoading => ObjCompiling}/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.h (100%) rename src/{ObjLoading => ObjCompiling}/Techset/Parsing/TechniqueFileParser.cpp (100%) rename src/{ObjLoading => ObjCompiling}/Techset/Parsing/TechniqueFileParser.h (100%) rename src/{ObjLoading => ObjCompiling}/Techset/Parsing/TechniqueFileParserState.cpp (100%) rename src/{ObjLoading => ObjCompiling}/Techset/Parsing/TechniqueFileParserState.h (100%) rename src/{ObjLoading => ObjCompiling}/Techset/Parsing/TechsetFileParser.cpp (62%) rename src/{ObjLoading => ObjCompiling}/Techset/Parsing/TechsetFileParser.h (60%) create mode 100644 src/ObjCompiling/Techset/Parsing/TechsetFileParserState.cpp create mode 100644 src/ObjCompiling/Techset/Parsing/TechsetFileParserState.h rename src/ObjLoading/Techset/{TechsetDefinitionCache.cpp => CommonTechsetCache.cpp} (50%) create mode 100644 src/ObjLoading/Techset/CommonTechsetCache.h delete mode 100644 src/ObjLoading/Techset/Parsing/TechsetFileParserState.cpp delete mode 100644 src/ObjLoading/Techset/Parsing/TechsetFileParserState.h delete mode 100644 src/ObjLoading/Techset/TechsetDefinition.cpp delete mode 100644 src/ObjLoading/Techset/TechsetDefinition.h delete mode 100644 src/ObjLoading/Techset/TechsetDefinitionCache.h delete mode 100644 src/ObjLoading/Techset/TechsetFileReader.cpp delete mode 100644 src/ObjLoading/Techset/TechsetFileReader.h diff --git a/src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h b/src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h index 9b0a08d8..0f4f1a32 100644 --- a/src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h +++ b/src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h @@ -3,13 +3,14 @@ #include "Game/IW4/CommonIW4.h" #include "Game/IW4/IW4.h" #include "StateMap/StateMapLayout.h" +#include "Techset/CommonTechset.h" #include #include namespace IW4 { - inline const char* techniqueTypeNames[]{ + static inline const char* techniqueTypeNames[]{ "depth prepass", "build floatz", "build shadowmap depth", @@ -60,8 +61,9 @@ namespace IW4 "debug bumpmap instanced", }; static_assert(std::extent_v == TECHNIQUE_COUNT); + static inline techset::CommonTechniqueTypeNames commonTechniqueTypeNames(techniqueTypeNames, std::extent_v); - static const char* materialStreamDestinationNames[]{ + static inline const char* materialStreamDestinationNames[]{ "position", "normal", "color[0]", @@ -78,7 +80,7 @@ namespace IW4 }; static_assert(std::extent_v == STREAM_DST_COUNT); - static const char* materialStreamDestinationAbbreviation[]{ + static inline const char* materialStreamDestinationAbbreviation[]{ "p", "n", "c0", @@ -95,7 +97,7 @@ namespace IW4 }; static_assert(std::extent_v == STREAM_DST_COUNT); - static const char* materialStreamSourceNames[]{ + static inline const char* materialStreamSourceNames[]{ "position", "color", "texcoord[0]", @@ -108,7 +110,7 @@ namespace IW4 }; static_assert(std::extent_v == STREAM_SRC_COUNT); - static const char* materialStreamSourceAbbreviation[]{ + static inline const char* materialStreamSourceAbbreviation[]{ "p", "c", "t0", @@ -121,18 +123,18 @@ namespace IW4 }; static_assert(std::extent_v == STREAM_SRC_COUNT); - inline CodeSamplerSource s_lightmapSamplers[]{ + static inline CodeSamplerSource s_lightmapSamplers[]{ {"primary", TEXTURE_SRC_CODE_LIGHTMAP_PRIMARY, nullptr, 0, 0}, {"secondary", TEXTURE_SRC_CODE_LIGHTMAP_SECONDARY, nullptr, 0, 0}, {}, }; - inline CodeSamplerSource s_lightSamplers[]{ + static inline CodeSamplerSource s_lightSamplers[]{ {"attenuation", TEXTURE_SRC_CODE_LIGHT_ATTENUATION, nullptr, 0, 0}, {}, }; - inline CodeSamplerSource s_codeSamplers[]{ + 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}, @@ -155,7 +157,7 @@ namespace IW4 {}, }; - inline CodeSamplerSource s_defaultCodeSamplers[]{ + 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}, @@ -177,7 +179,7 @@ namespace IW4 {}, }; - inline CodeConstantSource s_sunConsts[]{ + 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}, @@ -187,14 +189,14 @@ namespace IW4 {}, }; - inline CodeConstantSource s_nearPlaneConsts[]{ + 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}, {}, }; - inline CodeConstantSource s_codeConsts[]{ + 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}, @@ -313,7 +315,7 @@ namespace IW4 {}, }; - inline CodeConstantSource s_defaultCodeConsts[]{ + 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}, @@ -328,7 +330,7 @@ namespace IW4 {}, }; - inline MaterialUpdateFrequency s_codeConstUpdateFreq[]{ + static inline MaterialUpdateFrequency s_codeConstUpdateFreq[]{ MTL_UPDATE_RARELY, // LIGHT_POSITION MTL_UPDATE_RARELY, // LIGHT_DIFFUSE MTL_UPDATE_RARELY, // LIGHT_SPECULAR @@ -464,7 +466,7 @@ namespace IW4 }; static_assert(std::extent_v == CONST_SRC_TOTAL_COUNT); - inline MaterialUpdateFrequency s_codeSamplerUpdateFreq[]{ + static inline MaterialUpdateFrequency s_codeSamplerUpdateFreq[]{ MTL_UPDATE_RARELY, // BLACK MTL_UPDATE_RARELY, // WHITE MTL_UPDATE_RARELY, // IDENTITY_NORMAL_MAP @@ -495,14 +497,14 @@ namespace IW4 }; static_assert(std::extent_v == TEXTURE_SRC_CODE_COUNT); - inline MaterialTextureSource g_customSamplerSrc[]{ + 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); - inline MaterialTypeInfo g_materialTypeInfo[]{ + static inline MaterialTypeInfo g_materialTypeInfo[]{ {"", "" }, {"m/", "m_" }, {"mc/", "mc_"}, @@ -523,7 +525,7 @@ namespace IW4 return std::make_pair(Common::R_HashString(name, 0u), KnownMaterialTextureMap{name, additionalPropertySuffix}); } - inline std::unordered_map knownTextureMaps{ + static inline std::unordered_map knownTextureMaps{ MakeKnownTextureMap("colorMap", "Color"), MakeKnownTextureMap("colorMap0", "Color00"), MakeKnownTextureMap("colorMap1", "Color01"), @@ -538,7 +540,7 @@ namespace IW4 return std::make_pair(Common::R_HashString(name, 0u), name); } - inline std::unordered_map knownConstantNames{ + static inline std::unordered_map knownConstantNames{ MakeKnownConstantName("distortionScale"), MakeKnownConstantName("eyeOffsetParms"), MakeKnownConstantName("falloffBeginColor"), @@ -560,7 +562,7 @@ namespace IW4 WIREFRAME }; - inline state_map::StateMapLayoutEntries stateMapEntryLayout({ + static inline state_map::StateMapLayoutEntries stateMapEntryLayout({ {"alphaTest", 0, GFXS0_ATEST_MASK | GFXS0_ATEST_DISABLE, {"mtlAlphaTest"} }, {"blendFunc", 0, GFXS0_BLEND_RGB_MASK, {"mtlBlendOp", "mtlSrcBlend", "mtlDestBlend"} }, {"separateAlphaBlendFunc", 0, GFXS0_BLEND_ALPHA_MASK, {"mtlBlendOpAlpha", "mtlSrcBlendAlpha", "mtlDestBlendAlpha"}}, @@ -598,7 +600,7 @@ namespace IW4 } } }); - inline state_map::StateMapLayoutVars stateMapVarLayout({ + static inline state_map::StateMapLayoutVars stateMapVarLayout({ {"mtlAlphaTest", 0, { {"Always", GFXS0_ATEST_DISABLE}, @@ -818,5 +820,5 @@ namespace IW4 }}, }); - inline state_map::StateMapLayout stateMapLayout(std::extent_v, stateMapEntryLayout, stateMapVarLayout); + static inline state_map::StateMapLayout stateMapLayout(std::extent_v, stateMapEntryLayout, stateMapVarLayout); } // namespace IW4 diff --git a/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h b/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h index 4e773c3e..73569967 100644 --- a/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h +++ b/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h @@ -2,10 +2,11 @@ #include "Game/T6/T6.h" #include "Techset/CommonTechnique.h" +#include "Techset/CommonTechset.h" namespace T6 { - inline const char* techniqueTypeNames[]{ + static inline const char* techniqueTypeNames[]{ "depth prepass", "build shadowmap depth", "unlit", @@ -44,8 +45,9 @@ namespace T6 "debug performance", }; static_assert(std::extent_v == TECHNIQUE_COUNT); + static inline techset::CommonTechniqueTypeNames commonTechniqueTypeNames(techniqueTypeNames, std::extent_v); - static techset::CommonStreamRoutingSourceInfo streamRoutingSources[]{ + static inline techset::CommonStreamRoutingSourceInfo streamRoutingSources[]{ { .name = "position", .abbreviation = "p", @@ -104,7 +106,7 @@ namespace T6 }; static_assert(std::extent_v == STREAM_SRC_COUNT); - static techset::CommonStreamRoutingDestinationInfo streamRoutingDestinations[]{ + static inline techset::CommonStreamRoutingDestinationInfo streamRoutingDestinations[]{ { .name = "position", .abbreviation = "p", @@ -188,7 +190,7 @@ namespace T6 }; static_assert(std::extent_v == STREAM_DST_COUNT); - static techset::CommonCodeConstSourceInfo commonCodeConstSources[]{ + static inline techset::CommonCodeConstSourceInfo commonCodeConstSources[]{ { .value = CONST_SRC_CODE_LIGHT_POSITION, .accessor = "lightPosition", @@ -1511,7 +1513,7 @@ namespace T6 }, }; - static techset::CommonCodeSamplerSourceInfo commonCodeSamplerSources[]{ + static inline techset::CommonCodeSamplerSourceInfo commonCodeSamplerSources[]{ { .value = TEXTURE_SRC_CODE_BLACK, .accessor = "black", @@ -1789,7 +1791,7 @@ namespace T6 }, }; - inline MaterialTypeInfo g_materialTypeInfo[]{ + static inline MaterialTypeInfo g_materialTypeInfo[]{ {"", "" }, {"m/", "m_" }, {"mc/", "mc_" }, diff --git a/src/ObjCommon/Techset/CommonTechset.cpp b/src/ObjCommon/Techset/CommonTechset.cpp index 96bc0d3b..3d6ae765 100644 --- a/src/ObjCommon/Techset/CommonTechset.cpp +++ b/src/ObjCommon/Techset/CommonTechset.cpp @@ -2,21 +2,48 @@ #include -techset::CommonTechniqueTypeNames::CommonTechniqueTypeNames(const char** names, const size_t nameCount) - : m_names(nameCount) +namespace techset { - std::copy(names, &names[nameCount], m_names.data()); -} + CommonTechniqueTypeNames::CommonTechniqueTypeNames(const char** names, const size_t nameCount) + : m_names(nameCount) + { + std::copy(names, &names[nameCount], m_names.data()); -const char* techset::CommonTechniqueTypeNames::GetTechniqueTypeName(const size_t techniqueTypeIndex) const -{ - if (techniqueTypeIndex >= m_names.size()) - return nullptr; + m_technique_type_lookup.reserve(nameCount); + for (size_t i = 0; i < nameCount; i++) + m_technique_type_lookup.emplace(names[i], i); + } - return m_names[techniqueTypeIndex]; -} + const char* CommonTechniqueTypeNames::GetTechniqueTypeName(const size_t techniqueTypeIndex) const + { + if (techniqueTypeIndex >= m_names.size()) + return nullptr; -size_t techset::CommonTechniqueTypeNames::GetTechniqueTypeCount() const -{ - return m_names.size(); -} + return m_names[techniqueTypeIndex]; + } + + [[nodiscard]] std::optional CommonTechniqueTypeNames::GetTechniqueTypeByName(const std::string& name) const + { + const auto foundValue = m_technique_type_lookup.find(name); + if (foundValue != m_technique_type_lookup.end()) + return foundValue->second; + + return std::nullopt; + } + + size_t CommonTechniqueTypeNames::GetTechniqueTypeCount() const + { + return m_names.size(); + } + + CommonTechset::CommonTechset(const size_t techniqueTypeCount) + : m_technique_names(techniqueTypeCount) + { + } + + CommonTechset::CommonTechset(std::string name, std::vector techniqueNames) + : m_name(std::move(name)), + m_technique_names(std::move(techniqueNames)) + { + } +} // namespace techset diff --git a/src/ObjCommon/Techset/CommonTechset.h b/src/ObjCommon/Techset/CommonTechset.h index 5dd2c02e..e80d873d 100644 --- a/src/ObjCommon/Techset/CommonTechset.h +++ b/src/ObjCommon/Techset/CommonTechset.h @@ -1,7 +1,9 @@ #pragma once #include +#include #include +#include #include namespace techset @@ -12,15 +14,21 @@ namespace techset CommonTechniqueTypeNames(const char** names, size_t nameCount); [[nodiscard]] const char* GetTechniqueTypeName(size_t techniqueTypeIndex) const; + [[nodiscard]] std::optional GetTechniqueTypeByName(const std::string& name) const; [[nodiscard]] size_t GetTechniqueTypeCount() const; private: std::vector m_names; + std::unordered_map m_technique_type_lookup; }; class CommonTechset { public: + CommonTechset() = default; + explicit CommonTechset(size_t techniqueTypeCount); + CommonTechset(std::string name, std::vector techniqueNames); + std::string m_name; std::vector m_technique_names; }; diff --git a/src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.cpp b/src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.cpp index fd4de1c0..76a46ab9 100644 --- a/src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.cpp +++ b/src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.cpp @@ -11,10 +11,10 @@ #include "Pool/GlobalAssetPool.h" #include "StateMap/StateMapFromTechniqueExtractor.h" #include "StateMap/StateMapHandler.h" +#include "Techset/CommonTechsetCache.h" #include "Techset/TechniqueFileReader.h" #include "Techset/TechniqueStateMapCache.h" #include "Techset/TechsetCommon.h" -#include "Techset/TechsetDefinitionCache.h" #include "Utils/Logging/Log.h" #include @@ -795,7 +795,7 @@ namespace m_registration.AddDependency(techset); m_material.techniqueSet = techset->Asset(); - auto& definitionCache = m_context.GetZoneAssetCreationState<::techset::TechsetDefinitionCache>(); + auto& definitionCache = m_context.GetZoneAssetCreationState<::techset::CommonTechsetCache>(); bool failure = false; const auto* techsetDefinition = m_techset_creator->LoadTechsetDefinition(techsetName, m_context, failure); @@ -808,12 +808,12 @@ namespace SetTechniqueSetCameraRegion(techsetDefinition); } - void SetTechniqueSetStateBits(const ::techset::TechsetDefinition* techsetDefinition) + void SetTechniqueSetStateBits(const techset::CommonTechset* commonTechset) { for (auto i = 0; i < TECHNIQUE_COUNT; i++) { - std::string techniqueName; - if (techsetDefinition->GetTechniqueByIndex(i, techniqueName)) + auto techniqueName = commonTechset->m_technique_names[i]; + if (!techniqueName.empty()) { const auto stateBitsForTechnique = GetStateBitsForTechnique(techniqueName); const auto foundStateBits = std::ranges::find_if(m_state_bits, @@ -892,17 +892,17 @@ namespace return outBits; } - void SetTechniqueSetCameraRegion(const ::techset::TechsetDefinition* techsetDefinition) const + void SetTechniqueSetCameraRegion(const techset::CommonTechset* commonTechset) const { std::string tempName; - if (techsetDefinition->GetTechniqueByIndex(TECHNIQUE_LIT, tempName)) + if (!commonTechset->m_technique_names[TECHNIQUE_LIT].empty()) { if (m_material.info.sortKey >= SORTKEY_TRANS_START) m_material.cameraRegion = CAMERA_REGION_LIT_TRANS; else m_material.cameraRegion = CAMERA_REGION_LIT_OPAQUE; } - else if (techsetDefinition->GetTechniqueByIndex(TECHNIQUE_EMISSIVE, tempName)) + else if (!commonTechset->m_technique_names[TECHNIQUE_EMISSIVE].empty()) { m_material.cameraRegion = CAMERA_REGION_EMISSIVE; } diff --git a/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp b/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp index ac775a8f..65e5f671 100644 --- a/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp +++ b/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp @@ -7,11 +7,11 @@ #include "Shader/D3D9ShaderAnalyser.h" #include "Shader/ShaderCommon.h" #include "StateMap/StateMapReader.h" +#include "Techset/CommonTechsetCache.h" +#include "Techset/CommonTechsetLoader.h" #include "Techset/TechniqueFileReader.h" #include "Techset/TechniqueStateMapCache.h" #include "Techset/TechsetCommon.h" -#include "Techset/TechsetDefinitionCache.h" -#include "Techset/TechsetFileReader.h" #include "Utils/Alignment.h" #include "Utils/Logging/Log.h" @@ -1284,7 +1284,7 @@ namespace } private: - AssetCreationResult CreateTechsetFromDefinition(const std::string& assetName, const TechsetDefinition& definition, AssetCreationContext& context) + AssetCreationResult CreateTechsetFromDefinition(const std::string& assetName, const CommonTechset& definition, AssetCreationContext& context) { auto* techset = m_memory.Alloc(); techset->name = m_memory.Dup(assetName.c_str()); @@ -1294,8 +1294,8 @@ namespace const TechniqueLoader techniqueLoader(m_search_path, m_memory, context, this); for (auto i = 0u; i < std::extent_v; i++) { - std::string techniqueName; - if (definition.GetTechniqueByIndex(i, techniqueName)) + const auto& techniqueName = definition.m_technique_names[i]; + if (!techniqueName.empty()) { auto* technique = techniqueLoader.LoadMaterialTechnique(techniqueName); @@ -1312,10 +1312,10 @@ namespace return AssetCreationResult::Success(context.AddAsset(std::move(registration))); } - TechsetDefinition* LoadTechsetDefinition(const std::string& assetName, AssetCreationContext& context, bool& failure) override + CommonTechset* LoadTechsetDefinition(const std::string& assetName, AssetCreationContext& context, bool& failure) override { failure = false; - auto& definitionCache = context.GetZoneAssetCreationState(); + auto& definitionCache = context.GetZoneAssetCreationState(); auto* cachedTechsetDefinition = definitionCache.GetCachedTechsetDefinition(assetName); if (cachedTechsetDefinition) return cachedTechsetDefinition; @@ -1325,17 +1325,13 @@ namespace if (!file.IsOpen()) return nullptr; - const TechsetFileReader reader(*file.m_stream, techsetFileName, techniqueTypeNames, std::extent_v); - auto techsetDefinition = reader.ReadTechsetDefinition(); + auto techsetDefinition = LoadCommonTechset(assetName, commonTechniqueTypeNames, m_search_path, failure); if (!techsetDefinition) - { - failure = true; return nullptr; - } auto* techsetDefinitionPtr = techsetDefinition.get(); - definitionCache.AddTechsetDefinitionToCache(assetName, std::move(techsetDefinition)); + definitionCache.AddCommonTechsetToCache(assetName, std::move(techsetDefinition)); return techsetDefinitionPtr; } diff --git a/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.h b/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.h index 09fd1375..b1dd340c 100644 --- a/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.h +++ b/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.h @@ -4,7 +4,7 @@ #include "Game/IW4/IW4.h" #include "SearchPath/ISearchPath.h" #include "StateMap/StateMapDefinition.h" -#include "Techset/TechsetDefinition.h" +#include "Techset/CommonTechset.h" #include "Utils/MemoryManager.h" #include @@ -18,7 +18,7 @@ namespace techset ICreatorIW4() = default; virtual ~ICreatorIW4() = default; - virtual TechsetDefinition* LoadTechsetDefinition(const std::string& assetName, AssetCreationContext& context, bool& failure) = 0; + virtual CommonTechset* LoadTechsetDefinition(const std::string& assetName, AssetCreationContext& context, bool& failure) = 0; virtual const state_map::StateMapDefinition* LoadStateMapDefinition(const std::string& stateMapName, AssetCreationContext& context) = 0; }; diff --git a/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp b/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp index 8228234d..d9681a32 100644 --- a/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp +++ b/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp @@ -4,6 +4,7 @@ #include "Image/ImageIPakPostProcessor.h" #include "Image/ImageIwdPostProcessor.h" #include "KeyValuePairs/KeyValuePairsCompilerT6.h" +#include "Techset/TechsetCompilerT6.h" #include @@ -20,6 +21,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)); } void ConfigurePostProcessors(AssetCreatorCollection& collection, diff --git a/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.cpp b/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.cpp new file mode 100644 index 00000000..68882385 --- /dev/null +++ b/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.cpp @@ -0,0 +1,23 @@ +#include "TechsetCompilerT6.h" + +#include "Game/T6/T6.h" + +namespace +{ + class TechsetCompilerT6 final : public AssetCreator + { + public: + AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override + { + return AssetCreationResult::NoAction(); + } + }; +} // namespace + +namespace techset +{ + std::unique_ptr CreateCompilerT6(MemoryManager& memory, ISearchPath& searchPath) + { + return std::make_unique(); + } +} // namespace techset diff --git a/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.h b/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.h new file mode 100644 index 00000000..2af583f1 --- /dev/null +++ b/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.h @@ -0,0 +1,12 @@ +#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/Techset/CommonTechniqueLoader.cpp b/src/ObjCompiling/Techset/CommonTechniqueLoader.cpp new file mode 100644 index 00000000..4def5bcc --- /dev/null +++ b/src/ObjCompiling/Techset/CommonTechniqueLoader.cpp @@ -0,0 +1 @@ +#include "CommonTechniqueLoader.h" diff --git a/src/ObjCompiling/Techset/CommonTechniqueLoader.h b/src/ObjCompiling/Techset/CommonTechniqueLoader.h new file mode 100644 index 00000000..70722720 --- /dev/null +++ b/src/ObjCompiling/Techset/CommonTechniqueLoader.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Asset/AssetCreationContext.h" +#include "Techset/CommonTechnique.h" + +#include + +namespace techset +{ + std::unique_ptr + LoadCommonTechnique(const AssetCreationContext& context, const CommonCodeSourceInfos& codeSourceInfos, const CommonStreamRoutingInfos& routingInfos); +} // namespace techset diff --git a/src/ObjCompiling/Techset/CommonTechsetLoader.cpp b/src/ObjCompiling/Techset/CommonTechsetLoader.cpp new file mode 100644 index 00000000..34d54e11 --- /dev/null +++ b/src/ObjCompiling/Techset/CommonTechsetLoader.cpp @@ -0,0 +1,49 @@ +#include "CommonTechsetLoader.h" + +#include "Parsing/IParserLineStream.h" +#include "Parsing/Impl/CommentRemovingStreamProxy.h" +#include "Parsing/Impl/ParserSingleInputStream.h" +#include "Parsing/Simple/SimpleLexer.h" +#include "Techset/Parsing/TechsetFileParser.h" +#include "Techset/TechsetCommon.h" +#include "Utils/Logging/Log.h" + +#include +#include +#include +#include + +namespace techset +{ + std::unique_ptr + LoadCommonTechset(const std::string& assetName, const CommonTechniqueTypeNames& techniqueTypeNames, ISearchPath& searchPath, bool& failure) + { + failure = false; + + const auto fileName = GetFileNameForTechniqueName(assetName); + const auto techniqueFile = searchPath.Open(fileName); + if (!techniqueFile.IsOpen()) + return nullptr; + + SimpleLexer::Config lexerConfig; + lexerConfig.m_emit_new_line_tokens = false; + lexerConfig.m_read_strings = true; + lexerConfig.m_string_escape_sequences = false; + lexerConfig.m_read_integer_numbers = false; + lexerConfig.m_read_floating_point_numbers = false; + + ParserSingleInputStream baseStream(*techniqueFile.m_stream, fileName); + CommentRemovingStreamProxy commentProxy(&baseStream); + const auto lexer = std::make_unique(&commentProxy, std::move(lexerConfig)); + + const auto parser = std::make_unique(*lexer, techniqueTypeNames); + + const auto success = parser->Parse(); + if (success) + return parser->GetParsingResult(); + + con::error("Parsing techset file \"{}\" failed!", fileName); + failure = true; + return nullptr; + } +} // namespace techset diff --git a/src/ObjCompiling/Techset/CommonTechsetLoader.h b/src/ObjCompiling/Techset/CommonTechsetLoader.h new file mode 100644 index 00000000..dd8adbb7 --- /dev/null +++ b/src/ObjCompiling/Techset/CommonTechsetLoader.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Asset/AssetCreationContext.h" +#include "Techset/CommonTechset.h" + +#include + +namespace techset +{ + std::unique_ptr + LoadCommonTechset(const std::string& assetName, const CommonTechniqueTypeNames& techniqueTypeNames, ISearchPath& searchPath, bool& failure); +} // namespace techset diff --git a/src/ObjLoading/Techset/Parsing/Sequence/TechniqueNoScopeSequences.cpp b/src/ObjCompiling/Techset/Parsing/Sequence/TechniqueNoScopeSequences.cpp similarity index 100% rename from src/ObjLoading/Techset/Parsing/Sequence/TechniqueNoScopeSequences.cpp rename to src/ObjCompiling/Techset/Parsing/Sequence/TechniqueNoScopeSequences.cpp diff --git a/src/ObjLoading/Techset/Parsing/Sequence/TechniqueNoScopeSequences.h b/src/ObjCompiling/Techset/Parsing/Sequence/TechniqueNoScopeSequences.h similarity index 100% rename from src/ObjLoading/Techset/Parsing/Sequence/TechniqueNoScopeSequences.h rename to src/ObjCompiling/Techset/Parsing/Sequence/TechniqueNoScopeSequences.h diff --git a/src/ObjLoading/Techset/Parsing/Sequence/TechniquePassScopeSequences.cpp b/src/ObjCompiling/Techset/Parsing/Sequence/TechniquePassScopeSequences.cpp similarity index 100% rename from src/ObjLoading/Techset/Parsing/Sequence/TechniquePassScopeSequences.cpp rename to src/ObjCompiling/Techset/Parsing/Sequence/TechniquePassScopeSequences.cpp diff --git a/src/ObjLoading/Techset/Parsing/Sequence/TechniquePassScopeSequences.h b/src/ObjCompiling/Techset/Parsing/Sequence/TechniquePassScopeSequences.h similarity index 100% rename from src/ObjLoading/Techset/Parsing/Sequence/TechniquePassScopeSequences.h rename to src/ObjCompiling/Techset/Parsing/Sequence/TechniquePassScopeSequences.h diff --git a/src/ObjLoading/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.cpp b/src/ObjCompiling/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.cpp similarity index 100% rename from src/ObjLoading/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.cpp rename to src/ObjCompiling/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.cpp diff --git a/src/ObjLoading/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.h b/src/ObjCompiling/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.h similarity index 100% rename from src/ObjLoading/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.h rename to src/ObjCompiling/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.h diff --git a/src/ObjLoading/Techset/Parsing/TechniqueFileParser.cpp b/src/ObjCompiling/Techset/Parsing/TechniqueFileParser.cpp similarity index 100% rename from src/ObjLoading/Techset/Parsing/TechniqueFileParser.cpp rename to src/ObjCompiling/Techset/Parsing/TechniqueFileParser.cpp diff --git a/src/ObjLoading/Techset/Parsing/TechniqueFileParser.h b/src/ObjCompiling/Techset/Parsing/TechniqueFileParser.h similarity index 100% rename from src/ObjLoading/Techset/Parsing/TechniqueFileParser.h rename to src/ObjCompiling/Techset/Parsing/TechniqueFileParser.h diff --git a/src/ObjLoading/Techset/Parsing/TechniqueFileParserState.cpp b/src/ObjCompiling/Techset/Parsing/TechniqueFileParserState.cpp similarity index 100% rename from src/ObjLoading/Techset/Parsing/TechniqueFileParserState.cpp rename to src/ObjCompiling/Techset/Parsing/TechniqueFileParserState.cpp diff --git a/src/ObjLoading/Techset/Parsing/TechniqueFileParserState.h b/src/ObjCompiling/Techset/Parsing/TechniqueFileParserState.h similarity index 100% rename from src/ObjLoading/Techset/Parsing/TechniqueFileParserState.h rename to src/ObjCompiling/Techset/Parsing/TechniqueFileParserState.h index 08a87c48..b97b143c 100644 --- a/src/ObjLoading/Techset/Parsing/TechniqueFileParserState.h +++ b/src/ObjCompiling/Techset/Parsing/TechniqueFileParserState.h @@ -7,12 +7,12 @@ namespace techset class TechniqueParserState { public: + explicit TechniqueParserState(ITechniqueDefinitionAcceptor* acceptor); + ITechniqueDefinitionAcceptor* const m_acceptor; bool m_in_pass; bool m_in_shader; ShaderSelector m_current_shader; - - explicit TechniqueParserState(ITechniqueDefinitionAcceptor* acceptor); }; } // namespace techset diff --git a/src/ObjLoading/Techset/Parsing/TechsetFileParser.cpp b/src/ObjCompiling/Techset/Parsing/TechsetFileParser.cpp similarity index 62% rename from src/ObjLoading/Techset/Parsing/TechsetFileParser.cpp rename to src/ObjCompiling/Techset/Parsing/TechsetFileParser.cpp index 6b6f1b86..5bd6bfc3 100644 --- a/src/ObjLoading/Techset/Parsing/TechsetFileParser.cpp +++ b/src/ObjCompiling/Techset/Parsing/TechsetFileParser.cpp @@ -4,7 +4,7 @@ using namespace techset; -namespace techset +namespace { class SequenceTechniqueTypeName final : public TechsetParser::sequence_t { @@ -26,11 +26,11 @@ namespace techset { const auto& typeNameToken = result.NextCapture(CAPTURE_TYPE_NAME); - size_t techniqueTypeIndex; - if (!state->FindTechniqueTypeIndex(typeNameToken.StringValue(), techniqueTypeIndex)) + const auto maybeTechniqueTypeIndex = state->m_technique_type_names.GetTechniqueTypeByName(typeNameToken.StringValue()); + if (!maybeTechniqueTypeIndex.has_value()) throw ParsingException(typeNameToken.GetPos(), "Unknown technique type name"); - state->m_current_technique_types.push_back(techniqueTypeIndex); + state->m_current_technique_types.push_back(maybeTechniqueTypeIndex.value()); } }; @@ -64,31 +64,34 @@ namespace techset techniqueNameToken.m_type == SimpleParserValueType::STRING ? techniqueNameToken.StringValue() : techniqueNameToken.IdentifierValue(); for (const auto techniqueTypeIndex : state->m_current_technique_types) - state->m_definition->SetTechniqueByIndex(techniqueTypeIndex, techniqueName); + state->m_definition->m_technique_names[techniqueTypeIndex] = techniqueName; state->m_current_technique_types.clear(); } }; +} // namespace + +namespace techset +{ + TechsetParser::TechsetParser(SimpleLexer& lexer, const CommonTechniqueTypeNames& techniqueTypeNames) + : AbstractParser(&lexer, std::make_unique(techniqueTypeNames)) + { + } + + const std::vector& TechsetParser::GetTestsForState() + { + static std::vector allTests({ + new SequenceTechniqueTypeName(), + new SequenceTechniqueName(), + }); + static std::vector techniqueTypeNameOnlyTests({ + new SequenceTechniqueTypeName(), + }); + + return m_state->m_current_technique_types.empty() ? techniqueTypeNameOnlyTests : allTests; + } + + std::unique_ptr TechsetParser::GetParsingResult() const + { + return std::move(m_state->m_definition); + } } // namespace techset - -TechsetParser::TechsetParser(SimpleLexer* lexer, const char** validTechniqueTypeNames, const size_t validTechniqueTypeNameCount) - : AbstractParser(lexer, std::make_unique(validTechniqueTypeNames, validTechniqueTypeNameCount)) -{ -} - -const std::vector& TechsetParser::GetTestsForState() -{ - static std::vector allTests({ - new SequenceTechniqueTypeName(), - new SequenceTechniqueName(), - }); - static std::vector techniqueTypeNameOnlyTests({ - new SequenceTechniqueTypeName(), - }); - - return m_state->m_current_technique_types.empty() ? techniqueTypeNameOnlyTests : allTests; -} - -std::unique_ptr TechsetParser::GetTechsetDefinition() const -{ - return std::move(m_state->m_definition); -} diff --git a/src/ObjLoading/Techset/Parsing/TechsetFileParser.h b/src/ObjCompiling/Techset/Parsing/TechsetFileParser.h similarity index 60% rename from src/ObjLoading/Techset/Parsing/TechsetFileParser.h rename to src/ObjCompiling/Techset/Parsing/TechsetFileParser.h index 20620693..d10b718e 100644 --- a/src/ObjLoading/Techset/Parsing/TechsetFileParser.h +++ b/src/ObjCompiling/Techset/Parsing/TechsetFileParser.h @@ -3,19 +3,17 @@ #include "Parsing/Impl/AbstractParser.h" #include "Parsing/Simple/SimpleLexer.h" #include "Parsing/Simple/SimpleParserValue.h" -#include "Techset/TechsetDefinition.h" #include "TechsetFileParserState.h" -#include "Utils/ClassUtils.h" namespace techset { class TechsetParser final : public AbstractParser { + public: + TechsetParser(SimpleLexer& lexer, const CommonTechniqueTypeNames& techniqueTypeNames); + [[nodiscard]] std::unique_ptr GetParsingResult() const; + protected: const std::vector& GetTestsForState() override; - - public: - TechsetParser(SimpleLexer* lexer, const char** validTechniqueTypeNames, size_t validTechniqueTypeNameCount); - _NODISCARD std::unique_ptr GetTechsetDefinition() const; }; } // namespace techset diff --git a/src/ObjCompiling/Techset/Parsing/TechsetFileParserState.cpp b/src/ObjCompiling/Techset/Parsing/TechsetFileParserState.cpp new file mode 100644 index 00000000..5fb2a9fe --- /dev/null +++ b/src/ObjCompiling/Techset/Parsing/TechsetFileParserState.cpp @@ -0,0 +1,10 @@ +#include "TechsetFileParserState.h" + +namespace techset +{ + TechsetParserState::TechsetParserState(const CommonTechniqueTypeNames& techniqueTypeNames) + : m_technique_type_names(techniqueTypeNames), + m_definition(std::make_unique(techniqueTypeNames.GetTechniqueTypeCount())) + { + } +} // namespace techset diff --git a/src/ObjCompiling/Techset/Parsing/TechsetFileParserState.h b/src/ObjCompiling/Techset/Parsing/TechsetFileParserState.h new file mode 100644 index 00000000..fb0154c5 --- /dev/null +++ b/src/ObjCompiling/Techset/Parsing/TechsetFileParserState.h @@ -0,0 +1,20 @@ +#pragma once + +#include "Techset/CommonTechset.h" + +#include +#include +#include + +namespace techset +{ + class TechsetParserState + { + public: + explicit TechsetParserState(const CommonTechniqueTypeNames& techniqueTypeNames); + + const CommonTechniqueTypeNames& m_technique_type_names; + std::unique_ptr m_definition; + std::vector m_current_technique_types; + }; +} // namespace techset diff --git a/src/ObjLoading/Techset/TechsetDefinitionCache.cpp b/src/ObjLoading/Techset/CommonTechsetCache.cpp similarity index 50% rename from src/ObjLoading/Techset/TechsetDefinitionCache.cpp rename to src/ObjLoading/Techset/CommonTechsetCache.cpp index b4041b35..aa089e7b 100644 --- a/src/ObjLoading/Techset/TechsetDefinitionCache.cpp +++ b/src/ObjLoading/Techset/CommonTechsetCache.cpp @@ -1,8 +1,8 @@ -#include "TechsetDefinitionCache.h" +#include "CommonTechsetCache.h" using namespace techset; -TechsetDefinition* TechsetDefinitionCache::GetCachedTechsetDefinition(const std::string& techsetName) const +CommonTechset* CommonTechsetCache::GetCachedTechsetDefinition(const std::string& techsetName) const { const auto foundTechset = m_cache.find(techsetName); @@ -12,7 +12,7 @@ TechsetDefinition* TechsetDefinitionCache::GetCachedTechsetDefinition(const std: return nullptr; } -void TechsetDefinitionCache::AddTechsetDefinitionToCache(std::string name, std::unique_ptr definition) +void CommonTechsetCache::AddCommonTechsetToCache(std::string name, std::unique_ptr definition) { m_cache.emplace(std::make_pair(std::move(name), std::move(definition))); } diff --git a/src/ObjLoading/Techset/CommonTechsetCache.h b/src/ObjLoading/Techset/CommonTechsetCache.h new file mode 100644 index 00000000..dea2a1d2 --- /dev/null +++ b/src/ObjLoading/Techset/CommonTechsetCache.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Asset/IZoneAssetCreationState.h" +#include "Techset/CommonTechset.h" + +#include +#include +#include + +namespace techset +{ + class CommonTechsetCache final : public IZoneAssetCreationState + { + public: + [[nodiscard]] CommonTechset* GetCachedTechsetDefinition(const std::string& techsetName) const; + void AddCommonTechsetToCache(std::string name, std::unique_ptr definition); + + private: + std::unordered_map> m_cache; + }; +} // namespace techset diff --git a/src/ObjLoading/Techset/Parsing/TechsetFileParserState.cpp b/src/ObjLoading/Techset/Parsing/TechsetFileParserState.cpp deleted file mode 100644 index 78c89c75..00000000 --- a/src/ObjLoading/Techset/Parsing/TechsetFileParserState.cpp +++ /dev/null @@ -1,25 +0,0 @@ -#include "TechsetFileParserState.h" - -using namespace techset; - -TechsetParserState::TechsetParserState(const char** validTechniqueTypeNames, size_t validTechniqueTypeNameCount) - : m_definition(std::make_unique(validTechniqueTypeNameCount)) -{ - for (auto i = 0u; i < validTechniqueTypeNameCount; i++) - { - m_valid_technique_type_names.emplace(std::make_pair(std::string(validTechniqueTypeNames[i]), i)); - } -} - -bool TechsetParserState::FindTechniqueTypeIndex(const std::string& techniqueTypeName, size_t& techniqueTypeIndex) const -{ - const auto foundTechniqueType = m_valid_technique_type_names.find(techniqueTypeName); - - if (foundTechniqueType != m_valid_technique_type_names.end()) - { - techniqueTypeIndex = foundTechniqueType->second; - return true; - } - - return false; -} diff --git a/src/ObjLoading/Techset/Parsing/TechsetFileParserState.h b/src/ObjLoading/Techset/Parsing/TechsetFileParserState.h deleted file mode 100644 index 8271198f..00000000 --- a/src/ObjLoading/Techset/Parsing/TechsetFileParserState.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "Techset/TechsetDefinition.h" - -#include -#include -#include - -namespace techset -{ - class TechsetParserState - { - public: - std::map m_valid_technique_type_names; - std::unique_ptr m_definition; - std::vector m_current_technique_types; - - TechsetParserState(const char** validTechniqueTypeNames, size_t validTechniqueTypeNameCount); - - bool FindTechniqueTypeIndex(const std::string& techniqueTypeName, size_t& techniqueTypeIndex) const; - }; -} // namespace techset diff --git a/src/ObjLoading/Techset/TechsetDefinition.cpp b/src/ObjLoading/Techset/TechsetDefinition.cpp deleted file mode 100644 index dc5cf268..00000000 --- a/src/ObjLoading/Techset/TechsetDefinition.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "TechsetDefinition.h" - -#include - -using namespace techset; - -TechsetDefinition::TechsetDefinition(const size_t techniqueTypeCount) - : m_has_technique(techniqueTypeCount), - m_technique_names(techniqueTypeCount) -{ -} - -bool TechsetDefinition::GetTechniqueByIndex(const size_t index, std::string& techniqueName) const -{ - assert(index < m_has_technique.size()); - if (index >= m_has_technique.size() || !m_has_technique[index]) - return false; - - techniqueName = m_technique_names[index]; - return true; -} - -void TechsetDefinition::SetTechniqueByIndex(const size_t index, std::string techniqueName) -{ - assert(index < m_has_technique.size()); - if (index >= m_has_technique.size()) - return; - - m_has_technique[index] = true; - m_technique_names[index] = std::move(techniqueName); -} diff --git a/src/ObjLoading/Techset/TechsetDefinition.h b/src/ObjLoading/Techset/TechsetDefinition.h deleted file mode 100644 index f8f2bf95..00000000 --- a/src/ObjLoading/Techset/TechsetDefinition.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include -#include - -namespace techset -{ - class TechsetDefinition - { - std::vector m_has_technique; - std::vector m_technique_names; - - public: - explicit TechsetDefinition(size_t techniqueTypeCount); - bool GetTechniqueByIndex(size_t index, std::string& techniqueName) const; - void SetTechniqueByIndex(size_t index, std::string techniqueName); - }; -} // namespace techset diff --git a/src/ObjLoading/Techset/TechsetDefinitionCache.h b/src/ObjLoading/Techset/TechsetDefinitionCache.h deleted file mode 100644 index b231f56c..00000000 --- a/src/ObjLoading/Techset/TechsetDefinitionCache.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -#include "Asset/IZoneAssetCreationState.h" -#include "TechsetDefinition.h" -#include "Utils/ClassUtils.h" - -#include -#include -#include - -namespace techset -{ - class TechsetDefinitionCache final : public IZoneAssetCreationState - { - public: - _NODISCARD TechsetDefinition* GetCachedTechsetDefinition(const std::string& techsetName) const; - void AddTechsetDefinitionToCache(std::string name, std::unique_ptr definition); - - private: - std::unordered_map> m_cache; - }; -} // namespace techset diff --git a/src/ObjLoading/Techset/TechsetFileReader.cpp b/src/ObjLoading/Techset/TechsetFileReader.cpp deleted file mode 100644 index 8b7c61e5..00000000 --- a/src/ObjLoading/Techset/TechsetFileReader.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "TechsetFileReader.h" - -#include "Parsing/Impl/CommentRemovingStreamProxy.h" -#include "Parsing/Impl/ParserSingleInputStream.h" -#include "Parsing/TechsetFileParser.h" -#include "Utils/Logging/Log.h" - -#include -#include - -using namespace techset; - -TechsetFileReader::TechsetFileReader(std::istream& stream, std::string fileName, const char** validTechniqueTypeNames, const size_t validTechniqueTypeNameCount) - : m_file_name(std::move(fileName)), - m_valid_technique_type_names(validTechniqueTypeNames), - m_valid_technique_type_name_count(validTechniqueTypeNameCount) -{ - m_base_stream = std::make_unique(stream, m_file_name); - m_comment_proxy = std::make_unique(m_base_stream.get()); -} - -std::unique_ptr TechsetFileReader::ReadTechsetDefinition() const -{ - SimpleLexer::Config lexerConfig; - lexerConfig.m_emit_new_line_tokens = false; - lexerConfig.m_read_strings = true; - lexerConfig.m_string_escape_sequences = false; - lexerConfig.m_read_integer_numbers = false; - lexerConfig.m_read_floating_point_numbers = false; - const auto lexer = std::make_unique(m_comment_proxy.get(), std::move(lexerConfig)); - - const auto parser = std::make_unique(lexer.get(), m_valid_technique_type_names, m_valid_technique_type_name_count); - - const auto success = parser->Parse(); - if (success) - return parser->GetTechsetDefinition(); - - con::error("Parsing techset file \"{}\" failed!", m_file_name); - return nullptr; -} diff --git a/src/ObjLoading/Techset/TechsetFileReader.h b/src/ObjLoading/Techset/TechsetFileReader.h deleted file mode 100644 index 6ba9ac6e..00000000 --- a/src/ObjLoading/Techset/TechsetFileReader.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include "Parsing/IParserLineStream.h" -#include "TechsetDefinition.h" -#include "Utils/ClassUtils.h" - -#include -#include - -namespace techset -{ - class TechsetFileReader - { - std::string m_file_name; - const char** m_valid_technique_type_names; - size_t m_valid_technique_type_name_count; - std::unique_ptr m_base_stream; - std::unique_ptr m_comment_proxy; - - public: - TechsetFileReader(std::istream& stream, std::string fileName, const char** validTechniqueTypeNames, size_t validTechniqueTypeNameCount); - - _NODISCARD std::unique_ptr ReadTechsetDefinition() const; - }; -} // namespace techset diff --git a/src/ObjWriting/Game/IW4/Techset/TechsetDumperIW4.cpp b/src/ObjWriting/Game/IW4/Techset/TechsetDumperIW4.cpp index eb4554af..1a3d8119 100644 --- a/src/ObjWriting/Game/IW4/Techset/TechsetDumperIW4.cpp +++ b/src/ObjWriting/Game/IW4/Techset/TechsetDumperIW4.cpp @@ -474,10 +474,7 @@ namespace techniqueNames[techniqueIndex] = technique->name; } - return techset::CommonTechset{ - .m_name = techset.name, - .m_technique_names = std::move(techniqueNames), - }; + return techset::CommonTechset(techset.name, std::move(techniqueNames)); } void DumpTechset(const AssetDumpingContext& context, const MaterialTechniqueSet& techset) diff --git a/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp b/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp index 9504fcc2..a68a8206 100644 --- a/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp +++ b/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp @@ -301,10 +301,7 @@ namespace techniqueNames[techniqueIndex] = technique->name; } - return techset::CommonTechset{ - .m_name = techset.name, - .m_technique_names = std::move(techniqueNames), - }; + return techset::CommonTechset(techset.name, std::move(techniqueNames)); } void DumpTechset(const AssetDumpingContext& context, const MaterialTechniqueSet& techset) diff --git a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp index 6b346fcb..699dd34d 100644 --- a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp +++ b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp @@ -312,18 +312,14 @@ namespace techniqueNames[techniqueIndex] = technique->name; } - return techset::CommonTechset{ - .m_name = techset.name, - .m_technique_names = std::move(techniqueNames), - }; + 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); + techset::DumpCommonTechset(commonTechniqueTypeNames, context, commonTechset); } } // namespace From bf9beb1458e9312842343977f63356f18acd0dcb Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Thu, 22 Jan 2026 21:43:06 +0000 Subject: [PATCH 02/27] chore: make sure TechsetCompilerT6 sets proper worldVertFormat --- src/Common/Game/IW3/IW3_Assets.h | 18 ++++- src/Common/Game/IW4/IW4_Assets.h | 18 ++++- src/Common/Game/IW5/IW5_Assets.h | 18 ++++- src/Common/Game/T5/T5_Assets.h | 15 +++- src/Common/Game/T6/T6_Assets.h | 15 +++- src/ObjCommon/Techset/CommonTechset.cpp | 6 ++ src/ObjCommon/Techset/CommonTechset.h | 1 + src/ObjCommon/Techset/TechsetCommon.cpp | 24 +++++++ src/ObjCommon/Techset/TechsetCommon.h | 2 + .../Game/T6/Techset/TechsetCompilerT6.cpp | 71 ++++++++++++++++++- .../Techset/CommonTechsetLoader.cpp | 4 +- .../Techset/Parsing/TechsetFileParser.cpp | 4 +- .../Techset/Parsing/TechsetFileParser.h | 4 +- .../Parsing/TechsetFileParserState.cpp | 4 +- .../Techset/Parsing/TechsetFileParserState.h | 3 +- .../Game/T6/Techset/TechsetCompilerT6Test.cpp | 65 +++++++++++++++++ 16 files changed, 255 insertions(+), 17 deletions(-) create mode 100644 test/ObjCompilingTests/Game/T6/Techset/TechsetCompilerT6Test.cpp diff --git a/src/Common/Game/IW3/IW3_Assets.h b/src/Common/Game/IW3/IW3_Assets.h index 8f3c0e01..312e06d0 100644 --- a/src/Common/Game/IW3/IW3_Assets.h +++ b/src/Common/Game/IW3/IW3_Assets.h @@ -1425,10 +1425,26 @@ namespace IW3 TECHNIQUE_NONE = 0x24, }; + enum MaterialWorldVertexFormat : unsigned char + { + MTL_WORLDVERT_TEX_1_NRM_1 = 0x0, + MTL_WORLDVERT_TEX_2_NRM_1 = 0x1, + MTL_WORLDVERT_TEX_2_NRM_2 = 0x2, + MTL_WORLDVERT_TEX_3_NRM_1 = 0x3, + MTL_WORLDVERT_TEX_3_NRM_2 = 0x4, + MTL_WORLDVERT_TEX_3_NRM_3 = 0x5, + MTL_WORLDVERT_TEX_4_NRM_1 = 0x6, + MTL_WORLDVERT_TEX_4_NRM_2 = 0x7, + MTL_WORLDVERT_TEX_4_NRM_3 = 0x8, + MTL_WORLDVERT_TEX_5_NRM_1 = 0x9, + MTL_WORLDVERT_TEX_5_NRM_2 = 0xA, + MTL_WORLDVERT_TEX_5_NRM_3 = 0xB, + }; + struct MaterialTechniqueSet { const char* name; - char worldVertFormat; + MaterialWorldVertexFormat worldVertFormat; bool hasBeenUploaded; char unused[1]; MaterialTechniqueSet* remappedTechniqueSet; diff --git a/src/Common/Game/IW4/IW4_Assets.h b/src/Common/Game/IW4/IW4_Assets.h index 2407a5b0..7da63e1e 100644 --- a/src/Common/Game/IW4/IW4_Assets.h +++ b/src/Common/Game/IW4/IW4_Assets.h @@ -1668,10 +1668,26 @@ namespace IW4 TECHNIQUE_COUNT }; + enum MaterialWorldVertexFormat : unsigned char + { + MTL_WORLDVERT_TEX_1_NRM_1 = 0x0, + MTL_WORLDVERT_TEX_2_NRM_1 = 0x1, + MTL_WORLDVERT_TEX_2_NRM_2 = 0x2, + MTL_WORLDVERT_TEX_3_NRM_1 = 0x3, + MTL_WORLDVERT_TEX_3_NRM_2 = 0x4, + MTL_WORLDVERT_TEX_3_NRM_3 = 0x5, + MTL_WORLDVERT_TEX_4_NRM_1 = 0x6, + MTL_WORLDVERT_TEX_4_NRM_2 = 0x7, + MTL_WORLDVERT_TEX_4_NRM_3 = 0x8, + MTL_WORLDVERT_TEX_5_NRM_1 = 0x9, + MTL_WORLDVERT_TEX_5_NRM_2 = 0xA, + MTL_WORLDVERT_TEX_5_NRM_3 = 0xB, + }; + struct MaterialTechniqueSet { const char* name; - unsigned char worldVertFormat; + MaterialWorldVertexFormat worldVertFormat; bool hasBeenUploaded; unsigned char unused[1]; MaterialTechniqueSet* remappedTechniqueSet; diff --git a/src/Common/Game/IW5/IW5_Assets.h b/src/Common/Game/IW5/IW5_Assets.h index 01f7aab2..ac1d4571 100644 --- a/src/Common/Game/IW5/IW5_Assets.h +++ b/src/Common/Game/IW5/IW5_Assets.h @@ -1046,10 +1046,26 @@ namespace IW5 MaterialPass passArray[1]; }; + enum MaterialWorldVertexFormat : unsigned char + { + MTL_WORLDVERT_TEX_1_NRM_1 = 0x0, + MTL_WORLDVERT_TEX_2_NRM_1 = 0x1, + MTL_WORLDVERT_TEX_2_NRM_2 = 0x2, + MTL_WORLDVERT_TEX_3_NRM_1 = 0x3, + MTL_WORLDVERT_TEX_3_NRM_2 = 0x4, + MTL_WORLDVERT_TEX_3_NRM_3 = 0x5, + MTL_WORLDVERT_TEX_4_NRM_1 = 0x6, + MTL_WORLDVERT_TEX_4_NRM_2 = 0x7, + MTL_WORLDVERT_TEX_4_NRM_3 = 0x8, + MTL_WORLDVERT_TEX_5_NRM_1 = 0x9, + MTL_WORLDVERT_TEX_5_NRM_2 = 0xA, + MTL_WORLDVERT_TEX_5_NRM_3 = 0xB, + }; + struct MaterialTechniqueSet { const char* name; - unsigned char worldVertFormat; + MaterialWorldVertexFormat worldVertFormat; unsigned char unused[2]; MaterialTechniqueSet* remappedTechniqueSet; MaterialTechnique* techniques[54]; diff --git a/src/Common/Game/T5/T5_Assets.h b/src/Common/Game/T5/T5_Assets.h index c8e2cc5c..2d29e9c1 100644 --- a/src/Common/Game/T5/T5_Assets.h +++ b/src/Common/Game/T5/T5_Assets.h @@ -1668,10 +1668,23 @@ namespace T5 TECHNIQUE_COUNT }; + enum MaterialWorldVertexFormat : unsigned char + { + MTL_WORLDVERT_TEX_1_NRM_1 = 0x0, + MTL_WORLDVERT_TEX_2_NRM_1 = 0x1, + MTL_WORLDVERT_TEX_2_NRM_2 = 0x2, + MTL_WORLDVERT_TEX_3_NRM_1 = 0x3, + MTL_WORLDVERT_TEX_3_NRM_2 = 0x4, + MTL_WORLDVERT_TEX_3_NRM_3 = 0x5, + MTL_WORLDVERT_TEX_4_NRM_1 = 0x6, + MTL_WORLDVERT_TEX_4_NRM_2 = 0x7, + MTL_WORLDVERT_TEX_4_NRM_3 = 0x8, + }; + struct MaterialTechniqueSet { const char* name; - char worldVertFormat; + MaterialWorldVertexFormat worldVertFormat; char unused[1]; uint16_t techsetFlags; MaterialTechnique* techniques[130]; diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 22525cfc..07838f09 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -770,10 +770,23 @@ namespace T6 TECHNIQUE_COUNT }; + enum MaterialWorldVertexFormat : unsigned char + { + MTL_WORLDVERT_TEX_1_NRM_1 = 0x0, + MTL_WORLDVERT_TEX_2_NRM_1 = 0x1, + MTL_WORLDVERT_TEX_2_NRM_2 = 0x2, + MTL_WORLDVERT_TEX_3_NRM_1 = 0x3, + MTL_WORLDVERT_TEX_3_NRM_2 = 0x4, + MTL_WORLDVERT_TEX_3_NRM_3 = 0x5, + MTL_WORLDVERT_TEX_4_NRM_1 = 0x6, + MTL_WORLDVERT_TEX_4_NRM_2 = 0x7, + MTL_WORLDVERT_TEX_4_NRM_3 = 0x8, + }; + struct MaterialTechniqueSet { const char* name; - char worldVertFormat; + MaterialWorldVertexFormat worldVertFormat; MaterialTechnique* techniques[36]; }; diff --git a/src/ObjCommon/Techset/CommonTechset.cpp b/src/ObjCommon/Techset/CommonTechset.cpp index 3d6ae765..a96daa07 100644 --- a/src/ObjCommon/Techset/CommonTechset.cpp +++ b/src/ObjCommon/Techset/CommonTechset.cpp @@ -46,4 +46,10 @@ namespace techset m_technique_names(std::move(techniqueNames)) { } + + CommonTechset::CommonTechset(std::string name, const size_t techniqueTypeCount) + : m_name(std::move(name)), + m_technique_names(techniqueTypeCount) + { + } } // namespace techset diff --git a/src/ObjCommon/Techset/CommonTechset.h b/src/ObjCommon/Techset/CommonTechset.h index e80d873d..9ba15e57 100644 --- a/src/ObjCommon/Techset/CommonTechset.h +++ b/src/ObjCommon/Techset/CommonTechset.h @@ -28,6 +28,7 @@ namespace techset CommonTechset() = default; explicit CommonTechset(size_t techniqueTypeCount); CommonTechset(std::string name, std::vector techniqueNames); + CommonTechset(std::string name, size_t techniqueTypeCount); std::string m_name; std::vector m_technique_names; diff --git a/src/ObjCommon/Techset/TechsetCommon.cpp b/src/ObjCommon/Techset/TechsetCommon.cpp index f21097bd..e6455f01 100644 --- a/src/ObjCommon/Techset/TechsetCommon.cpp +++ b/src/ObjCommon/Techset/TechsetCommon.cpp @@ -18,4 +18,28 @@ namespace techset { return std::format("techsets/{}.techset", assetName); } + + void CountWorldVertFormatParameters(const std::string& assetName, size_t& texCount, size_t& normalCount) + { + texCount = 0; + normalCount = 0; + + if (assetName.empty()) + return; + + const auto nameLen = assetName.size(); + for (auto pos = 1u; pos < nameLen - 1u; pos++) + { + if (assetName[pos - 1] != '_' && !isdigit(assetName[pos - 1])) + continue; + if (!isdigit(assetName[pos + 1])) + continue; + + const auto c = tolower(assetName[pos]); + if (c == 'c') + texCount++; + else if (c == 'n') + normalCount++; + } + } } // namespace techset diff --git a/src/ObjCommon/Techset/TechsetCommon.h b/src/ObjCommon/Techset/TechsetCommon.h index ad65b5df..25cd3fc3 100644 --- a/src/ObjCommon/Techset/TechsetCommon.h +++ b/src/ObjCommon/Techset/TechsetCommon.h @@ -7,4 +7,6 @@ namespace techset std::string GetFileNameForStateMapName(const std::string& stateMapName); std::string GetFileNameForTechniqueName(const std::string& assetName); std::string GetFileNameForTechsetName(const std::string& assetName); + + void CountWorldVertFormatParameters(const std::string& assetName, size_t& texCount, size_t& normalCount); } // namespace techset diff --git a/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.cpp b/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.cpp index 68882385..9a672a30 100644 --- a/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.cpp +++ b/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.cpp @@ -1,16 +1,81 @@ #include "TechsetCompilerT6.h" #include "Game/T6/T6.h" +#include "Game/T6/Techset/TechsetConstantsT6.h" +#include "Techset/CommonTechsetLoader.h" +#include "Techset/TechsetCommon.h" + +using namespace T6; namespace { - class TechsetCompilerT6 final : public AssetCreator + MaterialWorldVertexFormat GetWorldVertexFormat(const std::string& name) + { + if (name.contains("lit_")) + { + size_t texCount = 0u, normalCount = 0u; + techset::CountWorldVertFormatParameters(name, texCount, normalCount); + + // 0 and 1 seem to be treated equally + texCount = std::max(texCount, 1u); + normalCount = std::max(normalCount, 1u); + + if (texCount == 1 && normalCount == 1) + return MTL_WORLDVERT_TEX_1_NRM_1; + if (texCount == 2 && normalCount == 1) + return MTL_WORLDVERT_TEX_2_NRM_1; + if (texCount == 2 && normalCount == 2) + return MTL_WORLDVERT_TEX_2_NRM_2; + if (texCount == 3 && normalCount == 1) + return MTL_WORLDVERT_TEX_3_NRM_1; + if (texCount == 3 && normalCount == 2) + return MTL_WORLDVERT_TEX_3_NRM_2; + if (texCount == 3 && normalCount == 3) + return MTL_WORLDVERT_TEX_3_NRM_3; + if (texCount == 4 && normalCount == 1) + return MTL_WORLDVERT_TEX_4_NRM_1; + if (texCount == 4 && normalCount == 2) + return MTL_WORLDVERT_TEX_4_NRM_2; + if (texCount == 4 && normalCount == 3) + return MTL_WORLDVERT_TEX_4_NRM_3; + } + + return static_cast(0); + } + + MaterialTechniqueSet* ConvertTechniqueSet(const techset::CommonTechset& commonTechset, MemoryManager& memory) + { + auto* techset = memory.Alloc(); + techset->name = memory.Dup(commonTechset.m_name.c_str()); + techset->worldVertFormat = GetWorldVertexFormat(commonTechset.m_name); + + return techset; + } + + class TechsetCompilerT6 final : public AssetCreator { public: + TechsetCompilerT6(ISearchPath& searchPath, MemoryManager& memory) + : m_search_path(searchPath), + m_memory(memory) + { + } + AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override { - return AssetCreationResult::NoAction(); + bool failure = false; + const auto commonTechset = techset::LoadCommonTechset(assetName, commonTechniqueTypeNames, m_search_path, failure); + if (!commonTechset) + return failure ? AssetCreationResult::Failure() : AssetCreationResult::NoAction(); + + auto* techset = ConvertTechniqueSet(*commonTechset, m_memory); + + return AssetCreationResult::Success(context.AddAsset(AssetRegistration(assetName, techset))); } + + private: + ISearchPath& m_search_path; + MemoryManager& m_memory; }; } // namespace @@ -18,6 +83,6 @@ namespace techset { std::unique_ptr CreateCompilerT6(MemoryManager& memory, ISearchPath& searchPath) { - return std::make_unique(); + return std::make_unique(searchPath, memory); } } // namespace techset diff --git a/src/ObjCompiling/Techset/CommonTechsetLoader.cpp b/src/ObjCompiling/Techset/CommonTechsetLoader.cpp index 34d54e11..407f8f80 100644 --- a/src/ObjCompiling/Techset/CommonTechsetLoader.cpp +++ b/src/ObjCompiling/Techset/CommonTechsetLoader.cpp @@ -20,7 +20,7 @@ namespace techset { failure = false; - const auto fileName = GetFileNameForTechniqueName(assetName); + const auto fileName = GetFileNameForTechsetName(assetName); const auto techniqueFile = searchPath.Open(fileName); if (!techniqueFile.IsOpen()) return nullptr; @@ -36,7 +36,7 @@ namespace techset CommentRemovingStreamProxy commentProxy(&baseStream); const auto lexer = std::make_unique(&commentProxy, std::move(lexerConfig)); - const auto parser = std::make_unique(*lexer, techniqueTypeNames); + const auto parser = std::make_unique(*lexer, assetName, techniqueTypeNames); const auto success = parser->Parse(); if (success) diff --git a/src/ObjCompiling/Techset/Parsing/TechsetFileParser.cpp b/src/ObjCompiling/Techset/Parsing/TechsetFileParser.cpp index 5bd6bfc3..4025ad29 100644 --- a/src/ObjCompiling/Techset/Parsing/TechsetFileParser.cpp +++ b/src/ObjCompiling/Techset/Parsing/TechsetFileParser.cpp @@ -72,8 +72,8 @@ namespace namespace techset { - TechsetParser::TechsetParser(SimpleLexer& lexer, const CommonTechniqueTypeNames& techniqueTypeNames) - : AbstractParser(&lexer, std::make_unique(techniqueTypeNames)) + TechsetParser::TechsetParser(SimpleLexer& lexer, std::string techsetName, const CommonTechniqueTypeNames& techniqueTypeNames) + : AbstractParser(&lexer, std::make_unique(std::move(techsetName), techniqueTypeNames)) { } diff --git a/src/ObjCompiling/Techset/Parsing/TechsetFileParser.h b/src/ObjCompiling/Techset/Parsing/TechsetFileParser.h index d10b718e..0bcab1a9 100644 --- a/src/ObjCompiling/Techset/Parsing/TechsetFileParser.h +++ b/src/ObjCompiling/Techset/Parsing/TechsetFileParser.h @@ -10,9 +10,9 @@ namespace techset class TechsetParser final : public AbstractParser { public: - TechsetParser(SimpleLexer& lexer, const CommonTechniqueTypeNames& techniqueTypeNames); + TechsetParser(SimpleLexer& lexer, std::string techsetName, const CommonTechniqueTypeNames& techniqueTypeNames); [[nodiscard]] std::unique_ptr GetParsingResult() const; - + protected: const std::vector& GetTestsForState() override; }; diff --git a/src/ObjCompiling/Techset/Parsing/TechsetFileParserState.cpp b/src/ObjCompiling/Techset/Parsing/TechsetFileParserState.cpp index 5fb2a9fe..46bbabc7 100644 --- a/src/ObjCompiling/Techset/Parsing/TechsetFileParserState.cpp +++ b/src/ObjCompiling/Techset/Parsing/TechsetFileParserState.cpp @@ -2,9 +2,9 @@ namespace techset { - TechsetParserState::TechsetParserState(const CommonTechniqueTypeNames& techniqueTypeNames) + TechsetParserState::TechsetParserState(std::string techsetName, const CommonTechniqueTypeNames& techniqueTypeNames) : m_technique_type_names(techniqueTypeNames), - m_definition(std::make_unique(techniqueTypeNames.GetTechniqueTypeCount())) + m_definition(std::make_unique(std::move(techsetName), techniqueTypeNames.GetTechniqueTypeCount())) { } } // namespace techset diff --git a/src/ObjCompiling/Techset/Parsing/TechsetFileParserState.h b/src/ObjCompiling/Techset/Parsing/TechsetFileParserState.h index fb0154c5..67a74b3f 100644 --- a/src/ObjCompiling/Techset/Parsing/TechsetFileParserState.h +++ b/src/ObjCompiling/Techset/Parsing/TechsetFileParserState.h @@ -4,6 +4,7 @@ #include #include +#include #include namespace techset @@ -11,7 +12,7 @@ namespace techset class TechsetParserState { public: - explicit TechsetParserState(const CommonTechniqueTypeNames& techniqueTypeNames); + TechsetParserState(std::string techsetName, const CommonTechniqueTypeNames& techniqueTypeNames); const CommonTechniqueTypeNames& m_technique_type_names; std::unique_ptr m_definition; diff --git a/test/ObjCompilingTests/Game/T6/Techset/TechsetCompilerT6Test.cpp b/test/ObjCompilingTests/Game/T6/Techset/TechsetCompilerT6Test.cpp new file mode 100644 index 00000000..1bfdce31 --- /dev/null +++ b/test/ObjCompilingTests/Game/T6/Techset/TechsetCompilerT6Test.cpp @@ -0,0 +1,65 @@ +#include "Game/T6/Techset/TechsetCompilerT6.h" + +#include "Game/T6/T6.h" +#include "SearchPath/MockSearchPath.h" +#include "Utils/TestMemoryManager.h" + +#include +#include +#include +#include + +using namespace T6; +using namespace std::string_literals; + +TEST_CASE("Game::T6::Techset::TechsetCompilerT6", "[techset][t6]") +{ + Zone zone("test", 0, GameId::T6, GamePlatform::PC); + AssetCreatorCollection creators(zone); + IgnoredAssetLookup ignoredAssets; + AssetCreationContext context(zone, &creators, &ignoredAssets); + MockSearchPath searchPath; + TestMemoryManager memory; + const auto sut = ::techset::CreateCompilerT6(memory, searchPath); + + SECTION("Sets correct worldVertFormat") + { + const auto [techsetName, expectedWorldVertFormat] = GENERATE(Catch::Generators::table({ + {"default", MTL_WORLDVERT_TEX_1_NRM_1}, + {"effect_zeqqz943", MTL_WORLDVERT_TEX_1_NRM_1}, + {"lit_r0c0_t1c1n1", MTL_WORLDVERT_TEX_2_NRM_1}, + {"lit_r0c0n0x0_b1c1n1s1v1", MTL_WORLDVERT_TEX_2_NRM_2}, + {"lit_r0c0n0x0_b1c1n1s1v1_b2c2n2x2", MTL_WORLDVERT_TEX_3_NRM_3}, + {"lit_sm_b0c0_b1c1_b2c2", MTL_WORLDVERT_TEX_3_NRM_1}, + {"lit_sm_b0c0_b1c1n1x1_b2c2n2v2", MTL_WORLDVERT_TEX_3_NRM_2}, + {"lit_sm_r0c0_b1c1_b2c2_b3c3", MTL_WORLDVERT_TEX_4_NRM_1}, + {"lit_sm_r0c0n0_b1c1_b2c2n2v2_m3c3", MTL_WORLDVERT_TEX_4_NRM_2}, + {"lit_sm_r0c0n0_b1c1n1s1", MTL_WORLDVERT_TEX_2_NRM_2}, + {"lit_sm_r0c0n0s0_b1c1n1s1_b2c2n2", MTL_WORLDVERT_TEX_3_NRM_3}, + {"lit_sm_r0c0n0x0_b1c1_b2c2n2s2", MTL_WORLDVERT_TEX_3_NRM_2}, + {"lit_sm_r0c0n0x0_b1c1n1_b2c2n2s2v2", MTL_WORLDVERT_TEX_3_NRM_3}, + {"lit_sm_r0c0n0x0_b1c1s1v1_m2c2_m3c3", MTL_WORLDVERT_TEX_4_NRM_1}, + {"lit_sm_r0c0n0x0_b1c1v1_b2c2n2s2_m3c3", MTL_WORLDVERT_TEX_4_NRM_2}, + {"lit_sm_r0c0s0_b1c1n1s1_m2c2", MTL_WORLDVERT_TEX_3_NRM_1}, + {"lit_sm_r0c0x0_b1c1", MTL_WORLDVERT_TEX_2_NRM_1}, + {"lit_sm_r0c0x0_b1c1n1s1_b2c2n2s2", MTL_WORLDVERT_TEX_3_NRM_2}, + {"lit_sm_r0c0x0_m1c1_m2c2_m3c3", MTL_WORLDVERT_TEX_4_NRM_1}, + {"lit_sm_t0c0n0_b1c1n1v1", MTL_WORLDVERT_TEX_2_NRM_2}, + {"lit_sm_t0c0n0s0_b1c1n1_b2c2n2s2v2", MTL_WORLDVERT_TEX_3_NRM_3}, + {"mc_lit_sm_r0c0d0_2213939z", MTL_WORLDVERT_TEX_1_NRM_1}, + {"wpc_lit_sm_b0c0s0_3f3q946z", MTL_WORLDVERT_TEX_1_NRM_1}, + {"wpc_lit_sm_r0c0n0s0o0_qj92q1f8", MTL_WORLDVERT_TEX_1_NRM_1}, + {"wpc_sw4_3d_burning_embers_nuketown_74j6971w", MTL_WORLDVERT_TEX_1_NRM_1}, + {"wpc_unlitdecalblend_add_j26wq580", MTL_WORLDVERT_TEX_1_NRM_1}, + })); + + CAPTURE(techsetName); + searchPath.AddFileData(std::format("techsets/{}.techset", techsetName), ""); + + const auto result = sut->CreateAsset(techsetName, context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* techset = static_cast(result.GetAssetInfo()->m_ptr); + CHECK(techset->worldVertFormat == expectedWorldVertFormat); + } +} From e7495149724e3d1c11b0c6703d184fc0260fa6e8 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Wed, 4 Feb 2026 21:05:39 +0000 Subject: [PATCH 03/27] fix: compilation with CommonTechset --- src/Common/{ => Techset}/StateMap/StateMapLayout.cpp | 0 src/Common/{ => Techset}/StateMap/StateMapLayout.h | 0 src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h | 2 +- src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.cpp | 4 ++-- src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp | 2 +- src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.h | 2 +- .../Techset/CommonTechsetCache.cpp | 0 .../Techset/CommonTechsetCache.h | 0 .../Parsing/Matcher/StateMapExpressionMatchers.cpp | 0 .../StateMap/Parsing/Matcher/StateMapExpressionMatchers.h | 2 +- .../Techset}/StateMap/Parsing/StateMapParser.cpp | 0 .../Techset}/StateMap/Parsing/StateMapParser.h | 6 ++---- .../Techset}/StateMap/Parsing/StateMapParserState.cpp | 0 .../Techset}/StateMap/Parsing/StateMapParserState.h | 4 ++-- .../Techset}/StateMap/StateMapDefinition.cpp | 0 .../Techset}/StateMap/StateMapDefinition.h | 0 .../Techset}/StateMap/StateMapFromTechniqueExtractor.cpp | 0 .../Techset}/StateMap/StateMapFromTechniqueExtractor.h | 0 .../Techset}/StateMap/StateMapHandler.cpp | 0 .../Techset}/StateMap/StateMapHandler.h | 7 +++---- .../Techset}/StateMap/StateMapReader.cpp | 0 .../Techset}/StateMap/StateMapReader.h | 2 +- .../Techset/TechniqueDefinitionAcceptor.cpp | 0 .../Techset/TechniqueDefinitionAcceptor.h | 0 .../Techset/TechniqueFileReader.cpp | 2 +- .../Techset/TechniqueFileReader.h | 1 - .../Techset/TechniqueStateMapCache.cpp | 0 .../Techset/TechniqueStateMapCache.h | 0 28 files changed, 15 insertions(+), 19 deletions(-) rename src/Common/{ => Techset}/StateMap/StateMapLayout.cpp (100%) rename src/Common/{ => Techset}/StateMap/StateMapLayout.h (100%) rename src/{ObjLoading => ObjCompiling}/Techset/CommonTechsetCache.cpp (100%) rename src/{ObjLoading => ObjCompiling}/Techset/CommonTechsetCache.h (100%) rename src/{ObjLoading => ObjCompiling/Techset}/StateMap/Parsing/Matcher/StateMapExpressionMatchers.cpp (100%) rename src/{ObjLoading => ObjCompiling/Techset}/StateMap/Parsing/Matcher/StateMapExpressionMatchers.h (91%) rename src/{ObjLoading => ObjCompiling/Techset}/StateMap/Parsing/StateMapParser.cpp (100%) rename src/{ObjLoading => ObjCompiling/Techset}/StateMap/Parsing/StateMapParser.h (71%) rename src/{ObjLoading => ObjCompiling/Techset}/StateMap/Parsing/StateMapParserState.cpp (100%) rename src/{ObjLoading => ObjCompiling/Techset}/StateMap/Parsing/StateMapParserState.h (88%) rename src/{ObjLoading => ObjCompiling/Techset}/StateMap/StateMapDefinition.cpp (100%) rename src/{ObjLoading => ObjCompiling/Techset}/StateMap/StateMapDefinition.h (100%) rename src/{ObjLoading => ObjCompiling/Techset}/StateMap/StateMapFromTechniqueExtractor.cpp (100%) rename src/{ObjLoading => ObjCompiling/Techset}/StateMap/StateMapFromTechniqueExtractor.h (100%) rename src/{ObjLoading => ObjCompiling/Techset}/StateMap/StateMapHandler.cpp (100%) rename src/{ObjLoading => ObjCompiling/Techset}/StateMap/StateMapHandler.h (81%) rename src/{ObjLoading => ObjCompiling/Techset}/StateMap/StateMapReader.cpp (100%) rename src/{ObjLoading => ObjCompiling/Techset}/StateMap/StateMapReader.h (94%) rename src/{ObjLoading => ObjCompiling}/Techset/TechniqueDefinitionAcceptor.cpp (100%) rename src/{ObjLoading => ObjCompiling}/Techset/TechniqueDefinitionAcceptor.h (100%) rename src/{ObjLoading => ObjCompiling}/Techset/TechniqueFileReader.cpp (96%) rename src/{ObjLoading => ObjCompiling}/Techset/TechniqueFileReader.h (95%) rename src/{ObjLoading => ObjCompiling}/Techset/TechniqueStateMapCache.cpp (100%) rename src/{ObjLoading => ObjCompiling}/Techset/TechniqueStateMapCache.h (100%) diff --git a/src/Common/StateMap/StateMapLayout.cpp b/src/Common/Techset/StateMap/StateMapLayout.cpp similarity index 100% rename from src/Common/StateMap/StateMapLayout.cpp rename to src/Common/Techset/StateMap/StateMapLayout.cpp diff --git a/src/Common/StateMap/StateMapLayout.h b/src/Common/Techset/StateMap/StateMapLayout.h similarity index 100% rename from src/Common/StateMap/StateMapLayout.h rename to src/Common/Techset/StateMap/StateMapLayout.h diff --git a/src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h b/src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h index 0f4f1a32..0881ff8c 100644 --- a/src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h +++ b/src/ObjCommon/Game/IW4/Techset/TechsetConstantsIW4.h @@ -2,8 +2,8 @@ #include "Game/IW4/CommonIW4.h" #include "Game/IW4/IW4.h" -#include "StateMap/StateMapLayout.h" #include "Techset/CommonTechset.h" +#include "Techset/StateMap/StateMapLayout.h" #include #include diff --git a/src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.cpp b/src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.cpp index 76a46ab9..0f3fdecd 100644 --- a/src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.cpp +++ b/src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.cpp @@ -9,9 +9,9 @@ #include "Gdt/AbstractGdtEntryReader.h" #include "Gdt/IGdtQueryable.h" #include "Pool/GlobalAssetPool.h" -#include "StateMap/StateMapFromTechniqueExtractor.h" -#include "StateMap/StateMapHandler.h" #include "Techset/CommonTechsetCache.h" +#include "Techset/StateMap/StateMapFromTechniqueExtractor.h" +#include "Techset/StateMap/StateMapHandler.h" #include "Techset/TechniqueFileReader.h" #include "Techset/TechniqueStateMapCache.h" #include "Techset/TechsetCommon.h" diff --git a/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp b/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp index 65e5f671..158b9984 100644 --- a/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp +++ b/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp @@ -6,9 +6,9 @@ #include "Game/IW4/Techset/TechsetConstantsIW4.h" #include "Shader/D3D9ShaderAnalyser.h" #include "Shader/ShaderCommon.h" -#include "StateMap/StateMapReader.h" #include "Techset/CommonTechsetCache.h" #include "Techset/CommonTechsetLoader.h" +#include "Techset/StateMap/StateMapReader.h" #include "Techset/TechniqueFileReader.h" #include "Techset/TechniqueStateMapCache.h" #include "Techset/TechsetCommon.h" diff --git a/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.h b/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.h index b1dd340c..c0e54d87 100644 --- a/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.h +++ b/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.h @@ -3,8 +3,8 @@ #include "Asset/IAssetCreator.h" #include "Game/IW4/IW4.h" #include "SearchPath/ISearchPath.h" -#include "StateMap/StateMapDefinition.h" #include "Techset/CommonTechset.h" +#include "Techset/StateMap/StateMapDefinition.h" #include "Utils/MemoryManager.h" #include diff --git a/src/ObjLoading/Techset/CommonTechsetCache.cpp b/src/ObjCompiling/Techset/CommonTechsetCache.cpp similarity index 100% rename from src/ObjLoading/Techset/CommonTechsetCache.cpp rename to src/ObjCompiling/Techset/CommonTechsetCache.cpp diff --git a/src/ObjLoading/Techset/CommonTechsetCache.h b/src/ObjCompiling/Techset/CommonTechsetCache.h similarity index 100% rename from src/ObjLoading/Techset/CommonTechsetCache.h rename to src/ObjCompiling/Techset/CommonTechsetCache.h diff --git a/src/ObjLoading/StateMap/Parsing/Matcher/StateMapExpressionMatchers.cpp b/src/ObjCompiling/Techset/StateMap/Parsing/Matcher/StateMapExpressionMatchers.cpp similarity index 100% rename from src/ObjLoading/StateMap/Parsing/Matcher/StateMapExpressionMatchers.cpp rename to src/ObjCompiling/Techset/StateMap/Parsing/Matcher/StateMapExpressionMatchers.cpp diff --git a/src/ObjLoading/StateMap/Parsing/Matcher/StateMapExpressionMatchers.h b/src/ObjCompiling/Techset/StateMap/Parsing/Matcher/StateMapExpressionMatchers.h similarity index 91% rename from src/ObjLoading/StateMap/Parsing/Matcher/StateMapExpressionMatchers.h rename to src/ObjCompiling/Techset/StateMap/Parsing/Matcher/StateMapExpressionMatchers.h index 1480bd91..b3a48882 100644 --- a/src/ObjLoading/StateMap/Parsing/Matcher/StateMapExpressionMatchers.h +++ b/src/ObjCompiling/Techset/StateMap/Parsing/Matcher/StateMapExpressionMatchers.h @@ -1,7 +1,7 @@ #pragma once #include "Parsing/Simple/Expression/SimpleExpressionMatchers.h" -#include "StateMap/Parsing/StateMapParserState.h" +#include "Techset/StateMap/Parsing/StateMapParserState.h" #include diff --git a/src/ObjLoading/StateMap/Parsing/StateMapParser.cpp b/src/ObjCompiling/Techset/StateMap/Parsing/StateMapParser.cpp similarity index 100% rename from src/ObjLoading/StateMap/Parsing/StateMapParser.cpp rename to src/ObjCompiling/Techset/StateMap/Parsing/StateMapParser.cpp diff --git a/src/ObjLoading/StateMap/Parsing/StateMapParser.h b/src/ObjCompiling/Techset/StateMap/Parsing/StateMapParser.h similarity index 71% rename from src/ObjLoading/StateMap/Parsing/StateMapParser.h rename to src/ObjCompiling/Techset/StateMap/Parsing/StateMapParser.h index dad1bcca..559eee6b 100644 --- a/src/ObjLoading/StateMap/Parsing/StateMapParser.h +++ b/src/ObjCompiling/Techset/StateMap/Parsing/StateMapParser.h @@ -4,8 +4,6 @@ #include "Parsing/Simple/SimpleLexer.h" #include "Parsing/Simple/SimpleParserValue.h" #include "StateMapParserState.h" -#include "Techset/TechsetDefinition.h" -#include "Utils/ClassUtils.h" namespace state_map { @@ -16,7 +14,7 @@ namespace state_map public: StateMapParser(SimpleLexer* lexer, std::string stateMapName, const StateMapLayout& layout); - _NODISCARD std::unique_ptr GetStateMapDefinition() const; - _NODISCARD StateMapParserState* GetState() const; + [[nodiscard]] std::unique_ptr GetStateMapDefinition() const; + [[nodiscard]] StateMapParserState* GetState() const; }; } // namespace state_map diff --git a/src/ObjLoading/StateMap/Parsing/StateMapParserState.cpp b/src/ObjCompiling/Techset/StateMap/Parsing/StateMapParserState.cpp similarity index 100% rename from src/ObjLoading/StateMap/Parsing/StateMapParserState.cpp rename to src/ObjCompiling/Techset/StateMap/Parsing/StateMapParserState.cpp diff --git a/src/ObjLoading/StateMap/Parsing/StateMapParserState.h b/src/ObjCompiling/Techset/StateMap/Parsing/StateMapParserState.h similarity index 88% rename from src/ObjLoading/StateMap/Parsing/StateMapParserState.h rename to src/ObjCompiling/Techset/StateMap/Parsing/StateMapParserState.h index 260d4e66..f32c64e3 100644 --- a/src/ObjLoading/StateMap/Parsing/StateMapParserState.h +++ b/src/ObjCompiling/Techset/StateMap/Parsing/StateMapParserState.h @@ -1,7 +1,7 @@ #pragma once -#include "StateMap/StateMapDefinition.h" -#include "StateMap/StateMapLayout.h" +#include "Techset/StateMap/StateMapDefinition.h" +#include "Techset/StateMap/StateMapLayout.h" #include #include diff --git a/src/ObjLoading/StateMap/StateMapDefinition.cpp b/src/ObjCompiling/Techset/StateMap/StateMapDefinition.cpp similarity index 100% rename from src/ObjLoading/StateMap/StateMapDefinition.cpp rename to src/ObjCompiling/Techset/StateMap/StateMapDefinition.cpp diff --git a/src/ObjLoading/StateMap/StateMapDefinition.h b/src/ObjCompiling/Techset/StateMap/StateMapDefinition.h similarity index 100% rename from src/ObjLoading/StateMap/StateMapDefinition.h rename to src/ObjCompiling/Techset/StateMap/StateMapDefinition.h diff --git a/src/ObjLoading/StateMap/StateMapFromTechniqueExtractor.cpp b/src/ObjCompiling/Techset/StateMap/StateMapFromTechniqueExtractor.cpp similarity index 100% rename from src/ObjLoading/StateMap/StateMapFromTechniqueExtractor.cpp rename to src/ObjCompiling/Techset/StateMap/StateMapFromTechniqueExtractor.cpp diff --git a/src/ObjLoading/StateMap/StateMapFromTechniqueExtractor.h b/src/ObjCompiling/Techset/StateMap/StateMapFromTechniqueExtractor.h similarity index 100% rename from src/ObjLoading/StateMap/StateMapFromTechniqueExtractor.h rename to src/ObjCompiling/Techset/StateMap/StateMapFromTechniqueExtractor.h diff --git a/src/ObjLoading/StateMap/StateMapHandler.cpp b/src/ObjCompiling/Techset/StateMap/StateMapHandler.cpp similarity index 100% rename from src/ObjLoading/StateMap/StateMapHandler.cpp rename to src/ObjCompiling/Techset/StateMap/StateMapHandler.cpp diff --git a/src/ObjLoading/StateMap/StateMapHandler.h b/src/ObjCompiling/Techset/StateMap/StateMapHandler.h similarity index 81% rename from src/ObjLoading/StateMap/StateMapHandler.h rename to src/ObjCompiling/Techset/StateMap/StateMapHandler.h index 6c421376..1dec3b06 100644 --- a/src/ObjLoading/StateMap/StateMapHandler.h +++ b/src/ObjCompiling/Techset/StateMap/StateMapHandler.h @@ -1,8 +1,7 @@ #pragma once -#include "StateMap/StateMapDefinition.h" -#include "StateMap/StateMapLayout.h" -#include "Utils/ClassUtils.h" +#include "Techset/StateMap/StateMapDefinition.h" +#include "Techset/StateMap/StateMapLayout.h" #include #include @@ -13,7 +12,7 @@ namespace state_map { public: void AddValue(std::string key, std::string value); - _NODISCARD SimpleExpressionValue ValueByName(const std::string& name) const override; + [[nodiscard]] SimpleExpressionValue ValueByName(const std::string& name) const override; private: std::unordered_map m_vars; diff --git a/src/ObjLoading/StateMap/StateMapReader.cpp b/src/ObjCompiling/Techset/StateMap/StateMapReader.cpp similarity index 100% rename from src/ObjLoading/StateMap/StateMapReader.cpp rename to src/ObjCompiling/Techset/StateMap/StateMapReader.cpp diff --git a/src/ObjLoading/StateMap/StateMapReader.h b/src/ObjCompiling/Techset/StateMap/StateMapReader.h similarity index 94% rename from src/ObjLoading/StateMap/StateMapReader.h rename to src/ObjCompiling/Techset/StateMap/StateMapReader.h index 5e52b3da..f3c53161 100644 --- a/src/ObjLoading/StateMap/StateMapReader.h +++ b/src/ObjCompiling/Techset/StateMap/StateMapReader.h @@ -2,8 +2,8 @@ #include "Parsing/IParserLineStream.h" #include "Parsing/StateMapParserState.h" -#include "StateMap/StateMapLayout.h" #include "StateMapDefinition.h" +#include "Techset/StateMap/StateMapLayout.h" #include "Utils/ClassUtils.h" #include diff --git a/src/ObjLoading/Techset/TechniqueDefinitionAcceptor.cpp b/src/ObjCompiling/Techset/TechniqueDefinitionAcceptor.cpp similarity index 100% rename from src/ObjLoading/Techset/TechniqueDefinitionAcceptor.cpp rename to src/ObjCompiling/Techset/TechniqueDefinitionAcceptor.cpp diff --git a/src/ObjLoading/Techset/TechniqueDefinitionAcceptor.h b/src/ObjCompiling/Techset/TechniqueDefinitionAcceptor.h similarity index 100% rename from src/ObjLoading/Techset/TechniqueDefinitionAcceptor.h rename to src/ObjCompiling/Techset/TechniqueDefinitionAcceptor.h diff --git a/src/ObjLoading/Techset/TechniqueFileReader.cpp b/src/ObjCompiling/Techset/TechniqueFileReader.cpp similarity index 96% rename from src/ObjLoading/Techset/TechniqueFileReader.cpp rename to src/ObjCompiling/Techset/TechniqueFileReader.cpp index 71a40fbf..884b9b32 100644 --- a/src/ObjLoading/Techset/TechniqueFileReader.cpp +++ b/src/ObjCompiling/Techset/TechniqueFileReader.cpp @@ -3,7 +3,7 @@ #include "Parsing/Impl/CommentRemovingStreamProxy.h" #include "Parsing/Impl/ParserSingleInputStream.h" #include "Parsing/Simple/SimpleLexer.h" -#include "Parsing/TechniqueFileParser.h" +#include "Techset/Parsing/TechniqueFileParser.h" #include "Utils/Logging/Log.h" #include diff --git a/src/ObjLoading/Techset/TechniqueFileReader.h b/src/ObjCompiling/Techset/TechniqueFileReader.h similarity index 95% rename from src/ObjLoading/Techset/TechniqueFileReader.h rename to src/ObjCompiling/Techset/TechniqueFileReader.h index 2090304b..9f72828e 100644 --- a/src/ObjLoading/Techset/TechniqueFileReader.h +++ b/src/ObjCompiling/Techset/TechniqueFileReader.h @@ -2,7 +2,6 @@ #include "Parsing/IParserLineStream.h" #include "TechniqueDefinitionAcceptor.h" -#include "Utils/ClassUtils.h" #include #include diff --git a/src/ObjLoading/Techset/TechniqueStateMapCache.cpp b/src/ObjCompiling/Techset/TechniqueStateMapCache.cpp similarity index 100% rename from src/ObjLoading/Techset/TechniqueStateMapCache.cpp rename to src/ObjCompiling/Techset/TechniqueStateMapCache.cpp diff --git a/src/ObjLoading/Techset/TechniqueStateMapCache.h b/src/ObjCompiling/Techset/TechniqueStateMapCache.h similarity index 100% rename from src/ObjLoading/Techset/TechniqueStateMapCache.h rename to src/ObjCompiling/Techset/TechniqueStateMapCache.h From a6d63e9b31ee6d8df7074e8edc271447ffd66637 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 27 Feb 2026 21:09:06 +0100 Subject: [PATCH 04/27] fix: constraint on asset name arrays --- src/Common/Game/IW3/GameIW3.cpp | 6 ++++-- src/Common/Game/IW4/GameIW4.cpp | 6 ++++-- src/Common/Game/IW5/GameIW5.cpp | 6 ++++-- src/Common/Game/T5/GameT5.cpp | 6 ++++-- src/Common/Game/T5/T5.h | 2 +- src/Common/Game/T6/GameT6.cpp | 6 ++++-- 6 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/Common/Game/IW3/GameIW3.cpp b/src/Common/Game/IW3/GameIW3.cpp index 31007508..17771f20 100644 --- a/src/Common/Game/IW3/GameIW3.cpp +++ b/src/Common/Game/IW3/GameIW3.cpp @@ -8,18 +8,20 @@ using namespace IW3; namespace { - constexpr const char* ASSET_TYPE_NAMES[ASSET_TYPE_COUNT]{ + constexpr const char* ASSET_TYPE_NAMES[]{ "xmodelpieces", "physpreset", "xanim", "xmodel", "material", "techniqueset", "image", "sound", "soundcurve", "loadedsound", "clipmap_unused", "clipmap", "comworld", "gameworldsp", "gameworldmp", "mapents", "gfxworld", "lightdef", "uimap", "font", "menulist", "menu", "localize", "weapon", "snddriverglobals", "fx", "impactfx", "aitype", "mptype", "character", "xmodelalias", "rawfile", "stringtable", }; + static_assert(std::extent_v == ASSET_TYPE_COUNT); - constexpr const char* SUB_ASSET_TYPE_NAMES[SUB_ASSET_TYPE_COUNT]{ + constexpr const char* SUB_ASSET_TYPE_NAMES[]{ "technique", "vertexshader", "pixelshader", }; + static_assert(std::extent_v == SUB_ASSET_TYPE_COUNT); } // namespace namespace IW3 diff --git a/src/Common/Game/IW4/GameIW4.cpp b/src/Common/Game/IW4/GameIW4.cpp index a3ca8860..88a05a2e 100644 --- a/src/Common/Game/IW4/GameIW4.cpp +++ b/src/Common/Game/IW4/GameIW4.cpp @@ -8,7 +8,7 @@ using namespace IW4; namespace { - constexpr const char* ASSET_TYPE_NAMES[ASSET_TYPE_COUNT]{ + constexpr const char* ASSET_TYPE_NAMES[]{ "physpreset", "physcollmap", "xanim", "xmodelsurfs", "xmodel", "material", "pixelshader", "vertexshader", "vertexdecl", "techniqueset", "image", "sound", "soundcurve", "loadedsound", "clipmap_unused", @@ -19,10 +19,12 @@ namespace "xmodelalias", "rawfile", "stringtable", "leaderboard", "structureddatadef", "tracer", "vehicle", "addonmapents", }; + static_assert(std::extent_v == ASSET_TYPE_COUNT); - constexpr const char* SUB_ASSET_TYPE_NAMES[SUB_ASSET_TYPE_COUNT]{ + constexpr const char* SUB_ASSET_TYPE_NAMES[]{ "technique", }; + static_assert(std::extent_v == SUB_ASSET_TYPE_COUNT); } // namespace namespace IW4 diff --git a/src/Common/Game/IW5/GameIW5.cpp b/src/Common/Game/IW5/GameIW5.cpp index f7dafcea..2a02dbb1 100644 --- a/src/Common/Game/IW5/GameIW5.cpp +++ b/src/Common/Game/IW5/GameIW5.cpp @@ -8,7 +8,7 @@ using namespace IW5; namespace { - constexpr const char* ASSET_TYPE_NAMES[ASSET_TYPE_COUNT]{ + constexpr const char* ASSET_TYPE_NAMES[]{ "physpreset", "physcollmap", "xanim", @@ -56,10 +56,12 @@ namespace "vehicle", "addonmapents", }; + static_assert(std::extent_v == ASSET_TYPE_COUNT); - constexpr const char* SUB_ASSET_TYPE_NAMES[SUB_ASSET_TYPE_COUNT]{ + constexpr const char* SUB_ASSET_TYPE_NAMES[]{ "technique", }; + static_assert(std::extent_v == SUB_ASSET_TYPE_COUNT); } // namespace namespace IW5 diff --git a/src/Common/Game/T5/GameT5.cpp b/src/Common/Game/T5/GameT5.cpp index d72c81bf..a385bac4 100644 --- a/src/Common/Game/T5/GameT5.cpp +++ b/src/Common/Game/T5/GameT5.cpp @@ -8,7 +8,7 @@ using namespace T5; namespace { - constexpr const char* ASSET_TYPE_NAMES[ASSET_TYPE_COUNT]{ + constexpr const char* ASSET_TYPE_NAMES[]{ "xmodelpieces", "physpreset", "physconstraints", "destructibledef", "xanim", "xmodel", "material", "techniqueset", "image", "soundbank", "soundpatch", "clipmap_unused", "clipmap", "comworld", "gameworldsp", "gameworldmp", "mapents", "gfxworld", "gfxlightdef", "uimap", "font", @@ -17,12 +17,14 @@ namespace "xmodelalias", "rawfile", "stringtable", "packindex", "xglobals", "ddl", "glasses", "emblemset", }; + static_assert(std::extent_v == ASSET_TYPE_COUNT); - constexpr const char* SUB_ASSET_TYPE_NAMES[SUB_ASSET_TYPE_COUNT]{ + constexpr const char* SUB_ASSET_TYPE_NAMES[]{ "technique", "vertexshader", "pixelshader", }; + static_assert(std::extent_v == SUB_ASSET_TYPE_COUNT); } // namespace namespace T5 diff --git a/src/Common/Game/T5/T5.h b/src/Common/Game/T5/T5.h index 89ebd8e7..1989889b 100644 --- a/src/Common/Game/T5/T5.h +++ b/src/Common/Game/T5/T5.h @@ -62,7 +62,7 @@ namespace T5 enum SubAssetType { - SUB_ASSET_TYPE_TECHNIQUE = ASSET_TYPE_COUNT, + SUB_ASSET_TYPE_TECHNIQUE, SUB_ASSET_TYPE_VERTEX_SHADER, SUB_ASSET_TYPE_PIXEL_SHADER, diff --git a/src/Common/Game/T6/GameT6.cpp b/src/Common/Game/T6/GameT6.cpp index 8ef710f9..cbb96687 100644 --- a/src/Common/Game/T6/GameT6.cpp +++ b/src/Common/Game/T6/GameT6.cpp @@ -8,7 +8,7 @@ using namespace T6; namespace { - constexpr const char* ASSET_TYPE_NAMES[ASSET_TYPE_COUNT]{ + constexpr const char* ASSET_TYPE_NAMES[]{ "xmodelpieces", "physpreset", "physconstraints", @@ -70,12 +70,14 @@ namespace "footstepfxtable", "zbarrier", }; + static_assert(std::extent_v == ASSET_TYPE_COUNT); - constexpr const char* SUB_ASSET_TYPE_NAMES[SUB_ASSET_TYPE_COUNT]{ + constexpr const char* SUB_ASSET_TYPE_NAMES[]{ "technique", "vertexshader", "pixelshader", }; + static_assert(std::extent_v == SUB_ASSET_TYPE_COUNT); } // namespace namespace T6 From 2e3b5501b62dda93c259df21e6c73b7188390619 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 27 Feb 2026 21:13:31 +0100 Subject: [PATCH 05/27] chore: extract more information from d3d11 shaders --- src/ObjCommon/Shader/D3D11ShaderAnalyser.cpp | 180 +++++++++++++++---- src/ObjCommon/Shader/D3D11ShaderAnalyser.h | 18 ++ 2 files changed, 164 insertions(+), 34 deletions(-) diff --git a/src/ObjCommon/Shader/D3D11ShaderAnalyser.cpp b/src/ObjCommon/Shader/D3D11ShaderAnalyser.cpp index f866236f..10a5f353 100644 --- a/src/ObjCommon/Shader/D3D11ShaderAnalyser.cpp +++ b/src/ObjCommon/Shader/D3D11ShaderAnalyser.cpp @@ -29,7 +29,12 @@ namespace d3d11 ConstantBufferVariable::ConstantBufferVariable() : m_offset(0u), m_size(0u), - m_flags(0u) + m_flags(0u), + m_is_used(false), + m_variable_class(VariableClass::UNKNOWN), + m_element_count(0), + m_row_count(0), + m_column_count(0) { } } // namespace d3d11 @@ -39,9 +44,6 @@ namespace constexpr auto TAG_RDEF = FileUtils::MakeMagic32('R', 'D', 'E', 'F'); constexpr auto TAG_SHDR = FileUtils::MakeMagic32('S', 'H', 'D', 'R'); - constexpr auto VERSION_5_0 = 0x500; - constexpr auto VERSION_5_1 = 0x501; - constexpr auto TARGET_VERSION_MASK = 0xFFFF; constexpr auto CHUNK_TABLE_OFFSET = 28u; struct FileRdefHeader @@ -50,7 +52,9 @@ namespace uint32_t constantBufferOffset; uint32_t boundResourceCount; uint32_t boundResourceOffset; - uint32_t target; + uint8_t minorVersion; + uint8_t majorVersion; + uint16_t type; uint32_t flags; uint32_t creatorOffset; }; @@ -172,6 +176,17 @@ namespace D3D11_SRV_DIMENSION_BUFFEREX }; + // https://learn.microsoft.com/en-us/windows/win32/api/d3dcommon/ne-d3dcommon-d3d_shader_input_flags + enum D3D_SHADER_INPUT_FLAGS + { + D3D_SIF_USERPACKED = 0x1, + D3D_SIF_COMPARISON_SAMPLER = 0x2, + D3D_SIF_TEXTURE_COMPONENT_0 = 0x4, + D3D_SIF_TEXTURE_COMPONENT_1 = 0x8, + D3D_SIF_TEXTURE_COMPONENTS = 0xc, + D3D_SIF_UNUSED = 0x10, + }; + struct FileBoundResource { uint32_t nameOffset; @@ -181,7 +196,7 @@ namespace uint32_t numSamples; uint32_t bindPoint; uint32_t bindCount; - uint32_t uFlags; + uint32_t uFlags; // D3D_SHADER_INPUT_FLAGS }; struct FileBoundResource_5_1 : FileBoundResource @@ -218,6 +233,15 @@ namespace D3D_CBUFFER_TYPE type; }; + // https://learn.microsoft.com/en-us/windows/win32/api/d3dcommon/ne-d3dcommon-d3d_shader_variable_flags + enum D3D_SHADER_VARIABLE_FLAGS + { + D3D_SVF_USERPACKED = 1, + D3D_SVF_USED = 2, + D3D_SVF_INTERFACE_POINTER = 4, + D3D_SVF_INTERFACE_PARAMETER = 8, + }; + struct FileConstantBufferVariable { uint32_t nameOffset; @@ -230,13 +254,46 @@ namespace struct FileConstantBufferVariable_5_0 : FileConstantBufferVariable { - // Wine project does not seem to know what this is - uint32_t unknown[4]; + uint32_t resourceBinding; + uint32_t resourceCount; + uint32_t samplerBinding; + uint32_t samplerCount; }; static_assert(sizeof(FileConstantBufferVariable) == 24); static_assert(sizeof(FileConstantBufferVariable_5_0) == 40); + enum D3D_SHADER_VARIABLE_CLASS : uint16_t + { + D3D_SVC_SCALAR = 0, + D3D_SVC_VECTOR, + D3D_SVC_MATRIX_ROWS, + D3D_SVC_MATRIX_COLUMNS, + D3D_SVC_OBJECT, + D3D_SVC_STRUCT, + D3D_SVC_INTERFACE_CLASS, + D3D_SVC_INTERFACE_POINTER, + D3D10_SVC_SCALAR, + D3D10_SVC_VECTOR, + D3D10_SVC_MATRIX_ROWS, + D3D10_SVC_MATRIX_COLUMNS, + D3D10_SVC_OBJECT, + D3D10_SVC_STRUCT, + D3D11_SVC_INTERFACE_CLASS, + D3D11_SVC_INTERFACE_POINTER + }; + + struct FileRdefType + { + D3D_SHADER_VARIABLE_CLASS class_; + uint16_t baseType; + uint16_t rowCount; + uint16_t columnCount; + uint16_t elementCount; + uint16_t fieldCount; + uint32_t fieldsOffset; + }; + enum FileProgramType : uint32_t { D3D10_SB_PIXEL_SHADER = 0, @@ -261,6 +318,16 @@ namespace static_assert(sizeof(FileShaderHeader) == 4); + constexpr bool IsAtLeastVersion(const uint8_t expectedMajor, const uint8_t expectedMinor, const uint8_t actualMajor, const uint8_t actualMinor) + { + if (actualMajor < expectedMajor) + return false; + if (actualMinor < expectedMinor) + return false; + + return true; + } + uint32_t ReadU32(const uint8_t*& ptr) { const auto result = *reinterpret_cast(ptr); @@ -451,6 +518,39 @@ namespace return true; } + VariableClass GetVariableClass(const D3D_SHADER_VARIABLE_CLASS variableClass) + { + switch (variableClass) + { + case D3D_SVC_SCALAR: + case D3D10_SVC_SCALAR: + return VariableClass::SCALAR; + case D3D_SVC_VECTOR: + case D3D10_SVC_VECTOR: + return VariableClass::VECTOR; + case D3D_SVC_MATRIX_ROWS: + case D3D10_SVC_MATRIX_ROWS: + return VariableClass::MATRIX_ROWS; + case D3D_SVC_MATRIX_COLUMNS: + case D3D10_SVC_MATRIX_COLUMNS: + return VariableClass::MATRIX_COLUMNS; + case D3D_SVC_OBJECT: + case D3D10_SVC_OBJECT: + return VariableClass::OBJECT; + case D3D_SVC_STRUCT: + case D3D10_SVC_STRUCT: + return VariableClass::STRUCT; + case D3D_SVC_INTERFACE_CLASS: + case D3D11_SVC_INTERFACE_CLASS: + return VariableClass::INTERFACE_CLASS; + case D3D_SVC_INTERFACE_POINTER: + case D3D11_SVC_INTERFACE_POINTER: + return VariableClass::INTERFACE_POINTER; + default: + return VariableClass::UNKNOWN; + } + } + bool PopulateConstantBufferVariable(ConstantBufferVariable& constantBufferVariable, const FileConstantBufferVariable& fileConstantBufferVariable, const uint8_t* shaderByteCode, @@ -467,6 +567,17 @@ namespace constantBufferVariable.m_offset = fileConstantBufferVariable.startOffset; constantBufferVariable.m_size = fileConstantBufferVariable.size; constantBufferVariable.m_flags = fileConstantBufferVariable.flags; + constantBufferVariable.m_is_used = fileConstantBufferVariable.flags & D3D_SVF_USED; + + if (fileConstantBufferVariable.typeOffset + sizeof(FileRdefType) > chunkSize) + return false; + + const auto type = reinterpret_cast(shaderByteCode + chunkOffset + fileConstantBufferVariable.typeOffset); + + constantBufferVariable.m_variable_class = GetVariableClass(type->class_); + constantBufferVariable.m_element_count = static_cast(type->elementCount); + constantBufferVariable.m_column_count = static_cast(type->columnCount); + constantBufferVariable.m_row_count = static_cast(type->rowCount); return true; } @@ -500,7 +611,8 @@ namespace const size_t shaderByteCodeSize, const size_t chunkOffset, const size_t chunkSize, - const unsigned targetVersion) + const uint8_t major, + const uint8_t minor) { const auto nameString = reinterpret_cast(shaderByteCode + chunkOffset + fileConstantBuffer.nameOffset); @@ -513,10 +625,10 @@ namespace constantBuffer.m_flags = fileConstantBuffer.flags; constantBuffer.m_type = GetType(fileConstantBuffer.type); - if (targetVersion < VERSION_5_0) + if (IsAtLeastVersion(5, 0, major, minor)) { - const auto* variables = reinterpret_cast(shaderByteCode + chunkOffset + fileConstantBuffer.variableOffset); - if (fileConstantBuffer.variableOffset + sizeof(FileConstantBufferVariable) * fileConstantBuffer.variableCount > chunkSize) + const auto* variables = reinterpret_cast(shaderByteCode + chunkOffset + fileConstantBuffer.variableOffset); + if (fileConstantBuffer.variableOffset + sizeof(FileConstantBufferVariable_5_0) * fileConstantBuffer.variableCount > chunkSize) return false; for (auto variableIndex = 0u; variableIndex < fileConstantBuffer.variableCount; variableIndex++) @@ -532,8 +644,8 @@ namespace } else { - const auto* variables = reinterpret_cast(shaderByteCode + chunkOffset + fileConstantBuffer.variableOffset); - if (fileConstantBuffer.variableOffset + sizeof(FileConstantBufferVariable_5_0) * fileConstantBuffer.variableCount > chunkSize) + const auto* variables = reinterpret_cast(shaderByteCode + chunkOffset + fileConstantBuffer.variableOffset); + if (fileConstantBuffer.variableOffset + sizeof(FileConstantBufferVariable) * fileConstantBuffer.variableCount > chunkSize) return false; for (auto variableIndex = 0u; variableIndex < fileConstantBuffer.variableCount; variableIndex++) @@ -562,7 +674,6 @@ namespace const auto* header = reinterpret_cast(shaderByteCode + chunkOffset); - const auto targetVersion = header->target & TARGET_VERSION_MASK; const auto creatorString = reinterpret_cast(shaderByteCode + chunkOffset + header->creatorOffset); if (!StringFitsInChunk(creatorString, shaderByteCode, shaderByteCodeSize)) @@ -570,23 +681,7 @@ namespace shaderInfo.m_creator = std::string(creatorString); - if (targetVersion < VERSION_5_1) - { - const auto* boundResources = reinterpret_cast(shaderByteCode + chunkOffset + header->boundResourceOffset); - if (header->boundResourceOffset + sizeof(FileBoundResource) * header->boundResourceCount > chunkSize) - return false; - - for (auto boundResourceIndex = 0u; boundResourceIndex < header->boundResourceCount; boundResourceIndex++) - { - const auto& fileBoundResource = boundResources[boundResourceIndex]; - BoundResource boundResource; - - PopulateBoundResource(boundResource, fileBoundResource, shaderByteCode, shaderByteCodeSize, chunkOffset); - - shaderInfo.m_bound_resources.emplace_back(std::move(boundResource)); - } - } - else + if (IsAtLeastVersion(5, 1, header->majorVersion, header->minorVersion)) { const auto* boundResources = reinterpret_cast(shaderByteCode + chunkOffset + header->boundResourceOffset); if (header->boundResourceOffset + sizeof(FileBoundResource_5_1) * header->boundResourceCount > chunkSize) @@ -603,6 +698,22 @@ namespace shaderInfo.m_bound_resources.emplace_back(std::move(boundResource)); } } + else + { + const auto* boundResources = reinterpret_cast(shaderByteCode + chunkOffset + header->boundResourceOffset); + if (header->boundResourceOffset + sizeof(FileBoundResource) * header->boundResourceCount > chunkSize) + return false; + + for (auto boundResourceIndex = 0u; boundResourceIndex < header->boundResourceCount; boundResourceIndex++) + { + const auto& fileBoundResource = boundResources[boundResourceIndex]; + BoundResource boundResource; + + PopulateBoundResource(boundResource, fileBoundResource, shaderByteCode, shaderByteCodeSize, chunkOffset); + + shaderInfo.m_bound_resources.emplace_back(std::move(boundResource)); + } + } const auto* constantBuffers = reinterpret_cast(shaderByteCode + chunkOffset + header->constantBufferOffset); if (header->constantBufferOffset + sizeof(FileConstantBuffer) * header->constantBufferCount > chunkSize) @@ -613,7 +724,8 @@ namespace const auto& fileConstantBuffer = constantBuffers[constantBufferIndex]; ConstantBuffer constantBuffer; - if (!PopulateConstantBuffer(constantBuffer, fileConstantBuffer, shaderByteCode, shaderByteCodeSize, chunkOffset, chunkSize, targetVersion)) + if (!PopulateConstantBuffer( + constantBuffer, fileConstantBuffer, shaderByteCode, shaderByteCodeSize, chunkOffset, chunkSize, header->majorVersion, header->minorVersion)) return false; shaderInfo.m_constant_buffers.emplace_back(std::move(constantBuffer)); @@ -684,5 +796,5 @@ std::unique_ptr ShaderAnalyser::GetShaderInfo(const void* shader, co if (!PopulateShaderInfoFromBytes(*shaderInfo, static_cast(shader), shaderSize)) return nullptr; - return shaderInfo; + return std::move(shaderInfo); } diff --git a/src/ObjCommon/Shader/D3D11ShaderAnalyser.h b/src/ObjCommon/Shader/D3D11ShaderAnalyser.h index e544fcea..39cacf7d 100644 --- a/src/ObjCommon/Shader/D3D11ShaderAnalyser.h +++ b/src/ObjCommon/Shader/D3D11ShaderAnalyser.h @@ -18,6 +18,19 @@ namespace d3d11 COMPUTE_SHADER }; + enum class VariableClass : std::uint8_t + { + UNKNOWN, + SCALAR, + VECTOR, + MATRIX_ROWS, + MATRIX_COLUMNS, + OBJECT, + STRUCT, + INTERFACE_CLASS, + INTERFACE_POINTER + }; + class ConstantBufferVariable { public: @@ -32,6 +45,11 @@ namespace d3d11 unsigned m_offset; unsigned m_size; unsigned m_flags; + bool m_is_used; + VariableClass m_variable_class; + std::uint16_t m_element_count; + std::uint16_t m_row_count; + std::uint16_t m_column_count; }; enum class ConstantBufferType : std::uint8_t From 2d2912741b3be11bedf79a9de9c7128eb0424d7a Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 27 Feb 2026 21:21:08 +0100 Subject: [PATCH 06/27] fix: not properly initializing sub asset pools --- src/ObjLoading/Asset/AssetCreationContext.cpp | 10 +++++++++- src/ObjLoading/Asset/IZoneAssetCreationState.h | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/ObjLoading/Asset/AssetCreationContext.cpp b/src/ObjLoading/Asset/AssetCreationContext.cpp index f547d3e0..1e19f6ab 100644 --- a/src/ObjLoading/Asset/AssetCreationContext.cpp +++ b/src/ObjLoading/Asset/AssetCreationContext.cpp @@ -67,11 +67,15 @@ AssetCreationContext::AssetCreationContext(Zone& zone, const AssetCreatorCollect : ZoneAssetCreationStateContainer(zone), m_zone(zone), m_forced_asset_pools(std::make_unique(zone, zone.m_priority)), - m_sub_asset_pools(IGame::GetGameById(zone.m_game_id)->GetSubAssetTypeCount()), m_creators(creators), m_ignored_asset_lookup(ignoredAssetLookup), m_forced_load_depth(0u) { + const auto subAssetTypeCount = IGame::GetGameById(zone.m_game_id)->GetSubAssetTypeCount(); + m_sub_asset_pools.resize(subAssetTypeCount); + + for (asset_type_t subAssetType = 0; subAssetType < subAssetTypeCount; subAssetType++) + m_sub_asset_pools[subAssetType] = std::make_unique(); } XAssetInfoGeneric* AssetCreationContext::AddAssetGeneric(GenericAssetRegistration registration) const @@ -171,6 +175,10 @@ XAssetInfoGeneric* AssetCreationContext::LoadSubAssetGeneric(const asset_type_t con::error(R"(Could not load sub asset "{}" of type "{}")", assetName, *IGame::GetGameById(m_zone.m_game_id)->GetSubAssetTypeName(subAssetType)); } + else + { + con::error(R"(Missing sub asset "{}" of type "{}")", assetName, *IGame::GetGameById(m_zone.m_game_id)->GetSubAssetTypeName(subAssetType)); + } return nullptr; } diff --git a/src/ObjLoading/Asset/IZoneAssetCreationState.h b/src/ObjLoading/Asset/IZoneAssetCreationState.h index 5692f553..44e5d204 100644 --- a/src/ObjLoading/Asset/IZoneAssetCreationState.h +++ b/src/ObjLoading/Asset/IZoneAssetCreationState.h @@ -42,7 +42,7 @@ public: class ZoneAssetCreationStateContainer { public: - ZoneAssetCreationStateContainer(Zone& zone) + explicit ZoneAssetCreationStateContainer(Zone& zone) : m_injection(*this, zone) { } From e66030a5df33987cd61c7bec401a8693fcf004f9 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 27 Feb 2026 22:06:08 +0100 Subject: [PATCH 07/27] chore: improve game shader types --- src/Common/Game/T5/T5_Assets.h | 8 ++- src/Common/Game/T6/T6_Assets.h | 60 +++++++++++--------- src/Common/Techset/StateMap/StateMapLayout.h | 1 + 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/Common/Game/T5/T5_Assets.h b/src/Common/Game/T5/T5_Assets.h index 2d29e9c1..65e8e1f6 100644 --- a/src/Common/Game/T5/T5_Assets.h +++ b/src/Common/Game/T5/T5_Assets.h @@ -1448,8 +1448,8 @@ namespace T5 struct MaterialArgumentCodeConst { uint16_t index; - char firstRow; - char rowCount; + unsigned char firstRow; + unsigned char rowCount; }; union MaterialArgumentDef @@ -1465,11 +1465,15 @@ namespace T5 MTL_ARG_MATERIAL_VERTEX_CONST = 0x0, MTL_ARG_LITERAL_VERTEX_CONST = 0x1, MTL_ARG_MATERIAL_PIXEL_SAMPLER = 0x2, + MTL_ARG_CODE_PRIM_BEGIN = 0x3, + MTL_ARG_CODE_VERTEX_CONST = 0x3, MTL_ARG_CODE_PIXEL_SAMPLER = 0x4, MTL_ARG_CODE_PIXEL_CONST = 0x5, + MTL_ARG_CODE_PRIM_END = 0x6, + MTL_ARG_MATERIAL_PIXEL_CONST = 0x6, MTL_ARG_LITERAL_PIXEL_CONST = 0x7, diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 07838f09..4bab9c89 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -3001,6 +3001,15 @@ namespace T6 VERTEX_SHADER_MODEL_UNLIT, }; + enum CustomSamplers + { + CUSTOM_SAMPLER_REFLECTION_PROBE = 0, + CUSTOM_SAMPLER_LIGHTMAP_PRIMARY, + CUSTOM_SAMPLER_LIGHTMAP_SECONDARY, + + CUSTOM_SAMPLER_COUNT + }; + enum MaterialType : unsigned char { MTL_TYPE_DEFAULT = 0x0, @@ -3035,6 +3044,20 @@ namespace T6 MaterialShaderArgument* args; }; + enum TechniqueFlags + { + TECHNIQUE_FLAG_1 = 0x1, + TECHNIQUE_FLAG_2 = 0x2, + TECHNIQUE_FLAG_4 = 0x4, + TECHNIQUE_FLAG_8 = 0x8, + TECHNIQUE_FLAG_10 = 0x10, + TECHNIQUE_FLAG_20 = 0x20, + TECHNIQUE_FLAG_40 = 0x40, + TECHNIQUE_FLAG_80 = 0x80, + TECHNIQUE_FLAG_100 = 0x100, + TECHNIQUE_FLAG_200 = 0x200, + }; + struct MaterialTechnique { const char* name; @@ -3043,14 +3066,6 @@ namespace T6 MaterialPass passArray[1]; }; - /* struct __cppobj ID3D11View : ID3D11DeviceChild - { - };*/ - - /* struct __cppobj ID3D11ShaderResourceView : ID3D11View - { - };*/ - struct type_align32(4) GfxImageLoadDef { char levelCount; @@ -3719,14 +3734,6 @@ namespace T6 GfxImage* secondary; }; - /* struct __cppobj ID3D11Resource : ID3D11DeviceChild - { - };*/ - - /* struct __cppobj ID3D11Buffer : ID3D11Resource - { - };*/ - struct type_align(4) GfxLightGridEntry { uint16_t colorsIndex; @@ -5793,8 +5800,8 @@ namespace T6 struct MaterialStreamRouting { - char source; - char dest; + unsigned char source; + unsigned char dest; }; struct MaterialVertexStreamRouting @@ -5805,7 +5812,7 @@ namespace T6 struct MaterialVertexDeclaration { - char streamCount; + unsigned char streamCount; bool hasOptionalSource; bool isLoaded; MaterialVertexStreamRouting routing; @@ -6160,8 +6167,8 @@ namespace T6 struct MaterialArgumentCodeConst { uint16_t index; - char firstRow; - char rowCount; + unsigned char firstRow; + unsigned char rowCount; }; union MaterialArgumentDef @@ -6177,14 +6184,19 @@ namespace T6 MTL_ARG_MATERIAL_VERTEX_CONST = 0x0, MTL_ARG_LITERAL_VERTEX_CONST = 0x1, MTL_ARG_MATERIAL_PIXEL_SAMPLER = 0x2, + MTL_ARG_CODE_PRIM_BEGIN = 0x3, + MTL_ARG_CODE_VERTEX_CONST = 0x3, MTL_ARG_CODE_PIXEL_SAMPLER = 0x4, MTL_ARG_CODE_PIXEL_CONST = 0x5, + MTL_ARG_CODE_PRIM_END = 0x6, + MTL_ARG_MATERIAL_PIXEL_CONST = 0x6, MTL_ARG_LITERAL_PIXEL_CONST = 0x7, - MLT_ARG_COUNT = 0x8, + + MLT_ARG_COUNT, }; struct MaterialShaderArgument @@ -6895,10 +6907,6 @@ namespace T6 vec3_t halfLengths; }; - /* struct __cppobj ID3D11InputLayout : ID3D11DeviceChild - { - };*/ - struct GfxLightRegionAxis { vec3_t dir; diff --git a/src/Common/Techset/StateMap/StateMapLayout.h b/src/Common/Techset/StateMap/StateMapLayout.h index 9bcb6166..811f80de 100644 --- a/src/Common/Techset/StateMap/StateMapLayout.h +++ b/src/Common/Techset/StateMap/StateMapLayout.h @@ -1,4 +1,5 @@ #pragma once + #include #include #include From 3ef8cc72601dffda5e84b5bb5cc2c72620676767 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 27 Feb 2026 22:11:50 +0100 Subject: [PATCH 08/27] chore: add more details to common techset infos in t5,t6 --- .../Game/T5/Techset/TechsetConstantsT5.h | 27 +++++ .../Game/T6/Techset/TechsetConstantsT6.h | 74 ++++++++++++ src/ObjCommon/Techset/CommonTechnique.cpp | 106 +++++++++++++++++- src/ObjCommon/Techset/CommonTechnique.h | 89 ++++++++++++++- .../Game/T5/Techset/TechsetDumperT5.cpp | 9 +- .../Game/T6/Techset/TechsetDumperT6.cpp | 9 +- 6 files changed, 295 insertions(+), 19 deletions(-) diff --git a/src/ObjCommon/Game/T5/Techset/TechsetConstantsT5.h b/src/ObjCommon/Game/T5/Techset/TechsetConstantsT5.h index ecb0e7ec..8c89b218 100644 --- a/src/ObjCommon/Game/T5/Techset/TechsetConstantsT5.h +++ b/src/ObjCommon/Game/T5/Techset/TechsetConstantsT5.h @@ -277,6 +277,11 @@ namespace T5 }; static_assert(std::extent_v == STREAM_DST_COUNT); + static inline techset::CommonStreamRoutingInfos commonRoutingInfos(streamRoutingSources, + std::extent_v, + streamRoutingDestinations, + std::extent_v); + static techset::CommonCodeConstSourceInfo commonCodeConstSources[]{ { .value = CONST_SRC_CODE_LIGHT_POSITION, @@ -1734,6 +1739,28 @@ namespace T5 }, }; + // 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 == MLT_ARG_COUNT); + + static inline techset::CommonCodeSourceInfos commonCodeSourceInfos(commonCodeConstSources, + std::extent_v, + commonCodeSamplerSources, + std::extent_v, + nullptr, + 0, + commonArgumentTypes, + std::extent_v); + inline MaterialTypeInfo g_materialTypeInfo[]{ {"", "" }, {"m/", "m_" }, diff --git a/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h b/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h index 73569967..acdc4371 100644 --- a/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h +++ b/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h @@ -190,6 +190,11 @@ namespace T6 }; static_assert(std::extent_v == STREAM_DST_COUNT); + static inline techset::CommonStreamRoutingInfos commonRoutingInfos(streamRoutingSources, + std::extent_v, + streamRoutingDestinations, + std::extent_v); + static inline techset::CommonCodeConstSourceInfo commonCodeConstSources[]{ { .value = CONST_SRC_CODE_LIGHT_POSITION, @@ -214,6 +219,7 @@ namespace T6 .accessor = "lightSpotFactors", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .techFlags = TECHNIQUE_FLAG_10, }, { .value = CONST_SRC_CODE_LIGHT_ATTENUATION, @@ -544,6 +550,7 @@ namespace T6 .accessor = "particleCloudVelWorld", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_OBJECT, + .techFlags = TECHNIQUE_FLAG_100, }, { .value = CONST_SRC_CODE_DEPTH_FROM_CLIP, @@ -1324,192 +1331,224 @@ namespace T6 .accessor = "worldMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX, }, { .value = CONST_SRC_CODE_INVERSE_WORLD_MATRIX, .accessor = "inverseWorldMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX, }, { .value = CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX, .accessor = "transposeWorldMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_WORLD_MATRIX, }, { .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_MATRIX, .accessor = "inverseTransposeWorldMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_WORLD_MATRIX, }, { .value = CONST_SRC_CODE_VIEW_MATRIX, .accessor = "viewMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_VIEW_MATRIX, }, { .value = CONST_SRC_CODE_INVERSE_VIEW_MATRIX, .accessor = "inverseViewMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_MATRIX, }, { .value = CONST_SRC_CODE_TRANSPOSE_VIEW_MATRIX, .accessor = "transposeViewMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .transposedMatrix = CONST_SRC_CODE_VIEW_MATRIX, }, { .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_VIEW_MATRIX, .accessor = "inverseTransposeViewMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .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_WORLD_VIEW_MATRIX, .accessor = "worldViewMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX, }, { .value = CONST_SRC_CODE_INVERSE_WORLD_VIEW_MATRIX, .accessor = "inverseWorldViewMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX, }, { .value = CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_MATRIX, .accessor = "transposeWorldViewMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_WORLD_VIEW_MATRIX, }, { .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_MATRIX, .accessor = "inverseTransposeWorldViewMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_WORLD_VIEW_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_WORLD_VIEW_PROJECTION_MATRIX, .accessor = "worldViewProjectionMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX, }, { .value = CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX, .accessor = "inverseWorldViewProjectionMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX, }, { .value = CONST_SRC_CODE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX, .accessor = "transposeWorldViewProjectionMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_WORLD_VIEW_PROJECTION_MATRIX, }, { .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_WORLD_VIEW_PROJECTION_MATRIX, .accessor = "inverseTransposeWorldViewProjectionMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::PER_PRIM, + .transposedMatrix = CONST_SRC_CODE_INVERSE_WORLD_VIEW_PROJECTION_MATRIX, }, { .value = CONST_SRC_CODE_SHADOW_LOOKUP_MATRIX, .accessor = "shadowLookupMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .transposedMatrix = CONST_SRC_CODE_TRANSPOSE_SHADOW_LOOKUP_MATRIX, }, { .value = CONST_SRC_CODE_INVERSE_SHADOW_LOOKUP_MATRIX, .accessor = "inverseShadowLookupMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .transposedMatrix = CONST_SRC_CODE_INVERSE_TRANSPOSE_SHADOW_LOOKUP_MATRIX, }, { .value = CONST_SRC_CODE_TRANSPOSE_SHADOW_LOOKUP_MATRIX, .accessor = "transposeShadowLookupMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .transposedMatrix = CONST_SRC_CODE_SHADOW_LOOKUP_MATRIX, }, { .value = CONST_SRC_CODE_INVERSE_TRANSPOSE_SHADOW_LOOKUP_MATRIX, .accessor = "inverseTransposeShadowLookupMatrix", .arrayCount = 0, .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .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, }, }; @@ -1538,11 +1577,13 @@ namespace T6 .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, @@ -1563,11 +1604,13 @@ namespace T6 .value = TEXTURE_SRC_CODE_RESOLVED_POST_SUN, .accessor = "resolvedPostSun", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .techFlags = TECHNIQUE_FLAG_1, }, { .value = TEXTURE_SRC_CODE_RESOLVED_SCENE, .accessor = "resolvedScene", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .techFlags = TECHNIQUE_FLAG_2, }, { .value = TEXTURE_SRC_CODE_POST_EFFECT_SRC, @@ -1608,16 +1651,19 @@ namespace T6 .value = TEXTURE_SRC_CODE_FLOATZ, .accessor = "floatZSampler", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .techFlags = TECHNIQUE_FLAG_40, }, { .value = TEXTURE_SRC_CODE_PROCESSED_FLOATZ, .accessor = "processedFloatZSampler", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .techFlags = TECHNIQUE_FLAG_40, }, { .value = TEXTURE_SRC_CODE_RAW_FLOATZ, .accessor = "rawFloatZSampler", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY, + .techFlags = TECHNIQUE_FLAG_40, }, { .value = TEXTURE_SRC_CODE_STENCIL, @@ -1648,6 +1694,7 @@ namespace T6 .value = TEXTURE_SRC_CODE_REFLECTION_PROBE, .accessor = "reflectionProbeSampler", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::CUSTOM, + .customSamplerIndex = CUSTOM_SAMPLER_REFLECTION_PROBE, }, { .value = TEXTURE_SRC_CODE_FEATHER_FLOAT_Z, @@ -1791,6 +1838,33 @@ namespace T6 }, }; + // 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 == MLT_ARG_COUNT); + + static inline const char* commonIgnoredArgAccessors[]{ + "combined_dlight", + "combined_glight", + }; + + static inline techset::CommonCodeSourceInfos commonCodeSourceInfos(commonCodeConstSources, + std::extent_v, + commonCodeSamplerSources, + std::extent_v, + commonIgnoredArgAccessors, + std::extent_v, + commonArgumentTypes, + std::extent_v); + static inline MaterialTypeInfo g_materialTypeInfo[]{ {"", "" }, {"m/", "m_" }, diff --git a/src/ObjCommon/Techset/CommonTechnique.cpp b/src/ObjCommon/Techset/CommonTechnique.cpp index a28b2a9c..f0e9ae1b 100644 --- a/src/ObjCommon/Techset/CommonTechnique.cpp +++ b/src/ObjCommon/Techset/CommonTechnique.cpp @@ -1,15 +1,22 @@ #include "CommonTechnique.h" #include +#include namespace techset { CommonCodeSourceInfos::CommonCodeSourceInfos(const CommonCodeConstSourceInfo* codeConstSourceInfos, const size_t codeConstCount, const CommonCodeSamplerSourceInfo* codeSamplerSourceInfos, - const size_t codeSamplerCount) + const size_t codeSamplerCount, + const char** ignoreArgAccessors, + const size_t ignoredArgAccessorCount, + const CommonShaderArgumentType* argumentTypes, + const size_t argumentTypeCount) : m_code_const_source_infos(codeConstCount), - m_code_sampler_source_infos(codeSamplerCount) + m_code_sampler_source_infos(codeSamplerCount), + m_ignored_arg_accessors(ignoredArgAccessorCount), + m_argument_types(argumentTypeCount) { std::copy(codeConstSourceInfos, &codeConstSourceInfos[codeConstCount], m_code_const_source_infos.data()); std::ranges::sort(m_code_const_source_infos, @@ -24,6 +31,21 @@ namespace techset { return a.value < b.value; }); + + for (size_t i = 0; i < ignoredArgAccessorCount; i++) + m_ignored_arg_accessors.emplace(ignoreArgAccessors[i]); + + std::copy(argumentTypes, &argumentTypes[argumentTypeCount], m_argument_types.data()); + + for (const auto& codeConstInfo : m_code_const_source_infos) + { + m_code_const_lookup.emplace(codeConstInfo.accessor, codeConstInfo.value); + } + + for (const auto& codeSamplerInfo : m_code_sampler_source_infos) + { + m_code_sampler_lookup.emplace(codeSamplerInfo.accessor, codeSamplerInfo.value); + } } std::optional CommonCodeSourceInfos::GetInfoForCodeConstSource(const CommonCodeConstSource codeConstSource) const @@ -55,6 +77,38 @@ namespace techset return std::nullopt; } + bool CommonCodeSourceInfos::IsArgAccessorIgnored(const std::string& accessor) const + { + return m_ignored_arg_accessors.contains(accessor); + } + + std::optional CommonCodeSourceInfos::GetCodeConstSourceForAccessor(const std::string& accessor) const + { + const auto foundEntry = m_code_const_lookup.find(accessor); + if (foundEntry == m_code_const_lookup.end()) + return std::nullopt; + + return foundEntry->second; + } + + std::optional CommonCodeSourceInfos::GetCodeSamplerSourceForAccessor(const std::string& accessor) const + { + const auto foundEntry = m_code_sampler_lookup.find(accessor); + if (foundEntry == m_code_sampler_lookup.end()) + return std::nullopt; + + return foundEntry->second; + } + + std::optional CommonCodeSourceInfos::GetArgumentTypeNumericValue(const CommonShaderArgumentType& argumentType) const + { + const auto foundValue = std::ranges::find(m_argument_types, argumentType); + if (foundValue == m_argument_types.end()) + return std::nullopt; + + return static_cast(foundValue - m_argument_types.begin()); + } + CommonStreamRoutingInfos::CommonStreamRoutingInfos(const CommonStreamRoutingSourceInfo* sourceInfos, const size_t sourceCount, const CommonStreamRoutingDestinationInfo* destinationNames, @@ -64,6 +118,18 @@ namespace techset { std::copy(sourceInfos, &sourceInfos[sourceCount], m_sources.data()); std::copy(destinationNames, &destinationNames[destinationCount], m_destinations.data()); + + for (size_t i = 0; i < sourceCount; i++) + { + m_source_name_lookup[sourceInfos[i].name] = static_cast(i); + m_source_abbreviation_lookup[sourceInfos[i].abbreviation] = static_cast(i); + } + + for (size_t i = 0; i < destinationCount; i++) + { + m_destination_name_lookup[destinationNames[i].name] = static_cast(i); + m_destination_abbreviation_lookup[destinationNames[i].abbreviation] = static_cast(i); + } } const char* CommonStreamRoutingInfos::GetSourceName(const CommonStreamSource source) const @@ -105,4 +171,40 @@ namespace techset return m_destinations[destination].abbreviation; } + + std::optional CommonStreamRoutingInfos::GetSourceByName(const std::string& name) const + { + const auto foundSource = m_source_name_lookup.find(name); + if (foundSource != m_source_name_lookup.end()) + return foundSource->second; + + return std::nullopt; + } + + std::optional CommonStreamRoutingInfos::GetSourceByAbbreviation(const std::string& abbreviation) const + { + const auto foundSource = m_source_abbreviation_lookup.find(abbreviation); + if (foundSource != m_source_abbreviation_lookup.end()) + return foundSource->second; + + return std::nullopt; + } + + std::optional CommonStreamRoutingInfos::GetDestinationByName(const std::string& name) const + { + const auto foundDestination = m_destination_name_lookup.find(name); + if (foundDestination != m_destination_name_lookup.end()) + return foundDestination->second; + + return std::nullopt; + } + + std::optional CommonStreamRoutingInfos::GetDestinationByAbbreviation(const std::string& abbreviation) const + { + const auto foundDestination = m_destination_abbreviation_lookup.find(abbreviation); + if (foundDestination != m_destination_abbreviation_lookup.end()) + return foundDestination->second; + + return std::nullopt; + } } // namespace techset diff --git a/src/ObjCommon/Techset/CommonTechnique.h b/src/ObjCommon/Techset/CommonTechnique.h index 37dcfe3f..4ae50e10 100644 --- a/src/ObjCommon/Techset/CommonTechnique.h +++ b/src/ObjCommon/Techset/CommonTechnique.h @@ -4,6 +4,9 @@ #include #include #include +#include +#include +#include #include namespace techset @@ -27,12 +30,46 @@ namespace techset const char* abbreviation; }; + enum class CommonTechniqueShaderType : std::uint8_t + { + VERTEX, + PIXEL + }; + + enum class CommonShaderValueType : std::uint8_t + { + // Value is set to a float4 value in the pass + LITERAL_CONST, + // Value is set to a float4 value in the material + MATERIAL_CONST, + // Value is set to a float4 value calculated in code + CODE_CONST, + // Value is set to a sampler from the material + MATERIAL_SAMPLER, + // Value is set to a sampler generated in code + CODE_SAMPLER + }; + + constexpr bool IsConstValueType(const CommonShaderValueType valueType) + { + return valueType == CommonShaderValueType::LITERAL_CONST || valueType == CommonShaderValueType::MATERIAL_CONST + || valueType == CommonShaderValueType::CODE_CONST; + } + + constexpr bool IsSamplerValueType(const CommonShaderValueType valueType) + { + return valueType == CommonShaderValueType::MATERIAL_SAMPLER || valueType == CommonShaderValueType::CODE_SAMPLER; + } + enum class CommonCodeSourceUpdateFrequency : std::uint8_t { PER_PRIM, PER_OBJECT, RARELY, CUSTOM, + IGNORE, + + COUNT }; struct CommonCodeConstSourceInfo @@ -41,6 +78,8 @@ namespace techset const char* accessor; std::uint8_t arrayCount; CommonCodeSourceUpdateFrequency updateFrequency; + std::optional techFlags; + std::optional transposedMatrix; }; struct CommonCodeSamplerSourceInfo @@ -48,6 +87,24 @@ namespace techset CommonCodeSamplerSource value; const char* accessor; CommonCodeSourceUpdateFrequency updateFrequency; + std::optional techFlags; + std::optional customSamplerIndex; + }; + + struct CommonShaderArgumentType + { + friend bool operator==(const CommonShaderArgumentType& lhs, const CommonShaderArgumentType& rhs) + { + return lhs.m_shader_type == rhs.m_shader_type && lhs.m_value_type == rhs.m_value_type; + } + + friend bool operator!=(const CommonShaderArgumentType& lhs, const CommonShaderArgumentType& rhs) + { + return !(lhs == rhs); + } + + CommonTechniqueShaderType m_shader_type; + CommonShaderValueType m_value_type; }; class CommonCodeSourceInfos @@ -56,14 +113,36 @@ namespace techset CommonCodeSourceInfos(const CommonCodeConstSourceInfo* codeConstSourceInfos, size_t codeConstCount, const CommonCodeSamplerSourceInfo* codeSamplerSourceInfos, - size_t codeSamplerCount); + size_t codeSamplerCount, + const char** ignoreArgAccessors, + size_t ignoredArgAccessorCount, + const CommonShaderArgumentType* argumentTypes, + size_t argumentTypeCount); [[nodiscard]] std::optional GetInfoForCodeConstSource(CommonCodeConstSource codeConstSource) const; [[nodiscard]] std::optional GetInfoForCodeSamplerSource(CommonCodeSamplerSource codeSamplerSource) const; + /** + * \brief Some games like T6 do not create args for certain variables. This checks whether an accessor identifies one of these variables. + * \param accessor The accessor of the variable + * \return \c true if the accessor should be ignored + */ + [[nodiscard]] bool IsArgAccessorIgnored(const std::string& accessor) const; + + [[nodiscard]] std::optional GetCodeConstSourceForAccessor(const std::string& accessor) const; + [[nodiscard]] std::optional GetCodeSamplerSourceForAccessor(const std::string& accessor) const; + + [[nodiscard]] std::optional GetArgumentTypeNumericValue(const CommonShaderArgumentType& argumentType) const; + private: std::vector m_code_const_source_infos; std::vector m_code_sampler_source_infos; + std::unordered_set m_ignored_arg_accessors; + + std::unordered_map m_code_const_lookup; + std::unordered_map m_code_sampler_lookup; + + std::vector m_argument_types; }; class CommonStreamRoutingInfos @@ -79,10 +158,18 @@ namespace techset [[nodiscard]] bool IsSourceOptional(CommonStreamSource source) const; [[nodiscard]] const char* GetDestinationName(CommonStreamDestination destination) const; [[nodiscard]] const char* GetDestinationAbbreviation(CommonStreamDestination destination) const; + [[nodiscard]] std::optional GetSourceByName(const std::string& name) const; + [[nodiscard]] std::optional GetSourceByAbbreviation(const std::string& abbreviation) const; + [[nodiscard]] std::optional GetDestinationByName(const std::string& name) const; + [[nodiscard]] std::optional GetDestinationByAbbreviation(const std::string& abbreviation) const; private: std::vector m_sources; std::vector m_destinations; + std::unordered_map m_source_name_lookup; + std::unordered_map m_destination_name_lookup; + std::unordered_map m_source_abbreviation_lookup; + std::unordered_map m_destination_abbreviation_lookup; }; union CommonShaderArgValue diff --git a/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp b/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp index a68a8206..22a11b2a 100644 --- a/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp +++ b/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp @@ -270,13 +270,6 @@ namespace void DumpTechniques(AssetDumpingContext& context, const MaterialTechniqueSet& techset) { - static techset::CommonCodeSourceInfos codeSourceInfos(commonCodeConstSources, - std::extent_v, - commonCodeSamplerSources, - std::extent_v); - static techset::CommonStreamRoutingInfos routingInfos( - streamRoutingSources, std::extent_v, streamRoutingDestinations, std::extent_v); - auto* techniqueState = context.GetZoneAssetDumperState(); const auto* materialConstantState = context.GetZoneAssetDumperState(); for (const auto* technique : techset.techniques) @@ -285,7 +278,7 @@ namespace { const auto commonTechnique = ConvertToCommonTechnique(*technique); - techset::DumpCommonTechnique(context, commonTechnique, codeSourceInfos, routingInfos, *materialConstantState); + techset::DumpCommonTechnique(context, commonTechnique, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState); } } } diff --git a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp index 699dd34d..68eac6e3 100644 --- a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp +++ b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp @@ -281,13 +281,6 @@ namespace void DumpTechniques(AssetDumpingContext& context, const MaterialTechniqueSet& techset) { - static techset::CommonCodeSourceInfos codeSourceInfos(commonCodeConstSources, - std::extent_v, - commonCodeSamplerSources, - std::extent_v); - static techset::CommonStreamRoutingInfos routingInfos( - streamRoutingSources, std::extent_v, streamRoutingDestinations, std::extent_v); - auto* techniqueState = context.GetZoneAssetDumperState(); const auto* materialConstantState = context.GetZoneAssetDumperState(); for (const auto* technique : techset.techniques) @@ -296,7 +289,7 @@ namespace { const auto commonTechnique = ConvertToCommonTechnique(*technique); - techset::DumpCommonTechnique(context, commonTechnique, codeSourceInfos, routingInfos, *materialConstantState); + techset::DumpCommonTechnique(context, commonTechnique, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState); } } } From 9a527c16fae59de00ad4303927fdf082e2ce8254 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 27 Feb 2026 21:28:28 +0100 Subject: [PATCH 09/27] feat: add t6 vertexdecl sub asset creator --- src/Common/Game/IW3/GameIW3.cpp | 1 + src/Common/Game/IW3/IW3.h | 1 + src/Common/Game/T5/GameT5.cpp | 1 + src/Common/Game/T5/T5.h | 1 + src/Common/Game/T6/GameT6.cpp | 1 + src/Common/Game/T6/T6.h | 6 +- src/ObjCommon/Techset/CommonTechnique.cpp | 14 ++++ src/ObjCommon/Techset/CommonTechnique.h | 5 ++ .../Techset/CommonVertexDeclCreator.cpp | 67 +++++++++++++++++++ .../Techset/CommonVertexDeclCreator.h | 11 +++ src/ObjCompiling/Game/T6/ObjCompilerT6.cpp | 3 + .../Game/T6/Techset/VertexDeclCompilerT6.cpp | 57 ++++++++++++++++ .../Game/T6/Techset/VertexDeclCompilerT6.h | 11 +++ .../Game/T5/Techset/TechsetDumperT5.cpp | 4 +- .../Game/T6/Techset/TechsetDumperT6.cpp | 4 +- 15 files changed, 179 insertions(+), 8 deletions(-) create mode 100644 src/ObjCommon/Techset/CommonVertexDeclCreator.cpp create mode 100644 src/ObjCommon/Techset/CommonVertexDeclCreator.h create mode 100644 src/ObjCompiling/Game/T6/Techset/VertexDeclCompilerT6.cpp create mode 100644 src/ObjCompiling/Game/T6/Techset/VertexDeclCompilerT6.h diff --git a/src/Common/Game/IW3/GameIW3.cpp b/src/Common/Game/IW3/GameIW3.cpp index 17771f20..b14dda08 100644 --- a/src/Common/Game/IW3/GameIW3.cpp +++ b/src/Common/Game/IW3/GameIW3.cpp @@ -18,6 +18,7 @@ namespace constexpr const char* SUB_ASSET_TYPE_NAMES[]{ "technique", + "vertexdecl", "vertexshader", "pixelshader", }; diff --git a/src/Common/Game/IW3/IW3.h b/src/Common/Game/IW3/IW3.h index ee7d6856..bfc5c489 100644 --- a/src/Common/Game/IW3/IW3.h +++ b/src/Common/Game/IW3/IW3.h @@ -53,6 +53,7 @@ namespace IW3 enum SubAssetType { SUB_ASSET_TYPE_TECHNIQUE, + SUB_ASSET_TYPE_VERTEX_DECL, SUB_ASSET_TYPE_VERTEX_SHADER, SUB_ASSET_TYPE_PIXEL_SHADER, diff --git a/src/Common/Game/T5/GameT5.cpp b/src/Common/Game/T5/GameT5.cpp index a385bac4..c54e40a4 100644 --- a/src/Common/Game/T5/GameT5.cpp +++ b/src/Common/Game/T5/GameT5.cpp @@ -21,6 +21,7 @@ namespace constexpr const char* SUB_ASSET_TYPE_NAMES[]{ "technique", + "vertexdecl", "vertexshader", "pixelshader", }; diff --git a/src/Common/Game/T5/T5.h b/src/Common/Game/T5/T5.h index 1989889b..962a87ad 100644 --- a/src/Common/Game/T5/T5.h +++ b/src/Common/Game/T5/T5.h @@ -63,6 +63,7 @@ namespace T5 enum SubAssetType { SUB_ASSET_TYPE_TECHNIQUE, + SUB_ASSET_TYPE_VERTEX_DECL, SUB_ASSET_TYPE_VERTEX_SHADER, SUB_ASSET_TYPE_PIXEL_SHADER, diff --git a/src/Common/Game/T6/GameT6.cpp b/src/Common/Game/T6/GameT6.cpp index cbb96687..1a4b6435 100644 --- a/src/Common/Game/T6/GameT6.cpp +++ b/src/Common/Game/T6/GameT6.cpp @@ -74,6 +74,7 @@ namespace constexpr const char* SUB_ASSET_TYPE_NAMES[]{ "technique", + "vertexdecl", "vertexshader", "pixelshader", }; diff --git a/src/Common/Game/T6/T6.h b/src/Common/Game/T6/T6.h index f3b052f1..47bd2ad7 100644 --- a/src/Common/Game/T6/T6.h +++ b/src/Common/Game/T6/T6.h @@ -83,6 +83,7 @@ namespace T6 enum SubAssetType { SUB_ASSET_TYPE_TECHNIQUE, + SUB_ASSET_TYPE_VERTEX_DECL, SUB_ASSET_TYPE_VERTEX_SHADER, SUB_ASSET_TYPE_PIXEL_SHADER, @@ -288,8 +289,9 @@ namespace T6 using AssetZBarrier = Asset; using SubAssetTechnique = SubAsset; - using SubAssetVertexShader = SubAsset; - using SubAssetPixelShader = SubAsset; + using SubAssetVertexDecl = SubAsset; + using SubAssetVertexShader = SubAsset; + using SubAssetPixelShader = SubAsset; } // namespace T6 DEFINE_ASSET_NAME_ACCESSOR(T6::AssetPhysPreset, name); diff --git a/src/ObjCommon/Techset/CommonTechnique.cpp b/src/ObjCommon/Techset/CommonTechnique.cpp index f0e9ae1b..d06c3f91 100644 --- a/src/ObjCommon/Techset/CommonTechnique.cpp +++ b/src/ObjCommon/Techset/CommonTechnique.cpp @@ -207,4 +207,18 @@ namespace techset return std::nullopt; } + + CommonVertexDeclaration::CommonVertexDeclaration(std::vector routing) + : m_routing(std::move(routing)) + { + } + + void CommonVertexDeclaration::SortRoutingEntries() + { + std::ranges::sort(m_routing, + [](const CommonStreamRouting& r1, const CommonStreamRouting& r2) + { + return r1.m_source < r2.m_source; + }); + } } // namespace techset diff --git a/src/ObjCommon/Techset/CommonTechnique.h b/src/ObjCommon/Techset/CommonTechnique.h index 4ae50e10..09cc2bef 100644 --- a/src/ObjCommon/Techset/CommonTechnique.h +++ b/src/ObjCommon/Techset/CommonTechnique.h @@ -234,6 +234,11 @@ namespace techset class CommonVertexDeclaration { public: + CommonVertexDeclaration() = default; + explicit CommonVertexDeclaration(std::vector routing); + + void SortRoutingEntries(); + std::vector m_routing; }; diff --git a/src/ObjCommon/Techset/CommonVertexDeclCreator.cpp b/src/ObjCommon/Techset/CommonVertexDeclCreator.cpp new file mode 100644 index 00000000..959a5875 --- /dev/null +++ b/src/ObjCommon/Techset/CommonVertexDeclCreator.cpp @@ -0,0 +1,67 @@ +#include "CommonVertexDeclCreator.h" + +#include "Utils/Logging/Log.h" + +#include + +namespace +{ + bool NextAbbreviation(const std::string& assetName, std::string& abbreviation, size_t& offset) + { + if (offset >= assetName.size()) + return false; + + if (offset + 1 < assetName.size() && isdigit(assetName[offset + 1])) + { + abbreviation = std::string(assetName, offset, 2); + offset += 2; + } + else + { + abbreviation = std::string(assetName, offset, 1); + offset += 1; + } + + return true; + } +} // namespace + +namespace techset +{ + std::optional CreateVertexDeclFromName(const std::string& name, const CommonStreamRoutingInfos& routingInfos) + { + CommonVertexDeclaration result; + 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; + } + + const auto maybeDestination = routingInfos.GetDestinationByAbbreviation(destinationAbbreviation); + if (!maybeDestination) + { + con::error("Unknown vertex decl destination abbreviation: {}", destinationAbbreviation); + return std::nullopt; + } + + result.m_routing.emplace_back(*maybeSource, *maybeDestination); + } + + result.SortRoutingEntries(); + + return result; + } +} // namespace techset diff --git a/src/ObjCommon/Techset/CommonVertexDeclCreator.h b/src/ObjCommon/Techset/CommonVertexDeclCreator.h new file mode 100644 index 00000000..a3e99b56 --- /dev/null +++ b/src/ObjCommon/Techset/CommonVertexDeclCreator.h @@ -0,0 +1,11 @@ +#pragma once + +#include "CommonTechnique.h" + +#include +#include + +namespace techset +{ + std::optional CreateVertexDeclFromName(const std::string& name, const CommonStreamRoutingInfos& routingInfos); +} diff --git a/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp b/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp index d9681a32..5e1412e1 100644 --- a/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp +++ b/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp @@ -5,6 +5,7 @@ #include "Image/ImageIwdPostProcessor.h" #include "KeyValuePairs/KeyValuePairsCompilerT6.h" #include "Techset/TechsetCompilerT6.h" +#include "Techset/VertexDeclCompilerT6.h" #include @@ -22,6 +23,8 @@ namespace collection.AddAssetCreator(key_value_pairs::CreateCompilerT6(memory, zone, zoneDefinition.m_zone_definition, zoneStates)); collection.AddAssetCreator(techset::CreateCompilerT6(memory, searchPath)); + + collection.AddSubAssetCreator(techset::CreateVertexDeclCompilerT6(memory)); } void ConfigurePostProcessors(AssetCreatorCollection& collection, diff --git a/src/ObjCompiling/Game/T6/Techset/VertexDeclCompilerT6.cpp b/src/ObjCompiling/Game/T6/Techset/VertexDeclCompilerT6.cpp new file mode 100644 index 00000000..b01f2607 --- /dev/null +++ b/src/ObjCompiling/Game/T6/Techset/VertexDeclCompilerT6.cpp @@ -0,0 +1,57 @@ +#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 new file mode 100644 index 00000000..434e602f --- /dev/null +++ b/src/ObjCompiling/Game/T6/Techset/VertexDeclCompilerT6.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Utils/MemoryManager.h" + +#include + +namespace techset +{ + std::unique_ptr CreateVertexDeclCompilerT6(MemoryManager& memory); +} diff --git a/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp b/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp index 22a11b2a..3b05e895 100644 --- a/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp +++ b/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp @@ -74,9 +74,7 @@ namespace } } - return techset::CommonVertexDeclaration{ - .m_routing = std::move(commonRouting), - }; + return techset::CommonVertexDeclaration(std::move(commonRouting)); } techset::CommonShaderArg ConvertToCommonArg(const MaterialShaderArgument& arg) diff --git a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp index 68eac6e3..035ada88 100644 --- a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp +++ b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp @@ -73,9 +73,7 @@ namespace } } - return techset::CommonVertexDeclaration{ - .m_routing = std::move(commonRouting), - }; + return techset::CommonVertexDeclaration(std::move(commonRouting)); } techset::CommonShaderArg ConvertToCommonArg(const MaterialShaderArgument& arg) From 86ae57578bea4416317d741c0c7b820d1bf4fe0b Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 27 Feb 2026 21:40:35 +0100 Subject: [PATCH 10/27] feat: add t6 sub asset loaders for shaders --- src/ObjLoading/Game/T6/ObjLoaderT6.cpp | 5 ++ .../Game/T6/Techset/PixelShaderLoaderT6.cpp | 55 +++++++++++++++++++ .../Game/T6/Techset/PixelShaderLoaderT6.h | 13 +++++ .../Game/T6/Techset/VertexShaderLoaderT6.cpp | 55 +++++++++++++++++++ .../Game/T6/Techset/VertexShaderLoaderT6.h | 13 +++++ 5 files changed, 141 insertions(+) create mode 100644 src/ObjLoading/Game/T6/Techset/PixelShaderLoaderT6.cpp create mode 100644 src/ObjLoading/Game/T6/Techset/PixelShaderLoaderT6.h create mode 100644 src/ObjLoading/Game/T6/Techset/VertexShaderLoaderT6.cpp create mode 100644 src/ObjLoading/Game/T6/Techset/VertexShaderLoaderT6.h diff --git a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp index 5642bf4a..7f5fbc09 100644 --- a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp +++ b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp @@ -29,6 +29,8 @@ #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" @@ -434,6 +436,9 @@ namespace T6 // collection.AddAssetCreator(std::make_unique(memory)); collection.AddAssetCreator(z_barrier::CreateRawLoaderT6(memory, searchPath, zone)); collection.AddAssetCreator(z_barrier::CreateGdtLoaderT6(memory, searchPath, gdt, zone)); + + collection.AddSubAssetCreator(techset::CreateVertexShaderLoaderT6(memory, searchPath)); + collection.AddSubAssetCreator(techset::CreatePixelShaderLoaderT6(memory, searchPath)); } } // namespace diff --git a/src/ObjLoading/Game/T6/Techset/PixelShaderLoaderT6.cpp b/src/ObjLoading/Game/T6/Techset/PixelShaderLoaderT6.cpp new file mode 100644 index 00000000..acd67d55 --- /dev/null +++ b/src/ObjLoading/Game/T6/Techset/PixelShaderLoaderT6.cpp @@ -0,0 +1,55 @@ +#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 new file mode 100644 index 00000000..199960cf --- /dev/null +++ b/src/ObjLoading/Game/T6/Techset/PixelShaderLoaderT6.h @@ -0,0 +1,13 @@ +#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 new file mode 100644 index 00000000..8dd2fa06 --- /dev/null +++ b/src/ObjLoading/Game/T6/Techset/VertexShaderLoaderT6.cpp @@ -0,0 +1,55 @@ +#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 new file mode 100644 index 00000000..d0ae6c76 --- /dev/null +++ b/src/ObjLoading/Game/T6/Techset/VertexShaderLoaderT6.h @@ -0,0 +1,13 @@ +#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 From 38abe459e177ff5f745fde67b5dcd0d2eb82dba8 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 27 Feb 2026 23:04:42 +0100 Subject: [PATCH 11/27] fix: errors with common techset dumping * not respecting transposing matrices * not respecting arrays --- src/ObjCommon/Techset/CommonTechnique.cpp | 90 ++++++ src/ObjCommon/Techset/CommonTechnique.h | 116 +++++--- .../Game/T5/Techset/TechsetDumperT5.cpp | 194 +++++-------- .../Game/T6/Techset/TechsetDumperT6.cpp | 256 ++++++++---------- .../Techset/CommonTechniqueDumper.cpp | 180 +++++++----- .../Techset/CommonTechniqueDumper.h | 1 + 6 files changed, 470 insertions(+), 367 deletions(-) diff --git a/src/ObjCommon/Techset/CommonTechnique.cpp b/src/ObjCommon/Techset/CommonTechnique.cpp index d06c3f91..f719d37d 100644 --- a/src/ObjCommon/Techset/CommonTechnique.cpp +++ b/src/ObjCommon/Techset/CommonTechnique.cpp @@ -208,6 +208,48 @@ namespace techset return std::nullopt; } + CommonShaderArg::CommonShaderArg(const CommonShaderArgumentType type, const CommonShaderArgDestination& destination, const CommonShaderArgValue& value) + : m_type(type), + m_destination(destination), + m_value(value) + { + } + + CommonCodeSourceUpdateFrequency CommonShaderArg::GetFrequency(const CommonCodeSourceInfos& infos) const + { + switch (m_type.m_value_type) + { + case CommonShaderValueType::CODE_CONST: + { + const auto info = infos.GetInfoForCodeConstSource(m_value.code_const_source.m_index); + assert(info); + return info->updateFrequency; + } + + case CommonShaderValueType::CODE_SAMPLER: + { + const auto info = infos.GetInfoForCodeSamplerSource(m_value.code_sampler_source); + assert(info); + return info->updateFrequency; + } + + case CommonShaderValueType::MATERIAL_CONST: + case CommonShaderValueType::LITERAL_CONST: + case CommonShaderValueType::MATERIAL_SAMPLER: + return CommonCodeSourceUpdateFrequency::RARELY; + + default: + assert(false); + return CommonCodeSourceUpdateFrequency::RARELY; + } + } + + CommonStreamRouting::CommonStreamRouting(const CommonStreamSource source, const CommonStreamDestination destination) + : m_source(source), + m_destination(destination) + { + } + CommonVertexDeclaration::CommonVertexDeclaration(std::vector routing) : m_routing(std::move(routing)) { @@ -221,4 +263,52 @@ namespace techset return r1.m_source < r2.m_source; }); } + + CommonTechniqueShader::CommonTechniqueShader() + : m_type(CommonTechniqueShaderType::VERTEX) + { + } + + CommonTechniqueShader::CommonTechniqueShader(const CommonTechniqueShaderType type, std::string name) + : m_type(type), + m_name(std::move(name)) + { + } + + CommonPass::CommonPass(const uint32_t samplerFlags, + std::string stateMap, + CommonTechniqueShader vertexShader, + CommonTechniqueShader pixelShader, + CommonVertexDeclaration vertexDeclaration) + : m_sampler_flags(samplerFlags), + m_state_map(std::move(stateMap)), + m_vertex_shader(std::move(vertexShader)), + m_pixel_shader(std::move(pixelShader)), + m_vertex_declaration(std::move(vertexDeclaration)) + { + } + + CommonPass::FrequencyCounts_t CommonPass::GetFrequencyCounts(const CommonCodeSourceInfos& infos) const + { + FrequencyCounts_t result; + for (auto& count : result) + count = 0; + + for (auto& arg : m_args) + result[std::to_underlying(arg.GetFrequency(infos))]++; + + return result; + } + + CommonTechnique::CommonTechnique(std::string name) + : m_name(std::move(name)), + m_flags(0) + { + } + + CommonTechnique::CommonTechnique(std::string name, const uint64_t flags) + : m_name(std::move(name)), + m_flags(flags) + { + } } // namespace techset diff --git a/src/ObjCommon/Techset/CommonTechnique.h b/src/ObjCommon/Techset/CommonTechnique.h index 09cc2bef..ab8950d6 100644 --- a/src/ObjCommon/Techset/CommonTechnique.h +++ b/src/ObjCommon/Techset/CommonTechnique.h @@ -172,10 +172,17 @@ namespace techset std::unordered_map m_destination_abbreviation_lookup; }; + struct CommonShaderArgCodeConstValue + { + CommonCodeConstSource m_index; + unsigned m_first_row; + unsigned m_row_count; + }; + union CommonShaderArgValue { std::array literal_value; - CommonCodeConstSource code_const_source; + CommonShaderArgCodeConstValue code_const_source; CommonCodeSamplerSource code_sampler_source; unsigned name_hash; }; @@ -186,12 +193,23 @@ namespace techset unsigned m_destination_register; }; + // In case of a constant: Offset in constant buffer + // In case of a sampler: Index of sampler + index of texture + union CommonShaderArgLocationDx11 + { + unsigned constant_buffer_offset; + + struct + { + unsigned texture_index; + unsigned sampler_index; + }; + }; + class CommonShaderArgDestinationDx11 { public: - // In case of a constant: Offset in constant buffer - // In case of a sampler: Index of sampler - unsigned m_location; + CommonShaderArgLocationDx11 m_location; unsigned m_size; unsigned m_buffer; }; @@ -202,31 +220,26 @@ namespace techset CommonShaderArgDestinationDx11 dx11; }; - enum class CommonShaderArgType : std::uint8_t - { - // Value is set to a float4 value in the pass - LITERAL_CONST, - // Value is set to a float4 value in the material - MATERIAL_CONST, - // Value is set to a float4 value calculated in code - CODE_CONST, - // Value is set to a sampler from the material - MATERIAL_SAMPLER, - // Value is set to a sampler generated in code - CODE_SAMPLER - }; - class CommonShaderArg { public: - CommonShaderArgType m_type; + CommonShaderArg() = default; + CommonShaderArg(CommonShaderArgumentType type, const CommonShaderArgDestination& destination, const CommonShaderArgValue& value); + + [[nodiscard]] CommonCodeSourceUpdateFrequency GetFrequency(const CommonCodeSourceInfos& infos) const; + + CommonShaderArgumentType m_type; CommonShaderArgDestination m_destination; CommonShaderArgValue m_value; + std::optional m_bin; }; class CommonStreamRouting { public: + CommonStreamRouting() = default; + CommonStreamRouting(CommonStreamSource source, CommonStreamDestination destination); + CommonStreamSource m_source; CommonStreamDestination m_destination; }; @@ -242,36 +255,61 @@ namespace techset std::vector m_routing; }; + class CommonTechniqueShaderBin + { + public: + const void* m_shader_bin; + size_t m_shader_bin_size; + }; + class CommonTechniqueShader { public: + CommonTechniqueShader(); + CommonTechniqueShader(CommonTechniqueShaderType type, std::string name); + + CommonTechniqueShaderType m_type; std::string m_name; - const void* m_shader_bin; - size_t m_shader_bin_size; + std::optional m_bin; + }; + + class CommonPass + { + public: + using FrequencyCounts_t = std::array; + + CommonPass() = default; + CommonPass(uint32_t samplerFlags, + std::string stateMap, + CommonTechniqueShader vertexShader, + CommonTechniqueShader pixelShader, + CommonVertexDeclaration vertexDeclaration); + + [[nodiscard]] FrequencyCounts_t GetFrequencyCounts(const CommonCodeSourceInfos& infos) const; + + uint32_t m_sampler_flags; + std::string m_state_map; + CommonTechniqueShader m_vertex_shader; + CommonTechniqueShader m_pixel_shader; + CommonVertexDeclaration m_vertex_declaration; std::vector m_args; }; + class CommonTechnique + { + public: + CommonTechnique() = default; + explicit CommonTechnique(std::string name); + CommonTechnique(std::string name, uint64_t flags); + + std::string m_name; + uint64_t m_flags; + std::vector m_passes; + }; + enum class DxVersion : std::uint8_t { DX9, DX11 }; - - class CommonPass - { - public: - uint32_t m_sampler_flags; - DxVersion m_dx_version; - CommonTechniqueShader m_vertex_shader; - CommonTechniqueShader m_pixel_shader; - CommonVertexDeclaration m_vertex_declaration; - }; - - class CommonTechnique - { - public: - std::string m_name; - uint64_t m_flags; - std::vector m_passes; - }; } // namespace techset diff --git a/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp b/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp index 3b05e895..30dcaf02 100644 --- a/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp +++ b/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp @@ -9,7 +9,6 @@ #include "Techset/TechniqueDumpingZoneState.h" #include -#include using namespace T5; @@ -67,10 +66,8 @@ namespace for (auto streamIndex = 0u; streamIndex < streamCount; streamIndex++) { const auto& routing = vertexDecl->routing.data[streamIndex]; - commonRouting.emplace_back(techset::CommonStreamRouting{ - .m_source = static_cast(routing.source), - .m_destination = static_cast(routing.dest), - }); + commonRouting.emplace_back(static_cast(routing.source), + static_cast(routing.dest)); } } @@ -79,92 +76,72 @@ namespace techset::CommonShaderArg ConvertToCommonArg(const MaterialShaderArgument& arg) { + const techset::CommonShaderArgDestination destination{.dx9 = {.m_destination_register = arg.dest}}; + switch (arg.type) { case MTL_ARG_CODE_VERTEX_CONST: case MTL_ARG_CODE_PIXEL_CONST: - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::CODE_CONST, - .m_destination = {.dx9 = - { - .m_destination_register = arg.dest, - }}, - .m_value = { - .code_const_source = static_cast(arg.u.codeConst.index), - } + { + const techset::CommonShaderArgCodeConstValue codeConstValue{ + .m_index = static_cast(arg.u.codeConst.index), + .m_first_row = arg.u.codeConst.firstRow, + .m_row_count = arg.u.codeConst.rowCount, }; + const techset::CommonShaderArgValue value{.code_const_source = codeConstValue}; + + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } case MTL_ARG_MATERIAL_VERTEX_CONST: case MTL_ARG_MATERIAL_PIXEL_CONST: - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::MATERIAL_CONST, - .m_destination = {.dx9 = - { - .m_destination_register = arg.dest, - }}, - .m_value = { - .name_hash = arg.u.nameHash, - } + { + const techset::CommonShaderArgValue value{ + .name_hash = arg.u.nameHash, }; + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } + case MTL_ARG_CODE_PIXEL_SAMPLER: - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::CODE_SAMPLER, - .m_destination = {.dx9 = - { - .m_destination_register = arg.dest, - }}, - .m_value = { - .code_sampler_source = static_cast(arg.u.codeSampler), - } + { + const techset::CommonShaderArgValue value{ + .code_sampler_source = static_cast(arg.u.codeSampler), }; + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } + case MTL_ARG_MATERIAL_PIXEL_SAMPLER: - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::MATERIAL_SAMPLER, - .m_destination = {.dx9 = - { - .m_destination_register = arg.dest, - }}, - .m_value = { - .name_hash = arg.u.nameHash, - } + { + const techset::CommonShaderArgValue value{ + .name_hash = arg.u.nameHash, }; + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } + default: case MTL_ARG_LITERAL_VERTEX_CONST: case MTL_ARG_LITERAL_PIXEL_CONST: + { + techset::CommonShaderArgValue value{}; if (arg.u.literalConst) { - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::LITERAL_CONST, - .m_destination = {.dx9 = - { - .m_destination_register = arg.dest, - }}, - .m_value = { - .literal_value = - { - (*arg.u.literalConst)[0], - (*arg.u.literalConst)[1], - (*arg.u.literalConst)[2], - (*arg.u.literalConst)[3], - }, } + value.literal_value = { + (*arg.u.literalConst)[0], + (*arg.u.literalConst)[1], + (*arg.u.literalConst)[2], + (*arg.u.literalConst)[3], }; } - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::LITERAL_CONST, - .m_destination = {.dx9 = - { - .m_destination_register = arg.dest, - }}, - .m_value = {}, - }; + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } } } - techset::CommonTechniqueShader ConvertToCommonShader(const MaterialPass& pass, const MaterialVertexShader* vertexShader) + techset::CommonTechniqueShader ConvertToCommonShader(const MaterialVertexShader* vertexShader) { techset::CommonTechniqueShader result{}; if (!vertexShader) @@ -175,34 +152,16 @@ namespace if (vertexShader->prog.loadDef.program) { - result.m_shader_bin = vertexShader->prog.loadDef.program; - result.m_shader_bin_size = vertexShader->prog.loadDef.programSize * sizeof(uint32_t); - } - - if (pass.args) - { - const size_t totalArgCount = pass.perPrimArgCount + pass.perObjArgCount + pass.stableArgCount; - for (auto argIndex = 0uz; argIndex < totalArgCount; argIndex++) - { - const auto& arg = pass.args[argIndex]; - - switch (arg.type) - { - case MTL_ARG_CODE_VERTEX_CONST: - case MTL_ARG_MATERIAL_VERTEX_CONST: - case MTL_ARG_LITERAL_VERTEX_CONST: - result.m_args.emplace_back(ConvertToCommonArg(arg)); - break; - default: - break; - } - } + result.m_bin = techset::CommonTechniqueShaderBin{ + .m_shader_bin = vertexShader->prog.loadDef.program, + .m_shader_bin_size = vertexShader->prog.loadDef.programSize * sizeof(uint32_t), + }; } return result; } - techset::CommonTechniqueShader ConvertToCommonShader(const MaterialPass& pass, const MaterialPixelShader* pixelShader) + techset::CommonTechniqueShader ConvertToCommonShader(const MaterialPixelShader* pixelShader) { techset::CommonTechniqueShader result{}; if (!pixelShader) @@ -213,30 +172,10 @@ namespace if (pixelShader->prog.loadDef.program) { - result.m_shader_bin = pixelShader->prog.loadDef.program; - result.m_shader_bin_size = pixelShader->prog.loadDef.programSize * sizeof(uint32_t); - } - - if (pass.args) - { - const size_t totalArgCount = pass.perPrimArgCount + pass.perObjArgCount + pass.stableArgCount; - for (auto argIndex = 0uz; argIndex < totalArgCount; argIndex++) - { - const auto& arg = pass.args[argIndex]; - - switch (arg.type) - { - case MTL_ARG_CODE_PIXEL_CONST: - case MTL_ARG_CODE_PIXEL_SAMPLER: - case MTL_ARG_MATERIAL_PIXEL_CONST: - case MTL_ARG_MATERIAL_PIXEL_SAMPLER: - case MTL_ARG_LITERAL_PIXEL_CONST: - result.m_args.emplace_back(ConvertToCommonArg(arg)); - break; - default: - break; - } - } + result.m_bin = techset::CommonTechniqueShaderBin{ + .m_shader_bin = pixelShader->prog.loadDef.program, + .m_shader_bin_size = pixelShader->prog.loadDef.programSize * sizeof(uint32_t), + }; } return result; @@ -244,26 +183,30 @@ namespace techset::CommonTechnique ConvertToCommonTechnique(const MaterialTechnique& technique) { - std::vector passes; + techset::CommonTechnique commonTechnique(technique.name ? technique.name : std::string(), technique.flags); for (auto passIndex = 0u; passIndex < technique.passCount; passIndex++) { const auto& pass = technique.passArray[passIndex]; + techset::CommonPass commonPass(pass.customSamplerFlags, + // No clue what the actual state map was + "passthrough", + ConvertToCommonShader(pass.vertexShader), + ConvertToCommonShader(pass.pixelShader), + ConvertToCommonVertexDeclaration(pass.vertexDecl)); - passes.emplace_back(techset::CommonPass{ - .m_sampler_flags = pass.customSamplerFlags, - .m_dx_version = techset::DxVersion::DX9, - .m_vertex_shader = ConvertToCommonShader(pass, pass.vertexShader), - .m_pixel_shader = ConvertToCommonShader(pass, pass.pixelShader), - .m_vertex_declaration = ConvertToCommonVertexDeclaration(pass.vertexDecl), - }); + if (pass.args) + { + const size_t totalArgCount = pass.perPrimArgCount + pass.perObjArgCount + pass.stableArgCount; + commonPass.m_args.reserve(totalArgCount); + for (auto argIndex = 0uz; argIndex < totalArgCount; argIndex++) + commonPass.m_args.emplace_back(ConvertToCommonArg(pass.args[argIndex])); + } + + commonTechnique.m_passes.emplace_back(std::move(commonPass)); } - return techset::CommonTechnique{ - .m_name = technique.name ? technique.name : std::string(), - .m_flags = technique.flags, - .m_passes = std::move(passes), - }; + return commonTechnique; } void DumpTechniques(AssetDumpingContext& context, const MaterialTechniqueSet& techset) @@ -276,7 +219,8 @@ namespace { const auto commonTechnique = ConvertToCommonTechnique(*technique); - techset::DumpCommonTechnique(context, commonTechnique, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState); + techset::DumpCommonTechnique( + context, commonTechnique, techset::DxVersion::DX9, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState); } } } diff --git a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp index 035ada88..e696658e 100644 --- a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp +++ b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp @@ -8,7 +8,7 @@ #include "Techset/ShaderDumpingZoneState.h" #include "Techset/TechniqueDumpingZoneState.h" -#include +#include using namespace T6; @@ -66,10 +66,8 @@ namespace for (auto streamIndex = 0u; streamIndex < streamCount; streamIndex++) { const auto& routing = vertexDecl->routing.data[streamIndex]; - commonRouting.emplace_back(techset::CommonStreamRouting{ - .m_source = static_cast(routing.source), - .m_destination = static_cast(routing.dest), - }); + commonRouting.emplace_back(static_cast(routing.source), + static_cast(routing.dest)); } } @@ -82,100 +80,119 @@ namespace { case MTL_ARG_CODE_VERTEX_CONST: case MTL_ARG_CODE_PIXEL_CONST: - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::CODE_CONST, - .m_destination = {.dx11 = - { - .m_location = arg.location.offset, - .m_size = arg.size, - .m_buffer = arg.buffer, - }}, - .m_value = { - .code_const_source = static_cast(arg.u.codeConst.index), - } + { + const techset::CommonShaderArgCodeConstValue codeConstValue{ + .m_index = static_cast(arg.u.codeConst.index), + .m_first_row = arg.u.codeConst.firstRow, + .m_row_count = arg.u.codeConst.rowCount, }; + const techset::CommonShaderArgValue value{.code_const_source = codeConstValue}; + const techset::CommonShaderArgLocationDx11 location{ + .constant_buffer_offset = arg.location.offset, + }; + const techset::CommonShaderArgDestination destination = { + .dx11 = { + .m_location = location, + .m_size = arg.size, + .m_buffer = arg.buffer, + } + }; + + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } case MTL_ARG_MATERIAL_VERTEX_CONST: case MTL_ARG_MATERIAL_PIXEL_CONST: - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::MATERIAL_CONST, - .m_destination = {.dx11 = - { - .m_location = arg.location.offset, - .m_size = arg.size, - .m_buffer = arg.buffer, - }}, - .m_value = { - .name_hash = arg.u.nameHash, - } + { + const techset::CommonShaderArgValue value{ + .name_hash = arg.u.nameHash, }; + const techset::CommonShaderArgLocationDx11 location{ + .constant_buffer_offset = arg.location.offset, + }; + const techset::CommonShaderArgDestination destination{ + .dx11 = { + .m_location = location, + .m_size = arg.size, + .m_buffer = arg.buffer, + } + }; + + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } case MTL_ARG_CODE_PIXEL_SAMPLER: - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::CODE_SAMPLER, - .m_destination = {.dx11 = - { - .m_location = arg.location.samplerIndex, - .m_size = arg.size, - .m_buffer = arg.buffer, - }}, - .m_value = { - .code_sampler_source = static_cast(arg.u.codeSampler), - } + { + const techset::CommonShaderArgValue value{ + .code_sampler_source = static_cast(arg.u.codeSampler), + }; + const techset::CommonShaderArgLocationDx11 location{ + .texture_index = arg.location.textureIndex, + .sampler_index = arg.location.samplerIndex, + }; + const techset::CommonShaderArgDestination destination = { + .dx11 = { + .m_location = location, + .m_size = arg.size, + .m_buffer = arg.buffer, + } }; + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } + case MTL_ARG_MATERIAL_PIXEL_SAMPLER: - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::MATERIAL_SAMPLER, - .m_destination = {.dx11 = - { - .m_location = arg.location.samplerIndex, - .m_size = arg.size, - .m_buffer = arg.buffer, - }}, - .m_value = { - .name_hash = arg.u.nameHash, - } + { + const techset::CommonShaderArgValue value{ + .name_hash = arg.u.nameHash, }; + const techset::CommonShaderArgLocationDx11 location{ + .texture_index = arg.location.textureIndex, + .sampler_index = arg.location.samplerIndex, + }; + const techset::CommonShaderArgDestination destination = { + .dx11 = { + .m_location = location, + .m_size = arg.size, + .m_buffer = arg.buffer, + } + }; + + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } default: case MTL_ARG_LITERAL_VERTEX_CONST: case MTL_ARG_LITERAL_PIXEL_CONST: + { + techset::CommonShaderArgValue value{}; if (arg.u.literalConst) { - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::LITERAL_CONST, - .m_destination = {.dx11 = - { - .m_location = arg.location.offset, - .m_size = arg.size, - .m_buffer = arg.buffer, - }}, - .m_value = { - .literal_value = - { - (*arg.u.literalConst)[0], - (*arg.u.literalConst)[1], - (*arg.u.literalConst)[2], - (*arg.u.literalConst)[3], - }, } + value.literal_value = { + (*arg.u.literalConst)[0], + (*arg.u.literalConst)[1], + (*arg.u.literalConst)[2], + (*arg.u.literalConst)[3], }; } - return techset::CommonShaderArg{ - .m_type = techset::CommonShaderArgType::LITERAL_CONST, - .m_destination = {.dx11 = - { - .m_location = arg.location.offset, - .m_size = arg.size, - .m_buffer = arg.buffer, - }}, - .m_value = {}, + const techset::CommonShaderArgLocationDx11 location{ + .constant_buffer_offset = arg.location.offset, }; + const techset::CommonShaderArgDestination destination = { + .dx11 = { + .m_location = location, + .m_size = arg.size, + .m_buffer = arg.buffer, + } + }; + + return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); + } } } - techset::CommonTechniqueShader ConvertToCommonShader(const MaterialPass& pass, const MaterialVertexShader* vertexShader) + techset::CommonTechniqueShader ConvertToCommonShader(const MaterialVertexShader* vertexShader) { techset::CommonTechniqueShader result{}; if (!vertexShader) @@ -186,34 +203,16 @@ namespace if (vertexShader->prog.loadDef.program) { - result.m_shader_bin = vertexShader->prog.loadDef.program; - result.m_shader_bin_size = vertexShader->prog.loadDef.programSize; - } - - if (pass.args) - { - const size_t totalArgCount = pass.perPrimArgCount + pass.perObjArgCount + pass.stableArgCount; - for (auto argIndex = 0uz; argIndex < totalArgCount; argIndex++) - { - const auto& arg = pass.args[argIndex]; - - switch (arg.type) - { - case MTL_ARG_CODE_VERTEX_CONST: - case MTL_ARG_MATERIAL_VERTEX_CONST: - case MTL_ARG_LITERAL_VERTEX_CONST: - result.m_args.emplace_back(ConvertToCommonArg(arg)); - break; - default: - break; - } - } + result.m_bin = techset::CommonTechniqueShaderBin{ + .m_shader_bin = vertexShader->prog.loadDef.program, + .m_shader_bin_size = vertexShader->prog.loadDef.programSize, + }; } return result; } - techset::CommonTechniqueShader ConvertToCommonShader(const MaterialPass& pass, const MaterialPixelShader* pixelShader) + techset::CommonTechniqueShader ConvertToCommonShader(const MaterialPixelShader* pixelShader) { techset::CommonTechniqueShader result{}; if (!pixelShader) @@ -224,30 +223,10 @@ namespace if (pixelShader->prog.loadDef.program) { - result.m_shader_bin = pixelShader->prog.loadDef.program; - result.m_shader_bin_size = pixelShader->prog.loadDef.programSize; - } - - if (pass.args) - { - const size_t totalArgCount = pass.perPrimArgCount + pass.perObjArgCount + pass.stableArgCount; - for (auto argIndex = 0uz; argIndex < totalArgCount; argIndex++) - { - const auto& arg = pass.args[argIndex]; - - switch (arg.type) - { - case MTL_ARG_CODE_PIXEL_CONST: - case MTL_ARG_CODE_PIXEL_SAMPLER: - case MTL_ARG_MATERIAL_PIXEL_CONST: - case MTL_ARG_MATERIAL_PIXEL_SAMPLER: - case MTL_ARG_LITERAL_PIXEL_CONST: - result.m_args.emplace_back(ConvertToCommonArg(arg)); - break; - default: - break; - } - } + result.m_bin = techset::CommonTechniqueShaderBin{ + .m_shader_bin = pixelShader->prog.loadDef.program, + .m_shader_bin_size = pixelShader->prog.loadDef.programSize, + }; } return result; @@ -255,26 +234,30 @@ namespace techset::CommonTechnique ConvertToCommonTechnique(const MaterialTechnique& technique) { - std::vector passes; + techset::CommonTechnique commonTechnique(technique.name ? technique.name : std::string(), technique.flags); for (auto passIndex = 0u; passIndex < technique.passCount; passIndex++) { const auto& pass = technique.passArray[passIndex]; + techset::CommonPass commonPass(pass.customSamplerFlags, + // No clue what the actual state map was + "passthrough", + ConvertToCommonShader(pass.vertexShader), + ConvertToCommonShader(pass.pixelShader), + ConvertToCommonVertexDeclaration(pass.vertexDecl)); - passes.emplace_back(techset::CommonPass{ - .m_sampler_flags = pass.customSamplerFlags, - .m_dx_version = techset::DxVersion::DX11, - .m_vertex_shader = ConvertToCommonShader(pass, pass.vertexShader), - .m_pixel_shader = ConvertToCommonShader(pass, pass.pixelShader), - .m_vertex_declaration = ConvertToCommonVertexDeclaration(pass.vertexDecl), - }); + if (pass.args) + { + const size_t totalArgCount = pass.perPrimArgCount + pass.perObjArgCount + pass.stableArgCount; + commonPass.m_args.reserve(totalArgCount); + for (auto argIndex = 0uz; argIndex < totalArgCount; argIndex++) + commonPass.m_args.emplace_back(ConvertToCommonArg(pass.args[argIndex])); + } + + commonTechnique.m_passes.emplace_back(std::move(commonPass)); } - return techset::CommonTechnique{ - .m_name = technique.name ? technique.name : std::string(), - .m_flags = technique.flags, - .m_passes = std::move(passes), - }; + return commonTechnique; } void DumpTechniques(AssetDumpingContext& context, const MaterialTechniqueSet& techset) @@ -287,7 +270,8 @@ namespace { const auto commonTechnique = ConvertToCommonTechnique(*technique); - techset::DumpCommonTechnique(context, commonTechnique, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState); + techset::DumpCommonTechnique( + context, commonTechnique, techset::DxVersion::DX11, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState); } } } diff --git a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp index d50942ab..b43b626c 100644 --- a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp +++ b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp @@ -13,20 +13,16 @@ using namespace techset; namespace { - enum class TechniqueShaderType : std::uint8_t - { - VERTEX_SHADER, - PIXEL_SHADER - }; - class TechniqueFileWriter : public AbstractTextDumper { public: TechniqueFileWriter(std::ostream& stream, + const DxVersion dxVersion, const CommonCodeSourceInfos& codeSourceInfos, const CommonStreamRoutingInfos& routingInfos, const AbstractMaterialConstantZoneState& constantZoneState) : AbstractTextDumper(stream), + m_dx_version(dxVersion), m_code_source_infos(codeSourceInfos), m_routing_infos(routingInfos), m_constant_zone_state(constantZoneState) @@ -73,8 +69,8 @@ namespace #endif DumpStateMap(); - DumpShader(technique, pass.m_vertex_shader, TechniqueShaderType::VERTEX_SHADER, pass.m_dx_version); - DumpShader(technique, pass.m_pixel_shader, TechniqueShaderType::PIXEL_SHADER, pass.m_dx_version); + DumpShader(technique, pass, pass.m_vertex_shader, CommonTechniqueShaderType::VERTEX, m_dx_version); + DumpShader(technique, pass, pass.m_pixel_shader, CommonTechniqueShaderType::PIXEL, m_dx_version); DumpVertexDecl(pass.m_vertex_declaration); DecIndent(); @@ -89,9 +85,13 @@ namespace m_stream << "stateMap \"passthrough\"; // TODO\n"; } - void DumpShader(const CommonTechnique& technique, const CommonTechniqueShader& shader, const TechniqueShaderType shaderType, const DxVersion dxVersion) + void DumpShader(const CommonTechnique& technique, + const CommonPass& pass, + const CommonTechniqueShader& shader, + const CommonTechniqueShaderType shaderType, + const DxVersion dxVersion) { - if (!shader.m_shader_bin) + if (!shader.m_bin || !shader.m_bin->m_shader_bin) { if (!shader.m_name.empty()) { @@ -105,7 +105,7 @@ namespace unsigned versionMajor, versionMinor; if (dxVersion == DxVersion::DX9) { - const auto shaderInfo = d3d9::ShaderAnalyser::GetShaderInfo(shader.m_shader_bin, shader.m_shader_bin_size); + const auto shaderInfo = d3d9::ShaderAnalyser::GetShaderInfo(shader.m_bin->m_shader_bin, shader.m_bin->m_shader_bin_size); assert(shaderInfo); if (!shaderInfo) return; @@ -115,13 +115,16 @@ namespace DumpShaderHeader(shader, shaderType, versionMajor, versionMinor); - for (const auto& arg : shader.m_args) - DumpShaderArgDx9(technique, arg, *shaderInfo); + for (const auto& arg : pass.m_args) + { + if (arg.m_type.m_shader_type == shaderType) + DumpShaderArgDx9(technique, arg, *shaderInfo); + } } else { assert(dxVersion == DxVersion::DX11); - const auto shaderInfo = d3d11::ShaderAnalyser::GetShaderInfo(shader.m_shader_bin, shader.m_shader_bin_size); + const auto shaderInfo = d3d11::ShaderAnalyser::GetShaderInfo(shader.m_bin->m_shader_bin, shader.m_bin->m_shader_bin_size); assert(shaderInfo); if (!shaderInfo) return; @@ -131,8 +134,11 @@ namespace DumpShaderHeader(shader, shaderType, versionMajor, versionMinor); - for (const auto& arg : shader.m_args) - DumpShaderArgDx11(technique, arg, *shaderInfo); + for (const auto& arg : pass.m_args) + { + if (arg.m_type.m_shader_type == shaderType) + DumpShaderArgDx11(technique, arg, *shaderInfo); + } } DecIndent(); @@ -140,9 +146,9 @@ namespace m_stream << "}\n"; } - void DumpShaderHeader(const CommonTechniqueShader& shader, const TechniqueShaderType shaderType, unsigned versionMajor, unsigned versionMinor) + void DumpShaderHeader(const CommonTechniqueShader& shader, const CommonTechniqueShaderType shaderType, unsigned versionMajor, unsigned versionMinor) { - const auto shaderTypeName = shaderType == TechniqueShaderType::VERTEX_SHADER ? "vertexShader" : "pixelShader"; + const auto shaderTypeName = shaderType == CommonTechniqueShaderType::VERTEX ? "vertexShader" : "pixelShader"; m_stream << "\n"; Indent(); @@ -154,9 +160,10 @@ namespace void DumpShaderArgDx9(const CommonTechnique& technique, const CommonShaderArg& arg, const d3d9::ShaderInfo& shaderInfo) const { - const auto expectedRegisterSet = arg.m_type == CommonShaderArgType::CODE_SAMPLER || arg.m_type == CommonShaderArgType::MATERIAL_SAMPLER - ? d3d9::RegisterSet::SAMPLER - : d3d9::RegisterSet::FLOAT_4; + const auto expectedRegisterSet = + arg.m_type.m_value_type == CommonShaderValueType::CODE_SAMPLER || arg.m_type.m_value_type == CommonShaderValueType::MATERIAL_SAMPLER + ? d3d9::RegisterSet::SAMPLER + : d3d9::RegisterSet::FLOAT_4; const auto destinationRegister = arg.m_destination.dx9.m_destination_register; const auto targetShaderArg = std::ranges::find_if(shaderInfo.m_constants, [destinationRegister, expectedRegisterSet](const d3d9::ShaderConstant& constant) @@ -170,11 +177,11 @@ namespace if (targetShaderArg == shaderInfo.m_constants.end()) { Indent(); - m_stream << std::format("// Unrecognized arg dest: {} type: {}\n", destinationRegister, static_cast(arg.m_type)); + m_stream << std::format("// Unrecognized arg dest: {} type: {}\n", destinationRegister, static_cast(arg.m_type.m_value_type)); con::error("Technique {}: Could not find arg (type: {}; dest: {}) in shader", technique.m_name, destinationRegister, - static_cast(arg.m_type)); + static_cast(arg.m_type.m_value_type)); return; } @@ -186,14 +193,14 @@ namespace else codeDestAccessor = targetShaderArg->m_name; - DumpShaderArg(technique, arg, codeDestAccessor); + const auto isTransposed = targetShaderArg->m_class == d3d9::ParameterClass::MATRIX_COLUMNS; + DumpShaderArg(technique, arg, codeDestAccessor, isTransposed); } void DumpShaderArgDx11(const CommonTechnique& technique, const CommonShaderArg& arg, const d3d11::ShaderInfo& shaderInfo) const { const auto& destination = arg.m_destination.dx11; - if (arg.m_type == CommonShaderArgType::CODE_CONST || arg.m_type == CommonShaderArgType::MATERIAL_CONST - || arg.m_type == CommonShaderArgType::LITERAL_CONST) + if (IsConstValueType(arg.m_type.m_value_type)) { const auto boundResource = std::ranges::find_if(shaderInfo.m_bound_resources, [destination](const d3d11::BoundResource& resource) @@ -207,13 +214,13 @@ namespace Indent(); m_stream << std::format("// Could not find bound resource for arg buffer: {} offset: {} type: {}\n", destination.m_buffer, - destination.m_location, - static_cast(arg.m_type)); + destination.m_location.constant_buffer_offset, + static_cast(arg.m_type.m_value_type)); con::error("Technique {}: Could not find bound resource for arg (buffer: {} offset: {} type: {}) in shader", technique.m_name, destination.m_buffer, - destination.m_location, - static_cast(arg.m_type)); + destination.m_location.constant_buffer_offset, + static_cast(arg.m_type.m_value_type)); return; } const auto buffer = std::ranges::find_if(shaderInfo.m_constant_buffers, @@ -229,75 +236,112 @@ namespace return; } - const auto variable = std::ranges::find_if(buffer->m_variables, - [destination](const d3d11::ConstantBufferVariable& var) - { - return var.m_offset <= destination.m_location - && var.m_offset + var.m_size >= destination.m_location + destination.m_size; - }); + const auto variable = + std::ranges::find_if(buffer->m_variables, + [destination](const d3d11::ConstantBufferVariable& var) + { + return var.m_offset <= destination.m_location.constant_buffer_offset + && var.m_offset + var.m_size >= destination.m_location.constant_buffer_offset + destination.m_size; + }); if (variable == buffer->m_variables.end()) { Indent(); m_stream << std::format("// Could not find variable in buffer: {} offset: {} type: {}\n", buffer->m_name, - destination.m_location, - static_cast(arg.m_type)); + destination.m_location.constant_buffer_offset, + static_cast(arg.m_type.m_value_type)); con::error("Technique {}: Could not find variable in buffer for arg (buffer: {} offset: {} type: {}) in shader", technique.m_name, buffer->m_name, - destination.m_location, - static_cast(arg.m_type)); + destination.m_location.constant_buffer_offset, + static_cast(arg.m_type.m_value_type)); return; } - DumpShaderArg(technique, arg, variable->m_name); + std::string codeDestAccessor; + if (variable->m_element_count <= 1) + { + codeDestAccessor = variable->m_name; + } + else + { + const auto elementSize = variable->m_size / variable->m_element_count; + + // Assert destination is aligned with element size + assert((destination.m_location.constant_buffer_offset - variable->m_offset) % elementSize == 0); + + const auto destinationIndex = (destination.m_location.constant_buffer_offset - variable->m_offset) / elementSize; + + codeDestAccessor = std::format("{}[{}]", variable->m_name, destinationIndex); + } + + const auto isTransposed = variable->m_variable_class == d3d11::VariableClass::MATRIX_COLUMNS; + DumpShaderArg(technique, arg, codeDestAccessor, isTransposed); } else { - assert(arg.m_type == CommonShaderArgType::CODE_SAMPLER || arg.m_type == CommonShaderArgType::MATERIAL_SAMPLER); + assert(IsSamplerValueType(arg.m_type.m_value_type)); - const auto boundResource = std::ranges::find_if(shaderInfo.m_bound_resources, - [destination](const d3d11::BoundResource& resource) - { - return (resource.m_type == d3d11::BoundResourceType::SAMPLER - || resource.m_type == d3d11::BoundResourceType::TEXTURE) - && resource.m_bind_point == destination.m_location; - }); - if (boundResource == shaderInfo.m_bound_resources.end()) + // The game seems to guarantee the texture name to be the accurate one + const auto boundTextureResource = std::ranges::find_if(shaderInfo.m_bound_resources, + [destination](const d3d11::BoundResource& resource) + { + if (resource.m_type == d3d11::BoundResourceType::TEXTURE) + return resource.m_bind_point == destination.m_location.texture_index; + + return false; + }); + if (boundTextureResource == shaderInfo.m_bound_resources.end()) { Indent(); - m_stream << std::format("// Could not find buffer for arg buffer: {} offset: {} type: {}\n", + m_stream << std::format("// Could not find buffer for arg buffer: {} sampler: {} texture: {} type: {}\n", destination.m_buffer, - destination.m_location, - static_cast(arg.m_type)); - con::error("Technique {}: Could not find buffer for arg (buffer: {} offset: {} type: {}) in shader", + destination.m_location.sampler_index, + destination.m_location.texture_index, + static_cast(arg.m_type.m_value_type)); + con::error("Technique {}: Could not find buffer for arg (buffer: {} sampler: {} texture: {} type: {}) in shader", technique.m_name, destination.m_buffer, - destination.m_location, - static_cast(arg.m_type)); + destination.m_location.sampler_index, + destination.m_location.texture_index, + static_cast(arg.m_type.m_value_type)); return; } - DumpShaderArg(technique, arg, boundResource->m_name); + DumpShaderArg(technique, arg, boundTextureResource->m_name, false); } } - void DumpShaderArg(const CommonTechnique& technique, const CommonShaderArg& arg, std::string codeDestAccessor) const + void DumpShaderArg(const CommonTechnique& technique, const CommonShaderArg& arg, std::string codeDestAccessor, const bool isTransposed) const { - if (arg.m_type == CommonShaderArgType::CODE_CONST) + if (arg.m_type.m_value_type == CommonShaderValueType::CODE_CONST) { - const auto constSourceInfo = m_code_source_infos.GetInfoForCodeConstSource(arg.m_value.code_const_source); + auto constSourceInfo = m_code_source_infos.GetInfoForCodeConstSource(arg.m_value.code_const_source.m_index); + + if (isTransposed) + { + assert(constSourceInfo); + if (constSourceInfo && constSourceInfo->transposedMatrix) + constSourceInfo = m_code_source_infos.GetInfoForCodeConstSource(*constSourceInfo->transposedMatrix); + } + if (constSourceInfo) { - if (codeDestAccessor != constSourceInfo->accessor) + std::string codeAccessor; + if (constSourceInfo->arrayCount <= 1) + codeAccessor = constSourceInfo->accessor; + else + codeAccessor = std::format("{}[{}]", constSourceInfo->accessor, arg.m_value.code_const_source.m_index - constSourceInfo->value); + + if (codeDestAccessor != codeAccessor) { Indent(); - m_stream << std::format("{} = constant.{};\n", codeDestAccessor, constSourceInfo->accessor); + m_stream << std::format("{} = constant.{};\n", codeDestAccessor, codeAccessor); } else { #ifdef TECHSET_DEBUG Indent(); - m_stream << std::format("// Omitted due to matching accessors: {} = constant.{};\n", codeDestAccessor, constSourceInfo->accessor); + m_stream << std::format("// Omitted due to matching accessors: {} = constant.{};\n", codeDestAccessor, codeAccessor); #endif } } @@ -309,7 +353,7 @@ namespace con::error("Technique {}: Could not find code source info for const {}", technique.m_name, codeDestAccessor); } } - else if (arg.m_type == CommonShaderArgType::CODE_SAMPLER) + else if (arg.m_type.m_value_type == CommonShaderValueType::CODE_SAMPLER) { const auto samplerSourceInfo = m_code_source_infos.GetInfoForCodeSamplerSource(arg.m_value.code_sampler_source); if (samplerSourceInfo) @@ -335,7 +379,7 @@ namespace con::error("Technique {}: Could not find code source info for sampler {}", technique.m_name, codeDestAccessor); } } - else if (arg.m_type == CommonShaderArgType::LITERAL_CONST) + else if (arg.m_type.m_value_type == CommonShaderValueType::LITERAL_CONST) { Indent(); m_stream << std::format("{} = float4({}, {}, {}, {});\n", @@ -345,7 +389,7 @@ namespace arg.m_value.literal_value[2], arg.m_value.literal_value[3]); } - else if (arg.m_type == CommonShaderArgType::MATERIAL_CONST || arg.m_type == CommonShaderArgType::MATERIAL_SAMPLER) + else if (arg.m_type.m_value_type == CommonShaderValueType::MATERIAL_CONST || arg.m_type.m_value_type == CommonShaderValueType::MATERIAL_SAMPLER) { Indent(); @@ -385,6 +429,7 @@ namespace } } + DxVersion m_dx_version; const CommonCodeSourceInfos& m_code_source_infos; const CommonStreamRoutingInfos& m_routing_infos; const AbstractMaterialConstantZoneState& m_constant_zone_state; @@ -395,6 +440,7 @@ namespace techset { void DumpCommonTechnique(const AssetDumpingContext& context, const CommonTechnique& technique, + const DxVersion dxVersion, const CommonCodeSourceInfos& codeSourceInfos, const CommonStreamRoutingInfos& routingInfos, const AbstractMaterialConstantZoneState& constantZoneState) @@ -402,7 +448,7 @@ namespace techset const auto techniqueFile = context.OpenAssetFile(GetFileNameForTechniqueName(technique.m_name)); if (techniqueFile) { - TechniqueFileWriter writer(*techniqueFile, codeSourceInfos, routingInfos, constantZoneState); + TechniqueFileWriter writer(*techniqueFile, dxVersion, codeSourceInfos, routingInfos, constantZoneState); writer.DumpTechnique(technique); } } diff --git a/src/ObjWriting/Techset/CommonTechniqueDumper.h b/src/ObjWriting/Techset/CommonTechniqueDumper.h index 4a3dc943..f2a6a4bd 100644 --- a/src/ObjWriting/Techset/CommonTechniqueDumper.h +++ b/src/ObjWriting/Techset/CommonTechniqueDumper.h @@ -8,6 +8,7 @@ namespace techset { void DumpCommonTechnique(const AssetDumpingContext& context, const CommonTechnique& technique, + DxVersion dxVersion, const CommonCodeSourceInfos& codeSourceInfos, const CommonStreamRoutingInfos& routingInfos, const AbstractMaterialConstantZoneState& constantZoneState); From a3f250fdca86aaa3efaed107d8b5e5a891df2d1e Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 27 Feb 2026 23:05:44 +0100 Subject: [PATCH 12/27] feat: compile t6 techsets --- src/ObjCompiling/Game/T6/ObjCompilerT6.cpp | 2 + .../Game/T6/Techset/TechniqueCompilerT6.cpp | 276 ++++++++ .../Game/T6/Techset/TechniqueCompilerT6.h | 12 + .../Game/T6/Techset/TechsetCompilerT6.cpp | 44 +- .../Techset/CommonShaderArgCreator.cpp | 665 ++++++++++++++++++ .../Techset/CommonShaderArgCreator.h | 62 ++ .../Techset/CommonTechniqueLoader.cpp | 46 ++ .../Techset/CommonTechniqueLoader.h | 10 +- .../Techset/CommonTechsetCache.cpp | 18 - src/ObjCompiling/Techset/CommonTechsetCache.h | 21 - .../Techset/CommonTechsetLoader.cpp | 1 - .../Techset/LiteralConstsZoneState.h | 131 ++++ .../Sequence/TechniqueNoScopeSequences.cpp | 6 +- .../Sequence/TechniquePassScopeSequences.cpp | 74 +- .../TechniqueShaderScopeSequences.cpp | 200 ++++-- .../Techset/Parsing/TechniqueFileParser.cpp | 36 +- .../Techset/Parsing/TechniqueFileParser.h | 12 +- .../Parsing/TechniqueFileParserState.cpp | 24 +- .../Parsing/TechniqueFileParserState.h | 22 +- .../StateMapFromTechniqueExtractor.cpp | 68 -- .../StateMap/StateMapFromTechniqueExtractor.h | 40 -- .../Techset/StateMap/StateMapReader.h | 5 +- .../{ => StateMap}/TechniqueStateMapCache.cpp | 0 .../{ => StateMap}/TechniqueStateMapCache.h | 7 +- .../Techset/TechniqueDefinitionAcceptor.cpp | 116 --- .../Techset/TechniqueDefinitionAcceptor.h | 100 --- .../Techset/TechniqueFileReader.cpp | 39 - .../Techset/TechniqueFileReader.h | 24 - 28 files changed, 1486 insertions(+), 575 deletions(-) create mode 100644 src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp create mode 100644 src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.h create mode 100644 src/ObjCompiling/Techset/CommonShaderArgCreator.cpp create mode 100644 src/ObjCompiling/Techset/CommonShaderArgCreator.h delete mode 100644 src/ObjCompiling/Techset/CommonTechsetCache.cpp delete mode 100644 src/ObjCompiling/Techset/CommonTechsetCache.h create mode 100644 src/ObjCompiling/Techset/LiteralConstsZoneState.h delete mode 100644 src/ObjCompiling/Techset/StateMap/StateMapFromTechniqueExtractor.cpp delete mode 100644 src/ObjCompiling/Techset/StateMap/StateMapFromTechniqueExtractor.h rename src/ObjCompiling/Techset/{ => StateMap}/TechniqueStateMapCache.cpp (100%) rename src/ObjCompiling/Techset/{ => StateMap}/TechniqueStateMapCache.h (69%) delete mode 100644 src/ObjCompiling/Techset/TechniqueDefinitionAcceptor.cpp delete mode 100644 src/ObjCompiling/Techset/TechniqueDefinitionAcceptor.h delete mode 100644 src/ObjCompiling/Techset/TechniqueFileReader.cpp delete mode 100644 src/ObjCompiling/Techset/TechniqueFileReader.h diff --git a/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp b/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp index 5e1412e1..7a825ec8 100644 --- a/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp +++ b/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp @@ -4,6 +4,7 @@ #include "Image/ImageIPakPostProcessor.h" #include "Image/ImageIwdPostProcessor.h" #include "KeyValuePairs/KeyValuePairsCompilerT6.h" +#include "Techset/TechniqueCompilerT6.h" #include "Techset/TechsetCompilerT6.h" #include "Techset/VertexDeclCompilerT6.h" @@ -24,6 +25,7 @@ namespace collection.AddAssetCreator(key_value_pairs::CreateCompilerT6(memory, zone, zoneDefinition.m_zone_definition, zoneStates)); collection.AddAssetCreator(techset::CreateCompilerT6(memory, searchPath)); + collection.AddSubAssetCreator(techset::CreateTechniqueCompilerT6(memory, searchPath)); collection.AddSubAssetCreator(techset::CreateVertexDeclCompilerT6(memory)); } diff --git a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp new file mode 100644 index 00000000..2eb162ef --- /dev/null +++ b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp @@ -0,0 +1,276 @@ +#include "TechniqueCompilerT6.h" + +#include "Game/T6/T6.h" +#include "Game/T6/Techset/TechsetConstantsT6.h" +#include "Techset/CommonShaderArgCreator.h" +#include "Techset/CommonTechniqueLoader.h" +#include "Techset/LiteralConstsZoneState.h" +#include "Utils/StringUtils.h" + +#include +#include + +using namespace T6; + +namespace +{ + unsigned ConvertArgumentType(const techset::CommonShaderArgumentType& type) + { + if (type.m_shader_type == techset::CommonTechniqueShaderType::VERTEX) + { + switch (type.m_value_type) + { + case techset::CommonShaderValueType::LITERAL_CONST: + return MTL_ARG_LITERAL_VERTEX_CONST; + case techset::CommonShaderValueType::MATERIAL_CONST: + return MTL_ARG_MATERIAL_VERTEX_CONST; + case techset::CommonShaderValueType::CODE_CONST: + return MTL_ARG_CODE_VERTEX_CONST; + case techset::CommonShaderValueType::MATERIAL_SAMPLER: + case techset::CommonShaderValueType::CODE_SAMPLER: + default: + assert(false); + return 0; + } + } + + assert(type.m_shader_type == techset::CommonTechniqueShaderType::PIXEL); + + switch (type.m_value_type) + { + case techset::CommonShaderValueType::LITERAL_CONST: + return MTL_ARG_LITERAL_PIXEL_CONST; + case techset::CommonShaderValueType::MATERIAL_CONST: + return MTL_ARG_MATERIAL_PIXEL_CONST; + case techset::CommonShaderValueType::CODE_CONST: + return MTL_ARG_CODE_PIXEL_CONST; + case techset::CommonShaderValueType::MATERIAL_SAMPLER: + return MTL_ARG_MATERIAL_PIXEL_SAMPLER; + case techset::CommonShaderValueType::CODE_SAMPLER: + return MTL_ARG_CODE_PIXEL_SAMPLER; + default: + assert(false); + return 0; + } + } + + void ConvertArgumentValue(MaterialArgumentDef& argValue, const techset::CommonShaderArg& commonArg, MemoryManager& memory, AssetCreationContext& context) + { + switch (commonArg.m_type.m_value_type) + { + case techset::CommonShaderValueType::LITERAL_CONST: + { + const techset::LiteralConst literal(commonArg.m_value.literal_value); + argValue.literalConst = context.GetZoneAssetCreationState>().GetAllocatedLiteral(literal)->GamePtr(); + break; + } + case techset::CommonShaderValueType::CODE_CONST: + argValue.codeConst.index = static_cast(commonArg.m_value.code_const_source.m_index); + argValue.codeConst.firstRow = static_cast(commonArg.m_value.code_const_source.m_first_row); + argValue.codeConst.rowCount = static_cast(commonArg.m_value.code_const_source.m_row_count); + break; + case techset::CommonShaderValueType::CODE_SAMPLER: + argValue.codeSampler = static_cast(commonArg.m_value.code_sampler_source); + break; + case techset::CommonShaderValueType::MATERIAL_CONST: + case techset::CommonShaderValueType::MATERIAL_SAMPLER: + argValue.nameHash = static_cast(commonArg.m_value.name_hash); + break; + } + } + + void ConvertMaterialArgs(MaterialPass& pass, const techset::CommonPass& commonPass, MemoryManager& memory, AssetCreationContext& context) + { + pass.args = memory.Alloc(commonPass.m_args.size()); + + const auto frequencyCount = commonPass.GetFrequencyCounts(commonCodeSourceInfos); + + pass.perObjArgCount = static_cast(frequencyCount[std::to_underlying(techset::CommonCodeSourceUpdateFrequency::PER_OBJECT)]); + pass.perPrimArgCount = static_cast(frequencyCount[std::to_underlying(techset::CommonCodeSourceUpdateFrequency::PER_PRIM)]); + pass.stableArgCount = static_cast(frequencyCount[std::to_underlying(techset::CommonCodeSourceUpdateFrequency::RARELY)]); + + const auto commonArgCount = commonPass.m_args.size(); + for (auto argIndex = 0u; argIndex < commonArgCount; argIndex++) + { + auto& arg = pass.args[argIndex]; + const auto& commonArg = commonPass.m_args[argIndex]; + + arg.type = static_cast(ConvertArgumentType(commonArg.m_type)); + + arg.size = static_cast(commonArg.m_destination.dx11.m_size); + arg.buffer = static_cast(commonArg.m_destination.dx11.m_buffer); + + if (techset::IsConstValueType(commonArg.m_type.m_value_type)) + { + arg.location.offset = static_cast(commonArg.m_destination.dx11.m_location.constant_buffer_offset); + } + else + { + assert(techset::IsSamplerValueType(commonArg.m_type.m_value_type)); + arg.location.textureIndex = + static_cast(commonArg.m_destination.dx11.m_location.texture_index); + arg.location.samplerIndex = + static_cast(commonArg.m_destination.dx11.m_location.sampler_index); + } + + ConvertArgumentValue(arg.u, commonArg, memory, context); + } + } + + void ConvertVertexDecl(MaterialPass& pass, const techset::CommonVertexDeclaration& commonDecl, AssetCreationContext& context) + { + std::ostringstream nameStream; + for (const auto& entry : commonDecl.m_routing) + { + nameStream << commonRoutingInfos.GetSourceAbbreviation(entry.m_source); + nameStream << commonRoutingInfos.GetDestinationAbbreviation(entry.m_destination); + } + + const std::string declName(nameStream.str()); + auto* vertexDeclAsset = context.LoadSubAsset(declName); + assert(vertexDeclAsset); + pass.vertexDecl = vertexDeclAsset ? vertexDeclAsset->Asset() : nullptr; + } + + void ConvertMaterialPass(MaterialPass& pass, const techset::CommonPass& commonPass, AssetCreationContext& context, MemoryManager& memory) + { + ConvertVertexDecl(pass, commonPass.m_vertex_declaration, context); + + if (!commonPass.m_vertex_shader.m_name.empty()) + { + auto* vertexShaderAsset = context.LoadSubAsset(commonPass.m_vertex_shader.m_name); + assert(vertexShaderAsset); + pass.vertexShader = vertexShaderAsset ? vertexShaderAsset->Asset() : nullptr; + } + + if (!commonPass.m_pixel_shader.m_name.empty()) + { + auto* pixelShaderAsset = context.LoadSubAsset(commonPass.m_pixel_shader.m_name); + assert(pixelShaderAsset); + pass.pixelShader = pixelShaderAsset ? pixelShaderAsset->Asset() : nullptr; + } + + ConvertMaterialArgs(pass, commonPass, memory, context); + } + + void UpdateTechniqueFlags(MaterialTechnique& technique, const techset::CommonTechnique& commonTechnique) + { + std::string lowerTechniqueName(commonTechnique.m_name); + utils::MakeStringLowerCase(lowerTechniqueName); + + // 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; + } + } + + MaterialTechnique* ConvertTechnique(const techset::CommonTechnique& commonTechnique, AssetCreationContext& context, MemoryManager& memory) + { + const auto additionalPassCount = std::max(commonTechnique.m_passes.size(), 1uz) - 1uz; + auto* technique = static_cast(memory.AllocRaw(sizeof(MaterialTechnique) + additionalPassCount * sizeof(MaterialPass))); + + const auto passCount = static_cast(commonTechnique.m_passes.size()); + + technique->name = memory.Dup(commonTechnique.m_name.c_str()); + + // Take common flags and apply further logic + technique->flags = static_cast(commonTechnique.m_flags); + UpdateTechniqueFlags(*technique, commonTechnique); + + technique->passCount = passCount; + + for (auto passIndex = 0u; passIndex < passCount; passIndex++) + ConvertMaterialPass(technique->passArray[passIndex], commonTechnique.m_passes[passIndex], context, memory); + + return technique; + } + + class TechniqueShaderLoaderT6 final : public techset::ITechniqueShaderLoader + { + public: + explicit TechniqueShaderLoaderT6(AssetCreationContext& context) + : m_context(context) + { + } + + std::optional LoadVertexShader(const std::string& name) override + { + auto* shaderAsset = m_context.LoadSubAsset(name); + if (!shaderAsset) + return std::nullopt; + + const auto* shader = shaderAsset->Asset(); + assert(shader->prog.loadDef.program && shader->prog.loadDef.programSize > 0); + if (!shader->prog.loadDef.program || shader->prog.loadDef.programSize == 0) + return std::nullopt; + + return techset::CommonTechniqueShaderBin{ + .m_shader_bin = shader->prog.loadDef.program, + .m_shader_bin_size = shader->prog.loadDef.programSize, + }; + } + + std::optional LoadPixelShader(const std::string& name) override + { + auto* shaderAsset = m_context.LoadSubAsset(name); + if (!shaderAsset) + return std::nullopt; + + const auto* shader = shaderAsset->Asset(); + assert(shader->prog.loadDef.program && shader->prog.loadDef.programSize > 0); + if (!shader->prog.loadDef.program || shader->prog.loadDef.programSize == 0) + return std::nullopt; + + return techset::CommonTechniqueShaderBin{ + .m_shader_bin = shader->prog.loadDef.program, + .m_shader_bin_size = shader->prog.loadDef.programSize, + }; + } + + private: + AssetCreationContext& m_context; + }; + + class TechniqueCompilerT6 final : public SubAssetCreator + { + public: + TechniqueCompilerT6(MemoryManager& memory, ISearchPath& searchPath) + : m_memory(memory), + m_search_path(searchPath) + { + } + + AssetCreationResult CreateSubAsset(const std::string& subAssetName, AssetCreationContext& context) override + { + bool failure = false; + TechniqueShaderLoaderT6 shaderLoader(context); + const auto commonShaderArgCreator = techset::CommonShaderArgCreator::CreateDx11(shaderLoader, context, commonCodeSourceInfos); + + const auto commonTechnique = + techset::LoadCommonTechnique(subAssetName, commonCodeSourceInfos, commonRoutingInfos, *commonShaderArgCreator, m_search_path, failure); + + if (!commonTechnique) + return failure ? AssetCreationResult::Failure() : AssetCreationResult::NoAction(); + + auto* convertedTechnique = ConvertTechnique(*commonTechnique, context, m_memory); + assert(convertedTechnique); + + return AssetCreationResult::Success(context.AddSubAsset(AssetRegistration(subAssetName, convertedTechnique))); + } + + private: + MemoryManager& m_memory; + ISearchPath& m_search_path; + }; +} // namespace + +namespace techset +{ + std::unique_ptr CreateTechniqueCompilerT6(MemoryManager& memory, ISearchPath& searchPath) + { + return std::make_unique(memory, searchPath); + } +} // namespace techset diff --git a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.h b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.h new file mode 100644 index 00000000..c859d4d0 --- /dev/null +++ b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.h @@ -0,0 +1,12 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +namespace techset +{ + std::unique_ptr CreateTechniqueCompilerT6(MemoryManager& memory, ISearchPath& searchPath); +} diff --git a/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.cpp b/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.cpp index 9a672a30..b23280fc 100644 --- a/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.cpp +++ b/src/ObjCompiling/Game/T6/Techset/TechsetCompilerT6.cpp @@ -17,8 +17,8 @@ namespace techset::CountWorldVertFormatParameters(name, texCount, normalCount); // 0 and 1 seem to be treated equally - texCount = std::max(texCount, 1u); - normalCount = std::max(normalCount, 1u); + texCount = std::max(texCount, 1uz); + normalCount = std::max(normalCount, 1uz); if (texCount == 1 && normalCount == 1) return MTL_WORLDVERT_TEX_1_NRM_1; @@ -43,6 +43,25 @@ namespace return static_cast(0); } + MaterialType GetMaterialType(const std::string& name) + { + for (unsigned materialTypeIndex = MTL_TYPE_MODEL; materialTypeIndex < MTL_TYPE_COUNT; materialTypeIndex++) + { + if (name.starts_with(g_materialTypeInfo[materialTypeIndex].techniqueSetPrefix)) + return static_cast(materialTypeIndex); + } + + return MTL_TYPE_DEFAULT; + } + + void ApplyMaterialTypeToTechnique(MaterialTechnique& technique, const MaterialType materialType) + { + for (auto passIndex = 0u; passIndex < technique.passCount; passIndex++) + { + technique.passArray[passIndex].materialType = materialType; + } + } + MaterialTechniqueSet* ConvertTechniqueSet(const techset::CommonTechset& commonTechset, MemoryManager& memory) { auto* techset = memory.Alloc(); @@ -69,6 +88,27 @@ namespace return failure ? AssetCreationResult::Failure() : AssetCreationResult::NoAction(); auto* techset = ConvertTechniqueSet(*commonTechset, m_memory); + const auto materialType = GetMaterialType(assetName); + + for (auto techniqueIndex = 0u; techniqueIndex < std::extent_v; techniqueIndex++) + { + const auto& techniqueName = commonTechset->m_technique_names[techniqueIndex]; + if (techniqueName.empty()) + continue; + + auto* technique = context.LoadSubAsset(techniqueName); + if (!technique) + return AssetCreationResult::Failure(); + + techset->techniques[techniqueIndex] = technique->Asset(); + + // 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); + + // Precompiled index? + } return AssetCreationResult::Success(context.AddAsset(AssetRegistration(assetName, techset))); } diff --git a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp new file mode 100644 index 00000000..8afff667 --- /dev/null +++ b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp @@ -0,0 +1,665 @@ +#include "CommonShaderArgCreator.h" + +#include "Shader/D3D11ShaderAnalyser.h" +#include "Shader/D3D9ShaderAnalyser.h" +#include "Utils/Djb2.h" + +#include +#include +#include + +namespace +{ + class BaseCommonShaderArgCreator : public techset::CommonShaderArgCreator + { + public: + explicit BaseCommonShaderArgCreator(techset::ITechniqueShaderLoader& shaderLoader, techset::CommonCodeSourceInfos& commonCodeSourceInfos) + : m_shader_loader(shaderLoader), + m_common_code_source_infos(commonCodeSourceInfos), + m_shader_type(techset::CommonTechniqueShaderType::VERTEX), + m_bin{}, + m_tech_flags(0), + m_sampler_flags(0) + { + } + + result::Expected EnterShader(const techset::CommonTechniqueShaderType shaderType, const std::string& name) override + { + m_shader_type = shaderType; + + std::optional maybeShader; + if (shaderType == techset::CommonTechniqueShaderType::VERTEX) + { + maybeShader = m_shader_loader.LoadVertexShader(name); + } + else if (shaderType == techset::CommonTechniqueShaderType::PIXEL) + { + maybeShader = m_shader_loader.LoadPixelShader(name); + } + + if (!maybeShader) + return result::Unexpected("Failed to load shader"); + + m_bin = *maybeShader; + + return NoResult{}; + } + + result::Expected LeaveShader() override + { + m_bin = {}; + + return AutoCreateMissingArgs(); + } + + result::Expected AcceptShaderConstantArgument(const techset::CommonShaderArgCreatorDestination& destination, + const techset::CommonCodeConstSource codeConstSource, + const unsigned sourceIndex) override + { + techset::CommonShaderArgDestination commonDestination{}; + bool isTransposed; + std::string errorMessage; + if (!FindDestinationForConstant(commonDestination, isTransposed, errorMessage, destination)) + { + if (!errorMessage.empty()) + return result::Unexpected(std::move(errorMessage)); + + return result::Unexpected(std::format("Could not find constant shader input with name {}", destination.m_argument_name)); + } + + return AcceptShaderConstantArgument(commonDestination, isTransposed, codeConstSource, sourceIndex); + } + + result::Expected AcceptShaderSamplerArgument(const techset::CommonShaderArgCreatorDestination& destination, + const techset::CommonCodeSamplerSource codeSamplerSource) override + { + techset::CommonShaderArgDestination commonDestination{}; + std::string errorMessage; + if (!FindDestinationForSampler(commonDestination, errorMessage, destination)) + { + if (!errorMessage.empty()) + return result::Unexpected(std::move(errorMessage)); + + return result::Unexpected(std::format("Could not find sampler shader input with name {}", destination.m_argument_name)); + } + + return AcceptShaderSamplerArgument(commonDestination, codeSamplerSource); + } + + result::Expected AcceptShaderLiteralArgument(const techset::CommonShaderArgCreatorDestination& destination, + const std::array& literalValue) override + { + techset::CommonShaderArgDestination commonDestination{}; + bool isTransposed; + std::string errorMessage; + if (!FindDestinationForConstant(commonDestination, isTransposed, errorMessage, destination)) + { + if (!errorMessage.empty()) + return result::Unexpected(std::move(errorMessage)); + + return result::Unexpected(std::format("Could not find constant shader input with name {}", destination.m_argument_name)); + } + + techset::CommonShaderArgumentType argumentType{ + .m_shader_type = m_shader_type, + .m_value_type = techset::CommonShaderValueType::LITERAL_CONST, + }; + + techset::CommonShaderArgValue value{.literal_value = literalValue}; + + m_args.emplace_back(argumentType, commonDestination, value); + return NoResult{}; + } + + result::Expected AcceptShaderMaterialArgument(const techset::CommonShaderArgCreatorDestination& destination, + const unsigned nameHash) override + { + techset::CommonShaderArgumentType argumentType{ + .m_shader_type = m_shader_type, + .m_value_type = techset::CommonShaderValueType::MATERIAL_CONST, + }; + + techset::CommonShaderArgDestination commonDestination{}; + bool isTransposed; + std::string errorMessage; + if (!FindDestinationForConstant(commonDestination, isTransposed, errorMessage, destination)) + { + if (!errorMessage.empty()) + return result::Unexpected(std::move(errorMessage)); + + argumentType.m_value_type = techset::CommonShaderValueType::MATERIAL_SAMPLER; + + if (!FindDestinationForSampler(commonDestination, errorMessage, destination)) + { + if (!errorMessage.empty()) + return result::Unexpected(std::move(errorMessage)); + + return result::Unexpected(std::format("Could not find shader input with name {}", destination.m_argument_name)); + } + } + + techset::CommonShaderArgValue value{.name_hash = nameHash}; + + m_args.emplace_back(argumentType, commonDestination, value); + return NoResult{}; + } + + result::Expected AcceptShaderMaterialArgument(const techset::CommonShaderArgCreatorDestination& destination, + const std::string& nameValue) override + { + // All game's call R_HashString here which has the same implementation in all games + return AcceptShaderMaterialArgument(destination, djb2_xor_nocase(nameValue.c_str(), 0)); + } + + result::Expected FinalizePass(techset::CommonTechnique& technique, techset::CommonPass& pass) override + { + std::ranges::sort(m_args, + [this](const techset::CommonShaderArg& arg0, const techset::CommonShaderArg& arg1) -> bool + { + const auto updateFreq0 = arg0.GetFrequency(m_common_code_source_infos); + const auto updateFreq1 = arg1.GetFrequency(m_common_code_source_infos); + if (updateFreq0 != updateFreq1) + return updateFreq0 < updateFreq1; + + const auto typeNumeric0 = m_common_code_source_infos.GetArgumentTypeNumericValue(arg0.m_type); + const auto typeNumeric1 = m_common_code_source_infos.GetArgumentTypeNumericValue(arg1.m_type); + assert(typeNumeric0); + assert(typeNumeric1); + if (*typeNumeric0 != *typeNumeric1) + return *typeNumeric0 < *typeNumeric1; + + if (arg0.m_type.m_value_type == techset::CommonShaderValueType::MATERIAL_CONST + || arg0.m_type.m_value_type == techset::CommonShaderValueType::MATERIAL_SAMPLER) + { + return arg0.m_value.name_hash < arg1.m_value.name_hash; + } + + return CompareArgumentDestinations(arg0, arg1); + }); + + technique.m_flags |= m_tech_flags; + pass.m_args = std::move(m_args); + pass.m_sampler_flags |= m_sampler_flags; + + m_tech_flags = 0; + m_args = std::vector(); + m_sampler_flags = 0; + + return NoResult{}; + } + + protected: + result::Expected AcceptShaderConstantArgument(const techset::CommonShaderArgDestination& commonDestination, + const bool isTransposed, + const techset::CommonCodeConstSource codeConstSource, + const unsigned sourceIndex) + { + techset::CommonShaderArgumentType argumentType{ + .m_shader_type = m_shader_type, + .m_value_type = techset::CommonShaderValueType::CODE_CONST, + }; + + const auto maybeInfo = m_common_code_source_infos.GetInfoForCodeConstSource(codeConstSource); + if (!maybeInfo) + return result::Unexpected("Could not find info for code constant"); + + techset::CommonShaderArgCodeConstValue value{ + .m_index = 0, + .m_first_row = 0, + .m_row_count = 1, + }; + + // All matrices have a transposed version + // this checks whether this is a matrix + if (maybeInfo->transposedMatrix) + { + if (sourceIndex >= 4) + return result::Unexpected(std::format("Index for matrix code const is out of bounds: {} (must be < 4)", sourceIndex)); + + value.m_index = isTransposed ? *maybeInfo->transposedMatrix : codeConstSource; + value.m_first_row = sourceIndex; + } + else + { + const auto arrayCount = std::max(maybeInfo->arrayCount, 1u); + if (sourceIndex >= arrayCount) + return result::Unexpected(std::format("Index for code const is out of bounds: {} (must be < {})", sourceIndex, arrayCount)); + + value.m_index = codeConstSource + static_cast(sourceIndex); + value.m_first_row = 0; + } + + m_args.emplace_back(argumentType, commonDestination, techset::CommonShaderArgValue{.code_const_source = value}); + return NoResult{}; + } + + result::Expected AcceptShaderSamplerArgument(const techset::CommonShaderArgDestination& commonDestination, + const techset::CommonCodeSamplerSource codeSamplerSource) + { + techset::CommonShaderArgumentType argumentType{ + .m_shader_type = m_shader_type, + .m_value_type = techset::CommonShaderValueType::CODE_SAMPLER, + }; + + m_args.emplace_back(argumentType, commonDestination, techset::CommonShaderArgValue{.code_sampler_source = codeSamplerSource}); + return NoResult{}; + } + + [[nodiscard]] virtual size_t CompareArgumentDestinations(const techset::CommonShaderArg& arg0, const techset::CommonShaderArg& arg1) const = 0; + + [[nodiscard]] virtual bool FindDestinationForConstant(techset::CommonShaderArgDestination& commonDestination, + bool& isTransposed, + std::string& errorMessage, + const techset::CommonShaderArgCreatorDestination& input) = 0; + [[nodiscard]] virtual bool FindDestinationForSampler(techset::CommonShaderArgDestination& commonDestination, + std::string& errorMessage, + const techset::CommonShaderArgCreatorDestination& input) = 0; + + virtual result::Expected AutoCreateMissingArgs() = 0; + + techset::ITechniqueShaderLoader& m_shader_loader; + techset::CommonCodeSourceInfos& m_common_code_source_infos; + + techset::CommonTechniqueShaderType m_shader_type; + techset::CommonTechniqueShaderBin m_bin; + + std::vector m_args; + uint64_t m_tech_flags; + unsigned m_sampler_flags; + }; + + class CommonShaderArgCreatorDx9 final : public BaseCommonShaderArgCreator + { + public: + explicit CommonShaderArgCreatorDx9(techset::ITechniqueShaderLoader& shaderLoader, techset::CommonCodeSourceInfos& commonCodeSourceInfos) + : BaseCommonShaderArgCreator(shaderLoader, commonCodeSourceInfos) + { + } + + result::Expected EnterShader(const techset::CommonTechniqueShaderType shaderType, const std::string& name) override + { + auto result = BaseCommonShaderArgCreator::EnterShader(shaderType, name); + if (!result) + return std::move(result); + + m_shader_info = d3d9::ShaderAnalyser::GetShaderInfo(m_bin.m_shader_bin, m_bin.m_shader_bin_size); + if (!m_shader_info) + return result::Unexpected(std::format("Failed to analyse dx9 shader {}", name)); + + return NoResult{}; + } + + result::Expected LeaveShader() override + { + auto result = BaseCommonShaderArgCreator::LeaveShader(); + m_shader_info = nullptr; + + return std::move(result); + } + + protected: + [[nodiscard]] size_t CompareArgumentDestinations(const techset::CommonShaderArg& arg0, const techset::CommonShaderArg& arg1) const override + { + return arg0.m_destination.dx9.m_destination_register < arg1.m_destination.dx9.m_destination_register; + } + + [[nodiscard]] bool FindDestinationForConstant(techset::CommonShaderArgDestination& commonDestination, + bool& isTransposed, + std::string& errorMessage, + const techset::CommonShaderArgCreatorDestination& input) override + { + assert(m_shader_info); + // TODO + return false; + } + + [[nodiscard]] bool FindDestinationForSampler(techset::CommonShaderArgDestination& commonDestination, + std::string& errorMessage, + const techset::CommonShaderArgCreatorDestination& input) override + { + assert(m_shader_info); + // TODO + return false; + } + + result::Expected AutoCreateMissingArgs() override + { + // TODO + return NoResult{}; + } + + private: + std::unique_ptr m_shader_info; + }; + + class CommonShaderArgCreatorDx11 final : public BaseCommonShaderArgCreator + { + public: + explicit CommonShaderArgCreatorDx11(techset::ITechniqueShaderLoader& shaderLoader, techset::CommonCodeSourceInfos& commonCodeSourceInfos) + : BaseCommonShaderArgCreator(shaderLoader, commonCodeSourceInfos) + { + } + + result::Expected EnterShader(const techset::CommonTechniqueShaderType shaderType, const std::string& name) override + { + auto result = BaseCommonShaderArgCreator::EnterShader(shaderType, name); + if (!result) + return std::move(result); + + m_shader_info = d3d11::ShaderAnalyser::GetShaderInfo(m_bin.m_shader_bin, m_bin.m_shader_bin_size); + if (!m_shader_info) + return result::Unexpected(std::format("Failed to analyse dx11 shader {}", name)); + + CountShaderArgs(); + + return NoResult{}; + } + + result::Expected LeaveShader() override + { + auto result = BaseCommonShaderArgCreator::LeaveShader(); + m_shader_info = nullptr; + + return std::move(result); + } + + protected: + [[nodiscard]] size_t CompareArgumentDestinations(const techset::CommonShaderArg& arg0, const techset::CommonShaderArg& arg1) const override + { + if (arg0.m_destination.dx11.m_buffer != arg1.m_destination.dx11.m_buffer) + return arg0.m_destination.dx11.m_buffer < arg1.m_destination.dx11.m_buffer; + + return LocationComparisonValue(arg0) < LocationComparisonValue(arg1); + } + + [[nodiscard]] static size_t LocationComparisonValue(const techset::CommonShaderArg& arg) + { + switch (arg.m_type.m_value_type) + { + case techset::CommonShaderValueType::LITERAL_CONST: + case techset::CommonShaderValueType::MATERIAL_CONST: + case techset::CommonShaderValueType::CODE_CONST: + return arg.m_destination.dx11.m_location.constant_buffer_offset; + case techset::CommonShaderValueType::MATERIAL_SAMPLER: + case techset::CommonShaderValueType::CODE_SAMPLER: + return arg.m_destination.dx11.m_location.sampler_index; + default: + assert(false); + return 0; + } + } + + [[nodiscard]] bool FindDestinationForConstant(techset::CommonShaderArgDestination& commonDestination, + bool& isTransposed, + std::string& errorMessage, + const techset::CommonShaderArgCreatorDestination& input) override + { + assert(m_shader_info); + + auto bufferIndex = 0uz; + auto usedConstantIndex = 0uz; + const auto bufferCount = m_shader_info->m_constant_buffers.size(); + while (bufferIndex < bufferCount) + { + const auto& buffer = m_shader_info->m_constant_buffers[bufferIndex]; + + auto variableIterator = buffer.m_variables.begin(); + const auto variableEnd = buffer.m_variables.end(); + for (; variableIterator != variableEnd; ++variableIterator) + { + if (variableIterator->m_name == input.m_argument_name) + break; + + if (variableIterator->m_is_used) + usedConstantIndex++; + } + + if (variableIterator != variableEnd) + { + const auto variableElementCount = std::max(variableIterator->m_element_count, 1); + const auto inputArgumentIndex = input.m_argument_index.value_or(0); + if (inputArgumentIndex >= variableElementCount) + { + errorMessage = std::format("Shader variable {} only has {} elements", variableIterator->m_name, variableElementCount); + return false; + } + + const auto variableElementSize = variableIterator->m_size / variableElementCount; + commonDestination.dx11.m_location.constant_buffer_offset = variableIterator->m_offset + variableElementSize * inputArgumentIndex; + commonDestination.dx11.m_size = variableElementSize; + commonDestination.dx11.m_buffer = static_cast(bufferIndex); + isTransposed = variableIterator->m_variable_class == d3d11::VariableClass::MATRIX_COLUMNS; + + m_const_arg_added[usedConstantIndex] = true; + + return true; + } + + bufferIndex++; + } + + return false; + } + + [[nodiscard]] bool FindDestinationForSampler(techset::CommonShaderArgDestination& commonDestination, + std::string& errorMessage, + const techset::CommonShaderArgCreatorDestination& input) override + { + assert(m_shader_info); + + // Find texture and its index + size_t textureIndex = 0; + auto maybeTextureResource = m_shader_info->m_bound_resources.begin(); + const auto resourceEnd = m_shader_info->m_bound_resources.end(); + for (; maybeTextureResource != resourceEnd; ++maybeTextureResource) + { + if (maybeTextureResource->m_type != d3d11::BoundResourceType::TEXTURE) + continue; + + if (maybeTextureResource->m_name == input.m_argument_name) + break; + + textureIndex++; + } + + // Find sampler + const auto maybeSamplerResource = + std::ranges::find_if(m_shader_info->m_bound_resources, + [input](const d3d11::BoundResource& boundResource) + { + return boundResource.m_type == d3d11::BoundResourceType::SAMPLER && boundResource.m_name == input.m_argument_name; + }); + + const auto hasTextureResource = maybeTextureResource != resourceEnd; + const auto hasSamplerResource = maybeSamplerResource != resourceEnd; + + if (!hasSamplerResource && !hasTextureResource) + return false; + + if (hasSamplerResource && !hasTextureResource) + { + errorMessage = std::format("Shader binds a sampler for argument {} but not a texture", input.m_argument_name); + return false; + } + assert(hasTextureResource); + + commonDestination.dx11.m_location.texture_index = maybeTextureResource->m_bind_point; + + // The game seems to be fine with not being able to find the sampler + // and just takes the same index as the texture + if (hasSamplerResource) + commonDestination.dx11.m_location.sampler_index = maybeSamplerResource->m_bind_point; + else + commonDestination.dx11.m_location.sampler_index = maybeTextureResource->m_bind_point; + + commonDestination.dx11.m_size = maybeTextureResource->m_bind_count; + commonDestination.dx11.m_buffer = 0; + + m_texture_arg_added[textureIndex] = true; + + return true; + } + + result::Expected AutoCreateMissingArgs() override + { + size_t bufferIndex = 0; + size_t usedConstantCount = 0; + size_t textureCount = 0; + + for (const auto& buffer : m_shader_info->m_constant_buffers) + { + for (const auto& variable : buffer.m_variables) + { + if (!variable.m_is_used) + continue; + + if (m_const_arg_added[usedConstantCount++]) + continue; + + auto result = AutoCreateConstantArg(variable, bufferIndex); + if (!result) + return std::move(result); + } + + bufferIndex++; + } + + for (const auto& maybeTextureResource : m_shader_info->m_bound_resources) + { + if (maybeTextureResource.m_type != d3d11::BoundResourceType::TEXTURE) + continue; + + if (m_texture_arg_added[textureCount++]) + continue; + + const auto maybeSamplerResource = std::ranges::find_if(m_shader_info->m_bound_resources, + [maybeTextureResource](const d3d11::BoundResource& boundResource) + { + return boundResource.m_type == d3d11::BoundResourceType::SAMPLER + && boundResource.m_name == maybeTextureResource.m_name; + }); + + auto result = AutoCreateSamplerArg(maybeTextureResource, + maybeSamplerResource != m_shader_info->m_bound_resources.end() ? maybeSamplerResource->m_bind_point + : maybeTextureResource.m_bind_point); + if (!result) + return std::move(result); + } + + // TODO + return NoResult{}; + } + + private: + void CountShaderArgs() + { + size_t usedConstantCount = 0; + size_t textureCount = 0; + + for (const auto& buffer : m_shader_info->m_constant_buffers) + { + for (const auto& variable : buffer.m_variables) + { + if (variable.m_is_used) + usedConstantCount++; + } + } + + for (const auto& resource : m_shader_info->m_bound_resources) + { + if (resource.m_type == d3d11::BoundResourceType::TEXTURE) + textureCount++; + } + + m_const_arg_added = std::vector(usedConstantCount, false); + m_texture_arg_added = std::vector(textureCount, false); + } + + result::Expected AutoCreateConstantArg(const d3d11::ConstantBufferVariable& variable, const size_t bufferIndex) + { + const auto maybeCodeConst = m_common_code_source_infos.GetCodeConstSourceForAccessor(variable.m_name); + if (!maybeCodeConst) + { + // Some variables are simply not added as args for some reason + if (m_common_code_source_infos.IsArgAccessorIgnored(variable.m_name)) + return NoResult{}; + + return result::Unexpected(std::format("Missing assignment to shader constant {}", variable.m_name)); + } + + const auto constInfo = m_common_code_source_infos.GetInfoForCodeConstSource(*maybeCodeConst); + if (!constInfo) + return result::Unexpected(std::format("Missing info for code const {}", variable.m_name)); + + const auto variableElementCount = std::max(variable.m_element_count, 1); + const auto variableElementSize = variable.m_size / variableElementCount; + 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 ({})", + variable.m_name, + variableElementCount, + infoArrayCount)); + } + + techset::CommonShaderArgDestination commonDestination; + commonDestination.dx11.m_size = variableElementSize; + commonDestination.dx11.m_buffer = static_cast(bufferIndex); + const auto isTransposed = variable.m_variable_class == d3d11::VariableClass::MATRIX_COLUMNS; + 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); + if (!result) + return std::move(result); + } + + return NoResult{}; + } + + result::Expected AutoCreateSamplerArg(const d3d11::BoundResource& textureResource, const unsigned samplerBindPoint) + { + const auto maybeCodeSampler = m_common_code_source_infos.GetCodeSamplerSourceForAccessor(textureResource.m_name); + if (!maybeCodeSampler) + return result::Unexpected(std::format("Missing assignment to shader texture {}", textureResource.m_name)); + + techset::CommonShaderArgDestination commonDestination; + commonDestination.dx11.m_location.texture_index = textureResource.m_bind_point; + commonDestination.dx11.m_location.sampler_index = samplerBindPoint; + commonDestination.dx11.m_size = textureResource.m_bind_count; + commonDestination.dx11.m_buffer = 0; + + return AcceptShaderSamplerArgument(commonDestination, *maybeCodeSampler); + } + + std::unique_ptr m_shader_info; + std::vector m_const_arg_added; + std::vector m_texture_arg_added; + }; +} // namespace + +namespace techset +{ + CommonShaderArgCreatorDestination::CommonShaderArgCreatorDestination(std::string argumentName) + : m_argument_name(std::move(argumentName)) + { + } + + CommonShaderArgCreatorDestination::CommonShaderArgCreatorDestination(std::string argumentName, const unsigned argumentIndex) + : m_argument_name(std::move(argumentName)), + m_argument_index(argumentIndex) + { + } + + std::unique_ptr + CommonShaderArgCreator::CreateDx9(ITechniqueShaderLoader& shaderLoader, AssetCreationContext& context, CommonCodeSourceInfos& commonCodeSourceInfos) + { + return std::make_unique(shaderLoader, commonCodeSourceInfos); + } + + std::unique_ptr + CommonShaderArgCreator::CreateDx11(ITechniqueShaderLoader& shaderLoader, AssetCreationContext& context, CommonCodeSourceInfos& commonCodeSourceInfos) + { + return std::make_unique(shaderLoader, commonCodeSourceInfos); + } +} // namespace techset diff --git a/src/ObjCompiling/Techset/CommonShaderArgCreator.h b/src/ObjCompiling/Techset/CommonShaderArgCreator.h new file mode 100644 index 00000000..80ba54de --- /dev/null +++ b/src/ObjCompiling/Techset/CommonShaderArgCreator.h @@ -0,0 +1,62 @@ +#pragma once + +#include "Asset/AssetCreationContext.h" +#include "Techset/CommonTechnique.h" +#include "Utils/Result.h" + +#include +#include +#include +#include + +namespace techset +{ + class ITechniqueShaderLoader + { + public: + ITechniqueShaderLoader() = default; + virtual ~ITechniqueShaderLoader() = default; + + virtual std::optional LoadVertexShader(const std::string& name) = 0; + virtual std::optional LoadPixelShader(const std::string& name) = 0; + }; + + class CommonShaderArgCreatorDestination + { + public: + std::string m_argument_name; + std::optional m_argument_index; + + CommonShaderArgCreatorDestination() = default; + explicit CommonShaderArgCreatorDestination(std::string argumentName); + CommonShaderArgCreatorDestination(std::string argumentName, unsigned argumentIndex); + }; + + class CommonShaderArgCreator + { + public: + CommonShaderArgCreator() = default; + virtual ~CommonShaderArgCreator() = default; + + virtual result::Expected EnterShader(CommonTechniqueShaderType shaderType, const std::string& name) = 0; + virtual result::Expected LeaveShader() = 0; + + virtual result::Expected + AcceptShaderConstantArgument(const CommonShaderArgCreatorDestination& destination, CommonCodeConstSource codeConstSource, unsigned sourceIndex) = 0; + virtual result::Expected AcceptShaderSamplerArgument(const CommonShaderArgCreatorDestination& destination, + CommonCodeSamplerSource codeSamplerSource) = 0; + virtual result::Expected AcceptShaderLiteralArgument(const CommonShaderArgCreatorDestination& destination, + const std::array& literalValue) = 0; + virtual result::Expected AcceptShaderMaterialArgument(const CommonShaderArgCreatorDestination& destination, + unsigned nameHash) = 0; + virtual result::Expected AcceptShaderMaterialArgument(const CommonShaderArgCreatorDestination& destination, + const std::string& nameValue) = 0; + + virtual result::Expected FinalizePass(techset::CommonTechnique& technique, CommonPass& pass) = 0; + + static std::unique_ptr + CreateDx9(ITechniqueShaderLoader& shaderLoader, AssetCreationContext& context, CommonCodeSourceInfos& commonCodeSourceInfos); + static std::unique_ptr + CreateDx11(ITechniqueShaderLoader& shaderLoader, AssetCreationContext& context, CommonCodeSourceInfos& commonCodeSourceInfos); + }; +} // namespace techset diff --git a/src/ObjCompiling/Techset/CommonTechniqueLoader.cpp b/src/ObjCompiling/Techset/CommonTechniqueLoader.cpp index 4def5bcc..6dd21eac 100644 --- a/src/ObjCompiling/Techset/CommonTechniqueLoader.cpp +++ b/src/ObjCompiling/Techset/CommonTechniqueLoader.cpp @@ -1 +1,47 @@ #include "CommonTechniqueLoader.h" + +#include "Parsing/Impl/CommentRemovingStreamProxy.h" +#include "Parsing/Impl/ParserSingleInputStream.h" +#include "Parsing/Simple/SimpleLexer.h" +#include "Parsing/TechniqueFileParser.h" +#include "Techset/TechsetCommon.h" +#include "Utils/Logging/Log.h" + +namespace techset +{ + std::unique_ptr LoadCommonTechnique(const std::string& techniqueName, + const CommonCodeSourceInfos& codeSourceInfos, + const CommonStreamRoutingInfos& routingInfos, + CommonShaderArgCreator& commonShaderArgCreator, + ISearchPath& searchPath, + bool& failure) + { + failure = false; + + const auto fileName = GetFileNameForTechniqueName(techniqueName); + const auto techniqueFile = searchPath.Open(fileName); + if (!techniqueFile.IsOpen()) + return nullptr; + + SimpleLexer::Config lexerConfig; + lexerConfig.m_emit_new_line_tokens = false; + lexerConfig.m_read_strings = true; + lexerConfig.m_string_escape_sequences = false; + lexerConfig.m_read_integer_numbers = true; + lexerConfig.m_read_floating_point_numbers = true; + + const auto baseStream = std::make_unique(*techniqueFile.m_stream, fileName); + const auto commentProxy = std::make_unique(baseStream.get()); + const auto lexer = std::make_unique(commentProxy.get(), std::move(lexerConfig)); + + const auto parser = std::make_unique(*lexer, techniqueName, codeSourceInfos, routingInfos, commonShaderArgCreator); + + const auto success = parser->Parse(); + if (success) + return parser->GetParsingResult(); + + failure = true; + con::error("Parsing technique file \"{}\" failed!", fileName); + return nullptr; + } +} // namespace techset diff --git a/src/ObjCompiling/Techset/CommonTechniqueLoader.h b/src/ObjCompiling/Techset/CommonTechniqueLoader.h index 70722720..77772ed3 100644 --- a/src/ObjCompiling/Techset/CommonTechniqueLoader.h +++ b/src/ObjCompiling/Techset/CommonTechniqueLoader.h @@ -1,12 +1,18 @@ #pragma once #include "Asset/AssetCreationContext.h" +#include "CommonShaderArgCreator.h" #include "Techset/CommonTechnique.h" #include +#include namespace techset { - std::unique_ptr - LoadCommonTechnique(const AssetCreationContext& context, const CommonCodeSourceInfos& codeSourceInfos, const CommonStreamRoutingInfos& routingInfos); + std::unique_ptr LoadCommonTechnique(const std::string& techniqueName, + const CommonCodeSourceInfos& codeSourceInfos, + const CommonStreamRoutingInfos& routingInfos, + CommonShaderArgCreator& commonShaderArgCreator, + ISearchPath& searchPath, + bool& failure); } // namespace techset diff --git a/src/ObjCompiling/Techset/CommonTechsetCache.cpp b/src/ObjCompiling/Techset/CommonTechsetCache.cpp deleted file mode 100644 index aa089e7b..00000000 --- a/src/ObjCompiling/Techset/CommonTechsetCache.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "CommonTechsetCache.h" - -using namespace techset; - -CommonTechset* CommonTechsetCache::GetCachedTechsetDefinition(const std::string& techsetName) const -{ - const auto foundTechset = m_cache.find(techsetName); - - if (foundTechset != m_cache.end()) - return foundTechset->second.get(); - - return nullptr; -} - -void CommonTechsetCache::AddCommonTechsetToCache(std::string name, std::unique_ptr definition) -{ - m_cache.emplace(std::make_pair(std::move(name), std::move(definition))); -} diff --git a/src/ObjCompiling/Techset/CommonTechsetCache.h b/src/ObjCompiling/Techset/CommonTechsetCache.h deleted file mode 100644 index dea2a1d2..00000000 --- a/src/ObjCompiling/Techset/CommonTechsetCache.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "Asset/IZoneAssetCreationState.h" -#include "Techset/CommonTechset.h" - -#include -#include -#include - -namespace techset -{ - class CommonTechsetCache final : public IZoneAssetCreationState - { - public: - [[nodiscard]] CommonTechset* GetCachedTechsetDefinition(const std::string& techsetName) const; - void AddCommonTechsetToCache(std::string name, std::unique_ptr definition); - - private: - std::unordered_map> m_cache; - }; -} // namespace techset diff --git a/src/ObjCompiling/Techset/CommonTechsetLoader.cpp b/src/ObjCompiling/Techset/CommonTechsetLoader.cpp index 407f8f80..faa78f90 100644 --- a/src/ObjCompiling/Techset/CommonTechsetLoader.cpp +++ b/src/ObjCompiling/Techset/CommonTechsetLoader.cpp @@ -9,7 +9,6 @@ #include "Utils/Logging/Log.h" #include -#include #include #include diff --git a/src/ObjCompiling/Techset/LiteralConstsZoneState.h b/src/ObjCompiling/Techset/LiteralConstsZoneState.h new file mode 100644 index 00000000..cb145132 --- /dev/null +++ b/src/ObjCompiling/Techset/LiteralConstsZoneState.h @@ -0,0 +1,131 @@ +#pragma once + +#include "Asset/IZoneAssetCreationState.h" + +#include +#include +#include + +namespace techset +{ + template class LiteralConst + { + public: + using game_ptr_t = const T (*)[4]; + + LiteralConst() = default; + + LiteralConst(T v0, T v1, T v2, T v3) + : m_value({v0, v1, v2, v3}) + { + } + + explicit LiteralConst(std::array value) + : m_value(value) + { + } + + friend bool operator<(const LiteralConst& lhs, const LiteralConst& rhs) + { + if (lhs.m_value[0] < rhs.m_value[0]) + return true; + if (lhs.m_value[0] > rhs.m_value[0]) + return false; + if (lhs.m_value[1] < rhs.m_value[1]) + return true; + if (lhs.m_value[1] > rhs.m_value[1]) + return false; + if (lhs.m_value[2] < rhs.m_value[2]) + return true; + if (lhs.m_value[2] > rhs.m_value[2]) + return false; + if (lhs.m_value[3] < rhs.m_value[3]) + return true; + if (lhs.m_value[3] > rhs.m_value[3]) + return false; + return false; + } + + friend bool operator==(const LiteralConst& lhs, const LiteralConst& rhs) + { + return lhs.m_value == rhs.m_value; + } + + friend bool operator!=(const LiteralConst& lhs, const LiteralConst& rhs) + { + return !(lhs == rhs); + } + + friend bool operator<=(const LiteralConst& lhs, const LiteralConst& rhs) + { + return !(rhs < lhs); + } + + friend bool operator>(const LiteralConst& lhs, const LiteralConst& rhs) + { + return rhs < lhs; + } + + friend bool operator>=(const LiteralConst& lhs, const LiteralConst& rhs) + { + return !(lhs < rhs); + } + + game_ptr_t GamePtr() const + { + return reinterpret_cast(m_value.data()); + } + + std::array m_value; + }; + + template struct LiteralConstHash + { + std::size_t operator()(const LiteralConst& v) const noexcept + { + std::size_t seed = 0x1DDB76B3; + seed ^= (seed << 6) + (seed >> 2) + 0x0354144B + std::hash()(v.m_value[0]); + seed ^= (seed << 6) + (seed >> 2) + 0x66847B5C + std::hash()(v.m_value[1]); + seed ^= (seed << 6) + (seed >> 2) + 0x77399D60 + std::hash()(v.m_value[2]); + seed ^= (seed << 6) + (seed >> 2) + 0x477AF9AB + std::hash()(v.m_value[3]); + return seed; + } + }; + + template class LiteralConstsZoneState : public IZoneAssetCreationState + { + public: + using literal_t = LiteralConst; + + LiteralConstsZoneState() + : m_memory(nullptr) + { + } + + void Inject(ZoneAssetCreationInjection& inject) override + { + m_memory = &inject.m_zone.Memory(); + } + + literal_t* GetAllocatedLiteral(const literal_t& literal) + { + const auto& existingEntry = m_allocated_literals.find(literal); + + if (existingEntry != m_allocated_literals.end()) + return existingEntry->second; + + auto* newLiteral = m_memory->Alloc(); + newLiteral->m_value[0] = literal.m_value[0]; + newLiteral->m_value[1] = literal.m_value[1]; + newLiteral->m_value[2] = literal.m_value[2]; + newLiteral->m_value[3] = literal.m_value[3]; + m_allocated_literals.emplace(literal, newLiteral); + + return newLiteral; + } + + private: + std::unordered_map> m_allocated_literals; + MemoryManager* m_memory; + }; +} // namespace techset diff --git a/src/ObjCompiling/Techset/Parsing/Sequence/TechniqueNoScopeSequences.cpp b/src/ObjCompiling/Techset/Parsing/Sequence/TechniqueNoScopeSequences.cpp index f94e1a71..baad556e 100644 --- a/src/ObjCompiling/Techset/Parsing/Sequence/TechniqueNoScopeSequences.cpp +++ b/src/ObjCompiling/Techset/Parsing/Sequence/TechniqueNoScopeSequences.cpp @@ -23,10 +23,8 @@ namespace techset protected: void ProcessMatch(TechniqueParserState* state, SequenceResult& result) const override { - assert(state->m_in_pass == false); - state->m_in_pass = true; - - state->m_acceptor->AcceptNextPass(); + assert(!state->m_current_pass); + state->m_current_pass = CommonPass(); } }; } // namespace techset diff --git a/src/ObjCompiling/Techset/Parsing/Sequence/TechniquePassScopeSequences.cpp b/src/ObjCompiling/Techset/Parsing/Sequence/TechniquePassScopeSequences.cpp index fca643b8..e61d5292 100644 --- a/src/ObjCompiling/Techset/Parsing/Sequence/TechniquePassScopeSequences.cpp +++ b/src/ObjCompiling/Techset/Parsing/Sequence/TechniquePassScopeSequences.cpp @@ -26,20 +26,22 @@ namespace techset protected: void ProcessMatch(TechniqueParserState* state, SequenceResult& result) const override { - assert(state->m_in_pass == true); + assert(state->m_current_pass); + assert(state->m_technique); - std::string errorMessage; - if (!state->m_acceptor->AcceptEndPass(errorMessage)) - throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), errorMessage); + auto finalizeResult = state->m_shader_arg_creator.FinalizePass(*state->m_technique, *state->m_current_pass); + if (!finalizeResult.has_value()) + throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), finalizeResult.error()); - state->m_in_pass = false; + state->m_current_pass->m_vertex_declaration.SortRoutingEntries(); + state->m_technique->m_passes.emplace_back(std::move(*state->m_current_pass)); + state->m_current_pass = std::nullopt; } }; class SequenceStateMap final : public TechniqueParser::sequence_t { - static constexpr auto CAPTURE_START = 1; - static constexpr auto CAPTURE_STATE_MAP_NAME = 2; + static constexpr auto CAPTURE_STATE_MAP_NAME = 1; public: SequenceStateMap() @@ -47,7 +49,7 @@ namespace techset const SimpleMatcherFactory create(this); AddMatchers({ - create.Keyword("stateMap").Capture(CAPTURE_START), + create.Keyword("stateMap"), create.String().Capture(CAPTURE_STATE_MAP_NAME), create.Char(';'), }); @@ -56,13 +58,9 @@ namespace techset protected: void ProcessMatch(TechniqueParserState* state, SequenceResult& result) const override { - const auto& firstToken = result.NextCapture(CAPTURE_START); + assert(state->m_current_pass); - std::string errorMessage; - const auto acceptorResult = state->m_acceptor->AcceptStateMap(result.NextCapture(CAPTURE_STATE_MAP_NAME).StringValue(), errorMessage); - - if (!acceptorResult) - throw ParsingException(firstToken.GetPos(), std::move(errorMessage)); + state->m_current_pass->m_state_map = result.NextCapture(CAPTURE_STATE_MAP_NAME).StringValue(); } }; @@ -71,7 +69,7 @@ namespace techset static constexpr auto TAG_VERTEX_SHADER = 1; static constexpr auto TAG_PIXEL_SHADER = 2; - static constexpr auto CAPTURE_START = 1; + static constexpr auto CAPTURE_FIRST_TOKEN = 1; static constexpr auto CAPTURE_VERSION = 2; static constexpr auto CAPTURE_VERSION_MAJOR = 3; static constexpr auto CAPTURE_VERSION_MINOR = 4; @@ -88,7 +86,7 @@ namespace techset create.Keyword("vertexShader").Tag(TAG_VERTEX_SHADER), create.Keyword("pixelShader").Tag(TAG_PIXEL_SHADER), }) - .Capture(CAPTURE_START), + .Capture(CAPTURE_FIRST_TOKEN), create.Or({ create.And({ create.Integer().Capture(CAPTURE_VERSION_MAJOR), @@ -106,31 +104,23 @@ namespace techset protected: void ProcessMatch(TechniqueParserState* state, SequenceResult& result) const override { - const auto& firstToken = result.NextCapture(CAPTURE_START); - // Don't care about shader version since it's stated in the shader bin anyway const auto& shaderNameToken = result.NextCapture(CAPTURE_SHADER_NAME); - bool acceptorResult; - std::string errorMessage; const auto shaderTag = result.NextTag(); assert(shaderTag == TAG_VERTEX_SHADER || shaderTag == TAG_PIXEL_SHADER); + if (shaderTag == TAG_VERTEX_SHADER) - { - acceptorResult = state->m_acceptor->AcceptVertexShader(shaderNameToken.StringValue(), errorMessage); - state->m_current_shader = ShaderSelector::VERTEX_SHADER; - } + state->m_current_shader_type = CommonTechniqueShaderType::VERTEX; else - { - acceptorResult = state->m_acceptor->AcceptPixelShader(shaderNameToken.StringValue(), errorMessage); - state->m_current_shader = ShaderSelector::PIXEL_SHADER; - } + state->m_current_shader_type = CommonTechniqueShaderType::PIXEL; - state->m_in_shader = true; + state->m_current_shader = CommonTechniqueShader(state->m_current_shader_type, shaderNameToken.StringValue()); - if (!acceptorResult) - throw ParsingException(firstToken.GetPos(), std::move(errorMessage)); + auto enterResult = state->m_shader_arg_creator.EnterShader(state->m_current_shader->m_type, state->m_current_shader->m_name); + if (!enterResult.has_value()) + throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), enterResult.error()); } }; @@ -191,13 +181,23 @@ namespace techset protected: void ProcessMatch(TechniqueParserState* state, SequenceResult& result) const override { - const auto& firstToken = result.NextCapture(CAPTURE_FIRST_TOKEN); - const std::string destinationString = CreateRoutingString(result, CAPTURE_STREAM_DESTINATION_NAME, CAPTURE_STREAM_DESTINATION_INDEX); - const std::string sourceString = CreateRoutingString(result, CAPTURE_STREAM_SOURCE_NAME, CAPTURE_STREAM_SOURCE_INDEX); + assert(state->m_current_pass); - std::string errorMessage; - if (!state->m_acceptor->AcceptVertexStreamRouting(destinationString, sourceString, errorMessage)) - throw ParsingException(firstToken.GetPos(), std::move(errorMessage)); + const auto& firstToken = result.NextCapture(CAPTURE_FIRST_TOKEN); + + const std::string destinationString = CreateRoutingString(result, CAPTURE_STREAM_DESTINATION_NAME, CAPTURE_STREAM_DESTINATION_INDEX); + const auto maybeDestination = state->m_routing_infos.GetDestinationByName(destinationString); + + if (!maybeDestination.has_value()) + throw ParsingException(firstToken.GetPos(), "Unknown routing destination"); + + const std::string sourceString = CreateRoutingString(result, CAPTURE_STREAM_SOURCE_NAME, CAPTURE_STREAM_SOURCE_INDEX); + const auto maybeSource = state->m_routing_infos.GetSourceByName(sourceString); + + if (!maybeSource.has_value()) + throw ParsingException(firstToken.GetPos(), "Unknown routing source"); + + state->m_current_pass->m_vertex_declaration.m_routing.emplace_back(*maybeSource, *maybeDestination); } }; } // namespace techset diff --git a/src/ObjCompiling/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.cpp b/src/ObjCompiling/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.cpp index 5811a145..17dbd95c 100644 --- a/src/ObjCompiling/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.cpp +++ b/src/ObjCompiling/Techset/Parsing/Sequence/TechniqueShaderScopeSequences.cpp @@ -1,6 +1,7 @@ #include "TechniqueShaderScopeSequences.h" #include "Parsing/Simple/Matcher/SimpleMatcherFactory.h" +#include "Techset/CommonShaderArgCreator.h" #include @@ -10,21 +11,34 @@ namespace techset { class SequenceEndShader final : public TechniqueParser::sequence_t { + static constexpr auto CAPTURE_FIRST_TOKEN = 1; + public: SequenceEndShader() { const SimpleMatcherFactory create(this); AddMatchers({ - create.Char('}'), + create.Char('}').Capture(CAPTURE_FIRST_TOKEN), }); } protected: void ProcessMatch(TechniqueParserState* state, SequenceResult& result) const override { - assert(state->m_in_shader == true); - state->m_in_shader = false; + assert(state->m_current_pass); + assert(state->m_current_shader); + + if (state->m_current_shader_type == CommonTechniqueShaderType::VERTEX) + state->m_current_pass->m_vertex_shader = std::move(*state->m_current_shader); + else + state->m_current_pass->m_pixel_shader = std::move(*state->m_current_shader); + + state->m_current_shader = std::nullopt; + + auto leaveShaderResult = state->m_shader_arg_creator.LeaveShader(); + if (!leaveShaderResult.has_value()) + throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), leaveShaderResult.error()); } }; @@ -134,40 +148,126 @@ namespace techset }); } - static void ProcessCodeArgument(const TechniqueParserState* state, SequenceResult& result, ShaderArgument arg, const bool isSampler) + protected: + void ProcessMatch(TechniqueParserState* state, SequenceResult& result) const override { - std::vector accessors; - while (result.HasNextCapture(CAPTURE_CODE_ACCESSOR)) - accessors.emplace_back(result.NextCapture(CAPTURE_CODE_ACCESSOR).IdentifierValue()); + assert(state->m_current_shader); - ShaderArgumentCodeSource source; - if (result.HasNextCapture(CAPTURE_CODE_INDEX)) + const auto& shaderArgumentNameToken = result.NextCapture(CAPTURE_SHADER_ARGUMENT); + + CommonShaderArgCreatorDestination destination; + if (result.HasNextCapture(CAPTURE_SHADER_INDEX)) { - const auto& codeIndexToken = result.NextCapture(CAPTURE_CODE_INDEX); - if (codeIndexToken.IntegerValue() < 0) - throw ParsingException(codeIndexToken.GetPos(), "Index cannot be negative"); - source = ShaderArgumentCodeSource(std::move(accessors), static_cast(codeIndexToken.IntegerValue())); + const auto& shaderArgumentIndexToken = result.NextCapture(CAPTURE_SHADER_INDEX); + if (shaderArgumentIndexToken.IntegerValue() < 0) + throw ParsingException(shaderArgumentIndexToken.GetPos(), "Index cannot be negative"); + const auto index = static_cast(shaderArgumentIndexToken.IntegerValue()); + destination = CommonShaderArgCreatorDestination(shaderArgumentNameToken.IdentifierValue(), index); } else - source = ShaderArgumentCodeSource(std::move(accessors)); + destination = CommonShaderArgCreatorDestination(shaderArgumentNameToken.IdentifierValue()); - std::string errorMessage; - if (!isSampler) + const auto typeTag = result.NextTag(); + assert(typeTag == TAG_CONSTANT || typeTag == TAG_SAMPLER || typeTag == TAG_LITERAL || typeTag == TAG_MATERIAL); + + if (typeTag == TAG_CONSTANT || typeTag == TAG_SAMPLER) { - if (!state->m_acceptor->AcceptShaderConstantArgument(state->m_current_shader, std::move(arg), std::move(source), errorMessage)) - throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), std::move(errorMessage)); + ProcessCodeArgument(state, result, destination, typeTag == TAG_SAMPLER); + } + else if (typeTag == TAG_LITERAL) + { + ProcessLiteralArgument(state, result, destination); } else { - if (!state->m_acceptor->AcceptShaderSamplerArgument(state->m_current_shader, std::move(arg), std::move(source), errorMessage)) - throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), std::move(errorMessage)); + ProcessMaterialArgument(state, result, destination); } } - static void ProcessLiteralArgument(const TechniqueParserState* state, SequenceResult& result, ShaderArgument arg) + private: + static void ProcessCodeArgument(const TechniqueParserState* state, + SequenceResult& result, + const CommonShaderArgCreatorDestination& destination, + const bool isSampler) { - float value[4]; - for (float& i : value) + const auto accessor = GetAccessorValue(result); + + union + { + CommonCodeConstSource constSource; + CommonCodeSamplerSource samplerSource; + }; + + unsigned sourceIndex = 0u; + + if (isSampler) + { + const auto maybeSamplerSource = state->m_code_source_infos.GetCodeSamplerSourceForAccessor(accessor); + if (!maybeSamplerSource.has_value()) + throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), "Unknown code sampler"); + + samplerSource = *maybeSamplerSource; + } + else + { + const auto maybeConstSource = state->m_code_source_infos.GetCodeConstSourceForAccessor(accessor); + if (!maybeConstSource.has_value()) + throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), "Unknown code constant"); + + constSource = *maybeConstSource; + } + + if (result.HasNextCapture(CAPTURE_CODE_INDEX)) + { + if (isSampler) + throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), "Code sampler is not an array"); + + const auto& codeIndexToken = result.NextCapture(CAPTURE_CODE_INDEX); + const auto indexIntValue = codeIndexToken.IntegerValue(); + if (indexIntValue < 0) + throw ParsingException(codeIndexToken.GetPos(), "Index cannot be negative"); + + sourceIndex = static_cast(indexIntValue); + + size_t codeArraySize = state->m_code_source_infos.GetInfoForCodeConstSource(constSource)->arrayCount; + + if (codeArraySize == 0) + throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), "Code constant is not an array"); + + if (codeArraySize <= sourceIndex) + { + throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), + std::format("Array overflow: Code array has size {}", codeArraySize)); + } + } + + result::Expected shaderCreatorResult(NoResult{}); + if (isSampler) + shaderCreatorResult = state->m_shader_arg_creator.AcceptShaderSamplerArgument(destination, samplerSource); + else + shaderCreatorResult = state->m_shader_arg_creator.AcceptShaderConstantArgument(destination, constSource, sourceIndex); + + if (!shaderCreatorResult.has_value()) + throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), std::move(shaderCreatorResult.error())); + } + + static std::string GetAccessorValue(SequenceResult& result) + { + std::ostringstream accessorStream; + + accessorStream << result.NextCapture(CAPTURE_CODE_ACCESSOR).IdentifierValue(); + while (result.HasNextCapture(CAPTURE_CODE_ACCESSOR)) + accessorStream << '.' << result.NextCapture(CAPTURE_CODE_ACCESSOR).IdentifierValue(); + + return accessorStream.str(); + } + + static void ProcessLiteralArgument(const TechniqueParserState* state, + SequenceResult& result, + const CommonShaderArgCreatorDestination& destination) + { + std::array argValue; + for (float& i : argValue) { const auto& literalValueToken = result.NextCapture(CAPTURE_LITERAL_VALUE); @@ -177,56 +277,30 @@ namespace techset i = static_cast(literalValueToken.IntegerValue()); } - const ShaderArgumentLiteralSource source(value); - std::string errorMessage; - if (!state->m_acceptor->AcceptShaderLiteralArgument(state->m_current_shader, std::move(arg), source, errorMessage)) - throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), std::move(errorMessage)); + auto shaderCreatorResult = state->m_shader_arg_creator.AcceptShaderLiteralArgument(destination, argValue); + + if (!shaderCreatorResult.has_value()) + throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), std::move(shaderCreatorResult.error())); } - static void ProcessMaterialArgument(const TechniqueParserState* state, SequenceResult& result, ShaderArgument arg) + static void ProcessMaterialArgument(const TechniqueParserState* state, + SequenceResult& result, + const CommonShaderArgCreatorDestination& destination) { - std::string errorMessage; + result::Expected shaderCreatorResult(NoResult{}); if (result.HasNextCapture(CAPTURE_MATERIAL_HASH)) { - ShaderArgumentMaterialSource source(static_cast(result.NextCapture(CAPTURE_MATERIAL_HASH).IntegerValue())); - if (!state->m_acceptor->AcceptShaderMaterialArgument(state->m_current_shader, std::move(arg), std::move(source), errorMessage)) - throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), std::move(errorMessage)); + shaderCreatorResult = state->m_shader_arg_creator.AcceptShaderMaterialArgument( + destination, static_cast(result.NextCapture(CAPTURE_MATERIAL_HASH).IntegerValue())); } else { - ShaderArgumentMaterialSource source(result.NextCapture(CAPTURE_MATERIAL_NAME).IdentifierValue()); - if (!state->m_acceptor->AcceptShaderMaterialArgument(state->m_current_shader, std::move(arg), std::move(source), errorMessage)) - throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), std::move(errorMessage)); + const auto stringValue = result.NextCapture(CAPTURE_MATERIAL_NAME).IdentifierValue(); + shaderCreatorResult = state->m_shader_arg_creator.AcceptShaderMaterialArgument(destination, stringValue); } - } - protected: - void ProcessMatch(TechniqueParserState* state, SequenceResult& result) const override - { - assert(state->m_in_shader == true); - - const auto& shaderArgumentNameToken = result.NextCapture(CAPTURE_SHADER_ARGUMENT); - - ShaderArgument arg; - if (result.HasNextCapture(CAPTURE_SHADER_INDEX)) - { - const auto& shaderArgumentIndexToken = result.NextCapture(CAPTURE_SHADER_INDEX); - if (shaderArgumentIndexToken.IntegerValue() < 0) - throw ParsingException(shaderArgumentIndexToken.GetPos(), "Index cannot be negative"); - const auto index = static_cast(shaderArgumentIndexToken.IntegerValue()); - arg = ShaderArgument(shaderArgumentNameToken.IdentifierValue(), index); - } - else - arg = ShaderArgument(shaderArgumentNameToken.IdentifierValue()); - - const auto typeTag = result.NextTag(); - assert(typeTag == TAG_CONSTANT || typeTag == TAG_SAMPLER || typeTag == TAG_LITERAL || typeTag == TAG_MATERIAL); - if (typeTag == TAG_CONSTANT || typeTag == TAG_SAMPLER) - ProcessCodeArgument(state, result, std::move(arg), typeTag == TAG_SAMPLER); - else if (typeTag == TAG_LITERAL) - ProcessLiteralArgument(state, result, std::move(arg)); - else - ProcessMaterialArgument(state, result, std::move(arg)); + if (!shaderCreatorResult.has_value()) + throw ParsingException(result.NextCapture(CAPTURE_FIRST_TOKEN).GetPos(), std::move(shaderCreatorResult.error())); } }; } // namespace techset diff --git a/src/ObjCompiling/Techset/Parsing/TechniqueFileParser.cpp b/src/ObjCompiling/Techset/Parsing/TechniqueFileParser.cpp index 1032d6ed..9159ad3e 100644 --- a/src/ObjCompiling/Techset/Parsing/TechniqueFileParser.cpp +++ b/src/ObjCompiling/Techset/Parsing/TechniqueFileParser.cpp @@ -4,20 +4,30 @@ #include "Sequence/TechniquePassScopeSequences.h" #include "Sequence/TechniqueShaderScopeSequences.h" -using namespace techset; - -TechniqueParser::TechniqueParser(SimpleLexer* lexer, ITechniqueDefinitionAcceptor* acceptor) - : AbstractParser(lexer, std::make_unique(acceptor)) +namespace techset { -} + TechniqueParser::TechniqueParser(SimpleLexer& lexer, + std::string techniqueName, + const CommonCodeSourceInfos& codeSourceInfos, + const CommonStreamRoutingInfos& routingInfos, + CommonShaderArgCreator& shaderArgCreator) + : AbstractParser(&lexer, std::make_unique(std::move(techniqueName), codeSourceInfos, routingInfos, shaderArgCreator)) + { + } -const std::vector& TechniqueParser::GetTestsForState() -{ - if (m_state->m_in_shader) - return TechniqueShaderScopeSequences::GetSequences(); + std::unique_ptr TechniqueParser::GetParsingResult() const + { + return std::move(m_state->m_technique); + } - if (m_state->m_in_pass) - return TechniquePassScopeSequences::GetSequences(); + const std::vector& TechniqueParser::GetTestsForState() + { + if (m_state->m_current_shader.has_value()) + return TechniqueShaderScopeSequences::GetSequences(); - return TechniqueNoScopeSequences::GetSequences(); -} + if (m_state->m_current_pass.has_value()) + return TechniquePassScopeSequences::GetSequences(); + + return TechniqueNoScopeSequences::GetSequences(); + } +} // namespace techset diff --git a/src/ObjCompiling/Techset/Parsing/TechniqueFileParser.h b/src/ObjCompiling/Techset/Parsing/TechniqueFileParser.h index 8944f573..b0232bd0 100644 --- a/src/ObjCompiling/Techset/Parsing/TechniqueFileParser.h +++ b/src/ObjCompiling/Techset/Parsing/TechniqueFileParser.h @@ -4,15 +4,21 @@ #include "Parsing/Simple/SimpleLexer.h" #include "Parsing/Simple/SimpleParserValue.h" #include "TechniqueFileParserState.h" +#include "Techset/CommonTechnique.h" namespace techset { class TechniqueParser final : public AbstractParser { + public: + TechniqueParser(SimpleLexer& lexer, + std::string techniqueName, + const CommonCodeSourceInfos& codeSourceInfos, + const CommonStreamRoutingInfos& routingInfos, + CommonShaderArgCreator& shaderArgCreator); + [[nodiscard]] std::unique_ptr GetParsingResult() const; + protected: const std::vector& GetTestsForState() override; - - public: - TechniqueParser(SimpleLexer* lexer, ITechniqueDefinitionAcceptor* acceptor); }; } // namespace techset diff --git a/src/ObjCompiling/Techset/Parsing/TechniqueFileParserState.cpp b/src/ObjCompiling/Techset/Parsing/TechniqueFileParserState.cpp index 97cdfa52..d0a42cf9 100644 --- a/src/ObjCompiling/Techset/Parsing/TechniqueFileParserState.cpp +++ b/src/ObjCompiling/Techset/Parsing/TechniqueFileParserState.cpp @@ -1,14 +1,16 @@ #include "TechniqueFileParserState.h" -#include - -using namespace techset; - -TechniqueParserState::TechniqueParserState(ITechniqueDefinitionAcceptor* acceptor) - : m_acceptor(acceptor), - m_in_pass(false), - m_in_shader(false), - m_current_shader(ShaderSelector::VERTEX_SHADER) +namespace techset { - assert(acceptor); -} + TechniqueParserState::TechniqueParserState(std::string techniqueName, + const CommonCodeSourceInfos& codeSourceInfos, + const CommonStreamRoutingInfos& routingInfos, + CommonShaderArgCreator& shaderArgCreator) + : m_technique(std::make_unique(std::move(techniqueName))), + m_code_source_infos(codeSourceInfos), + m_routing_infos(routingInfos), + m_shader_arg_creator(shaderArgCreator), + m_current_shader_type(CommonTechniqueShaderType::VERTEX) + { + } +} // namespace techset diff --git a/src/ObjCompiling/Techset/Parsing/TechniqueFileParserState.h b/src/ObjCompiling/Techset/Parsing/TechniqueFileParserState.h index b97b143c..2e3d775c 100644 --- a/src/ObjCompiling/Techset/Parsing/TechniqueFileParserState.h +++ b/src/ObjCompiling/Techset/Parsing/TechniqueFileParserState.h @@ -1,18 +1,28 @@ #pragma once -#include "Techset/TechniqueDefinitionAcceptor.h" +#include "Techset/CommonShaderArgCreator.h" +#include "Techset/CommonTechnique.h" + +#include namespace techset { class TechniqueParserState { public: - explicit TechniqueParserState(ITechniqueDefinitionAcceptor* acceptor); + TechniqueParserState(std::string techniqueName, + const CommonCodeSourceInfos& codeSourceInfos, + const CommonStreamRoutingInfos& routingInfos, + CommonShaderArgCreator& shaderArgCreator); - ITechniqueDefinitionAcceptor* const m_acceptor; + std::unique_ptr m_technique; - bool m_in_pass; - bool m_in_shader; - ShaderSelector m_current_shader; + const CommonCodeSourceInfos& m_code_source_infos; + const CommonStreamRoutingInfos& m_routing_infos; + CommonShaderArgCreator& m_shader_arg_creator; + + std::optional m_current_pass; + std::optional m_current_shader; + CommonTechniqueShaderType m_current_shader_type; }; } // namespace techset diff --git a/src/ObjCompiling/Techset/StateMap/StateMapFromTechniqueExtractor.cpp b/src/ObjCompiling/Techset/StateMap/StateMapFromTechniqueExtractor.cpp deleted file mode 100644 index 473d08c2..00000000 --- a/src/ObjCompiling/Techset/StateMap/StateMapFromTechniqueExtractor.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "StateMapFromTechniqueExtractor.h" - -using namespace state_map; - -std::string StateMapFromTechniqueExtractor::RetrieveStateMap() -{ - return std::move(m_state_map); -} - -void StateMapFromTechniqueExtractor::AcceptNextPass() {} - -bool StateMapFromTechniqueExtractor::AcceptEndPass(std::string& errorMessage) -{ - return true; -} - -bool StateMapFromTechniqueExtractor::AcceptStateMap(const std::string& stateMapName, std::string& errorMessage) -{ - m_state_map = stateMapName; - return true; -} - -bool StateMapFromTechniqueExtractor::AcceptVertexShader(const std::string& vertexShaderName, std::string& errorMessage) -{ - return true; -} - -bool StateMapFromTechniqueExtractor::AcceptPixelShader(const std::string& pixelShaderName, std::string& errorMessage) -{ - return true; -} - -bool StateMapFromTechniqueExtractor::AcceptShaderConstantArgument(techset::ShaderSelector shader, - techset::ShaderArgument shaderArgument, - techset::ShaderArgumentCodeSource source, - std::string& errorMessage) -{ - return true; -} - -bool StateMapFromTechniqueExtractor::AcceptShaderSamplerArgument(techset::ShaderSelector shader, - techset::ShaderArgument shaderArgument, - techset::ShaderArgumentCodeSource source, - std::string& errorMessage) -{ - return true; -} - -bool StateMapFromTechniqueExtractor::AcceptShaderLiteralArgument(techset::ShaderSelector shader, - techset::ShaderArgument shaderArgument, - techset::ShaderArgumentLiteralSource source, - std::string& errorMessage) -{ - return true; -} - -bool StateMapFromTechniqueExtractor::AcceptShaderMaterialArgument(techset::ShaderSelector shader, - techset::ShaderArgument shaderArgument, - techset::ShaderArgumentMaterialSource source, - std::string& errorMessage) -{ - return true; -} - -bool StateMapFromTechniqueExtractor::AcceptVertexStreamRouting(const std::string& destination, const std::string& source, std::string& errorMessage) -{ - return true; -} diff --git a/src/ObjCompiling/Techset/StateMap/StateMapFromTechniqueExtractor.h b/src/ObjCompiling/Techset/StateMap/StateMapFromTechniqueExtractor.h deleted file mode 100644 index 48f70d9d..00000000 --- a/src/ObjCompiling/Techset/StateMap/StateMapFromTechniqueExtractor.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include "Techset/TechniqueDefinitionAcceptor.h" - -#include - -namespace state_map -{ - class StateMapFromTechniqueExtractor final : public techset::ITechniqueDefinitionAcceptor - { - public: - std::string RetrieveStateMap(); - - void AcceptNextPass() override; - bool AcceptEndPass(std::string& errorMessage) override; - bool AcceptStateMap(const std::string& stateMapName, std::string& errorMessage) override; - bool AcceptVertexShader(const std::string& vertexShaderName, std::string& errorMessage) override; - bool AcceptPixelShader(const std::string& pixelShaderName, std::string& errorMessage) override; - bool AcceptShaderConstantArgument(techset::ShaderSelector shader, - techset::ShaderArgument shaderArgument, - techset::ShaderArgumentCodeSource source, - std::string& errorMessage) override; - bool AcceptShaderSamplerArgument(techset::ShaderSelector shader, - techset::ShaderArgument shaderArgument, - techset::ShaderArgumentCodeSource source, - std::string& errorMessage) override; - bool AcceptShaderLiteralArgument(techset::ShaderSelector shader, - techset::ShaderArgument shaderArgument, - techset::ShaderArgumentLiteralSource source, - std::string& errorMessage) override; - bool AcceptShaderMaterialArgument(techset::ShaderSelector shader, - techset::ShaderArgument shaderArgument, - techset::ShaderArgumentMaterialSource source, - std::string& errorMessage) override; - bool AcceptVertexStreamRouting(const std::string& destination, const std::string& source, std::string& errorMessage) override; - - private: - std::string m_state_map; - }; -} // namespace state_map diff --git a/src/ObjCompiling/Techset/StateMap/StateMapReader.h b/src/ObjCompiling/Techset/StateMap/StateMapReader.h index f3c53161..c1bda74f 100644 --- a/src/ObjCompiling/Techset/StateMap/StateMapReader.h +++ b/src/ObjCompiling/Techset/StateMap/StateMapReader.h @@ -4,7 +4,6 @@ #include "Parsing/StateMapParserState.h" #include "StateMapDefinition.h" #include "Techset/StateMap/StateMapLayout.h" -#include "Utils/ClassUtils.h" #include #include @@ -22,7 +21,7 @@ namespace state_map public: StateMapReader(std::istream& stream, std::string fileName, std::string stateMapName, const StateMapLayout& layout); - _NODISCARD bool IsValidEndState(const StateMapParserState* state) const; - _NODISCARD std::unique_ptr ReadStateMapDefinition() const; + [[nodiscard]] bool IsValidEndState(const StateMapParserState* state) const; + [[nodiscard]] std::unique_ptr ReadStateMapDefinition() const; }; } // namespace state_map diff --git a/src/ObjCompiling/Techset/TechniqueStateMapCache.cpp b/src/ObjCompiling/Techset/StateMap/TechniqueStateMapCache.cpp similarity index 100% rename from src/ObjCompiling/Techset/TechniqueStateMapCache.cpp rename to src/ObjCompiling/Techset/StateMap/TechniqueStateMapCache.cpp diff --git a/src/ObjCompiling/Techset/TechniqueStateMapCache.h b/src/ObjCompiling/Techset/StateMap/TechniqueStateMapCache.h similarity index 69% rename from src/ObjCompiling/Techset/TechniqueStateMapCache.h rename to src/ObjCompiling/Techset/StateMap/TechniqueStateMapCache.h index aaf8b245..be1d8af8 100644 --- a/src/ObjCompiling/Techset/TechniqueStateMapCache.h +++ b/src/ObjCompiling/Techset/StateMap/TechniqueStateMapCache.h @@ -1,8 +1,7 @@ #pragma once #include "Asset/IZoneAssetCreationState.h" -#include "StateMap/StateMapDefinition.h" -#include "Utils/ClassUtils.h" +#include "Techset/StateMap/StateMapDefinition.h" #include #include @@ -13,10 +12,10 @@ namespace techset class TechniqueStateMapCache final : public IZoneAssetCreationState { public: - _NODISCARD const state_map::StateMapDefinition* GetCachedStateMap(const std::string& name) const; + [[nodiscard]] const state_map::StateMapDefinition* GetCachedStateMap(const std::string& name) const; void AddStateMapToCache(std::unique_ptr stateMap); - _NODISCARD const state_map::StateMapDefinition* GetStateMapForTechnique(const std::string& techniqueName) const; + [[nodiscard]] const state_map::StateMapDefinition* GetStateMapForTechnique(const std::string& techniqueName) const; void SetTechniqueUsesStateMap(std::string techniqueName, const state_map::StateMapDefinition* stateMap); private: diff --git a/src/ObjCompiling/Techset/TechniqueDefinitionAcceptor.cpp b/src/ObjCompiling/Techset/TechniqueDefinitionAcceptor.cpp deleted file mode 100644 index c576a9d3..00000000 --- a/src/ObjCompiling/Techset/TechniqueDefinitionAcceptor.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "TechniqueDefinitionAcceptor.h" - -using namespace techset; - -ShaderArgument::ShaderArgument() - : m_argument_index_specified(false), - m_argument_index(0u) -{ -} - -ShaderArgument::ShaderArgument(std::string argumentName) - : m_argument_name(std::move(argumentName)), - m_argument_index_specified(false), - m_argument_index(0u) -{ -} - -ShaderArgument::ShaderArgument(std::string argumentName, const unsigned argumentIndex) - : m_argument_name(std::move(argumentName)), - m_argument_index_specified(true), - m_argument_index(argumentIndex) -{ -} - -ShaderArgumentCodeSource::ShaderArgumentCodeSource() - : m_index_accessor_specified(false), - m_index_accessor(0u) -{ -} - -ShaderArgumentCodeSource::ShaderArgumentCodeSource(std::vector accessors) - : m_accessors(std::move(accessors)), - m_index_accessor_specified(false), - m_index_accessor(0u) -{ -} - -ShaderArgumentCodeSource::ShaderArgumentCodeSource(std::vector accessors, const unsigned indexAccessor) - : m_accessors(std::move(accessors)), - m_index_accessor_specified(true), - m_index_accessor(indexAccessor) -{ -} - -ShaderArgumentLiteralSource::ShaderArgumentLiteralSource() - : m_value{} -{ -} - -ShaderArgumentLiteralSource::ShaderArgumentLiteralSource(const float v0, const float v1, const float v2, const float v3) - : m_value{v0, v1, v2, v3} -{ -} - -ShaderArgumentLiteralSource::ShaderArgumentLiteralSource(float value[4]) - : m_value{value[0], value[1], value[2], value[3]} -{ -} - -namespace techset -{ - bool operator<(const ShaderArgumentLiteralSource& lhs, const ShaderArgumentLiteralSource& rhs) - { - if (lhs.m_value[0] < rhs.m_value[0]) - return true; - if (lhs.m_value[0] > rhs.m_value[0]) - return false; - if (lhs.m_value[1] < rhs.m_value[1]) - return true; - if (lhs.m_value[1] > rhs.m_value[1]) - return false; - if (lhs.m_value[2] < rhs.m_value[2]) - return true; - if (lhs.m_value[2] > rhs.m_value[2]) - return false; - if (lhs.m_value[3] < rhs.m_value[3]) - return true; - if (lhs.m_value[3] > rhs.m_value[3]) - return false; - return false; - } - - bool operator<=(const ShaderArgumentLiteralSource& lhs, const ShaderArgumentLiteralSource& rhs) - { - return !(rhs < lhs); - } - - bool operator>(const ShaderArgumentLiteralSource& lhs, const ShaderArgumentLiteralSource& rhs) - { - return rhs < lhs; - } - - bool operator>=(const ShaderArgumentLiteralSource& lhs, const ShaderArgumentLiteralSource& rhs) - { - return !(lhs < rhs); - } -} // namespace techset - -ShaderArgumentMaterialSource::ShaderArgumentMaterialSource() - : m_is_hash(false), - m_hash(0u) -{ -} - -ShaderArgumentMaterialSource::ShaderArgumentMaterialSource(const unsigned hash) - : m_is_hash(true), - m_hash(hash) -{ -} - -ShaderArgumentMaterialSource::ShaderArgumentMaterialSource(std::string name) - : m_is_hash(false), - m_hash(0u), - m_name(std::move(name)) -{ -} diff --git a/src/ObjCompiling/Techset/TechniqueDefinitionAcceptor.h b/src/ObjCompiling/Techset/TechniqueDefinitionAcceptor.h deleted file mode 100644 index 353c52cb..00000000 --- a/src/ObjCompiling/Techset/TechniqueDefinitionAcceptor.h +++ /dev/null @@ -1,100 +0,0 @@ -#pragma once - -#include -#include - -namespace techset -{ - enum class ShaderSelector - { - VERTEX_SHADER, - PIXEL_SHADER - }; - - class ShaderArgument - { - public: - std::string m_argument_name; - bool m_argument_index_specified; - unsigned m_argument_index; - - ShaderArgument(); - explicit ShaderArgument(std::string argumentName); - ShaderArgument(std::string argumentName, unsigned argumentIndex); - }; - - class ShaderArgumentCodeSource - { - public: - std::vector m_accessors; - bool m_index_accessor_specified; - unsigned m_index_accessor; - - ShaderArgumentCodeSource(); - explicit ShaderArgumentCodeSource(std::vector accessors); - ShaderArgumentCodeSource(std::vector accessors, unsigned indexAccessor); - }; - - class ShaderArgumentLiteralSource - { - public: - float m_value[4]; - - ShaderArgumentLiteralSource(); - ShaderArgumentLiteralSource(float v0, float v1, float v2, float v3); - explicit ShaderArgumentLiteralSource(float value[4]); - - friend bool operator<(const ShaderArgumentLiteralSource& lhs, const ShaderArgumentLiteralSource& rhs); - friend bool operator<=(const ShaderArgumentLiteralSource& lhs, const ShaderArgumentLiteralSource& rhs); - friend bool operator>(const ShaderArgumentLiteralSource& lhs, const ShaderArgumentLiteralSource& rhs); - friend bool operator>=(const ShaderArgumentLiteralSource& lhs, const ShaderArgumentLiteralSource& rhs); - }; - - class ShaderArgumentMaterialSource - { - public: - ShaderArgumentMaterialSource(); - explicit ShaderArgumentMaterialSource(unsigned hash); - explicit ShaderArgumentMaterialSource(std::string name); - - bool m_is_hash; - unsigned m_hash; - std::string m_name; - }; - - class ITechniqueDefinitionAcceptor - { - protected: - ITechniqueDefinitionAcceptor() = default; - - public: - virtual ~ITechniqueDefinitionAcceptor() = default; - ITechniqueDefinitionAcceptor(const ITechniqueDefinitionAcceptor& other) = default; - ITechniqueDefinitionAcceptor(ITechniqueDefinitionAcceptor&& other) noexcept = default; - ITechniqueDefinitionAcceptor& operator=(const ITechniqueDefinitionAcceptor& other) = default; - ITechniqueDefinitionAcceptor& operator=(ITechniqueDefinitionAcceptor&& other) noexcept = default; - - virtual void AcceptNextPass() = 0; - virtual bool AcceptEndPass(std::string& errorMessage) = 0; - - virtual bool AcceptStateMap(const std::string& stateMapName, std::string& errorMessage) = 0; - - virtual bool AcceptVertexShader(const std::string& vertexShaderName, std::string& errorMessage) = 0; - virtual bool AcceptPixelShader(const std::string& pixelShaderName, std::string& errorMessage) = 0; - - virtual bool - AcceptShaderConstantArgument(ShaderSelector shader, ShaderArgument shaderArgument, ShaderArgumentCodeSource source, std::string& errorMessage) = 0; - virtual bool - AcceptShaderSamplerArgument(ShaderSelector shader, ShaderArgument shaderArgument, ShaderArgumentCodeSource source, std::string& errorMessage) = 0; - virtual bool AcceptShaderLiteralArgument(ShaderSelector shader, - ShaderArgument shaderArgument, - ShaderArgumentLiteralSource source, - std::string& errorMessage) = 0; - virtual bool AcceptShaderMaterialArgument(ShaderSelector shader, - ShaderArgument shaderArgument, - ShaderArgumentMaterialSource source, - std::string& errorMessage) = 0; - - virtual bool AcceptVertexStreamRouting(const std::string& destination, const std::string& source, std::string& errorMessage) = 0; - }; -} // namespace techset diff --git a/src/ObjCompiling/Techset/TechniqueFileReader.cpp b/src/ObjCompiling/Techset/TechniqueFileReader.cpp deleted file mode 100644 index 884b9b32..00000000 --- a/src/ObjCompiling/Techset/TechniqueFileReader.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "TechniqueFileReader.h" - -#include "Parsing/Impl/CommentRemovingStreamProxy.h" -#include "Parsing/Impl/ParserSingleInputStream.h" -#include "Parsing/Simple/SimpleLexer.h" -#include "Techset/Parsing/TechniqueFileParser.h" -#include "Utils/Logging/Log.h" - -#include - -using namespace techset; - -TechniqueFileReader::TechniqueFileReader(std::istream& stream, std::string fileName, ITechniqueDefinitionAcceptor* acceptor) - : m_file_name(std::move(fileName)), - m_acceptor(acceptor) -{ - m_base_stream = std::make_unique(stream, m_file_name); - m_comment_proxy = std::make_unique(m_base_stream.get()); -} - -bool TechniqueFileReader::ReadTechniqueDefinition() const -{ - SimpleLexer::Config lexerConfig; - lexerConfig.m_emit_new_line_tokens = false; - lexerConfig.m_read_strings = true; - lexerConfig.m_string_escape_sequences = false; - lexerConfig.m_read_integer_numbers = true; - lexerConfig.m_read_floating_point_numbers = true; - const auto lexer = std::make_unique(m_comment_proxy.get(), std::move(lexerConfig)); - - const auto parser = std::make_unique(lexer.get(), m_acceptor); - - const auto success = parser->Parse(); - if (success) - return true; - - con::error("Parsing technique file \"{}\" failed!", m_file_name); - return false; -} diff --git a/src/ObjCompiling/Techset/TechniqueFileReader.h b/src/ObjCompiling/Techset/TechniqueFileReader.h deleted file mode 100644 index 9f72828e..00000000 --- a/src/ObjCompiling/Techset/TechniqueFileReader.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "Parsing/IParserLineStream.h" -#include "TechniqueDefinitionAcceptor.h" - -#include -#include - -namespace techset -{ - class TechniqueFileReader - { - public: - TechniqueFileReader(std::istream& stream, std::string fileName, ITechniqueDefinitionAcceptor* acceptor); - - [[nodiscard]] bool ReadTechniqueDefinition() const; - - private: - std::string m_file_name; - ITechniqueDefinitionAcceptor* m_acceptor; - std::unique_ptr m_base_stream; - std::unique_ptr m_comment_proxy; - }; -} // namespace techset From 38cb7d37591cc3b8b6e5153e52195e8c73dd2504 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 28 Feb 2026 11:35:37 +0000 Subject: [PATCH 13/27] feat: set proper tech flags and sampler flags for loaded techniques --- src/ObjCompiling/Techset/CommonShaderArgCreator.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp index 8afff667..717b15b7 100644 --- a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp +++ b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp @@ -230,6 +230,9 @@ namespace } m_args.emplace_back(argumentType, commonDestination, techset::CommonShaderArgValue{.code_const_source = value}); + if (maybeInfo->techFlags) + m_tech_flags |= *maybeInfo->techFlags; + return NoResult{}; } @@ -241,7 +244,16 @@ namespace .m_value_type = techset::CommonShaderValueType::CODE_SAMPLER, }; + const auto maybeInfo = m_common_code_source_infos.GetInfoForCodeSamplerSource(codeSamplerSource); + if (!maybeInfo) + return result::Unexpected("Could not find info for code sampler"); + m_args.emplace_back(argumentType, commonDestination, techset::CommonShaderArgValue{.code_sampler_source = codeSamplerSource}); + if (maybeInfo->techFlags) + m_tech_flags |= *maybeInfo->techFlags; + if (maybeInfo->customSamplerIndex) + m_sampler_flags |= (1 << *maybeInfo->customSamplerIndex); + return NoResult{}; } From 5ab3fd7ca02cccc21f54b2ef0f5270007a6d985a Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 28 Feb 2026 15:27:03 +0100 Subject: [PATCH 14/27] chore: enable techset debugging on dumper creation level --- src/ObjWriting/Game/T5/ObjWriterT5.cpp | 8 +++- .../Game/T5/Techset/TechsetDumperT5.cpp | 11 ++++-- .../Game/T5/Techset/TechsetDumperT5.h | 5 +++ src/ObjWriting/Game/T6/ObjWriterT6.cpp | 8 +++- .../Game/T6/Techset/TechsetDumperT6.cpp | 11 ++++-- .../Game/T6/Techset/TechsetDumperT6.h | 5 +++ .../Techset/CommonTechniqueDumper.cpp | 37 +++++++++---------- .../Techset/CommonTechniqueDumper.h | 3 +- 8 files changed, 60 insertions(+), 28 deletions(-) diff --git a/src/ObjWriting/Game/T5/ObjWriterT5.cpp b/src/ObjWriting/Game/T5/ObjWriterT5.cpp index 99549385..19c5e277 100644 --- a/src/ObjWriting/Game/T5/ObjWriterT5.cpp +++ b/src/ObjWriting/Game/T5/ObjWriterT5.cpp @@ -18,7 +18,13 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context) // REGISTER_DUMPER(AssetDumperXAnimParts, m_xanim_parts) 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(AssetDumperSndBank, m_sound_bank) // REGISTER_DUMPER(AssetDumperSndPatch, m_sound_patch) diff --git a/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp b/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp index 30dcaf02..6f37efe8 100644 --- a/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp +++ b/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp @@ -209,7 +209,7 @@ namespace return commonTechnique; } - void DumpTechniques(AssetDumpingContext& context, const MaterialTechniqueSet& techset) + void DumpTechniques(AssetDumpingContext& context, const MaterialTechniqueSet& techset, const bool debug) { auto* techniqueState = context.GetZoneAssetDumperState(); const auto* materialConstantState = context.GetZoneAssetDumperState(); @@ -220,7 +220,7 @@ namespace const auto commonTechnique = ConvertToCommonTechnique(*technique); techset::DumpCommonTechnique( - context, commonTechnique, techset::DxVersion::DX9, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState); + context, commonTechnique, techset::DxVersion::DX9, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState, debug); } } } @@ -250,6 +250,11 @@ namespace namespace techset { + DumperT5::DumperT5(const bool debug) + : m_debug(debug) + { + } + void DumperT5::Dump(AssetDumpingContext& context) { context.GetZoneAssetDumperState()->EnsureInitialized(); @@ -260,7 +265,7 @@ namespace techset { const auto* techniqueSet = asset.Asset(); DumpTechset(context, *techniqueSet); - DumpTechniques(context, *techniqueSet); + DumpTechniques(context, *techniqueSet, m_debug); DumpShaders(context, *techniqueSet); } } // namespace techset diff --git a/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.h b/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.h index 1d1aef2d..bbaadf35 100644 --- a/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.h +++ b/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.h @@ -8,9 +8,14 @@ namespace techset class DumperT5 final : public AbstractAssetDumper { public: + explicit DumperT5(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/Game/T6/ObjWriterT6.cpp b/src/ObjWriting/Game/T6/ObjWriterT6.cpp index 9f8f7b12..b43d4947 100644 --- a/src/ObjWriting/Game/T6/ObjWriterT6.cpp +++ b/src/ObjWriting/Game/T6/ObjWriterT6.cpp @@ -35,7 +35,13 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context) // REGISTER_DUMPER(AssetDumperXAnimParts, m_xanim_parts) 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()); RegisterAssetDumper(std::make_unique()); // REGISTER_DUMPER(AssetDumperSndPatch, m_sound_patch) diff --git a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp index e696658e..ba204f1c 100644 --- a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp +++ b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp @@ -260,7 +260,7 @@ namespace return commonTechnique; } - void DumpTechniques(AssetDumpingContext& context, const MaterialTechniqueSet& techset) + void DumpTechniques(AssetDumpingContext& context, const MaterialTechniqueSet& techset, const bool debug) { auto* techniqueState = context.GetZoneAssetDumperState(); const auto* materialConstantState = context.GetZoneAssetDumperState(); @@ -271,7 +271,7 @@ namespace const auto commonTechnique = ConvertToCommonTechnique(*technique); techset::DumpCommonTechnique( - context, commonTechnique, techset::DxVersion::DX11, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState); + context, commonTechnique, techset::DxVersion::DX11, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState, debug); } } } @@ -300,6 +300,11 @@ namespace namespace techset { + DumperT6::DumperT6(const bool debug) + : m_debug(debug) + { + } + void DumperT6::Dump(AssetDumpingContext& context) { context.GetZoneAssetDumperState()->EnsureInitialized(); @@ -310,7 +315,7 @@ namespace techset { const auto* techniqueSet = asset.Asset(); DumpTechset(context, *techniqueSet); - DumpTechniques(context, *techniqueSet); + DumpTechniques(context, *techniqueSet, m_debug); DumpShaders(context, *techniqueSet); } } // namespace techset diff --git a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.h b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.h index d69edb93..913d1e85 100644 --- a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.h +++ b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.h @@ -8,9 +8,14 @@ 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 b43b626c..d5c64043 100644 --- a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp +++ b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp @@ -20,8 +20,10 @@ namespace const DxVersion dxVersion, const CommonCodeSourceInfos& codeSourceInfos, const CommonStreamRoutingInfos& routingInfos, - const AbstractMaterialConstantZoneState& constantZoneState) + const AbstractMaterialConstantZoneState& constantZoneState, + const bool debug) : AbstractTextDumper(stream), + m_debug(debug), m_dx_version(dxVersion), m_code_source_infos(codeSourceInfos), m_routing_infos(routingInfos), @@ -31,8 +33,7 @@ namespace void DumpTechnique(const CommonTechnique& technique) { -#ifdef TECHSET_DEBUG - if (technique.m_flags) + if (m_debug && technique.m_flags) { for (auto i = 0u; i < sizeof(CommonTechnique::m_flags) * 8u; i++) { @@ -44,7 +45,6 @@ namespace } } } -#endif for (const auto& pass : technique.m_passes) DumpPass(technique, pass); @@ -56,17 +56,18 @@ namespace m_stream << "{\n"; IncIndent(); -#ifdef TECHSET_DEBUG - for (auto i = 0u; i < sizeof(CommonPass::m_sampler_flags) * 8u; i++) + if (m_debug) { - const auto mask = 1ull << i; - if (pass.m_sampler_flags & mask) + for (auto i = 0u; i < sizeof(CommonPass::m_sampler_flags) * 8u; i++) { - Indent(); - m_stream << std::format("// CUSTOM SAMPLER FLAGS: 0x{:x}\n", mask); + const auto mask = 1ull << i; + if (pass.m_sampler_flags & mask) + { + Indent(); + m_stream << std::format("// CUSTOM SAMPLER FLAGS: 0x{:x}\n", mask); + } } } -#endif DumpStateMap(); DumpShader(technique, pass, pass.m_vertex_shader, CommonTechniqueShaderType::VERTEX, m_dx_version); @@ -337,12 +338,10 @@ namespace Indent(); m_stream << std::format("{} = constant.{};\n", codeDestAccessor, codeAccessor); } - else + else if (m_debug) { -#ifdef TECHSET_DEBUG Indent(); m_stream << std::format("// Omitted due to matching accessors: {} = constant.{};\n", codeDestAccessor, codeAccessor); -#endif } } else @@ -363,12 +362,10 @@ namespace Indent(); m_stream << std::format("{} = sampler.{};\n", codeDestAccessor, samplerSourceInfo->accessor); } - else + else if (m_debug) { -#ifdef TECHSET_DEBUG Indent(); m_stream << std::format("// Omitted due to matching accessors: {} = sampler.{};\n", codeDestAccessor, samplerSourceInfo->accessor); -#endif } } else @@ -429,6 +426,7 @@ namespace } } + bool m_debug; DxVersion m_dx_version; const CommonCodeSourceInfos& m_code_source_infos; const CommonStreamRoutingInfos& m_routing_infos; @@ -443,12 +441,13 @@ namespace techset const DxVersion dxVersion, const CommonCodeSourceInfos& codeSourceInfos, const CommonStreamRoutingInfos& routingInfos, - const AbstractMaterialConstantZoneState& constantZoneState) + const AbstractMaterialConstantZoneState& constantZoneState, + const bool debug) { const auto techniqueFile = context.OpenAssetFile(GetFileNameForTechniqueName(technique.m_name)); if (techniqueFile) { - TechniqueFileWriter writer(*techniqueFile, dxVersion, codeSourceInfos, routingInfos, constantZoneState); + TechniqueFileWriter writer(*techniqueFile, dxVersion, codeSourceInfos, routingInfos, constantZoneState, debug); writer.DumpTechnique(technique); } } diff --git a/src/ObjWriting/Techset/CommonTechniqueDumper.h b/src/ObjWriting/Techset/CommonTechniqueDumper.h index f2a6a4bd..828dbcb9 100644 --- a/src/ObjWriting/Techset/CommonTechniqueDumper.h +++ b/src/ObjWriting/Techset/CommonTechniqueDumper.h @@ -11,5 +11,6 @@ namespace techset DxVersion dxVersion, const CommonCodeSourceInfos& codeSourceInfos, const CommonStreamRoutingInfos& routingInfos, - const AbstractMaterialConstantZoneState& constantZoneState); + const AbstractMaterialConstantZoneState& constantZoneState, + bool debug); } // namespace techset From aec1372c5bb236e5b42355f671b3fb59eb22e56b Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 28 Feb 2026 22:53:02 +0100 Subject: [PATCH 15/27] fix: vertex decl compiler not recognizing abbreviations with more than 1 digit --- .../Techset/CommonVertexDeclCreator.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/ObjCommon/Techset/CommonVertexDeclCreator.cpp b/src/ObjCommon/Techset/CommonVertexDeclCreator.cpp index 959a5875..ec100fe4 100644 --- a/src/ObjCommon/Techset/CommonVertexDeclCreator.cpp +++ b/src/ObjCommon/Techset/CommonVertexDeclCreator.cpp @@ -2,7 +2,7 @@ #include "Utils/Logging/Log.h" -#include +#include namespace { @@ -11,16 +11,12 @@ namespace if (offset >= assetName.size()) return false; - if (offset + 1 < assetName.size() && isdigit(assetName[offset + 1])) - { - abbreviation = std::string(assetName, offset, 2); - offset += 2; - } - else - { - abbreviation = std::string(assetName, offset, 1); - offset += 1; - } + auto digitCount = 0; + while (offset + digitCount + 1 < assetName.size() && isdigit(assetName[offset + digitCount + 1])) + digitCount++; + + abbreviation = std::string(assetName, offset, digitCount + 1); + offset += digitCount + 1; return true; } From c0a7114b24c927b203ee544e15935cb64cf6ad59 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 28 Feb 2026 22:53:27 +0100 Subject: [PATCH 16/27] chore: add tests for techset and technique compilation --- src/Common/Game/T6/T6_Assets.h | 8 +- .../Material/MaterialConstantZoneStateT6.cpp | 1 + .../T6/Techset/TechniqueCompilerT6Test.cpp | 328 +++++++++++++++ .../Game/T6/Techset/TechsetCompilerT6Test.cpp | 90 ++++- .../T6/Techset/VertexDeclCompilerT6Test.cpp | 63 +++ .../Game/T6/Techset/ps_advanced.hlsl.cso | Bin 0 -> 16412 bytes .../Game/T6/Techset/ps_simple.hlsl.cso | Bin 0 -> 432 bytes .../Game/T6/Techset/vs_advanced.hlsl.cso | Bin 0 -> 9164 bytes .../Game/T6/Techset/vs_simple.hlsl.cso | Bin 0 -> 5964 bytes .../Game/T6/Techset/TechsetDumperT6Test.cpp | 382 ++++++++++++++++++ .../Game/T6/Techset/ps_advanced.hlsl.cso | Bin 0 -> 16412 bytes .../Game/T6/Techset/ps_simple.hlsl.cso | Bin 0 -> 432 bytes .../Game/T6/Techset/vs_advanced.hlsl.cso | Bin 0 -> 9164 bytes .../Game/T6/Techset/vs_simple.hlsl.cso | Bin 0 -> 5964 bytes 14 files changed, 867 insertions(+), 5 deletions(-) create mode 100644 test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp create mode 100644 test/ObjCompilingTests/Game/T6/Techset/VertexDeclCompilerT6Test.cpp create mode 100644 test/ObjCompilingTests/Game/T6/Techset/ps_advanced.hlsl.cso create mode 100644 test/ObjCompilingTests/Game/T6/Techset/ps_simple.hlsl.cso create mode 100644 test/ObjCompilingTests/Game/T6/Techset/vs_advanced.hlsl.cso create mode 100644 test/ObjCompilingTests/Game/T6/Techset/vs_simple.hlsl.cso create mode 100644 test/ObjWritingTests/Game/T6/Techset/TechsetDumperT6Test.cpp create mode 100644 test/ObjWritingTests/Game/T6/Techset/ps_advanced.hlsl.cso create mode 100644 test/ObjWritingTests/Game/T6/Techset/ps_simple.hlsl.cso create mode 100644 test/ObjWritingTests/Game/T6/Techset/vs_advanced.hlsl.cso create mode 100644 test/ObjWritingTests/Game/T6/Techset/vs_simple.hlsl.cso diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 4bab9c89..2ee51b42 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -5760,9 +5760,13 @@ namespace T6 STREAM_SRC_TEXCOORD_0 = 0x2, STREAM_SRC_NORMAL = 0x3, STREAM_SRC_TANGENT = 0x4, - STREAM_SRC_TEXCOORD_1 = 0x5, - STREAM_SRC_OPTIONAL_BEGIN = 0x6, + STREAM_SRC_PRE_OPTIONAL_BEGIN = 0x5, + + STREAM_SRC_TEXCOORD_1 = 0x5, + + STREAM_SRC_OPTIONAL_BEGIN = 0x6, + STREAM_SRC_TEXCOORD_2 = 0x6, STREAM_SRC_TEXCOORD_3 = 0x7, STREAM_SRC_NORMAL_TRANSFORM_0 = 0x8, diff --git a/src/ObjWriting/Game/T6/Material/MaterialConstantZoneStateT6.cpp b/src/ObjWriting/Game/T6/Material/MaterialConstantZoneStateT6.cpp index caf9d8b3..cc140b4a 100644 --- a/src/ObjWriting/Game/T6/Material/MaterialConstantZoneStateT6.cpp +++ b/src/ObjWriting/Game/T6/Material/MaterialConstantZoneStateT6.cpp @@ -409,6 +409,7 @@ namespace "colorMap", "colorMap1", "colorMap2", + "colorMap3", "colorMap2D", "colorMapPostSun", "colorMapPostSunSampler", diff --git a/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp b/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp new file mode 100644 index 00000000..64459b88 --- /dev/null +++ b/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp @@ -0,0 +1,328 @@ +#include "Game/T6/Techset/TechniqueCompilerT6.h" + +#include "Game/T6/T6.h" +#include "Game/T6/Techset/PixelShaderLoaderT6.h" +#include "Game/T6/Techset/VertexDeclCompilerT6.h" +#include "Game/T6/Techset/VertexShaderLoaderT6.h" +#include "OatTestPaths.h" +#include "SearchPath/MockSearchPath.h" +#include "Shader/ShaderCommon.h" +#include "Utils/MemoryManager.h" + +#include +#include +#include +#include + +using namespace T6; +using namespace Catch; +using namespace std::literals; +namespace fs = std::filesystem; + +namespace +{ + void GivenVertexShaderFile(const std::string& name, MockSearchPath& searchPath) + { + const auto filePath = oat::paths::GetTestDirectory() / "ObjCompilingTests/Game/T6/Techset" / std::format("vs_{}.cso", name); + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + std::string data(fileSize, '\0'); + file.read(data.data(), fileSize); + REQUIRE(file.gcount() == static_cast(fileSize)); + + searchPath.AddFileData(shader::GetFileNameForVertexShaderAssetName(name), std::move(data)); + } + + void GivenPixelShaderFile(const std::string& name, MockSearchPath& searchPath) + { + const auto filePath = oat::paths::GetTestDirectory() / "ObjCompilingTests/Game/T6/Techset" / std::format("ps_{}.cso", name); + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + std::string data(fileSize, '\0'); + file.read(data.data(), fileSize); + REQUIRE(file.gcount() == static_cast(fileSize)); + + searchPath.AddFileData(shader::GetFileNameForPixelShaderAssetName(name), std::move(data)); + } +} // namespace + +TEST_CASE("TechniqueCompilerT6", "[t6][techset][compiler]") +{ + + Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC); + zone.Register(); + + MemoryManager memory; + AssetCreatorCollection creatorCollection(zone); + IgnoredAssetLookup ignoredAssetLookup; + AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup); + MockSearchPath searchPath; + + creatorCollection.AddSubAssetCreator(techset::CreateVertexDeclCompilerT6(memory)); + creatorCollection.AddSubAssetCreator(techset::CreateVertexShaderLoaderT6(memory, searchPath)); + creatorCollection.AddSubAssetCreator(techset::CreatePixelShaderLoaderT6(memory, searchPath)); + + auto loader = techset::CreateTechniqueCompilerT6(memory, searchPath); + + SECTION("Can compile simple technique") + { + searchPath.AddFileData("techniques/example_zprepass.tech", R"TECHNIQUE( +{ + stateMap "passthrough"; + + vertexShader 4.0 "simple.hlsl" + { + } + + pixelShader 4.0 "simple.hlsl" + { + } + + vertex.position = code.position; +} +)TECHNIQUE"); + + GivenVertexShaderFile("simple.hlsl", searchPath); + GivenPixelShaderFile("simple.hlsl", searchPath); + + auto result = loader->CreateSubAsset("example_zprepass", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* technique = assetInfo->Asset(); + + CHECK(technique->name == "example_zprepass"s); + CHECK(technique->flags == 0x84); + + REQUIRE(technique->passCount == 1); + auto& pass = technique->passArray[0]; + CHECK(pass.customSamplerFlags == 0); + + // idk + // CHECK(pass.precompiledIndex == VERTEX_SHADER_MODEL_UNLIT); + + // Set from techset + // CHECK(pass.materialType == MTL_TYPE_MODEL_VERTCOL); + + REQUIRE(pass.vertexShader); + CHECK(pass.vertexShader->name == "simple.hlsl"s); + REQUIRE(pass.pixelShader); + CHECK(pass.pixelShader->name == "simple.hlsl"s); + + REQUIRE(pass.vertexDecl); + auto& vertexDecl = *pass.vertexDecl; + CHECK(vertexDecl.hasOptionalSource == false); + CHECK(vertexDecl.isLoaded == false); + REQUIRE(vertexDecl.streamCount == 1); + CHECK(vertexDecl.routing.data[0].source == STREAM_SRC_POSITION); + CHECK(vertexDecl.routing.data[0].dest == STREAM_DST_POSITION); + + REQUIRE(pass.perPrimArgCount == 1); + REQUIRE(pass.perObjArgCount == 1); + REQUIRE(pass.stableArgCount == 0); + CHECK(pass.args[0].type == MTL_ARG_CODE_VERTEX_CONST); + CHECK(pass.args[0].location.offset == 0); + CHECK(pass.args[0].size == 0x40); + CHECK(pass.args[0].buffer == 3); + CHECK(pass.args[0].u.codeConst.index == CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX); + CHECK(pass.args[0].u.codeConst.firstRow == 0); + CHECK(pass.args[0].u.codeConst.rowCount == 4); + + CHECK(pass.args[1].type == MTL_ARG_CODE_VERTEX_CONST); + CHECK(pass.args[1].location.offset == 0x240); + CHECK(pass.args[1].size == 0x40); + CHECK(pass.args[1].buffer == 0); + CHECK(pass.args[1].u.codeConst.index == CONST_SRC_CODE_TRANSPOSE_VIEW_PROJECTION_MATRIX); + CHECK(pass.args[1].u.codeConst.firstRow == 0); + CHECK(pass.args[1].u.codeConst.rowCount == 4); + } + + SECTION("Can compile advanced technique") + { + searchPath.AddFileData("techniques/example_lit_sun_shadow.tech", R"TECHNIQUE( +{ + stateMap "passthrough"; + + vertexShader 4.0 "advanced.hlsl" + { + } + + pixelShader 4.0 "advanced.hlsl" + { + normalMapSampler = material.normalMap; + normalMapSampler1 = material.normalMap1; + colorMapSampler = material.colorMap; + colorMapSampler1 = material.colorMap1; + colorMapSampler3 = material.colorMap3; + colorMapSampler2 = material.colorMap2; + alphaRevealParms1 = material.alphaRevealParms1; + } + + vertex.position = code.position; + vertex.color[0] = code.color; + vertex.texcoord[0] = code.texcoord[0]; + vertex.normal = code.normal; + vertex.texcoord[2] = code.tangent; + vertex.texcoord[1] = code.texcoord[1]; + vertex.texcoord[3] = code.texcoord[2]; + vertex.texcoord[4] = code.texcoord[3]; + vertex.texcoord[5] = code.normalTransform[0]; +} +)TECHNIQUE"); + + GivenVertexShaderFile("advanced.hlsl", searchPath); + GivenPixelShaderFile("advanced.hlsl", searchPath); + + auto result = loader->CreateSubAsset("example_lit_sun_shadow", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* technique = assetInfo->Asset(); + + CHECK(technique->name == "example_lit_sun_shadow"s); + CHECK(technique->flags == 0x88); + + REQUIRE(technique->passCount == 1); + auto& pass = technique->passArray[0]; + CHECK(pass.customSamplerFlags == 3); + + // idk + // CHECK(pass.precompiledIndex == VERTEX_SHADER_NONE); + + // Set from techset + // CHECK(pass.materialType == MTL_TYPE_DEFAULT); + + REQUIRE(pass.vertexShader); + CHECK(pass.vertexShader->name == "advanced.hlsl"s); + REQUIRE(pass.pixelShader); + CHECK(pass.pixelShader->name == "advanced.hlsl"s); + + REQUIRE(pass.vertexDecl); + auto& vertexDecl = *pass.vertexDecl; + CHECK(vertexDecl.hasOptionalSource == true); + CHECK(vertexDecl.isLoaded == false); + REQUIRE(vertexDecl.streamCount == 9); + CHECK(vertexDecl.routing.data[0].source == STREAM_SRC_POSITION); + CHECK(vertexDecl.routing.data[0].dest == STREAM_DST_POSITION); + CHECK(vertexDecl.routing.data[1].source == STREAM_SRC_COLOR); + CHECK(vertexDecl.routing.data[1].dest == STREAM_DST_COLOR_0); + CHECK(vertexDecl.routing.data[2].source == STREAM_SRC_TEXCOORD_0); + CHECK(vertexDecl.routing.data[2].dest == STREAM_DST_TEXCOORD_0); + CHECK(vertexDecl.routing.data[3].source == STREAM_SRC_NORMAL); + CHECK(vertexDecl.routing.data[3].dest == STREAM_DST_NORMAL); + CHECK(vertexDecl.routing.data[4].source == STREAM_SRC_TANGENT); + CHECK(vertexDecl.routing.data[4].dest == STREAM_DST_TEXCOORD_2); + CHECK(vertexDecl.routing.data[5].source == STREAM_SRC_TEXCOORD_1); + CHECK(vertexDecl.routing.data[5].dest == STREAM_DST_TEXCOORD_1); + CHECK(vertexDecl.routing.data[6].source == STREAM_SRC_TEXCOORD_2); + CHECK(vertexDecl.routing.data[6].dest == STREAM_DST_TEXCOORD_3); + CHECK(vertexDecl.routing.data[7].source == STREAM_SRC_TEXCOORD_3); + CHECK(vertexDecl.routing.data[7].dest == STREAM_DST_TEXCOORD_4); + CHECK(vertexDecl.routing.data[8].source == STREAM_SRC_NORMAL_TRANSFORM_0); + CHECK(vertexDecl.routing.data[8].dest == STREAM_DST_TEXCOORD_5); + + REQUIRE(pass.perPrimArgCount == 1); + REQUIRE(pass.perObjArgCount == 1); + REQUIRE(pass.stableArgCount == 11); + CHECK(pass.args[0].type == MTL_ARG_CODE_VERTEX_CONST); + CHECK(pass.args[0].location.offset == 0); + CHECK(pass.args[0].size == 0x40); + CHECK(pass.args[0].buffer == 3); + CHECK(pass.args[0].u.codeConst.index == CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX); + CHECK(pass.args[0].u.codeConst.firstRow == 0); + CHECK(pass.args[0].u.codeConst.rowCount == 4); + + CHECK(pass.args[1].type == MTL_ARG_CODE_VERTEX_CONST); + CHECK(pass.args[1].location.offset == 0x240); + CHECK(pass.args[1].size == 0x40); + CHECK(pass.args[1].buffer == 0); + CHECK(pass.args[1].u.codeConst.index == CONST_SRC_CODE_TRANSPOSE_VIEW_PROJECTION_MATRIX); + CHECK(pass.args[1].u.codeConst.firstRow == 0); + CHECK(pass.args[1].u.codeConst.rowCount == 4); + + CHECK(pass.args[2].type == MTL_ARG_MATERIAL_PIXEL_SAMPLER); + CHECK(pass.args[2].location.textureIndex == 1); + CHECK(pass.args[2].location.samplerIndex == 1); + CHECK(pass.args[2].size == 1); + CHECK(pass.args[2].buffer == 0); + CHECK(pass.args[2].u.nameHash == 0x59d30d0f); + + CHECK(pass.args[3].type == MTL_ARG_MATERIAL_PIXEL_SAMPLER); + CHECK(pass.args[3].location.textureIndex == 3); + CHECK(pass.args[3].location.samplerIndex == 5); + CHECK(pass.args[3].size == 1); + CHECK(pass.args[3].buffer == 0); + CHECK(pass.args[3].u.nameHash == 0x9434aede); + + CHECK(pass.args[4].type == MTL_ARG_MATERIAL_PIXEL_SAMPLER); + CHECK(pass.args[4].location.textureIndex == 0); + CHECK(pass.args[4].location.samplerIndex == 0); + CHECK(pass.args[4].size == 1); + CHECK(pass.args[4].buffer == 0); + CHECK(pass.args[4].u.nameHash == 0xa0ab1041); + + CHECK(pass.args[5].type == MTL_ARG_MATERIAL_PIXEL_SAMPLER); + CHECK(pass.args[5].location.textureIndex == 2); + CHECK(pass.args[5].location.samplerIndex == 2); + CHECK(pass.args[5].size == 1); + CHECK(pass.args[5].buffer == 0); + CHECK(pass.args[5].u.nameHash == 0xb60d1850); + + CHECK(pass.args[6].type == MTL_ARG_MATERIAL_PIXEL_SAMPLER); + CHECK(pass.args[6].location.textureIndex == 5); + CHECK(pass.args[6].location.samplerIndex == 4); + CHECK(pass.args[6].size == 1); + CHECK(pass.args[6].buffer == 0); + CHECK(pass.args[6].u.nameHash == 0xb60d1852); + + CHECK(pass.args[7].type == MTL_ARG_MATERIAL_PIXEL_SAMPLER); + CHECK(pass.args[7].location.textureIndex == 4); + CHECK(pass.args[7].location.samplerIndex == 3); + CHECK(pass.args[7].size == 1); + CHECK(pass.args[7].buffer == 0); + CHECK(pass.args[7].u.nameHash == 0xb60d1853); + + CHECK(pass.args[8].type == MTL_ARG_CODE_VERTEX_CONST); + CHECK(pass.args[8].location.offset == 0x300); + CHECK(pass.args[8].size == 0x40); + CHECK(pass.args[8].buffer == 0); + CHECK(pass.args[8].u.codeConst.index == CONST_SRC_CODE_TRANSPOSE_SHADOW_LOOKUP_MATRIX); + CHECK(pass.args[8].u.codeConst.firstRow == 0); + CHECK(pass.args[8].u.codeConst.rowCount == 4); + + CHECK(pass.args[9].type == MTL_ARG_CODE_PIXEL_SAMPLER); + CHECK(pass.args[9].location.textureIndex == 9); + CHECK(pass.args[9].location.samplerIndex == 9); + CHECK(pass.args[9].size == 1); + CHECK(pass.args[9].buffer == 0); + CHECK(pass.args[9].u.codeSampler == TEXTURE_SRC_CODE_SHADOWMAP_SUN); + + CHECK(pass.args[10].type == MTL_ARG_CODE_PIXEL_CONST); + CHECK(pass.args[10].location.offset == 0x610); + CHECK(pass.args[10].size == 0x10); + CHECK(pass.args[10].buffer == 0); + CHECK(pass.args[10].u.codeConst.index == CONST_SRC_CODE_SHADOWMAP_SWITCH_PARTITION); + CHECK(pass.args[10].u.codeConst.firstRow == 0); + CHECK(pass.args[10].u.codeConst.rowCount == 1); + + CHECK(pass.args[11].type == MTL_ARG_CODE_PIXEL_CONST); + CHECK(pass.args[11].location.offset == 0x630); + CHECK(pass.args[11].size == 0x10); + CHECK(pass.args[11].buffer == 0); + CHECK(pass.args[11].u.codeConst.index == CONST_SRC_CODE_SUNSHADOWMAP_PIXEL_SIZE); + CHECK(pass.args[11].u.codeConst.firstRow == 0); + CHECK(pass.args[11].u.codeConst.rowCount == 1); + + CHECK(pass.args[12].type == MTL_ARG_MATERIAL_PIXEL_CONST); + CHECK(pass.args[12].location.offset == 0x3b0); + CHECK(pass.args[12].size == 0x10); + CHECK(pass.args[12].buffer == 1); + CHECK(pass.args[12].u.nameHash == 0x88befc31); + } +} diff --git a/test/ObjCompilingTests/Game/T6/Techset/TechsetCompilerT6Test.cpp b/test/ObjCompilingTests/Game/T6/Techset/TechsetCompilerT6Test.cpp index 1bfdce31..4eb3a709 100644 --- a/test/ObjCompilingTests/Game/T6/Techset/TechsetCompilerT6Test.cpp +++ b/test/ObjCompilingTests/Game/T6/Techset/TechsetCompilerT6Test.cpp @@ -2,6 +2,7 @@ #include "Game/T6/T6.h" #include "SearchPath/MockSearchPath.h" +#include "Techset/TechsetCommon.h" #include "Utils/TestMemoryManager.h" #include @@ -12,7 +13,20 @@ using namespace T6; using namespace std::string_literals; -TEST_CASE("Game::T6::Techset::TechsetCompilerT6", "[techset][t6]") +namespace +{ + MaterialTechnique* GivenTechnique(const std::string& name, AssetCreationContext& context, MemoryManager& memory) + { + auto* technique = memory.Alloc(); + technique->name = memory.Dup(name.c_str()); + + context.AddSubAsset(name, technique); + + return technique; + } +} // namespace + +TEST_CASE("TechsetCompilerT6", "[techset][t6][compiler]") { Zone zone("test", 0, GameId::T6, GamePlatform::PC); AssetCreatorCollection creators(zone); @@ -20,7 +34,7 @@ TEST_CASE("Game::T6::Techset::TechsetCompilerT6", "[techset][t6]") AssetCreationContext context(zone, &creators, &ignoredAssets); MockSearchPath searchPath; TestMemoryManager memory; - const auto sut = ::techset::CreateCompilerT6(memory, searchPath); + const auto sut = techset::CreateCompilerT6(memory, searchPath); SECTION("Sets correct worldVertFormat") { @@ -54,7 +68,7 @@ TEST_CASE("Game::T6::Techset::TechsetCompilerT6", "[techset][t6]") })); CAPTURE(techsetName); - searchPath.AddFileData(std::format("techsets/{}.techset", techsetName), ""); + searchPath.AddFileData(techset::GetFileNameForTechsetName(techsetName), ""); const auto result = sut->CreateAsset(techsetName, context); REQUIRE(result.HasBeenSuccessful()); @@ -62,4 +76,74 @@ TEST_CASE("Game::T6::Techset::TechsetCompilerT6", "[techset][t6]") const auto* techset = static_cast(result.GetAssetInfo()->m_ptr); CHECK(techset->worldVertFormat == expectedWorldVertFormat); } + + SECTION("Can parse simple techset") + { + searchPath.AddFileData(techset::GetFileNameForTechsetName("simple"), R"TECHSET( +"depth prepass": + example_zprepass; + +"lit sun shadow": + example_lit_sun_shadow; +)TECHSET"); + + auto* exampleZPrepass = GivenTechnique("example_zprepass", context, memory); + auto* exampleLitSunShadow = GivenTechnique("example_lit_sun_shadow", context, memory); + + const auto result = sut->CreateAsset("simple", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* techset = static_cast(result.GetAssetInfo()->m_ptr); + CHECK(techset->name == "simple"s); + CHECK(techset->worldVertFormat == MTL_WORLDVERT_TEX_1_NRM_1); + + size_t techniqueCount = 0; + for (auto* technique : techset->techniques) + { + if (technique) + techniqueCount++; + } + + CHECK(techniqueCount == 2); + CHECK(techset->techniques[TECHNIQUE_DEPTH_PREPASS] == exampleZPrepass); + CHECK(techset->techniques[TECHNIQUE_LIT_SUN_SHADOW] == exampleLitSunShadow); + } + + SECTION("Can parse techset with same technique used multiple times") + { + searchPath.AddFileData(techset::GetFileNameForTechsetName("simple"), R"TECHSET( +"depth prepass": +"build shadowmap depth": + example_zprepass; + +"lit": +"lit sun": +"lit sun shadow": + example_lit_sun_shadow; +)TECHSET"); + + auto* exampleZPrepass = GivenTechnique("example_zprepass", context, memory); + auto* exampleLitSunShadow = GivenTechnique("example_lit_sun_shadow", context, memory); + + const auto result = sut->CreateAsset("simple", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* techset = static_cast(result.GetAssetInfo()->m_ptr); + CHECK(techset->name == "simple"s); + CHECK(techset->worldVertFormat == MTL_WORLDVERT_TEX_1_NRM_1); + + size_t techniqueCount = 0; + for (auto* technique : techset->techniques) + { + if (technique) + techniqueCount++; + } + + CHECK(techniqueCount == 5); + CHECK(techset->techniques[TECHNIQUE_DEPTH_PREPASS] == exampleZPrepass); + CHECK(techset->techniques[TECHNIQUE_BUILD_SHADOWMAP_DEPTH] == exampleZPrepass); + CHECK(techset->techniques[TECHNIQUE_LIT] == exampleLitSunShadow); + CHECK(techset->techniques[TECHNIQUE_LIT_SUN] == exampleLitSunShadow); + CHECK(techset->techniques[TECHNIQUE_LIT_SUN_SHADOW] == exampleLitSunShadow); + } } diff --git a/test/ObjCompilingTests/Game/T6/Techset/VertexDeclCompilerT6Test.cpp b/test/ObjCompilingTests/Game/T6/Techset/VertexDeclCompilerT6Test.cpp new file mode 100644 index 00000000..34734029 --- /dev/null +++ b/test/ObjCompilingTests/Game/T6/Techset/VertexDeclCompilerT6Test.cpp @@ -0,0 +1,63 @@ +#include "Game/T6/Techset/VertexDeclCompilerT6.h" + +#include "Game/T6/T6.h" +#include "Utils/MemoryManager.h" + +#include + +using namespace T6; +using namespace Catch; +using namespace std::literals; + +TEST_CASE("VertexDeclCompilerT6", "[t6][techset][compiler]") +{ + Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC); + zone.Register(); + + MemoryManager memory; + AssetCreatorCollection creatorCollection(zone); + IgnoredAssetLookup ignoredAssetLookup; + AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup); + + auto loader = techset::CreateVertexDeclCompilerT6(memory); + + SECTION("Can create simple vertex decl") + { + auto result = loader->CreateSubAsset("pp", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* decl = assetInfo->Asset(); + + CHECK(decl->hasOptionalSource == false); + CHECK(decl->isLoaded == false); + + REQUIRE(decl->streamCount == 1); + CHECK(decl->routing.data[0].source == STREAM_SRC_POSITION); + CHECK(decl->routing.data[0].dest == STREAM_DST_POSITION); + } + + SECTION("Can create advanced vertex decl") + { + auto result = loader->CreateSubAsset("pbcc1tt10t1t1n1n", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* decl = assetInfo->Asset(); + + CHECK(decl->hasOptionalSource == true); + CHECK(decl->isLoaded == false); + + REQUIRE(decl->streamCount == 5); + CHECK(decl->routing.data[0].source == STREAM_SRC_POSITION); + CHECK(decl->routing.data[0].dest == STREAM_DST_BLENDWEIGHT); + CHECK(decl->routing.data[1].source == STREAM_SRC_COLOR); + CHECK(decl->routing.data[1].dest == STREAM_DST_COLOR_1); + CHECK(decl->routing.data[2].source == STREAM_SRC_TANGENT); + CHECK(decl->routing.data[2].dest == STREAM_DST_TEXCOORD_10); + CHECK(decl->routing.data[3].source == STREAM_SRC_TEXCOORD_1); + CHECK(decl->routing.data[3].dest == STREAM_DST_TEXCOORD_1); + CHECK(decl->routing.data[4].source == STREAM_SRC_NORMAL_TRANSFORM_1); + CHECK(decl->routing.data[4].dest == STREAM_DST_NORMAL); + } +} diff --git a/test/ObjCompilingTests/Game/T6/Techset/ps_advanced.hlsl.cso b/test/ObjCompilingTests/Game/T6/Techset/ps_advanced.hlsl.cso new file mode 100644 index 0000000000000000000000000000000000000000..b01854324de62edc5d7d7705933b37bc30c43076 GIT binary patch literal 16412 zcmeI3e{3Abb;pM%iIOPGx+-dGtB!QA8x&C7_DD*yrCQ?hhbTFbth0`m6(dNvzFU$P zE$_~IcarE9!C8o1I0h0SX$#v35V}EA*ECWh0SdH;BF2BDK^vzm;51HKv`m1gNnNCb z3^=XR+WmfK=k4w8ja0+wj|lKMd$aR-Z{Ezj`ME=7?9|BUk3aXJzudiH=3BR%`pKu? zxbfcA9;MVRj#BFo@5b}&4yA6$DdpgqA5!YX*r9PBECbnZtx;+l;#=^jwQs(e`8lQb zL-rX6A?gaW&F6WGTx862(IRJg)M5ChMb7d>{*M;<+L(ORB4>Lge+I_V_1|dZ&HM!p+B8tAPok)Z1k&Qt6H3K%eAwnm}1jyddja%&opPFvWs4+RxP{1 zoC>@t-zzmMwQ3=#J?Kf@8rnoGL#wI^UQjG~Rd2LbZ8RH99)Iv7$ZOII^v^?R=kti$ zbf5|J%U-;H{pXd+vO`T6yD@ypn)HN8ml2btc@;cIT{;t?ZS*gYgHfOTCw4vqp11Hn z1a~a_OW*~=XS}Sx?thI0zPlydGJLG-w(cI;fKJN!8sQg z3P>|dB3`lR`{1kK8$vbJH2NQ73`aVKKWX^0h#d>R2;R2vzXD&f@KzSez?UujL*OeGej0q$!q0(oQ$sU!5dS|8p0)6&!E+Y=EO_3+{{-Bz@IMDHSoq7} zlNSC%@VbS+4&Ju#4O`)V3*QbtZ{fFtFIxB!@Ffd(!Iv$(4ZdRGPlB&n_#c6*-fsVY z89Zw^mWgOyd<#5h(f=3lyhT6rF8JS~p9L>i_zv(%a10e4ZbzEoF2r^4woc(ZVfZP; zs}?&h3Mw$JZs_8;5iFF1D?0=N5LHn z{~hpxg?|ow(!#$8UbpbCg10UFCGZOt{!ifZ7XCW;qJ?k9d27kScY-g2r^o*Q_)8Y< zfUj8WybpZU!Y9BL&VT8Calx||UIout_-}&eE&OqC$HJckFIf2RgHKxcm%!^5ezsCA zk5z*3RIC;jdej=#6M0K1x7>K3SaN+&opFPTTW#Kt48?j-sZK*L)Rne3TGc|WQQ`So z;eD(!HPvc(YNj0E)Z7eeem?fzugdzI9-iNi)@r9)^2PU-WTaBfbr=qT{t`xIme<<4|KlC<^n2@1nyMJPh@q#?JyYIjlTfxUdF(SsU}= znTmH79~?=&O7)BvG`y3LnVd1wr5%2v#J!}>)&jqLywxn%YC%Gv-HQGRVc2<^9r1!% zn0)vi&ka;9%slS7%^5E!xWQ~gO>0ebzSDM7lnUTdZXNJOH65s_#>L}V~#huv+4ALQe1 zsaXpe;df(HN9_oyqD~Z{%bZankuhF>tzoJ^9O|3YNGG>6CNdX-{3duROz>lyV{3l_m;v?&X zTaT@ISl)FgxwBs2-d9)Q3+It}Ey8OGbES5aR}7eAClaZ{iPVVl<~&pVXh$$>bf$l9S@fK#_2gdE{?VQ zW~J^|a0}&~YXOjN4P5f?jL ziQ5ZPW1io1!{kWCZKzVE>S2slN>~Mhk=nT~Fu?udB~uUPEA2Yl7S2f(o{boJL5c-F!vz;hN}0?%9c z8F0tK9|JE~_@}@pE&Q|KbqjwUylvrs3Vy-DzXm>U;ok;dG#qY^b|PYlKryW@#H@x?%c#C95tMPoXIWt8_|gr=N#CA4CErBJ|E$-zLRlpSdV)#>dX8g#}#bEnPy;& zE6j+?zCsQYk$vW6AZJ-(pLrR`ab*(eGcN;qA7i|*z47{Q0+;$TF9Y?tN78=r2Z+=}1N?7b z{{wK<_$P8mDOJWJY1+IC&jYN^WVqtWJ7w}t-^x47ly~}2-s!goHiUNAM&TSA^3Hmm zx(VG@56immzD}Cu#nUV^o@Tl6G|P^sS$;gtI>ghghfe3i@>v(AAIz#X-^*sTfBAj| z?<`y1SuWoLaF!|WEKlA!HbkG}K{)$MIP1gr0odU<5zet8`Wz1)`r=A1^v?{2HEj%_ zi?5g+aePNsF;B+9PuRtL(@%!Ks(mT`9KvvAUix?3v~B#OW_LAxE;?*?T!(o$E*P^8 z1F)lYOq_90k4M@LAE@Y%aWL32JxhEvz>nCcFKM5?U>#_S_8E%~eH_#6$!Z5uIm(sGt_V@|D)$#vgKy&>KZ7(3&cjxX`9 zZKHoTQcnL$eMH8X9AU$NDSzD5k9Ebn7Se{uBO4w4#8_j#%iBBSk^bUXGwtkSU9@eK z%{b%WCo#YDn7l#sJ`Y>0BkLN|$G^^Mn@1`1-FoVap2XBg3;M)&aT`xR_0++qpSpSI z#czD$0Bb-Sq9?v(|In7qBVBK^)^M(I{;+MjjVMRz953fuZF_BJr_OJ;ZRgoSgm{^@ zwo#95k+~slyqfQ*D`SUs>y>i0X7!#wj+lKK*EzY))CDs7M(P9_trNl|9>cudYHatJ zSn8B0*YtnF7RupT&blzZmMzvb-UjNUoW22+$^PS*jrYOAbI%gPM(fkSL(RL#f-!pI2pYT1?2nqYF@7uM{ym9+X(}&+P z?LT>A*v5laeyk&`&rY>=jrjhsQk$fYxL;G=TMyS#jx+A@y9`I2 zHeZ3S*p~5+l-s_w=`G=UQ!;AH4U{O)q}@E3fW+c<70T{^8>F*oNEspE)qI^Nvfc zv-^gA^^dn*x*pr`qu>4agSYiRa`6}XpTGFEAA3XBV;f%C^PgX-uity=m11z|FCL%z znVt{akMx{w=P=VcbNbiz?Kt@TLqCf4Bv~KgbMdE{(_Fu}4|89U`OdWp`_zH{*jf;- zUygPC!hGHo)!(dBuYEEHi}?2qc*aee_|AGqYu$gd7RfrX9{DbRB8T6OU%J*he8bRx zX}>V<|HNANcI{lN4P9&9b=ZckweC7>L)Th&9k!ust@{~ngRB*oKc2(v?9Az|wa%;$ z={fyVoI5tkIY`c7=3M5O^=%3BH99Y+*F$`#=x=zgmC)NL>!zHKM4#U?)WJUq>)DDY zzK*8Ljh_Qy^PP1RzGDzyif`c?eeUHtoZbuGSx3WjK3wyb&+h*l``J6|=>Kg${C};Z zJTuBVD)Us%j4Bt()?hFu*E%P?wnq1%l2_Kv^x8^WQjV+#TwD2|F8Ur+?+Iqz9Y3E# z4yEu<$@zW1Av$lG?|OX8>#}J#-WJ;K0b_meF9?QFk1YWh=gMnaLRrR9YH;w?gI_rO zUHrMHy#$fUIQT*MpE?ZmZ<6`APMr)frg%>5z8ec!(AK-_=ZO}qL`9G8jBxGXSw97D3Ep>4V^9_EQTLaoxdCt IlD(DiUrF~qKmY&$ literal 0 HcmV?d00001 diff --git a/test/ObjCompilingTests/Game/T6/Techset/ps_simple.hlsl.cso b/test/ObjCompilingTests/Game/T6/Techset/ps_simple.hlsl.cso new file mode 100644 index 0000000000000000000000000000000000000000..cfe8445a2501036fc948b644c9b0391efd4260c6 GIT binary patch literal 432 zcmZ>XaB}{!<3Xc&*;X^D5B7Zh~40iX^ z0SbZa=Kx{_AO-;tpBcNkIU}Vqh=>S`A|}IeU2Ggz700jbI7wY-+)x^kLc3~9smhDJ32A64*Z{#`oUeIrrRi&;6LYlj)14sS~Gvb^BXapSfowbdIbX{p^ivrUE`UeY*TzuwlqTJj~yZ$L#yhe~0fhW)-q$SyvKm^SPqPMy!nTiW^jG zZquFeo9(b|>J4vc8Tlsdej3kr@N{p(ADd`z4A1sqJeD#0*zIv;+_D*4e-=4emM?b_zpO-Xx`7VfOHZ0uA*ND-vd7g9roL>`k!GAP(a4CZutiCg5}f~ z{sZu?qW?4SZH51i_OPG|$kKM+rhUsHO6(tcH|&FF=l22db%p1_Hxzynd`sao;M)qn z2)?86I{2=_Ti|;N|17xK*YE!qz{eH-HSnCmUjd&``1ipJ3f~5=DEt@T3ku%_Zz=pH zcvs>3?m+w%emD4r!XF0TQuqn*ZH1o&-%;j7@g z3SS4`Q~0;R&Hn!QzXm?8@HfD73jaO$gu?#?UQqZ!On61%cY`m0W2r>xLAx-HBX5Cs zEiYJJLB6NhxkUMa{&Cg8#})2_=M?@T_=Lj02wqV5*TE|ae+7I&;je+W6#jGYuEKu} zzOL{;f^R7NZSXCHkK(?ut?;|RcNG2r_^!h9;Cl)$g7f8t?xQ5{%?kLq!Y_m86y5}% zQ22}B1%-bJyrS@Lf-fliRq&R=e+1rD_zm!Nh5rV8L*X~Uw-i3g`WZSV<&zXV=T_&Rt+;oksXQ1~WzOX1hN zW_{WV+*;`QO|!W4br|Ix$c(xJ`awn`36t zUz+k8eh?R;YkY)Q${RRZ_LmR>W5gWqt&-LAnpfSR?OuS)woH*e?RH<3%r!q~)MqlZ_)PQ@1@jZbc=954)(!l) z`oekF35*{%F1t>+>;@GlSZSN3NE6d|F;%{lDnBjdveRhHE-p%S&aF%FOyIgrsgxQW zSAI7ot0VpyB?~036~oYNcARMS#KiU>Q`_>x%mPVBvM>^oEQo|0OWEOc$9+^GFFUo+ z5883y5+9>Lh>KB$x@?(LdK#wvk2I|N#aQ3gO1E0eU=njNn9OSAv*6e*P%M_LMQkzt zNaZ%O7E&Z-VhTIWbE^%nF6yR@amCwk#c5T%Rku;BKi_GGsSv5+%e7@EKRy6D+x5)qBA;omQJiNIiw(1&#iy*SxT{jKvq)gCkn$bi{A0E%{9@ zF*oEk?e!rtyyBp9&uQ2_dSz`saGLf63cQtbO)M!?*UTn=gbm@Jq(!fRrt?lKb>`uC zk5bK9aRcY6mWd18N48i+)C~5DKf})e*kf}&wKF}nl5y8u>;4ixAp~CSbQXNFa9-qR!{d< z%cj=wJM|f74GTzK5PfK}Un}2_jv065xrVzk^VEFRZQwx0ao@hO7OjgXJB`q5H9R*k z?rIn~Q_c#Oo3nzm&c9Z5!%izI6vN=M1M8 z&f5qY{xidA>i~X7P@g(XWSk4(GBR@fl#T3ApLHhY_$iq5EAvPW)8-Hg)Mr~J za*m09R%WZ`=FiQZH&e4SvvX$t^u?*!*|}+Res=E3;*8mxMI4@m1Nht$wJBI%bhV-zkT>hlpU=Q~*x2LReh$A@D%U^(@em@^K-`{Do@?PTL1`fSTY zJDhj%hcRR#=QraKd=un&)BfZ0YNF4!Ow{LRMcS`kxSZTrGNInAo}HfiI}8+H@!uHa zB@Da#IP4Kb8aNus2us`99A@Li4y%t?({DbMA08lwIFjE#Ku()%Um751 zoFe-<+b{Z${IGNVpx7TE|Df0(Ab-fpuMd!a2y(_m=C6Ej+&>xPO#jMu{gD0Cvi*0B zM|&oZ<;U1CJ=V=d`91ji2pGpPmSV@S>=`GfF`L^tD4k5nj;3Ufzxu;d??b=RPGpnN zXH5HTMd*O|l~;*|J<Um5ZQ^G*)Q!S#{B=Y|7U#kU1A{PJDQp&L?xN0 z@~~ZxHva_XLgFsIOe^!l`3w*juAd8|ah$~#YDw(M*K^P?<^y;rr+z+XZkMr%U-yAa ze==S&tiQ4BSU4X{kEF)LHI&ukddxDJ12j*^D4F||eC(zjAI{}OeiRMmoW2)j`X_ox z9I(fueP#DJ+fa{tbOdG0Nn-CY+lTbaJt*g>#0yQLSR*$)=V(K6#C0qXKdo%I00m=C zr5^Twh9N!{Uc!oO|jpQO-G!;*ybb zZ&A*5r^(46Pv$c117%#F?3+o}yR1*L{Z=OJB*tm~p_Z&?#+L6f$tA{-zLgCZpfDiD z>9)fKsu}*3#|*PHAjTX|I<}E5#EYCU;yA_cNcVbwj5T>W#+uyPk7Atlf%+0-${1tj z5@VJb<8(WbvF$^*#dGuWzF3EQf$NDfGA8QS_R-#;Oy-Gq2bnv*7i66c6(B%*4DT-{ z%4CfR6CLc;WPS3SVPCQjS^ltHLzdqfUoL(RX2*9Y?Lo%74DS?-ubc}LC{up_06F}O z?+gRvh)*Qvd7;_Ixt7F+_b0}N{WD&C&+{I|_dMf9#`iq$Q+&_Up6KyjMLpW!eC17S z=Vg1IOCFtFkV$Nyp6oM;A^Vp(r`{s}(+lZyLvbF(%i3q0IKPok_N=5&*CA($=PbUr zaju!9O*A&Nu_-wdxF+cXb0+#MZTa42e;g<0KCK6z4+gePa!y>orGFfDM9w%f4Ht}g z=KXZIfIql*rXOkhaSX3IUz`u2@eCf`W0~&8^Ee**#w2-Md*{FC KKeF{s?fwVKQMfh$ literal 0 HcmV?d00001 diff --git a/test/ObjCompilingTests/Game/T6/Techset/vs_simple.hlsl.cso b/test/ObjCompilingTests/Game/T6/Techset/vs_simple.hlsl.cso new file mode 100644 index 0000000000000000000000000000000000000000..50c95fc29c08b8338853f79221339352893c14be GIT binary patch literal 5964 zcmb8zUu+vm9S88qwc&ce-I?Ced!Q25U4aVm;5elei9fcJI;oUvmaJQna**tK$If2Y zyUXmlaZa4@@q_@O2qB?^2aF0Y1fd8OA*7QoZwLvbfI#8_iJ$|4xRE)Hm(7nX*%+jLI#k z?4}IlLKwtJEL`7fZzJ8Oem{@>``G)B;h)*4zqeyQJd52JB_Df-4hqIrO#A{;vT<+0 zi&U3R0$b12|1vpjy#6=gCC0xCuQ0w3w;2B!e2eklz$3=rg7+DpeWwt6jK3E?VEiKd zfblZ?knxYhkKjnsZP{ejksdSkUHA$7jH&ON`d^?F6Q^Q)&-ego#W>BY%zp~+GxdJ~ zKVJJlYy#EK(KjTk6j{f1}*Y`R29^+;BfblEv1IAb2hm5boj~I91$Bakt6UM&? z7pEuB|10nUB2r$@%{jwg4l@p@ixN2*xfM44$hA``XaiBS?eq4M3;ZsLZa8XZ27 zenr9c(Woz8YRgiEI(+%Mbd(5nZ(1R2V3Vhm+CA%-$P z(hps3eGD7rb*GtxD%JxxJjZk(vQtb0s!J`0L9XHG`KL9^=~s1q6V)EJ&OXerI}LN= zHOk{K{}8Ixn&}a@7=1~l+syPZA|qWa;7;?T?R#!kUBviY`Znx1k>&NIUv*#V#>vPK zvBjIsZAW43q*_2mNw?YwyFnt93|y%ij%v%q_Fk5v8^yGQxFe(|G>&KQcu8{`lP@s~ zM>^B#L_&YJ9R@VTWJ0%T{v6VdI}Q%+Ilj3^Z|^pg6POi9d7WzkrWC?mu}@#ZX7HD7 zEzd{Oh7*mfd05`lt?6{6a&AOIXXrjMSsSA!aIb_b^fLhNv9(;Zl#6OY?n-m|ZTy6w zyyn$$_*B<%AD(3t#!0<5Tr6|poXCacd^n#EFXh7z=flhS@FV%~N}l!RcVSIUTHZ;f^hnZj|P#QRMH6COs+ijkq=%ER6;=9W=ZksX2JUrHv?B zlz!squ;w|jXnKLf9QB%51ywEVO+cBR7Y9%2c~?O~PnPVrhS%X_+4D7f=lea}V*Ic0 zEyn)|j~JiD?_+(&-vi%cd=5Tfd*a3hCj+e+v|>D5GlmuP zLsG0pGN{H_of={2$Hj(>lOiorm}vZlYkkdLy8a=QQm?e$6tQPp_U7>@-v6yt`L z>UEkQt5e!gA6XlGEfn_6&EeC_US3@5p+W^m`W(tOa2e`fFCr(zMeJEj?dke#qAOJ> zASXl{bib(cbc}6GOPZIL@ymiTv$1|wmy>|Ck* z*(v4JhRSPG%IQ3)oQ}!$Psd1)Uo^+X@zZ+dvtKaf&rT_SUv~T{ +#include +#include +#include +#include + +using namespace T6; +using namespace Catch; +using namespace std::literals; +namespace fs = std::filesystem; + +namespace +{ + std::string Trimmed(const std::string& input) + { + auto start = input.find_first_not_of(" \r\n"); + if (start == std::string::npos) + start = 0; + + auto end = input.find_last_not_of(" \r\n"); + if (end == std::string::npos) + end = input.length(); + else + end = end + 1; + + return input.substr(start, end - start); + } + + MaterialVertexShader* GivenVertexShader(const std::string& name, MemoryManager& memory) + { + const auto filePath = oat::paths::GetTestDirectory() / "ObjWritingTests/Game/T6/Techset" / std::format("vs_{}.cso", name); + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + auto* shader = memory.Alloc(); + shader->name = memory.Dup(name.c_str()); + shader->prog.loadDef.program = memory.Alloc(fileSize); + shader->prog.loadDef.programSize = static_cast(fileSize); + file.read(shader->prog.loadDef.program, fileSize); + REQUIRE(file.gcount() == static_cast(fileSize)); + + return shader; + } + + MaterialPixelShader* GivenPixelShader(const std::string& name, MemoryManager& memory) + { + const auto filePath = oat::paths::GetTestDirectory() / "ObjWritingTests/Game/T6/Techset" / std::format("ps_{}.cso", name); + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + auto* shader = memory.Alloc(); + shader->name = memory.Dup(name.c_str()); + shader->prog.loadDef.program = memory.Alloc(fileSize); + shader->prog.loadDef.programSize = static_cast(fileSize); + file.read(shader->prog.loadDef.program, fileSize); + REQUIRE(file.gcount() == static_cast(fileSize)); + + return shader; + } + + MaterialTechnique* GivenDepthPrepassTechnique(MemoryManager& memory) + { + auto* technique = memory.Alloc(); + technique->name = "example_zprepass"; + technique->flags = 0x84; + technique->passCount = 1; + + auto& pass = technique->passArray[0]; + pass.perPrimArgCount = 1; + pass.perObjArgCount = 1; + pass.stableArgCount = 0; + pass.customSamplerFlags = 0; + pass.precompiledIndex = VERTEX_SHADER_MODEL_UNLIT; + pass.materialType = MTL_TYPE_MODEL_VERTCOL; + + pass.vertexShader = GivenVertexShader("simple.hlsl", memory); + pass.pixelShader = GivenPixelShader("simple.hlsl", memory); + + pass.vertexDecl = memory.Alloc(); + auto& vertexDecl = *pass.vertexDecl; + vertexDecl.streamCount = 1; + vertexDecl.hasOptionalSource = false; + vertexDecl.isLoaded = false; + vertexDecl.routing.data[0].source = STREAM_SRC_POSITION; + vertexDecl.routing.data[0].dest = STREAM_DST_POSITION; + + pass.args = memory.Alloc(2); + pass.args[0].type = MTL_ARG_CODE_VERTEX_CONST; + pass.args[0].location.offset = 0; + pass.args[0].size = 0x40; + pass.args[0].buffer = 3; + pass.args[0].u.codeConst.index = CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX; + pass.args[0].u.codeConst.firstRow = 0; + pass.args[0].u.codeConst.rowCount = 4; + + pass.args[1].type = MTL_ARG_CODE_VERTEX_CONST; + pass.args[1].location.offset = 0x240; + pass.args[1].size = 0x40; + pass.args[1].buffer = 0; + pass.args[1].u.codeConst.index = CONST_SRC_CODE_TRANSPOSE_VIEW_PROJECTION_MATRIX; + pass.args[1].u.codeConst.firstRow = 0; + pass.args[1].u.codeConst.rowCount = 4; + + return technique; + } + + MaterialTechnique* GivenLitSunShadowTechnique(MemoryManager& memory) + { + auto* technique = memory.Alloc(); + technique->name = "example_lit_sun_shadow"; + technique->flags = 0x88; + technique->passCount = 1; + + auto& pass = technique->passArray[0]; + pass.perPrimArgCount = 1; + pass.perObjArgCount = 1; + pass.stableArgCount = 11; + pass.customSamplerFlags = 3; + pass.precompiledIndex = VERTEX_SHADER_NONE; + pass.materialType = MTL_TYPE_DEFAULT; + + pass.vertexShader = GivenVertexShader("advanced.hlsl", memory); + pass.pixelShader = GivenPixelShader("advanced.hlsl", memory); + + pass.vertexDecl = memory.Alloc(); + auto& vertexDecl = *pass.vertexDecl; + vertexDecl.streamCount = 9; + vertexDecl.hasOptionalSource = true; + vertexDecl.isLoaded = false; + vertexDecl.routing.data[0].source = STREAM_SRC_POSITION; + vertexDecl.routing.data[0].dest = STREAM_DST_POSITION; + vertexDecl.routing.data[1].source = STREAM_SRC_COLOR; + vertexDecl.routing.data[1].dest = STREAM_DST_COLOR_0; + vertexDecl.routing.data[2].source = STREAM_SRC_TEXCOORD_0; + vertexDecl.routing.data[2].dest = STREAM_DST_TEXCOORD_0; + vertexDecl.routing.data[3].source = STREAM_SRC_NORMAL; + vertexDecl.routing.data[3].dest = STREAM_DST_NORMAL; + vertexDecl.routing.data[4].source = STREAM_SRC_TANGENT; + vertexDecl.routing.data[4].dest = STREAM_DST_TEXCOORD_2; + vertexDecl.routing.data[5].source = STREAM_SRC_TEXCOORD_1; + vertexDecl.routing.data[5].dest = STREAM_DST_TEXCOORD_1; + vertexDecl.routing.data[6].source = STREAM_SRC_TEXCOORD_2; + vertexDecl.routing.data[6].dest = STREAM_DST_TEXCOORD_3; + vertexDecl.routing.data[7].source = STREAM_SRC_TEXCOORD_3; + vertexDecl.routing.data[7].dest = STREAM_DST_TEXCOORD_4; + vertexDecl.routing.data[8].source = STREAM_SRC_NORMAL_TRANSFORM_0; + vertexDecl.routing.data[8].dest = STREAM_DST_TEXCOORD_5; + + pass.args = memory.Alloc(13); + pass.args[0].type = MTL_ARG_CODE_VERTEX_CONST; + pass.args[0].location.offset = 0; + pass.args[0].size = 0x40; + pass.args[0].buffer = 3; + pass.args[0].u.codeConst.index = CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX; + pass.args[0].u.codeConst.firstRow = 0; + pass.args[0].u.codeConst.rowCount = 4; + + pass.args[1].type = MTL_ARG_CODE_VERTEX_CONST; + pass.args[1].location.offset = 0x240; + pass.args[1].size = 0x40; + pass.args[1].buffer = 0; + pass.args[1].u.codeConst.index = CONST_SRC_CODE_TRANSPOSE_VIEW_PROJECTION_MATRIX; + pass.args[1].u.codeConst.firstRow = 0; + pass.args[1].u.codeConst.rowCount = 4; + + pass.args[2].type = MTL_ARG_MATERIAL_PIXEL_SAMPLER; + pass.args[2].location.textureIndex = 1; + pass.args[2].location.samplerIndex = 1; + pass.args[2].size = 1; + pass.args[2].buffer = 0; + pass.args[2].u.nameHash = 0x59d30d0f; + + pass.args[3].type = MTL_ARG_MATERIAL_PIXEL_SAMPLER; + pass.args[3].location.textureIndex = 3; + pass.args[3].location.samplerIndex = 5; + pass.args[3].size = 1; + pass.args[3].buffer = 0; + pass.args[3].u.nameHash = 0x9434aede; + + pass.args[4].type = MTL_ARG_MATERIAL_PIXEL_SAMPLER; + pass.args[4].location.textureIndex = 0; + pass.args[4].location.samplerIndex = 0; + pass.args[4].size = 1; + pass.args[4].buffer = 0; + pass.args[4].u.nameHash = 0xa0ab1041; + + pass.args[5].type = MTL_ARG_MATERIAL_PIXEL_SAMPLER; + pass.args[5].location.textureIndex = 2; + pass.args[5].location.samplerIndex = 2; + pass.args[5].size = 1; + pass.args[5].buffer = 0; + pass.args[5].u.nameHash = 0xb60d1850; + + pass.args[6].type = MTL_ARG_MATERIAL_PIXEL_SAMPLER; + pass.args[6].location.textureIndex = 5; + pass.args[6].location.samplerIndex = 4; + pass.args[6].size = 1; + pass.args[6].buffer = 0; + pass.args[6].u.nameHash = 0xb60d1852; + + pass.args[7].type = MTL_ARG_MATERIAL_PIXEL_SAMPLER; + pass.args[7].location.textureIndex = 4; + pass.args[7].location.samplerIndex = 3; + pass.args[7].size = 1; + pass.args[7].buffer = 0; + pass.args[7].u.nameHash = 0xb60d1853; + + pass.args[8].type = MTL_ARG_CODE_VERTEX_CONST; + pass.args[8].location.offset = 0x300; + pass.args[8].size = 0x40; + pass.args[8].buffer = 0; + pass.args[8].u.codeConst.index = CONST_SRC_CODE_TRANSPOSE_SHADOW_LOOKUP_MATRIX; + pass.args[8].u.codeConst.firstRow = 0; + pass.args[8].u.codeConst.rowCount = 4; + + pass.args[9].type = MTL_ARG_CODE_PIXEL_SAMPLER; + pass.args[9].location.textureIndex = 9; + pass.args[9].location.samplerIndex = 9; + pass.args[9].size = 1; + pass.args[9].buffer = 0; + pass.args[9].u.codeSampler = TEXTURE_SRC_CODE_SHADOWMAP_SUN; + + pass.args[10].type = MTL_ARG_CODE_PIXEL_CONST; + pass.args[10].location.offset = 0x610; + pass.args[10].size = 0x10; + pass.args[10].buffer = 0; + pass.args[10].u.codeConst.index = CONST_SRC_CODE_SHADOWMAP_SWITCH_PARTITION; + pass.args[10].u.codeConst.firstRow = 0; + pass.args[10].u.codeConst.rowCount = 1; + + pass.args[11].type = MTL_ARG_CODE_PIXEL_CONST; + pass.args[11].location.offset = 0x630; + pass.args[11].size = 0x10; + pass.args[11].buffer = 0; + pass.args[11].u.codeConst.index = CONST_SRC_CODE_SUNSHADOWMAP_PIXEL_SIZE; + pass.args[11].u.codeConst.firstRow = 0; + pass.args[11].u.codeConst.rowCount = 1; + + pass.args[12].type = MTL_ARG_MATERIAL_PIXEL_CONST; + pass.args[12].location.offset = 0x3b0; + pass.args[12].size = 0x10; + pass.args[12].buffer = 1; + pass.args[12].u.nameHash = 0x88befc31; + + return technique; + } + + MaterialTechniqueSet* GivenTechset(Zone& zone, MemoryManager& memory) + { + auto* techset = memory.Alloc(); + techset->name = "example_techset"; + techset->worldVertFormat = MTL_WORLDVERT_TEX_4_NRM_2; + + techset->techniques[TECHNIQUE_DEPTH_PREPASS] = GivenDepthPrepassTechnique(memory); + techset->techniques[TECHNIQUE_LIT_SUN_SHADOW] = GivenLitSunShadowTechnique(memory); + + zone.m_pools.AddAsset(std::make_unique>(ASSET_TYPE_TECHNIQUE_SET, techset->name, techset)); + return techset; + } +} // namespace + +TEST_CASE("TechsetDumperT6", "[t6][techset][dumper]") +{ + Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC); + zone.Register(); + + MemoryManager memory; + MockSearchPath mockObjPath; + MockOutputPath mockOutput; + AssetDumpingContext context(zone, "", mockOutput, mockObjPath, std::nullopt); + + GivenTechset(zone, memory); + + techset::DumperT6 dumper(true); + + SECTION("Can dump techset") + { + std::string expected(R"TECHSET( +"depth prepass": + example_zprepass; + +"lit sun shadow": + example_lit_sun_shadow; +)TECHSET"); + + dumper.Dump(context); + + const auto* file = mockOutput.GetMockedFile("techsets/example_techset.techset"); + REQUIRE(file); + REQUIRE(Trimmed(file->AsString()) == Trimmed(expected)); + } + + SECTION("Can dump simple technique") + { + std::string expected(R"TECHNIQUE( +// TECHNIQUE FLAGS: 0x4 +// TECHNIQUE FLAGS: 0x80 +{ + stateMap "passthrough"; // TODO + + vertexShader 4.0 "simple.hlsl" + { + // Omitted due to matching accessors: worldMatrix = constant.worldMatrix; + // Omitted due to matching accessors: viewProjectionMatrix = constant.viewProjectionMatrix; + } + + pixelShader 4.0 "simple.hlsl" + { + } + + vertex.position = code.position; +} +)TECHNIQUE"); + dumper.Dump(context); + + const auto* file = mockOutput.GetMockedFile("techniques/example_zprepass.tech"); + REQUIRE(file); + REQUIRE(Trimmed(file->AsString()) == Trimmed(expected)); + } + + SECTION("Can dump advanced technique") + { + std::string expected(R"TECHNIQUE( +// TECHNIQUE FLAGS: 0x8 +// TECHNIQUE FLAGS: 0x80 +{ + // CUSTOM SAMPLER FLAGS: 0x1 + // CUSTOM SAMPLER FLAGS: 0x2 + stateMap "passthrough"; // TODO + + vertexShader 4.0 "advanced.hlsl" + { + // Omitted due to matching accessors: worldMatrix = constant.worldMatrix; + // Omitted due to matching accessors: viewProjectionMatrix = constant.viewProjectionMatrix; + // Omitted due to matching accessors: shadowLookupMatrix = constant.shadowLookupMatrix; + } + + pixelShader 4.0 "advanced.hlsl" + { + normalMapSampler = material.normalMap; + normalMapSampler1 = material.normalMap1; + colorMapSampler = material.colorMap; + colorMapSampler1 = material.colorMap1; + colorMapSampler3 = material.colorMap3; + colorMapSampler2 = material.colorMap2; + // Omitted due to matching accessors: shadowmapSamplerSun = sampler.shadowmapSamplerSun; + // Omitted due to matching accessors: shadowmapSwitchPartition = constant.shadowmapSwitchPartition; + // Omitted due to matching accessors: sunShadowmapPixelSize = constant.sunShadowmapPixelSize; + alphaRevealParms1 = material.alphaRevealParms1; + } + + vertex.position = code.position; + vertex.color[0] = code.color; + vertex.texcoord[0] = code.texcoord[0]; + vertex.normal = code.normal; + vertex.texcoord[2] = code.tangent; + vertex.texcoord[1] = code.texcoord[1]; + vertex.texcoord[3] = code.texcoord[2]; + vertex.texcoord[4] = code.texcoord[3]; + vertex.texcoord[5] = code.normalTransform[0]; +} +)TECHNIQUE"); + dumper.Dump(context); + + const auto* file = mockOutput.GetMockedFile("techniques/example_lit_sun_shadow.tech"); + REQUIRE(file); + REQUIRE(Trimmed(file->AsString()) == Trimmed(expected)); + } +} diff --git a/test/ObjWritingTests/Game/T6/Techset/ps_advanced.hlsl.cso b/test/ObjWritingTests/Game/T6/Techset/ps_advanced.hlsl.cso new file mode 100644 index 0000000000000000000000000000000000000000..b01854324de62edc5d7d7705933b37bc30c43076 GIT binary patch literal 16412 zcmeI3e{3Abb;pM%iIOPGx+-dGtB!QA8x&C7_DD*yrCQ?hhbTFbth0`m6(dNvzFU$P zE$_~IcarE9!C8o1I0h0SX$#v35V}EA*ECWh0SdH;BF2BDK^vzm;51HKv`m1gNnNCb z3^=XR+WmfK=k4w8ja0+wj|lKMd$aR-Z{Ezj`ME=7?9|BUk3aXJzudiH=3BR%`pKu? zxbfcA9;MVRj#BFo@5b}&4yA6$DdpgqA5!YX*r9PBECbnZtx;+l;#=^jwQs(e`8lQb zL-rX6A?gaW&F6WGTx862(IRJg)M5ChMb7d>{*M;<+L(ORB4>Lge+I_V_1|dZ&HM!p+B8tAPok)Z1k&Qt6H3K%eAwnm}1jyddja%&opPFvWs4+RxP{1 zoC>@t-zzmMwQ3=#J?Kf@8rnoGL#wI^UQjG~Rd2LbZ8RH99)Iv7$ZOII^v^?R=kti$ zbf5|J%U-;H{pXd+vO`T6yD@ypn)HN8ml2btc@;cIT{;t?ZS*gYgHfOTCw4vqp11Hn z1a~a_OW*~=XS}Sx?thI0zPlydGJLG-w(cI;fKJN!8sQg z3P>|dB3`lR`{1kK8$vbJH2NQ73`aVKKWX^0h#d>R2;R2vzXD&f@KzSez?UujL*OeGej0q$!q0(oQ$sU!5dS|8p0)6&!E+Y=EO_3+{{-Bz@IMDHSoq7} zlNSC%@VbS+4&Ju#4O`)V3*QbtZ{fFtFIxB!@Ffd(!Iv$(4ZdRGPlB&n_#c6*-fsVY z89Zw^mWgOyd<#5h(f=3lyhT6rF8JS~p9L>i_zv(%a10e4ZbzEoF2r^4woc(ZVfZP; zs}?&h3Mw$JZs_8;5iFF1D?0=N5LHn z{~hpxg?|ow(!#$8UbpbCg10UFCGZOt{!ifZ7XCW;qJ?k9d27kScY-g2r^o*Q_)8Y< zfUj8WybpZU!Y9BL&VT8Calx||UIout_-}&eE&OqC$HJckFIf2RgHKxcm%!^5ezsCA zk5z*3RIC;jdej=#6M0K1x7>K3SaN+&opFPTTW#Kt48?j-sZK*L)Rne3TGc|WQQ`So z;eD(!HPvc(YNj0E)Z7eeem?fzugdzI9-iNi)@r9)^2PU-WTaBfbr=qT{t`xIme<<4|KlC<^n2@1nyMJPh@q#?JyYIjlTfxUdF(SsU}= znTmH79~?=&O7)BvG`y3LnVd1wr5%2v#J!}>)&jqLywxn%YC%Gv-HQGRVc2<^9r1!% zn0)vi&ka;9%slS7%^5E!xWQ~gO>0ebzSDM7lnUTdZXNJOH65s_#>L}V~#huv+4ALQe1 zsaXpe;df(HN9_oyqD~Z{%bZankuhF>tzoJ^9O|3YNGG>6CNdX-{3duROz>lyV{3l_m;v?&X zTaT@ISl)FgxwBs2-d9)Q3+It}Ey8OGbES5aR}7eAClaZ{iPVVl<~&pVXh$$>bf$l9S@fK#_2gdE{?VQ zW~J^|a0}&~YXOjN4P5f?jL ziQ5ZPW1io1!{kWCZKzVE>S2slN>~Mhk=nT~Fu?udB~uUPEA2Yl7S2f(o{boJL5c-F!vz;hN}0?%9c z8F0tK9|JE~_@}@pE&Q|KbqjwUylvrs3Vy-DzXm>U;ok;dG#qY^b|PYlKryW@#H@x?%c#C95tMPoXIWt8_|gr=N#CA4CErBJ|E$-zLRlpSdV)#>dX8g#}#bEnPy;& zE6j+?zCsQYk$vW6AZJ-(pLrR`ab*(eGcN;qA7i|*z47{Q0+;$TF9Y?tN78=r2Z+=}1N?7b z{{wK<_$P8mDOJWJY1+IC&jYN^WVqtWJ7w}t-^x47ly~}2-s!goHiUNAM&TSA^3Hmm zx(VG@56immzD}Cu#nUV^o@Tl6G|P^sS$;gtI>ghghfe3i@>v(AAIz#X-^*sTfBAj| z?<`y1SuWoLaF!|WEKlA!HbkG}K{)$MIP1gr0odU<5zet8`Wz1)`r=A1^v?{2HEj%_ zi?5g+aePNsF;B+9PuRtL(@%!Ks(mT`9KvvAUix?3v~B#OW_LAxE;?*?T!(o$E*P^8 z1F)lYOq_90k4M@LAE@Y%aWL32JxhEvz>nCcFKM5?U>#_S_8E%~eH_#6$!Z5uIm(sGt_V@|D)$#vgKy&>KZ7(3&cjxX`9 zZKHoTQcnL$eMH8X9AU$NDSzD5k9Ebn7Se{uBO4w4#8_j#%iBBSk^bUXGwtkSU9@eK z%{b%WCo#YDn7l#sJ`Y>0BkLN|$G^^Mn@1`1-FoVap2XBg3;M)&aT`xR_0++qpSpSI z#czD$0Bb-Sq9?v(|In7qBVBK^)^M(I{;+MjjVMRz953fuZF_BJr_OJ;ZRgoSgm{^@ zwo#95k+~slyqfQ*D`SUs>y>i0X7!#wj+lKK*EzY))CDs7M(P9_trNl|9>cudYHatJ zSn8B0*YtnF7RupT&blzZmMzvb-UjNUoW22+$^PS*jrYOAbI%gPM(fkSL(RL#f-!pI2pYT1?2nqYF@7uM{ym9+X(}&+P z?LT>A*v5laeyk&`&rY>=jrjhsQk$fYxL;G=TMyS#jx+A@y9`I2 zHeZ3S*p~5+l-s_w=`G=UQ!;AH4U{O)q}@E3fW+c<70T{^8>F*oNEspE)qI^Nvfc zv-^gA^^dn*x*pr`qu>4agSYiRa`6}XpTGFEAA3XBV;f%C^PgX-uity=m11z|FCL%z znVt{akMx{w=P=VcbNbiz?Kt@TLqCf4Bv~KgbMdE{(_Fu}4|89U`OdWp`_zH{*jf;- zUygPC!hGHo)!(dBuYEEHi}?2qc*aee_|AGqYu$gd7RfrX9{DbRB8T6OU%J*he8bRx zX}>V<|HNANcI{lN4P9&9b=ZckweC7>L)Th&9k!ust@{~ngRB*oKc2(v?9Az|wa%;$ z={fyVoI5tkIY`c7=3M5O^=%3BH99Y+*F$`#=x=zgmC)NL>!zHKM4#U?)WJUq>)DDY zzK*8Ljh_Qy^PP1RzGDzyif`c?eeUHtoZbuGSx3WjK3wyb&+h*l``J6|=>Kg${C};Z zJTuBVD)Us%j4Bt()?hFu*E%P?wnq1%l2_Kv^x8^WQjV+#TwD2|F8Ur+?+Iqz9Y3E# z4yEu<$@zW1Av$lG?|OX8>#}J#-WJ;K0b_meF9?QFk1YWh=gMnaLRrR9YH;w?gI_rO zUHrMHy#$fUIQT*MpE?ZmZ<6`APMr)frg%>5z8ec!(AK-_=ZO}qL`9G8jBxGXSw97D3Ep>4V^9_EQTLaoxdCt IlD(DiUrF~qKmY&$ literal 0 HcmV?d00001 diff --git a/test/ObjWritingTests/Game/T6/Techset/ps_simple.hlsl.cso b/test/ObjWritingTests/Game/T6/Techset/ps_simple.hlsl.cso new file mode 100644 index 0000000000000000000000000000000000000000..cfe8445a2501036fc948b644c9b0391efd4260c6 GIT binary patch literal 432 zcmZ>XaB}{!<3Xc&*;X^D5B7Zh~40iX^ z0SbZa=Kx{_AO-;tpBcNkIU}Vqh=>S`A|}IeU2Ggz700jbI7wY-+)x^kLc3~9smhDJ32A64*Z{#`oUeIrrRi&;6LYlj)14sS~Gvb^BXapSfowbdIbX{p^ivrUE`UeY*TzuwlqTJj~yZ$L#yhe~0fhW)-q$SyvKm^SPqPMy!nTiW^jG zZquFeo9(b|>J4vc8Tlsdej3kr@N{p(ADd`z4A1sqJeD#0*zIv;+_D*4e-=4emM?b_zpO-Xx`7VfOHZ0uA*ND-vd7g9roL>`k!GAP(a4CZutiCg5}f~ z{sZu?qW?4SZH51i_OPG|$kKM+rhUsHO6(tcH|&FF=l22db%p1_Hxzynd`sao;M)qn z2)?86I{2=_Ti|;N|17xK*YE!qz{eH-HSnCmUjd&``1ipJ3f~5=DEt@T3ku%_Zz=pH zcvs>3?m+w%emD4r!XF0TQuqn*ZH1o&-%;j7@g z3SS4`Q~0;R&Hn!QzXm?8@HfD73jaO$gu?#?UQqZ!On61%cY`m0W2r>xLAx-HBX5Cs zEiYJJLB6NhxkUMa{&Cg8#})2_=M?@T_=Lj02wqV5*TE|ae+7I&;je+W6#jGYuEKu} zzOL{;f^R7NZSXCHkK(?ut?;|RcNG2r_^!h9;Cl)$g7f8t?xQ5{%?kLq!Y_m86y5}% zQ22}B1%-bJyrS@Lf-fliRq&R=e+1rD_zm!Nh5rV8L*X~Uw-i3g`WZSV<&zXV=T_&Rt+;oksXQ1~WzOX1hN zW_{WV+*;`QO|!W4br|Ix$c(xJ`awn`36t zUz+k8eh?R;YkY)Q${RRZ_LmR>W5gWqt&-LAnpfSR?OuS)woH*e?RH<3%r!q~)MqlZ_)PQ@1@jZbc=954)(!l) z`oekF35*{%F1t>+>;@GlSZSN3NE6d|F;%{lDnBjdveRhHE-p%S&aF%FOyIgrsgxQW zSAI7ot0VpyB?~036~oYNcARMS#KiU>Q`_>x%mPVBvM>^oEQo|0OWEOc$9+^GFFUo+ z5883y5+9>Lh>KB$x@?(LdK#wvk2I|N#aQ3gO1E0eU=njNn9OSAv*6e*P%M_LMQkzt zNaZ%O7E&Z-VhTIWbE^%nF6yR@amCwk#c5T%Rku;BKi_GGsSv5+%e7@EKRy6D+x5)qBA;omQJiNIiw(1&#iy*SxT{jKvq)gCkn$bi{A0E%{9@ zF*oEk?e!rtyyBp9&uQ2_dSz`saGLf63cQtbO)M!?*UTn=gbm@Jq(!fRrt?lKb>`uC zk5bK9aRcY6mWd18N48i+)C~5DKf})e*kf}&wKF}nl5y8u>;4ixAp~CSbQXNFa9-qR!{d< z%cj=wJM|f74GTzK5PfK}Un}2_jv065xrVzk^VEFRZQwx0ao@hO7OjgXJB`q5H9R*k z?rIn~Q_c#Oo3nzm&c9Z5!%izI6vN=M1M8 z&f5qY{xidA>i~X7P@g(XWSk4(GBR@fl#T3ApLHhY_$iq5EAvPW)8-Hg)Mr~J za*m09R%WZ`=FiQZH&e4SvvX$t^u?*!*|}+Res=E3;*8mxMI4@m1Nht$wJBI%bhV-zkT>hlpU=Q~*x2LReh$A@D%U^(@em@^K-`{Do@?PTL1`fSTY zJDhj%hcRR#=QraKd=un&)BfZ0YNF4!Ow{LRMcS`kxSZTrGNInAo}HfiI}8+H@!uHa zB@Da#IP4Kb8aNus2us`99A@Li4y%t?({DbMA08lwIFjE#Ku()%Um751 zoFe-<+b{Z${IGNVpx7TE|Df0(Ab-fpuMd!a2y(_m=C6Ej+&>xPO#jMu{gD0Cvi*0B zM|&oZ<;U1CJ=V=d`91ji2pGpPmSV@S>=`GfF`L^tD4k5nj;3Ufzxu;d??b=RPGpnN zXH5HTMd*O|l~;*|J<Um5ZQ^G*)Q!S#{B=Y|7U#kU1A{PJDQp&L?xN0 z@~~ZxHva_XLgFsIOe^!l`3w*juAd8|ah$~#YDw(M*K^P?<^y;rr+z+XZkMr%U-yAa ze==S&tiQ4BSU4X{kEF)LHI&ukddxDJ12j*^D4F||eC(zjAI{}OeiRMmoW2)j`X_ox z9I(fueP#DJ+fa{tbOdG0Nn-CY+lTbaJt*g>#0yQLSR*$)=V(K6#C0qXKdo%I00m=C zr5^Twh9N!{Uc!oO|jpQO-G!;*ybb zZ&A*5r^(46Pv$c117%#F?3+o}yR1*L{Z=OJB*tm~p_Z&?#+L6f$tA{-zLgCZpfDiD z>9)fKsu}*3#|*PHAjTX|I<}E5#EYCU;yA_cNcVbwj5T>W#+uyPk7Atlf%+0-${1tj z5@VJb<8(WbvF$^*#dGuWzF3EQf$NDfGA8QS_R-#;Oy-Gq2bnv*7i66c6(B%*4DT-{ z%4CfR6CLc;WPS3SVPCQjS^ltHLzdqfUoL(RX2*9Y?Lo%74DS?-ubc}LC{up_06F}O z?+gRvh)*Qvd7;_Ixt7F+_b0}N{WD&C&+{I|_dMf9#`iq$Q+&_Up6KyjMLpW!eC17S z=Vg1IOCFtFkV$Nyp6oM;A^Vp(r`{s}(+lZyLvbF(%i3q0IKPok_N=5&*CA($=PbUr zaju!9O*A&Nu_-wdxF+cXb0+#MZTa42e;g<0KCK6z4+gePa!y>orGFfDM9w%f4Ht}g z=KXZIfIql*rXOkhaSX3IUz`u2@eCf`W0~&8^Ee**#w2-Md*{FC KKeF{s?fwVKQMfh$ literal 0 HcmV?d00001 diff --git a/test/ObjWritingTests/Game/T6/Techset/vs_simple.hlsl.cso b/test/ObjWritingTests/Game/T6/Techset/vs_simple.hlsl.cso new file mode 100644 index 0000000000000000000000000000000000000000..50c95fc29c08b8338853f79221339352893c14be GIT binary patch literal 5964 zcmb8zUu+vm9S88qwc&ce-I?Ced!Q25U4aVm;5elei9fcJI;oUvmaJQna**tK$If2Y zyUXmlaZa4@@q_@O2qB?^2aF0Y1fd8OA*7QoZwLvbfI#8_iJ$|4xRE)Hm(7nX*%+jLI#k z?4}IlLKwtJEL`7fZzJ8Oem{@>``G)B;h)*4zqeyQJd52JB_Df-4hqIrO#A{;vT<+0 zi&U3R0$b12|1vpjy#6=gCC0xCuQ0w3w;2B!e2eklz$3=rg7+DpeWwt6jK3E?VEiKd zfblZ?knxYhkKjnsZP{ejksdSkUHA$7jH&ON`d^?F6Q^Q)&-ego#W>BY%zp~+GxdJ~ zKVJJlYy#EK(KjTk6j{f1}*Y`R29^+;BfblEv1IAb2hm5boj~I91$Bakt6UM&? z7pEuB|10nUB2r$@%{jwg4l@p@ixN2*xfM44$hA``XaiBS?eq4M3;ZsLZa8XZ27 zenr9c(Woz8YRgiEI(+%Mbd(5nZ(1R2V3Vhm+CA%-$P z(hps3eGD7rb*GtxD%JxxJjZk(vQtb0s!J`0L9XHG`KL9^=~s1q6V)EJ&OXerI}LN= zHOk{K{}8Ixn&}a@7=1~l+syPZA|qWa;7;?T?R#!kUBviY`Znx1k>&NIUv*#V#>vPK zvBjIsZAW43q*_2mNw?YwyFnt93|y%ij%v%q_Fk5v8^yGQxFe(|G>&KQcu8{`lP@s~ zM>^B#L_&YJ9R@VTWJ0%T{v6VdI}Q%+Ilj3^Z|^pg6POi9d7WzkrWC?mu}@#ZX7HD7 zEzd{Oh7*mfd05`lt?6{6a&AOIXXrjMSsSA!aIb_b^fLhNv9(;Zl#6OY?n-m|ZTy6w zyyn$$_*B<%AD(3t#!0<5Tr6|poXCacd^n#EFXh7z=flhS@FV%~N}l!RcVSIUTHZ;f^hnZj|P#QRMH6COs+ijkq=%ER6;=9W=ZksX2JUrHv?B zlz!squ;w|jXnKLf9QB%51ywEVO+cBR7Y9%2c~?O~PnPVrhS%X_+4D7f=lea}V*Ic0 zEyn)|j~JiD?_+(&-vi%cd=5Tfd*a3hCj+e+v|>D5GlmuP zLsG0pGN{H_of={2$Hj(>lOiorm}vZlYkkdLy8a=QQm?e$6tQPp_U7>@-v6yt`L z>UEkQt5e!gA6XlGEfn_6&EeC_US3@5p+W^m`W(tOa2e`fFCr(zMeJEj?dke#qAOJ> zASXl{bib(cbc}6GOPZIL@ymiTv$1|wmy>|Ck* z*(v4JhRSPG%IQ3)oQ}!$Psd1)Uo^+X@zZ+dvtKaf&rT_SUv~T{ Date: Sun, 1 Mar 2026 00:55:18 +0100 Subject: [PATCH 17/27] fix: not setting shader arg flags when auto creating --- src/ObjCompiling/Techset/CommonShaderArgCreator.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp index 717b15b7..e80e7d23 100644 --- a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp +++ b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp @@ -626,6 +626,9 @@ namespace return std::move(result); } + if (constInfo->techFlags) + m_tech_flags |= *constInfo->techFlags; + return NoResult{}; } @@ -635,12 +638,21 @@ namespace if (!maybeCodeSampler) return result::Unexpected(std::format("Missing assignment to shader texture {}", textureResource.m_name)); + const auto samplerInfo = m_common_code_source_infos.GetInfoForCodeSamplerSource(*maybeCodeSampler); + if (!samplerInfo) + return result::Unexpected(std::format("Missing info for code sampler {}", textureResource.m_name)); + techset::CommonShaderArgDestination commonDestination; commonDestination.dx11.m_location.texture_index = textureResource.m_bind_point; commonDestination.dx11.m_location.sampler_index = samplerBindPoint; commonDestination.dx11.m_size = textureResource.m_bind_count; commonDestination.dx11.m_buffer = 0; + if (samplerInfo->techFlags) + m_tech_flags |= *samplerInfo->techFlags; + if (samplerInfo->customSamplerIndex) + m_sampler_flags |= (1 << *samplerInfo->customSamplerIndex); + return AcceptShaderSamplerArgument(commonDestination, *maybeCodeSampler); } From b2f51b2ae192ae515935d988dedfba3d6c63f423 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sun, 1 Mar 2026 00:56:56 +0100 Subject: [PATCH 18/27] fix: technique loading tech flags --- src/Common/Game/T5/T5_Assets.h | 23 ++++++++++++++++ src/Common/Game/T6/T6_Assets.h | 10 ++++++- .../Game/T6/Techset/TechsetConstantsT6.h | 1 - .../Game/T6/Techset/TechniqueCompilerT6.cpp | 27 ++++++++++++++++--- .../T6/Techset/TechniqueCompilerT6Test.cpp | 14 ++++++---- 5 files changed, 64 insertions(+), 11 deletions(-) diff --git a/src/Common/Game/T5/T5_Assets.h b/src/Common/Game/T5/T5_Assets.h index 65e8e1f6..58bdd757 100644 --- a/src/Common/Game/T5/T5_Assets.h +++ b/src/Common/Game/T5/T5_Assets.h @@ -1504,6 +1504,29 @@ namespace T5 const char* techniqueSetPrefix; }; + enum TechniqueFlags + { + TECHNIQUE_FLAG_1 = 0x1, + TECHNIQUE_FLAG_2 = 0x2, + TECHNIQUE_FLAG_4 = 0x4, + + // Vertex decl has optional source + TECHNIQUE_FLAG_8 = 0x8, + + TECHNIQUE_FLAG_10 = 0x10, + TECHNIQUE_FLAG_20 = 0x20, + TECHNIQUE_FLAG_40 = 0x40, + + // Any material that has statebits according to any of the following sets this: + // - GFXS1_DEPTHWRITE set + // - Any depth test (No GFXS1_DEPTHTEST_DISABLE set) + // - Any polygon offset that is not GFXS1_POLYGON_OFFSET_0 + TECHNIQUE_FLAG_80 = 0x80, + + TECHNIQUE_FLAG_100 = 0x100, + TECHNIQUE_FLAG_200 = 0x200, + }; + struct MaterialPass { MaterialVertexDeclaration* vertexDecl; diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 2ee51b42..8ab7f84f 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -3004,7 +3004,6 @@ namespace T6 enum CustomSamplers { CUSTOM_SAMPLER_REFLECTION_PROBE = 0, - CUSTOM_SAMPLER_LIGHTMAP_PRIMARY, CUSTOM_SAMPLER_LIGHTMAP_SECONDARY, CUSTOM_SAMPLER_COUNT @@ -3049,11 +3048,20 @@ namespace T6 TECHNIQUE_FLAG_1 = 0x1, TECHNIQUE_FLAG_2 = 0x2, TECHNIQUE_FLAG_4 = 0x4, + + // Vertex decl has optional source TECHNIQUE_FLAG_8 = 0x8, + TECHNIQUE_FLAG_10 = 0x10, TECHNIQUE_FLAG_20 = 0x20, TECHNIQUE_FLAG_40 = 0x40, + + // Any material that has statebits according to any of the following sets this: + // - GFXS1_DEPTHWRITE set + // - Any depth test (No GFXS1_DEPTHTEST_DISABLE set) + // - Any polygon offset that is not GFXS1_POLYGON_OFFSET_0 TECHNIQUE_FLAG_80 = 0x80, + TECHNIQUE_FLAG_100 = 0x100, TECHNIQUE_FLAG_200 = 0x200, }; diff --git a/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h b/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h index acdc4371..84e6b48f 100644 --- a/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h +++ b/src/ObjCommon/Game/T6/Techset/TechsetConstantsT6.h @@ -1577,7 +1577,6 @@ namespace T6 .value = TEXTURE_SRC_CODE_LIGHTMAP_PRIMARY, .accessor = "lightmapSamplerPrimary", .updateFrequency = techset::CommonCodeSourceUpdateFrequency::CUSTOM, - .customSamplerIndex = CUSTOM_SAMPLER_LIGHTMAP_PRIMARY, }, { .value = TEXTURE_SRC_CODE_LIGHTMAP_SECONDARY, diff --git a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp index 2eb162ef..d33d6cb1 100644 --- a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp +++ b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp @@ -151,6 +151,22 @@ namespace } ConvertMaterialArgs(pass, commonPass, memory, context); + pass.customSamplerFlags = static_cast(commonPass.m_sampler_flags); + } + + bool AnyDeclHasOptionalSource(const MaterialTechnique& technique) + { + for (auto passIndex = 0u; passIndex < technique.passCount; passIndex++) + { + const auto& pass = technique.passArray[passIndex]; + if (!pass.vertexDecl) + continue; + + if (pass.vertexDecl->hasOptionalSource) + return true; + } + + return false; } void UpdateTechniqueFlags(MaterialTechnique& technique, const techset::CommonTechnique& commonTechnique) @@ -165,6 +181,9 @@ namespace { technique.flags |= TECHNIQUE_FLAG_4; } + + if (AnyDeclHasOptionalSource(technique)) + technique.flags |= TECHNIQUE_FLAG_8; } MaterialTechnique* ConvertTechnique(const techset::CommonTechnique& commonTechnique, AssetCreationContext& context, MemoryManager& memory) @@ -176,15 +195,15 @@ namespace technique->name = memory.Dup(commonTechnique.m_name.c_str()); - // Take common flags and apply further logic - technique->flags = static_cast(commonTechnique.m_flags); - UpdateTechniqueFlags(*technique, commonTechnique); - technique->passCount = passCount; for (auto passIndex = 0u; passIndex < passCount; passIndex++) ConvertMaterialPass(technique->passArray[passIndex], commonTechnique.m_passes[passIndex], context, memory); + // Take common flags and apply further logic + technique->flags = static_cast(commonTechnique.m_flags); + UpdateTechniqueFlags(*technique, commonTechnique); + return technique; } diff --git a/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp b/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp index 64459b88..5adb211d 100644 --- a/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp +++ b/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp @@ -72,7 +72,7 @@ TEST_CASE("TechniqueCompilerT6", "[t6][techset][compiler]") SECTION("Can compile simple technique") { - searchPath.AddFileData("techniques/example_zprepass.tech", R"TECHNIQUE( + searchPath.AddFileData("techniques/pimp_technique_zprepass_example.tech", R"TECHNIQUE( { stateMap "passthrough"; @@ -91,14 +91,16 @@ TEST_CASE("TechniqueCompilerT6", "[t6][techset][compiler]") GivenVertexShaderFile("simple.hlsl", searchPath); GivenPixelShaderFile("simple.hlsl", searchPath); - auto result = loader->CreateSubAsset("example_zprepass", context); + auto result = loader->CreateSubAsset("pimp_technique_zprepass_example", context); REQUIRE(result.HasBeenSuccessful()); const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); const auto* technique = assetInfo->Asset(); - CHECK(technique->name == "example_zprepass"s); - CHECK(technique->flags == 0x84); + CHECK(technique->name == "pimp_technique_zprepass_example"s); + + // Usually would be 0x80 set as well, but that's only set when postprocessing with materials + CHECK(technique->flags == 0x04); REQUIRE(technique->passCount == 1); auto& pass = technique->passArray[0]; @@ -186,7 +188,9 @@ TEST_CASE("TechniqueCompilerT6", "[t6][techset][compiler]") const auto* technique = assetInfo->Asset(); CHECK(technique->name == "example_lit_sun_shadow"s); - CHECK(technique->flags == 0x88); + + // Usually would be 0x80 set as well, but that's only set when postprocessing with materials + CHECK(technique->flags == 0x08); REQUIRE(technique->passCount == 1); auto& pass = technique->passArray[0]; From 400c6ca78a7de910c802a80f834077719754a6fa Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sun, 1 Mar 2026 01:13:35 +0100 Subject: [PATCH 19/27] fix: use buffer binding point instead of index --- .../Techset/CommonShaderArgCreator.cpp | 34 ++++++--- .../T6/Techset/TechniqueCompilerT6Test.cpp | 72 +++++++++++++++++-- 2 files changed, 91 insertions(+), 15 deletions(-) diff --git a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp index e80e7d23..03621a69 100644 --- a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp +++ b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp @@ -408,12 +408,20 @@ namespace { assert(m_shader_info); - auto bufferIndex = 0uz; auto usedConstantIndex = 0uz; - const auto bufferCount = m_shader_info->m_constant_buffers.size(); - while (bufferIndex < bufferCount) + for (const auto& buffer : m_shader_info->m_constant_buffers) { - const auto& buffer = m_shader_info->m_constant_buffers[bufferIndex]; + const auto bufferBinding = + std::ranges::find_if(m_shader_info->m_bound_resources, + [buffer](const d3d11::BoundResource& boundResource) + { + return boundResource.m_type == d3d11::BoundResourceType::CBUFFER && boundResource.m_name == buffer.m_name; + }); + if (bufferBinding == m_shader_info->m_bound_resources.end()) + { + errorMessage = std::format("Failed to find binding for constant buffer {}", buffer.m_name); + return false; + } auto variableIterator = buffer.m_variables.begin(); const auto variableEnd = buffer.m_variables.end(); @@ -439,15 +447,13 @@ namespace const auto variableElementSize = variableIterator->m_size / variableElementCount; commonDestination.dx11.m_location.constant_buffer_offset = variableIterator->m_offset + variableElementSize * inputArgumentIndex; commonDestination.dx11.m_size = variableElementSize; - commonDestination.dx11.m_buffer = static_cast(bufferIndex); + commonDestination.dx11.m_buffer = bufferBinding->m_bind_point; isTransposed = variableIterator->m_variable_class == d3d11::VariableClass::MATRIX_COLUMNS; m_const_arg_added[usedConstantIndex] = true; return true; } - - bufferIndex++; } return false; @@ -514,12 +520,20 @@ namespace result::Expected AutoCreateMissingArgs() override { - size_t bufferIndex = 0; size_t usedConstantCount = 0; size_t textureCount = 0; for (const auto& buffer : m_shader_info->m_constant_buffers) { + const auto bufferBinding = + std::ranges::find_if(m_shader_info->m_bound_resources, + [buffer](const d3d11::BoundResource& boundResource) + { + return boundResource.m_type == d3d11::BoundResourceType::CBUFFER && boundResource.m_name == buffer.m_name; + }); + if (bufferBinding == m_shader_info->m_bound_resources.end()) + return result::Unexpected(std::format("Failed to find binding for constant buffer {}", buffer.m_name)); + for (const auto& variable : buffer.m_variables) { if (!variable.m_is_used) @@ -528,12 +542,10 @@ namespace if (m_const_arg_added[usedConstantCount++]) continue; - auto result = AutoCreateConstantArg(variable, bufferIndex); + auto result = AutoCreateConstantArg(variable, bufferBinding->m_bind_point); if (!result) return std::move(result); } - - bufferIndex++; } for (const auto& maybeTextureResource : m_shader_info->m_bound_resources) diff --git a/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp b/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp index 5adb211d..3ddd149d 100644 --- a/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp +++ b/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp @@ -8,6 +8,7 @@ #include "SearchPath/MockSearchPath.h" #include "Shader/ShaderCommon.h" #include "Utils/MemoryManager.h" +#include "catch2/generators/catch_generators.hpp" #include #include @@ -72,7 +73,8 @@ TEST_CASE("TechniqueCompilerT6", "[t6][techset][compiler]") SECTION("Can compile simple technique") { - searchPath.AddFileData("techniques/pimp_technique_zprepass_example.tech", R"TECHNIQUE( + const auto [inputName, inputData] = GENERATE(Catch::Generators::table({ + {"auto-create args", R"TECHNIQUE( { stateMap "passthrough"; @@ -86,7 +88,28 @@ TEST_CASE("TechniqueCompilerT6", "[t6][techset][compiler]") vertex.position = code.position; } -)TECHNIQUE"); +)TECHNIQUE"}, + {"manual args", R"TECHNIQUE( +{ + stateMap "passthrough"; + + vertexShader 4.0 "simple.hlsl" + { + worldMatrix = constant.worldMatrix; + viewProjectionMatrix = constant.viewProjectionMatrix; + } + + pixelShader 4.0 "simple.hlsl" + { + } + + vertex.position = code.position; +} +)TECHNIQUE"}, + })); + + CAPTURE(inputName); + searchPath.AddFileData("techniques/pimp_technique_zprepass_example.tech", inputData); GivenVertexShaderFile("simple.hlsl", searchPath); GivenPixelShaderFile("simple.hlsl", searchPath); @@ -147,7 +170,8 @@ TEST_CASE("TechniqueCompilerT6", "[t6][techset][compiler]") SECTION("Can compile advanced technique") { - searchPath.AddFileData("techniques/example_lit_sun_shadow.tech", R"TECHNIQUE( + const auto [inputName, inputData] = GENERATE(Catch::Generators::table({ + {"auto-create args", R"TECHNIQUE( { stateMap "passthrough"; @@ -176,7 +200,47 @@ TEST_CASE("TechniqueCompilerT6", "[t6][techset][compiler]") vertex.texcoord[4] = code.texcoord[3]; vertex.texcoord[5] = code.normalTransform[0]; } -)TECHNIQUE"); +)TECHNIQUE"}, + {"manual args", R"TECHNIQUE( +{ + stateMap "passthrough"; + + vertexShader 4.0 "advanced.hlsl" + { + worldMatrix = constant.worldMatrix; + viewProjectionMatrix = constant.viewProjectionMatrix; + shadowLookupMatrix = constant.shadowLookupMatrix; + } + + pixelShader 4.0 "advanced.hlsl" + { + normalMapSampler = material.normalMap; + normalMapSampler1 = material.normalMap1; + colorMapSampler = material.colorMap; + colorMapSampler1 = material.colorMap1; + colorMapSampler3 = material.colorMap3; + colorMapSampler2 = material.colorMap2; + shadowmapSamplerSun = sampler.shadowmapSamplerSun; + shadowmapSwitchPartition = constant.shadowmapSwitchPartition; + sunShadowmapPixelSize = constant.sunShadowmapPixelSize; + alphaRevealParms1 = material.alphaRevealParms1; + } + + vertex.position = code.position; + vertex.color[0] = code.color; + vertex.texcoord[0] = code.texcoord[0]; + vertex.normal = code.normal; + vertex.texcoord[2] = code.tangent; + vertex.texcoord[1] = code.texcoord[1]; + vertex.texcoord[3] = code.texcoord[2]; + vertex.texcoord[4] = code.texcoord[3]; + vertex.texcoord[5] = code.normalTransform[0]; +} +)TECHNIQUE"}, + })); + + CAPTURE(inputName); + searchPath.AddFileData("techniques/example_lit_sun_shadow.tech", inputData); GivenVertexShaderFile("advanced.hlsl", searchPath); GivenPixelShaderFile("advanced.hlsl", searchPath); From dcd67adad454dd97bf4f17eb29014cc0bbc27461 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sun, 1 Mar 2026 01:27:52 +0100 Subject: [PATCH 20/27] fix: shader arg matrix row count --- src/ObjCompiling/Techset/CommonShaderArgCreator.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp index 03621a69..9f0c5c10 100644 --- a/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp +++ b/src/ObjCompiling/Techset/CommonShaderArgCreator.cpp @@ -203,15 +203,14 @@ namespace if (!maybeInfo) return result::Unexpected("Could not find info for code constant"); + const auto isMatrix = maybeInfo->transposedMatrix.has_value(); techset::CommonShaderArgCodeConstValue value{ .m_index = 0, .m_first_row = 0, - .m_row_count = 1, + .m_row_count = isMatrix ? 4u : 1u, }; - // All matrices have a transposed version - // this checks whether this is a matrix - if (maybeInfo->transposedMatrix) + if (isMatrix) { if (sourceIndex >= 4) return result::Unexpected(std::format("Index for matrix code const is out of bounds: {} (must be < 4)", sourceIndex)); From 7ab9adc17cf914170975323f8a8d3ad4b86b47eb Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sun, 1 Mar 2026 13:31:24 +0100 Subject: [PATCH 21/27] chore: handle flag 80 on t6 techniques --- src/ObjCompiling/Game/T6/ObjCompilerT6.cpp | 2 +- .../Game/T6/Techset/TechniqueCompilerT6.cpp | 38 +++++++++++++++++-- .../Game/T6/Techset/TechniqueCompilerT6.h | 2 +- .../Asset/AssetCreatorCollection.cpp | 2 + .../Techset/CommonTechniqueDumper.cpp | 9 ++++- src/ZoneCommon/Pool/AssetPool.h | 4 +- .../T6/Techset/TechniqueCompilerT6Test.cpp | 2 +- 7 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp b/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp index 7a825ec8..34e0cbb1 100644 --- a/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp +++ b/src/ObjCompiling/Game/T6/ObjCompilerT6.cpp @@ -25,7 +25,7 @@ namespace collection.AddAssetCreator(key_value_pairs::CreateCompilerT6(memory, zone, zoneDefinition.m_zone_definition, zoneStates)); collection.AddAssetCreator(techset::CreateCompilerT6(memory, searchPath)); - collection.AddSubAssetCreator(techset::CreateTechniqueCompilerT6(memory, searchPath)); + collection.AddSubAssetCreator(techset::CreateTechniqueCompilerT6(memory, zone, searchPath)); collection.AddSubAssetCreator(techset::CreateVertexDeclCompilerT6(memory)); } diff --git a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp index d33d6cb1..08e285f3 100644 --- a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp +++ b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp @@ -207,6 +207,27 @@ namespace return technique; } + void ApplyTechFlagsFromMaterial(const Material& material) + { + if (!material.techniqueSet || material.stateBitsTable) + return; + + for (auto techType = 0u; techType < TECHNIQUE_COUNT; techType++) + { + auto* technique = material.techniqueSet->techniques[techType]; + const auto stateBitsEntry = material.stateBitsEntry[techType]; + + if (!technique || stateBitsEntry < 0 || static_cast(stateBitsEntry) >= material.stateBitsCount) + continue; + + const auto& stateBits = material.stateBitsTable[static_cast(stateBitsEntry)].loadBits; + const bool shouldSetFlag80 = stateBits.structured.depthTestDisabled == 0 || stateBits.structured.depthWrite > 0 + || stateBits.structured.depthTest > 0 || stateBits.structured.polygonOffset > 0; + if (shouldSetFlag80) + technique->flags |= TECHNIQUE_FLAG_80; + } + } + class TechniqueShaderLoaderT6 final : public techset::ITechniqueShaderLoader { public: @@ -256,8 +277,9 @@ namespace class TechniqueCompilerT6 final : public SubAssetCreator { public: - TechniqueCompilerT6(MemoryManager& memory, ISearchPath& searchPath) + TechniqueCompilerT6(MemoryManager& memory, Zone& zone, ISearchPath& searchPath) : m_memory(memory), + m_zone(zone), m_search_path(searchPath) { } @@ -280,16 +302,26 @@ namespace return AssetCreationResult::Success(context.AddSubAsset(AssetRegistration(subAssetName, convertedTechnique))); } + void FinalizeZone(AssetCreationContext& context) override + { + const auto materials = m_zone.m_pools.PoolAssets(); + for (auto* materialAsset : materials) + { + ApplyTechFlagsFromMaterial(*materialAsset->Asset()); + } + } + private: MemoryManager& m_memory; + Zone& m_zone; ISearchPath& m_search_path; }; } // namespace namespace techset { - std::unique_ptr CreateTechniqueCompilerT6(MemoryManager& memory, ISearchPath& searchPath) + std::unique_ptr CreateTechniqueCompilerT6(MemoryManager& memory, Zone& zone, ISearchPath& searchPath) { - return std::make_unique(memory, searchPath); + return std::make_unique(memory, zone, searchPath); } } // namespace techset diff --git a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.h b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.h index c859d4d0..869acca8 100644 --- a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.h +++ b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.h @@ -8,5 +8,5 @@ namespace techset { - std::unique_ptr CreateTechniqueCompilerT6(MemoryManager& memory, ISearchPath& searchPath); + std::unique_ptr CreateTechniqueCompilerT6(MemoryManager& memory, Zone& zone, ISearchPath& searchPath); } diff --git a/src/ObjLoading/Asset/AssetCreatorCollection.cpp b/src/ObjLoading/Asset/AssetCreatorCollection.cpp index 13282c69..3edaabaa 100644 --- a/src/ObjLoading/Asset/AssetCreatorCollection.cpp +++ b/src/ObjLoading/Asset/AssetCreatorCollection.cpp @@ -111,6 +111,8 @@ AssetCreationResult AssetCreatorCollection::CreateDefaultAsset(const asset_type_ void AssetCreatorCollection::FinalizeZone(AssetCreationContext& context) const { + for (const auto& creator : m_sub_asset_creators) + creator->FinalizeZone(context); for (const auto& creator : m_asset_creators) creator->FinalizeZone(context); for (const auto& postProcessor : m_asset_post_processors) diff --git a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp index d5c64043..8afb185c 100644 --- a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp +++ b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp @@ -317,11 +317,12 @@ namespace if (arg.m_type.m_value_type == CommonShaderValueType::CODE_CONST) { auto constSourceInfo = m_code_source_infos.GetInfoForCodeConstSource(arg.m_value.code_const_source.m_index); + const auto isMatrix = constSourceInfo && constSourceInfo->transposedMatrix.has_value(); if (isTransposed) { - assert(constSourceInfo); - if (constSourceInfo && constSourceInfo->transposedMatrix) + assert(isMatrix); + if (isMatrix) constSourceInfo = m_code_source_infos.GetInfoForCodeConstSource(*constSourceInfo->transposedMatrix); } @@ -333,6 +334,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); + if (codeDestAccessor != codeAccessor) { Indent(); diff --git a/src/ZoneCommon/Pool/AssetPool.h b/src/ZoneCommon/Pool/AssetPool.h index 55f25cd0..27cc7266 100644 --- a/src/ZoneCommon/Pool/AssetPool.h +++ b/src/ZoneCommon/Pool/AssetPool.h @@ -102,12 +102,12 @@ public: { } - AssetPoolIterator begin() + AssetPoolIterator begin() const { return AssetPoolIterator(m_asset_pool.begin()); } - AssetPoolIterator end() + AssetPoolIterator end() const { return AssetPoolIterator(m_asset_pool.end()); } diff --git a/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp b/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp index 3ddd149d..43b0c4aa 100644 --- a/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp +++ b/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp @@ -69,7 +69,7 @@ TEST_CASE("TechniqueCompilerT6", "[t6][techset][compiler]") creatorCollection.AddSubAssetCreator(techset::CreateVertexShaderLoaderT6(memory, searchPath)); creatorCollection.AddSubAssetCreator(techset::CreatePixelShaderLoaderT6(memory, searchPath)); - auto loader = techset::CreateTechniqueCompilerT6(memory, searchPath); + auto loader = techset::CreateTechniqueCompilerT6(memory, zone, searchPath); SECTION("Can compile simple technique") { From bbb282a206fbb13527788a3e7f4ce29d91e6ee44 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Fri, 23 Jan 2026 21:55:27 +0000 Subject: [PATCH 22/27] chore: deactivate IW4 material and techset compilation for now --- .../Game/IW4/Material/CompilerMaterialIW4.cpp | 10 +++++---- .../Game/IW4/Techset/CompilerTechsetIW4.cpp | 21 +++++++++++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.cpp b/src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.cpp index 0f3fdecd..d2e20bc0 100644 --- a/src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.cpp +++ b/src/ObjCompiling/Game/IW4/Material/CompilerMaterialIW4.cpp @@ -9,11 +9,8 @@ #include "Gdt/AbstractGdtEntryReader.h" #include "Gdt/IGdtQueryable.h" #include "Pool/GlobalAssetPool.h" -#include "Techset/CommonTechsetCache.h" -#include "Techset/StateMap/StateMapFromTechniqueExtractor.h" #include "Techset/StateMap/StateMapHandler.h" -#include "Techset/TechniqueFileReader.h" -#include "Techset/TechniqueStateMapCache.h" +#include "Techset/StateMap/TechniqueStateMapCache.h" #include "Techset/TechsetCommon.h" #include "Utils/Logging/Log.h" @@ -28,6 +25,7 @@ using namespace IW4; namespace { + /* class SkipMaterialException final : public std::exception { }; @@ -1328,6 +1326,7 @@ namespace std::unique_ptr m_techset_creator; }; + */ class MaterialLoader final : public AssetCreator { @@ -1341,6 +1340,8 @@ namespace AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override { + return AssetCreationResult::NoAction(); + /* const auto* entry = m_gdt.GetGdtEntryByGdfAndName(ObjConstants::GDF_FILENAME_MATERIAL, assetName); if (!entry) return AssetCreationResult::NoAction(); @@ -1367,6 +1368,7 @@ namespace } return AssetCreationResult::Failure(); + */ } private: diff --git a/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp b/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp index 158b9984..161fa2e9 100644 --- a/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp +++ b/src/ObjCompiling/Game/IW4/Techset/CompilerTechsetIW4.cpp @@ -6,11 +6,9 @@ #include "Game/IW4/Techset/TechsetConstantsIW4.h" #include "Shader/D3D9ShaderAnalyser.h" #include "Shader/ShaderCommon.h" -#include "Techset/CommonTechsetCache.h" #include "Techset/CommonTechsetLoader.h" #include "Techset/StateMap/StateMapReader.h" -#include "Techset/TechniqueFileReader.h" -#include "Techset/TechniqueStateMapCache.h" +#include "Techset/StateMap/TechniqueStateMapCache.h" #include "Techset/TechsetCommon.h" #include "Utils/Alignment.h" #include "Utils/Logging/Log.h" @@ -32,6 +30,7 @@ using namespace std::string_literals; namespace { + /* class LoadedTechnique { public: @@ -407,7 +406,7 @@ namespace if (arg1.m_arg.type == MTL_ARG_MATERIAL_VERTEX_CONST || arg1.m_arg.type == MTL_ARG_MATERIAL_PIXEL_CONST || arg1.m_arg.type == MTL_ARG_MATERIAL_PIXEL_SAMPLER) - return arg1.m_arg.u.codeSampler < arg2.m_arg.u.codeSampler; + return arg1.m_arg.u.nameHash < arg2.m_arg.u.nameHash; return arg1.m_arg.dest < arg2.m_arg.dest; }); @@ -1263,7 +1262,7 @@ namespace TechniqueZoneLoadingState& m_zone_state; techset::ICreatorIW4* m_techset_creator; }; - + */ class TechsetLoader final : public techset::ICreatorIW4 { public: @@ -1275,15 +1274,18 @@ namespace AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override { + return AssetCreationResult::NoAction(); + /* bool failure = false; const auto* techsetDefinition = LoadTechsetDefinition(assetName, context, failure); if (!techsetDefinition) return failure ? AssetCreationResult::Failure() : AssetCreationResult::NoAction(); return CreateTechsetFromDefinition(assetName, *techsetDefinition, context); + */ } - private: + /* AssetCreationResult CreateTechsetFromDefinition(const std::string& assetName, const CommonTechset& definition, AssetCreationContext& context) { auto* techset = m_memory.Alloc(); @@ -1311,9 +1313,11 @@ namespace return AssetCreationResult::Success(context.AddAsset(std::move(registration))); } + */ CommonTechset* LoadTechsetDefinition(const std::string& assetName, AssetCreationContext& context, bool& failure) override { + /* failure = false; auto& definitionCache = context.GetZoneAssetCreationState(); auto* cachedTechsetDefinition = definitionCache.GetCachedTechsetDefinition(assetName); @@ -1334,10 +1338,13 @@ namespace definitionCache.AddCommonTechsetToCache(assetName, std::move(techsetDefinition)); return techsetDefinitionPtr; + */ + return nullptr; } const state_map::StateMapDefinition* LoadStateMapDefinition(const std::string& stateMapName, AssetCreationContext& context) override { + /* auto& stateMapCache = context.GetZoneAssetCreationState(); auto* cachedStateMap = stateMapCache.GetCachedStateMap(stateMapName); if (cachedStateMap) @@ -1358,6 +1365,8 @@ namespace stateMapCache.AddStateMapToCache(std::move(stateMapDefinition)); return stateMapDefinitionPtr; + */ + return nullptr; } private: From d0ee167d2d845a65b0e5ed07b5fa4f1fa0453b18 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sun, 1 Mar 2026 16:33:53 +0100 Subject: [PATCH 23/27] fix: not properly setting common technique shader type --- src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp index ba204f1c..e905b8d9 100644 --- a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp +++ b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp @@ -194,7 +194,7 @@ namespace techset::CommonTechniqueShader ConvertToCommonShader(const MaterialVertexShader* vertexShader) { - techset::CommonTechniqueShader result{}; + techset::CommonTechniqueShader result(techset::CommonTechniqueShaderType::VERTEX, std::string()); if (!vertexShader) return result; @@ -214,7 +214,7 @@ namespace techset::CommonTechniqueShader ConvertToCommonShader(const MaterialPixelShader* pixelShader) { - techset::CommonTechniqueShader result{}; + techset::CommonTechniqueShader result(techset::CommonTechniqueShaderType::PIXEL, std::string()); if (!pixelShader) return result; From 12199b53950a31c530ba661b005acd430a81350c Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sun, 1 Mar 2026 16:39:00 +0100 Subject: [PATCH 24/27] fix: not properly respecting code const array boundaries when dumping techniques --- src/ObjCommon/Techset/CommonTechnique.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ObjCommon/Techset/CommonTechnique.cpp b/src/ObjCommon/Techset/CommonTechnique.cpp index f719d37d..d67d5617 100644 --- a/src/ObjCommon/Techset/CommonTechnique.cpp +++ b/src/ObjCommon/Techset/CommonTechnique.cpp @@ -52,8 +52,9 @@ namespace techset { for (const auto& codeConstSourceInfo : m_code_const_source_infos) { - const auto codeConstSourceInfoEnd = static_cast(codeConstSourceInfo.value) + codeConstSourceInfo.arrayCount; - if (codeConstSourceInfo.value <= codeConstSource && codeConstSourceInfoEnd >= codeConstSource) + const auto arrayCount = std::max(codeConstSourceInfo.arrayCount, 1); + const auto codeConstSourceInfoEnd = static_cast(codeConstSourceInfo.value) + arrayCount; + if (codeConstSourceInfo.value <= codeConstSource && codeConstSourceInfoEnd > codeConstSource) return codeConstSourceInfo; if (codeConstSourceInfoEnd > codeConstSource) From 925e51cb1092b18fa392a555a07dfa8b24dd2acb Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sun, 1 Mar 2026 18:36:27 +0100 Subject: [PATCH 25/27] fix: not setting correct flags on technique post processing when reusing assets --- .../Game/T6/Techset/TechniqueCompilerT6.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp index 08e285f3..0a243db9 100644 --- a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp +++ b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp @@ -207,14 +207,19 @@ namespace return technique; } - void ApplyTechFlagsFromMaterial(const Material& material) + void ApplyTechFlagsFromMaterial(const Material& material, const Zone& zone) { - if (!material.techniqueSet || material.stateBitsTable) + if (!material.techniqueSet || !material.techniqueSet->name || !material.stateBitsTable) + return; + + // Find the techniqueset asset from our zone since the material may link to a different one + const auto techniqueSetAsset = zone.m_pools.GetAsset(material.techniqueSet->name); + if (!techniqueSetAsset) return; for (auto techType = 0u; techType < TECHNIQUE_COUNT; techType++) { - auto* technique = material.techniqueSet->techniques[techType]; + auto* technique = techniqueSetAsset->Asset()->techniques[techType]; const auto stateBitsEntry = material.stateBitsEntry[techType]; if (!technique || stateBitsEntry < 0 || static_cast(stateBitsEntry) >= material.stateBitsCount) @@ -307,7 +312,7 @@ namespace const auto materials = m_zone.m_pools.PoolAssets(); for (auto* materialAsset : materials) { - ApplyTechFlagsFromMaterial(*materialAsset->Asset()); + ApplyTechFlagsFromMaterial(*materialAsset->Asset(), m_zone); } } From 1611c222ccfbac312fa25f9d2d4a15c791f44cc3 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Mon, 2 Mar 2026 22:07:55 +0000 Subject: [PATCH 26/27] chore: add logic for computing precompiled index on material pass --- src/Common/Game/T6/T6_Assets.h | 6 +- src/ObjCommon/Techset/CommonTechnique.cpp | 6 +- src/ObjCommon/Techset/CommonTechnique.h | 4 +- .../Game/T6/Techset/TechniqueCompilerT6.cpp | 251 ++++++++++++++++++ src/ObjLoading/Asset/AssetCreationContext.h | 6 + .../Game/T5/Techset/TechsetDumperT5.cpp | 3 +- .../Game/T6/Techset/TechsetDumperT6.cpp | 15 +- .../Techset/CommonTechniqueDumper.cpp | 6 + src/ZoneCommon/Pool/AssetPool.h | 4 +- .../Game/T6/Techset/TechsetDumperT6Test.cpp | 2 + 10 files changed, 291 insertions(+), 12 deletions(-) diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 8ab7f84f..d38ed38e 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -3001,7 +3001,7 @@ namespace T6 VERTEX_SHADER_MODEL_UNLIT, }; - enum CustomSamplers + enum CustomSampler { CUSTOM_SAMPLER_REFLECTION_PROBE = 0, CUSTOM_SAMPLER_LIGHTMAP_SECONDARY, @@ -6191,7 +6191,7 @@ namespace T6 unsigned int nameHash; }; - enum MaterialShaderArgumentType + enum MaterialShaderArgumentType : uint16_t { MTL_ARG_MATERIAL_VERTEX_CONST = 0x0, MTL_ARG_LITERAL_VERTEX_CONST = 0x1, @@ -6213,7 +6213,7 @@ namespace T6 struct MaterialShaderArgument { - uint16_t type; + MaterialShaderArgumentType type; MaterialArgumentLocation location; uint16_t size; uint16_t buffer; diff --git a/src/ObjCommon/Techset/CommonTechnique.cpp b/src/ObjCommon/Techset/CommonTechnique.cpp index d67d5617..52ef6f5f 100644 --- a/src/ObjCommon/Techset/CommonTechnique.cpp +++ b/src/ObjCommon/Techset/CommonTechnique.cpp @@ -280,12 +280,14 @@ namespace techset std::string stateMap, CommonTechniqueShader vertexShader, CommonTechniqueShader pixelShader, - CommonVertexDeclaration vertexDeclaration) + CommonVertexDeclaration vertexDeclaration, + std::string comment) : m_sampler_flags(samplerFlags), m_state_map(std::move(stateMap)), m_vertex_shader(std::move(vertexShader)), m_pixel_shader(std::move(pixelShader)), - m_vertex_declaration(std::move(vertexDeclaration)) + m_vertex_declaration(std::move(vertexDeclaration)), + m_comment(std::move(comment)) { } diff --git a/src/ObjCommon/Techset/CommonTechnique.h b/src/ObjCommon/Techset/CommonTechnique.h index ab8950d6..8e54aa40 100644 --- a/src/ObjCommon/Techset/CommonTechnique.h +++ b/src/ObjCommon/Techset/CommonTechnique.h @@ -283,7 +283,8 @@ namespace techset std::string stateMap, CommonTechniqueShader vertexShader, CommonTechniqueShader pixelShader, - CommonVertexDeclaration vertexDeclaration); + CommonVertexDeclaration vertexDeclaration, + std::string comment); [[nodiscard]] FrequencyCounts_t GetFrequencyCounts(const CommonCodeSourceInfos& infos) const; @@ -292,6 +293,7 @@ namespace techset CommonTechniqueShader m_vertex_shader; CommonTechniqueShader m_pixel_shader; CommonVertexDeclaration m_vertex_declaration; + std::string m_comment; std::vector m_args; }; diff --git a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp index 0a243db9..44640a04 100644 --- a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp +++ b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp @@ -8,12 +8,218 @@ #include "Utils/StringUtils.h" #include +#include #include +#include using namespace T6; namespace { + class PrecompiledIndexMapping + { + public: + [[nodiscard]] bool + Matches(const MaterialType materialType, const std::vector& passCodeConsts, const unsigned samplerFlags) const + { + if (m_material_type && materialType != *m_material_type) + return false; + if (m_vertex_const_constraints.size() > passCodeConsts.size()) + return false; + + auto passCodeConstIndex = 0u; + for (const auto codeConstConstraint : m_vertex_const_constraints) + { + if (passCodeConsts[passCodeConstIndex++] != codeConstConstraint) + return false; + } + + auto expectedSamplerFlags = 0u; + for (const auto customSampler : m_custom_sampler_constraints) + expectedSamplerFlags |= (1 << customSampler); + + return samplerFlags == expectedSamplerFlags; + } + + VertexShaderPrecompiledIndex m_value; + std::optional m_material_type; + std::vector m_vertex_const_constraints; + std::vector m_custom_sampler_constraints; + }; + + // clang-format off + inline PrecompiledIndexMapping precompiledIndexMappings[]{ + { + .m_value = VERTEX_SHADER_MODEL_LIT, + .m_material_type = MTL_TYPE_MODEL_VERTCOL, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + CONST_SRC_CODE_GRID_LIGHTING_SH_2, + }, + .m_custom_sampler_constraints = {}, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT, + .m_material_type = MTL_TYPE_MODEL_VERTCOL, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, + }, + .m_custom_sampler_constraints = {}, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT, + .m_material_type = MTL_TYPE_MODEL_VERTCOL, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + CONST_SRC_CODE_GRID_LIGHTING_SH_2, + }, + .m_custom_sampler_constraints = {}, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT, + .m_material_type = MTL_TYPE_MODEL_VERTCOL, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + }, + .m_custom_sampler_constraints = {}, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT, + .m_material_type = MTL_TYPE_MODEL_VERTCOL, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + CONST_SRC_CODE_GRID_LIGHTING_SH_2, + }, + .m_custom_sampler_constraints = { + CUSTOM_SAMPLER_REFLECTION_PROBE, + }, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT, + .m_material_type = MTL_TYPE_MODEL_VERTCOL, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + }, + .m_custom_sampler_constraints = { + CUSTOM_SAMPLER_REFLECTION_PROBE, + }, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT, + .m_material_type = MTL_TYPE_MODEL_VERTCOL, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + CONST_SRC_CODE_GRID_LIGHTING_SH_2, + }, + .m_custom_sampler_constraints = { + CUSTOM_SAMPLER_REFLECTION_PROBE, + }, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, + .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + CONST_SRC_CODE_GRID_LIGHTING_SH_2, + }, + .m_custom_sampler_constraints = {}, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, + .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, + }, + .m_custom_sampler_constraints = {}, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, + .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + CONST_SRC_CODE_GRID_LIGHTING_SH_2, + }, + .m_custom_sampler_constraints = {}, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, + .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + }, + .m_custom_sampler_constraints = {}, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, + .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + CONST_SRC_CODE_GRID_LIGHTING_SH_2, + }, + .m_custom_sampler_constraints = { + CUSTOM_SAMPLER_REFLECTION_PROBE, + }, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, + .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + }, + .m_custom_sampler_constraints = { + CUSTOM_SAMPLER_REFLECTION_PROBE, + }, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, + .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + CONST_SRC_CODE_GRID_LIGHTING_SH_2, + }, + .m_custom_sampler_constraints = { + CUSTOM_SAMPLER_REFLECTION_PROBE, + }, + }, + { + .m_value = VERTEX_SHADER_MODEL_UNLIT, + .m_material_type = std::nullopt, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + }, + .m_custom_sampler_constraints = {}, + }, + }; + // clang-format on + unsigned ConvertArgumentType(const techset::CommonShaderArgumentType& type) { if (type.m_shader_type == techset::CommonTechniqueShaderType::VERTEX) @@ -233,6 +439,41 @@ namespace } } + void ApplyPrecompiledIndex(MaterialPass& pass) + { + if (!pass.args) + return; + + std::vector codeConstants; + const auto argCount = static_cast(pass.perPrimArgCount); + for (auto argIndex = 0u; argIndex < argCount; argIndex++) + { + const auto& arg = pass.args[argIndex]; + if (arg.type != MTL_ARG_CODE_VERTEX_CONST) + continue; + + const auto codeConst = static_cast(arg.u.codeConst.index); + + // Make sure we are agnostic of the used transposed versions + const auto codeConstInfo = commonCodeSourceInfos.GetInfoForCodeConstSource(codeConst); + if (codeConstInfo && codeConstInfo->transposedMatrix) + codeConstants.emplace_back(std::min(codeConst, *codeConstInfo->transposedMatrix)); + else + codeConstants.emplace_back(codeConst); + } + + const auto end = std::end(precompiledIndexMappings); + const auto foundMapping = std::find_if(std::begin(precompiledIndexMappings), + end, + [&codeConstants, pass](const PrecompiledIndexMapping& mapping) -> bool + { + return mapping.Matches(pass.materialType, codeConstants, pass.customSamplerFlags); + }); + + if (foundMapping != end) + pass.precompiledIndex = foundMapping->m_value; + } + class TechniqueShaderLoaderT6 final : public techset::ITechniqueShaderLoader { public: @@ -314,6 +555,16 @@ namespace { ApplyTechFlagsFromMaterial(*materialAsset->Asset(), m_zone); } + + const auto techniques = context.PoolSubAssets(); + for (auto* techniqueSubAsset : techniques) + { + auto& technique = *techniqueSubAsset->Asset(); + for (auto passIndex = 0u; passIndex < technique.passCount; passIndex++) + { + ApplyPrecompiledIndex(technique.passArray[passIndex]); + } + } } private: diff --git a/src/ObjLoading/Asset/AssetCreationContext.h b/src/ObjLoading/Asset/AssetCreationContext.h index 0c349457..501da641 100644 --- a/src/ObjLoading/Asset/AssetCreationContext.h +++ b/src/ObjLoading/Asset/AssetCreationContext.h @@ -3,6 +3,7 @@ #include "Asset/IZoneAssetCreationState.h" #include "AssetRegistration.h" #include "Game/IAsset.h" +#include "Pool/AssetPool.h" #include "Pool/XAssetInfo.h" #include "Zone/AssetList/AssetList.h" #include "Zone/ZoneTypes.h" @@ -89,6 +90,11 @@ public: XAssetInfoGeneric* ForceLoadDependencyGeneric(asset_type_t assetType, const std::string& assetName); + template [[nodiscard]] AssetPoolIterators PoolSubAssets() const + { + return AssetPoolIterators(*m_sub_asset_pools[SubAsset_t::EnumEntry]); + } + private: [[nodiscard]] XAssetInfoGeneric* LoadDefaultAssetDependency(asset_type_t assetType, const std::string& assetName); diff --git a/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp b/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp index 6f37efe8..d7586677 100644 --- a/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp +++ b/src/ObjWriting/Game/T5/Techset/TechsetDumperT5.cpp @@ -193,7 +193,8 @@ namespace "passthrough", ConvertToCommonShader(pass.vertexShader), ConvertToCommonShader(pass.pixelShader), - ConvertToCommonVertexDeclaration(pass.vertexDecl)); + ConvertToCommonVertexDeclaration(pass.vertexDecl), + std::string()); if (pass.args) { diff --git a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp index e905b8d9..63d2d4a0 100644 --- a/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp +++ b/src/ObjWriting/Game/T6/Techset/TechsetDumperT6.cpp @@ -232,19 +232,28 @@ namespace return result; } - techset::CommonTechnique ConvertToCommonTechnique(const MaterialTechnique& technique) + techset::CommonTechnique ConvertToCommonTechnique(const MaterialTechnique& technique, const bool debug) { techset::CommonTechnique commonTechnique(technique.name ? technique.name : std::string(), technique.flags); for (auto passIndex = 0u; passIndex < technique.passCount; passIndex++) { const auto& pass = technique.passArray[passIndex]; + + std::string comment; + if (debug) + { + comment = std::format( + "MaterialType: {}; PrecompiledIndex: {}", static_cast(pass.materialType), static_cast(pass.precompiledIndex)); + } + techset::CommonPass commonPass(pass.customSamplerFlags, // No clue what the actual state map was "passthrough", ConvertToCommonShader(pass.vertexShader), ConvertToCommonShader(pass.pixelShader), - ConvertToCommonVertexDeclaration(pass.vertexDecl)); + ConvertToCommonVertexDeclaration(pass.vertexDecl), + std::move(comment)); if (pass.args) { @@ -268,7 +277,7 @@ namespace { if (technique && techniqueState->ShouldDumpTechnique(technique)) { - const auto commonTechnique = ConvertToCommonTechnique(*technique); + const auto commonTechnique = ConvertToCommonTechnique(*technique, debug); techset::DumpCommonTechnique( context, commonTechnique, techset::DxVersion::DX11, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState, debug); diff --git a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp index 8afb185c..e83bd777 100644 --- a/src/ObjWriting/Techset/CommonTechniqueDumper.cpp +++ b/src/ObjWriting/Techset/CommonTechniqueDumper.cpp @@ -67,6 +67,12 @@ namespace m_stream << std::format("// CUSTOM SAMPLER FLAGS: 0x{:x}\n", mask); } } + + if (!pass.m_comment.empty()) + { + Indent(); + m_stream << std::format("// {}\n", pass.m_comment); + } } DumpStateMap(); diff --git a/src/ZoneCommon/Pool/AssetPool.h b/src/ZoneCommon/Pool/AssetPool.h index 27cc7266..f06e0ea9 100644 --- a/src/ZoneCommon/Pool/AssetPool.h +++ b/src/ZoneCommon/Pool/AssetPool.h @@ -67,7 +67,7 @@ private: std::vector> m_assets; }; -template class AssetPoolIterator +template class AssetPoolIterator { public: explicit AssetPoolIterator(AssetPool::Iterator i) @@ -94,7 +94,7 @@ private: AssetPool::Iterator m_iterator; }; -template class AssetPoolIterators +template class AssetPoolIterators { public: explicit AssetPoolIterators(AssetPool& assetPool) diff --git a/test/ObjWritingTests/Game/T6/Techset/TechsetDumperT6Test.cpp b/test/ObjWritingTests/Game/T6/Techset/TechsetDumperT6Test.cpp index 972896c2..9c2c8c04 100644 --- a/test/ObjWritingTests/Game/T6/Techset/TechsetDumperT6Test.cpp +++ b/test/ObjWritingTests/Game/T6/Techset/TechsetDumperT6Test.cpp @@ -309,6 +309,7 @@ TEST_CASE("TechsetDumperT6", "[t6][techset][dumper]") // TECHNIQUE FLAGS: 0x4 // TECHNIQUE FLAGS: 0x80 { + // MaterialType: 2; PrecompiledIndex: 3 stateMap "passthrough"; // TODO vertexShader 4.0 "simple.hlsl" @@ -339,6 +340,7 @@ TEST_CASE("TechsetDumperT6", "[t6][techset][dumper]") { // CUSTOM SAMPLER FLAGS: 0x1 // CUSTOM SAMPLER FLAGS: 0x2 + // MaterialType: 0; PrecompiledIndex: 0 stateMap "passthrough"; // TODO vertexShader 4.0 "advanced.hlsl" From 6eb0ec41790ec9e7e841ca8d9adece35d9b8a466 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Wed, 4 Mar 2026 22:12:39 +0000 Subject: [PATCH 27/27] chore: reorganize precompiled index logic into separate file --- .../Game/T6/Techset/PrecompiledIndexT6.cpp | 256 ++++++++++++++++++ .../Game/T6/Techset/PrecompiledIndexT6.h | 8 + .../Game/T6/Techset/TechniqueCompilerT6.cpp | 240 +--------------- 3 files changed, 265 insertions(+), 239 deletions(-) create mode 100644 src/ObjCompiling/Game/T6/Techset/PrecompiledIndexT6.cpp create mode 100644 src/ObjCompiling/Game/T6/Techset/PrecompiledIndexT6.h diff --git a/src/ObjCompiling/Game/T6/Techset/PrecompiledIndexT6.cpp b/src/ObjCompiling/Game/T6/Techset/PrecompiledIndexT6.cpp new file mode 100644 index 00000000..30b463cb --- /dev/null +++ b/src/ObjCompiling/Game/T6/Techset/PrecompiledIndexT6.cpp @@ -0,0 +1,256 @@ +#include "PrecompiledIndexT6.h" + +#include "Game/T6/Techset/TechsetConstantsT6.h" +#include "Techset/CommonTechnique.h" + +#include +#include + +using namespace T6; + +namespace +{ + class PrecompiledIndexMapping + { + public: + VertexShaderPrecompiledIndex m_value; + std::optional m_material_type; + std::vector m_vertex_const_constraints; + std::vector m_custom_sampler_constraints; + }; + + // clang-format off + inline PrecompiledIndexMapping precompiledIndexMappings[]{ + { + .m_value = VERTEX_SHADER_MODEL_LIT, + .m_material_type = MTL_TYPE_MODEL_VERTCOL, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + CONST_SRC_CODE_GRID_LIGHTING_SH_2, + }, + .m_custom_sampler_constraints = {}, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT, + .m_material_type = MTL_TYPE_MODEL_VERTCOL, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, + }, + .m_custom_sampler_constraints = {}, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT, + .m_material_type = MTL_TYPE_MODEL_VERTCOL, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + CONST_SRC_CODE_GRID_LIGHTING_SH_2, + }, + .m_custom_sampler_constraints = {}, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT, + .m_material_type = MTL_TYPE_MODEL_VERTCOL, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + }, + .m_custom_sampler_constraints = {}, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT, + .m_material_type = MTL_TYPE_MODEL_VERTCOL, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + CONST_SRC_CODE_GRID_LIGHTING_SH_2, + }, + .m_custom_sampler_constraints = { + CUSTOM_SAMPLER_REFLECTION_PROBE, + }, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT, + .m_material_type = MTL_TYPE_MODEL_VERTCOL, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + }, + .m_custom_sampler_constraints = { + CUSTOM_SAMPLER_REFLECTION_PROBE, + }, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT, + .m_material_type = MTL_TYPE_MODEL_VERTCOL, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + CONST_SRC_CODE_GRID_LIGHTING_SH_2, + }, + .m_custom_sampler_constraints = { + CUSTOM_SAMPLER_REFLECTION_PROBE, + }, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, + .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + CONST_SRC_CODE_GRID_LIGHTING_SH_2, + }, + .m_custom_sampler_constraints = {}, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, + .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, + }, + .m_custom_sampler_constraints = {}, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, + .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + CONST_SRC_CODE_GRID_LIGHTING_SH_2, + }, + .m_custom_sampler_constraints = {}, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, + .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + }, + .m_custom_sampler_constraints = {}, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, + .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + CONST_SRC_CODE_GRID_LIGHTING_SH_2, + }, + .m_custom_sampler_constraints = { + CUSTOM_SAMPLER_REFLECTION_PROBE, + }, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, + .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + }, + .m_custom_sampler_constraints = { + CUSTOM_SAMPLER_REFLECTION_PROBE, + }, + }, + { + .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, + .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + CONST_SRC_CODE_GRID_LIGHTING_SH_0, + CONST_SRC_CODE_GRID_LIGHTING_SH_1, + CONST_SRC_CODE_GRID_LIGHTING_SH_2, + }, + .m_custom_sampler_constraints = { + CUSTOM_SAMPLER_REFLECTION_PROBE, + }, + }, + { + .m_value = VERTEX_SHADER_MODEL_UNLIT, + .m_material_type = std::nullopt, + .m_vertex_const_constraints = { + CONST_SRC_CODE_WORLD_MATRIX, + }, + .m_custom_sampler_constraints = {}, + }, + }; + // clang-format on + + [[nodiscard]] bool MappingMatches(const PrecompiledIndexMapping& mapping, + const MaterialType materialType, + const std::vector& passCodeConsts, + const unsigned samplerFlags) + { + if (mapping.m_material_type && *mapping.m_material_type != materialType) + return false; + if (mapping.m_vertex_const_constraints.size() > passCodeConsts.size()) + return false; + + auto passCodeConstIndex = 0u; + for (const auto codeConstConstraint : mapping.m_vertex_const_constraints) + { + if (passCodeConsts[passCodeConstIndex++] != codeConstConstraint) + return false; + } + + auto expectedSamplerFlags = 0u; + for (const auto customSampler : mapping.m_custom_sampler_constraints) + expectedSamplerFlags |= (1 << customSampler); + + return samplerFlags == expectedSamplerFlags; + } +} // namespace + +namespace T6 +{ + void ApplyPrecompiledIndex(MaterialPass& pass) + { + if (!pass.args) + return; + + std::vector codeConstants; + const auto argCount = static_cast(pass.perPrimArgCount); + for (auto argIndex = 0u; argIndex < argCount; argIndex++) + { + const auto& arg = pass.args[argIndex]; + if (arg.type != MTL_ARG_CODE_VERTEX_CONST) + continue; + + const auto codeConst = static_cast(arg.u.codeConst.index); + + // Make sure we are agnostic of the used transposed versions + const auto codeConstInfo = commonCodeSourceInfos.GetInfoForCodeConstSource(codeConst); + if (codeConstInfo && codeConstInfo->transposedMatrix) + codeConstants.emplace_back(std::min(codeConst, *codeConstInfo->transposedMatrix)); + else + codeConstants.emplace_back(codeConst); + } + + const auto end = std::end(precompiledIndexMappings); + const auto foundMapping = std::find_if(std::begin(precompiledIndexMappings), + end, + [&codeConstants, pass](const PrecompiledIndexMapping& mapping) -> bool + { + return MappingMatches(mapping, pass.materialType, codeConstants, pass.customSamplerFlags); + }); + + if (foundMapping != end) + pass.precompiledIndex = foundMapping->m_value; + } +} // namespace T6 diff --git a/src/ObjCompiling/Game/T6/Techset/PrecompiledIndexT6.h b/src/ObjCompiling/Game/T6/Techset/PrecompiledIndexT6.h new file mode 100644 index 00000000..1f192906 --- /dev/null +++ b/src/ObjCompiling/Game/T6/Techset/PrecompiledIndexT6.h @@ -0,0 +1,8 @@ +#pragma once + +#include "Game/T6/T6.h" + +namespace T6 +{ + void ApplyPrecompiledIndex(MaterialPass& pass); +} diff --git a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp index 44640a04..6b61a657 100644 --- a/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp +++ b/src/ObjCompiling/Game/T6/Techset/TechniqueCompilerT6.cpp @@ -2,6 +2,7 @@ #include "Game/T6/T6.h" #include "Game/T6/Techset/TechsetConstantsT6.h" +#include "PrecompiledIndexT6.h" #include "Techset/CommonShaderArgCreator.h" #include "Techset/CommonTechniqueLoader.h" #include "Techset/LiteralConstsZoneState.h" @@ -16,210 +17,6 @@ using namespace T6; namespace { - class PrecompiledIndexMapping - { - public: - [[nodiscard]] bool - Matches(const MaterialType materialType, const std::vector& passCodeConsts, const unsigned samplerFlags) const - { - if (m_material_type && materialType != *m_material_type) - return false; - if (m_vertex_const_constraints.size() > passCodeConsts.size()) - return false; - - auto passCodeConstIndex = 0u; - for (const auto codeConstConstraint : m_vertex_const_constraints) - { - if (passCodeConsts[passCodeConstIndex++] != codeConstConstraint) - return false; - } - - auto expectedSamplerFlags = 0u; - for (const auto customSampler : m_custom_sampler_constraints) - expectedSamplerFlags |= (1 << customSampler); - - return samplerFlags == expectedSamplerFlags; - } - - VertexShaderPrecompiledIndex m_value; - std::optional m_material_type; - std::vector m_vertex_const_constraints; - std::vector m_custom_sampler_constraints; - }; - - // clang-format off - inline PrecompiledIndexMapping precompiledIndexMappings[]{ - { - .m_value = VERTEX_SHADER_MODEL_LIT, - .m_material_type = MTL_TYPE_MODEL_VERTCOL, - .m_vertex_const_constraints = { - CONST_SRC_CODE_WORLD_MATRIX, - CONST_SRC_CODE_GRID_LIGHTING_SH_0, - CONST_SRC_CODE_GRID_LIGHTING_SH_1, - CONST_SRC_CODE_GRID_LIGHTING_SH_2, - }, - .m_custom_sampler_constraints = {}, - }, - { - .m_value = VERTEX_SHADER_MODEL_LIT, - .m_material_type = MTL_TYPE_MODEL_VERTCOL, - .m_vertex_const_constraints = { - CONST_SRC_CODE_WORLD_MATRIX, - CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, - }, - .m_custom_sampler_constraints = {}, - }, - { - .m_value = VERTEX_SHADER_MODEL_LIT, - .m_material_type = MTL_TYPE_MODEL_VERTCOL, - .m_vertex_const_constraints = { - CONST_SRC_CODE_WORLD_MATRIX, - CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, - CONST_SRC_CODE_GRID_LIGHTING_SH_0, - CONST_SRC_CODE_GRID_LIGHTING_SH_1, - CONST_SRC_CODE_GRID_LIGHTING_SH_2, - }, - .m_custom_sampler_constraints = {}, - }, - { - .m_value = VERTEX_SHADER_MODEL_LIT, - .m_material_type = MTL_TYPE_MODEL_VERTCOL, - .m_vertex_const_constraints = { - CONST_SRC_CODE_WORLD_MATRIX, - CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, - CONST_SRC_CODE_GRID_LIGHTING_SH_0, - CONST_SRC_CODE_GRID_LIGHTING_SH_1, - }, - .m_custom_sampler_constraints = {}, - }, - { - .m_value = VERTEX_SHADER_MODEL_LIT, - .m_material_type = MTL_TYPE_MODEL_VERTCOL, - .m_vertex_const_constraints = { - CONST_SRC_CODE_WORLD_MATRIX, - CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, - CONST_SRC_CODE_GRID_LIGHTING_SH_0, - CONST_SRC_CODE_GRID_LIGHTING_SH_1, - CONST_SRC_CODE_GRID_LIGHTING_SH_2, - }, - .m_custom_sampler_constraints = { - CUSTOM_SAMPLER_REFLECTION_PROBE, - }, - }, - { - .m_value = VERTEX_SHADER_MODEL_LIT, - .m_material_type = MTL_TYPE_MODEL_VERTCOL, - .m_vertex_const_constraints = { - CONST_SRC_CODE_WORLD_MATRIX, - }, - .m_custom_sampler_constraints = { - CUSTOM_SAMPLER_REFLECTION_PROBE, - }, - }, - { - .m_value = VERTEX_SHADER_MODEL_LIT, - .m_material_type = MTL_TYPE_MODEL_VERTCOL, - .m_vertex_const_constraints = { - CONST_SRC_CODE_WORLD_MATRIX, - CONST_SRC_CODE_GRID_LIGHTING_SH_0, - CONST_SRC_CODE_GRID_LIGHTING_SH_1, - CONST_SRC_CODE_GRID_LIGHTING_SH_2, - }, - .m_custom_sampler_constraints = { - CUSTOM_SAMPLER_REFLECTION_PROBE, - }, - }, - { - .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, - .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, - .m_vertex_const_constraints = { - CONST_SRC_CODE_WORLD_MATRIX, - CONST_SRC_CODE_GRID_LIGHTING_SH_0, - CONST_SRC_CODE_GRID_LIGHTING_SH_1, - CONST_SRC_CODE_GRID_LIGHTING_SH_2, - }, - .m_custom_sampler_constraints = {}, - }, - { - .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, - .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, - .m_vertex_const_constraints = { - CONST_SRC_CODE_WORLD_MATRIX, - CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, - }, - .m_custom_sampler_constraints = {}, - }, - { - .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, - .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, - .m_vertex_const_constraints = { - CONST_SRC_CODE_WORLD_MATRIX, - CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, - CONST_SRC_CODE_GRID_LIGHTING_SH_0, - CONST_SRC_CODE_GRID_LIGHTING_SH_1, - CONST_SRC_CODE_GRID_LIGHTING_SH_2, - }, - .m_custom_sampler_constraints = {}, - }, - { - .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, - .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, - .m_vertex_const_constraints = { - CONST_SRC_CODE_WORLD_MATRIX, - CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, - CONST_SRC_CODE_GRID_LIGHTING_SH_0, - CONST_SRC_CODE_GRID_LIGHTING_SH_1, - }, - .m_custom_sampler_constraints = {}, - }, - { - .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, - .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, - .m_vertex_const_constraints = { - CONST_SRC_CODE_WORLD_MATRIX, - CONST_SRC_CODE_GRID_LIGHTING_COORDS_AND_VIS, - CONST_SRC_CODE_GRID_LIGHTING_SH_0, - CONST_SRC_CODE_GRID_LIGHTING_SH_1, - CONST_SRC_CODE_GRID_LIGHTING_SH_2, - }, - .m_custom_sampler_constraints = { - CUSTOM_SAMPLER_REFLECTION_PROBE, - }, - }, - { - .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, - .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, - .m_vertex_const_constraints = { - CONST_SRC_CODE_WORLD_MATRIX, - }, - .m_custom_sampler_constraints = { - CUSTOM_SAMPLER_REFLECTION_PROBE, - }, - }, - { - .m_value = VERTEX_SHADER_MODEL_LIT_LIGHTMAP_VC, - .m_material_type = MTL_TYPE_MODEL_LIGHTMAP_VC, - .m_vertex_const_constraints = { - CONST_SRC_CODE_WORLD_MATRIX, - CONST_SRC_CODE_GRID_LIGHTING_SH_0, - CONST_SRC_CODE_GRID_LIGHTING_SH_1, - CONST_SRC_CODE_GRID_LIGHTING_SH_2, - }, - .m_custom_sampler_constraints = { - CUSTOM_SAMPLER_REFLECTION_PROBE, - }, - }, - { - .m_value = VERTEX_SHADER_MODEL_UNLIT, - .m_material_type = std::nullopt, - .m_vertex_const_constraints = { - CONST_SRC_CODE_WORLD_MATRIX, - }, - .m_custom_sampler_constraints = {}, - }, - }; - // clang-format on - unsigned ConvertArgumentType(const techset::CommonShaderArgumentType& type) { if (type.m_shader_type == techset::CommonTechniqueShaderType::VERTEX) @@ -439,41 +236,6 @@ namespace } } - void ApplyPrecompiledIndex(MaterialPass& pass) - { - if (!pass.args) - return; - - std::vector codeConstants; - const auto argCount = static_cast(pass.perPrimArgCount); - for (auto argIndex = 0u; argIndex < argCount; argIndex++) - { - const auto& arg = pass.args[argIndex]; - if (arg.type != MTL_ARG_CODE_VERTEX_CONST) - continue; - - const auto codeConst = static_cast(arg.u.codeConst.index); - - // Make sure we are agnostic of the used transposed versions - const auto codeConstInfo = commonCodeSourceInfos.GetInfoForCodeConstSource(codeConst); - if (codeConstInfo && codeConstInfo->transposedMatrix) - codeConstants.emplace_back(std::min(codeConst, *codeConstInfo->transposedMatrix)); - else - codeConstants.emplace_back(codeConst); - } - - const auto end = std::end(precompiledIndexMappings); - const auto foundMapping = std::find_if(std::begin(precompiledIndexMappings), - end, - [&codeConstants, pass](const PrecompiledIndexMapping& mapping) -> bool - { - return mapping.Matches(pass.materialType, codeConstants, pass.customSamplerFlags); - }); - - if (foundMapping != end) - pass.precompiledIndex = foundMapping->m_value; - } - class TechniqueShaderLoaderT6 final : public techset::ITechniqueShaderLoader { public: