2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2026-01-23 08:31:51 +00:00

chore: make sure TechsetCompilerT6 sets proper worldVertFormat

This commit is contained in:
Jan Laupetin
2026-01-22 21:43:06 +00:00
parent d714afbcdd
commit d4a95d046e
16 changed files with 255 additions and 17 deletions

View File

@@ -1468,10 +1468,26 @@ namespace IW3
TECHNIQUE_NONE = 0x24, TECHNIQUE_NONE = 0x24,
}; };
enum MaterialWorldVertexFormat : unsigned char
{
MTL_WORLDVERT_TEX_1_NRM_1 = 0x0,
MTL_WORLDVERT_TEX_2_NRM_1 = 0x1,
MTL_WORLDVERT_TEX_2_NRM_2 = 0x2,
MTL_WORLDVERT_TEX_3_NRM_1 = 0x3,
MTL_WORLDVERT_TEX_3_NRM_2 = 0x4,
MTL_WORLDVERT_TEX_3_NRM_3 = 0x5,
MTL_WORLDVERT_TEX_4_NRM_1 = 0x6,
MTL_WORLDVERT_TEX_4_NRM_2 = 0x7,
MTL_WORLDVERT_TEX_4_NRM_3 = 0x8,
MTL_WORLDVERT_TEX_5_NRM_1 = 0x9,
MTL_WORLDVERT_TEX_5_NRM_2 = 0xA,
MTL_WORLDVERT_TEX_5_NRM_3 = 0xB,
};
struct MaterialTechniqueSet struct MaterialTechniqueSet
{ {
const char* name; const char* name;
char worldVertFormat; MaterialWorldVertexFormat worldVertFormat;
bool hasBeenUploaded; bool hasBeenUploaded;
char unused[1]; char unused[1];
MaterialTechniqueSet* remappedTechniqueSet; MaterialTechniqueSet* remappedTechniqueSet;

View File

@@ -1721,10 +1721,26 @@ namespace IW4
TECHNIQUE_COUNT TECHNIQUE_COUNT
}; };
enum MaterialWorldVertexFormat : unsigned char
{
MTL_WORLDVERT_TEX_1_NRM_1 = 0x0,
MTL_WORLDVERT_TEX_2_NRM_1 = 0x1,
MTL_WORLDVERT_TEX_2_NRM_2 = 0x2,
MTL_WORLDVERT_TEX_3_NRM_1 = 0x3,
MTL_WORLDVERT_TEX_3_NRM_2 = 0x4,
MTL_WORLDVERT_TEX_3_NRM_3 = 0x5,
MTL_WORLDVERT_TEX_4_NRM_1 = 0x6,
MTL_WORLDVERT_TEX_4_NRM_2 = 0x7,
MTL_WORLDVERT_TEX_4_NRM_3 = 0x8,
MTL_WORLDVERT_TEX_5_NRM_1 = 0x9,
MTL_WORLDVERT_TEX_5_NRM_2 = 0xA,
MTL_WORLDVERT_TEX_5_NRM_3 = 0xB,
};
struct MaterialTechniqueSet struct MaterialTechniqueSet
{ {
const char* name; const char* name;
unsigned char worldVertFormat; MaterialWorldVertexFormat worldVertFormat;
bool hasBeenUploaded; bool hasBeenUploaded;
unsigned char unused[1]; unsigned char unused[1];
MaterialTechniqueSet* remappedTechniqueSet; MaterialTechniqueSet* remappedTechniqueSet;

View File

@@ -1102,10 +1102,26 @@ namespace IW5
MaterialPass passArray[1]; MaterialPass passArray[1];
}; };
enum MaterialWorldVertexFormat : unsigned char
{
MTL_WORLDVERT_TEX_1_NRM_1 = 0x0,
MTL_WORLDVERT_TEX_2_NRM_1 = 0x1,
MTL_WORLDVERT_TEX_2_NRM_2 = 0x2,
MTL_WORLDVERT_TEX_3_NRM_1 = 0x3,
MTL_WORLDVERT_TEX_3_NRM_2 = 0x4,
MTL_WORLDVERT_TEX_3_NRM_3 = 0x5,
MTL_WORLDVERT_TEX_4_NRM_1 = 0x6,
MTL_WORLDVERT_TEX_4_NRM_2 = 0x7,
MTL_WORLDVERT_TEX_4_NRM_3 = 0x8,
MTL_WORLDVERT_TEX_5_NRM_1 = 0x9,
MTL_WORLDVERT_TEX_5_NRM_2 = 0xA,
MTL_WORLDVERT_TEX_5_NRM_3 = 0xB,
};
struct MaterialTechniqueSet struct MaterialTechniqueSet
{ {
const char* name; const char* name;
unsigned char worldVertFormat; MaterialWorldVertexFormat worldVertFormat;
unsigned char unused[2]; unsigned char unused[2];
MaterialTechniqueSet* remappedTechniqueSet; MaterialTechniqueSet* remappedTechniqueSet;
MaterialTechnique* techniques[54]; MaterialTechnique* techniques[54];

View File

@@ -1720,10 +1720,23 @@ namespace T5
TECHNIQUE_COUNT TECHNIQUE_COUNT
}; };
enum MaterialWorldVertexFormat : unsigned char
{
MTL_WORLDVERT_TEX_1_NRM_1 = 0x0,
MTL_WORLDVERT_TEX_2_NRM_1 = 0x1,
MTL_WORLDVERT_TEX_2_NRM_2 = 0x2,
MTL_WORLDVERT_TEX_3_NRM_1 = 0x3,
MTL_WORLDVERT_TEX_3_NRM_2 = 0x4,
MTL_WORLDVERT_TEX_3_NRM_3 = 0x5,
MTL_WORLDVERT_TEX_4_NRM_1 = 0x6,
MTL_WORLDVERT_TEX_4_NRM_2 = 0x7,
MTL_WORLDVERT_TEX_4_NRM_3 = 0x8,
};
struct MaterialTechniqueSet struct MaterialTechniqueSet
{ {
const char* name; const char* name;
char worldVertFormat; MaterialWorldVertexFormat worldVertFormat;
char unused[1]; char unused[1];
uint16_t techsetFlags; uint16_t techsetFlags;
MaterialTechnique* techniques[130]; MaterialTechnique* techniques[130];

View File

@@ -840,10 +840,23 @@ namespace T6
TECHNIQUE_COUNT TECHNIQUE_COUNT
}; };
enum MaterialWorldVertexFormat : unsigned char
{
MTL_WORLDVERT_TEX_1_NRM_1 = 0x0,
MTL_WORLDVERT_TEX_2_NRM_1 = 0x1,
MTL_WORLDVERT_TEX_2_NRM_2 = 0x2,
MTL_WORLDVERT_TEX_3_NRM_1 = 0x3,
MTL_WORLDVERT_TEX_3_NRM_2 = 0x4,
MTL_WORLDVERT_TEX_3_NRM_3 = 0x5,
MTL_WORLDVERT_TEX_4_NRM_1 = 0x6,
MTL_WORLDVERT_TEX_4_NRM_2 = 0x7,
MTL_WORLDVERT_TEX_4_NRM_3 = 0x8,
};
struct MaterialTechniqueSet struct MaterialTechniqueSet
{ {
const char* name; const char* name;
char worldVertFormat; MaterialWorldVertexFormat worldVertFormat;
MaterialTechnique* techniques[36]; MaterialTechnique* techniques[36];
}; };

View File

@@ -46,4 +46,10 @@ namespace techset
m_technique_names(std::move(techniqueNames)) m_technique_names(std::move(techniqueNames))
{ {
} }
CommonTechset::CommonTechset(std::string name, const size_t techniqueTypeCount)
: m_name(std::move(name)),
m_technique_names(techniqueTypeCount)
{
}
} // namespace techset } // namespace techset

View File

@@ -28,6 +28,7 @@ namespace techset
CommonTechset() = default; CommonTechset() = default;
explicit CommonTechset(size_t techniqueTypeCount); explicit CommonTechset(size_t techniqueTypeCount);
CommonTechset(std::string name, std::vector<std::string> techniqueNames); CommonTechset(std::string name, std::vector<std::string> techniqueNames);
CommonTechset(std::string name, size_t techniqueTypeCount);
std::string m_name; std::string m_name;
std::vector<std::string> m_technique_names; std::vector<std::string> m_technique_names;

View File

@@ -18,4 +18,28 @@ namespace techset
{ {
return std::format("techsets/{}.techset", assetName); return std::format("techsets/{}.techset", assetName);
} }
void CountWorldVertFormatParameters(const std::string& assetName, size_t& texCount, size_t& normalCount)
{
texCount = 0;
normalCount = 0;
if (assetName.empty())
return;
const auto nameLen = assetName.size();
for (auto pos = 1u; pos < nameLen - 1u; pos++)
{
if (assetName[pos - 1] != '_' && !isdigit(assetName[pos - 1]))
continue;
if (!isdigit(assetName[pos + 1]))
continue;
const auto c = tolower(assetName[pos]);
if (c == 'c')
texCount++;
else if (c == 'n')
normalCount++;
}
}
} // namespace techset } // namespace techset

View File

@@ -7,4 +7,6 @@ namespace techset
std::string GetFileNameForStateMapName(const std::string& stateMapName); std::string GetFileNameForStateMapName(const std::string& stateMapName);
std::string GetFileNameForTechniqueName(const std::string& assetName); std::string GetFileNameForTechniqueName(const std::string& assetName);
std::string GetFileNameForTechsetName(const std::string& assetName); std::string GetFileNameForTechsetName(const std::string& assetName);
void CountWorldVertFormatParameters(const std::string& assetName, size_t& texCount, size_t& normalCount);
} // namespace techset } // namespace techset

View File

@@ -1,16 +1,81 @@
#include "TechsetCompilerT6.h" #include "TechsetCompilerT6.h"
#include "Game/T6/T6.h" #include "Game/T6/T6.h"
#include "Game/T6/Techset/TechsetConstantsT6.h"
#include "Techset/CommonTechsetLoader.h"
#include "Techset/TechsetCommon.h"
using namespace T6;
namespace namespace
{ {
class TechsetCompilerT6 final : public AssetCreator<T6::AssetTechniqueSet> MaterialWorldVertexFormat GetWorldVertexFormat(const std::string& name)
{
if (name.contains("lit_"))
{
size_t texCount = 0u, normalCount = 0u;
techset::CountWorldVertFormatParameters(name, texCount, normalCount);
// 0 and 1 seem to be treated equally
texCount = std::max(texCount, 1u);
normalCount = std::max(normalCount, 1u);
if (texCount == 1 && normalCount == 1)
return MTL_WORLDVERT_TEX_1_NRM_1;
if (texCount == 2 && normalCount == 1)
return MTL_WORLDVERT_TEX_2_NRM_1;
if (texCount == 2 && normalCount == 2)
return MTL_WORLDVERT_TEX_2_NRM_2;
if (texCount == 3 && normalCount == 1)
return MTL_WORLDVERT_TEX_3_NRM_1;
if (texCount == 3 && normalCount == 2)
return MTL_WORLDVERT_TEX_3_NRM_2;
if (texCount == 3 && normalCount == 3)
return MTL_WORLDVERT_TEX_3_NRM_3;
if (texCount == 4 && normalCount == 1)
return MTL_WORLDVERT_TEX_4_NRM_1;
if (texCount == 4 && normalCount == 2)
return MTL_WORLDVERT_TEX_4_NRM_2;
if (texCount == 4 && normalCount == 3)
return MTL_WORLDVERT_TEX_4_NRM_3;
}
return static_cast<MaterialWorldVertexFormat>(0);
}
MaterialTechniqueSet* ConvertTechniqueSet(const techset::CommonTechset& commonTechset, MemoryManager& memory)
{
auto* techset = memory.Alloc<MaterialTechniqueSet>();
techset->name = memory.Dup(commonTechset.m_name.c_str());
techset->worldVertFormat = GetWorldVertexFormat(commonTechset.m_name);
return techset;
}
class TechsetCompilerT6 final : public AssetCreator<AssetTechniqueSet>
{ {
public: public:
TechsetCompilerT6(ISearchPath& searchPath, MemoryManager& memory)
: m_search_path(searchPath),
m_memory(memory)
{
}
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
{ {
return AssetCreationResult::NoAction(); bool failure = false;
const auto commonTechset = techset::LoadCommonTechset(assetName, commonTechniqueTypeNames, m_search_path, failure);
if (!commonTechset)
return failure ? AssetCreationResult::Failure() : AssetCreationResult::NoAction();
auto* techset = ConvertTechniqueSet(*commonTechset, m_memory);
return AssetCreationResult::Success(context.AddAsset(AssetRegistration<AssetTechniqueSet>(assetName, techset)));
} }
private:
ISearchPath& m_search_path;
MemoryManager& m_memory;
}; };
} // namespace } // namespace
@@ -18,6 +83,6 @@ namespace techset
{ {
std::unique_ptr<IAssetCreator> CreateCompilerT6(MemoryManager& memory, ISearchPath& searchPath) std::unique_ptr<IAssetCreator> CreateCompilerT6(MemoryManager& memory, ISearchPath& searchPath)
{ {
return std::make_unique<TechsetCompilerT6>(); return std::make_unique<TechsetCompilerT6>(searchPath, memory);
} }
} // namespace techset } // namespace techset

View File

@@ -20,7 +20,7 @@ namespace techset
{ {
failure = false; failure = false;
const auto fileName = GetFileNameForTechniqueName(assetName); const auto fileName = GetFileNameForTechsetName(assetName);
const auto techniqueFile = searchPath.Open(fileName); const auto techniqueFile = searchPath.Open(fileName);
if (!techniqueFile.IsOpen()) if (!techniqueFile.IsOpen())
return nullptr; return nullptr;
@@ -36,7 +36,7 @@ namespace techset
CommentRemovingStreamProxy commentProxy(&baseStream); CommentRemovingStreamProxy commentProxy(&baseStream);
const auto lexer = std::make_unique<SimpleLexer>(&commentProxy, std::move(lexerConfig)); const auto lexer = std::make_unique<SimpleLexer>(&commentProxy, std::move(lexerConfig));
const auto parser = std::make_unique<TechsetParser>(*lexer, techniqueTypeNames); const auto parser = std::make_unique<TechsetParser>(*lexer, assetName, techniqueTypeNames);
const auto success = parser->Parse(); const auto success = parser->Parse();
if (success) if (success)

View File

@@ -72,8 +72,8 @@ namespace
namespace techset namespace techset
{ {
TechsetParser::TechsetParser(SimpleLexer& lexer, const CommonTechniqueTypeNames& techniqueTypeNames) TechsetParser::TechsetParser(SimpleLexer& lexer, std::string techsetName, const CommonTechniqueTypeNames& techniqueTypeNames)
: AbstractParser(&lexer, std::make_unique<TechsetParserState>(techniqueTypeNames)) : AbstractParser(&lexer, std::make_unique<TechsetParserState>(std::move(techsetName), techniqueTypeNames))
{ {
} }

View File

@@ -10,7 +10,7 @@ namespace techset
class TechsetParser final : public AbstractParser<SimpleParserValue, TechsetParserState> class TechsetParser final : public AbstractParser<SimpleParserValue, TechsetParserState>
{ {
public: public:
TechsetParser(SimpleLexer& lexer, const CommonTechniqueTypeNames& techniqueTypeNames); TechsetParser(SimpleLexer& lexer, std::string techsetName, const CommonTechniqueTypeNames& techniqueTypeNames);
[[nodiscard]] std::unique_ptr<CommonTechset> GetParsingResult() const; [[nodiscard]] std::unique_ptr<CommonTechset> GetParsingResult() const;
protected: protected:

View File

@@ -2,9 +2,9 @@
namespace techset namespace techset
{ {
TechsetParserState::TechsetParserState(const CommonTechniqueTypeNames& techniqueTypeNames) TechsetParserState::TechsetParserState(std::string techsetName, const CommonTechniqueTypeNames& techniqueTypeNames)
: m_technique_type_names(techniqueTypeNames), : m_technique_type_names(techniqueTypeNames),
m_definition(std::make_unique<CommonTechset>(techniqueTypeNames.GetTechniqueTypeCount())) m_definition(std::make_unique<CommonTechset>(std::move(techsetName), techniqueTypeNames.GetTechniqueTypeCount()))
{ {
} }
} // namespace techset } // namespace techset

View File

@@ -4,6 +4,7 @@
#include <cstddef> #include <cstddef>
#include <memory> #include <memory>
#include <string>
#include <vector> #include <vector>
namespace techset namespace techset
@@ -11,7 +12,7 @@ namespace techset
class TechsetParserState class TechsetParserState
{ {
public: public:
explicit TechsetParserState(const CommonTechniqueTypeNames& techniqueTypeNames); TechsetParserState(std::string techsetName, const CommonTechniqueTypeNames& techniqueTypeNames);
const CommonTechniqueTypeNames& m_technique_type_names; const CommonTechniqueTypeNames& m_technique_type_names;
std::unique_ptr<CommonTechset> m_definition; std::unique_ptr<CommonTechset> m_definition;

View File

@@ -0,0 +1,65 @@
#include "Game/T6/Techset/TechsetCompilerT6.h"
#include "Game/T6/GameAssetPoolT6.h"
#include "SearchPath/MockSearchPath.h"
#include "Utils/TestMemoryManager.h"
#include <catch2/catch_test_macros.hpp>
#include <catch2/generators/catch_generators.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
#include <memory>
using namespace T6;
using namespace std::string_literals;
TEST_CASE("Game::T6::Techset::TechsetCompilerT6", "[techset][t6]")
{
Zone zone("test", 0, GameId::T6, GamePlatform::PC);
AssetCreatorCollection creators(zone);
IgnoredAssetLookup ignoredAssets;
AssetCreationContext context(zone, &creators, &ignoredAssets);
MockSearchPath searchPath;
TestMemoryManager memory;
const auto sut = ::techset::CreateCompilerT6(memory, searchPath);
SECTION("Sets correct worldVertFormat")
{
const auto [techsetName, expectedWorldVertFormat] = GENERATE(Catch::Generators::table<const char*, MaterialWorldVertexFormat>({
{"default", MTL_WORLDVERT_TEX_1_NRM_1},
{"effect_zeqqz943", MTL_WORLDVERT_TEX_1_NRM_1},
{"lit_r0c0_t1c1n1", MTL_WORLDVERT_TEX_2_NRM_1},
{"lit_r0c0n0x0_b1c1n1s1v1", MTL_WORLDVERT_TEX_2_NRM_2},
{"lit_r0c0n0x0_b1c1n1s1v1_b2c2n2x2", MTL_WORLDVERT_TEX_3_NRM_3},
{"lit_sm_b0c0_b1c1_b2c2", MTL_WORLDVERT_TEX_3_NRM_1},
{"lit_sm_b0c0_b1c1n1x1_b2c2n2v2", MTL_WORLDVERT_TEX_3_NRM_2},
{"lit_sm_r0c0_b1c1_b2c2_b3c3", MTL_WORLDVERT_TEX_4_NRM_1},
{"lit_sm_r0c0n0_b1c1_b2c2n2v2_m3c3", MTL_WORLDVERT_TEX_4_NRM_2},
{"lit_sm_r0c0n0_b1c1n1s1", MTL_WORLDVERT_TEX_2_NRM_2},
{"lit_sm_r0c0n0s0_b1c1n1s1_b2c2n2", MTL_WORLDVERT_TEX_3_NRM_3},
{"lit_sm_r0c0n0x0_b1c1_b2c2n2s2", MTL_WORLDVERT_TEX_3_NRM_2},
{"lit_sm_r0c0n0x0_b1c1n1_b2c2n2s2v2", MTL_WORLDVERT_TEX_3_NRM_3},
{"lit_sm_r0c0n0x0_b1c1s1v1_m2c2_m3c3", MTL_WORLDVERT_TEX_4_NRM_1},
{"lit_sm_r0c0n0x0_b1c1v1_b2c2n2s2_m3c3", MTL_WORLDVERT_TEX_4_NRM_2},
{"lit_sm_r0c0s0_b1c1n1s1_m2c2", MTL_WORLDVERT_TEX_3_NRM_1},
{"lit_sm_r0c0x0_b1c1", MTL_WORLDVERT_TEX_2_NRM_1},
{"lit_sm_r0c0x0_b1c1n1s1_b2c2n2s2", MTL_WORLDVERT_TEX_3_NRM_2},
{"lit_sm_r0c0x0_m1c1_m2c2_m3c3", MTL_WORLDVERT_TEX_4_NRM_1},
{"lit_sm_t0c0n0_b1c1n1v1", MTL_WORLDVERT_TEX_2_NRM_2},
{"lit_sm_t0c0n0s0_b1c1n1_b2c2n2s2v2", MTL_WORLDVERT_TEX_3_NRM_3},
{"mc_lit_sm_r0c0d0_2213939z", MTL_WORLDVERT_TEX_1_NRM_1},
{"wpc_lit_sm_b0c0s0_3f3q946z", MTL_WORLDVERT_TEX_1_NRM_1},
{"wpc_lit_sm_r0c0n0s0o0_qj92q1f8", MTL_WORLDVERT_TEX_1_NRM_1},
{"wpc_sw4_3d_burning_embers_nuketown_74j6971w", MTL_WORLDVERT_TEX_1_NRM_1},
{"wpc_unlitdecalblend_add_j26wq580", MTL_WORLDVERT_TEX_1_NRM_1},
}));
CAPTURE(techsetName);
searchPath.AddFileData(std::format("techsets/{}.techset", techsetName), "");
const auto result = sut->CreateAsset(techsetName, context);
REQUIRE(result.HasBeenSuccessful());
const auto* techset = static_cast<MaterialTechniqueSet*>(result.GetAssetInfo()->m_ptr);
CHECK(techset->worldVertFormat == expectedWorldVertFormat);
}
}