diff --git a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp index 37afdf89..7dff3c69 100644 --- a/src/ObjLoading/Game/T6/ObjLoaderT6.cpp +++ b/src/ObjLoading/Game/T6/ObjLoaderT6.cpp @@ -40,6 +40,7 @@ #include "Weapon/RawLoaderWeaponT6.h" #include "ZBarrier/GdtLoaderZBarrierT6.h" #include "ZBarrier/RawLoaderZBarrierT6.h" +#include "TechniqueSet/LoaderTechniqueSetT6.h" #include #include @@ -400,7 +401,7 @@ namespace T6 // collection.AddAssetCreator(std::make_unique(memory)); collection.AddAssetCreator(CreateXModelLoader(memory, searchPath, zone)); collection.AddAssetCreator(CreateMaterialLoader(memory, searchPath)); - // collection.AddAssetCreator(std::make_unique(memory)); + collection.AddAssetCreator(CreateTechniqueSetLoader(memory, searchPath)); collection.AddAssetCreator(CreateImageLoader(memory, searchPath)); collection.AddAssetCreator(CreateSoundBankLoader(memory, searchPath)); // collection.AddAssetCreator(std::make_unique(memory)); diff --git a/src/ObjLoading/Game/T6/TechniqueSet/LoaderTechniqueSetT6.cpp b/src/ObjLoading/Game/T6/TechniqueSet/LoaderTechniqueSetT6.cpp new file mode 100644 index 00000000..f9e793f5 --- /dev/null +++ b/src/ObjLoading/Game/T6/TechniqueSet/LoaderTechniqueSetT6.cpp @@ -0,0 +1,183 @@ +#include "Game/T6/T6.h" +#include "LoaderTechniqueSetT6.h" + +#include +#include +#include + +using namespace T6; + +namespace +{ + class TechniqueSetLoader final : public AssetCreator + { + 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(assetName, techniqueSet)); + } + + private: + MemoryManager& m_memory; + ISearchPath& m_search_path; + }; +} // namespace + +namespace T6 +{ + std::unique_ptr> CreateTechniqueSetLoader(MemoryManager& memory, ISearchPath& searchPath) + { + return std::make_unique(memory, searchPath); + } +} // namespace T6 diff --git a/src/ObjLoading/Game/T6/TechniqueSet/LoaderTechniqueSetT6.h b/src/ObjLoading/Game/T6/TechniqueSet/LoaderTechniqueSetT6.h new file mode 100644 index 00000000..78081a86 --- /dev/null +++ b/src/ObjLoading/Game/T6/TechniqueSet/LoaderTechniqueSetT6.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Asset/IAssetCreator.h" +#include "Game/T6/T6.h" +#include "SearchPath/ISearchPath.h" +#include "Utils/MemoryManager.h" + +#include + +namespace T6 +{ + std::unique_ptr> CreateTechniqueSetLoader(MemoryManager& memory, ISearchPath& searchPath); +} // namespace T6 diff --git a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperTechniqueSet.cpp b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperTechniqueSet.cpp index e5b0b142..9ff914a8 100644 --- a/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperTechniqueSet.cpp +++ b/src/ObjWriting/Game/T6/AssetDumpers/AssetDumperTechniqueSet.cpp @@ -1,5 +1,6 @@ #include "AssetDumperTechniqueSet.h" +#include #include #include @@ -58,7 +59,7 @@ bool AssetDumperTechniqueSet::ShouldDump(XAssetInfo* asset void AssetDumperTechniqueSet::DumpPixelShader(const AssetDumpingContext& context, const MaterialPixelShader* pixelShader) { std::ostringstream ss; - ss << "shader_bin/ps_" << pixelShader->name << ".cso"; + ss << "techniquesets/shader_bin/ps_" << pixelShader->name; 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) { std::ostringstream ss; - ss << "shader_bin/vs_" << vertexShader->name << ".cso"; + ss << "techniquesets/shader_bin/vs_" << vertexShader->name; const auto shaderFile = context.OpenAssetFile(ss.str()); @@ -86,21 +87,110 @@ void AssetDumperTechniqueSet::DumpAsset(AssetDumpingContext& context, XAssetInfo const auto* techniqueSet = asset->Asset(); auto* shaderState = context.GetZoneAssetDumperState(); + 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) { - if (!technique || !shaderState->ShouldDumpTechnique(technique)) - continue; + nlohmann::json techniqueJs = nlohmann::json::object(); - for (auto passIndex = 0u; passIndex < technique->passCount; passIndex++) + if (technique != NULL) { - const auto* pixelShader = technique->passArray[passIndex].pixelShader; + techniqueJs["name"] = technique->name; + techniqueJs["flags"] = technique->flags; + techniqueJs["passCount"] = technique->passCount; - if (pixelShader && shaderState->ShouldDumpPixelShader(pixelShader)) - DumpPixelShader(context, pixelShader); + _ASSERT(technique->passCount == 1); - const auto* vertexShader = technique->passArray[passIndex].vertexShader; - if (vertexShader && shaderState->ShouldDumpVertexShader(vertexShader)) - DumpVertexShader(context, vertexShader); + techniqueJs["passArray"] = nlohmann::json::array(); + for (auto passIndex = 0u; passIndex < technique->passCount; passIndex++) + { + const MaterialPass* currPass = &technique->passArray[passIndex]; + nlohmann::json passJs = nlohmann::json::object(); + + passJs["perPrimArgCount"] = currPass->perPrimArgCount; + passJs["perObjArgCount"] = currPass->perObjArgCount; + passJs["stableArgCount"] = currPass->stableArgCount; + passJs["customSamplerFlags"] = currPass->customSamplerFlags; + passJs["precompiledIndex"] = currPass->precompiledIndex; + passJs["materialType"] = currPass->materialType; + + nlohmann::json vertDeclJs = nlohmann::json::object(); + if (currPass->vertexDecl != NULL) + { + 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()); }