From c8ebc0fa17336e5f6c4c38d98f27183b07734284 Mon Sep 17 00:00:00 2001 From: Nigel Barink Date: Sat, 5 Nov 2022 12:50:01 +0100 Subject: [PATCH] Working on scene and project serialisation Added scene/project save and load to main menu, added file dialogs for opening and saving scene/project --- Editor/premake5.lua | 9 +-- Editor/src/Dialog.h | 72 ++++++++++++++++++++ Editor/src/Project.cpp | 23 ++++++- Editor/src/Project.h | 13 ++-- Editor/src/SceneSerializer.h | 110 +++++++++++++++++++++++++++++++ Editor/src/main.cpp | 124 +++++++++++++++++++++++++++-------- Editor/src/widgets.cpp | 37 +++++------ libraries.lua | 7 +- premake5.lua | 1 + 9 files changed, 336 insertions(+), 60 deletions(-) create mode 100644 Editor/src/Dialog.h create mode 100644 Editor/src/SceneSerializer.h diff --git a/Editor/premake5.lua b/Editor/premake5.lua index c56d5be..0dd7b56 100644 --- a/Editor/premake5.lua +++ b/Editor/premake5.lua @@ -6,7 +6,8 @@ buildmessage "Building editor ..." links{ "YoggieEngine", "ImGuizmo", - "yaml-cpp" + "yaml-cpp", + "nfd.lib" } includedirs{ @@ -25,18 +26,18 @@ includedirs{ incfolder["imguizmo"], incfolder["entt"], incfolder["yamlcpp"], + incfolder["nativefiledialog"], "./include" } libdirs { - staticlib["yoggie"] + staticlib["yoggie"], + staticlib["nativefiledialog"] } files { "./src/*.h", "./src/*.cpp" } - -include("../yaml-cpp") diff --git a/Editor/src/Dialog.h b/Editor/src/Dialog.h new file mode 100644 index 0000000..6459601 --- /dev/null +++ b/Editor/src/Dialog.h @@ -0,0 +1,72 @@ +#pragma once +#include +#include +#include +#include +#include +#include "Project.h" +struct DialogSpec { + const std::string& id; + const std::string& Title; + const std::string& confirmText; + DialogSpec() = default; +}; + +//classes based on RAII +class Dialog { +public: + Dialog( DialogSpec spec, std::function onConfirm) + : path(nullptr), location() { + if (ImGui::BeginPopupModal(spec.id.c_str(), NULL, ImGuiWindowFlags_NoMove)) + { + ImGui::Text(spec.Title.c_str()); + ImGui::Separator(); + + ImGui::LabelText("##Directory", "Directory: %s", location.c_str()); + if (ImGui::Button("...")) { + nfdresult_t result = NFD_OpenDialog(NULL, NULL, &path); + + switch (result) { + case (NFD_OKAY): + location = std::string(path); + break; + case(NFD_CANCEL): + std::cout << "NFD_CANCEL" << std::endl; + case (NFD_ERROR): + std::cout << "NFD_Error: " << NFD_GetError() << std::endl; + break; + + }; + + } + + if (ImGui::Button(spec.confirmText.c_str(), ImVec2(120, 0))) + { + onConfirm(location); + + ImGui::CloseCurrentPopup(); + } + + ImGui::SetItemDefaultFocus(); + ImGui::SameLine(); + + if (ImGui::Button("Cancel", ImVec2(120, 0))) + { + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + + } + } + + ~Dialog() { + delete path; + } + +protected : + char* path; + std::string location; +}; + + diff --git a/Editor/src/Project.cpp b/Editor/src/Project.cpp index ab1cf60..72e9f52 100644 --- a/Editor/src/Project.cpp +++ b/Editor/src/Project.cpp @@ -6,16 +6,35 @@ #include -void Project::CreateProject(std::filesystem::path path) { +void Project::SaveProject(std::filesystem::path path, Project& project) +{ YAML::Emitter projectYAML; projectYAML << YAML::Key << "Project" << YAML::Value << "new"; std::ofstream projectFile; - path.append(ProjectName.append(".yproj")); + path.append(project.Name.append(".yproj")); std::cout << path.u8string() << std::endl; projectFile.open(path.u8string()); projectFile << projectYAML.c_str(); projectFile.close(); +} + +void Project::LoadProject(std::filesystem::path path, Project& project) +{ + std::string YAMLProject; + std::stringstream sstream; + std::ifstream projectFile; + projectFile.open(path.u8string()); + + sstream << projectFile.rdbuf(); + YAMLProject = sstream.str(); + + projectFile.close(); + + + std::cout << YAMLProject << std::endl; + + } \ No newline at end of file diff --git a/Editor/src/Project.h b/Editor/src/Project.h index 0a22e22..7ddb511 100644 --- a/Editor/src/Project.h +++ b/Editor/src/Project.h @@ -2,9 +2,12 @@ #include class Project { public: - Project(const std::string& name): ProjectName(name){} - void CreateProject(std::filesystem::path path ); -private: - std::string ProjectName; + Project(const std::string& name): Name(name){} + + static void SaveProject(std::filesystem::path path, Project& project); + static void LoadProject(std::filesystem::path path, Project& project); +private: + std::string Name; + +}; -}; \ No newline at end of file diff --git a/Editor/src/SceneSerializer.h b/Editor/src/SceneSerializer.h new file mode 100644 index 0000000..a65ff42 --- /dev/null +++ b/Editor/src/SceneSerializer.h @@ -0,0 +1,110 @@ +#pragma once +#include "../../YoggieEngine/src/BarinkEngine.h" +#include +#include +#include +#include + +void WriteFile(std::string& emitter, std::filesystem::path path) +{ + std::cout << "Writing Scene file to: " << path.u8string() << std::endl; + std::ofstream sceneFile; + sceneFile.open(path.u8string()); + + sceneFile << emitter.c_str(); + + sceneFile.close(); +} + +YAML::Emitter& operator<< (YAML::Emitter& emitter, glm::vec3& vector) { + emitter << YAML::Flow << YAML::BeginSeq << vector.x << vector.y << vector.x << YAML::EndSeq; + return emitter; +} + +void Serialize(YAML::Emitter& emitter, TransformComponent& transform) +{ + emitter << YAML::BeginMap; + emitter << YAML::Key << "Transform" << YAML::Value << YAML::Flow << YAML::BeginSeq; + + emitter << YAML::Key << "Position"; + emitter << YAML::Value << transform.Position; + + emitter << YAML::Key << "Rotation"; + emitter << YAML::Value << transform.Rotation; + + emitter << YAML::Key << "Scale"; + emitter << YAML::Value << transform.Scale; + + emitter << YAML::EndSeq << YAML::EndMap; +} + +void Serialize(YAML::Emitter& emitter, IdentifierComponent& identifier) +{ + emitter << YAML::BeginMap; + emitter << YAML::Key << "Ident"; + emitter << YAML::Value << identifier.name; + emitter << YAML::EndMap; +} + +void Serialize(YAML::Emitter& emitter, LightComponent& light) +{ + emitter << YAML::BeginMap << "Light"; + emitter << YAML::Key << "strength"; + emitter << YAML::Value << light.Strength; + + emitter << YAML::Key << "Color"; + emitter << YAML::Value << light.Color; + emitter << YAML::EndMap; +} + + std::string Serialize( Scene& scene) { + YAML::Emitter sceneYAML; + + sceneYAML << "YOGGIE_SCENE_FILE" ; + + + scene.getReg().each([&scene, &sceneYAML](auto enttNumber) { + Entity entity = Entity(enttNumber, &scene); + + Serialize(sceneYAML, entity.GetComponent()); + Serialize(sceneYAML, entity.GetComponent()); + if (entity.HasComponent()) { + Serialize(sceneYAML, entity.GetComponent()); + } + + }); + return std::string(sceneYAML.c_str()); +} + + void Parse(std::string& YAML) { + std::vector nodes = YAML::LoadAll(YAML); + + for(YAML::Node node : nodes) + { + std::cout << node.Type() << std::endl; + } + + } + + void SaveScene(std::filesystem::path path, Scene& scene) { + std::string YAMLString = Serialize(scene); + WriteFile(YAMLString, path); + } + + + void LoadScene(std::filesystem::path path, Scene& scene) + { + std::ifstream sceneFile; + std::string YAMLScene; + sceneFile.open(path.u8string()); + + std::stringstream sstream; + sstream << sceneFile.rdbuf(); + YAMLScene = sstream.str(); + + sceneFile.close(); + + + Parse(YAMLScene); + + } \ No newline at end of file diff --git a/Editor/src/main.cpp b/Editor/src/main.cpp index 05cb4c0..625ca42 100644 --- a/Editor/src/main.cpp +++ b/Editor/src/main.cpp @@ -1,32 +1,51 @@ #include #include #include -#include "Project.h" +#include +#include #include "../../libs/guizmo/ImGuizmo.h" - #include "../../YoggieEngine/src/BarinkEngine.h" #include "../../YoggieEngine/src/AssetManager/ModelImporter.h" #include "../../YoggieEngine/src/Graphics/Memory/Framebuffer.h" #include "../../YoggieEngine/src/PerfCounter.cpp" #include "../../YoggieEngine/src/Scene/Entity.h" #include "Widgets.h" +#include "Project.h" +#include "SceneSerializer.h" + + + using namespace YoggieEngine; /* * Define globals */ +struct EditorContext { + Project CurrentProject; + Scene MainScene; + + EditorContext() = default; + EditorContext(EditorContext& other) = default; + ~EditorContext() = default; +}; + +Project CurrentProject ("test"); +Scene MainScene; + Framebuffer* framebuffer; -Scene Level1; SceneObject* Model; Entity cube; + entt::entity Selected; + /* * Runs once at startup * - USe to initialize the game/sandbox/demo */ void Start() { + auto io = ImGui::GetIO(); io.Fonts->AddFontFromFileTTF("build/Debug/Fonts/Roboto-Regular.ttf", 18); @@ -38,29 +57,34 @@ void Start() { // Create a cube Model = importer.Import("build/Debug/Models/Cube.obj"); - cube = Level1.AddEntity("cube"); + cube = MainScene.AddEntity("cube"); auto& render3DComponent = cube.AddComponent(); render3DComponent.mesh = *(Model->renderable->mesh); cube.GetComponent().Position = glm::vec3(1.0f, 0.0f, 5.0f); - auto cube2 = Level1.AddEntity("Cube1"); + auto cube2 = MainScene.AddEntity("Cube1"); auto& rendercube2 = cube2.AddComponent(); rendercube2.mesh = *(Model->renderable->mesh); // create an ambient light source - auto AmbientLight = Level1.AddEntity("AmbientLight"); + auto AmbientLight = MainScene.AddEntity("AmbientLight"); auto light = AmbientLight.AddComponent(); light.Color = glm::vec3(1.0f); light.Strength = 1.0f; Selected = (entt::entity) -1; - renderer.Prepare(Level1); - + renderer.Prepare(MainScene); } + + +char* path = nullptr; +char* savePath = nullptr; +char* scenePath = nullptr; +char* openScenePath = nullptr; /* * Runs every frame * - Use to draw Immediate mode graphics (Not meant for HUD's ) @@ -69,25 +93,44 @@ void ImmediateGraphicsDraw() { ImGui::DockSpaceOverViewport(ImGui::GetMainViewport()); // Show a menu bar + ImGui::BeginMainMenuBar(); + ImGui::PushItemFlag(ImGuiItemFlags_SelectableDontClosePopup, true); if (ImGui::BeginMenu("Application")) { - if (ImGui::BeginMenu("Project")) { - if (ImGui::MenuItem("New project")) - { - Project p("New-Project"); - p.CreateProject("I:/Dev/MyGameEngine"); + if (ImGui::MenuItem("Load Project")) + { + nfdresult_t result = NFD_OpenDialog({ "yproj" }, NULL, &path); + switch (result) { + case(NFD_OKAY): + Project::LoadProject( path, CurrentProject); + break; + case(NFD_CANCEL): + break; + case(NFD_ERROR): + std::cout << "NFD_Error: " << NFD_GetError() << std::endl; + break; } - if (ImGui::MenuItem("Load Project")) - { - - } - - ImGui::EndMenu(); } - + + if (ImGui::MenuItem("Save project as...")) { + nfdresult_t result = NFD_SaveDialog({ "yproj" }, NULL, &savePath); + switch (result) { + case(NFD_OKAY): + std::cout << "Save as: " << savePath << std::endl; + Project::SaveProject(savePath, CurrentProject); + break; + case(NFD_CANCEL): + break; + case(NFD_ERROR): + std::cout << "NFD_Error: " << NFD_GetError() << std::endl; + break; + } + } + + if (ImGui::MenuItem("Preferences")) { @@ -101,19 +144,45 @@ void ImmediateGraphicsDraw() ImGui::EndMenu(); } + ImGui::PopItemFlag(); + if (ImGui::BeginMenu("Scene")) { - if (ImGui::MenuItem("Save scene")) { + if (ImGui::MenuItem("Save scene")) + { + nfdresult_t result= NFD_SaveDialog({"yscene"},NULL, &scenePath); + switch (result) { + case(NFD_OKAY): + SaveScene(scenePath, MainScene); + break; + case(NFD_CANCEL): + break; + case(NFD_ERROR): + std::cout << "NFD_Error: " << NFD_GetError() << std::endl; + break; + } } - if (ImGui::MenuItem("Load scene")) { + if (ImGui::MenuItem("Load scene")) + { + auto result = NFD_OpenDialog({ "yscene" }, NULL, &openScenePath); + switch (result) { + case (NFD_OKAY): + LoadScene(openScenePath, MainScene); + break; + case(NFD_CANCEL): + break; + case(NFD_ERROR): + std::cout << "NFD_Error: " << NFD_GetError() << std::endl; + break; + } } if (ImGui::MenuItem("Add Entity")) { - Level1.AddEntity("New entity"); + MainScene.AddEntity("New entity"); } ImGui::EndMenu(); @@ -122,10 +191,11 @@ void ImmediateGraphicsDraw() ImGui::EndMainMenuBar(); + //ShowStats(); - Viewport(*framebuffer, Level1); - SceneExplorer(Selected, Level1); - Inspector(Selected, Level1 ); + Viewport(*framebuffer, MainScene); + SceneExplorer(Selected, MainScene); + Inspector(Selected, MainScene ); Settings(); AssetsFinder(); @@ -139,7 +209,7 @@ void ImmediateGraphicsDraw() void Render() { - renderer.Render( *framebuffer, Level1); + renderer.Render( *framebuffer, MainScene); } /* diff --git a/Editor/src/widgets.cpp b/Editor/src/widgets.cpp index 140c31e..6273251 100644 --- a/Editor/src/widgets.cpp +++ b/Editor/src/widgets.cpp @@ -25,50 +25,49 @@ void Inspector(entt::entity ent , Scene& scene) { static glm::vec3 Position = glm::vec3(0.0f, 0.0f, 0.0f); static glm::vec3 Rotation = glm::vec3(0.0f, 0.0f, 0.0f); if (scene.getReg().valid(ent)) { - Entity entity = Entity(ent, &scene); - - auto component = entity.GetComponent(); - ImGui::LabelText("## Name:", component.name.c_str()); - - - + if (ImGui::Button("Add Component")) ImGui::OpenPopup("Component picker"); - + ImGui::SameLine(); if (ImGui::BeginPopup("Component picker")) { for (int i = 0; i < IM_ARRAYSIZE(names); i++) if (ImGui::MenuItem(names[i])) { - std::cout << "Add a " << names[i] << " to " + std::cout << "Add a " << names[i] << " to " << entity.GetComponent().name << std::endl; } ImGui::EndPopup(); } - - ImGui::NewLine(); - - + + ImGui::NewLine(); + + auto component = entity.GetComponent(); + char* buf = new char(component.name.length()); + strcpy(buf, component.name.c_str()); + ImGui::InputText("Name:",buf , IM_ARRAYSIZE(buf), ImGuiInputTextFlags_ReadOnly); + + if (entity.HasComponent()) { auto& transform = entity.GetComponent(); - if (ImGui::CollapsingHeader("Transform", ImGuiTreeNodeFlags_None )) { + if (ImGui::CollapsingHeader("Transform", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::DragFloat3("Position", glm::value_ptr(transform.Position), 0.01); ImGui::DragFloat3("Rotation", glm::value_ptr(transform.Rotation), 0.01); ImGui::DragFloat3("Scale", glm::value_ptr(transform.Scale), 0.01, 0); - - } } if (entity.HasComponent()) { auto& light = entity.GetComponent(); - ImGui::DragFloat("Strength", &light.Strength, 0.001f); - ImGui::ColorEdit3("Colour", glm::value_ptr(light.Color)); + if (ImGui::CollapsingHeader("Light", ImGuiTreeNodeFlags_DefaultOpen)) { + ImGui::DragFloat("Strength", &light.Strength, 0.001f); + ImGui::ColorEdit3("Colour", glm::value_ptr(light.Color)); + } } @@ -89,9 +88,7 @@ void Inspector(entt::entity ent , Scene& scene) { } - ImGui::End(); - } void SceneExplorer(entt::entity& selected, Scene& scene ) diff --git a/libraries.lua b/libraries.lua index 90777ef..af99809 100644 --- a/libraries.lua +++ b/libraries.lua @@ -23,10 +23,13 @@ incfolder["gorillaaudio"] = "%{wks.location}/libs/GorillaAudio/include" -- Immediate Mode GUI incfolder["imgui"] = "%{wks.location}/libs/ImGui" incfolder["imguizmo"] = "%{wks.location}/libs/guizmo" +incfolder["nativefiledialog"] = "%{wks.location}/libs/nativefiledialog/src/include" + + + staticlib = {} staticlib["yoggie"] = "Yoggie/build/Debug" - - +staticlib["nativefiledialog"]= "%{wks.location}/libs/nativefiledialog/build/lib/Release/x64" diff --git a/premake5.lua b/premake5.lua index 8d835f2..310ceeb 100644 --- a/premake5.lua +++ b/premake5.lua @@ -35,3 +35,4 @@ group("Other") group("Libraries") include('../ImGui') include("../ImGuizmo") + include("../yaml-cpp")