feat: add vec3 type to nhollman json / fix: scene serialisation stuff

This commit is contained in:
2026-10-18 15:20:01 +02:00
parent 7223e9ce07
commit 94fa2bb4b2
18 changed files with 670 additions and 289 deletions
@@ -1,6 +1,7 @@
#include <destrum/Components/MeshRendererComponent.h>
#include <destrum/Assets/AssetReference.h>
#include <destrum/Graphics/GfxDevice.h>
#include <destrum/Graphics/Resources/PrimitiveMeshes.h>
#include <destrum/Graphics/Renderer.h>
#include <destrum/ObjectModel/Transform.h>
@@ -10,8 +11,11 @@
#include <imgui.h>
#include <filesystem>
#include <stdexcept>
#include <spdlog/spdlog.h>
MeshRendererComponent::MeshRendererComponent(GameObject& parent): Component(parent, "MeshRendererComponent") {
}
@@ -54,27 +58,39 @@ void MeshRendererComponent::Update(float) {
}
nlohmann::json MeshRendererComponent::Serialize() const {
// Only keys are saved, mesh and material ids are cache slots that change between runs
std::string savedMeshKey = meshKey;
std::string savedMaterialKey = materialKey;
if (GameState::GetInstance().HasRenderer()) {
if (const auto* resources = GameState::GetInstance().Renderer().getResources()) {
if (savedMeshKey.empty() && meshID != NULL_MESH_ID) {
savedMeshKey = resources->meshes().getMeshKey(meshID);
}
if (savedMaterialKey.empty() && materialID != NULL_MATERIAL_ID) {
savedMaterialKey = resources->materials().getMaterialKey(materialID);
}
}
}
if (savedMeshKey.empty() && meshID != NULL_MESH_ID) {
throw std::runtime_error("MeshRendererComponent has a mesh without a key, it cannot be saved");
}
if (savedMaterialKey.empty() && materialID != NULL_MATERIAL_ID) {
throw std::runtime_error("MeshRendererComponent has a material without a key, it cannot be saved");
}
return {
{"meshId", meshID},
{"materialId", materialID},
{"meshKey", meshKey},
{"materialKey", materialKey}
{"meshKey", savedMeshKey},
{"materialKey", savedMaterialKey}
};
}
void MeshRendererComponent::Deserialize(const nlohmann::json& data) {
if (data.contains("meshId")) {
meshID = data.at("meshId").get<MeshID>();
}
if (data.contains("materialId")) {
materialID = data.at("materialId").get<MaterialID>();
}
if (data.contains("meshKey")) {
meshKey = data.at("meshKey").get<std::string>();
}
if (data.contains("materialKey")) {
materialKey = data.at("materialKey").get<std::string>();
}
meshKey = data.value("meshKey", std::string{});
materialKey = data.value("materialKey", std::string{});
// Older scenes also stored raw ids, only trust them when there is no key
meshID = meshKey.empty() ? data.value("meshId", NULL_MESH_ID) : NULL_MESH_ID;
materialID = materialKey.empty() ? data.value("materialId", NULL_MATERIAL_ID) : NULL_MATERIAL_ID;
}
void MeshRendererComponent::ResolveReferences(const ObjectMap&) {
@@ -89,7 +105,9 @@ void MeshRendererComponent::ResolveReferences(const ObjectMap&) {
const auto loadAssetForKey = [&](const std::string& key) {
const auto asset = AssetReference::fromCacheKey(key);
if (!asset) {
// Runtime-only keys such as "BulbMaterial#2" also contain a '#', they are not files
if (!asset || (asset->path.find("://") == std::string::npos &&
!std::filesystem::exists(asset->path))) {
return;
}
if (!GameState::GetInstance().HasGfxDevice()) {
@@ -102,6 +120,20 @@ void MeshRendererComponent::ResolveReferences(const ObjectMap&) {
if (!meshKey.empty()) {
auto resolved = resources->meshes().findMeshByKey(meshKey);
if (!resolved && PrimitiveMeshes::IsPrimitiveKey(meshKey)) {
resolved = resources->meshes().findMeshByKey(PrimitiveMeshes::StripDuplicateSuffix(meshKey));
if (!resolved) {
auto primitive = PrimitiveMeshes::MakeFromKey(meshKey);
if (!primitive) {
throw std::runtime_error("Invalid primitive mesh key: " + meshKey);
}
if (!GameState::GetInstance().HasGfxDevice()) {
throw std::runtime_error("Cannot build primitive mesh without a graphics device: " + meshKey);
}
resolved = resources->meshes().addMesh(GameState::GetInstance().Gfx(), *primitive);
}
meshKey = resources->meshes().getMeshKey(*resolved);
}
if (!resolved) {
loadAssetForKey(meshKey);
resolved = resources->meshes().findMeshByKey(meshKey);
@@ -129,11 +161,15 @@ void MeshRendererComponent::ResolveReferences(const ObjectMap&) {
resolved = resources->materials().findMaterialByName(materialKey);
}
if (!resolved) {
throw std::runtime_error("Material resource not found: " + materialKey);
if (resolved) {
materialID = *resolved;
materialKey = resources->materials().getMaterialKey(*resolved);
} else {
// Keep the key so saving again does not lose which material was meant
spdlog::warn("Material \"{}\" on \"{}\" not found, using the placeholder material",
materialKey, GetGameObject()->GetName());
materialID = resources->materials().getPlaceholderMaterialId();
}
materialID = *resolved;
materialKey = resources->materials().getMaterialKey(*resolved);
}
if (meshID != NULL_MESH_ID && meshKey.empty()) {