289 lines
14 KiB
C++
289 lines
14 KiB
C++
#include "MetaCoreScene/MetaCoreSceneSerializer.h"
|
||
#include "MetaCoreFoundation/MetaCoreReflection.h"
|
||
#include <nlohmann/json.hpp>
|
||
#include <fstream>
|
||
#include <iostream>
|
||
#include <sstream>
|
||
|
||
using json = nlohmann::json;
|
||
|
||
namespace MetaCore {
|
||
|
||
// 辅助方法:将 glm::vec3 序列化为 JSON 数组 [x, y, z]
|
||
static json Vec3ToJson(const glm::vec3& vec) {
|
||
return { vec.x, vec.y, vec.z };
|
||
}
|
||
|
||
// 辅助方法:从 JSON 数组 [x, y, z] 反序列化出 glm::vec3
|
||
static glm::vec3 JsonToVec3(const json& j) {
|
||
if (j.is_array() && j.size() >= 3) {
|
||
return glm::vec3(j[0].get<float>(), j[1].get<float>(), j[2].get<float>());
|
||
}
|
||
return glm::vec3(0.0f);
|
||
}
|
||
|
||
// 辅助方法:将 MetaCoreAssetGuid 转换为 String,方便文本化存储
|
||
static std::string GuidToString(const MetaCoreAssetGuid& guid) {
|
||
return guid.IsValid() ? guid.ToString() : "";
|
||
}
|
||
|
||
// 辅助方法:从 String 反解析为 MetaCoreAssetGuid
|
||
static MetaCoreAssetGuid StringToGuid(const std::string& str) {
|
||
return str.empty() ? MetaCoreAssetGuid{} : MetaCoreAssetGuid::Parse(str).value_or(MetaCoreAssetGuid{});
|
||
}
|
||
|
||
bool MetaCoreSceneSerializer::SaveSceneToJson(
|
||
const std::filesystem::path& absolutePath,
|
||
const MetaCoreSceneDocument& sceneDocument,
|
||
const MetaCoreTypeRegistry& registry
|
||
) {
|
||
try {
|
||
json sceneJson;
|
||
sceneJson["SceneName"] = sceneDocument.Name;
|
||
sceneJson["Selection"] = {
|
||
{"SelectedObjectIds", sceneDocument.Selection.SelectedObjectIds},
|
||
{"ActiveObjectId", sceneDocument.Selection.ActiveObjectId},
|
||
{"SelectionAnchorId", sceneDocument.Selection.SelectionAnchorId}
|
||
};
|
||
|
||
json gameObjectsArray = json::array();
|
||
for (const auto& obj : sceneDocument.GameObjects) {
|
||
json objJson;
|
||
objJson["Id"] = obj.Id;
|
||
objJson["ParentId"] = obj.ParentId;
|
||
objJson["Name"] = obj.Name;
|
||
|
||
// 序列化 Transform 组件
|
||
objJson["Transform"] = {
|
||
{"Position", Vec3ToJson(obj.Transform.Position)},
|
||
{"RotationEulerDegrees", Vec3ToJson(obj.Transform.RotationEulerDegrees)},
|
||
{"Scale", Vec3ToJson(obj.Transform.Scale)}
|
||
};
|
||
|
||
// 序列化 MeshRenderer 组件 (如果有)
|
||
if (obj.MeshRenderer.has_value()) {
|
||
const auto& mesh = obj.MeshRenderer.value();
|
||
json meshJson;
|
||
meshJson["MeshSource"] = static_cast<int>(mesh.MeshSource);
|
||
meshJson["BuiltinMesh"] = static_cast<int>(mesh.BuiltinMesh);
|
||
meshJson["MeshAssetGuid"] = GuidToString(mesh.MeshAssetGuid);
|
||
|
||
json matGuids = json::array();
|
||
for (const auto& guid : mesh.MaterialAssetGuids) {
|
||
matGuids.push_back(GuidToString(guid));
|
||
}
|
||
meshJson["MaterialAssetGuids"] = matGuids;
|
||
meshJson["SourceModelAssetGuid"] = GuidToString(mesh.SourceModelAssetGuid);
|
||
meshJson["SourceModelPath"] = mesh.SourceModelPath;
|
||
meshJson["SourceNodePath"] = mesh.SourceNodePath;
|
||
|
||
meshJson["BaseColorTextureGuid"] = GuidToString(mesh.BaseColorTextureGuid);
|
||
meshJson["MetallicRoughnessTextureGuid"] = GuidToString(mesh.MetallicRoughnessTextureGuid);
|
||
meshJson["NormalTextureGuid"] = GuidToString(mesh.NormalTextureGuid);
|
||
meshJson["EmissiveTextureGuid"] = GuidToString(mesh.EmissiveTextureGuid);
|
||
meshJson["AoTextureGuid"] = GuidToString(mesh.AoTextureGuid);
|
||
|
||
meshJson["BaseColorTexturePath"] = mesh.BaseColorTexturePath;
|
||
meshJson["MetallicRoughnessTexturePath"] = mesh.MetallicRoughnessTexturePath;
|
||
meshJson["NormalTexturePath"] = mesh.NormalTexturePath;
|
||
meshJson["EmissiveTexturePath"] = mesh.EmissiveTexturePath;
|
||
meshJson["AoTexturePath"] = mesh.AoTexturePath;
|
||
|
||
meshJson["DoubleSided"] = mesh.DoubleSided;
|
||
meshJson["Metallic"] = mesh.Metallic;
|
||
meshJson["Roughness"] = mesh.Roughness;
|
||
meshJson["AlphaMode"] = static_cast<int>(mesh.AlphaMode);
|
||
meshJson["AlphaCutoff"] = mesh.AlphaCutoff;
|
||
meshJson["EmissiveColor"] = Vec3ToJson(mesh.EmissiveColor);
|
||
meshJson["BaseColor"] = Vec3ToJson(mesh.BaseColor);
|
||
meshJson["ModelNodeIndex"] = mesh.ModelNodeIndex;
|
||
meshJson["SubMeshIndex"] = mesh.SubMeshIndex;
|
||
meshJson["Visible"] = mesh.Visible;
|
||
|
||
objJson["MeshRenderer"] = meshJson;
|
||
}
|
||
|
||
// 序列化 Light 组件 (如果有)
|
||
if (obj.Light.has_value()) {
|
||
const auto& light = obj.Light.value();
|
||
json lightJson;
|
||
lightJson["Color"] = Vec3ToJson(light.Color);
|
||
lightJson["Intensity"] = light.Intensity;
|
||
objJson["Light"] = lightJson;
|
||
}
|
||
|
||
// 序列化 Camera 组件 (如果有)
|
||
if (obj.Camera.has_value()) {
|
||
const auto& cam = obj.Camera.value();
|
||
json camJson;
|
||
camJson["FieldOfViewDegrees"] = cam.FieldOfViewDegrees;
|
||
camJson["NearClip"] = cam.NearClip;
|
||
camJson["FarClip"] = cam.FarClip;
|
||
camJson["IsPrimary"] = cam.IsPrimary;
|
||
objJson["Camera"] = camJson;
|
||
}
|
||
|
||
// 序列化 PrefabInstance 预制体元数据 (如果有)
|
||
if (obj.PrefabInstance.has_value()) {
|
||
const auto& prefab = obj.PrefabInstance.value();
|
||
json prefabJson;
|
||
prefabJson["PrefabAssetGuid"] = GuidToString(prefab.PrefabAssetGuid);
|
||
prefabJson["PrefabObjectId"] = prefab.PrefabObjectId;
|
||
prefabJson["PrefabInstanceRootId"] = prefab.PrefabInstanceRootId;
|
||
objJson["PrefabInstance"] = prefabJson;
|
||
}
|
||
|
||
gameObjectsArray.push_back(objJson);
|
||
}
|
||
|
||
sceneJson["GameObjects"] = gameObjectsArray;
|
||
|
||
std::ofstream file(absolutePath);
|
||
if (!file.is_open()) {
|
||
std::cerr << "SaveSceneToJson: 无法打开文件写入 " << absolutePath << std::endl;
|
||
return false;
|
||
}
|
||
|
||
// 使用 4 个空格缩进,完美支持 Git diff 差分
|
||
file << sceneJson.dump(4);
|
||
return true;
|
||
} catch (const std::exception& e) {
|
||
std::cerr << "SaveSceneToJson: 发生异常 - " << e.what() << std::endl;
|
||
return false;
|
||
}
|
||
}
|
||
|
||
std::optional<MetaCoreSceneDocument> MetaCoreSceneSerializer::LoadSceneFromJson(
|
||
const std::filesystem::path& absolutePath,
|
||
const MetaCoreTypeRegistry& registry
|
||
) {
|
||
try {
|
||
std::ifstream file(absolutePath);
|
||
if (!file.is_open()) {
|
||
std::cerr << "LoadSceneFromJson: 无法打开文件进行读取 " << absolutePath << std::endl;
|
||
return std::nullopt;
|
||
}
|
||
|
||
json sceneJson;
|
||
file >> sceneJson;
|
||
|
||
MetaCoreSceneDocument sceneDocument;
|
||
if (sceneJson.contains("SceneName")) {
|
||
sceneDocument.Name = sceneJson["SceneName"].get<std::string>();
|
||
}
|
||
|
||
if (sceneJson.contains("Selection")) {
|
||
const auto& selectionJson = sceneJson["Selection"];
|
||
if (selectionJson.contains("SelectedObjectIds")) {
|
||
sceneDocument.Selection.SelectedObjectIds = selectionJson["SelectedObjectIds"].get<std::vector<MetaCoreId>>();
|
||
}
|
||
if (selectionJson.contains("ActiveObjectId")) {
|
||
sceneDocument.Selection.ActiveObjectId = selectionJson["ActiveObjectId"].get<MetaCoreId>();
|
||
}
|
||
if (selectionJson.contains("SelectionAnchorId")) {
|
||
sceneDocument.Selection.SelectionAnchorId = selectionJson["SelectionAnchorId"].get<MetaCoreId>();
|
||
}
|
||
}
|
||
|
||
if (sceneJson.contains("GameObjects") && sceneJson["GameObjects"].is_array()) {
|
||
for (const auto& objJson : sceneJson["GameObjects"]) {
|
||
MetaCoreGameObjectData obj;
|
||
obj.Id = objJson["Id"].get<MetaCoreId>();
|
||
obj.ParentId = objJson["ParentId"].get<MetaCoreId>();
|
||
obj.Name = objJson["Name"].get<std::string>();
|
||
|
||
// 反序列化 Transform 组件
|
||
if (objJson.contains("Transform")) {
|
||
const auto& transJson = objJson["Transform"];
|
||
obj.Transform.Position = JsonToVec3(transJson["Position"]);
|
||
obj.Transform.RotationEulerDegrees = JsonToVec3(transJson["RotationEulerDegrees"]);
|
||
obj.Transform.Scale = JsonToVec3(transJson["Scale"]);
|
||
}
|
||
|
||
// 反序列化 MeshRenderer 组件 (如果有)
|
||
if (objJson.contains("MeshRenderer")) {
|
||
const auto& meshJson = objJson["MeshRenderer"];
|
||
MetaCoreMeshRendererComponent mesh;
|
||
mesh.MeshSource = static_cast<MetaCoreMeshSourceKind>(meshJson["MeshSource"].get<int>());
|
||
mesh.BuiltinMesh = static_cast<MetaCoreBuiltinMeshType>(meshJson["BuiltinMesh"].get<int>());
|
||
mesh.MeshAssetGuid = StringToGuid(meshJson["MeshAssetGuid"].get<std::string>());
|
||
|
||
if (meshJson.contains("MaterialAssetGuids") && meshJson["MaterialAssetGuids"].is_array()) {
|
||
for (const auto& mGuidJson : meshJson["MaterialAssetGuids"]) {
|
||
mesh.MaterialAssetGuids.push_back(StringToGuid(mGuidJson.get<std::string>()));
|
||
}
|
||
}
|
||
|
||
mesh.SourceModelAssetGuid = StringToGuid(meshJson["SourceModelAssetGuid"].get<std::string>());
|
||
mesh.SourceModelPath = meshJson["SourceModelPath"].get<std::string>();
|
||
mesh.SourceNodePath = meshJson["SourceNodePath"].get<std::string>();
|
||
|
||
mesh.BaseColorTextureGuid = StringToGuid(meshJson["BaseColorTextureGuid"].get<std::string>());
|
||
mesh.MetallicRoughnessTextureGuid = StringToGuid(meshJson["MetallicRoughnessTextureGuid"].get<std::string>());
|
||
mesh.NormalTextureGuid = StringToGuid(meshJson["NormalTextureGuid"].get<std::string>());
|
||
mesh.EmissiveTextureGuid = StringToGuid(meshJson["EmissiveTextureGuid"].get<std::string>());
|
||
mesh.AoTextureGuid = StringToGuid(meshJson["AoTextureGuid"].get<std::string>());
|
||
|
||
mesh.BaseColorTexturePath = meshJson["BaseColorTexturePath"].get<std::string>();
|
||
mesh.MetallicRoughnessTexturePath = meshJson["MetallicRoughnessTexturePath"].get<std::string>();
|
||
mesh.NormalTexturePath = meshJson["NormalTexturePath"].get<std::string>();
|
||
mesh.EmissiveTexturePath = meshJson["EmissiveTexturePath"].get<std::string>();
|
||
mesh.AoTexturePath = meshJson["AoTexturePath"].get<std::string>();
|
||
|
||
mesh.DoubleSided = meshJson["DoubleSided"].get<bool>();
|
||
mesh.Metallic = meshJson["Metallic"].get<float>();
|
||
mesh.Roughness = meshJson["Roughness"].get<float>();
|
||
mesh.AlphaMode = static_cast<MetaCoreMeshAlphaMode>(meshJson["AlphaMode"].get<int>());
|
||
mesh.AlphaCutoff = meshJson["AlphaCutoff"].get<float>();
|
||
mesh.EmissiveColor = JsonToVec3(meshJson["EmissiveColor"]);
|
||
mesh.BaseColor = JsonToVec3(meshJson["BaseColor"]);
|
||
mesh.ModelNodeIndex = meshJson["ModelNodeIndex"].get<std::int32_t>();
|
||
mesh.SubMeshIndex = meshJson["SubMeshIndex"].get<std::int32_t>();
|
||
mesh.Visible = meshJson["Visible"].get<bool>();
|
||
|
||
obj.MeshRenderer = mesh;
|
||
}
|
||
|
||
// 反序列化 Light 组件 (如果有)
|
||
if (objJson.contains("Light")) {
|
||
const auto& lightJson = objJson["Light"];
|
||
MetaCoreLightComponent light;
|
||
light.Color = JsonToVec3(lightJson["Color"]);
|
||
light.Intensity = lightJson["Intensity"].get<float>();
|
||
obj.Light = light;
|
||
}
|
||
|
||
// 反序列化 Camera 组件 (如果有)
|
||
if (objJson.contains("Camera")) {
|
||
const auto& camJson = objJson["Camera"];
|
||
MetaCoreCameraComponent cam;
|
||
cam.FieldOfViewDegrees = camJson["FieldOfViewDegrees"].get<float>();
|
||
cam.NearClip = camJson["NearClip"].get<float>();
|
||
cam.FarClip = camJson["FarClip"].get<float>();
|
||
cam.IsPrimary = camJson["IsPrimary"].get<bool>();
|
||
obj.Camera = cam;
|
||
}
|
||
|
||
// 反序列化 PrefabInstance 预制体元数据 (如果有)
|
||
if (objJson.contains("PrefabInstance")) {
|
||
const auto& prefabJson = objJson["PrefabInstance"];
|
||
MetaCorePrefabInstanceMetadata prefab;
|
||
prefab.PrefabAssetGuid = StringToGuid(prefabJson["PrefabAssetGuid"].get<std::string>());
|
||
prefab.PrefabObjectId = prefabJson["PrefabObjectId"].get<MetaCoreId>();
|
||
prefab.PrefabInstanceRootId = prefabJson["PrefabInstanceRootId"].get<MetaCoreId>();
|
||
obj.PrefabInstance = prefab;
|
||
}
|
||
|
||
sceneDocument.GameObjects.push_back(obj);
|
||
}
|
||
}
|
||
|
||
return sceneDocument;
|
||
} catch (const std::exception& e) {
|
||
std::cerr << "LoadSceneFromJson: 发生异常 - " << e.what() << std::endl;
|
||
return std::nullopt;
|
||
}
|
||
}
|
||
|
||
} // namespace MetaCore
|