From c0a7114b24c927b203ee544e15935cb64cf6ad59 Mon Sep 17 00:00:00 2001 From: Jan Laupetin Date: Sat, 28 Feb 2026 22:53:27 +0100 Subject: [PATCH] chore: add tests for techset and technique compilation --- src/Common/Game/T6/T6_Assets.h | 8 +- .../Material/MaterialConstantZoneStateT6.cpp | 1 + .../T6/Techset/TechniqueCompilerT6Test.cpp | 328 +++++++++++++++ .../Game/T6/Techset/TechsetCompilerT6Test.cpp | 90 ++++- .../T6/Techset/VertexDeclCompilerT6Test.cpp | 63 +++ .../Game/T6/Techset/ps_advanced.hlsl.cso | Bin 0 -> 16412 bytes .../Game/T6/Techset/ps_simple.hlsl.cso | Bin 0 -> 432 bytes .../Game/T6/Techset/vs_advanced.hlsl.cso | Bin 0 -> 9164 bytes .../Game/T6/Techset/vs_simple.hlsl.cso | Bin 0 -> 5964 bytes .../Game/T6/Techset/TechsetDumperT6Test.cpp | 382 ++++++++++++++++++ .../Game/T6/Techset/ps_advanced.hlsl.cso | Bin 0 -> 16412 bytes .../Game/T6/Techset/ps_simple.hlsl.cso | Bin 0 -> 432 bytes .../Game/T6/Techset/vs_advanced.hlsl.cso | Bin 0 -> 9164 bytes .../Game/T6/Techset/vs_simple.hlsl.cso | Bin 0 -> 5964 bytes 14 files changed, 867 insertions(+), 5 deletions(-) create mode 100644 test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp create mode 100644 test/ObjCompilingTests/Game/T6/Techset/VertexDeclCompilerT6Test.cpp create mode 100644 test/ObjCompilingTests/Game/T6/Techset/ps_advanced.hlsl.cso create mode 100644 test/ObjCompilingTests/Game/T6/Techset/ps_simple.hlsl.cso create mode 100644 test/ObjCompilingTests/Game/T6/Techset/vs_advanced.hlsl.cso create mode 100644 test/ObjCompilingTests/Game/T6/Techset/vs_simple.hlsl.cso create mode 100644 test/ObjWritingTests/Game/T6/Techset/TechsetDumperT6Test.cpp create mode 100644 test/ObjWritingTests/Game/T6/Techset/ps_advanced.hlsl.cso create mode 100644 test/ObjWritingTests/Game/T6/Techset/ps_simple.hlsl.cso create mode 100644 test/ObjWritingTests/Game/T6/Techset/vs_advanced.hlsl.cso create mode 100644 test/ObjWritingTests/Game/T6/Techset/vs_simple.hlsl.cso diff --git a/src/Common/Game/T6/T6_Assets.h b/src/Common/Game/T6/T6_Assets.h index 4bab9c89..2ee51b42 100644 --- a/src/Common/Game/T6/T6_Assets.h +++ b/src/Common/Game/T6/T6_Assets.h @@ -5760,9 +5760,13 @@ namespace T6 STREAM_SRC_TEXCOORD_0 = 0x2, STREAM_SRC_NORMAL = 0x3, STREAM_SRC_TANGENT = 0x4, - STREAM_SRC_TEXCOORD_1 = 0x5, - STREAM_SRC_OPTIONAL_BEGIN = 0x6, + STREAM_SRC_PRE_OPTIONAL_BEGIN = 0x5, + + STREAM_SRC_TEXCOORD_1 = 0x5, + + STREAM_SRC_OPTIONAL_BEGIN = 0x6, + STREAM_SRC_TEXCOORD_2 = 0x6, STREAM_SRC_TEXCOORD_3 = 0x7, STREAM_SRC_NORMAL_TRANSFORM_0 = 0x8, diff --git a/src/ObjWriting/Game/T6/Material/MaterialConstantZoneStateT6.cpp b/src/ObjWriting/Game/T6/Material/MaterialConstantZoneStateT6.cpp index caf9d8b3..cc140b4a 100644 --- a/src/ObjWriting/Game/T6/Material/MaterialConstantZoneStateT6.cpp +++ b/src/ObjWriting/Game/T6/Material/MaterialConstantZoneStateT6.cpp @@ -409,6 +409,7 @@ namespace "colorMap", "colorMap1", "colorMap2", + "colorMap3", "colorMap2D", "colorMapPostSun", "colorMapPostSunSampler", diff --git a/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp b/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp new file mode 100644 index 00000000..64459b88 --- /dev/null +++ b/test/ObjCompilingTests/Game/T6/Techset/TechniqueCompilerT6Test.cpp @@ -0,0 +1,328 @@ +#include "Game/T6/Techset/TechniqueCompilerT6.h" + +#include "Game/T6/T6.h" +#include "Game/T6/Techset/PixelShaderLoaderT6.h" +#include "Game/T6/Techset/VertexDeclCompilerT6.h" +#include "Game/T6/Techset/VertexShaderLoaderT6.h" +#include "OatTestPaths.h" +#include "SearchPath/MockSearchPath.h" +#include "Shader/ShaderCommon.h" +#include "Utils/MemoryManager.h" + +#include +#include +#include +#include + +using namespace T6; +using namespace Catch; +using namespace std::literals; +namespace fs = std::filesystem; + +namespace +{ + void GivenVertexShaderFile(const std::string& name, MockSearchPath& searchPath) + { + const auto filePath = oat::paths::GetTestDirectory() / "ObjCompilingTests/Game/T6/Techset" / std::format("vs_{}.cso", name); + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + std::string data(fileSize, '\0'); + file.read(data.data(), fileSize); + REQUIRE(file.gcount() == static_cast(fileSize)); + + searchPath.AddFileData(shader::GetFileNameForVertexShaderAssetName(name), std::move(data)); + } + + void GivenPixelShaderFile(const std::string& name, MockSearchPath& searchPath) + { + const auto filePath = oat::paths::GetTestDirectory() / "ObjCompilingTests/Game/T6/Techset" / std::format("ps_{}.cso", name); + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + std::string data(fileSize, '\0'); + file.read(data.data(), fileSize); + REQUIRE(file.gcount() == static_cast(fileSize)); + + searchPath.AddFileData(shader::GetFileNameForPixelShaderAssetName(name), std::move(data)); + } +} // namespace + +TEST_CASE("TechniqueCompilerT6", "[t6][techset][compiler]") +{ + + Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC); + zone.Register(); + + MemoryManager memory; + AssetCreatorCollection creatorCollection(zone); + IgnoredAssetLookup ignoredAssetLookup; + AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup); + MockSearchPath searchPath; + + creatorCollection.AddSubAssetCreator(techset::CreateVertexDeclCompilerT6(memory)); + creatorCollection.AddSubAssetCreator(techset::CreateVertexShaderLoaderT6(memory, searchPath)); + creatorCollection.AddSubAssetCreator(techset::CreatePixelShaderLoaderT6(memory, searchPath)); + + auto loader = techset::CreateTechniqueCompilerT6(memory, searchPath); + + SECTION("Can compile simple technique") + { + searchPath.AddFileData("techniques/example_zprepass.tech", R"TECHNIQUE( +{ + stateMap "passthrough"; + + vertexShader 4.0 "simple.hlsl" + { + } + + pixelShader 4.0 "simple.hlsl" + { + } + + vertex.position = code.position; +} +)TECHNIQUE"); + + GivenVertexShaderFile("simple.hlsl", searchPath); + GivenPixelShaderFile("simple.hlsl", searchPath); + + auto result = loader->CreateSubAsset("example_zprepass", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* technique = assetInfo->Asset(); + + CHECK(technique->name == "example_zprepass"s); + CHECK(technique->flags == 0x84); + + REQUIRE(technique->passCount == 1); + auto& pass = technique->passArray[0]; + CHECK(pass.customSamplerFlags == 0); + + // idk + // CHECK(pass.precompiledIndex == VERTEX_SHADER_MODEL_UNLIT); + + // Set from techset + // CHECK(pass.materialType == MTL_TYPE_MODEL_VERTCOL); + + REQUIRE(pass.vertexShader); + CHECK(pass.vertexShader->name == "simple.hlsl"s); + REQUIRE(pass.pixelShader); + CHECK(pass.pixelShader->name == "simple.hlsl"s); + + REQUIRE(pass.vertexDecl); + auto& vertexDecl = *pass.vertexDecl; + CHECK(vertexDecl.hasOptionalSource == false); + CHECK(vertexDecl.isLoaded == false); + REQUIRE(vertexDecl.streamCount == 1); + CHECK(vertexDecl.routing.data[0].source == STREAM_SRC_POSITION); + CHECK(vertexDecl.routing.data[0].dest == STREAM_DST_POSITION); + + REQUIRE(pass.perPrimArgCount == 1); + REQUIRE(pass.perObjArgCount == 1); + REQUIRE(pass.stableArgCount == 0); + CHECK(pass.args[0].type == MTL_ARG_CODE_VERTEX_CONST); + CHECK(pass.args[0].location.offset == 0); + CHECK(pass.args[0].size == 0x40); + CHECK(pass.args[0].buffer == 3); + CHECK(pass.args[0].u.codeConst.index == CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX); + CHECK(pass.args[0].u.codeConst.firstRow == 0); + CHECK(pass.args[0].u.codeConst.rowCount == 4); + + CHECK(pass.args[1].type == MTL_ARG_CODE_VERTEX_CONST); + CHECK(pass.args[1].location.offset == 0x240); + CHECK(pass.args[1].size == 0x40); + CHECK(pass.args[1].buffer == 0); + CHECK(pass.args[1].u.codeConst.index == CONST_SRC_CODE_TRANSPOSE_VIEW_PROJECTION_MATRIX); + CHECK(pass.args[1].u.codeConst.firstRow == 0); + CHECK(pass.args[1].u.codeConst.rowCount == 4); + } + + SECTION("Can compile advanced technique") + { + searchPath.AddFileData("techniques/example_lit_sun_shadow.tech", R"TECHNIQUE( +{ + stateMap "passthrough"; + + vertexShader 4.0 "advanced.hlsl" + { + } + + pixelShader 4.0 "advanced.hlsl" + { + normalMapSampler = material.normalMap; + normalMapSampler1 = material.normalMap1; + colorMapSampler = material.colorMap; + colorMapSampler1 = material.colorMap1; + colorMapSampler3 = material.colorMap3; + colorMapSampler2 = material.colorMap2; + alphaRevealParms1 = material.alphaRevealParms1; + } + + vertex.position = code.position; + vertex.color[0] = code.color; + vertex.texcoord[0] = code.texcoord[0]; + vertex.normal = code.normal; + vertex.texcoord[2] = code.tangent; + vertex.texcoord[1] = code.texcoord[1]; + vertex.texcoord[3] = code.texcoord[2]; + vertex.texcoord[4] = code.texcoord[3]; + vertex.texcoord[5] = code.normalTransform[0]; +} +)TECHNIQUE"); + + GivenVertexShaderFile("advanced.hlsl", searchPath); + GivenPixelShaderFile("advanced.hlsl", searchPath); + + auto result = loader->CreateSubAsset("example_lit_sun_shadow", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* technique = assetInfo->Asset(); + + CHECK(technique->name == "example_lit_sun_shadow"s); + CHECK(technique->flags == 0x88); + + REQUIRE(technique->passCount == 1); + auto& pass = technique->passArray[0]; + CHECK(pass.customSamplerFlags == 3); + + // idk + // CHECK(pass.precompiledIndex == VERTEX_SHADER_NONE); + + // Set from techset + // CHECK(pass.materialType == MTL_TYPE_DEFAULT); + + REQUIRE(pass.vertexShader); + CHECK(pass.vertexShader->name == "advanced.hlsl"s); + REQUIRE(pass.pixelShader); + CHECK(pass.pixelShader->name == "advanced.hlsl"s); + + REQUIRE(pass.vertexDecl); + auto& vertexDecl = *pass.vertexDecl; + CHECK(vertexDecl.hasOptionalSource == true); + CHECK(vertexDecl.isLoaded == false); + REQUIRE(vertexDecl.streamCount == 9); + CHECK(vertexDecl.routing.data[0].source == STREAM_SRC_POSITION); + CHECK(vertexDecl.routing.data[0].dest == STREAM_DST_POSITION); + CHECK(vertexDecl.routing.data[1].source == STREAM_SRC_COLOR); + CHECK(vertexDecl.routing.data[1].dest == STREAM_DST_COLOR_0); + CHECK(vertexDecl.routing.data[2].source == STREAM_SRC_TEXCOORD_0); + CHECK(vertexDecl.routing.data[2].dest == STREAM_DST_TEXCOORD_0); + CHECK(vertexDecl.routing.data[3].source == STREAM_SRC_NORMAL); + CHECK(vertexDecl.routing.data[3].dest == STREAM_DST_NORMAL); + CHECK(vertexDecl.routing.data[4].source == STREAM_SRC_TANGENT); + CHECK(vertexDecl.routing.data[4].dest == STREAM_DST_TEXCOORD_2); + CHECK(vertexDecl.routing.data[5].source == STREAM_SRC_TEXCOORD_1); + CHECK(vertexDecl.routing.data[5].dest == STREAM_DST_TEXCOORD_1); + CHECK(vertexDecl.routing.data[6].source == STREAM_SRC_TEXCOORD_2); + CHECK(vertexDecl.routing.data[6].dest == STREAM_DST_TEXCOORD_3); + CHECK(vertexDecl.routing.data[7].source == STREAM_SRC_TEXCOORD_3); + CHECK(vertexDecl.routing.data[7].dest == STREAM_DST_TEXCOORD_4); + CHECK(vertexDecl.routing.data[8].source == STREAM_SRC_NORMAL_TRANSFORM_0); + CHECK(vertexDecl.routing.data[8].dest == STREAM_DST_TEXCOORD_5); + + REQUIRE(pass.perPrimArgCount == 1); + REQUIRE(pass.perObjArgCount == 1); + REQUIRE(pass.stableArgCount == 11); + CHECK(pass.args[0].type == MTL_ARG_CODE_VERTEX_CONST); + CHECK(pass.args[0].location.offset == 0); + CHECK(pass.args[0].size == 0x40); + CHECK(pass.args[0].buffer == 3); + CHECK(pass.args[0].u.codeConst.index == CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX); + CHECK(pass.args[0].u.codeConst.firstRow == 0); + CHECK(pass.args[0].u.codeConst.rowCount == 4); + + CHECK(pass.args[1].type == MTL_ARG_CODE_VERTEX_CONST); + CHECK(pass.args[1].location.offset == 0x240); + CHECK(pass.args[1].size == 0x40); + CHECK(pass.args[1].buffer == 0); + CHECK(pass.args[1].u.codeConst.index == CONST_SRC_CODE_TRANSPOSE_VIEW_PROJECTION_MATRIX); + CHECK(pass.args[1].u.codeConst.firstRow == 0); + CHECK(pass.args[1].u.codeConst.rowCount == 4); + + CHECK(pass.args[2].type == MTL_ARG_MATERIAL_PIXEL_SAMPLER); + CHECK(pass.args[2].location.textureIndex == 1); + CHECK(pass.args[2].location.samplerIndex == 1); + CHECK(pass.args[2].size == 1); + CHECK(pass.args[2].buffer == 0); + CHECK(pass.args[2].u.nameHash == 0x59d30d0f); + + CHECK(pass.args[3].type == MTL_ARG_MATERIAL_PIXEL_SAMPLER); + CHECK(pass.args[3].location.textureIndex == 3); + CHECK(pass.args[3].location.samplerIndex == 5); + CHECK(pass.args[3].size == 1); + CHECK(pass.args[3].buffer == 0); + CHECK(pass.args[3].u.nameHash == 0x9434aede); + + CHECK(pass.args[4].type == MTL_ARG_MATERIAL_PIXEL_SAMPLER); + CHECK(pass.args[4].location.textureIndex == 0); + CHECK(pass.args[4].location.samplerIndex == 0); + CHECK(pass.args[4].size == 1); + CHECK(pass.args[4].buffer == 0); + CHECK(pass.args[4].u.nameHash == 0xa0ab1041); + + CHECK(pass.args[5].type == MTL_ARG_MATERIAL_PIXEL_SAMPLER); + CHECK(pass.args[5].location.textureIndex == 2); + CHECK(pass.args[5].location.samplerIndex == 2); + CHECK(pass.args[5].size == 1); + CHECK(pass.args[5].buffer == 0); + CHECK(pass.args[5].u.nameHash == 0xb60d1850); + + CHECK(pass.args[6].type == MTL_ARG_MATERIAL_PIXEL_SAMPLER); + CHECK(pass.args[6].location.textureIndex == 5); + CHECK(pass.args[6].location.samplerIndex == 4); + CHECK(pass.args[6].size == 1); + CHECK(pass.args[6].buffer == 0); + CHECK(pass.args[6].u.nameHash == 0xb60d1852); + + CHECK(pass.args[7].type == MTL_ARG_MATERIAL_PIXEL_SAMPLER); + CHECK(pass.args[7].location.textureIndex == 4); + CHECK(pass.args[7].location.samplerIndex == 3); + CHECK(pass.args[7].size == 1); + CHECK(pass.args[7].buffer == 0); + CHECK(pass.args[7].u.nameHash == 0xb60d1853); + + CHECK(pass.args[8].type == MTL_ARG_CODE_VERTEX_CONST); + CHECK(pass.args[8].location.offset == 0x300); + CHECK(pass.args[8].size == 0x40); + CHECK(pass.args[8].buffer == 0); + CHECK(pass.args[8].u.codeConst.index == CONST_SRC_CODE_TRANSPOSE_SHADOW_LOOKUP_MATRIX); + CHECK(pass.args[8].u.codeConst.firstRow == 0); + CHECK(pass.args[8].u.codeConst.rowCount == 4); + + CHECK(pass.args[9].type == MTL_ARG_CODE_PIXEL_SAMPLER); + CHECK(pass.args[9].location.textureIndex == 9); + CHECK(pass.args[9].location.samplerIndex == 9); + CHECK(pass.args[9].size == 1); + CHECK(pass.args[9].buffer == 0); + CHECK(pass.args[9].u.codeSampler == TEXTURE_SRC_CODE_SHADOWMAP_SUN); + + CHECK(pass.args[10].type == MTL_ARG_CODE_PIXEL_CONST); + CHECK(pass.args[10].location.offset == 0x610); + CHECK(pass.args[10].size == 0x10); + CHECK(pass.args[10].buffer == 0); + CHECK(pass.args[10].u.codeConst.index == CONST_SRC_CODE_SHADOWMAP_SWITCH_PARTITION); + CHECK(pass.args[10].u.codeConst.firstRow == 0); + CHECK(pass.args[10].u.codeConst.rowCount == 1); + + CHECK(pass.args[11].type == MTL_ARG_CODE_PIXEL_CONST); + CHECK(pass.args[11].location.offset == 0x630); + CHECK(pass.args[11].size == 0x10); + CHECK(pass.args[11].buffer == 0); + CHECK(pass.args[11].u.codeConst.index == CONST_SRC_CODE_SUNSHADOWMAP_PIXEL_SIZE); + CHECK(pass.args[11].u.codeConst.firstRow == 0); + CHECK(pass.args[11].u.codeConst.rowCount == 1); + + CHECK(pass.args[12].type == MTL_ARG_MATERIAL_PIXEL_CONST); + CHECK(pass.args[12].location.offset == 0x3b0); + CHECK(pass.args[12].size == 0x10); + CHECK(pass.args[12].buffer == 1); + CHECK(pass.args[12].u.nameHash == 0x88befc31); + } +} diff --git a/test/ObjCompilingTests/Game/T6/Techset/TechsetCompilerT6Test.cpp b/test/ObjCompilingTests/Game/T6/Techset/TechsetCompilerT6Test.cpp index 1bfdce31..4eb3a709 100644 --- a/test/ObjCompilingTests/Game/T6/Techset/TechsetCompilerT6Test.cpp +++ b/test/ObjCompilingTests/Game/T6/Techset/TechsetCompilerT6Test.cpp @@ -2,6 +2,7 @@ #include "Game/T6/T6.h" #include "SearchPath/MockSearchPath.h" +#include "Techset/TechsetCommon.h" #include "Utils/TestMemoryManager.h" #include @@ -12,7 +13,20 @@ using namespace T6; using namespace std::string_literals; -TEST_CASE("Game::T6::Techset::TechsetCompilerT6", "[techset][t6]") +namespace +{ + MaterialTechnique* GivenTechnique(const std::string& name, AssetCreationContext& context, MemoryManager& memory) + { + auto* technique = memory.Alloc(); + technique->name = memory.Dup(name.c_str()); + + context.AddSubAsset(name, technique); + + return technique; + } +} // namespace + +TEST_CASE("TechsetCompilerT6", "[techset][t6][compiler]") { Zone zone("test", 0, GameId::T6, GamePlatform::PC); AssetCreatorCollection creators(zone); @@ -20,7 +34,7 @@ TEST_CASE("Game::T6::Techset::TechsetCompilerT6", "[techset][t6]") AssetCreationContext context(zone, &creators, &ignoredAssets); MockSearchPath searchPath; TestMemoryManager memory; - const auto sut = ::techset::CreateCompilerT6(memory, searchPath); + const auto sut = techset::CreateCompilerT6(memory, searchPath); SECTION("Sets correct worldVertFormat") { @@ -54,7 +68,7 @@ TEST_CASE("Game::T6::Techset::TechsetCompilerT6", "[techset][t6]") })); CAPTURE(techsetName); - searchPath.AddFileData(std::format("techsets/{}.techset", techsetName), ""); + searchPath.AddFileData(techset::GetFileNameForTechsetName(techsetName), ""); const auto result = sut->CreateAsset(techsetName, context); REQUIRE(result.HasBeenSuccessful()); @@ -62,4 +76,74 @@ TEST_CASE("Game::T6::Techset::TechsetCompilerT6", "[techset][t6]") const auto* techset = static_cast(result.GetAssetInfo()->m_ptr); CHECK(techset->worldVertFormat == expectedWorldVertFormat); } + + SECTION("Can parse simple techset") + { + searchPath.AddFileData(techset::GetFileNameForTechsetName("simple"), R"TECHSET( +"depth prepass": + example_zprepass; + +"lit sun shadow": + example_lit_sun_shadow; +)TECHSET"); + + auto* exampleZPrepass = GivenTechnique("example_zprepass", context, memory); + auto* exampleLitSunShadow = GivenTechnique("example_lit_sun_shadow", context, memory); + + const auto result = sut->CreateAsset("simple", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* techset = static_cast(result.GetAssetInfo()->m_ptr); + CHECK(techset->name == "simple"s); + CHECK(techset->worldVertFormat == MTL_WORLDVERT_TEX_1_NRM_1); + + size_t techniqueCount = 0; + for (auto* technique : techset->techniques) + { + if (technique) + techniqueCount++; + } + + CHECK(techniqueCount == 2); + CHECK(techset->techniques[TECHNIQUE_DEPTH_PREPASS] == exampleZPrepass); + CHECK(techset->techniques[TECHNIQUE_LIT_SUN_SHADOW] == exampleLitSunShadow); + } + + SECTION("Can parse techset with same technique used multiple times") + { + searchPath.AddFileData(techset::GetFileNameForTechsetName("simple"), R"TECHSET( +"depth prepass": +"build shadowmap depth": + example_zprepass; + +"lit": +"lit sun": +"lit sun shadow": + example_lit_sun_shadow; +)TECHSET"); + + auto* exampleZPrepass = GivenTechnique("example_zprepass", context, memory); + auto* exampleLitSunShadow = GivenTechnique("example_lit_sun_shadow", context, memory); + + const auto result = sut->CreateAsset("simple", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* techset = static_cast(result.GetAssetInfo()->m_ptr); + CHECK(techset->name == "simple"s); + CHECK(techset->worldVertFormat == MTL_WORLDVERT_TEX_1_NRM_1); + + size_t techniqueCount = 0; + for (auto* technique : techset->techniques) + { + if (technique) + techniqueCount++; + } + + CHECK(techniqueCount == 5); + CHECK(techset->techniques[TECHNIQUE_DEPTH_PREPASS] == exampleZPrepass); + CHECK(techset->techniques[TECHNIQUE_BUILD_SHADOWMAP_DEPTH] == exampleZPrepass); + CHECK(techset->techniques[TECHNIQUE_LIT] == exampleLitSunShadow); + CHECK(techset->techniques[TECHNIQUE_LIT_SUN] == exampleLitSunShadow); + CHECK(techset->techniques[TECHNIQUE_LIT_SUN_SHADOW] == exampleLitSunShadow); + } } diff --git a/test/ObjCompilingTests/Game/T6/Techset/VertexDeclCompilerT6Test.cpp b/test/ObjCompilingTests/Game/T6/Techset/VertexDeclCompilerT6Test.cpp new file mode 100644 index 00000000..34734029 --- /dev/null +++ b/test/ObjCompilingTests/Game/T6/Techset/VertexDeclCompilerT6Test.cpp @@ -0,0 +1,63 @@ +#include "Game/T6/Techset/VertexDeclCompilerT6.h" + +#include "Game/T6/T6.h" +#include "Utils/MemoryManager.h" + +#include + +using namespace T6; +using namespace Catch; +using namespace std::literals; + +TEST_CASE("VertexDeclCompilerT6", "[t6][techset][compiler]") +{ + Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC); + zone.Register(); + + MemoryManager memory; + AssetCreatorCollection creatorCollection(zone); + IgnoredAssetLookup ignoredAssetLookup; + AssetCreationContext context(zone, &creatorCollection, &ignoredAssetLookup); + + auto loader = techset::CreateVertexDeclCompilerT6(memory); + + SECTION("Can create simple vertex decl") + { + auto result = loader->CreateSubAsset("pp", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* decl = assetInfo->Asset(); + + CHECK(decl->hasOptionalSource == false); + CHECK(decl->isLoaded == false); + + REQUIRE(decl->streamCount == 1); + CHECK(decl->routing.data[0].source == STREAM_SRC_POSITION); + CHECK(decl->routing.data[0].dest == STREAM_DST_POSITION); + } + + SECTION("Can create advanced vertex decl") + { + auto result = loader->CreateSubAsset("pbcc1tt10t1t1n1n", context); + REQUIRE(result.HasBeenSuccessful()); + + const auto* assetInfo = reinterpret_cast*>(result.GetAssetInfo()); + const auto* decl = assetInfo->Asset(); + + CHECK(decl->hasOptionalSource == true); + CHECK(decl->isLoaded == false); + + REQUIRE(decl->streamCount == 5); + CHECK(decl->routing.data[0].source == STREAM_SRC_POSITION); + CHECK(decl->routing.data[0].dest == STREAM_DST_BLENDWEIGHT); + CHECK(decl->routing.data[1].source == STREAM_SRC_COLOR); + CHECK(decl->routing.data[1].dest == STREAM_DST_COLOR_1); + CHECK(decl->routing.data[2].source == STREAM_SRC_TANGENT); + CHECK(decl->routing.data[2].dest == STREAM_DST_TEXCOORD_10); + CHECK(decl->routing.data[3].source == STREAM_SRC_TEXCOORD_1); + CHECK(decl->routing.data[3].dest == STREAM_DST_TEXCOORD_1); + CHECK(decl->routing.data[4].source == STREAM_SRC_NORMAL_TRANSFORM_1); + CHECK(decl->routing.data[4].dest == STREAM_DST_NORMAL); + } +} diff --git a/test/ObjCompilingTests/Game/T6/Techset/ps_advanced.hlsl.cso b/test/ObjCompilingTests/Game/T6/Techset/ps_advanced.hlsl.cso new file mode 100644 index 0000000000000000000000000000000000000000..b01854324de62edc5d7d7705933b37bc30c43076 GIT binary patch literal 16412 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 IlD(DiUrF~qKmY&$ literal 0 HcmV?d00001 diff --git a/test/ObjCompilingTests/Game/T6/Techset/ps_simple.hlsl.cso b/test/ObjCompilingTests/Game/T6/Techset/ps_simple.hlsl.cso new file mode 100644 index 0000000000000000000000000000000000000000..cfe8445a2501036fc948b644c9b0391efd4260c6 GIT binary patch literal 432 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 KKeF{s?fwVKQMfh$ literal 0 HcmV?d00001 diff --git a/test/ObjCompilingTests/Game/T6/Techset/vs_simple.hlsl.cso b/test/ObjCompilingTests/Game/T6/Techset/vs_simple.hlsl.cso new file mode 100644 index 0000000000000000000000000000000000000000..50c95fc29c08b8338853f79221339352893c14be GIT binary patch literal 5964 zcmb8zUu+vm9S88qwc&ce-I?Ced!Q25U4aVm;5elei9fcJI;oUvmaJQna**tK$If2Y zyUXmlaZa4@@q_@O2qB?^2aF0Y1fd8OA*7QoZwLvbfI#8_iJ$|4xRE)Hm(7nX*%+jLI#k z?4}IlLKwtJEL`7fZzJ8Oem{@>``G)B;h)*4zqeyQJd52JB_Df-4hqIrO#A{;vT<+0 zi&U3R0$b12|1vpjy#6=gCC0xCuQ0w3w;2B!e2eklz$3=rg7+DpeWwt6jK3E?VEiKd zfblZ?knxYhkKjnsZP{ejksdSkUHA$7jH&ON`d^?F6Q^Q)&-ego#W>BY%zp~+GxdJ~ zKVJJlYy#EK(KjTk6j{f1}*Y`R29^+;BfblEv1IAb2hm5boj~I91$Bakt6UM&? z7pEuB|10nUB2r$@%{jwg4l@p@ixN2*xfM44$hA``XaiBS?eq4M3;ZsLZa8XZ27 zenr9c(Woz8YRgiEI(+%Mbd(5nZ(1R2V3Vhm+CA%-$P z(hps3eGD7rb*GtxD%JxxJjZk(vQtb0s!J`0L9XHG`KL9^=~s1q6V)EJ&OXerI}LN= zHOk{K{}8Ixn&}a@7=1~l+syPZA|qWa;7;?T?R#!kUBviY`Znx1k>&NIUv*#V#>vPK zvBjIsZAW43q*_2mNw?YwyFnt93|y%ij%v%q_Fk5v8^yGQxFe(|G>&KQcu8{`lP@s~ zM>^B#L_&YJ9R@VTWJ0%T{v6VdI}Q%+Ilj3^Z|^pg6POi9d7WzkrWC?mu}@#ZX7HD7 zEzd{Oh7*mfd05`lt?6{6a&AOIXXrjMSsSA!aIb_b^fLhNv9(;Zl#6OY?n-m|ZTy6w zyyn$$_*B<%AD(3t#!0<5Tr6|poXCacd^n#EFXh7z=flhS@FV%~N}l!RcVSIUTHZ;f^hnZj|P#QRMH6COs+ijkq=%ER6;=9W=ZksX2JUrHv?B zlz!squ;w|jXnKLf9QB%51ywEVO+cBR7Y9%2c~?O~PnPVrhS%X_+4D7f=lea}V*Ic0 zEyn)|j~JiD?_+(&-vi%cd=5Tfd*a3hCj+e+v|>D5GlmuP zLsG0pGN{H_of={2$Hj(>lOiorm}vZlYkkdLy8a=QQm?e$6tQPp_U7>@-v6yt`L z>UEkQt5e!gA6XlGEfn_6&EeC_US3@5p+W^m`W(tOa2e`fFCr(zMeJEj?dke#qAOJ> zASXl{bib(cbc}6GOPZIL@ymiTv$1|wmy>|Ck* z*(v4JhRSPG%IQ3)oQ}!$Psd1)Uo^+X@zZ+dvtKaf&rT_SUv~T{ +#include +#include +#include +#include + +using namespace T6; +using namespace Catch; +using namespace std::literals; +namespace fs = std::filesystem; + +namespace +{ + std::string Trimmed(const std::string& input) + { + auto start = input.find_first_not_of(" \r\n"); + if (start == std::string::npos) + start = 0; + + auto end = input.find_last_not_of(" \r\n"); + if (end == std::string::npos) + end = input.length(); + else + end = end + 1; + + return input.substr(start, end - start); + } + + MaterialVertexShader* GivenVertexShader(const std::string& name, MemoryManager& memory) + { + const auto filePath = oat::paths::GetTestDirectory() / "ObjWritingTests/Game/T6/Techset" / std::format("vs_{}.cso", name); + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + auto* shader = memory.Alloc(); + shader->name = memory.Dup(name.c_str()); + shader->prog.loadDef.program = memory.Alloc(fileSize); + shader->prog.loadDef.programSize = static_cast(fileSize); + file.read(shader->prog.loadDef.program, fileSize); + REQUIRE(file.gcount() == static_cast(fileSize)); + + return shader; + } + + MaterialPixelShader* GivenPixelShader(const std::string& name, MemoryManager& memory) + { + const auto filePath = oat::paths::GetTestDirectory() / "ObjWritingTests/Game/T6/Techset" / std::format("ps_{}.cso", name); + const auto fileSize = static_cast(fs::file_size(filePath)); + + std::ifstream file(filePath, std::ios::binary); + REQUIRE(file.is_open()); + + auto* shader = memory.Alloc(); + shader->name = memory.Dup(name.c_str()); + shader->prog.loadDef.program = memory.Alloc(fileSize); + shader->prog.loadDef.programSize = static_cast(fileSize); + file.read(shader->prog.loadDef.program, fileSize); + REQUIRE(file.gcount() == static_cast(fileSize)); + + return shader; + } + + MaterialTechnique* GivenDepthPrepassTechnique(MemoryManager& memory) + { + auto* technique = memory.Alloc(); + technique->name = "example_zprepass"; + technique->flags = 0x84; + technique->passCount = 1; + + auto& pass = technique->passArray[0]; + pass.perPrimArgCount = 1; + pass.perObjArgCount = 1; + pass.stableArgCount = 0; + pass.customSamplerFlags = 0; + pass.precompiledIndex = VERTEX_SHADER_MODEL_UNLIT; + pass.materialType = MTL_TYPE_MODEL_VERTCOL; + + pass.vertexShader = GivenVertexShader("simple.hlsl", memory); + pass.pixelShader = GivenPixelShader("simple.hlsl", memory); + + pass.vertexDecl = memory.Alloc(); + auto& vertexDecl = *pass.vertexDecl; + vertexDecl.streamCount = 1; + vertexDecl.hasOptionalSource = false; + vertexDecl.isLoaded = false; + vertexDecl.routing.data[0].source = STREAM_SRC_POSITION; + vertexDecl.routing.data[0].dest = STREAM_DST_POSITION; + + pass.args = memory.Alloc(2); + pass.args[0].type = MTL_ARG_CODE_VERTEX_CONST; + pass.args[0].location.offset = 0; + pass.args[0].size = 0x40; + pass.args[0].buffer = 3; + pass.args[0].u.codeConst.index = CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX; + pass.args[0].u.codeConst.firstRow = 0; + pass.args[0].u.codeConst.rowCount = 4; + + pass.args[1].type = MTL_ARG_CODE_VERTEX_CONST; + pass.args[1].location.offset = 0x240; + pass.args[1].size = 0x40; + pass.args[1].buffer = 0; + pass.args[1].u.codeConst.index = CONST_SRC_CODE_TRANSPOSE_VIEW_PROJECTION_MATRIX; + pass.args[1].u.codeConst.firstRow = 0; + pass.args[1].u.codeConst.rowCount = 4; + + return technique; + } + + MaterialTechnique* GivenLitSunShadowTechnique(MemoryManager& memory) + { + auto* technique = memory.Alloc(); + technique->name = "example_lit_sun_shadow"; + technique->flags = 0x88; + technique->passCount = 1; + + auto& pass = technique->passArray[0]; + pass.perPrimArgCount = 1; + pass.perObjArgCount = 1; + pass.stableArgCount = 11; + pass.customSamplerFlags = 3; + pass.precompiledIndex = VERTEX_SHADER_NONE; + pass.materialType = MTL_TYPE_DEFAULT; + + pass.vertexShader = GivenVertexShader("advanced.hlsl", memory); + pass.pixelShader = GivenPixelShader("advanced.hlsl", memory); + + pass.vertexDecl = memory.Alloc(); + auto& vertexDecl = *pass.vertexDecl; + vertexDecl.streamCount = 9; + vertexDecl.hasOptionalSource = true; + vertexDecl.isLoaded = false; + vertexDecl.routing.data[0].source = STREAM_SRC_POSITION; + vertexDecl.routing.data[0].dest = STREAM_DST_POSITION; + vertexDecl.routing.data[1].source = STREAM_SRC_COLOR; + vertexDecl.routing.data[1].dest = STREAM_DST_COLOR_0; + vertexDecl.routing.data[2].source = STREAM_SRC_TEXCOORD_0; + vertexDecl.routing.data[2].dest = STREAM_DST_TEXCOORD_0; + vertexDecl.routing.data[3].source = STREAM_SRC_NORMAL; + vertexDecl.routing.data[3].dest = STREAM_DST_NORMAL; + vertexDecl.routing.data[4].source = STREAM_SRC_TANGENT; + vertexDecl.routing.data[4].dest = STREAM_DST_TEXCOORD_2; + vertexDecl.routing.data[5].source = STREAM_SRC_TEXCOORD_1; + vertexDecl.routing.data[5].dest = STREAM_DST_TEXCOORD_1; + vertexDecl.routing.data[6].source = STREAM_SRC_TEXCOORD_2; + vertexDecl.routing.data[6].dest = STREAM_DST_TEXCOORD_3; + vertexDecl.routing.data[7].source = STREAM_SRC_TEXCOORD_3; + vertexDecl.routing.data[7].dest = STREAM_DST_TEXCOORD_4; + vertexDecl.routing.data[8].source = STREAM_SRC_NORMAL_TRANSFORM_0; + vertexDecl.routing.data[8].dest = STREAM_DST_TEXCOORD_5; + + pass.args = memory.Alloc(13); + pass.args[0].type = MTL_ARG_CODE_VERTEX_CONST; + pass.args[0].location.offset = 0; + pass.args[0].size = 0x40; + pass.args[0].buffer = 3; + pass.args[0].u.codeConst.index = CONST_SRC_CODE_TRANSPOSE_WORLD_MATRIX; + pass.args[0].u.codeConst.firstRow = 0; + pass.args[0].u.codeConst.rowCount = 4; + + pass.args[1].type = MTL_ARG_CODE_VERTEX_CONST; + pass.args[1].location.offset = 0x240; + pass.args[1].size = 0x40; + pass.args[1].buffer = 0; + pass.args[1].u.codeConst.index = CONST_SRC_CODE_TRANSPOSE_VIEW_PROJECTION_MATRIX; + pass.args[1].u.codeConst.firstRow = 0; + pass.args[1].u.codeConst.rowCount = 4; + + pass.args[2].type = MTL_ARG_MATERIAL_PIXEL_SAMPLER; + pass.args[2].location.textureIndex = 1; + pass.args[2].location.samplerIndex = 1; + pass.args[2].size = 1; + pass.args[2].buffer = 0; + pass.args[2].u.nameHash = 0x59d30d0f; + + pass.args[3].type = MTL_ARG_MATERIAL_PIXEL_SAMPLER; + pass.args[3].location.textureIndex = 3; + pass.args[3].location.samplerIndex = 5; + pass.args[3].size = 1; + pass.args[3].buffer = 0; + pass.args[3].u.nameHash = 0x9434aede; + + pass.args[4].type = MTL_ARG_MATERIAL_PIXEL_SAMPLER; + pass.args[4].location.textureIndex = 0; + pass.args[4].location.samplerIndex = 0; + pass.args[4].size = 1; + pass.args[4].buffer = 0; + pass.args[4].u.nameHash = 0xa0ab1041; + + pass.args[5].type = MTL_ARG_MATERIAL_PIXEL_SAMPLER; + pass.args[5].location.textureIndex = 2; + pass.args[5].location.samplerIndex = 2; + pass.args[5].size = 1; + pass.args[5].buffer = 0; + pass.args[5].u.nameHash = 0xb60d1850; + + pass.args[6].type = MTL_ARG_MATERIAL_PIXEL_SAMPLER; + pass.args[6].location.textureIndex = 5; + pass.args[6].location.samplerIndex = 4; + pass.args[6].size = 1; + pass.args[6].buffer = 0; + pass.args[6].u.nameHash = 0xb60d1852; + + pass.args[7].type = MTL_ARG_MATERIAL_PIXEL_SAMPLER; + pass.args[7].location.textureIndex = 4; + pass.args[7].location.samplerIndex = 3; + pass.args[7].size = 1; + pass.args[7].buffer = 0; + pass.args[7].u.nameHash = 0xb60d1853; + + pass.args[8].type = MTL_ARG_CODE_VERTEX_CONST; + pass.args[8].location.offset = 0x300; + pass.args[8].size = 0x40; + pass.args[8].buffer = 0; + pass.args[8].u.codeConst.index = CONST_SRC_CODE_TRANSPOSE_SHADOW_LOOKUP_MATRIX; + pass.args[8].u.codeConst.firstRow = 0; + pass.args[8].u.codeConst.rowCount = 4; + + pass.args[9].type = MTL_ARG_CODE_PIXEL_SAMPLER; + pass.args[9].location.textureIndex = 9; + pass.args[9].location.samplerIndex = 9; + pass.args[9].size = 1; + pass.args[9].buffer = 0; + pass.args[9].u.codeSampler = TEXTURE_SRC_CODE_SHADOWMAP_SUN; + + pass.args[10].type = MTL_ARG_CODE_PIXEL_CONST; + pass.args[10].location.offset = 0x610; + pass.args[10].size = 0x10; + pass.args[10].buffer = 0; + pass.args[10].u.codeConst.index = CONST_SRC_CODE_SHADOWMAP_SWITCH_PARTITION; + pass.args[10].u.codeConst.firstRow = 0; + pass.args[10].u.codeConst.rowCount = 1; + + pass.args[11].type = MTL_ARG_CODE_PIXEL_CONST; + pass.args[11].location.offset = 0x630; + pass.args[11].size = 0x10; + pass.args[11].buffer = 0; + pass.args[11].u.codeConst.index = CONST_SRC_CODE_SUNSHADOWMAP_PIXEL_SIZE; + pass.args[11].u.codeConst.firstRow = 0; + pass.args[11].u.codeConst.rowCount = 1; + + pass.args[12].type = MTL_ARG_MATERIAL_PIXEL_CONST; + pass.args[12].location.offset = 0x3b0; + pass.args[12].size = 0x10; + pass.args[12].buffer = 1; + pass.args[12].u.nameHash = 0x88befc31; + + return technique; + } + + MaterialTechniqueSet* GivenTechset(Zone& zone, MemoryManager& memory) + { + auto* techset = memory.Alloc(); + techset->name = "example_techset"; + techset->worldVertFormat = MTL_WORLDVERT_TEX_4_NRM_2; + + techset->techniques[TECHNIQUE_DEPTH_PREPASS] = GivenDepthPrepassTechnique(memory); + techset->techniques[TECHNIQUE_LIT_SUN_SHADOW] = GivenLitSunShadowTechnique(memory); + + zone.m_pools.AddAsset(std::make_unique>(ASSET_TYPE_TECHNIQUE_SET, techset->name, techset)); + return techset; + } +} // namespace + +TEST_CASE("TechsetDumperT6", "[t6][techset][dumper]") +{ + Zone zone("MockZone", 0, GameId::T6, GamePlatform::PC); + zone.Register(); + + MemoryManager memory; + MockSearchPath mockObjPath; + MockOutputPath mockOutput; + AssetDumpingContext context(zone, "", mockOutput, mockObjPath, std::nullopt); + + GivenTechset(zone, memory); + + techset::DumperT6 dumper(true); + + SECTION("Can dump techset") + { + std::string expected(R"TECHSET( +"depth prepass": + example_zprepass; + +"lit sun shadow": + example_lit_sun_shadow; +)TECHSET"); + + dumper.Dump(context); + + const auto* file = mockOutput.GetMockedFile("techsets/example_techset.techset"); + REQUIRE(file); + REQUIRE(Trimmed(file->AsString()) == Trimmed(expected)); + } + + SECTION("Can dump simple technique") + { + std::string expected(R"TECHNIQUE( +// TECHNIQUE FLAGS: 0x4 +// TECHNIQUE FLAGS: 0x80 +{ + stateMap "passthrough"; // TODO + + vertexShader 4.0 "simple.hlsl" + { + // Omitted due to matching accessors: worldMatrix = constant.worldMatrix; + // Omitted due to matching accessors: viewProjectionMatrix = constant.viewProjectionMatrix; + } + + pixelShader 4.0 "simple.hlsl" + { + } + + vertex.position = code.position; +} +)TECHNIQUE"); + dumper.Dump(context); + + const auto* file = mockOutput.GetMockedFile("techniques/example_zprepass.tech"); + REQUIRE(file); + REQUIRE(Trimmed(file->AsString()) == Trimmed(expected)); + } + + SECTION("Can dump advanced technique") + { + std::string expected(R"TECHNIQUE( +// TECHNIQUE FLAGS: 0x8 +// TECHNIQUE FLAGS: 0x80 +{ + // CUSTOM SAMPLER FLAGS: 0x1 + // CUSTOM SAMPLER FLAGS: 0x2 + stateMap "passthrough"; // TODO + + vertexShader 4.0 "advanced.hlsl" + { + // Omitted due to matching accessors: worldMatrix = constant.worldMatrix; + // Omitted due to matching accessors: viewProjectionMatrix = constant.viewProjectionMatrix; + // Omitted due to matching accessors: shadowLookupMatrix = constant.shadowLookupMatrix; + } + + pixelShader 4.0 "advanced.hlsl" + { + normalMapSampler = material.normalMap; + normalMapSampler1 = material.normalMap1; + colorMapSampler = material.colorMap; + colorMapSampler1 = material.colorMap1; + colorMapSampler3 = material.colorMap3; + colorMapSampler2 = material.colorMap2; + // Omitted due to matching accessors: shadowmapSamplerSun = sampler.shadowmapSamplerSun; + // Omitted due to matching accessors: shadowmapSwitchPartition = constant.shadowmapSwitchPartition; + // Omitted due to matching accessors: sunShadowmapPixelSize = constant.sunShadowmapPixelSize; + alphaRevealParms1 = material.alphaRevealParms1; + } + + vertex.position = code.position; + vertex.color[0] = code.color; + vertex.texcoord[0] = code.texcoord[0]; + vertex.normal = code.normal; + vertex.texcoord[2] = code.tangent; + vertex.texcoord[1] = code.texcoord[1]; + vertex.texcoord[3] = code.texcoord[2]; + vertex.texcoord[4] = code.texcoord[3]; + vertex.texcoord[5] = code.normalTransform[0]; +} +)TECHNIQUE"); + dumper.Dump(context); + + const auto* file = mockOutput.GetMockedFile("techniques/example_lit_sun_shadow.tech"); + REQUIRE(file); + REQUIRE(Trimmed(file->AsString()) == Trimmed(expected)); + } +} diff --git a/test/ObjWritingTests/Game/T6/Techset/ps_advanced.hlsl.cso b/test/ObjWritingTests/Game/T6/Techset/ps_advanced.hlsl.cso new file mode 100644 index 0000000000000000000000000000000000000000..b01854324de62edc5d7d7705933b37bc30c43076 GIT binary patch literal 16412 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 IlD(DiUrF~qKmY&$ literal 0 HcmV?d00001 diff --git a/test/ObjWritingTests/Game/T6/Techset/ps_simple.hlsl.cso b/test/ObjWritingTests/Game/T6/Techset/ps_simple.hlsl.cso new file mode 100644 index 0000000000000000000000000000000000000000..cfe8445a2501036fc948b644c9b0391efd4260c6 GIT binary patch literal 432 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 KKeF{s?fwVKQMfh$ literal 0 HcmV?d00001 diff --git a/test/ObjWritingTests/Game/T6/Techset/vs_simple.hlsl.cso b/test/ObjWritingTests/Game/T6/Techset/vs_simple.hlsl.cso new file mode 100644 index 0000000000000000000000000000000000000000..50c95fc29c08b8338853f79221339352893c14be GIT binary patch literal 5964 zcmb8zUu+vm9S88qwc&ce-I?Ced!Q25U4aVm;5elei9fcJI;oUvmaJQna**tK$If2Y zyUXmlaZa4@@q_@O2qB?^2aF0Y1fd8OA*7QoZwLvbfI#8_iJ$|4xRE)Hm(7nX*%+jLI#k z?4}IlLKwtJEL`7fZzJ8Oem{@>``G)B;h)*4zqeyQJd52JB_Df-4hqIrO#A{;vT<+0 zi&U3R0$b12|1vpjy#6=gCC0xCuQ0w3w;2B!e2eklz$3=rg7+DpeWwt6jK3E?VEiKd zfblZ?knxYhkKjnsZP{ejksdSkUHA$7jH&ON`d^?F6Q^Q)&-ego#W>BY%zp~+GxdJ~ zKVJJlYy#EK(KjTk6j{f1}*Y`R29^+;BfblEv1IAb2hm5boj~I91$Bakt6UM&? z7pEuB|10nUB2r$@%{jwg4l@p@ixN2*xfM44$hA``XaiBS?eq4M3;ZsLZa8XZ27 zenr9c(Woz8YRgiEI(+%Mbd(5nZ(1R2V3Vhm+CA%-$P z(hps3eGD7rb*GtxD%JxxJjZk(vQtb0s!J`0L9XHG`KL9^=~s1q6V)EJ&OXerI}LN= zHOk{K{}8Ixn&}a@7=1~l+syPZA|qWa;7;?T?R#!kUBviY`Znx1k>&NIUv*#V#>vPK zvBjIsZAW43q*_2mNw?YwyFnt93|y%ij%v%q_Fk5v8^yGQxFe(|G>&KQcu8{`lP@s~ zM>^B#L_&YJ9R@VTWJ0%T{v6VdI}Q%+Ilj3^Z|^pg6POi9d7WzkrWC?mu}@#ZX7HD7 zEzd{Oh7*mfd05`lt?6{6a&AOIXXrjMSsSA!aIb_b^fLhNv9(;Zl#6OY?n-m|ZTy6w zyyn$$_*B<%AD(3t#!0<5Tr6|poXCacd^n#EFXh7z=flhS@FV%~N}l!RcVSIUTHZ;f^hnZj|P#QRMH6COs+ijkq=%ER6;=9W=ZksX2JUrHv?B zlz!squ;w|jXnKLf9QB%51ywEVO+cBR7Y9%2c~?O~PnPVrhS%X_+4D7f=lea}V*Ic0 zEyn)|j~JiD?_+(&-vi%cd=5Tfd*a3hCj+e+v|>D5GlmuP zLsG0pGN{H_of={2$Hj(>lOiorm}vZlYkkdLy8a=QQm?e$6tQPp_U7>@-v6yt`L z>UEkQt5e!gA6XlGEfn_6&EeC_US3@5p+W^m`W(tOa2e`fFCr(zMeJEj?dke#qAOJ> zASXl{bib(cbc}6GOPZIL@ymiTv$1|wmy>|Ck* z*(v4JhRSPG%IQ3)oQ}!$Psd1)Uo^+X@zZ+dvtKaf&rT_SUv~T{