Working on scene and project serialisation
Added scene/project save and load to main menu, added file dialogs for opening and saving scene/project
This commit is contained in:
		
							
								
								
									
										72
									
								
								Editor/src/Dialog.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								Editor/src/Dialog.h
									
									
									
									
									
										Normal 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; | ||||
| }; | ||||
|  | ||||
|  | ||||
| @ -6,16 +6,35 @@ | ||||
| #include <yaml-cpp/yaml.h> | ||||
|  | ||||
|  | ||||
| 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; | ||||
|  | ||||
| 	 | ||||
| } | ||||
| @ -2,9 +2,12 @@ | ||||
| #include <filesystem> | ||||
| 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; | ||||
|  | ||||
| }; | ||||
|  | ||||
| }; | ||||
							
								
								
									
										110
									
								
								Editor/src/SceneSerializer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								Editor/src/SceneSerializer.h
									
									
									
									
									
										Normal 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); | ||||
|  | ||||
|  } | ||||
| @ -1,32 +1,51 @@ | ||||
| #include <glm/gtc/type_ptr.hpp> | ||||
| #include <glm/gtc/matrix_transform.hpp> | ||||
| #include <imgui.h> | ||||
| #include "Project.h" | ||||
| #include <imgui_internal.h> | ||||
| #include <nfd.h> | ||||
|  | ||||
| #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>(); | ||||
|     render3DComponent.mesh = *(Model->renderable->mesh); | ||||
|  | ||||
|     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>(); | ||||
|     rendercube2.mesh = *(Model->renderable->mesh); | ||||
|  | ||||
|  | ||||
|     // create an ambient light source | ||||
|     auto AmbientLight = Level1.AddEntity("AmbientLight"); | ||||
|     auto AmbientLight = MainScene.AddEntity("AmbientLight"); | ||||
|     auto light = AmbientLight.AddComponent<LightComponent>(); | ||||
|     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); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  | ||||
| @ -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<IdentifierComponent>(); | ||||
|         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<IdentifierComponent>().name << std::endl; | ||||
|                 } | ||||
|  | ||||
|             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>()) { | ||||
|             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("Rotation", glm::value_ptr(transform.Rotation), 0.01); | ||||
|                 ImGui::DragFloat3("Scale", glm::value_ptr(transform.Scale), 0.01, 0); | ||||
|  | ||||
|  | ||||
|             } | ||||
|                  | ||||
|         } | ||||
|  | ||||
|         if (entity.HasComponent<LightComponent>()) { | ||||
|             auto& light = entity.GetComponent<LightComponent>(); | ||||
|             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 ) | ||||
|  | ||||
		Reference in New Issue
	
	Block a user