Working on scene and project serialisation

Added scene/project save and load to main menu, added file dialogs for opening and saving scene/project
main
Nigel Barink 2022-11-05 12:50:01 +01:00
parent 41d5b87c7b
commit c8ebc0fa17
9 changed files with 336 additions and 60 deletions

View File

@ -6,7 +6,8 @@ buildmessage "Building editor ..."
links{ links{
"YoggieEngine", "YoggieEngine",
"ImGuizmo", "ImGuizmo",
"yaml-cpp" "yaml-cpp",
"nfd.lib"
} }
includedirs{ includedirs{
@ -25,18 +26,18 @@ includedirs{
incfolder["imguizmo"], incfolder["imguizmo"],
incfolder["entt"], incfolder["entt"],
incfolder["yamlcpp"], incfolder["yamlcpp"],
incfolder["nativefiledialog"],
"./include" "./include"
} }
libdirs { libdirs {
staticlib["yoggie"] staticlib["yoggie"],
staticlib["nativefiledialog"]
} }
files { files {
"./src/*.h", "./src/*.h",
"./src/*.cpp" "./src/*.cpp"
} }
include("../yaml-cpp")

72
Editor/src/Dialog.h Normal file
View File

@ -0,0 +1,72 @@
#pragma once
#include <string>
#include <imgui.h>
#include <nfd.h>
#include <iostream>
#include <functional>
#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<void(std::string&)> 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;
};

View File

@ -6,16 +6,35 @@
#include <yaml-cpp/yaml.h> #include <yaml-cpp/yaml.h>
void Project::CreateProject(std::filesystem::path path) { void Project::SaveProject(std::filesystem::path path, Project& project)
{
YAML::Emitter projectYAML; YAML::Emitter projectYAML;
projectYAML << YAML::Key << "Project" << YAML::Value << "new"; projectYAML << YAML::Key << "Project" << YAML::Value << "new";
std::ofstream projectFile; std::ofstream projectFile;
path.append(ProjectName.append(".yproj")); path.append(project.Name.append(".yproj"));
std::cout << path.u8string() << std::endl; std::cout << path.u8string() << std::endl;
projectFile.open(path.u8string()); projectFile.open(path.u8string());
projectFile << projectYAML.c_str(); projectFile << projectYAML.c_str();
projectFile.close(); 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;
} }

View File

@ -2,9 +2,12 @@
#include <filesystem> #include <filesystem>
class Project { class Project {
public: public:
Project(const std::string& name): ProjectName(name){} Project(const std::string& name): Name(name){}
void CreateProject(std::filesystem::path path );
private: static void SaveProject(std::filesystem::path path, Project& project);
std::string ProjectName; static void LoadProject(std::filesystem::path path, Project& project);
private:
std::string Name;
};
};

View File

@ -0,0 +1,110 @@
#pragma once
#include "../../YoggieEngine/src/BarinkEngine.h"
#include <yaml-cpp/yaml.h>
#include <string>
#include <filesystem>
#include <fstream>
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<IdentifierComponent>());
Serialize(sceneYAML, entity.GetComponent<TransformComponent>());
if (entity.HasComponent<LightComponent>()) {
Serialize(sceneYAML, entity.GetComponent<LightComponent>());
}
});
return std::string(sceneYAML.c_str());
}
void Parse(std::string& YAML) {
std::vector<YAML::Node> 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);
}

View File

@ -1,32 +1,51 @@
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <imgui.h> #include <imgui.h>
#include "Project.h" #include <imgui_internal.h>
#include <nfd.h>
#include "../../libs/guizmo/ImGuizmo.h" #include "../../libs/guizmo/ImGuizmo.h"
#include "../../YoggieEngine/src/BarinkEngine.h" #include "../../YoggieEngine/src/BarinkEngine.h"
#include "../../YoggieEngine/src/AssetManager/ModelImporter.h" #include "../../YoggieEngine/src/AssetManager/ModelImporter.h"
#include "../../YoggieEngine/src/Graphics/Memory/Framebuffer.h" #include "../../YoggieEngine/src/Graphics/Memory/Framebuffer.h"
#include "../../YoggieEngine/src/PerfCounter.cpp" #include "../../YoggieEngine/src/PerfCounter.cpp"
#include "../../YoggieEngine/src/Scene/Entity.h" #include "../../YoggieEngine/src/Scene/Entity.h"
#include "Widgets.h" #include "Widgets.h"
#include "Project.h"
#include "SceneSerializer.h"
using namespace YoggieEngine; using namespace YoggieEngine;
/* /*
* Define globals * Define globals
*/ */
struct EditorContext {
Project CurrentProject;
Scene MainScene;
EditorContext() = default;
EditorContext(EditorContext& other) = default;
~EditorContext() = default;
};
Project CurrentProject ("test");
Scene MainScene;
Framebuffer* framebuffer; Framebuffer* framebuffer;
Scene Level1;
SceneObject* Model; SceneObject* Model;
Entity cube; Entity cube;
entt::entity Selected; entt::entity Selected;
/* /*
* Runs once at startup * Runs once at startup
* - USe to initialize the game/sandbox/demo * - USe to initialize the game/sandbox/demo
*/ */
void Start() { void Start() {
auto io = ImGui::GetIO(); auto io = ImGui::GetIO();
io.Fonts->AddFontFromFileTTF("build/Debug/Fonts/Roboto-Regular.ttf", 18); io.Fonts->AddFontFromFileTTF("build/Debug/Fonts/Roboto-Regular.ttf", 18);
@ -38,29 +57,34 @@ void Start() {
// Create a cube // Create a cube
Model = importer.Import("build/Debug/Models/Cube.obj"); Model = importer.Import("build/Debug/Models/Cube.obj");
cube = Level1.AddEntity("cube"); cube = MainScene.AddEntity("cube");
auto& render3DComponent = cube.AddComponent<Render3DComponent>(); auto& render3DComponent = cube.AddComponent<Render3DComponent>();
render3DComponent.mesh = *(Model->renderable->mesh); render3DComponent.mesh = *(Model->renderable->mesh);
cube.GetComponent<TransformComponent>().Position = glm::vec3(1.0f, 0.0f, 5.0f); cube.GetComponent<TransformComponent>().Position = glm::vec3(1.0f, 0.0f, 5.0f);
auto cube2 = Level1.AddEntity("Cube1"); auto cube2 = MainScene.AddEntity("Cube1");
auto& rendercube2 = cube2.AddComponent<Render3DComponent>(); auto& rendercube2 = cube2.AddComponent<Render3DComponent>();
rendercube2.mesh = *(Model->renderable->mesh); rendercube2.mesh = *(Model->renderable->mesh);
// create an ambient light source // create an ambient light source
auto AmbientLight = Level1.AddEntity("AmbientLight"); auto AmbientLight = MainScene.AddEntity("AmbientLight");
auto light = AmbientLight.AddComponent<LightComponent>(); auto light = AmbientLight.AddComponent<LightComponent>();
light.Color = glm::vec3(1.0f); light.Color = glm::vec3(1.0f);
light.Strength = 1.0f; light.Strength = 1.0f;
Selected = (entt::entity) -1; 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 * Runs every frame
* - Use to draw Immediate mode graphics (Not meant for HUD's ) * - Use to draw Immediate mode graphics (Not meant for HUD's )
@ -69,25 +93,44 @@ void ImmediateGraphicsDraw()
{ ImGui::DockSpaceOverViewport(ImGui::GetMainViewport()); { ImGui::DockSpaceOverViewport(ImGui::GetMainViewport());
// Show a menu bar // Show a menu bar
ImGui::BeginMainMenuBar(); ImGui::BeginMainMenuBar();
ImGui::PushItemFlag(ImGuiItemFlags_SelectableDontClosePopup, true);
if (ImGui::BeginMenu("Application")) { if (ImGui::BeginMenu("Application")) {
if (ImGui::BeginMenu("Project")) { if (ImGui::MenuItem("Load Project"))
if (ImGui::MenuItem("New project")) {
{ nfdresult_t result = NFD_OpenDialog({ "yproj" }, NULL, &path);
Project p("New-Project"); switch (result) {
p.CreateProject("I:/Dev/MyGameEngine"); 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")) if (ImGui::MenuItem("Preferences"))
{ {
@ -101,19 +144,45 @@ void ImmediateGraphicsDraw()
ImGui::EndMenu(); ImGui::EndMenu();
} }
ImGui::PopItemFlag();
if (ImGui::BeginMenu("Scene")) { 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")) { if (ImGui::MenuItem("Add Entity")) {
Level1.AddEntity("New entity"); MainScene.AddEntity("New entity");
} }
ImGui::EndMenu(); ImGui::EndMenu();
@ -122,10 +191,11 @@ void ImmediateGraphicsDraw()
ImGui::EndMainMenuBar(); ImGui::EndMainMenuBar();
//ShowStats(); //ShowStats();
Viewport(*framebuffer, Level1); Viewport(*framebuffer, MainScene);
SceneExplorer(Selected, Level1); SceneExplorer(Selected, MainScene);
Inspector(Selected, Level1 ); Inspector(Selected, MainScene );
Settings(); Settings();
AssetsFinder(); AssetsFinder();
@ -139,7 +209,7 @@ void ImmediateGraphicsDraw()
void Render() void Render()
{ {
renderer.Render( *framebuffer, Level1); renderer.Render( *framebuffer, MainScene);
} }
/* /*

View File

@ -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 Position = glm::vec3(0.0f, 0.0f, 0.0f);
static glm::vec3 Rotation = 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)) { if (scene.getReg().valid(ent)) {
Entity entity = Entity(ent, &scene); Entity entity = Entity(ent, &scene);
auto component = entity.GetComponent<IdentifierComponent>();
ImGui::LabelText("## Name:", component.name.c_str());
if (ImGui::Button("Add Component")) if (ImGui::Button("Add Component"))
ImGui::OpenPopup("Component picker"); ImGui::OpenPopup("Component picker");
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::BeginPopup("Component picker")) { if (ImGui::BeginPopup("Component picker")) {
for (int i = 0; i < IM_ARRAYSIZE(names); i++) for (int i = 0; i < IM_ARRAYSIZE(names); i++)
if (ImGui::MenuItem(names[i])) { if (ImGui::MenuItem(names[i])) {
std::cout << "Add a " << names[i] << " to " std::cout << "Add a " << names[i] << " to "
<< entity.GetComponent<IdentifierComponent>().name << std::endl; << entity.GetComponent<IdentifierComponent>().name << std::endl;
} }
ImGui::EndPopup(); ImGui::EndPopup();
} }
ImGui::NewLine();
ImGui::NewLine();
auto component = entity.GetComponent<IdentifierComponent>();
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<TransformComponent>()) { if (entity.HasComponent<TransformComponent>()) {
auto& transform = entity.GetComponent<TransformComponent>(); auto& transform = entity.GetComponent<TransformComponent>();
if (ImGui::CollapsingHeader("Transform", ImGuiTreeNodeFlags_None )) { if (ImGui::CollapsingHeader("Transform", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::DragFloat3("Position", glm::value_ptr(transform.Position), 0.01); ImGui::DragFloat3("Position", glm::value_ptr(transform.Position), 0.01);
ImGui::DragFloat3("Rotation", glm::value_ptr(transform.Rotation), 0.01); ImGui::DragFloat3("Rotation", glm::value_ptr(transform.Rotation), 0.01);
ImGui::DragFloat3("Scale", glm::value_ptr(transform.Scale), 0.01, 0); ImGui::DragFloat3("Scale", glm::value_ptr(transform.Scale), 0.01, 0);
} }
} }
if (entity.HasComponent<LightComponent>()) { if (entity.HasComponent<LightComponent>()) {
auto& light = entity.GetComponent<LightComponent>(); auto& light = entity.GetComponent<LightComponent>();
ImGui::DragFloat("Strength", &light.Strength, 0.001f); if (ImGui::CollapsingHeader("Light", ImGuiTreeNodeFlags_DefaultOpen)) {
ImGui::ColorEdit3("Colour", glm::value_ptr(light.Color)); 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(); ImGui::End();
} }
void SceneExplorer(entt::entity& selected, Scene& scene ) void SceneExplorer(entt::entity& selected, Scene& scene )

View File

@ -23,10 +23,13 @@ incfolder["gorillaaudio"] = "%{wks.location}/libs/GorillaAudio/include"
-- Immediate Mode GUI -- Immediate Mode GUI
incfolder["imgui"] = "%{wks.location}/libs/ImGui" incfolder["imgui"] = "%{wks.location}/libs/ImGui"
incfolder["imguizmo"] = "%{wks.location}/libs/guizmo" incfolder["imguizmo"] = "%{wks.location}/libs/guizmo"
incfolder["nativefiledialog"] = "%{wks.location}/libs/nativefiledialog/src/include"
staticlib = {} staticlib = {}
staticlib["yoggie"] = "Yoggie/build/Debug" staticlib["yoggie"] = "Yoggie/build/Debug"
staticlib["nativefiledialog"]= "%{wks.location}/libs/nativefiledialog/build/lib/Release/x64"

View File

@ -35,3 +35,4 @@ group("Other")
group("Libraries") group("Libraries")
include('../ImGui') include('../ImGui')
include("../ImGuizmo") include("../ImGuizmo")
include("../yaml-cpp")