From 74a6035c325c1310fbebdb058beecb39648da82d Mon Sep 17 00:00:00 2001 From: Light Date: Tue, 5 Oct 2021 13:44:32 +0330 Subject: [PATCH] Scene Serialization - Scenes can now be serialized and de-serialized into .yaml files - Added yaml-cpp as Dependency --- .gitmodules | 3 + CMakeLists.txt | 2 + Dependencies/yaml-cpp | 1 + Engine/CMakeLists.txt | 1 + Engine/src/Engine/Camera/Camera.h | 6 +- Engine/src/Engine/Graphics/Texture.cpp | 11 +- Engine/src/Engine/Graphics/Texture.h | 9 +- Engine/src/Engine/Scene/Scene.h | 3 + Engine/src/Engine/Utility/ResourceManager.cpp | 5 +- Engine/src/Engine/Utility/Serializer.cpp | 256 ++++++++++++++++++ Engine/src/Engine/Utility/Serializer.h | 31 +++ .../GraphicsAPI/DirectX/dxTexture.cpp | 11 +- .../Platform/GraphicsAPI/DirectX/dxTexture.h | 2 +- .../Platform/GraphicsAPI/OpenGL/glTexture.cpp | 6 +- .../Platform/GraphicsAPI/OpenGL/glTexture.h | 2 +- Mirror/CMakeLists.txt | 1 + Mirror/src/EditorLayer.cpp | 5 + 17 files changed, 336 insertions(+), 19 deletions(-) create mode 160000 Dependencies/yaml-cpp create mode 100644 Engine/src/Engine/Utility/Serializer.cpp create mode 100644 Engine/src/Engine/Utility/Serializer.h diff --git a/.gitmodules b/.gitmodules index 74f85a1..37350a6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -16,3 +16,6 @@ [submodule "Dependencies/ShaderConductor"] path = Dependencies/ShaderConductor url = https://github.com/Light3039/shaderconductor +[submodule "Dependencies/yaml-cpp"] + path = Dependencies/yaml-cpp + url = https://github.com/jbeder/yaml-cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index df57f71..d38cd25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,7 @@ add_subdirectory(${DEPENDENCIES_DIR}glm/) add_subdirectory(${DEPENDENCIES_DIR}entt/) add_subdirectory(${DEPENDENCIES_DIR}imgui/) add_subdirectory(${DEPENDENCIES_DIR}stb_image/) +add_subdirectory(${DEPENDENCIES_DIR}yaml-cpp/) target_link_libraries(Engine glad) target_link_libraries(Engine glfw) @@ -46,6 +47,7 @@ target_link_libraries(Engine spdlog) target_link_libraries(Engine imgui) target_link_libraries(Engine stb_image) target_link_libraries(Engine ShaderConductor) +target_link_libraries(Engine yaml-cpp) target_link_libraries(imgui glad) target_link_libraries(imgui glfw) diff --git a/Dependencies/yaml-cpp b/Dependencies/yaml-cpp new file mode 160000 index 0000000..0d9dbcf --- /dev/null +++ b/Dependencies/yaml-cpp @@ -0,0 +1 @@ +Subproject commit 0d9dbcfe8c0df699aed8ae050dddaca614178fb1 diff --git a/Engine/CMakeLists.txt b/Engine/CMakeLists.txt index 85b6836..dfd8c1e 100644 --- a/Engine/CMakeLists.txt +++ b/Engine/CMakeLists.txt @@ -48,6 +48,7 @@ ${DEPENDENCIES_DIR}imgui/ ${DEPENDENCIES_DIR}spdlog/include/ ${DEPENDENCIES_DIR}stb_image/ ${DEPENDENCIES_DIR}ShaderConductor/Include/ +${DEPENDENCIES_DIR}yaml-cpp/include/ ) source_group(TREE ${ENGINE_DIR} FILES ${ENGINE_ALL_FILES} ${ENGINE_RES_FILES}) diff --git a/Engine/src/Engine/Camera/Camera.h b/Engine/src/Engine/Camera/Camera.h index bb812df..1c11677 100644 --- a/Engine/src/Engine/Camera/Camera.h +++ b/Engine/src/Engine/Camera/Camera.h @@ -17,9 +17,11 @@ namespace Light { public: Camera() = default; - const glm::mat4& GetProjection() const { return m_Projection; } + inline const glm::mat4& GetProjection() const { return m_Projection; } - const glm::vec4& GetBackgroundColor() const { return m_BackgroundColor; } + inline const glm::vec4& GetBackgroundColor() const { return m_BackgroundColor; } + + inline void SetBackgroundColor(const glm::vec4& color) { m_BackgroundColor = color; } }; } \ No newline at end of file diff --git a/Engine/src/Engine/Graphics/Texture.cpp b/Engine/src/Engine/Graphics/Texture.cpp index 015f830..61f0d40 100644 --- a/Engine/src/Engine/Graphics/Texture.cpp +++ b/Engine/src/Engine/Graphics/Texture.cpp @@ -11,15 +11,15 @@ namespace Light { - RefTexture::Create(unsigned int width, unsigned int height, unsigned int components, unsigned char* pixels, Ref sharedContext) + RefTexture::Create(unsigned int width, unsigned int height, unsigned int components, unsigned char* pixels, Ref sharedContext, const std::string& filePath) { switch (GraphicsContext::GetGraphicsAPI()) { case GraphicsAPI::OpenGL: - return CreateRef(width, height, components, pixels); + return CreateRef(width, height, components, pixels, filePath); case GraphicsAPI::DirectX: LT_WIN( - return CreateRef(width, height, components, pixels, std::static_pointer_cast(sharedContext));) + return CreateRef(width, height, components, pixels, std::static_pointer_cast(sharedContext), filePath);) default: LT_ENGINE_ASSERT(false, "Texture::Create: invalid/unsupported 'GraphicsAPI' {}", GraphicsContext::GetGraphicsAPI()); @@ -27,4 +27,9 @@ namespace Light { } } + Texture::Texture(const std::string& filePath): + m_FilePath(filePath) + { + } + } \ No newline at end of file diff --git a/Engine/src/Engine/Graphics/Texture.h b/Engine/src/Engine/Graphics/Texture.h index 1539181..9c1fab2 100644 --- a/Engine/src/Engine/Graphics/Texture.h +++ b/Engine/src/Engine/Graphics/Texture.h @@ -10,7 +10,7 @@ namespace Light { class Texture { public: - static Ref Create(unsigned int width, unsigned int height, unsigned int components, unsigned char* pixels, Ref sharedContext); + static Ref Create(unsigned int width, unsigned int height, unsigned int components, unsigned char* pixels, Ref sharedContext, const std::string& filePath); Texture(const Texture&) = delete; Texture& operator=(const Texture&) = delete; @@ -19,8 +19,13 @@ namespace Light { virtual void Bind(unsigned int slot = 0) = 0; + inline const std::string& GetFilePath() const { return m_FilePath; } + protected: - Texture() = default; + Texture(const std::string& filePath); + + protected: + std::string m_FilePath; }; } \ No newline at end of file diff --git a/Engine/src/Engine/Scene/Scene.h b/Engine/src/Engine/Scene/Scene.h index 7999d3d..a6fe21c 100644 --- a/Engine/src/Engine/Scene/Scene.h +++ b/Engine/src/Engine/Scene/Scene.h @@ -16,8 +16,11 @@ namespace Light { class Scene { + private: friend class Entity; + friend class SceneSerializer; friend class SceneHierarchyPanel; + private: entt::registry m_Registry; diff --git a/Engine/src/Engine/Utility/ResourceManager.cpp b/Engine/src/Engine/Utility/ResourceManager.cpp index 038c3e8..6ea08e4 100644 --- a/Engine/src/Engine/Utility/ResourceManager.cpp +++ b/Engine/src/Engine/Utility/ResourceManager.cpp @@ -55,7 +55,7 @@ namespace Light { ImageFileHandle imgFile = FileManager::ReadImageFile(path, desiredComponents); // create texture - m_Textures[name] = Ref(Texture::Create(imgFile.GetWidth(), imgFile.GetHeight(), imgFile.GetComponents(), imgFile.GetData(), GraphicsContext::GetSharedContext())); + m_Textures[name] = Ref(Texture::Create(imgFile.GetWidth(), imgFile.GetHeight(), imgFile.GetComponents(), imgFile.GetData(), GraphicsContext::GetSharedContext(), path) ); // free file imgFile.Release(); @@ -71,5 +71,4 @@ namespace Light { m_Textures[name] = nullptr; } - -} \ No newline at end of file + \ No newline at end of file diff --git a/Engine/src/Engine/Utility/Serializer.cpp b/Engine/src/Engine/Utility/Serializer.cpp new file mode 100644 index 0000000..d6ffdff --- /dev/null +++ b/Engine/src/Engine/Utility/Serializer.cpp @@ -0,0 +1,256 @@ +#include "ltpch.h" +#include "Serializer.h" + +#include "Scene/Components.h" + +#include "Graphics/Texture.h" + +namespace YAML { + + template<> + struct convert + { + static Node encode(const glm::vec3 & rhs) + { + Node node; + node.push_back(rhs.x); + node.push_back(rhs.y); + node.push_back(rhs.z); + return node; + } + + static bool decode(const Node& node, glm::vec3& rhs) + { + if (!node.IsSequence() || node.size() != 3) + return false; + + rhs.x = node[0].as(); + rhs.y = node[1].as(); + rhs.z = node[2].as(); + return true; + } + }; + + template<> + struct convert + { + static Node encode(const glm::vec4& rhs) + { + Node node; + node.push_back(rhs.x); + node.push_back(rhs.y); + node.push_back(rhs.z); + node.push_back(rhs.w); + return node; + } + + static bool decode(const Node& node, glm::vec4& rhs) + { + if (!node.IsSequence() || node.size() != 3) + return false; + + rhs.x = node[0].as(); + rhs.y = node[1].as(); + rhs.z = node[2].as(); + rhs.w = node[3].as(); + return true; + } + }; +} + +namespace Light { + + static YAML::Emitter& operator << (YAML::Emitter& out, const glm::vec3& v) + { + out << YAML::Flow; + out << YAML::BeginSeq << v.x << v.y << v.z << YAML::EndSeq; + return out; + } + + static YAML::Emitter& operator << (YAML::Emitter& out, const glm::vec4& v) + { + out << YAML::Flow; + out << YAML::BeginSeq << v.x << v.y << v.z << v.w << YAML::EndSeq; + return out; + } + + SceneSerializer::SceneSerializer(const Ref& scene): + m_Scene(scene) + { + } + + void SceneSerializer::Serialize(const std::string& filePath) + { + YAML::Emitter out; + out << YAML::BeginMap; // Scene + out << YAML::Key << "Scene" << YAML::Value << "Untitled"; + + out << YAML::Key << "Entities" << YAML::Value << YAML::BeginSeq; + m_Scene->m_Registry.each([&](auto entityID) + { + Entity entity = { entityID, m_Scene.get() }; + if (!entity) + return; + + SerializeEntity(out, entity); + }); + out << YAML::EndSeq; + out << YAML::EndMap; + + std::filesystem::create_directories(filePath.substr(0ull, filePath.find_last_of('/'))); + + std::ofstream fout(filePath); + fout << out.c_str(); + } + + bool SceneSerializer::Deserialize(const std::string& filePath) + { + std::ifstream stream(filePath); + std::stringstream ss; + ss << stream.rdbuf(); + + YAML::Node data = YAML::Load(ss.str()); + if (!data["Scene"]) + return false; + + std::string sceneName = data["Scene"].as(); + LT_ENGINE_TRACE("SceneSerializer::Deserialize: Deserializing scene: '{}'", sceneName); + + auto entities = data["Entities"]; + if (entities) + { + for (auto entity : entities) + { + uint64_t uuid = entity["Entity"].as(); // #todo + + std::string name; + auto tagComponent = entity["TagComponent"]; + if (tagComponent) + name = tagComponent["Tag"].as(); + + LT_ENGINE_TRACE("SceneSerializer::Deserialize: Deserialized entity '{}' : '{}'", uuid, name); + + Entity deserializedEntity = m_Scene->CreateEntity(name); + + auto transformComponent = entity["TransformComponent"]; + if (transformComponent) + { + auto& entityTransforomComponent = deserializedEntity.GetComponent(); + + entityTransforomComponent.translation = transformComponent["Translation"].as(); + entityTransforomComponent.rotation = transformComponent["Rotation"].as(); + entityTransforomComponent.scale = transformComponent["Scale"].as(); + } + + auto cameraComponent = entity["CameraComponent"]; + if(cameraComponent) + { + auto& entityCameraComponent = deserializedEntity.AddComponent(); + + auto& cameraSpecifications = cameraComponent["Camera"]; + entityCameraComponent.camera.SetProjectionType((SceneCamera::ProjectionType)cameraSpecifications["ProjectionType"].as()); + + entityCameraComponent.camera.SetOrthographicSize(cameraSpecifications["OrthographicsSize"].as()); + entityCameraComponent.camera.SetOrthographicNearPlane(cameraSpecifications["OrthographicsNearPlane"].as()); + entityCameraComponent.camera.SetOrthographicFarPlane(cameraSpecifications["OrthographicsFarPlane"].as()); + + entityCameraComponent.camera.SetPerspectiveVerticalFOV(cameraSpecifications["PerspectiveVerticalFOV"].as()); + entityCameraComponent.camera.SetPerspectiveNearPlane(cameraSpecifications["PerspectiveNearPlane"].as()); + entityCameraComponent.camera.SetPerspectiveFarPlane(cameraSpecifications["PerspectiveFarPlane"].as()); + + entityCameraComponent.camera.SetBackgroundColor(cameraSpecifications["BackgroundColor"].as()); + + entityCameraComponent.isPrimary = cameraComponent["IsPrimary"].as(); + } + + // #todo: figure out texture de-serialization + } + } + + return false; + } + + void SceneSerializer::SerializeBinary(const std::string& filePath) + { + LT_ENGINE_ERROR("SceneSerializer::SerializeRuntime: NO_IMPLEMENT"); + } + + bool SceneSerializer::DeserializeBinary(const std::string& filePath) + { + LT_ENGINE_ERROR("SceneSerializer::DeserializeBinary: NO_IMPLEMENT"); + return false; + } + + void SceneSerializer::SerializeEntity(YAML::Emitter& out, Entity entity) + { + out << YAML::BeginMap; // entity + out << YAML::Key << "Entity" << YAML::Value << "69696969696969"; // dummy uuid + out << YAML::EndMap; // entity + + if (entity.HasComponent()) + { + out << YAML::Key << "TagComponent"; + out << YAML::BeginMap; // tag component + + auto& tagComponent = entity.GetComponent().tag; + out << YAML::Key << "Tag" << YAML::Value << tagComponent; + + out << YAML::EndMap; // tag component + } + + if (entity.HasComponent()) + { + out << YAML::Key << "TransformComponent"; + out << YAML::BeginMap; // transform component + + auto& transformComponent = entity.GetComponent(); + + out << YAML::Key << "Translation" << YAML::Value << transformComponent.translation; + out << YAML::Key << "Rotation" << YAML::Value << transformComponent.rotation; + out << YAML::Key << "Scale" << YAML::Value << transformComponent.scale; + + out << YAML::EndMap; // transform component; + } + + if (entity.HasComponent()) + { + out << YAML::Key << "SpriteRendererComponent"; + out << YAML::BeginMap; // sprite renderer component; + + auto& spriteRendererComponent = entity.GetComponent(); + + out << YAML::Key << "Texture" << YAML::Value << spriteRendererComponent.texture->GetFilePath(); + out << YAML::Key << "Tint" << YAML::Value << spriteRendererComponent.tint; + + out << YAML::EndMap; // sprite renderer component + } + + // #todo: + // if(entity.HasComponent()) + + if (entity.HasComponent()) + { + out << YAML::Key << "CameraComponent"; + out << YAML::BeginMap; // camera component + + auto& cameraComponent = entity.GetComponent(); + + out << YAML::Key << "Camera" << YAML::Value; + out << YAML::BeginMap; // camera + out << YAML::Key << "OrthographicSize" << YAML::Value << cameraComponent.camera.GetOrthographicSize(); + out << YAML::Key << "OrthographicFarPlane" << YAML::Value << cameraComponent.camera.GetOrthographicFarPlane(); + out << YAML::Key << "OrthographicNearPlane" << YAML::Value << cameraComponent.camera.GetOrthographicNearPlane(); + out << YAML::Key << "PerspectiveVerticalFOV" << YAML::Value << cameraComponent.camera.GetPerspectiveVerticalFOV(); + out << YAML::Key << "PerspectiveFarPlane" << YAML::Value << cameraComponent.camera.GetPerspectiveFarPlane(); + out << YAML::Key << "PerspectiveNearPlane" << YAML::Value << cameraComponent.camera.GetPerspectiveNearPlane(); + out << YAML::Key << "ProjectionType" << YAML::Value << (int)cameraComponent.camera.GetProjectionType(); + out << YAML::Key << "BackgroundColor" << YAML::Value << cameraComponent.camera.GetBackgroundColor(); + out << YAML::EndMap; // camera + + out << YAML::Key << "IsPrimary" << YAML::Value << cameraComponent.isPrimary; + + out << YAML::EndMap; // camera component + } + } + +} \ No newline at end of file diff --git a/Engine/src/Engine/Utility/Serializer.h b/Engine/src/Engine/Utility/Serializer.h new file mode 100644 index 0000000..80a12e1 --- /dev/null +++ b/Engine/src/Engine/Utility/Serializer.h @@ -0,0 +1,31 @@ +#pragma once + +#include "Base/Base.h" + +#include "Scene/Scene.h" +#include "Scene/Entity.h" + +#include + +namespace Light { + + class SceneSerializer + { + public: + SceneSerializer(const Ref& scene); + + void Serialize(const std::string& filePath); + bool Deserialize(const std::string& filePath); + + void SerializeBinary(const std::string& filePath); + bool DeserializeBinary(const std::string& filePath); + + private: + void SerializeEntity(YAML::Emitter& out, Entity entity); + + private: + Ref m_Scene; + }; + + +} \ No newline at end of file diff --git a/Engine/src/Platform/GraphicsAPI/DirectX/dxTexture.cpp b/Engine/src/Platform/GraphicsAPI/DirectX/dxTexture.cpp index e629ce3..8e1872a 100644 --- a/Engine/src/Platform/GraphicsAPI/DirectX/dxTexture.cpp +++ b/Engine/src/Platform/GraphicsAPI/DirectX/dxTexture.cpp @@ -4,11 +4,12 @@ namespace Light { - dxTexture::dxTexture(unsigned int width, unsigned int height, unsigned int components, unsigned char* pixels, Ref sharedContext) - : m_Context(sharedContext), - m_Texture2D(nullptr), - m_ShaderResourceView(nullptr), - m_SamplerState(nullptr) + dxTexture::dxTexture(unsigned int width, unsigned int height, unsigned int components, unsigned char* pixels, Ref sharedContext, const std::string& filePath): + Texture(filePath), + m_Context(sharedContext), + m_Texture2D(nullptr), + m_ShaderResourceView(nullptr), + m_SamplerState(nullptr) { // texture2d desc D3D11_TEXTURE2D_DESC t2dDesc = {}; diff --git a/Engine/src/Platform/GraphicsAPI/DirectX/dxTexture.h b/Engine/src/Platform/GraphicsAPI/DirectX/dxTexture.h index 6ee061b..3157d30 100644 --- a/Engine/src/Platform/GraphicsAPI/DirectX/dxTexture.h +++ b/Engine/src/Platform/GraphicsAPI/DirectX/dxTexture.h @@ -21,7 +21,7 @@ namespace Light { Microsoft::WRL::ComPtr m_SamplerState; public: - dxTexture(unsigned int width, unsigned int height, unsigned int components, unsigned char* pixels, Ref sharedContext); + dxTexture(unsigned int width, unsigned int height, unsigned int components, unsigned char* pixels, Ref sharedContext, const std::string& filePath); void Bind(unsigned int slot = 0u) override; }; diff --git a/Engine/src/Platform/GraphicsAPI/OpenGL/glTexture.cpp b/Engine/src/Platform/GraphicsAPI/OpenGL/glTexture.cpp index 09a520b..1469e99 100644 --- a/Engine/src/Platform/GraphicsAPI/OpenGL/glTexture.cpp +++ b/Engine/src/Platform/GraphicsAPI/OpenGL/glTexture.cpp @@ -5,9 +5,11 @@ namespace Light { - glTexture::glTexture(unsigned int width, unsigned int height, unsigned int components, unsigned char* pixels) - : m_TextureID(NULL) + glTexture::glTexture(unsigned int width, unsigned int height, unsigned int components, unsigned char* pixels, const std::string& filePath): + Texture(filePath), + m_TextureID(NULL) { + // create texture glCreateTextures(GL_TEXTURE_2D, 1, &m_TextureID); diff --git a/Engine/src/Platform/GraphicsAPI/OpenGL/glTexture.h b/Engine/src/Platform/GraphicsAPI/OpenGL/glTexture.h index 34d7dfc..f527f3c 100644 --- a/Engine/src/Platform/GraphicsAPI/OpenGL/glTexture.h +++ b/Engine/src/Platform/GraphicsAPI/OpenGL/glTexture.h @@ -12,7 +12,7 @@ namespace Light { unsigned int m_TextureID; public: - glTexture(unsigned int width, unsigned int height, unsigned int components, unsigned char* pixels); + glTexture(unsigned int width, unsigned int height, unsigned int components, unsigned char* pixels, const std::string& filePath); ~glTexture(); void Bind(unsigned int slot = 0u) override; diff --git a/Mirror/CMakeLists.txt b/Mirror/CMakeLists.txt index 24865d9..ec12de4 100644 --- a/Mirror/CMakeLists.txt +++ b/Mirror/CMakeLists.txt @@ -21,6 +21,7 @@ ${DEPENDENCIES_DIR}glm/ ${DEPENDENCIES_DIR}imgui/ ${DEPENDENCIES_DIR}spdlog/include ${DEPENDENCIES_DIR}stb_image/ +${DEPENDENCIES_DIR}yaml-cpp/include ) diff --git a/Mirror/src/EditorLayer.cpp b/Mirror/src/EditorLayer.cpp index f63e53a..c146d88 100644 --- a/Mirror/src/EditorLayer.cpp +++ b/Mirror/src/EditorLayer.cpp @@ -1,5 +1,7 @@ #include "EditorLayer.h" +#include "Utility/Serializer.h" + namespace Light { EditorLayer::EditorLayer(const std::string& name) @@ -19,6 +21,9 @@ namespace Light { // for native script components m_Scene->OnCreate(); + + SceneSerializer serializer(m_Scene); + serializer.Serialize("assets/scenes/test.yaml"); } void EditorLayer::OnUpdate(float deltaTime)