diff --git a/Assets/Application.SHConfig b/Assets/Application.SHConfig new file mode 100644 index 00000000..3f7a4ac0 --- /dev/null +++ b/Assets/Application.SHConfig @@ -0,0 +1,4 @@ +Start in Fullscreen: false +Starting Scene ID: 94283040 +Window Size: {x: 1920, y: 1080} +Window Title: SHADE Engine \ No newline at end of file diff --git a/Assets/Materials/TestMat.shmat b/Assets/Materials/TestMat.shmat index 089576f3..c1bb43c5 100644 --- a/Assets/Materials/TestMat.shmat +++ b/Assets/Materials/TestMat.shmat @@ -2,7 +2,7 @@ FragmentShader: 46377769 SubPass: G-Buffer Write Properties: - data.color: {x: 1, y: 0.200000003, z: 0.100000001, w: 1} + data.color: {x: 1, y: 1, z: 1, w: 1} data.textureIndex: 64651793 data.alpha: 0 data.beta: {x: 1, y: 1, z: 1} \ No newline at end of file diff --git a/Assets/Materials/WhiteMat.shmat b/Assets/Materials/WhiteMat.shmat new file mode 100644 index 00000000..5a1cb199 --- /dev/null +++ b/Assets/Materials/WhiteMat.shmat @@ -0,0 +1,8 @@ +- VertexShader: 39210065 + FragmentShader: 46377769 + SubPass: G-Buffer Write + Properties: + data.color: {x: 1, y: 1, z: 1, w: 1} + data.textureIndex: 0 + data.alpha: 0 + data.beta: {x: 1, y: 1, z: 1} \ No newline at end of file diff --git a/Assets/Materials/WhiteMat.shmat.shmeta b/Assets/Materials/WhiteMat.shmat.shmeta new file mode 100644 index 00000000..588afba4 --- /dev/null +++ b/Assets/Materials/WhiteMat.shmat.shmeta @@ -0,0 +1,3 @@ +Name: WhiteMat +ID: 124370424 +Type: 7 diff --git a/Assets/Scenes/M2Scene.shade b/Assets/Scenes/M2Scene.shade new file mode 100644 index 00000000..38c0a523 --- /dev/null +++ b/Assets/Scenes/M2Scene.shade @@ -0,0 +1,216 @@ +- EID: 0 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Camera Component: + Position: {x: 0, y: 0, z: 0} + Pitch: 0 + Yaw: 0 + Roll: 0 + Width: 1920 + Height: 1080 + Near: 0.00999999978 + Far: 10000 + Perspective: true + Light Component: + Position: {x: 0, y: 0, z: 0} + Type: Directional + Direction: {x: 1.79999995, y: 0, z: 1} + Color: {x: 0.951541841, y: 0.921719015, z: 0.553319454, w: 1} + Layer: 4294967295 + Strength: 0 + Scripts: ~ +- EID: 1 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: -1.440328, y: -4.41369677, z: -5} + Rotate: {x: -0, y: 0, z: -0} + Scale: {x: 49.4798889, y: 0.5, z: 17.5} + Renderable Component: + Mesh: 149697411 + Material: 126974645 + RigidBody Component: + Type: Static + Mass: 1 + Drag: 0 + Angular Drag: 0 + Use Gravity: true + Interpolate: true + Freeze Position X: false + Freeze Position Y: false + Freeze Position Z: false + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false + Collider Component: + Colliders: + - Is Trigger: false + Type: Box + Half Extents: {x: 0.0170898438, y: 0.00048828125, z: 0.0170898438} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0, z: 0} + Scripts: ~ +- EID: 2 + Name: Player + IsActive: true + NumberOfChildren: 2 + Components: + Transform Component: + Translate: {x: -3.06177855, y: -2, z: -5} + Rotate: {x: -0, y: 0, z: -0} + Scale: {x: 2, y: 2, z: 2} + Renderable Component: + Mesh: 149697411 + Material: 126974645 + RigidBody Component: + Type: Dynamic + Mass: 1 + Drag: 0 + Angular Drag: 0 + Use Gravity: true + Interpolate: true + Freeze Position X: false + Freeze Position Y: false + Freeze Position Z: false + Freeze Rotation X: false + Freeze Rotation Y: false + Freeze Rotation Z: false + Collider Component: + Colliders: + - Is Trigger: false + Type: Box + Half Extents: {x: 0.0009765625, y: 0.0009765625, z: 0.0009765625} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0.5, z: 0} + Scripts: ~ +- EID: 3 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: -0.0094268322, y: 0, z: 0} + Rotate: {x: -0, y: 0, z: -0} + Scale: {x: 1, y: 1, z: 1} + Scripts: ~ +- EID: 4 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: 0, z: 0} + Rotate: {x: 0, y: 0, z: 0} + Scale: {x: 1, y: 1, z: 1} + Scripts: ~ +- EID: 5 + Name: item + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 0, y: -2, z: -5} + Rotate: {x: 0, y: 0, z: 0} + Scale: {x: 2, y: 2, z: 2} + Renderable Component: + Mesh: 149697411 + Material: 126974645 + RigidBody Component: + Type: Dynamic + Mass: 1 + Drag: 0 + Angular Drag: 0 + Use Gravity: true + Interpolate: false + Freeze Position X: false + Freeze Position Y: false + Freeze Position Z: false + Freeze Rotation X: true + Freeze Rotation Y: true + Freeze Rotation Z: true + Collider Component: + Colliders: + - Is Trigger: false + Type: Box + Half Extents: {x: 0.0009765625, y: 0.0009765625, z: 0.0009765625} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0.5, z: 0} + - Is Trigger: true + Type: Box + Half Extents: {x: 0.001953125, y: 0.001953125, z: 0.001953125} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0.5, z: 0} + Scripts: ~ +- EID: 6 + Name: AI + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: -8, y: -2, z: 2.5} + Rotate: {x: 0, y: 0, z: 0} + Scale: {x: 2, y: 2, z: 2} + Renderable Component: + Mesh: 149697411 + Material: 126974645 + RigidBody Component: + Type: Dynamic + Mass: 1 + Drag: 0 + Angular Drag: 0 + Use Gravity: true + Interpolate: false + Freeze Position X: false + Freeze Position Y: false + Freeze Position Z: false + Freeze Rotation X: true + Freeze Rotation Y: true + Freeze Rotation Z: true + Collider Component: + Colliders: + - Is Trigger: false + Type: Box + Half Extents: {x: 0.0009765625, y: 0.0009765625, z: 0.0009765625} + Friction: 0.400000006 + Bounciness: 0 + Density: 1 + Position Offset: {x: 0, y: 0.5, z: 0} + Scripts: ~ +- EID: 7 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Transform Component: + Translate: {x: 3, y: -1, z: -1} + Rotate: {x: 0, y: 0, z: 0} + Scale: {x: 5, y: 5, z: 5} + Renderable Component: + Mesh: 149697411 + Material: 126974645 + Scripts: ~ +- EID: 8 + Name: Default + IsActive: true + NumberOfChildren: 0 + Components: + Light Component: + Position: {x: 0, y: 0, z: 0} + Type: Ambient + Direction: {x: 0, y: 0, z: 1} + Color: {x: 1, y: 1, z: 1, w: 1} + Layer: 4294967295 + Strength: 0.25 + Scripts: ~ \ No newline at end of file diff --git a/Assets/Scenes/M2Scene.shade.shmeta b/Assets/Scenes/M2Scene.shade.shmeta new file mode 100644 index 00000000..9289949c --- /dev/null +++ b/Assets/Scenes/M2Scene.shade.shmeta @@ -0,0 +1,3 @@ +Name: M2Scene +ID: 94283040 +Type: 5 diff --git a/SHADE_Application/src/Application/SBApplication.cpp b/SHADE_Application/src/Application/SBApplication.cpp index c43ca45d..f4102067 100644 --- a/SHADE_Application/src/Application/SBApplication.cpp +++ b/SHADE_Application/src/Application/SBApplication.cpp @@ -41,6 +41,8 @@ #include "Assets/SHAssetManager.h" +#include "Scenes/SBMainScene.h" +#include "Serialization/Configurations/SHConfigurationManager.h" #include "Tools/SHLogger.h" #include "Tools/SHDebugDraw.h" @@ -60,8 +62,9 @@ namespace Sandbox { // Set working directory SHFileUtilities::SetWorkDirToExecDir(); - - window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow); + WindowData wndData{}; + auto& appConfig = SHConfigurationManager::LoadApplicationConfig(&wndData); + window.Create(hInstance, hPrevInstance, lpCmdLine, nCmdShow, wndData); // Create Systems SHSystemManager::CreateSystem(); @@ -80,7 +83,11 @@ namespace Sandbox SDL_Init(SDL_INIT_VIDEO); sdlWindow = SDL_CreateWindowFrom(window.GetHWND()); SHSystemManager::CreateSystem(); - SHSystemManager::GetSystem()->SetSDLWindow(sdlWindow); + if(auto editor = SHSystemManager::GetSystem()) + { + editor->SetSDLWindow(sdlWindow); + editor->SetSHWindow(&window); + } #endif // Create Routines @@ -128,7 +135,7 @@ namespace Sandbox SHSystemManager::Init(); - SHSceneManager::InitSceneManager("TestScene"); + SHSceneManager::InitSceneManager(appConfig.startingSceneID); SHFrameRateController::UpdateFRC(); diff --git a/SHADE_Application/src/Scenes/SBMainScene.cpp b/SHADE_Application/src/Scenes/SBMainScene.cpp new file mode 100644 index 00000000..34190915 --- /dev/null +++ b/SHADE_Application/src/Scenes/SBMainScene.cpp @@ -0,0 +1,62 @@ + #include "SBpch.h" +#include "SBMainScene.h" + +#include "ECS_Base/Managers/SHSystemManager.h" +#include "Graphics/MiddleEnd/Meshes/SHPrimitiveGenerator.h" +#include "ECS_Base/Managers/SHEntityManager.h" +#include "Graphics/MiddleEnd/Interface/SHRenderable.h" +#include "Scene/SHSceneManager.h" +#include "Graphics/MiddleEnd/Interface/SHGraphicsSystem.h" +#include "Scripting/SHScriptEngine.h" +#include "Math/Transform/SHTransformComponent.h" +#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" +#include "Physics/Components/SHRigidBodyComponent.h" +#include "Physics/Components/SHColliderComponent.h" +#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" + +#include "Assets/SHAssetManager.h" +#include "Camera/SHCameraComponent.h" +#include "Resource/SHResourceManager.h" +#include "Serialization/SHSerialization.h" + + using namespace SHADE; + +namespace Sandbox +{ + + void SBMainScene::WindowFocusFunc([[maybe_unused]] void* window, int focused) + { + if (focused) + { + } + else + { + } + } + + void SBMainScene::Load() + { + } + + void SBMainScene::Init() + { + sceneName = SHSerialization::DeserializeSceneFromFile(sceneAssetID); + } + + void SBMainScene::Update(float dt) + { + } + + void SBMainScene::Render() + { + } + + void SBMainScene::Unload() + { + } + + void SBMainScene::Free() + { + //SHSerialization::SerializeScene("resources/scenes/Scene01.SHADE"); + } +} diff --git a/SHADE_Application/src/Scenes/SBMainScene.h b/SHADE_Application/src/Scenes/SBMainScene.h new file mode 100644 index 00000000..7bd10118 --- /dev/null +++ b/SHADE_Application/src/Scenes/SBMainScene.h @@ -0,0 +1,30 @@ +#pragma once + +#include "Scene/SHScene.h" +#include "Scene/SHSceneManager.h" + +namespace Sandbox +{ + class SBMainScene : public SHADE::SHScene + { + private: + EntityID camera; + EntityID testObj; + std::vector stressTestObjects; + + public: + virtual void Load(); + virtual void Init(); + virtual void Update(float dt); + virtual void Render(); + virtual void Free(); + virtual void Unload(); + + //TODO: Change to new window DO IT IN CPP TOO + void WindowFocusFunc(void* window, int focused); + + SBMainScene(void) = default; + }; + +} + diff --git a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp index a18cd70f..d875d743 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/AssetBrowser/SHAssetBrowser.cpp @@ -189,12 +189,17 @@ namespace SHADE switch (file.assetMeta->type) { case AssetType::INVALID: break; - case AssetType::SHADER: icon = ICON_FA_FILE_CODE; break; - case AssetType::SHADER_BUILT_IN: icon = ICON_FA_FILE_CODE; break; - case AssetType::TEXTURE: icon = ICON_FA_IMAGES; break; - case AssetType::MESH: icon = ICON_FA_CUBES; break; - case AssetType::SCENE: icon = ICON_MD_IMAGE; break; - case AssetType::PREFAB: icon = ICON_FA_BOX_OPEN; break; + case AssetType::SHADER: break; + case AssetType::SHADER_BUILT_IN: break; + case AssetType::TEXTURE: break; + case AssetType::MESH: break; + case AssetType::SCENE: + if(auto editor = SHSystemManager::GetSystem()) + { + editor->LoadScene(file.assetMeta->id); + } + break; + case AssetType::PREFAB: break; case AssetType::MATERIAL: if (auto matInspector = SHEditorWindowManager::GetEditorWindow()) { diff --git a/SHADE_Engine/src/Editor/EditorWindow/MaterialInspector/SHMaterialInspector.cpp b/SHADE_Engine/src/Editor/EditorWindow/MaterialInspector/SHMaterialInspector.cpp index 3eb8564f..13ecb9fa 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MaterialInspector/SHMaterialInspector.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/MaterialInspector/SHMaterialInspector.cpp @@ -6,8 +6,8 @@ #include "Assets/SHAssetManager.h" #include "Editor/IconsMaterialDesign.h" -#include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" #include "Editor/SHEditorWidgets.hpp" +#include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" #include "Resource/SHResourceManager.h" namespace SHADE diff --git a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp index 06c0c2ae..af2d5517 100644 --- a/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp +++ b/SHADE_Engine/src/Editor/EditorWindow/MenuBar/SHEditorMenuBar.cpp @@ -3,6 +3,7 @@ //#==============================================================# //|| SHADE Includes || //#==============================================================# +#include "Editor/SHEditorWidgets.hpp" #include "Editor/SHEditor.h" #include "SHEditorMenuBar.h" #include "Editor/IconsMaterialDesign.h" @@ -17,7 +18,11 @@ #include #include +#include "Assets/SHAssetManager.h" +#include "Assets/Asset Types/SHSceneAsset.h" +#include "Scene/SHSceneManager.h" #include "Serialization/SHSerialization.h" +#include "Serialization/Configurations/SHConfigurationManager.h" namespace SHADE { @@ -75,13 +80,17 @@ namespace SHADE { if (ImGui::BeginMenu("File")) { + if(ImGui::Selectable("New Scene")) + { + SHSystemManager::GetSystem()->NewScene(); + } if(ImGui::Selectable("Save")) { - SHSerialization::SerializeSceneToFile("../../Assets/Scenes/Test.SHADE"); + SHSystemManager::GetSystem()->SaveScene(); } if(ImGui::Selectable("Load")) { - SHSerialization::DeserializeSceneFromFile("../../Assets/Scenes/Test.SHADE"); + //SHSystemManager::GetSystem()->LoadScene() } ImGui::EndMenu(); } @@ -155,6 +164,35 @@ namespace SHADE } ImGui::EndMenu(); } + + if (ImGui::BeginMenu("Application Config")) + { + auto& appConfig = SHConfigurationManager::applicationConfig; + ImGui::InputText("Window Title", &appConfig.windowTitle); + ImGui::Checkbox("Start in Fullscreen", &appConfig.startInFullScreen); + SHEditorWidgets::DragN("Window Size", { "Width", "Height" }, { &appConfig.windowSize.x, &appConfig.windowSize.y }); + //ImGui::InputScalar("Starting Scene", ImGuiDataType_U32, &appConfig.startingSceneID); + auto sceneAsset = SHAssetManager::GetData(appConfig.startingSceneID); + + if(ImGui::BeginCombo("Starting Scne", sceneAsset ? sceneAsset->name.data() : "")) + { + auto scenes = SHAssetManager::GetAllRecordOfType(AssetType::SCENE); + for(auto const& scene : scenes) + { + if(ImGui::Selectable(scene.name.data())) + { + appConfig.startingSceneID = scene.id; + } + } + ImGui::EndCombo(); + } + if (ImGui::Button("Save")) + { + SHConfigurationManager::SaveApplicationConfig(); + } + ImGui::EndMenu(); + } + ImGui::EndMainMenuBar(); } @@ -175,13 +213,16 @@ namespace SHADE ImGui::BeginDisabled(editor->editorState == SHEditor::State::PLAY); if(ImGui::SmallButton(ICON_MD_PLAY_ARROW)) { - const SHEditorStateChangeEvent STATE_CHANGE_EVENT + if(editor->SaveScene()) { - .previousState = editor->editorState - }; - editor->editorState = SHEditor::State::PLAY; + const SHEditorStateChangeEvent STATE_CHANGE_EVENT + { + .previousState = editor->editorState + }; + editor->editorState = SHEditor::State::PLAY; - SHEventManager::BroadcastEvent(STATE_CHANGE_EVENT, SH_EDITOR_ON_PLAY_EVENT); + SHEventManager::BroadcastEvent(STATE_CHANGE_EVENT, SH_EDITOR_ON_PLAY_EVENT); + } } ImGui::EndDisabled(); ImGui::BeginDisabled(editor->editorState == SHEditor::State::PAUSE); @@ -206,6 +247,7 @@ namespace SHADE editor->editorState = SHEditor::State::STOP; SHEventManager::BroadcastEvent(STATE_CHANGE_EVENT, SH_EDITOR_ON_STOP_EVENT); + editor->LoadScene(SHSceneManager::GetCurrentSceneAssetID()); } ImGui::EndDisabled(); ImGui::EndMenuBar(); diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index 6974d213..de8ac9d2 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -45,7 +45,11 @@ #include #include +#include "Assets/SHAssetManager.h" +#include "Assets/Asset Types/SHSceneAsset.h" #include "Graphics/MiddleEnd/Interface/SHMousePickSystem.h" +#include "Scene/SHSceneManager.h" +#include "Serialization/SHSerialization.h" #include "Tools/SHDebugDraw.h" RTTR_REGISTRATION @@ -147,7 +151,9 @@ namespace SHADE window->Update(); } } - + + RenderSceneNamePrompt(); + RenderUnsavedChangesPrompt(); //PollPicking(); if(ImGui::IsKeyDown(ImGuiKey_LeftShift) && ImGui::IsKeyDown(ImGuiKey_LeftCtrl) && ImGui::IsKeyReleased(ImGuiKey_Z)) @@ -172,6 +178,60 @@ namespace SHADE } } + void SHEditor::RenderSceneNamePrompt() noexcept + { + if(isSceneNamePromptOpen) + { + ImGui::OpenPopup(sceneNamePromptName.data()); + } + + if(ImGui::BeginPopupModal(sceneNamePromptName.data(), &isSceneNamePromptOpen)) + { + static std::string newSceneName{}; + ImGui::Text("Enter new scene name"); + ImGui::InputText("##name", &newSceneName); + ImGui::BeginDisabled(newSceneName.empty()); + if(ImGui::Button("Save")) + { + SaveScene(newSceneName); + newSceneName.clear(); + isSceneNamePromptOpen = false; + ImGui::CloseCurrentPopup(); + } + ImGui::EndDisabled(); + ImGui::SameLine(); + if(ImGui::Button("Cancel")) + { + isSceneNamePromptOpen = false; + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } + } + + void SHEditor::RenderUnsavedChangesPrompt() noexcept + { + if(isUnsavedChangesPromptOpen) + { + ImGui::OpenPopup(unsavedChangesPromptName.data()); + } + + if(ImGui::BeginPopupModal(unsavedChangesPromptName.data(), &isUnsavedChangesPromptOpen)) + { + ImGui::Text("You have unsaved changes!"); + if(ImGui::Button("Save")) + { + isSceneNamePromptOpen = true; + } + ImGui::SameLine(); + if(ImGui::Button("Cancel")) + { + isUnsavedChangesPromptOpen = false; + ImGui::CloseCurrentPopup(); + } + } + } + void SHEditor::InitLayout() noexcept { if(!std::filesystem::exists(io->IniFilename)) @@ -470,6 +530,66 @@ namespace SHADE } } + void SHEditor::NewScene() + { + if(shWindow->IsUnsavedChanges()) + { + //Unsaved changes prompt + sceneToLoad = 0; + isUnsavedChangesPromptOpen = true; + } + else + { + SHSceneManager::RestartScene(0); + shWindow->ToggleUnsavedChanges(); + } + } + + bool SHEditor::SaveScene(std::string const& newSceneName) + { + auto const data = SHAssetManager::GetData(SHSceneManager::GetCurrentSceneAssetID()); + if (!data) + { + if (newSceneName.empty()) + { + //Prompt for scene name + isSceneNamePromptOpen = true; + return false; + } + //Else We have a new name + + SHSceneManager::SetCurrentSceneName(newSceneName); + SHSceneManager::SetCurrentSceneAssetID(SHAssetManager::CreateNewAsset(AssetType::SCENE, newSceneName)); + } + //Get data, if data is null, asset doesn't exist, prompt for a name and create a new asset with the name + + //serialize the scene + if(SHSerialization::SerializeSceneToFile(SHSceneManager::GetCurrentSceneAssetID())) + { + if(shWindow->IsUnsavedChanges()) + shWindow->ToggleUnsavedChanges(); + + return true; + } + return false; + } + + void SHEditor::LoadScene(AssetID const& assetID) noexcept + { + if(shWindow->IsUnsavedChanges()) + { + //Unsaved changes prompt + isUnsavedChangesPromptOpen = true; + sceneToLoad = assetID; + } + else + { + //Load the scene + sceneToLoad = 0; + SHSceneManager::RestartScene(assetID); + } + } + void SHEditor::NewFrame() { SDL_Event event; diff --git a/SHADE_Engine/src/Editor/SHEditor.h b/SHADE_Engine/src/Editor/SHEditor.h index 6e0ef5ae..0f5a3aaa 100644 --- a/SHADE_Engine/src/Editor/SHEditor.h +++ b/SHADE_Engine/src/Editor/SHEditor.h @@ -16,15 +16,18 @@ #include "Resource/SHHandle.h" #include "EditorWindow/SHEditorWindow.h" #include "Tools/SHLog.h" -#include "Gizmos/SHTransformGizmo.h"` +#include "Gizmos/SHTransformGizmo.h" #include "Events/SHEventDefines.h" #include "Events/SHEvent.h" +#include "Graphics/Windowing/SHWindow.h" //#==============================================================# //|| Library Includes || //#==============================================================# #include +#include "Assets/SHAssetMacros.h" + namespace SHADE { //#==============================================================# @@ -171,9 +174,16 @@ namespace SHADE void InitBackend(); void SetSDLWindow(SDL_Window* inSDLWindow){sdlWindow = inSDLWindow;}; + void SetSHWindow(SHWindow* inWindow){shWindow = inWindow;} void PollPicking(); + void NewScene(); + + bool SaveScene(std::string const& newSceneName = {}); + + void LoadScene(AssetID const& assetID) noexcept; + // List of selected entities std::vector selectedEntities; @@ -191,6 +201,10 @@ namespace SHADE */ void Render(); + void RenderSceneNamePrompt() noexcept; + + void RenderUnsavedChangesPrompt() noexcept; + void InitLayout() noexcept; void InitFonts() noexcept; @@ -199,12 +213,22 @@ namespace SHADE SHEventHandle onEditorStateChanged(SHEventPtr eventPtr); + bool isSceneNamePromptOpen = false; + + bool isUnsavedChangesPromptOpen = false; + + static constexpr std::string_view sceneNamePromptName = "Save scene as..."; + static constexpr std::string_view unsavedChangesPromptName = "Unsaved Changes"; + + AssetID sceneToLoad = 0; + // Handle to command pool used for ImGui Vulkan Backend Handle imguiCommandPool; // Handle to command buffer used for ImGui Vulkan Backend Handle imguiCommandBuffer; SDL_Window* sdlWindow {nullptr}; + SHWindow* shWindow {nullptr}; ImGuiIO* io{nullptr}; diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h index de137b28..c9dd4eda 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHBatch.h @@ -88,6 +88,7 @@ namespace SHADE /* Getter Functions */ /*-----------------------------------------------------------------------------*/ Handle GetPipeline() const noexcept { return pipeline; }; + bool IsEmpty() const noexcept { return subBatches.empty(); } private: /*-----------------------------------------------------------------------------*/ diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp index df389879..b827652e 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Batching/SHSuperBatch.cpp @@ -68,6 +68,10 @@ namespace SHADE return; batch->Remove(renderable); + + // If batch is empty, remove batch + if (batch->IsEmpty()) + batches.erase(batch); } void SHSuperBatch::Clear() noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index be67f1b3..43de46bb 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -270,7 +270,15 @@ namespace SHADE worldRenderer->SetCameraDirector(cameraSystem->CreateDirector()); // Create default materials + std::array defaultTexture = { 255, 255, 255, 255 }; + std::vector mipOffsets{}; + mipOffsets.push_back(0); + auto tex = AddTexture(4, defaultTexture.data(), 1, 1, SHTexture::TextureFormat::eR8G8B8A8Unorm, mipOffsets); + BuildTextures(); + defaultMaterial = AddMaterial(defaultVertShader, defaultFragShader, gBufferSubpass); + defaultMaterial->SetProperty("data.textureIndex", tex->TextureArrayIndex); + // Create debug draw pipeline debugDrawPipeline = createDebugDrawPipeline(debugDrawNode->GetRenderpass(), debugDrawSubpass); @@ -764,6 +772,7 @@ namespace SHADE void SHGraphicsSystem::BeginRoutine::Execute(double) noexcept { + SHResourceManager::FinaliseChanges(); reinterpret_cast(system)->BeginRender(); } @@ -789,7 +798,6 @@ namespace SHADE void SHGraphicsSystem::EndRoutine::Execute(double) noexcept { reinterpret_cast(system)->EndRender(); - SHResourceManager::FinaliseChanges(); } /*-----------------------------------------------------------------------------------*/ @@ -806,11 +814,6 @@ namespace SHADE { if (!renderable.HasChanged()) continue; - - if (!renderable.GetMesh()) - { - SHLOG_CRITICAL("NULL Mesh provided!"); - } // Remove from the SuperBatch it is previously in (prevMat if mat has changed) Handle prevMaterial = renderable.HasMaterialChanged() ? renderable.GetPrevMaterial() : renderable.GetMaterial(); @@ -821,8 +824,9 @@ namespace SHADE } // Add to new SuperBatch if there is a material + // Add to new SuperBatch if there is a material and a mesh to render Handle newMatInstance = renderable.GetMaterial(); - if (newMatInstance) + if (newMatInstance && renderable.GetMesh()) { Handle newSuperBatch = newMatInstance->GetBaseMaterial()->GetPipeline()->GetPipelineState().GetSubpass()->GetSuperBatch(); newSuperBatch->Add(&renderable); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp index 8719458b..3b6448fa 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Textures/SHTextureLibrary.cpp @@ -156,14 +156,15 @@ namespace SHADE /* Build Descriptor Set with all the Textures only if there are textures */ if (!texOrder.empty()) { - if (!texDescriptors) + if (texDescriptors) { - texDescriptors = descPool->Allocate - ( - { SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS] }, - { static_cast(texOrder.size()) } - ); + texDescriptors.Free(); } + texDescriptors = descPool->Allocate + ( + { SHGraphicsGlobalData::GetDescSetLayouts()[SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS] }, + { static_cast(texOrder.size()) } + ); texDescriptors->ModifyWriteDescImage ( SHGraphicsConstants::DescriptorSetIndex::STATIC_GLOBALS, diff --git a/SHADE_Engine/src/Graphics/Windowing/SHWindow.cpp b/SHADE_Engine/src/Graphics/Windowing/SHWindow.cpp index e0dbc1a4..22ca5eba 100644 --- a/SHADE_Engine/src/Graphics/Windowing/SHWindow.cpp +++ b/SHADE_Engine/src/Graphics/Windowing/SHWindow.cpp @@ -4,7 +4,6 @@ #include "ECS_Base/Managers/SHSystemManager.h" #include "Input/SHInputManager.h" - namespace SHADE { SHWindow::SHWindow() @@ -151,11 +150,11 @@ namespace SHADE SetWindowText(wndHWND, LPCWSTR(wndData.title.c_str())); } - SHWindow::SHVec2 SHWindow::GetPosition() const + SHWindow::WindowSize SHWindow::GetPosition() const { RECT rect; GetWindowRect(wndHWND, &rect); - return SHVec2(static_cast(rect.left), static_cast(rect.top)); + return WindowSize(static_cast(rect.left), static_cast(rect.top)); } void SHWindow::SetPosition(unsigned x, unsigned y) @@ -165,18 +164,18 @@ namespace SHADE wndData.y = y; } - SHWindow::SHVec2 SHWindow::GetWindowSize() const + SHWindow::WindowSize SHWindow::GetWindowSize() const { RECT rect; GetClientRect(wndHWND, &rect); - return SHVec2(static_cast(rect.right - rect.left), static_cast(rect.bottom - rect.top)); + return WindowSize(static_cast(rect.right - rect.left), static_cast(rect.bottom - rect.top)); } - SHWindow::SHVec2 SHWindow::GetCurrentDisplaySize() const + SHWindow::WindowSize SHWindow::GetCurrentDisplaySize() const { unsigned screenWidth = GetSystemMetrics(SM_CXSCREEN); unsigned screenHeight = GetSystemMetrics(SM_CYSCREEN); - return SHVec2(screenWidth, screenHeight); + return WindowSize(screenWidth, screenHeight); } void SHWindow::SetMouseVisible(bool show) @@ -260,7 +259,7 @@ namespace SHADE return wndHWND; } - const WindowData SHWindow::GetWindowData() const + const WindowData SHWindow::GetWindowData() const noexcept { return wndData; } @@ -287,6 +286,15 @@ namespace SHADE windowCloseCallbacks.erase(callbackid); } + void SHWindow::ToggleUnsavedChanges() noexcept + { + unsavedChanges = !unsavedChanges; + std::wstring title = wndData.title; + if(unsavedChanges) + title.append(L"*"); + SetWindowText(wndHWND, title.data()); + } + LRESULT SHWindow::WndProcStatic(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { auto window = windowMap.GetWindow(hwnd); diff --git a/SHADE_Engine/src/Graphics/Windowing/SHWindow.h b/SHADE_Engine/src/Graphics/Windowing/SHWindow.h index 11308d90..06df9036 100644 --- a/SHADE_Engine/src/Graphics/Windowing/SHWindow.h +++ b/SHADE_Engine/src/Graphics/Windowing/SHWindow.h @@ -74,7 +74,7 @@ namespace SHADE class SH_API SHWindow { public: - using SHVec2 = std::pair; + using WindowSize = std::pair; typedef std::function WindowResizeCallbackFn; typedef std::function WindowCloseCallbackFn; typedef uint16_t CALLBACKID; @@ -92,15 +92,15 @@ namespace SHADE void SetTitle(std::wstring title); - SHVec2 GetPosition() const; + WindowSize GetPosition() const; void SetPosition(unsigned x, unsigned y); //void SetPosition(SHMathVec2U); - SHVec2 GetWindowSize() const; + WindowSize GetWindowSize() const; //Get size of display the window is in (whichever window contains the window origin) - SHVec2 GetCurrentDisplaySize() const; + WindowSize GetCurrentDisplaySize() const; void SetMouseVisible(bool show); @@ -123,7 +123,7 @@ namespace SHADE HWND GetHWND(); - const WindowData GetWindowData() const; + const WindowData GetWindowData() const noexcept; CALLBACKID RegisterWindowSizeCallback(WindowResizeCallbackFn); void UnregisterWindowSizeCallback(CALLBACKID const& callbackid); @@ -131,6 +131,8 @@ namespace SHADE void UnregisterWindowCloseCallback(CALLBACKID const& callbackid); bool IsMinimized() const { return wndData.isMinimised; } + void ToggleUnsavedChanges() noexcept; + bool IsUnsavedChanges() const noexcept{return unsavedChanges;} protected: static LRESULT CALLBACK WndProcStatic(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); @@ -164,7 +166,8 @@ namespace SHADE std::unordered_map windowCloseCallbacks; CALLBACKID windowResizeCallbackCount{}; CALLBACKID windowCloseCallbackCount{}; - //TODO: Shift to events abstraction + + bool unsavedChanges = false; void OnCreate(HWND hwnd, LPCREATESTRUCT create_struct); void OnClose(); diff --git a/SHADE_Engine/src/Resource/SHResourceManager.hpp b/SHADE_Engine/src/Resource/SHResourceManager.hpp index dd5b681f..01d82a7b 100644 --- a/SHADE_Engine/src/Resource/SHResourceManager.hpp +++ b/SHADE_Engine/src/Resource/SHResourceManager.hpp @@ -24,7 +24,7 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/Shaders/SHVkShaderModule.h" #include "Graphics/Devices/SHVkLogicalDevice.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" -#include "Serialization/SHSerializationHelper.hpp" +#include "Serialization/SHYAMLConverters.h" namespace SHADE { @@ -282,6 +282,9 @@ namespace SHADE case SHADE::SHShaderBlockInterface::Variable::Type::INT: { Handle texture = LoadOrGet(PROP_NODE.as()); + // HACK: Need to split this out to a separate pass before loading the materials and subsequently, the scenes + gfxSystem->BuildTextures(); + if (texture) { matHandle->SetProperty(VARIABLE->offset, texture->TextureArrayIndex); diff --git a/SHADE_Engine/src/Scene/SHScene.h b/SHADE_Engine/src/Scene/SHScene.h index a81c70ef..1f06824e 100644 --- a/SHADE_Engine/src/Scene/SHScene.h +++ b/SHADE_Engine/src/Scene/SHScene.h @@ -13,6 +13,7 @@ #include #include "SHSceneGraph.h" +#include "Assets/SHAssetMacros.h" #include "ECS_Base/General/SHFamily.h" namespace SHADE @@ -32,6 +33,7 @@ namespace SHADE virtual ~SHScene() = default; std::string sceneName; + AssetID sceneAssetID; SHSceneGraph& GetSceneGraph() noexcept { return sceneGraph; } diff --git a/SHADE_Engine/src/Scene/SHSceneManager.cpp b/SHADE_Engine/src/Scene/SHSceneManager.cpp index 2baf0b9c..be9c7755 100644 --- a/SHADE_Engine/src/Scene/SHSceneManager.cpp +++ b/SHADE_Engine/src/Scene/SHSceneManager.cpp @@ -29,7 +29,7 @@ namespace SHADE std::string SHSceneManager::newSceneName{}; uint32_t SHSceneManager::currentSceneID = UINT32_MAX; uint32_t SHSceneManager::nextSceneID = UINT32_MAX; - + AssetID SHSceneManager::currentSceneAssetID{}; SHScene* SHSceneManager::currentScene = nullptr; //SHScene* SHSceneManager::nextScene = nullptr; @@ -107,16 +107,18 @@ namespace SHADE } } - void SHSceneManager::RestartScene(std::string const& sceneName) noexcept + void SHSceneManager::RestartScene(AssetID const& assetID ) noexcept { - if (currentScene->sceneName != sceneName) + if (currentScene->sceneAssetID != assetID) { - cleanReload = true; - newSceneName = sceneName; + //cleanReload = true; + cleanReload = false; + //newSceneName = sceneName; } else cleanReload = false; + currentScene->sceneAssetID = assetID; nextSceneID = currentSceneID; sceneChanged = true; } @@ -151,4 +153,20 @@ namespace SHADE { return currentScene->sceneName; } + + void SHSceneManager::SetCurrentSceneName(std::string const& sceneName) noexcept + { + currentScene->sceneName = sceneName; + } + + AssetID SHSceneManager::GetCurrentSceneAssetID() noexcept + { + return currentScene->sceneAssetID; + } + + void SHSceneManager::SetCurrentSceneAssetID(AssetID const& newAssetID) + { + currentScene->sceneAssetID = newAssetID; + currentSceneAssetID = newAssetID; + } } diff --git a/SHADE_Engine/src/Scene/SHSceneManager.h b/SHADE_Engine/src/Scene/SHSceneManager.h index 2e4b1717..23d13261 100644 --- a/SHADE_Engine/src/Scene/SHSceneManager.h +++ b/SHADE_Engine/src/Scene/SHSceneManager.h @@ -20,6 +20,7 @@ //Project Headers #include "SH_API.h" #include "ECS_Base/General/SHFamily.h" +#include "Assets/SHAssetMacros.h" namespace SHADE { @@ -47,6 +48,9 @@ namespace SHADE //pointer to the current scene static SHScene* currentScene; + //Scene AssetID of the current scene + static AssetID currentSceneAssetID; + //Used in reloading scene. static std::string newSceneName; @@ -80,10 +84,10 @@ namespace SHADE * None. ***************************************************************************/ template - static std::enable_if_t, void> InitSceneManager(std::string const& sceneName) noexcept + static std::enable_if_t, void> InitSceneManager(AssetID const& sceneAssetID) noexcept { //prevSceneCreate = newScene; - newScene = [sceneName]() { currentScene = new T(); currentScene->sceneName = sceneName; }; + newScene = [sceneAssetID]() { currentScene = new T(); currentScene->sceneAssetID = sceneAssetID; }; //nextSceneID = SHFamilyID::GetID(); nextSceneID = 0; @@ -99,7 +103,7 @@ namespace SHADE * None. ***************************************************************************/ template - static std::enable_if_t, void> ChangeScene(std::string const& sceneName) noexcept + static std::enable_if_t, void> ChangeScene(AssetID const& sceneAssetID) noexcept { //check if this new Scene is current Scene (Use RestartScene instead) if (currentSceneID == SHFamilyID::GetID()) @@ -107,7 +111,7 @@ namespace SHADE return; } //prevSceneCreate = newScene; - newScene = [sceneName]() { currentScene = new T(); currentScene->sceneName; }; + newScene = [sceneAssetID]() { currentScene = new T(); currentScene->sceneAssetID = sceneAssetID; }; nextSceneID = SHFamilyID::GetID(); sceneChanged = true; } @@ -137,11 +141,11 @@ namespace SHADE * Restarts current scene. Only Scene::Init() and Scene::Free() * Scene::Load() and Scene::Unload() will not be called. * Edit: allows for RestartScene to restart the scene with a different - * scene name. - * If a sceneName is different from the current one, Load and Unload will + * scene asset ID. + * If a scene asset id is different from the current one, Load and Unload will * run. ***************************************************************************/ - static void RestartScene(std::string const& sceneName ) noexcept; + static void RestartScene(AssetID const& assetID ) noexcept; /*!************************************************************************* * \brief @@ -164,7 +168,10 @@ namespace SHADE static void Exit() noexcept; static std::string GetSceneName() noexcept; - + static void SetCurrentSceneName(std::string const& sceneName) noexcept; + static AssetID GetCurrentSceneAssetID() noexcept; + //Only if scene doesn't exist, and scene asset id needs to be updated to the new one + static void SetCurrentSceneAssetID(AssetID const& newAssetID); }; diff --git a/SHADE_Engine/src/Serialization/Configurations/SHConfigurationManager.cpp b/SHADE_Engine/src/Serialization/Configurations/SHConfigurationManager.cpp new file mode 100644 index 00000000..6fa4e9bf --- /dev/null +++ b/SHADE_Engine/src/Serialization/Configurations/SHConfigurationManager.cpp @@ -0,0 +1,89 @@ +#include "SHpch.h" +#include "SHConfigurationManager.h" +#include "Tools/FileIO/SHFileIO.h" +#include "Serialization/SHSerializationHelper.hpp" + +namespace SHADE +{ + SHApplicationConfig SHConfigurationManager::applicationConfig; +#ifdef SHEDITOR + SHEditorConfig SHConfigurationManager::editorConfig; +#endif + + void SHConfigurationManager::SaveApplicationConfig() + { + YAML::Emitter out; + out << SHSerializationHelper::RTTRToNode(applicationConfig); + SHFileIO::WriteStringToFile(applicationConfigPath, out.c_str()); + } + + SHApplicationConfig& SHConfigurationManager::LoadApplicationConfig(WindowData* wndData) + { + if(!std::filesystem::exists(applicationConfigPath)) + { + SaveApplicationConfig(); + return applicationConfig; + } + + auto const node = YAML::Load(SHFileIO::GetStringFromFile(applicationConfigPath)); + auto properties = rttr::type::get().get_properties(); + for(auto const& property : properties) + { + if(node[property.get_name().data()].IsDefined()) + SHSerializationHelper::InitializeProperty(&applicationConfig, property, node[property.get_name().data()]); + } + + if(wndData != nullptr) + { + wndData->isFullscreen = applicationConfig.startInFullScreen; + wndData->title = std::wstring(applicationConfig.windowTitle.begin(), applicationConfig.windowTitle.end()); + wndData->width = static_cast(applicationConfig.windowSize.x); + wndData->height = static_cast(applicationConfig.windowSize.y); + } + + return applicationConfig; + } + +#ifdef SHEDITOR + void SHConfigurationManager::SaveEditorConfig() + { + YAML::Emitter out; + out << SHSerializationHelper::RTTRToNode(editorConfig); + SHFileIO::WriteStringToFile(editorConfigPath, out.c_str()); + } + + SHEditorConfig& SHConfigurationManager::LoadEditorConfig() + { + auto const node = YAML::Load(SHFileIO::GetStringFromFile(editorConfigPath)); + auto properties = rttr::type::get().get_properties(); + for(auto const& property : properties) + { + if(node[property.get_name().data()].IsDefined()) + SHSerializationHelper::InitializeProperty(&editorConfig, property, node[property.get_name().data()]); + } + return editorConfig; + } + + void SHConfigurationManager::FetchEditorCameraData() + { + + } + + void SHConfigurationManager::SetEditorCameraData() + { + + } +#endif +} + +RTTR_REGISTRATION +{ + using namespace rttr; + using namespace SHADE; + + registration::class_("Application Config") + .property("Start in Fullscreen", &SHApplicationConfig::startInFullScreen) + .property("Starting Scene ID", &SHApplicationConfig::startingSceneID) + .property("Window Size", &SHApplicationConfig::windowSize) + .property("Window Title", &SHApplicationConfig::windowTitle); +} diff --git a/SHADE_Engine/src/Serialization/Configurations/SHConfigurationManager.h b/SHADE_Engine/src/Serialization/Configurations/SHConfigurationManager.h new file mode 100644 index 00000000..abf679ca --- /dev/null +++ b/SHADE_Engine/src/Serialization/Configurations/SHConfigurationManager.h @@ -0,0 +1,44 @@ +#pragma once +#include +#include "Assets/SHAssetMacros.h" +#include "Graphics/Windowing/SHWindow.h" +#include "SH_API.h" +#include "Math/Vector/SHVec2.h" + +namespace SHADE +{ + + struct SHApplicationConfig + { + bool startInFullScreen{ false }; + AssetID startingSceneID{}; + SHVec2 windowSize {1920, 1080}; + std::string windowTitle {"SHADE Engine"}; + RTTR_ENABLE() + }; + + struct SHEditorConfig + { + + }; + + class SH_API SHConfigurationManager + { + public: + static constexpr std::string_view applicationConfigPath{"../../Assets/Application.SHConfig"}; + static constexpr std::string_view editorConfigPath{"../../Assets/Editor/Editor.SHConfig"}; + + static void SaveApplicationConfig(); + static SHApplicationConfig& LoadApplicationConfig(WindowData* wndData = nullptr); + static SHApplicationConfig applicationConfig; +#ifdef SHEDITOR + static void SaveEditorConfig(); + static SHEditorConfig& LoadEditorConfig(); + static SHEditorConfig editorConfig; + private: + static void FetchEditorCameraData(); + static void SetEditorCameraData(); +#endif + + }; +} diff --git a/SHADE_Engine/src/Serialization/SHSerialization.cpp b/SHADE_Engine/src/Serialization/SHSerialization.cpp index 03498951..f2829b95 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.cpp +++ b/SHADE_Engine/src/Serialization/SHSerialization.cpp @@ -1,8 +1,8 @@ #include "SHpch.h" #include -#include "SHSerializationHelper.hpp" #include "SHSerialization.h" +#include "SHSerializationHelper.hpp" #include "ECS_Base/Managers/SHEntityManager.h" #include "Scene/SHSceneManager.h" @@ -10,6 +10,7 @@ #include "Assets/SHAssetManager.h" #include +#include "Assets/Asset Types/SHSceneAsset.h" #include "Camera/SHCameraComponent.h" #include "Graphics/MiddleEnd/Interface/SHRenderable.h" #include "Math/Transform/SHTransformComponent.h" @@ -17,19 +18,23 @@ #include "ECS_Base/Managers/SHSystemManager.h" #include "Graphics/MiddleEnd/Lights/SHLightComponent.h" #include "Scripting/SHScriptEngine.h" +#include "Tools/FileIO/SHFileIO.h" namespace SHADE { - void SHSerialization::SerializeSceneToFile(std::filesystem::path const& path) + bool SHSerialization::SerializeSceneToFile(AssetID const& sceneAssetID) { + auto assetData = SHAssetManager::GetData(sceneAssetID); + if(!assetData) + { + SHLOG_ERROR("Asset does not exist: {}", sceneAssetID); + return false; + } YAML::Emitter out; SerializeSceneToEmitter(out); - std::ofstream file(path.c_str()); - if (file.good()) - { - file << out.c_str(); - file.close(); - } + assetData->data = out.c_str(); + + return SHAssetManager::SaveAsset(sceneAssetID); } std::string SHSerialization::SerializeSceneToString() @@ -91,31 +96,16 @@ namespace SHADE return eid; } - void SHSerialization::DeserializeSceneFromFile(std::filesystem::path const& path) + std::string SHSerialization::DeserializeSceneFromFile(AssetID const& sceneAssetID) noexcept { - //TODO:Shift to using XQ's FileIO - std::ifstream iFile; - iFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); - std::string fileContent = ""; - - try + auto assetData = SHAssetManager::GetData(sceneAssetID); + if(!assetData) { - // Open file - // Read file's buffer contents into streams - iFile.open(path); - std::stringstream fileStream; - fileStream << iFile.rdbuf(); - - fileContent = fileStream.str(); - - // Close file handler - iFile.close(); + SHLOG_ERROR("Attempted to load scene that doesn't exist {}", sceneAssetID) + SHSceneManager::SetCurrentSceneAssetID(0); + return NewSceneName.data(); } - catch (std::ifstream::failure e) - { - SHLOG_ERROR("Could not read file"); - } - YAML::Node entities = YAML::Load(fileContent); + YAML::Node entities = YAML::Load(assetData->data); std::vector createdEntities{}; //Create Entities @@ -126,15 +116,24 @@ namespace SHADE if (createdEntities.empty()) { SHLOG_ERROR("Failed to create entities from deserializaiton") - return; + return NewSceneName.data(); } - //Initialize Entity auto entityVecIt = createdEntities.begin(); + AssetQueue assetQueue; + for (auto it = entities.begin(); it != entities.end(); ++it) + { + SHSerializationHelper::FetchAssetsFromComponent((*it)[ComponentsNode], *entityVecIt, assetQueue); + } + LoadAssetsFromAssetQueue(assetQueue); + //Initialize Entity + entityVecIt = createdEntities.begin(); for (auto it = entities.begin(); it != entities.end(); ++it) { InitializeEntity(*it, *entityVecIt++); } - } + + return assetData->name; + } void SHSerialization::EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out) { @@ -264,6 +263,33 @@ namespace SHADE return componentIDList; } + void SHSerialization::LoadAssetsFromAssetQueue(AssetQueue& assetQueue) + { + for (auto& [assetId, assetType] : assetQueue) + { + switch(assetType) + { + case AssetType::INVALID: break; + case AssetType::SHADER: break; + case AssetType::SHADER_BUILT_IN: break; + case AssetType::TEXTURE: + SHResourceManager::LoadOrGet(assetId); + break; + case AssetType::MESH: + SHResourceManager::LoadOrGet(assetId); + break; + case AssetType::SCENE: break; + case AssetType::PREFAB: break; + case AssetType::MATERIAL: + SHResourceManager::LoadOrGet(assetId); + break; + case AssetType::MAX_COUNT: break; + default: ; + } + } + SHResourceManager::FinaliseChanges(); + } + void SHSerialization::InitializeEntity(YAML::Node const& entityNode, EntityID const& eid) { auto const componentsNode = entityNode[ComponentsNode]; diff --git a/SHADE_Engine/src/Serialization/SHSerialization.h b/SHADE_Engine/src/Serialization/SHSerialization.h index 018bf0c3..3cb268f2 100644 --- a/SHADE_Engine/src/Serialization/SHSerialization.h +++ b/SHADE_Engine/src/Serialization/SHSerialization.h @@ -4,7 +4,10 @@ #include #include -#include + +#include "ECS_Base/SHECSMacros.h" +#include +#include namespace YAML { @@ -25,12 +28,11 @@ namespace SHADE struct SH_API SHSerialization { - //TODO: change paths to resource ID - static void SerializeSceneToFile(std::filesystem::path const& path); + static bool SerializeSceneToFile(AssetID const& sceneAssetID); static std::string SerializeSceneToString(); static void SerializeSceneToEmitter(YAML::Emitter& out); - static void DeserializeSceneFromFile(std::filesystem::path const& path); + static std::string DeserializeSceneFromFile(AssetID const& sceneAssetID) noexcept; static void EmitEntity(SHSceneNode* entityNode, YAML::Emitter& out); @@ -42,7 +44,11 @@ namespace SHADE static EntityID DeserializeEntitiesFromString(std::string const& data, EntityID const& parentEID = MAX_EID) noexcept; static std::vector GetComponentIDList(YAML::Node const& componentsNode); + + static void LoadAssetsFromAssetQueue(std::unordered_map& assetQueue); private: static void InitializeEntity(YAML::Node const& entityNode, EntityID const& eid); + + static constexpr std::string_view NewSceneName = "New Scene"; }; } \ No newline at end of file diff --git a/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp b/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp index ed4f118a..b062b348 100644 --- a/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp +++ b/SHADE_Engine/src/Serialization/SHSerializationHelper.hpp @@ -1,329 +1,20 @@ #pragma once +#include "SHYAMLConverters.h" #include #include "ECS_Base/Components/SHComponent.h" #include +#include #include "ECS_Base/Managers/SHComponentManager.h" -#include "Math/Vector/SHVec2.h" -#include "Math/Vector/SHVec3.h" -#include "Math/Vector/SHVec4.h" -#include "Resource/SHResourceManager.h" -#include "Graphics/MiddleEnd/Interface/SHRenderable.h" -#include "Graphics/MiddleEnd/Interface/SHMaterial.h" -#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" -#include "SHSerializationTools.h" -#include "Physics/Components/SHColliderComponent.h" #include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" #include "Tools/SHLog.h" -namespace YAML -{ - using namespace SHADE; - - template<> - struct convert - { - static constexpr const char* x = "x"; - static constexpr const char* y = "y"; - static constexpr const char* z = "z"; - static constexpr const char* w = "w"; - - static Node encode(SHVec4 const& rhs) - { - Node node; - node.SetStyle(EmitterStyle::Flow); - node[x] = rhs.x; - node[y] = rhs.y; - node[z] = rhs.z; - node[w] = rhs.w; - return node; - } - static bool decode(Node const& node, SHVec4& rhs) - { - if (node[x].IsDefined()) - rhs.x = node[x].as(); - if (node[y].IsDefined()) - rhs.y = node[y].as(); - if (node[z].IsDefined()) - rhs.z = node[z].as(); - if (node[w].IsDefined()) - rhs.w = node[w].as(); - return true; - } - }; - - template<> - struct convert - { - static constexpr const char* x = "x"; - static constexpr const char* y = "y"; - static constexpr const char* z = "z"; - - static Node encode(SHVec3 const& rhs) - { - Node node; - node.SetStyle(EmitterStyle::Flow); - node[x] = rhs.x; - node[y] = rhs.y; - node[z] = rhs.z; - return node; - } - static bool decode(Node const& node, SHVec3& rhs) - { - if (node[x].IsDefined()) - rhs.x = node[x].as(); - if (node[y].IsDefined()) - rhs.y = node[y].as(); - if (node[z].IsDefined()) - rhs.z = node[z].as(); - return true; - } - }; - - template<> - struct convert - { - static constexpr const char* x = "x"; - static constexpr const char* y = "y"; - - static Node encode(SHVec2 const& rhs) - { - Node node; - node.SetStyle(EmitterStyle::Flow); - node[x] = rhs.x; - node[y] = rhs.y; - return node; - } - static bool decode(Node const& node, SHVec2& rhs) - { - if (node[x].IsDefined()) - rhs.x = node[x].as(); - if (node[y].IsDefined()) - rhs.y = node[y].as(); - return true; - } - }; - - template<> - struct convert - { - static constexpr const char* IsTrigger = "Is Trigger"; - - static constexpr const char* Type = "Type"; - static constexpr const char* HalfExtents = "Half Extents"; - static constexpr const char* Radius = "Radius"; - - static constexpr const char* Friction = "Friction"; - static constexpr const char* Bounciness = "Bounciness"; - static constexpr const char* Density = "Density"; - static constexpr const char* PositionOffset = "Position Offset"; - - static Node encode(SHCollider& rhs) - { - Node node; - - node[IsTrigger] = rhs.IsTrigger(); - - rttr::type const shapeRttrType = rttr::type::get(); - rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); - SHCollider::Type colliderType = rhs.GetType(); - - node[Type] = enumAlign.value_to_name(colliderType).data(); - - switch (colliderType) - { - case SHCollider::Type::BOX: - { - auto const bb = reinterpret_cast(rhs.GetShape()); - node[HalfExtents] = bb->GetHalfExtents(); - } - break; - case SHCollider::Type::SPHERE: - { - auto const bs = reinterpret_cast(rhs.GetShape()); - node[Radius] = bs->GetRadius(); - } - break; - case SHCollider::Type::CAPSULE: break; - default:; - } - - node[Friction] = rhs.GetFriction(); - node[Bounciness] = rhs.GetBounciness(); - node[Density] = rhs.GetDensity(); - node[PositionOffset] = rhs.GetPositionOffset(); - - return node; - } - static bool decode(Node const& node, SHCollider& rhs) - { - if (node[IsTrigger].IsDefined()) - rhs.SetIsTrigger(node[IsTrigger].as()); - if (!node[Type].IsDefined()) - return false; - rttr::type const shapeRttrType = rttr::type::get(); - rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); - bool ok; - const SHCollider::Type colliderType = enumAlign.name_to_value(node[Type].as()).convert(&ok); - if (!ok) - return false; - switch (colliderType) - { - case SHCollider::Type::BOX: - { - if (node[HalfExtents].IsDefined()) - rhs.SetBoundingBox(node[HalfExtents].as()); - } - break; - case SHCollider::Type::SPHERE: - { - if (node[Radius].IsDefined()) - rhs.SetBoundingSphere(node[Radius].as()); - } - break; - case SHCollider::Type::CAPSULE: break; - default:; - } - if (node[Friction].IsDefined()) - rhs.SetFriction(node[Friction].as()); - if (node[Bounciness].IsDefined()) - rhs.SetBounciness(rhs.GetBounciness()); - if (node[Density].IsDefined()) - rhs.SetDensity(node[Density].as()); - if (node[PositionOffset].IsDefined()) - rhs.SetPositionOffset(node[PositionOffset].as()); - - return true; - } - }; - - template<> - struct convert - { - static constexpr const char* Colliders = "Colliders"; - static Node encode(SHColliderComponent& rhs) - { - Node node, collidersNode; - auto const& colliders = rhs.GetColliders(); - int const numColliders = static_cast(colliders.size()); - for (int i = 0; i < numColliders; ++i) - { - auto& collider = rhs.GetCollider(i); - Node colliderNode = convert::encode(collider); - if (colliderNode.IsDefined()) - collidersNode[i] = colliderNode; - } - node[Colliders] = collidersNode; - return node; - } - static bool decode(Node const& node, SHColliderComponent& rhs) - { - if (node[Colliders].IsDefined()) - { - int numColliders{}; - for (auto const& colliderNode : node[Colliders]) - { - rttr::type const shapeRttrType = rttr::type::get(); - rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); - bool ok = false; - const SHCollider::Type colliderType = enumAlign.name_to_value(colliderNode[convert::Type].as()).convert(&ok); - if (!ok) - return false; - - switch (colliderType) - { - case SHCollider::Type::BOX: rhs.AddBoundingBox(); break; - case SHCollider::Type::SPHERE: rhs.AddBoundingSphere(); break; - case SHCollider::Type::CAPSULE: break; - default:; - } - YAML::convert::decode(colliderNode, rhs.GetCollider(numColliders++)); - } - } - return true; - } - }; - - template<> - struct convert - { - static constexpr std::string_view VERT_SHADER_YAML_TAG = "VertexShader"; - static constexpr std::string_view FRAG_SHADER_YAML_TAG = "FragmentShader"; - static constexpr std::string_view SUBPASS_YAML_TAG = "SubPass"; - static constexpr std::string_view PROPS_YAML_TAG = "Properties"; - - static YAML::Node encode(SHMaterialSpec const& rhs) - { - YAML::Node node; - node[VERT_SHADER_YAML_TAG.data()] = rhs.vertexShader; - node[FRAG_SHADER_YAML_TAG.data()] = rhs.fragShader; - node[SUBPASS_YAML_TAG.data()] = rhs.subpassName; - node[PROPS_YAML_TAG.data()] = rhs.properties; - return node; - } - - static bool decode(YAML::Node const& node, SHMaterialSpec& rhs) - { - // Retrieve Shader Asset IDs - if (node[VERT_SHADER_YAML_TAG.data()].IsDefined()) - rhs.vertexShader = node[VERT_SHADER_YAML_TAG.data()].as(); - if (node[FRAG_SHADER_YAML_TAG.data()].IsDefined()) - rhs.fragShader = node[FRAG_SHADER_YAML_TAG.data()].as(); - - // Retrieve Subpass - if (node[SUBPASS_YAML_TAG.data()].IsDefined()) - rhs.subpassName = node[SUBPASS_YAML_TAG.data()].as(); - - // Retrieve - if (node[PROPS_YAML_TAG.data()].IsDefined()) - rhs.properties = node[PROPS_YAML_TAG.data()]; - - return true; - } - }; - - template<> - struct convert - { - static constexpr std::string_view MESH_YAML_TAG = "Mesh"; - static constexpr std::string_view MAT_YAML_TAG = "Material"; - - static YAML::Node encode(SHRenderable const& rhs) - { - YAML::Node node; - node[MESH_YAML_TAG.data()] = SHResourceManager::GetAssetID(rhs.GetMesh()).value_or(0); - node[MAT_YAML_TAG.data()] = SHResourceManager::GetAssetID(rhs.GetMaterial()->GetBaseMaterial()).value_or(0); - return node; - } - static bool decode(YAML::Node const& node, SHRenderable& rhs) - { - if (node[MESH_YAML_TAG.data()].IsDefined()) - { - rhs.SetMesh(SHResourceManager::LoadOrGet(node[MESH_YAML_TAG.data()].as())); - } - if (node[MAT_YAML_TAG.data()].IsDefined()) - { - // Temporarily, use default material - auto gfxSystem = SHSystemManager::GetSystem(); - if (!gfxSystem) - return false; - Handle baseMat = SHResourceManager::LoadOrGet(node[MAT_YAML_TAG.data()].as()); - if (!baseMat) - { - baseMat = gfxSystem->GetDefaultMaterial(); - SHLog::Warning("[SHSerializationHelper] Unable to load specified material. Falling back to default material."); - } - rhs.SetMaterial(gfxSystem->AddOrGetBaseMaterialInstance(baseMat)); - } - return true; - } - }; -} namespace SHADE { + using AssetQueue = std::unordered_map; struct SHSerializationHelper { @@ -397,6 +88,8 @@ namespace SHADE node = YAML::Null; } } + else if (varType == rttr::type::get()) + node = var.to_string(); else { auto properties = var.get_type().get_properties(); @@ -432,63 +125,65 @@ namespace SHADE return node; } - template , bool> = true> - static void InitializeProperty(ComponentType* component, rttr::property const& prop, YAML::Node const& propertyNode) + template + static void InitializeProperty(Type* object, rttr::property const& prop, YAML::Node const& propertyNode) { auto propType = prop.get_type(); if (propType == rttr::type::get()) { SHVec4 vec = propertyNode.as(); - prop.set_value(component, vec); + prop.set_value(object, vec); } else if (propType == rttr::type::get()) { SHVec3 vec = propertyNode.as(); - prop.set_value(component, vec); + prop.set_value(object, vec); } else if (propType == rttr::type::get()) { SHVec2 vec = propertyNode.as(); - prop.set_value(component, vec); + prop.set_value(object, vec); } else if (propType.is_arithmetic()) { bool ok = false; if (propType == rttr::type::get()) - prop.set_value(component, propertyNode.as()); + prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) - prop.set_value(component, propertyNode.as()); + prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) - prop.set_value(component, propertyNode.as()); + prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) - prop.set_value(component, propertyNode.as()); + prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) - prop.set_value(component, propertyNode.as()); + prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) - prop.set_value(component, propertyNode.as()); + prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) - prop.set_value(component, propertyNode.as()); + prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) - prop.set_value(component, propertyNode.as()); + prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) - prop.set_value(component, propertyNode.as()); + prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) - prop.set_value(component, propertyNode.as()); + prop.set_value(object, propertyNode.as()); else if (propType == rttr::type::get()) - prop.set_value(component, propertyNode.as()); + prop.set_value(object, propertyNode.as()); } else if (propType.is_enumeration()) { auto enumAlign = prop.get_enumeration(); - prop.set_value(component, enumAlign.name_to_value(propertyNode.as())); + prop.set_value(object, enumAlign.name_to_value(propertyNode.as())); } + else if (propType == rttr::type::get()) + prop.set_value(object, propertyNode.as()); else { auto properties = propType.get_properties(); for (auto const& property : properties) { - if (propertyNode[property.get_name().data()].IsDefined()) - InitializeProperty(component, property, propertyNode[property.get_name().data()]); + if(propertyNode[property.get_name().data()].IsDefined()) + InitializeProperty(object, property, propertyNode[property.get_name().data()]); } } } @@ -513,18 +208,73 @@ namespace SHADE } } + template , bool> = true> + static YAML::Node GetComponentNode(YAML::Node const& componentsNode, EntityID const& eid) + { + auto component = SHComponentManager::GetComponent_s(eid); + if (componentsNode.IsNull() && !component) + return {}; + auto rttrType = rttr::type::get(); + auto componentNode = componentsNode[rttrType.get_name().data()]; + if (!componentNode.IsDefined()) + return {}; + return componentNode; + } + template , bool> = true> static void ConvertNodeToComponent(YAML::Node const& componentsNode, EntityID const& eid) { auto component = SHComponentManager::GetComponent_s(eid); if (componentsNode.IsNull() && !component) return; - auto rttrType = rttr::type::get(); - auto componentNode = componentsNode[rttrType.get_name().data()]; - if (!componentNode.IsDefined()) - return; - YAML::convert::decode(componentNode, *component); + + YAML::convert::decode(GetComponentNode(componentsNode, eid), *component); } + template , bool> = true> + static void FetchAssetsFromComponent(YAML::Node const& componentsNode, EntityID const& eid, AssetQueue& assetQueue) + { + } + + template<> + static void FetchAssetsFromComponent(YAML::Node const& componentsNode, EntityID const& eid, AssetQueue& assetQueue) + { + auto node = GetComponentNode(componentsNode, eid); + if(!node.IsDefined()) + return; + if (auto const& meshNode = node[YAML::convert::MESH_YAML_TAG.data()]; meshNode.IsDefined()) + { + assetQueue.insert({meshNode.as(), AssetType::MESH}); + //SHResourceManager::LoadOrGet(node[YAML::convert::MESH_YAML_TAG.data()].as()); + } + if (auto const& matNode = node[YAML::convert::MAT_YAML_TAG.data()]; matNode.IsDefined()) + { + auto const matAsset = SHAssetManager::GetData(matNode.as()); + if(matAsset) + { + SHMaterialSpec spec; + YAML::convert::decode(*YAML::Load(matAsset->data).begin(), spec); + if(spec.properties.IsDefined()) + { + auto fragShader = SHResourceManager::LoadOrGet(spec.fragShader); + auto interface = fragShader->GetReflectedData().GetDescriptorBindingInfo().GetShaderBlockInterface(SHGraphicsConstants::DescriptorSetIndex::PER_INSTANCE, SHGraphicsConstants::DescriptorSetBindings::BATCHED_PER_INST_DATA); + int const varCount = static_cast(interface->GetVariableCount()); + + for (int i = 0; i < varCount; ++i) + { + auto variable = interface->GetVariable(i); + if(variable->type != SHShaderBlockInterface::Variable::Type::INT) + continue; + const std::string& VAR_NAME = interface->GetVariableName(i); + if(VAR_NAME.empty()) + continue; + assetQueue.insert({spec.properties[VAR_NAME.data()].as(), AssetType::TEXTURE}); + } + } + } + //assetQueue.insert({matNode.as(), AssetType::MATERIAL}); + //SHResourceManager::LoadOrGet(node[YAML::convert::MAT_YAML_TAG.data()].as()); + } + } }; } diff --git a/SHADE_Engine/src/Serialization/SHYAMLConverters.h b/SHADE_Engine/src/Serialization/SHYAMLConverters.h new file mode 100644 index 00000000..af0b280b --- /dev/null +++ b/SHADE_Engine/src/Serialization/SHYAMLConverters.h @@ -0,0 +1,317 @@ +#pragma once +#include "Graphics/MiddleEnd/Interface/SHRenderable.h" +#include "Graphics/MiddleEnd/Materials/SHMaterialSpec.h" +#include "Math/Geometry/SHBoundingBox.h" +#include "Math/Geometry/SHBoundingSphere.h" +#include "Physics/SHCollider.h" +#include "Resource/SHResourceManager.h" +#include "Math/Vector/SHVec2.h" +#include "Math/Vector/SHVec3.h" +#include "Math/Vector/SHVec4.h" +#include "Graphics/MiddleEnd/Interface/SHMaterial.h" +#include "Graphics/MiddleEnd/Interface/SHMaterialInstance.h" +#include "SHSerializationTools.h" +#include "Physics/Components/SHColliderComponent.h" +namespace YAML +{ + using namespace SHADE; + + template<> + struct convert + { + static constexpr const char* x = "x"; + static constexpr const char* y = "y"; + static constexpr const char* z = "z"; + static constexpr const char* w = "w"; + + static Node encode(SHVec4 const& rhs) + { + Node node; + node.SetStyle(EmitterStyle::Flow); + node[x] = rhs.x; + node[y] = rhs.y; + node[z] = rhs.z; + node[w] = rhs.w; + return node; + } + static bool decode(Node const& node, SHVec4& rhs) + { + if (node[x].IsDefined()) + rhs.x = node[x].as(); + if (node[y].IsDefined()) + rhs.y = node[y].as(); + if (node[z].IsDefined()) + rhs.z = node[z].as(); + if (node[w].IsDefined()) + rhs.w = node[w].as(); + return true; + } + }; + + template<> + struct convert + { + static constexpr const char* x = "x"; + static constexpr const char* y = "y"; + static constexpr const char* z = "z"; + + static Node encode(SHVec3 const& rhs) + { + Node node; + node.SetStyle(EmitterStyle::Flow); + node[x] = rhs.x; + node[y] = rhs.y; + node[z] = rhs.z; + return node; + } + static bool decode(Node const& node, SHVec3& rhs) + { + if (node[x].IsDefined()) + rhs.x = node[x].as(); + if (node[y].IsDefined()) + rhs.y = node[y].as(); + if (node[z].IsDefined()) + rhs.z = node[z].as(); + return true; + } + }; + + template<> + struct convert + { + static constexpr const char* x = "x"; + static constexpr const char* y = "y"; + + static Node encode(SHVec2 const& rhs) + { + Node node; + node.SetStyle(EmitterStyle::Flow); + node[x] = rhs.x; + node[y] = rhs.y; + return node; + } + static bool decode(Node const& node, SHVec2& rhs) + { + if (node[x].IsDefined()) + rhs.x = node[x].as(); + if (node[y].IsDefined()) + rhs.y = node[y].as(); + return true; + } + }; + + template<> + struct convert + { + static constexpr const char* IsTrigger = "Is Trigger"; + + static constexpr const char* Type = "Type"; + static constexpr const char* HalfExtents = "Half Extents"; + static constexpr const char* Radius = "Radius"; + + static constexpr const char* Friction = "Friction"; + static constexpr const char* Bounciness = "Bounciness"; + static constexpr const char* Density = "Density"; + static constexpr const char* PositionOffset = "Position Offset"; + + static Node encode(SHCollider& rhs) + { + Node node; + + node[IsTrigger] = rhs.IsTrigger(); + + rttr::type const shapeRttrType = rttr::type::get(); + rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); + SHCollider::Type colliderType = rhs.GetType(); + + node[Type] = enumAlign.value_to_name(colliderType).data(); + + switch (colliderType) + { + case SHCollider::Type::BOX: + { + auto const bb = reinterpret_cast(rhs.GetShape()); + node[HalfExtents] = bb->GetHalfExtents(); + } + break; + case SHCollider::Type::SPHERE: + { + auto const bs = reinterpret_cast(rhs.GetShape()); + node[Radius] = bs->GetRadius(); + } + break; + case SHCollider::Type::CAPSULE: break; + default:; + } + + node[Friction] = rhs.GetFriction(); + node[Bounciness] = rhs.GetBounciness(); + node[Density] = rhs.GetDensity(); + node[PositionOffset] = rhs.GetPositionOffset(); + + return node; + } + static bool decode(Node const& node, SHCollider& rhs) + { + if (node[IsTrigger].IsDefined()) + rhs.SetIsTrigger(node[IsTrigger].as()); + if (!node[Type].IsDefined()) + return false; + rttr::type const shapeRttrType = rttr::type::get(); + rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); + bool ok; + const SHCollider::Type colliderType = enumAlign.name_to_value(node[Type].as()).convert(&ok); + if (!ok) + return false; + switch (colliderType) + { + case SHCollider::Type::BOX: + { + if (node[HalfExtents].IsDefined()) + rhs.SetBoundingBox(node[HalfExtents].as()); + } + break; + case SHCollider::Type::SPHERE: + { + if (node[Radius].IsDefined()) + rhs.SetBoundingSphere(node[Radius].as()); + } + break; + case SHCollider::Type::CAPSULE: break; + default:; + } + if (node[Friction].IsDefined()) + rhs.SetFriction(node[Friction].as()); + if (node[Bounciness].IsDefined()) + rhs.SetBounciness(rhs.GetBounciness()); + if (node[Density].IsDefined()) + rhs.SetDensity(node[Density].as()); + if (node[PositionOffset].IsDefined()) + rhs.SetPositionOffset(node[PositionOffset].as()); + + return true; + } + }; + + template<> + struct convert + { + static constexpr const char* Colliders = "Colliders"; + static Node encode(SHColliderComponent& rhs) + { + Node node, collidersNode; + auto const& colliders = rhs.GetColliders(); + int const numColliders = static_cast(colliders.size()); + for (int i = 0; i < numColliders; ++i) + { + auto& collider = rhs.GetCollider(i); + Node colliderNode = convert::encode(collider); + if (colliderNode.IsDefined()) + collidersNode[i] = colliderNode; + } + node[Colliders] = collidersNode; + return node; + } + static bool decode(Node const& node, SHColliderComponent& rhs) + { + if (node[Colliders].IsDefined()) + { + int numColliders{}; + for (auto const& colliderNode : node[Colliders]) + { + rttr::type const shapeRttrType = rttr::type::get(); + rttr::enumeration const enumAlign = shapeRttrType.get_enumeration(); + bool ok = false; + const SHCollider::Type colliderType = enumAlign.name_to_value(colliderNode[convert::Type].as()).convert(&ok); + if (!ok) + return false; + + switch (colliderType) + { + case SHCollider::Type::BOX: rhs.AddBoundingBox(); break; + case SHCollider::Type::SPHERE: rhs.AddBoundingSphere(); break; + case SHCollider::Type::CAPSULE: break; + default:; + } + YAML::convert::decode(colliderNode, rhs.GetCollider(numColliders++)); + } + } + return true; + } + }; + + template<> + struct convert + { + static constexpr std::string_view VERT_SHADER_YAML_TAG = "VertexShader"; + static constexpr std::string_view FRAG_SHADER_YAML_TAG = "FragmentShader"; + static constexpr std::string_view SUBPASS_YAML_TAG = "SubPass"; + static constexpr std::string_view PROPS_YAML_TAG = "Properties"; + + static YAML::Node encode(SHMaterialSpec const& rhs) + { + YAML::Node node; + node[VERT_SHADER_YAML_TAG.data()] = rhs.vertexShader; + node[FRAG_SHADER_YAML_TAG.data()] = rhs.fragShader; + node[SUBPASS_YAML_TAG.data()] = rhs.subpassName; + node[PROPS_YAML_TAG.data()] = rhs.properties; + return node; + } + + static bool decode(YAML::Node const& node, SHMaterialSpec& rhs) + { + // Retrieve Shader Asset IDs + if (node[VERT_SHADER_YAML_TAG.data()].IsDefined()) + rhs.vertexShader = node[VERT_SHADER_YAML_TAG.data()].as(); + if (node[FRAG_SHADER_YAML_TAG.data()].IsDefined()) + rhs.fragShader = node[FRAG_SHADER_YAML_TAG.data()].as(); + + // Retrieve Subpass + if (node[SUBPASS_YAML_TAG.data()].IsDefined()) + rhs.subpassName = node[SUBPASS_YAML_TAG.data()].as(); + + // Retrieve + if (node[PROPS_YAML_TAG.data()].IsDefined()) + rhs.properties = node[PROPS_YAML_TAG.data()]; + + return true; + } + }; + + template<> + struct convert + { + static constexpr std::string_view MESH_YAML_TAG = "Mesh"; + static constexpr std::string_view MAT_YAML_TAG = "Material"; + + static YAML::Node encode(SHRenderable const& rhs) + { + YAML::Node node; + node[MESH_YAML_TAG.data()] = SHResourceManager::GetAssetID(rhs.GetMesh()).value_or(0); + node[MAT_YAML_TAG.data()] = SHResourceManager::GetAssetID(rhs.GetMaterial()->GetBaseMaterial()).value_or(0); + return node; + } + static bool decode(YAML::Node const& node, SHRenderable& rhs) + { + if (node[MESH_YAML_TAG.data()].IsDefined()) + { + rhs.SetMesh(SHResourceManager::LoadOrGet(node[MESH_YAML_TAG.data()].as())); + } + if (node[MAT_YAML_TAG.data()].IsDefined()) + { + // Temporarily, use default material + auto gfxSystem = SHSystemManager::GetSystem(); + if (!gfxSystem) + return false; + Handle baseMat = SHResourceManager::LoadOrGet(node[MAT_YAML_TAG.data()].as()); + if (!baseMat) + { + baseMat = gfxSystem->GetDefaultMaterial(); + SHLog::Warning("[SHSerializationHelper] Unable to load specified material. Falling back to default material."); + } + rhs.SetMaterial(gfxSystem->AddOrGetBaseMaterialInstance(baseMat)); + } + return true; + } + }; +} diff --git a/SHADE_Engine/src/Tools/FileIO/SHFieIO.cpp b/SHADE_Engine/src/Tools/FileIO/SHFieIO.cpp new file mode 100644 index 00000000..c4fec120 --- /dev/null +++ b/SHADE_Engine/src/Tools/FileIO/SHFieIO.cpp @@ -0,0 +1,31 @@ +#include "SHpch.h" +#include "SHFileIO.h" +#include + +namespace SHADE +{ + int SHFileIO::WriteStringToFile(std::filesystem::path const& filePath, std::string_view const& strView) + { + std::ofstream file(filePath); + if(file.good()) + { + file << strView; + file.close(); + return 1; + } + return 0; + } + + std::string SHFileIO::GetStringFromFile(std::filesystem::path const& filePath) + { + std::ifstream iFile; + iFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); + std::string fileData{}; + iFile.open(filePath, std::iostream::binary); + std::stringstream ss; + ss << iFile.rdbuf(); + fileData = ss.str(); + iFile.close(); + return fileData; + } +} diff --git a/SHADE_Engine/src/Tools/FileIO/SHFileIO.h b/SHADE_Engine/src/Tools/FileIO/SHFileIO.h new file mode 100644 index 00000000..adc95d5b --- /dev/null +++ b/SHADE_Engine/src/Tools/FileIO/SHFileIO.h @@ -0,0 +1,14 @@ +#pragma once +#include +#include +#include +#include + +namespace SHADE +{ + struct SH_API SHFileIO + { + static int WriteStringToFile(std::filesystem::path const& filePath, std::string_view const& strView); + static std::string GetStringFromFile(std::filesystem::path const& file); + }; +} \ No newline at end of file diff --git a/SHADE_Managed/premake5.lua b/SHADE_Managed/premake5.lua index b383f002..88021071 100644 --- a/SHADE_Managed/premake5.lua +++ b/SHADE_Managed/premake5.lua @@ -38,6 +38,7 @@ project "SHADE_Managed" "%{IncludeDir.RTTR}/include", "%{IncludeDir.dotnet}\\include", "%{IncludeDir.reactphysics3d}\\include", + "%{IncludeDir.VULKAN}\\include", "%{wks.location}/SHADE_Engine/src" }