feat? add basich ah scene loading
This commit is contained in:
@@ -2,13 +2,10 @@
|
||||
|
||||
#include <stdexcept>
|
||||
#include <destrum/ObjectModel/GameObject.h>
|
||||
// #include "imgui.h"
|
||||
|
||||
Component::Component(GameObject& pParent, const std::string& name): Object(name), m_ParentGameObjectPtr(&pParent) {
|
||||
// if (m_ParentGameObjectPtr == nullptr) {
|
||||
// //TODO: Change pParent ot be a reference
|
||||
// throw std::runtime_error("Component made with no GameObject??");
|
||||
// }
|
||||
Component::Component(GameObject& pParent, const std::string& name)
|
||||
: Object(name),
|
||||
m_ParentGameObjectPtr(&pParent) {
|
||||
}
|
||||
|
||||
Transform& Component::GetTransform() const {
|
||||
@@ -16,7 +13,6 @@ Transform& Component::GetTransform() const {
|
||||
}
|
||||
|
||||
void Component::Destroy() {
|
||||
// const bool isBeingDestroyed = GetIsBeingDestroyed();
|
||||
Object::Destroy();
|
||||
}
|
||||
|
||||
@@ -40,5 +36,4 @@ void Component::ImGuiRender() {
|
||||
}
|
||||
|
||||
void Component::Render(const RenderContext& ctx) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,30 @@
|
||||
#include <destrum/ObjectModel/GameObject.h>
|
||||
#include <string>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
|
||||
// #include "Managers/ResourceManager.h"
|
||||
|
||||
GameObject::~GameObject() {
|
||||
// spdlog::debug("GameObject destroyed: {}", GetName());
|
||||
}
|
||||
|
||||
GameObject::GameObject(const std::string& name)
|
||||
: Object(name),
|
||||
m_Id(s_NextId++) {
|
||||
}
|
||||
|
||||
void GameObject::SetIdForDeserialization(ObjectId id) {
|
||||
m_Id = id;
|
||||
|
||||
// Prevent newly created objects from reusing loaded IDs.
|
||||
if (id >= s_NextId) {
|
||||
s_NextId = id + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::SetActiveDirty() {
|
||||
m_ActiveDirty = true;
|
||||
|
||||
for (const Transform* child : m_TransformPtr.GetChildren()) {
|
||||
child->GetOwner()->SetActiveDirty();
|
||||
}
|
||||
@@ -21,7 +33,7 @@ void GameObject::SetActiveDirty() {
|
||||
void GameObject::UpdateActiveState() {
|
||||
const auto* parentPtr = m_TransformPtr.GetParent();
|
||||
|
||||
if(parentPtr == nullptr) {
|
||||
if (parentPtr == nullptr) {
|
||||
m_ActiveInHierarchy = m_Active;
|
||||
} else {
|
||||
m_ActiveInHierarchy = m_Active && parentPtr->GetOwner()->IsActiveInHierarchy();
|
||||
@@ -38,49 +50,51 @@ bool GameObject::IsActiveInHierarchy() {
|
||||
return m_ActiveInHierarchy;
|
||||
}
|
||||
|
||||
GameObject::GameObject(const std::string& name): Object(name) {
|
||||
}
|
||||
|
||||
void GameObject::Update() {
|
||||
for (const auto& component: m_Components) {
|
||||
for (const auto& component : m_Components) {
|
||||
if (!component->isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!component->HasStarted) {
|
||||
component->Start();
|
||||
component->HasStarted = true;
|
||||
}
|
||||
|
||||
component->Update();
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::LateUpdate() {
|
||||
for (const auto& component: m_Components) {
|
||||
component->LateUpdate();
|
||||
for (const auto& component : m_Components) {
|
||||
if (component->isEnabled()) {
|
||||
component->LateUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::FixedUpdate() {
|
||||
for (const auto& component: m_Components) {
|
||||
component->FixedUpdate();
|
||||
for (const auto& component : m_Components) {
|
||||
if (component->isEnabled()) {
|
||||
component->FixedUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GameObject::Render(const RenderContext& ctx) const {
|
||||
for (const auto& component: m_Components) {
|
||||
component->Render(ctx);
|
||||
for (const auto& component : m_Components) {
|
||||
if (component->isEnabled()) {
|
||||
component->Render(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// void GameObject::ImGuiRender() {
|
||||
// for (const auto& component: m_Components) {
|
||||
// component->ImGuiRender();
|
||||
// }
|
||||
// }
|
||||
|
||||
void GameObject::Destroy() {
|
||||
Object::Destroy();
|
||||
|
||||
m_TransformPtr.SetParent(nullptr);
|
||||
|
||||
for (const auto& component: m_Components) {
|
||||
for (const auto& component : m_Components) {
|
||||
component->Destroy();
|
||||
}
|
||||
|
||||
@@ -93,4 +107,4 @@ void GameObject::CleanupComponents() {
|
||||
std::erase_if(m_Components, [](const std::unique_ptr<Component>& component) {
|
||||
return component->IsBeingDestroyed();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ GameObject* Scene::CreateGameObject(std::string name)
|
||||
|
||||
GameObject* rawPtr = obj.get();
|
||||
|
||||
// obj->SetScene(this);
|
||||
obj->SetScene(this);
|
||||
m_pendingAdditions.emplace_back(std::move(obj));
|
||||
|
||||
return rawPtr;
|
||||
@@ -61,15 +61,9 @@ void Scene::Load() {
|
||||
}
|
||||
|
||||
void Scene::Update() {
|
||||
if (!m_pendingAdditions.empty()) {
|
||||
for (auto& obj : m_pendingAdditions) {
|
||||
m_objects.emplace_back(std::move(obj));
|
||||
}
|
||||
m_pendingAdditions.clear();
|
||||
}
|
||||
CommitPendingAdditions();
|
||||
|
||||
|
||||
for (const auto& object: m_objects) {
|
||||
for (const auto& object : m_objects) {
|
||||
if (object->IsActiveInHierarchy()) {
|
||||
object->Update();
|
||||
}
|
||||
@@ -155,3 +149,15 @@ void Scene::DestroyGameObjects() {
|
||||
assert(m_BeingUnloaded && "Scene is being cleared but not unloaded? Weird");
|
||||
}
|
||||
}
|
||||
|
||||
void Scene::CommitPendingAdditions() {
|
||||
if (m_pendingAdditions.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& obj : m_pendingAdditions) {
|
||||
m_objects.emplace_back(std::move(obj));
|
||||
}
|
||||
|
||||
m_pendingAdditions.clear();
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// destrum/Serialization/ComponentRegistry.cpp
|
||||
|
||||
#include <destrum/Serialization/ComponentRegistry.h>
|
||||
#include <destrum/Serialization/ComponentFactory.h>
|
||||
|
||||
#include <destrum/Components/MeshRendererComponent.h>
|
||||
#include <destrum/Components/Rotator.h>
|
||||
#include <destrum/Components/Spinner.h>
|
||||
#include <destrum/Components/OrbitAndSpin.h>
|
||||
#include <destrum/Components/Animator.h>
|
||||
|
||||
#include <destrum/Components/Physics/Rigidbody.h>
|
||||
#include <destrum/Components/Physics/BoxCollider.h>
|
||||
#include <destrum/Components/Physics/SphereCollider.h>
|
||||
|
||||
void RegisterEngineComponents()
|
||||
{
|
||||
static bool registered = false;
|
||||
if (registered) {
|
||||
return;
|
||||
}
|
||||
|
||||
registered = true;
|
||||
|
||||
ComponentFactory::Register("MeshRenderer", [](GameObject& owner) {
|
||||
return owner.AddComponent<MeshRendererComponent>();
|
||||
});
|
||||
|
||||
// ComponentFactory::Register("Rotator", [](GameObject& owner) {
|
||||
// return owner.AddComponent<Rotator>();
|
||||
// });
|
||||
|
||||
// ComponentFactory::Register("Spinner", [](GameObject& owner) {
|
||||
// return owner.AddComponent<Spinner>();
|
||||
// });
|
||||
|
||||
// ComponentFactory::Register("OrbitAndSpin", [](GameObject& owner) {
|
||||
// return owner.AddComponent<OrbitAndSpin>();
|
||||
// });
|
||||
|
||||
ComponentFactory::Register("Animator", [](GameObject& owner) {
|
||||
return owner.AddComponent<Animator>();
|
||||
});
|
||||
|
||||
ComponentFactory::Register("Rigidbody", [](GameObject& owner) {
|
||||
return owner.AddComponent<Rigidbody>();
|
||||
});
|
||||
|
||||
ComponentFactory::Register("BoxCollider", [](GameObject& owner) {
|
||||
return owner.AddComponent<BoxCollider>();
|
||||
});
|
||||
|
||||
ComponentFactory::Register("SphereCollider", [](GameObject& owner) {
|
||||
return owner.AddComponent<SphereCollider>();
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
#include <destrum/Serialization/SceneSerializer.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <destrum/Scene/Scene.h>
|
||||
#include <destrum/ObjectModel/GameObject.h>
|
||||
#include <destrum/ObjectModel/Component.h>
|
||||
#include <destrum/ObjectModel/ObjectId.h>
|
||||
#include <destrum/Serialization/ComponentFactory.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
bool SceneSerializer::Save(Scene& scene, const std::filesystem::path& path) {
|
||||
scene.CommitPendingAdditions();
|
||||
|
||||
json root;
|
||||
|
||||
root["version"] = 1;
|
||||
root["name"] = scene.GetName();
|
||||
root["objects"] = json::array();
|
||||
|
||||
for (const auto& objectPtr : scene.GetObjects()) {
|
||||
if (!objectPtr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const GameObject& object = *objectPtr;
|
||||
|
||||
json objectJson;
|
||||
objectJson["id"] = object.GetId();
|
||||
objectJson["name"] = object.GetName();
|
||||
objectJson["active"] = object.IsActive();
|
||||
|
||||
// Transform should be saved separately because in your engine it is not a component.
|
||||
// Replace this with your actual Transform getters.
|
||||
objectJson["transform"] = {
|
||||
// Example:
|
||||
// { "position", { object.GetTransform().GetLocalPosition().x,
|
||||
// object.GetTransform().GetLocalPosition().y,
|
||||
// object.GetTransform().GetLocalPosition().z } },
|
||||
// { "rotation", { ... } },
|
||||
// { "scale", { ... } }
|
||||
};
|
||||
|
||||
const Transform* parent = object.GetTransform().GetParent();
|
||||
objectJson["parent"] = parent
|
||||
? parent->GetOwner()->GetId()
|
||||
: InvalidObjectId;
|
||||
|
||||
objectJson["components"] = json::array();
|
||||
|
||||
for (const auto& componentPtr : object.GetComponents()) {
|
||||
if (!componentPtr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const Component& component = *componentPtr;
|
||||
|
||||
json componentJson;
|
||||
componentJson["type"] = component.GetTypeName();
|
||||
componentJson["enabled"] = component.isEnabled();
|
||||
componentJson["data"] = component.Serialize();
|
||||
|
||||
objectJson["components"].push_back(componentJson);
|
||||
}
|
||||
|
||||
root["objects"].push_back(objectJson);
|
||||
}
|
||||
|
||||
std::ofstream file(path);
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "Failed to open scene file for writing: " << path << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
file << root.dump(4);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SceneSerializer::Load(Scene& scene, const std::filesystem::path& path) {
|
||||
std::ifstream file(path);
|
||||
if (!file.is_open()) {
|
||||
std::cerr << "Failed to open scene file for reading: " << path << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
json root;
|
||||
|
||||
try {
|
||||
file >> root;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Failed to parse scene file: " << e.what() << '\n';
|
||||
return false;
|
||||
}
|
||||
|
||||
scene.RemoveAll();
|
||||
|
||||
std::unordered_map<ObjectId, GameObject*> idMap;
|
||||
std::vector<const json*> objectJsonList;
|
||||
|
||||
try {
|
||||
const auto& objectsJson = root.at("objects");
|
||||
|
||||
// Pass 1:
|
||||
// Create all GameObjects first.
|
||||
for (const auto& objectJson : objectsJson) {
|
||||
const auto id = objectJson.at("id").get<ObjectId>();
|
||||
const std::string name = objectJson.value("name", "GameObject");
|
||||
const bool active = objectJson.value("active", true);
|
||||
|
||||
GameObject* object = scene.CreateGameObject(name);
|
||||
object->SetIdForDeserialization(id);
|
||||
object->SetActive(active);
|
||||
|
||||
idMap[id] = object;
|
||||
objectJsonList.push_back(&objectJson);
|
||||
}
|
||||
|
||||
scene.CommitPendingAdditions();
|
||||
|
||||
// Pass 2:
|
||||
// Restore transforms and parent-child hierarchy.
|
||||
for (const json* objectJson : objectJsonList) {
|
||||
const auto id = objectJson->at("id").get<ObjectId>();
|
||||
|
||||
GameObject* object = idMap.at(id);
|
||||
|
||||
// Replace this with your actual Transform deserialization.
|
||||
if (objectJson->contains("transform")) {
|
||||
const json& transformJson = objectJson->at("transform");
|
||||
|
||||
auto position = transformJson.at("position");
|
||||
object->GetTransform().SetLocalPosition({
|
||||
position[0].get<float>(),
|
||||
position[1].get<float>(),
|
||||
position[2].get<float>()
|
||||
});
|
||||
|
||||
auto rotation = transformJson.at("rotation");
|
||||
object->GetTransform().SetLocalRotation({
|
||||
rotation[0].get<float>(),
|
||||
rotation[1].get<float>(),
|
||||
rotation[2].get<float>()
|
||||
});
|
||||
|
||||
auto scale = transformJson.at("scale");
|
||||
object->GetTransform().SetLocalScale({
|
||||
scale[0].get<float>(),
|
||||
scale[1].get<float>(),
|
||||
scale[2].get<float>()
|
||||
});
|
||||
}
|
||||
|
||||
const ObjectId parentId = objectJson->value("parent", InvalidObjectId);
|
||||
|
||||
if (parentId != InvalidObjectId) {
|
||||
auto parentIt = idMap.find(parentId);
|
||||
|
||||
if (parentIt != idMap.end()) {
|
||||
object->GetTransform().SetParent(&parentIt->second->GetTransform());
|
||||
} else {
|
||||
std::cerr << "Parent not found while loading object " << id << '\n';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 3:
|
||||
// Create and deserialize components.
|
||||
for (const json* objectJson : objectJsonList) {
|
||||
const auto id = objectJson->at("id").get<ObjectId>();
|
||||
GameObject* object = idMap.at(id);
|
||||
|
||||
if (!objectJson->contains("components")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto& componentJson : objectJson->at("components")) {
|
||||
const std::string type = componentJson.at("type").get<std::string>();
|
||||
|
||||
Component* component = ComponentFactory::Create(type, *object);
|
||||
|
||||
if (!component) {
|
||||
std::cerr << "Unknown component type while loading scene: " << type << '\n';
|
||||
continue;
|
||||
}
|
||||
|
||||
component->SetEnabled(componentJson.value("enabled", true));
|
||||
|
||||
if (componentJson.contains("data")) {
|
||||
component->Deserialize(componentJson.at("data"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pass 4:
|
||||
// Resolve object references now that all objects and components exist.
|
||||
for (const auto& objectPtr : scene.GetObjects()) {
|
||||
if (!objectPtr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto& componentPtr : objectPtr->GetComponents()) {
|
||||
if (!componentPtr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
componentPtr->ResolveReferences(idMap);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Failed to load scene: " << e.what() << '\n';
|
||||
scene.RemoveAll();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user