#options GAME(IW3, IW4, IW5, T5, T6) #filename "Game/" + GAME + "/Techset/TechsetDumper" + GAME + ".cpp" #set DUMPER_HEADER "\"TechsetDumper" + GAME + ".h\"" #set MATERIAL_CONSTANT_ZONE_STATE_HEADER "\"Game/" + GAME + "/Material/MaterialConstantZoneState" + GAME + ".h\"" #set TECHSET_CONSTANTS_HEADER "\"Game/" + GAME + "/Techset/TechsetConstants" + GAME + ".h\"" #if GAME == "IW3" #define FEATURE_IW3 #define IS_DX9 #define DUMP_SHADERS "1" #elif GAME == "IW4" #define FEATURE_IW4 #define IS_DX9 #elif GAME == "IW5" #define FEATURE_IW5 #define IS_DX9 #elif GAME == "T5" #define FEATURE_T5 #define IS_DX9 #define DUMP_SHADERS "1" #elif GAME == "T6" #define FEATURE_T6 #define IS_DX11 #define DUMP_SHADERS "1" #endif // This file was templated. // See TechsetDumper.cpp.template. // Do not modify, changes will be lost. #include DUMPER_HEADER #include MATERIAL_CONSTANT_ZONE_STATE_HEADER #include TECHSET_CONSTANTS_HEADER #include "Pool/GlobalAssetPool.h" #include "Techset/CommonTechniqueDumper.h" #include "Techset/CommonTechsetDumper.h" #include "Techset/CommonVertexDeclCreator.h" #include "Techset/TechniqueDumpingZoneState.h" #if defined(DUMP_SHADERS) #include "Shader/ShaderCommon.h" #include "Techset/ShaderDumpingZoneState.h" #endif #include #include using namespace GAME; namespace { #if defined(DUMP_SHADERS) void DumpPixelShader(const AssetDumpingContext& context, const MaterialPixelShader& pixelShader) { const auto shaderFile = context.OpenAssetFile(shader::GetFileNameForPixelShaderAssetName(pixelShader.name)); if (!shaderFile) return; #if defined(IS_DX11) shaderFile->write(pixelShader.prog.loadDef.program, pixelShader.prog.loadDef.programSize); #else shaderFile->write(reinterpret_cast(pixelShader.prog.loadDef.program), static_cast(pixelShader.prog.loadDef.programSize) * sizeof(GfxPixelShaderLoadDef::program)); #endif } void DumpVertexShader(const AssetDumpingContext& context, const MaterialVertexShader& vertexShader) { const auto shaderFile = context.OpenAssetFile(shader::GetFileNameForVertexShaderAssetName(vertexShader.name)); if (!shaderFile) return; #if defined(IS_DX11) shaderFile->write(vertexShader.prog.loadDef.program, vertexShader.prog.loadDef.programSize); #else shaderFile->write(reinterpret_cast(vertexShader.prog.loadDef.program), static_cast(vertexShader.prog.loadDef.programSize) * sizeof(GfxVertexShaderLoadDef::program)); #endif } void DumpShaders(AssetDumpingContext& context, const MaterialTechniqueSet& techset) { auto* shaderState = context.GetZoneAssetDumperState(); for (const auto* technique : techset.techniques) { if (!technique || !shaderState->ShouldDumpTechnique(technique)) continue; for (auto passIndex = 0u; passIndex < technique->passCount; passIndex++) { const auto* pixelShader = technique->passArray[passIndex].pixelShader; if (pixelShader && shaderState->ShouldDumpPixelShader(pixelShader)) DumpPixelShader(context, *pixelShader); const auto* vertexShader = technique->passArray[passIndex].vertexShader; if (vertexShader && shaderState->ShouldDumpVertexShader(vertexShader)) DumpVertexShader(context, *vertexShader); } } } #endif techset::CommonVertexDeclaration ConvertToCommonVertexDeclaration(const MaterialVertexDeclaration* vertexDecl) { std::vector commonRouting; #if defined(FEATURE_IW4) || defined(FEATURE_IW5) if (vertexDecl && vertexDecl->name && vertexDecl->name[0] != ',') #else if (vertexDecl) #endif { const auto streamCount = std::min(static_cast(vertexDecl->streamCount), std::extent_v); for (auto streamIndex = 0u; streamIndex < streamCount; streamIndex++) { const auto& routing = vertexDecl->routing.data[streamIndex]; commonRouting.emplace_back(static_cast(routing.source), static_cast(routing.dest)); } } #if defined(FEATURE_IW4) || defined(FEATURE_IW5) else if (vertexDecl && vertexDecl->name) { auto result = techset::CreateVertexDeclFromName(&vertexDecl->name[1], commonRoutingInfos); if (result.has_value()) return std::move(*result); } #endif return techset::CommonVertexDeclaration(std::move(commonRouting)); } techset::CommonShaderArg ConvertToCommonArg(const MaterialShaderArgument& arg) { #if defined(IS_DX9) const techset::CommonShaderArgDestination destination = {.dx9 = {.m_destination_register = arg.dest}}; #endif switch (arg.type) { case MTL_ARG_CODE_VERTEX_CONST: case MTL_ARG_CODE_PIXEL_CONST: { 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}; #if defined(IS_DX11) 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, } }; #endif return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); } case MTL_ARG_MATERIAL_VERTEX_CONST: case MTL_ARG_MATERIAL_PIXEL_CONST: { const techset::CommonShaderArgValue value{ .name_hash = arg.u.nameHash, }; #if defined(IS_DX11) 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, } }; #endif return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); } case MTL_ARG_CODE_PIXEL_SAMPLER: { const techset::CommonShaderArgValue value{ .code_sampler_source = static_cast(arg.u.codeSampler), }; #if defined(IS_DX11) const techset::CommonShaderArgLocationDx11 location{ .texture_index = arg.location.textureIndex, .sampler_index = arg.location.samplerIndex, }; const techset::CommonShaderArgDestination destination = { .dx11 = { .m_location = location, .m_size = arg.size, .m_buffer = arg.buffer, } }; #endif return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); } #if defined(FEATURE_IW5) case MTL_ARG_MATERIAL_VERTEX_SAMPLER: #endif case MTL_ARG_MATERIAL_PIXEL_SAMPLER: { const techset::CommonShaderArgValue value{ .name_hash = arg.u.nameHash, }; #if defined(IS_DX11) const techset::CommonShaderArgLocationDx11 location{ .texture_index = arg.location.textureIndex, .sampler_index = arg.location.samplerIndex, }; const techset::CommonShaderArgDestination destination = { .dx11 = { .m_location = location, .m_size = arg.size, .m_buffer = arg.buffer, } }; #endif return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); } case MTL_ARG_LITERAL_VERTEX_CONST: case MTL_ARG_LITERAL_PIXEL_CONST: { techset::CommonShaderArgValue value{}; if (arg.u.literalConst) { value.literal_value = { (*arg.u.literalConst)[0], (*arg.u.literalConst)[1], (*arg.u.literalConst)[2], (*arg.u.literalConst)[3], }; } #if defined(IS_DX11) 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, } }; #endif return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value); } default: assert(false); return techset::CommonShaderArg(); } } techset::CommonTechniqueShader ConvertToCommonShader(const MaterialVertexShader* vertexShader) { #if defined(FEATURE_IW4) || defined(FEATURE_IW5) if (vertexShader && vertexShader->name && vertexShader->name[0] == ',') { auto* globalAsset = GameGlobalAssetPools::GetGlobalPoolsForGame(GameId::GAME)->GetAsset(&vertexShader->name[1]); if (globalAsset) vertexShader = globalAsset->Asset(); } #endif techset::CommonTechniqueShader result(techset::CommonTechniqueShaderType::VERTEX, std::string()); if (!vertexShader) return result; if (vertexShader->name) result.m_name = vertexShader->name; if (vertexShader->prog.loadDef.program) { result.m_bin = techset::CommonTechniqueShaderBin{ .m_shader_bin = vertexShader->prog.loadDef.program, #if defined(IS_DX9) .m_shader_bin_size = vertexShader->prog.loadDef.programSize * sizeof(std::remove_pointer_t), #else .m_shader_bin_size = vertexShader->prog.loadDef.programSize, #endif }; } return result; } techset::CommonTechniqueShader ConvertToCommonShader(const MaterialPixelShader* pixelShader) { #if defined(FEATURE_IW4) || defined(FEATURE_IW5) if (pixelShader && pixelShader->name && pixelShader->name[0] == ',') { auto* globalAsset = GameGlobalAssetPools::GetGlobalPoolsForGame(GameId::GAME)->GetAsset(&pixelShader->name[1]); if (globalAsset) pixelShader = globalAsset->Asset(); } #endif techset::CommonTechniqueShader result(techset::CommonTechniqueShaderType::PIXEL, std::string()); if (!pixelShader) return result; if (pixelShader->name) result.m_name = pixelShader->name; if (pixelShader->prog.loadDef.program) { result.m_bin = techset::CommonTechniqueShaderBin{ .m_shader_bin = pixelShader->prog.loadDef.program, #if defined(IS_DX9) .m_shader_bin_size = pixelShader->prog.loadDef.programSize * sizeof(std::remove_pointer_t), #else .m_shader_bin_size = pixelShader->prog.loadDef.programSize, #endif }; } return result; } 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; #ifdef FEATURE_T6 if (debug) { comment = std::format( "MaterialType: {}; PrecompiledIndex: {}", static_cast(pass.materialType), static_cast(pass.precompiledIndex)); } #endif techset::CommonPass commonPass(pass.customSamplerFlags, // No clue what the actual state map was "passthrough", ConvertToCommonShader(pass.vertexShader), ConvertToCommonShader(pass.pixelShader), ConvertToCommonVertexDeclaration(pass.vertexDecl), std::move(comment)); 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 commonTechnique; } void DumpTechniques(AssetDumpingContext& context, const MaterialTechniqueSet& techset, const bool debug) { auto* techniqueState = context.GetZoneAssetDumperState(); const auto* materialConstantState = context.GetZoneAssetDumperState(); for (const auto* technique : techset.techniques) { if (technique && techniqueState->ShouldDumpTechnique(technique)) { const auto commonTechnique = ConvertToCommonTechnique(*technique, debug); techset::DumpCommonTechnique(context, commonTechnique, #if defined(IS_DX9) techset::DxVersion::DX9, #elif defined(IS_DX11) techset::DxVersion::DX11, #endif commonCodeSourceInfos, commonRoutingInfos, *materialConstantState, debug); } } } techset::CommonTechset ConvertToCommonTechset(const MaterialTechniqueSet& techset) { std::vector techniqueNames(std::extent_v); for (auto techniqueIndex = 0u; techniqueIndex < std::extent_v; techniqueIndex++) { const auto* technique = techset.techniques[techniqueIndex]; if (technique && technique->name) techniqueNames[techniqueIndex] = technique->name; } return techset::CommonTechset(techset.name, std::move(techniqueNames)); } void DumpTechset(const AssetDumpingContext& context, const MaterialTechniqueSet& techset) { const auto commonTechset = ConvertToCommonTechset(techset); techset::DumpCommonTechset(commonTechniqueTypeNames, context, commonTechset); } } // namespace #set CLASS_NAME "Dumper" + GAME namespace techset { CLASS_NAME::CLASS_NAME(const bool debug) : m_debug(debug) { } void CLASS_NAME::Dump(AssetDumpingContext& context) { context.GetZoneAssetDumperState()->EnsureInitialized(); AbstractAssetDumper::Dump(context); } void CLASS_NAME::DumpAsset(AssetDumpingContext& context, const XAssetInfo& asset) { const auto* techniqueSet = asset.Asset(); DumpTechset(context, *techniqueSet); DumpTechniques(context, *techniqueSet, m_debug); #if defined(DUMP_SHADERS) DumpShaders(context, *techniqueSet); #endif } } // namespace techset