2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-03-15 17:33:03 +00:00

Merge pull request #707 from Laupetin/feature/techset-iw4

feat: techsets for iw4
This commit is contained in:
Jan
2026-03-14 14:05:46 +01:00
committed by GitHub
57 changed files with 2397 additions and 1665 deletions

View File

@@ -223,6 +223,8 @@ namespace IW4
using AssetTracer = Asset<ASSET_TYPE_TRACER, TracerDef>;
using AssetVehicle = Asset<ASSET_TYPE_VEHICLE, VehicleDef>;
using AssetAddonMapEnts = Asset<ASSET_TYPE_ADDON_MAP_ENTS, AddonMapEnts>;
using SubAssetTechnique = SubAsset<SUB_ASSET_TYPE_TECHNIQUE, MaterialTechnique>;
} // namespace IW4
DEFINE_ASSET_NAME_ACCESSOR(IW4::AssetPhysPreset, name);

View File

@@ -1207,9 +1207,13 @@ namespace IW4
STREAM_SRC_COLOR = 0x1,
STREAM_SRC_TEXCOORD_0 = 0x2,
STREAM_SRC_NORMAL = 0x3,
STREAM_SRC_TANGENT = 0x4,
STREAM_SRC_OPTIONAL_BEGIN = 0x5,
STREAM_SRC_PRE_OPTIONAL_BEGIN = 0x4,
STREAM_SRC_TANGENT = 0x4,
STREAM_SRC_OPTIONAL_BEGIN = 0x5,
STREAM_SRC_TEXCOORD_1 = 0x5,
STREAM_SRC_TEXCOORD_2 = 0x6,
STREAM_SRC_NORMAL_TRANSFORM_0 = 0x7,
@@ -1586,18 +1590,20 @@ namespace IW4
enum TechniqueFlags
{
// Guesses purely based on data analysis:
TECHNIQUE_FLAG_1 = 0x1, // uses resolvedPostSun code sampler // MTL_TECHFLAG_NEEDS_RESOLVED_POST_SUN
TECHNIQUE_FLAG_2 = 0x2, // uses resolvedScene code sampler MTL_TECHFLAG_NEEDS_RESOLVED_SCENE
TECHNIQUE_FLAG_4 = 0x4, // zprepass only
TECHNIQUE_FLAG_8 = 0x8, // build_floatz only
TECHNIQUE_FLAG_10 = 0x10, // build_shadowmap_depth + build_shadowmap_model only
TECHNIQUE_FLAG_20 =
0x20, // techniques with _i_ in its name (all use texcoord[1] in decl -> other optional stream sources are not used at all so might be any optional)
TECHNIQUE_FLAG_40 = 0x40, // uses code constant light.spotDir or light.spotFactors
TECHNIQUE_FLAG_80 = 0x80, // uses floatZ sampler and does not have 0x100 flag
TECHNIQUE_FLAG_100 = 0x100, // distortion_scale_zfeather_dtex + distortion_scale_ua_zfeather + distortion_scale_zfeather
TECHNIQUE_FLAG_200 = 0x200, // ?
MTL_TECHFLAG_NEEDS_RESOLVED_POST_SUN = 0x1,
MTL_TECHFLAG_NEEDS_RESOLVED_SCENE = 0x2,
// These 3 are set so rare, it seems like they are just based on name just like other games do
MTL_TECHFLAG_ZPREPASS = 0x4,
MTL_TECHFLAG_BUILD_FLOATZ = 0x8,
MTL_TECHFLAG_BUILD_SHADOW_MAP_DEPTH_OR_MODEL = 0x10,
MTL_TECHFLAG_DECL_HAS_OPTIONAL_SOURCE = 0x20,
MTL_TECHFLAG_USES_LIGHT_SPOT_FACTORS = 0x40,
MTL_TECHFLAG_USES_FLOATZ = 0x80, // uses floatZ sampler and does not have 0x100 flag
MTL_TECHFLAG_USES_DISTORTION_FLOATZ = 0x100, // distortion_scale_zfeather_dtex + distortion_scale_ua_zfeather + distortion_scale_zfeather
TECHNIQUE_FLAG_200 = 0x200, // ?
};
struct MaterialTechnique

View File

@@ -3045,16 +3045,16 @@ namespace T6
enum TechniqueFlags
{
TECHNIQUE_FLAG_1 = 0x1,
TECHNIQUE_FLAG_2 = 0x2,
TECHNIQUE_FLAG_4 = 0x4,
MTL_TECHFLAG_NEEDS_RESOLVED_POST_SUN = 0x1,
MTL_TECHFLAG_NEEDS_RESOLVED_SCENE = 0x2,
MTL_TECHFLAG_ZPREPASS = 0x4,
// Vertex decl has optional source
TECHNIQUE_FLAG_8 = 0x8,
MTL_TECHFLAG_DECL_HAS_OPTIONAL_SOURCE = 0x8,
TECHNIQUE_FLAG_10 = 0x10,
MTL_TECHFLAG_USES_LIGHT_SPOT_FACTORS = 0x10,
TECHNIQUE_FLAG_20 = 0x20,
TECHNIQUE_FLAG_40 = 0x40,
MTL_TECHFLAG_USES_FLOATZ = 0x40,
// Any material that has statebits according to any of the following sets this:
// - GFXS1_DEPTHWRITE set
@@ -6208,7 +6208,7 @@ namespace T6
MTL_ARG_MATERIAL_PIXEL_CONST = 0x6,
MTL_ARG_LITERAL_PIXEL_CONST = 0x7,
MLT_ARG_COUNT,
MTL_ARG_COUNT,
};
struct MaterialShaderArgument

File diff suppressed because it is too large Load Diff

View File

@@ -219,7 +219,7 @@ namespace T6
.accessor = "lightSpotFactors",
.arrayCount = 0,
.updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY,
.techFlags = TECHNIQUE_FLAG_10,
.techFlags = MTL_TECHFLAG_USES_LIGHT_SPOT_FACTORS,
},
{
.value = CONST_SRC_CODE_LIGHT_ATTENUATION,
@@ -1603,13 +1603,13 @@ namespace T6
.value = TEXTURE_SRC_CODE_RESOLVED_POST_SUN,
.accessor = "resolvedPostSun",
.updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY,
.techFlags = TECHNIQUE_FLAG_1,
.techFlags = MTL_TECHFLAG_NEEDS_RESOLVED_POST_SUN,
},
{
.value = TEXTURE_SRC_CODE_RESOLVED_SCENE,
.accessor = "resolvedScene",
.updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY,
.techFlags = TECHNIQUE_FLAG_2,
.techFlags = MTL_TECHFLAG_NEEDS_RESOLVED_SCENE,
},
{
.value = TEXTURE_SRC_CODE_POST_EFFECT_SRC,
@@ -1650,19 +1650,19 @@ namespace T6
.value = TEXTURE_SRC_CODE_FLOATZ,
.accessor = "floatZSampler",
.updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY,
.techFlags = TECHNIQUE_FLAG_40,
.techFlags = MTL_TECHFLAG_USES_FLOATZ,
},
{
.value = TEXTURE_SRC_CODE_PROCESSED_FLOATZ,
.accessor = "processedFloatZSampler",
.updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY,
.techFlags = TECHNIQUE_FLAG_40,
.techFlags = MTL_TECHFLAG_USES_FLOATZ,
},
{
.value = TEXTURE_SRC_CODE_RAW_FLOATZ,
.accessor = "rawFloatZSampler",
.updateFrequency = techset::CommonCodeSourceUpdateFrequency::RARELY,
.techFlags = TECHNIQUE_FLAG_40,
.techFlags = MTL_TECHFLAG_USES_FLOATZ,
},
{
.value = TEXTURE_SRC_CODE_STENCIL,
@@ -1848,7 +1848,7 @@ namespace T6
{.m_shader_type = techset::CommonTechniqueShaderType::PIXEL, .m_value_type = techset::CommonShaderValueType::MATERIAL_CONST },
{.m_shader_type = techset::CommonTechniqueShaderType::PIXEL, .m_value_type = techset::CommonShaderValueType::LITERAL_CONST },
};
static_assert(std::extent_v<decltype(commonArgumentTypes)> == MLT_ARG_COUNT);
static_assert(std::extent_v<decltype(commonArgumentTypes)> == MTL_ARG_COUNT);
static inline const char* commonIgnoredArgAccessors[]{
"combined_dlight",

View File

@@ -24,6 +24,34 @@ namespace
namespace techset
{
std::optional<bool> HasOptionalSourceByName(const std::string& name, const CommonStreamRoutingInfos& routingInfos)
{
size_t currentOffset = 0u;
std::string sourceAbbreviation;
while (NextAbbreviation(name, sourceAbbreviation, currentOffset))
{
std::string destinationAbbreviation;
if (!NextAbbreviation(name, destinationAbbreviation, currentOffset))
{
con::error("Failed to detect vertex decl destination abbreviation: {}", name);
return std::nullopt;
}
const auto maybeSource = routingInfos.GetSourceByAbbreviation(sourceAbbreviation);
if (!maybeSource)
{
con::error("Unknown vertex decl source abbreviation: {}", sourceAbbreviation);
return std::nullopt;
}
if (routingInfos.IsSourceOptional(*maybeSource))
return true;
}
return false;
}
std::optional<CommonVertexDeclaration> CreateVertexDeclFromName(const std::string& name, const CommonStreamRoutingInfos& routingInfos)
{
CommonVertexDeclaration result;

View File

@@ -7,5 +7,6 @@
namespace techset
{
std::optional<bool> HasOptionalSourceByName(const std::string& name, const CommonStreamRoutingInfos& routingInfos);
std::optional<CommonVertexDeclaration> CreateVertexDeclFromName(const std::string& name, const CommonStreamRoutingInfos& routingInfos);
}
} // namespace techset

View File

@@ -50,6 +50,9 @@ function ObjCompiling:project()
path.join(folder, "ObjCompiling")
}
}
ObjCommon:use()
useSourceTemplating("ObjCompiling")
self:include(includes)
minilzo:include(includes)

View File

@@ -1,10 +1,11 @@
#include "ObjCompilerIW4.h"
#include "Game/IW4/IW4.h"
#include "Game/IW4/Techset/TechniqueCompilerIW4.h"
#include "Game/IW4/Techset/TechsetCompilerIW4.h"
#include "Game/IW4/Techset/VertexDeclCompilerIW4.h"
#include "Image/ImageIwdPostProcessor.h"
#include "Material/CompilerMaterialIW4.h"
#include "Techset/CompilerTechsetIW4.h"
#include "Techset/CompilerVertexDeclIW4.h"
#include <memory>
@@ -18,9 +19,11 @@ namespace
#ifdef EXPERIMENTAL_MATERIAL_COMPILATION
collection.AddAssetCreator(material::CreateCompilerIW4(memory, searchPath, gdt));
collection.AddAssetCreator(techset::CreateLoaderIW4(memory, searchPath));
#endif
collection.AddAssetCreator(vertex_decl::CreateLoaderIW4(memory));
collection.AddAssetCreator(techset::CreateVertexDeclCompilerIW4(memory));
collection.AddAssetCreator(techset::CreateTechsetCompilerIW4(memory, searchPath));
collection.AddSubAssetCreator(techset::CreateTechniqueCompilerIW4(memory, zone, searchPath));
}
void ConfigurePostProcessors(AssetCreatorCollection& collection,

View File

@@ -1,8 +1,6 @@
#include "CompilerTechsetIW4.h"
#include "Game/IW4/IW4.h"
#include "Game/IW4/Shader/LoaderPixelShaderIW4.h"
#include "Game/IW4/Shader/LoaderVertexShaderIW4.h"
#include "Game/IW4/Techset/TechsetConstantsIW4.h"
#include "Shader/D3D9ShaderAnalyser.h"
#include "Shader/ShaderCommon.h"
@@ -1062,13 +1060,13 @@ namespace
// The other ones might be handled by the game in the same fashion because there is not recognizable pattern that connects the shaders with the same
// flags
static std::unordered_map<std::string, size_t> flagsByTechniqueName({
{"zprepass", TECHNIQUE_FLAG_4 | TECHNIQUE_FLAG_200 },
{"build_floatz", TECHNIQUE_FLAG_8 },
{"build_shadowmap_depth", TECHNIQUE_FLAG_10 | TECHNIQUE_FLAG_200},
{"build_shadowmap_model", TECHNIQUE_FLAG_10 | TECHNIQUE_FLAG_200},
{"distortion_scale_ua_zfeather", TECHNIQUE_FLAG_100 },
{"distortion_scale_zfeather", TECHNIQUE_FLAG_100 },
{"distortion_scale_zfeather_dtex", TECHNIQUE_FLAG_100 },
{"zprepass", MTL_TECHFLAG_ZPREPASS | TECHNIQUE_FLAG_200 },
{"build_floatz", MTL_TECHFLAG_BUILD_FLOATZ },
{"build_shadowmap_depth", MTL_TECHFLAG_BUILD_SHADOW_MAP_DEPTH_OR_MODEL | TECHNIQUE_FLAG_200},
{"build_shadowmap_model", MTL_TECHFLAG_BUILD_SHADOW_MAP_DEPTH_OR_MODEL | TECHNIQUE_FLAG_200},
{"distortion_scale_ua_zfeather", MTL_TECHFLAG_USES_DISTORTION_FLOATZ },
{"distortion_scale_zfeather", MTL_TECHFLAG_USES_DISTORTION_FLOATZ },
{"distortion_scale_zfeather_dtex", MTL_TECHFLAG_USES_DISTORTION_FLOATZ },
{"alternate_scene_overlay", TECHNIQUE_FLAG_200 },
{"blur_apply", TECHNIQUE_FLAG_200 },
{"build_floatz", TECHNIQUE_FLAG_200 },
@@ -1119,7 +1117,7 @@ namespace
const auto& pass = technique.passArray[i];
if (pass.vertexDecl && pass.vertexDecl->hasOptionalSource)
{
technique.flags |= TECHNIQUE_FLAG_20;
technique.flags |= MTL_TECHFLAG_DECL_HAS_OPTIONAL_SOURCE;
break;
}
}
@@ -1132,16 +1130,16 @@ namespace
switch (arg.m_arg.u.codeSampler)
{
case TEXTURE_SRC_CODE_RESOLVED_POST_SUN:
techniqueFlags |= TECHNIQUE_FLAG_1;
techniqueFlags |= MTL_TECHFLAG_NEEDS_RESOLVED_POST_SUN;
break;
case TEXTURE_SRC_CODE_RESOLVED_SCENE:
techniqueFlags |= TECHNIQUE_FLAG_2;
techniqueFlags |= MTL_TECHFLAG_NEEDS_RESOLVED_SCENE;
break;
case TEXTURE_SRC_CODE_FLOATZ:
case TEXTURE_SRC_CODE_PROCESSED_FLOATZ:
case TEXTURE_SRC_CODE_RAW_FLOATZ:
if ((techniqueFlags & TECHNIQUE_FLAG_100) == 0)
techniqueFlags |= TECHNIQUE_FLAG_80;
if ((techniqueFlags & MTL_TECHFLAG_USES_DISTORTION_FLOATZ) == 0)
techniqueFlags |= MTL_TECHFLAG_USES_FLOATZ;
break;
default:
break;
@@ -1153,7 +1151,7 @@ namespace
{
case CONST_SRC_CODE_LIGHT_SPOTDIR:
case CONST_SRC_CODE_LIGHT_SPOTFACTORS:
techniqueFlags |= TECHNIQUE_FLAG_40;
techniqueFlags |= MTL_TECHFLAG_USES_LIGHT_SPOT_FACTORS;
break;
default:
break;

View File

@@ -1,102 +0,0 @@
#include "CompilerVertexDeclIW4.h"
#include "Game/IW4/IW4.h"
#include "Game/IW4/Techset/TechsetConstantsIW4.h"
#include "Utils/Logging/Log.h"
#include <cstring>
#include <format>
#include <iostream>
using namespace IW4;
namespace
{
class LoaderVertexDecl final : public AssetCreator<AssetVertexDecl>
{
public:
LoaderVertexDecl(MemoryManager& memory)
: m_memory(memory)
{
}
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
{
auto* decl = m_memory.Alloc<MaterialVertexDeclaration>();
decl->name = m_memory.Dup(assetName.c_str());
size_t currentOffset = 0u;
std::string sourceAbbreviation;
while (NextAbbreviation(assetName, sourceAbbreviation, currentOffset))
{
if (decl->streamCount >= std::extent_v<decltype(MaterialVertexStreamRouting::data)>)
{
con::error("Failed to add vertex decl stream. Too many abbreviations: {}", assetName);
return AssetCreationResult::Failure();
}
std::string destinationAbbreviation;
if (!NextAbbreviation(assetName, destinationAbbreviation, currentOffset))
{
con::error("Failed to detect vertex decl destination abbreviation: {}", assetName);
return AssetCreationResult::Failure();
}
const auto foundSourceAbbreviation = std::ranges::find(materialStreamSourceAbbreviation, sourceAbbreviation);
if (foundSourceAbbreviation == std::end(materialStreamSourceAbbreviation))
{
con::error("Unknown vertex decl source abbreviation: {}", sourceAbbreviation);
return AssetCreationResult::Failure();
}
const auto foundDestinationAbbreviation = std::ranges::find(materialStreamDestinationAbbreviation, destinationAbbreviation);
if (foundDestinationAbbreviation == std::end(materialStreamDestinationAbbreviation))
{
con::error("Unknown vertex decl destination abbreviation: {}", destinationAbbreviation);
return AssetCreationResult::Failure();
}
const auto sourceIndex = static_cast<MaterialStreamStreamSource_e>(foundSourceAbbreviation - std::begin(materialStreamSourceAbbreviation));
const auto destinationIndex =
static_cast<MaterialStreamDestination_e>(foundDestinationAbbreviation - std::begin(materialStreamDestinationAbbreviation));
decl->routing.data[decl->streamCount].source = sourceIndex;
decl->routing.data[decl->streamCount].dest = destinationIndex;
decl->hasOptionalSource = decl->hasOptionalSource || sourceIndex >= STREAM_SRC_OPTIONAL_BEGIN;
decl->streamCount++;
}
return AssetCreationResult::Success(context.AddAsset<AssetVertexDecl>(assetName, decl));
}
static 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;
}
MemoryManager& m_memory;
};
} // namespace
namespace vertex_decl
{
std::unique_ptr<AssetCreator<AssetVertexDecl>> CreateLoaderIW4(MemoryManager& memory)
{
return std::make_unique<LoaderVertexDecl>(memory);
}
} // namespace vertex_decl

View File

@@ -1,13 +0,0 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "Game/IW4/IW4.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
namespace vertex_decl
{
std::unique_ptr<AssetCreator<IW4::AssetVertexDecl>> CreateLoaderIW4(MemoryManager& memory);
} // namespace vertex_decl

View File

@@ -1,12 +1,12 @@
#include "ObjCompilerT6.h"
#include "Game/T6/T6.h"
#include "Game/T6/Techset/TechniqueCompilerT6.h"
#include "Game/T6/Techset/TechsetCompilerT6.h"
#include "Game/T6/Techset/VertexDeclCompilerT6.h"
#include "Image/ImageIPakPostProcessor.h"
#include "Image/ImageIwdPostProcessor.h"
#include "KeyValuePairs/KeyValuePairsCompilerT6.h"
#include "Techset/TechniqueCompilerT6.h"
#include "Techset/TechsetCompilerT6.h"
#include "Techset/VertexDeclCompilerT6.h"
#include <memory>
@@ -23,7 +23,7 @@ namespace
auto& memory = zone.Memory();
collection.AddAssetCreator(key_value_pairs::CreateCompilerT6(memory, zone, zoneDefinition.m_zone_definition, zoneStates));
collection.AddAssetCreator(techset::CreateCompilerT6(memory, searchPath));
collection.AddAssetCreator(techset::CreateTechsetCompilerT6(memory, searchPath));
collection.AddSubAssetCreator(techset::CreateTechniqueCompilerT6(memory, zone, searchPath));
collection.AddSubAssetCreator(techset::CreateVertexDeclCompilerT6(memory));

View File

@@ -1,12 +0,0 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
namespace techset
{
std::unique_ptr<ISubAssetCreator> CreateTechniqueCompilerT6(MemoryManager& memory, Zone& zone, ISearchPath& searchPath);
}

View File

@@ -1,12 +0,0 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
namespace techset
{
std::unique_ptr<IAssetCreator> CreateCompilerT6(MemoryManager& memory, ISearchPath& searchPath);
} // namespace techset

View File

@@ -1,57 +0,0 @@
#include "VertexDeclCompilerT6.h"
#include "Game/T6/T6.h"
#include "Game/T6/Techset/TechsetConstantsT6.h"
#include "Techset/CommonVertexDeclCreator.h"
#include "Utils/Logging/Log.h"
using namespace T6;
namespace
{
class VertexDeclCompilerT6 final : public SubAssetCreator<SubAssetVertexDecl>
{
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<decltype(MaterialVertexStreamRouting::data)>)
{
con::error("Vertex declaration can only have up to {} routing entries", std::extent_v<decltype(MaterialVertexStreamRouting::data)>);
return AssetCreationResult::Failure();
}
auto* vertexDecl = m_memory.Alloc<MaterialVertexDeclaration>();
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<SubAssetVertexDecl>(subAssetName, vertexDecl)));
}
private:
MemoryManager& m_memory;
};
} // namespace
namespace techset
{
std::unique_ptr<ISubAssetCreator> CreateVertexDeclCompilerT6(MemoryManager& memory)
{
return std::make_unique<VertexDeclCompilerT6>(memory);
}
} // namespace techset

View File

@@ -1,11 +0,0 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "Utils/MemoryManager.h"
#include <memory>
namespace techset
{
std::unique_ptr<ISubAssetCreator> CreateVertexDeclCompilerT6(MemoryManager& memory);
}

View File

@@ -2,7 +2,9 @@
#include "Shader/D3D11ShaderAnalyser.h"
#include "Shader/D3D9ShaderAnalyser.h"
#include "Utils/Alignment.h"
#include "Utils/Djb2.h"
#include "Utils/Logging/Log.h"
#include <algorithm>
#include <cassert>
@@ -58,8 +60,9 @@ namespace
{
techset::CommonShaderArgDestination commonDestination{};
bool isTransposed;
unsigned rowCount;
std::string errorMessage;
if (!FindDestinationForConstant(commonDestination, isTransposed, errorMessage, destination))
if (!FindDestinationForConstant(commonDestination, isTransposed, rowCount, errorMessage, destination))
{
if (!errorMessage.empty())
return result::Unexpected(std::move(errorMessage));
@@ -67,7 +70,7 @@ namespace
return result::Unexpected(std::format("Could not find constant shader input with name {}", destination.m_argument_name));
}
return AcceptShaderConstantArgument(commonDestination, isTransposed, codeConstSource, sourceIndex);
return AcceptShaderConstantArgument(commonDestination, isTransposed, rowCount, codeConstSource, sourceIndex);
}
result::Expected<NoResult, std::string> AcceptShaderSamplerArgument(const techset::CommonShaderArgCreatorDestination& destination,
@@ -91,8 +94,9 @@ namespace
{
techset::CommonShaderArgDestination commonDestination{};
bool isTransposed;
unsigned rowCount;
std::string errorMessage;
if (!FindDestinationForConstant(commonDestination, isTransposed, errorMessage, destination))
if (!FindDestinationForConstant(commonDestination, isTransposed, rowCount, errorMessage, destination))
{
if (!errorMessage.empty())
return result::Unexpected(std::move(errorMessage));
@@ -121,8 +125,9 @@ namespace
techset::CommonShaderArgDestination commonDestination{};
bool isTransposed;
unsigned rowCount;
std::string errorMessage;
if (!FindDestinationForConstant(commonDestination, isTransposed, errorMessage, destination))
if (!FindDestinationForConstant(commonDestination, isTransposed, rowCount, errorMessage, destination))
{
if (!errorMessage.empty())
return result::Unexpected(std::move(errorMessage));
@@ -191,6 +196,7 @@ namespace
protected:
result::Expected<NoResult, std::string> AcceptShaderConstantArgument(const techset::CommonShaderArgDestination& commonDestination,
const bool isTransposed,
const unsigned rowCount,
const techset::CommonCodeConstSource codeConstSource,
const unsigned sourceIndex)
{
@@ -207,7 +213,7 @@ namespace
techset::CommonShaderArgCodeConstValue value{
.m_index = 0,
.m_first_row = 0,
.m_row_count = isMatrix ? 4u : 1u,
.m_row_count = isMatrix ? rowCount : 1u,
};
if (isMatrix)
@@ -260,6 +266,7 @@ namespace
[[nodiscard]] virtual bool FindDestinationForConstant(techset::CommonShaderArgDestination& commonDestination,
bool& isTransposed,
unsigned& rowCount,
std::string& errorMessage,
const techset::CommonShaderArgCreatorDestination& input) = 0;
[[nodiscard]] virtual bool FindDestinationForSampler(techset::CommonShaderArgDestination& commonDestination,
@@ -297,6 +304,8 @@ namespace
if (!m_shader_info)
return result::Unexpected(std::format("Failed to analyse dx9 shader {}", name));
m_arg_added = std::vector(m_shader_info->m_constants.size(), false);
return NoResult{};
}
@@ -316,12 +325,32 @@ namespace
[[nodiscard]] bool FindDestinationForConstant(techset::CommonShaderArgDestination& commonDestination,
bool& isTransposed,
unsigned& rowCount,
std::string& errorMessage,
const techset::CommonShaderArgCreatorDestination& input) override
{
assert(m_shader_info);
// TODO
return false;
const auto foundConstant =
std::ranges::find_if(m_shader_info->m_constants,
[input](const d3d9::ShaderConstant& constant)
{
return constant.m_register_set == d3d9::RegisterSet::FLOAT_4 && constant.m_name == input.m_argument_name;
});
if (foundConstant == m_shader_info->m_constants.end())
return false;
const auto variableElementCount = std::max<unsigned>(foundConstant->m_register_count, 1);
commonDestination.dx9.m_destination_register = foundConstant->m_register_index;
isTransposed = foundConstant->m_class == d3d9::ParameterClass::MATRIX_COLUMNS;
rowCount = foundConstant->m_register_count;
const auto argIndex = static_cast<size_t>(foundConstant - m_shader_info->m_constants.begin());
m_arg_added[argIndex] = true;
return true;
}
[[nodiscard]] bool FindDestinationForSampler(techset::CommonShaderArgDestination& commonDestination,
@@ -329,18 +358,133 @@ namespace
const techset::CommonShaderArgCreatorDestination& input) override
{
assert(m_shader_info);
// TODO
return false;
const auto foundConstant =
std::ranges::find_if(m_shader_info->m_constants,
[input](const d3d9::ShaderConstant& constant)
{
return constant.m_register_set == d3d9::RegisterSet::SAMPLER && constant.m_name == input.m_argument_name;
});
if (foundConstant == m_shader_info->m_constants.end())
return false;
commonDestination.dx9.m_destination_register = foundConstant->m_register_index;
const auto argIndex = static_cast<size_t>(foundConstant - m_shader_info->m_constants.begin());
m_arg_added[argIndex] = true;
return true;
}
result::Expected<NoResult, std::string> AutoCreateMissingArgs() override
{
// TODO
const auto argCount = m_shader_info->m_constants.size();
for (size_t argIndex = 0; argIndex < argCount; argIndex++)
{
if (m_arg_added[argIndex])
continue;
const auto& shaderArg = m_shader_info->m_constants[argIndex];
if (shaderArg.m_register_set == d3d9::RegisterSet::FLOAT_4)
{
auto result = AutoCreateConstantArg(shaderArg);
if (!result)
return std::move(result);
}
else
{
assert(shaderArg.m_register_set == d3d9::RegisterSet::SAMPLER);
auto result = AutoCreateSamplerArg(shaderArg);
if (!result)
return std::move(result);
}
}
return NoResult{};
}
private:
result::Expected<NoResult, std::string> AutoCreateConstantArg(const d3d9::ShaderConstant& shaderArg)
{
const auto maybeCodeConst = m_common_code_source_infos.GetCodeConstSourceForAccessor(shaderArg.m_name);
if (!maybeCodeConst)
{
// Some variables are simply not added as args for some reason
if (m_common_code_source_infos.IsArgAccessorIgnored(shaderArg.m_name))
return NoResult{};
return result::Unexpected(std::format("Missing assignment to shader constant {}", shaderArg.m_name));
}
const auto constInfo = m_common_code_source_infos.GetInfoForCodeConstSource(*maybeCodeConst);
if (!constInfo)
return result::Unexpected(std::format("Missing info for code const {}", shaderArg.m_name));
const auto elementSize = ElementSizeForArg(shaderArg);
const auto elementCount = utils::Align(shaderArg.m_register_count, elementSize) / elementSize;
const auto infoArrayCount = std::max<unsigned>(constInfo->arrayCount, 1);
if (elementCount > infoArrayCount)
{
return result::Unexpected(std::format("Could not auto create argument for constant {} as it has more elements ({}) than the code constant ({})",
shaderArg.m_name,
elementCount,
infoArrayCount));
}
techset::CommonShaderArgDestination commonDestination;
const auto isTransposed = shaderArg.m_class == d3d9::ParameterClass::MATRIX_COLUMNS;
for (auto elementIndex = 0u; elementIndex < elementCount; elementIndex++)
{
commonDestination.dx9.m_destination_register = shaderArg.m_register_index + elementIndex;
auto result = AcceptShaderConstantArgument(commonDestination, isTransposed, shaderArg.m_register_count, *maybeCodeConst, elementIndex);
if (!result)
return std::move(result);
}
if (constInfo->techFlags)
m_tech_flags |= *constInfo->techFlags;
return NoResult{};
}
[[nodiscard]] static unsigned ElementSizeForArg(const d3d9::ShaderConstant& arg)
{
switch (arg.m_class)
{
case d3d9::ParameterClass::MATRIX_COLUMNS:
case d3d9::ParameterClass::MATRIX_ROWS:
return 4;
default:
return 1;
}
}
result::Expected<NoResult, std::string> AutoCreateSamplerArg(const d3d9::ShaderConstant& shaderArg)
{
const auto maybeCodeSampler = m_common_code_source_infos.GetCodeSamplerSourceForAccessor(shaderArg.m_name);
if (!maybeCodeSampler)
return result::Unexpected(std::format("Missing assignment to shader texture {}", shaderArg.m_name));
const auto samplerInfo = m_common_code_source_infos.GetInfoForCodeSamplerSource(*maybeCodeSampler);
if (!samplerInfo)
return result::Unexpected(std::format("Missing info for code sampler {}", shaderArg.m_name));
techset::CommonShaderArgDestination commonDestination;
commonDestination.dx9.m_destination_register = shaderArg.m_register_index;
if (samplerInfo->techFlags)
m_tech_flags |= *samplerInfo->techFlags;
if (samplerInfo->customSamplerIndex)
m_sampler_flags |= (1 << *samplerInfo->customSamplerIndex);
return AcceptShaderSamplerArgument(commonDestination, *maybeCodeSampler);
}
std::unique_ptr<d3d9::ShaderInfo> m_shader_info;
std::vector<bool> m_arg_added;
};
class CommonShaderArgCreatorDx11 final : public BaseCommonShaderArgCreator
@@ -402,6 +546,7 @@ namespace
[[nodiscard]] bool FindDestinationForConstant(techset::CommonShaderArgDestination& commonDestination,
bool& isTransposed,
unsigned& rowCount,
std::string& errorMessage,
const techset::CommonShaderArgCreatorDestination& input) override
{
@@ -448,6 +593,7 @@ namespace
commonDestination.dx11.m_size = variableElementSize;
commonDestination.dx11.m_buffer = bufferBinding->m_bind_point;
isTransposed = variableIterator->m_variable_class == d3d11::VariableClass::MATRIX_COLUMNS;
rowCount = variableIterator->m_row_count;
m_const_arg_added[usedConstantIndex] = true;
@@ -569,7 +715,6 @@ namespace
return std::move(result);
}
// TODO
return NoResult{};
}
@@ -632,7 +777,7 @@ namespace
for (auto elementIndex = 0u; elementIndex < variableElementCount; elementIndex++)
{
commonDestination.dx11.m_location.constant_buffer_offset = variable.m_offset + variableElementSize * elementIndex;
auto result = AcceptShaderConstantArgument(commonDestination, isTransposed, *maybeCodeConst, elementIndex);
auto result = AcceptShaderConstantArgument(commonDestination, isTransposed, variable.m_row_count, *maybeCodeConst, elementIndex);
if (!result)
return std::move(result);
}

View File

@@ -1,19 +1,58 @@
#include "TechniqueCompilerT6.h"
#options GAME(IW4, T6)
#include "Game/T6/T6.h"
#include "Game/T6/Techset/TechsetConstantsT6.h"
#include "PrecompiledIndexT6.h"
#filename "Game/" + GAME + "/Techset/TechniqueCompiler" + GAME + ".cpp"
#set COMPILER_HEADER "\"TechniqueCompiler" + GAME + ".h\""
#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\""
#set TECHSET_CONSTANTS_HEADER "\"Game/" + GAME + "/Techset/TechsetConstants" + GAME + ".h\""
#if GAME == "IW3"
#define FEATURE_IW3
#define IS_DX9
#elif GAME == "IW4"
#define FEATURE_IW4
#define IS_DX9
#elif GAME == "IW5"
#define FEATURE_IW5
#define IS_DX9
#elif GAME == "T5"
#define FEATURE_T5
#define IS_DX9
#define SHADERS_ARE_SUBASSETS
#elif GAME == "T6"
#define FEATURE_T6
#define IS_DX11
#define SHADERS_ARE_SUBASSETS
#endif
// This file was templated.
// See TechniqueCompiler.cpp.template.
// Do not modify, changes will be lost.
#include COMPILER_HEADER
#include GAME_HEADER
#include TECHSET_CONSTANTS_HEADER
#include "Techset/CommonShaderArgCreator.h"
#include "Techset/CommonTechniqueLoader.h"
#include "Techset/CommonVertexDeclCreator.h"
#include "Techset/LiteralConstsZoneState.h"
#include "Utils/StringUtils.h"
#if defined(FEATURE_T6)
#set PRECOMPILED_INDEX_HEADER "\"Game/" + GAME + "/Techset/PrecompiledIndex" + GAME + ".h\""
#include PRECOMPILED_INDEX_HEADER
#endif
#include <cassert>
#include <optional>
#include <sstream>
#include <vector>
using namespace T6;
using namespace GAME;
#set SHADER_LOADER_CLASS_NAME "TechniqueShaderLoader" + GAME
#set COMPILER_CLASS_NAME "TechniqueCompiler" + GAME
namespace
{
@@ -100,6 +139,9 @@ namespace
arg.type = static_cast<decltype(MaterialShaderArgument::type)>(ConvertArgumentType(commonArg.m_type));
#if defined(IS_DX9)
arg.dest = static_cast<decltype(MaterialShaderArgument::dest)>(commonArg.m_destination.dx9.m_destination_register);
#else
arg.size = static_cast<decltype(MaterialShaderArgument::size)>(commonArg.m_destination.dx11.m_size);
arg.buffer = static_cast<decltype(MaterialShaderArgument::buffer)>(commonArg.m_destination.dx11.m_buffer);
@@ -115,6 +157,7 @@ namespace
arg.location.samplerIndex =
static_cast<decltype(MaterialArgumentLocation::samplerIndex)>(commonArg.m_destination.dx11.m_location.sampler_index);
}
#endif
ConvertArgumentValue(arg.u, commonArg, memory, context);
}
@@ -130,7 +173,11 @@ namespace
}
const std::string declName(nameStream.str());
#if defined(SHADERS_ARE_SUBASSETS)
auto* vertexDeclAsset = context.LoadSubAsset<SubAssetVertexDecl>(declName);
#else
auto* vertexDeclAsset = context.LoadDependency<AssetVertexDecl>(declName);
#endif
assert(vertexDeclAsset);
pass.vertexDecl = vertexDeclAsset ? vertexDeclAsset->Asset() : nullptr;
}
@@ -141,14 +188,22 @@ namespace
if (!commonPass.m_vertex_shader.m_name.empty())
{
#if defined(SHADERS_ARE_SUBASSETS)
auto* vertexShaderAsset = context.LoadSubAsset<SubAssetVertexShader>(commonPass.m_vertex_shader.m_name);
#else
auto* vertexShaderAsset = context.LoadDependency<AssetVertexShader>(commonPass.m_vertex_shader.m_name);
#endif
assert(vertexShaderAsset);
pass.vertexShader = vertexShaderAsset ? vertexShaderAsset->Asset() : nullptr;
}
if (!commonPass.m_pixel_shader.m_name.empty())
{
#if defined(SHADERS_ARE_SUBASSETS)
auto* pixelShaderAsset = context.LoadSubAsset<SubAssetPixelShader>(commonPass.m_pixel_shader.m_name);
#else
auto* pixelShaderAsset = context.LoadDependency<AssetPixelShader>(commonPass.m_pixel_shader.m_name);
#endif
assert(pixelShaderAsset);
pass.pixelShader = pixelShaderAsset ? pixelShaderAsset->Asset() : nullptr;
}
@@ -157,7 +212,43 @@ namespace
pass.customSamplerFlags = static_cast<decltype(MaterialPass::customSamplerFlags)>(commonPass.m_sampler_flags);
}
bool AnyDeclHasOptionalSource(const MaterialTechnique& technique)
#ifdef FEATURE_IW4
// Not sure if this is actually how this is calculated.
// It produces identical results at least though.
constexpr MaterialConstantSource ALLOWED_PIXEL_CONSTANTS_FOR_FLAG_200[]{
CONST_SRC_CODE_RENDER_TARGET_SIZE,
CONST_SRC_CODE_VIEWPORT_DIMENSIONS,
};
bool ShouldApplyFlag200(const MaterialTechnique& technique)
{
for (auto passIndex = 0u; passIndex < technique.passCount; passIndex++)
{
const auto& pass = technique.passArray[passIndex];
if (!pass.args)
continue;
const unsigned argCount = pass.perPrimArgCount + pass.perObjArgCount + pass.stableArgCount;
for (auto argIndex = 0u; argIndex < argCount; argIndex++)
{
const auto& arg = pass.args[argIndex];
if (arg.type == MTL_ARG_MATERIAL_VERTEX_CONST || arg.type == MTL_ARG_MATERIAL_PIXEL_SAMPLER || arg.type == MTL_ARG_MATERIAL_PIXEL_CONST)
return false;
if (arg.type == MTL_ARG_CODE_PIXEL_CONST)
{
const auto foundAllowedConstant = std::ranges::find(ALLOWED_PIXEL_CONSTANTS_FOR_FLAG_200, arg.u.codeConst.index);
if (foundAllowedConstant == std::end(ALLOWED_PIXEL_CONSTANTS_FOR_FLAG_200))
return false;
}
}
}
return true;
}
#endif
bool AnyDeclHasOptionalSource(const MaterialTechnique& technique, AssetCreationContext& context)
{
for (auto passIndex = 0u; passIndex < technique.passCount; passIndex++)
{
@@ -165,28 +256,55 @@ namespace
if (!pass.vertexDecl)
continue;
#if defined(SHADERS_ARE_SUBASSETS)
if (pass.vertexDecl->hasOptionalSource)
return true;
#else
if (pass.vertexDecl->name && pass.vertexDecl->name[0] == ',')
{
if (techset::HasOptionalSourceByName(&pass.vertexDecl->name[1], commonRoutingInfos).value_or(false))
return true;
}
else if (pass.vertexDecl->hasOptionalSource)
return true;
#endif
}
return false;
}
void UpdateTechniqueFlags(MaterialTechnique& technique, const techset::CommonTechnique& commonTechnique)
void UpdateTechniqueFlags(MaterialTechnique& technique, const techset::CommonTechnique& commonTechnique, AssetCreationContext& context)
{
std::string lowerTechniqueName(commonTechnique.m_name);
utils::MakeStringLowerCase(lowerTechniqueName);
#if defined(FEATURE_IW4)
// Not a particularly cool way to do this but...
// the game actually does this :shrug:
if (lowerTechniqueName == "zprepass")
technique.flags |= MTL_TECHFLAG_ZPREPASS;
else if (lowerTechniqueName == "build_floatz")
technique.flags |= MTL_TECHFLAG_BUILD_FLOATZ;
else if (lowerTechniqueName == "build_shadowmap_depth" || lowerTechniqueName == "build_shadowmap_model")
technique.flags |= MTL_TECHFLAG_BUILD_SHADOW_MAP_DEPTH_OR_MODEL;
if (technique.flags & MTL_TECHFLAG_USES_FLOATZ && lowerTechniqueName.starts_with("distortion_"))
technique.flags = (technique.flags & ~MTL_TECHFLAG_USES_FLOATZ) | MTL_TECHFLAG_USES_DISTORTION_FLOATZ;
if (ShouldApplyFlag200(technique))
technique.flags |= TECHNIQUE_FLAG_200;
#elif defined(FEATURE_T6)
// Not a particularly cool way to do this but...
// the game actually does this :shrug:
if (lowerTechniqueName == "zprepass" || lowerTechniqueName.starts_with("pimp_technique_zprepass_")
|| lowerTechniqueName.starts_with("pimp_technique_layer_zprepass_") || lowerTechniqueName.starts_with("pimp_technique_buildshadowmap_"))
{
technique.flags |= TECHNIQUE_FLAG_4;
technique.flags |= MTL_TECHFLAG_ZPREPASS;
}
#endif
if (AnyDeclHasOptionalSource(technique))
technique.flags |= TECHNIQUE_FLAG_8;
if (AnyDeclHasOptionalSource(technique, context))
technique.flags |= MTL_TECHFLAG_DECL_HAS_OPTIONAL_SOURCE;
}
MaterialTechnique* ConvertTechnique(const techset::CommonTechnique& commonTechnique, AssetCreationContext& context, MemoryManager& memory)
@@ -205,11 +323,12 @@ namespace
// Take common flags and apply further logic
technique->flags = static_cast<decltype(MaterialTechnique::flags)>(commonTechnique.m_flags);
UpdateTechniqueFlags(*technique, commonTechnique);
UpdateTechniqueFlags(*technique, commonTechnique, context);
return technique;
}
#if defined(FEATURE_T6)
void ApplyTechFlagsFromMaterial(const Material& material, const Zone& zone)
{
if (!material.techniqueSet || !material.techniqueSet->name || !material.stateBitsTable)
@@ -235,18 +354,23 @@ namespace
technique->flags |= TECHNIQUE_FLAG_80;
}
}
#endif
class TechniqueShaderLoaderT6 final : public techset::ITechniqueShaderLoader
class SHADER_LOADER_CLASS_NAME final : public techset::ITechniqueShaderLoader
{
public:
explicit TechniqueShaderLoaderT6(AssetCreationContext& context)
explicit SHADER_LOADER_CLASS_NAME(AssetCreationContext& context)
: m_context(context)
{
}
std::optional<techset::CommonTechniqueShaderBin> LoadVertexShader(const std::string& name) override
{
#if defined(SHADERS_ARE_SUBASSETS)
auto* shaderAsset = m_context.LoadSubAsset<SubAssetVertexShader>(name);
#else
auto* shaderAsset = m_context.ForceLoadDependency<AssetVertexShader>(name);
#endif
if (!shaderAsset)
return std::nullopt;
@@ -257,13 +381,22 @@ namespace
return techset::CommonTechniqueShaderBin{
.m_shader_bin = shader->prog.loadDef.program,
#if defined(IS_DX9)
.m_shader_bin_size =
static_cast<size_t>(shader->prog.loadDef.programSize) * sizeof(std::remove_pointer_t<decltype(GfxVertexShaderLoadDef::program)>),
#else
.m_shader_bin_size = shader->prog.loadDef.programSize,
#endif
};
}
std::optional<techset::CommonTechniqueShaderBin> LoadPixelShader(const std::string& name) override
{
#if defined(SHADERS_ARE_SUBASSETS)
auto* shaderAsset = m_context.LoadSubAsset<SubAssetPixelShader>(name);
#else
auto* shaderAsset = m_context.ForceLoadDependency<AssetPixelShader>(name);
#endif
if (!shaderAsset)
return std::nullopt;
@@ -274,7 +407,12 @@ namespace
return techset::CommonTechniqueShaderBin{
.m_shader_bin = shader->prog.loadDef.program,
#if defined(IS_DX9)
.m_shader_bin_size =
static_cast<size_t>(shader->prog.loadDef.programSize) * sizeof(std::remove_pointer_t<decltype(GfxPixelShaderLoadDef::program)>),
#else
.m_shader_bin_size = shader->prog.loadDef.programSize,
#endif
};
}
@@ -282,10 +420,10 @@ namespace
AssetCreationContext& m_context;
};
class TechniqueCompilerT6 final : public SubAssetCreator<SubAssetTechnique>
class COMPILER_CLASS_NAME final : public SubAssetCreator<SubAssetTechnique>
{
public:
TechniqueCompilerT6(MemoryManager& memory, Zone& zone, ISearchPath& searchPath)
COMPILER_CLASS_NAME(MemoryManager& memory, Zone& zone, ISearchPath& searchPath)
: m_memory(memory),
m_zone(zone),
m_search_path(searchPath)
@@ -295,8 +433,12 @@ namespace
AssetCreationResult CreateSubAsset(const std::string& subAssetName, AssetCreationContext& context) override
{
bool failure = false;
TechniqueShaderLoaderT6 shaderLoader(context);
SHADER_LOADER_CLASS_NAME shaderLoader(context);
#if defined(IS_DX9)
const auto commonShaderArgCreator = techset::CommonShaderArgCreator::CreateDx9(shaderLoader, context, commonCodeSourceInfos);
#else
const auto commonShaderArgCreator = techset::CommonShaderArgCreator::CreateDx11(shaderLoader, context, commonCodeSourceInfos);
#endif
const auto commonTechnique =
techset::LoadCommonTechnique(subAssetName, commonCodeSourceInfos, commonRoutingInfos, *commonShaderArgCreator, m_search_path, failure);
@@ -312,6 +454,9 @@ namespace
void FinalizeZone(AssetCreationContext& context) override
{
#if defined(FEATURE_IW4)
// TODO
#elif defined(FEATURE_T6)
const auto materials = m_zone.m_pools.PoolAssets<AssetMaterial>();
for (auto* materialAsset : materials)
{
@@ -327,6 +472,7 @@ namespace
ApplyPrecompiledIndex(technique.passArray[passIndex]);
}
}
#endif
}
private:
@@ -336,10 +482,12 @@ namespace
};
} // namespace
#set CREATE_COMPILER_METHOD "CreateTechniqueCompiler" + GAME
namespace techset
{
std::unique_ptr<ISubAssetCreator> CreateTechniqueCompilerT6(MemoryManager& memory, Zone& zone, ISearchPath& searchPath)
std::unique_ptr<ISubAssetCreator> CREATE_COMPILER_METHOD(MemoryManager& memory, Zone& zone, ISearchPath& searchPath)
{
return std::make_unique<TechniqueCompilerT6>(memory, zone, searchPath);
return std::make_unique<COMPILER_CLASS_NAME>(memory, zone, searchPath);
}
} // namespace techset

View File

@@ -0,0 +1,34 @@
#options GAME(IW4, T6)
#filename "Game/" + GAME + "/Techset/TechniqueCompiler" + GAME + ".h"
#if GAME == "IW3"
#define FEATURE_IW3
#elif GAME == "IW4"
#define FEATURE_IW4
#elif GAME == "IW5"
#define FEATURE_IW5
#elif GAME == "T5"
#define FEATURE_T5
#elif GAME == "T6"
#define FEATURE_T6
#endif
// This file was templated.
// See TechniqueCompiler.h.template.
// Do not modify, changes will be lost.
#pragma once
#include "Asset/IAssetCreator.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
#set CREATE_COMPILER_METHOD "CreateTechniqueCompiler" + GAME
namespace techset
{
std::unique_ptr<ISubAssetCreator> CREATE_COMPILER_METHOD(MemoryManager& memory, Zone& zone, ISearchPath& searchPath);
}

View File

@@ -1,11 +1,37 @@
#include "TechsetCompilerT6.h"
#options GAME(IW4, T6)
#include "Game/T6/T6.h"
#include "Game/T6/Techset/TechsetConstantsT6.h"
#filename "Game/" + GAME + "/Techset/TechsetCompiler" + GAME + ".cpp"
#set COMPILER_HEADER "\"TechsetCompiler" + GAME + ".h\""
#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\""
#set TECHSET_CONSTANTS_HEADER "\"Game/" + GAME + "/Techset/TechsetConstants" + GAME + ".h\""
#if GAME == "IW3"
#define FEATURE_IW3
#elif GAME == "IW4"
#define FEATURE_IW4
#elif GAME == "IW5"
#define FEATURE_IW5
#elif GAME == "T5"
#define FEATURE_T5
#elif GAME == "T6"
#define FEATURE_T6
#endif
// This file was templated.
// See TechsetCompiler.cpp.template.
// Do not modify, changes will be lost.
#include COMPILER_HEADER
#include GAME_HEADER
#include TECHSET_CONSTANTS_HEADER
#include "Techset/CommonTechsetLoader.h"
#include "Techset/TechsetCommon.h"
using namespace T6;
using namespace GAME;
#set COMPILER_CLASS_NAME "TechsetCompiler" + GAME
namespace
{
@@ -43,6 +69,7 @@ namespace
return static_cast<MaterialWorldVertexFormat>(0);
}
#if defined(FEATURE_T6)
MaterialType GetMaterialType(const std::string& name)
{
for (unsigned materialTypeIndex = MTL_TYPE_MODEL; materialTypeIndex < MTL_TYPE_COUNT; materialTypeIndex++)
@@ -61,6 +88,7 @@ namespace
technique.passArray[passIndex].materialType = materialType;
}
}
#endif
MaterialTechniqueSet* ConvertTechniqueSet(const techset::CommonTechset& commonTechset, MemoryManager& memory)
{
@@ -71,10 +99,10 @@ namespace
return techset;
}
class TechsetCompilerT6 final : public AssetCreator<AssetTechniqueSet>
class COMPILER_CLASS_NAME final : public AssetCreator<AssetTechniqueSet>
{
public:
TechsetCompilerT6(ISearchPath& searchPath, MemoryManager& memory)
COMPILER_CLASS_NAME(ISearchPath& searchPath, MemoryManager& memory)
: m_search_path(searchPath),
m_memory(memory)
{
@@ -88,7 +116,9 @@ namespace
return failure ? AssetCreationResult::Failure() : AssetCreationResult::NoAction();
auto* techset = ConvertTechniqueSet(*commonTechset, m_memory);
#if defined(FEATURE_T6)
const auto materialType = GetMaterialType(assetName);
#endif
for (auto techniqueIndex = 0u; techniqueIndex < std::extent_v<decltype(MaterialTechniqueSet::techniques)>; techniqueIndex++)
{
@@ -102,12 +132,12 @@ namespace
techset->techniques[techniqueIndex] = technique->Asset();
#if defined(FEATURE_T6)
// Another techset may override this for the technique
// but the game determines the material type by techset name.
// So this may just be a constraint that cannot be changed.
ApplyMaterialTypeToTechnique(*techset->techniques[techniqueIndex], materialType);
// Precompiled index?
#endif
}
return AssetCreationResult::Success(context.AddAsset(AssetRegistration<AssetTechniqueSet>(assetName, techset)));
@@ -119,10 +149,12 @@ namespace
};
} // namespace
#set CREATE_COMPILER_METHOD "CreateTechsetCompiler" + GAME
namespace techset
{
std::unique_ptr<IAssetCreator> CreateCompilerT6(MemoryManager& memory, ISearchPath& searchPath)
std::unique_ptr<IAssetCreator> CREATE_COMPILER_METHOD(MemoryManager& memory, ISearchPath& searchPath)
{
return std::make_unique<TechsetCompilerT6>(searchPath, memory);
return std::make_unique<COMPILER_CLASS_NAME>(searchPath, memory);
}
} // namespace techset

View File

@@ -0,0 +1,34 @@
#options GAME(IW4, T6)
#filename "Game/" + GAME + "/Techset/TechsetCompiler" + GAME + ".h"
#if GAME == "IW3"
#define FEATURE_IW3
#elif GAME == "IW4"
#define FEATURE_IW4
#elif GAME == "IW5"
#define FEATURE_IW5
#elif GAME == "T5"
#define FEATURE_T5
#elif GAME == "T6"
#define FEATURE_T6
#endif
// This file was templated.
// See TechsetCompiler.h.template.
// Do not modify, changes will be lost.
#pragma once
#include "Asset/IAssetCreator.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
#set CREATE_COMPILER_METHOD "CreateTechsetCompiler" + GAME
namespace techset
{
std::unique_ptr<IAssetCreator> CREATE_COMPILER_METHOD(MemoryManager& memory, ISearchPath& searchPath);
}

View File

@@ -0,0 +1,104 @@
#options GAME(IW4, T6)
#filename "Game/" + GAME + "/Techset/VertexDeclCompiler" + GAME + ".cpp"
#set COMPILER_HEADER "\"VertexDeclCompiler" + GAME + ".h\""
#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\""
#set TECHSET_CONSTANTS_HEADER "\"Game/" + GAME + "/Techset/TechsetConstants" + GAME + ".h\""
#if GAME == "IW3"
#define FEATURE_IW3
#elif GAME == "IW4"
#define FEATURE_IW4
#elif GAME == "IW5"
#define FEATURE_IW5
#elif GAME == "T5"
#define FEATURE_T5
#elif GAME == "T6"
#define FEATURE_T6
#define IS_SUB_ASSET
#endif
// This file was templated.
// See VertexDeclCompiler.cpp.template.
// Do not modify, changes will be lost.
#include COMPILER_HEADER
#include GAME_HEADER
#include TECHSET_CONSTANTS_HEADER
#include "Techset/CommonVertexDeclCreator.h"
#include "Utils/Logging/Log.h"
using namespace GAME;
#set COMPILER_CLASS_NAME "VertexDeclCompiler" + GAME
#if defined(IS_SUB_ASSET)
#define ABSTRACT_CREATOR_NAME SubAssetCreator
#define OVERRIDDEN_CREATOR_METHOD CreateSubAsset
#define ADD_ASSET_METHOD AddSubAsset
#define ASSET_NAME SubAssetVertexDecl
#define INTERFACE_NAME ISubAssetCreator
#else
#define ABSTRACT_CREATOR_NAME AssetCreator
#define OVERRIDDEN_CREATOR_METHOD CreateAsset
#define ADD_ASSET_METHOD AddAsset
#define ASSET_NAME AssetVertexDecl
#define INTERFACE_NAME IAssetCreator
#endif
namespace
{
class COMPILER_CLASS_NAME final : public ABSTRACT_CREATOR_NAME<ASSET_NAME>
{
public:
explicit COMPILER_CLASS_NAME(MemoryManager& memory)
: m_memory(memory)
{
}
AssetCreationResult OVERRIDDEN_CREATOR_METHOD(const std::string& assetName, AssetCreationContext& context) override
{
const auto commonVertexDecl = techset::CreateVertexDeclFromName(assetName, commonRoutingInfos);
if (!commonVertexDecl)
return AssetCreationResult::Failure();
if (commonVertexDecl->m_routing.size() > std::extent_v<decltype(MaterialVertexStreamRouting::data)>)
{
con::error("Vertex declaration can only have up to {} routing entries", std::extent_v<decltype(MaterialVertexStreamRouting::data)>);
return AssetCreationResult::Failure();
}
auto* vertexDecl = m_memory.Alloc<MaterialVertexDeclaration>();
#ifndef IS_SUB_ASSET
vertexDecl->name = m_memory.Dup(assetName.c_str());
#endif
for (const auto& commonRoutingEntry : commonVertexDecl->m_routing)
{
vertexDecl->routing.data[vertexDecl->streamCount].source = commonRoutingEntry.m_source;
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.ADD_ASSET_METHOD(AssetRegistration<ASSET_NAME>(assetName, vertexDecl)));
}
private:
MemoryManager& m_memory;
};
} // namespace
#set CREATE_COMPILER_METHOD "CreateVertexDeclCompiler" + GAME
namespace techset
{
std::unique_ptr<INTERFACE_NAME> CREATE_COMPILER_METHOD(MemoryManager& memory)
{
return std::make_unique<COMPILER_CLASS_NAME>(memory);
}
} // namespace techset

View File

@@ -0,0 +1,39 @@
#options GAME(IW4, T6)
#filename "Game/" + GAME + "/Techset/VertexDeclCompiler" + GAME + ".h"
#if GAME == "IW3"
#define FEATURE_IW3
#elif GAME == "IW4"
#define FEATURE_IW4
#elif GAME == "IW5"
#define FEATURE_IW5
#elif GAME == "T5"
#define FEATURE_T5
#elif GAME == "T6"
#define FEATURE_T6
#endif
// This file was templated.
// See VertexDeclCompiler.h.template.
// Do not modify, changes will be lost.
#pragma once
#include "Asset/IAssetCreator.h"
#include "Utils/MemoryManager.h"
#include <memory>
#set CREATE_COMPILER_METHOD "CreateVertexDeclCompiler" + GAME
#if defined(FEATURE_T6)
#define INTERFACE_NAME ISubAssetCreator
#else
#define INTERFACE_NAME IAssetCreator
#endif
namespace techset
{
std::unique_ptr<INTERFACE_NAME> CREATE_COMPILER_METHOD(MemoryManager& memory);
}

View File

@@ -6,6 +6,8 @@
#include "Game/IW4/IW4.h"
#include "Game/IW4/Image/ImageLoaderEmbeddedIW4.h"
#include "Game/IW4/Image/ImageLoaderExternalIW4.h"
#include "Game/IW4/Techset/PixelShaderLoaderIW4.h"
#include "Game/IW4/Techset/VertexShaderLoaderIW4.h"
#include "Game/IW4/XModel/LoaderXModelIW4.h"
#include "Leaderboard/LoaderLeaderboardIW4.h"
#include "LightDef/LightDefLoaderIW4.h"
@@ -16,8 +18,6 @@
#include "PhysPreset/GdtLoaderPhysPresetIW4.h"
#include "PhysPreset/RawLoaderPhysPresetIW4.h"
#include "RawFile/LoaderRawFileIW4.h"
#include "Shader/LoaderPixelShaderIW4.h"
#include "Shader/LoaderVertexShaderIW4.h"
#include "Sound/LoaderSoundCurveIW4.h"
#include "StringTable/LoaderStringTableIW4.h"
#include "StructuredDataDef/LoaderStructuredDataDefIW4.h"
@@ -129,8 +129,8 @@ namespace
// collection.AddAssetCreator(std::make_unique<AssetLoaderXModelSurfs>(memory));
collection.AddAssetCreator(xmodel::CreateLoaderIW4(memory, searchPath, zone));
collection.AddAssetCreator(material::CreateLoaderIW4(memory, searchPath));
collection.AddAssetCreator(shader::CreatePixelShaderLoaderIW4(memory, searchPath));
collection.AddAssetCreator(shader::CreateVertexShaderLoaderIW4(memory, searchPath));
collection.AddAssetCreator(techset::CreateVertexShaderLoaderIW4(memory, searchPath));
collection.AddAssetCreator(techset::CreatePixelShaderLoaderIW4(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderTechset>(memory));
collection.AddAssetCreator(image::CreateLoaderEmbeddedIW4(memory, searchPath));
collection.AddAssetCreator(image::CreateLoaderExternalIW4(memory, searchPath));

View File

@@ -1,64 +0,0 @@
#include "LoaderPixelShaderIW4.h"
#include "Game/IW4/IW4.h"
#include "Shader/ShaderCommon.h"
#include "Utils/Logging/Log.h"
#include <cstdint>
#include <format>
#include <iostream>
using namespace IW4;
namespace
{
class PixelShaderLoader final : public AssetCreator<AssetPixelShader>
{
public:
PixelShaderLoader(MemoryManager& memory, ISearchPath& searchPath)
: m_memory(memory),
m_search_path(searchPath)
{
}
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
{
const auto fileName = shader::GetFileNameForPixelShaderAssetName(assetName);
const auto file = m_search_path.Open(fileName);
if (!file.IsOpen())
return AssetCreationResult::NoAction();
if (file.m_length % sizeof(uint32_t) != 0)
{
con::error("Invalid pixel shader \"{}\": Size must be dividable by {}", assetName, sizeof(uint32_t));
return AssetCreationResult::Failure();
}
auto* pixelShader = m_memory.Alloc<MaterialPixelShader>();
pixelShader->name = m_memory.Dup(assetName.c_str());
pixelShader->prog.loadDef.programSize = static_cast<uint16_t>(static_cast<size_t>(file.m_length) / sizeof(uint32_t));
pixelShader->prog.loadDef.loadForRenderer = 0;
pixelShader->prog.ps = nullptr;
auto* fileBuffer = m_memory.Alloc<uint32_t>(pixelShader->prog.loadDef.programSize);
file.m_stream->read(reinterpret_cast<char*>(fileBuffer), static_cast<std::streamsize>(pixelShader->prog.loadDef.programSize) * sizeof(uint32_t));
if (file.m_stream->gcount() != file.m_length)
return AssetCreationResult::Failure();
pixelShader->prog.loadDef.program = fileBuffer;
return AssetCreationResult::Success(context.AddAsset<AssetPixelShader>(assetName, pixelShader));
}
private:
MemoryManager& m_memory;
ISearchPath& m_search_path;
};
} // namespace
namespace shader
{
std::unique_ptr<AssetCreator<AssetPixelShader>> CreatePixelShaderLoaderIW4(MemoryManager& memory, ISearchPath& searchPath)
{
return std::make_unique<PixelShaderLoader>(memory, searchPath);
}
} // namespace shader

View File

@@ -1,13 +0,0 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "Game/IW4/IW4.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
namespace shader
{
std::unique_ptr<AssetCreator<IW4::AssetPixelShader>> CreatePixelShaderLoaderIW4(MemoryManager& memory, ISearchPath& searchPath);
} // namespace shader

View File

@@ -1,64 +0,0 @@
#include "LoaderVertexShaderIW4.h"
#include "Game/IW4/IW4.h"
#include "Shader/ShaderCommon.h"
#include "Utils/Logging/Log.h"
#include <cstdint>
#include <format>
#include <iostream>
using namespace IW4;
namespace
{
class VertexShaderLoader final : public AssetCreator<AssetVertexShader>
{
public:
VertexShaderLoader(MemoryManager& memory, ISearchPath& searchPath)
: m_memory(memory),
m_search_path(searchPath)
{
}
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
{
const auto fileName = shader::GetFileNameForVertexShaderAssetName(assetName);
const auto file = m_search_path.Open(fileName);
if (!file.IsOpen())
return AssetCreationResult::NoAction();
if (file.m_length % sizeof(uint32_t) != 0)
{
con::error("Invalid vertex shader \"{}\": Size must be dividable by {}", assetName, sizeof(uint32_t));
return AssetCreationResult::Failure();
}
auto* vertexShader = m_memory.Alloc<MaterialVertexShader>();
vertexShader->name = m_memory.Dup(assetName.c_str());
vertexShader->prog.loadDef.programSize = static_cast<uint16_t>(static_cast<size_t>(file.m_length) / sizeof(uint32_t));
vertexShader->prog.loadDef.loadForRenderer = 0;
vertexShader->prog.vs = nullptr;
auto* fileBuffer = m_memory.Alloc<uint32_t>(vertexShader->prog.loadDef.programSize);
file.m_stream->read(reinterpret_cast<char*>(fileBuffer), static_cast<std::streamsize>(vertexShader->prog.loadDef.programSize) * sizeof(uint32_t));
if (file.m_stream->gcount() != file.m_length)
return AssetCreationResult::Failure();
vertexShader->prog.loadDef.program = fileBuffer;
return AssetCreationResult::Success(context.AddAsset<AssetVertexShader>(assetName, vertexShader));
}
private:
MemoryManager& m_memory;
ISearchPath& m_search_path;
};
} // namespace
namespace shader
{
std::unique_ptr<AssetCreator<AssetVertexShader>> CreateVertexShaderLoaderIW4(MemoryManager& memory, ISearchPath& searchPath)
{
return std::make_unique<VertexShaderLoader>(memory, searchPath);
}
} // namespace shader

View File

@@ -1,13 +0,0 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "Game/IW4/IW4.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
namespace shader
{
std::unique_ptr<AssetCreator<IW4::AssetVertexShader>> CreateVertexShaderLoaderIW4(MemoryManager& memory, ISearchPath& searchPath);
} // namespace shader

View File

@@ -9,6 +9,8 @@
#include "Game/T6/Image/ImageLoaderEmbeddedT6.h"
#include "Game/T6/Image/ImageLoaderExternalT6.h"
#include "Game/T6/T6.h"
#include "Game/T6/Techset/PixelShaderLoaderT6.h"
#include "Game/T6/Techset/VertexShaderLoaderT6.h"
#include "Game/T6/XModel/LoaderXModelT6.h"
#include "Image/Dx12TextureLoader.h"
#include "Image/IwiLoader.h"
@@ -29,8 +31,6 @@
#include "Slug/LoaderSlugT6.h"
#include "Sound/LoaderSoundBankT6.h"
#include "StringTable/LoaderStringTableT6.h"
#include "Techset/PixelShaderLoaderT6.h"
#include "Techset/VertexShaderLoaderT6.h"
#include "Tracer/GdtLoaderTracerT6.h"
#include "Tracer/RawLoaderTracerT6.h"
#include "Utils/Logging/Log.h"

View File

@@ -1,55 +0,0 @@
#include "PixelShaderLoaderT6.h"
#include "Game/T6/T6.h"
#include "Shader/ShaderCommon.h"
#include <format>
#include <iostream>
using namespace T6;
namespace
{
class PixelShaderLoader final : public SubAssetCreator<SubAssetPixelShader>
{
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<MaterialPixelShader>();
pixelShader->name = m_memory.Dup(assetName.c_str());
pixelShader->prog.loadDef.programSize = static_cast<decltype(GfxPixelShaderLoadDef::programSize)>(file.m_length);
pixelShader->prog.ps = nullptr;
auto* fileBuffer = m_memory.Alloc<char>(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<SubAssetPixelShader>(assetName, pixelShader));
}
private:
MemoryManager& m_memory;
ISearchPath& m_search_path;
};
} // namespace
namespace techset
{
std::unique_ptr<SubAssetCreator<SubAssetPixelShader>> CreatePixelShaderLoaderT6(MemoryManager& memory, ISearchPath& searchPath)
{
return std::make_unique<PixelShaderLoader>(memory, searchPath);
}
} // namespace techset

View File

@@ -1,13 +0,0 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "Game/T6/T6.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
namespace techset
{
std::unique_ptr<SubAssetCreator<T6::SubAssetPixelShader>> CreatePixelShaderLoaderT6(MemoryManager& memory, ISearchPath& searchPath);
} // namespace techset

View File

@@ -1,55 +0,0 @@
#include "VertexShaderLoaderT6.h"
#include "Game/T6/T6.h"
#include "Shader/ShaderCommon.h"
#include <format>
#include <iostream>
using namespace T6;
namespace
{
class VertexShaderLoader final : public SubAssetCreator<SubAssetVertexShader>
{
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<MaterialVertexShader>();
vertexShader->name = m_memory.Dup(assetName.c_str());
vertexShader->prog.loadDef.programSize = static_cast<decltype(GfxVertexShaderLoadDef::programSize)>(file.m_length);
vertexShader->prog.vs = nullptr;
auto* fileBuffer = m_memory.Alloc<char>(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<SubAssetVertexShader>(assetName, vertexShader));
}
private:
MemoryManager& m_memory;
ISearchPath& m_search_path;
};
} // namespace
namespace techset
{
std::unique_ptr<SubAssetCreator<SubAssetVertexShader>> CreateVertexShaderLoaderT6(MemoryManager& memory, ISearchPath& searchPath)
{
return std::make_unique<VertexShaderLoader>(memory, searchPath);
}
} // namespace techset

View File

@@ -1,13 +0,0 @@
#pragma once
#include "Asset/IAssetCreator.h"
#include "Game/T6/T6.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
namespace techset
{
std::unique_ptr<SubAssetCreator<T6::SubAssetVertexShader>> CreateVertexShaderLoaderT6(MemoryManager& memory, ISearchPath& searchPath);
} // namespace techset

View File

@@ -0,0 +1,117 @@
#options GAME(IW4, T6)
#filename "Game/" + GAME + "/Techset/PixelShaderLoader" + GAME + ".cpp"
#set LOADER_HEADER "\"PixelShaderLoader" + GAME + ".h\""
#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\""
#if GAME == "IW3"
#define FEATURE_IW3
#define IS_DX9
#elif GAME == "IW4"
#define FEATURE_IW4
#define IS_DX9
#elif GAME == "IW5"
#define FEATURE_IW5
#define IS_DX9
#elif GAME == "T5"
#define FEATURE_T5
#define IS_DX9
#elif GAME == "T6"
#define FEATURE_T6
#define IS_DX11
#define IS_SUB_ASSET
#endif
#include LOADER_HEADER
#include GAME_HEADER
#include "Shader/ShaderCommon.h"
#include "Utils/Logging/Log.h"
#include <format>
#include <iostream>
using namespace GAME;
#set LOADER_CLASS_NAME "PixelShaderLoader" + GAME
#if defined(IS_SUB_ASSET)
#define ABSTRACT_CREATOR_NAME SubAssetCreator
#define OVERRIDDEN_CREATOR_METHOD CreateSubAsset
#define ADD_ASSET_METHOD AddSubAsset
#define ASSET_NAME SubAssetPixelShader
#define INTERFACE_NAME ISubAssetCreator
#else
#define ABSTRACT_CREATOR_NAME AssetCreator
#define OVERRIDDEN_CREATOR_METHOD CreateAsset
#define ADD_ASSET_METHOD AddAsset
#define ASSET_NAME AssetPixelShader
#define INTERFACE_NAME IAssetCreator
#endif
namespace
{
class LOADER_CLASS_NAME final : public ABSTRACT_CREATOR_NAME<ASSET_NAME>
{
public:
LOADER_CLASS_NAME(MemoryManager& memory, ISearchPath& searchPath)
: m_memory(memory),
m_search_path(searchPath)
{
}
AssetCreationResult OVERRIDDEN_CREATOR_METHOD(const std::string& assetName, AssetCreationContext& context) override
{
const auto fileName = shader::GetFileNameForPixelShaderAssetName(assetName);
const auto file = m_search_path.Open(fileName);
if (!file.IsOpen())
return AssetCreationResult::NoAction();
#if defined(IS_DX9)
if (file.m_length % sizeof(uint32_t) != 0)
{
con::error("Invalid pixel shader \"{}\": Size must be dividable by {}", assetName, sizeof(uint32_t));
return AssetCreationResult::Failure();
}
#endif
auto* pixelShader = m_memory.Alloc<MaterialPixelShader>();
pixelShader->name = m_memory.Dup(assetName.c_str());
pixelShader->prog.loadDef.programSize = static_cast<decltype(GfxPixelShaderLoadDef::programSize)>(
#if defined(IS_DX9)
file.m_length / sizeof(std::remove_pointer_t<decltype(GfxPixelShaderLoadDef::program)>)
#else
file.m_length
#endif
);
pixelShader->prog.ps = nullptr;
auto* fileBuffer = m_memory.Alloc<char>(static_cast<size_t>(file.m_length));
file.m_stream->read(fileBuffer, file.m_length);
if (file.m_stream->gcount() != file.m_length)
return AssetCreationResult::Failure();
#if defined(IS_DX9)
pixelShader->prog.loadDef.program = reinterpret_cast<decltype(GfxPixelShaderLoadDef::program)>(fileBuffer);
#else
pixelShader->prog.loadDef.program = fileBuffer;
#endif
return AssetCreationResult::Success(context.ADD_ASSET_METHOD<ASSET_NAME>(assetName, pixelShader));
}
private:
MemoryManager& m_memory;
ISearchPath& m_search_path;
};
} // namespace
#set CREATE_LOADER_METHOD "CreatePixelShaderLoader" + GAME
namespace techset
{
std::unique_ptr<INTERFACE_NAME> CREATE_LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath)
{
return std::make_unique<LOADER_CLASS_NAME>(memory, searchPath);
}
} // namespace techset

View File

@@ -0,0 +1,40 @@
#options GAME(IW4, T6)
#filename "Game/" + GAME + "/Techset/PixelShaderLoader" + GAME + ".h"
#if GAME == "IW3"
#define FEATURE_IW3
#elif GAME == "IW4"
#define FEATURE_IW4
#elif GAME == "IW5"
#define FEATURE_IW5
#elif GAME == "T5"
#define FEATURE_T5
#elif GAME == "T6"
#define FEATURE_T6
#endif
// This file was templated.
// See PixelShaderLoader.h.template.
// Do not modify, changes will be lost.
#pragma once
#include "Asset/IAssetCreator.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
#set CREATE_LOADER_METHOD "CreatePixelShaderLoader" + GAME
#if defined(FEATURE_T6)
#define INTERFACE_NAME ISubAssetCreator
#else
#define INTERFACE_NAME IAssetCreator
#endif
namespace techset
{
std::unique_ptr<INTERFACE_NAME> CREATE_LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath);
} // namespace techset

View File

@@ -0,0 +1,118 @@
#options GAME(IW4, T6)
#filename "Game/" + GAME + "/Techset/VertexShaderLoader" + GAME + ".cpp"
#set LOADER_HEADER "\"VertexShaderLoader" + GAME + ".h\""
#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\""
#if GAME == "IW3"
#define FEATURE_IW3
#define IS_DX9
#elif GAME == "IW4"
#define FEATURE_IW4
#define IS_DX9
#elif GAME == "IW5"
#define FEATURE_IW5
#define IS_DX9
#elif GAME == "T5"
#define FEATURE_T5
#define IS_DX9
#elif GAME == "T6"
#define FEATURE_T6
#define IS_DX11
#define IS_SUB_ASSET
#endif
#include LOADER_HEADER
#include GAME_HEADER
#include "Shader/ShaderCommon.h"
#include "Utils/Logging/Log.h"
#include <format>
#include <iostream>
using namespace GAME;
#set LOADER_CLASS_NAME "VertexShaderLoader" + GAME
#if defined(IS_SUB_ASSET)
#define ABSTRACT_CREATOR_NAME SubAssetCreator
#define OVERRIDDEN_CREATOR_METHOD CreateSubAsset
#define ADD_ASSET_METHOD AddSubAsset
#define ASSET_NAME SubAssetVertexShader
#define INTERFACE_NAME ISubAssetCreator
#else
#define ABSTRACT_CREATOR_NAME AssetCreator
#define OVERRIDDEN_CREATOR_METHOD CreateAsset
#define ADD_ASSET_METHOD AddAsset
#define ASSET_NAME AssetVertexShader
#define INTERFACE_NAME IAssetCreator
#endif
namespace
{
class LOADER_CLASS_NAME final : public ABSTRACT_CREATOR_NAME<ASSET_NAME>
{
public:
LOADER_CLASS_NAME(MemoryManager& memory, ISearchPath& searchPath)
: m_memory(memory),
m_search_path(searchPath)
{
}
AssetCreationResult OVERRIDDEN_CREATOR_METHOD(const std::string& assetName, AssetCreationContext& context) override
{
const auto fileName = shader::GetFileNameForVertexShaderAssetName(assetName);
const auto file = m_search_path.Open(fileName);
if (!file.IsOpen())
return AssetCreationResult::NoAction();
#if defined(IS_DX9)
if (file.m_length % sizeof(uint32_t) != 0)
{
con::error("Invalid vertex shader \"{}\": Size must be dividable by {}", assetName, sizeof(uint32_t));
return AssetCreationResult::Failure();
}
#endif
auto* vertexShader = m_memory.Alloc<MaterialVertexShader>();
vertexShader->name = m_memory.Dup(assetName.c_str());
vertexShader->prog.loadDef.programSize = static_cast<decltype(GfxVertexShaderLoadDef::programSize)>(
#if defined(IS_DX9)
file.m_length / sizeof(std::remove_pointer_t<decltype(GfxVertexShaderLoadDef::program)>)
#else
file.m_length
#endif
);
vertexShader->prog.vs = nullptr;
auto* fileBuffer = m_memory.Alloc<char>(static_cast<size_t>(file.m_length));
file.m_stream->read(fileBuffer, file.m_length);
if (file.m_stream->gcount() != file.m_length)
return AssetCreationResult::Failure();
#if defined(IS_DX9)
vertexShader->prog.loadDef.program = reinterpret_cast<decltype(GfxVertexShaderLoadDef::program)>(fileBuffer);
#else
vertexShader->prog.loadDef.program = fileBuffer;
#endif
return AssetCreationResult::Success(context.ADD_ASSET_METHOD<ASSET_NAME>(assetName, vertexShader));
}
private:
MemoryManager& m_memory;
ISearchPath& m_search_path;
};
} // namespace
#set CREATE_LOADER_METHOD "CreateVertexShaderLoader" + GAME
namespace techset
{
std::unique_ptr<INTERFACE_NAME> CREATE_LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath)
{
return std::make_unique<LOADER_CLASS_NAME>(memory, searchPath);
}
} // namespace techset

View File

@@ -0,0 +1,40 @@
#options GAME(IW4, T6)
#filename "Game/" + GAME + "/Techset/VertexShaderLoader" + GAME + ".h"
#if GAME == "IW3"
#define FEATURE_IW3
#elif GAME == "IW4"
#define FEATURE_IW4
#elif GAME == "IW5"
#define FEATURE_IW5
#elif GAME == "T5"
#define FEATURE_T5
#elif GAME == "T6"
#define FEATURE_T6
#endif
// This file was templated.
// See VertexShaderLoader.h.template.
// Do not modify, changes will be lost.
#pragma once
#include "Asset/IAssetCreator.h"
#include "SearchPath/ISearchPath.h"
#include "Utils/MemoryManager.h"
#include <memory>
#set CREATE_LOADER_METHOD "CreateVertexShaderLoader" + GAME
#if defined(FEATURE_T6)
#define INTERFACE_NAME ISubAssetCreator
#else
#define INTERFACE_NAME IAssetCreator
#endif
namespace techset
{
std::unique_ptr<INTERFACE_NAME> CREATE_LOADER_METHOD(MemoryManager& memory, ISearchPath& searchPath);
} // namespace techset

View File

@@ -1,6 +1,9 @@
#include "ObjWriterIW4.h"
#include "Game/IW4/Material/MaterialJsonDumperIW4.h"
#include "Game/IW4/Techset/PixelShaderDumperIW4.h"
#include "Game/IW4/Techset/TechsetDumperIW4.h"
#include "Game/IW4/Techset/VertexShaderDumperIW4.h"
#include "Game/IW4/XModel/XModelDumperIW4.h"
#include "Image/ImageDumperIW4.h"
#include "Leaderboard/LeaderboardJsonDumperIW4.h"
@@ -13,13 +16,10 @@
#include "PhysCollmap/PhysCollmapDumperIW4.h"
#include "PhysPreset/PhysPresetInfoStringDumperIW4.h"
#include "RawFile/RawFileDumperIW4.h"
#include "Shader/PixelShaderDumperIW4.h"
#include "Shader/VertexShaderDumperIW4.h"
#include "Sound/LoadedSoundDumperIW4.h"
#include "Sound/SndCurveDumperIW4.h"
#include "StringTable/StringTableDumperIW4.h"
#include "StructuredDataDef/StructuredDataDefDumperIW4.h"
#include "Techset/TechsetDumperIW4.h"
#include "Tracer/TracerDumperIW4.h"
#include "Vehicle/VehicleDumperIW4.h"
#include "Weapon/WeaponDumperIW4.h"
@@ -36,9 +36,15 @@ void ObjWriter::RegisterAssetDumpers(AssetDumpingContext& context)
#ifdef EXPERIMENTAL_MATERIAL_COMPILATION
RegisterAssetDumper(std::make_unique<material::DecompilingGdtDumperIW4>());
#endif
RegisterAssetDumper(std::make_unique<shader::PixelShaderDumperIW4>());
RegisterAssetDumper(std::make_unique<shader::VertexShaderDumperIW4>());
RegisterAssetDumper(std::make_unique<techset::DumperIW4>());
RegisterAssetDumper(std::make_unique<techset::PixelShaderDumperIW4>());
RegisterAssetDumper(std::make_unique<techset::VertexShaderDumperIW4>());
RegisterAssetDumper(std::make_unique<techset::DumperIW4>(
#ifdef TECHSET_DEBUG
true
#else
false
#endif
));
RegisterAssetDumper(std::make_unique<image::DumperIW4>());
// REGISTER_DUMPER(AssetDumpersnd_alias_list_t)
RegisterAssetDumper(std::make_unique<sound_curve::DumperIW4>());

View File

@@ -1,20 +0,0 @@
#include "PixelShaderDumperIW4.h"
#include "Shader/ShaderCommon.h"
using namespace IW4;
namespace shader
{
void PixelShaderDumperIW4::DumpAsset(AssetDumpingContext& context, const XAssetInfo<AssetPixelShader::Type>& asset)
{
const auto* pixelShader = asset.Asset();
const auto shaderFile = context.OpenAssetFile(shader::GetFileNameForPixelShaderAssetName(asset.m_name));
if (!shaderFile)
return;
shaderFile->write(reinterpret_cast<const char*>(pixelShader->prog.loadDef.program),
static_cast<std::streamsize>(pixelShader->prog.loadDef.programSize) * 4u);
}
} // namespace shader

View File

@@ -1,13 +0,0 @@
#pragma once
#include "Dumping/AbstractAssetDumper.h"
#include "Game/IW4/IW4.h"
namespace shader
{
class PixelShaderDumperIW4 final : public AbstractAssetDumper<IW4::AssetPixelShader>
{
protected:
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<IW4::AssetPixelShader::Type>& asset) override;
};
} // namespace shader

View File

@@ -1,20 +0,0 @@
#include "VertexShaderDumperIW4.h"
#include "Shader/ShaderCommon.h"
using namespace IW4;
namespace shader
{
void VertexShaderDumperIW4::DumpAsset(AssetDumpingContext& context, const XAssetInfo<AssetVertexShader::Type>& asset)
{
const auto* vertexShader = asset.Asset();
const auto shaderFile = context.OpenAssetFile(shader::GetFileNameForVertexShaderAssetName(asset.m_name));
if (!shaderFile)
return;
shaderFile->write(reinterpret_cast<const char*>(vertexShader->prog.loadDef.program),
static_cast<std::streamsize>(vertexShader->prog.loadDef.programSize) * 4u);
}
} // namespace shader

View File

@@ -1,13 +0,0 @@
#pragma once
#include "Dumping/AbstractAssetDumper.h"
#include "Game/IW4/IW4.h"
namespace shader
{
class VertexShaderDumperIW4 final : public AbstractAssetDumper<IW4::AssetVertexShader>
{
protected:
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<IW4::AssetVertexShader::Type>& asset) override;
};
} // namespace shader

View File

@@ -1,510 +0,0 @@
#include "TechsetDumperIW4.h"
#include "Dumping/AbstractTextDumper.h"
#include "Game/IW4/Techset/TechsetConstantsIW4.h"
#include "Pool/GlobalAssetPool.h"
#include "Shader/D3D9ShaderAnalyser.h"
#include "Techset/CommonTechset.h"
#include "Techset/CommonTechsetDumper.h"
#include "Techset/TechniqueDumpingZoneState.h"
#include "Techset/TechsetCommon.h"
#include "Utils/Logging/Log.h"
#include <algorithm>
#include <cassert>
#include <format>
#include <set>
#include <sstream>
#include <type_traits>
using namespace IW4;
namespace
{
class TechniqueFileWriter : public AbstractTextDumper
{
void DumpStateMap() const
{
Indent();
// TODO: Actual statemap: Maybe find all materials using this techset and try to make out rules for the flags based on the statebitstable
m_stream << "stateMap \"passthrough\"; // TODO\n";
}
static bool FindCodeConstantSourceAccessor(const MaterialConstantSource sourceIndexToFind,
const CodeConstantSource* codeConstantTable,
std::string& codeSourceAccessor)
{
const auto* currentCodeConst = codeConstantTable;
while (currentCodeConst->name != nullptr)
{
if (currentCodeConst->subtable != nullptr)
{
std::string accessorInSubTable;
if (FindCodeConstantSourceAccessor(sourceIndexToFind, currentCodeConst->subtable, accessorInSubTable))
{
std::ostringstream ss;
ss << currentCodeConst->name << '.' << accessorInSubTable;
codeSourceAccessor = ss.str();
return true;
}
}
else if (currentCodeConst->arrayCount > 0)
{
if (currentCodeConst->source <= sourceIndexToFind
&& static_cast<unsigned>(currentCodeConst->source) + currentCodeConst->arrayCount > static_cast<unsigned>(sourceIndexToFind))
{
std::ostringstream ss;
ss << currentCodeConst->name << '[' << (static_cast<unsigned>(sourceIndexToFind) - static_cast<unsigned>(currentCodeConst->source))
<< ']';
codeSourceAccessor = ss.str();
return true;
}
}
else if (currentCodeConst->source == sourceIndexToFind)
{
codeSourceAccessor = currentCodeConst->name;
return true;
}
currentCodeConst++;
}
return false;
}
static bool FindCodeSamplerSourceAccessor(const MaterialTextureSource sourceIndexToFind,
const CodeSamplerSource* codeSamplerTable,
std::string& codeSourceAccessor)
{
const auto* currentCodeConst = codeSamplerTable;
while (currentCodeConst->name != nullptr)
{
if (currentCodeConst->subtable != nullptr)
{
std::string accessorInSubTable;
if (FindCodeSamplerSourceAccessor(sourceIndexToFind, currentCodeConst->subtable, accessorInSubTable))
{
std::ostringstream ss;
ss << currentCodeConst->name << '.' << accessorInSubTable;
codeSourceAccessor = ss.str();
return true;
}
}
else if (currentCodeConst->arrayCount > 0)
{
if (currentCodeConst->source <= sourceIndexToFind
&& static_cast<unsigned>(currentCodeConst->source) + currentCodeConst->arrayCount > static_cast<unsigned>(sourceIndexToFind))
{
std::ostringstream ss;
ss << currentCodeConst->name << '[' << (static_cast<unsigned>(sourceIndexToFind) - static_cast<unsigned>(currentCodeConst->source))
<< ']';
codeSourceAccessor = ss.str();
return true;
}
}
else if (currentCodeConst->source == sourceIndexToFind)
{
codeSourceAccessor = currentCodeConst->name;
return true;
}
currentCodeConst++;
}
return false;
}
void DumpShaderArg(const MaterialShaderArgument& arg, const d3d9::ShaderInfo& shaderInfo) const
{
const auto expectedRegisterSet =
arg.type == MTL_ARG_CODE_PIXEL_SAMPLER || arg.type == MTL_ARG_MATERIAL_PIXEL_SAMPLER ? d3d9::RegisterSet::SAMPLER : d3d9::RegisterSet::FLOAT_4;
const auto targetShaderArg = std::ranges::find_if(shaderInfo.m_constants,
[arg, expectedRegisterSet](const d3d9::ShaderConstant& constant)
{
return constant.m_register_set == expectedRegisterSet && constant.m_register_index <= arg.dest
&& constant.m_register_index + constant.m_register_count > arg.dest;
});
assert(targetShaderArg != shaderInfo.m_constants.end());
if (targetShaderArg == shaderInfo.m_constants.end())
{
m_stream << "// Unrecognized arg dest:" << arg.dest << " type: " << arg.type << "\n";
return;
}
std::string codeDestAccessor;
if (targetShaderArg->m_type_elements > 1)
{
std::ostringstream ss;
ss << targetShaderArg->m_name << '[' << (arg.dest - targetShaderArg->m_register_index) << ']';
codeDestAccessor = ss.str();
}
else
codeDestAccessor = targetShaderArg->m_name;
if (arg.type == MTL_ARG_CODE_VERTEX_CONST || arg.type == MTL_ARG_CODE_PIXEL_CONST)
{
const auto sourceIndex = static_cast<MaterialConstantSource>(arg.u.codeConst.index);
std::string codeSourceAccessor;
if (FindCodeConstantSourceAccessor(sourceIndex, s_codeConsts, codeSourceAccessor)
|| FindCodeConstantSourceAccessor(sourceIndex, s_defaultCodeConsts, codeSourceAccessor))
{
if (codeDestAccessor != codeSourceAccessor)
{
Indent();
m_stream << codeDestAccessor << " = constant." << codeSourceAccessor << ";\n";
}
else
{
#ifdef TECHSET_DEBUG
Indent();
m_stream << "// Omitted due to matching accessors: " << codeDestAccessor << " = constant." << codeSourceAccessor << ";\n";
#endif
}
}
else
{
assert(false);
Indent();
m_stream << codeDestAccessor << " = UNKNOWN;\n";
}
}
else if (arg.type == MTL_ARG_CODE_PIXEL_SAMPLER)
{
const auto sourceIndex = static_cast<MaterialTextureSource>(arg.u.codeSampler);
std::string codeSourceAccessor;
if (FindCodeSamplerSourceAccessor(sourceIndex, s_codeSamplers, codeSourceAccessor)
|| FindCodeSamplerSourceAccessor(sourceIndex, s_defaultCodeSamplers, codeSourceAccessor))
{
if (codeDestAccessor != codeSourceAccessor)
{
Indent();
m_stream << codeDestAccessor << " = sampler." << codeSourceAccessor << ";\n";
}
else
{
#ifdef TECHSET_DEBUG
Indent();
m_stream << "// Omitted due to matching accessors: " << codeDestAccessor << " = sampler." << codeSourceAccessor << ";\n";
#endif
}
}
else
{
assert(false);
Indent();
m_stream << codeDestAccessor << " = UNKNOWN;\n";
}
}
else if (arg.type == MTL_ARG_LITERAL_VERTEX_CONST || arg.type == MTL_ARG_LITERAL_PIXEL_CONST)
{
if (arg.u.literalConst)
{
Indent();
m_stream << codeDestAccessor << " = float4( " << (*arg.u.literalConst)[0] << ", " << (*arg.u.literalConst)[1] << ", "
<< (*arg.u.literalConst)[2] << ", " << (*arg.u.literalConst)[3] << " );\n";
}
}
else if (arg.type == MTL_ARG_MATERIAL_PIXEL_CONST || arg.type == MTL_ARG_MATERIAL_VERTEX_CONST || arg.type == MTL_ARG_MATERIAL_PIXEL_SAMPLER)
{
Indent();
m_stream << codeDestAccessor << " = material.";
const auto knownConstantName = knownConstantNames.find(arg.u.nameHash);
if (knownConstantName != knownConstantNames.end())
{
m_stream << knownConstantName->second;
}
else
{
const auto knownMaterialTextureName = knownTextureMaps.find(arg.u.nameHash);
if (knownMaterialTextureName != knownTextureMaps.end())
{
m_stream << knownMaterialTextureName->second.m_name;
}
else
{
const auto shaderArgNameHash = Common::R_HashString(targetShaderArg->m_name.c_str(), 0u);
if (shaderArgNameHash == arg.u.nameHash)
m_stream << targetShaderArg->m_name;
else
m_stream << "#0x" << std::hex << arg.u.nameHash;
}
}
m_stream << ";\n";
}
else
{
assert(false);
}
}
void DumpVertexShader(const MaterialPass& pass)
{
auto vertexShader = pass.vertexShader;
if (vertexShader == nullptr || vertexShader->name == nullptr)
return;
if (vertexShader->name[0] == ',')
{
const auto loadedVertexShaderFromOtherZone =
GameGlobalAssetPools::GetGlobalPoolsForGame(GameId::IW4)->GetAsset<AssetVertexShader>(&vertexShader->name[1]);
if (loadedVertexShaderFromOtherZone == nullptr)
{
// Cannot dump when shader is referenced due to unknown constant names and unknown version
Indent();
con::error("Cannot dump vertex shader {} due to being a referenced asset", &vertexShader->name[1]);
m_stream << std::format("// Cannot dump vertex shader {} due to being a referenced asset\n", &vertexShader->name[1]);
return;
}
vertexShader = loadedVertexShaderFromOtherZone->Asset();
}
const auto vertexShaderInfo =
d3d9::ShaderAnalyser::GetShaderInfo(vertexShader->prog.loadDef.program, vertexShader->prog.loadDef.programSize * sizeof(uint32_t));
assert(vertexShaderInfo);
if (!vertexShaderInfo)
return;
m_stream << "\n";
Indent();
m_stream << "vertexShader " << vertexShaderInfo->m_version_major << "." << vertexShaderInfo->m_version_minor << " \"" << vertexShader->name
<< "\"\n";
Indent();
m_stream << "{\n";
IncIndent();
if (pass.args)
{
const auto totalArgCount =
static_cast<size_t>(pass.perPrimArgCount) + static_cast<size_t>(pass.perObjArgCount) + static_cast<size_t>(pass.stableArgCount);
for (auto i = 0u; i < totalArgCount; i++)
{
const auto& arg = pass.args[i];
if (arg.type == MTL_ARG_MATERIAL_VERTEX_CONST || arg.type == MTL_ARG_LITERAL_VERTEX_CONST || arg.type == MTL_ARG_CODE_VERTEX_CONST)
{
DumpShaderArg(arg, *vertexShaderInfo);
}
}
}
DecIndent();
Indent();
m_stream << "}\n";
}
void DumpPixelShader(const MaterialPass& pass)
{
auto pixelShader = pass.pixelShader;
if (pixelShader == nullptr || pixelShader->name == nullptr)
return;
if (pixelShader->name[0] == ',')
{
const auto loadedPixelShaderFromOtherZone =
GameGlobalAssetPools::GetGlobalPoolsForGame(GameId::IW4)->GetAsset<AssetPixelShader>(&pixelShader->name[1]);
if (loadedPixelShaderFromOtherZone == nullptr)
{
// Cannot dump when shader is referenced due to unknown constant names and unknown version
Indent();
con::error("Cannot dump pixel shader {} due to being a referenced asset", &pixelShader->name[1]);
m_stream << std::format("// Cannot dump pixel shader {} due to being a referenced asset\n", &pixelShader->name[1]);
return;
}
pixelShader = loadedPixelShaderFromOtherZone->Asset();
}
const auto pixelShaderInfo =
d3d9::ShaderAnalyser::GetShaderInfo(pixelShader->prog.loadDef.program, pixelShader->prog.loadDef.programSize * sizeof(uint32_t));
assert(pixelShaderInfo);
if (!pixelShaderInfo)
return;
m_stream << "\n";
Indent();
m_stream << "pixelShader " << pixelShaderInfo->m_version_major << "." << pixelShaderInfo->m_version_minor << " \"" << pixelShader->name << "\"\n";
Indent();
m_stream << "{\n";
IncIndent();
if (pass.args)
{
const auto totalArgCount =
static_cast<size_t>(pass.perPrimArgCount) + static_cast<size_t>(pass.perObjArgCount) + static_cast<size_t>(pass.stableArgCount);
for (auto i = 0u; i < totalArgCount; i++)
{
const auto& arg = pass.args[i];
if (arg.type == MTL_ARG_MATERIAL_PIXEL_SAMPLER || arg.type == MTL_ARG_CODE_PIXEL_SAMPLER || arg.type == MTL_ARG_CODE_PIXEL_CONST
|| arg.type == MTL_ARG_MATERIAL_PIXEL_CONST || arg.type == MTL_ARG_LITERAL_PIXEL_CONST)
{
DumpShaderArg(arg, *pixelShaderInfo);
}
}
}
DecIndent();
Indent();
m_stream << "}\n";
}
static const char* GetStreamDestinationString(const MaterialStreamDestination_e dst)
{
const auto dstIndex = static_cast<size_t>(dst);
assert(dstIndex < std::extent_v<decltype(materialStreamDestinationNames)>);
if (dstIndex < std::extent_v<decltype(materialStreamDestinationNames)>)
return materialStreamDestinationNames[dstIndex];
return "";
}
static const char* GetStreamSourceString(const MaterialStreamStreamSource_e src)
{
const auto srcIndex = static_cast<size_t>(src);
assert(srcIndex < std::extent_v<decltype(materialStreamSourceNames)>);
if (srcIndex < std::extent_v<decltype(materialStreamSourceNames)>)
return materialStreamSourceNames[srcIndex];
return "";
}
void DumpVertexDecl(const MaterialPass& pass)
{
const auto* vertexDecl = pass.vertexDecl;
if (vertexDecl == nullptr)
return;
if (vertexDecl->name && vertexDecl->name[0] == ',')
{
const auto loadedVertexDeclFromOtherZone =
GameGlobalAssetPools::GetGlobalPoolsForGame(GameId::IW4)->GetAsset<AssetVertexDecl>(&vertexDecl->name[1]);
if (loadedVertexDeclFromOtherZone == nullptr)
{
// Cannot dump when shader is referenced due to unknown constant names and unknown version
Indent();
con::error("Cannot dump vertex decl {} due to being a referenced asset", &vertexDecl->name[1]);
m_stream << std::format("// Cannot dump vertex decl {} due to being a referenced asset\n", &vertexDecl->name[1]);
return;
}
vertexDecl = loadedVertexDeclFromOtherZone->Asset();
}
m_stream << "\n";
#ifdef TECHSET_DEBUG
Indent();
m_stream << "// Decl: " << vertexDecl->name << "\n";
#endif
const auto streamCount = std::min(static_cast<size_t>(vertexDecl->streamCount), std::extent_v<decltype(MaterialVertexStreamRouting::data)>);
for (auto streamIndex = 0u; streamIndex < streamCount; streamIndex++)
{
const auto& stream = vertexDecl->routing.data[streamIndex];
Indent();
m_stream << "vertex." << GetStreamDestinationString(static_cast<MaterialStreamDestination_e>(stream.dest)) << " = code."
<< GetStreamSourceString(static_cast<MaterialStreamStreamSource_e>(stream.source)) << ";\n";
}
}
void DumpPass(const MaterialPass& pass)
{
m_stream << "{\n";
IncIndent();
#ifdef TECHSET_DEBUG
for (auto i = 0u; i < 8; i++)
{
const auto mask = 1u << i;
if (pass.customSamplerFlags & mask)
{
Indent();
m_stream << "// CUSTOM SAMPLER FLAGS: 0x" << std::hex << mask << "\n";
}
}
#endif
DumpStateMap();
DumpVertexShader(pass);
DumpPixelShader(pass);
DumpVertexDecl(pass);
DecIndent();
m_stream << "}\n";
}
public:
explicit TechniqueFileWriter(std::ostream& stream)
: AbstractTextDumper(stream)
{
}
void DumpTechnique(const MaterialTechnique* technique)
{
#ifdef TECHSET_DEBUG
if (technique->flags)
{
for (auto i = 0u; i < 16; i++)
{
const auto mask = 1u << i;
if (technique->flags & mask)
{
Indent();
m_stream << "// TECHNIQUE FLAGS: 0x" << std::hex << mask << "\n";
}
}
}
#endif
for (auto i = 0u; i < technique->passCount; i++)
DumpPass(technique->passArray[i]);
}
};
techset::CommonTechset ConvertToCommonTechset(const MaterialTechniqueSet& techset)
{
std::vector<std::string> techniqueNames(std::extent_v<decltype(techniqueTypeNames)>);
for (auto techniqueIndex = 0u; techniqueIndex < std::extent_v<decltype(techniqueTypeNames)>; techniqueIndex++)
{
const auto* technique = techset.techniques[techniqueIndex];
if (technique && technique->name)
techniqueNames[techniqueIndex] = technique->name;
}
return techset::CommonTechset(techset.name, std::move(techniqueNames));
}
void DumpTechset(const AssetDumpingContext& context, const MaterialTechniqueSet& techset)
{
static techset::CommonTechniqueTypeNames commonNames(techniqueTypeNames, std::extent_v<decltype(techniqueTypeNames)>);
const auto commonTechset = ConvertToCommonTechset(techset);
techset::DumpCommonTechset(commonNames, context, commonTechset);
}
} // namespace
namespace techset
{
void DumperIW4::DumpAsset(AssetDumpingContext& context, const XAssetInfo<AssetTechniqueSet::Type>& asset)
{
const auto* techniqueSet = asset.Asset();
DumpTechset(context, *techniqueSet);
auto* techniqueState = context.GetZoneAssetDumperState<TechniqueDumpingZoneState>();
for (const auto* technique : techniqueSet->techniques)
{
if (technique && techniqueState->ShouldDumpTechnique(technique))
{
const auto techniqueFile = context.OpenAssetFile(GetFileNameForTechniqueName(technique->name));
if (techniqueFile)
{
TechniqueFileWriter writer(*techniqueFile);
writer.DumpTechnique(technique);
}
}
}
}
} // namespace techset

View File

@@ -1,13 +0,0 @@
#pragma once
#include "Dumping/AbstractAssetDumper.h"
#include "Game/IW4/IW4.h"
namespace techset
{
class DumperIW4 final : public AbstractAssetDumper<IW4::AssetTechniqueSet>
{
protected:
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<IW4::AssetTechniqueSet::Type>& asset) override;
};
} // namespace techset

View File

@@ -2,6 +2,7 @@
#include "FontIcon/FontIconDumperT6.h"
#include "Game/T6/Material/MaterialJsonDumperT6.h"
#include "Game/T6/Techset/TechsetDumperT6.h"
#include "Game/T6/XModel/XModelDumperT6.h"
#include "Image/ImageDumperT6.h"
#include "Leaderboard/LeaderboardJsonDumperT6.h"
@@ -16,7 +17,6 @@
#include "Sound/SndBankDumperT6.h"
#include "Sound/SndDriverGlobalsDumperT6.h"
#include "StringTable/StringTableDumperT6.h"
#include "Techset/TechsetDumperT6.h"
#include "Tracer/TracerDumperT6.h"
#include "Vehicle/VehicleDumperT6.h"
#include "Weapon/AttachmentDumperT6.h"

View File

@@ -1,21 +0,0 @@
#pragma once
#include "Dumping/AbstractAssetDumper.h"
#include "Game/T6/T6.h"
namespace techset
{
class DumperT6 final : public AbstractAssetDumper<T6::AssetTechniqueSet>
{
public:
explicit DumperT6(bool debug);
void Dump(AssetDumpingContext& context) override;
protected:
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<T6::AssetTechniqueSet::Type>& asset) override;
private:
bool m_debug;
};
} // namespace techset

View File

@@ -102,8 +102,9 @@ namespace
{
if (!shader.m_name.empty())
{
Indent();
m_stream << std::format("// ERROR: Cannot dump shader {} as its data is not loaded\n", shader.m_name);
con::error("Technique {}: Cannot dump shader {} as its data is not loaded\n", technique.m_name, shader.m_name);
con::error("Technique {}: Cannot dump shader {} as its data is not loaded", technique.m_name, shader.m_name);
}
return;
@@ -201,7 +202,7 @@ namespace
codeDestAccessor = targetShaderArg->m_name;
const auto isTransposed = targetShaderArg->m_class == d3d9::ParameterClass::MATRIX_COLUMNS;
DumpShaderArg(technique, arg, codeDestAccessor, isTransposed);
DumpShaderArg(technique, arg, codeDestAccessor, isTransposed, targetShaderArg->m_register_count);
}
void DumpShaderArgDx11(const CommonTechnique& technique, const CommonShaderArg& arg, const d3d11::ShaderInfo& shaderInfo) const
@@ -283,7 +284,8 @@ namespace
}
const auto isTransposed = variable->m_variable_class == d3d11::VariableClass::MATRIX_COLUMNS;
DumpShaderArg(technique, arg, codeDestAccessor, isTransposed);
DumpShaderArg(technique, arg, codeDestAccessor, isTransposed, variable->m_row_count);
}
else
{
@@ -314,11 +316,15 @@ namespace
static_cast<unsigned>(arg.m_type.m_value_type));
return;
}
DumpShaderArg(technique, arg, boundTextureResource->m_name, false);
DumpShaderArg(technique, arg, boundTextureResource->m_name, false, 0);
}
}
void DumpShaderArg(const CommonTechnique& technique, const CommonShaderArg& arg, std::string codeDestAccessor, const bool isTransposed) const
void DumpShaderArg(const CommonTechnique& technique,
const CommonShaderArg& arg,
std::string codeDestAccessor,
const bool isTransposed,
const size_t shaderRowCount) const
{
if (arg.m_type.m_value_type == CommonShaderValueType::CODE_CONST)
{
@@ -340,9 +346,10 @@ namespace
else
codeAccessor = std::format("{}[{}]", constSourceInfo->accessor, arg.m_value.code_const_source.m_index - constSourceInfo->value);
// Assert that the value uses 4 rows when matrix and 1 otherwise.
// If this is untrue, there must be more code handling the selected rows
assert((isMatrix && arg.m_value.code_const_source.m_row_count == 4) || arg.m_value.code_const_source.m_row_count == 1);
// Assert that when a code const is not a matrix, the game uses one row of it per arg
// If it is a matrix, the game uses as many rows as can be seen in the shader
assert(isMatrix || arg.m_value.code_const_source.m_row_count == 1);
assert(!isMatrix || arg.m_value.code_const_source.m_row_count == shaderRowCount);
if (codeDestAccessor != codeAccessor)
{

View File

@@ -0,0 +1,46 @@
#options GAME(IW4)
#filename "Game/" + GAME + "/Techset/PixelShaderDumper" + GAME + ".cpp"
#set DUMPER_HEADER "\"PixelShaderDumper" + GAME + ".h\""
#if GAME == "IW3"
#define FEATURE_IW3
#define IS_DX9
#elif GAME == "IW4"
#define FEATURE_IW4
#define IS_DX9
#elif GAME == "IW5"
#define FEATURE_IW5
#define IS_DX9
#endif
// This file was templated.
// See PixelShaderDumper.cpp.template.
// Do not modify, changes will be lost.
#include DUMPER_HEADER
#include "Shader/ShaderCommon.h"
#include <type_traits>
using namespace GAME;
#set CLASS_NAME "PixelShaderDumper" + GAME
namespace techset
{
void CLASS_NAME::DumpAsset(AssetDumpingContext& context, const XAssetInfo<AssetPixelShader::Type>& asset)
{
const auto& shader = *asset.Asset();
const auto shaderFile = context.OpenAssetFile(shader::GetFileNameForPixelShaderAssetName(shader.name));
if (!shaderFile)
return;
shaderFile->write(reinterpret_cast<const char*>(shader.prog.loadDef.program),
static_cast<std::streamsize>(shader.prog.loadDef.programSize)
* sizeof(std::remove_pointer_t<decltype(GfxPixelShaderLoadDef::program)>));
}
} // namespace techset

View File

@@ -0,0 +1,25 @@
#options GAME(IW4)
#filename "Game/" + GAME + "/Techset/PixelShaderDumper" + GAME + ".h"
#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\""
// This file was templated.
// See PixelShaderDumper.h.template.
// Do not modify, changes will be lost.
#pragma once
#include "Dumping/AbstractAssetDumper.h"
#include GAME_HEADER
#set CLASS_NAME "PixelShaderDumper" + GAME
namespace techset
{
class CLASS_NAME final : public AbstractAssetDumper<GAME::AssetPixelShader>
{
protected:
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<GAME::AssetPixelShader::Type>& asset) override;
};
} // namespace techset

View File

@@ -1,19 +1,56 @@
#include "TechsetDumperT6.h"
#options GAME(IW4, T6)
#include "Game/T6/Material/MaterialConstantZoneStateT6.h"
#include "Game/T6/Techset/TechsetConstantsT6.h"
#include "Shader/ShaderCommon.h"
#filename "Game/" + GAME + "/Techset/TechsetDumper" + GAME + ".cpp"
#set DUMPER_HEADER "\"TechsetDumper" + GAME + ".h\""
#set MATERIAL_CONSTANT_ZONE_STATE_HEADER "\"Game/" + GAME + "/Material/MaterialConstantZoneState" + GAME + ".h\""
#set TECHSET_CONSTANTS_HEADER "\"Game/" + GAME + "/Techset/TechsetConstants" + GAME + ".h\""
#if GAME == "IW3"
#define FEATURE_IW3
#define IS_DX9
#elif GAME == "IW4"
#define FEATURE_IW4
#define IS_DX9
#elif GAME == "IW5"
#define FEATURE_IW5
#define IS_DX9
#elif GAME == "T5"
#define FEATURE_T5
#define IS_DX9
#elif GAME == "T6"
#define FEATURE_T6
#define IS_DX11
#define DUMP_SHADERS "1"
#endif
// This file was templated.
// See TechsetDumper.cpp.template.
// Do not modify, changes will be lost.
#include DUMPER_HEADER
#include MATERIAL_CONSTANT_ZONE_STATE_HEADER
#include TECHSET_CONSTANTS_HEADER
#include "Pool/GlobalAssetPool.h"
#include "Techset/CommonTechniqueDumper.h"
#include "Techset/CommonTechsetDumper.h"
#include "Techset/ShaderDumpingZoneState.h"
#include "Techset/CommonVertexDeclCreator.h"
#include "Techset/TechniqueDumpingZoneState.h"
#if defined(DUMP_SHADERS)
#include "Shader/ShaderCommon.h"
#include "Techset/ShaderDumpingZoneState.h"
#endif
#include <cassert>
#include <format>
using namespace T6;
using namespace GAME;
namespace
{
#if defined(DUMP_SHADERS)
void DumpPixelShader(const AssetDumpingContext& context, const MaterialPixelShader& pixelShader)
{
const auto shaderFile = context.OpenAssetFile(shader::GetFileNameForPixelShaderAssetName(pixelShader.name));
@@ -21,7 +58,12 @@ namespace
if (!shaderFile)
return;
#if defined(FEATURE_T6)
shaderFile->write(pixelShader.prog.loadDef.program, pixelShader.prog.loadDef.programSize);
#else
shaderFile->write(reinterpret_cast<const char*>(pixelShader.prog.loadDef.program),
static_cast<std::streamsize>(pixelShader.prog.loadDef.programSize) * sizeof(GfxPixelShaderLoadDef::program));
#endif
}
void DumpVertexShader(const AssetDumpingContext& context, const MaterialVertexShader& vertexShader)
@@ -31,7 +73,12 @@ namespace
if (!shaderFile)
return;
#if defined(FEATURE_T6)
shaderFile->write(vertexShader.prog.loadDef.program, vertexShader.prog.loadDef.programSize);
#else
shaderFile->write(reinterpret_cast<const char*>(vertexShader.prog.loadDef.program),
static_cast<std::streamsize>(vertexShader.prog.loadDef.programSize) * sizeof(GfxVertexShaderLoadDef::program));
#endif
}
void DumpShaders(AssetDumpingContext& context, const MaterialTechniqueSet& techset)
@@ -55,12 +102,17 @@ namespace
}
}
}
#endif
techset::CommonVertexDeclaration ConvertToCommonVertexDeclaration(const MaterialVertexDeclaration* vertexDecl)
{
std::vector<techset::CommonStreamRouting> commonRouting;
#if defined(FEATURE_IW4)
if (vertexDecl && vertexDecl->name && vertexDecl->name[0] != ',')
#else
if (vertexDecl)
#endif
{
const auto streamCount = std::min(static_cast<size_t>(vertexDecl->streamCount), std::extent_v<decltype(MaterialVertexStreamRouting::data)>);
for (auto streamIndex = 0u; streamIndex < streamCount; streamIndex++)
@@ -70,12 +122,24 @@ namespace
static_cast<techset::CommonStreamDestination>(routing.dest));
}
}
#if defined(FEATURE_IW4)
else if (vertexDecl && vertexDecl->name)
{
auto result = techset::CreateVertexDeclFromName(&vertexDecl->name[1], commonRoutingInfos);
if (result.has_value())
return std::move(*result);
}
#endif
return techset::CommonVertexDeclaration(std::move(commonRouting));
}
techset::CommonShaderArg ConvertToCommonArg(const MaterialShaderArgument& arg)
{
#if defined(IS_DX9)
const techset::CommonShaderArgDestination destination = {.dx9 = {.m_destination_register = arg.dest}};
#endif
switch (arg.type)
{
case MTL_ARG_CODE_VERTEX_CONST:
@@ -87,6 +151,7 @@ namespace
.m_row_count = arg.u.codeConst.rowCount,
};
const techset::CommonShaderArgValue value{.code_const_source = codeConstValue};
#if defined(IS_DX11)
const techset::CommonShaderArgLocationDx11 location{
.constant_buffer_offset = arg.location.offset,
};
@@ -97,6 +162,7 @@ namespace
.m_buffer = arg.buffer,
}
};
#endif
return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value);
}
@@ -107,6 +173,7 @@ namespace
const techset::CommonShaderArgValue value{
.name_hash = arg.u.nameHash,
};
#if defined(IS_DX11)
const techset::CommonShaderArgLocationDx11 location{
.constant_buffer_offset = arg.location.offset,
};
@@ -117,6 +184,7 @@ namespace
.m_buffer = arg.buffer,
}
};
#endif
return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value);
}
@@ -126,6 +194,7 @@ namespace
const techset::CommonShaderArgValue value{
.code_sampler_source = static_cast<techset::CommonCodeSamplerSource>(arg.u.codeSampler),
};
#if defined(IS_DX11)
const techset::CommonShaderArgLocationDx11 location{
.texture_index = arg.location.textureIndex,
.sampler_index = arg.location.samplerIndex,
@@ -137,6 +206,7 @@ namespace
.m_buffer = arg.buffer,
}
};
#endif
return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value);
}
@@ -146,6 +216,7 @@ namespace
const techset::CommonShaderArgValue value{
.name_hash = arg.u.nameHash,
};
#if defined(IS_DX11)
const techset::CommonShaderArgLocationDx11 location{
.texture_index = arg.location.textureIndex,
.sampler_index = arg.location.samplerIndex,
@@ -157,6 +228,7 @@ namespace
.m_buffer = arg.buffer,
}
};
#endif
return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value);
}
@@ -176,6 +248,7 @@ namespace
};
}
#if defined(IS_DX11)
const techset::CommonShaderArgLocationDx11 location{
.constant_buffer_offset = arg.location.offset,
};
@@ -186,6 +259,7 @@ namespace
.m_buffer = arg.buffer,
}
};
#endif
return techset::CommonShaderArg(commonArgumentTypes[arg.type], destination, value);
}
@@ -194,6 +268,15 @@ namespace
techset::CommonTechniqueShader ConvertToCommonShader(const MaterialVertexShader* vertexShader)
{
#if defined(FEATURE_IW4)
if (vertexShader && vertexShader->name && vertexShader->name[0] == ',')
{
auto* globalAsset = GameGlobalAssetPools::GetGlobalPoolsForGame(GameId::IW4)->GetAsset<AssetVertexShader>(&vertexShader->name[1]);
if (globalAsset)
vertexShader = globalAsset->Asset();
}
#endif
techset::CommonTechniqueShader result(techset::CommonTechniqueShaderType::VERTEX, std::string());
if (!vertexShader)
return result;
@@ -205,7 +288,11 @@ namespace
{
result.m_bin = techset::CommonTechniqueShaderBin{
.m_shader_bin = vertexShader->prog.loadDef.program,
#if defined(IS_DX9)
.m_shader_bin_size = vertexShader->prog.loadDef.programSize * sizeof(std::remove_pointer_t<decltype(GfxVertexShaderLoadDef::program)>),
#else
.m_shader_bin_size = vertexShader->prog.loadDef.programSize,
#endif
};
}
@@ -214,6 +301,15 @@ namespace
techset::CommonTechniqueShader ConvertToCommonShader(const MaterialPixelShader* pixelShader)
{
#if defined(FEATURE_IW4)
if (pixelShader && pixelShader->name && pixelShader->name[0] == ',')
{
auto* globalAsset = GameGlobalAssetPools::GetGlobalPoolsForGame(GameId::IW4)->GetAsset<AssetPixelShader>(&pixelShader->name[1]);
if (globalAsset)
pixelShader = globalAsset->Asset();
}
#endif
techset::CommonTechniqueShader result(techset::CommonTechniqueShaderType::PIXEL, std::string());
if (!pixelShader)
return result;
@@ -225,7 +321,11 @@ namespace
{
result.m_bin = techset::CommonTechniqueShaderBin{
.m_shader_bin = pixelShader->prog.loadDef.program,
#if defined(IS_DX9)
.m_shader_bin_size = pixelShader->prog.loadDef.programSize * sizeof(std::remove_pointer_t<decltype(GfxPixelShaderLoadDef::program)>),
#else
.m_shader_bin_size = pixelShader->prog.loadDef.programSize,
#endif
};
}
@@ -241,11 +341,13 @@ namespace
const auto& pass = technique.passArray[passIndex];
std::string comment;
#ifdef FEATURE_T6
if (debug)
{
comment = std::format(
"MaterialType: {}; PrecompiledIndex: {}", static_cast<unsigned>(pass.materialType), static_cast<unsigned>(pass.precompiledIndex));
}
#endif
techset::CommonPass commonPass(pass.customSamplerFlags,
// No clue what the actual state map was
@@ -279,8 +381,17 @@ namespace
{
const auto commonTechnique = ConvertToCommonTechnique(*technique, debug);
techset::DumpCommonTechnique(
context, commonTechnique, techset::DxVersion::DX11, commonCodeSourceInfos, commonRoutingInfos, *materialConstantState, debug);
techset::DumpCommonTechnique(context,
commonTechnique,
#if defined(IS_DX9)
techset::DxVersion::DX9,
#elif defined(IS_DX11)
techset::DxVersion::DX11,
#endif
commonCodeSourceInfos,
commonRoutingInfos,
*materialConstantState,
debug);
}
}
}
@@ -307,24 +418,28 @@ namespace
}
} // namespace
#set CLASS_NAME "Dumper" + GAME
namespace techset
{
DumperT6::DumperT6(const bool debug)
CLASS_NAME::CLASS_NAME(const bool debug)
: m_debug(debug)
{
}
void DumperT6::Dump(AssetDumpingContext& context)
void CLASS_NAME::Dump(AssetDumpingContext& context)
{
context.GetZoneAssetDumperState<MaterialConstantZoneState>()->EnsureInitialized();
AbstractAssetDumper::Dump(context);
}
void DumperT6::DumpAsset(AssetDumpingContext& context, const XAssetInfo<AssetTechniqueSet::Type>& asset)
void CLASS_NAME::DumpAsset(AssetDumpingContext& context, const XAssetInfo<AssetTechniqueSet::Type>& asset)
{
const auto* techniqueSet = asset.Asset();
DumpTechset(context, *techniqueSet);
DumpTechniques(context, *techniqueSet, m_debug);
#if defined(DUMP_SHADERS)
DumpShaders(context, *techniqueSet);
#endif
}
} // namespace techset

View File

@@ -0,0 +1,33 @@
#options GAME(IW4, T6)
#filename "Game/" + GAME + "/Techset/TechsetDumper" + GAME + ".h"
#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\""
// This file was templated.
// See TechsetDumper.h.template.
// Do not modify, changes will be lost.
#pragma once
#include "Dumping/AbstractAssetDumper.h"
#include GAME_HEADER
#set CLASS_NAME "Dumper" + GAME
namespace techset
{
class CLASS_NAME final : public AbstractAssetDumper<GAME::AssetTechniqueSet>
{
public:
explicit CLASS_NAME(bool debug);
void Dump(AssetDumpingContext& context) override;
protected:
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<GAME::AssetTechniqueSet::Type>& asset) override;
private:
bool m_debug;
};
} // namespace techset

View File

@@ -0,0 +1,46 @@
#options GAME(IW4)
#filename "Game/" + GAME + "/Techset/VertexShaderDumper" + GAME + ".cpp"
#set DUMPER_HEADER "\"VertexShaderDumper" + GAME + ".h\""
#if GAME == "IW3"
#define FEATURE_IW3
#define IS_DX9
#elif GAME == "IW4"
#define FEATURE_IW4
#define IS_DX9
#elif GAME == "IW5"
#define FEATURE_IW5
#define IS_DX9
#endif
// This file was templated.
// See VertexShaderDumper.cpp.template.
// Do not modify, changes will be lost.
#include DUMPER_HEADER
#include "Shader/ShaderCommon.h"
#include <type_traits>
using namespace GAME;
#set CLASS_NAME "VertexShaderDumper" + GAME
namespace techset
{
void CLASS_NAME::DumpAsset(AssetDumpingContext& context, const XAssetInfo<AssetVertexShader::Type>& asset)
{
const auto& shader = *asset.Asset();
const auto shaderFile = context.OpenAssetFile(shader::GetFileNameForVertexShaderAssetName(shader.name));
if (!shaderFile)
return;
shaderFile->write(reinterpret_cast<const char*>(shader.prog.loadDef.program),
static_cast<std::streamsize>(shader.prog.loadDef.programSize)
* sizeof(std::remove_pointer_t<decltype(GfxVertexShaderLoadDef::program)>));
}
} // namespace techset

View File

@@ -0,0 +1,25 @@
#options GAME(IW4)
#filename "Game/" + GAME + "/Techset/VertexShaderDumper" + GAME + ".h"
#set GAME_HEADER "\"Game/" + GAME + "/" + GAME + ".h\""
// This file was templated.
// See VertexShaderDumper.h.template.
// Do not modify, changes will be lost.
#pragma once
#include "Dumping/AbstractAssetDumper.h"
#include GAME_HEADER
#set CLASS_NAME "VertexShaderDumper" + GAME
namespace techset
{
class CLASS_NAME final : public AbstractAssetDumper<GAME::AssetVertexShader>
{
protected:
void DumpAsset(AssetDumpingContext& context, const XAssetInfo<GAME::AssetVertexShader::Type>& asset) override;
};
} // namespace techset

View File

@@ -3,6 +3,8 @@ ObjCompilingTests = {}
function ObjCompilingTests:include(includes)
if includes:handle(self:name()) then
includedirs {
"%{wks.location}/src/ObjLoading",
"%{wks.location}/src/ObjCompiling",
path.join(TestFolder(), "ObjCompilingTests")
}
end

View File

@@ -34,7 +34,7 @@ TEST_CASE("TechsetCompilerT6", "[techset][t6][compiler]")
AssetCreationContext context(zone, &creators, &ignoredAssets);
MockSearchPath searchPath;
TestMemoryManager memory;
const auto sut = techset::CreateCompilerT6(memory, searchPath);
const auto sut = techset::CreateTechsetCompilerT6(memory, searchPath);
SECTION("Sets correct worldVertFormat")
{

View File

@@ -12,19 +12,19 @@ function useSourceTemplating(projectName)
local resultExtension = path.getextension(relativeResultPath)
local data = io.readfile(templateFile)
local gameOptionsStart, gameOptionsCount = string.find(data, "#options%s+GAME%s*%(")
local gameOptionsStart, gameOptionsEnd = string.find(data, "#options%s+GAME%s*%(")
if gameOptionsStart == nil then
error("Source template " .. relativeTemplatePath .. " must define an option called GAME")
end
local gameOptionsPos, gameOptionsLenPlusOne = string.find(data, "[%a%d%s,]+%)", gameOptionsStart + gameOptionsCount)
local gameOptionsArgsStart, gameOptionsArgsEnd = string.find(data, "[%a%d%s,]+%)", gameOptionsEnd + 1)
if gameOptionsPos ~= gameOptionsStart + gameOptionsCount then
if gameOptionsArgsStart ~= gameOptionsEnd + 1 then
error("Source template " .. relativeTemplatePath .. " must define an option called GAME")
end
local gameOptions = string.sub(data, gameOptionsPos, gameOptionsLenPlusOne - 1)
local gameOptions = string.sub(data, gameOptionsArgsStart, gameOptionsArgsEnd - 1)
local games = string.explode(gameOptions, ",%s*")
files {