diff --git a/src/ObjCommon/Game/T6/Json/JsonXModel.h b/src/ObjCommon/Game/T6/Json/JsonXModel.h new file mode 100644 index 00000000..28ac5563 --- /dev/null +++ b/src/ObjCommon/Game/T6/Json/JsonXModel.h @@ -0,0 +1,36 @@ +#pragma once + +#include "Game/T6/T6.h" + +#include "Json/JsonCommon.h" +#include "Json/JsonExtension.h" +#include +#include +#include +#include +#include + +namespace T6 +{ + class JsonXModelLod + { + public: + std::string file; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonXModelLod, file); + + class JsonXModel + { + public: + std::vector lods; + unsigned collLod; + std::optional physPreset; + std::optional physConstraints; + unsigned flags; + JsonVec3 lightingOriginOffset; + float lightingOriginRange; + }; + + NLOHMANN_DEFINE_TYPE_EXTENSION(JsonXModel, lods, collLod, physPreset, physConstraints, flags, lightingOriginOffset, lightingOriginRange); +} // namespace T6 diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderXModel.cpp b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderXModel.cpp new file mode 100644 index 00000000..8cbbd072 --- /dev/null +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderXModel.cpp @@ -0,0 +1,44 @@ +#include "AssetLoaderXModel.h" + +#include "Game/T6/XModel/JsonXModelLoader.h" +#include "Game/T6/T6.h" +#include "Pool/GlobalAssetPool.h" + +#include +#include +#include + +using namespace T6; + +void* AssetLoaderXModel::CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) +{ + auto* xmodel = memory->Create(); + memset(xmodel, 0, sizeof(XModel)); + xmodel->name = memory->Dup(assetName.c_str()); + + return xmodel; +} + +bool AssetLoaderXModel::CanLoadFromRaw() const +{ + return true; +} + +bool AssetLoaderXModel::LoadFromRaw( + const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const +{ + const auto file = searchPath->Open(std::format("xmodel/{}.json", assetName)); + if (!file.IsOpen()) + return false; + + auto* xmodel = memory->Alloc(); + xmodel->name = memory->Dup(assetName.c_str()); + + std::vector dependencies; + if (LoadXModelAsJson(*file.m_stream, *xmodel, memory, manager, dependencies)) + manager->AddAsset(assetName, xmodel, std::move(dependencies)); + else + std::cerr << "Failed to load xmodel \"" << assetName << "\"\n"; + + return true; +} diff --git a/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderXModel.h b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderXModel.h new file mode 100644 index 00000000..0e0115da --- /dev/null +++ b/src/ObjLoading/Game/T6/AssetLoaders/AssetLoaderXModel.h @@ -0,0 +1,19 @@ +#pragma once +#include "AssetLoading/BasicAssetLoader.h" +#include "AssetLoading/IAssetLoadingManager.h" +#include "Game/T6/T6.h" +#include "SearchPath/ISearchPath.h" + +namespace T6 +{ + class AssetLoaderXModel final : public BasicAssetLoader + { + static std::string GetFileNameForAsset(const std::string& assetName); + + public: + _NODISCARD void* CreateEmptyAsset(const std::string& assetName, MemoryManager* memory) override; + _NODISCARD bool CanLoadFromRaw() const override; + bool + LoadFromRaw(const std::string& assetName, ISearchPath* searchPath, MemoryManager* memory, IAssetLoadingManager* manager, Zone* zone) const override; + }; +} // namespace T6 diff --git a/src/ObjLoading/Game/T6/XModel/JsonXModelLoader.cpp b/src/ObjLoading/Game/T6/XModel/JsonXModelLoader.cpp new file mode 100644 index 00000000..6dc2268a --- /dev/null +++ b/src/ObjLoading/Game/T6/XModel/JsonXModelLoader.cpp @@ -0,0 +1,116 @@ +#include "JsonXModelLoader.h" + +#include "Game/T6/CommonT6.h" +#include "Game/T6/Json/JsonXModel.h" + +#include +#include +#include + +using namespace nlohmann; +using namespace T6; + +namespace +{ + class JsonLoader + { + public: + JsonLoader(std::istream& stream, MemoryManager& memory, IAssetLoadingManager& manager, std::set& dependencies) + : m_stream(stream), + m_memory(memory), + m_manager(manager), + m_dependencies(dependencies) + + { + } + + bool Load(XModel& xmodel) const + { + const auto jRoot = json::parse(m_stream); + std::string type; + unsigned version; + + jRoot.at("_type").get_to(type); + jRoot.at("_version").get_to(version); + + if (type != "xmodel" || version != 1u) + { + std::cerr << "Tried to load xmodel \"" << xmodel.name << "\" but did not find expected type material of version 1\n"; + return false; + } + + const auto jXModel = jRoot.get(); + return CreateXModelFromJson(jXModel, xmodel); + } + + private: + static void PrintError(const XModel& xmodel, const std::string& message) + { + std::cerr << "Cannot load xmodel \"" << xmodel.name << "\": " << message << "\n"; + } + + bool CreateXModelFromJson(const JsonXModel& jXModel, XModel& xmodel) const + { + xmodel.collLod = static_cast(jXModel.collLod); + + if (jXModel.physPreset) + { + auto* physPreset = m_manager.LoadDependency(jXModel.physPreset.value()); + if (!physPreset) + { + PrintError(xmodel, "Could not find phys preset"); + return false; + } + m_dependencies.emplace(physPreset); + xmodel.physPreset = physPreset->Asset(); + } + else + { + xmodel.physPreset = nullptr; + } + + if (jXModel.physConstraints) + { + auto* physConstraints = m_manager.LoadDependency(jXModel.physConstraints.value()); + if (!physConstraints) + { + PrintError(xmodel, "Could not find phys constraints"); + return false; + } + m_dependencies.emplace(physConstraints); + xmodel.physConstraints = physConstraints->Asset(); + } + else + { + xmodel.physConstraints = nullptr; + } + + xmodel.flags = jXModel.flags; + xmodel.lightingOriginOffset.x = jXModel.lightingOriginOffset.x; + xmodel.lightingOriginOffset.y = jXModel.lightingOriginOffset.y; + xmodel.lightingOriginOffset.z = jXModel.lightingOriginOffset.z; + xmodel.lightingOriginRange = jXModel.lightingOriginRange; + + return true; + } + + std::istream& m_stream; + MemoryManager& m_memory; + IAssetLoadingManager& m_manager; + std::set& m_dependencies; + }; +} // namespace + +namespace T6 +{ + bool LoadXModelAsJson( + std::istream& stream, XModel& xmodel, MemoryManager* memory, IAssetLoadingManager* manager, std::vector& dependencies) + { + std::set dependenciesSet; + const JsonLoader loader(stream, *memory, *manager, dependenciesSet); + + dependencies.assign_range(dependenciesSet); + + return loader.Load(xmodel); + } +} // namespace T6 diff --git a/src/ObjLoading/Game/T6/XModel/JsonXModelLoader.h b/src/ObjLoading/Game/T6/XModel/JsonXModelLoader.h new file mode 100644 index 00000000..d7747287 --- /dev/null +++ b/src/ObjLoading/Game/T6/XModel/JsonXModelLoader.h @@ -0,0 +1,13 @@ +#pragma once + +#include "AssetLoading/IAssetLoadingManager.h" +#include "Game/T6/T6.h" +#include "Utils/MemoryManager.h" + +#include + +namespace T6 +{ + bool LoadXModelAsJson( + std::istream& stream, XModel& xmodel, MemoryManager* memory, IAssetLoadingManager* manager, std::vector& dependencies); +} // namespace T6 diff --git a/src/ObjWriting/Game/T6/XModel/JsonXModelWriter.cpp b/src/ObjWriting/Game/T6/XModel/JsonXModelWriter.cpp new file mode 100644 index 00000000..5f05331a --- /dev/null +++ b/src/ObjWriting/Game/T6/XModel/JsonXModelWriter.cpp @@ -0,0 +1,71 @@ +#include "JsonXModelWriter.h" + +#include "Game/T6/CommonT6.h" +#include "Game/T6/Json/JsonXModel.h" + +#include +#include + +using namespace nlohmann; +using namespace T6; + +namespace +{ + class JsonDumper + { + public: + JsonDumper(AssetDumpingContext& context, std::ostream& stream) + : m_stream(stream) + { + } + + void Dump(const XModel* xmodel) const + { + JsonXModel jsonXModel; + CreateJsonXModel(jsonXModel, *xmodel); + json jRoot = jsonXModel; + + jRoot["_type"] = "xmodel"; + jRoot["_version"] = 1; + + m_stream << std::setw(4) << jRoot << "\n"; + } + + private: + static const char* AssetName(const char* input) + { + if (input && input[0] == ',') + return &input[1]; + + return input; + } + + void CreateJsonXModel(JsonXModel& jXModel, const XModel& xmodel) const + { + jXModel.collLod = xmodel.collLod; + + if (xmodel.physPreset && xmodel.physPreset->name) + jXModel.physPreset = AssetName(xmodel.physPreset->name); + + if (xmodel.physConstraints && xmodel.physConstraints->name) + jXModel.physConstraints = AssetName(xmodel.physConstraints->name); + + jXModel.flags = xmodel.flags; + jXModel.lightingOriginOffset.x = xmodel.lightingOriginOffset.x; + jXModel.lightingOriginOffset.y = xmodel.lightingOriginOffset.y; + jXModel.lightingOriginOffset.z = xmodel.lightingOriginOffset.z; + jXModel.lightingOriginRange = xmodel.lightingOriginRange; + } + + std::ostream& m_stream; + }; +} // namespace + +namespace T6 +{ + void DumpXModelAsJson(std::ostream& stream, const XModel* xmodel, AssetDumpingContext& context) + { + const JsonDumper dumper(context, stream); + dumper.Dump(xmodel); + } +} // namespace T6 diff --git a/src/ObjWriting/Game/T6/XModel/JsonXModelWriter.h b/src/ObjWriting/Game/T6/XModel/JsonXModelWriter.h new file mode 100644 index 00000000..f40f008d --- /dev/null +++ b/src/ObjWriting/Game/T6/XModel/JsonXModelWriter.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Dumping/AssetDumpingContext.h" +#include "Game/T6/T6.h" + +#include + +namespace T6 +{ + void DumpXModelAsJson(std::ostream& stream, const XModel* xmodel, AssetDumpingContext& context); +} // namespace T6 diff --git a/src/ObjWriting/Model/XModel/XModelExportWriter.cpp b/src/ObjWriting/Model/XModel/XModelExportWriter.cpp index c8b96395..668ee9ea 100644 --- a/src/ObjWriting/Model/XModel/XModelExportWriter.cpp +++ b/src/ObjWriting/Model/XModel/XModelExportWriter.cpp @@ -2,6 +2,7 @@ #include "Math/Quaternion.h" +#include #include #include