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:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -50,6 +50,9 @@ function ObjCompiling:project()
|
||||
path.join(folder, "ObjCompiling")
|
||||
}
|
||||
}
|
||||
|
||||
ObjCommon:use()
|
||||
useSourceTemplating("ObjCompiling")
|
||||
|
||||
self:include(includes)
|
||||
minilzo:include(includes)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
34
src/ObjCompiling/Techset/TechniqueCompiler.h.template
Normal file
34
src/ObjCompiling/Techset/TechniqueCompiler.h.template
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
34
src/ObjCompiling/Techset/TechsetCompiler.h.template
Normal file
34
src/ObjCompiling/Techset/TechsetCompiler.h.template
Normal 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);
|
||||
}
|
||||
104
src/ObjCompiling/Techset/VertexDeclCompiler.cpp.template
Normal file
104
src/ObjCompiling/Techset/VertexDeclCompiler.cpp.template
Normal 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
|
||||
39
src/ObjCompiling/Techset/VertexDeclCompiler.h.template
Normal file
39
src/ObjCompiling/Techset/VertexDeclCompiler.h.template
Normal 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);
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
117
src/ObjLoading/Techset/PixelShaderLoader.cpp.template
Normal file
117
src/ObjLoading/Techset/PixelShaderLoader.cpp.template
Normal 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
|
||||
40
src/ObjLoading/Techset/PixelShaderLoader.h.template
Normal file
40
src/ObjLoading/Techset/PixelShaderLoader.h.template
Normal 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
|
||||
118
src/ObjLoading/Techset/VertexShaderLoader.cpp.template
Normal file
118
src/ObjLoading/Techset/VertexShaderLoader.cpp.template
Normal 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
|
||||
40
src/ObjLoading/Techset/VertexShaderLoader.h.template
Normal file
40
src/ObjLoading/Techset/VertexShaderLoader.h.template
Normal 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
|
||||
@@ -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>());
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
46
src/ObjWriting/Techset/PixelShaderDumper.cpp.template
Normal file
46
src/ObjWriting/Techset/PixelShaderDumper.cpp.template
Normal 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
|
||||
25
src/ObjWriting/Techset/PixelShaderDumper.h.template
Normal file
25
src/ObjWriting/Techset/PixelShaderDumper.h.template
Normal 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
|
||||
@@ -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
|
||||
33
src/ObjWriting/Techset/TechsetDumper.h.template
Normal file
33
src/ObjWriting/Techset/TechsetDumper.h.template
Normal 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
|
||||
46
src/ObjWriting/Techset/VertexShaderDumper.cpp.template
Normal file
46
src/ObjWriting/Techset/VertexShaderDumper.cpp.template
Normal 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
|
||||
25
src/ObjWriting/Techset/VertexShaderDumper.h.template
Normal file
25
src/ObjWriting/Techset/VertexShaderDumper.h.template
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
{
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user