2
0
mirror of https://github.com/Laupetin/OpenAssetTools.git synced 2025-11-22 21:02:07 +00:00

merge extended techset functioanality

This commit is contained in:
LJW-Dev
2025-07-07 23:08:58 +08:00
4 changed files with 299 additions and 12 deletions

View File

@@ -41,6 +41,7 @@
#include "ZBarrier/GdtLoaderZBarrierT6.h" #include "ZBarrier/GdtLoaderZBarrierT6.h"
#include "ZBarrier/RawLoaderZBarrierT6.h" #include "ZBarrier/RawLoaderZBarrierT6.h"
#include "CustomMap/LoaderCustomMapT6.h" #include "CustomMap/LoaderCustomMapT6.h"
#include "TechniqueSet/LoaderTechniqueSetT6.h"
#include <format> #include <format>
#include <memory> #include <memory>
@@ -403,7 +404,7 @@ namespace T6
// collection.AddAssetCreator(std::make_unique<AssetLoaderXAnim>(memory)); // collection.AddAssetCreator(std::make_unique<AssetLoaderXAnim>(memory));
collection.AddAssetCreator(CreateXModelLoader(memory, searchPath, zone)); collection.AddAssetCreator(CreateXModelLoader(memory, searchPath, zone));
collection.AddAssetCreator(CreateMaterialLoader(memory, searchPath)); collection.AddAssetCreator(CreateMaterialLoader(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderTechniqueSet>(memory)); collection.AddAssetCreator(CreateTechniqueSetLoader(memory, searchPath));
collection.AddAssetCreator(CreateImageLoader(memory, searchPath)); collection.AddAssetCreator(CreateImageLoader(memory, searchPath));
collection.AddAssetCreator(CreateSoundBankLoader(memory, searchPath)); collection.AddAssetCreator(CreateSoundBankLoader(memory, searchPath));
// collection.AddAssetCreator(std::make_unique<AssetLoaderSoundPatch>(memory)); // collection.AddAssetCreator(std::make_unique<AssetLoaderSoundPatch>(memory));

View File

@@ -0,0 +1,183 @@
#include "Game/T6/T6.h"
#include "LoaderTechniqueSetT6.h"
#include <cstring>
#include <format>
#include <nlohmann/json.hpp>
using namespace T6;
namespace
{
class TechniqueSetLoader final : public AssetCreator<AssetTechniqueSet>
{
public:
TechniqueSetLoader(MemoryManager& memory, ISearchPath& searchPath)
: m_memory(memory),
m_search_path(searchPath)
{
}
AssetCreationResult CreateAsset(const std::string& assetName, AssetCreationContext& context) override
{
const auto fileName = std::format("techniquesets/{}.json", assetName);
const auto file = m_search_path.Open(assetName);
if (!file.IsOpen())
return AssetCreationResult::NoAction();
MaterialTechniqueSet* techniqueSet = new MaterialTechniqueSet;
memset(techniqueSet, 0, sizeof(MaterialTechniqueSet));
const auto js = nlohmann::json::parse(*file.m_stream.get());
std::string techSetName = js["name"];
techniqueSet->name = _strdup(techSetName.c_str());
techniqueSet->worldVertFormat = (unsigned char)js["worldVertFormat"];
for (int i = 0; i < 36; i++)
{
nlohmann::json techniqueJs = js["techniques"][i];
if (techniqueJs.size() == 0)
{
techniqueSet->techniques[i] = NULL;
}
else
{
MaterialTechnique* technique = new MaterialTechnique;
techniqueSet->techniques[i] = technique;
std::string techName = techniqueJs["name"];
technique->name = _strdup(techName.c_str());
technique->flags = techniqueJs["flags"];
technique->passCount = techniqueJs["passCount"];
_ASSERT(technique->passCount == 1);
for (auto passIndex = 0u; passIndex < technique->passCount; passIndex++)
{
MaterialPass* currPass = &technique->passArray[passIndex];
nlohmann::json passJs = techniqueJs["passArray"][passIndex];
currPass->perPrimArgCount = (unsigned char)passJs["perPrimArgCount"];
currPass->perObjArgCount = (unsigned char)passJs["perObjArgCount"];
currPass->stableArgCount = (unsigned char)passJs["stableArgCount"];
currPass->customSamplerFlags = (unsigned char)passJs["customSamplerFlags"];
currPass->precompiledIndex = (unsigned char)passJs["precompiledIndex"];
currPass->materialType = (unsigned char)passJs["materialType"];
int argCount = currPass->perPrimArgCount + currPass->perObjArgCount + currPass->stableArgCount;
if (argCount == 0)
{
currPass->args = NULL;
}
else
{
currPass->args = new MaterialShaderArgument[argCount];
for (int i = 0; i < argCount; i++)
{
MaterialShaderArgument* currArg = &currPass->args[i];
auto currArgJs = passJs["args"][i];
currArg->type = currArgJs["type"];
currArg->location.offset = currArgJs["location"];
currArg->size = currArgJs["size"];
currArg->buffer = currArgJs["buffer"];
if (currArg->type == MTL_ARG_LITERAL_VERTEX_CONST || currArg->type == MTL_ARG_LITERAL_PIXEL_CONST)
{
float* consts = new float[4];
consts[0] = currArgJs["u"]["const0"];
consts[1] = currArgJs["u"]["const1"];
consts[2] = currArgJs["u"]["const2"];
consts[3] = currArgJs["u"]["const3"];
currArg->u.literalConst = (float(*)[4])consts;
}
else
{
currArg->u.nameHash = currArgJs["u"]["value"];
}
}
}
if (passJs["vertexDecl"].size() == 0)
{
currPass->vertexDecl = NULL;
}
else
{
currPass->vertexDecl = new MaterialVertexDeclaration;
currPass->vertexDecl->streamCount = (unsigned char)passJs["vertexDecl"]["streamCount"];
currPass->vertexDecl->hasOptionalSource = passJs["vertexDecl"]["hasOptionalSource"];
currPass->vertexDecl->isLoaded = passJs["vertexDecl"]["isLoaded"];
for (int i = 0; i < 16; i++)
{
currPass->vertexDecl->routing.data[i].source = (unsigned char)passJs["vertexDecl"]["routing"][i]["source"];
currPass->vertexDecl->routing.data[i].dest = (unsigned char)passJs["vertexDecl"]["routing"][i]["dest"];
}
}
if (passJs["pixelShader"].size() == 0)
{
currPass->pixelShader = NULL;
}
else
{
currPass->pixelShader = new MaterialPixelShader;
std::string pixelName = passJs["pixelShader"]["name"];
currPass->pixelShader->name = _strdup(pixelName.c_str());
currPass->pixelShader->prog.ps = NULL;
const auto psFileName = std::format("techniques/shader_bin/ps_{}", pixelName);
const auto psFile = m_search_path.Open(psFileName);
if (!psFile.IsOpen())
{
printf("ERROR: Cant find pixel shader %s\n", psFileName.c_str());
return AssetCreationResult::Failure();
}
currPass->pixelShader->prog.loadDef.programSize = psFile.m_length;
currPass->pixelShader->prog.loadDef.program = new char[psFile.m_length];
psFile.m_stream->read(currPass->pixelShader->prog.loadDef.program, psFile.m_length);
}
if (passJs["vertexShader"].size() == 0)
{
currPass->vertexShader = NULL;
}
else
{
currPass->vertexShader = new MaterialVertexShader;
std::string vertexName = passJs["vertexShader"]["name"];
currPass->vertexShader->name = _strdup(vertexName.c_str());
currPass->vertexShader->prog.vs = NULL;
const auto vsFileName = std::format("techniques/shader_bin/vs_{}", vertexName);
const auto vsFile = m_search_path.Open(vsFileName);
if (!vsFile.IsOpen())
{
printf("ERROR: Cant find vertex shader %s\n", vsFileName.c_str());
return AssetCreationResult::Failure();
}
currPass->vertexShader->prog.loadDef.programSize = vsFile.m_length;
currPass->vertexShader->prog.loadDef.program = new char[vsFile.m_length];
vsFile.m_stream->read(currPass->vertexShader->prog.loadDef.program, vsFile.m_length);
}
}
}
}
return AssetCreationResult::Success(context.AddAsset<AssetTechniqueSet>(assetName, techniqueSet));
}
private:
MemoryManager& m_memory;
ISearchPath& m_search_path;
};
} // namespace
namespace T6
{
std::unique_ptr<AssetCreator<AssetTechniqueSet>> CreateTechniqueSetLoader(MemoryManager& memory, ISearchPath& searchPath)
{
return std::make_unique<TechniqueSetLoader>(memory, searchPath);
}
} // namespace T6

View File

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

View File

@@ -1,5 +1,6 @@
#include "AssetDumperTechniqueSet.h" #include "AssetDumperTechniqueSet.h"
#include <nlohmann/json.hpp>
#include <sstream> #include <sstream>
#include <unordered_set> #include <unordered_set>
@@ -58,7 +59,7 @@ bool AssetDumperTechniqueSet::ShouldDump(XAssetInfo<MaterialTechniqueSet>* asset
void AssetDumperTechniqueSet::DumpPixelShader(const AssetDumpingContext& context, const MaterialPixelShader* pixelShader) void AssetDumperTechniqueSet::DumpPixelShader(const AssetDumpingContext& context, const MaterialPixelShader* pixelShader)
{ {
std::ostringstream ss; std::ostringstream ss;
ss << "shader_bin/ps_" << pixelShader->name << ".cso"; ss << "techniquesets/shader_bin/ps_" << pixelShader->name;
const auto shaderFile = context.OpenAssetFile(ss.str()); const auto shaderFile = context.OpenAssetFile(ss.str());
@@ -71,7 +72,7 @@ void AssetDumperTechniqueSet::DumpPixelShader(const AssetDumpingContext& context
void AssetDumperTechniqueSet::DumpVertexShader(const AssetDumpingContext& context, const MaterialVertexShader* vertexShader) void AssetDumperTechniqueSet::DumpVertexShader(const AssetDumpingContext& context, const MaterialVertexShader* vertexShader)
{ {
std::ostringstream ss; std::ostringstream ss;
ss << "shader_bin/vs_" << vertexShader->name << ".cso"; ss << "techniquesets/shader_bin/vs_" << vertexShader->name;
const auto shaderFile = context.OpenAssetFile(ss.str()); const auto shaderFile = context.OpenAssetFile(ss.str());
@@ -86,21 +87,110 @@ void AssetDumperTechniqueSet::DumpAsset(AssetDumpingContext& context, XAssetInfo
const auto* techniqueSet = asset->Asset(); const auto* techniqueSet = asset->Asset();
auto* shaderState = context.GetZoneAssetDumperState<ShaderZoneState>(); auto* shaderState = context.GetZoneAssetDumperState<ShaderZoneState>();
const auto assetFile = context.OpenAssetFile(std::format("techniquesets/{}.json", techniqueSet->name));
if (!assetFile)
return;
nlohmann::json js;
js["name"] = techniqueSet->name;
js["worldVertFormat"] = techniqueSet->worldVertFormat;
js["techniques"] = nlohmann::json::array();
for (const auto* technique : techniqueSet->techniques) for (const auto* technique : techniqueSet->techniques)
{ {
if (!technique || !shaderState->ShouldDumpTechnique(technique)) nlohmann::json techniqueJs = nlohmann::json::object();
continue;
if (technique != NULL)
{
techniqueJs["name"] = technique->name;
techniqueJs["flags"] = technique->flags;
techniqueJs["passCount"] = technique->passCount;
_ASSERT(technique->passCount == 1);
techniqueJs["passArray"] = nlohmann::json::array();
for (auto passIndex = 0u; passIndex < technique->passCount; passIndex++) for (auto passIndex = 0u; passIndex < technique->passCount; passIndex++)
{ {
const auto* pixelShader = technique->passArray[passIndex].pixelShader; const MaterialPass* currPass = &technique->passArray[passIndex];
nlohmann::json passJs = nlohmann::json::object();
if (pixelShader && shaderState->ShouldDumpPixelShader(pixelShader)) passJs["perPrimArgCount"] = currPass->perPrimArgCount;
DumpPixelShader(context, pixelShader); passJs["perObjArgCount"] = currPass->perObjArgCount;
passJs["stableArgCount"] = currPass->stableArgCount;
passJs["customSamplerFlags"] = currPass->customSamplerFlags;
passJs["precompiledIndex"] = currPass->precompiledIndex;
passJs["materialType"] = currPass->materialType;
const auto* vertexShader = technique->passArray[passIndex].vertexShader; nlohmann::json vertDeclJs = nlohmann::json::object();
if (vertexShader && shaderState->ShouldDumpVertexShader(vertexShader)) if (currPass->vertexDecl != NULL)
DumpVertexShader(context, vertexShader); {
vertDeclJs["streamCount"] = currPass->vertexDecl->streamCount;
vertDeclJs["hasOptionalSource"] = currPass->vertexDecl->hasOptionalSource;
vertDeclJs["isLoaded"] = currPass->vertexDecl->isLoaded;
for (int i = 0; i < 16; i++)
{
vertDeclJs["routing"][i]["source"] = currPass->vertexDecl->routing.data[i].source;
vertDeclJs["routing"][i]["dest"] = currPass->vertexDecl->routing.data[i].dest;
_ASSERT(currPass->vertexDecl->routing.decl[i] == NULL);
} }
} }
passJs["vertexDecl"] = vertDeclJs;
passJs["args"] = nlohmann::json::array();
if (currPass->args != NULL)
{
for (int i = 0; i < currPass->perPrimArgCount + currPass->perObjArgCount + currPass->stableArgCount; i++)
{
nlohmann::json argsJs = nlohmann::json::object();
MaterialShaderArgument* currArg = &currPass->args[i];
argsJs["type"] = currArg->type;
argsJs["location"] = currArg->location.offset;
argsJs["size"] = currArg->size;
argsJs["buffer"] = currArg->buffer;
if (currArg->type == MTL_ARG_LITERAL_VERTEX_CONST || currArg->type == MTL_ARG_LITERAL_PIXEL_CONST)
{
argsJs["u"]["const0"] = currArg->u.literalConst[0];
argsJs["u"]["const1"] = currArg->u.literalConst[1];
argsJs["u"]["const2"] = currArg->u.literalConst[2];
argsJs["u"]["const3"] = currArg->u.literalConst[3];
}
else
{
argsJs["u"]["value"] = currArg->u.nameHash;
}
passJs["args"].push_back(argsJs);
}
}
nlohmann::json pixelJs = nlohmann::json::object();
if (currPass->pixelShader != NULL)
{
pixelJs["name"] = currPass->pixelShader->name;
if (shaderState->ShouldDumpPixelShader(currPass->pixelShader))
DumpPixelShader(context, currPass->pixelShader);
}
passJs["pixelShader"] = pixelJs;
nlohmann::json vertexJs = nlohmann::json::object();
if (currPass->vertexShader != NULL)
{
vertexJs["name"] = currPass->vertexShader->name;
if (shaderState->ShouldDumpVertexShader(currPass->vertexShader))
DumpVertexShader(context, currPass->vertexShader);
}
passJs["vertexShader"] = vertexJs;
techniqueJs["passArray"].push_back(passJs);
}
}
js["techniques"].push_back(techniqueJs);
}
std::string jsonString = js.dump(4);
assetFile->write(jsonString.c_str(), jsonString.size());
} }