feat: fix scene loading that it loads from disk if not already loaded

This commit is contained in:
2026-08-11 01:52:14 +02:00
parent f298c7ada5
commit 662940793e
20 changed files with 964 additions and 434 deletions
+1 -1
View File
@@ -31,7 +31,7 @@ private:
GameObject* capybara = nullptr;
char scenePath[512]{"game://scenes/debug_scene.json"};
char scenePath[512]{"scenes/debug_scene.json"};
char newSceneName[128]{"EmptyScene"};
std::string sceneStatus;
};
+226 -260
View File
@@ -1,6 +1,7 @@
#include "Lightkeeper.h"
#include <destrum/FS/AssetFS.h>
#include <destrum/Assets/AssetManager.h>
#include "glm/gtx/transform.hpp"
#include "spdlog/spdlog.h"
#include <destrum/Components/Physics/Rigidbody.h>
@@ -27,7 +28,9 @@
#include "destrum/Util/ModelDocUtils.h"
namespace {
std::filesystem::path ResolveScenePath(std::string_view value) {
std::filesystem::path ResolveScenePath(
std::string_view value,
const std::filesystem::path& exeDir) {
if (value.empty()) {
throw std::invalid_argument("Scene path cannot be empty");
}
@@ -36,7 +39,8 @@ namespace {
return AssetFS::GetInstance().GetFullPath(value);
}
return std::filesystem::path{value};
const std::filesystem::path path{value};
return path.is_absolute() ? path : exeDir / path;
}
}
@@ -68,37 +72,6 @@ void LightKeeper::customInit()
staticModelOptions.loadSkeleton = false;
staticModelOptions.loadAnimations = false;
auto kittyModel = ModelDoc::LoadModel(
AssetFS::GetInstance().GetFullPath("game://kitty.glb").generic_string(),
staticModelOptions
);
ModelDocUtils::LogModelDocSummary(kittyModel, "kitty.glb");
const auto& kittyPrimitive = ModelDocUtils::GetFirstPrimitiveOrThrow(kittyModel, "game://kitty.glb");
auto testMesh = kittyPrimitive.mesh;
testMesh.name = "Test Mesh";
auto testMeshID = resources.meshes().addMesh(gfxDevice, testMesh);
spdlog::info("TestMesh uploaded with id: {}", testMeshID);
const auto testTexturePath = ModelDocUtils::PickTexturePath(
kittyModel,
kittyPrimitive,
AssetFS::GetInstance().GetFullPath("game://kitty.png")
);
const auto testimgID = resources.loadImageFromFile(gfxDevice, testTexturePath);
spdlog::info("Test image loaded from '{}' with id: {}", testTexturePath.generic_string(), testimgID);
auto testMaterialID = resources.materials().addMaterial({
.baseColor = ModelDocUtils::GetImportedBaseColor(
kittyModel, kittyPrimitive),
.diffuseTexture = testimgID,
.name = ModelDocUtils::GetImportedMaterialName(
kittyModel, kittyPrimitive, "TestMaterial"),
});
spdlog::info("Test material created with id: {}", testMaterialID);
camera.SetRotation(glm::radians(glm::vec2(90.f, 0.f)));
auto& scene = SceneManager::GetInstance().CreateScene("Main");
@@ -168,64 +141,64 @@ void LightKeeper::customInit()
characterModelOptions.loadSkeleton = true;
characterModelOptions.loadAnimations = true;
auto charModel = ModelDoc::LoadModel(
AssetFS::GetInstance().GetFullPath("engine://cotw-capybara-male/source/capybara.fbx").generic_string(),
characterModelOptions
);
ModelDocUtils::LogModelDocSummary(charModel, "capybara.fbx");
const auto& charPrimitive = ModelDocUtils::GetFirstSkinnedPrimitiveOrFirstOrThrow(
charModel,
"engine://cotw-capybara-male/source/capybara.fbx"
);
const auto charMeshID = resources.meshes().addMesh(gfxDevice, charPrimitive.mesh);
const auto charTexturePath = ModelDocUtils::PickTexturePath(
charModel,
charPrimitive,
AssetFS::GetInstance().GetFullPath(
"engine://cotw-capybara-male/textures/capybara_male_light_brown_dif.ddsc.DECA.RE.pngballs")
);
const auto charTextureID = resources.loadImageFromFile(gfxDevice, charTexturePath);
// const auto charTextureID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("engine://char.jpg"));
const auto charMaterialID = resources.materials().addMaterial({
.baseColor = ModelDocUtils::GetImportedBaseColor(
charModel, charPrimitive),
.diffuseTexture = charTextureID,
.name = ModelDocUtils::GetImportedMaterialName(
charModel, charPrimitive, "CharacterMaterial"),
});
const auto charMeshComp = CharObj->AddComponent<MeshRendererComponent>();
charMeshComp->SetMeshID(charMeshID);
charMeshComp->SetMaterialID(charMaterialID);
const auto animator = CharObj->AddComponent<Animator>();
animator->setSkeleton(std::move(charModel.skeleton));
std::string firstAnimationName;
for (auto& clip : charModel.animations)
{
spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration);
if (firstAnimationName.empty())
firstAnimationName = clip.name;
animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip)));
}
if (!firstAnimationName.empty())
{
spdlog::info("Playing animation: '{}'", firstAnimationName);
animator->play(firstAnimationName);
}
animator->play("capybara_canter_fwd_01|capybara_canter_fwd_01|run");
CharObj->GetTransform().SetWorldPosition(glm::vec3(0.f, 0.f, 0.f));
// auto charModel = ModelDoc::LoadModel(
// AssetFS::GetInstance().GetFullPath("engine://cotw-capybara-male/source/capybara.fbx").generic_string(),
// characterModelOptions
// );
// ModelDocUtils::LogModelDocSummary(charModel, "capybara.fbx");
//
// const auto& charPrimitive = ModelDocUtils::GetFirstSkinnedPrimitiveOrFirstOrThrow(
// charModel,
// "engine://cotw-capybara-male/source/capybara.fbx"
// );
//
// const auto charMeshID = resources.meshes().addMesh(gfxDevice, charPrimitive.mesh);
//
// const auto charTexturePath = ModelDocUtils::PickTexturePath(
// charModel,
// charPrimitive,
// AssetFS::GetInstance().GetFullPath(
// "engine://cotw-capybara-male/textures/capybara_male_light_brown_dif.ddsc.DECA.RE.pngballs")
// );
//
// const auto charTextureID = resources.loadImageFromFile(gfxDevice, charTexturePath);
// // const auto charTextureID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("engine://char.jpg"));
// const auto charMaterialID = resources.materials().addMaterial({
// .baseColor = ModelDocUtils::GetImportedBaseColor(
// charModel, charPrimitive),
// .diffuseTexture = charTextureID,
// .name = ModelDocUtils::GetImportedMaterialName(
// charModel, charPrimitive, "CharacterMaterial"),
// });
//
// const auto charMeshComp = CharObj->AddComponent<MeshRendererComponent>();
// charMeshComp->SetMeshID(charMeshID);
// charMeshComp->SetMaterialID(charMaterialID);
//
// const auto animator = CharObj->AddComponent<Animator>();
// animator->setSkeleton(std::move(charModel.skeleton));
//
// std::string firstAnimationName;
//
// for (auto& clip : charModel.animations)
// {
// spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration);
//
// if (firstAnimationName.empty())
// firstAnimationName = clip.name;
//
// animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip)));
// }
//
// if (!firstAnimationName.empty())
// {
// spdlog::info("Playing animation: '{}'", firstAnimationName);
// animator->play(firstAnimationName);
// }
//
// animator->play("capybara_canter_fwd_01|capybara_canter_fwd_01|run");
//
// CharObj->GetTransform().SetWorldPosition(glm::vec3(0.f, 0.f, 0.f));
// CharObj->GetTransform().SetWorldScale(0.01f, 0.01f, 0.01f);
// ModelDoc::LoadOptions options{};
@@ -282,184 +255,177 @@ void LightKeeper::customInit()
// }
{
const auto CharObj = scene.CreateGameObject("Character");
ModelDoc::LoadOptions characterOptions{};
characterOptions.meshImportMode = ModelDoc::MeshImportMode::MergedPerNode;
characterOptions.loadMaterials = true;
characterOptions.loadSkeleton = true;
characterOptions.loadAnimations = false;
auto charModel = ModelDoc::LoadModel(
AssetFS::GetInstance()
.GetFullPath("engine://characterMedium.fbx")
.generic_string(),
characterOptions
);
const auto& charPrimitive =
ModelDocUtils::GetFirstSkinnedPrimitiveOrFirstOrThrow(
charModel,
"engine://characterMedium.fbx"
);
const auto charMeshID = resources.meshes().addMesh(gfxDevice, charPrimitive.mesh);
const auto charTextureID = resources.loadImageFromFile(gfxDevice,
AssetFS::GetInstance().GetFullPath("engine://textures/criminalMaleA.png")
);
const auto charMaterialID = resources.materials().addMaterial({
.baseColor = ModelDocUtils::GetImportedBaseColor(
charModel, charPrimitive),
.diffuseTexture = charTextureID,
.name = ModelDocUtils::GetImportedMaterialName(
charModel,
charPrimitive,
"CharacterMaterial"
),
});
const auto charMeshComp = CharObj->AddComponent<MeshRendererComponent>();
charMeshComp->SetMeshID(charMeshID);
charMeshComp->SetMaterialID(charMaterialID);
const auto animator = CharObj->AddComponent<Animator>();
animator->setSkeleton(charModel.skeleton);
auto runClips = ModelDoc::LoadAnimationClips(
AssetFS::GetInstance()
.GetFullPath("engine://run.fbx")
.generic_string(),
charModel.skeleton
);
for (auto& clip : runClips)
{
spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration);
animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip)));
}
if (!runClips.empty())
{
animator->play("Root|Run");
}
CharObj->GetTransform().SetWorldPosition(glm::vec3(0.f));
CharObj->GetTransform().SetWorldPosition(glm::vec3(5, 0, 0));
}
auto cubeModel = ModelDoc::LoadModel(
AssetFS::GetInstance()
.GetFullPath("engine://cube.fbx")
.generic_string(),
staticModelOptions
);
ModelDocUtils::LogModelDocSummary(cubeModel, "cube.fbx");
const auto& cubePrimitive = ModelDocUtils::GetFirstPrimitiveOrThrow(cubeModel, "game://cube.fbx");
const auto eliasTextuerPath = ModelDocUtils::PickTexturePath(
cubeModel,
cubePrimitive,
AssetFS::GetInstance().GetFullPath("game://grass.png")
);
const auto eliasTextueID = resources.loadImageFromFile(gfxDevice, eliasTextuerPath);
const auto eliasMaterialID = resources.materials().addMaterial({
.baseColor = ModelDocUtils::GetImportedBaseColor(
planeModel, planePrimitive),
.textureFilteringMode =
TextureFilteringMode::Anisotropic,
.diffuseTexture = eliasTextueID,
.name = ModelDocUtils::GetImportedMaterialName(
planeModel, planePrimitive, "GroundPlaneMaterial"),
});
const auto cubeMeshID = resources.meshes().addMesh(gfxDevice, cubePrimitive.mesh);
//
// for (int i{0}; i < 100; i++)
// {
// auto cube = std::make_shared<GameObject>("Cube");
// const auto CharObj = scene.CreateGameObject("Character");
//
// cube->AddComponent<BoxCollider>(glm::vec3{0.5f});
// cube->AddComponent<Rigidbody>();
// ModelDoc::LoadOptions characterOptions{};
// characterOptions.meshImportMode = ModelDoc::MeshImportMode::MergedPerNode;
// characterOptions.loadMaterials = true;
// characterOptions.loadSkeleton = true;
// characterOptions.loadAnimations = false;
//
// auto meshComp = cube->AddComponent<MeshRendererComponent>();
// meshComp->SetMeshID(cubeMeshID);
// meshComp->SetMaterialID(eliasMaterialID);
// auto charModel = AssetManager::GetInstance().LoadModel("engine://characterMedium.fbx", characterOptions);
//
// cube->GetTransform().SetWorldPosition(glm::vec3(0.0f, i, 0.0f));
// cube->GetTransform().SetWorldScale(glm::vec3(0.005f));
// const auto& charPrimitive =
// ModelDocUtils::GetFirstSkinnedPrimitiveOrFirstOrThrow(
// charModel,
// "engine://characterMedium.fbx"
// );
//
// scene.Add(cube);
// scene.GetPhysics().RegisterGameObject(*cube);
// }
// const int cubeCount = 10;
// const float spacing = 1.0f;
// const auto charMeshID = resources.meshes().addMesh(gfxDevice, charPrimitive.mesh);
//
// for (int x = 0; x < cubeCount; x++)
// {
// for (int y = 0; y < 3; y++)
// const auto charTextureID = resources.loadImageFromFile(gfxDevice,
// AssetFS::GetInstance().GetFullPath("engine://textures/criminalMaleA.png")
// );
//
// const auto charMaterialID = resources.materials().addMaterial({
// .baseColor = ModelDocUtils::GetImportedBaseColor(
// charModel, charPrimitive),
// .diffuseTexture = charTextureID,
// .name = ModelDocUtils::GetImportedMaterialName(
// charModel,
// charPrimitive,
// "CharacterMaterial"
// ),
// });
//
// const auto charMeshComp = CharObj->AddComponent<MeshRendererComponent>();
// charMeshComp->SetMeshID(charMeshID);
// charMeshComp->SetMaterialID(charMaterialID);
//
// const auto animator = CharObj->AddComponent<Animator>();
// animator->setSkeleton(charModel.skeleton);
//
// auto runClips = AssetManager::GetInstance().LoadAnimationClips(
// "engine://run.fbx",
// charModel.skeleton
// );
//
// for (auto& clip : runClips)
// {
// for (int z = 0; z < cubeCount; z++)
// {
// auto cube = std::make_shared<GameObject>("Cube");
//
// cube->AddComponent<BoxCollider>(glm::vec3{0.5f});
// cube->AddComponent<Rigidbody>();
//
// auto meshComp = cube->AddComponent<MeshRendererComponent>();
// meshComp->SetMeshID(cubeMeshID);
// meshComp->SetMaterialID(eliasMaterialID);
//
// cube->GetTransform().SetWorldPosition(glm::vec3(
// (x - cubeCount / 2.0f) * spacing,
// y * spacing + 0,
// (z - cubeCount / 2.0f) * spacing
// ));
//
// cube->GetTransform().SetWorldScale(glm::vec3(0.005f));
//
// scene.Add(cube);
// scene.GetPhysics().RegisterGameObject(*cube);
// }
// spdlog::info("Loaded animation: '{}' ({:.2f}s)", clip.name, clip.duration);
// animator->addClip(std::make_shared<SkeletalAnimation>(std::move(clip)));
// }
//
// if (!runClips.empty())
// {
// animator->play("Root|Run");
// }
//
// CharObj->GetTransform().SetWorldPosition(glm::vec3(0.f));
// CharObj->GetTransform().SetWorldPosition(glm::vec3(5, 0, 0));
// }
//
// auto cubeModel = ModelDoc::LoadModel(
// AssetFS::GetInstance()
// .GetFullPath("engine://cube.fbx")
// .generic_string(),
// staticModelOptions
// );
// ModelDocUtils::LogModelDocSummary(cubeModel, "cube.fbx");
//
// const auto& cubePrimitive = ModelDocUtils::GetFirstPrimitiveOrThrow(cubeModel, "game://cube.fbx");
//
//
// const auto eliasTextuerPath = ModelDocUtils::PickTexturePath(
// cubeModel,
// cubePrimitive,
// AssetFS::GetInstance().GetFullPath("game://grass.png")
// );
//
// const auto eliasTextueID = resources.loadImageFromFile(gfxDevice, eliasTextuerPath);
// const auto eliasMaterialID = resources.materials().addMaterial({
// .baseColor = ModelDocUtils::GetImportedBaseColor(
// planeModel, planePrimitive),
// .textureFilteringMode =
// TextureFilteringMode::Anisotropic,
// .diffuseTexture = eliasTextueID,
// .name = ModelDocUtils::GetImportedMaterialName(
// planeModel, planePrimitive, "GroundPlaneMaterial"),
// });
//
// const auto cubeMeshID = resources.meshes().addMesh(gfxDevice, cubePrimitive.mesh);
// //
// // for (int i{0}; i < 100; i++)
// // {
// // auto cube = std::make_shared<GameObject>("Cube");
// //
// // cube->AddComponent<BoxCollider>(glm::vec3{0.5f});
// // cube->AddComponent<Rigidbody>();
// //
// // auto meshComp = cube->AddComponent<MeshRendererComponent>();
// // meshComp->SetMeshID(cubeMeshID);
// // meshComp->SetMaterialID(eliasMaterialID);
// //
// // cube->GetTransform().SetWorldPosition(glm::vec3(0.0f, i, 0.0f));
// // cube->GetTransform().SetWorldScale(glm::vec3(0.005f));
// //
// // scene.Add(cube);
// // scene.GetPhysics().RegisterGameObject(*cube);
// // }
//
// // const int cubeCount = 10;
// // const float spacing = 1.0f;
// //
// // for (int x = 0; x < cubeCount; x++)
// // {
// // for (int y = 0; y < 3; y++)
// // {
// // for (int z = 0; z < cubeCount; z++)
// // {
// // auto cube = std::make_shared<GameObject>("Cube");
// //
// // cube->AddComponent<BoxCollider>(glm::vec3{0.5f});
// // cube->AddComponent<Rigidbody>();
// //
// // auto meshComp = cube->AddComponent<MeshRendererComponent>();
// // meshComp->SetMeshID(cubeMeshID);
// // meshComp->SetMaterialID(eliasMaterialID);
// //
// // cube->GetTransform().SetWorldPosition(glm::vec3(
// // (x - cubeCount / 2.0f) * spacing,
// // y * spacing + 0,
// // (z - cubeCount / 2.0f) * spacing
// // ));
// //
// // cube->GetTransform().SetWorldScale(glm::vec3(0.005f));
// //
// // scene.Add(cube);
// // scene.GetPhysics().RegisterGameObject(*cube);
// // }
// // }
// // }
// {
auto sphereModel = AssetManager::GetInstance().LoadModel("engine://sphere.fbx", staticModelOptions);
ModelDocUtils::LogModelDocSummary(sphereModel, "sphere.fbx");
//
const auto& spherePrimitive = ModelDocUtils::GetFirstPrimitiveOrThrow(sphereModel, "game://sphere.fbx");
//
//
// const auto sphereTexturePath = ModelDocUtils::PickTexturePath(
// sphereModel,
// spherePrimitive,
// AssetFS::GetInstance().GetFullPath("game://238882.png")
// );
//
// const auto sphereTextureID = resources.loadImageFromFile(gfxDevice, sphereTexturePath);
// sphereMaterial = resources.materials().addMaterial({
// .baseColor = ModelDocUtils::GetImportedBaseColor(planeModel, planePrimitive),
// .textureFilteringMode =TextureFilteringMode::Anisotropic,
// .diffuseTexture = sphereTextureID,
// .name = ModelDocUtils::GetImportedMaterialName(
// planeModel, planePrimitive,
// "GroundPlaneMaterial"),
// });
//
sphereMesh = resources.meshes().addMesh(gfxDevice, spherePrimitive.mesh);
//
// }
sphereMaterial = resources.materials().addSimpleColorMaterial({0.5f, 0.3f, 0.8f}, "Blue");
{
auto sphereModel = ModelDoc::LoadModel(
AssetFS::GetInstance().GetFullPath("engine://sphere.fbx").generic_string(),
staticModelOptions
);
ModelDocUtils::LogModelDocSummary(sphereModel, "sphere.fbx");
const auto& spherePrimitive = ModelDocUtils::GetFirstPrimitiveOrThrow(sphereModel, "game://sphere.fbx");
const auto sphereTexturePath = ModelDocUtils::PickTexturePath(
sphereModel,
spherePrimitive,
AssetFS::GetInstance().GetFullPath("game://238882.png")
);
const auto sphereTextureID = resources.loadImageFromFile(gfxDevice, sphereTexturePath);
sphereMaterial = resources.materials().addMaterial({
.baseColor = ModelDocUtils::GetImportedBaseColor(planeModel, planePrimitive),
.textureFilteringMode =TextureFilteringMode::Anisotropic,
.diffuseTexture = sphereTextureID,
.name = ModelDocUtils::GetImportedMaterialName(
planeModel, planePrimitive,
"GroundPlaneMaterial"),
});
sphereMesh = resources.meshes().addMesh(gfxDevice, spherePrimitive.mesh);
}
}
void LightKeeper::customUpdate(float dt)
@@ -501,7 +467,7 @@ void LightKeeper::customUpdate(float dt)
if (ImGui::Button("Save Current Scene")) {
try {
const auto path = ResolveScenePath(scenePath);
const auto path = ResolveScenePath(scenePath, m_params.exeDir);
const auto parent = path.parent_path();
if (!parent.empty()) {
std::filesystem::create_directories(parent);
@@ -522,7 +488,7 @@ void LightKeeper::customUpdate(float dt)
ImGui::SameLine();
if (ImGui::Button("Load Scene")) {
try {
const auto path = ResolveScenePath(scenePath);
const auto path = ResolveScenePath(scenePath, m_params.exeDir);
if (SceneSerializer::Load(
SceneManager::GetInstance().GetCurrentScene(),
path)) {