feat? add basich ah scene loading
This commit is contained in:
@@ -53,6 +53,9 @@ set(SRC_FILES
|
|||||||
"src/FS/AssetFS.cpp"
|
"src/FS/AssetFS.cpp"
|
||||||
"src/FS/Manifest.cpp"
|
"src/FS/Manifest.cpp"
|
||||||
|
|
||||||
|
"src/Serialization/SceneSerializer.cpp"
|
||||||
|
"src/Serialization/ComponentRegistry.cpp"
|
||||||
|
|
||||||
"src/Util/DeltaTime.cpp"
|
"src/Util/DeltaTime.cpp"
|
||||||
|
|
||||||
"src/Physics/PhysicsWorld.cpp"
|
"src/Physics/PhysicsWorld.cpp"
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ public:
|
|||||||
explicit Animator(GameObject& parent);
|
explicit Animator(GameObject& parent);
|
||||||
|
|
||||||
void Update() override;
|
void Update() override;
|
||||||
|
std::string GetTypeName() const override
|
||||||
|
{
|
||||||
|
return "Animator";
|
||||||
|
}
|
||||||
void ImGuiInspector() override;
|
void ImGuiInspector() override;
|
||||||
|
|
||||||
void addClip(std::shared_ptr<SkeletalAnimation> clip);
|
void addClip(std::shared_ptr<SkeletalAnimation> clip);
|
||||||
|
|||||||
@@ -18,6 +18,11 @@ public:
|
|||||||
|
|
||||||
void SetMaterialID(MaterialID id) { materialID = id; }
|
void SetMaterialID(MaterialID id) { materialID = id; }
|
||||||
MaterialID GetMaterialID() const { return materialID; }
|
MaterialID GetMaterialID() const { return materialID; }
|
||||||
|
std::string GetTypeName() const override
|
||||||
|
{
|
||||||
|
return "MeshRendererComponent";
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MeshID meshID{NULL_MESH_ID};
|
MeshID meshID{NULL_MESH_ID};
|
||||||
MaterialID materialID{NULL_MATERIAL_ID};
|
MaterialID materialID{NULL_MATERIAL_ID};
|
||||||
|
|||||||
@@ -11,6 +11,11 @@ public:
|
|||||||
|
|
||||||
void Update() override {}
|
void Update() override {}
|
||||||
|
|
||||||
|
std::string GetTypeName() const override
|
||||||
|
{
|
||||||
|
return "BoxCollider";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] PhysicsShapeDesc BuildPhysicsShape() const override {
|
[[nodiscard]] PhysicsShapeDesc BuildPhysicsShape() const override {
|
||||||
return PhysicsShapeDesc::Box(m_HalfExtents, m_CenterOffset, m_IsTrigger);
|
return PhysicsShapeDesc::Box(m_HalfExtents, m_CenterOffset, m_IsTrigger);
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ public:
|
|||||||
|
|
||||||
void Update() override {}
|
void Update() override {}
|
||||||
|
|
||||||
|
std::string GetTypeName() const override
|
||||||
|
{
|
||||||
|
return "RigidBody";
|
||||||
|
}
|
||||||
|
|
||||||
void AttachPhysicsBody(PhysicsWorld* world, PhysicsBodyHandle body);
|
void AttachPhysicsBody(PhysicsWorld* world, PhysicsBodyHandle body);
|
||||||
void DetachPhysicsBody();
|
void DetachPhysicsBody();
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ public:
|
|||||||
, m_Radius(radius) {}
|
, m_Radius(radius) {}
|
||||||
|
|
||||||
void Update() override {}
|
void Update() override {}
|
||||||
|
std::string GetTypeName() const override
|
||||||
|
{
|
||||||
|
return "SphereCollider";
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] PhysicsShapeDesc BuildPhysicsShape() const override {
|
[[nodiscard]] PhysicsShapeDesc BuildPhysicsShape() const override {
|
||||||
return PhysicsShapeDesc::Sphere(m_Radius, m_CenterOffset, m_IsTrigger);
|
return PhysicsShapeDesc::Sphere(m_Radius, m_CenterOffset, m_IsTrigger);
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
#ifndef COMPONENT_H
|
#ifndef COMPONENT_H
|
||||||
#define COMPONENT_H
|
#define COMPONENT_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#include <destrum/Graphics/RenderContext.h>
|
#include <destrum/Graphics/RenderContext.h>
|
||||||
#include <destrum/ObjectModel/Object.h>
|
#include <destrum/ObjectModel/Object.h>
|
||||||
|
#include <destrum/ObjectModel/ObjectId.h>
|
||||||
|
|
||||||
class GameObject;
|
class GameObject;
|
||||||
class Transform;
|
class Transform;
|
||||||
|
|
||||||
class Component : public Object {
|
class Component : public Object {
|
||||||
public:
|
public:
|
||||||
|
using ObjectMap = std::unordered_map<ObjectId, GameObject*>;
|
||||||
|
|
||||||
~Component() override = default;
|
~Component() override = default;
|
||||||
|
|
||||||
@@ -22,26 +29,40 @@ public:
|
|||||||
[[nodiscard]] Transform& GetTransform() const;
|
[[nodiscard]] Transform& GetTransform() const;
|
||||||
|
|
||||||
void Destroy() override;
|
void Destroy() override;
|
||||||
|
|
||||||
virtual void Start();
|
virtual void Start();
|
||||||
virtual void SetEnabled(bool enabled);
|
virtual void SetEnabled(bool enabled);
|
||||||
|
|
||||||
virtual void Update() = 0;
|
virtual void Update() = 0;
|
||||||
virtual void LateUpdate();
|
virtual void LateUpdate();
|
||||||
virtual void FixedUpdate();
|
virtual void FixedUpdate();
|
||||||
virtual void ImGuiInspector(); //Specifically for the inspector
|
|
||||||
virtual void ImGuiRender();
|
|
||||||
|
|
||||||
|
virtual void ImGuiInspector();
|
||||||
|
virtual void ImGuiRender();
|
||||||
|
|
||||||
virtual void Render(const RenderContext& ctx);
|
virtual void Render(const RenderContext& ctx);
|
||||||
|
|
||||||
|
// Serialization.
|
||||||
|
virtual std::string GetTypeName() const = 0;
|
||||||
|
|
||||||
|
virtual nlohmann::json Serialize() const {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Deserialize(const nlohmann::json& data) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void ResolveReferences(const ObjectMap& objects) {
|
||||||
|
}
|
||||||
|
|
||||||
bool HasStarted{false};
|
bool HasStarted{false};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit Component(GameObject& pParent, const std::string& name = "Component");
|
explicit Component(GameObject& pParent, const std::string& name = "Component");
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GameObject* m_ParentGameObjectPtr{};
|
GameObject* m_ParentGameObjectPtr{};
|
||||||
bool m_IsEnabled{true};
|
bool m_IsEnabled{true};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COMPONENT_H
|
#endif // COMPONENT_H
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <destrum/ObjectModel/Component.h>
|
#include <destrum/ObjectModel/Component.h>
|
||||||
#include <destrum/ObjectModel/Object.h>
|
#include <destrum/ObjectModel/Object.h>
|
||||||
|
#include <destrum/ObjectModel/ObjectId.h>
|
||||||
#include <destrum/ObjectModel/Transform.h>
|
#include <destrum/ObjectModel/Transform.h>
|
||||||
|
|
||||||
class Scene;
|
class Scene;
|
||||||
@@ -31,14 +34,28 @@ public:
|
|||||||
SetActiveDirty();
|
SetActiveDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] std::vector<std::unique_ptr<Component>>& GetComponents() { return m_Components; }
|
[[nodiscard]] bool IsActive() const { return m_Active; }
|
||||||
|
|
||||||
|
[[nodiscard]] ObjectId GetId() const { return m_Id; }
|
||||||
|
|
||||||
|
// Use this only while loading a scene.
|
||||||
|
void SetIdForDeserialization(ObjectId id);
|
||||||
|
|
||||||
|
[[nodiscard]] Scene* GetScene() const { return m_Scene; }
|
||||||
|
|
||||||
|
[[nodiscard]] std::vector<std::unique_ptr<Component>>& GetComponents() {
|
||||||
|
return m_Components;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const std::vector<std::unique_ptr<Component>>& GetComponents() const {
|
||||||
|
return m_Components;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] Transform& GetTransform() { return m_TransformPtr; }
|
[[nodiscard]] Transform& GetTransform() { return m_TransformPtr; }
|
||||||
|
[[nodiscard]] const Transform& GetTransform() const { return m_TransformPtr; }
|
||||||
|
|
||||||
[[nodiscard]] bool IsActiveInHierarchy();
|
[[nodiscard]] bool IsActiveInHierarchy();
|
||||||
|
|
||||||
[[nodiscard]] bool IsActive() const { return m_Active; }
|
|
||||||
|
|
||||||
explicit GameObject(const std::string& name = "GameObject");
|
explicit GameObject(const std::string& name = "GameObject");
|
||||||
~GameObject() override;
|
~GameObject() override;
|
||||||
|
|
||||||
@@ -57,20 +74,30 @@ public:
|
|||||||
return static_cast<TComponent*>(addedComponent.get());
|
return static_cast<TComponent*>(addedComponent.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Component>
|
template <typename TComponent>
|
||||||
[[nodiscard]] Component *GetComponent() {
|
[[nodiscard]] TComponent* GetComponent() {
|
||||||
for (const auto& component : m_Components) {
|
for (const auto& component : m_Components) {
|
||||||
if (auto casted = dynamic_cast<Component*>(component.get())) {
|
if (auto casted = dynamic_cast<TComponent*>(component.get())) {
|
||||||
return casted;
|
return casted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Component>
|
template <typename TComponent>
|
||||||
Component *DestroyComponent() {
|
[[nodiscard]] const TComponent* GetComponent() const {
|
||||||
for (const auto& component : m_Components) {
|
for (const auto& component : m_Components) {
|
||||||
if (auto casted = dynamic_cast<Component*>(component.get())) {
|
if (auto casted = dynamic_cast<const TComponent*>(component.get())) {
|
||||||
|
return casted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TComponent>
|
||||||
|
TComponent* DestroyComponent() {
|
||||||
|
for (const auto& component : m_Components) {
|
||||||
|
if (auto casted = dynamic_cast<TComponent*>(component.get())) {
|
||||||
casted->Destroy();
|
casted->Destroy();
|
||||||
return casted;
|
return casted;
|
||||||
}
|
}
|
||||||
@@ -78,40 +105,50 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Component>
|
template <typename TComponent>
|
||||||
[[nodiscard]] bool HasComponent() {
|
[[nodiscard]] bool HasComponent() const {
|
||||||
for (const auto& component : m_Components) {
|
for (const auto& component : m_Components) {
|
||||||
if (auto casted = dynamic_cast<Component*>(component.get())) {
|
if (dynamic_cast<TComponent*>(component.get())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Component>
|
template <typename TComponent>
|
||||||
Component *GetComponentInChildren() {
|
TComponent* GetComponentInChildren() {
|
||||||
return GetComponentInChildrenRecursive<Component>(&GetTransform());
|
return GetComponentInChildrenRecursive<TComponent>(&GetTransform());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename Component>
|
template <typename TComponent>
|
||||||
static Component *GetComponentInChildrenRecursive(Transform* transform) {
|
static TComponent* GetComponentInChildrenRecursive(Transform* transform) {
|
||||||
if (!transform) return nullptr;
|
if (!transform) return nullptr;
|
||||||
|
|
||||||
GameObject* owner = transform->GetOwner();
|
GameObject* owner = transform->GetOwner();
|
||||||
if (owner) {
|
if (owner) {
|
||||||
if (Component* comp = owner->GetComponent<Component>()) {
|
if (TComponent* comp = owner->GetComponent<TComponent>()) {
|
||||||
return comp;
|
return comp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Transform* child : transform->GetChildren()) {
|
for (Transform* child : transform->GetChildren()) {
|
||||||
if (Component* found = GetComponentInChildrenRecursive<Component>(child)) {
|
if (TComponent* found = GetComponentInChildrenRecursive<TComponent>(child)) {
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetScene(Scene* scene) { m_Scene = scene; }
|
||||||
|
|
||||||
void SetActiveDirty();
|
void SetActiveDirty();
|
||||||
|
void UpdateActiveState();
|
||||||
|
|
||||||
|
inline static ObjectId s_NextId{1};
|
||||||
|
|
||||||
|
ObjectId m_Id{InvalidObjectId};
|
||||||
|
|
||||||
bool m_Active{true};
|
bool m_Active{true};
|
||||||
Scene* m_Scene{};
|
Scene* m_Scene{};
|
||||||
@@ -119,6 +156,5 @@ private:
|
|||||||
std::vector<std::unique_ptr<Component>> m_Components{};
|
std::vector<std::unique_ptr<Component>> m_Components{};
|
||||||
|
|
||||||
bool m_ActiveDirty{true};
|
bool m_ActiveDirty{true};
|
||||||
bool m_ActiveInHierarchy{true}; //Derived
|
bool m_ActiveInHierarchy{true};
|
||||||
void UpdateActiveState();
|
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef DESTRUM_OBJECTID_H
|
||||||
|
#define DESTRUM_OBJECTID_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
using ObjectId = std::uint64_t;
|
||||||
|
|
||||||
|
inline constexpr ObjectId InvalidObjectId = 0;
|
||||||
|
|
||||||
|
#endif //DESTRUM_OBJECTID_H
|
||||||
@@ -35,6 +35,12 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] bool IsBeingUnloaded() const { return m_BeingUnloaded; }
|
[[nodiscard]] bool IsBeingUnloaded() const { return m_BeingUnloaded; }
|
||||||
|
|
||||||
|
void CommitPendingAdditions();
|
||||||
|
|
||||||
|
[[nodiscard]] const std::vector<std::shared_ptr<GameObject>>& GetObjects() const {
|
||||||
|
return m_objects;
|
||||||
|
}
|
||||||
|
|
||||||
void SetRegisterBindings(std::function<void()> registerBindings) {
|
void SetRegisterBindings(std::function<void()> registerBindings) {
|
||||||
m_registerBindings = std::move(registerBindings);
|
m_registerBindings = std::move(registerBindings);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#ifndef DESTRUM_COMPONENTFACTORY_H
|
||||||
|
#define DESTRUM_COMPONENTFACTORY_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <destrum/ObjectModel/Component.h>
|
||||||
|
#include <destrum/ObjectModel/GameObject.h>
|
||||||
|
|
||||||
|
class ComponentFactory final {
|
||||||
|
public:
|
||||||
|
using CreateFn = std::function<Component*(GameObject&)>;
|
||||||
|
|
||||||
|
static void Register(const std::string& typeName, CreateFn createFn) {
|
||||||
|
Registry()[typeName] = std::move(createFn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Component* Create(const std::string& typeName, GameObject& owner) {
|
||||||
|
const auto it = Registry().find(typeName);
|
||||||
|
|
||||||
|
if (it == Registry().end()) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return it->second(owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::unordered_map<std::string, CreateFn>& Registry() {
|
||||||
|
static std::unordered_map<std::string, CreateFn> registry;
|
||||||
|
return registry;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //DESTRUM_COMPONENTFACTORY_H
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#ifndef DESTRUM_COMPONENTREGISTRY_H
|
||||||
|
#define DESTRUM_COMPONENTREGISTRY_H
|
||||||
|
|
||||||
|
void RegisterEngineComponents();
|
||||||
|
|
||||||
|
#endif //DESTRUM_COMPONENTREGISTRY_H
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef DESTRUM_SCENESERIALIZER_H
|
||||||
|
#define DESTRUM_SCENESERIALIZER_H
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
class Scene;
|
||||||
|
|
||||||
|
class SceneSerializer final {
|
||||||
|
public:
|
||||||
|
static bool Save(Scene& scene, const std::filesystem::path& path);
|
||||||
|
static bool Load(Scene& scene, const std::filesystem::path& path);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //DESTRUM_SCENESERIALIZER_H
|
||||||
@@ -2,13 +2,10 @@
|
|||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <destrum/ObjectModel/GameObject.h>
|
#include <destrum/ObjectModel/GameObject.h>
|
||||||
// #include "imgui.h"
|
|
||||||
|
|
||||||
Component::Component(GameObject& pParent, const std::string& name): Object(name), m_ParentGameObjectPtr(&pParent) {
|
Component::Component(GameObject& pParent, const std::string& name)
|
||||||
// if (m_ParentGameObjectPtr == nullptr) {
|
: Object(name),
|
||||||
// //TODO: Change pParent ot be a reference
|
m_ParentGameObjectPtr(&pParent) {
|
||||||
// throw std::runtime_error("Component made with no GameObject??");
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform& Component::GetTransform() const {
|
Transform& Component::GetTransform() const {
|
||||||
@@ -16,7 +13,6 @@ Transform& Component::GetTransform() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Component::Destroy() {
|
void Component::Destroy() {
|
||||||
// const bool isBeingDestroyed = GetIsBeingDestroyed();
|
|
||||||
Object::Destroy();
|
Object::Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,5 +36,4 @@ void Component::ImGuiRender() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Component::Render(const RenderContext& ctx) {
|
void Component::Render(const RenderContext& ctx) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,18 +1,30 @@
|
|||||||
#include <destrum/ObjectModel/GameObject.h>
|
#include <destrum/ObjectModel/GameObject.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "spdlog/spdlog.h"
|
#include "spdlog/spdlog.h"
|
||||||
|
|
||||||
// #include "Managers/ResourceManager.h"
|
|
||||||
|
|
||||||
GameObject::~GameObject() {
|
GameObject::~GameObject() {
|
||||||
// spdlog::debug("GameObject destroyed: {}", GetName());
|
// 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() {
|
void GameObject::SetActiveDirty() {
|
||||||
m_ActiveDirty = true;
|
m_ActiveDirty = true;
|
||||||
|
|
||||||
for (const Transform* child : m_TransformPtr.GetChildren()) {
|
for (const Transform* child : m_TransformPtr.GetChildren()) {
|
||||||
child->GetOwner()->SetActiveDirty();
|
child->GetOwner()->SetActiveDirty();
|
||||||
}
|
}
|
||||||
@@ -38,42 +50,44 @@ bool GameObject::IsActiveInHierarchy() {
|
|||||||
return m_ActiveInHierarchy;
|
return m_ActiveInHierarchy;
|
||||||
}
|
}
|
||||||
|
|
||||||
GameObject::GameObject(const std::string& name): Object(name) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameObject::Update() {
|
void GameObject::Update() {
|
||||||
for (const auto& component : m_Components) {
|
for (const auto& component : m_Components) {
|
||||||
|
if (!component->isEnabled()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (!component->HasStarted) {
|
if (!component->HasStarted) {
|
||||||
component->Start();
|
component->Start();
|
||||||
component->HasStarted = true;
|
component->HasStarted = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
component->Update();
|
component->Update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameObject::LateUpdate() {
|
void GameObject::LateUpdate() {
|
||||||
for (const auto& component : m_Components) {
|
for (const auto& component : m_Components) {
|
||||||
|
if (component->isEnabled()) {
|
||||||
component->LateUpdate();
|
component->LateUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GameObject::FixedUpdate() {
|
void GameObject::FixedUpdate() {
|
||||||
for (const auto& component : m_Components) {
|
for (const auto& component : m_Components) {
|
||||||
|
if (component->isEnabled()) {
|
||||||
component->FixedUpdate();
|
component->FixedUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GameObject::Render(const RenderContext& ctx) const {
|
void GameObject::Render(const RenderContext& ctx) const {
|
||||||
for (const auto& component : m_Components) {
|
for (const auto& component : m_Components) {
|
||||||
|
if (component->isEnabled()) {
|
||||||
component->Render(ctx);
|
component->Render(ctx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// void GameObject::ImGuiRender() {
|
|
||||||
// for (const auto& component: m_Components) {
|
|
||||||
// component->ImGuiRender();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
void GameObject::Destroy() {
|
void GameObject::Destroy() {
|
||||||
Object::Destroy();
|
Object::Destroy();
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ GameObject* Scene::CreateGameObject(std::string name)
|
|||||||
|
|
||||||
GameObject* rawPtr = obj.get();
|
GameObject* rawPtr = obj.get();
|
||||||
|
|
||||||
// obj->SetScene(this);
|
obj->SetScene(this);
|
||||||
m_pendingAdditions.emplace_back(std::move(obj));
|
m_pendingAdditions.emplace_back(std::move(obj));
|
||||||
|
|
||||||
return rawPtr;
|
return rawPtr;
|
||||||
@@ -61,13 +61,7 @@ void Scene::Load() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Scene::Update() {
|
void Scene::Update() {
|
||||||
if (!m_pendingAdditions.empty()) {
|
CommitPendingAdditions();
|
||||||
for (auto& obj : m_pendingAdditions) {
|
|
||||||
m_objects.emplace_back(std::move(obj));
|
|
||||||
}
|
|
||||||
m_pendingAdditions.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
for (const auto& object : m_objects) {
|
for (const auto& object : m_objects) {
|
||||||
if (object->IsActiveInHierarchy()) {
|
if (object->IsActiveInHierarchy()) {
|
||||||
@@ -155,3 +149,15 @@ void Scene::DestroyGameObjects() {
|
|||||||
assert(m_BeingUnloaded && "Scene is being cleared but not unloaded? Weird");
|
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