From 368d8c598c2fe34407d7e1d1d31ccefc462922d7 Mon Sep 17 00:00:00 2001 From: Niels Eppenhof Date: Mon, 6 Jan 2025 23:50:48 +0100 Subject: [PATCH] Code style part 3 --- .clang-format | 6 +- Dependencies.lua | 4 +- EppoEditor/Source/EditorLayer.cpp | 1320 ++++++------ EppoEditor/Source/EditorLayer.h | 114 +- EppoEditor/Source/EppoEditor.cpp | 40 +- .../Source/Panel/ContentBrowserPanel.cpp | 146 +- EppoEditor/Source/Panel/ContentBrowserPanel.h | 34 +- EppoEditor/Source/Panel/Panel.cpp | 38 +- EppoEditor/Source/Panel/Panel.h | 32 +- EppoEditor/Source/Panel/PanelManager.cpp | 34 +- EppoEditor/Source/Panel/PanelManager.h | 94 +- EppoEditor/Source/Panel/PropertyPanel.cpp | 1618 +++++++------- EppoEditor/Source/Panel/PropertyPanel.h | 22 +- .../Source/Panel/SceneHierarchyPanel.cpp | 98 +- EppoEditor/Source/Panel/SceneHierarchyPanel.h | 16 +- EppoEditor/Source/ThumbnailCache.cpp | 42 +- EppoEditor/Source/ThumbnailCache.h | 30 +- EppoEditor/premake5.lua | 40 +- EppoEngine/Source/Core/Log.h | 18 +- EppoEngine/Source/Core/Ref.h | 320 +-- EppoEngine/Source/Core/Window.cpp | 298 +-- EppoEngine/Source/Platform/FileDialog.h | 12 +- .../Platform/Vulkan/VulkanCommandBuffer.cpp | 426 ++-- .../Platform/Vulkan/VulkanCommandBuffer.h | 94 +- .../Source/Platform/Vulkan/VulkanContext.cpp | 272 +-- .../Source/Platform/Vulkan/VulkanContext.h | 76 +- .../Platform/Vulkan/VulkanDebugRenderer.cpp | 38 +- .../Platform/Vulkan/VulkanDebugRenderer.h | 14 +- .../Source/Platform/Vulkan/VulkanImage.cpp | 558 ++--- .../Source/Platform/Vulkan/VulkanImage.h | 80 +- .../Platform/Vulkan/VulkanIndexBuffer.cpp | 211 +- .../Platform/Vulkan/VulkanIndexBuffer.h | 52 +- .../Platform/Vulkan/VulkanLogicalDevice.cpp | 322 +-- .../Platform/Vulkan/VulkanLogicalDevice.h | 40 +- .../Platform/Vulkan/VulkanPhysicalDevice.cpp | 332 +-- .../Platform/Vulkan/VulkanPhysicalDevice.h | 96 +- .../Source/Platform/Vulkan/VulkanPipeline.cpp | 557 ++--- .../Source/Platform/Vulkan/VulkanPipeline.h | 36 +- .../Source/Platform/Vulkan/VulkanRenderer.cpp | 356 ++-- .../Source/Platform/Vulkan/VulkanRenderer.h | 64 +- .../Platform/Vulkan/VulkanSceneRenderer.cpp | 1875 ++++++++--------- .../Platform/Vulkan/VulkanSceneRenderer.h | 221 +- .../Source/Platform/Vulkan/VulkanShader.cpp | 764 +++---- .../Source/Platform/Vulkan/VulkanShader.h | 42 +- .../Platform/Vulkan/VulkanSwapchain.cpp | 582 ++--- .../Source/Platform/Vulkan/VulkanSwapchain.h | 88 +- .../Platform/Vulkan/VulkanUniformBuffer.cpp | 82 +- .../Platform/Vulkan/VulkanUniformBuffer.h | 38 +- .../Platform/Vulkan/VulkanVertexBuffer.cpp | 207 +- .../Platform/Vulkan/VulkanVertexBuffer.h | 38 +- .../Source/Platform/Windows/FileDialog.cpp | 98 +- EppoEngine/Source/Project/Project.cpp | 136 +- EppoEngine/Source/Project/Project.h | 76 +- .../Source/Project/ProjectSerializer.cpp | 89 +- EppoEngine/Source/Project/ProjectSerializer.h | 18 +- EppoEngine/Source/Renderer/Camera/Camera.h | 25 +- .../Source/Renderer/Camera/EditorCamera.cpp | 150 +- .../Source/Renderer/Camera/EditorCamera.h | 86 +- .../Source/Renderer/Camera/SceneCamera.cpp | 216 +- .../Source/Renderer/Camera/SceneCamera.h | 80 +- EppoEngine/Source/Renderer/CommandBuffer.cpp | 19 +- EppoEngine/Source/Renderer/CommandBuffer.h | 18 +- EppoEngine/Source/Renderer/CommandQueue.cpp | 38 +- EppoEngine/Source/Renderer/CommandQueue.h | 28 +- EppoEngine/Source/Renderer/DebugRenderer.cpp | 19 +- EppoEngine/Source/Renderer/DebugRenderer.h | 16 +- EppoEngine/Source/Renderer/DrawCommand.h | 28 +- .../Source/Renderer/GarbageCollector.cpp | 82 +- EppoEngine/Source/Renderer/GarbageCollector.h | 32 +- EppoEngine/Source/Renderer/Image.cpp | 19 +- EppoEngine/Source/Renderer/Image.h | 117 +- EppoEngine/Source/Renderer/IndexBuffer.cpp | 48 +- EppoEngine/Source/Renderer/IndexBuffer.h | 20 +- EppoEngine/Source/Renderer/Mesh/Material.h | 20 +- EppoEngine/Source/Renderer/Mesh/Mesh.cpp | 444 ++-- EppoEngine/Source/Renderer/Mesh/Mesh.h | 78 +- EppoEngine/Source/Renderer/Mesh/Submesh.cpp | 13 +- EppoEngine/Source/Renderer/Mesh/Submesh.h | 63 +- EppoEngine/Source/Renderer/Pipeline.cpp | 19 +- EppoEngine/Source/Renderer/Pipeline.h | 211 +- EppoEngine/Source/Renderer/RenderTypes.h | 22 +- EppoEngine/Source/Renderer/Renderer.cpp | 19 +- EppoEngine/Source/Renderer/Renderer.h | 32 +- .../Source/Renderer/RendererContext.cpp | 29 +- EppoEngine/Source/Renderer/RendererContext.h | 44 +- EppoEngine/Source/Renderer/SceneRenderer.cpp | 19 +- EppoEngine/Source/Renderer/SceneRenderer.h | 74 +- EppoEngine/Source/Renderer/Shader.cpp | 101 +- EppoEngine/Source/Renderer/Shader.h | 116 +- EppoEngine/Source/Renderer/ShaderIncluder.cpp | 45 +- EppoEngine/Source/Renderer/ShaderIncluder.h | 13 +- EppoEngine/Source/Renderer/ShaderLibrary.cpp | 32 +- EppoEngine/Source/Renderer/ShaderLibrary.h | 26 +- EppoEngine/Source/Renderer/UniformBuffer.cpp | 19 +- EppoEngine/Source/Renderer/UniformBuffer.h | 16 +- EppoEngine/Source/Renderer/Vertex.h | 40 +- EppoEngine/Source/Renderer/VertexBuffer.cpp | 48 +- EppoEngine/Source/Renderer/VertexBuffer.h | 18 +- .../Source/Renderer/VertexBufferLayout.cpp | 134 +- .../Source/Renderer/VertexBufferLayout.h | 126 +- EppoEngine/Source/Scene/Components.h | 198 +- EppoEngine/Source/Scene/Entity.cpp | 6 +- EppoEngine/Source/Scene/Entity.h | 106 +- EppoEngine/Source/Scene/Scene.cpp | 749 ++++--- EppoEngine/Source/Scene/Scene.h | 76 +- EppoEngine/Source/Scene/SceneSerializer.cpp | 907 ++++---- EppoEngine/Source/Scene/SceneSerializer.h | 24 +- EppoEngine/Source/Scripting/ScriptClass.cpp | 82 +- EppoEngine/Source/Scripting/ScriptClass.h | 34 +- EppoEngine/Source/Scripting/ScriptEngine.cpp | 716 ++++--- EppoEngine/Source/Scripting/ScriptEngine.h | 216 +- EppoEngine/Source/Scripting/ScriptField.h | 98 +- EppoEngine/Source/Scripting/ScriptGlue.cpp | 376 ++-- EppoEngine/Source/Scripting/ScriptGlue.h | 18 +- .../Source/Scripting/ScriptInstance.cpp | 128 +- EppoEngine/Source/Scripting/ScriptInstance.h | 90 +- EppoEngine/Source/Utility/Random.h | 54 +- EppoEngine/Source/pch.h | 6 +- EppoScripting/Source/Core/Input.cs | 14 +- EppoScripting/Source/Core/KeyCodes.cs | 252 +-- EppoScripting/Source/Core/Log.cs | 52 +- EppoScripting/Source/InternalCalls.cs | 64 +- EppoScripting/Source/Math/Vector2.cs | 54 +- EppoScripting/Source/Math/Vector3.cs | 88 +- EppoScripting/Source/Math/Vector4.cs | 114 +- EppoScripting/Source/Scene/Components.cs | 52 +- EppoScripting/Source/Scene/Entity.cs | 226 +- EppoTesting/Source/Core/Buffer.cpp | 282 +-- EppoTesting/Source/Core/Hash.cpp | 48 +- EppoTesting/Source/Core/LayerStack.cpp | 92 +- EppoTesting/Source/Core/Ref.cpp | 332 +-- EppoTesting/Source/Core/UUID.cpp | 50 +- EppoTesting/Source/Core/Window.cpp | 128 +- 133 files changed, 10553 insertions(+), 10395 deletions(-) diff --git a/.clang-format b/.clang-format index a6e968db..0704b184 100644 --- a/.clang-format +++ b/.clang-format @@ -7,7 +7,7 @@ AlignConsecutiveDeclarations: false AlignOperands: false AlignTrailingComments: false AllowShortBlocksOnASingleLine: false -AllowShortFunctionsOnASingleLine: None +AllowShortFunctionsOnASingleLine: All AllowShortIfStatementsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: false AlwaysBreakTemplateDeclarations: Yes @@ -31,8 +31,8 @@ BraceWrapping: SplitEmptyNamespace: false AfterObjCDeclaration: false BreakBeforeBraces: Custom -ColumnLimit: 200 -ContinuationIndentWidth: 0 +ColumnLimit: 140 +ContinuationIndentWidth: 4 Cpp11BracedListStyle: false IncludeBlocks: Regroup IncludeCategories: diff --git a/Dependencies.lua b/Dependencies.lua index 200d2634..f20af267 100644 --- a/Dependencies.lua +++ b/Dependencies.lua @@ -60,8 +60,8 @@ if (os.target() == "windows") then StaticLibrary["spirv_cross_glsl_release"] = "%{StaticLibraryDir.vulkan}/spirv-cross-glsl.lib" StaticLibrary["vulkan"] = "%{StaticLibraryDir.vulkan}/vulkan-1.lib" StaticLibrary["winmm"] = "Winmm.lib" - StaticLibrary["winsock"] = "Ws2_32.lib" - StaticLibrary["winversion"] = "Version.lib" + StaticLibrary["winsock"] = "Ws2_32.lib" + StaticLibrary["winversion"] = "Version.lib" else StaticLibrary["glfw"] = "glfw3" StaticLibrary["shaderc"] = "shaderc_shared" diff --git a/EppoEditor/Source/EditorLayer.cpp b/EppoEditor/Source/EditorLayer.cpp index 1de09bc1..517618da 100644 --- a/EppoEditor/Source/EditorLayer.cpp +++ b/EppoEditor/Source/EditorLayer.cpp @@ -11,671 +11,671 @@ namespace Eppo { - static const std::string CONTENT_BROWSER_PANEL = "ContentBrowserPanel"; - static const std::string PROPERTY_PANEL = "PropertyPanel"; - static const std::string SCENE_HIERARCHY_PANEL = "SceneHierarchyPanel"; - - namespace - { - bool s_NewProjectPopup = false; - bool s_PreferencesPopup = false; - - void ReplaceToken(std::string& input, const char* token, const std::string& value) - { - size_t pos = 0; - while ((pos = input.find(token, pos)) != std::string::npos) - { - input.replace(pos, strlen(token), value); - pos += strlen(token); - } - } - } - - EditorLayer::EditorLayer() - : Layer("EditorLayer"), m_PanelManager(PanelManager::Get()) - {} - - void EditorLayer::OnAttach() - { - // Load resources - m_IconPlay = Image::Create(ImageSpecification("Resources/Textures/Icons/PlayButton.png")); - m_IconStop = Image::Create(ImageSpecification("Resources/Textures/Icons/StopButton.png")); - - // Setup UI panels - m_PanelManager.AddPanel(SCENE_HIERARCHY_PANEL, true, m_PanelManager); - m_PanelManager.AddPanel(PROPERTY_PANEL, true, m_PanelManager); - - m_PanelManager.SetSceneContext(m_EditorScene); - - // Open scene - OpenProject(); - - RenderSpecification renderSpec; - renderSpec.Width = 1600; - renderSpec.Height = 900; + static const std::string CONTENT_BROWSER_PANEL = "ContentBrowserPanel"; + static const std::string PROPERTY_PANEL = "PropertyPanel"; + static const std::string SCENE_HIERARCHY_PANEL = "SceneHierarchyPanel"; + + namespace + { + bool s_NewProjectPopup = false; + bool s_PreferencesPopup = false; + + void ReplaceToken(std::string& input, const char* token, const std::string& value) + { + size_t pos = 0; + while ((pos = input.find(token, pos)) != std::string::npos) + { + input.replace(pos, strlen(token), value); + pos += strlen(token); + } + } + } + + EditorLayer::EditorLayer() + : Layer("EditorLayer"), m_PanelManager(PanelManager::Get()) + {} + + void EditorLayer::OnAttach() + { + // Load resources + m_IconPlay = Image::Create(ImageSpecification("Resources/Textures/Icons/PlayButton.png")); + m_IconStop = Image::Create(ImageSpecification("Resources/Textures/Icons/StopButton.png")); + + // Setup UI panels + m_PanelManager.AddPanel(SCENE_HIERARCHY_PANEL, true, m_PanelManager); + m_PanelManager.AddPanel(PROPERTY_PANEL, true, m_PanelManager); + + m_PanelManager.SetSceneContext(m_EditorScene); + + // Open scene + OpenProject(); + + RenderSpecification renderSpec; + renderSpec.Width = 1600; + renderSpec.Height = 900; #ifdef EPPO_DEBUG - renderSpec.DebugRendering = true; + renderSpec.DebugRendering = true; #endif - m_ViewportRenderer = SceneRenderer::Create(m_EditorScene, renderSpec); - } - - void EditorLayer::OnDetach() - { - CloseProject(); - - m_PanelManager.Shutdown(); - - m_IconPlay = nullptr; - m_IconStop = nullptr; - - m_ViewportRenderer = nullptr; - } - - void EditorLayer::Update(float timestep) - { - if (m_ViewportWidth > 0 && m_ViewportHeight > 0) - { - m_EditorCamera.SetViewportSize(glm::vec2(m_ViewportWidth, m_ViewportHeight)); - m_ViewportRenderer->Resize(m_ViewportWidth, m_ViewportHeight); - m_EditorScene->SetViewportSize(m_ViewportWidth, m_ViewportHeight); - m_ActiveScene->SetViewportSize(m_ViewportWidth, m_ViewportHeight); - } - - switch (m_SceneState) - { - case SceneState::Edit: - { - if (m_ViewportFocused) - m_EditorCamera.OnUpdate(timestep); - break; - } - - case SceneState::Play: - { - m_ActiveScene->OnUpdateRuntime(timestep); - break; - } - } - } - - void EditorLayer::Render() - { - if (!Project::GetActive()) - return; - - switch (m_SceneState) - { - case SceneState::Edit: - { - m_ActiveScene->OnRenderEditor(m_ViewportRenderer, m_EditorCamera); - break; - } - - case SceneState::Play: - { - m_ActiveScene->OnRenderRuntime(m_ViewportRenderer); - break; - } - } - } - - void EditorLayer::RenderGui() - { - // ImGui docking example - static bool dockspaceOpen = true; - static bool optFullscreenPersistence = true; - const bool optFullscreen = optFullscreenPersistence; - static ImGuiDockNodeFlags dockspaceFlags = ImGuiDockNodeFlags_None; - - // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into, - // because it would be confusing to have two docking targets within each others. - ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking; - if (optFullscreen) - { - const ImGuiViewport* viewport = ImGui::GetMainViewport(); - ImGui::SetNextWindowPos(viewport->Pos); - ImGui::SetNextWindowSize(viewport->Size); - ImGui::SetNextWindowViewport(viewport->ID); - ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); - window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; - window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; - } - - // When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background - // and handle the pass-thru hole, so we ask Begin() to not render a background. - if (dockspaceFlags & ImGuiDockNodeFlags_PassthruCentralNode) - window_flags |= ImGuiWindowFlags_NoBackground; - - // Important: note that we proceed even if Begin() returns false (aka window is collapsed). - // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive, - // all active windows docked into it will lose their parent and become undocked. - // We cannot preserve the docking relationship between an active window and an inactive docking, otherwise - // any change of dockspace/settings would lead to windows being stuck in limbo and never being visible. - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); - ImGui::Begin("DockSpace", &dockspaceOpen, window_flags); - ImGui::PopStyleVar(); // ImGuiStyleVar_WindowPadding - - if (optFullscreen) - ImGui::PopStyleVar(2); // ImGuiStyleVar_WindowBorderSize, ImGuiStyleVar_WindowRounding - - // Submit the DockSpace - const ImGuiIO& io = ImGui::GetIO(); - ImGuiStyle& style = ImGui::GetStyle(); - const float minWinSizeX = style.WindowMinSize.x; - style.WindowMinSize.x = 370.0f; - if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) - { - const ImGuiID dockspace_id = ImGui::GetID("MyDockSpace"); - ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspaceFlags); - } - - style.WindowMinSize.x = minWinSizeX; - - // Menubar - if (ImGui::BeginMenuBar()) - { - if (ImGui::BeginMenu("File")) - { - if (ImGui::MenuItem("New Project")) - s_NewProjectPopup = true; - - if (ImGui::MenuItem("Save Project", "CTRL+S")) - SaveProject(); - - if (ImGui::MenuItem("Open Project", "CTRL+O")) - OpenProject(); - - if (ImGui::MenuItem("New Scene")) - NewScene(); - - ImGui::Separator(); - - if (ImGui::MenuItem("Import asset")) - ImportAsset(); - - if (ImGui::MenuItem("Project settings")) - s_PreferencesPopup = true; - - if (ImGui::MenuItem("Exit")) - Application::Get().Close(); - - ImGui::EndMenu(); - } - - if (ImGui::BeginMenu("Testing")) - { - if (ImGui::MenuItem("Serialize asset registry")) - Project::GetActive()->GetAssetManagerEditor()->SerializeAssetRegistry(); - - ImGui::EndMenu(); - } - - ImGui::EndMenuBar(); - } - - // Popups - if (s_NewProjectPopup) - { - constexpr ImGuiPopupFlags flags = ImGuiPopupFlags_NoOpenOverExistingPopup; - ImGui::OpenPopup("New Project", flags); - s_NewProjectPopup = false; - } - - if (s_PreferencesPopup) - { - constexpr ImGuiPopupFlags flags = ImGuiPopupFlags_NoOpenOverExistingPopup; - ImGui::OpenPopup("Project settings", flags); - s_PreferencesPopup = false; - } - - // Viewport - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0 )); - ImGui::Begin("Viewport"); - - m_ViewportFocused = ImGui::IsWindowFocused(); - m_ViewportHovered = ImGui::IsWindowHovered(); - Application::Get().GetImGuiLayer()->BlockEvents(!m_ViewportHovered); - - const ImVec2 viewportSize = ImGui::GetContentRegionAvail(); - m_ViewportWidth = static_cast(viewportSize.x); - m_ViewportHeight = static_cast(viewportSize.y); - - UI::Image(m_ViewportRenderer->GetFinalImage(), ImVec2(static_cast(m_ViewportWidth), static_cast(m_ViewportHeight)), ImVec2(0, 1), ImVec2(1, 0)); - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("SCENE_ASSET")) - { - const auto handle = payload->Data; - OpenScene(*static_cast(handle)); - } - ImGui::EndDragDropTarget(); - } - - ImGui::End(); // Viewport - ImGui::PopStyleVar(); - - // Panels - m_PanelManager.RenderGui(); - - // Performance - m_ViewportRenderer->RenderGui(); - - UI_File_NewProject(); - UI_File_Preferences(); - UI_Toolbar(); - - ImGui::End(); // DockSpace - } - - void EditorLayer::OnEvent(Event& e) - { - if (m_SceneState == SceneState::Edit) - m_EditorCamera.OnEvent(e); - - EventDispatcher dispatcher(e); - - dispatcher.Dispatch(BIND_EVENT_FN(EditorLayer::OnKeyPressed)); - } - - bool EditorLayer::OnKeyPressed(const KeyPressedEvent& e) - { - if (e.IsRepeat()) - return false; - - const bool alt = Input::IsKeyPressed(Key::LeftAlt) || Input::IsKeyPressed(Key::RightAlt); - const bool control = Input::IsKeyPressed(Key::LeftControl) || Input::IsKeyPressed(Key::RightControl); - const bool shift = Input::IsKeyPressed(Key::LeftShift) || Input::IsKeyPressed(Key::RightShift); - - switch (e.GetKeyCode()) - { - case Key::O: - { - if (control) - OpenProject(); - break; - } - - case Key::S: - { - if (control) - SaveProject(); - break; - } - } - - return false; - } - - void EditorLayer::OnScenePlay() - { - if (!m_EditorScene) - return; - - m_SceneState = SceneState::Play; - m_ActiveScene = Scene::Copy(m_EditorScene); - - ScriptEngine::SetSceneContext(m_ActiveScene); - m_PanelManager.SetSceneContext(m_ActiveScene); - - m_ActiveScene->OnRuntimeStart(); - } - - void EditorLayer::OnSceneStop() - { - if (!m_ActiveScene) - return; - - m_SceneState = SceneState::Edit; - - m_ActiveScene->OnRuntimeStop(); - m_ActiveScene = m_EditorScene; - - ScriptEngine::SetSceneContext(m_EditorScene); - m_PanelManager.SetSceneContext(m_ActiveScene); - } - - void EditorLayer::CloseProject() - { - SaveProject(); - - m_PanelManager.SetSceneContext(nullptr); - ScriptEngine::SetSceneContext(nullptr); - - if (Project::GetActive()) - Project::SetActive(nullptr); - - m_EditorScene = nullptr; - m_ActiveScene = nullptr; - } - - void EditorLayer::NewProject(const std::string& name) - { - // Create project directory - std::filesystem::path projectPath = Filesystem::GetAppRootDirectory() / "Projects" / name; - Filesystem::CreateDirectory(projectPath); - - // Copy new project template - Filesystem::Copy("Resources/Templates/NewProject", projectPath); - - // Create directories - Filesystem::CreateDirectory(projectPath / "Assets" / "Scripts" / "Source"); - Filesystem::CreateDirectory(projectPath / "Assets" / "Meshes"); - Filesystem::CreateDirectory(projectPath / "Assets" / "Scenes"); - Filesystem::CreateDirectory(projectPath / "Assets" / "Textures"); - - { - std::ifstream in(projectPath / "project.epproj"); - std::stringstream ss; - ss << in.rdbuf(); - in.close(); - - std::string inputStr = ss.str(); - ReplaceToken(inputStr, "$PROJECT_NAME$", name); - - std::ofstream out(projectPath / "project.epproj"); - out << inputStr; - out.close(); - - Filesystem::Rename(projectPath, "project.epproj", name + ".epproj"); - } - - { - Filesystem::Move(projectPath / "premake5.lua", projectPath / "Assets" / "Scripts" / "premake5.lua"); - - std::ifstream in(projectPath / "Assets" / "Scripts" / "premake5.lua"); - std::stringstream ss; - ss << in.rdbuf(); - in.close(); - - std::string inputStr = ss.str(); - ReplaceToken(inputStr, "$PROJECT_NAME$", name); - - std::ofstream out(projectPath / "Assets" / "Scripts" / "premake5.lua"); - out << inputStr; - out.close(); - } - - Filesystem::Move(projectPath / "Win-GenerateProjects.bat", projectPath / "Assets" / "Scripts" / "Win-GenerateProjects.bat"); - - // Create hello world script - Filesystem::Copy("Resources/Templates/Scripts/Main.cs", projectPath / "Assets" / "Scripts" / "Source"); - - { - std::ifstream in(projectPath / "Assets" / "Scripts" / "Source" / "Main.cs"); - std::stringstream ss; - ss << in.rdbuf(); - in.close(); - - std::string inputStr = ss.str(); - ReplaceToken(inputStr, "$PROJECT_NAME$", name); - - std::ofstream out(projectPath / "Assets" / "Scripts" / "Source" / "Main.cs"); - out << inputStr; - out.close(); - } - - // Run premake - std::filesystem::path batchFile = projectPath / "Assets" / "Scripts" / "Win-GenerateProjects.bat"; - - // todo: not working - // system(batchFile.string().c_str()); - - // Open project - OpenProject(projectPath / std::filesystem::path(name + ".epproj")); - } - - bool EditorLayer::OpenProject() - { - const std::filesystem::path filePath = FileDialog::OpenFile("EppoEngine Project (*.epproj)\0*.epproj\0", Project::GetProjectsDirectory()); - - if (filePath.empty()) - { - if (Project::GetActive()) - return false; - else - { - s_NewProjectPopup = true; - return true; - } - } - - OpenProject(filePath); - - return true; - } - - void EditorLayer::OpenProject(const std::filesystem::path& filepath) - { - if (filepath.extension().string() != ".epproj") - { - EPPO_ERROR("Could not load '{}' because it is not a project file!", filepath.string()); - return; - } - - if (Project::GetActive()) - CloseProject(); - - if (Project::Open(filepath)) - { - const auto& projSpec = Project::GetActive()->GetSpecification(); - - const std::filesystem::path scriptPath = Project::GetAssetsDirectory() / "Scripts" / "Binaries" / std::filesystem::path(projSpec.Name + ".dll"); - ScriptEngine::LoadAppAssembly(scriptPath); - - if (!projSpec.StartScene) - NewScene(); - else - OpenScene(projSpec.StartScene); - - m_PanelManager.AddPanel(CONTENT_BROWSER_PANEL, true, m_PanelManager); - Application::Get().GetWindow().SetWindowTitle("EppoEngine Editor - " + projSpec.Name); - } - } - - void EditorLayer::SaveProject() - { + m_ViewportRenderer = SceneRenderer::Create(m_EditorScene, renderSpec); + } + + void EditorLayer::OnDetach() + { + CloseProject(); + + m_PanelManager.Shutdown(); + + m_IconPlay = nullptr; + m_IconStop = nullptr; + + m_ViewportRenderer = nullptr; + } + + void EditorLayer::Update(float timestep) + { + if (m_ViewportWidth > 0 && m_ViewportHeight > 0) + { + m_EditorCamera.SetViewportSize(glm::vec2(m_ViewportWidth, m_ViewportHeight)); + m_ViewportRenderer->Resize(m_ViewportWidth, m_ViewportHeight); + m_EditorScene->SetViewportSize(m_ViewportWidth, m_ViewportHeight); + m_ActiveScene->SetViewportSize(m_ViewportWidth, m_ViewportHeight); + } + + switch (m_SceneState) + { + case SceneState::Edit: + { + if (m_ViewportFocused) + m_EditorCamera.OnUpdate(timestep); + break; + } + + case SceneState::Play: + { + m_ActiveScene->OnUpdateRuntime(timestep); + break; + } + } + } + + void EditorLayer::Render() + { + if (!Project::GetActive()) + return; + + switch (m_SceneState) + { + case SceneState::Edit: + { + m_ActiveScene->OnRenderEditor(m_ViewportRenderer, m_EditorCamera); + break; + } + + case SceneState::Play: + { + m_ActiveScene->OnRenderRuntime(m_ViewportRenderer); + break; + } + } + } + + void EditorLayer::RenderGui() + { + // ImGui docking example + static bool dockspaceOpen = true; + static bool optFullscreenPersistence = true; + const bool optFullscreen = optFullscreenPersistence; + static ImGuiDockNodeFlags dockspaceFlags = ImGuiDockNodeFlags_None; + + // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into, + // because it would be confusing to have two docking targets within each others. + ImGuiWindowFlags window_flags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking; + if (optFullscreen) + { + const ImGuiViewport* viewport = ImGui::GetMainViewport(); + ImGui::SetNextWindowPos(viewport->Pos); + ImGui::SetNextWindowSize(viewport->Size); + ImGui::SetNextWindowViewport(viewport->ID); + ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); + window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; + window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; + } + + // When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background + // and handle the pass-thru hole, so we ask Begin() to not render a background. + if (dockspaceFlags & ImGuiDockNodeFlags_PassthruCentralNode) + window_flags |= ImGuiWindowFlags_NoBackground; + + // Important: note that we proceed even if Begin() returns false (aka window is collapsed). + // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive, + // all active windows docked into it will lose their parent and become undocked. + // We cannot preserve the docking relationship between an active window and an inactive docking, otherwise + // any change of dockspace/settings would lead to windows being stuck in limbo and never being visible. + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); + ImGui::Begin("DockSpace", &dockspaceOpen, window_flags); + ImGui::PopStyleVar(); // ImGuiStyleVar_WindowPadding + + if (optFullscreen) + ImGui::PopStyleVar(2); // ImGuiStyleVar_WindowBorderSize, ImGuiStyleVar_WindowRounding + + // Submit the DockSpace + const ImGuiIO& io = ImGui::GetIO(); + ImGuiStyle& style = ImGui::GetStyle(); + const float minWinSizeX = style.WindowMinSize.x; + style.WindowMinSize.x = 370.0f; + if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) + { + const ImGuiID dockspace_id = ImGui::GetID("MyDockSpace"); + ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspaceFlags); + } + + style.WindowMinSize.x = minWinSizeX; + + // Menubar + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("File")) + { + if (ImGui::MenuItem("New Project")) + s_NewProjectPopup = true; + + if (ImGui::MenuItem("Save Project", "CTRL+S")) + SaveProject(); + + if (ImGui::MenuItem("Open Project", "CTRL+O")) + OpenProject(); + + if (ImGui::MenuItem("New Scene")) + NewScene(); + + ImGui::Separator(); + + if (ImGui::MenuItem("Import asset")) + ImportAsset(); + + if (ImGui::MenuItem("Project settings")) + s_PreferencesPopup = true; + + if (ImGui::MenuItem("Exit")) + Application::Get().Close(); + + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu("Testing")) + { + if (ImGui::MenuItem("Serialize asset registry")) + Project::GetActive()->GetAssetManagerEditor()->SerializeAssetRegistry(); + + ImGui::EndMenu(); + } + + ImGui::EndMenuBar(); + } + + // Popups + if (s_NewProjectPopup) + { + constexpr ImGuiPopupFlags flags = ImGuiPopupFlags_NoOpenOverExistingPopup; + ImGui::OpenPopup("New Project", flags); + s_NewProjectPopup = false; + } + + if (s_PreferencesPopup) + { + constexpr ImGuiPopupFlags flags = ImGuiPopupFlags_NoOpenOverExistingPopup; + ImGui::OpenPopup("Project settings", flags); + s_PreferencesPopup = false; + } + + // Viewport + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0 )); + ImGui::Begin("Viewport"); + + m_ViewportFocused = ImGui::IsWindowFocused(); + m_ViewportHovered = ImGui::IsWindowHovered(); + Application::Get().GetImGuiLayer()->BlockEvents(!m_ViewportHovered); + + const ImVec2 viewportSize = ImGui::GetContentRegionAvail(); + m_ViewportWidth = static_cast(viewportSize.x); + m_ViewportHeight = static_cast(viewportSize.y); + + UI::Image(m_ViewportRenderer->GetFinalImage(), ImVec2(static_cast(m_ViewportWidth), static_cast(m_ViewportHeight)), ImVec2(0, 1), ImVec2(1, 0)); + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("SCENE_ASSET")) + { + const auto handle = payload->Data; + OpenScene(*static_cast(handle)); + } + ImGui::EndDragDropTarget(); + } + + ImGui::End(); // Viewport + ImGui::PopStyleVar(); + + // Panels + m_PanelManager.RenderGui(); + + // Performance + m_ViewportRenderer->RenderGui(); + + UI_File_NewProject(); + UI_File_Preferences(); + UI_Toolbar(); + + ImGui::End(); // DockSpace + } + + void EditorLayer::OnEvent(Event& e) + { + if (m_SceneState == SceneState::Edit) + m_EditorCamera.OnEvent(e); + + EventDispatcher dispatcher(e); + + dispatcher.Dispatch(BIND_EVENT_FN(EditorLayer::OnKeyPressed)); + } + + bool EditorLayer::OnKeyPressed(const KeyPressedEvent& e) + { + if (e.IsRepeat()) + return false; + + const bool alt = Input::IsKeyPressed(Key::LeftAlt) || Input::IsKeyPressed(Key::RightAlt); + const bool control = Input::IsKeyPressed(Key::LeftControl) || Input::IsKeyPressed(Key::RightControl); + const bool shift = Input::IsKeyPressed(Key::LeftShift) || Input::IsKeyPressed(Key::RightShift); + + switch (e.GetKeyCode()) + { + case Key::O: + { + if (control) + OpenProject(); + break; + } + + case Key::S: + { + if (control) + SaveProject(); + break; + } + } + + return false; + } + + void EditorLayer::OnScenePlay() + { + if (!m_EditorScene) + return; + + m_SceneState = SceneState::Play; + m_ActiveScene = Scene::Copy(m_EditorScene); + + ScriptEngine::SetSceneContext(m_ActiveScene); + m_PanelManager.SetSceneContext(m_ActiveScene); + + m_ActiveScene->OnRuntimeStart(); + } + + void EditorLayer::OnSceneStop() + { + if (!m_ActiveScene) + return; + + m_SceneState = SceneState::Edit; + + m_ActiveScene->OnRuntimeStop(); + m_ActiveScene = m_EditorScene; + + ScriptEngine::SetSceneContext(m_EditorScene); + m_PanelManager.SetSceneContext(m_ActiveScene); + } + + void EditorLayer::CloseProject() + { + SaveProject(); + + m_PanelManager.SetSceneContext(nullptr); + ScriptEngine::SetSceneContext(nullptr); + + if (Project::GetActive()) + Project::SetActive(nullptr); + + m_EditorScene = nullptr; + m_ActiveScene = nullptr; + } + + void EditorLayer::NewProject(const std::string& name) + { + // Create project directory + std::filesystem::path projectPath = Filesystem::GetAppRootDirectory() / "Projects" / name; + Filesystem::CreateDirectory(projectPath); + + // Copy new project template + Filesystem::Copy("Resources/Templates/NewProject", projectPath); + + // Create directories + Filesystem::CreateDirectory(projectPath / "Assets" / "Scripts" / "Source"); + Filesystem::CreateDirectory(projectPath / "Assets" / "Meshes"); + Filesystem::CreateDirectory(projectPath / "Assets" / "Scenes"); + Filesystem::CreateDirectory(projectPath / "Assets" / "Textures"); + + { + std::ifstream in(projectPath / "project.epproj"); + std::stringstream ss; + ss << in.rdbuf(); + in.close(); + + std::string inputStr = ss.str(); + ReplaceToken(inputStr, "$PROJECT_NAME$", name); + + std::ofstream out(projectPath / "project.epproj"); + out << inputStr; + out.close(); + + Filesystem::Rename(projectPath, "project.epproj", name + ".epproj"); + } + + { + Filesystem::Move(projectPath / "premake5.lua", projectPath / "Assets" / "Scripts" / "premake5.lua"); + + std::ifstream in(projectPath / "Assets" / "Scripts" / "premake5.lua"); + std::stringstream ss; + ss << in.rdbuf(); + in.close(); + + std::string inputStr = ss.str(); + ReplaceToken(inputStr, "$PROJECT_NAME$", name); + + std::ofstream out(projectPath / "Assets" / "Scripts" / "premake5.lua"); + out << inputStr; + out.close(); + } + + Filesystem::Move(projectPath / "Win-GenerateProjects.bat", projectPath / "Assets" / "Scripts" / "Win-GenerateProjects.bat"); + + // Create hello world script + Filesystem::Copy("Resources/Templates/Scripts/Main.cs", projectPath / "Assets" / "Scripts" / "Source"); + + { + std::ifstream in(projectPath / "Assets" / "Scripts" / "Source" / "Main.cs"); + std::stringstream ss; + ss << in.rdbuf(); + in.close(); + + std::string inputStr = ss.str(); + ReplaceToken(inputStr, "$PROJECT_NAME$", name); + + std::ofstream out(projectPath / "Assets" / "Scripts" / "Source" / "Main.cs"); + out << inputStr; + out.close(); + } + + // Run premake + std::filesystem::path batchFile = projectPath / "Assets" / "Scripts" / "Win-GenerateProjects.bat"; + + // todo: not working + // system(batchFile.string().c_str()); + + // Open project + OpenProject(projectPath / std::filesystem::path(name + ".epproj")); + } + + bool EditorLayer::OpenProject() + { + const std::filesystem::path filePath = FileDialog::OpenFile("EppoEngine Project (*.epproj)\0*.epproj\0", Project::GetProjectsDirectory()); + + if (filePath.empty()) + { + if (Project::GetActive()) + return false; + else + { + s_NewProjectPopup = true; + return true; + } + } + + OpenProject(filePath); + + return true; + } + + void EditorLayer::OpenProject(const std::filesystem::path& filepath) + { + if (filepath.extension().string() != ".epproj") + { + EPPO_ERROR("Could not load '{}' because it is not a project file!", filepath.string()); + return; + } + + if (Project::GetActive()) + CloseProject(); + + if (Project::Open(filepath)) + { + const auto& projSpec = Project::GetActive()->GetSpecification(); + + const std::filesystem::path scriptPath = Project::GetAssetsDirectory() / "Scripts" / "Binaries" / std::filesystem::path(projSpec.Name + ".dll"); + ScriptEngine::LoadAppAssembly(scriptPath); + + if (!projSpec.StartScene) + NewScene(); + else + OpenScene(projSpec.StartScene); + + m_PanelManager.AddPanel(CONTENT_BROWSER_PANEL, true, m_PanelManager); + Application::Get().GetWindow().SetWindowTitle("EppoEngine Editor - " + projSpec.Name); + } + } + + void EditorLayer::SaveProject() + { EPPO_ASSERT(Project::GetActive()); - SaveScene(); - - Project::SaveActive(); - } - - void EditorLayer::NewScene() - { - // TODO: Check for changes. Maybe using a list of changes considering a undo feature - m_EditorScene = CreateRef(); - m_ActiveScene = m_EditorScene; - m_ActiveScenePath = std::filesystem::path(); - - m_PanelManager.SetSceneContext(m_ActiveScene); - } - - void EditorLayer::OpenScene(const std::filesystem::path& filepath) - { - if (filepath.extension().string() != ".epscene") - { - EPPO_ERROR("Could not load '{}' because it is not a scene file!", filepath.string()); - return; - } - - const auto newScene = CreateRef(); - if (const SceneSerializer serializer(newScene); - serializer.Deserialize(filepath)) - { - m_EditorScene = newScene; - m_ActiveScene = m_EditorScene; - m_ActiveScenePath = filepath; - - m_PanelManager.SetSceneContext(m_EditorScene); - } - } - - void EditorLayer::OpenScene(const AssetHandle handle) - { + SaveScene(); + + Project::SaveActive(); + } + + void EditorLayer::NewScene() + { + // TODO: Check for changes. Maybe using a list of changes considering a undo feature + m_EditorScene = CreateRef(); + m_ActiveScene = m_EditorScene; + m_ActiveScenePath = std::filesystem::path(); + + m_PanelManager.SetSceneContext(m_ActiveScene); + } + + void EditorLayer::OpenScene(const std::filesystem::path& filepath) + { + if (filepath.extension().string() != ".epscene") + { + EPPO_ERROR("Could not load '{}' because it is not a scene file!", filepath.string()); + return; + } + + const auto newScene = CreateRef(); + if (const SceneSerializer serializer(newScene); + serializer.Deserialize(filepath)) + { + m_EditorScene = newScene; + m_ActiveScene = m_EditorScene; + m_ActiveScenePath = filepath; + + m_PanelManager.SetSceneContext(m_EditorScene); + } + } + + void EditorLayer::OpenScene(const AssetHandle handle) + { EPPO_ASSERT(handle); - if (m_SceneState != SceneState::Edit) - OnSceneStop(); - - m_EditorScene = AssetManager::GetAsset(handle); - m_ActiveScene = m_EditorScene; - - m_ActiveScenePath = Project::GetActive()->GetAssetManagerEditor()->GetFilepath(handle); - - m_PanelManager.SetSceneContext(m_ActiveScene); - } - - void EditorLayer::SaveScene() - { - if (m_ActiveScenePath.empty()) - SaveSceneAs(); - else - AssetImporter::ExportScene(m_ActiveScene, m_ActiveScenePath); - } - - void EditorLayer::SaveSceneAs() - { - if (const std::filesystem::path filepath = FileDialog::SaveFile("EppoEngine Scene (*.epscene)\0*.epscene\0"); - !filepath.empty()) - { - m_ActiveScenePath = filepath; - AssetImporter::ExportScene(m_ActiveScene, m_ActiveScenePath); - } - } - - void EditorLayer::ImportAsset() - { - if (const std::filesystem::path filepath = FileDialog::OpenFile("Asset file (.epscene, .glb, .gltf, .jpeg, .jpg, .png)\0*.epscene;*.glb;*.gltf;*.jpeg;*.jpg;*.png\0\0", Project::GetAssetsDirectory()); - !filepath.empty()) - { - Project::GetActive()->GetAssetManagerEditor()->ImportAsset(filepath); - } - } - - void EditorLayer::UI_File_NewProject() - { - if (constexpr ImGuiWindowFlags flags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize; - ImGui::BeginPopupModal("New Project", nullptr, flags)) - { - static char nameBuffer[200]{}; - static bool projectExists = false; - - ImGui::Text("Project Name"); - ImGui::InputText("##ProjectName", nameBuffer, 200); - - const auto projectPath = std::string(nameBuffer); - const std::filesystem::path fullProjectPath = Filesystem::GetAppRootDirectory() / "Projects" / projectPath; - - projectExists = Filesystem::Exists(fullProjectPath); - - if (Filesystem::Exists(fullProjectPath) && !projectPath.empty()) - { - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.8f, 0.1f, 0.1f, 1.0f)); - ImGui::Text("Project name already exists"); - ImGui::PopStyleColor(); - } - else - { - ImGui::Text("Project path: \n%s", fullProjectPath.string().c_str()); - } - - ImGui::Dummy(ImVec2(50, 20)); - - if (ImGui::Button("Cancel", ImVec2(100, 30))) - ImGui::CloseCurrentPopup(); - - ImGui::SameLine(); - - if (projectExists) - ImGui::BeginDisabled(); - - if (ImGui::Button("Create", ImVec2(100, 30))) - { - NewProject(projectPath); - ImGui::CloseCurrentPopup(); - } - - if (projectExists) - ImGui::EndDisabled(); - - ImGui::EndPopup(); - } - } - - void EditorLayer::UI_File_Preferences() - { - if (constexpr ImGuiWindowFlags flags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize; - ImGui::BeginPopupModal("Project settings", nullptr, flags)) - { - auto& spec = Project::GetActive()->GetSpecification(); - - static std::string nameBuffer = std::string(200, ' ').replace(0, 200, spec.Name); - - ImGui::Text("Project Name"); - ImGui::InputText("##ProjectName", nameBuffer.data(), 200); - - ImGui::Text("Project Directory"); - ImGui::InputText("##ProjectDirectory", spec.ProjectDirectory.string().data(), spec.ProjectDirectory.string().length(), ImGuiInputTextFlags_ReadOnly); - - ImGui::Text("Start Scene"); - - const auto assetManager = Project::GetActive()->GetAssetManagerEditor(); - const auto& assetRegistry = assetManager->GetAssetRegistry(); - - const AssetHandle startScene = spec.StartScene; - - if (const auto& startSceneMetadata = assetRegistry.at(startScene); - ImGui::BeginCombo("##StartScene", startSceneMetadata.GetName().c_str())) - { - for (const auto& [handle, metadata] : assetRegistry) - { - if (metadata.Type != AssetType::Scene) - continue; - - const bool isSelected = startSceneMetadata.GetName() == metadata.GetName(); - - if (ImGui::Selectable(metadata.GetName().c_str(), isSelected)) - spec.StartScene = metadata.Handle; - - if (isSelected) - ImGui::SetItemDefaultFocus(); - } - ImGui::EndCombo(); - } - - if (ImGui::Button("OK", ImVec2(100, 30))) - ImGui::CloseCurrentPopup(); - - ImGui::EndPopup(); - } - } - - void EditorLayer::UI_Toolbar() - { - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 2)); - ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2(0, 0)); - ImGui::Begin("Scene Control", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); - - const float buttonSize = ImGui::GetWindowHeight() - 4.0f; - - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); - ImGui::SetCursorPosX((ImGui::GetWindowContentRegionMax().x * 0.5f) - (buttonSize * 0.5f)); - - if (m_SceneState == SceneState::Edit) - { - if (UI::ImageButton("##Play", m_IconPlay, ImVec2(buttonSize, buttonSize))) - OnScenePlay(); - } - else if (m_SceneState == SceneState::Play) - { - if (UI::ImageButton("##Stop", m_IconStop, ImVec2(buttonSize, buttonSize))) - OnSceneStop(); - } - - ImGui::PopStyleVar(3); - ImGui::End(); - } + if (m_SceneState != SceneState::Edit) + OnSceneStop(); + + m_EditorScene = AssetManager::GetAsset(handle); + m_ActiveScene = m_EditorScene; + + m_ActiveScenePath = Project::GetActive()->GetAssetManagerEditor()->GetFilepath(handle); + + m_PanelManager.SetSceneContext(m_ActiveScene); + } + + void EditorLayer::SaveScene() + { + if (m_ActiveScenePath.empty()) + SaveSceneAs(); + else + AssetImporter::ExportScene(m_ActiveScene, m_ActiveScenePath); + } + + void EditorLayer::SaveSceneAs() + { + if (const std::filesystem::path filepath = FileDialog::SaveFile("EppoEngine Scene (*.epscene)\0*.epscene\0"); + !filepath.empty()) + { + m_ActiveScenePath = filepath; + AssetImporter::ExportScene(m_ActiveScene, m_ActiveScenePath); + } + } + + void EditorLayer::ImportAsset() + { + if (const std::filesystem::path filepath = FileDialog::OpenFile("Asset file (.epscene, .glb, .gltf, .jpeg, .jpg, .png)\0*.epscene;*.glb;*.gltf;*.jpeg;*.jpg;*.png\0\0", Project::GetAssetsDirectory()); + !filepath.empty()) + { + Project::GetActive()->GetAssetManagerEditor()->ImportAsset(filepath); + } + } + + void EditorLayer::UI_File_NewProject() + { + if (constexpr ImGuiWindowFlags flags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize; + ImGui::BeginPopupModal("New Project", nullptr, flags)) + { + static char nameBuffer[200]{}; + static bool projectExists = false; + + ImGui::Text("Project Name"); + ImGui::InputText("##ProjectName", nameBuffer, 200); + + const auto projectPath = std::string(nameBuffer); + const std::filesystem::path fullProjectPath = Filesystem::GetAppRootDirectory() / "Projects" / projectPath; + + projectExists = Filesystem::Exists(fullProjectPath); + + if (Filesystem::Exists(fullProjectPath) && !projectPath.empty()) + { + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.8f, 0.1f, 0.1f, 1.0f)); + ImGui::Text("Project name already exists"); + ImGui::PopStyleColor(); + } + else + { + ImGui::Text("Project path: \n%s", fullProjectPath.string().c_str()); + } + + ImGui::Dummy(ImVec2(50, 20)); + + if (ImGui::Button("Cancel", ImVec2(100, 30))) + ImGui::CloseCurrentPopup(); + + ImGui::SameLine(); + + if (projectExists) + ImGui::BeginDisabled(); + + if (ImGui::Button("Create", ImVec2(100, 30))) + { + NewProject(projectPath); + ImGui::CloseCurrentPopup(); + } + + if (projectExists) + ImGui::EndDisabled(); + + ImGui::EndPopup(); + } + } + + void EditorLayer::UI_File_Preferences() + { + if (constexpr ImGuiWindowFlags flags = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize; + ImGui::BeginPopupModal("Project settings", nullptr, flags)) + { + auto& spec = Project::GetActive()->GetSpecification(); + + static std::string nameBuffer = std::string(200, ' ').replace(0, 200, spec.Name); + + ImGui::Text("Project Name"); + ImGui::InputText("##ProjectName", nameBuffer.data(), 200); + + ImGui::Text("Project Directory"); + ImGui::InputText("##ProjectDirectory", spec.ProjectDirectory.string().data(), spec.ProjectDirectory.string().length(), ImGuiInputTextFlags_ReadOnly); + + ImGui::Text("Start Scene"); + + const auto assetManager = Project::GetActive()->GetAssetManagerEditor(); + const auto& assetRegistry = assetManager->GetAssetRegistry(); + + const AssetHandle startScene = spec.StartScene; + + if (const auto& startSceneMetadata = assetRegistry.at(startScene); + ImGui::BeginCombo("##StartScene", startSceneMetadata.GetName().c_str())) + { + for (const auto& [handle, metadata] : assetRegistry) + { + if (metadata.Type != AssetType::Scene) + continue; + + const bool isSelected = startSceneMetadata.GetName() == metadata.GetName(); + + if (ImGui::Selectable(metadata.GetName().c_str(), isSelected)) + spec.StartScene = metadata.Handle; + + if (isSelected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + + if (ImGui::Button("OK", ImVec2(100, 30))) + ImGui::CloseCurrentPopup(); + + ImGui::EndPopup(); + } + } + + void EditorLayer::UI_Toolbar() + { + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 2)); + ImGui::PushStyleVar(ImGuiStyleVar_ItemInnerSpacing, ImVec2(0, 0)); + ImGui::Begin("Scene Control", nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse); + + const float buttonSize = ImGui::GetWindowHeight() - 4.0f; + + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + ImGui::SetCursorPosX((ImGui::GetWindowContentRegionMax().x * 0.5f) - (buttonSize * 0.5f)); + + if (m_SceneState == SceneState::Edit) + { + if (UI::ImageButton("##Play", m_IconPlay, ImVec2(buttonSize, buttonSize))) + OnScenePlay(); + } + else if (m_SceneState == SceneState::Play) + { + if (UI::ImageButton("##Stop", m_IconStop, ImVec2(buttonSize, buttonSize))) + OnSceneStop(); + } + + ImGui::PopStyleVar(3); + ImGui::End(); + } } diff --git a/EppoEditor/Source/EditorLayer.h b/EppoEditor/Source/EditorLayer.h index 7154060d..26abb19e 100644 --- a/EppoEditor/Source/EditorLayer.h +++ b/EppoEditor/Source/EditorLayer.h @@ -6,72 +6,72 @@ namespace Eppo { - class EditorLayer : public Layer - { - public: - EditorLayer(); - ~EditorLayer() override = default; - - void OnAttach() override; - void OnDetach() override; - - void Update(float timestep) override; - void Render() override; - void RenderGui() override; + class EditorLayer : public Layer + { + public: + EditorLayer(); + ~EditorLayer() override = default; + + void OnAttach() override; + void OnDetach() override; + + void Update(float timestep) override; + void Render() override; + void RenderGui() override; - void OnEvent(Event& e) override; + void OnEvent(Event& e) override; - private: - bool OnKeyPressed(const KeyPressedEvent& e); + private: + bool OnKeyPressed(const KeyPressedEvent& e); - void OnScenePlay(); - void OnSceneStop(); + void OnScenePlay(); + void OnSceneStop(); - void CloseProject(); - void NewProject(const std::string& name); - bool OpenProject(); - void OpenProject(const std::filesystem::path& filepath); - void SaveProject(); + void CloseProject(); + void NewProject(const std::string& name); + bool OpenProject(); + void OpenProject(const std::filesystem::path& filepath); + void SaveProject(); - void NewScene(); - void OpenScene(AssetHandle handle); - void OpenScene(const std::filesystem::path& filepath); - void SaveScene(); - void SaveSceneAs(); + void NewScene(); + void OpenScene(AssetHandle handle); + void OpenScene(const std::filesystem::path& filepath); + void SaveScene(); + void SaveSceneAs(); - void ImportAsset(); + void ImportAsset(); - void UI_File_NewProject(); - void UI_File_Preferences(); - void UI_Toolbar(); + void UI_File_NewProject(); + void UI_File_Preferences(); + void UI_Toolbar(); - private: - // Scene - Ref m_ViewportRenderer; - Ref m_ActiveScene = CreateRef(); - Ref m_EditorScene = CreateRef(); - std::filesystem::path m_ActiveScenePath; - - // Editor - PanelManager& m_PanelManager; - EditorCamera m_EditorCamera = EditorCamera(glm::vec3(-10.0f, 1.0f, 0.0f), 0.0f, 0.0f); + private: + // Scene + Ref m_ViewportRenderer; + Ref m_ActiveScene = CreateRef(); + Ref m_EditorScene = CreateRef(); + std::filesystem::path m_ActiveScenePath; + + // Editor + PanelManager& m_PanelManager; + EditorCamera m_EditorCamera = EditorCamera(glm::vec3(-10.0f, 1.0f, 0.0f), 0.0f, 0.0f); - // Viewport - uint32_t m_ViewportWidth = 0; - uint32_t m_ViewportHeight = 0; - bool m_ViewportFocused = false; - bool m_ViewportHovered = false; + // Viewport + uint32_t m_ViewportWidth = 0; + uint32_t m_ViewportHeight = 0; + bool m_ViewportFocused = false; + bool m_ViewportHovered = false; - // Scene state - enum class SceneState : uint8_t - { - Edit, - Play - }; - SceneState m_SceneState = SceneState::Edit; + // Scene state + enum class SceneState : uint8_t + { + Edit, + Play + }; + SceneState m_SceneState = SceneState::Edit; - // Resources - Ref m_IconPlay; - Ref m_IconStop; - }; + // Resources + Ref m_IconPlay; + Ref m_IconStop; + }; } diff --git a/EppoEditor/Source/EppoEditor.cpp b/EppoEditor/Source/EppoEditor.cpp index 8eac3303..22873d64 100644 --- a/EppoEditor/Source/EppoEditor.cpp +++ b/EppoEditor/Source/EppoEditor.cpp @@ -5,24 +5,24 @@ namespace Eppo { - class Editor : public Application - { - public: - explicit Editor(const ApplicationSpecification& specification) - : Application(specification) - { - PushLayer(new EditorLayer()); - } - - ~Editor() = default; - }; - - Application* CreateApplication(const ApplicationCommandLineArgs args) - { - ApplicationSpecification spec; - spec.Name = "EppoEditor"; - spec.CommandLineArgs = args; - - return new Editor(spec); - } + class Editor : public Application + { + public: + explicit Editor(const ApplicationSpecification& specification) + : Application(specification) + { + PushLayer(new EditorLayer()); + } + + ~Editor() = default; + }; + + Application* CreateApplication(const ApplicationCommandLineArgs args) + { + ApplicationSpecification spec; + spec.Name = "EppoEditor"; + spec.CommandLineArgs = args; + + return new Editor(spec); + } } diff --git a/EppoEditor/Source/Panel/ContentBrowserPanel.cpp b/EppoEditor/Source/Panel/ContentBrowserPanel.cpp index 12051081..ca6099c7 100644 --- a/EppoEditor/Source/Panel/ContentBrowserPanel.cpp +++ b/EppoEditor/Source/Panel/ContentBrowserPanel.cpp @@ -2,77 +2,77 @@ namespace Eppo { - namespace Utils - { - static const char* GetImGuiPayloadTypeFromExtension(const std::filesystem::path& filepath) - { - if (filepath == ".glb") return "MESH_ASSET"; - if (filepath == ".gltf") return "MESH_ASSET"; - if (filepath == ".png") return "TEXTURE_ASSET"; - if (filepath == ".cs") return "SCRIPT_ASSET"; - - return "CONTENT_BROWSER_ITEM"; - } - } - - ContentBrowserPanel::ContentBrowserPanel(PanelManager& panelManager) - : Panel(panelManager) - { - - } - - void ContentBrowserPanel::RenderGui() - { - ScopedBegin scopedBegin("Content Browser Panel"); - - ImGui::BeginGroup(); - - const char* items[] = { "Meshes", "Scenes", "Scripts", "Textures" }; - static int currentItem = 0; - if (ImGui::BeginListBox("##Assets", ImVec2(100.0f, -FLT_MIN))) - { - for (int n = 0; n < IM_ARRAYSIZE(items); n++) - { - const bool isSelected = (currentItem == n); - if (ImGui::Selectable(items[n], isSelected)) - currentItem = n; - - if (isSelected) - ImGui::SetItemDefaultFocus(); - } - ImGui::EndListBox(); - } - - ImGui::EndGroup(); - ImGui::SameLine(); - - ImGui::BeginGroup(); - - const auto assetManager = Project::GetActive()->GetAssetManagerEditor(); - const auto& assetRegistry = assetManager->GetAssetRegistry(); - const AssetType currentAssetType = Utils::AssetTypeFromString(items[currentItem]); - - for (const auto& [handle, metadata] : assetRegistry) - { - if (currentAssetType != metadata.Type) - continue; - - Ref thumbnail = m_ThumbnailCache.GetOrCreateThumbnail(currentAssetType); - - ImGui::BeginGroup(); - - UI::ImageButton(metadata.GetName(), thumbnail, ImVec2(128.0f, 128.0f), ImVec2(0, 1), ImVec2(1, 0)); - if (ImGui::BeginDragDropSource()) - { - ImGui::SetDragDropPayload(Utils::AssetTypeToImGuiPayloadType(currentAssetType), &handle, sizeof(AssetHandle)); - ImGui::EndDragDropSource(); - } - - ImGui::TextDisabled(metadata.GetName().c_str()); - ImGui::EndGroup(); - ImGui::SameLine(); - } - - ImGui::EndGroup(); - } + namespace Utils + { + static const char* GetImGuiPayloadTypeFromExtension(const std::filesystem::path& filepath) + { + if (filepath == ".glb") return "MESH_ASSET"; + if (filepath == ".gltf") return "MESH_ASSET"; + if (filepath == ".png") return "TEXTURE_ASSET"; + if (filepath == ".cs") return "SCRIPT_ASSET"; + + return "CONTENT_BROWSER_ITEM"; + } + } + + ContentBrowserPanel::ContentBrowserPanel(PanelManager& panelManager) + : Panel(panelManager) + { + + } + + void ContentBrowserPanel::RenderGui() + { + ScopedBegin scopedBegin("Content Browser Panel"); + + ImGui::BeginGroup(); + + const char* items[] = { "Meshes", "Scenes", "Scripts", "Textures" }; + static int currentItem = 0; + if (ImGui::BeginListBox("##Assets", ImVec2(100.0f, -FLT_MIN))) + { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + const bool isSelected = (currentItem == n); + if (ImGui::Selectable(items[n], isSelected)) + currentItem = n; + + if (isSelected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndListBox(); + } + + ImGui::EndGroup(); + ImGui::SameLine(); + + ImGui::BeginGroup(); + + const auto assetManager = Project::GetActive()->GetAssetManagerEditor(); + const auto& assetRegistry = assetManager->GetAssetRegistry(); + const AssetType currentAssetType = Utils::AssetTypeFromString(items[currentItem]); + + for (const auto& [handle, metadata] : assetRegistry) + { + if (currentAssetType != metadata.Type) + continue; + + Ref thumbnail = m_ThumbnailCache.GetOrCreateThumbnail(currentAssetType); + + ImGui::BeginGroup(); + + UI::ImageButton(metadata.GetName(), thumbnail, ImVec2(128.0f, 128.0f), ImVec2(0, 1), ImVec2(1, 0)); + if (ImGui::BeginDragDropSource()) + { + ImGui::SetDragDropPayload(Utils::AssetTypeToImGuiPayloadType(currentAssetType), &handle, sizeof(AssetHandle)); + ImGui::EndDragDropSource(); + } + + ImGui::TextDisabled(metadata.GetName().c_str()); + ImGui::EndGroup(); + ImGui::SameLine(); + } + + ImGui::EndGroup(); + } } diff --git a/EppoEditor/Source/Panel/ContentBrowserPanel.h b/EppoEditor/Source/Panel/ContentBrowserPanel.h index dc4b3743..ae00c8fb 100644 --- a/EppoEditor/Source/Panel/ContentBrowserPanel.h +++ b/EppoEditor/Source/Panel/ContentBrowserPanel.h @@ -5,25 +5,25 @@ namespace Eppo { - class ContentBrowserPanel : public Panel - { - public: - explicit ContentBrowserPanel(PanelManager& panelManager); + class ContentBrowserPanel : public Panel + { + public: + explicit ContentBrowserPanel(PanelManager& panelManager); - void RenderGui() override; + void RenderGui() override; - private: - ThumbnailCache m_ThumbnailCache; + private: + ThumbnailCache m_ThumbnailCache; - struct FileTreeNode - { - std::string Name; - std::string Type; - size_t Size; - bool IsFolder = false; - bool IsOpen = false; - }; + struct FileTreeNode + { + std::string Name; + std::string Type; + size_t Size; + bool IsFolder = false; + bool IsOpen = false; + }; - std::vector m_FileTreeNodes; - }; + std::vector m_FileTreeNodes; + }; } diff --git a/EppoEditor/Source/Panel/Panel.cpp b/EppoEditor/Source/Panel/Panel.cpp index 3b2c5367..d798b0ea 100644 --- a/EppoEditor/Source/Panel/Panel.cpp +++ b/EppoEditor/Source/Panel/Panel.cpp @@ -4,27 +4,27 @@ namespace Eppo { - Panel::Panel(PanelManager& panelManager) - : m_PanelManager(panelManager) - {} + Panel::Panel(PanelManager& panelManager) + : m_PanelManager(panelManager) + {} - Ref Panel::GetSceneContext() const - { - return m_PanelManager.GetSceneContext(); - } + Ref Panel::GetSceneContext() const + { + return m_PanelManager.GetSceneContext(); + } - Entity Panel::GetSelectedEntity() const - { - return m_PanelManager.GetSelectedEntity(); - } + Entity Panel::GetSelectedEntity() const + { + return m_PanelManager.GetSelectedEntity(); + } - void Panel::SetSceneContext(const Ref& scene) const - { - m_PanelManager.SetSceneContext(scene); - } + void Panel::SetSceneContext(const Ref& scene) const + { + m_PanelManager.SetSceneContext(scene); + } - void Panel::SetSelectedEntity(const Entity entity) const - { - m_PanelManager.SetSelectedEntity(entity); - } + void Panel::SetSelectedEntity(const Entity entity) const + { + m_PanelManager.SetSelectedEntity(entity); + } } diff --git a/EppoEditor/Source/Panel/Panel.h b/EppoEditor/Source/Panel/Panel.h index f0cbe42f..7f957453 100644 --- a/EppoEditor/Source/Panel/Panel.h +++ b/EppoEditor/Source/Panel/Panel.h @@ -4,24 +4,24 @@ namespace Eppo { - class PanelManager; + class PanelManager; - class Panel - { - public: - explicit Panel(PanelManager& panelManager); - virtual ~Panel() = default; + class Panel + { + public: + explicit Panel(PanelManager& panelManager); + virtual ~Panel() = default; - virtual void RenderGui() = 0; + virtual void RenderGui() = 0; - protected: - [[nodiscard]] Ref GetSceneContext() const; - [[nodiscard]] Entity GetSelectedEntity() const; - - void SetSceneContext(const Ref& scene) const; - void SetSelectedEntity(Entity entity) const; + protected: + [[nodiscard]] Ref GetSceneContext() const; + [[nodiscard]] Entity GetSelectedEntity() const; + + void SetSceneContext(const Ref& scene) const; + void SetSelectedEntity(Entity entity) const; - protected: - PanelManager& m_PanelManager; - }; + protected: + PanelManager& m_PanelManager; + }; } diff --git a/EppoEditor/Source/Panel/PanelManager.cpp b/EppoEditor/Source/Panel/PanelManager.cpp index 6b28f77a..b8cf19eb 100644 --- a/EppoEditor/Source/Panel/PanelManager.cpp +++ b/EppoEditor/Source/Panel/PanelManager.cpp @@ -2,23 +2,23 @@ namespace Eppo { - void PanelManager::Shutdown() - { - m_PanelData.clear(); - } + void PanelManager::Shutdown() + { + m_PanelData.clear(); + } - void PanelManager::RenderGui() - { - for (const auto& [name, panelData] : m_PanelData) - { - if (panelData.IsOpen) - panelData.Panel->RenderGui(); - } - } + void PanelManager::RenderGui() + { + for (const auto& [name, panelData] : m_PanelData) + { + if (panelData.IsOpen) + panelData.Panel->RenderGui(); + } + } - PanelManager& PanelManager::Get() - { - static PanelManager p; - return p; - } + PanelManager& PanelManager::Get() + { + static PanelManager p; + return p; + } } diff --git a/EppoEditor/Source/Panel/PanelManager.h b/EppoEditor/Source/Panel/PanelManager.h index 1f91af35..c7d16bcc 100644 --- a/EppoEditor/Source/Panel/PanelManager.h +++ b/EppoEditor/Source/Panel/PanelManager.h @@ -6,67 +6,67 @@ namespace Eppo { - struct PanelData - { - Ref Panel; - bool IsOpen = false; - }; + struct PanelData + { + Ref Panel; + bool IsOpen = false; + }; - class PanelManager - { - public: - ~PanelManager() = default; + class PanelManager + { + public: + ~PanelManager() = default; - void Shutdown(); - void RenderGui(); + void Shutdown(); + void RenderGui(); - Ref GetSceneContext() { return m_SceneContext; } - [[nodiscard]] Entity GetSelectedEntity() const { return m_SelectedEntity; } + Ref GetSceneContext() { return m_SceneContext; } + [[nodiscard]] Entity GetSelectedEntity() const { return m_SelectedEntity; } - void SetSceneContext(const Ref& scene) { m_SceneContext = scene; } - void SetSelectedEntity(const Entity entity) { m_SelectedEntity = entity; } + void SetSceneContext(const Ref& scene) { m_SceneContext = scene; } + void SetSelectedEntity(const Entity entity) { m_SelectedEntity = entity; } - template - void AddPanel(const std::string& name, const bool isOpen, Args&&... args) - { - static_assert(std::is_base_of_v, "Class is not based on Panel!"); + template + void AddPanel(const std::string& name, const bool isOpen, Args&&... args) + { + static_assert(std::is_base_of_v, "Class is not based on Panel!"); - if (HasPanel(name)) - return; + if (HasPanel(name)) + return; - PanelData panelData; - panelData.Panel = CreateRef(std::forward(args)...); - panelData.IsOpen = isOpen; + PanelData panelData; + panelData.Panel = CreateRef(std::forward(args)...); + panelData.IsOpen = isOpen; - m_PanelData.insert({ name, panelData }); - } + m_PanelData.insert({ name, panelData }); + } - template - Ref GetPanel(const std::string& name) - { - static_assert(std::is_base_of_v, "Class is not based on Panel!"); + template + Ref GetPanel(const std::string& name) + { + static_assert(std::is_base_of_v, "Class is not based on Panel!"); - const auto it = m_PanelData.find(name); - if (it == m_PanelData.end()) - return nullptr; + const auto it = m_PanelData.find(name); + if (it == m_PanelData.end()) + return nullptr; - return it->second.Panel; // TODO: Might not work? dynamic cast to derived class - } + return it->second.Panel; // TODO: Might not work? dynamic cast to derived class + } - bool HasPanel(const std::string& name) const - { - return m_PanelData.contains(name); - } + bool HasPanel(const std::string& name) const + { + return m_PanelData.contains(name); + } - static PanelManager& Get(); + static PanelManager& Get(); - private: - PanelManager() = default; + private: + PanelManager() = default; - private: - std::unordered_map m_PanelData; + private: + std::unordered_map m_PanelData; - Ref m_SceneContext; - Entity m_SelectedEntity; - }; + Ref m_SceneContext; + Entity m_SelectedEntity; + }; } diff --git a/EppoEditor/Source/Panel/PropertyPanel.cpp b/EppoEditor/Source/Panel/PropertyPanel.cpp index 229ca77e..5fae4d3b 100644 --- a/EppoEditor/Source/Panel/PropertyPanel.cpp +++ b/EppoEditor/Source/Panel/PropertyPanel.cpp @@ -9,813 +9,813 @@ namespace Eppo { - namespace Utils - { - template - static std::string GetComponentString() - { - const std::string fullType = typeid(T).name(); - const size_t pos = fullType.find_last_of(':'); - const size_t stringSize = fullType.size() - (pos + 1); - - return fullType.substr(pos + 1, stringSize - 9); - } - } - - PropertyPanel::PropertyPanel(PanelManager& panelManager) - : Panel(panelManager) - {} - - void PropertyPanel::RenderGui() - { - ScopedBegin scopedBegin("Properties"); - - Entity entity = GetSelectedEntity(); - if (!entity) - return; - - DrawComponent(entity, [](auto& component) - { - std::string& tag = component.Tag; - - // ImGui wants a char*, we use std::string - // We could cast a c_str to char*, but we still could not write to it - char buffer[256]{ 0 }; - // Since ImGui accounts for the buffer size AND the null termination char, we can safely use strncpy. - std::strncpy(buffer, tag.c_str(), sizeof(buffer)); - - // Double quote prevents the label from showing - if (ImGui::InputText("##Tag", buffer, sizeof(buffer))) - tag = std::string(buffer); // TODO: Add support for empty labels --> Don't crash... - }); - - ImGui::SameLine(); - - // Add components - if (ImGui::Button("Add component")) - ImGui::OpenPopup("AddComponent"); - - if (ImGui::BeginPopup("AddComponent")) - { - DrawAddComponentEntry("Sprite"); - DrawAddComponentEntry("Mesh"); - DrawAddComponentEntry("Directional Light"); - DrawAddComponentEntry("Script"); - DrawAddComponentEntry("Rigid Body"); - DrawAddComponentEntry("Camera"); - DrawAddComponentEntry("Point Light"); - - ImGui::EndPopup(); - } - - DrawComponent(entity, [](auto& component) - { - if (ImGui::BeginTable("##", 4)) - { - ImGui::PushID("Translation"); - ImGui::TableNextColumn(); - ImGui::Text("Translation"); - - ImGui::TableNextColumn(); - if (ImGui::Button("X")) - component.Translation.x = 0.0f; - ImGui::SameLine(); - ImGui::DragFloat("##TranslationX", &component.Translation.x, 0.1f); - - ImGui::TableNextColumn(); - if (ImGui::Button("Y")) - component.Translation.y = 0.0f; - ImGui::SameLine(); - ImGui::DragFloat("##TranslationY", &component.Translation.y, 0.1f); - - ImGui::TableNextColumn(); - if (ImGui::Button("Z")) - component.Translation.z = 0.0f; - ImGui::SameLine(); - ImGui::DragFloat("##TranslationZ", &component.Translation.z, 0.1f); - - ImGui::TableNextRow(); - ImGui::PopID(); - - ImGui::PushID("Rotation"); - ImGui::TableNextColumn(); - ImGui::Text("Rotation"); - - ImGui::TableNextColumn(); - if (ImGui::Button("X")) - component.Rotation.x = 0.0f; - ImGui::SameLine(); - ImGui::DragFloat("##RotationX", &component.Rotation.x, 0.1f); - - ImGui::TableNextColumn(); - if (ImGui::Button("Y")) - component.Rotation.y = 0.0f; - ImGui::SameLine(); - ImGui::DragFloat("##RotationY", &component.Rotation.y, 0.1f); - - ImGui::TableNextColumn(); - if (ImGui::Button("Z")) - component.Rotation.z = 0.0f; - ImGui::SameLine(); - ImGui::DragFloat("##RotationZ", &component.Rotation.z, 0.1f); - - ImGui::TableNextRow(); - ImGui::PopID(); - - ImGui::PushID("Scale"); - ImGui::TableNextColumn(); - ImGui::Text("Scale"); - - ImGui::TableNextColumn(); - if (ImGui::Button("X")) - component.Scale.x = 0.0f; - ImGui::SameLine(); - ImGui::DragFloat("##ScaleX", &component.Scale.x, 0.1f); - - ImGui::TableNextColumn(); - if (ImGui::Button("Y")) - component.Scale.y = 0.0f; - ImGui::SameLine(); - ImGui::DragFloat("##ScaleY", &component.Scale.y, 0.1f); - - ImGui::TableNextColumn(); - if (ImGui::Button("Z")) - component.Scale.z = 0.0f; - ImGui::SameLine(); - ImGui::DragFloat("##ScaleZ", &component.Scale.z, 0.1f); - - ImGui::PopID(); - ImGui::EndTable(); - } - }); - - DrawComponent(entity, [](auto& component) - { - if (component.TextureHandle) - { - ImGui::TextDisabled(Project::GetActive()->GetAssetManagerEditor()->GetMetadata(component.TextureHandle).Filepath.string().c_str()); - ImGui::SameLine(); - if (ImGui::Button("X")) - component.TextureHandle = 0; - } else - { - ImGui::Button("Texture", ImVec2(100.0f, 0.0f)); - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("TEXTURE_ASSET")) - { - auto path = (const wchar_t*)payload->Data; - std::filesystem::path texturePath = path; - - //Ref texture = AssetManager::GetAsset(texturePath); - //component.TextureHandle = texture->Handle; - } - ImGui::EndDragDropTarget(); - } - } - - ImGui::ColorEdit4("Color", glm::value_ptr(component.Color)); - }); - - DrawComponent(entity, [](auto& component) - { - if (component.MeshHandle) - { - ImGui::TextDisabled(Project::GetActive()->GetAssetManagerEditor()->GetMetadata(component.MeshHandle).Filepath.string().c_str()); - ImGui::SameLine(); - if (ImGui::Button("X")) - component.MeshHandle = 0; - } else - { - ImGui::Button("Mesh", ImVec2(100.0f, 0.0f)); - if (ImGui::BeginDragDropTarget()) - { - if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MESH_ASSET")) - { - const auto handle = payload->Data; - component.MeshHandle = *static_cast(handle); - } - ImGui::EndDragDropTarget(); - } - } - }); - - DrawComponent(entity, [](auto& component) - { - if (ImGui::BeginTable("##", 4)) - { - ImGui::TableNextColumn(); - ImGui::Text("Direction"); - - ImGui::TableNextColumn(); - if (ImGui::Button("X")) - component.Direction.x = 0.0f; - ImGui::SameLine(); - ImGui::DragFloat("##DirectionX", &component.Direction.x, 0.1f); - - ImGui::TableNextColumn(); - if (ImGui::Button("Y")) - component.Direction.y = 0.0f; - ImGui::SameLine(); - ImGui::DragFloat("##DirectionY", &component.Direction.y, 0.1f); - - ImGui::TableNextColumn(); - if (ImGui::Button("Z")) - component.Direction.z = 0.0f; - ImGui::SameLine(); - ImGui::DragFloat("##DirectionZ", &component.Direction.z, 0.1f); - - ImGui::EndTable(); - } - - ImGui::ColorEdit4("Albedo Color", glm::value_ptr(component.AlbedoColor)); - ImGui::ColorEdit4("Ambient Color", glm::value_ptr(component.AmbientColor)); - ImGui::ColorEdit4("Specular Color", glm::value_ptr(component.SpecularColor)); - }, "Directional Light"); - - DrawComponent(entity, [entity, scene = GetSceneContext()](auto& component) mutable - { - std::string& name = component.ClassName; - - if (ImGui::BeginCombo("Class", name.c_str())) - { - for (const auto& [className, scriptClass] : ScriptEngine::GetEntityClasses()) - { - bool isSelected = className == name; - - if (ImGui::Selectable(className.c_str(), isSelected)) - name = className; - - if (isSelected) - ImGui::SetItemDefaultFocus(); - } - - ImGui::EndCombo(); - } - - UUID uuid = entity.GetUUID(); - - if (scene->IsRunning()) - { - if (Ref instance = ScriptEngine::GetEntityInstance(uuid)) - { - const auto& fields = instance->GetScriptClass()->GetFields(); - for (const auto& [name, field] : fields) - { - switch (field.Type) - { - case ScriptFieldType::Float: - { - float data = instance->GetFieldValue(name); - if (ImGui::InputFloat(name.c_str(), &data)) - instance->SetFieldValue(name, data); - break; - } - - case ScriptFieldType::Double: - { - double data = instance->GetFieldValue(name); - if (ImGui::InputDouble(name.c_str(), &data)) - instance->SetFieldValue(name, data); - break; - } - - case ScriptFieldType::Bool: - { - bool data = instance->GetFieldValue(name); - if (ImGui::Checkbox(name.c_str(), &data)) - instance->SetFieldValue(name, data); - break; - } - - case ScriptFieldType::Char: - { - int8_t data = instance->GetFieldValue(name); - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S8, &data)) - instance->SetFieldValue(name, data); - break; - } - - case ScriptFieldType::Int16: - { - int16_t data = instance->GetFieldValue(name); - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S16, &data)) - instance->SetFieldValue(name, data); - break; - } - - case ScriptFieldType::Int32: - { - int32_t data = instance->GetFieldValue(name); - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S32, &data)) - instance->SetFieldValue(name, data); - break; - } - - case ScriptFieldType::Int64: - { - int64_t data = instance->GetFieldValue(name); - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S64, &data)) - instance->SetFieldValue(name, data); - break; - } - - case ScriptFieldType::Byte: - { - uint8_t data = instance->GetFieldValue(name); - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U8, &data)) - instance->SetFieldValue(name, data); - break; - } - - case ScriptFieldType::UInt16: - { - uint16_t data = instance->GetFieldValue(name); - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U16, &data)) - instance->SetFieldValue(name, data); - break; - } - - case ScriptFieldType::UInt32: - { - uint32_t data = instance->GetFieldValue(name); - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U32, &data)) - instance->SetFieldValue(name, data); - break; - } - - case ScriptFieldType::UInt64: - { - uint64_t data = instance->GetFieldValue(name); - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U64, &data)) - instance->SetFieldValue(name, data); - break; - } - - case ScriptFieldType::Vector2: - { - glm::vec2 data = instance->GetFieldValue(name); - if (ImGui::InputFloat2(name.c_str(), glm::value_ptr(data))) - instance->SetFieldValue(name, data); - break; - } - - case ScriptFieldType::Vector3: - { - if (auto data = instance->GetFieldValue(name); - ImGui::InputFloat3(name.c_str(), glm::value_ptr(data))) - { - instance->SetFieldValue(name, data); - } - break; - } - - case ScriptFieldType::Vector4: - { - if (auto data = instance->GetFieldValue(name); - ImGui::InputFloat4(name.c_str(), glm::value_ptr(data))) - { - instance->SetFieldValue(name, data); - } - break; - } - } - } - } - } else - { - if (Ref entityClass = ScriptEngine::GetEntityClass(name)) - { - const auto& fields = entityClass->GetFields(); - auto& entityFields = ScriptEngine::GetScriptFieldMap(uuid); - - for (const auto& [name, field] : fields) - { - if (auto it = entityFields.find(name); - it != entityFields.end()) - { - ScriptFieldInstance& scriptField = it->second; - - switch (field.Type) - { - case ScriptFieldType::Float: - { - float data = scriptField.GetValue(); - if (ImGui::InputFloat(name.c_str(), &data)) - scriptField.SetValue(data); - break; - } - - case ScriptFieldType::Double: - { - double data = scriptField.GetValue(); - if (ImGui::InputDouble(name.c_str(), &data)) - scriptField.SetValue(data); - break; - } - - case ScriptFieldType::Bool: - { - bool data = scriptField.GetValue(); - if (ImGui::Checkbox(name.c_str(), &data)) - scriptField.SetValue(data); - break; - } - - case ScriptFieldType::Char: - { - int8_t data = scriptField.GetValue(); - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S8, &data)) - scriptField.SetValue(data); - break; - } - - case ScriptFieldType::Int16: - { - int16_t data = scriptField.GetValue(); - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S16, &data)) - scriptField.SetValue(data); - break; - } - - case ScriptFieldType::Int32: - { - int32_t data = scriptField.GetValue(); - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S32, &data)) - scriptField.SetValue(data); - break; - } - - case ScriptFieldType::Int64: - { - int64_t data = scriptField.GetValue(); - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S64, &data)) - scriptField.SetValue(data); - break; - } - - case ScriptFieldType::Byte: - { - uint8_t data = scriptField.GetValue(); - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U8, &data)) - scriptField.SetValue(data); - break; - } - - case ScriptFieldType::UInt16: - { - uint16_t data = scriptField.GetValue(); - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U16, &data)) - scriptField.SetValue(data); - break; - } - - case ScriptFieldType::UInt32: - { - uint32_t data = scriptField.GetValue(); - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U32, &data)) - scriptField.SetValue(data); - break; - } - - case ScriptFieldType::UInt64: - { - uint64_t data = scriptField.GetValue(); - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U64, &data)) - scriptField.SetValue(data); - break; - } - - case ScriptFieldType::Vector2: - { - if (auto data = scriptField.GetValue(); - ImGui::InputFloat2(name.c_str(), glm::value_ptr(data))) - { - scriptField.SetValue(data); - } - break; - } - - case ScriptFieldType::Vector3: - { - if (auto data = scriptField.GetValue(); - ImGui::InputFloat3(name.c_str(), glm::value_ptr(data))) - { - scriptField.SetValue(data); - } - break; - } - - case ScriptFieldType::Vector4: - { - if (auto data = scriptField.GetValue(); - ImGui::InputFloat4(name.c_str(), glm::value_ptr(data))) - { - scriptField.SetValue(data); - } - break; - } - } - } else - { - switch (field.Type) - { - case ScriptFieldType::Float: - { - float data = 0.0f; - if (ImGui::InputFloat(name.c_str(), &data)) - { - ScriptFieldInstance& scriptField = entityFields[name]; - scriptField.Field = field; - scriptField.SetValue(data); - } - break; - } - - case ScriptFieldType::Double: - { - double data = 0.0; - if (ImGui::InputDouble(name.c_str(), &data)) - { - ScriptFieldInstance& scriptField = entityFields[name]; - scriptField.Field = field; - scriptField.SetValue(data); - } - break; - } - - case ScriptFieldType::Bool: - { - bool data = false; - if (ImGui::Checkbox(name.c_str(), &data)) - { - ScriptFieldInstance& scriptField = entityFields[name]; - scriptField.Field = field; - scriptField.SetValue(data); - } - break; - } - - case ScriptFieldType::Char: - { - int8_t data = 0; - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S8, &data)) - { - ScriptFieldInstance& scriptField = entityFields[name]; - scriptField.Field = field; - scriptField.SetValue(data); - } - break; - } - - case ScriptFieldType::Int16: - { - int16_t data = 0; - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S16, &data)) - { - ScriptFieldInstance& scriptField = entityFields[name]; - scriptField.Field = field; - scriptField.SetValue(data); - } - break; - } - - case ScriptFieldType::Int32: - { - int32_t data = 0; - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S32, &data)) - { - ScriptFieldInstance& scriptField = entityFields[name]; - scriptField.Field = field; - scriptField.SetValue(data); - } - break; - } - - case ScriptFieldType::Int64: - { - int64_t data = 0; - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S64, &data)) - { - ScriptFieldInstance& scriptField = entityFields[name]; - scriptField.Field = field; - scriptField.SetValue(data); - } - break; - } - - case ScriptFieldType::Byte: - { - uint8_t data = 0; - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U8, &data)) - { - ScriptFieldInstance& scriptField = entityFields[name]; - scriptField.Field = field; - scriptField.SetValue(data); - } - break; - } - - case ScriptFieldType::UInt16: - { - uint16_t data = 0; - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U16, &data)) - { - ScriptFieldInstance& scriptField = entityFields[name]; - scriptField.Field = field; - scriptField.SetValue(data); - } - break; - } - - case ScriptFieldType::UInt32: - { - uint32_t data = 0; - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U32, &data)) - { - ScriptFieldInstance& scriptField = entityFields[name]; - scriptField.Field = field; - scriptField.SetValue(data); - } - break; - } - - case ScriptFieldType::UInt64: - { - uint64_t data = 0; - if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U64, &data)) - { - ScriptFieldInstance& scriptField = entityFields[name]; - scriptField.Field = field; - scriptField.SetValue(data); - } - break; - } - - case ScriptFieldType::Vector2: - { - if (auto data = glm::vec2(0.0f); - ImGui::InputFloat2(name.c_str(), glm::value_ptr(data))) - { - ScriptFieldInstance& scriptField = entityFields[name]; - scriptField.Field = field; - scriptField.SetValue(data); - } - break; - } - - case ScriptFieldType::Vector3: - { - if (auto data = glm::vec3(0.0f); - ImGui::InputFloat3(name.c_str(), glm::value_ptr(data))) - { - ScriptFieldInstance& scriptField = entityFields[name]; - scriptField.Field = field; - scriptField.SetValue(data); - } - break; - } - - case ScriptFieldType::Vector4: - { - if (auto data = glm::vec4(0.0f); - ImGui::InputFloat4(name.c_str(), glm::value_ptr(data))) - { - ScriptFieldInstance& scriptField = entityFields[name]; - scriptField.Field = field; - scriptField.SetValue(data); - } - break; - } - } - } - } - } - } - }); - - DrawComponent(entity, [](auto& component) - { - const char* bodyTypes[] = { "Static", "Dynamic", "Kinematic" }; - - if (const char* currentBodyType = bodyTypes[static_cast(component.Type)]; - ImGui::BeginCombo("Body Type", currentBodyType)) - { - for (uint32_t i = 0; i < 2; i++) - { - const bool isSelected = currentBodyType == bodyTypes[i]; - - if (ImGui::Selectable(bodyTypes[i], isSelected)) - { - currentBodyType = bodyTypes[i]; - component.Type = static_cast(i); - } - - if (isSelected) - ImGui::SetItemDefaultFocus(); - } - - ImGui::EndCombo(); - } - - ImGui::DragFloat("Mass", &component.Mass, 0.1f); - }, "Rigid Body"); - - DrawComponent(entity, [](auto& component) - { - auto& camera = component.Camera; - - const char* projectionTypes[] = { "Orthographic", "Perspective" }; - - if (const char* currentProjectionType = projectionTypes[static_cast(camera.GetProjectionType())]; - ImGui::BeginCombo("Projection Type", currentProjectionType)) - { - for (uint32_t i = 0; i < 2; i++) - { - const bool isSelected = currentProjectionType == projectionTypes[i]; - - if (ImGui::Selectable(projectionTypes[i], isSelected)) - { - currentProjectionType = projectionTypes[i]; - camera.SetProjectionType(static_cast(i)); - } - - if (isSelected) - ImGui::SetItemDefaultFocus(); - } - - ImGui::EndCombo(); - } - - if (camera.GetProjectionType() == ProjectionType::Perspective) - { - float fov = glm::degrees(camera.GetPerspectiveFov()); - if (ImGui::DragFloat("Field of view", &fov)) - camera.SetPerspectiveFov(fov); - - float nearClip = camera.GetPerspectiveNearClip(); - if (ImGui::DragFloat("Near clip", &nearClip)) - camera.SetPerspectiveNearClip(nearClip); - - float farClip = camera.GetPerspectiveFarClip(); - if (ImGui::DragFloat("Far clip", &farClip)) - camera.SetPerspectiveFarClip(farClip); - } - - if (camera.GetProjectionType() == ProjectionType::Orthographic) - { - float size = camera.GetOrthographicSize(); - if (ImGui::DragFloat("Size", &size)) - camera.SetOrthographicSize(size); - - float nearClip = camera.GetOrthographicNearClip(); - if (ImGui::DragFloat("Near clip", &nearClip)) - camera.SetOrthographicNearClip(nearClip); - - float farClip = camera.GetOrthographicFarClip(); - if (ImGui::DragFloat("Far clip", &farClip)) - camera.SetOrthographicFarClip(farClip); - } - }); - - DrawComponent(entity, [](auto& component) - { - ImGui::ColorEdit4("Color", glm::value_ptr(component.Color)); - }, "Point Light"); - } - - template - void PropertyPanel::DrawAddComponentEntry(const std::string& label) const - { - if (!GetSelectedEntity().HasComponent()) - { - if (ImGui::MenuItem(label.c_str())) - { - GetSelectedEntity().AddComponent(); - ImGui::CloseCurrentPopup(); - } - } - } - - template - void PropertyPanel::DrawComponent(Entity entity, FN uiFn, const std::string& tag) - { - if (!entity.HasComponent()) - return; - - auto& c = entity.GetComponent(); - - std::string label; - if (!tag.empty()) - label = tag; - else - label = Utils::GetComponentString(); - - bool closedHeader = true; // If this is set to false by ImGui, we delete the component - if (ImGui::CollapsingHeader(label.c_str(), &closedHeader, ImGuiTreeNodeFlags_DefaultOpen)) - uiFn(c); - - if (!closedHeader) - entity.RemoveComponent(); - } + namespace Utils + { + template + static std::string GetComponentString() + { + const std::string fullType = typeid(T).name(); + const size_t pos = fullType.find_last_of(':'); + const size_t stringSize = fullType.size() - (pos + 1); + + return fullType.substr(pos + 1, stringSize - 9); + } + } + + PropertyPanel::PropertyPanel(PanelManager& panelManager) + : Panel(panelManager) + {} + + void PropertyPanel::RenderGui() + { + ScopedBegin scopedBegin("Properties"); + + Entity entity = GetSelectedEntity(); + if (!entity) + return; + + DrawComponent(entity, [](auto& component) + { + std::string& tag = component.Tag; + + // ImGui wants a char*, we use std::string + // We could cast a c_str to char*, but we still could not write to it + char buffer[256]{ 0 }; + // Since ImGui accounts for the buffer size AND the null termination char, we can safely use strncpy. + std::strncpy(buffer, tag.c_str(), sizeof(buffer)); + + // Double quote prevents the label from showing + if (ImGui::InputText("##Tag", buffer, sizeof(buffer))) + tag = std::string(buffer); // TODO: Add support for empty labels --> Don't crash... + }); + + ImGui::SameLine(); + + // Add components + if (ImGui::Button("Add component")) + ImGui::OpenPopup("AddComponent"); + + if (ImGui::BeginPopup("AddComponent")) + { + DrawAddComponentEntry("Sprite"); + DrawAddComponentEntry("Mesh"); + DrawAddComponentEntry("Directional Light"); + DrawAddComponentEntry("Script"); + DrawAddComponentEntry("Rigid Body"); + DrawAddComponentEntry("Camera"); + DrawAddComponentEntry("Point Light"); + + ImGui::EndPopup(); + } + + DrawComponent(entity, [](auto& component) + { + if (ImGui::BeginTable("##", 4)) + { + ImGui::PushID("Translation"); + ImGui::TableNextColumn(); + ImGui::Text("Translation"); + + ImGui::TableNextColumn(); + if (ImGui::Button("X")) + component.Translation.x = 0.0f; + ImGui::SameLine(); + ImGui::DragFloat("##TranslationX", &component.Translation.x, 0.1f); + + ImGui::TableNextColumn(); + if (ImGui::Button("Y")) + component.Translation.y = 0.0f; + ImGui::SameLine(); + ImGui::DragFloat("##TranslationY", &component.Translation.y, 0.1f); + + ImGui::TableNextColumn(); + if (ImGui::Button("Z")) + component.Translation.z = 0.0f; + ImGui::SameLine(); + ImGui::DragFloat("##TranslationZ", &component.Translation.z, 0.1f); + + ImGui::TableNextRow(); + ImGui::PopID(); + + ImGui::PushID("Rotation"); + ImGui::TableNextColumn(); + ImGui::Text("Rotation"); + + ImGui::TableNextColumn(); + if (ImGui::Button("X")) + component.Rotation.x = 0.0f; + ImGui::SameLine(); + ImGui::DragFloat("##RotationX", &component.Rotation.x, 0.1f); + + ImGui::TableNextColumn(); + if (ImGui::Button("Y")) + component.Rotation.y = 0.0f; + ImGui::SameLine(); + ImGui::DragFloat("##RotationY", &component.Rotation.y, 0.1f); + + ImGui::TableNextColumn(); + if (ImGui::Button("Z")) + component.Rotation.z = 0.0f; + ImGui::SameLine(); + ImGui::DragFloat("##RotationZ", &component.Rotation.z, 0.1f); + + ImGui::TableNextRow(); + ImGui::PopID(); + + ImGui::PushID("Scale"); + ImGui::TableNextColumn(); + ImGui::Text("Scale"); + + ImGui::TableNextColumn(); + if (ImGui::Button("X")) + component.Scale.x = 0.0f; + ImGui::SameLine(); + ImGui::DragFloat("##ScaleX", &component.Scale.x, 0.1f); + + ImGui::TableNextColumn(); + if (ImGui::Button("Y")) + component.Scale.y = 0.0f; + ImGui::SameLine(); + ImGui::DragFloat("##ScaleY", &component.Scale.y, 0.1f); + + ImGui::TableNextColumn(); + if (ImGui::Button("Z")) + component.Scale.z = 0.0f; + ImGui::SameLine(); + ImGui::DragFloat("##ScaleZ", &component.Scale.z, 0.1f); + + ImGui::PopID(); + ImGui::EndTable(); + } + }); + + DrawComponent(entity, [](auto& component) + { + if (component.TextureHandle) + { + ImGui::TextDisabled(Project::GetActive()->GetAssetManagerEditor()->GetMetadata(component.TextureHandle).Filepath.string().c_str()); + ImGui::SameLine(); + if (ImGui::Button("X")) + component.TextureHandle = 0; + } else + { + ImGui::Button("Texture", ImVec2(100.0f, 0.0f)); + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("TEXTURE_ASSET")) + { + auto path = (const wchar_t*)payload->Data; + std::filesystem::path texturePath = path; + + //Ref texture = AssetManager::GetAsset(texturePath); + //component.TextureHandle = texture->Handle; + } + ImGui::EndDragDropTarget(); + } + } + + ImGui::ColorEdit4("Color", glm::value_ptr(component.Color)); + }); + + DrawComponent(entity, [](auto& component) + { + if (component.MeshHandle) + { + ImGui::TextDisabled(Project::GetActive()->GetAssetManagerEditor()->GetMetadata(component.MeshHandle).Filepath.string().c_str()); + ImGui::SameLine(); + if (ImGui::Button("X")) + component.MeshHandle = 0; + } else + { + ImGui::Button("Mesh", ImVec2(100.0f, 0.0f)); + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("MESH_ASSET")) + { + const auto handle = payload->Data; + component.MeshHandle = *static_cast(handle); + } + ImGui::EndDragDropTarget(); + } + } + }); + + DrawComponent(entity, [](auto& component) + { + if (ImGui::BeginTable("##", 4)) + { + ImGui::TableNextColumn(); + ImGui::Text("Direction"); + + ImGui::TableNextColumn(); + if (ImGui::Button("X")) + component.Direction.x = 0.0f; + ImGui::SameLine(); + ImGui::DragFloat("##DirectionX", &component.Direction.x, 0.1f); + + ImGui::TableNextColumn(); + if (ImGui::Button("Y")) + component.Direction.y = 0.0f; + ImGui::SameLine(); + ImGui::DragFloat("##DirectionY", &component.Direction.y, 0.1f); + + ImGui::TableNextColumn(); + if (ImGui::Button("Z")) + component.Direction.z = 0.0f; + ImGui::SameLine(); + ImGui::DragFloat("##DirectionZ", &component.Direction.z, 0.1f); + + ImGui::EndTable(); + } + + ImGui::ColorEdit4("Albedo Color", glm::value_ptr(component.AlbedoColor)); + ImGui::ColorEdit4("Ambient Color", glm::value_ptr(component.AmbientColor)); + ImGui::ColorEdit4("Specular Color", glm::value_ptr(component.SpecularColor)); + }, "Directional Light"); + + DrawComponent(entity, [entity, scene = GetSceneContext()](auto& component) mutable + { + std::string& name = component.ClassName; + + if (ImGui::BeginCombo("Class", name.c_str())) + { + for (const auto& [className, scriptClass] : ScriptEngine::GetEntityClasses()) + { + bool isSelected = className == name; + + if (ImGui::Selectable(className.c_str(), isSelected)) + name = className; + + if (isSelected) + ImGui::SetItemDefaultFocus(); + } + + ImGui::EndCombo(); + } + + UUID uuid = entity.GetUUID(); + + if (scene->IsRunning()) + { + if (Ref instance = ScriptEngine::GetEntityInstance(uuid)) + { + const auto& fields = instance->GetScriptClass()->GetFields(); + for (const auto& [name, field] : fields) + { + switch (field.Type) + { + case ScriptFieldType::Float: + { + float data = instance->GetFieldValue(name); + if (ImGui::InputFloat(name.c_str(), &data)) + instance->SetFieldValue(name, data); + break; + } + + case ScriptFieldType::Double: + { + double data = instance->GetFieldValue(name); + if (ImGui::InputDouble(name.c_str(), &data)) + instance->SetFieldValue(name, data); + break; + } + + case ScriptFieldType::Bool: + { + bool data = instance->GetFieldValue(name); + if (ImGui::Checkbox(name.c_str(), &data)) + instance->SetFieldValue(name, data); + break; + } + + case ScriptFieldType::Char: + { + int8_t data = instance->GetFieldValue(name); + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S8, &data)) + instance->SetFieldValue(name, data); + break; + } + + case ScriptFieldType::Int16: + { + int16_t data = instance->GetFieldValue(name); + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S16, &data)) + instance->SetFieldValue(name, data); + break; + } + + case ScriptFieldType::Int32: + { + int32_t data = instance->GetFieldValue(name); + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S32, &data)) + instance->SetFieldValue(name, data); + break; + } + + case ScriptFieldType::Int64: + { + int64_t data = instance->GetFieldValue(name); + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S64, &data)) + instance->SetFieldValue(name, data); + break; + } + + case ScriptFieldType::Byte: + { + uint8_t data = instance->GetFieldValue(name); + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U8, &data)) + instance->SetFieldValue(name, data); + break; + } + + case ScriptFieldType::UInt16: + { + uint16_t data = instance->GetFieldValue(name); + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U16, &data)) + instance->SetFieldValue(name, data); + break; + } + + case ScriptFieldType::UInt32: + { + uint32_t data = instance->GetFieldValue(name); + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U32, &data)) + instance->SetFieldValue(name, data); + break; + } + + case ScriptFieldType::UInt64: + { + uint64_t data = instance->GetFieldValue(name); + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U64, &data)) + instance->SetFieldValue(name, data); + break; + } + + case ScriptFieldType::Vector2: + { + glm::vec2 data = instance->GetFieldValue(name); + if (ImGui::InputFloat2(name.c_str(), glm::value_ptr(data))) + instance->SetFieldValue(name, data); + break; + } + + case ScriptFieldType::Vector3: + { + if (auto data = instance->GetFieldValue(name); + ImGui::InputFloat3(name.c_str(), glm::value_ptr(data))) + { + instance->SetFieldValue(name, data); + } + break; + } + + case ScriptFieldType::Vector4: + { + if (auto data = instance->GetFieldValue(name); + ImGui::InputFloat4(name.c_str(), glm::value_ptr(data))) + { + instance->SetFieldValue(name, data); + } + break; + } + } + } + } + } else + { + if (Ref entityClass = ScriptEngine::GetEntityClass(name)) + { + const auto& fields = entityClass->GetFields(); + auto& entityFields = ScriptEngine::GetScriptFieldMap(uuid); + + for (const auto& [name, field] : fields) + { + if (auto it = entityFields.find(name); + it != entityFields.end()) + { + ScriptFieldInstance& scriptField = it->second; + + switch (field.Type) + { + case ScriptFieldType::Float: + { + float data = scriptField.GetValue(); + if (ImGui::InputFloat(name.c_str(), &data)) + scriptField.SetValue(data); + break; + } + + case ScriptFieldType::Double: + { + double data = scriptField.GetValue(); + if (ImGui::InputDouble(name.c_str(), &data)) + scriptField.SetValue(data); + break; + } + + case ScriptFieldType::Bool: + { + bool data = scriptField.GetValue(); + if (ImGui::Checkbox(name.c_str(), &data)) + scriptField.SetValue(data); + break; + } + + case ScriptFieldType::Char: + { + int8_t data = scriptField.GetValue(); + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S8, &data)) + scriptField.SetValue(data); + break; + } + + case ScriptFieldType::Int16: + { + int16_t data = scriptField.GetValue(); + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S16, &data)) + scriptField.SetValue(data); + break; + } + + case ScriptFieldType::Int32: + { + int32_t data = scriptField.GetValue(); + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S32, &data)) + scriptField.SetValue(data); + break; + } + + case ScriptFieldType::Int64: + { + int64_t data = scriptField.GetValue(); + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S64, &data)) + scriptField.SetValue(data); + break; + } + + case ScriptFieldType::Byte: + { + uint8_t data = scriptField.GetValue(); + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U8, &data)) + scriptField.SetValue(data); + break; + } + + case ScriptFieldType::UInt16: + { + uint16_t data = scriptField.GetValue(); + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U16, &data)) + scriptField.SetValue(data); + break; + } + + case ScriptFieldType::UInt32: + { + uint32_t data = scriptField.GetValue(); + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U32, &data)) + scriptField.SetValue(data); + break; + } + + case ScriptFieldType::UInt64: + { + uint64_t data = scriptField.GetValue(); + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U64, &data)) + scriptField.SetValue(data); + break; + } + + case ScriptFieldType::Vector2: + { + if (auto data = scriptField.GetValue(); + ImGui::InputFloat2(name.c_str(), glm::value_ptr(data))) + { + scriptField.SetValue(data); + } + break; + } + + case ScriptFieldType::Vector3: + { + if (auto data = scriptField.GetValue(); + ImGui::InputFloat3(name.c_str(), glm::value_ptr(data))) + { + scriptField.SetValue(data); + } + break; + } + + case ScriptFieldType::Vector4: + { + if (auto data = scriptField.GetValue(); + ImGui::InputFloat4(name.c_str(), glm::value_ptr(data))) + { + scriptField.SetValue(data); + } + break; + } + } + } else + { + switch (field.Type) + { + case ScriptFieldType::Float: + { + float data = 0.0f; + if (ImGui::InputFloat(name.c_str(), &data)) + { + ScriptFieldInstance& scriptField = entityFields[name]; + scriptField.Field = field; + scriptField.SetValue(data); + } + break; + } + + case ScriptFieldType::Double: + { + double data = 0.0; + if (ImGui::InputDouble(name.c_str(), &data)) + { + ScriptFieldInstance& scriptField = entityFields[name]; + scriptField.Field = field; + scriptField.SetValue(data); + } + break; + } + + case ScriptFieldType::Bool: + { + bool data = false; + if (ImGui::Checkbox(name.c_str(), &data)) + { + ScriptFieldInstance& scriptField = entityFields[name]; + scriptField.Field = field; + scriptField.SetValue(data); + } + break; + } + + case ScriptFieldType::Char: + { + int8_t data = 0; + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S8, &data)) + { + ScriptFieldInstance& scriptField = entityFields[name]; + scriptField.Field = field; + scriptField.SetValue(data); + } + break; + } + + case ScriptFieldType::Int16: + { + int16_t data = 0; + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S16, &data)) + { + ScriptFieldInstance& scriptField = entityFields[name]; + scriptField.Field = field; + scriptField.SetValue(data); + } + break; + } + + case ScriptFieldType::Int32: + { + int32_t data = 0; + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S32, &data)) + { + ScriptFieldInstance& scriptField = entityFields[name]; + scriptField.Field = field; + scriptField.SetValue(data); + } + break; + } + + case ScriptFieldType::Int64: + { + int64_t data = 0; + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_S64, &data)) + { + ScriptFieldInstance& scriptField = entityFields[name]; + scriptField.Field = field; + scriptField.SetValue(data); + } + break; + } + + case ScriptFieldType::Byte: + { + uint8_t data = 0; + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U8, &data)) + { + ScriptFieldInstance& scriptField = entityFields[name]; + scriptField.Field = field; + scriptField.SetValue(data); + } + break; + } + + case ScriptFieldType::UInt16: + { + uint16_t data = 0; + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U16, &data)) + { + ScriptFieldInstance& scriptField = entityFields[name]; + scriptField.Field = field; + scriptField.SetValue(data); + } + break; + } + + case ScriptFieldType::UInt32: + { + uint32_t data = 0; + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U32, &data)) + { + ScriptFieldInstance& scriptField = entityFields[name]; + scriptField.Field = field; + scriptField.SetValue(data); + } + break; + } + + case ScriptFieldType::UInt64: + { + uint64_t data = 0; + if (ImGui::InputScalar(name.c_str(), ImGuiDataType_U64, &data)) + { + ScriptFieldInstance& scriptField = entityFields[name]; + scriptField.Field = field; + scriptField.SetValue(data); + } + break; + } + + case ScriptFieldType::Vector2: + { + if (auto data = glm::vec2(0.0f); + ImGui::InputFloat2(name.c_str(), glm::value_ptr(data))) + { + ScriptFieldInstance& scriptField = entityFields[name]; + scriptField.Field = field; + scriptField.SetValue(data); + } + break; + } + + case ScriptFieldType::Vector3: + { + if (auto data = glm::vec3(0.0f); + ImGui::InputFloat3(name.c_str(), glm::value_ptr(data))) + { + ScriptFieldInstance& scriptField = entityFields[name]; + scriptField.Field = field; + scriptField.SetValue(data); + } + break; + } + + case ScriptFieldType::Vector4: + { + if (auto data = glm::vec4(0.0f); + ImGui::InputFloat4(name.c_str(), glm::value_ptr(data))) + { + ScriptFieldInstance& scriptField = entityFields[name]; + scriptField.Field = field; + scriptField.SetValue(data); + } + break; + } + } + } + } + } + } + }); + + DrawComponent(entity, [](auto& component) + { + const char* bodyTypes[] = { "Static", "Dynamic", "Kinematic" }; + + if (const char* currentBodyType = bodyTypes[static_cast(component.Type)]; + ImGui::BeginCombo("Body Type", currentBodyType)) + { + for (uint32_t i = 0; i < 2; i++) + { + const bool isSelected = currentBodyType == bodyTypes[i]; + + if (ImGui::Selectable(bodyTypes[i], isSelected)) + { + currentBodyType = bodyTypes[i]; + component.Type = static_cast(i); + } + + if (isSelected) + ImGui::SetItemDefaultFocus(); + } + + ImGui::EndCombo(); + } + + ImGui::DragFloat("Mass", &component.Mass, 0.1f); + }, "Rigid Body"); + + DrawComponent(entity, [](auto& component) + { + auto& camera = component.Camera; + + const char* projectionTypes[] = { "Orthographic", "Perspective" }; + + if (const char* currentProjectionType = projectionTypes[static_cast(camera.GetProjectionType())]; + ImGui::BeginCombo("Projection Type", currentProjectionType)) + { + for (uint32_t i = 0; i < 2; i++) + { + const bool isSelected = currentProjectionType == projectionTypes[i]; + + if (ImGui::Selectable(projectionTypes[i], isSelected)) + { + currentProjectionType = projectionTypes[i]; + camera.SetProjectionType(static_cast(i)); + } + + if (isSelected) + ImGui::SetItemDefaultFocus(); + } + + ImGui::EndCombo(); + } + + if (camera.GetProjectionType() == ProjectionType::Perspective) + { + float fov = glm::degrees(camera.GetPerspectiveFov()); + if (ImGui::DragFloat("Field of view", &fov)) + camera.SetPerspectiveFov(fov); + + float nearClip = camera.GetPerspectiveNearClip(); + if (ImGui::DragFloat("Near clip", &nearClip)) + camera.SetPerspectiveNearClip(nearClip); + + float farClip = camera.GetPerspectiveFarClip(); + if (ImGui::DragFloat("Far clip", &farClip)) + camera.SetPerspectiveFarClip(farClip); + } + + if (camera.GetProjectionType() == ProjectionType::Orthographic) + { + float size = camera.GetOrthographicSize(); + if (ImGui::DragFloat("Size", &size)) + camera.SetOrthographicSize(size); + + float nearClip = camera.GetOrthographicNearClip(); + if (ImGui::DragFloat("Near clip", &nearClip)) + camera.SetOrthographicNearClip(nearClip); + + float farClip = camera.GetOrthographicFarClip(); + if (ImGui::DragFloat("Far clip", &farClip)) + camera.SetOrthographicFarClip(farClip); + } + }); + + DrawComponent(entity, [](auto& component) + { + ImGui::ColorEdit4("Color", glm::value_ptr(component.Color)); + }, "Point Light"); + } + + template + void PropertyPanel::DrawAddComponentEntry(const std::string& label) const + { + if (!GetSelectedEntity().HasComponent()) + { + if (ImGui::MenuItem(label.c_str())) + { + GetSelectedEntity().AddComponent(); + ImGui::CloseCurrentPopup(); + } + } + } + + template + void PropertyPanel::DrawComponent(Entity entity, FN uiFn, const std::string& tag) + { + if (!entity.HasComponent()) + return; + + auto& c = entity.GetComponent(); + + std::string label; + if (!tag.empty()) + label = tag; + else + label = Utils::GetComponentString(); + + bool closedHeader = true; // If this is set to false by ImGui, we delete the component + if (ImGui::CollapsingHeader(label.c_str(), &closedHeader, ImGuiTreeNodeFlags_DefaultOpen)) + uiFn(c); + + if (!closedHeader) + entity.RemoveComponent(); + } } diff --git a/EppoEditor/Source/Panel/PropertyPanel.h b/EppoEditor/Source/Panel/PropertyPanel.h index f05d8487..03c66f13 100644 --- a/EppoEditor/Source/Panel/PropertyPanel.h +++ b/EppoEditor/Source/Panel/PropertyPanel.h @@ -4,18 +4,18 @@ namespace Eppo { - class PropertyPanel : public Panel - { - public: - explicit PropertyPanel(PanelManager& panelManager); + class PropertyPanel : public Panel + { + public: + explicit PropertyPanel(PanelManager& panelManager); - void RenderGui() override; + void RenderGui() override; - private: - template - void DrawAddComponentEntry(const std::string& label) const; + private: + template + void DrawAddComponentEntry(const std::string& label) const; - template - void DrawComponent(Entity entity, FN uiFn, const std::string& tag = std::string()); - }; + template + void DrawComponent(Entity entity, FN uiFn, const std::string& tag = std::string()); + }; } diff --git a/EppoEditor/Source/Panel/SceneHierarchyPanel.cpp b/EppoEditor/Source/Panel/SceneHierarchyPanel.cpp index 8a5e572e..bbb65bfd 100644 --- a/EppoEditor/Source/Panel/SceneHierarchyPanel.cpp +++ b/EppoEditor/Source/Panel/SceneHierarchyPanel.cpp @@ -2,66 +2,66 @@ namespace Eppo { - SceneHierarchyPanel::SceneHierarchyPanel(PanelManager& panelManager) - : Panel(panelManager) - {} + SceneHierarchyPanel::SceneHierarchyPanel(PanelManager& panelManager) + : Panel(panelManager) + {} - void SceneHierarchyPanel::RenderGui() - { - ScopedBegin scopedBegin("Scene Hierarchy"); + void SceneHierarchyPanel::RenderGui() + { + ScopedBegin scopedBegin("Scene Hierarchy"); - GetSceneContext()->m_Registry.each([&](auto entityID) - { - const Entity entity(entityID, GetSceneContext().get()); - DrawEntityNode(entity); - }); + GetSceneContext()->m_Registry.each([&](auto entityID) + { + const Entity entity(entityID, GetSceneContext().get()); + DrawEntityNode(entity); + }); - if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && ImGui::IsWindowHovered()) - SetSelectedEntity({}); + if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && ImGui::IsWindowHovered()) + SetSelectedEntity({}); - if (ImGui::BeginPopupContextWindow(nullptr, ImGuiPopupFlags_NoOpenOverItems | ImGuiPopupFlags_MouseButtonRight)) - { - if (ImGui::MenuItem("Create new entity")) - GetSceneContext()->CreateEntity("New entity"); + if (ImGui::BeginPopupContextWindow(nullptr, ImGuiPopupFlags_NoOpenOverItems | ImGuiPopupFlags_MouseButtonRight)) + { + if (ImGui::MenuItem("Create new entity")) + GetSceneContext()->CreateEntity("New entity"); - ImGui::EndPopup(); - } - } + ImGui::EndPopup(); + } + } - void SceneHierarchyPanel::DrawEntityNode(Entity entity) const - { - const std::string& tag = entity.GetComponent().Tag; + void SceneHierarchyPanel::DrawEntityNode(Entity entity) const + { + const std::string& tag = entity.GetComponent().Tag; - ImGuiTreeNodeFlags flags = (GetSelectedEntity() == entity ? ImGuiTreeNodeFlags_Selected : 0); - flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; + ImGuiTreeNodeFlags flags = (GetSelectedEntity() == entity ? ImGuiTreeNodeFlags_Selected : 0); + flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth; - ImGui::PushID(reinterpret_cast(static_cast(entity.GetUUID()))); - const bool opened = ImGui::TreeNodeEx(tag.c_str(), flags); - - if (ImGui::IsItemClicked()) - SetSelectedEntity(entity); + ImGui::PushID(reinterpret_cast(static_cast(entity.GetUUID()))); + const bool opened = ImGui::TreeNodeEx(tag.c_str(), flags); + + if (ImGui::IsItemClicked()) + SetSelectedEntity(entity); - bool entityDeleted = false; - if (ImGui::BeginPopupContextItem()) - { - if (ImGui::MenuItem("Duplicate entity")) - EPPO_ASSERT(false); - if (ImGui::MenuItem("Delete entity")) - entityDeleted = true; + bool entityDeleted = false; + if (ImGui::BeginPopupContextItem()) + { + if (ImGui::MenuItem("Duplicate entity")) + EPPO_ASSERT(false); + if (ImGui::MenuItem("Delete entity")) + entityDeleted = true; - ImGui::EndPopup(); - } - ImGui::PopID(); + ImGui::EndPopup(); + } + ImGui::PopID(); - if (opened) - ImGui::TreePop(); + if (opened) + ImGui::TreePop(); - if (entityDeleted) - { - if (GetSelectedEntity() == entity) - SetSelectedEntity({}); + if (entityDeleted) + { + if (GetSelectedEntity() == entity) + SetSelectedEntity({}); - GetSceneContext()->DestroyEntity(entity); - } - } + GetSceneContext()->DestroyEntity(entity); + } + } } diff --git a/EppoEditor/Source/Panel/SceneHierarchyPanel.h b/EppoEditor/Source/Panel/SceneHierarchyPanel.h index 633886d4..25babf25 100644 --- a/EppoEditor/Source/Panel/SceneHierarchyPanel.h +++ b/EppoEditor/Source/Panel/SceneHierarchyPanel.h @@ -5,14 +5,14 @@ namespace Eppo { - class SceneHierarchyPanel : public Panel - { - public: - explicit SceneHierarchyPanel(PanelManager& panelManager); + class SceneHierarchyPanel : public Panel + { + public: + explicit SceneHierarchyPanel(PanelManager& panelManager); - void RenderGui() override; + void RenderGui() override; - private: - void DrawEntityNode(Entity entity) const; - }; + private: + void DrawEntityNode(Entity entity) const; + }; } diff --git a/EppoEditor/Source/ThumbnailCache.cpp b/EppoEditor/Source/ThumbnailCache.cpp index 9b0ef374..4d5434c7 100644 --- a/EppoEditor/Source/ThumbnailCache.cpp +++ b/EppoEditor/Source/ThumbnailCache.cpp @@ -4,29 +4,29 @@ namespace Eppo { - ThumbnailCache::ThumbnailCache() - { - m_AssetTypeThumbnails[AssetType::None] = Image::Create(ImageSpecification("Resources/Textures/Icons/Unknown.png")); - m_AssetTypeThumbnails[AssetType::Mesh] = Image::Create(ImageSpecification("Resources/Textures/Icons/Mesh.png")); - m_AssetTypeThumbnails[AssetType::Scene] = Image::Create(ImageSpecification("Resources/Textures/Icons/Scene.png")); - m_AssetTypeThumbnails[AssetType::Script] = Image::Create(ImageSpecification("Resources/Textures/Icons/Script.png")); - m_AssetTypeThumbnails[AssetType::Texture] = Image::Create(ImageSpecification("Resources/Textures/Icons/Texture.png")); - } + ThumbnailCache::ThumbnailCache() + { + m_AssetTypeThumbnails[AssetType::None] = Image::Create(ImageSpecification("Resources/Textures/Icons/Unknown.png")); + m_AssetTypeThumbnails[AssetType::Mesh] = Image::Create(ImageSpecification("Resources/Textures/Icons/Mesh.png")); + m_AssetTypeThumbnails[AssetType::Scene] = Image::Create(ImageSpecification("Resources/Textures/Icons/Scene.png")); + m_AssetTypeThumbnails[AssetType::Script] = Image::Create(ImageSpecification("Resources/Textures/Icons/Script.png")); + m_AssetTypeThumbnails[AssetType::Texture] = Image::Create(ImageSpecification("Resources/Textures/Icons/Texture.png")); + } - Ref ThumbnailCache::GetOrCreateThumbnail(const std::filesystem::path& filepath) - { - const auto absPath = Project::GetAssetFilepath(filepath); - const std::filesystem::file_time_type lastWriteTime = std::filesystem::last_write_time(absPath); - uint64_t timestamp = std::chrono::duration_cast(lastWriteTime.time_since_epoch()).count(); + Ref ThumbnailCache::GetOrCreateThumbnail(const std::filesystem::path& filepath) + { + const auto absPath = Project::GetAssetFilepath(filepath); + const std::filesystem::file_time_type lastWriteTime = std::filesystem::last_write_time(absPath); + uint64_t timestamp = std::chrono::duration_cast(lastWriteTime.time_since_epoch()).count(); - return nullptr; - } + return nullptr; + } - Ref ThumbnailCache::GetOrCreateThumbnail(const AssetType type) - { - if (!m_AssetTypeThumbnails.contains(type)) - return m_AssetTypeThumbnails.at(AssetType::None); + Ref ThumbnailCache::GetOrCreateThumbnail(const AssetType type) + { + if (!m_AssetTypeThumbnails.contains(type)) + return m_AssetTypeThumbnails.at(AssetType::None); - return m_AssetTypeThumbnails.at(type); - } + return m_AssetTypeThumbnails.at(type); + } } diff --git a/EppoEditor/Source/ThumbnailCache.h b/EppoEditor/Source/ThumbnailCache.h index f76cf583..7d313e57 100644 --- a/EppoEditor/Source/ThumbnailCache.h +++ b/EppoEditor/Source/ThumbnailCache.h @@ -4,22 +4,22 @@ namespace Eppo { - struct Thumbnail - { - uint64_t Timestamp; - Ref Image; - }; + struct Thumbnail + { + uint64_t Timestamp; + Ref Image; + }; - class ThumbnailCache - { - public: - ThumbnailCache(); + class ThumbnailCache + { + public: + ThumbnailCache(); - Ref GetOrCreateThumbnail(const std::filesystem::path& filepath); - Ref GetOrCreateThumbnail(AssetType type); + Ref GetOrCreateThumbnail(const std::filesystem::path& filepath); + Ref GetOrCreateThumbnail(AssetType type); - private: - std::unordered_map m_AssetThumbnails; - std::unordered_map> m_AssetTypeThumbnails; - }; + private: + std::unordered_map m_AssetThumbnails; + std::unordered_map> m_AssetTypeThumbnails; + }; } diff --git a/EppoEditor/premake5.lua b/EppoEditor/premake5.lua index 48b76044..4f588cd3 100644 --- a/EppoEditor/premake5.lua +++ b/EppoEditor/premake5.lua @@ -7,9 +7,9 @@ project "EppoEditor" targetdir ("%{wks.location}/Bin/" .. OutputDir .. "/%{prj.name}") objdir ("%{wks.location}/Bin-Int/" .. OutputDir .. "/%{prj.name}") - dependson { - "EppoScripting" - } + dependson { + "EppoScripting" + } files { "Source/**.h", @@ -21,12 +21,12 @@ project "EppoEditor" "%{wks.location}/EppoEngine/Source", "%{wks.location}/EppoEngine/Vendor", - "%{IncludeDir.entt}", - "%{IncludeDir.glm}", - "%{IncludeDir.imgui}", + "%{IncludeDir.entt}", + "%{IncludeDir.glm}", + "%{IncludeDir.imgui}", "%{IncludeDir.spdlog}", "%{IncludeDir.tracy}", - "%{IncludeDir.yaml_cpp}" + "%{IncludeDir.yaml_cpp}" } links { @@ -34,7 +34,7 @@ project "EppoEditor" } filter "system:windows" - systemversion "latest" + systemversion "latest" defines { "EPPO_PLATFORM_WINDOWS" @@ -64,30 +64,30 @@ project "EppoEditor" runtime "Debug" symbols "On" - defines { - "TRACY_ENABLE", + defines { + "TRACY_ENABLE", "TRACY_ONLY_LOCALHOST" - } + } filter {"system:windows", "configurations:Debug"} - postbuildcommands { + postbuildcommands { '{COPY} "%{DynamicLibrary.mono_debug}" "%{cfg.targetdir}"' - } + } filter "configurations:Release" defines "EPPO_RELEASE" runtime "Release" optimize "On" - defines { - "TRACY_ENABLE", + defines { + "TRACY_ENABLE", "TRACY_ONLY_LOCALHOST" - } + } filter {"system:windows", "configurations:Release"} - postbuildcommands { + postbuildcommands { '{COPY} "%{DynamicLibrary.mono_release}" "%{cfg.targetdir}"' - } + } filter "configurations:Dist" defines "EPPO_DIST" @@ -95,6 +95,6 @@ project "EppoEditor" optimize "On" filter {"system:windows", "configurations:Dist"} - postbuildcommands { + postbuildcommands { '{COPY} "%{DynamicLibrary.mono_release}" "%{cfg.targetdir}"' - } + } diff --git a/EppoEngine/Source/Core/Log.h b/EppoEngine/Source/Core/Log.h index 3ca850f6..a653b2fc 100644 --- a/EppoEngine/Source/Core/Log.h +++ b/EppoEngine/Source/Core/Log.h @@ -39,18 +39,18 @@ struct fmt::formatter> : fmt::formatter } }; -#define EPPO_TRACE(...) ::Eppo::Log::GetCoreLogger()->trace(__VA_ARGS__) -#define EPPO_INFO(...) ::Eppo::Log::GetCoreLogger()->info(__VA_ARGS__) -#define EPPO_WARN(...) ::Eppo::Log::GetCoreLogger()->warn(__VA_ARGS__) -#define EPPO_ERROR(...) ::Eppo::Log::GetCoreLogger()->error(__VA_ARGS__) +#define EPPO_TRACE(...) ::Eppo::Log::GetCoreLogger()->trace(__VA_ARGS__) +#define EPPO_INFO(...) ::Eppo::Log::GetCoreLogger()->info(__VA_ARGS__) +#define EPPO_WARN(...) ::Eppo::Log::GetCoreLogger()->warn(__VA_ARGS__) +#define EPPO_ERROR(...) ::Eppo::Log::GetCoreLogger()->error(__VA_ARGS__) #if defined(EPPO_TRACK_MEMORY) - #define EPPO_MEM_WARN(...) ::Eppo::Log::GetCoreLogger()->trace(__VA_ARGS__) + #define EPPO_MEM_WARN(...) ::Eppo::Log::GetCoreLogger()->trace(__VA_ARGS__) #else #define EPPO_MEM_WARN(...) #endif -#define EPPO_SCRIPT_TRACE(...) ::Eppo::Log::GetScriptLogger()->trace(__VA_ARGS__) -#define EPPO_SCRIPT_INFO(...) ::Eppo::Log::GetScriptLogger()->info(__VA_ARGS__) -#define EPPO_SCRIPT_WARN(...) ::Eppo::Log::GetScriptLogger()->warn(__VA_ARGS__) -#define EPPO_SCRIPT_ERROR(...) ::Eppo::Log::GetScriptLogger()->error(__VA_ARGS__) +#define EPPO_SCRIPT_TRACE(...) ::Eppo::Log::GetScriptLogger()->trace(__VA_ARGS__) +#define EPPO_SCRIPT_INFO(...) ::Eppo::Log::GetScriptLogger()->info(__VA_ARGS__) +#define EPPO_SCRIPT_WARN(...) ::Eppo::Log::GetScriptLogger()->warn(__VA_ARGS__) +#define EPPO_SCRIPT_ERROR(...) ::Eppo::Log::GetScriptLogger()->error(__VA_ARGS__) diff --git a/EppoEngine/Source/Core/Ref.h b/EppoEngine/Source/Core/Ref.h index 0a03ab10..3ead1cfa 100644 --- a/EppoEngine/Source/Core/Ref.h +++ b/EppoEngine/Source/Core/Ref.h @@ -2,167 +2,167 @@ // namespace Eppo // { -// class RefCounter -// { -// public: -// void IncreaseRefCount() -// { -// m_RefCount++; -// } - -// void DecreaseRefCount() -// { -// m_RefCount--; -// } - -// uint32_t GetRefCount() const -// { -// return m_RefCount; -// } - -// template -// friend class Ref2; +// class RefCounter +// { +// public: +// void IncreaseRefCount() +// { +// m_RefCount++; +// } + +// void DecreaseRefCount() +// { +// m_RefCount--; +// } + +// uint32_t GetRefCount() const +// { +// return m_RefCount; +// } + +// template +// friend class Ref2; -// private: -// uint32_t m_RefCount = 0; -// }; - -// template -// class Ref2 -// { -// public: -// // Default constructor -// Ref2() -// {} - -// // Destructor -// ~Ref2() -// { -// if (m_Object) -// DecRef(); -// } +// private: +// uint32_t m_RefCount = 0; +// }; + +// template +// class Ref2 +// { +// public: +// // Default constructor +// Ref2() +// {} + +// // Destructor +// ~Ref2() +// { +// if (m_Object) +// DecRef(); +// } -// // Construct from raw pointer -// Ref2(T* object) -// { -// m_Object = object; -// IncRef(); -// } - -// // Copy constructor -// Ref2(const Ref2& other) -// { -// m_Object = other.m_Object; -// IncRef(); -// } - -// // Copy assignment operator -// Ref2& operator=(const Ref2& other) -// { -// m_Object = other.m_Object; -// IncRef(); -// } - -// // Copy constructor child to base -// template -// Ref2& operator=(const Ref2& other) -// { -// if (m_Object) -// DecRef(); - -// m_Object = other.m_Object; -// IncRef(); - -// return *this; -// } - -// // Move constructor -// Ref2(Ref2&& other) noexcept -// { -// m_Object = other.m_Object; -// other.m_Object = nullptr; -// } - -// // Move assignment operator -// Ref2& operator=(Ref2&& other) noexcept -// { -// m_Object = other.m_Object; -// other.m_Object = nullptr; - -// return *m_Object; -// } - -// // Raw pointer -// const T* Raw() const -// { -// EPPO_ASSERT(m_Object); - -// return m_Object; -// } - -// // Pointer access -// T* operator->() const -// { -// EPPO_ASSERT(m_Object); - -// return m_Object; -// } - -// // Create -// template -// static Ref2 Create(Args&&... args) -// { -// T* object = new T(std::forward(args)...); - -// return Ref2(object); -// } - -// // Cast to polymorphic type -// template -// Ref2& As() -// { -// EPPO_ASSERT(m_Object); -// T2* ptr = dynamic_cast(m_Object); -// EPPO_ASSERT(ptr); +// // Construct from raw pointer +// Ref2(T* object) +// { +// m_Object = object; +// IncRef(); +// } + +// // Copy constructor +// Ref2(const Ref2& other) +// { +// m_Object = other.m_Object; +// IncRef(); +// } + +// // Copy assignment operator +// Ref2& operator=(const Ref2& other) +// { +// m_Object = other.m_Object; +// IncRef(); +// } + +// // Copy constructor child to base +// template +// Ref2& operator=(const Ref2& other) +// { +// if (m_Object) +// DecRef(); + +// m_Object = other.m_Object; +// IncRef(); + +// return *this; +// } + +// // Move constructor +// Ref2(Ref2&& other) noexcept +// { +// m_Object = other.m_Object; +// other.m_Object = nullptr; +// } + +// // Move assignment operator +// Ref2& operator=(Ref2&& other) noexcept +// { +// m_Object = other.m_Object; +// other.m_Object = nullptr; + +// return *m_Object; +// } + +// // Raw pointer +// const T* Raw() const +// { +// EPPO_ASSERT(m_Object); + +// return m_Object; +// } + +// // Pointer access +// T* operator->() const +// { +// EPPO_ASSERT(m_Object); + +// return m_Object; +// } + +// // Create +// template +// static Ref2 Create(Args&&... args) +// { +// T* object = new T(std::forward(args)...); + +// return Ref2(object); +// } + +// // Cast to polymorphic type +// template +// Ref2& As() +// { +// EPPO_ASSERT(m_Object); +// T2* ptr = dynamic_cast(m_Object); +// EPPO_ASSERT(ptr); -// return Ref2(ptr); -// } - -// uint32_t GetRefCount() const -// { -// if (m_Object) -// return m_Object->GetRefCount(); -// else -// return 0; -// } - -// private: -// // Increase ref count -// void IncRef() const -// { -// EPPO_ASSERT(m_Object); - -// m_Object->IncreaseRefCount(); -// } - -// // Decrease ref count -// void DecRef() const -// { -// EPPO_ASSERT(m_Object); - -// m_Object->DecreaseRefCount(); - -// if (m_Object->GetRefCount() == 0) -// { -// delete m_Object; -// m_Object = nullptr; -// } -// } - -// private: -// mutable T* m_Object = nullptr; - -// template -// friend class Ref2; -// }; +// return Ref2(ptr); +// } + +// uint32_t GetRefCount() const +// { +// if (m_Object) +// return m_Object->GetRefCount(); +// else +// return 0; +// } + +// private: +// // Increase ref count +// void IncRef() const +// { +// EPPO_ASSERT(m_Object); + +// m_Object->IncreaseRefCount(); +// } + +// // Decrease ref count +// void DecRef() const +// { +// EPPO_ASSERT(m_Object); + +// m_Object->DecreaseRefCount(); + +// if (m_Object->GetRefCount() == 0) +// { +// delete m_Object; +// m_Object = nullptr; +// } +// } + +// private: +// mutable T* m_Object = nullptr; + +// template +// friend class Ref2; +// }; // } diff --git a/EppoEngine/Source/Core/Window.cpp b/EppoEngine/Source/Core/Window.cpp index a55e8fb7..4d4cb248 100644 --- a/EppoEngine/Source/Core/Window.cpp +++ b/EppoEngine/Source/Core/Window.cpp @@ -9,155 +9,155 @@ namespace Eppo { - namespace - { - void GLFWErrorCallback(int error, const char* description) - { - EPPO_ERROR("GLFW Error: ({}) {}", error, description); - } - } - - Window::Window(WindowSpecification specification) - : m_Specification(std::move(specification)) - { - const int success = glfwInit(); + namespace + { + void GLFWErrorCallback(int error, const char* description) + { + EPPO_ERROR("GLFW Error: ({}) {}", error, description); + } + } + + Window::Window(WindowSpecification specification) + : m_Specification(std::move(specification)) + { + const int success = glfwInit(); EPPO_ASSERT(success); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - - #ifdef EPPO_DEBUG - glfwSetErrorCallback(GLFWErrorCallback); - #endif - - // Get primary monitor - GLFWmonitor* primaryMonitor = glfwGetPrimaryMonitor(); - const GLFWvidmode* mode = glfwGetVideoMode(primaryMonitor); - - if (m_Specification.OverrideSpecification) - { - m_Specification.Width = mode->width; - m_Specification.Height = mode->height; - m_Specification.RefreshRate = mode->refreshRate; - } - - // Create window - EPPO_INFO("Creating window '{}' ({}x{}@{}Hz)", m_Specification.Title, m_Specification.Width, m_Specification.Height, m_Specification.RefreshRate); - glfwWindowHint(GLFW_POSITION_X, 25); - glfwWindowHint(GLFW_POSITION_Y, 50); - m_Window = glfwCreateWindow(static_cast(m_Specification.Width), static_cast(m_Specification.Height), - m_Specification.Title.c_str(), nullptr, nullptr); - } - - void Window::Init() - { - // Create renderer context - m_Context = RendererContext::Create(m_Window); - m_Context->Init(); - - glfwSetWindowUserPointer(m_Window, &m_Callback); - - glfwSetWindowCloseCallback(m_Window, [](GLFWwindow* window) - { - const EventCallbackFn& callback = *static_cast(glfwGetWindowUserPointer(window)); - WindowCloseEvent e; - callback(e); - }); - - glfwSetWindowSizeCallback(m_Window, [](GLFWwindow* window, int width, int height) - { - const EventCallbackFn& callback = *static_cast(glfwGetWindowUserPointer(window)); - WindowResizeEvent e(width, height); - callback(e); - }); - - glfwSetKeyCallback(m_Window, [](GLFWwindow* window, int key, int scancode, int action, int mods) - { - const EventCallbackFn& callback = *static_cast(glfwGetWindowUserPointer(window)); - - switch (action) - { - case GLFW_PRESS: - { - KeyPressedEvent e(static_cast(key)); - callback(e); - break; - } - - case GLFW_RELEASE: - { - KeyReleasedEvent e(static_cast(key)); - callback(e); - break; - } - - case GLFW_REPEAT: - { - KeyPressedEvent e(static_cast(key), true); - callback(e); - break; - } - } - }); - - glfwSetCharCallback(m_Window, [](GLFWwindow* window, unsigned int keycode) - { - const EventCallbackFn& callback = *static_cast(glfwGetWindowUserPointer(window)); - KeyTypedEvent e(static_cast(keycode)); - callback(e); - }); - - glfwSetMouseButtonCallback(m_Window, [](GLFWwindow* window, int button, int action, int mods) - { - const EventCallbackFn& callback = *static_cast(glfwGetWindowUserPointer(window)); - - switch (action) - { - case GLFW_PRESS: - { - MouseButtonPressedEvent e(static_cast(button)); - callback(e); - break; - } - - case GLFW_RELEASE: - { - MouseButtonReleasedEvent e(static_cast(button)); - callback(e); - break; - } - } - }); - - glfwSetScrollCallback(m_Window, [](GLFWwindow* window, double xOffset, double yOffset) - { - const EventCallbackFn& callback = *static_cast(glfwGetWindowUserPointer(window)); - MouseScrolledEvent e(static_cast(xOffset), static_cast(yOffset)); - callback(e); - }); - - glfwSetCursorPosCallback(m_Window, [](GLFWwindow* window, double xPos, double yPos) - { - const EventCallbackFn& callback = *static_cast(glfwGetWindowUserPointer(window)); - MouseMovedEvent e(static_cast(xPos), static_cast(yPos)); - callback(e); - }); - } - - void Window::Shutdown() const - { - m_Context->Shutdown(); - - glfwDestroyWindow(m_Window); - glfwTerminate(); - } - - void Window::ProcessEvents() - { - glfwPollEvents(); - } - - void Window::SetWindowTitle(const std::string& name) const - { - glfwSetWindowTitle(m_Window, name.c_str()); - } + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + + #ifdef EPPO_DEBUG + glfwSetErrorCallback(GLFWErrorCallback); + #endif + + // Get primary monitor + GLFWmonitor* primaryMonitor = glfwGetPrimaryMonitor(); + const GLFWvidmode* mode = glfwGetVideoMode(primaryMonitor); + + if (m_Specification.OverrideSpecification) + { + m_Specification.Width = mode->width; + m_Specification.Height = mode->height; + m_Specification.RefreshRate = mode->refreshRate; + } + + // Create window + EPPO_INFO("Creating window '{}' ({}x{}@{}Hz)", m_Specification.Title, m_Specification.Width, m_Specification.Height, m_Specification.RefreshRate); + glfwWindowHint(GLFW_POSITION_X, 25); + glfwWindowHint(GLFW_POSITION_Y, 50); + m_Window = glfwCreateWindow(static_cast(m_Specification.Width), static_cast(m_Specification.Height), + m_Specification.Title.c_str(), nullptr, nullptr); + } + + void Window::Init() + { + // Create renderer context + m_Context = RendererContext::Create(m_Window); + m_Context->Init(); + + glfwSetWindowUserPointer(m_Window, &m_Callback); + + glfwSetWindowCloseCallback(m_Window, [](GLFWwindow* window) + { + const EventCallbackFn& callback = *static_cast(glfwGetWindowUserPointer(window)); + WindowCloseEvent e; + callback(e); + }); + + glfwSetWindowSizeCallback(m_Window, [](GLFWwindow* window, int width, int height) + { + const EventCallbackFn& callback = *static_cast(glfwGetWindowUserPointer(window)); + WindowResizeEvent e(width, height); + callback(e); + }); + + glfwSetKeyCallback(m_Window, [](GLFWwindow* window, int key, int scancode, int action, int mods) + { + const EventCallbackFn& callback = *static_cast(glfwGetWindowUserPointer(window)); + + switch (action) + { + case GLFW_PRESS: + { + KeyPressedEvent e(static_cast(key)); + callback(e); + break; + } + + case GLFW_RELEASE: + { + KeyReleasedEvent e(static_cast(key)); + callback(e); + break; + } + + case GLFW_REPEAT: + { + KeyPressedEvent e(static_cast(key), true); + callback(e); + break; + } + } + }); + + glfwSetCharCallback(m_Window, [](GLFWwindow* window, unsigned int keycode) + { + const EventCallbackFn& callback = *static_cast(glfwGetWindowUserPointer(window)); + KeyTypedEvent e(static_cast(keycode)); + callback(e); + }); + + glfwSetMouseButtonCallback(m_Window, [](GLFWwindow* window, int button, int action, int mods) + { + const EventCallbackFn& callback = *static_cast(glfwGetWindowUserPointer(window)); + + switch (action) + { + case GLFW_PRESS: + { + MouseButtonPressedEvent e(static_cast(button)); + callback(e); + break; + } + + case GLFW_RELEASE: + { + MouseButtonReleasedEvent e(static_cast(button)); + callback(e); + break; + } + } + }); + + glfwSetScrollCallback(m_Window, [](GLFWwindow* window, double xOffset, double yOffset) + { + const EventCallbackFn& callback = *static_cast(glfwGetWindowUserPointer(window)); + MouseScrolledEvent e(static_cast(xOffset), static_cast(yOffset)); + callback(e); + }); + + glfwSetCursorPosCallback(m_Window, [](GLFWwindow* window, double xPos, double yPos) + { + const EventCallbackFn& callback = *static_cast(glfwGetWindowUserPointer(window)); + MouseMovedEvent e(static_cast(xPos), static_cast(yPos)); + callback(e); + }); + } + + void Window::Shutdown() const + { + m_Context->Shutdown(); + + glfwDestroyWindow(m_Window); + glfwTerminate(); + } + + void Window::ProcessEvents() + { + glfwPollEvents(); + } + + void Window::SetWindowTitle(const std::string& name) const + { + glfwSetWindowTitle(m_Window, name.c_str()); + } } diff --git a/EppoEngine/Source/Platform/FileDialog.h b/EppoEngine/Source/Platform/FileDialog.h index 07eb7f07..8f36eb1b 100644 --- a/EppoEngine/Source/Platform/FileDialog.h +++ b/EppoEngine/Source/Platform/FileDialog.h @@ -4,10 +4,10 @@ namespace Eppo { - class FileDialog - { - public: - static std::filesystem::path OpenFile(const char* filter, const std::filesystem::path& initialDir); - static std::filesystem::path SaveFile(const char* filter); - }; + class FileDialog + { + public: + static std::filesystem::path OpenFile(const char* filter, const std::filesystem::path& initialDir); + static std::filesystem::path SaveFile(const char* filter); + }; } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanCommandBuffer.cpp b/EppoEngine/Source/Platform/Vulkan/VulkanCommandBuffer.cpp index 564cb7d0..2b148c28 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanCommandBuffer.cpp +++ b/EppoEngine/Source/Platform/Vulkan/VulkanCommandBuffer.cpp @@ -6,234 +6,234 @@ namespace Eppo { - VulkanCommandBuffer::VulkanCommandBuffer(const bool manualSubmission, uint32_t count) - : m_ManualSubmission(manualSubmission) - { - const auto context = VulkanContext::Get(); - const auto logicalDevice = context->GetLogicalDevice(); - const VkDevice device = logicalDevice->GetNativeDevice(); + VulkanCommandBuffer::VulkanCommandBuffer(const bool manualSubmission, uint32_t count) + : m_ManualSubmission(manualSubmission) + { + const auto context = VulkanContext::Get(); + const auto logicalDevice = context->GetLogicalDevice(); + const VkDevice device = logicalDevice->GetNativeDevice(); - // Create command pool - VkCommandPoolCreateInfo commandPoolCreateInfo{}; - commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - commandPoolCreateInfo.queueFamilyIndex = context->GetPhysicalDevice()->GetQueueFamilyIndices().Graphics; - commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + // Create command pool + VkCommandPoolCreateInfo commandPoolCreateInfo{}; + commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + commandPoolCreateInfo.queueFamilyIndex = context->GetPhysicalDevice()->GetQueueFamilyIndices().Graphics; + commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - VK_CHECK(vkCreateCommandPool(device, &commandPoolCreateInfo, nullptr, &m_CommandPool), "Failed to create command pool!"); + VK_CHECK(vkCreateCommandPool(device, &commandPoolCreateInfo, nullptr, &m_CommandPool), "Failed to create command pool!"); - // Allocate command buffers - if (count == 0) - count = VulkanConfig::MaxFramesInFlight; + // Allocate command buffers + if (count == 0) + count = VulkanConfig::MaxFramesInFlight; - m_CommandBuffers.resize(count); + m_CommandBuffers.resize(count); - VkCommandBufferAllocateInfo commandBufferAllocateInfo{}; - commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - commandBufferAllocateInfo.commandPool = m_CommandPool; - commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - commandBufferAllocateInfo.commandBufferCount = count; + VkCommandBufferAllocateInfo commandBufferAllocateInfo{}; + commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + commandBufferAllocateInfo.commandPool = m_CommandPool; + commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + commandBufferAllocateInfo.commandBufferCount = count; - VK_CHECK(vkAllocateCommandBuffers(device, &commandBufferAllocateInfo, m_CommandBuffers.data()), "Failed to allocate command buffers!"); + VK_CHECK(vkAllocateCommandBuffers(device, &commandBufferAllocateInfo, m_CommandBuffers.data()), "Failed to allocate command buffers!"); - // Create fences - m_Fences.resize(count); + // Create fences + m_Fences.resize(count); - VkFenceCreateInfo fenceCreateInfo{}; - fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + VkFenceCreateInfo fenceCreateInfo{}; + fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - for (auto& fence : m_Fences) + for (auto& fence : m_Fences) VK_CHECK(vkCreateFence(device, &fenceCreateInfo, nullptr, &fence), "Failed to create fences!"); - // Queries - const VkCommandBuffer commandBuffer = logicalDevice->GetCommandBuffer(true); - m_QueryPools.resize(VulkanConfig::MaxFramesInFlight); + // Queries + const VkCommandBuffer commandBuffer = logicalDevice->GetCommandBuffer(true); + m_QueryPools.resize(VulkanConfig::MaxFramesInFlight); - VkQueryPoolCreateInfo queryPoolInfo{}; - queryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; - queryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP; - queryPoolInfo.queryCount = m_QueryCount; + VkQueryPoolCreateInfo queryPoolInfo{}; + queryPoolInfo.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; + queryPoolInfo.queryType = VK_QUERY_TYPE_TIMESTAMP; + queryPoolInfo.queryCount = m_QueryCount; - for (auto& queryPool : m_QueryPools) - { + for (auto& queryPool : m_QueryPools) + { VK_CHECK(vkCreateQueryPool(device, &queryPoolInfo, nullptr, &queryPool), "Failed to create query pool!"); - vkCmdResetQueryPool(commandBuffer, queryPool, 0, m_QueryCount); - } - - m_Timestamps.resize(VulkanConfig::MaxFramesInFlight); - for (auto& timestamp : m_Timestamps) - timestamp.resize(m_QueryCount); - - m_TimestampDeltas.resize(VulkanConfig::MaxFramesInFlight); - for (auto& timestamp : m_TimestampDeltas) - timestamp.resize(m_QueryCount / 2); - - m_PipelineQueryPools.resize(VulkanConfig::MaxFramesInFlight); - queryPoolInfo.queryType = VK_QUERY_TYPE_PIPELINE_STATISTICS; - queryPoolInfo.queryCount = m_PipelineQueryCount; - queryPoolInfo.pipelineStatistics = - VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT | - VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT | - VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT | - VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT | - VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT | - VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT; - - for (auto& pipelineQueryPool : m_PipelineQueryPools) - { + vkCmdResetQueryPool(commandBuffer, queryPool, 0, m_QueryCount); + } + + m_Timestamps.resize(VulkanConfig::MaxFramesInFlight); + for (auto& timestamp : m_Timestamps) + timestamp.resize(m_QueryCount); + + m_TimestampDeltas.resize(VulkanConfig::MaxFramesInFlight); + for (auto& timestamp : m_TimestampDeltas) + timestamp.resize(m_QueryCount / 2); + + m_PipelineQueryPools.resize(VulkanConfig::MaxFramesInFlight); + queryPoolInfo.queryType = VK_QUERY_TYPE_PIPELINE_STATISTICS; + queryPoolInfo.queryCount = m_PipelineQueryCount; + queryPoolInfo.pipelineStatistics = + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT | + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT | + VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT | + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT | + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT | + VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT; + + for (auto& pipelineQueryPool : m_PipelineQueryPools) + { VK_CHECK(vkCreateQueryPool(device, &queryPoolInfo, nullptr, &pipelineQueryPool), "Failed to create query pool!"); - vkCmdResetQueryPool(commandBuffer, pipelineQueryPool, 0, m_PipelineQueryCount); - } - - logicalDevice->FlushCommandBuffer(commandBuffer); - - m_PipelineStatistics.resize(VulkanConfig::MaxFramesInFlight); - - // Cleanup - context->SubmitResourceFree([this, device]() - { - for (uint32_t i = 0; i < VulkanConfig::MaxFramesInFlight; i++) - { - vkDestroyQueryPool(device, m_QueryPools[i], nullptr); - vkDestroyQueryPool(device, m_PipelineQueryPools[i], nullptr); - vkDestroyFence(device, m_Fences[i], nullptr); - } - - vkDestroyCommandPool(device, m_CommandPool, nullptr); - }); - } - - void VulkanCommandBuffer::RT_Begin() - { - m_QueryIndex = 2; - - const auto renderer = VulkanContext::Get()->GetRenderer(); - renderer->SubmitCommand([this]() - { - const auto context = VulkanContext::Get(); - const uint32_t frameIndex = context->GetCurrentFrameIndex(); - - VkCommandBufferBeginInfo commandBufferBeginInfo{}; - commandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - commandBufferBeginInfo.pNext = nullptr; - - VK_CHECK(vkBeginCommandBuffer(m_CommandBuffers[frameIndex], &commandBufferBeginInfo), "Failed to begin command buffer!"); - - vkCmdResetQueryPool(m_CommandBuffers[frameIndex], m_QueryPools[frameIndex], 0, m_QueryCount); - vkCmdWriteTimestamp2(m_CommandBuffers[frameIndex], VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, m_QueryPools[frameIndex], 0); - - vkCmdResetQueryPool(m_CommandBuffers[frameIndex], m_PipelineQueryPools[frameIndex], 0, m_PipelineQueryCount); - vkCmdBeginQuery(m_CommandBuffers[frameIndex], m_PipelineQueryPools[frameIndex], 0, 0); - }); - } - - void VulkanCommandBuffer::RT_End() - { - const auto renderer = VulkanContext::Get()->GetRenderer(); - renderer->SubmitCommand([this]() - { - const auto context = VulkanContext::Get(); - const uint32_t frameIndex = context->GetCurrentFrameIndex(); - - vkCmdWriteTimestamp(m_CommandBuffers[frameIndex], VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, m_QueryPools[frameIndex], 1); - vkCmdEndQuery(m_CommandBuffers[frameIndex], m_PipelineQueryPools[frameIndex], 0); - - VK_CHECK(vkEndCommandBuffer(m_CommandBuffers[frameIndex]), "Failed to end command buffer!"); - - // Statistics - const auto physicalDevice = context->GetPhysicalDevice(); - const VkDevice device = context->GetLogicalDevice()->GetNativeDevice(); - vkGetQueryPoolResults(device, m_QueryPools[frameIndex], 0, m_QueryCount, sizeof(uint64_t) * m_QueryCount, m_Timestamps[frameIndex].data(), sizeof(uint64_t), VK_QUERY_RESULT_64_BIT); - - for (uint32_t i = 0; i < m_QueryIndex; i += 2) - { - const uint64_t begin = m_Timestamps[frameIndex][i]; - const uint64_t end = m_Timestamps[frameIndex][i + 1]; - - float delta = 0.0f; - if (end > begin) - delta = (end - begin) * physicalDevice->GetDeviceProperties().limits.timestampPeriod * 0.000001f; - - m_TimestampDeltas[frameIndex][i / 2] = delta; - } - - vkGetQueryPoolResults(device, m_PipelineQueryPools[frameIndex], 0, 1, sizeof(PipelineStatistics), &m_PipelineStatistics[frameIndex], sizeof(uint64_t), VK_QUERY_RESULT_64_BIT); - }); - } - - void VulkanCommandBuffer::RT_Submit() const - { - if (!m_ManualSubmission) - { - EPPO_WARN("Trying to manually submit command buffer on a command buffer that will be submitted automatically!"); - return; - } - - const auto renderer = VulkanContext::Get()->GetRenderer(); - renderer->SubmitCommand([this]() - { - const auto context = VulkanContext::Get(); - const auto logicalDevice = context->GetLogicalDevice(); - const VkDevice device = logicalDevice->GetNativeDevice(); - const uint32_t frameIndex = context->GetCurrentFrameIndex(); - - VkCommandBufferSubmitInfo cmdSubmitInfo{}; - cmdSubmitInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO; - cmdSubmitInfo.commandBuffer = m_CommandBuffers[frameIndex]; - - VkSubmitInfo2 submitInfo{}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2; - submitInfo.pCommandBufferInfos = &cmdSubmitInfo; - - VK_CHECK(vkResetFences(device, 1, &m_Fences[frameIndex]), "Failed to reset fence!"); + vkCmdResetQueryPool(commandBuffer, pipelineQueryPool, 0, m_PipelineQueryCount); + } + + logicalDevice->FlushCommandBuffer(commandBuffer); + + m_PipelineStatistics.resize(VulkanConfig::MaxFramesInFlight); + + // Cleanup + context->SubmitResourceFree([this, device]() + { + for (uint32_t i = 0; i < VulkanConfig::MaxFramesInFlight; i++) + { + vkDestroyQueryPool(device, m_QueryPools[i], nullptr); + vkDestroyQueryPool(device, m_PipelineQueryPools[i], nullptr); + vkDestroyFence(device, m_Fences[i], nullptr); + } + + vkDestroyCommandPool(device, m_CommandPool, nullptr); + }); + } + + void VulkanCommandBuffer::RT_Begin() + { + m_QueryIndex = 2; + + const auto renderer = VulkanContext::Get()->GetRenderer(); + renderer->SubmitCommand([this]() + { + const auto context = VulkanContext::Get(); + const uint32_t frameIndex = context->GetCurrentFrameIndex(); + + VkCommandBufferBeginInfo commandBufferBeginInfo{}; + commandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + commandBufferBeginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + commandBufferBeginInfo.pNext = nullptr; + + VK_CHECK(vkBeginCommandBuffer(m_CommandBuffers[frameIndex], &commandBufferBeginInfo), "Failed to begin command buffer!"); + + vkCmdResetQueryPool(m_CommandBuffers[frameIndex], m_QueryPools[frameIndex], 0, m_QueryCount); + vkCmdWriteTimestamp2(m_CommandBuffers[frameIndex], VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, m_QueryPools[frameIndex], 0); + + vkCmdResetQueryPool(m_CommandBuffers[frameIndex], m_PipelineQueryPools[frameIndex], 0, m_PipelineQueryCount); + vkCmdBeginQuery(m_CommandBuffers[frameIndex], m_PipelineQueryPools[frameIndex], 0, 0); + }); + } + + void VulkanCommandBuffer::RT_End() + { + const auto renderer = VulkanContext::Get()->GetRenderer(); + renderer->SubmitCommand([this]() + { + const auto context = VulkanContext::Get(); + const uint32_t frameIndex = context->GetCurrentFrameIndex(); + + vkCmdWriteTimestamp(m_CommandBuffers[frameIndex], VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, m_QueryPools[frameIndex], 1); + vkCmdEndQuery(m_CommandBuffers[frameIndex], m_PipelineQueryPools[frameIndex], 0); + + VK_CHECK(vkEndCommandBuffer(m_CommandBuffers[frameIndex]), "Failed to end command buffer!"); + + // Statistics + const auto physicalDevice = context->GetPhysicalDevice(); + const VkDevice device = context->GetLogicalDevice()->GetNativeDevice(); + vkGetQueryPoolResults(device, m_QueryPools[frameIndex], 0, m_QueryCount, sizeof(uint64_t) * m_QueryCount, m_Timestamps[frameIndex].data(), sizeof(uint64_t), VK_QUERY_RESULT_64_BIT); + + for (uint32_t i = 0; i < m_QueryIndex; i += 2) + { + const uint64_t begin = m_Timestamps[frameIndex][i]; + const uint64_t end = m_Timestamps[frameIndex][i + 1]; + + float delta = 0.0f; + if (end > begin) + delta = (end - begin) * physicalDevice->GetDeviceProperties().limits.timestampPeriod * 0.000001f; + + m_TimestampDeltas[frameIndex][i / 2] = delta; + } + + vkGetQueryPoolResults(device, m_PipelineQueryPools[frameIndex], 0, 1, sizeof(PipelineStatistics), &m_PipelineStatistics[frameIndex], sizeof(uint64_t), VK_QUERY_RESULT_64_BIT); + }); + } + + void VulkanCommandBuffer::RT_Submit() const + { + if (!m_ManualSubmission) + { + EPPO_WARN("Trying to manually submit command buffer on a command buffer that will be submitted automatically!"); + return; + } + + const auto renderer = VulkanContext::Get()->GetRenderer(); + renderer->SubmitCommand([this]() + { + const auto context = VulkanContext::Get(); + const auto logicalDevice = context->GetLogicalDevice(); + const VkDevice device = logicalDevice->GetNativeDevice(); + const uint32_t frameIndex = context->GetCurrentFrameIndex(); + + VkCommandBufferSubmitInfo cmdSubmitInfo{}; + cmdSubmitInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO; + cmdSubmitInfo.commandBuffer = m_CommandBuffers[frameIndex]; + + VkSubmitInfo2 submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2; + submitInfo.pCommandBufferInfos = &cmdSubmitInfo; + + VK_CHECK(vkResetFences(device, 1, &m_Fences[frameIndex]), "Failed to reset fence!"); VK_CHECK(vkQueueSubmit2(logicalDevice->GetGraphicsQueue(), 1, &submitInfo, m_Fences[frameIndex]), "Failed to submit work to queue!"); VK_CHECK(vkWaitForFences(device, 1, &m_Fences[frameIndex], VK_TRUE, UINT64_MAX), "Failed to wait for fence!"); - }); - } - - uint32_t VulkanCommandBuffer::RT_BeginTimestampQuery() - { - uint32_t queryIndex = m_QueryIndex; - m_QueryIndex += 2; - - const auto renderer = VulkanContext::Get()->GetRenderer(); - renderer->SubmitCommand([this, queryIndex]() - { - const uint32_t imageIndex = VulkanContext::Get()->GetCurrentFrameIndex(); - - vkCmdWriteTimestamp(m_CommandBuffers[imageIndex], VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, m_QueryPools[imageIndex], queryIndex); - }); - - return queryIndex; - } - - void VulkanCommandBuffer::RT_EndTimestampQuery(uint32_t queryIndex) const - { - const auto renderer = VulkanContext::Get()->GetRenderer(); - renderer->SubmitCommand([this, queryIndex]() - { - const uint32_t imageIndex = VulkanContext::Get()->GetCurrentFrameIndex(); - - vkCmdWriteTimestamp(m_CommandBuffers[imageIndex], VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, m_QueryPools[imageIndex], queryIndex + 1); - }); - } - - float VulkanCommandBuffer::GetTimestamp(const uint32_t frameIndex, const uint32_t queryIndex) const - { - const auto& timing = m_TimestampDeltas[frameIndex]; - - return timing[queryIndex / 2]; - } - - void VulkanCommandBuffer::ResetCommandBuffer(const uint32_t frameIndex) const - { - vkResetCommandBuffer(m_CommandBuffers[frameIndex], 0); - } - - VkCommandBuffer VulkanCommandBuffer::GetCurrentCommandBuffer() const - { - const uint32_t imageIndex = VulkanContext::Get()->GetCurrentFrameIndex(); - return m_CommandBuffers[imageIndex]; - } + }); + } + + uint32_t VulkanCommandBuffer::RT_BeginTimestampQuery() + { + uint32_t queryIndex = m_QueryIndex; + m_QueryIndex += 2; + + const auto renderer = VulkanContext::Get()->GetRenderer(); + renderer->SubmitCommand([this, queryIndex]() + { + const uint32_t imageIndex = VulkanContext::Get()->GetCurrentFrameIndex(); + + vkCmdWriteTimestamp(m_CommandBuffers[imageIndex], VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, m_QueryPools[imageIndex], queryIndex); + }); + + return queryIndex; + } + + void VulkanCommandBuffer::RT_EndTimestampQuery(uint32_t queryIndex) const + { + const auto renderer = VulkanContext::Get()->GetRenderer(); + renderer->SubmitCommand([this, queryIndex]() + { + const uint32_t imageIndex = VulkanContext::Get()->GetCurrentFrameIndex(); + + vkCmdWriteTimestamp(m_CommandBuffers[imageIndex], VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, m_QueryPools[imageIndex], queryIndex + 1); + }); + } + + float VulkanCommandBuffer::GetTimestamp(const uint32_t frameIndex, const uint32_t queryIndex) const + { + const auto& timing = m_TimestampDeltas[frameIndex]; + + return timing[queryIndex / 2]; + } + + void VulkanCommandBuffer::ResetCommandBuffer(const uint32_t frameIndex) const + { + vkResetCommandBuffer(m_CommandBuffers[frameIndex], 0); + } + + VkCommandBuffer VulkanCommandBuffer::GetCurrentCommandBuffer() const + { + const uint32_t imageIndex = VulkanContext::Get()->GetCurrentFrameIndex(); + return m_CommandBuffers[imageIndex]; + } } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanCommandBuffer.h b/EppoEngine/Source/Platform/Vulkan/VulkanCommandBuffer.h index 4ef7e670..bcd7daed 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanCommandBuffer.h +++ b/EppoEngine/Source/Platform/Vulkan/VulkanCommandBuffer.h @@ -5,49 +5,53 @@ namespace Eppo { - struct PipelineStatistics - { - uint64_t InputAssemblyVertices = 0; - uint64_t InputAssemblyPrimitives = 0; - uint64_t VertexShaderInvocations = 0; - uint64_t ClippingInvocations = 0; - uint64_t ClippingPrimitives = 0; - uint64_t FragmentShaderInvocations = 0; - }; - - class VulkanCommandBuffer : public CommandBuffer - { - public: - VulkanCommandBuffer(bool manualSubmission, uint32_t count); - ~VulkanCommandBuffer() override = default; - - void RT_Begin() override; - void RT_End() override; - void RT_Submit() const override; - - uint32_t RT_BeginTimestampQuery(); - void RT_EndTimestampQuery(uint32_t queryIndex) const; - [[nodiscard]] float GetTimestamp(uint32_t frameIndex, uint32_t queryIndex = 0) const; - [[nodiscard]] const PipelineStatistics& GetPipelineStatistics(const uint32_t frameIndex) const { return m_PipelineStatistics[frameIndex]; } - - void ResetCommandBuffer(uint32_t frameIndex) const; - [[nodiscard]] VkCommandBuffer GetCurrentCommandBuffer() const; - - private: - VkCommandPool m_CommandPool; - std::vector m_CommandBuffers; - std::vector m_Fences; - - std::vector m_QueryPools; - std::vector> m_Timestamps; - std::vector> m_TimestampDeltas; - uint32_t m_QueryIndex = 2; - uint32_t m_QueryCount = 12; - - std::vector m_PipelineQueryPools; - std::vector m_PipelineStatistics; - uint32_t m_PipelineQueryCount = 6; - - bool m_ManualSubmission; - }; + struct PipelineStatistics + { + uint64_t InputAssemblyVertices = 0; + uint64_t InputAssemblyPrimitives = 0; + uint64_t VertexShaderInvocations = 0; + uint64_t ClippingInvocations = 0; + uint64_t ClippingPrimitives = 0; + uint64_t FragmentShaderInvocations = 0; + }; + + class VulkanCommandBuffer final : public CommandBuffer + { + public: + VulkanCommandBuffer(bool manualSubmission, uint32_t count); + ~VulkanCommandBuffer() override = default; + + void RT_Begin() override; + void RT_End() override; + void RT_Submit() const override; + + uint32_t RT_BeginTimestampQuery(); + void RT_EndTimestampQuery(uint32_t queryIndex) const; + [[nodiscard]] float GetTimestamp(uint32_t frameIndex, uint32_t queryIndex = 0) const; + + [[nodiscard]] const PipelineStatistics& GetPipelineStatistics(const uint32_t frameIndex) const + { + return m_PipelineStatistics[frameIndex]; + } + + void ResetCommandBuffer(uint32_t frameIndex) const; + [[nodiscard]] VkCommandBuffer GetCurrentCommandBuffer() const; + + private: + VkCommandPool m_CommandPool; + std::vector m_CommandBuffers; + std::vector m_Fences; + + std::vector m_QueryPools; + std::vector> m_Timestamps; + std::vector> m_TimestampDeltas; + uint32_t m_QueryIndex = 2; + uint32_t m_QueryCount = 12; + + std::vector m_PipelineQueryPools; + std::vector m_PipelineStatistics; + uint32_t m_PipelineQueryCount = 6; + + bool m_ManualSubmission; + }; } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanContext.cpp b/EppoEngine/Source/Platform/Vulkan/VulkanContext.cpp index 6e36d3aa..12e9a77e 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanContext.cpp +++ b/EppoEngine/Source/Platform/Vulkan/VulkanContext.cpp @@ -8,147 +8,147 @@ namespace Eppo { - VulkanContext::VulkanContext(GLFWwindow* windowHandle) - : m_WindowHandle(windowHandle) - { + VulkanContext::VulkanContext(GLFWwindow* windowHandle) + : m_WindowHandle(windowHandle) + { EPPO_ASSERT(windowHandle); - } + } - void VulkanContext::Init() - { - // Initialize Volk for loading Vulkan functions + void VulkanContext::Init() + { + // Initialize Volk for loading Vulkan functions VK_CHECK(volkInitialize(), "Failed to initialize volk!"); - VkApplicationInfo appInfo{}; - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.pApplicationName = "EppoEngine"; - appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); - appInfo.pEngineName = "EppoEngine"; - appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); - appInfo.apiVersion = VK_API_VERSION_1_3; - - const auto extensions = GetRequiredExtensions(); - - VkInstanceCreateInfo instanceInfo{}; - instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - instanceInfo.pApplicationInfo = &appInfo; - instanceInfo.enabledExtensionCount = static_cast(extensions.size()); - instanceInfo.ppEnabledExtensionNames = extensions.data(); - - VkDebugUtilsMessengerCreateInfoEXT debugInfo{}; - if (VulkanConfig::EnableValidation) - { - instanceInfo.enabledLayerCount = static_cast(VulkanConfig::ValidationLayers.size()); - instanceInfo.ppEnabledLayerNames = VulkanConfig::ValidationLayers.data(); - - debugInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - debugInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - debugInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; - debugInfo.pfnUserCallback = DebugCallback; - debugInfo.pUserData = nullptr; - - instanceInfo.pNext = &debugInfo; - } - else - { - instanceInfo.enabledLayerCount = 0; - instanceInfo.pNext = nullptr; - } - - VK_CHECK(vkCreateInstance(&instanceInfo, nullptr, &s_Instance), "Failed to create instance!"); - - // After creating vulkan instance, load all required vulkan entrypoints - volkLoadInstance(s_Instance); - - // Debug messenger + VkApplicationInfo appInfo{}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.pApplicationName = "EppoEngine"; + appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.pEngineName = "EppoEngine"; + appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); + appInfo.apiVersion = VK_API_VERSION_1_3; + + const auto extensions = GetRequiredExtensions(); + + VkInstanceCreateInfo instanceInfo{}; + instanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + instanceInfo.pApplicationInfo = &appInfo; + instanceInfo.enabledExtensionCount = static_cast(extensions.size()); + instanceInfo.ppEnabledExtensionNames = extensions.data(); + + VkDebugUtilsMessengerCreateInfoEXT debugInfo{}; + if (VulkanConfig::EnableValidation) + { + instanceInfo.enabledLayerCount = static_cast(VulkanConfig::ValidationLayers.size()); + instanceInfo.ppEnabledLayerNames = VulkanConfig::ValidationLayers.data(); + + debugInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + debugInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + debugInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + debugInfo.pfnUserCallback = DebugCallback; + debugInfo.pUserData = nullptr; + + instanceInfo.pNext = &debugInfo; + } + else + { + instanceInfo.enabledLayerCount = 0; + instanceInfo.pNext = nullptr; + } + + VK_CHECK(vkCreateInstance(&instanceInfo, nullptr, &s_Instance), "Failed to create instance!"); + + // After creating vulkan instance, load all required vulkan entrypoints + volkLoadInstance(s_Instance); + + // Debug messenger if (VulkanConfig::EnableValidation) VK_CHECK(CreateDebugUtilsMessengerEXT(s_Instance, &debugInfo, nullptr, &m_DebugMessenger), "Failed to create debug messenger!"); - // Devices - m_PhysicalDevice = CreateRef(); - m_LogicalDevice = CreateRef(m_PhysicalDevice); - - // Allocator - VulkanAllocator::Init(); - - // Swapchain - m_Swapchain = CreateRef(m_LogicalDevice); - - // Renderer - m_Renderer = CreateRef(); - - // Create tracy profiler context - const VkCommandBuffer cmd = m_LogicalDevice->GetCommandBuffer(false); - - #if defined(TRACY_ENABLE) - m_TracyContext = TracyVkContext( - m_PhysicalDevice->GetNativeDevice(), - m_LogicalDevice->GetNativeDevice(), - m_LogicalDevice->GetGraphicsQueue(), - cmd - ) - #endif - - m_LogicalDevice->FreeCommandBuffer(cmd); - } - - void VulkanContext::Shutdown() - { - #if defined(TRACY_ENABLE) - EPPO_MEM_WARN("Releasing tracy context {}", static_cast(m_TracyContext)); - TracyVkDestroy(m_TracyContext) - #endif - - m_Renderer->Shutdown(); - m_GarbageCollector.Shutdown(); - - if (VulkanConfig::EnableValidation) - DestroyDebugUtilsMessengerEXT(s_Instance, m_DebugMessenger, nullptr); - - EPPO_MEM_WARN("Releasing vulkan instance {}", static_cast(s_Instance)); - vkDestroyInstance(s_Instance, nullptr); - } - - void VulkanContext::BeginFrame() - { - m_Swapchain->BeginFrame(); - } - - void VulkanContext::PresentFrame() - { - m_Swapchain->PresentFrame(); - } - - void VulkanContext::WaitIdle() - { - vkDeviceWaitIdle(m_LogicalDevice->GetNativeDevice()); - } - - void VulkanContext::SubmitResourceFree(const std::function& fn, const bool freeOnShutdown) - { - m_GarbageCollector.SubmitFreeFn(fn, freeOnShutdown); - } - - void VulkanContext::RunGC(const uint32_t frameNumber) - { - m_GarbageCollector.Update(frameNumber); - } - - Ref VulkanContext::Get() - { - return std::static_pointer_cast(RendererContext::Get()); - } - - std::vector VulkanContext::GetRequiredExtensions() - { - uint32_t glfwExtensionCount = 0; - const char** glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); - - std::vector extensions(glfwExtensions, glfwExtensions + glfwExtensionCount); - - if (VulkanConfig::EnableValidation) - extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - - return extensions; - } + // Devices + m_PhysicalDevice = CreateRef(); + m_LogicalDevice = CreateRef(m_PhysicalDevice); + + // Allocator + VulkanAllocator::Init(); + + // Swapchain + m_Swapchain = CreateRef(m_LogicalDevice); + + // Renderer + m_Renderer = CreateRef(); + + // Create tracy profiler context + const VkCommandBuffer cmd = m_LogicalDevice->GetCommandBuffer(false); + + #if defined(TRACY_ENABLE) + m_TracyContext = TracyVkContext( + m_PhysicalDevice->GetNativeDevice(), + m_LogicalDevice->GetNativeDevice(), + m_LogicalDevice->GetGraphicsQueue(), + cmd + ) + #endif + + m_LogicalDevice->FreeCommandBuffer(cmd); + } + + void VulkanContext::Shutdown() + { + #if defined(TRACY_ENABLE) + EPPO_MEM_WARN("Releasing tracy context {}", static_cast(m_TracyContext)); + TracyVkDestroy(m_TracyContext) + #endif + + m_Renderer->Shutdown(); + m_GarbageCollector.Shutdown(); + + if (VulkanConfig::EnableValidation) + DestroyDebugUtilsMessengerEXT(s_Instance, m_DebugMessenger, nullptr); + + EPPO_MEM_WARN("Releasing vulkan instance {}", static_cast(s_Instance)); + vkDestroyInstance(s_Instance, nullptr); + } + + void VulkanContext::BeginFrame() + { + m_Swapchain->BeginFrame(); + } + + void VulkanContext::PresentFrame() + { + m_Swapchain->PresentFrame(); + } + + void VulkanContext::WaitIdle() + { + vkDeviceWaitIdle(m_LogicalDevice->GetNativeDevice()); + } + + void VulkanContext::SubmitResourceFree(const std::function& fn, const bool freeOnShutdown) + { + m_GarbageCollector.SubmitFreeFn(fn, freeOnShutdown); + } + + void VulkanContext::RunGC(const uint32_t frameNumber) + { + m_GarbageCollector.Update(frameNumber); + } + + Ref VulkanContext::Get() + { + return std::static_pointer_cast(RendererContext::Get()); + } + + std::vector VulkanContext::GetRequiredExtensions() + { + uint32_t glfwExtensionCount = 0; + const char** glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); + + std::vector extensions(glfwExtensions, glfwExtensions + glfwExtensionCount); + + if (VulkanConfig::EnableValidation) + extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + + return extensions; + } } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanContext.h b/EppoEngine/Source/Platform/Vulkan/VulkanContext.h index c43994e1..fae9733f 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanContext.h +++ b/EppoEngine/Source/Platform/Vulkan/VulkanContext.h @@ -13,54 +13,58 @@ namespace Eppo { - class VulkanContext : public RendererContext - { - public: - explicit VulkanContext(GLFWwindow* windowHandle); - ~VulkanContext() override = default; + class VulkanContext final : public RendererContext + { + public: + explicit VulkanContext(GLFWwindow* windowHandle); + VulkanContext(const VulkanContext&) = delete; + VulkanContext(const VulkanContext&&) = delete; + VulkanContext& operator=(const VulkanContext&) = delete; + VulkanContext& operator=(const VulkanContext&&) = delete; + ~VulkanContext() override = default; - void Init() override; - void Shutdown() override; + void Init() override; + void Shutdown() override; - [[nodiscard]] uint32_t GetCurrentFrameIndex() const override { return m_Swapchain->GetCurrentImageIndex(); } - void BeginFrame() override; - void PresentFrame() override; - void WaitIdle() override; + [[nodiscard]] uint32_t GetCurrentFrameIndex() const override { return m_Swapchain->GetCurrentImageIndex(); } + void BeginFrame() override; + void PresentFrame() override; + void WaitIdle() override; - void SubmitResourceFree(const std::function& fn, bool freeOnShutdown = true); - void RunGC(uint32_t frameNumber); + void SubmitResourceFree(const std::function& fn, bool freeOnShutdown = true); + void RunGC(uint32_t frameNumber); - [[nodiscard]] Ref GetLogicalDevice() const { return m_LogicalDevice; } - [[nodiscard]] Ref GetPhysicalDevice() const { return m_PhysicalDevice; } - [[nodiscard]] Ref GetSwapchain() const { return m_Swapchain; } + [[nodiscard]] Ref GetLogicalDevice() const { return m_LogicalDevice; } + [[nodiscard]] Ref GetPhysicalDevice() const { return m_PhysicalDevice; } + [[nodiscard]] Ref GetSwapchain() const { return m_Swapchain; } - [[nodiscard]] Ref GetRenderer() const override { return m_Renderer; } + [[nodiscard]] Ref GetRenderer() const override { return m_Renderer; } - DescriptorLayoutBuilder& GetDescriptorLayoutBuilder() { return m_DescriptorLayoutBuilder; } + DescriptorLayoutBuilder& GetDescriptorLayoutBuilder() { return m_DescriptorLayoutBuilder; } - static VkInstance GetVulkanInstance() { return s_Instance; } - GLFWwindow* GetWindowHandle() override { return m_WindowHandle; } - [[nodiscard]] TracyVkCtx GetTracyContext() const { return m_TracyContext; } + static VkInstance GetVulkanInstance() { return s_Instance; } + GLFWwindow* GetWindowHandle() override { return m_WindowHandle; } + [[nodiscard]] TracyVkCtx GetTracyContext() const { return m_TracyContext; } - static Ref Get(); + static Ref Get(); - private: - [[nodiscard]] static std::vector GetRequiredExtensions(); + private: + [[nodiscard]] static std::vector GetRequiredExtensions(); - private: - GLFWwindow* m_WindowHandle = nullptr; - VkDebugUtilsMessengerEXT m_DebugMessenger = nullptr; + private: + GLFWwindow* m_WindowHandle = nullptr; + VkDebugUtilsMessengerEXT m_DebugMessenger = nullptr; - Ref m_LogicalDevice; - Ref m_PhysicalDevice; - Ref m_Renderer; - Ref m_Swapchain; + Ref m_LogicalDevice; + Ref m_PhysicalDevice; + Ref m_Renderer; + Ref m_Swapchain; - DescriptorLayoutBuilder m_DescriptorLayoutBuilder; - GarbageCollector m_GarbageCollector; + DescriptorLayoutBuilder m_DescriptorLayoutBuilder; + GarbageCollector m_GarbageCollector; - TracyVkCtx m_TracyContext = nullptr; + TracyVkCtx m_TracyContext = nullptr; - inline static VkInstance s_Instance; - }; + inline static VkInstance s_Instance; + }; } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanDebugRenderer.cpp b/EppoEngine/Source/Platform/Vulkan/VulkanDebugRenderer.cpp index ee3dfa4b..b3a5a56a 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanDebugRenderer.cpp +++ b/EppoEngine/Source/Platform/Vulkan/VulkanDebugRenderer.cpp @@ -6,27 +6,27 @@ namespace Eppo { - void VulkanDebugRenderer::StartDebugLabel(const Ref& commandBuffer, const std::string& label) - { - const auto cmd = std::static_pointer_cast(commandBuffer); - const VkCommandBuffer cb = cmd->GetCurrentCommandBuffer(); + void VulkanDebugRenderer::StartDebugLabel(const Ref& commandBuffer, const std::string& label) + { + const auto cmd = std::static_pointer_cast(commandBuffer); + const VkCommandBuffer cb = cmd->GetCurrentCommandBuffer(); - VkDebugUtilsLabelEXT debugLabel{}; - debugLabel.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; - debugLabel.pLabelName = label.c_str(); - debugLabel.color[0] = 0.5f; - debugLabel.color[1] = 0.5f; - debugLabel.color[2] = 0.0f; - debugLabel.color[3] = 1.0f; + VkDebugUtilsLabelEXT debugLabel{}; + debugLabel.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT; + debugLabel.pLabelName = label.c_str(); + debugLabel.color[0] = 0.5f; + debugLabel.color[1] = 0.5f; + debugLabel.color[2] = 0.0f; + debugLabel.color[3] = 1.0f; - vkCmdBeginDebugUtilsLabelEXT(cb, &debugLabel); - } + vkCmdBeginDebugUtilsLabelEXT(cb, &debugLabel); + } - void VulkanDebugRenderer::EndDebugLabel(const Ref& commandBuffer) - { - const auto cmd = std::static_pointer_cast(commandBuffer); - const VkCommandBuffer cb = cmd->GetCurrentCommandBuffer(); + void VulkanDebugRenderer::EndDebugLabel(const Ref& commandBuffer) + { + const auto cmd = std::static_pointer_cast(commandBuffer); + const VkCommandBuffer cb = cmd->GetCurrentCommandBuffer(); - vkCmdEndDebugUtilsLabelEXT(cb); - } + vkCmdEndDebugUtilsLabelEXT(cb); + } } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanDebugRenderer.h b/EppoEngine/Source/Platform/Vulkan/VulkanDebugRenderer.h index a4fade2c..172966ca 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanDebugRenderer.h +++ b/EppoEngine/Source/Platform/Vulkan/VulkanDebugRenderer.h @@ -4,12 +4,12 @@ namespace Eppo { - class VulkanDebugRenderer : public DebugRenderer - { - public: - VulkanDebugRenderer() = default; + class VulkanDebugRenderer final : public DebugRenderer + { + public: + VulkanDebugRenderer() = default; - void StartDebugLabel(const Ref& commandBuffer, const std::string& label) override; - void EndDebugLabel(const Ref& commandBuffer) override; - }; + void StartDebugLabel(const Ref& commandBuffer, const std::string& label) override; + void EndDebugLabel(const Ref& commandBuffer) override; + }; } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanImage.cpp b/EppoEngine/Source/Platform/Vulkan/VulkanImage.cpp index 8efc8cee..f0745b42 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanImage.cpp +++ b/EppoEngine/Source/Platform/Vulkan/VulkanImage.cpp @@ -5,284 +5,286 @@ namespace Eppo { - VulkanImage::VulkanImage(ImageSpecification specification) - : m_Specification(std::move(specification)) - { - EPPO_PROFILE_FUNCTION("VulkanImage::VulkanImage"); - - // Do we have data? - if (!m_Specification.Filepath.empty()) - { - int width; - int height; - int channels; - - stbi_set_flip_vertically_on_load(1); - - if (stbi_is_hdr(m_Specification.Filepath.string().c_str())) - { - m_ImageData = stbi_loadf(m_Specification.Filepath.string().c_str(), &width, &height, &channels, 4); - m_IsHDR = true; - } - else - m_ImageData = stbi_load(m_Specification.Filepath.string().c_str(), &width, &height, &channels, 4); - - auto format = ImageFormat::None; - if (m_IsHDR) - format = ImageFormat::RGB16; - else - format = ImageFormat::RGBA8; - - m_Specification.Width = width; - m_Specification.Height = height; - m_Specification.Format = format; - m_Specification.Usage = ImageUsage::Texture; - } - - // Image usage - VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT; - if (m_Specification.Usage == ImageUsage::Texture) - { - usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - } - else - { - if (m_Specification.Format == ImageFormat::Depth) - usageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - else - usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - } - - // Image - VkImageCreateInfo imageCreateInfo{}; - imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; - imageCreateInfo.extent.width = m_Specification.Width; - imageCreateInfo.extent.height = m_Specification.Height; - imageCreateInfo.extent.depth = 1; - imageCreateInfo.mipLevels = 1; - imageCreateInfo.arrayLayers = m_Specification.CubeMap ? 6 : 1; - imageCreateInfo.format = Utils::ImageFormatToVkFormat(m_Specification.Format); - imageCreateInfo.usage = usageFlags; - imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageCreateInfo.flags = m_Specification.CubeMap ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0; - imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - m_ImageInfo.Allocation = VulkanAllocator::AllocateImage(m_ImageInfo.Image, imageCreateInfo, VMA_MEMORY_USAGE_GPU_ONLY); - - // Image view - VkImageViewCreateInfo imageViewCreateInfo{}; - imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - imageViewCreateInfo.image = m_ImageInfo.Image; - imageViewCreateInfo.viewType = m_Specification.CubeMap ? VK_IMAGE_VIEW_TYPE_CUBE : VK_IMAGE_VIEW_TYPE_2D; - imageViewCreateInfo.format = Utils::ImageFormatToVkFormat(m_Specification.Format); - imageViewCreateInfo.subresourceRange = {}; - imageViewCreateInfo.subresourceRange.aspectMask = Utils::IsDepthFormat(m_Specification.Format) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; - imageViewCreateInfo.subresourceRange.baseMipLevel = 0; - imageViewCreateInfo.subresourceRange.levelCount = 1; - imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; - imageViewCreateInfo.subresourceRange.layerCount = m_Specification.CubeMap ? 6 : 1; - - Ref context = VulkanContext::Get(); - VkDevice device = context->GetLogicalDevice()->GetNativeDevice(); + VulkanImage::VulkanImage(ImageSpecification specification) + : m_Specification(std::move(specification)) + { + EPPO_PROFILE_FUNCTION("VulkanImage::VulkanImage"); + + // Do we have data? + if (!m_Specification.Filepath.empty()) + { + int width; + int height; + int channels; + + stbi_set_flip_vertically_on_load(1); + + if (stbi_is_hdr(m_Specification.Filepath.string().c_str())) + { + m_ImageData = stbi_loadf(m_Specification.Filepath.string().c_str(), &width, &height, &channels, 4); + m_IsHDR = true; + } + else + m_ImageData = stbi_load(m_Specification.Filepath.string().c_str(), &width, &height, &channels, 4); + + auto format = ImageFormat::None; + if (m_IsHDR) + format = ImageFormat::RGB16; + else + format = ImageFormat::RGBA8; + + m_Specification.Width = width; + m_Specification.Height = height; + m_Specification.Format = format; + m_Specification.Usage = ImageUsage::Texture; + } + + // Image usage + VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_SAMPLED_BIT; + if (m_Specification.Usage == ImageUsage::Texture) + { + usageFlags |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + } + else + { + if (m_Specification.Format == ImageFormat::Depth) + usageFlags |= VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + else + usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + } + + // Image + VkImageCreateInfo imageCreateInfo{}; + imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; + imageCreateInfo.extent.width = m_Specification.Width; + imageCreateInfo.extent.height = m_Specification.Height; + imageCreateInfo.extent.depth = 1; + imageCreateInfo.mipLevels = 1; + imageCreateInfo.arrayLayers = m_Specification.CubeMap ? 6 : 1; + imageCreateInfo.format = Utils::ImageFormatToVkFormat(m_Specification.Format); + imageCreateInfo.usage = usageFlags; + imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageCreateInfo.flags = m_Specification.CubeMap ? VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT : 0; + imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + + m_ImageInfo.Allocation = VulkanAllocator::AllocateImage(m_ImageInfo.Image, imageCreateInfo, VMA_MEMORY_USAGE_GPU_ONLY); + + // Image view + VkImageViewCreateInfo imageViewCreateInfo{}; + imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imageViewCreateInfo.image = m_ImageInfo.Image; + imageViewCreateInfo.viewType = m_Specification.CubeMap ? VK_IMAGE_VIEW_TYPE_CUBE : VK_IMAGE_VIEW_TYPE_2D; + imageViewCreateInfo.format = Utils::ImageFormatToVkFormat(m_Specification.Format); + imageViewCreateInfo.subresourceRange = {}; + imageViewCreateInfo.subresourceRange.aspectMask = Utils::IsDepthFormat(m_Specification.Format) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; + imageViewCreateInfo.subresourceRange.baseMipLevel = 0; + imageViewCreateInfo.subresourceRange.levelCount = 1; + imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; + imageViewCreateInfo.subresourceRange.layerCount = m_Specification.CubeMap ? 6 : 1; + + Ref context = VulkanContext::Get(); + VkDevice device = context->GetLogicalDevice()->GetNativeDevice(); VK_CHECK(vkCreateImageView(device, &imageViewCreateInfo, nullptr, &m_ImageInfo.ImageView), "Failed to create image view!"); - // Sampler - Ref physicalDevice = context->GetPhysicalDevice(); - - VkSamplerCreateInfo samplerCreateInfo{}; - samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerCreateInfo.anisotropyEnable = VK_TRUE; - samplerCreateInfo.maxAnisotropy = physicalDevice->GetDeviceProperties().limits.maxSamplerAnisotropy; - samplerCreateInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; - samplerCreateInfo.unnormalizedCoordinates = VK_FALSE; - samplerCreateInfo.compareEnable = VK_FALSE; - samplerCreateInfo.compareOp = VK_COMPARE_OP_ALWAYS; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.mipLodBias = 0.0f; - samplerCreateInfo.minLod = 0.0f; - samplerCreateInfo.maxLod = 0.0f; - - VK_CHECK(vkCreateSampler(device, &samplerCreateInfo, nullptr, &m_ImageInfo.Sampler), "Failed to create sampler!"); - - VkCommandBuffer commandBuffer = context->GetLogicalDevice()->GetCommandBuffer(true); - - if (Utils::IsDepthFormat(m_Specification.Format)) - TransitionImage(commandBuffer, m_ImageInfo.Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL); - else - TransitionImage(commandBuffer, m_ImageInfo.Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - context->GetLogicalDevice()->FlushCommandBuffer(commandBuffer); - - if (m_Specification.Format == ImageFormat::Depth) - m_ImageInfo.ImageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; - else - m_ImageInfo.ImageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - if (m_ImageData) - { - SetData(m_ImageData); - stbi_image_free(m_ImageData); - m_ImageData = nullptr; - } - } - - VulkanImage::~VulkanImage() - { - Release(); - } - - void VulkanImage::SetData(void* data, const uint32_t channels) - { - EPPO_PROFILE_FUNCTION("VulkanImage::SetData"); - - uint64_t size = static_cast(m_Specification.Width) * m_Specification.Height * channels; - - // HDR uses 32 bit instead of 8 bit so we need double the size - if (m_IsHDR) - size *= 4; - - // Create staging buffer - VkBufferCreateInfo stagingBufferInfo{}; - stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - stagingBufferInfo.size = size; - stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - stagingBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VkBuffer stagingBuffer; - const VmaAllocation stagingBufferAlloc = VulkanAllocator::AllocateBuffer(stagingBuffer, stagingBufferInfo, VMA_MEMORY_USAGE_CPU_TO_GPU); - - void* memData = VulkanAllocator::MapMemory(stagingBufferAlloc); - memcpy(memData, data, size); - VulkanAllocator::UnmapMemory(stagingBufferAlloc); - - const VkCommandBuffer commandBuffer = VulkanContext::Get()->GetLogicalDevice()->GetCommandBuffer(true); - - // Transition to layout optimal for transferring - TransitionImage(commandBuffer, m_ImageInfo.Image, m_ImageInfo.ImageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - // Copy image data to image - VkBufferImageCopy copyRegion{}; - copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - copyRegion.imageSubresource.baseArrayLayer = 0; - copyRegion.imageSubresource.layerCount = 1; - copyRegion.imageSubresource.mipLevel = 0; - copyRegion.imageExtent.width = m_Specification.Width; - copyRegion.imageExtent.height = m_Specification.Height; - copyRegion.imageExtent.depth = 1; - copyRegion.bufferOffset = 0; - - vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, m_ImageInfo.Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); - - // Transition image back to presentable layout - TransitionImage(commandBuffer, m_ImageInfo.Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - // Flush command buffer - VulkanContext::Get()->GetLogicalDevice()->FlushCommandBuffer(commandBuffer); - - VulkanAllocator::DestroyBuffer(stagingBuffer, stagingBufferAlloc); - } - - void VulkanImage::Release() - { - const VkDevice device = VulkanContext::Get()->GetLogicalDevice()->GetNativeDevice(); - - if (m_ImageInfo.Sampler) - { - EPPO_MEM_WARN("Releasing sampler {}", static_cast(m_ImageInfo.Sampler)); - vkDestroySampler(device, m_ImageInfo.Sampler, nullptr); - m_ImageInfo.Sampler = nullptr; - } - - if (m_ImageInfo.ImageView) - { - EPPO_MEM_WARN("Releasing image view {}", static_cast(m_ImageInfo.ImageView)); - vkDestroyImageView(device, m_ImageInfo.ImageView, nullptr); - m_ImageInfo.ImageView = nullptr; - } - - if (m_ImageInfo.Image) - { - EPPO_MEM_WARN("Releasing image {}", static_cast(m_ImageInfo.Image)); - VulkanAllocator::DestroyImage(m_ImageInfo.Image, m_ImageInfo.Allocation); - m_ImageInfo.Image = nullptr; - m_ImageInfo.Allocation = nullptr; - } - } - - void VulkanImage::TransitionImage(const VkCommandBuffer commandBuffer, const VkImage image, const VkImageLayout srcLayout, const VkImageLayout dstLayout, VkPipelineStageFlags2 srcStageMask, VkPipelineStageFlags2 dstStageMask) - { - EPPO_PROFILE_FUNCTION("VulkanImage::TransitionImage"); - - if (!srcStageMask) - srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; - if (!dstStageMask) - dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; - - VkImageMemoryBarrier2 imageBarrier{}; - imageBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; - imageBarrier.srcStageMask = srcStageMask; - imageBarrier.dstStageMask = dstStageMask; - imageBarrier.srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT; - imageBarrier.dstAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT | VK_ACCESS_2_MEMORY_READ_BIT; - imageBarrier.oldLayout = srcLayout; - imageBarrier.newLayout = dstLayout; - imageBarrier.image = image; - imageBarrier.subresourceRange.aspectMask = GetImageAspectFlags(dstLayout); - imageBarrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; - imageBarrier.subresourceRange.baseArrayLayer = 0; - imageBarrier.subresourceRange.baseMipLevel = 0; - imageBarrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; - imageBarrier.pNext = nullptr; - - VkDependencyInfo depInfo{}; - depInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; - depInfo.imageMemoryBarrierCount = 1; - depInfo.pImageMemoryBarriers = &imageBarrier; - depInfo.pNext = nullptr; - - vkCmdPipelineBarrier2(commandBuffer, &depInfo); - } - - VkImageAspectFlags VulkanImage::GetImageAspectFlags(const VkImageLayout layout) - { - switch (layout) - { - case VK_IMAGE_LAYOUT_UNDEFINED: - { - return VK_IMAGE_ASPECT_NONE; - } - - case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: - case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - { - return VK_IMAGE_ASPECT_COLOR_BIT; - } - - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: - case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: - case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: - case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL: - case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL: - case VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL: - case VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL: - { - return VK_IMAGE_ASPECT_DEPTH_BIT; - } - } - - EPPO_ASSERT(false); - return VK_IMAGE_ASPECT_NONE; - } + // Sampler + Ref physicalDevice = context->GetPhysicalDevice(); + + VkSamplerCreateInfo samplerCreateInfo{}; + samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerCreateInfo.magFilter = VK_FILTER_LINEAR; + samplerCreateInfo.minFilter = VK_FILTER_LINEAR; + samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerCreateInfo.anisotropyEnable = VK_TRUE; + samplerCreateInfo.maxAnisotropy = physicalDevice->GetDeviceProperties().limits.maxSamplerAnisotropy; + samplerCreateInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK; + samplerCreateInfo.unnormalizedCoordinates = VK_FALSE; + samplerCreateInfo.compareEnable = VK_FALSE; + samplerCreateInfo.compareOp = VK_COMPARE_OP_ALWAYS; + samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerCreateInfo.mipLodBias = 0.0f; + samplerCreateInfo.minLod = 0.0f; + samplerCreateInfo.maxLod = 0.0f; + + VK_CHECK(vkCreateSampler(device, &samplerCreateInfo, nullptr, &m_ImageInfo.Sampler), "Failed to create sampler!"); + + VkCommandBuffer commandBuffer = context->GetLogicalDevice()->GetCommandBuffer(true); + + if (Utils::IsDepthFormat(m_Specification.Format)) + TransitionImage(commandBuffer, m_ImageInfo.Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL); + else + TransitionImage(commandBuffer, m_ImageInfo.Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + context->GetLogicalDevice()->FlushCommandBuffer(commandBuffer); + + if (m_Specification.Format == ImageFormat::Depth) + m_ImageInfo.ImageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL; + else + m_ImageInfo.ImageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + if (m_ImageData) + { + SetData(m_ImageData); + stbi_image_free(m_ImageData); + m_ImageData = nullptr; + } + } + + VulkanImage::~VulkanImage() + { + Release(); + } + + void VulkanImage::SetData(void* data, const uint32_t channels) + { + EPPO_PROFILE_FUNCTION("VulkanImage::SetData"); + + uint64_t size = static_cast(m_Specification.Width) * m_Specification.Height * channels; + + // HDR uses 32 bit instead of 8 bit so we need double the size + if (m_IsHDR) + size *= 4; + + // Create staging buffer + VkBufferCreateInfo stagingBufferInfo{}; + stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + stagingBufferInfo.size = size; + stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + stagingBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VkBuffer stagingBuffer; + const VmaAllocation stagingBufferAlloc = VulkanAllocator::AllocateBuffer(stagingBuffer, stagingBufferInfo, VMA_MEMORY_USAGE_CPU_TO_GPU); + + void* memData = VulkanAllocator::MapMemory(stagingBufferAlloc); + memcpy(memData, data, size); + VulkanAllocator::UnmapMemory(stagingBufferAlloc); + + const VkCommandBuffer commandBuffer = VulkanContext::Get()->GetLogicalDevice()->GetCommandBuffer(true); + + // Transition to layout optimal for transferring + TransitionImage(commandBuffer, m_ImageInfo.Image, m_ImageInfo.ImageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + // Copy image data to image + VkBufferImageCopy copyRegion{}; + copyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + copyRegion.imageSubresource.baseArrayLayer = 0; + copyRegion.imageSubresource.layerCount = 1; + copyRegion.imageSubresource.mipLevel = 0; + copyRegion.imageExtent.width = m_Specification.Width; + copyRegion.imageExtent.height = m_Specification.Height; + copyRegion.imageExtent.depth = 1; + copyRegion.bufferOffset = 0; + + vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, m_ImageInfo.Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); + + // Transition image back to presentable layout + TransitionImage(commandBuffer, m_ImageInfo.Image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + // Flush command buffer + VulkanContext::Get()->GetLogicalDevice()->FlushCommandBuffer(commandBuffer); + + VulkanAllocator::DestroyBuffer(stagingBuffer, stagingBufferAlloc); + } + + void VulkanImage::Release() + { + const VkDevice device = VulkanContext::Get()->GetLogicalDevice()->GetNativeDevice(); + + if (m_ImageInfo.Sampler) + { + EPPO_MEM_WARN("Releasing sampler {}", static_cast(m_ImageInfo.Sampler)); + vkDestroySampler(device, m_ImageInfo.Sampler, nullptr); + m_ImageInfo.Sampler = nullptr; + } + + if (m_ImageInfo.ImageView) + { + EPPO_MEM_WARN("Releasing image view {}", static_cast(m_ImageInfo.ImageView)); + vkDestroyImageView(device, m_ImageInfo.ImageView, nullptr); + m_ImageInfo.ImageView = nullptr; + } + + if (m_ImageInfo.Image) + { + EPPO_MEM_WARN("Releasing image {}", static_cast(m_ImageInfo.Image)); + VulkanAllocator::DestroyImage(m_ImageInfo.Image, m_ImageInfo.Allocation); + m_ImageInfo.Image = nullptr; + m_ImageInfo.Allocation = nullptr; + } + } + + void VulkanImage::TransitionImage(const VkCommandBuffer commandBuffer, const VkImage image, const VkImageLayout srcLayout, const VkImageLayout dstLayout, + VkPipelineStageFlags2 srcStageMask, + VkPipelineStageFlags2 dstStageMask) + { + EPPO_PROFILE_FUNCTION("VulkanImage::TransitionImage"); + + if (!srcStageMask) + srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; + if (!dstStageMask) + dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT; + + VkImageMemoryBarrier2 imageBarrier{}; + imageBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2; + imageBarrier.srcStageMask = srcStageMask; + imageBarrier.dstStageMask = dstStageMask; + imageBarrier.srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT; + imageBarrier.dstAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT | VK_ACCESS_2_MEMORY_READ_BIT; + imageBarrier.oldLayout = srcLayout; + imageBarrier.newLayout = dstLayout; + imageBarrier.image = image; + imageBarrier.subresourceRange.aspectMask = GetImageAspectFlags(dstLayout); + imageBarrier.subresourceRange.layerCount = VK_REMAINING_ARRAY_LAYERS; + imageBarrier.subresourceRange.baseArrayLayer = 0; + imageBarrier.subresourceRange.baseMipLevel = 0; + imageBarrier.subresourceRange.levelCount = VK_REMAINING_MIP_LEVELS; + imageBarrier.pNext = nullptr; + + VkDependencyInfo depInfo{}; + depInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO; + depInfo.imageMemoryBarrierCount = 1; + depInfo.pImageMemoryBarriers = &imageBarrier; + depInfo.pNext = nullptr; + + vkCmdPipelineBarrier2(commandBuffer, &depInfo); + } + + VkImageAspectFlags VulkanImage::GetImageAspectFlags(const VkImageLayout layout) + { + switch (layout) + { + case VK_IMAGE_LAYOUT_UNDEFINED: + { + return VK_IMAGE_ASPECT_NONE; + } + + case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR: + case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL: + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + { + return VK_IMAGE_ASPECT_COLOR_BIT; + } + + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL: + case VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL: + case VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL: + { + return VK_IMAGE_ASPECT_DEPTH_BIT; + } + } + + EPPO_ASSERT(false); + return VK_IMAGE_ASPECT_NONE; + } } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanImage.h b/EppoEngine/Source/Platform/Vulkan/VulkanImage.h index c0d5c526..666a2da7 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanImage.h +++ b/EppoEngine/Source/Platform/Vulkan/VulkanImage.h @@ -6,53 +6,59 @@ namespace Eppo { - struct ImageInfo - { - VkImage Image = nullptr; - VkImageView ImageView = nullptr; - VkImageLayout ImageLayout; - VkSampler Sampler = nullptr; - VmaAllocation Allocation = nullptr; - }; + struct ImageInfo + { + VkImage Image = nullptr; + VkImageView ImageView = nullptr; + VkImageLayout ImageLayout; + VkSampler Sampler = nullptr; + VmaAllocation Allocation = nullptr; + }; - class VulkanImage final : public Image - { - public: - explicit VulkanImage(ImageSpecification specification); - ~VulkanImage(); + class VulkanImage final : public Image + { + public: + explicit VulkanImage(ImageSpecification specification); + VulkanImage(const VulkanImage&) = delete; + VulkanImage(const VulkanImage&&) = delete; + VulkanImage& operator=(const VulkanImage&) = delete; + VulkanImage& operator=(const VulkanImage&&) = delete; + ~VulkanImage() override; - void SetData(void* data, uint32_t channels = 4) override; - void Release() override; + void SetData(void* data, uint32_t channels = 4) override; + void Release() override; - [[nodiscard]] const ImageSpecification& GetSpecification() const override { return m_Specification; } + [[nodiscard]] const ImageSpecification& GetSpecification() const override { return m_Specification; } - [[nodiscard]] uint32_t GetWidth() const override { return m_Specification.Width; } - [[nodiscard]] uint32_t GetHeight() const override { return m_Specification.Height; } + [[nodiscard]] uint32_t GetWidth() const override { return m_Specification.Width; } + [[nodiscard]] uint32_t GetHeight() const override { return m_Specification.Height; } - ImageInfo& GetImageInfo() { return m_ImageInfo; } + ImageInfo& GetImageInfo() { return m_ImageInfo; } - static void TransitionImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout srcLayout, VkImageLayout dstLayout, VkPipelineStageFlags2 srcStageMask = VK_PIPELINE_STAGE_2_NONE, VkPipelineStageFlags2 dstStageMask = VK_PIPELINE_STAGE_2_NONE); - static VkImageAspectFlags GetImageAspectFlags(VkImageLayout layout); + static void TransitionImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout srcLayout, VkImageLayout dstLayout, + VkPipelineStageFlags2 srcStageMask = VK_PIPELINE_STAGE_2_NONE, + VkPipelineStageFlags2 dstStageMask = VK_PIPELINE_STAGE_2_NONE); + static VkImageAspectFlags GetImageAspectFlags(VkImageLayout layout); - private: - ImageSpecification m_Specification; - ImageInfo m_ImageInfo; + private: + ImageSpecification m_Specification; + ImageInfo m_ImageInfo; - bool m_IsHDR = false; + bool m_IsHDR = false; - void* m_ImageData = nullptr; - }; + void* m_ImageData = nullptr; + }; - namespace Utils - { - inline VkFormat ImageFormatToVkFormat(ImageFormat format) - { - EPPO_ASSERT(format != ImageFormat::None); + namespace Utils + { + inline VkFormat ImageFormatToVkFormat(ImageFormat format) + { + EPPO_ASSERT(format != ImageFormat::None); - Ref context = VulkanContext::Get(); - Ref physicalDevice = context->GetPhysicalDevice(); + Ref context = VulkanContext::Get(); + Ref physicalDevice = context->GetPhysicalDevice(); - return physicalDevice->GetSupportedImageFormat(format); - } - } + return physicalDevice->GetSupportedImageFormat(format); + } + } } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanIndexBuffer.cpp b/EppoEngine/Source/Platform/Vulkan/VulkanIndexBuffer.cpp index 017f1df0..c39b03cb 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanIndexBuffer.cpp +++ b/EppoEngine/Source/Platform/Vulkan/VulkanIndexBuffer.cpp @@ -6,109 +6,110 @@ namespace Eppo { - VulkanIndexBuffer::VulkanIndexBuffer(const uint32_t size) - : m_Size(size), m_IsMemoryMapped(true) - { - // Create GPU local buffer - VkBufferCreateInfo indexBufferInfo{}; - indexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - indexBufferInfo.size = m_Size; - indexBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; - indexBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - m_Allocation = VulkanAllocator::AllocateBuffer(m_Buffer, indexBufferInfo, VMA_MEMORY_USAGE_CPU_TO_GPU); - m_MappedMemory = VulkanAllocator::MapMemory(m_Allocation); - } - - VulkanIndexBuffer::VulkanIndexBuffer(Buffer buffer) - : m_Size(buffer.Size), m_IsMemoryMapped(false) - { - EPPO_PROFILE_FUNCTION("VulkanIndexBuffer::VulkanIndexBuffer"); - - // Create GPU local buffer - VkBufferCreateInfo indexBufferInfo{}; - indexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - indexBufferInfo.size = m_Size; - indexBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; - indexBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - m_Allocation = VulkanAllocator::AllocateBuffer(m_Buffer, indexBufferInfo, VMA_MEMORY_USAGE_GPU_ONLY); - - CopyWithStagingBuffer(buffer); - } - - VulkanIndexBuffer::~VulkanIndexBuffer() - { - EPPO_MEM_WARN("Releasing index buffer {}", static_cast(this)); - - if (m_IsMemoryMapped) - VulkanAllocator::UnmapMemory(m_Allocation); - VulkanAllocator::DestroyBuffer(m_Buffer, m_Allocation); - } - - void VulkanIndexBuffer::SetData(const Buffer buffer) - { - // If buffer is bigger than our GPU buffer, recreate buffer - if (buffer.Size > m_Size) - { - // Create GPU local buffer - VkBufferCreateInfo indexBufferInfo{}; - indexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - indexBufferInfo.size = m_Size; - indexBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; - indexBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - if (m_IsMemoryMapped) - { - VulkanAllocator::UnmapMemory(m_Allocation); - m_Allocation = VulkanAllocator::AllocateBuffer(m_Buffer, indexBufferInfo, VMA_MEMORY_USAGE_CPU_TO_GPU); - m_MappedMemory = VulkanAllocator::MapMemory(m_Allocation); - } else - { - m_Allocation = VulkanAllocator::AllocateBuffer(m_Buffer, indexBufferInfo, VMA_MEMORY_USAGE_GPU_ONLY); - } - - m_Size = buffer.Size; - } - - // Now we have a GPU buffer of the correct size, copy data using either staging buffer or mapped memory - if (m_IsMemoryMapped) - memcpy(m_MappedMemory, buffer.Data, buffer.Size); - else - CopyWithStagingBuffer(buffer); - } - - void VulkanIndexBuffer::CopyWithStagingBuffer(const Buffer buffer) const - { - // Create staging buffer - VkBufferCreateInfo stagingBufferInfo{}; - stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - stagingBufferInfo.size = buffer.Size; - stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - stagingBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VkBuffer stagingBuffer; - const VmaAllocation stagingBufferAlloc = VulkanAllocator::AllocateBuffer(stagingBuffer, stagingBufferInfo, VMA_MEMORY_USAGE_CPU_TO_GPU); - - // Copy data to staging buffer - void* memData = VulkanAllocator::MapMemory(stagingBufferAlloc); - memcpy(memData, buffer.Data, buffer.Size); - VulkanAllocator::UnmapMemory(stagingBufferAlloc); - - // Copy data from staging buffer to GPU local buffer - const Ref context = VulkanContext::Get(); - const Ref logicalDevice = context->GetLogicalDevice(); - const VkCommandBuffer commandBuffer = logicalDevice->GetCommandBuffer(true); - - VkBufferCopy copyRegion; - copyRegion.srcOffset = 0; - copyRegion.dstOffset = 0; - copyRegion.size = buffer.Size; - - vkCmdCopyBuffer(commandBuffer, stagingBuffer, m_Buffer, 1, ©Region); - logicalDevice->FlushCommandBuffer(commandBuffer); - - // Clean up - VulkanAllocator::DestroyBuffer(stagingBuffer, stagingBufferAlloc); - } + VulkanIndexBuffer::VulkanIndexBuffer(const uint32_t size) + : m_Size(size), m_IsMemoryMapped(true) + { + // Create GPU local buffer + VkBufferCreateInfo indexBufferInfo{}; + indexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + indexBufferInfo.size = m_Size; + indexBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + indexBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + m_Allocation = VulkanAllocator::AllocateBuffer(m_Buffer, indexBufferInfo, VMA_MEMORY_USAGE_CPU_TO_GPU); + m_MappedMemory = VulkanAllocator::MapMemory(m_Allocation); + } + + VulkanIndexBuffer::VulkanIndexBuffer(Buffer buffer) + : m_Size(buffer.Size), m_IsMemoryMapped(false) + { + EPPO_PROFILE_FUNCTION("VulkanIndexBuffer::VulkanIndexBuffer"); + + // Create GPU local buffer + VkBufferCreateInfo indexBufferInfo{}; + indexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + indexBufferInfo.size = m_Size; + indexBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + indexBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + m_Allocation = VulkanAllocator::AllocateBuffer(m_Buffer, indexBufferInfo, VMA_MEMORY_USAGE_GPU_ONLY); + + CopyWithStagingBuffer(buffer); + } + + VulkanIndexBuffer::~VulkanIndexBuffer() + { + EPPO_MEM_WARN("Releasing index buffer {}", static_cast(this)); + + if (m_IsMemoryMapped) + VulkanAllocator::UnmapMemory(m_Allocation); + VulkanAllocator::DestroyBuffer(m_Buffer, m_Allocation); + } + + void VulkanIndexBuffer::SetData(const Buffer buffer) + { + // If buffer is bigger than our GPU buffer, recreate buffer + if (buffer.Size > m_Size) + { + // Create GPU local buffer + VkBufferCreateInfo indexBufferInfo{}; + indexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + indexBufferInfo.size = m_Size; + indexBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT; + indexBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + if (m_IsMemoryMapped) + { + VulkanAllocator::UnmapMemory(m_Allocation); + m_Allocation = VulkanAllocator::AllocateBuffer(m_Buffer, indexBufferInfo, VMA_MEMORY_USAGE_CPU_TO_GPU); + m_MappedMemory = VulkanAllocator::MapMemory(m_Allocation); + } + else + { + m_Allocation = VulkanAllocator::AllocateBuffer(m_Buffer, indexBufferInfo, VMA_MEMORY_USAGE_GPU_ONLY); + } + + m_Size = buffer.Size; + } + + // Now we have a GPU buffer of the correct size, copy data using either staging buffer or mapped memory + if (m_IsMemoryMapped) + memcpy(m_MappedMemory, buffer.Data, buffer.Size); + else + CopyWithStagingBuffer(buffer); + } + + void VulkanIndexBuffer::CopyWithStagingBuffer(const Buffer buffer) const + { + // Create staging buffer + VkBufferCreateInfo stagingBufferInfo{}; + stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + stagingBufferInfo.size = buffer.Size; + stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + stagingBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VkBuffer stagingBuffer; + const VmaAllocation stagingBufferAlloc = VulkanAllocator::AllocateBuffer(stagingBuffer, stagingBufferInfo, VMA_MEMORY_USAGE_CPU_TO_GPU); + + // Copy data to staging buffer + void* memData = VulkanAllocator::MapMemory(stagingBufferAlloc); + memcpy(memData, buffer.Data, buffer.Size); + VulkanAllocator::UnmapMemory(stagingBufferAlloc); + + // Copy data from staging buffer to GPU local buffer + const Ref context = VulkanContext::Get(); + const Ref logicalDevice = context->GetLogicalDevice(); + const VkCommandBuffer commandBuffer = logicalDevice->GetCommandBuffer(true); + + VkBufferCopy copyRegion; + copyRegion.srcOffset = 0; + copyRegion.dstOffset = 0; + copyRegion.size = buffer.Size; + + vkCmdCopyBuffer(commandBuffer, stagingBuffer, m_Buffer, 1, ©Region); + logicalDevice->FlushCommandBuffer(commandBuffer); + + // Clean up + VulkanAllocator::DestroyBuffer(stagingBuffer, stagingBufferAlloc); + } } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanIndexBuffer.h b/EppoEngine/Source/Platform/Vulkan/VulkanIndexBuffer.h index d5485d29..a89d5bb6 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanIndexBuffer.h +++ b/EppoEngine/Source/Platform/Vulkan/VulkanIndexBuffer.h @@ -5,28 +5,32 @@ namespace Eppo { - class VulkanIndexBuffer : public IndexBuffer - { - public: - explicit VulkanIndexBuffer(uint32_t size); - explicit VulkanIndexBuffer(Buffer buffer); - ~VulkanIndexBuffer() override; - - void SetData(Buffer buffer) override; - - [[nodiscard]] VkBuffer GetBuffer() const { return m_Buffer; } - [[nodiscard]] uint32_t GetIndexCount() const override { return m_Size / sizeof(uint32_t); } - - private: - void CopyWithStagingBuffer(Buffer buffer) const; - - private: - uint32_t m_Size; - - VkBuffer m_Buffer; - VmaAllocation m_Allocation; - - bool m_IsMemoryMapped; - void* m_MappedMemory = nullptr; - }; + class VulkanIndexBuffer final : public IndexBuffer + { + public: + explicit VulkanIndexBuffer(uint32_t size); + explicit VulkanIndexBuffer(Buffer buffer); + VulkanIndexBuffer(const VulkanIndexBuffer&) = delete; + VulkanIndexBuffer(const VulkanIndexBuffer&&) = delete; + VulkanIndexBuffer& operator=(const VulkanIndexBuffer&) = delete; + VulkanIndexBuffer& operator=(const VulkanIndexBuffer&&) = delete; + ~VulkanIndexBuffer() override; + + void SetData(Buffer buffer) override; + + [[nodiscard]] VkBuffer GetBuffer() const { return m_Buffer; } + [[nodiscard]] uint32_t GetIndexCount() const override { return m_Size / sizeof(uint32_t); } + + private: + void CopyWithStagingBuffer(Buffer buffer) const; + + private: + uint32_t m_Size; + + VkBuffer m_Buffer; + VmaAllocation m_Allocation; + + bool m_IsMemoryMapped; + void* m_MappedMemory = nullptr; + }; } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanLogicalDevice.cpp b/EppoEngine/Source/Platform/Vulkan/VulkanLogicalDevice.cpp index dac37f46..1d2c8e5d 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanLogicalDevice.cpp +++ b/EppoEngine/Source/Platform/Vulkan/VulkanLogicalDevice.cpp @@ -5,171 +5,171 @@ namespace Eppo { - VulkanLogicalDevice::VulkanLogicalDevice(const Ref& physicalDevice) - : m_PhysicalDevice(physicalDevice) - { - // Check if requested extensions are supported by the GPU - bool extensionsSupported = true; - for (const auto& extension : VulkanConfig::DeviceExtensions) - { - if (!m_PhysicalDevice->IsExtensionSupported(extension)) - extensionsSupported = false; - } + VulkanLogicalDevice::VulkanLogicalDevice(const Ref& physicalDevice) + : m_PhysicalDevice(physicalDevice) + { + // Check if requested extensions are supported by the GPU + bool extensionsSupported = true; + for (const auto& extension : VulkanConfig::DeviceExtensions) + { + if (!m_PhysicalDevice->IsExtensionSupported(extension)) + extensionsSupported = false; + } EPPO_ASSERT(extensionsSupported); - // Create device queue - QueueFamilyIndices indices = m_PhysicalDevice->GetQueueFamilyIndices(); - std::vector queueCreateInfos; - float queuePriority = 1.0f; - - VkDeviceQueueCreateInfo deviceQueueCreateInfo{}; - deviceQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - deviceQueueCreateInfo.queueFamilyIndex = indices.Graphics; - deviceQueueCreateInfo.queueCount = 1; - deviceQueueCreateInfo.pQueuePriorities = &queuePriority; - queueCreateInfos.push_back(deviceQueueCreateInfo); - - VkPhysicalDeviceFeatures deviceFeatures = m_PhysicalDevice->GetDeviceFeatures(); - - ///// ENABLE FEATURES HERE - VkPhysicalDeviceSynchronization2Features syncFeatures{}; - syncFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES; - syncFeatures.synchronization2 = VK_TRUE; - - VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexingFeatures{}; - descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; - descriptorIndexingFeatures.shaderSampledImageArrayNonUniformIndexing = VK_TRUE; - descriptorIndexingFeatures.runtimeDescriptorArray = VK_TRUE; - descriptorIndexingFeatures.pNext = &syncFeatures; - - VkPhysicalDeviceMultiviewFeatures multiviewFeatures{}; - multiviewFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; - multiviewFeatures.multiview = VK_TRUE; - multiviewFeatures.pNext = &descriptorIndexingFeatures; - - VkPhysicalDeviceDynamicRenderingFeatures dynamicRenderingFeatures{}; - dynamicRenderingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES; - dynamicRenderingFeatures.dynamicRendering = VK_TRUE; - dynamicRenderingFeatures.pNext = &multiviewFeatures; - ///// - - VkDeviceCreateInfo deviceCreateInfo{}; - deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - deviceCreateInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); - deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data(); - deviceCreateInfo.enabledExtensionCount = static_cast(VulkanConfig::DeviceExtensions.size()); - deviceCreateInfo.ppEnabledExtensionNames = VulkanConfig::DeviceExtensions.data(); - deviceCreateInfo.pEnabledFeatures = &deviceFeatures; - deviceCreateInfo.pNext = &dynamicRenderingFeatures; - - if (VulkanConfig::EnableValidation) - { - deviceCreateInfo.enabledLayerCount = static_cast(VulkanConfig::ValidationLayers.size()); - deviceCreateInfo.ppEnabledLayerNames = VulkanConfig::ValidationLayers.data(); - } - else - { - deviceCreateInfo.enabledLayerCount = 0; - deviceCreateInfo.ppEnabledLayerNames = nullptr; - } - - VK_CHECK(vkCreateDevice(physicalDevice->GetNativeDevice(), &deviceCreateInfo, nullptr, &m_Device), "Failed to create logical device!"); - - // Device queue - vkGetDeviceQueue(m_Device, indices.Graphics, 0, &m_GraphicsQueue); - - // Create command pool - VkCommandPoolCreateInfo commandPoolCreateInfo{}; - commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - commandPoolCreateInfo.queueFamilyIndex = indices.Graphics; - commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - - VK_CHECK(vkCreateCommandPool(m_Device, &commandPoolCreateInfo, nullptr, &m_CommandPool), "Failed to create command pool!"); - - // Clean up - Ref context = VulkanContext::Get(); - context->SubmitResourceFree([this]() - { - EPPO_MEM_WARN("Releasing logical device and command pool {}", static_cast(this)); - vkDestroyCommandPool(m_Device, m_CommandPool, nullptr); - - vkDeviceWaitIdle(m_Device); - vkDestroyDevice(m_Device, nullptr); - }); - } - - VkCommandBuffer VulkanLogicalDevice::GetCommandBuffer(const bool begin) const - { - EPPO_PROFILE_FUNCTION("VulkanLogicalDevice::GetCommandBuffer"); - - VkCommandBuffer commandBuffer; - - VkCommandBufferAllocateInfo allocateInfo{}; - allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocateInfo.commandPool = m_CommandPool; - allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocateInfo.commandBufferCount = 1; - - VK_CHECK(vkAllocateCommandBuffers(m_Device, &allocateInfo, &commandBuffer), "Failed to allocate command buffer!"); - - if (begin) - { - VkCommandBufferBeginInfo beginInfo{}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - VK_CHECK(vkBeginCommandBuffer(commandBuffer, &beginInfo), "Failed to begin command buffer!"); - } - - return commandBuffer; - } - - VkCommandBuffer VulkanLogicalDevice::GetSecondaryCommandBuffer() const - { - EPPO_PROFILE_FUNCTION("VulkanLogicalDevice::GetSecondaryCommandBuffer"); - - VkCommandBuffer commandBuffer; - - VkCommandBufferAllocateInfo allocateInfo{}; - allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocateInfo.commandPool = m_CommandPool; - allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; - allocateInfo.commandBufferCount = 1; - - VK_CHECK(vkAllocateCommandBuffers(m_Device, &allocateInfo, &commandBuffer), "Failed to allocate command buffer!"); - - return commandBuffer; - } - - void VulkanLogicalDevice::FlushCommandBuffer(const VkCommandBuffer commandBuffer) const - { - EPPO_PROFILE_FUNCTION("VulkanLogicalDevice::FlushCommandBuffer"); - - VK_CHECK(vkEndCommandBuffer(commandBuffer), "Failed to end command buffer!"); - - VkSubmitInfo submitInfo{}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &commandBuffer; - - // We need this work to be done when this function ends so we synchronize it - VkFenceCreateInfo fenceInfo{}; - fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceInfo.flags = 0; - - VkFence fence; + // Create device queue + QueueFamilyIndices indices = m_PhysicalDevice->GetQueueFamilyIndices(); + std::vector queueCreateInfos; + float queuePriority = 1.0f; + + VkDeviceQueueCreateInfo deviceQueueCreateInfo{}; + deviceQueueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + deviceQueueCreateInfo.queueFamilyIndex = indices.Graphics; + deviceQueueCreateInfo.queueCount = 1; + deviceQueueCreateInfo.pQueuePriorities = &queuePriority; + queueCreateInfos.push_back(deviceQueueCreateInfo); + + VkPhysicalDeviceFeatures deviceFeatures = m_PhysicalDevice->GetDeviceFeatures(); + + ///// ENABLE FEATURES HERE + VkPhysicalDeviceSynchronization2Features syncFeatures{}; + syncFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SYNCHRONIZATION_2_FEATURES; + syncFeatures.synchronization2 = VK_TRUE; + + VkPhysicalDeviceDescriptorIndexingFeatures descriptorIndexingFeatures{}; + descriptorIndexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES; + descriptorIndexingFeatures.shaderSampledImageArrayNonUniformIndexing = VK_TRUE; + descriptorIndexingFeatures.runtimeDescriptorArray = VK_TRUE; + descriptorIndexingFeatures.pNext = &syncFeatures; + + VkPhysicalDeviceMultiviewFeatures multiviewFeatures{}; + multiviewFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES; + multiviewFeatures.multiview = VK_TRUE; + multiviewFeatures.pNext = &descriptorIndexingFeatures; + + VkPhysicalDeviceDynamicRenderingFeatures dynamicRenderingFeatures{}; + dynamicRenderingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES; + dynamicRenderingFeatures.dynamicRendering = VK_TRUE; + dynamicRenderingFeatures.pNext = &multiviewFeatures; + ///// + + VkDeviceCreateInfo deviceCreateInfo{}; + deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + deviceCreateInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); + deviceCreateInfo.pQueueCreateInfos = queueCreateInfos.data(); + deviceCreateInfo.enabledExtensionCount = static_cast(VulkanConfig::DeviceExtensions.size()); + deviceCreateInfo.ppEnabledExtensionNames = VulkanConfig::DeviceExtensions.data(); + deviceCreateInfo.pEnabledFeatures = &deviceFeatures; + deviceCreateInfo.pNext = &dynamicRenderingFeatures; + + if (VulkanConfig::EnableValidation) + { + deviceCreateInfo.enabledLayerCount = static_cast(VulkanConfig::ValidationLayers.size()); + deviceCreateInfo.ppEnabledLayerNames = VulkanConfig::ValidationLayers.data(); + } + else + { + deviceCreateInfo.enabledLayerCount = 0; + deviceCreateInfo.ppEnabledLayerNames = nullptr; + } + + VK_CHECK(vkCreateDevice(physicalDevice->GetNativeDevice(), &deviceCreateInfo, nullptr, &m_Device), "Failed to create logical device!"); + + // Device queue + vkGetDeviceQueue(m_Device, indices.Graphics, 0, &m_GraphicsQueue); + + // Create command pool + VkCommandPoolCreateInfo commandPoolCreateInfo{}; + commandPoolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + commandPoolCreateInfo.queueFamilyIndex = indices.Graphics; + commandPoolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + + VK_CHECK(vkCreateCommandPool(m_Device, &commandPoolCreateInfo, nullptr, &m_CommandPool), "Failed to create command pool!"); + + // Clean up + Ref context = VulkanContext::Get(); + context->SubmitResourceFree([this]() + { + EPPO_MEM_WARN("Releasing logical device and command pool {}", static_cast(this)); + vkDestroyCommandPool(m_Device, m_CommandPool, nullptr); + + vkDeviceWaitIdle(m_Device); + vkDestroyDevice(m_Device, nullptr); + }); + } + + VkCommandBuffer VulkanLogicalDevice::GetCommandBuffer(const bool begin) const + { + EPPO_PROFILE_FUNCTION("VulkanLogicalDevice::GetCommandBuffer"); + + VkCommandBuffer commandBuffer; + + VkCommandBufferAllocateInfo allocateInfo{}; + allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocateInfo.commandPool = m_CommandPool; + allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocateInfo.commandBufferCount = 1; + + VK_CHECK(vkAllocateCommandBuffers(m_Device, &allocateInfo, &commandBuffer), "Failed to allocate command buffer!"); + + if (begin) + { + VkCommandBufferBeginInfo beginInfo{}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + VK_CHECK(vkBeginCommandBuffer(commandBuffer, &beginInfo), "Failed to begin command buffer!"); + } + + return commandBuffer; + } + + VkCommandBuffer VulkanLogicalDevice::GetSecondaryCommandBuffer() const + { + EPPO_PROFILE_FUNCTION("VulkanLogicalDevice::GetSecondaryCommandBuffer"); + + VkCommandBuffer commandBuffer; + + VkCommandBufferAllocateInfo allocateInfo{}; + allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocateInfo.commandPool = m_CommandPool; + allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_SECONDARY; + allocateInfo.commandBufferCount = 1; + + VK_CHECK(vkAllocateCommandBuffers(m_Device, &allocateInfo, &commandBuffer), "Failed to allocate command buffer!"); + + return commandBuffer; + } + + void VulkanLogicalDevice::FlushCommandBuffer(const VkCommandBuffer commandBuffer) const + { + EPPO_PROFILE_FUNCTION("VulkanLogicalDevice::FlushCommandBuffer"); + + VK_CHECK(vkEndCommandBuffer(commandBuffer), "Failed to end command buffer!"); + + VkSubmitInfo submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + + // We need this work to be done when this function ends so we synchronize it + VkFenceCreateInfo fenceInfo{}; + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.flags = 0; + + VkFence fence; VK_CHECK(vkCreateFence(m_Device, &fenceInfo, nullptr, &fence), "Failed to create fence!"); - VK_CHECK(vkQueueSubmit(m_GraphicsQueue, 1, &submitInfo, fence), "Failed to submit work to queue!"); - vkWaitForFences(m_Device, 1, &fence, VK_TRUE, UINT64_MAX); + VK_CHECK(vkQueueSubmit(m_GraphicsQueue, 1, &submitInfo, fence), "Failed to submit work to queue!"); + vkWaitForFences(m_Device, 1, &fence, VK_TRUE, UINT64_MAX); - // Clean up - vkDestroyFence(m_Device, fence, nullptr); - vkFreeCommandBuffers(m_Device, m_CommandPool, 1, &commandBuffer); - } + // Clean up + vkDestroyFence(m_Device, fence, nullptr); + vkFreeCommandBuffers(m_Device, m_CommandPool, 1, &commandBuffer); + } - void VulkanLogicalDevice::FreeCommandBuffer(const VkCommandBuffer commandBuffer) const - { - vkFreeCommandBuffers(m_Device, m_CommandPool, 1, &commandBuffer); - } + void VulkanLogicalDevice::FreeCommandBuffer(const VkCommandBuffer commandBuffer) const + { + vkFreeCommandBuffers(m_Device, m_CommandPool, 1, &commandBuffer); + } } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanLogicalDevice.h b/EppoEngine/Source/Platform/Vulkan/VulkanLogicalDevice.h index 4fa5762a..2815f51a 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanLogicalDevice.h +++ b/EppoEngine/Source/Platform/Vulkan/VulkanLogicalDevice.h @@ -4,27 +4,31 @@ namespace Eppo { - class VulkanLogicalDevice - { - public: - explicit VulkanLogicalDevice(const Ref& physicalDevice); - virtual ~VulkanLogicalDevice() = default; + class VulkanLogicalDevice final + { + public: + explicit VulkanLogicalDevice(const Ref& physicalDevice); + VulkanLogicalDevice(const VulkanLogicalDevice&) = delete; + VulkanLogicalDevice(const VulkanLogicalDevice&&) = delete; + VulkanLogicalDevice& operator=(const VulkanLogicalDevice&) = delete; + VulkanLogicalDevice& operator=(const VulkanLogicalDevice&&) = delete; + ~VulkanLogicalDevice() = default; - [[nodiscard]] VkDevice GetNativeDevice() const { return m_Device; } + [[nodiscard]] VkDevice GetNativeDevice() const { return m_Device; } - [[nodiscard]] Ref GetPhysicalDevice() const { return m_PhysicalDevice; } - [[nodiscard]] VkQueue GetGraphicsQueue() const { return m_GraphicsQueue; } + [[nodiscard]] Ref GetPhysicalDevice() const { return m_PhysicalDevice; } + [[nodiscard]] VkQueue GetGraphicsQueue() const { return m_GraphicsQueue; } - [[nodiscard]] VkCommandBuffer GetCommandBuffer(bool begin) const; - [[nodiscard]] VkCommandBuffer GetSecondaryCommandBuffer() const; - void FlushCommandBuffer(VkCommandBuffer commandBuffer) const; - void FreeCommandBuffer(VkCommandBuffer commandBuffer) const; + [[nodiscard]] VkCommandBuffer GetCommandBuffer(bool begin) const; + [[nodiscard]] VkCommandBuffer GetSecondaryCommandBuffer() const; + void FlushCommandBuffer(VkCommandBuffer commandBuffer) const; + void FreeCommandBuffer(VkCommandBuffer commandBuffer) const; - private: - Ref m_PhysicalDevice; - VkDevice m_Device; + private: + Ref m_PhysicalDevice; + VkDevice m_Device; - VkQueue m_GraphicsQueue; - VkCommandPool m_CommandPool; - }; + VkQueue m_GraphicsQueue; + VkCommandPool m_CommandPool; + }; } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanPhysicalDevice.cpp b/EppoEngine/Source/Platform/Vulkan/VulkanPhysicalDevice.cpp index 8241fbbd..44b70496 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanPhysicalDevice.cpp +++ b/EppoEngine/Source/Platform/Vulkan/VulkanPhysicalDevice.cpp @@ -7,175 +7,175 @@ namespace Eppo { - namespace - { - std::string DecodeDriverVersion(const uint32_t driverVersion, const uint32_t vendorId) - { - std::string versionStr = "Unknown version"; - - switch (vendorId) - { - // Nvidia - case 0x10DE: - { - const uint32_t d1 = (driverVersion >> 22) & 0x3ff; - const uint32_t d2 = (driverVersion >> 14) & 0x0ff; - const uint32_t d3 = (driverVersion >> 6) & 0x0ff; - const uint32_t d4 = driverVersion & 0x003f; - - versionStr = std::to_string(d1) + "." + std::to_string(d2) + "." + std::to_string(d3) + "." + std::to_string(d4); - break; - } - - // Intel - case 0x8086: - { - const uint32_t d1 = driverVersion >> 14; - const uint32_t d2 = driverVersion & 0x3ff; - - versionStr = std::to_string(d1) + "." + std::to_string(d2); - break; - } - - default: - { - const uint32_t d1 = driverVersion >> 22; - const uint32_t d2 = (driverVersion >> 12) & 0x3ff; - const uint32_t d3 = driverVersion & 0xfff; - - versionStr = std::to_string(d1) + "." + std::to_string(d2) + "." + std::to_string(d3); - } - } - - return versionStr; - } - - const std::unordered_map s_GpuVendors = { - { 0x1002, "AMD" }, - { 0x1010, "ImgTec" }, - { 0x10DE, "NVIDIA" }, - { 0x13B5, "ARM" }, - { 0x5143, "Qualcomm" }, - { 0x8086, "Intel" } - }; - } - - VulkanPhysicalDevice::VulkanPhysicalDevice() - { - const auto instance = VulkanContext::GetVulkanInstance(); - - // Get physical devices available - uint32_t deviceCount = 0; - vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); + namespace + { + std::string DecodeDriverVersion(const uint32_t driverVersion, const uint32_t vendorId) + { + std::string versionStr = "Unknown version"; + + switch (vendorId) + { + // Nvidia + case 0x10DE: + { + const uint32_t d1 = (driverVersion >> 22) & 0x3ff; + const uint32_t d2 = (driverVersion >> 14) & 0x0ff; + const uint32_t d3 = (driverVersion >> 6) & 0x0ff; + const uint32_t d4 = driverVersion & 0x003f; + + versionStr = std::to_string(d1) + "." + std::to_string(d2) + "." + std::to_string(d3) + "." + std::to_string(d4); + break; + } + + // Intel + case 0x8086: + { + const uint32_t d1 = driverVersion >> 14; + const uint32_t d2 = driverVersion & 0x3ff; + + versionStr = std::to_string(d1) + "." + std::to_string(d2); + break; + } + + default: + { + const uint32_t d1 = driverVersion >> 22; + const uint32_t d2 = (driverVersion >> 12) & 0x3ff; + const uint32_t d3 = driverVersion & 0xfff; + + versionStr = std::to_string(d1) + "." + std::to_string(d2) + "." + std::to_string(d3); + } + } + + return versionStr; + } + + const std::unordered_map s_GpuVendors = { + { 0x1002, "AMD" }, + { 0x1010, "ImgTec" }, + { 0x10DE, "NVIDIA" }, + { 0x13B5, "ARM" }, + { 0x5143, "Qualcomm" }, + { 0x8086, "Intel" } + }; + } + + VulkanPhysicalDevice::VulkanPhysicalDevice() + { + const auto instance = VulkanContext::GetVulkanInstance(); + + // Get physical devices available + uint32_t deviceCount = 0; + vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); EPPO_ASSERT(deviceCount > 0); - std::vector devices(deviceCount); - vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); - - // Select physical device, we prefer a discrete GPU - for (const auto& device : devices) - { - vkGetPhysicalDeviceProperties(device, &m_Properties); - if (m_Properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) - { - m_PhysicalDevice = device; - break; - } - } - - // No discrete GPU available, select first GPU possible - if (!m_PhysicalDevice) - { - EPPO_WARN("No discrete GPU found!"); - m_PhysicalDevice = devices.back(); + std::vector devices(deviceCount); + vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); + + // Select physical device, we prefer a discrete GPU + for (const auto& device : devices) + { + vkGetPhysicalDeviceProperties(device, &m_Properties); + if (m_Properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) + { + m_PhysicalDevice = device; + break; + } + } + + // No discrete GPU available, select first GPU possible + if (!m_PhysicalDevice) + { + EPPO_WARN("No discrete GPU found!"); + m_PhysicalDevice = devices.back(); EPPO_ASSERT(m_PhysicalDevice); - } - - // Get properties and features from selected device - vkGetPhysicalDeviceFeatures(m_PhysicalDevice, &m_Features); - vkGetPhysicalDeviceMemoryProperties(m_PhysicalDevice, &m_MemoryProperties); - - EPPO_INFO("GPU Info:\n" - "\t\t\tVendor: {}\n" - "\t\t\tModel: {}\n" - "\t\t\tDriver version: {}", - s_GpuVendors.find(m_Properties.vendorID) != s_GpuVendors.end() ? s_GpuVendors.at(m_Properties.vendorID) : "Unknown", - m_Properties.deviceName, - DecodeDriverVersion(m_Properties.driverVersion, m_Properties.vendorID)); - - // Create surface - Ref context = VulkanContext::Get(); + } + + // Get properties and features from selected device + vkGetPhysicalDeviceFeatures(m_PhysicalDevice, &m_Features); + vkGetPhysicalDeviceMemoryProperties(m_PhysicalDevice, &m_MemoryProperties); + + EPPO_INFO("GPU Info:\n" + "\t\t\tVendor: {}\n" + "\t\t\tModel: {}\n" + "\t\t\tDriver version: {}", + s_GpuVendors.contains(m_Properties.vendorID) ? s_GpuVendors.at(m_Properties.vendorID) : "Unknown", + m_Properties.deviceName, + DecodeDriverVersion(m_Properties.driverVersion, m_Properties.vendorID)); + + // Create surface + const Ref context = VulkanContext::Get(); VK_CHECK(glfwCreateWindowSurface(VulkanContext::GetVulkanInstance(), context->GetWindowHandle(), nullptr, &m_Surface), "Failed to create surface!"); - context->SubmitResourceFree([this]() - { - EPPO_WARN("Releasing surface {}", static_cast(this)); - vkDestroySurfaceKHR(VulkanContext::GetVulkanInstance(), m_Surface, nullptr); - }); - - // Queue family indices - m_QueueFamilyIndices = FindQueueFamilyIndices(); - - // Device extensions - uint32_t extensionCount = 0; - vkEnumerateDeviceExtensionProperties(m_PhysicalDevice, nullptr, &extensionCount, nullptr); - - std::vector availableExtensions(extensionCount); - vkEnumerateDeviceExtensionProperties(m_PhysicalDevice, nullptr, &extensionCount, availableExtensions.data()); - - EPPO_INFO("Selected device has {} extensions", availableExtensions.size()); - for (const auto& [extensionName, specVersion] : availableExtensions) - m_SupportedExtensions.emplace_back(extensionName); - - // Device image formats - // These formats are mandatory to be supported - m_SupportedImageFormats[ImageFormat::RGBA8] = VK_FORMAT_R8G8B8A8_SRGB; - m_SupportedImageFormats[ImageFormat::RGB16] = VK_FORMAT_R32G32B32A32_SFLOAT; - - // Depth - constexpr std::array formats = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT }; - for (const auto& format : formats) - { - VkFormatProperties properties; - vkGetPhysicalDeviceFormatProperties(m_PhysicalDevice, format, &properties); - if (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) - { - m_SupportedImageFormats[ImageFormat::Depth] = format; - break; - } - } - } - - bool VulkanPhysicalDevice::IsExtensionSupported(const std::string_view extension) - { - return std::find(m_SupportedExtensions.begin(), m_SupportedExtensions.end(), extension) != m_SupportedExtensions.end(); - } - - QueueFamilyIndices VulkanPhysicalDevice::FindQueueFamilyIndices() const - { - QueueFamilyIndices indices; - - uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(m_PhysicalDevice, &queueFamilyCount, nullptr); - - std::vector queueFamilies(queueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(m_PhysicalDevice, &queueFamilyCount, queueFamilies.data()); - - for (size_t i = 0; i < queueFamilies.size(); i++) - { - if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) - indices.Graphics = static_cast(i); - - VkBool32 presentSupport = false; - vkGetPhysicalDeviceSurfaceSupportKHR(m_PhysicalDevice, i, m_Surface, &presentSupport); - - if (presentSupport) - indices.Present = static_cast(i); - - if (indices.IsComplete()) - break; - } - - return indices; - } + context->SubmitResourceFree([this]() + { + EPPO_WARN("Releasing surface {}", static_cast(this)); + vkDestroySurfaceKHR(VulkanContext::GetVulkanInstance(), m_Surface, nullptr); + }); + + // Queue family indices + m_QueueFamilyIndices = FindQueueFamilyIndices(); + + // Device extensions + uint32_t extensionCount = 0; + vkEnumerateDeviceExtensionProperties(m_PhysicalDevice, nullptr, &extensionCount, nullptr); + + std::vector availableExtensions(extensionCount); + vkEnumerateDeviceExtensionProperties(m_PhysicalDevice, nullptr, &extensionCount, availableExtensions.data()); + + EPPO_INFO("Selected device has {} extensions", availableExtensions.size()); + for (const auto& [extensionName, specVersion] : availableExtensions) + m_SupportedExtensions.emplace_back(extensionName); + + // Device image formats + // These formats are mandatory to be supported + m_SupportedImageFormats[ImageFormat::RGBA8] = VK_FORMAT_R8G8B8A8_SRGB; + m_SupportedImageFormats[ImageFormat::RGB16] = VK_FORMAT_R32G32B32A32_SFLOAT; + + // Depth + constexpr std::array formats = { VK_FORMAT_D32_SFLOAT, VK_FORMAT_D32_SFLOAT_S8_UINT }; + for (const auto& format : formats) + { + VkFormatProperties properties; + vkGetPhysicalDeviceFormatProperties(m_PhysicalDevice, format, &properties); + if (properties.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) + { + m_SupportedImageFormats[ImageFormat::Depth] = format; + break; + } + } + } + + bool VulkanPhysicalDevice::IsExtensionSupported(const std::string_view extension) + { + return std::ranges::find(m_SupportedExtensions, extension) != m_SupportedExtensions.end(); + } + + QueueFamilyIndices VulkanPhysicalDevice::FindQueueFamilyIndices() const + { + QueueFamilyIndices indices; + + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(m_PhysicalDevice, &queueFamilyCount, nullptr); + + std::vector queueFamilies(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(m_PhysicalDevice, &queueFamilyCount, queueFamilies.data()); + + for (size_t i = 0; i < queueFamilies.size(); i++) + { + if (queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + indices.Graphics = static_cast(i); + + VkBool32 presentSupport = false; + vkGetPhysicalDeviceSurfaceSupportKHR(m_PhysicalDevice, static_cast(i), m_Surface, &presentSupport); + + if (presentSupport) + indices.Present = static_cast(i); + + if (indices.IsComplete()) + break; + } + + return indices; + } } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanPhysicalDevice.h b/EppoEngine/Source/Platform/Vulkan/VulkanPhysicalDevice.h index 5403dd65..1f1d608e 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanPhysicalDevice.h +++ b/EppoEngine/Source/Platform/Vulkan/VulkanPhysicalDevice.h @@ -5,50 +5,54 @@ namespace Eppo { - struct QueueFamilyIndices - { - int32_t Graphics = -1; - int32_t Present = -1; - - [[nodiscard]] bool IsComplete() const - { - return Graphics > -1 && Present > -1; - } - }; - - class VulkanPhysicalDevice - { - public: - VulkanPhysicalDevice(); - ~VulkanPhysicalDevice() = default; - - [[nodiscard]] VkPhysicalDevice GetNativeDevice() const { return m_PhysicalDevice; } - [[nodiscard]] VkSurfaceKHR GetSurface() const { return m_Surface; } - - [[nodiscard]] QueueFamilyIndices& GetQueueFamilyIndices() { return m_QueueFamilyIndices; } - [[nodiscard]] const QueueFamilyIndices& GetQueueFamilyIndices() const { return m_QueueFamilyIndices; } - - [[nodiscard]] const VkPhysicalDeviceProperties& GetDeviceProperties() const { return m_Properties; } - [[nodiscard]] const VkPhysicalDeviceMemoryProperties& GetDeviceMemoryProperties() const { return m_MemoryProperties; } - [[nodiscard]] const VkPhysicalDeviceFeatures& GetDeviceFeatures() const { return m_Features; } - - [[nodiscard]] VkFormat GetSupportedImageFormat(const ImageFormat format) { return m_SupportedImageFormats[format]; } - bool IsExtensionSupported(std::string_view extension); - - private: - [[nodiscard]] QueueFamilyIndices FindQueueFamilyIndices() const; - - private: - VkPhysicalDevice m_PhysicalDevice; - VkPhysicalDeviceProperties m_Properties; - VkPhysicalDeviceMemoryProperties m_MemoryProperties; - VkPhysicalDeviceFeatures m_Features; - - VkSurfaceKHR m_Surface; - - std::unordered_map m_SupportedImageFormats; - - QueueFamilyIndices m_QueueFamilyIndices; - std::vector m_SupportedExtensions; - }; + struct QueueFamilyIndices + { + int32_t Graphics = -1; + int32_t Present = -1; + + [[nodiscard]] bool IsComplete() const + { + return Graphics > -1 && Present > -1; + } + }; + + class VulkanPhysicalDevice final + { + public: + VulkanPhysicalDevice(); + VulkanPhysicalDevice(const VulkanPhysicalDevice&) = delete; + VulkanPhysicalDevice(const VulkanPhysicalDevice&&) = delete; + VulkanPhysicalDevice& operator=(const VulkanPhysicalDevice&) = delete; + VulkanPhysicalDevice& operator=(const VulkanPhysicalDevice&&) = delete; + ~VulkanPhysicalDevice() = default; + + [[nodiscard]] VkPhysicalDevice GetNativeDevice() const { return m_PhysicalDevice; } + [[nodiscard]] VkSurfaceKHR GetSurface() const { return m_Surface; } + + [[nodiscard]] QueueFamilyIndices& GetQueueFamilyIndices() { return m_QueueFamilyIndices; } + [[nodiscard]] const QueueFamilyIndices& GetQueueFamilyIndices() const { return m_QueueFamilyIndices; } + + [[nodiscard]] const VkPhysicalDeviceProperties& GetDeviceProperties() const { return m_Properties; } + [[nodiscard]] const VkPhysicalDeviceMemoryProperties& GetDeviceMemoryProperties() const { return m_MemoryProperties; } + [[nodiscard]] const VkPhysicalDeviceFeatures& GetDeviceFeatures() const { return m_Features; } + + [[nodiscard]] VkFormat GetSupportedImageFormat(const ImageFormat format) { return m_SupportedImageFormats[format]; } + bool IsExtensionSupported(std::string_view extension); + + private: + [[nodiscard]] QueueFamilyIndices FindQueueFamilyIndices() const; + + private: + VkPhysicalDevice m_PhysicalDevice; + VkPhysicalDeviceProperties m_Properties; + VkPhysicalDeviceMemoryProperties m_MemoryProperties; + VkPhysicalDeviceFeatures m_Features; + + VkSurfaceKHR m_Surface; + + std::unordered_map m_SupportedImageFormats; + + QueueFamilyIndices m_QueueFamilyIndices; + std::vector m_SupportedExtensions; + }; } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanPipeline.cpp b/EppoEngine/Source/Platform/Vulkan/VulkanPipeline.cpp index 0a64e7e0..c877f687 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanPipeline.cpp +++ b/EppoEngine/Source/Platform/Vulkan/VulkanPipeline.cpp @@ -8,273 +8,292 @@ namespace Eppo { - namespace - { - VkPrimitiveTopology TopologyToVkTopology(const PrimitiveTopology topology) - { - switch (topology) - { - case PrimitiveTopology::Lines: return VK_PRIMITIVE_TOPOLOGY_LINE_LIST; - case PrimitiveTopology::Triangles: return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - } - - EPPO_ASSERT(false); - return VK_PRIMITIVE_TOPOLOGY_MAX_ENUM; - } - - VkPolygonMode PolygonModeToVkPolygonMode(const PolygonMode mode) - { - switch (mode) - { - case PolygonMode::Fill: return VK_POLYGON_MODE_FILL; - case PolygonMode::Line: return VK_POLYGON_MODE_LINE; - } - - EPPO_ASSERT(false); - return VK_POLYGON_MODE_MAX_ENUM; - } - - VkCullModeFlags CullModeToVkCullMode(const CullMode mode) - { - switch (mode) - { - case CullMode::Back: return VK_CULL_MODE_BACK_BIT; - case CullMode::Front: return VK_CULL_MODE_FRONT_BIT; - case CullMode::FrontAndBack: return VK_CULL_MODE_FRONT_AND_BACK; - } - - EPPO_ASSERT(false); - return VK_CULL_MODE_FLAG_BITS_MAX_ENUM; - } - - VkFrontFace CullFrontFaceToVkFrontFace(const CullFrontFace frontFace) - { - switch (frontFace) - { - case CullFrontFace::Clockwise: return VK_FRONT_FACE_CLOCKWISE; - case CullFrontFace::CounterClockwise: return VK_FRONT_FACE_COUNTER_CLOCKWISE; - } - - EPPO_ASSERT(false); - return VK_FRONT_FACE_MAX_ENUM; - } - - VkCompareOp DepthCompareOpToVkCompareOp(const DepthCompareOp op) - { - switch (op) - { - case DepthCompareOp::Less: return VK_COMPARE_OP_LESS; - case DepthCompareOp::Equal: return VK_COMPARE_OP_EQUAL; - case DepthCompareOp::LessOrEqual: return VK_COMPARE_OP_LESS_OR_EQUAL; - case DepthCompareOp::Greater: return VK_COMPARE_OP_GREATER; - case DepthCompareOp::NotEqual: return VK_COMPARE_OP_NOT_EQUAL; - case DepthCompareOp::GreaterOrEqual:return VK_COMPARE_OP_GREATER_OR_EQUAL; - - case DepthCompareOp::Always: return VK_COMPARE_OP_ALWAYS; - case DepthCompareOp::Never: return VK_COMPARE_OP_NEVER; - } - - EPPO_ASSERT(false); - return VK_COMPARE_OP_MAX_ENUM; - } - } - - VulkanPipeline::VulkanPipeline(PipelineSpecification specification) - : m_Specification(std::move(specification)) - { - Ref context = VulkanContext::Get(); - Ref swapchain = context->GetSwapchain(); - VkDevice device = context->GetLogicalDevice()->GetNativeDevice(); - - VkVertexInputBindingDescription bindingDescription{}; - bindingDescription.binding = 0; - bindingDescription.stride = m_Specification.Layout.GetStride(); - bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - - std::vector attributeDescriptions; - const auto& elements = m_Specification.Layout.GetElements(); - for (size_t i = 0; i < elements.size(); i++) - { - VkVertexInputAttributeDescription& attributeDescription = attributeDescriptions.emplace_back(); - attributeDescription.binding = 0; - attributeDescription.location = static_cast(i); - attributeDescription.format = static_cast(Utils::ShaderDataTypeToVkFormat(elements[i].Type)); - attributeDescription.offset = static_cast(elements[i].Offset); - } - - VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo{}; - vertexInputStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertexInputStateCreateInfo.vertexBindingDescriptionCount = elements.empty() ? 0 : 1; - vertexInputStateCreateInfo.pVertexBindingDescriptions = elements.empty() ? nullptr : &bindingDescription; - vertexInputStateCreateInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()); - vertexInputStateCreateInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); - - VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo{}; - inputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssemblyStateCreateInfo.topology = TopologyToVkTopology(m_Specification.Topology); - inputAssemblyStateCreateInfo.primitiveRestartEnable = VK_FALSE; - - VkPipelineViewportStateCreateInfo viewportStateCreateInfo{}; - viewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportStateCreateInfo.viewportCount = 1; - viewportStateCreateInfo.scissorCount = 1; - - VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo{}; - rasterizationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizationStateCreateInfo.depthClampEnable = VK_FALSE; - rasterizationStateCreateInfo.rasterizerDiscardEnable = VK_FALSE; - rasterizationStateCreateInfo.polygonMode = PolygonModeToVkPolygonMode(m_Specification.PolygonMode); - rasterizationStateCreateInfo.lineWidth = 1.0f; - rasterizationStateCreateInfo.cullMode = CullModeToVkCullMode(m_Specification.CullMode); - rasterizationStateCreateInfo.frontFace = CullFrontFaceToVkFrontFace(m_Specification.CullFrontFace); - rasterizationStateCreateInfo.depthBiasEnable = VK_FALSE; - rasterizationStateCreateInfo.depthBiasConstantFactor = 0.0f; - rasterizationStateCreateInfo.depthBiasClamp = 0.0f; - rasterizationStateCreateInfo.depthBiasSlopeFactor = 0.0f; - - VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo{}; - multisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampleStateCreateInfo.sampleShadingEnable = VK_FALSE; - multisampleStateCreateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - multisampleStateCreateInfo.minSampleShading = 1.0f; - multisampleStateCreateInfo.pSampleMask = VK_NULL_HANDLE; - multisampleStateCreateInfo.alphaToCoverageEnable = VK_FALSE; - multisampleStateCreateInfo.alphaToOneEnable = VK_FALSE; - - VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo{}; - depthStencilStateCreateInfo.stencilTestEnable = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depthStencilStateCreateInfo.depthTestEnable = m_Specification.TestDepth; - depthStencilStateCreateInfo.depthWriteEnable = m_Specification.WriteDepth; - depthStencilStateCreateInfo.depthCompareOp = DepthCompareOpToVkCompareOp(m_Specification.DepthCompareOp); - depthStencilStateCreateInfo.depthBoundsTestEnable = VK_FALSE; - depthStencilStateCreateInfo.minDepthBounds = 0.0f; - depthStencilStateCreateInfo.maxDepthBounds = 1.0f; - depthStencilStateCreateInfo.stencilTestEnable = VK_FALSE; - - std::vector attachmentStates; - for (const auto& attachment : m_Specification.RenderAttachments) - { - if (attachment.RenderImage->GetSpecification().Format == ImageFormat::Depth) - continue; - - VkPipelineColorBlendAttachmentState& colorBlendAttachmentState = attachmentStates.emplace_back(); - colorBlendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - colorBlendAttachmentState.blendEnable = VK_FALSE; - colorBlendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; - colorBlendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; - colorBlendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; - colorBlendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; - colorBlendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; - colorBlendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; - } - - VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo{}; - colorBlendStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlendStateCreateInfo.logicOpEnable = VK_FALSE; - colorBlendStateCreateInfo.logicOp = VK_LOGIC_OP_COPY; - colorBlendStateCreateInfo.attachmentCount = static_cast(attachmentStates.size()); - colorBlendStateCreateInfo.pAttachments = attachmentStates.data(); - colorBlendStateCreateInfo.blendConstants[0] = 0.0f; - colorBlendStateCreateInfo.blendConstants[1] = 0.0f; - colorBlendStateCreateInfo.blendConstants[2] = 0.0f; - colorBlendStateCreateInfo.blendConstants[3] = 0.0f; - - std::array dynamicStates = { - VK_DYNAMIC_STATE_VIEWPORT, - VK_DYNAMIC_STATE_SCISSOR - }; - - VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo{}; - dynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - dynamicStateCreateInfo.dynamicStateCount = static_cast(dynamicStates.size()); - dynamicStateCreateInfo.pDynamicStates = dynamicStates.data(); - - // Allocate descriptor sets - Ref shader = std::static_pointer_cast(m_Specification.Shader); - const auto& descriptorSetLayouts = shader->GetDescriptorSetLayouts(); - - // Create pipeline layout - VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{}; - pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutCreateInfo.setLayoutCount = static_cast(descriptorSetLayouts.size()); - pipelineLayoutCreateInfo.pSetLayouts = descriptorSetLayouts.data(); - pipelineLayoutCreateInfo.pushConstantRangeCount = static_cast(shader->GetPushConstantRanges().size()); - pipelineLayoutCreateInfo.pPushConstantRanges = !shader->GetPushConstantRanges().empty() ? shader->GetPushConstantRanges().data() : nullptr; - - VK_CHECK(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &m_PipelineLayout), "Failed to create pipeline layout!"); - - // Create pipeline rendering infos - const auto& shaderStageInfos = shader->GetPipelineShaderStageInfos(); - - std::vector formats; - for (const auto& colorAttachment : m_Specification.RenderAttachments) - { - if (const auto format = colorAttachment.RenderImage->GetSpecification().Format; - format != ImageFormat::Depth) - { - VkFormat& vkFormat = formats.emplace_back(); - vkFormat = Utils::ImageFormatToVkFormat(format); - } - } - - VkPipelineRenderingCreateInfo renderingInfo{}; - renderingInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO; - renderingInfo.colorAttachmentCount = static_cast(formats.size()); - renderingInfo.pColorAttachmentFormats = formats.data(); - renderingInfo.depthAttachmentFormat = m_Specification.TestDepth ? Utils::ImageFormatToVkFormat(ImageFormat::Depth) : VK_FORMAT_UNDEFINED; - - if (m_Specification.CubeMap) - renderingInfo.viewMask = 0b111111; - - // Create pipeline - VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo{}; - graphicsPipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - graphicsPipelineCreateInfo.stageCount = static_cast(shaderStageInfos.size()); - graphicsPipelineCreateInfo.pStages = shaderStageInfos.data(); - graphicsPipelineCreateInfo.pVertexInputState = &vertexInputStateCreateInfo; - graphicsPipelineCreateInfo.pInputAssemblyState = &inputAssemblyStateCreateInfo; - graphicsPipelineCreateInfo.pViewportState = &viewportStateCreateInfo; - graphicsPipelineCreateInfo.pRasterizationState = &rasterizationStateCreateInfo; - graphicsPipelineCreateInfo.pMultisampleState = &multisampleStateCreateInfo; - graphicsPipelineCreateInfo.pDepthStencilState = &depthStencilStateCreateInfo; - graphicsPipelineCreateInfo.pColorBlendState = &colorBlendStateCreateInfo; - graphicsPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo; - graphicsPipelineCreateInfo.layout = m_PipelineLayout; - graphicsPipelineCreateInfo.renderPass = nullptr; // Dynamic rendering - graphicsPipelineCreateInfo.subpass = 0; - graphicsPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; - graphicsPipelineCreateInfo.basePipelineIndex = -1; - graphicsPipelineCreateInfo.pNext = &renderingInfo; - - VK_CHECK(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &graphicsPipelineCreateInfo, nullptr, &m_Pipeline), "Failed to create graphics pipeline!"); - - if (m_Specification.CreateDepthImage) - { - // We simply want a depth attachment to go with our color attachments - ImageSpecification imageSpec; - imageSpec.Format = ImageFormat::Depth; - imageSpec.Width = m_Specification.Width; - imageSpec.Height = m_Specification.Height; - imageSpec.Usage = ImageUsage::Attachment; - - Ref image = Image::Create(imageSpec); - - m_Specification.RenderAttachments.emplace_back(image, true, 1.0f); - - VkCommandBuffer cmd = context->GetLogicalDevice()->GetCommandBuffer(true); - VulkanImage::TransitionImage(cmd, std::static_pointer_cast(image)->GetImageInfo().Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL); - context->GetLogicalDevice()->FlushCommandBuffer(cmd); - } - } - - VulkanPipeline::~VulkanPipeline() - { - const VkDevice device = VulkanContext::Get()->GetLogicalDevice()->GetNativeDevice(); - - EPPO_MEM_WARN("Releasing pipeline {}", static_cast(m_Pipeline)); - vkDestroyPipeline(device, m_Pipeline, nullptr); - - EPPO_MEM_WARN("Releasing pipeline layout {}", static_cast(m_PipelineLayout)); - vkDestroyPipelineLayout(device, m_PipelineLayout, nullptr); - } + namespace + { + VkPrimitiveTopology TopologyToVkTopology(const PrimitiveTopology topology) + { + switch (topology) + { + case PrimitiveTopology::Lines: + return VK_PRIMITIVE_TOPOLOGY_LINE_LIST; + case PrimitiveTopology::Triangles: + return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + } + + EPPO_ASSERT(false); + return VK_PRIMITIVE_TOPOLOGY_MAX_ENUM; + } + + VkPolygonMode PolygonModeToVkPolygonMode(const PolygonMode mode) + { + switch (mode) + { + case PolygonMode::Fill: + return VK_POLYGON_MODE_FILL; + case PolygonMode::Line: + return VK_POLYGON_MODE_LINE; + } + + EPPO_ASSERT(false); + return VK_POLYGON_MODE_MAX_ENUM; + } + + VkCullModeFlags CullModeToVkCullMode(const CullMode mode) + { + switch (mode) + { + case CullMode::Back: + return VK_CULL_MODE_BACK_BIT; + case CullMode::Front: + return VK_CULL_MODE_FRONT_BIT; + case CullMode::FrontAndBack: + return VK_CULL_MODE_FRONT_AND_BACK; + } + + EPPO_ASSERT(false); + return VK_CULL_MODE_FLAG_BITS_MAX_ENUM; + } + + VkFrontFace CullFrontFaceToVkFrontFace(const CullFrontFace frontFace) + { + switch (frontFace) + { + case CullFrontFace::Clockwise: + return VK_FRONT_FACE_CLOCKWISE; + case CullFrontFace::CounterClockwise: + return VK_FRONT_FACE_COUNTER_CLOCKWISE; + } + + EPPO_ASSERT(false); + return VK_FRONT_FACE_MAX_ENUM; + } + + VkCompareOp DepthCompareOpToVkCompareOp(const DepthCompareOp op) + { + switch (op) + { + case DepthCompareOp::Less: + return VK_COMPARE_OP_LESS; + case DepthCompareOp::Equal: + return VK_COMPARE_OP_EQUAL; + case DepthCompareOp::LessOrEqual: + return VK_COMPARE_OP_LESS_OR_EQUAL; + case DepthCompareOp::Greater: + return VK_COMPARE_OP_GREATER; + case DepthCompareOp::NotEqual: + return VK_COMPARE_OP_NOT_EQUAL; + case DepthCompareOp::GreaterOrEqual: + return VK_COMPARE_OP_GREATER_OR_EQUAL; + + case DepthCompareOp::Always: + return VK_COMPARE_OP_ALWAYS; + case DepthCompareOp::Never: + return VK_COMPARE_OP_NEVER; + } + + EPPO_ASSERT(false); + return VK_COMPARE_OP_MAX_ENUM; + } + } + + VulkanPipeline::VulkanPipeline(PipelineSpecification specification) + : m_Specification(std::move(specification)) + { + Ref context = VulkanContext::Get(); + Ref swapchain = context->GetSwapchain(); + VkDevice device = context->GetLogicalDevice()->GetNativeDevice(); + + VkVertexInputBindingDescription bindingDescription{}; + bindingDescription.binding = 0; + bindingDescription.stride = m_Specification.Layout.GetStride(); + bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + std::vector attributeDescriptions; + const auto& elements = m_Specification.Layout.GetElements(); + for (size_t i = 0; i < elements.size(); i++) + { + VkVertexInputAttributeDescription& attributeDescription = attributeDescriptions.emplace_back(); + attributeDescription.binding = 0; + attributeDescription.location = static_cast(i); + attributeDescription.format = static_cast(Utils::ShaderDataTypeToVkFormat(elements[i].Type)); + attributeDescription.offset = static_cast(elements[i].Offset); + } + + VkPipelineVertexInputStateCreateInfo vertexInputStateCreateInfo{}; + vertexInputStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputStateCreateInfo.vertexBindingDescriptionCount = elements.empty() ? 0 : 1; + vertexInputStateCreateInfo.pVertexBindingDescriptions = elements.empty() ? nullptr : &bindingDescription; + vertexInputStateCreateInfo.vertexAttributeDescriptionCount = static_cast(attributeDescriptions.size()); + vertexInputStateCreateInfo.pVertexAttributeDescriptions = attributeDescriptions.data(); + + VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo{}; + inputAssemblyStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssemblyStateCreateInfo.topology = TopologyToVkTopology(m_Specification.Topology); + inputAssemblyStateCreateInfo.primitiveRestartEnable = VK_FALSE; + + VkPipelineViewportStateCreateInfo viewportStateCreateInfo{}; + viewportStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportStateCreateInfo.viewportCount = 1; + viewportStateCreateInfo.scissorCount = 1; + + VkPipelineRasterizationStateCreateInfo rasterizationStateCreateInfo{}; + rasterizationStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizationStateCreateInfo.depthClampEnable = VK_FALSE; + rasterizationStateCreateInfo.rasterizerDiscardEnable = VK_FALSE; + rasterizationStateCreateInfo.polygonMode = PolygonModeToVkPolygonMode(m_Specification.PolygonMode); + rasterizationStateCreateInfo.lineWidth = 1.0f; + rasterizationStateCreateInfo.cullMode = CullModeToVkCullMode(m_Specification.CullMode); + rasterizationStateCreateInfo.frontFace = CullFrontFaceToVkFrontFace(m_Specification.CullFrontFace); + rasterizationStateCreateInfo.depthBiasEnable = VK_FALSE; + rasterizationStateCreateInfo.depthBiasConstantFactor = 0.0f; + rasterizationStateCreateInfo.depthBiasClamp = 0.0f; + rasterizationStateCreateInfo.depthBiasSlopeFactor = 0.0f; + + VkPipelineMultisampleStateCreateInfo multisampleStateCreateInfo{}; + multisampleStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampleStateCreateInfo.sampleShadingEnable = VK_FALSE; + multisampleStateCreateInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + multisampleStateCreateInfo.minSampleShading = 1.0f; + multisampleStateCreateInfo.pSampleMask = VK_NULL_HANDLE; + multisampleStateCreateInfo.alphaToCoverageEnable = VK_FALSE; + multisampleStateCreateInfo.alphaToOneEnable = VK_FALSE; + + VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo{}; + depthStencilStateCreateInfo.stencilTestEnable = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencilStateCreateInfo.depthTestEnable = m_Specification.TestDepth; + depthStencilStateCreateInfo.depthWriteEnable = m_Specification.WriteDepth; + depthStencilStateCreateInfo.depthCompareOp = DepthCompareOpToVkCompareOp(m_Specification.DepthCompareOp); + depthStencilStateCreateInfo.depthBoundsTestEnable = VK_FALSE; + depthStencilStateCreateInfo.minDepthBounds = 0.0f; + depthStencilStateCreateInfo.maxDepthBounds = 1.0f; + depthStencilStateCreateInfo.stencilTestEnable = VK_FALSE; + + std::vector attachmentStates; + for (const auto& attachment : m_Specification.RenderAttachments) + { + if (attachment.RenderImage->GetSpecification().Format == ImageFormat::Depth) + continue; + + VkPipelineColorBlendAttachmentState& colorBlendAttachmentState = attachmentStates.emplace_back(); + colorBlendAttachmentState.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | + VK_COLOR_COMPONENT_A_BIT; + colorBlendAttachmentState.blendEnable = VK_FALSE; + colorBlendAttachmentState.srcColorBlendFactor = VK_BLEND_FACTOR_ONE; + colorBlendAttachmentState.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO; + colorBlendAttachmentState.colorBlendOp = VK_BLEND_OP_ADD; + colorBlendAttachmentState.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + colorBlendAttachmentState.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; + colorBlendAttachmentState.alphaBlendOp = VK_BLEND_OP_ADD; + } + + VkPipelineColorBlendStateCreateInfo colorBlendStateCreateInfo{}; + colorBlendStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlendStateCreateInfo.logicOpEnable = VK_FALSE; + colorBlendStateCreateInfo.logicOp = VK_LOGIC_OP_COPY; + colorBlendStateCreateInfo.attachmentCount = static_cast(attachmentStates.size()); + colorBlendStateCreateInfo.pAttachments = attachmentStates.data(); + colorBlendStateCreateInfo.blendConstants[0] = 0.0f; + colorBlendStateCreateInfo.blendConstants[1] = 0.0f; + colorBlendStateCreateInfo.blendConstants[2] = 0.0f; + colorBlendStateCreateInfo.blendConstants[3] = 0.0f; + + std::array dynamicStates = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }; + + VkPipelineDynamicStateCreateInfo dynamicStateCreateInfo{}; + dynamicStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicStateCreateInfo.dynamicStateCount = static_cast(dynamicStates.size()); + dynamicStateCreateInfo.pDynamicStates = dynamicStates.data(); + + // Allocate descriptor sets + Ref shader = std::static_pointer_cast(m_Specification.Shader); + const auto& descriptorSetLayouts = shader->GetDescriptorSetLayouts(); + + // Create pipeline layout + VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo{}; + pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutCreateInfo.setLayoutCount = static_cast(descriptorSetLayouts.size()); + pipelineLayoutCreateInfo.pSetLayouts = descriptorSetLayouts.data(); + pipelineLayoutCreateInfo.pushConstantRangeCount = static_cast(shader->GetPushConstantRanges().size()); + pipelineLayoutCreateInfo.pPushConstantRanges = !shader->GetPushConstantRanges().empty() ? shader->GetPushConstantRanges().data() : nullptr; + + VK_CHECK(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, nullptr, &m_PipelineLayout), "Failed to create pipeline layout!"); + + // Create pipeline rendering infos + const auto& shaderStageInfos = shader->GetPipelineShaderStageInfos(); + + std::vector formats; + for (const auto& colorAttachment : m_Specification.RenderAttachments) + { + if (const auto format = colorAttachment.RenderImage->GetSpecification().Format; format != ImageFormat::Depth) + { + VkFormat& vkFormat = formats.emplace_back(); + vkFormat = Utils::ImageFormatToVkFormat(format); + } + } + + VkPipelineRenderingCreateInfo renderingInfo{}; + renderingInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO; + renderingInfo.colorAttachmentCount = static_cast(formats.size()); + renderingInfo.pColorAttachmentFormats = formats.data(); + renderingInfo.depthAttachmentFormat = m_Specification.TestDepth ? Utils::ImageFormatToVkFormat(ImageFormat::Depth) : VK_FORMAT_UNDEFINED; + + if (m_Specification.CubeMap) + renderingInfo.viewMask = 0b111111; + + // Create pipeline + VkGraphicsPipelineCreateInfo graphicsPipelineCreateInfo{}; + graphicsPipelineCreateInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + graphicsPipelineCreateInfo.stageCount = static_cast(shaderStageInfos.size()); + graphicsPipelineCreateInfo.pStages = shaderStageInfos.data(); + graphicsPipelineCreateInfo.pVertexInputState = &vertexInputStateCreateInfo; + graphicsPipelineCreateInfo.pInputAssemblyState = &inputAssemblyStateCreateInfo; + graphicsPipelineCreateInfo.pViewportState = &viewportStateCreateInfo; + graphicsPipelineCreateInfo.pRasterizationState = &rasterizationStateCreateInfo; + graphicsPipelineCreateInfo.pMultisampleState = &multisampleStateCreateInfo; + graphicsPipelineCreateInfo.pDepthStencilState = &depthStencilStateCreateInfo; + graphicsPipelineCreateInfo.pColorBlendState = &colorBlendStateCreateInfo; + graphicsPipelineCreateInfo.pDynamicState = &dynamicStateCreateInfo; + graphicsPipelineCreateInfo.layout = m_PipelineLayout; + graphicsPipelineCreateInfo.renderPass = nullptr; // Dynamic rendering + graphicsPipelineCreateInfo.subpass = 0; + graphicsPipelineCreateInfo.basePipelineHandle = VK_NULL_HANDLE; + graphicsPipelineCreateInfo.basePipelineIndex = -1; + graphicsPipelineCreateInfo.pNext = &renderingInfo; + + VK_CHECK(vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &graphicsPipelineCreateInfo, nullptr, &m_Pipeline), + "Failed to create graphics pipeline!"); + + if (m_Specification.CreateDepthImage) + { + // We simply want a depth attachment to go with our color attachments + ImageSpecification imageSpec; + imageSpec.Format = ImageFormat::Depth; + imageSpec.Width = m_Specification.Width; + imageSpec.Height = m_Specification.Height; + imageSpec.Usage = ImageUsage::Attachment; + + Ref image = Image::Create(imageSpec); + + m_Specification.RenderAttachments.emplace_back(image, true, 1.0f); + + VkCommandBuffer cmd = context->GetLogicalDevice()->GetCommandBuffer(true); + VulkanImage::TransitionImage(cmd, std::static_pointer_cast(image)->GetImageInfo().Image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL); + context->GetLogicalDevice()->FlushCommandBuffer(cmd); + } + } + + VulkanPipeline::~VulkanPipeline() + { + const VkDevice device = VulkanContext::Get()->GetLogicalDevice()->GetNativeDevice(); + + EPPO_MEM_WARN("Releasing pipeline {}", static_cast(m_Pipeline)); + vkDestroyPipeline(device, m_Pipeline, nullptr); + + EPPO_MEM_WARN("Releasing pipeline layout {}", static_cast(m_PipelineLayout)); + vkDestroyPipelineLayout(device, m_PipelineLayout, nullptr); + } } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanPipeline.h b/EppoEngine/Source/Platform/Vulkan/VulkanPipeline.h index 3197da39..bb170865 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanPipeline.h +++ b/EppoEngine/Source/Platform/Vulkan/VulkanPipeline.h @@ -6,25 +6,29 @@ namespace Eppo { - class VulkanPipeline : public Pipeline - { - public: - explicit VulkanPipeline(PipelineSpecification specification); - ~VulkanPipeline() override; + class VulkanPipeline final : public Pipeline + { + public: + explicit VulkanPipeline(PipelineSpecification specification); + VulkanPipeline(const VulkanPipeline&) = delete; + VulkanPipeline(const VulkanPipeline&&) = delete; + VulkanPipeline& operator=(const VulkanPipeline&) = delete; + VulkanPipeline& operator=(const VulkanPipeline&&) = delete; + ~VulkanPipeline() override; - [[nodiscard]] Ref GetImage(const uint32_t index) const override { return m_Specification.RenderAttachments.at(index).RenderImage; } - [[nodiscard]] Ref GetFinalImage() const override { return m_Specification.RenderAttachments.at(0).RenderImage; } + [[nodiscard]] Ref GetImage(const uint32_t index) const override { return m_Specification.RenderAttachments.at(index).RenderImage; } + [[nodiscard]] Ref GetFinalImage() const override { return m_Specification.RenderAttachments.at(0).RenderImage; } - [[nodiscard]] VkPipeline GetPipeline() const { return m_Pipeline; } - [[nodiscard]] VkPipelineLayout GetPipelineLayout() const { return m_PipelineLayout; } + [[nodiscard]] VkPipeline GetPipeline() const { return m_Pipeline; } + [[nodiscard]] VkPipelineLayout GetPipelineLayout() const { return m_PipelineLayout; } - [[nodiscard]] const PipelineSpecification& GetSpecification() const override { return m_Specification; } - PipelineSpecification& GetSpecification() override { return m_Specification; } + [[nodiscard]] const PipelineSpecification& GetSpecification() const override { return m_Specification; } + PipelineSpecification& GetSpecification() override { return m_Specification; } - private: - PipelineSpecification m_Specification; + private: + PipelineSpecification m_Specification; - VkPipeline m_Pipeline; - VkPipelineLayout m_PipelineLayout; - }; + VkPipeline m_Pipeline; + VkPipelineLayout m_PipelineLayout; + }; } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanRenderer.cpp b/EppoEngine/Source/Platform/Vulkan/VulkanRenderer.cpp index 1b719a14..38ae2a13 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanRenderer.cpp +++ b/EppoEngine/Source/Platform/Vulkan/VulkanRenderer.cpp @@ -7,185 +7,187 @@ namespace Eppo { - bool VulkanRenderer::s_IsInstantiated = false; - - VulkanRenderer::VulkanRenderer() - { - EPPO_ASSERT(!s_IsInstantiated); - s_IsInstantiated = true; - - const Ref context = VulkanContext::Get(); - const Ref logicalDevice = context->GetLogicalDevice(); - const Ref swapchain = context->GetSwapchain(); - - // Create descriptor allocators - const std::vector ratios = { - { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 3.0f }, - { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 3.0f }, - { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 3.0f }, - { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 4.0f } - }; - - for (uint32_t i = 0; i < VulkanConfig::MaxFramesInFlight; i++) - m_DescriptorAllocators[i].Init(1000, ratios); - - // Load shaders - constexpr std::array shaders = { - "Resources/Shaders/composite.glsl", - "Resources/Shaders/debug.glsl", - "Resources/Shaders/env.glsl", - "Resources/Shaders/geometry.glsl", - "Resources/Shaders/predepth.glsl", - "Resources/Shaders/skybox.glsl" - }; + bool VulkanRenderer::s_IsInstantiated = false; + + VulkanRenderer::VulkanRenderer() + { + EPPO_ASSERT(!s_IsInstantiated); + s_IsInstantiated = true; + + const Ref context = VulkanContext::Get(); + const Ref logicalDevice = context->GetLogicalDevice(); + const Ref swapchain = context->GetSwapchain(); + + // Create descriptor allocators + const std::vector ratios = { + { .Type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, .Ratio = 3.0f }, + { .Type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, .Ratio = 3.0f }, + { .Type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .Ratio = 3.0f }, + { .Type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, .Ratio = 4.0f } + }; + + for (uint32_t i = 0; i < VulkanConfig::MaxFramesInFlight; i++) + m_DescriptorAllocators[i].Init(1000, ratios); + + // Load shaders + constexpr std::array shaders = { + "Resources/Shaders/composite.glsl", + "Resources/Shaders/debug.glsl", + "Resources/Shaders/env.glsl", + "Resources/Shaders/geometry.glsl", + "Resources/Shaders/predepth.glsl", + "Resources/Shaders/skybox.glsl" + }; #ifdef EPPO_DEBUG - std::for_each(std::execution::seq, shaders.cbegin(), shaders.cend(), [&](const std::string& path) - { - m_ShaderLibrary.Load(path); - }); + std::for_each(std::execution::seq, shaders.cbegin(), shaders.cend(), [&](const std::string& path) + { + m_ShaderLibrary.Load(path); + }); #elif defined(EPPO_RELEASE) - std::for_each(std::execution::par, shaders.cbegin(), shaders.cend(), [&](const std::string& path) - { - m_ShaderLibrary.Load(path); - }); + std::for_each(std::execution::par, shaders.cbegin(), shaders.cend(), [&](const std::string& path) + { + m_ShaderLibrary.Load(path); + }); #endif - } - - void VulkanRenderer::Shutdown() - { - for (auto& allocator : m_DescriptorAllocators) - { - EPPO_MEM_WARN("Releasing descriptor pool {}", static_cast(&allocator)); - allocator.DestroyPools(); - } - } - - void VulkanRenderer::ExecuteRenderCommands() - { - EPPO_PROFILE_FUNCTION("VulkanRenderer::ExecuteRenderCommands"); - - m_CommandQueue.Execute(); - } - - void VulkanRenderer::SubmitCommand(RenderCommand command) - { - m_CommandQueue.AddCommand(std::move(command)); - } - - void VulkanRenderer::BeginRenderPass(const Ref& commandBuffer, const Ref& pipeline, bool bindPipeline) - { - EPPO_PROFILE_FUNCTION("VulkanRenderer::BeginRenderPass"); - - const Ref context = VulkanContext::Get(); - const Ref swapchain = context->GetSwapchain(); - const Ref vkPipeline = std::static_pointer_cast(pipeline); - - // Setup render attachments - const auto& spec = pipeline->GetSpecification(); - - VkRenderingInfo renderingInfo{}; - renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO; - renderingInfo.renderArea.offset = { 0, 0 }; - renderingInfo.renderArea.extent = { spec.Width, spec.Height }; - renderingInfo.layerCount = 1; - - std::vector colorAttachmentInfos; - VkRenderingAttachmentInfo depthAttachmentInfo{}; - - if (spec.SwapchainTarget) - { - VkRenderingAttachmentInfo& attachmentInfo = colorAttachmentInfos.emplace_back(); - attachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; - attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - attachmentInfo.imageView = swapchain->GetCurrentImageView(); - attachmentInfo.clearValue.color = { 0.0f, 0.0f, 0.0f, 0.0f }; - - renderingInfo.colorAttachmentCount = 1; - renderingInfo.pColorAttachments = &attachmentInfo; - } else - { - bool depth = false; - - for (const auto& attachment : spec.RenderAttachments) - { - if (const auto& image = attachment.RenderImage; - image->GetSpecification().Format == ImageFormat::Depth) - { - depthAttachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; - depthAttachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - depthAttachmentInfo.loadOp = attachment.Clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; - depthAttachmentInfo.imageView = std::static_pointer_cast(image)->GetImageInfo().ImageView; - depthAttachmentInfo.clearValue.depthStencil = { attachment.ClearValue.Depth, 0 }; - depthAttachmentInfo.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; - - depth = true; - } else - { - VkRenderingAttachmentInfo& attachmentInfo = colorAttachmentInfos.emplace_back(); - attachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; - attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachmentInfo.loadOp = attachment.Clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; - attachmentInfo.imageView = std::static_pointer_cast(image)->GetImageInfo().ImageView; - attachmentInfo.clearValue.color = { attachment.ClearValue.Color.r, attachment.ClearValue.Color.g, attachment.ClearValue.Color.b, attachment.ClearValue.Color.a }; - attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - } - } - - renderingInfo.colorAttachmentCount = static_cast(colorAttachmentInfos.size()); - renderingInfo.pColorAttachments = colorAttachmentInfos.data(); - - if (depth) - renderingInfo.pDepthAttachment = &depthAttachmentInfo; - - if (spec.CubeMap) - renderingInfo.viewMask = 0b111111; - } - - // Begin dynamic rendering - const auto cmd = std::static_pointer_cast(commandBuffer); - const VkCommandBuffer cb = cmd->GetCurrentCommandBuffer(); - vkCmdBeginRendering(cb, &renderingInfo); - - if (bindPipeline) - { - // Bind pipeline - vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, vkPipeline->GetPipeline()); - - // Set viewport - VkViewport viewport; - viewport.x = 0.0f; - viewport.y = 0.0f; - viewport.width = static_cast(spec.Width); - viewport.height = static_cast(spec.Height); - viewport.minDepth = 0.0f; - viewport.maxDepth = 1.0f; - - vkCmdSetViewport(cb, 0, 1, &viewport); - - // Set scissor - VkRect2D scissor; - scissor.offset = { 0, 0 }; - scissor.extent = { spec.Width, spec.Height }; - - vkCmdSetScissor(cb, 0, 1, &scissor); - } - } - - void VulkanRenderer::EndRenderPass(const Ref& commandBuffer) - { - EPPO_PROFILE_FUNCTION("VulkanRenderer::EndRenderPass"); - - const auto cmd = std::static_pointer_cast(commandBuffer); - const VkCommandBuffer cb = cmd->GetCurrentCommandBuffer(); - vkCmdEndRendering(cb); - } - - void* VulkanRenderer::AllocateDescriptor(void* layout) - { - const uint32_t frameIndex = VulkanContext::Get()->GetCurrentFrameIndex(); - return m_DescriptorAllocators[frameIndex].Allocate(layout); - } + } + + void VulkanRenderer::Shutdown() + { + for (auto& allocator : m_DescriptorAllocators) + { + EPPO_MEM_WARN("Releasing descriptor pool {}", static_cast(&allocator)); + allocator.DestroyPools(); + } + } + + void VulkanRenderer::ExecuteRenderCommands() + { + EPPO_PROFILE_FUNCTION("VulkanRenderer::ExecuteRenderCommands"); + + m_CommandQueue.Execute(); + } + + void VulkanRenderer::SubmitCommand(RenderCommand command) + { + m_CommandQueue.AddCommand(std::move(command)); + } + + void VulkanRenderer::BeginRenderPass(const Ref& commandBuffer, const Ref& pipeline, bool bindPipeline) + { + EPPO_PROFILE_FUNCTION("VulkanRenderer::BeginRenderPass"); + + const Ref context = VulkanContext::Get(); + const Ref swapchain = context->GetSwapchain(); + const Ref vkPipeline = std::static_pointer_cast(pipeline); + + // Setup render attachments + const auto& spec = pipeline->GetSpecification(); + + VkRenderingInfo renderingInfo{}; + renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO; + renderingInfo.renderArea.offset = { .x = 0, .y = 0 }; + renderingInfo.renderArea.extent = { .width = spec.Width, .height = spec.Height }; + renderingInfo.layerCount = 1; + + std::vector colorAttachmentInfos; + VkRenderingAttachmentInfo depthAttachmentInfo{}; + + if (spec.SwapchainTarget) + { + VkRenderingAttachmentInfo& attachmentInfo = colorAttachmentInfos.emplace_back(); + attachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; + attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + attachmentInfo.imageView = swapchain->GetCurrentImageView(); + attachmentInfo.clearValue.color = { 0.0f, 0.0f, 0.0f, 0.0f }; + + renderingInfo.colorAttachmentCount = 1; + renderingInfo.pColorAttachments = &attachmentInfo; + } + else + { + bool depth = false; + + for (const auto& attachment : spec.RenderAttachments) + { + if (const auto& image = attachment.RenderImage; image->GetSpecification().Format == ImageFormat::Depth) + { + depthAttachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; + depthAttachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + depthAttachmentInfo.loadOp = attachment.Clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; + depthAttachmentInfo.imageView = std::static_pointer_cast(image)->GetImageInfo().ImageView; + depthAttachmentInfo.clearValue.depthStencil = { .depth = attachment.ClearValue.Depth, .stencil = 0 }; + depthAttachmentInfo.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; + + depth = true; + } + else + { + VkRenderingAttachmentInfo& attachmentInfo = colorAttachmentInfos.emplace_back(); + attachmentInfo.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO; + attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + attachmentInfo.loadOp = attachment.Clear ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD; + attachmentInfo.imageView = std::static_pointer_cast(image)->GetImageInfo().ImageView; + attachmentInfo.clearValue.color = { attachment.ClearValue.Color.r, attachment.ClearValue.Color.g, attachment.ClearValue.Color.b, + attachment.ClearValue.Color.a }; + attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + } + } + + renderingInfo.colorAttachmentCount = static_cast(colorAttachmentInfos.size()); + renderingInfo.pColorAttachments = colorAttachmentInfos.data(); + + if (depth) + renderingInfo.pDepthAttachment = &depthAttachmentInfo; + + if (spec.CubeMap) + renderingInfo.viewMask = 0b111111; + } + + // Begin dynamic rendering + const auto cmd = std::static_pointer_cast(commandBuffer); + const VkCommandBuffer cb = cmd->GetCurrentCommandBuffer(); + vkCmdBeginRendering(cb, &renderingInfo); + + if (bindPipeline) + { + // Bind pipeline + vkCmdBindPipeline(cb, VK_PIPELINE_BIND_POINT_GRAPHICS, vkPipeline->GetPipeline()); + + // Set viewport + VkViewport viewport; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = static_cast(spec.Width); + viewport.height = static_cast(spec.Height); + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + vkCmdSetViewport(cb, 0, 1, &viewport); + + // Set scissor + VkRect2D scissor; + scissor.offset = { .x = 0, .y = 0 }; + scissor.extent = { .width = spec.Width, .height = spec.Height }; + + vkCmdSetScissor(cb, 0, 1, &scissor); + } + } + + void VulkanRenderer::EndRenderPass(const Ref& commandBuffer) + { + EPPO_PROFILE_FUNCTION("VulkanRenderer::EndRenderPass"); + + const auto cmd = std::static_pointer_cast(commandBuffer); + const VkCommandBuffer cb = cmd->GetCurrentCommandBuffer(); + vkCmdEndRendering(cb); + } + + void* VulkanRenderer::AllocateDescriptor(void* layout) + { + const uint32_t frameIndex = VulkanContext::Get()->GetCurrentFrameIndex(); + return m_DescriptorAllocators[frameIndex].Allocate(layout); + } } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanRenderer.h b/EppoEngine/Source/Platform/Vulkan/VulkanRenderer.h index b794f73d..5db4c2e4 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanRenderer.h +++ b/EppoEngine/Source/Platform/Vulkan/VulkanRenderer.h @@ -6,36 +6,36 @@ namespace Eppo { - class VulkanRenderer final : public Renderer - { - public: - VulkanRenderer(); - VulkanRenderer(const VulkanRenderer&) = delete; - VulkanRenderer(const VulkanRenderer&&) = delete; - VulkanRenderer& operator=(const VulkanRenderer&) = delete; - VulkanRenderer& operator=(const VulkanRenderer&&) = delete; - ~VulkanRenderer() override = default; - - void Shutdown() override; - - // Render queue commands - void ExecuteRenderCommands() override; - void SubmitCommand(RenderCommand command) override; - - // Render passes - void BeginRenderPass(const Ref& commandBuffer, const Ref& pipeline, bool bindPipeline = true) override; - void EndRenderPass(const Ref& commandBuffer) override; - - // Shaders - Ref GetShader(const std::string& name) override { return m_ShaderLibrary.Get(name); } - void* AllocateDescriptor(void* layout) override; - - private: - CommandQueue m_CommandQueue; - ShaderLibrary m_ShaderLibrary; - - std::array m_DescriptorAllocators; - - static bool s_IsInstantiated; - }; + class VulkanRenderer final : public Renderer + { + public: + VulkanRenderer(); + VulkanRenderer(const VulkanRenderer&) = delete; + VulkanRenderer(const VulkanRenderer&&) = delete; + VulkanRenderer& operator=(const VulkanRenderer&) = delete; + VulkanRenderer& operator=(const VulkanRenderer&&) = delete; + ~VulkanRenderer() override = default; + + void Shutdown() override; + + // Render queue commands + void ExecuteRenderCommands() override; + void SubmitCommand(RenderCommand command) override; + + // Render passes + void BeginRenderPass(const Ref& commandBuffer, const Ref& pipeline, bool bindPipeline = true) override; + void EndRenderPass(const Ref& commandBuffer) override; + + // Shaders + Ref GetShader(const std::string& name) override { return m_ShaderLibrary.Get(name); } + void* AllocateDescriptor(void* layout) override; + + private: + CommandQueue m_CommandQueue; + ShaderLibrary m_ShaderLibrary; + + std::array m_DescriptorAllocators; + + static bool s_IsInstantiated; + }; } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanSceneRenderer.cpp b/EppoEngine/Source/Platform/Vulkan/VulkanSceneRenderer.cpp index b7948bf8..6998a40b 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanSceneRenderer.cpp +++ b/EppoEngine/Source/Platform/Vulkan/VulkanSceneRenderer.cpp @@ -22,948 +22,947 @@ namespace Eppo { - VulkanSceneRenderer::VulkanSceneRenderer(const Ref& scene, const RenderSpecification& renderSpec) - : m_RenderSpecification(renderSpec), m_Scene(scene) - { - Ref context = VulkanContext::Get(); - Ref swapchain = context->GetSwapchain(); - auto renderer = context->GetRenderer(); - - m_CommandBuffer = swapchain->GetCommandBuffer(); - m_DebugRenderer = DebugRenderer::Create(); - - VkCommandBuffer cmd = context->GetLogicalDevice()->GetCommandBuffer(true); - - // PreDepth - { - for (uint32_t i = 0; i < s_MaxLights; i++) - { - ImageSpecification imageSpec; - imageSpec.Format = ImageFormat::Depth; - imageSpec.Width = 1024; - imageSpec.Height = 1024; - imageSpec.CubeMap = true; - - m_ShadowMaps[i] = Image::Create(imageSpec); - - VulkanImage::TransitionImage(cmd, std::static_pointer_cast(m_ShadowMaps[i])->GetImageInfo().Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL); - } - - PipelineSpecification pipelineSpec; - pipelineSpec.CreateDepthImage = true; - pipelineSpec.TestDepth = true; - pipelineSpec.WriteDepth = true; - pipelineSpec.Width = 1024; - pipelineSpec.Height = 1024; - pipelineSpec.Shader = renderer->GetShader("predepth"); - pipelineSpec.Layout = { - { ShaderDataType::Float3, "inPosition" }, - { ShaderDataType::Float3, "inNormal" }, - { ShaderDataType::Float2, "inTexCoord" } - }; - - m_PreDepthPipeline = Pipeline::Create(pipelineSpec); - } - - // Environment - { - ImageSpecification imageSpec("Resources/Textures/Environment/HDR_040_Field.hdr"); - m_EnvironmentMap = Image::Create(imageSpec); - - ImageSpecification cubeImageSpec; - cubeImageSpec.CubeMap = true; - cubeImageSpec.Format = ImageFormat::RGB16; - cubeImageSpec.Width = 512; - cubeImageSpec.Height = 512; - m_EnvironmentCubeMap = Image::Create(cubeImageSpec); - - VulkanImage::TransitionImage(cmd, std::static_pointer_cast(m_EnvironmentCubeMap)->GetImageInfo().Image, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - PipelineSpecification pipelineSpec; - pipelineSpec.RenderAttachments = { - RenderAttachment{ m_EnvironmentCubeMap, true, glm::vec4(0.0f) } - }; - pipelineSpec.CubeMap = true; - pipelineSpec.CullFrontFace = CullFrontFace::CounterClockwise; - pipelineSpec.Width = m_EnvironmentCubeMap->GetWidth(); - pipelineSpec.Height = m_EnvironmentCubeMap->GetHeight(); - pipelineSpec.Shader = renderer->GetShader("env"); - - m_EnvPipeline = Pipeline::Create(pipelineSpec); - } - - // Geometry - { - ImageSpecification imageSpec; - imageSpec.Format = ImageFormat::RGBA8; - imageSpec.Usage = ImageUsage::Attachment; - imageSpec.Width = m_RenderSpecification.Width; - imageSpec.Height = m_RenderSpecification.Height; - - PipelineSpecification pipelineSpec; - pipelineSpec.RenderAttachments = { - RenderAttachment{ Image::Create(imageSpec), true, glm::vec4(0.0f) }, - RenderAttachment{ Image::Create(imageSpec), true, glm::vec4(0.0f) }, - RenderAttachment{ Image::Create(imageSpec), true, glm::vec4(0.0f) } - }; - pipelineSpec.CreateDepthImage = true; - pipelineSpec.TestDepth = true; - pipelineSpec.WriteDepth = true; - pipelineSpec.Width = m_RenderSpecification.Width; - pipelineSpec.Height = m_RenderSpecification.Height; - pipelineSpec.Shader = renderer->GetShader("geometry"); - pipelineSpec.Layout = { - { ShaderDataType::Float3, "inPosition" }, - { ShaderDataType::Float3, "inNormal" }, - { ShaderDataType::Float2, "inTexCoord" } - }; - - m_GeometryPipeline = Pipeline::Create(pipelineSpec); - } - - // Skybox - { - Ref depthImage = m_GeometryPipeline->GetImage(3); - - PipelineSpecification pipelineSpec; - pipelineSpec.RenderAttachments = { - RenderAttachment{ m_GeometryPipeline->GetFinalImage(), false, glm::vec4(0.0f) }, - RenderAttachment{ depthImage, false, 1.0f } - }; - pipelineSpec.DepthCompareOp = DepthCompareOp::LessOrEqual; - pipelineSpec.TestDepth = true; - pipelineSpec.CullMode = CullMode::Front; - pipelineSpec.Width = m_RenderSpecification.Width; - pipelineSpec.Height = m_RenderSpecification.Height; - pipelineSpec.Shader = renderer->GetShader("skybox"); - - m_SkyboxPipeline = Pipeline::Create(pipelineSpec); - } - - // Debug Line - if (m_RenderSpecification.DebugRendering) - { - Ref dstImage = m_GeometryPipeline->GetFinalImage(); - - PipelineSpecification pipelineSpec; - pipelineSpec.RenderAttachments = { - RenderAttachment{ dstImage, false, glm::vec4(0.0f) } - }; - pipelineSpec.Topology = PrimitiveTopology::Lines; - pipelineSpec.PolygonMode = PolygonMode::Line; - pipelineSpec.Width = dstImage->GetWidth(); - pipelineSpec.Height = dstImage->GetHeight(); - pipelineSpec.Shader = renderer->GetShader("debug"); - pipelineSpec.Layout = { - { ShaderDataType::Float3, "inPosition" }, - { ShaderDataType::Float4, "inColor" } - }; - - m_DebugLinePipeline = Pipeline::Create(pipelineSpec); - } - - // Composite - { - PipelineSpecification pipelineSpec; - pipelineSpec.SwapchainTarget = true; - pipelineSpec.Width = swapchain->GetWidth(); - pipelineSpec.Height = swapchain->GetHeight(); - pipelineSpec.Shader = renderer->GetShader("composite"); - - m_CompositePipeline = Pipeline::Create(pipelineSpec); - } - - // Execute image transitions - context->GetLogicalDevice()->FlushCommandBuffer(cmd); - - // Create descriptor sets from geometry shader - const auto geometryShader = std::static_pointer_cast(m_GeometryPipeline->GetSpecification().Shader); - const auto& descriptorSetLayouts = geometryShader->GetDescriptorSetLayouts(); - for (uint32_t i = 0; i < VulkanConfig::MaxFramesInFlight; i++) - { - for (uint32_t j = 0; j < 4; j++) - m_DescriptorSets[i][j] = static_cast(renderer->AllocateDescriptor(descriptorSetLayouts[j])); - } - - // Vertex and Index buffers - m_DebugLineVertexBuffer = VertexBuffer::Create(sizeof(LineVertex) * 100); - m_DebugLineIndexBuffer = IndexBuffer::Create(sizeof(uint32_t) * 100); - - // Uniform buffers - // Set 0 - m_EnvironmentUB = UniformBuffer::Create(sizeof(EnvironmentData), 2); - // Set 1 - m_CameraUB = UniformBuffer::Create(sizeof(CameraData), 0); - m_LightsUB = UniformBuffer::Create(sizeof(LightsData), 1); - } - - void VulkanSceneRenderer::RenderGui() - { - EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::RenderGui"); - - ImGui::Begin("Performance"); - - uint32_t frameIndex = VulkanContext::Get()->GetCurrentFrameIndex(); - frameIndex = frameIndex == 0 ? 1 : 0; - - const auto cmd = std::static_pointer_cast(m_CommandBuffer); - - ImGui::Text("GPU Time: %.3fms", cmd->GetTimestamp(frameIndex)); - ImGui::Text("PreDepth Pass: %.3fms", cmd->GetTimestamp(frameIndex, m_TimestampQueries.PreDepthQuery)); - ImGui::Text("Geometry Pass: %.3fms", cmd->GetTimestamp(frameIndex, m_TimestampQueries.GeometryQuery)); - ImGui::Text("Skybox Pass: %.3fms", cmd->GetTimestamp(frameIndex, m_TimestampQueries.SkyboxQuery)); - - if (m_RenderSpecification.DebugRendering) - ImGui::Text("Debug Line Pass: %.3fms", cmd->GetTimestamp(frameIndex, m_TimestampQueries.DebugLineQuery)); - - ImGui::Text("Composite Pass: %.3fms", cmd->GetTimestamp(frameIndex, m_TimestampQueries.CompositeQuery)); - - ImGui::Separator(); - - const auto& pipelineStats = cmd->GetPipelineStatistics(frameIndex); - - ImGui::Text("Pipeline statistics:"); - ImGui::Text("Input Assembly Vertices: %llu", pipelineStats.InputAssemblyVertices); - ImGui::Text("Input Assembly Primitives: %llu", pipelineStats.InputAssemblyPrimitives); - ImGui::Text("Vertex Shader Invocations: %llu", pipelineStats.VertexShaderInvocations); - ImGui::Text("Clipping Invocations: %llu", pipelineStats.ClippingInvocations); - ImGui::Text("Clipping Primitives: %llu", pipelineStats.ClippingPrimitives); - ImGui::Text("Fragment Shader Invocations: %llu", pipelineStats.FragmentShaderInvocations); - - ImGui::Separator(); - - ImGui::Text("Draw calls: %u", m_RenderStatistics.DrawCalls); - ImGui::Text("Meshes: %u", m_RenderStatistics.Meshes); - ImGui::Text("Submeshes: %u", m_RenderStatistics.Submeshes); - ImGui::Text("Instances: %u", m_RenderStatistics.MeshInstances); - ImGui::Text("Camera position: %.2f, %.2f, %.2f", m_CameraBuffer.Position.x, m_CameraBuffer.Position.y, m_CameraBuffer.Position.z); - - ImGui::End(); - - ImGui::Begin("Debug Maps"); - - { - const Ref image = m_GeometryPipeline->GetImage(1); - const float height = (static_cast(image->GetHeight()) / static_cast(image->GetWidth())) * 300; - UI::Image(m_GeometryPipeline->GetImage(1), ImVec2(300.0f, height), ImVec2(0, 1), ImVec2(1, 0)); - } - - { - const Ref image = m_GeometryPipeline->GetImage(2); - const float height = (static_cast(image->GetHeight()) / static_cast(image->GetWidth())) * 300; - UI::Image(m_GeometryPipeline->GetImage(2), ImVec2(300.0f, height), ImVec2(0, 1), ImVec2(1, 0)); - } - - ImGui::End(); - } - - void VulkanSceneRenderer::Resize(uint32_t width, uint32_t height) - { - //m_GeometryFramebuffer->Resize(width, height); - } - - void VulkanSceneRenderer::BeginScene(const EditorCamera& editorCamera) - { - EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::BeginScene"); - - // Cleanup from last draw - m_DrawList.clear(); - - // Reset statistics - memset(&m_RenderStatistics, 0, sizeof(RenderStatistics)); - - // Camera UB - m_CameraBuffer.View = editorCamera.GetViewMatrix(); - m_CameraBuffer.Projection = editorCamera.GetProjectionMatrix(); - m_CameraBuffer.ViewProjection = editorCamera.GetViewProjectionMatrix(); - m_CameraBuffer.Position = glm::vec4(editorCamera.GetPosition(), 0.0f); - m_CameraUB->SetData(&m_CameraBuffer, sizeof(m_CameraBuffer)); - } - - void VulkanSceneRenderer::BeginScene(const Camera& camera, const glm::mat4& transform) - { - EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::BeginScene"); - - // Cleanup from last draw - m_DrawList.clear(); - - // Reset statistics - memset(&m_RenderStatistics, 0, sizeof(RenderStatistics)); - - // Camera UB - m_CameraBuffer.View = glm::inverse(transform); - m_CameraBuffer.Projection = camera.GetProjectionMatrix(); - m_CameraBuffer.ViewProjection = camera.GetProjectionMatrix() * glm::inverse(transform); - m_CameraBuffer.Position = transform[3]; - m_CameraUB->SetData(&m_CameraBuffer, sizeof(m_CameraBuffer)); - } - - void VulkanSceneRenderer::EndScene() - { - EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::EndScene"); - - Flush(); - } - - void VulkanSceneRenderer::SubmitDrawCommand(const EntityType type, Ref drawCommand) - { - EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::SubmitDrawCommand"); - - if (type == EntityType::PointLight && m_DrawList[EntityType::PointLight].size() == 8) - { - EPPO_WARN("Trying to submit more point lights than we currently support!"); - return; - } - - m_DrawList[type].emplace_back(drawCommand); - } - - Ref VulkanSceneRenderer::GetFinalImage() - { - return m_GeometryPipeline->GetFinalImage(); - } - - void VulkanSceneRenderer::Flush() - { - EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::Flush"); - - m_CommandBuffer->RT_Begin(); - - // Prepare buffers - PrepareBuffers(); - PrepareImages(); - UpdateDescriptors(); - - // Record render commands - GuiPass(); - PreDepthPass(); - EnvPass(); - GeometryPass(); - SkyboxPass(); - - if (m_RenderSpecification.DebugRendering) - DebugLinePass(); - - CompositePass(); - - const auto cmd = std::static_pointer_cast(m_CommandBuffer); - const auto renderer = VulkanContext::Get()->GetRenderer(); - renderer->SubmitCommand([cmd]() - { - const auto context = VulkanContext::Get(); - const VkCommandBuffer commandBuffer = cmd->GetCurrentCommandBuffer(); - EPPO_PROFILE_GPU_END(context->GetTracyContext(), commandBuffer) - }); - - // Submit work - m_CommandBuffer->RT_End(); - } - - void Eppo::VulkanSceneRenderer::PrepareBuffers() - { - EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::PrepareBuffers"); - - // Environment UB - m_EnvironmentBuffer.Projection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f); - m_EnvironmentBuffer.View[0] = glm::lookAt(glm::vec3(0.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)); - m_EnvironmentBuffer.View[1] = glm::lookAt(glm::vec3(0.0f), glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)); - m_EnvironmentBuffer.View[2] = glm::lookAt(glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); - m_EnvironmentBuffer.View[3] = glm::lookAt(glm::vec3(0.0f), glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)); - m_EnvironmentBuffer.View[4] = glm::lookAt(glm::vec3(0.0f), glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)); - m_EnvironmentBuffer.View[5] = glm::lookAt(glm::vec3(0.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)); - m_EnvironmentUB->SetData(&m_EnvironmentBuffer, sizeof(EnvironmentData)); - - // Lights UB - m_LightsBuffer.Projection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 50.0f); - m_LightsBuffer.NumLights = 0; - - std::vector lineVertices; - std::vector lineIndices; - uint32_t vertexCount = 0; - - uint32_t i = 0; - while (i < 8 && !m_DrawList[EntityType::PointLight].empty()) - { - Ref dc = m_DrawList[EntityType::PointLight].back(); - const auto plCmd = std::static_pointer_cast(dc); - - auto& [view, position, color] = m_LightsBuffer.Lights[i]; - position = glm::vec4(plCmd->Position, 1.0f); - color = plCmd->Color; - view[0] = lookAt(plCmd->Position, plCmd->Position + glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)); - view[1] = lookAt(plCmd->Position, plCmd->Position + glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)); - view[2] = lookAt(plCmd->Position, plCmd->Position + glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); - view[3] = lookAt(plCmd->Position, plCmd->Position + glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)); - view[4] = lookAt(plCmd->Position, plCmd->Position + glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)); - view[5] = lookAt(plCmd->Position, plCmd->Position + glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)); - - // Setup Debug Lines - LineVertex& p0 = lineVertices.emplace_back(); - p0.Position = plCmd->Position - glm::vec3(0.0f, 0.5f, 0.0f); - p0.Color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); - lineIndices.emplace_back(vertexCount); - vertexCount++; - - LineVertex& p1 = lineVertices.emplace_back(); - p1.Position = plCmd->Position + glm::vec3(0.0f, 0.5f, 0.0f); - p1.Color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); - lineIndices.emplace_back(vertexCount); - vertexCount++; - - LineVertex& p2 = lineVertices.emplace_back(); - p2.Position = plCmd->Position - glm::vec3(0.5f, 0.0f, 0.0f); - p2.Color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); - lineIndices.emplace_back(vertexCount); - vertexCount++; - - LineVertex& p3 = lineVertices.emplace_back(); - p3.Position = plCmd->Position + glm::vec3(0.5f, 0.0f, 0.0f); - p3.Color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); - lineIndices.emplace_back(vertexCount); - vertexCount++; - - LineVertex& p4 = lineVertices.emplace_back(); - p4.Position = plCmd->Position - glm::vec3(0.0f, 0.0f, 0.5f); - p4.Color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); - lineIndices.emplace_back(vertexCount); - vertexCount++; - - LineVertex& p5 = lineVertices.emplace_back(); - p5.Position = plCmd->Position + glm::vec3(0.0f, 0.0f, 0.5f); - p5.Color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); - lineIndices.emplace_back(vertexCount); - vertexCount++; - - m_DrawList[EntityType::PointLight].pop_back(); - i++; - } - - m_LightsBuffer.NumLights = i; - - if (!lineVertices.empty() && !lineIndices.empty()) - { - Buffer ib = Buffer::Copy(lineIndices.data(), static_cast(sizeof(uint32_t)) * static_cast(lineIndices.size())); - m_DebugLineIndexBuffer->SetData(ib); - ib.Release(); - - Buffer vb = Buffer::Copy(lineVertices.data(), static_cast(sizeof(LineVertex)) * static_cast(lineVertices.size())); - m_DebugLineVertexBuffer->SetData(vb); - vb.Release(); - - m_DebugLineCount = static_cast(lineIndices.size()); - } - - m_LightsUB->SetData(&m_LightsBuffer, sizeof(LightsData)); - } - - void VulkanSceneRenderer::PrepareImages() const - { - const auto cmd = std::static_pointer_cast(m_CommandBuffer); - const auto renderer = VulkanContext::Get()->GetRenderer(); - - renderer->SubmitCommand([this, cmd]() - { - EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::PrepareImages"); - - const auto commandBuffer = cmd->GetCurrentCommandBuffer(); - - // Transition depth images for writing - for (uint32_t i = 0; i < s_MaxLights; i++) - VulkanImage::TransitionImage( - commandBuffer, - std::static_pointer_cast(m_ShadowMaps[i])->GetImageInfo().Image, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, - VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT - ); - }); - } - - void VulkanSceneRenderer::UpdateDescriptors() - { - const auto renderer = VulkanContext::Get()->GetRenderer(); - renderer->SubmitCommand([this]() - { - EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::UpdateDescriptors"); - - const uint32_t frameIndex = VulkanContext::Get()->GetCurrentFrameIndex(); - const auto descriptorSets = m_DescriptorSets[frameIndex]; - - DescriptorWriter writer; - - // Set 0 - Global - { - // Binding 0 - const auto& info = std::static_pointer_cast(m_EnvironmentMap)->GetImageInfo(); - writer.WriteImage(0, info.ImageView, info.Sampler, info.ImageLayout, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); - } - - { - // Binding 1 - const auto& info = std::static_pointer_cast(m_EnvironmentCubeMap)->GetImageInfo(); - writer.WriteImage(1, info.ImageView, info.Sampler, info.ImageLayout, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); - } - - { - // Binding 2 - const auto& buffers = std::static_pointer_cast(m_EnvironmentUB)->GetBuffers(); - const VkBuffer buffer = buffers[frameIndex]; - writer.WriteBuffer(m_EnvironmentUB->GetBinding(), buffer, sizeof(EnvironmentData), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); - } - - writer.UpdateSet(descriptorSets[0]); - writer.Clear(); - - // Set 1 - Scene - { - // Binding 0 - const auto& buffers = std::static_pointer_cast(m_CameraUB)->GetBuffers(); - const VkBuffer buffer = buffers[frameIndex]; - writer.WriteBuffer(m_CameraUB->GetBinding(), buffer, sizeof(CameraData), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); - } - - { - // Binding 1 - const auto& buffers = std::static_pointer_cast(m_LightsUB)->GetBuffers(); - const VkBuffer buffer = buffers[frameIndex]; - writer.WriteBuffer(m_LightsUB->GetBinding(), buffer, sizeof(LightsData), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); - } - - std::vector imageInfos; - { - // Binding 2 - for (const auto& shadowMap : m_ShadowMaps) - { - const ImageInfo& imageInfo = std::static_pointer_cast(shadowMap)->GetImageInfo(); - - auto& [sampler, imageView, imageLayout] = imageInfos.emplace_back(); - imageLayout = imageInfo.ImageLayout; - imageView = imageInfo.ImageView; - sampler = imageInfo.Sampler; - } - - writer.WriteImages(2, imageInfos, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); - } - - writer.UpdateSet(descriptorSets[1]); - writer.Clear(); - imageInfos.clear(); - - // Set 2 - Material - // TODO: When we go over the max limit, we need to do this in the pass itself - { - // Binding 0 - for (const auto& dc : m_DrawList[EntityType::Mesh]) - { - const auto meshCmd = std::static_pointer_cast(dc); - - for (const auto& image : meshCmd->Mesh->GetImages()) - { - const ImageInfo& imageInfo = std::static_pointer_cast(image)->GetImageInfo(); - - auto& [sampler, imageView, imageLayout] = imageInfos.emplace_back(); - imageLayout = imageInfo.ImageLayout; - imageView = imageInfo.ImageView; - sampler = imageInfo.Sampler; - } - - writer.WriteImages(0, imageInfos, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); - } - } - - writer.UpdateSet(descriptorSets[2]); - }); - } - - void VulkanSceneRenderer::GuiPass() - { - const auto renderer = VulkanContext::Get()->GetRenderer(); - renderer->SubmitCommand([]() - { - EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::GuiPass"); - - ImGui_ImplVulkan_NewFrame(); - ImGui_ImplGlfw_NewFrame(); - ImGui::NewFrame(); - - Application::Get().RenderGui(); - - ImGui::Render(); - }); - } - - void VulkanSceneRenderer::PreDepthPass() - { - const auto cmd = std::static_pointer_cast(m_CommandBuffer); - const auto pipeline = std::static_pointer_cast(m_PreDepthPipeline); - const auto renderer = VulkanContext::Get()->GetRenderer(); - - m_TimestampQueries.PreDepthQuery = cmd->RT_BeginTimestampQuery(); - - renderer->SubmitCommand([this, cmd, pipeline, renderer]() - { - EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::PreDepthPass"); - - // Get all required variables - const VkCommandBuffer commandBuffer = cmd->GetCurrentCommandBuffer(); - auto& spec = pipeline->GetSpecification(); - - const auto& pcr = std::static_pointer_cast(spec.Shader)->GetPushConstantRanges(); - ScopedBuffer pcrBuffer(pcr[0].size); - - // Profiling - EPPO_PROFILE_GPU(VulkanContext::Get()->GetTracyContext(), cmd->GetCurrentCommandBuffer(), "PreDepth") - - // Insert debug label - if (m_RenderSpecification.DebugRendering) - m_DebugRenderer->StartDebugLabel(m_CommandBuffer, "PreDepthPass"); - - // Update descriptor sets - const uint32_t frameIndex = VulkanContext::Get()->GetCurrentFrameIndex(); - const auto& descriptorSets = m_DescriptorSets[frameIndex]; - - for (uint32_t i = 0; i < m_LightsBuffer.NumLights; i++) - { - spec.RenderAttachments.clear(); - spec.RenderAttachments.emplace_back(m_ShadowMaps[i], true, 1.0f); - - // Begin rendering - renderer->BeginRenderPass(m_CommandBuffer, m_PreDepthPipeline); - - // Bind descriptor sets - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->GetPipelineLayout(), 0, 3, descriptorSets.data(), 0, nullptr); - - // Render geometry - for (const auto& dc : m_DrawList[EntityType::Mesh]) - { - const auto meshCmd = std::static_pointer_cast(dc); - m_RenderStatistics.MeshInstances++; - - for (const auto& submesh : meshCmd->Mesh->GetSubmeshes()) - { - // Bind vertex buffer - const auto vertexBuffer = std::static_pointer_cast(submesh.GetVertexBuffer()); - VkBuffer vb = { vertexBuffer->GetBuffer() }; - constexpr VkDeviceSize offsets[] = { 0 }; - - vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vb, offsets); - - // Bind index buffer - const auto indexBuffer = std::static_pointer_cast(submesh.GetIndexBuffer()); - vkCmdBindIndexBuffer(commandBuffer, indexBuffer->GetBuffer(), 0, VK_INDEX_TYPE_UINT32); - - // Draw call - glm::mat4 finalTransform = meshCmd->Transform * submesh.GetLocalTransform(); - - for (const auto& p : submesh.GetPrimitives()) - { - pcrBuffer.SetData(finalTransform); - pcrBuffer.SetData(i, 64); - - vkCmdPushConstants(commandBuffer, pipeline->GetPipelineLayout(), VK_SHADER_STAGE_ALL_GRAPHICS, 0, pcrBuffer.Size(), pcrBuffer.Data()); - - m_RenderStatistics.DrawCalls++; - vkCmdDrawIndexed(commandBuffer, p.IndexCount, 1, p.FirstIndex, static_cast(p.FirstVertex), 0); - } - } - } - - // End rendering - renderer->EndRenderPass(m_CommandBuffer); - } - - // Transition image for reading - for (uint32_t i = 0; i < s_MaxLights; i++) - VulkanImage::TransitionImage( - commandBuffer, - std::static_pointer_cast(m_ShadowMaps[i])->GetImageInfo().Image, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL - ); - - if (m_RenderSpecification.DebugRendering) - m_DebugRenderer->EndDebugLabel(m_CommandBuffer); - }); - - cmd->RT_EndTimestampQuery(m_TimestampQueries.PreDepthQuery); - } - - void VulkanSceneRenderer::EnvPass() - { - const auto cmd = std::static_pointer_cast(m_CommandBuffer); - const auto pipeline = std::static_pointer_cast(m_EnvPipeline); - const auto renderer = VulkanContext::Get()->GetRenderer(); - - renderer->SubmitCommand([this, cmd, pipeline, renderer]() - { - EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::EnvPass"); + VulkanSceneRenderer::VulkanSceneRenderer(const Ref& scene, const RenderSpecification& renderSpec) + : m_RenderSpecification(renderSpec), m_Scene(scene) + { + Ref context = VulkanContext::Get(); + Ref swapchain = context->GetSwapchain(); + auto renderer = context->GetRenderer(); + + m_CommandBuffer = swapchain->GetCommandBuffer(); + m_DebugRenderer = DebugRenderer::Create(); + + VkCommandBuffer cmd = context->GetLogicalDevice()->GetCommandBuffer(true); + + // PreDepth + { + for (uint32_t i = 0; i < s_MaxLights; i++) + { + ImageSpecification imageSpec; + imageSpec.Format = ImageFormat::Depth; + imageSpec.Width = 1024; + imageSpec.Height = 1024; + imageSpec.CubeMap = true; + + m_ShadowMaps[i] = Image::Create(imageSpec); + + VulkanImage::TransitionImage(cmd, std::static_pointer_cast(m_ShadowMaps[i])->GetImageInfo().Image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL); + } + + PipelineSpecification pipelineSpec; + pipelineSpec.CreateDepthImage = true; + pipelineSpec.TestDepth = true; + pipelineSpec.WriteDepth = true; + pipelineSpec.Width = 1024; + pipelineSpec.Height = 1024; + pipelineSpec.Shader = renderer->GetShader("predepth"); + pipelineSpec.Layout = { + { ShaderDataType::Float3, "inPosition" }, + { ShaderDataType::Float3, "inNormal" }, + { ShaderDataType::Float2, "inTexCoord" } + }; + + m_PreDepthPipeline = Pipeline::Create(pipelineSpec); + } + + // Environment + { + ImageSpecification imageSpec("Resources/Textures/Environment/HDR_040_Field.hdr"); + m_EnvironmentMap = Image::Create(imageSpec); + + ImageSpecification cubeImageSpec; + cubeImageSpec.CubeMap = true; + cubeImageSpec.Format = ImageFormat::RGB16; + cubeImageSpec.Width = 512; + cubeImageSpec.Height = 512; + m_EnvironmentCubeMap = Image::Create(cubeImageSpec); + + VulkanImage::TransitionImage(cmd, std::static_pointer_cast(m_EnvironmentCubeMap)->GetImageInfo().Image, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + + PipelineSpecification pipelineSpec; + pipelineSpec.RenderAttachments = { + RenderAttachment{ m_EnvironmentCubeMap, true, glm::vec4(0.0f) } + }; + pipelineSpec.CubeMap = true; + pipelineSpec.CullFrontFace = CullFrontFace::CounterClockwise; + pipelineSpec.Width = m_EnvironmentCubeMap->GetWidth(); + pipelineSpec.Height = m_EnvironmentCubeMap->GetHeight(); + pipelineSpec.Shader = renderer->GetShader("env"); + + m_EnvPipeline = Pipeline::Create(pipelineSpec); + } + + // Geometry + { + ImageSpecification imageSpec; + imageSpec.Format = ImageFormat::RGBA8; + imageSpec.Usage = ImageUsage::Attachment; + imageSpec.Width = m_RenderSpecification.Width; + imageSpec.Height = m_RenderSpecification.Height; + + PipelineSpecification pipelineSpec; + pipelineSpec.RenderAttachments = { + RenderAttachment{ Image::Create(imageSpec), true, glm::vec4(0.0f) }, + RenderAttachment{ Image::Create(imageSpec), true, glm::vec4(0.0f) }, + RenderAttachment{ Image::Create(imageSpec), true, glm::vec4(0.0f) } + }; + pipelineSpec.CreateDepthImage = true; + pipelineSpec.TestDepth = true; + pipelineSpec.WriteDepth = true; + pipelineSpec.Width = m_RenderSpecification.Width; + pipelineSpec.Height = m_RenderSpecification.Height; + pipelineSpec.Shader = renderer->GetShader("geometry"); + pipelineSpec.Layout = { + { ShaderDataType::Float3, "inPosition" }, + { ShaderDataType::Float3, "inNormal" }, + { ShaderDataType::Float2, "inTexCoord" } + }; + + m_GeometryPipeline = Pipeline::Create(pipelineSpec); + } + + // Skybox + { + Ref depthImage = m_GeometryPipeline->GetImage(3); + + PipelineSpecification pipelineSpec; + pipelineSpec.RenderAttachments = { + RenderAttachment{ m_GeometryPipeline->GetFinalImage(), false, glm::vec4(0.0f) }, + RenderAttachment{ depthImage, false, 1.0f } + }; + pipelineSpec.DepthCompareOp = DepthCompareOp::LessOrEqual; + pipelineSpec.TestDepth = true; + pipelineSpec.CullMode = CullMode::Front; + pipelineSpec.Width = m_RenderSpecification.Width; + pipelineSpec.Height = m_RenderSpecification.Height; + pipelineSpec.Shader = renderer->GetShader("skybox"); + + m_SkyboxPipeline = Pipeline::Create(pipelineSpec); + } + + // Debug Line + if (m_RenderSpecification.DebugRendering) + { + Ref dstImage = m_GeometryPipeline->GetFinalImage(); + + PipelineSpecification pipelineSpec; + pipelineSpec.RenderAttachments = { + RenderAttachment{ dstImage, false, glm::vec4(0.0f) } + }; + pipelineSpec.Topology = PrimitiveTopology::Lines; + pipelineSpec.PolygonMode = PolygonMode::Line; + pipelineSpec.Width = dstImage->GetWidth(); + pipelineSpec.Height = dstImage->GetHeight(); + pipelineSpec.Shader = renderer->GetShader("debug"); + pipelineSpec.Layout = { + { ShaderDataType::Float3, "inPosition" }, + { ShaderDataType::Float4, "inColor" } + }; + + m_DebugLinePipeline = Pipeline::Create(pipelineSpec); + } + + // Composite + { + PipelineSpecification pipelineSpec; + pipelineSpec.SwapchainTarget = true; + pipelineSpec.Width = swapchain->GetWidth(); + pipelineSpec.Height = swapchain->GetHeight(); + pipelineSpec.Shader = renderer->GetShader("composite"); + + m_CompositePipeline = Pipeline::Create(pipelineSpec); + } + + // Execute image transitions + context->GetLogicalDevice()->FlushCommandBuffer(cmd); + + // Create descriptor sets from geometry shader + const auto geometryShader = std::static_pointer_cast(m_GeometryPipeline->GetSpecification().Shader); + const auto& descriptorSetLayouts = geometryShader->GetDescriptorSetLayouts(); + for (uint32_t i = 0; i < VulkanConfig::MaxFramesInFlight; i++) + { + for (uint32_t j = 0; j < 4; j++) + m_DescriptorSets[i][j] = static_cast(renderer->AllocateDescriptor(descriptorSetLayouts[j])); + } + + // Vertex and Index buffers + m_DebugLineVertexBuffer = VertexBuffer::Create(sizeof(LineVertex) * 100); + m_DebugLineIndexBuffer = IndexBuffer::Create(sizeof(uint32_t) * 100); + + // Uniform buffers + // Set 0 + m_EnvironmentUB = UniformBuffer::Create(sizeof(EnvironmentData), 2); + // Set 1 + m_CameraUB = UniformBuffer::Create(sizeof(CameraData), 0); + m_LightsUB = UniformBuffer::Create(sizeof(LightsData), 1); + } + + void VulkanSceneRenderer::RenderGui() + { + EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::RenderGui"); + + ImGui::Begin("Performance"); + + uint32_t frameIndex = VulkanContext::Get()->GetCurrentFrameIndex(); + frameIndex = frameIndex == 0 ? 1 : 0; + + const auto cmd = std::static_pointer_cast(m_CommandBuffer); + + ImGui::Text("GPU Time: %.3fms", cmd->GetTimestamp(frameIndex)); + ImGui::Text("PreDepth Pass: %.3fms", cmd->GetTimestamp(frameIndex, m_TimestampQueries.PreDepthQuery)); + ImGui::Text("Geometry Pass: %.3fms", cmd->GetTimestamp(frameIndex, m_TimestampQueries.GeometryQuery)); + ImGui::Text("Skybox Pass: %.3fms", cmd->GetTimestamp(frameIndex, m_TimestampQueries.SkyboxQuery)); + + if (m_RenderSpecification.DebugRendering) + ImGui::Text("Debug Line Pass: %.3fms", cmd->GetTimestamp(frameIndex, m_TimestampQueries.DebugLineQuery)); + + ImGui::Text("Composite Pass: %.3fms", cmd->GetTimestamp(frameIndex, m_TimestampQueries.CompositeQuery)); + + ImGui::Separator(); + + const auto& pipelineStats = cmd->GetPipelineStatistics(frameIndex); + + ImGui::Text("Pipeline statistics:"); + ImGui::Text("Input Assembly Vertices: %llu", pipelineStats.InputAssemblyVertices); + ImGui::Text("Input Assembly Primitives: %llu", pipelineStats.InputAssemblyPrimitives); + ImGui::Text("Vertex Shader Invocations: %llu", pipelineStats.VertexShaderInvocations); + ImGui::Text("Clipping Invocations: %llu", pipelineStats.ClippingInvocations); + ImGui::Text("Clipping Primitives: %llu", pipelineStats.ClippingPrimitives); + ImGui::Text("Fragment Shader Invocations: %llu", pipelineStats.FragmentShaderInvocations); + + ImGui::Separator(); + + ImGui::Text("Draw calls: %u", m_RenderStatistics.DrawCalls); + ImGui::Text("Meshes: %u", m_RenderStatistics.Meshes); + ImGui::Text("Submeshes: %u", m_RenderStatistics.Submeshes); + ImGui::Text("Instances: %u", m_RenderStatistics.MeshInstances); + ImGui::Text("Camera position: %.2f, %.2f, %.2f", m_CameraBuffer.Position.x, m_CameraBuffer.Position.y, m_CameraBuffer.Position.z); + + ImGui::End(); + + ImGui::Begin("Debug Maps"); + + { + const Ref image = m_GeometryPipeline->GetImage(1); + const float height = (static_cast(image->GetHeight()) / static_cast(image->GetWidth())) * 300; + UI::Image(m_GeometryPipeline->GetImage(1), ImVec2(300.0f, height), ImVec2(0, 1), ImVec2(1, 0)); + } + + { + const Ref image = m_GeometryPipeline->GetImage(2); + const float height = (static_cast(image->GetHeight()) / static_cast(image->GetWidth())) * 300; + UI::Image(m_GeometryPipeline->GetImage(2), ImVec2(300.0f, height), ImVec2(0, 1), ImVec2(1, 0)); + } + + ImGui::End(); + } + + void VulkanSceneRenderer::Resize(uint32_t width, uint32_t height) + { + //m_GeometryFramebuffer->Resize(width, height); + } + + void VulkanSceneRenderer::BeginScene(const EditorCamera& editorCamera) + { + EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::BeginScene"); + + // Cleanup from last draw + m_DrawList.clear(); + + // Reset statistics + memset(&m_RenderStatistics, 0, sizeof(RenderStatistics)); + + // Camera UB + m_CameraBuffer.View = editorCamera.GetViewMatrix(); + m_CameraBuffer.Projection = editorCamera.GetProjectionMatrix(); + m_CameraBuffer.ViewProjection = editorCamera.GetViewProjectionMatrix(); + m_CameraBuffer.Position = glm::vec4(editorCamera.GetPosition(), 0.0f); + m_CameraUB->SetData(&m_CameraBuffer, sizeof(m_CameraBuffer)); + } + + void VulkanSceneRenderer::BeginScene(const Camera& camera, const glm::mat4& transform) + { + EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::BeginScene"); + + // Cleanup from last draw + m_DrawList.clear(); + + // Reset statistics + memset(&m_RenderStatistics, 0, sizeof(RenderStatistics)); + + // Camera UB + m_CameraBuffer.View = glm::inverse(transform); + m_CameraBuffer.Projection = camera.GetProjectionMatrix(); + m_CameraBuffer.ViewProjection = camera.GetProjectionMatrix() * glm::inverse(transform); + m_CameraBuffer.Position = transform[3]; + m_CameraUB->SetData(&m_CameraBuffer, sizeof(m_CameraBuffer)); + } + + void VulkanSceneRenderer::EndScene() + { + EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::EndScene"); + + Flush(); + } + + void VulkanSceneRenderer::SubmitDrawCommand(const EntityType type, Ref drawCommand) + { + EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::SubmitDrawCommand"); + + if (type == EntityType::PointLight && m_DrawList[EntityType::PointLight].size() == 8) + { + EPPO_WARN("Trying to submit more point lights than we currently support!"); + return; + } + + m_DrawList[type].emplace_back(drawCommand); + } + + Ref VulkanSceneRenderer::GetFinalImage() + { + return m_GeometryPipeline->GetFinalImage(); + } + + void VulkanSceneRenderer::Flush() + { + EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::Flush"); + + m_CommandBuffer->RT_Begin(); + + // Prepare buffers + PrepareBuffers(); + PrepareImages(); + UpdateDescriptors(); + + // Record render commands + GuiPass(); + PreDepthPass(); + EnvPass(); + GeometryPass(); + SkyboxPass(); + + if (m_RenderSpecification.DebugRendering) + DebugLinePass(); + + CompositePass(); + + const auto cmd = std::static_pointer_cast(m_CommandBuffer); + const auto renderer = VulkanContext::Get()->GetRenderer(); + renderer->SubmitCommand([cmd]() + { + const auto context = VulkanContext::Get(); + const VkCommandBuffer commandBuffer = cmd->GetCurrentCommandBuffer(); + EPPO_PROFILE_GPU_END(context->GetTracyContext(), commandBuffer) + }); + + // Submit work + m_CommandBuffer->RT_End(); + } + + void Eppo::VulkanSceneRenderer::PrepareBuffers() + { + EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::PrepareBuffers"); + + // Environment UB + m_EnvironmentBuffer.Projection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f); + m_EnvironmentBuffer.View[0] = glm::lookAt(glm::vec3(0.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)); + m_EnvironmentBuffer.View[1] = glm::lookAt(glm::vec3(0.0f), glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)); + m_EnvironmentBuffer.View[2] = glm::lookAt(glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); + m_EnvironmentBuffer.View[3] = glm::lookAt(glm::vec3(0.0f), glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)); + m_EnvironmentBuffer.View[4] = glm::lookAt(glm::vec3(0.0f), glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)); + m_EnvironmentBuffer.View[5] = glm::lookAt(glm::vec3(0.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)); + m_EnvironmentUB->SetData(&m_EnvironmentBuffer, sizeof(EnvironmentData)); + + // Lights UB + m_LightsBuffer.Projection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 50.0f); + m_LightsBuffer.NumLights = 0; + + std::vector lineVertices; + std::vector lineIndices; + uint32_t vertexCount = 0; + + uint32_t i = 0; + while (i < 8 && !m_DrawList[EntityType::PointLight].empty()) + { + Ref dc = m_DrawList[EntityType::PointLight].back(); + const auto plCmd = std::static_pointer_cast(dc); + + auto& [view, position, color] = m_LightsBuffer.Lights[i]; + position = glm::vec4(plCmd->Position, 1.0f); + color = plCmd->Color; + view[0] = lookAt(plCmd->Position, plCmd->Position + glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)); + view[1] = lookAt(plCmd->Position, plCmd->Position + glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)); + view[2] = lookAt(plCmd->Position, plCmd->Position + glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)); + view[3] = lookAt(plCmd->Position, plCmd->Position + glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)); + view[4] = lookAt(plCmd->Position, plCmd->Position + glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)); + view[5] = lookAt(plCmd->Position, plCmd->Position + glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)); + + // Setup Debug Lines + LineVertex& p0 = lineVertices.emplace_back(); + p0.Position = plCmd->Position - glm::vec3(0.0f, 0.5f, 0.0f); + p0.Color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); + lineIndices.emplace_back(vertexCount); + vertexCount++; + + LineVertex& p1 = lineVertices.emplace_back(); + p1.Position = plCmd->Position + glm::vec3(0.0f, 0.5f, 0.0f); + p1.Color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); + lineIndices.emplace_back(vertexCount); + vertexCount++; + + LineVertex& p2 = lineVertices.emplace_back(); + p2.Position = plCmd->Position - glm::vec3(0.5f, 0.0f, 0.0f); + p2.Color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); + lineIndices.emplace_back(vertexCount); + vertexCount++; + + LineVertex& p3 = lineVertices.emplace_back(); + p3.Position = plCmd->Position + glm::vec3(0.5f, 0.0f, 0.0f); + p3.Color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); + lineIndices.emplace_back(vertexCount); + vertexCount++; + + LineVertex& p4 = lineVertices.emplace_back(); + p4.Position = plCmd->Position - glm::vec3(0.0f, 0.0f, 0.5f); + p4.Color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); + lineIndices.emplace_back(vertexCount); + vertexCount++; + + LineVertex& p5 = lineVertices.emplace_back(); + p5.Position = plCmd->Position + glm::vec3(0.0f, 0.0f, 0.5f); + p5.Color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); + lineIndices.emplace_back(vertexCount); + vertexCount++; + + m_DrawList[EntityType::PointLight].pop_back(); + i++; + } + + m_LightsBuffer.NumLights = i; + + if (!lineVertices.empty() && !lineIndices.empty()) + { + Buffer ib = Buffer::Copy(lineIndices.data(), static_cast(sizeof(uint32_t)) * static_cast(lineIndices.size())); + m_DebugLineIndexBuffer->SetData(ib); + ib.Release(); + + Buffer vb = Buffer::Copy(lineVertices.data(), static_cast(sizeof(LineVertex)) * static_cast(lineVertices.size())); + m_DebugLineVertexBuffer->SetData(vb); + vb.Release(); + + m_DebugLineCount = static_cast(lineIndices.size()); + } + + m_LightsUB->SetData(&m_LightsBuffer, sizeof(LightsData)); + } + + void VulkanSceneRenderer::PrepareImages() const + { + const auto cmd = std::static_pointer_cast(m_CommandBuffer); + const auto renderer = VulkanContext::Get()->GetRenderer(); + + renderer->SubmitCommand([this, cmd]() + { + EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::PrepareImages"); + + const auto commandBuffer = cmd->GetCurrentCommandBuffer(); + + // Transition depth images for writing + for (uint32_t i = 0; i < s_MaxLights; i++) + VulkanImage::TransitionImage( + commandBuffer, + std::static_pointer_cast(m_ShadowMaps[i])->GetImageInfo().Image, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT, + VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT); + }); + } + + void VulkanSceneRenderer::UpdateDescriptors() + { + const auto renderer = VulkanContext::Get()->GetRenderer(); + renderer->SubmitCommand([this]() + { + EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::UpdateDescriptors"); + + const uint32_t frameIndex = VulkanContext::Get()->GetCurrentFrameIndex(); + const auto descriptorSets = m_DescriptorSets[frameIndex]; + + DescriptorWriter writer; + + // Set 0 - Global + { + // Binding 0 + const auto& info = std::static_pointer_cast(m_EnvironmentMap)->GetImageInfo(); + writer.WriteImage(0, info.ImageView, info.Sampler, info.ImageLayout, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + } + + { + // Binding 1 + const auto& info = std::static_pointer_cast(m_EnvironmentCubeMap)->GetImageInfo(); + writer.WriteImage(1, info.ImageView, info.Sampler, info.ImageLayout, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + } + + { + // Binding 2 + const auto& buffers = std::static_pointer_cast(m_EnvironmentUB)->GetBuffers(); + const VkBuffer buffer = buffers[frameIndex]; + writer.WriteBuffer(m_EnvironmentUB->GetBinding(), buffer, sizeof(EnvironmentData), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + } + + writer.UpdateSet(descriptorSets[0]); + writer.Clear(); + + // Set 1 - Scene + { + // Binding 0 + const auto& buffers = std::static_pointer_cast(m_CameraUB)->GetBuffers(); + const VkBuffer buffer = buffers[frameIndex]; + writer.WriteBuffer(m_CameraUB->GetBinding(), buffer, sizeof(CameraData), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + } + + { + // Binding 1 + const auto& buffers = std::static_pointer_cast(m_LightsUB)->GetBuffers(); + const VkBuffer buffer = buffers[frameIndex]; + writer.WriteBuffer(m_LightsUB->GetBinding(), buffer, sizeof(LightsData), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER); + } + + std::vector imageInfos; + { + // Binding 2 + for (const auto& shadowMap : m_ShadowMaps) + { + const ImageInfo& imageInfo = std::static_pointer_cast(shadowMap)->GetImageInfo(); + + auto& [sampler, imageView, imageLayout] = imageInfos.emplace_back(); + imageLayout = imageInfo.ImageLayout; + imageView = imageInfo.ImageView; + sampler = imageInfo.Sampler; + } + + writer.WriteImages(2, imageInfos, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + } + + writer.UpdateSet(descriptorSets[1]); + writer.Clear(); + imageInfos.clear(); + + // Set 2 - Material + // TODO: When we go over the max limit, we need to do this in the pass itself + { + // Binding 0 + for (const auto& dc : m_DrawList[EntityType::Mesh]) + { + for (const auto meshCmd = std::static_pointer_cast(dc); const auto& image : meshCmd->Mesh->GetImages()) + { + const ImageInfo& imageInfo = std::static_pointer_cast(image)->GetImageInfo(); + + auto& [sampler, imageView, imageLayout] = imageInfos.emplace_back(); + imageLayout = imageInfo.ImageLayout; + imageView = imageInfo.ImageView; + sampler = imageInfo.Sampler; + } + + writer.WriteImages(0, imageInfos, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER); + } + } + + writer.UpdateSet(descriptorSets[2]); + }); + } + + void VulkanSceneRenderer::GuiPass() + { + const auto renderer = VulkanContext::Get()->GetRenderer(); + renderer->SubmitCommand([]() + { + EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::GuiPass"); + + ImGui_ImplVulkan_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + + Application::Get().RenderGui(); + + ImGui::Render(); + }); + } + + void VulkanSceneRenderer::PreDepthPass() + { + const auto cmd = std::static_pointer_cast(m_CommandBuffer); + const auto pipeline = std::static_pointer_cast(m_PreDepthPipeline); + const auto renderer = VulkanContext::Get()->GetRenderer(); + + m_TimestampQueries.PreDepthQuery = cmd->RT_BeginTimestampQuery(); + + renderer->SubmitCommand([this, cmd, pipeline, renderer]() + { + EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::PreDepthPass"); + + // Get all required variables + const VkCommandBuffer commandBuffer = cmd->GetCurrentCommandBuffer(); + auto& spec = pipeline->GetSpecification(); + + const auto& pcr = std::static_pointer_cast(spec.Shader)->GetPushConstantRanges(); + ScopedBuffer pcrBuffer(pcr[0].size); + + // Profiling + EPPO_PROFILE_GPU(VulkanContext::Get()->GetTracyContext(), cmd->GetCurrentCommandBuffer(), "PreDepth") + + // Insert debug label + if (m_RenderSpecification.DebugRendering) + m_DebugRenderer->StartDebugLabel(m_CommandBuffer, "PreDepthPass"); + + // Update descriptor sets + const uint32_t frameIndex = VulkanContext::Get()->GetCurrentFrameIndex(); + const auto& descriptorSets = m_DescriptorSets[frameIndex]; + + for (uint32_t i = 0; i < m_LightsBuffer.NumLights; i++) + { + spec.RenderAttachments.clear(); + spec.RenderAttachments.emplace_back(m_ShadowMaps[i], true, 1.0f); + + // Begin rendering + renderer->BeginRenderPass(m_CommandBuffer, m_PreDepthPipeline); + + // Bind descriptor sets + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->GetPipelineLayout(), 0, 3, descriptorSets.data(), 0, nullptr); + + // Render geometry + for (const auto& dc : m_DrawList[EntityType::Mesh]) + { + const auto meshCmd = std::static_pointer_cast(dc); + m_RenderStatistics.MeshInstances++; + + for (const auto& submesh : meshCmd->Mesh->GetSubmeshes()) + { + // Bind vertex buffer + const auto vertexBuffer = std::static_pointer_cast(submesh.GetVertexBuffer()); + VkBuffer vb = { vertexBuffer->GetBuffer() }; + constexpr VkDeviceSize offsets[] = { 0 }; + + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vb, offsets); + + // Bind index buffer + const auto indexBuffer = std::static_pointer_cast(submesh.GetIndexBuffer()); + vkCmdBindIndexBuffer(commandBuffer, indexBuffer->GetBuffer(), 0, VK_INDEX_TYPE_UINT32); + + // Draw call + glm::mat4 finalTransform = meshCmd->Transform * submesh.GetLocalTransform(); + + for (const auto& p : submesh.GetPrimitives()) + { + pcrBuffer.SetData(finalTransform); + pcrBuffer.SetData(i, 64); + + vkCmdPushConstants(commandBuffer, pipeline->GetPipelineLayout(), VK_SHADER_STAGE_ALL_GRAPHICS, 0, pcrBuffer.Size(), + pcrBuffer.Data()); - const VkCommandBuffer commandBuffer = cmd->GetCurrentCommandBuffer(); - - // Profiling - EPPO_PROFILE_GPU(VulkanContext::Get()->GetTracyContext(), cmd->GetCurrentCommandBuffer(), "EnvPass") - - // Insert debug label - if (m_RenderSpecification.DebugRendering) - m_DebugRenderer->StartDebugLabel(m_CommandBuffer, "EnvPass"); - - // Begin rendering - renderer->BeginRenderPass(m_CommandBuffer, pipeline); - - // Bind descriptor sets - const uint32_t frameIndex = VulkanContext::Get()->GetCurrentFrameIndex(); - const auto& descriptorSets = m_DescriptorSets[frameIndex]; - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->GetPipelineLayout(), 0, 3, descriptorSets.data(), 0, nullptr); - - // Draw call - m_RenderStatistics.DrawCalls++; - vkCmdDraw(commandBuffer, 36, 1, 0, 0); + m_RenderStatistics.DrawCalls++; + vkCmdDrawIndexed(commandBuffer, p.IndexCount, 1, p.FirstIndex, static_cast(p.FirstVertex), 0); + } + } + } - renderer->EndRenderPass(m_CommandBuffer); + // End rendering + renderer->EndRenderPass(m_CommandBuffer); + } - // End debug label - if (m_RenderSpecification.DebugRendering) - m_DebugRenderer->EndDebugLabel(m_CommandBuffer); - }); - } + // Transition image for reading + for (uint32_t i = 0; i < s_MaxLights; i++) + VulkanImage::TransitionImage( + commandBuffer, + std::static_pointer_cast(m_ShadowMaps[i])->GetImageInfo().Image, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL + ); - void VulkanSceneRenderer::SkyboxPass() - { - const auto cmd = std::static_pointer_cast(m_CommandBuffer); - const auto pipeline = std::static_pointer_cast(m_SkyboxPipeline); - const auto renderer = VulkanContext::Get()->GetRenderer(); + if (m_RenderSpecification.DebugRendering) + m_DebugRenderer->EndDebugLabel(m_CommandBuffer); + }); - m_TimestampQueries.SkyboxQuery = cmd->RT_BeginTimestampQuery(); - - renderer->SubmitCommand([this, cmd, pipeline, renderer]() - { - EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::SkyboxPass"); + cmd->RT_EndTimestampQuery(m_TimestampQueries.PreDepthQuery); + } - const VkCommandBuffer commandBuffer = cmd->GetCurrentCommandBuffer(); - - // Profiling - EPPO_PROFILE_GPU(VulkanContext::Get()->GetTracyContext(), cmd->GetCurrentCommandBuffer(), "SkyboxPass") - - // Insert debug label - if (m_RenderSpecification.DebugRendering) - m_DebugRenderer->StartDebugLabel(m_CommandBuffer, "SkyboxPass"); - - // Begin rendering - renderer->BeginRenderPass(m_CommandBuffer, pipeline); - - // Bind descriptor sets - const uint32_t frameIndex = VulkanContext::Get()->GetCurrentFrameIndex(); - const auto& descriptorSets = m_DescriptorSets[frameIndex]; - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->GetPipelineLayout(), 0, 3, descriptorSets.data(), 0, nullptr); - - // Draw call - m_RenderStatistics.DrawCalls++; - vkCmdDraw(commandBuffer, 36, 1, 0, 0); - - renderer->EndRenderPass(m_CommandBuffer); - - // End debug label - if (m_RenderSpecification.DebugRendering) - m_DebugRenderer->EndDebugLabel(m_CommandBuffer); - }); - - cmd->RT_EndTimestampQuery(m_TimestampQueries.SkyboxQuery); - } - - void VulkanSceneRenderer::GeometryPass() - { - const auto cmd = std::static_pointer_cast(m_CommandBuffer); - const auto pipeline = std::static_pointer_cast(m_GeometryPipeline); - const auto renderer = VulkanContext::Get()->GetRenderer(); - - m_TimestampQueries.GeometryQuery = cmd->RT_BeginTimestampQuery(); - - renderer->SubmitCommand([this, cmd, pipeline, renderer]() - { - EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::GeometryPass"); - - const VkCommandBuffer commandBuffer = cmd->GetCurrentCommandBuffer(); - - // Profiling - EPPO_PROFILE_GPU(VulkanContext::Get()->GetTracyContext(), cmd->GetCurrentCommandBuffer(), "GeometryPass") - - // Insert debug label - if (m_RenderSpecification.DebugRendering) - m_DebugRenderer->StartDebugLabel(m_CommandBuffer, "GeometryPass"); - - // Begin rendering - renderer->BeginRenderPass(m_CommandBuffer, pipeline); - - // Bind descriptor sets - const uint32_t frameIndex = VulkanContext::Get()->GetCurrentFrameIndex(); - const auto& descriptorSets = m_DescriptorSets[frameIndex]; - - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->GetPipelineLayout(), 0, 3, descriptorSets.data(), 0, nullptr); - - // Render geometry - for (const auto& dc : m_DrawList[EntityType::Mesh]) - { - const auto meshCmd = std::static_pointer_cast(dc); - - m_RenderStatistics.Meshes++; - m_RenderStatistics.MeshInstances++; - - for (const auto& submesh : meshCmd->Mesh->GetSubmeshes()) - { - m_RenderStatistics.Submeshes++; - - // Bind vertex buffer - const auto vertexBuffer = std::static_pointer_cast(submesh.GetVertexBuffer()); - VkBuffer vb = { vertexBuffer->GetBuffer() }; - constexpr VkDeviceSize offsets[] = { 0 }; - - vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vb, offsets); - - // Bind index buffer - const auto indexBuffer = std::static_pointer_cast(submesh.GetIndexBuffer()); - vkCmdBindIndexBuffer(commandBuffer, indexBuffer->GetBuffer(), 0, VK_INDEX_TYPE_UINT32); - - // Draw call - glm::mat4 finalTransform = meshCmd->Transform * submesh.GetLocalTransform(); - - for (const auto& p : submesh.GetPrimitives()) - { - const auto& shader = pipeline->GetSpecification().Shader; - const auto& pcr = std::static_pointer_cast(shader)->GetPushConstantRanges(); - - ScopedBuffer buffer(pcr[0].size); - buffer.SetData(finalTransform); - buffer.SetData(p.Material->DiffuseColor, 64); - buffer.SetData(p.Material->DiffuseMapIndex, 80); - buffer.SetData(p.Material->NormalMapIndex, 84); - buffer.SetData(p.Material->RoughnessMetallicMapIndex, 88); - - vkCmdPushConstants(commandBuffer, pipeline->GetPipelineLayout(), VK_SHADER_STAGE_ALL_GRAPHICS, 0, buffer.Size(), buffer.Data()); - - m_RenderStatistics.DrawCalls++; - vkCmdDrawIndexed(commandBuffer, p.IndexCount, 1, p.FirstIndex, static_cast(p.FirstVertex), 0); - } - } - } - - // End rendering - renderer->EndRenderPass(m_CommandBuffer); - - // End debug label - if (m_RenderSpecification.DebugRendering) - m_DebugRenderer->EndDebugLabel(m_CommandBuffer); - }); - - cmd->RT_EndTimestampQuery(m_TimestampQueries.GeometryQuery); - } - - void VulkanSceneRenderer::DebugLinePass() - { - const auto cmd = std::static_pointer_cast(m_CommandBuffer); - const auto pipeline = std::static_pointer_cast(m_DebugLinePipeline); - const auto renderer = VulkanContext::Get()->GetRenderer(); - - m_TimestampQueries.DebugLineQuery = cmd->RT_BeginTimestampQuery(); - - if (m_LightsBuffer.NumLights > 0) - { - renderer->SubmitCommand([this, cmd, pipeline, renderer]() - { - EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::DebugLinePass"); - - const VkCommandBuffer commandBuffer = cmd->GetCurrentCommandBuffer(); - - // Profiling - EPPO_PROFILE_GPU(VulkanContext::Get()->GetTracyContext(), cmd->GetCurrentCommandBuffer(), "DebugLinePass") - - // Insert debug label - if (m_RenderSpecification.DebugRendering) - m_DebugRenderer->StartDebugLabel(m_CommandBuffer, "DebugLinePass"); - - // Begin rendering - renderer->BeginRenderPass(m_CommandBuffer, m_DebugLinePipeline); - - // Bind descriptor sets - const uint32_t frameIndex = VulkanContext::Get()->GetCurrentFrameIndex(); - const auto& descriptorSets = m_DescriptorSets[frameIndex]; - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->GetPipelineLayout(), 0, 3, descriptorSets.data(), 0, nullptr); - - // Bind vertex buffer - const auto vertexBuffer = std::static_pointer_cast(m_DebugLineVertexBuffer); - const VkBuffer vb = { vertexBuffer->GetBuffer() }; - constexpr VkDeviceSize offsets[] = { 0 }; - - vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vb, offsets); - - // Bind index buffer - const auto indexBuffer = std::static_pointer_cast(m_DebugLineIndexBuffer); - vkCmdBindIndexBuffer(commandBuffer, indexBuffer->GetBuffer(), 0, VK_INDEX_TYPE_UINT32); - - // Draw call - m_RenderStatistics.DrawCalls++; - vkCmdDrawIndexed(commandBuffer, m_DebugLineCount, 1, 0, 0, 0); - - // End rendering - renderer->EndRenderPass(m_CommandBuffer); - - if (m_RenderSpecification.DebugRendering) - m_DebugRenderer->EndDebugLabel(m_CommandBuffer); - }); - } - - cmd->RT_EndTimestampQuery(m_TimestampQueries.DebugLineQuery); - } - - void VulkanSceneRenderer::CompositePass() - { - const auto cmd = std::static_pointer_cast(m_CommandBuffer); - const auto pipeline = std::static_pointer_cast(m_CompositePipeline); - const auto renderer = VulkanContext::Get()->GetRenderer(); - - m_TimestampQueries.CompositeQuery = cmd->RT_BeginTimestampQuery(); - - renderer->SubmitCommand([this, cmd, pipeline, renderer]() - { - EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::CompositePass"); - - const Ref context = VulkanContext::Get(); - const Ref swapchain = context->GetSwapchain(); - const VkCommandBuffer commandBuffer = cmd->GetCurrentCommandBuffer(); - - // Profiling - EPPO_PROFILE_GPU(VulkanContext::Get()->GetTracyContext(), cmd->GetCurrentCommandBuffer(), "CompositePass") - - // Insert debug label - if (m_RenderSpecification.DebugRendering) - m_DebugRenderer->StartDebugLabel(cmd, "CompositePass"); - - VulkanImage::TransitionImage(commandBuffer, swapchain->GetCurrentImage(), VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - // Begin rendering - renderer->BeginRenderPass(cmd, pipeline, false); - - ImDrawData* data = ImGui::GetDrawData(); - ImGui_ImplVulkan_RenderDrawData(data, commandBuffer); - - if (const ImGuiIO& io = ImGui::GetIO(); - io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) - { - GLFWwindow* backupContext = glfwGetCurrentContext(); - ImGui::UpdatePlatformWindows(); - ImGui::RenderPlatformWindowsDefault(); - glfwMakeContextCurrent(backupContext); - } - - // End rendering - renderer->EndRenderPass(cmd); - - VulkanImage::TransitionImage(commandBuffer, swapchain->GetCurrentImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); - - if (m_RenderSpecification.DebugRendering) - m_DebugRenderer->EndDebugLabel(cmd); - }); - - cmd->RT_EndTimestampQuery(m_TimestampQueries.CompositeQuery); - } + void VulkanSceneRenderer::EnvPass() + { + const auto cmd = std::static_pointer_cast(m_CommandBuffer); + const auto pipeline = std::static_pointer_cast(m_EnvPipeline); + const auto renderer = VulkanContext::Get()->GetRenderer(); + + renderer->SubmitCommand([this, cmd, pipeline, renderer]() + { + EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::EnvPass"); + + const VkCommandBuffer commandBuffer = cmd->GetCurrentCommandBuffer(); + + // Profiling + EPPO_PROFILE_GPU(VulkanContext::Get()->GetTracyContext(), cmd->GetCurrentCommandBuffer(), "EnvPass") + + // Insert debug label + if (m_RenderSpecification.DebugRendering) + m_DebugRenderer->StartDebugLabel(m_CommandBuffer, "EnvPass"); + + // Begin rendering + renderer->BeginRenderPass(m_CommandBuffer, pipeline); + + // Bind descriptor sets + const uint32_t frameIndex = VulkanContext::Get()->GetCurrentFrameIndex(); + const auto& descriptorSets = m_DescriptorSets[frameIndex]; + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->GetPipelineLayout(), 0, 3, descriptorSets.data(), 0, nullptr); + + // Draw call + m_RenderStatistics.DrawCalls++; + vkCmdDraw(commandBuffer, 36, 1, 0, 0); + + renderer->EndRenderPass(m_CommandBuffer); + + // End debug label + if (m_RenderSpecification.DebugRendering) + m_DebugRenderer->EndDebugLabel(m_CommandBuffer); + }); + } + + void VulkanSceneRenderer::SkyboxPass() + { + const auto cmd = std::static_pointer_cast(m_CommandBuffer); + const auto pipeline = std::static_pointer_cast(m_SkyboxPipeline); + const auto renderer = VulkanContext::Get()->GetRenderer(); + + m_TimestampQueries.SkyboxQuery = cmd->RT_BeginTimestampQuery(); + + renderer->SubmitCommand([this, cmd, pipeline, renderer]() + { + EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::SkyboxPass"); + + const VkCommandBuffer commandBuffer = cmd->GetCurrentCommandBuffer(); + + // Profiling + EPPO_PROFILE_GPU(VulkanContext::Get()->GetTracyContext(), cmd->GetCurrentCommandBuffer(), "SkyboxPass") + + // Insert debug label + if (m_RenderSpecification.DebugRendering) + m_DebugRenderer->StartDebugLabel(m_CommandBuffer, "SkyboxPass"); + + // Begin rendering + renderer->BeginRenderPass(m_CommandBuffer, pipeline); + + // Bind descriptor sets + const uint32_t frameIndex = VulkanContext::Get()->GetCurrentFrameIndex(); + const auto& descriptorSets = m_DescriptorSets[frameIndex]; + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->GetPipelineLayout(), 0, 3, descriptorSets.data(), 0, nullptr); + + // Draw call + m_RenderStatistics.DrawCalls++; + vkCmdDraw(commandBuffer, 36, 1, 0, 0); + + renderer->EndRenderPass(m_CommandBuffer); + + // End debug label + if (m_RenderSpecification.DebugRendering) + m_DebugRenderer->EndDebugLabel(m_CommandBuffer); + }); + + cmd->RT_EndTimestampQuery(m_TimestampQueries.SkyboxQuery); + } + + void VulkanSceneRenderer::GeometryPass() + { + const auto cmd = std::static_pointer_cast(m_CommandBuffer); + const auto pipeline = std::static_pointer_cast(m_GeometryPipeline); + const auto renderer = VulkanContext::Get()->GetRenderer(); + + m_TimestampQueries.GeometryQuery = cmd->RT_BeginTimestampQuery(); + + renderer->SubmitCommand([this, cmd, pipeline, renderer]() + { + EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::GeometryPass"); + + const VkCommandBuffer commandBuffer = cmd->GetCurrentCommandBuffer(); + + // Profiling + EPPO_PROFILE_GPU(VulkanContext::Get()->GetTracyContext(), cmd->GetCurrentCommandBuffer(), "GeometryPass") + + // Insert debug label + if (m_RenderSpecification.DebugRendering) + m_DebugRenderer->StartDebugLabel(m_CommandBuffer, "GeometryPass"); + + // Begin rendering + renderer->BeginRenderPass(m_CommandBuffer, pipeline); + + // Bind descriptor sets + const uint32_t frameIndex = VulkanContext::Get()->GetCurrentFrameIndex(); + const auto& descriptorSets = m_DescriptorSets[frameIndex]; + + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->GetPipelineLayout(), 0, 3, descriptorSets.data(), 0, nullptr); + + // Render geometry + for (const auto& dc : m_DrawList[EntityType::Mesh]) + { + const auto meshCmd = std::static_pointer_cast(dc); + + m_RenderStatistics.Meshes++; + m_RenderStatistics.MeshInstances++; + + for (const auto& submesh : meshCmd->Mesh->GetSubmeshes()) + { + m_RenderStatistics.Submeshes++; + + // Bind vertex buffer + const auto vertexBuffer = std::static_pointer_cast(submesh.GetVertexBuffer()); + VkBuffer vb = { vertexBuffer->GetBuffer() }; + constexpr VkDeviceSize offsets[] = { 0 }; + + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vb, offsets); + + // Bind index buffer + const auto indexBuffer = std::static_pointer_cast(submesh.GetIndexBuffer()); + vkCmdBindIndexBuffer(commandBuffer, indexBuffer->GetBuffer(), 0, VK_INDEX_TYPE_UINT32); + + // Draw call + glm::mat4 finalTransform = meshCmd->Transform * submesh.GetLocalTransform(); + + for (const auto& p : submesh.GetPrimitives()) + { + const auto& shader = pipeline->GetSpecification().Shader; + const auto& pcr = std::static_pointer_cast(shader)->GetPushConstantRanges(); + + ScopedBuffer buffer(pcr[0].size); + buffer.SetData(finalTransform); + buffer.SetData(p.Material->DiffuseColor, 64); + buffer.SetData(p.Material->DiffuseMapIndex, 80); + buffer.SetData(p.Material->NormalMapIndex, 84); + buffer.SetData(p.Material->RoughnessMetallicMapIndex, 88); + + vkCmdPushConstants(commandBuffer, pipeline->GetPipelineLayout(), VK_SHADER_STAGE_ALL_GRAPHICS, 0, buffer.Size(), buffer.Data()); + + m_RenderStatistics.DrawCalls++; + vkCmdDrawIndexed(commandBuffer, p.IndexCount, 1, p.FirstIndex, static_cast(p.FirstVertex), 0); + } + } + } + + // End rendering + renderer->EndRenderPass(m_CommandBuffer); + + // End debug label + if (m_RenderSpecification.DebugRendering) + m_DebugRenderer->EndDebugLabel(m_CommandBuffer); + }); + + cmd->RT_EndTimestampQuery(m_TimestampQueries.GeometryQuery); + } + + void VulkanSceneRenderer::DebugLinePass() + { + const auto cmd = std::static_pointer_cast(m_CommandBuffer); + const auto pipeline = std::static_pointer_cast(m_DebugLinePipeline); + const auto renderer = VulkanContext::Get()->GetRenderer(); + + m_TimestampQueries.DebugLineQuery = cmd->RT_BeginTimestampQuery(); + + if (m_LightsBuffer.NumLights > 0) + { + renderer->SubmitCommand([this, cmd, pipeline, renderer]() + { + EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::DebugLinePass"); + + const VkCommandBuffer commandBuffer = cmd->GetCurrentCommandBuffer(); + + // Profiling + EPPO_PROFILE_GPU(VulkanContext::Get()->GetTracyContext(), cmd->GetCurrentCommandBuffer(), "DebugLinePass") + + // Insert debug label + if (m_RenderSpecification.DebugRendering) + m_DebugRenderer->StartDebugLabel(m_CommandBuffer, "DebugLinePass"); + + // Begin rendering + renderer->BeginRenderPass(m_CommandBuffer, m_DebugLinePipeline); + + // Bind descriptor sets + const uint32_t frameIndex = VulkanContext::Get()->GetCurrentFrameIndex(); + const auto& descriptorSets = m_DescriptorSets[frameIndex]; + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline->GetPipelineLayout(), 0, 3, descriptorSets.data(), 0, nullptr); + + // Bind vertex buffer + const auto vertexBuffer = std::static_pointer_cast(m_DebugLineVertexBuffer); + const VkBuffer vb = { vertexBuffer->GetBuffer() }; + constexpr VkDeviceSize offsets[] = { 0 }; + + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &vb, offsets); + + // Bind index buffer + const auto indexBuffer = std::static_pointer_cast(m_DebugLineIndexBuffer); + vkCmdBindIndexBuffer(commandBuffer, indexBuffer->GetBuffer(), 0, VK_INDEX_TYPE_UINT32); + + // Draw call + m_RenderStatistics.DrawCalls++; + vkCmdDrawIndexed(commandBuffer, m_DebugLineCount, 1, 0, 0, 0); + + // End rendering + renderer->EndRenderPass(m_CommandBuffer); + + if (m_RenderSpecification.DebugRendering) + m_DebugRenderer->EndDebugLabel(m_CommandBuffer); + }); + } + + cmd->RT_EndTimestampQuery(m_TimestampQueries.DebugLineQuery); + } + + void VulkanSceneRenderer::CompositePass() + { + const auto cmd = std::static_pointer_cast(m_CommandBuffer); + const auto pipeline = std::static_pointer_cast(m_CompositePipeline); + const auto renderer = VulkanContext::Get()->GetRenderer(); + + m_TimestampQueries.CompositeQuery = cmd->RT_BeginTimestampQuery(); + + renderer->SubmitCommand([this, cmd, pipeline, renderer]() + { + EPPO_PROFILE_FUNCTION("VulkanSceneRenderer::CompositePass"); + + const Ref context = VulkanContext::Get(); + const Ref swapchain = context->GetSwapchain(); + const VkCommandBuffer commandBuffer = cmd->GetCurrentCommandBuffer(); + + // Profiling + EPPO_PROFILE_GPU(VulkanContext::Get()->GetTracyContext(), cmd->GetCurrentCommandBuffer(), "CompositePass") + + // Insert debug label + if (m_RenderSpecification.DebugRendering) + m_DebugRenderer->StartDebugLabel(cmd, "CompositePass"); + + VulkanImage::TransitionImage(commandBuffer, swapchain->GetCurrentImage(), VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + // Begin rendering + renderer->BeginRenderPass(cmd, pipeline, false); + + ImDrawData* data = ImGui::GetDrawData(); + ImGui_ImplVulkan_RenderDrawData(data, commandBuffer); + + if (const ImGuiIO& io = ImGui::GetIO(); io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + GLFWwindow* backupContext = glfwGetCurrentContext(); + ImGui::UpdatePlatformWindows(); + ImGui::RenderPlatformWindowsDefault(); + glfwMakeContextCurrent(backupContext); + } + + // End rendering + renderer->EndRenderPass(cmd); + + VulkanImage::TransitionImage(commandBuffer, swapchain->GetCurrentImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + + if (m_RenderSpecification.DebugRendering) + m_DebugRenderer->EndDebugLabel(cmd); + }); + + cmd->RT_EndTimestampQuery(m_TimestampQueries.CompositeQuery); + } } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanSceneRenderer.h b/EppoEngine/Source/Platform/Vulkan/VulkanSceneRenderer.h index 25827bdb..1b01fc17 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanSceneRenderer.h +++ b/EppoEngine/Source/Platform/Vulkan/VulkanSceneRenderer.h @@ -13,113 +13,116 @@ namespace Eppo { - class VulkanSceneRenderer final : public SceneRenderer - { - public: - VulkanSceneRenderer(const Ref& scene, const RenderSpecification& renderSpec); - VulkanSceneRenderer(const VulkanSceneRenderer&) = delete; - VulkanSceneRenderer(const VulkanSceneRenderer&&) = delete; - VulkanSceneRenderer& operator=(const VulkanSceneRenderer&) = delete; - VulkanSceneRenderer& operator=(const VulkanSceneRenderer&&) = delete; - ~VulkanSceneRenderer() override = default; - - void RenderGui() override; - void Resize(uint32_t width, uint32_t height) override; - - void BeginScene(const EditorCamera& editorCamera) override; - void BeginScene(const Camera& camera, const glm::mat4& transform) override; - void EndScene() override; - - void SubmitDrawCommand(EntityType type, Ref drawCommand) override; - Ref GetFinalImage() override; - - private: - void Flush(); - void PrepareBuffers(); - void PrepareImages() const; - void UpdateDescriptors(); - - static void GuiPass(); - void PreDepthPass(); - void EnvPass(); - void SkyboxPass(); - void GeometryPass(); - void DebugLinePass(); - void CompositePass(); - - private: - RenderSpecification m_RenderSpecification; - Ref m_Scene; - - Ref m_CommandBuffer; - Ref m_DebugRenderer; - - Ref m_PreDepthPipeline; - Ref m_EnvPipeline; - Ref m_SkyboxPipeline; - Ref m_GeometryPipeline; - Ref m_DebugLinePipeline; - Ref m_CompositePipeline; - - static constexpr uint32_t s_MaxLights = 8; - - // Frame in flight --> Set - std::unordered_map> m_DescriptorSets; - - // Set 0, Binding 0 - struct EnvironmentData - { - glm::mat4 Projection; - std::array View; - } m_EnvironmentBuffer; - Ref m_EnvironmentUB; - - // Set 0, Binding 1 - Ref m_EnvironmentMap; - // Set 0, Binding 2 - Ref m_EnvironmentCubeMap; - - // Set 1, Binding 0 - struct CameraData - { - glm::mat4 View; - glm::mat4 Projection; - glm::mat4 ViewProjection; - glm::vec4 Position; - } m_CameraBuffer; - Ref m_CameraUB; - - // Set 1, Binding 1 - struct LightsData - { - glm::mat4 Projection; - PointLight Lights[s_MaxLights]; - uint32_t NumLights; - } m_LightsBuffer; - Ref m_LightsUB; - - // Set 1, Binding 2 - std::array, s_MaxLights> m_ShadowMaps; - - // Draw commands - std::unordered_map>> m_DrawList; - - // Buffers - Buffer m_PushConstantBuffer; - Ref m_DebugLineVertexBuffer; - Ref m_DebugLineIndexBuffer; - uint32_t m_DebugLineCount = 0; - - // Statistics - RenderStatistics m_RenderStatistics; - - struct TimestampQueries - { - uint32_t CompositeQuery = UINT32_MAX; - uint32_t DebugLineQuery = UINT32_MAX; - uint32_t GeometryQuery = UINT32_MAX; - uint32_t PreDepthQuery = UINT32_MAX; - uint32_t SkyboxQuery = UINT32_MAX; - } m_TimestampQueries; - }; + class VulkanSceneRenderer final : public SceneRenderer + { + public: + VulkanSceneRenderer(const Ref& scene, const RenderSpecification& renderSpec); + VulkanSceneRenderer(const VulkanSceneRenderer&) = delete; + VulkanSceneRenderer(const VulkanSceneRenderer&&) = delete; + VulkanSceneRenderer& operator=(const VulkanSceneRenderer&) = delete; + VulkanSceneRenderer& operator=(const VulkanSceneRenderer&&) = delete; + ~VulkanSceneRenderer() override = default; + + void RenderGui() override; + void Resize(uint32_t width, uint32_t height) override; + + void BeginScene(const EditorCamera& editorCamera) override; + void BeginScene(const Camera& camera, const glm::mat4& transform) override; + void EndScene() override; + + void SubmitDrawCommand(EntityType type, Ref drawCommand) override; + Ref GetFinalImage() override; + + private: + void Flush(); + void PrepareBuffers(); + void PrepareImages() const; + void UpdateDescriptors(); + + static void GuiPass(); + void PreDepthPass(); + void EnvPass(); + void SkyboxPass(); + void GeometryPass(); + void DebugLinePass(); + void CompositePass(); + + private: + RenderSpecification m_RenderSpecification; + Ref m_Scene; + + Ref m_CommandBuffer; + Ref m_DebugRenderer; + + Ref m_PreDepthPipeline; + Ref m_EnvPipeline; + Ref m_SkyboxPipeline; + Ref m_GeometryPipeline; + Ref m_DebugLinePipeline; + Ref m_CompositePipeline; + + static constexpr uint32_t s_MaxLights = 8; + + // Frame in flight --> Set + std::unordered_map> m_DescriptorSets; + + // Set 0, Binding 0 + struct EnvironmentData + { + glm::mat4 Projection; + std::array View; + } m_EnvironmentBuffer; + + Ref m_EnvironmentUB; + + // Set 0, Binding 1 + Ref m_EnvironmentMap; + // Set 0, Binding 2 + Ref m_EnvironmentCubeMap; + + // Set 1, Binding 0 + struct CameraData + { + glm::mat4 View; + glm::mat4 Projection; + glm::mat4 ViewProjection; + glm::vec4 Position; + } m_CameraBuffer; + + Ref m_CameraUB; + + // Set 1, Binding 1 + struct LightsData + { + glm::mat4 Projection; + PointLight Lights[s_MaxLights]; + uint32_t NumLights; + } m_LightsBuffer; + + Ref m_LightsUB; + + // Set 1, Binding 2 + std::array, s_MaxLights> m_ShadowMaps; + + // Draw commands + std::unordered_map>> m_DrawList; + + // Buffers + Buffer m_PushConstantBuffer; + Ref m_DebugLineVertexBuffer; + Ref m_DebugLineIndexBuffer; + uint32_t m_DebugLineCount = 0; + + // Statistics + RenderStatistics m_RenderStatistics; + + struct TimestampQueries + { + uint32_t CompositeQuery = UINT32_MAX; + uint32_t DebugLineQuery = UINT32_MAX; + uint32_t GeometryQuery = UINT32_MAX; + uint32_t PreDepthQuery = UINT32_MAX; + uint32_t SkyboxQuery = UINT32_MAX; + } m_TimestampQueries; + }; } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanShader.cpp b/EppoEngine/Source/Platform/Vulkan/VulkanShader.cpp index f4130aec..173bf257 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanShader.cpp +++ b/EppoEngine/Source/Platform/Vulkan/VulkanShader.cpp @@ -12,394 +12,402 @@ namespace Eppo { - namespace - { - shaderc_shader_kind ShaderStageToShaderCKind(const ShaderStage stage) - { - switch (stage) - { - case ShaderStage::Vertex: return shaderc_vertex_shader; - case ShaderStage::Fragment: return shaderc_fragment_shader; - } - - EPPO_ASSERT(false); - return static_cast(-1); - } - - VkShaderStageFlagBits ShaderStageToVkShaderStage(const ShaderStage stage) - { - if (stage == ShaderStage::Vertex) return VK_SHADER_STAGE_VERTEX_BIT; - if (stage == ShaderStage::Fragment) return VK_SHADER_STAGE_FRAGMENT_BIT; - - return VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM; - } - - VkDescriptorType ShaderResourceTypeToVkDescriptorType(const ShaderResourceType type) - { - if (type == ShaderResourceType::UniformBuffer) return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - if (type == ShaderResourceType::Sampler) return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - - return VK_DESCRIPTOR_TYPE_MAX_ENUM; - } - } - - VulkanShader::VulkanShader(const ShaderSpecification& specification) - : Shader(specification) - { - EPPO_PROFILE_FUNCTION("VulkanShader::VulkanShader"); - - // Read shader source - const std::string shaderSource = Filesystem::ReadText(GetSpecification().Filepath); - - // Preprocess by shader stage - const auto sources = PreProcess(shaderSource); - - // Compile or get cache - CompileOrGetCache(sources); - - m_ShaderResources[0] = {}; - m_ShaderResources[1] = {}; - m_ShaderResources[2] = {}; - m_ShaderResources[3] = {}; - - // Reflection - for (const auto& [type, data] : m_ShaderBytes) - Reflect(type, data); - - CreatePipelineShaderInfos(); - CreateDescriptorSetLayouts(); - } - - std::unordered_map VulkanShader::PreProcess(std::string_view source) const - { - EPPO_PROFILE_FUNCTION("VulkanShader::PreProcess"); - - std::unordered_map shaderSources; - - // Find stage token - const auto stageToken = "#stage"; - const size_t stageTokenLength = strlen(stageToken); - size_t pos = source.find(stageToken, 0); - - // Process entire source - while (pos != std::string::npos) - { - // Make sure we aren't eol after type token - const size_t eol = source.find_first_of("\r\n", pos); + namespace + { + shaderc_shader_kind ShaderStageToShaderCKind(const ShaderStage stage) + { + switch (stage) + { + case ShaderStage::Vertex: + return shaderc_vertex_shader; + case ShaderStage::Fragment: + return shaderc_fragment_shader; + } + + EPPO_ASSERT(false); + return static_cast(-1); + } + + VkShaderStageFlagBits ShaderStageToVkShaderStage(const ShaderStage stage) + { + if (stage == ShaderStage::Vertex) + return VK_SHADER_STAGE_VERTEX_BIT; + if (stage == ShaderStage::Fragment) + return VK_SHADER_STAGE_FRAGMENT_BIT; + + return VK_SHADER_STAGE_FLAG_BITS_MAX_ENUM; + } + + VkDescriptorType ShaderResourceTypeToVkDescriptorType(const ShaderResourceType type) + { + if (type == ShaderResourceType::UniformBuffer) + return VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + if (type == ShaderResourceType::Sampler) + return VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + + return VK_DESCRIPTOR_TYPE_MAX_ENUM; + } + } + + VulkanShader::VulkanShader(const ShaderSpecification& specification) + : Shader(specification) + { + EPPO_PROFILE_FUNCTION("VulkanShader::VulkanShader"); + + // Read shader source + const std::string shaderSource = Filesystem::ReadText(GetSpecification().Filepath); + + // Preprocess by shader stage + const auto sources = PreProcess(shaderSource); + + // Compile or get cache + CompileOrGetCache(sources); + + m_ShaderResources[0] = {}; + m_ShaderResources[1] = {}; + m_ShaderResources[2] = {}; + m_ShaderResources[3] = {}; + + // Reflection + for (const auto& [type, data] : m_ShaderBytes) + Reflect(type, data); + + CreatePipelineShaderInfos(); + CreateDescriptorSetLayouts(); + } + + std::unordered_map VulkanShader::PreProcess(std::string_view source) const + { + EPPO_PROFILE_FUNCTION("VulkanShader::PreProcess"); + + std::unordered_map shaderSources; + + // Find stage token + const auto stageToken = "#stage"; + const size_t stageTokenLength = strlen(stageToken); + size_t pos = source.find(stageToken, 0); + + // Process entire source + while (pos != std::string::npos) + { + // Make sure we aren't eol after type token + const size_t eol = source.find_first_of("\r\n", pos); EPPO_ASSERT(eol != std::string::npos); // "Syntax error: No stage specified!" - // Extract shader stage - const size_t begin = pos + stageTokenLength + 1; - const auto stage = std::string(source.substr(begin, eol - begin)); + // Extract shader stage + const size_t begin = pos + stageTokenLength + 1; + const auto stage = std::string(source.substr(begin, eol - begin)); EPPO_ASSERT(static_cast(Utils::StringToShaderStage(stage))); // "Invalid stage specified!" - // If there is no other stage token, take the string till eof. Otherwise till the next stage token - const size_t nextLinePos = source.find_first_not_of("\r\n", eol); + // If there is no other stage token, take the string till eof. Otherwise till the next stage token + const size_t nextLinePos = source.find_first_not_of("\r\n", eol); EPPO_ASSERT(nextLinePos != std::string::npos); // "Syntax error: No source after stage token!" - pos = source.find(stageToken, nextLinePos); - shaderSources[Utils::StringToShaderStage(stage)] = (pos == std::string::npos) ? std::string(source.substr(nextLinePos)) : std::string(source.substr(nextLinePos, pos - nextLinePos)); - } - - // Process includes - for (auto& [stage, stageSource] : shaderSources) - { - shaderc::Compiler compiler; - shaderc::CompileOptions options; - options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_3); - options.SetIncluder(CreateScope()); - options.SetOptimizationLevel(shaderc_optimization_level_zero); - - auto result = compiler.PreprocessGlsl(stageSource, ShaderStageToShaderCKind(stage), GetSpecification().Filepath.string().c_str(), options); - stageSource = std::string(result.cbegin(), result.cend()); - } - - return shaderSources; - } - - void VulkanShader::Compile(const ShaderStage stage, const std::string& source) - { - EPPO_PROFILE_FUNCTION("VulkanShader::Compile"); - - const shaderc::Compiler compiler; - shaderc::CompileOptions options; - options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_3); - options.SetIncluder(CreateScope()); - options.SetOptimizationLevel(shaderc_optimization_level_zero); - options.SetGenerateDebugInfo(); - - // Compile source - const shaderc::SpvCompilationResult result = compiler.CompileGlslToSpv(source, ShaderStageToShaderCKind(stage), GetSpecification().Filepath.string().c_str(), options); - if (result.GetCompilationStatus() != shaderc_compilation_status_success) - { - EPPO_ERROR("Failed to compile shader with filename: {}", GetSpecification().Filepath); - EPPO_ERROR(result.GetErrorMessage()); + pos = source.find(stageToken, nextLinePos); + shaderSources[Utils::StringToShaderStage(stage)] = (pos == std::string::npos) + ? std::string(source.substr(nextLinePos)) + : std::string(source.substr(nextLinePos, pos - nextLinePos)); + } + + // Process includes + for (auto& [stage, stageSource] : shaderSources) + { + shaderc::Compiler compiler; + shaderc::CompileOptions options; + options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_3); + options.SetIncluder(CreateScope()); + options.SetOptimizationLevel(shaderc_optimization_level_zero); + + auto result = compiler.PreprocessGlsl(stageSource, ShaderStageToShaderCKind(stage), GetSpecification().Filepath.string().c_str(), options); + stageSource = std::string(result.cbegin(), result.cend()); + } + + return shaderSources; + } + + void VulkanShader::Compile(const ShaderStage stage, const std::string& source) + { + EPPO_PROFILE_FUNCTION("VulkanShader::Compile"); + + const shaderc::Compiler compiler; + shaderc::CompileOptions options; + options.SetTargetEnvironment(shaderc_target_env_vulkan, shaderc_env_version_vulkan_1_3); + options.SetIncluder(CreateScope()); + options.SetOptimizationLevel(shaderc_optimization_level_zero); + options.SetGenerateDebugInfo(); + + // Compile source + const shaderc::SpvCompilationResult result = compiler.CompileGlslToSpv(source, ShaderStageToShaderCKind(stage), + GetSpecification().Filepath.string().c_str(), options); + if (result.GetCompilationStatus() != shaderc_compilation_status_success) + { + EPPO_ERROR("Failed to compile shader with filename: {}", GetSpecification().Filepath); + EPPO_ERROR(result.GetErrorMessage()); EPPO_ASSERT(false); - } - - m_ShaderBytes[stage] = std::vector(result.cbegin(), result.cend()); - - // Write cache - const std::string cachePath = Utils::GetOrCreateCacheDirectory().string() + "/" + GetName() + "." + Utils::ShaderStageToString(stage); - Filesystem::WriteBytes(cachePath, m_ShaderBytes.at(stage)); - - // Write cache hash - const std::string cacheHashPath = cachePath + ".hash"; - const uint64_t hash = Hash::GenerateFnv(source); - Filesystem::WriteText(cacheHashPath, std::to_string(hash)); - } - - void VulkanShader::CompileOrGetCache(const std::unordered_map& sources) - { - EPPO_PROFILE_FUNCTION("VulkanShader::CompileOrGetCache"); - - const std::filesystem::path cacheDir = Utils::GetOrCreateCacheDirectory(); - - for (const auto& [stage, source] : sources) - { - std::string cacheFile = cacheDir.string() + "/" + GetName() + "." + Utils::ShaderStageToString(stage); - std::string cacheHashFile = cacheFile + ".hash"; - - // Check if cache needs to be busted - bool cacheVerified = false; - if (Filesystem::Exists(cacheFile) && Filesystem::Exists(cacheHashFile)) - { - std::string hash = std::to_string(Hash::GenerateFnv(source)); - - // Check if cache needs to be busted - if (std::string cacheHash = Filesystem::ReadText(cacheHashFile); - cacheHash == hash) - { - cacheVerified = true; - } - } - - if (cacheVerified) - { - EPPO_INFO("Loading shader cache: {}.glsl (Stage: {})", GetName(), Utils::ShaderStageToString(stage)); - - // Read shader cache - ScopedBuffer buffer(Filesystem::ReadBytes(cacheFile)); - - // Since the buffer size is 1 byte aligned and a uint32_t is 4 byte aligned, we only need a quarter of the size - std::vector vec(buffer.Size() / sizeof(uint32_t)); - - // Copy the data into the vector - memcpy(vec.data(), buffer.Data(), buffer.Size()); - m_ShaderBytes[stage] = vec; - } - else - { - EPPO_INFO("Triggering recompilation of shader due to hash mismatch: {}.glsl (Stage: {})", GetName(), Utils::ShaderStageToString(stage)); - - Compile(stage, source); - } - } - } - - void VulkanShader::Reflect(const ShaderStage stage, const std::vector& shaderBytes) - { - EPPO_PROFILE_FUNCTION("VulkanShader::Reflect"); - - const spirv_cross::Compiler compiler(shaderBytes); - spirv_cross::ShaderResources resources = compiler.get_shader_resources(); - - EPPO_TRACE("Shader::Reflect - {}.glsl (Stage: {})", GetName(), Utils::ShaderStageToString(stage)); - EPPO_TRACE(" {} Push constants", resources.push_constant_buffers.size()); - EPPO_TRACE(" {} Uniform buffers", resources.uniform_buffers.size()); - EPPO_TRACE(" {} Sampled images", resources.sampled_images.size()); - - if (!resources.push_constant_buffers.empty()) - { - EPPO_TRACE(" Push constants:"); + } + + m_ShaderBytes[stage] = std::vector(result.cbegin(), result.cend()); + + // Write cache + const std::string cachePath = Utils::GetOrCreateCacheDirectory().string() + "/" + GetName() + "." + Utils::ShaderStageToString(stage); + Filesystem::WriteBytes(cachePath, m_ShaderBytes.at(stage)); + + // Write cache hash + const std::string cacheHashPath = cachePath + ".hash"; + const uint64_t hash = Hash::GenerateFnv(source); + Filesystem::WriteText(cacheHashPath, std::to_string(hash)); + } + + void VulkanShader::CompileOrGetCache(const std::unordered_map& sources) + { + EPPO_PROFILE_FUNCTION("VulkanShader::CompileOrGetCache"); + + const std::filesystem::path cacheDir = Utils::GetOrCreateCacheDirectory(); + + for (const auto& [stage, source] : sources) + { + std::string cacheFile = cacheDir.string() + "/" + GetName() + "." + Utils::ShaderStageToString(stage); + std::string cacheHashFile = cacheFile + ".hash"; + + // Check if cache needs to be busted + bool cacheVerified = false; + if (Filesystem::Exists(cacheFile) && Filesystem::Exists(cacheHashFile)) + { + std::string hash = std::to_string(Hash::GenerateFnv(source)); + + // Check if cache needs to be busted + if (std::string cacheHash = Filesystem::ReadText(cacheHashFile); cacheHash == hash) + { + cacheVerified = true; + } + } + + if (cacheVerified) + { + EPPO_INFO("Loading shader cache: {}.glsl (Stage: {})", GetName(), Utils::ShaderStageToString(stage)); + + // Read shader cache + ScopedBuffer buffer(Filesystem::ReadBytes(cacheFile)); + + // Since the buffer size is 1 byte aligned and a uint32_t is 4 byte aligned, we only need a quarter of the size + std::vector vec(buffer.Size() / sizeof(uint32_t)); + + // Copy the data into the vector + memcpy(vec.data(), buffer.Data(), buffer.Size()); + m_ShaderBytes[stage] = vec; + } + else + { + EPPO_INFO("Triggering recompilation of shader due to hash mismatch: {}.glsl (Stage: {})", GetName(), Utils::ShaderStageToString(stage)); + + Compile(stage, source); + } + } + } + + void VulkanShader::Reflect(const ShaderStage stage, const std::vector& shaderBytes) + { + EPPO_PROFILE_FUNCTION("VulkanShader::Reflect"); + + const spirv_cross::Compiler compiler(shaderBytes); + spirv_cross::ShaderResources resources = compiler.get_shader_resources(); + + EPPO_TRACE("Shader::Reflect - {}.glsl (Stage: {})", GetName(), Utils::ShaderStageToString(stage)); + EPPO_TRACE(" {} Push constants", resources.push_constant_buffers.size()); + EPPO_TRACE(" {} Uniform buffers", resources.uniform_buffers.size()); + EPPO_TRACE(" {} Sampled images", resources.sampled_images.size()); + + if (!resources.push_constant_buffers.empty()) + { + EPPO_TRACE(" Push constants:"); EPPO_ASSERT(resources.push_constant_buffers.size() == 1); // At the moment, vulkan only supports one push constant buffer - const auto& resource = resources.push_constant_buffers[0]; - const auto& bufferType = compiler.get_type(resource.base_type_id); - size_t bufferSize = compiler.get_declared_struct_size(bufferType); - size_t memberCount = bufferType.member_types.size(); - - if (m_PushConstantRanges.empty()) - { - auto& [stageFlags, offset, size] = m_PushConstantRanges.emplace_back(); - size = static_cast(bufferSize); - stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS; - offset = 0; - } - - if (!resource.name.empty()) - EPPO_TRACE(" {}", resource.name); - EPPO_TRACE(" Size = {}", bufferSize); - EPPO_TRACE(" Members = {}", memberCount); - - for (size_t i = 0; i < memberCount; i++) - EPPO_TRACE(" Member: {} ({})", - compiler.get_member_name(resource.base_type_id, static_cast(i)), - static_cast(compiler.get_type(resource.base_type_id).member_types[i])); - } - - if (!resources.uniform_buffers.empty()) - { - EPPO_TRACE(" Uniform buffers:"); - - for (const auto& resource : resources.uniform_buffers) - { - const auto& bufferType = compiler.get_type(resource.base_type_id); - size_t bufferSize = compiler.get_declared_struct_size(bufferType); - uint32_t set = compiler.get_decoration(resource.id, spv::DecorationDescriptorSet); - uint32_t binding = compiler.get_decoration(resource.id, spv::DecorationBinding); - size_t memberCount = bufferType.member_types.size(); - - bool bindingExists = false; - for (auto& sr : m_ShaderResources[set]) - { - if (sr.Binding == binding) - { - sr.Type = ShaderStage::All; - bindingExists = true; - break; - } - } - - if (!bindingExists) - { - ShaderResource& shaderResource = m_ShaderResources[set].emplace_back(); - shaderResource.Type = stage; - shaderResource.ResourceType = ShaderResourceType::UniformBuffer; - shaderResource.Binding = binding; - shaderResource.Size = static_cast(bufferSize); - shaderResource.Name = resource.name; - } - - EPPO_TRACE(" {}", resource.name); - EPPO_TRACE(" Size = {}", bufferSize); - EPPO_TRACE(" Set = {}", set); - EPPO_TRACE(" Binding = {}", binding); - EPPO_TRACE(" Members = {}", memberCount); - } - } - - if (!resources.sampled_images.empty()) - { - EPPO_TRACE(" Sampled images:"); - - for (const auto& resource : resources.sampled_images) - { - const auto& bufferType = compiler.get_type(resource.base_type_id); - - uint32_t set = compiler.get_decoration(resource.id, spv::DecorationDescriptorSet); - uint32_t binding = compiler.get_decoration(resource.id, spv::DecorationBinding); - auto& spirVtype = compiler.get_type(resource.type_id); - uint32_t arraySize = 0; - if (!spirVtype.array.empty()) - arraySize = spirVtype.array[0]; - - bool bindingExists = false; - for (auto& sr : m_ShaderResources[set]) - { - if (sr.Binding == binding) - { - sr.Type = ShaderStage::All; - bindingExists = true; - break; - } - } - - if (!bindingExists) - { - ShaderResource& shaderResource = m_ShaderResources[set].emplace_back(); - shaderResource.Type = stage; - shaderResource.ResourceType = ShaderResourceType::Sampler; - shaderResource.Binding = binding; - shaderResource.ArraySize = arraySize; - shaderResource.Name = resource.name; - } - - EPPO_TRACE(" Set = {}", set); - EPPO_TRACE(" Binding = {}", binding); - } - } - EPPO_TRACE(""); - } - - void VulkanShader::CreatePipelineShaderInfos() - { - EPPO_PROFILE_FUNCTION("VulkanShader::CreatePipelineShaderInfos"); - - const auto context = VulkanContext::Get(); - VkDevice device = context->GetLogicalDevice()->GetNativeDevice(); - - for (const auto& [type, shaderBytes] : m_ShaderBytes) - { - VkShaderModuleCreateInfo shaderModuleCreateInfo{}; - shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - shaderModuleCreateInfo.codeSize = shaderBytes.size() * sizeof(uint32_t); - shaderModuleCreateInfo.pCode = shaderBytes.data(); - - VkShaderModule shaderModule; + const auto& resource = resources.push_constant_buffers[0]; + const auto& bufferType = compiler.get_type(resource.base_type_id); + size_t bufferSize = compiler.get_declared_struct_size(bufferType); + size_t memberCount = bufferType.member_types.size(); + + if (m_PushConstantRanges.empty()) + { + auto& [stageFlags, offset, size] = m_PushConstantRanges.emplace_back(); + size = static_cast(bufferSize); + stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS; + offset = 0; + } + + if (!resource.name.empty()) + EPPO_TRACE(" {}", resource.name); + EPPO_TRACE(" Size = {}", bufferSize); + EPPO_TRACE(" Members = {}", memberCount); + + for (size_t i = 0; i < memberCount; i++) + EPPO_TRACE(" Member: {} ({})", + compiler.get_member_name(resource.base_type_id, static_cast(i)), + static_cast(compiler.get_type(resource.base_type_id).member_types[i])); + } + + if (!resources.uniform_buffers.empty()) + { + EPPO_TRACE(" Uniform buffers:"); + + for (const auto& resource : resources.uniform_buffers) + { + const auto& bufferType = compiler.get_type(resource.base_type_id); + size_t bufferSize = compiler.get_declared_struct_size(bufferType); + uint32_t set = compiler.get_decoration(resource.id, spv::DecorationDescriptorSet); + uint32_t binding = compiler.get_decoration(resource.id, spv::DecorationBinding); + size_t memberCount = bufferType.member_types.size(); + + bool bindingExists = false; + for (auto& sr : m_ShaderResources[set]) + { + if (sr.Binding == binding) + { + sr.Type = ShaderStage::All; + bindingExists = true; + break; + } + } + + if (!bindingExists) + { + ShaderResource& shaderResource = m_ShaderResources[set].emplace_back(); + shaderResource.Type = stage; + shaderResource.ResourceType = ShaderResourceType::UniformBuffer; + shaderResource.Binding = binding; + shaderResource.Size = static_cast(bufferSize); + shaderResource.Name = resource.name; + } + + EPPO_TRACE(" {}", resource.name); + EPPO_TRACE(" Size = {}", bufferSize); + EPPO_TRACE(" Set = {}", set); + EPPO_TRACE(" Binding = {}", binding); + EPPO_TRACE(" Members = {}", memberCount); + } + } + + if (!resources.sampled_images.empty()) + { + EPPO_TRACE(" Sampled images:"); + + for (const auto& resource : resources.sampled_images) + { + const auto& bufferType = compiler.get_type(resource.base_type_id); + + uint32_t set = compiler.get_decoration(resource.id, spv::DecorationDescriptorSet); + uint32_t binding = compiler.get_decoration(resource.id, spv::DecorationBinding); + auto& spirVtype = compiler.get_type(resource.type_id); + uint32_t arraySize = 0; + if (!spirVtype.array.empty()) + arraySize = spirVtype.array[0]; + + bool bindingExists = false; + for (auto& sr : m_ShaderResources[set]) + { + if (sr.Binding == binding) + { + sr.Type = ShaderStage::All; + bindingExists = true; + break; + } + } + + if (!bindingExists) + { + ShaderResource& shaderResource = m_ShaderResources[set].emplace_back(); + shaderResource.Type = stage; + shaderResource.ResourceType = ShaderResourceType::Sampler; + shaderResource.Binding = binding; + shaderResource.ArraySize = arraySize; + shaderResource.Name = resource.name; + } + + EPPO_TRACE(" Set = {}", set); + EPPO_TRACE(" Binding = {}", binding); + } + } + EPPO_TRACE(""); + } + + void VulkanShader::CreatePipelineShaderInfos() + { + EPPO_PROFILE_FUNCTION("VulkanShader::CreatePipelineShaderInfos"); + + const auto context = VulkanContext::Get(); + VkDevice device = context->GetLogicalDevice()->GetNativeDevice(); + + for (const auto& [type, shaderBytes] : m_ShaderBytes) + { + VkShaderModuleCreateInfo shaderModuleCreateInfo{}; + shaderModuleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + shaderModuleCreateInfo.codeSize = shaderBytes.size() * sizeof(uint32_t); + shaderModuleCreateInfo.pCode = shaderBytes.data(); + + VkShaderModule shaderModule; VK_CHECK(vkCreateShaderModule(device, &shaderModuleCreateInfo, nullptr, &shaderModule), "Failed to create shader module!"); - VkPipelineShaderStageCreateInfo& shaderStageCreateInfo = m_ShaderInfos.emplace_back(); - shaderStageCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - shaderStageCreateInfo.stage = ShaderStageToVkShaderStage(type); - shaderStageCreateInfo.module = shaderModule; - shaderStageCreateInfo.pName = "main"; - - context->SubmitResourceFree([device, shaderModule]() - { - EPPO_MEM_WARN("Releasing shader module {}", static_cast(shaderModule)); - vkDestroyShaderModule(device, shaderModule, nullptr); - }, false); - } - } - - void VulkanShader::CreateDescriptorSetLayouts() - { - EPPO_PROFILE_FUNCTION("VulkanShader::CreateDescriptorSetLayouts"); - - const auto context = VulkanContext::Get(); - const VkDevice device = context->GetLogicalDevice()->GetNativeDevice(); - - auto& builder = context->GetDescriptorLayoutBuilder(); - - m_DescriptorSetLayouts.resize(4); - for (const auto& [set, setResources] : m_ShaderResources) - { - if (setResources.empty()) - continue; - - for (const auto& resource : setResources) - { - // TODO: This is as dirty as code can get - if (resource.Binding == 0 && set == 2) - { - builder.AddBinding(resource.Binding, ShaderResourceTypeToVkDescriptorType(resource.ResourceType), 512); - continue; - } - - builder.AddBinding(resource.Binding, ShaderResourceTypeToVkDescriptorType(resource.ResourceType), resource.ArraySize); - } - - m_DescriptorSetLayouts[set] = builder.Build(VK_SHADER_STAGE_ALL); - } - - VkDescriptorSetLayoutCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - createInfo.bindingCount = 0; - createInfo.pBindings = nullptr; - - VkDescriptorSetLayout layout; + VkPipelineShaderStageCreateInfo& shaderStageCreateInfo = m_ShaderInfos.emplace_back(); + shaderStageCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + shaderStageCreateInfo.stage = ShaderStageToVkShaderStage(type); + shaderStageCreateInfo.module = shaderModule; + shaderStageCreateInfo.pName = "main"; + + context->SubmitResourceFree([device, shaderModule]() + { + EPPO_MEM_WARN("Releasing shader module {}", static_cast(shaderModule)); + vkDestroyShaderModule(device, shaderModule, nullptr); + }, false); + } + } + + void VulkanShader::CreateDescriptorSetLayouts() + { + EPPO_PROFILE_FUNCTION("VulkanShader::CreateDescriptorSetLayouts"); + + const auto context = VulkanContext::Get(); + const VkDevice device = context->GetLogicalDevice()->GetNativeDevice(); + + auto& builder = context->GetDescriptorLayoutBuilder(); + + m_DescriptorSetLayouts.resize(4); + for (const auto& [set, setResources] : m_ShaderResources) + { + if (setResources.empty()) + continue; + + for (const auto& resource : setResources) + { + // TODO: This is as dirty as code can get + if (resource.Binding == 0 && set == 2) + { + builder.AddBinding(resource.Binding, ShaderResourceTypeToVkDescriptorType(resource.ResourceType), 512); + continue; + } + + builder.AddBinding(resource.Binding, ShaderResourceTypeToVkDescriptorType(resource.ResourceType), resource.ArraySize); + } + + m_DescriptorSetLayouts[set] = builder.Build(VK_SHADER_STAGE_ALL); + } + + VkDescriptorSetLayoutCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + createInfo.bindingCount = 0; + createInfo.pBindings = nullptr; + + VkDescriptorSetLayout layout; VK_CHECK(vkCreateDescriptorSetLayout(device, &createInfo, nullptr, &layout), "Failed to create descriptor set layout!"); - for (auto& descriptorSetLayout : m_DescriptorSetLayouts) - { - if (!descriptorSetLayout) - descriptorSetLayout = layout; - } - - context->SubmitResourceFree([device, layout]() - { - EPPO_MEM_WARN("Releasing descriptor set layout {}", static_cast(layout)); - vkDestroyDescriptorSetLayout(device, layout, nullptr); - }); - } + for (auto& descriptorSetLayout : m_DescriptorSetLayouts) + { + if (!descriptorSetLayout) + descriptorSetLayout = layout; + } + + context->SubmitResourceFree([device, layout]() + { + EPPO_MEM_WARN("Releasing descriptor set layout {}", static_cast(layout)); + vkDestroyDescriptorSetLayout(device, layout, nullptr); + }); + } } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanShader.h b/EppoEngine/Source/Platform/Vulkan/VulkanShader.h index 45bd783f..395f84af 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanShader.h +++ b/EppoEngine/Source/Platform/Vulkan/VulkanShader.h @@ -5,29 +5,29 @@ namespace Eppo { - class VulkanShader : public Shader - { - public: - explicit VulkanShader(const ShaderSpecification& specification); + class VulkanShader final : public Shader + { + public: + explicit VulkanShader(const ShaderSpecification& specification); - [[nodiscard]] const std::vector& GetPipelineShaderStageInfos() const { return m_ShaderInfos; } - [[nodiscard]] const std::vector& GetDescriptorSetLayouts() const { return m_DescriptorSetLayouts; } - [[nodiscard]] const std::vector& GetPushConstantRanges() const { return m_PushConstantRanges; } + [[nodiscard]] const std::vector& GetPipelineShaderStageInfos() const { return m_ShaderInfos; } + [[nodiscard]] const std::vector& GetDescriptorSetLayouts() const { return m_DescriptorSetLayouts; } + [[nodiscard]] const std::vector& GetPushConstantRanges() const { return m_PushConstantRanges; } - private: - [[nodiscard]] std::unordered_map PreProcess(std::string_view source) const; - void Compile(ShaderStage stage, const std::string& source); - void CompileOrGetCache(const std::unordered_map& sources); - void Reflect(ShaderStage stage, const std::vector& shaderBytes); - void CreatePipelineShaderInfos(); - void CreateDescriptorSetLayouts(); + private: + [[nodiscard]] std::unordered_map PreProcess(std::string_view source) const; + void Compile(ShaderStage stage, const std::string& source); + void CompileOrGetCache(const std::unordered_map& sources); + void Reflect(ShaderStage stage, const std::vector& shaderBytes); + void CreatePipelineShaderInfos(); + void CreateDescriptorSetLayouts(); - private: - std::unordered_map> m_ShaderBytes; - std::unordered_map> m_ShaderResources; + private: + std::unordered_map> m_ShaderBytes; + std::unordered_map> m_ShaderResources; - std::vector m_ShaderInfos; - std::vector m_DescriptorSetLayouts; - std::vector m_PushConstantRanges; - }; + std::vector m_ShaderInfos; + std::vector m_DescriptorSetLayouts; + std::vector m_PushConstantRanges; + }; } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanSwapchain.cpp b/EppoEngine/Source/Platform/Vulkan/VulkanSwapchain.cpp index 4495d7e2..a99bf803 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanSwapchain.cpp +++ b/EppoEngine/Source/Platform/Vulkan/VulkanSwapchain.cpp @@ -9,316 +9,322 @@ namespace Eppo { - VulkanSwapchain::VulkanSwapchain(const Ref& logicalDevice) - : m_LogicalDevice(logicalDevice) - { - Create(); - } - - void VulkanSwapchain::Create(bool recreate) - { - Ref context = VulkanContext::Get(); - Ref physicalDevice = context->GetPhysicalDevice(); - - // Swapchain support details - SwapchainSupportDetails details = QuerySwapchainSupportDetails(physicalDevice); - - VkSurfaceFormatKHR surfaceFormat = SelectSurfaceFormat(details.Formats); - m_ImageFormat = surfaceFormat.format; - - VkPresentModeKHR presentMode = SelectPresentMode(details.PresentModes); - m_Extent = SelectExtent(details.Capabilities); - - // Image count - uint32_t imageCount = details.Capabilities.minImageCount + 1; - if (details.Capabilities.maxImageCount > 0 && imageCount > details.Capabilities.maxImageCount) - imageCount = details.Capabilities.maxImageCount; - - // TODO: Remove this and use a dynamic amount of images - imageCount = VulkanConfig::MaxFramesInFlight; - - // Create swapchain - VkSwapchainKHR oldSwapchain; - if (recreate) - oldSwapchain = m_Swapchain; - - VkSwapchainCreateInfoKHR createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - createInfo.surface = physicalDevice->GetSurface(); - createInfo.preTransform = details.Capabilities.currentTransform; - createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - createInfo.presentMode = presentMode; - createInfo.clipped = VK_TRUE; - createInfo.oldSwapchain = recreate ? oldSwapchain : VK_NULL_HANDLE; - createInfo.minImageCount = imageCount; - createInfo.imageFormat = m_ImageFormat; - createInfo.imageColorSpace = surfaceFormat.colorSpace; - createInfo.imageExtent = m_Extent; - createInfo.imageArrayLayers = 1; - createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - - auto& [graphicsIndex, presentIndex] = physicalDevice->GetQueueFamilyIndices(); - std::array queueFamilies = { static_cast(graphicsIndex), static_cast(presentIndex) }; - - if (graphicsIndex != presentIndex) - { - createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - createInfo.queueFamilyIndexCount = static_cast(queueFamilies.size()); - createInfo.pQueueFamilyIndices = queueFamilies.data(); - } - else - { - createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - createInfo.queueFamilyIndexCount = 0; - createInfo.pQueueFamilyIndices = nullptr; - } - - VkDevice device = m_LogicalDevice->GetNativeDevice(); + VulkanSwapchain::VulkanSwapchain(const Ref& logicalDevice) + : m_LogicalDevice(logicalDevice) + { + Create(); + } + + void VulkanSwapchain::Create(bool recreate) + { + Ref context = VulkanContext::Get(); + Ref physicalDevice = context->GetPhysicalDevice(); + + // Swapchain support details + SwapchainSupportDetails details = QuerySwapchainSupportDetails(physicalDevice); + + VkSurfaceFormatKHR surfaceFormat = SelectSurfaceFormat(details.Formats); + m_ImageFormat = surfaceFormat.format; + + VkPresentModeKHR presentMode = SelectPresentMode(details.PresentModes); + m_Extent = SelectExtent(details.Capabilities); + + // Image count + uint32_t imageCount = details.Capabilities.minImageCount + 1; + if (details.Capabilities.maxImageCount > 0 && imageCount > details.Capabilities.maxImageCount) + imageCount = details.Capabilities.maxImageCount; + + // TODO: Remove this and use a dynamic amount of images + imageCount = VulkanConfig::MaxFramesInFlight; + + // Create swapchain + VkSwapchainKHR oldSwapchain; + if (recreate) + oldSwapchain = m_Swapchain; + + VkSwapchainCreateInfoKHR createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = physicalDevice->GetSurface(); + createInfo.preTransform = details.Capabilities.currentTransform; + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + createInfo.presentMode = presentMode; + createInfo.clipped = VK_TRUE; + createInfo.oldSwapchain = recreate ? oldSwapchain : VK_NULL_HANDLE; + createInfo.minImageCount = imageCount; + createInfo.imageFormat = m_ImageFormat; + createInfo.imageColorSpace = surfaceFormat.colorSpace; + createInfo.imageExtent = m_Extent; + createInfo.imageArrayLayers = 1; + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + + auto& [graphicsIndex, presentIndex] = physicalDevice->GetQueueFamilyIndices(); + std::array queueFamilies = { + static_cast(graphicsIndex), + static_cast(presentIndex) + }; + + if (graphicsIndex != presentIndex) + { + createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + createInfo.queueFamilyIndexCount = static_cast(queueFamilies.size()); + createInfo.pQueueFamilyIndices = queueFamilies.data(); + } + else + { + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.queueFamilyIndexCount = 0; + createInfo.pQueueFamilyIndices = nullptr; + } + + VkDevice device = m_LogicalDevice->GetNativeDevice(); VK_CHECK(vkCreateSwapchainKHR(device, &createInfo, nullptr, &m_Swapchain), "Failed to create swapchain!"); - if (recreate) - vkDestroySwapchainKHR(device, oldSwapchain, nullptr); - - // Get swapchain images - vkGetSwapchainImagesKHR(device, m_Swapchain, &imageCount, nullptr); - m_Images.resize(imageCount); - vkGetSwapchainImagesKHR(device, m_Swapchain, &imageCount, m_Images.data()); - - // Create image views - VkCommandBuffer cmd = m_LogicalDevice->GetCommandBuffer(true); - m_ImageViews.resize(imageCount); - - for (uint32_t i = 0; i < imageCount; i++) - { - VkImageViewCreateInfo imageViewCreateInfo{}; - imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - imageViewCreateInfo.image = m_Images[i]; - imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - imageViewCreateInfo.format = m_ImageFormat; - imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - imageViewCreateInfo.subresourceRange.baseMipLevel = 0; - imageViewCreateInfo.subresourceRange.levelCount = 1; - imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; - imageViewCreateInfo.subresourceRange.layerCount = 1; - - VK_CHECK(vkCreateImageView(device, &imageViewCreateInfo, nullptr, &m_ImageViews[i]), "Failed to create image view!"); - - // Transition images to present layout - VulkanImage::TransitionImage(cmd, m_Images[i], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); - } - - m_LogicalDevice->FlushCommandBuffer(cmd); - - if (!recreate) - { - // These things do not need to be recreated upon swapchain recreation - m_CommandBuffer = CreateRef(false, 0); - - // Sync objects - m_Fences.resize(VulkanConfig::MaxFramesInFlight); - m_PresentSemaphores.resize(VulkanConfig::MaxFramesInFlight); - m_RenderSemaphores.resize(VulkanConfig::MaxFramesInFlight); - - VkFenceCreateInfo fenceCreateInfo{}; - fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - - VkSemaphoreCreateInfo semaphoreCreateInfo{}; - semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - - for (uint32_t i = 0; i < VulkanConfig::MaxFramesInFlight; i++) - { + if (recreate) + vkDestroySwapchainKHR(device, oldSwapchain, nullptr); + + // Get swapchain images + vkGetSwapchainImagesKHR(device, m_Swapchain, &imageCount, nullptr); + m_Images.resize(imageCount); + vkGetSwapchainImagesKHR(device, m_Swapchain, &imageCount, m_Images.data()); + + // Create image views + VkCommandBuffer cmd = m_LogicalDevice->GetCommandBuffer(true); + m_ImageViews.resize(imageCount); + + for (uint32_t i = 0; i < imageCount; i++) + { + VkImageViewCreateInfo imageViewCreateInfo{}; + imageViewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + imageViewCreateInfo.image = m_Images[i]; + imageViewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + imageViewCreateInfo.format = m_ImageFormat; + imageViewCreateInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + imageViewCreateInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + imageViewCreateInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + imageViewCreateInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + imageViewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageViewCreateInfo.subresourceRange.baseMipLevel = 0; + imageViewCreateInfo.subresourceRange.levelCount = 1; + imageViewCreateInfo.subresourceRange.baseArrayLayer = 0; + imageViewCreateInfo.subresourceRange.layerCount = 1; + + VK_CHECK(vkCreateImageView(device, &imageViewCreateInfo, nullptr, &m_ImageViews[i]), "Failed to create image view!"); + + // Transition images to present layout + VulkanImage::TransitionImage(cmd, m_Images[i], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + } + + m_LogicalDevice->FlushCommandBuffer(cmd); + + if (!recreate) + { + // These things do not need to be recreated upon swapchain recreation + m_CommandBuffer = CreateRef(false, 0); + + // Sync objects + m_Fences.resize(VulkanConfig::MaxFramesInFlight); + m_PresentSemaphores.resize(VulkanConfig::MaxFramesInFlight); + m_RenderSemaphores.resize(VulkanConfig::MaxFramesInFlight); + + VkFenceCreateInfo fenceCreateInfo{}; + fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + VkSemaphoreCreateInfo semaphoreCreateInfo{}; + semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + for (uint32_t i = 0; i < VulkanConfig::MaxFramesInFlight; i++) + { VK_CHECK(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &m_RenderSemaphores[i]), "Failed to create semaphore!"); VK_CHECK(vkCreateSemaphore(device, &semaphoreCreateInfo, nullptr, &m_PresentSemaphores[i]), "Failed to create semaphore!"); VK_CHECK(vkCreateFence(device, &fenceCreateInfo, nullptr, &m_Fences[i]), "Failed to create fence!"); - } - } + } + } - context->SubmitResourceFree([this]() - { - EPPO_WARN("Releasing swapchain {}", static_cast(this)); - Destroy(); - }); - } + context->SubmitResourceFree([this]() + { + EPPO_WARN("Releasing swapchain {}", static_cast(this)); + Destroy(); + }); + } - void VulkanSwapchain::Cleanup() - { + void VulkanSwapchain::Cleanup() + { - } + } - void VulkanSwapchain::Destroy() const - { - const VkDevice device = m_LogicalDevice->GetNativeDevice(); + void VulkanSwapchain::Destroy() const + { + const VkDevice device = m_LogicalDevice->GetNativeDevice(); - for (uint32_t i = 0; i < VulkanConfig::MaxFramesInFlight; i++) - { - EPPO_MEM_WARN("Releasing semaphore {}", static_cast(m_PresentSemaphores[i])); - vkDestroySemaphore(device, m_PresentSemaphores[i], nullptr); + for (uint32_t i = 0; i < VulkanConfig::MaxFramesInFlight; i++) + { + EPPO_MEM_WARN("Releasing semaphore {}", static_cast(m_PresentSemaphores[i])); + vkDestroySemaphore(device, m_PresentSemaphores[i], nullptr); - EPPO_MEM_WARN("Releasing semaphore {}", static_cast(m_RenderSemaphores[i])); - vkDestroySemaphore(device, m_RenderSemaphores[i], nullptr); + EPPO_MEM_WARN("Releasing semaphore {}", static_cast(m_RenderSemaphores[i])); + vkDestroySemaphore(device, m_RenderSemaphores[i], nullptr); - EPPO_MEM_WARN("Releasing fence {}", static_cast(m_Fences[i])); - vkDestroyFence(device, m_Fences[i], nullptr); + EPPO_MEM_WARN("Releasing fence {}", static_cast(m_Fences[i])); + vkDestroyFence(device, m_Fences[i], nullptr); - EPPO_MEM_WARN("Releasing image view {}", static_cast(m_ImageViews[i])); - vkDestroyImageView(device, m_ImageViews[i], nullptr); - } + EPPO_MEM_WARN("Releasing image view {}", static_cast(m_ImageViews[i])); + vkDestroyImageView(device, m_ImageViews[i], nullptr); + } - vkDestroySwapchainKHR(device, m_Swapchain, nullptr); - } + vkDestroySwapchainKHR(device, m_Swapchain, nullptr); + } - void VulkanSwapchain::BeginFrame() - { - EPPO_PROFILE_FUNCTION("VulkanSwapchain::BeginFrame"); + void VulkanSwapchain::BeginFrame() + { + EPPO_PROFILE_FUNCTION("VulkanSwapchain::BeginFrame"); - const VkDevice device = m_LogicalDevice->GetNativeDevice(); + const VkDevice device = m_LogicalDevice->GetNativeDevice(); - vkAcquireNextImageKHR(device, m_Swapchain, UINT64_MAX, m_PresentSemaphores[m_CurrentFrameIndex], VK_NULL_HANDLE, &m_CurrentImageIndex); - m_CommandBuffer->ResetCommandBuffer(m_CurrentFrameIndex); - } + vkAcquireNextImageKHR(device, m_Swapchain, UINT64_MAX, m_PresentSemaphores[m_CurrentFrameIndex], VK_NULL_HANDLE, &m_CurrentImageIndex); + m_CommandBuffer->ResetCommandBuffer(m_CurrentFrameIndex); + } - void VulkanSwapchain::PresentFrame() - { - EPPO_PROFILE_FUNCTION("VulkanSwapchain::PresentFrame"); + void VulkanSwapchain::PresentFrame() + { + EPPO_PROFILE_FUNCTION("VulkanSwapchain::PresentFrame"); - constexpr VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - const VkCommandBuffer commandBuffer = m_CommandBuffer->GetCurrentCommandBuffer(); + constexpr VkPipelineStageFlags waitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + const VkCommandBuffer commandBuffer = m_CommandBuffer->GetCurrentCommandBuffer(); - VkSubmitInfo submitInfo{}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.waitSemaphoreCount = 1; - submitInfo.pWaitSemaphores = &m_PresentSemaphores[m_CurrentFrameIndex]; - submitInfo.pWaitDstStageMask = &waitStage; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &commandBuffer; - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = &m_RenderSemaphores[m_CurrentFrameIndex]; + VkSubmitInfo submitInfo{}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = &m_PresentSemaphores[m_CurrentFrameIndex]; + submitInfo.pWaitDstStageMask = &waitStage; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = &m_RenderSemaphores[m_CurrentFrameIndex]; - VK_CHECK(vkResetFences(m_LogicalDevice->GetNativeDevice(), 1, &m_Fences[m_CurrentFrameIndex]), "Failed to reset fence!"); + VK_CHECK(vkResetFences(m_LogicalDevice->GetNativeDevice(), 1, &m_Fences[m_CurrentFrameIndex]), "Failed to reset fence!"); VK_CHECK(vkQueueSubmit(m_LogicalDevice->GetGraphicsQueue(), 1, &submitInfo, m_Fences[m_CurrentFrameIndex]), "Failed to submit work to queue!"); - VkPresentInfoKHR presentInfo{}; - presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - presentInfo.waitSemaphoreCount = 1; - presentInfo.pWaitSemaphores = &m_RenderSemaphores[m_CurrentFrameIndex]; - presentInfo.swapchainCount = 1; - presentInfo.pSwapchains = &m_Swapchain; - presentInfo.pImageIndices = &m_CurrentImageIndex; - presentInfo.pResults = nullptr; - - if (const VkResult result = vkQueuePresentKHR(m_LogicalDevice->GetGraphicsQueue(), &presentInfo); - result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) - { - OnResize(); - } - - m_CurrentFrameIndex = (m_CurrentFrameIndex + 1) % VulkanConfig::MaxFramesInFlight; - - // TODO: Maybe do this elsewhere? - m_FrameCounter++; - VulkanContext::Get()->RunGC(m_FrameCounter); - - vkWaitForFences(m_LogicalDevice->GetNativeDevice(), 1, &m_Fences[m_CurrentFrameIndex], VK_TRUE, UINT64_MAX); - } - - void VulkanSwapchain::OnResize() - { - // TODO: Swapchain::OnResize + VkPresentInfoKHR presentInfo{}; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = &m_RenderSemaphores[m_CurrentFrameIndex]; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = &m_Swapchain; + presentInfo.pImageIndices = &m_CurrentImageIndex; + presentInfo.pResults = nullptr; + + if (const VkResult result = vkQueuePresentKHR(m_LogicalDevice->GetGraphicsQueue(), &presentInfo); result == VK_ERROR_OUT_OF_DATE_KHR || result == + VK_SUBOPTIMAL_KHR) + { + OnResize(); + } + + m_CurrentFrameIndex = (m_CurrentFrameIndex + 1) % VulkanConfig::MaxFramesInFlight; + + // TODO: Maybe do this elsewhere? + m_FrameCounter++; + VulkanContext::Get()->RunGC(m_FrameCounter); + + vkWaitForFences(m_LogicalDevice->GetNativeDevice(), 1, &m_Fences[m_CurrentFrameIndex], VK_TRUE, UINT64_MAX); + } + + void VulkanSwapchain::OnResize() + { + // TODO: Swapchain::OnResize EPPO_ASSERT(false); - } - - SwapchainSupportDetails VulkanSwapchain::QuerySwapchainSupportDetails(const Ref& physicalDevice) const - { - SwapchainSupportDetails details; - const VkPhysicalDevice device = physicalDevice->GetNativeDevice(); - - auto* surface = m_LogicalDevice->GetPhysicalDevice()->GetSurface(); - - // Capabilities - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.Capabilities); - - // Formats - uint32_t formatCount = 0; - vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr); - - if (formatCount != 0) - { - details.Formats.resize(formatCount); - vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.Formats.data()); - } - - // Presentation modes - uint32_t presentModeCount = 0; - vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr); - - if (presentModeCount != 0) - { - details.PresentModes.resize(presentModeCount); - vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.PresentModes.data()); - } - - return details; - } - - VkSurfaceFormatKHR VulkanSwapchain::SelectSurfaceFormat(const std::vector& surfaceFormats) - { - VkSurfaceFormatKHR surfaceFormat{}; - - for (const auto& format : surfaceFormats) - { - if (format.format == VK_FORMAT_R8G8B8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) - { - surfaceFormat = format; - break; - } - } - - if (surfaceFormat.format == VK_FORMAT_UNDEFINED) - { - EPPO_WARN("Undefined swapchain format!"); - surfaceFormat = surfaceFormats.back(); - } - - return surfaceFormat; - } - - VkPresentModeKHR VulkanSwapchain::SelectPresentMode(const std::vector& presentModes) - { - VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; // FIFO_KHR is required to be supported so will always be valid - - for (const auto& mode : presentModes) - { - if (mode == VK_PRESENT_MODE_IMMEDIATE_KHR) - { - presentMode = mode; - break; - } - } - - return presentMode; - } - - VkExtent2D VulkanSwapchain::SelectExtent(const VkSurfaceCapabilitiesKHR& capabilities) - { - VkExtent2D extent = capabilities.currentExtent; - - if (capabilities.currentExtent.width == UINT32_MAX) - { - int width = 0; - int height = 0; - glfwGetFramebufferSize(Application::Get().GetWindow().GetNativeWindow(), &width, &height); - - extent = { static_cast(width), static_cast(height) }; - - extent.width = std::clamp(extent.width, capabilities.maxImageExtent.width, capabilities.maxImageExtent.width); - extent.height = std::clamp(extent.height, capabilities.maxImageExtent.height, capabilities.maxImageExtent.height); - } - - return extent; - } + } + + SwapchainSupportDetails VulkanSwapchain::QuerySwapchainSupportDetails(const Ref& physicalDevice) const + { + SwapchainSupportDetails details; + const VkPhysicalDevice device = physicalDevice->GetNativeDevice(); + + auto* surface = m_LogicalDevice->GetPhysicalDevice()->GetSurface(); + + // Capabilities + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface, &details.Capabilities); + + // Formats + uint32_t formatCount = 0; + vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, nullptr); + + if (formatCount != 0) + { + details.Formats.resize(formatCount); + vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &formatCount, details.Formats.data()); + } + + // Presentation modes + uint32_t presentModeCount = 0; + vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, nullptr); + + if (presentModeCount != 0) + { + details.PresentModes.resize(presentModeCount); + vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &presentModeCount, details.PresentModes.data()); + } + + return details; + } + + VkSurfaceFormatKHR VulkanSwapchain::SelectSurfaceFormat(const std::vector& surfaceFormats) + { + VkSurfaceFormatKHR surfaceFormat{}; + + for (const auto& format : surfaceFormats) + { + if (format.format == VK_FORMAT_R8G8B8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + { + surfaceFormat = format; + break; + } + } + + if (surfaceFormat.format == VK_FORMAT_UNDEFINED) + { + EPPO_WARN("Undefined swapchain format!"); + surfaceFormat = surfaceFormats.back(); + } + + return surfaceFormat; + } + + VkPresentModeKHR VulkanSwapchain::SelectPresentMode(const std::vector& presentModes) + { + VkPresentModeKHR presentMode = VK_PRESENT_MODE_FIFO_KHR; // FIFO_KHR is required to be supported so will always be valid + + for (const auto& mode : presentModes) + { + if (mode == VK_PRESENT_MODE_IMMEDIATE_KHR) + { + presentMode = mode; + break; + } + } + + return presentMode; + } + + VkExtent2D VulkanSwapchain::SelectExtent(const VkSurfaceCapabilitiesKHR& capabilities) + { + VkExtent2D extent = capabilities.currentExtent; + + if (capabilities.currentExtent.width == UINT32_MAX) + { + int width = 0; + int height = 0; + glfwGetFramebufferSize(Application::Get().GetWindow().GetNativeWindow(), &width, &height); + + extent = { + .width = static_cast(width), + .height = static_cast(height) + }; + + extent.width = std::clamp(extent.width, capabilities.maxImageExtent.width, capabilities.maxImageExtent.width); + extent.height = std::clamp(extent.height, capabilities.maxImageExtent.height, capabilities.maxImageExtent.height); + } + + return extent; + } } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanSwapchain.h b/EppoEngine/Source/Platform/Vulkan/VulkanSwapchain.h index d41c7a01..864fb6a4 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanSwapchain.h +++ b/EppoEngine/Source/Platform/Vulkan/VulkanSwapchain.h @@ -7,63 +7,63 @@ struct GLFWwindow; namespace Eppo { - struct SwapchainSupportDetails - { - VkSurfaceCapabilitiesKHR Capabilities; - std::vector Formats; - std::vector PresentModes; - }; + struct SwapchainSupportDetails + { + VkSurfaceCapabilitiesKHR Capabilities; + std::vector Formats; + std::vector PresentModes; + }; - class VulkanSwapchain - { - public: - explicit VulkanSwapchain(const Ref& logicalDevice); + class VulkanSwapchain + { + public: + explicit VulkanSwapchain(const Ref& logicalDevice); - void Create(bool recreate = false); + void Create(bool recreate = false); - void Cleanup(); - void Destroy() const; + void Cleanup(); + void Destroy() const; - void BeginFrame(); - void PresentFrame(); + void BeginFrame(); + void PresentFrame(); - void OnResize(); + void OnResize(); - [[nodiscard]] VkImage GetCurrentImage() const { return m_Images[m_CurrentFrameIndex]; } - [[nodiscard]] VkImageView GetCurrentImageView() const { return m_ImageViews[m_CurrentFrameIndex]; } - [[nodiscard]] uint32_t GetCurrentImageIndex() const { return m_CurrentImageIndex; } + [[nodiscard]] VkImage GetCurrentImage() const { return m_Images[m_CurrentFrameIndex]; } + [[nodiscard]] VkImageView GetCurrentImageView() const { return m_ImageViews[m_CurrentFrameIndex]; } + [[nodiscard]] uint32_t GetCurrentImageIndex() const { return m_CurrentImageIndex; } - [[nodiscard]] uint32_t GetWidth() const { return m_Extent.width; } - [[nodiscard]] uint32_t GetHeight() const { return m_Extent.height; } - [[nodiscard]] VkExtent2D GetExtent() const { return m_Extent; } + [[nodiscard]] uint32_t GetWidth() const { return m_Extent.width; } + [[nodiscard]] uint32_t GetHeight() const { return m_Extent.height; } + [[nodiscard]] VkExtent2D GetExtent() const { return m_Extent; } - [[nodiscard]] Ref GetCommandBuffer() const { return m_CommandBuffer; } + [[nodiscard]] Ref GetCommandBuffer() const { return m_CommandBuffer; } - private: - [[nodiscard]] SwapchainSupportDetails QuerySwapchainSupportDetails(const Ref& physicalDevice) const; + private: + [[nodiscard]] SwapchainSupportDetails QuerySwapchainSupportDetails(const Ref& physicalDevice) const; - static VkSurfaceFormatKHR SelectSurfaceFormat(const std::vector& surfaceFormats); - static VkPresentModeKHR SelectPresentMode(const std::vector& presentModes); - static VkExtent2D SelectExtent(const VkSurfaceCapabilitiesKHR& capabilities); + static VkSurfaceFormatKHR SelectSurfaceFormat(const std::vector& surfaceFormats); + static VkPresentModeKHR SelectPresentMode(const std::vector& presentModes); + static VkExtent2D SelectExtent(const VkSurfaceCapabilitiesKHR& capabilities); - private: - Ref m_LogicalDevice; - Ref m_CommandBuffer; + private: + Ref m_LogicalDevice; + Ref m_CommandBuffer; - VkSwapchainKHR m_Swapchain; - VkExtent2D m_Extent; - VkFormat m_ImageFormat; + VkSwapchainKHR m_Swapchain; + VkExtent2D m_Extent; + VkFormat m_ImageFormat; - uint32_t m_CurrentFrameIndex = 0; - uint32_t m_CurrentImageIndex = 0; - uint32_t m_FrameCounter = 0; + uint32_t m_CurrentFrameIndex = 0; + uint32_t m_CurrentImageIndex = 0; + uint32_t m_FrameCounter = 0; - std::vector m_Images; - std::vector m_ImageViews; - std::vector m_Framebuffers; + std::vector m_Images; + std::vector m_ImageViews; + std::vector m_Framebuffers; - std::vector m_Fences; - std::vector m_PresentSemaphores; - std::vector m_RenderSemaphores; - }; + std::vector m_Fences; + std::vector m_PresentSemaphores; + std::vector m_RenderSemaphores; + }; } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanUniformBuffer.cpp b/EppoEngine/Source/Platform/Vulkan/VulkanUniformBuffer.cpp index d78b8818..9433955a 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanUniformBuffer.cpp +++ b/EppoEngine/Source/Platform/Vulkan/VulkanUniformBuffer.cpp @@ -5,47 +5,47 @@ namespace Eppo { - VulkanUniformBuffer::VulkanUniformBuffer(const uint32_t size, const uint32_t binding) - : m_Size(size), m_Binding(binding) - { - m_Buffers.resize(VulkanConfig::MaxFramesInFlight); - m_Allocations.resize(VulkanConfig::MaxFramesInFlight); - m_MappedMemory.resize(VulkanConfig::MaxFramesInFlight); - m_DescriptorBufferInfos.resize(VulkanConfig::MaxFramesInFlight); - - VkBufferCreateInfo bufferInfo{}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = m_Size; - bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - for (uint32_t i = 0; i < VulkanConfig::MaxFramesInFlight; i++) - { - m_Allocations[i] = VulkanAllocator::AllocateBuffer(m_Buffers[i], bufferInfo, VMA_MEMORY_USAGE_CPU_ONLY); - m_MappedMemory[i] = VulkanAllocator::MapMemory(m_Allocations[i]); - - m_DescriptorBufferInfos[i].buffer = m_Buffers[i]; - m_DescriptorBufferInfos[i].offset = 0; - m_DescriptorBufferInfos[i].range = m_Size; - } - } - - VulkanUniformBuffer::~VulkanUniformBuffer() - { - for (uint32_t i = 0; i < VulkanConfig::MaxFramesInFlight; i++) - { - EPPO_MEM_WARN("Releasing uniform buffer {}", static_cast(this)); - VulkanAllocator::UnmapMemory(m_Allocations[i]); - VulkanAllocator::DestroyBuffer(m_Buffers[i], m_Allocations[i]); - } - } - - void VulkanUniformBuffer::SetData(void* data, const uint32_t size) - { - EPPO_PROFILE_FUNCTION("VulkanUniformBuffer::SetData"); + VulkanUniformBuffer::VulkanUniformBuffer(const uint32_t size, const uint32_t binding) + : m_Size(size), m_Binding(binding) + { + m_Buffers.resize(VulkanConfig::MaxFramesInFlight); + m_Allocations.resize(VulkanConfig::MaxFramesInFlight); + m_MappedMemory.resize(VulkanConfig::MaxFramesInFlight); + m_DescriptorBufferInfos.resize(VulkanConfig::MaxFramesInFlight); + + VkBufferCreateInfo bufferInfo{}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = m_Size; + bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + for (uint32_t i = 0; i < VulkanConfig::MaxFramesInFlight; i++) + { + m_Allocations[i] = VulkanAllocator::AllocateBuffer(m_Buffers[i], bufferInfo, VMA_MEMORY_USAGE_CPU_ONLY); + m_MappedMemory[i] = VulkanAllocator::MapMemory(m_Allocations[i]); + + m_DescriptorBufferInfos[i].buffer = m_Buffers[i]; + m_DescriptorBufferInfos[i].offset = 0; + m_DescriptorBufferInfos[i].range = m_Size; + } + } + + VulkanUniformBuffer::~VulkanUniformBuffer() + { + for (uint32_t i = 0; i < VulkanConfig::MaxFramesInFlight; i++) + { + EPPO_MEM_WARN("Releasing uniform buffer {}", static_cast(this)); + VulkanAllocator::UnmapMemory(m_Allocations[i]); + VulkanAllocator::DestroyBuffer(m_Buffers[i], m_Allocations[i]); + } + } + + void VulkanUniformBuffer::SetData(void* data, const uint32_t size) + { + EPPO_PROFILE_FUNCTION("VulkanUniformBuffer::SetData"); EPPO_ASSERT(size == m_Size); - const uint32_t imageIndex = VulkanContext::Get()->GetCurrentFrameIndex(); - memcpy(m_MappedMemory[imageIndex], data, size); - } + const uint32_t imageIndex = VulkanContext::Get()->GetCurrentFrameIndex(); + memcpy(m_MappedMemory[imageIndex], data, size); + } } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanUniformBuffer.h b/EppoEngine/Source/Platform/Vulkan/VulkanUniformBuffer.h index 73e82c6c..4dd143ac 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanUniformBuffer.h +++ b/EppoEngine/Source/Platform/Vulkan/VulkanUniformBuffer.h @@ -5,27 +5,31 @@ namespace Eppo { - class VulkanUniformBuffer final : public UniformBuffer - { - public: - VulkanUniformBuffer(uint32_t size, uint32_t binding); - ~VulkanUniformBuffer() override; + class VulkanUniformBuffer final : public UniformBuffer + { + public: + VulkanUniformBuffer(uint32_t size, uint32_t binding); + VulkanUniformBuffer(const VulkanUniformBuffer&) = delete; + VulkanUniformBuffer(const VulkanUniformBuffer&&) = delete; + VulkanUniformBuffer& operator=(const VulkanUniformBuffer&) = delete; + VulkanUniformBuffer& operator=(const VulkanUniformBuffer&&) = delete; + ~VulkanUniformBuffer() override; - void SetData(void* data, uint32_t size) override; + void SetData(void* data, uint32_t size) override; - [[nodiscard]] const std::vector& GetBuffers() const { return m_Buffers; } - [[nodiscard]] uint32_t GetBinding() const override { return m_Binding; } + [[nodiscard]] const std::vector& GetBuffers() const { return m_Buffers; } + [[nodiscard]] uint32_t GetBinding() const override { return m_Binding; } - [[nodiscard]] const std::vector& GetDescriptorBufferInfos() const { return m_DescriptorBufferInfos; } + [[nodiscard]] const std::vector& GetDescriptorBufferInfos() const { return m_DescriptorBufferInfos; } - private: - uint32_t m_Size; - uint32_t m_Binding; + private: + uint32_t m_Size; + uint32_t m_Binding; - std::vector m_Buffers; - std::vector m_Allocations; - std::vector m_MappedMemory; + std::vector m_Buffers; + std::vector m_Allocations; + std::vector m_MappedMemory; - std::vector m_DescriptorBufferInfos; - }; + std::vector m_DescriptorBufferInfos; + }; } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanVertexBuffer.cpp b/EppoEngine/Source/Platform/Vulkan/VulkanVertexBuffer.cpp index 249a5684..8510758e 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanVertexBuffer.cpp +++ b/EppoEngine/Source/Platform/Vulkan/VulkanVertexBuffer.cpp @@ -6,107 +6,108 @@ namespace Eppo { - VulkanVertexBuffer::VulkanVertexBuffer(const uint32_t size) - : m_Size(size), m_IsMemoryMapped(true) - { - VkBufferCreateInfo vertexBufferInfo{}; - vertexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - vertexBufferInfo.size = size; - vertexBufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - vertexBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - m_Allocation = VulkanAllocator::AllocateBuffer(m_Buffer, vertexBufferInfo, VMA_MEMORY_USAGE_CPU_TO_GPU); - m_MappedMemory = VulkanAllocator::MapMemory(m_Allocation); - } - - VulkanVertexBuffer::VulkanVertexBuffer(const Buffer buffer) - : m_Size(buffer.Size), m_IsMemoryMapped(false) - { - EPPO_PROFILE_FUNCTION("VulkanVertexBuffer::VulkanVertexBuffer"); - - // Create GPU local buffer - VkBufferCreateInfo vertexBufferInfo{}; - vertexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - vertexBufferInfo.size = buffer.Size; - vertexBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - - m_Allocation = VulkanAllocator::AllocateBuffer(m_Buffer, vertexBufferInfo, VMA_MEMORY_USAGE_GPU_ONLY); - - CopyWithStagingBuffer(buffer); - } - - VulkanVertexBuffer::~VulkanVertexBuffer() - { - EPPO_MEM_WARN("Releasing vertex buffer {}", static_cast(this)); - - if (m_IsMemoryMapped) - VulkanAllocator::UnmapMemory(m_Allocation); - VulkanAllocator::DestroyBuffer(m_Buffer, m_Allocation); - } - - void VulkanVertexBuffer::SetData(const Buffer buffer) - { - // If buffer is bigger than our GPU buffer, recreate buffer - if (buffer.Size > m_Size) - { - // Create GPU local buffer - VkBufferCreateInfo vertexBufferInfo{}; - vertexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - vertexBufferInfo.size = buffer.Size; - vertexBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; - - if (m_IsMemoryMapped) - { - VulkanAllocator::UnmapMemory(m_Allocation); - m_Allocation = VulkanAllocator::AllocateBuffer(m_Buffer, vertexBufferInfo, VMA_MEMORY_USAGE_CPU_TO_GPU); - m_MappedMemory = VulkanAllocator::MapMemory(m_Allocation); - } else - { - m_Allocation = VulkanAllocator::AllocateBuffer(m_Buffer, vertexBufferInfo, VMA_MEMORY_USAGE_GPU_ONLY); - } - - m_Size = buffer.Size; - } - - // Now we have a GPU buffer of the correct size, copy data using either staging buffer or mapped memory - if (m_IsMemoryMapped) - memcpy(m_MappedMemory, buffer.Data, buffer.Size); - else - CopyWithStagingBuffer(buffer); - } - - void VulkanVertexBuffer::CopyWithStagingBuffer(Buffer buffer) const - { - // Create staging buffer - VkBufferCreateInfo stagingBufferInfo{}; - stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - stagingBufferInfo.size = buffer.Size; - stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - stagingBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VkBuffer stagingBuffer; - const VmaAllocation stagingBufferAlloc = VulkanAllocator::AllocateBuffer(stagingBuffer, stagingBufferInfo, VMA_MEMORY_USAGE_CPU_TO_GPU); - - // Copy data to staging buffer - void* memData = VulkanAllocator::MapMemory(stagingBufferAlloc); - memcpy(memData, buffer.Data, buffer.Size); - VulkanAllocator::UnmapMemory(stagingBufferAlloc); - - // Copy data from staging buffer to GPU local buffer - const auto context = VulkanContext::Get(); - const auto logicalDevice = context->GetLogicalDevice(); - const VkCommandBuffer commandBuffer = logicalDevice->GetCommandBuffer(true); - - VkBufferCopy copyRegion; - copyRegion.srcOffset = 0; - copyRegion.dstOffset = 0; - copyRegion.size = buffer.Size; - - vkCmdCopyBuffer(commandBuffer, stagingBuffer, m_Buffer, 1, ©Region); - logicalDevice->FlushCommandBuffer(commandBuffer); - - // Clean up - VulkanAllocator::DestroyBuffer(stagingBuffer, stagingBufferAlloc); - buffer.Release(); - } + VulkanVertexBuffer::VulkanVertexBuffer(const uint32_t size) + : m_Size(size), m_IsMemoryMapped(true) + { + VkBufferCreateInfo vertexBufferInfo{}; + vertexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + vertexBufferInfo.size = size; + vertexBufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + vertexBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + m_Allocation = VulkanAllocator::AllocateBuffer(m_Buffer, vertexBufferInfo, VMA_MEMORY_USAGE_CPU_TO_GPU); + m_MappedMemory = VulkanAllocator::MapMemory(m_Allocation); + } + + VulkanVertexBuffer::VulkanVertexBuffer(const Buffer buffer) + : m_Size(buffer.Size), m_IsMemoryMapped(false) + { + EPPO_PROFILE_FUNCTION("VulkanVertexBuffer::VulkanVertexBuffer"); + + // Create GPU local buffer + VkBufferCreateInfo vertexBufferInfo{}; + vertexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + vertexBufferInfo.size = buffer.Size; + vertexBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + + m_Allocation = VulkanAllocator::AllocateBuffer(m_Buffer, vertexBufferInfo, VMA_MEMORY_USAGE_GPU_ONLY); + + CopyWithStagingBuffer(buffer); + } + + VulkanVertexBuffer::~VulkanVertexBuffer() + { + EPPO_MEM_WARN("Releasing vertex buffer {}", static_cast(this)); + + if (m_IsMemoryMapped) + VulkanAllocator::UnmapMemory(m_Allocation); + VulkanAllocator::DestroyBuffer(m_Buffer, m_Allocation); + } + + void VulkanVertexBuffer::SetData(const Buffer buffer) + { + // If buffer is bigger than our GPU buffer, recreate buffer + if (buffer.Size > m_Size) + { + // Create GPU local buffer + VkBufferCreateInfo vertexBufferInfo{}; + vertexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + vertexBufferInfo.size = buffer.Size; + vertexBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT; + + if (m_IsMemoryMapped) + { + VulkanAllocator::UnmapMemory(m_Allocation); + m_Allocation = VulkanAllocator::AllocateBuffer(m_Buffer, vertexBufferInfo, VMA_MEMORY_USAGE_CPU_TO_GPU); + m_MappedMemory = VulkanAllocator::MapMemory(m_Allocation); + } + else + { + m_Allocation = VulkanAllocator::AllocateBuffer(m_Buffer, vertexBufferInfo, VMA_MEMORY_USAGE_GPU_ONLY); + } + + m_Size = buffer.Size; + } + + // Now we have a GPU buffer of the correct size, copy data using either staging buffer or mapped memory + if (m_IsMemoryMapped) + memcpy(m_MappedMemory, buffer.Data, buffer.Size); + else + CopyWithStagingBuffer(buffer); + } + + void VulkanVertexBuffer::CopyWithStagingBuffer(Buffer buffer) const + { + // Create staging buffer + VkBufferCreateInfo stagingBufferInfo{}; + stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + stagingBufferInfo.size = buffer.Size; + stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + stagingBufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VkBuffer stagingBuffer; + const VmaAllocation stagingBufferAlloc = VulkanAllocator::AllocateBuffer(stagingBuffer, stagingBufferInfo, VMA_MEMORY_USAGE_CPU_TO_GPU); + + // Copy data to staging buffer + void* memData = VulkanAllocator::MapMemory(stagingBufferAlloc); + memcpy(memData, buffer.Data, buffer.Size); + VulkanAllocator::UnmapMemory(stagingBufferAlloc); + + // Copy data from staging buffer to GPU local buffer + const auto context = VulkanContext::Get(); + const auto logicalDevice = context->GetLogicalDevice(); + const VkCommandBuffer commandBuffer = logicalDevice->GetCommandBuffer(true); + + VkBufferCopy copyRegion; + copyRegion.srcOffset = 0; + copyRegion.dstOffset = 0; + copyRegion.size = buffer.Size; + + vkCmdCopyBuffer(commandBuffer, stagingBuffer, m_Buffer, 1, ©Region); + logicalDevice->FlushCommandBuffer(commandBuffer); + + // Clean up + VulkanAllocator::DestroyBuffer(stagingBuffer, stagingBufferAlloc); + buffer.Release(); + } } diff --git a/EppoEngine/Source/Platform/Vulkan/VulkanVertexBuffer.h b/EppoEngine/Source/Platform/Vulkan/VulkanVertexBuffer.h index e7a78f46..14b0474b 100644 --- a/EppoEngine/Source/Platform/Vulkan/VulkanVertexBuffer.h +++ b/EppoEngine/Source/Platform/Vulkan/VulkanVertexBuffer.h @@ -5,26 +5,30 @@ namespace Eppo { - class VulkanVertexBuffer : public VertexBuffer - { - public: - explicit VulkanVertexBuffer(uint32_t size); - explicit VulkanVertexBuffer(Buffer buffer); - ~VulkanVertexBuffer() override; + class VulkanVertexBuffer final : public VertexBuffer + { + public: + explicit VulkanVertexBuffer(uint32_t size); + explicit VulkanVertexBuffer(Buffer buffer); + VulkanVertexBuffer(const VulkanVertexBuffer&) = delete; + VulkanVertexBuffer(const VulkanVertexBuffer&&) = delete; + VulkanVertexBuffer& operator=(const VulkanVertexBuffer&) = delete; + VulkanVertexBuffer& operator=(const VulkanVertexBuffer&&) = delete; + ~VulkanVertexBuffer() override; - void SetData(Buffer buffer) override; - [[nodiscard]] VkBuffer GetBuffer() const { return m_Buffer; } + void SetData(Buffer buffer) override; + [[nodiscard]] VkBuffer GetBuffer() const { return m_Buffer; } - private: - void CopyWithStagingBuffer(Buffer buffer) const; + private: + void CopyWithStagingBuffer(Buffer buffer) const; - private: - uint32_t m_Size; + private: + uint32_t m_Size; - VkBuffer m_Buffer; - VmaAllocation m_Allocation; + VkBuffer m_Buffer; + VmaAllocation m_Allocation; - bool m_IsMemoryMapped; - void* m_MappedMemory = nullptr; - }; + bool m_IsMemoryMapped; + void* m_MappedMemory = nullptr; + }; } diff --git a/EppoEngine/Source/Platform/Windows/FileDialog.cpp b/EppoEngine/Source/Platform/Windows/FileDialog.cpp index 92b4de4d..2c625c60 100644 --- a/EppoEngine/Source/Platform/Windows/FileDialog.cpp +++ b/EppoEngine/Source/Platform/Windows/FileDialog.cpp @@ -11,64 +11,64 @@ namespace Eppo { - std::filesystem::path FileDialog::OpenFile(const char* filter, const std::filesystem::path& initialDir) - { - EPPO_PROFILE_FUNCTION("FileDialog::OpenFile"); + std::filesystem::path FileDialog::OpenFile(const char* filter, const std::filesystem::path& initialDir) + { + EPPO_PROFILE_FUNCTION("FileDialog::OpenFile"); - OPENFILENAMEA ofn; - CHAR szFile[260]{ 0 }; - ZeroMemory(&ofn, sizeof(OPENFILENAME)); - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = glfwGetWin32Window(RendererContext::Get()->GetWindowHandle()); - ofn.lpstrFile = szFile; - ofn.nMaxFile = sizeof(szFile); + OPENFILENAMEA ofn; + CHAR szFile[260]{ 0 }; + ZeroMemory(&ofn, sizeof(OPENFILENAME)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = glfwGetWin32Window(RendererContext::Get()->GetWindowHandle()); + ofn.lpstrFile = szFile; + ofn.nMaxFile = sizeof(szFile); - if (initialDir.empty()) - { - if (CHAR currentDir[256]{}; - GetCurrentDirectoryA(256, currentDir)) - { - ofn.lpstrInitialDir = currentDir; - } - } else - { - ofn.lpstrInitialDir = initialDir.string().c_str(); - } + if (initialDir.empty()) + { + if (CHAR currentDir[256]{}; GetCurrentDirectoryA(256, currentDir)) + { + ofn.lpstrInitialDir = currentDir; + } + } + else + { + ofn.lpstrInitialDir = initialDir.string().c_str(); + } - ofn.lpstrFilter = filter; - ofn.nFilterIndex = 1; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; + ofn.lpstrFilter = filter; + ofn.nFilterIndex = 1; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR; - if (GetOpenFileNameA(&ofn) == TRUE) - return ofn.lpstrFile; + if (GetOpenFileNameA(&ofn) == TRUE) + return ofn.lpstrFile; - return {}; - } + return {}; + } - std::filesystem::path FileDialog::SaveFile(const char* filter) - { - EPPO_PROFILE_FUNCTION("FileDialog::SaveFile"); + std::filesystem::path FileDialog::SaveFile(const char* filter) + { + EPPO_PROFILE_FUNCTION("FileDialog::SaveFile"); - OPENFILENAMEA ofn; - CHAR szFile[260]{}; - CHAR currentDir[256]{}; - ZeroMemory(&ofn, sizeof(OPENFILENAME)); - ofn.lStructSize = sizeof(OPENFILENAME); - ofn.hwndOwner = glfwGetWin32Window(RendererContext::Get()->GetWindowHandle()); - ofn.lpstrFile = szFile; - ofn.nMaxFile = sizeof(szFile); + OPENFILENAMEA ofn; + CHAR szFile[260]{}; + CHAR currentDir[256]{}; + ZeroMemory(&ofn, sizeof(OPENFILENAME)); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = glfwGetWin32Window(RendererContext::Get()->GetWindowHandle()); + ofn.lpstrFile = szFile; + ofn.nMaxFile = sizeof(szFile); - if (GetCurrentDirectoryA(256, currentDir)) - ofn.lpstrInitialDir = currentDir; + if (GetCurrentDirectoryA(256, currentDir)) + ofn.lpstrInitialDir = currentDir; - ofn.lpstrFilter = filter; - ofn.nFilterIndex = 1; - ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR; - ofn.lpstrDefExt = std::strchr(filter, '\0') + 1; + ofn.lpstrFilter = filter; + ofn.nFilterIndex = 1; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR; + ofn.lpstrDefExt = std::strchr(filter, '\0') + 1; - if (GetSaveFileNameA(&ofn) == TRUE) - return ofn.lpstrFile; + if (GetSaveFileNameA(&ofn) == TRUE) + return ofn.lpstrFile; - return {}; - } + return {}; + } } diff --git a/EppoEngine/Source/Project/Project.cpp b/EppoEngine/Source/Project/Project.cpp index c5c3bb0f..d6c127c5 100644 --- a/EppoEngine/Source/Project/Project.cpp +++ b/EppoEngine/Source/Project/Project.cpp @@ -7,97 +7,95 @@ namespace Eppo { - const std::filesystem::path& Project::GetProjectDirectory() - { + const std::filesystem::path& Project::GetProjectDirectory() + { EPPO_ASSERT(s_ActiveProject); - return s_ActiveProject->m_Specification.ProjectDirectory; - } + return s_ActiveProject->m_Specification.ProjectDirectory; + } - std::filesystem::path Project::GetProjectsDirectory() - { - return Filesystem::GetAppRootDirectory() / "Projects"; - } + std::filesystem::path Project::GetProjectsDirectory() + { + return Filesystem::GetAppRootDirectory() / "Projects"; + } - std::filesystem::path Project::GetProjectFile() - { + std::filesystem::path Project::GetProjectFile() + { EPPO_ASSERT(s_ActiveProject); - return GetProjectDirectory() / std::filesystem::path(s_ActiveProject->m_Specification.Name + ".epproj"); - } + return GetProjectDirectory() / std::filesystem::path(s_ActiveProject->m_Specification.Name + ".epproj"); + } - std::filesystem::path Project::GetAssetsDirectory() - { + std::filesystem::path Project::GetAssetsDirectory() + { EPPO_ASSERT(s_ActiveProject); - return GetProjectDirectory() / "Assets"; - } + return GetProjectDirectory() / "Assets"; + } - std::filesystem::path Project::GetAssetFilepath(const std::filesystem::path& filepath) - { + std::filesystem::path Project::GetAssetFilepath(const std::filesystem::path& filepath) + { EPPO_ASSERT(s_ActiveProject); - return GetAssetsDirectory() / filepath; - } + return GetAssetsDirectory() / filepath; + } - std::filesystem::path Project::GetAssetRelativeFilepath(const std::filesystem::path& filepath) - { + std::filesystem::path Project::GetAssetRelativeFilepath(const std::filesystem::path& filepath) + { EPPO_ASSERT(s_ActiveProject); - return std::filesystem::relative(filepath, GetAssetsDirectory()); - } + return std::filesystem::relative(filepath, GetAssetsDirectory()); + } - Ref Project::New() - { - s_ActiveProject = CreateRef(); - return s_ActiveProject; - } + Ref Project::New() + { + s_ActiveProject = CreateRef(); + return s_ActiveProject; + } - Ref Project::New(const ProjectSpecification& specification) - { - New(); - s_ActiveProject->m_Specification = specification; - return s_ActiveProject; - } + Ref Project::New(const ProjectSpecification& specification) + { + New(); + s_ActiveProject->m_Specification = specification; + return s_ActiveProject; + } - Ref Project::Open(const std::filesystem::path& filepath) - { - EPPO_PROFILE_FUNCTION("Project::Open"); + Ref Project::Open(const std::filesystem::path& filepath) + { + EPPO_PROFILE_FUNCTION("Project::Open"); - const auto project = CreateRef(); + const auto project = CreateRef(); - if (ProjectSerializer serializer(project); - serializer.Deserialize(filepath)) - { - project->GetSpecification().ProjectDirectory = filepath.parent_path(); - s_ActiveProject = project; + if (ProjectSerializer serializer(project); serializer.Deserialize(filepath)) + { + project->GetSpecification().ProjectDirectory = filepath.parent_path(); + s_ActiveProject = project; - const auto assetManager = CreateRef(); - s_ActiveProject->m_AssetManager = assetManager; - assetManager->DeserializeAssetRegistry(); + const auto assetManager = CreateRef(); + s_ActiveProject->m_AssetManager = assetManager; + assetManager->DeserializeAssetRegistry(); - return s_ActiveProject; - } + return s_ActiveProject; + } - return nullptr; - } + return nullptr; + } - bool Project::SaveActive() - { - EPPO_PROFILE_FUNCTION("Project::SaveActive"); + bool Project::SaveActive() + { + EPPO_PROFILE_FUNCTION("Project::SaveActive"); - // Serialize every scene - const auto& registry = s_ActiveProject->GetAssetManagerEditor()->GetAssetRegistry(); + // Serialize every scene + for (const auto& registry = s_ActiveProject->GetAssetManagerEditor()->GetAssetRegistry(); const auto& [handle, metadata] : + registry) + { + if (metadata.Type != AssetType::Scene) + continue; - for (const auto& [handle, metadata] : registry) - { - if (metadata.Type != AssetType::Scene) - continue; + Ref scene = AssetManager::GetAsset(handle); - Ref scene = AssetManager::GetAsset(handle); + SceneSerializer serializer(scene); + serializer.Serialize(GetAssetFilepath(metadata.Filepath)); + } - SceneSerializer serializer(scene); - serializer.Serialize(GetAssetFilepath(metadata.Filepath)); - } + s_ActiveProject->GetAssetManagerEditor()->SerializeAssetRegistry(); - s_ActiveProject->GetAssetManagerEditor()->SerializeAssetRegistry(); - - const ProjectSerializer serializer(s_ActiveProject); - return serializer.Serialize(); - } + const ProjectSerializer serializer(s_ActiveProject); + return serializer.Serialize(); + } } diff --git a/EppoEngine/Source/Project/Project.h b/EppoEngine/Source/Project/Project.h index f2403549..2b3f4113 100644 --- a/EppoEngine/Source/Project/Project.h +++ b/EppoEngine/Source/Project/Project.h @@ -4,40 +4,44 @@ namespace Eppo { - struct ProjectSpecification - { - std::string Name = "Untitled"; - - AssetHandle StartScene = 0; - std::filesystem::path ProjectDirectory; - }; - - class Project - { - public: - ProjectSpecification& GetSpecification() { return m_Specification; } - [[nodiscard]] Ref GetAssetManager() const { return m_AssetManager; } - [[nodiscard]] Ref GetAssetManagerEditor() const { return std::static_pointer_cast(m_AssetManager); } - - static const std::filesystem::path& GetProjectDirectory(); - static std::filesystem::path GetProjectsDirectory(); - static std::filesystem::path GetProjectFile(); - static std::filesystem::path GetAssetsDirectory(); - static std::filesystem::path GetAssetFilepath(const std::filesystem::path& filepath); - static std::filesystem::path GetAssetRelativeFilepath(const std::filesystem::path& filepath); - - static Ref GetActive() { return s_ActiveProject; } - static void SetActive(const Ref& project) { s_ActiveProject = project; } - - static Ref New(); - static Ref New(const ProjectSpecification& specification); - static Ref Open(const std::filesystem::path& filepath); - static bool SaveActive(); - - private: - ProjectSpecification m_Specification; - Ref m_AssetManager; - - inline static Ref s_ActiveProject; - }; + struct ProjectSpecification + { + std::string Name = "Untitled"; + + AssetHandle StartScene = 0; + std::filesystem::path ProjectDirectory; + }; + + class Project + { + public: + ProjectSpecification& GetSpecification() { return m_Specification; } + [[nodiscard]] Ref GetAssetManager() const { return m_AssetManager; } + + [[nodiscard]] Ref GetAssetManagerEditor() const + { + return std::static_pointer_cast(m_AssetManager); + } + + static const std::filesystem::path& GetProjectDirectory(); + static std::filesystem::path GetProjectsDirectory(); + static std::filesystem::path GetProjectFile(); + static std::filesystem::path GetAssetsDirectory(); + static std::filesystem::path GetAssetFilepath(const std::filesystem::path& filepath); + static std::filesystem::path GetAssetRelativeFilepath(const std::filesystem::path& filepath); + + static Ref GetActive() { return s_ActiveProject; } + static void SetActive(const Ref& project) { s_ActiveProject = project; } + + static Ref New(); + static Ref New(const ProjectSpecification& specification); + static Ref Open(const std::filesystem::path& filepath); + static bool SaveActive(); + + private: + ProjectSpecification m_Specification; + Ref m_AssetManager; + + inline static Ref s_ActiveProject; + }; } diff --git a/EppoEngine/Source/Project/ProjectSerializer.cpp b/EppoEngine/Source/Project/ProjectSerializer.cpp index 18ec1ed3..d89e6ddb 100644 --- a/EppoEngine/Source/Project/ProjectSerializer.cpp +++ b/EppoEngine/Source/Project/ProjectSerializer.cpp @@ -5,65 +5,66 @@ namespace Eppo { - ProjectSerializer::ProjectSerializer(const Ref& project) - : m_Project(project) - {} + ProjectSerializer::ProjectSerializer(const Ref& project) + : m_Project(project) + {} - bool ProjectSerializer::Serialize() const - { - EPPO_PROFILE_FUNCTION("ProjectSerializer::Serialize"); + bool ProjectSerializer::Serialize() const + { + EPPO_PROFILE_FUNCTION("ProjectSerializer::Serialize"); - const auto& spec = m_Project->GetSpecification(); + const auto& spec = m_Project->GetSpecification(); - YAML::Emitter out; + YAML::Emitter out; - out << YAML::BeginMap; - out << YAML::Key << "Project" << YAML::Value; + out << YAML::BeginMap; + out << YAML::Key << "Project" << YAML::Value; - out << YAML::BeginMap; - out << YAML::Key << "Name" << YAML::Value << spec.Name; - out << YAML::Key << "ProjectDirectory" << YAML::Value << spec.ProjectDirectory.string(); - out << YAML::Key << "StartScene" << YAML::Value << spec.StartScene; - out << YAML::EndMap; + out << YAML::BeginMap; + out << YAML::Key << "Name" << YAML::Value << spec.Name; + out << YAML::Key << "ProjectDirectory" << YAML::Value << spec.ProjectDirectory.string(); + out << YAML::Key << "StartScene" << YAML::Value << spec.StartScene; + out << YAML::EndMap; - out << YAML::EndMap; + out << YAML::EndMap; - std::ofstream fout(spec.ProjectDirectory / std::filesystem::path(spec.Name + ".epproj")); - fout << out.c_str(); + std::ofstream fout(spec.ProjectDirectory / std::filesystem::path(spec.Name + ".epproj")); + fout << out.c_str(); - return true; - } + return true; + } - bool ProjectSerializer::Deserialize(const std::filesystem::path& filepath) const - { - EPPO_PROFILE_FUNCTION("ProjectSerializer::Deserialize"); + bool ProjectSerializer::Deserialize(const std::filesystem::path& filepath) const + { + EPPO_PROFILE_FUNCTION("ProjectSerializer::Deserialize"); - auto& spec = m_Project->GetSpecification(); + auto& spec = m_Project->GetSpecification(); - YAML::Node data; + YAML::Node data; - try - { - data = YAML::LoadFile(filepath.string()); - } catch (YAML::ParserException& e) - { - EPPO_ERROR("Failed to load project file '{}'!\nError: {}", filepath, e.what()); - return false; - } + try + { + data = YAML::LoadFile(filepath.string()); + } + catch (YAML::ParserException& e) + { + EPPO_ERROR("Failed to load project file '{}'!\nError: {}", filepath, e.what()); + return false; + } - auto projectNode = data["Project"]; - if (!projectNode) - return false; + auto projectNode = data["Project"]; + if (!projectNode) + return false; - spec.Name = projectNode["Name"].as(); - EPPO_INFO("Deserializing project '{}'", spec.Name); + spec.Name = projectNode["Name"].as(); + EPPO_INFO("Deserializing project '{}'", spec.Name); - if (projectNode["ProjectDirectory"]) - spec.ProjectDirectory = std::filesystem::path(projectNode["ProjectDirectory"].as()); + if (projectNode["ProjectDirectory"]) + spec.ProjectDirectory = std::filesystem::path(projectNode["ProjectDirectory"].as()); - if (projectNode["StartScene"]) - spec.StartScene = projectNode["StartScene"].as(); + if (projectNode["StartScene"]) + spec.StartScene = projectNode["StartScene"].as(); - return true; - } + return true; + } } diff --git a/EppoEngine/Source/Project/ProjectSerializer.h b/EppoEngine/Source/Project/ProjectSerializer.h index 353d6d2f..16cc3dc6 100644 --- a/EppoEngine/Source/Project/ProjectSerializer.h +++ b/EppoEngine/Source/Project/ProjectSerializer.h @@ -4,15 +4,15 @@ namespace Eppo { - class ProjectSerializer - { - public: - explicit ProjectSerializer(const Ref& project); + class ProjectSerializer + { + public: + explicit ProjectSerializer(const Ref& project); - [[nodiscard]] bool Serialize() const; - [[nodiscard]] bool Deserialize(const std::filesystem::path& filepath) const; + [[nodiscard]] bool Serialize() const; + [[nodiscard]] bool Deserialize(const std::filesystem::path& filepath) const; - private: - Ref m_Project; - }; + private: + Ref m_Project; + }; } diff --git a/EppoEngine/Source/Renderer/Camera/Camera.h b/EppoEngine/Source/Renderer/Camera/Camera.h index 7e28ce81..b8a4032c 100644 --- a/EppoEngine/Source/Renderer/Camera/Camera.h +++ b/EppoEngine/Source/Renderer/Camera/Camera.h @@ -4,19 +4,20 @@ namespace Eppo { - class Camera - { - public: - Camera() = default; - explicit Camera(const glm::mat4& projectionMatrix) - : m_ProjectionMatrix(projectionMatrix) - {} + class Camera + { + public: + Camera() = default; - virtual ~Camera() = default; + explicit Camera(const glm::mat4& projectionMatrix) + : m_ProjectionMatrix(projectionMatrix) + {} - [[nodiscard]] const glm::mat4& GetProjectionMatrix() const { return m_ProjectionMatrix; } + virtual ~Camera() = default; - protected: - glm::mat4 m_ProjectionMatrix; - }; + [[nodiscard]] const glm::mat4& GetProjectionMatrix() const { return m_ProjectionMatrix; } + + protected: + glm::mat4 m_ProjectionMatrix; + }; } diff --git a/EppoEngine/Source/Renderer/Camera/EditorCamera.cpp b/EppoEngine/Source/Renderer/Camera/EditorCamera.cpp index d118c61a..19c096ac 100644 --- a/EppoEngine/Source/Renderer/Camera/EditorCamera.cpp +++ b/EppoEngine/Source/Renderer/Camera/EditorCamera.cpp @@ -8,79 +8,79 @@ namespace Eppo { - EditorCamera::EditorCamera() - { - UpdateCameraVectors(); - } - - EditorCamera::EditorCamera(const glm::vec3& position, float pitch, float yaw) - : m_Position(position), m_Pitch(pitch), m_Yaw(yaw) - { - UpdateCameraVectors(); - } - - void EditorCamera::OnUpdate(const float timestep) - { - EPPO_PROFILE_FUNCTION("EditorCamera::OnUpdate"); - - float velocity = m_MovementSpeed * timestep; - - if (Input::IsKeyPressed(Key::LeftShift) || Input::IsKeyPressed(Key::RightShift)) - velocity *= 3.0f; - - if (Input::IsKeyPressed(Key::W)) - m_Position += m_FrontDirection * velocity; - if (Input::IsKeyPressed(Key::S)) - m_Position -= m_FrontDirection * velocity; - if (Input::IsKeyPressed(Key::A)) - m_Position -= m_RightDirection * velocity; - if (Input::IsKeyPressed(Key::D)) - m_Position += m_RightDirection * velocity; - - if (Input::IsKeyPressed(Key::Q)) - m_Yaw -= velocity * 2.0f; - if (Input::IsKeyPressed(Key::E)) - m_Yaw += velocity * 2.0f; - - if (Input::IsKeyPressed(Key::R)) - m_Pitch += velocity * 2.0f; - if (Input::IsKeyPressed(Key::F)) - m_Pitch -= velocity * 2.0f; - - UpdateCameraVectors(); - } - - void EditorCamera::OnEvent(Event& e) - { - EPPO_PROFILE_FUNCTION("EditorCamera::OnEvent"); - - EventDispatcher dispatcher(e); - //dispatcher.Dispatch(BIND_EVENT_FN(EditorCamera::OnMouseScroll)); - } - - void EditorCamera::SetViewportSize(const glm::vec2& size) - { - if (m_ViewportSize == size) - return; - - m_ViewportSize = size; - } - - void EditorCamera::UpdateCameraVectors() - { - EPPO_PROFILE_FUNCTION("EditorCamera::UpdateCameraVectors"); - - const auto front = glm::vec3( - cos(glm::radians(m_Yaw)) * cos(glm::radians(m_Pitch)), - sin(glm::radians(m_Pitch)), - sin(glm::radians(m_Yaw)) * cos(glm::radians(m_Pitch)) - ); - - m_FrontDirection = glm::normalize(front); - m_RightDirection = glm::normalize(glm::cross(m_FrontDirection, m_WorldUpDirection)); - m_UpDirection = glm::normalize(glm::cross(m_RightDirection, m_FrontDirection)); - - m_ViewMatrix = glm::lookAt(m_Position, m_Position + m_FrontDirection, m_UpDirection); - m_ProjectionMatrix = glm::perspective(glm::radians(m_Zoom), m_ViewportSize.x / m_ViewportSize.y, 0.1f, 100.0f); - } + EditorCamera::EditorCamera() + { + UpdateCameraVectors(); + } + + EditorCamera::EditorCamera(const glm::vec3& position, float pitch, float yaw) + : m_Position(position), m_Pitch(pitch), m_Yaw(yaw) + { + UpdateCameraVectors(); + } + + void EditorCamera::OnUpdate(const float timestep) + { + EPPO_PROFILE_FUNCTION("EditorCamera::OnUpdate"); + + float velocity = m_MovementSpeed * timestep; + + if (Input::IsKeyPressed(Key::LeftShift) || Input::IsKeyPressed(Key::RightShift)) + velocity *= 3.0f; + + if (Input::IsKeyPressed(Key::W)) + m_Position += m_FrontDirection * velocity; + if (Input::IsKeyPressed(Key::S)) + m_Position -= m_FrontDirection * velocity; + if (Input::IsKeyPressed(Key::A)) + m_Position -= m_RightDirection * velocity; + if (Input::IsKeyPressed(Key::D)) + m_Position += m_RightDirection * velocity; + + if (Input::IsKeyPressed(Key::Q)) + m_Yaw -= velocity * 2.0f; + if (Input::IsKeyPressed(Key::E)) + m_Yaw += velocity * 2.0f; + + if (Input::IsKeyPressed(Key::R)) + m_Pitch += velocity * 2.0f; + if (Input::IsKeyPressed(Key::F)) + m_Pitch -= velocity * 2.0f; + + UpdateCameraVectors(); + } + + void EditorCamera::OnEvent(Event& e) + { + EPPO_PROFILE_FUNCTION("EditorCamera::OnEvent"); + + EventDispatcher dispatcher(e); + //dispatcher.Dispatch(BIND_EVENT_FN(EditorCamera::OnMouseScroll)); + } + + void EditorCamera::SetViewportSize(const glm::vec2& size) + { + if (m_ViewportSize == size) + return; + + m_ViewportSize = size; + } + + void EditorCamera::UpdateCameraVectors() + { + EPPO_PROFILE_FUNCTION("EditorCamera::UpdateCameraVectors"); + + const auto front = glm::vec3( + cos(glm::radians(m_Yaw)) * cos(glm::radians(m_Pitch)), + sin(glm::radians(m_Pitch)), + sin(glm::radians(m_Yaw)) * cos(glm::radians(m_Pitch)) + ); + + m_FrontDirection = glm::normalize(front); + m_RightDirection = glm::normalize(glm::cross(m_FrontDirection, m_WorldUpDirection)); + m_UpDirection = glm::normalize(glm::cross(m_RightDirection, m_FrontDirection)); + + m_ViewMatrix = glm::lookAt(m_Position, m_Position + m_FrontDirection, m_UpDirection); + m_ProjectionMatrix = glm::perspective(glm::radians(m_Zoom), m_ViewportSize.x / m_ViewportSize.y, 0.1f, 100.0f); + } } diff --git a/EppoEngine/Source/Renderer/Camera/EditorCamera.h b/EppoEngine/Source/Renderer/Camera/EditorCamera.h index 384d1efd..41b80cd5 100644 --- a/EppoEngine/Source/Renderer/Camera/EditorCamera.h +++ b/EppoEngine/Source/Renderer/Camera/EditorCamera.h @@ -5,45 +5,49 @@ namespace Eppo { - class EditorCamera : public Camera - { - public: - EditorCamera(); - explicit EditorCamera(const glm::vec3& position, float pitch = 0.0f, float yaw = 0.0f); - ~EditorCamera() override = default; - - void OnUpdate(float timestep); - void OnEvent(Event& e); - - void SetViewportSize(const glm::vec2& size); - - [[nodiscard]] glm::vec3 GetPosition() const { return m_Position; } - [[nodiscard]] float GetPitch() const { return m_Pitch; } - [[nodiscard]] float GetYaw() const { return m_Yaw; } - - [[nodiscard]] const glm::mat4& GetViewMatrix() const { return m_ViewMatrix; } - [[nodiscard]] glm::mat4 GetViewProjectionMatrix() const { return m_ProjectionMatrix * m_ViewMatrix; } - - private: - // Update matrixes - void UpdateCameraVectors(); - - private: - glm::mat4 m_ViewMatrix; - - glm::vec3 m_Position = glm::vec3(0.0f); - glm::vec3 m_FrontDirection = glm::vec3(0.0f, 0.0f, -1.0f); - glm::vec3 m_UpDirection; - glm::vec3 m_RightDirection; - glm::vec3 m_WorldUpDirection = glm::vec3(0.0f, 1.0f, 0.0f); - - float m_Pitch = 0.0f; - float m_Yaw = 0.0f; - - float m_MovementSpeed = 3.0f; - float m_MouseSensitivity = 0.1f; - float m_Zoom = 45.0f; - - glm::vec2 m_ViewportSize = { 1280.0f, 720.0f }; - }; + class EditorCamera final : public Camera + { + public: + EditorCamera(); + EditorCamera(const EditorCamera&) = delete; + EditorCamera(const EditorCamera&&) = delete; + EditorCamera& operator=(const EditorCamera&) = delete; + EditorCamera& operator=(const EditorCamera&&) = delete; + explicit EditorCamera(const glm::vec3& position, float pitch = 0.0f, float yaw = 0.0f); + ~EditorCamera() override = default; + + void OnUpdate(float timestep); + void OnEvent(Event& e); + + void SetViewportSize(const glm::vec2& size); + + [[nodiscard]] glm::vec3 GetPosition() const { return m_Position; } + [[nodiscard]] float GetPitch() const { return m_Pitch; } + [[nodiscard]] float GetYaw() const { return m_Yaw; } + + [[nodiscard]] const glm::mat4& GetViewMatrix() const { return m_ViewMatrix; } + [[nodiscard]] glm::mat4 GetViewProjectionMatrix() const { return m_ProjectionMatrix * m_ViewMatrix; } + + private: + // Update matrixes + void UpdateCameraVectors(); + + private: + glm::mat4 m_ViewMatrix; + + glm::vec3 m_Position = glm::vec3(0.0f); + glm::vec3 m_FrontDirection = glm::vec3(0.0f, 0.0f, -1.0f); + glm::vec3 m_UpDirection; + glm::vec3 m_RightDirection; + glm::vec3 m_WorldUpDirection = glm::vec3(0.0f, 1.0f, 0.0f); + + float m_Pitch = 0.0f; + float m_Yaw = 0.0f; + + float m_MovementSpeed = 3.0f; + float m_MouseSensitivity = 0.1f; + float m_Zoom = 45.0f; + + glm::vec2 m_ViewportSize = { 1280.0f, 720.0f }; + }; } diff --git a/EppoEngine/Source/Renderer/Camera/SceneCamera.cpp b/EppoEngine/Source/Renderer/Camera/SceneCamera.cpp index 6a2bbece..23f74acd 100644 --- a/EppoEngine/Source/Renderer/Camera/SceneCamera.cpp +++ b/EppoEngine/Source/Renderer/Camera/SceneCamera.cpp @@ -3,124 +3,126 @@ namespace Eppo { - SceneCamera::SceneCamera() - { - RecalculateProjection(); - } + SceneCamera::SceneCamera() + { + RecalculateProjection(); + } - void SceneCamera::SetPerspective(const float fov, const float nearClip, const float farClip) - { - EPPO_PROFILE_FUNCTION("SceneCamera::SetPerspective"); + void SceneCamera::SetPerspective(const float fov, const float nearClip, const float farClip) + { + EPPO_PROFILE_FUNCTION("SceneCamera::SetPerspective"); - m_ProjectionType = ProjectionType::Perspective; + m_ProjectionType = ProjectionType::Perspective; - m_PerspectiveFov = fov; - m_PerspectiveNearClip = nearClip; - m_PerspectiveFarClip = farClip; + m_PerspectiveFov = fov; + m_PerspectiveNearClip = nearClip; + m_PerspectiveFarClip = farClip; - RecalculateProjection(); - } + RecalculateProjection(); + } - void SceneCamera::SetOrthographic(const float size, const float nearClip, const float farClip) - { - EPPO_PROFILE_FUNCTION("SceneCamera::SetOrthographic"); + void SceneCamera::SetOrthographic(const float size, const float nearClip, const float farClip) + { + EPPO_PROFILE_FUNCTION("SceneCamera::SetOrthographic"); - m_ProjectionType = ProjectionType::Orthographic; + m_ProjectionType = ProjectionType::Orthographic; - m_OrthographicSize = size; - m_OrthographicNearClip = nearClip; - m_OrthographicFarClip = farClip; + m_OrthographicSize = size; + m_OrthographicNearClip = nearClip; + m_OrthographicFarClip = farClip; - RecalculateProjection(); - } + RecalculateProjection(); + } - void SceneCamera::SetViewportSize(const uint32_t width, const uint32_t height) - { - EPPO_PROFILE_FUNCTION("SceneCamera::SetViewportSize"); + void SceneCamera::SetViewportSize(const uint32_t width, const uint32_t height) + { + EPPO_PROFILE_FUNCTION("SceneCamera::SetViewportSize"); - SetViewportSize(static_cast(width), static_cast(height)); - } + SetViewportSize(static_cast(width), static_cast(height)); + } - void SceneCamera::SetViewportSize(const float width, const float height) - { - EPPO_PROFILE_FUNCTION("SceneCamera::SetViewportSize"); + void SceneCamera::SetViewportSize(const float width, const float height) + { + EPPO_PROFILE_FUNCTION("SceneCamera::SetViewportSize"); EPPO_ASSERT(width > 0 && height > 0); - m_AspectRatio = width / height; - RecalculateProjection(); - } - - void SceneCamera::SetPerspectiveFov(const float fov) - { - EPPO_PROFILE_FUNCTION("SceneCamera::SetPerspectiveFov"); - - m_PerspectiveFov = fov; - RecalculateProjection(); - } - - void SceneCamera::SetPerspectiveNearClip(const float nearClip) - { - EPPO_PROFILE_FUNCTION("SceneCamera::SetPerspectiveNearClip"); - - m_PerspectiveNearClip = nearClip; - RecalculateProjection(); - } - - void SceneCamera::SetPerspectiveFarClip(const float farClip) - { - EPPO_PROFILE_FUNCTION("SceneCamera::SetPerspectiveFarClip"); - - m_PerspectiveFarClip = farClip; - RecalculateProjection(); - } - - void SceneCamera::SetOrthographicSize(const float size) - { - EPPO_PROFILE_FUNCTION("SceneCamera::SetOrthographicSize"); - - m_OrthographicSize = size; - RecalculateProjection(); - } - - void SceneCamera::SetOrthographicNearClip(const float nearClip) - { - EPPO_PROFILE_FUNCTION("SceneCamera::SetOrthographicNearClip"); - - m_OrthographicNearClip = nearClip; - RecalculateProjection(); - } - - void SceneCamera::SetOrthographicFarClip(const float farClip) - { - EPPO_PROFILE_FUNCTION("SceneCamera::SetOrthographicFarClip"); - - m_OrthographicFarClip = farClip; - RecalculateProjection(); - } - - void SceneCamera::SetProjectionType(const ProjectionType type) - { - EPPO_PROFILE_FUNCTION("SceneCamera::SetProjectionType"); - - m_ProjectionType = type; - RecalculateProjection(); - } - - void SceneCamera::RecalculateProjection() - { - EPPO_PROFILE_FUNCTION("SceneCamera::RecalculateProjection"); - - if (m_ProjectionType == ProjectionType::Perspective) - { - m_ProjectionMatrix = glm::perspective(m_PerspectiveFov, m_AspectRatio, m_PerspectiveNearClip, m_PerspectiveFarClip); - } else if (m_ProjectionType == ProjectionType::Orthographic) - { - const float left = -m_OrthographicSize * m_AspectRatio * 0.5f; - const float right = m_OrthographicSize * m_AspectRatio * 0.5f; - const float bottom = -m_OrthographicSize * 0.5f; - const float top = m_OrthographicSize * 0.5f; - - m_ProjectionMatrix = glm::ortho(left, right, bottom, top, m_OrthographicNearClip, m_OrthographicFarClip); - } - } + m_AspectRatio = width / height; + RecalculateProjection(); + } + + void SceneCamera::SetPerspectiveFov(const float fov) + { + EPPO_PROFILE_FUNCTION("SceneCamera::SetPerspectiveFov"); + + m_PerspectiveFov = fov; + RecalculateProjection(); + } + + void SceneCamera::SetPerspectiveNearClip(const float nearClip) + { + EPPO_PROFILE_FUNCTION("SceneCamera::SetPerspectiveNearClip"); + + m_PerspectiveNearClip = nearClip; + RecalculateProjection(); + } + + void SceneCamera::SetPerspectiveFarClip(const float farClip) + { + EPPO_PROFILE_FUNCTION("SceneCamera::SetPerspectiveFarClip"); + + m_PerspectiveFarClip = farClip; + RecalculateProjection(); + } + + void SceneCamera::SetOrthographicSize(const float size) + { + EPPO_PROFILE_FUNCTION("SceneCamera::SetOrthographicSize"); + + m_OrthographicSize = size; + RecalculateProjection(); + } + + void SceneCamera::SetOrthographicNearClip(const float nearClip) + { + EPPO_PROFILE_FUNCTION("SceneCamera::SetOrthographicNearClip"); + + m_OrthographicNearClip = nearClip; + RecalculateProjection(); + } + + void SceneCamera::SetOrthographicFarClip(const float farClip) + { + EPPO_PROFILE_FUNCTION("SceneCamera::SetOrthographicFarClip"); + + m_OrthographicFarClip = farClip; + RecalculateProjection(); + } + + void SceneCamera::SetProjectionType(const ProjectionType type) + { + EPPO_PROFILE_FUNCTION("SceneCamera::SetProjectionType"); + + m_ProjectionType = type; + RecalculateProjection(); + } + + void SceneCamera::RecalculateProjection() + { + EPPO_PROFILE_FUNCTION("SceneCamera::RecalculateProjection"); + + if (m_ProjectionType == ProjectionType::Perspective) + { + m_ProjectionMatrix = glm::perspective(m_PerspectiveFov, m_AspectRatio, m_PerspectiveNearClip, + m_PerspectiveFarClip); + } + else if (m_ProjectionType == ProjectionType::Orthographic) + { + const float left = -m_OrthographicSize * m_AspectRatio * 0.5f; + const float right = m_OrthographicSize * m_AspectRatio * 0.5f; + const float bottom = -m_OrthographicSize * 0.5f; + const float top = m_OrthographicSize * 0.5f; + + m_ProjectionMatrix = glm::ortho(left, right, bottom, top, m_OrthographicNearClip, m_OrthographicFarClip); + } + } } diff --git a/EppoEngine/Source/Renderer/Camera/SceneCamera.h b/EppoEngine/Source/Renderer/Camera/SceneCamera.h index 0db42292..93f34943 100644 --- a/EppoEngine/Source/Renderer/Camera/SceneCamera.h +++ b/EppoEngine/Source/Renderer/Camera/SceneCamera.h @@ -4,59 +4,59 @@ namespace Eppo { - enum class ProjectionType : uint8_t - { - Orthographic, - Perspective - }; + enum class ProjectionType : uint8_t + { + Orthographic, + Perspective + }; - class SceneCamera : public Camera - { - public: - SceneCamera(); - ~SceneCamera() override = default; + class SceneCamera final : public Camera + { + public: + SceneCamera(); + ~SceneCamera() override = default; - void SetPerspective(float fov, float nearClip, float farClip); - void SetOrthographic(float size, float nearClip, float farClip); + void SetPerspective(float fov, float nearClip, float farClip); + void SetOrthographic(float size, float nearClip, float farClip); - void SetViewportSize(uint32_t width, uint32_t height); - void SetViewportSize(float width, float height); + void SetViewportSize(uint32_t width, uint32_t height); + void SetViewportSize(float width, float height); - [[nodiscard]] float GetPerspectiveFov() const { return m_PerspectiveFov; } - void SetPerspectiveFov(float fov); + [[nodiscard]] float GetPerspectiveFov() const { return m_PerspectiveFov; } + void SetPerspectiveFov(float fov); - [[nodiscard]] float GetPerspectiveNearClip() const { return m_PerspectiveNearClip; } - void SetPerspectiveNearClip(float nearClip); + [[nodiscard]] float GetPerspectiveNearClip() const { return m_PerspectiveNearClip; } + void SetPerspectiveNearClip(float nearClip); - [[nodiscard]] float GetPerspectiveFarClip() const { return m_PerspectiveFarClip; } - void SetPerspectiveFarClip(float farClip); + [[nodiscard]] float GetPerspectiveFarClip() const { return m_PerspectiveFarClip; } + void SetPerspectiveFarClip(float farClip); - [[nodiscard]] float GetOrthographicSize() const { return m_OrthographicSize; } - void SetOrthographicSize(float size); + [[nodiscard]] float GetOrthographicSize() const { return m_OrthographicSize; } + void SetOrthographicSize(float size); - [[nodiscard]] float GetOrthographicNearClip() const { return m_OrthographicNearClip; } - void SetOrthographicNearClip(float nearClip); + [[nodiscard]] float GetOrthographicNearClip() const { return m_OrthographicNearClip; } + void SetOrthographicNearClip(float nearClip); - [[nodiscard]] float GetOrthographicFarClip() const { return m_OrthographicFarClip; } - void SetOrthographicFarClip(float farClip); + [[nodiscard]] float GetOrthographicFarClip() const { return m_OrthographicFarClip; } + void SetOrthographicFarClip(float farClip); - [[nodiscard]] ProjectionType GetProjectionType() const { return m_ProjectionType; } - void SetProjectionType(ProjectionType type); + [[nodiscard]] ProjectionType GetProjectionType() const { return m_ProjectionType; } + void SetProjectionType(ProjectionType type); - private: - void RecalculateProjection(); + private: + void RecalculateProjection(); - private: - ProjectionType m_ProjectionType = ProjectionType::Orthographic; + private: + ProjectionType m_ProjectionType = ProjectionType::Orthographic; - float m_PerspectiveFov = glm::radians(45.0f); - float m_PerspectiveNearClip = 0.01f; - float m_PerspectiveFarClip = 1000.0f; + float m_PerspectiveFov = glm::radians(45.0f); + float m_PerspectiveNearClip = 0.01f; + float m_PerspectiveFarClip = 1000.0f; - float m_OrthographicSize = 10.0f; - float m_OrthographicNearClip = -1.0f; - float m_OrthographicFarClip = 1.0f; + float m_OrthographicSize = 10.0f; + float m_OrthographicNearClip = -1.0f; + float m_OrthographicFarClip = 1.0f; - float m_AspectRatio = 0.0f; - }; + float m_AspectRatio = 0.0f; + }; } diff --git a/EppoEngine/Source/Renderer/CommandBuffer.cpp b/EppoEngine/Source/Renderer/CommandBuffer.cpp index 78080b92..e5e92dc0 100644 --- a/EppoEngine/Source/Renderer/CommandBuffer.cpp +++ b/EppoEngine/Source/Renderer/CommandBuffer.cpp @@ -6,14 +6,15 @@ namespace Eppo { - Ref CommandBuffer::Create(bool manualSubmission, uint32_t count) - { - switch (RendererContext::GetAPI()) - { - case RendererAPI::Vulkan: return CreateRef(manualSubmission, count); - } + Ref CommandBuffer::Create(bool manualSubmission, uint32_t count) + { + switch (RendererContext::GetAPI()) + { + case RendererAPI::Vulkan: + return CreateRef(manualSubmission, count); + } - EPPO_ASSERT(false); - return nullptr; - } + EPPO_ASSERT(false); + return nullptr; + } } diff --git a/EppoEngine/Source/Renderer/CommandBuffer.h b/EppoEngine/Source/Renderer/CommandBuffer.h index ba667076..77efe587 100644 --- a/EppoEngine/Source/Renderer/CommandBuffer.h +++ b/EppoEngine/Source/Renderer/CommandBuffer.h @@ -2,15 +2,15 @@ namespace Eppo { - class CommandBuffer - { - public: - virtual ~CommandBuffer() = default; + class CommandBuffer + { + public: + virtual ~CommandBuffer() = default; - virtual void RT_Begin() = 0; - virtual void RT_End() = 0; - virtual void RT_Submit() const = 0; + virtual void RT_Begin() = 0; + virtual void RT_End() = 0; + virtual void RT_Submit() const = 0; - static Ref Create(bool manualSubmission = true, uint32_t count = 0); - }; + static Ref Create(bool manualSubmission = true, uint32_t count = 0); + }; } diff --git a/EppoEngine/Source/Renderer/CommandQueue.cpp b/EppoEngine/Source/Renderer/CommandQueue.cpp index 4f626653..ae4df37f 100644 --- a/EppoEngine/Source/Renderer/CommandQueue.cpp +++ b/EppoEngine/Source/Renderer/CommandQueue.cpp @@ -3,28 +3,28 @@ namespace Eppo { - CommandQueue::CommandQueue(const bool isMultiThreaded) - : m_IsMultiThreaded(isMultiThreaded) - {} + CommandQueue::CommandQueue(const bool isMultiThreaded) + : m_IsMultiThreaded(isMultiThreaded) + {} - void CommandQueue::AddCommand(RenderCommand fn) - { - EPPO_PROFILE_FUNCTION("RenderCommandQueue::AddCommand"); + void CommandQueue::AddCommand(RenderCommand fn) + { + EPPO_PROFILE_FUNCTION("RenderCommandQueue::AddCommand"); - m_CommandQueue.push(std::move(fn)); - m_CommandCount++; - } + m_CommandQueue.push(std::move(fn)); + m_CommandCount++; + } - void CommandQueue::Execute() - { - EPPO_PROFILE_FUNCTION("RenderCommandQueue::Execute"); + void CommandQueue::Execute() + { + EPPO_PROFILE_FUNCTION("RenderCommandQueue::Execute"); - for (uint32_t i = 0; i < m_CommandCount; i++) - { - m_CommandQueue.front()(); - m_CommandQueue.pop(); - } + for (uint32_t i = 0; i < m_CommandCount; i++) + { + m_CommandQueue.front()(); + m_CommandQueue.pop(); + } - m_CommandCount = 0; - } + m_CommandCount = 0; + } } diff --git a/EppoEngine/Source/Renderer/CommandQueue.h b/EppoEngine/Source/Renderer/CommandQueue.h index 91500ed1..1b040b80 100644 --- a/EppoEngine/Source/Renderer/CommandQueue.h +++ b/EppoEngine/Source/Renderer/CommandQueue.h @@ -4,22 +4,22 @@ namespace Eppo { - using RenderCommand = std::function; + using RenderCommand = std::function; - class CommandQueue - { - public: - explicit CommandQueue(bool isMultiThreaded = false); - ~CommandQueue() = default; + class CommandQueue + { + public: + explicit CommandQueue(bool isMultiThreaded = false); + ~CommandQueue() = default; - void AddCommand(RenderCommand fn); - void Execute(); + void AddCommand(RenderCommand fn); + void Execute(); - private: - std::queue m_CommandQueue; - uint32_t m_CommandCount = 0; + private: + std::queue m_CommandQueue; + uint32_t m_CommandCount = 0; - bool m_IsMultiThreaded; - std::mutex m_Mutex; - }; + bool m_IsMultiThreaded; + std::mutex m_Mutex; + }; } diff --git a/EppoEngine/Source/Renderer/DebugRenderer.cpp b/EppoEngine/Source/Renderer/DebugRenderer.cpp index 4bc7b6a7..de94ee2e 100644 --- a/EppoEngine/Source/Renderer/DebugRenderer.cpp +++ b/EppoEngine/Source/Renderer/DebugRenderer.cpp @@ -6,14 +6,15 @@ namespace Eppo { - Ref DebugRenderer::Create() - { - switch (RendererContext::GetAPI()) - { - case RendererAPI::Vulkan: return CreateRef(); - } + Ref DebugRenderer::Create() + { + switch (RendererContext::GetAPI()) + { + case RendererAPI::Vulkan: + return CreateRef(); + } - EPPO_ASSERT(false); - return nullptr; - } + EPPO_ASSERT(false); + return nullptr; + } } diff --git a/EppoEngine/Source/Renderer/DebugRenderer.h b/EppoEngine/Source/Renderer/DebugRenderer.h index 0c3ef882..8199c532 100644 --- a/EppoEngine/Source/Renderer/DebugRenderer.h +++ b/EppoEngine/Source/Renderer/DebugRenderer.h @@ -4,14 +4,14 @@ namespace Eppo { - class DebugRenderer - { - public: - virtual ~DebugRenderer() = default; + class DebugRenderer + { + public: + virtual ~DebugRenderer() = default; - virtual void StartDebugLabel(const Ref& commandBuffer, const std::string& label) = 0; - virtual void EndDebugLabel(const Ref& commandBuffer) = 0; + virtual void StartDebugLabel(const Ref& commandBuffer, const std::string& label) = 0; + virtual void EndDebugLabel(const Ref& commandBuffer) = 0; - static Ref Create(); - }; + static Ref Create(); + }; } diff --git a/EppoEngine/Source/Renderer/DrawCommand.h b/EppoEngine/Source/Renderer/DrawCommand.h index a161ec0c..7e521bd3 100644 --- a/EppoEngine/Source/Renderer/DrawCommand.h +++ b/EppoEngine/Source/Renderer/DrawCommand.h @@ -8,20 +8,20 @@ namespace Eppo { - struct DrawCommand - { - EntityHandle Handle; - }; + struct DrawCommand + { + EntityHandle Handle; + }; - struct MeshCommand : DrawCommand - { - Ref Mesh; - glm::mat4 Transform; - }; + struct MeshCommand : DrawCommand + { + Ref Mesh; + glm::mat4 Transform; + }; - struct PointLightCommand : DrawCommand - { - glm::vec4 Color; - glm::vec3 Position; - }; + struct PointLightCommand : DrawCommand + { + glm::vec4 Color; + glm::vec3 Position; + }; } diff --git a/EppoEngine/Source/Renderer/GarbageCollector.cpp b/EppoEngine/Source/Renderer/GarbageCollector.cpp index 9e56af1b..3168b6ca 100644 --- a/EppoEngine/Source/Renderer/GarbageCollector.cpp +++ b/EppoEngine/Source/Renderer/GarbageCollector.cpp @@ -3,47 +3,47 @@ namespace Eppo { - bool GarbageCollector::s_IsInstantiated = false; + bool GarbageCollector::s_IsInstantiated = false; - GarbageCollector::GarbageCollector() - { + GarbageCollector::GarbageCollector() + { EPPO_ASSERT(!s_IsInstantiated); - s_IsInstantiated = true; - } - - void GarbageCollector::Update(const uint32_t frameNumber) - { - m_CurrentFrameNumber = frameNumber; - - for (auto it = m_FreeFns.begin(); it != m_FreeFns.lower_bound(m_CurrentFrameNumber);) - { - for (const auto& fn : it->second) - fn(); - - it = m_FreeFns.erase(it); - } - } - - void GarbageCollector::SubmitFreeFn(std::function fn, const bool freeOnShutdown) - { - if (freeOnShutdown) - m_FreeFnsOnShutdown.emplace_back(fn); - else - m_FreeFns[m_CurrentFrameNumber + 3].emplace_back(fn); - } - - void GarbageCollector::Shutdown() - { - // First deallocate resources that were dynamic (to be deallocated in frame X) - for (const auto& [frameNumber, fns] : m_FreeFns) - { - // Execute free function - for (const auto& fn : fns) - fn(); - } - - // Secondly deallocate resources that were allocated for the entire lifetime - for (auto it = m_FreeFnsOnShutdown.rbegin(); it != m_FreeFnsOnShutdown.rend(); ++it) - (*it)(); - } + s_IsInstantiated = true; + } + + void GarbageCollector::Update(const uint32_t frameNumber) + { + m_CurrentFrameNumber = frameNumber; + + for (auto it = m_FreeFns.begin(); it != m_FreeFns.lower_bound(m_CurrentFrameNumber);) + { + for (const auto& fn : it->second) + fn(); + + it = m_FreeFns.erase(it); + } + } + + void GarbageCollector::SubmitFreeFn(std::function fn, const bool freeOnShutdown) + { + if (freeOnShutdown) + m_FreeFnsOnShutdown.emplace_back(fn); + else + m_FreeFns[m_CurrentFrameNumber + 3].emplace_back(fn); + } + + void GarbageCollector::Shutdown() + { + // First deallocate resources that were dynamic (to be deallocated in frame X) + for (const auto& [frameNumber, fns] : m_FreeFns) + { + // Execute free function + for (const auto& fn : fns) + fn(); + } + + // Secondly deallocate resources that were allocated for the entire lifetime + for (auto it = m_FreeFnsOnShutdown.rbegin(); it != m_FreeFnsOnShutdown.rend(); ++it) + (*it)(); + } } diff --git a/EppoEngine/Source/Renderer/GarbageCollector.h b/EppoEngine/Source/Renderer/GarbageCollector.h index b8b11fd7..2e2e6cb1 100644 --- a/EppoEngine/Source/Renderer/GarbageCollector.h +++ b/EppoEngine/Source/Renderer/GarbageCollector.h @@ -5,26 +5,26 @@ namespace Eppo { - class GarbageCollector - { - public: - GarbageCollector(); + class GarbageCollector + { + public: + GarbageCollector(); - void Update(uint32_t frameNumber); + void Update(uint32_t frameNumber); - void SubmitFreeFn(std::function fn, bool freeOnShutdown = true); - void Shutdown(); + void SubmitFreeFn(std::function fn, bool freeOnShutdown = true); + void Shutdown(); - private: - uint32_t m_CurrentFrameNumber = 0; + private: + uint32_t m_CurrentFrameNumber = 0; - // Key being the frame number in which it is to be deleted - // uint32_t gives us approximately 19.884 hours at 60 fps before we run out of frame numbers - std::map>> m_FreeFns; + // Key being the frame number in which it is to be deleted + // uint32_t gives us approximately 19.884 hours at 60 fps before we run out of frame numbers + std::map>> m_FreeFns; - // Resources that should only be freed on shutdown - std::deque> m_FreeFnsOnShutdown; + // Resources that should only be freed on shutdown + std::deque> m_FreeFnsOnShutdown; - static bool s_IsInstantiated; - }; + static bool s_IsInstantiated; + }; } diff --git a/EppoEngine/Source/Renderer/Image.cpp b/EppoEngine/Source/Renderer/Image.cpp index cef4866e..84c5be2c 100644 --- a/EppoEngine/Source/Renderer/Image.cpp +++ b/EppoEngine/Source/Renderer/Image.cpp @@ -6,14 +6,15 @@ namespace Eppo { - Ref Image::Create(const ImageSpecification& specification) - { - switch (RendererContext::GetAPI()) - { - case RendererAPI::Vulkan: return CreateRef(specification); - } + Ref Image::Create(const ImageSpecification& specification) + { + switch (RendererContext::GetAPI()) + { + case RendererAPI::Vulkan: + return CreateRef(specification); + } - EPPO_ASSERT(false) - return nullptr; - } + EPPO_ASSERT(false); + return nullptr; + } } diff --git a/EppoEngine/Source/Renderer/Image.h b/EppoEngine/Source/Renderer/Image.h index b3c0e8fe..1b5dd6a8 100644 --- a/EppoEngine/Source/Renderer/Image.h +++ b/EppoEngine/Source/Renderer/Image.h @@ -2,62 +2,63 @@ namespace Eppo { - enum class ImageFormat - { - None = 0, - - // Color - RGB16, - RGBA8, - - // Depth - Depth - }; - - enum class ImageUsage - { - Texture, - Attachment - }; - - struct ImageSpecification - { - uint32_t Width = 0; - uint32_t Height = 0; - - ImageFormat Format = ImageFormat::None; - ImageUsage Usage; - - std::filesystem::path Filepath; - - bool CubeMap = false; - - ImageSpecification() = default; - ImageSpecification(std::filesystem::path filepath) - : Filepath(std::move(filepath)) - {} - }; - - class Image - { - public: - virtual ~Image() = default; - - virtual void SetData(void* data, uint32_t channels = 4) = 0; - virtual void Release() = 0; - - [[nodiscard]] virtual const ImageSpecification& GetSpecification() const = 0; - [[nodiscard]] virtual uint32_t GetWidth() const = 0; - [[nodiscard]] virtual uint32_t GetHeight() const = 0; - - static Ref Create(const ImageSpecification& specification); - }; - - namespace Utils - { - inline bool IsDepthFormat(const ImageFormat format) - { - return format == ImageFormat::Depth; - } - } + enum class ImageFormat : uint8_t + { + None = 0, + + // Color + RGB16, + RGBA8, + + // Depth + Depth + }; + + enum class ImageUsage : uint8_t + { + Texture, + Attachment + }; + + struct ImageSpecification + { + uint32_t Width = 0; + uint32_t Height = 0; + + ImageFormat Format = ImageFormat::None; + ImageUsage Usage; + + std::filesystem::path Filepath; + + bool CubeMap = false; + + ImageSpecification() = default; + + ImageSpecification(std::filesystem::path filepath) + : Filepath(std::move(filepath)) + {} + }; + + class Image + { + public: + virtual ~Image() = default; + + virtual void SetData(void* data, uint32_t channels = 4) = 0; + virtual void Release() = 0; + + [[nodiscard]] virtual const ImageSpecification& GetSpecification() const = 0; + [[nodiscard]] virtual uint32_t GetWidth() const = 0; + [[nodiscard]] virtual uint32_t GetHeight() const = 0; + + static Ref Create(const ImageSpecification& specification); + }; + + namespace Utils + { + inline bool IsDepthFormat(const ImageFormat format) + { + return format == ImageFormat::Depth; + } + } } diff --git a/EppoEngine/Source/Renderer/IndexBuffer.cpp b/EppoEngine/Source/Renderer/IndexBuffer.cpp index b773c3df..58efdde3 100644 --- a/EppoEngine/Source/Renderer/IndexBuffer.cpp +++ b/EppoEngine/Source/Renderer/IndexBuffer.cpp @@ -6,32 +6,34 @@ namespace Eppo { - Ref IndexBuffer::Create(uint32_t size) - { - switch (RendererContext::GetAPI()) - { - case RendererAPI::Vulkan: return CreateRef(size); - } + Ref IndexBuffer::Create(uint32_t size) + { + switch (RendererContext::GetAPI()) + { + case RendererAPI::Vulkan: + return CreateRef(size); + } - EPPO_ASSERT(false); - return nullptr; - } + EPPO_ASSERT(false); + return nullptr; + } - Ref IndexBuffer::Create(const void* data, const uint32_t size) - { - const Buffer buffer = Buffer::Copy(data, size); + Ref IndexBuffer::Create(const void* data, const uint32_t size) + { + const Buffer buffer = Buffer::Copy(data, size); - return Create(buffer); - } + return Create(buffer); + } - Ref IndexBuffer::Create(Buffer buffer) - { - switch (RendererContext::GetAPI()) - { - case RendererAPI::Vulkan: return CreateRef(buffer); - } + Ref IndexBuffer::Create(Buffer buffer) + { + switch (RendererContext::GetAPI()) + { + case RendererAPI::Vulkan: + return CreateRef(buffer); + } - EPPO_ASSERT(false); - return nullptr; - } + EPPO_ASSERT(false); + return nullptr; + } } diff --git a/EppoEngine/Source/Renderer/IndexBuffer.h b/EppoEngine/Source/Renderer/IndexBuffer.h index b9bde981..cefdf7f6 100644 --- a/EppoEngine/Source/Renderer/IndexBuffer.h +++ b/EppoEngine/Source/Renderer/IndexBuffer.h @@ -4,16 +4,16 @@ namespace Eppo { - class IndexBuffer - { - public: - virtual ~IndexBuffer() = default; + class IndexBuffer + { + public: + virtual ~IndexBuffer() = default; - virtual void SetData(Buffer buffer) = 0; - [[nodiscard]] virtual uint32_t GetIndexCount() const = 0; + virtual void SetData(Buffer buffer) = 0; + [[nodiscard]] virtual uint32_t GetIndexCount() const = 0; - static Ref Create(uint32_t size); - static Ref Create(const void* data, uint32_t size); - static Ref Create(Buffer buffer); - }; + static Ref Create(uint32_t size); + static Ref Create(const void* data, uint32_t size); + static Ref Create(Buffer buffer); + }; } diff --git a/EppoEngine/Source/Renderer/Mesh/Material.h b/EppoEngine/Source/Renderer/Mesh/Material.h index 83f50b44..c4d4853f 100644 --- a/EppoEngine/Source/Renderer/Mesh/Material.h +++ b/EppoEngine/Source/Renderer/Mesh/Material.h @@ -2,15 +2,15 @@ namespace Eppo { - struct Material - { - float Roughness = 0.0f; - float Metallic = 0.0f; - float NormalMapIntensity = 0.0f; - glm::vec4 DiffuseColor = glm::vec4(1.0f); + struct Material + { + float Roughness = 0.0f; + float Metallic = 0.0f; + float NormalMapIntensity = 0.0f; + glm::vec4 DiffuseColor = glm::vec4(1.0f); - int32_t DiffuseMapIndex = -1; - int32_t NormalMapIndex = -1; - int32_t RoughnessMetallicMapIndex = -1; - }; + int32_t DiffuseMapIndex = -1; + int32_t NormalMapIndex = -1; + int32_t RoughnessMetallicMapIndex = -1; + }; } diff --git a/EppoEngine/Source/Renderer/Mesh/Mesh.cpp b/EppoEngine/Source/Renderer/Mesh/Mesh.cpp index d36f3c1f..23c32c0f 100644 --- a/EppoEngine/Source/Renderer/Mesh/Mesh.cpp +++ b/EppoEngine/Source/Renderer/Mesh/Mesh.cpp @@ -11,224 +11,230 @@ namespace Eppo { - Mesh::Mesh(std::filesystem::path filepath) - : m_Filepath(std::move(filepath)) - { - EPPO_PROFILE_FUNCTION("Mesh::Mesh"); - - tinygltf::Model model; - std::string error; - std::string warning; - - { - EPPO_PROFILE_FUNCTION("LoadGLB"); - - tinygltf::TinyGLTF loader; - const bool result = loader.LoadBinaryFromFile(&model, &error, &warning, m_Filepath.string()); - - if (!warning.empty()) - EPPO_WARN(warning); - if (!error.empty()) - EPPO_ERROR(error); - - if (!result) - { - EPPO_ERROR("Failed to parse mesh file '{}'!", m_Filepath.string()); - return; - } - } - - ProcessMaterials(model); - ProcessImages(model); - - for (const auto& node : model.nodes) - ProcessNode(model, node); - } - - void Mesh::ProcessNode(const tinygltf::Model& model, const tinygltf::Node& node) - { - EPPO_PROFILE_FUNCTION("Mesh::ProcessNode"); - - if (const int32_t meshIndex = node.mesh; - meshIndex > -1) - { - // Get local mesh transform - auto localTransform = glm::mat4(1.0f); - - if (!node.translation.empty()) - { - const glm::vec3 translation = glm::make_vec3(node.translation.data()); - localTransform = glm::translate(localTransform, translation); - } - - if (!node.rotation.empty()) - { - const glm::quat rotation = glm::make_quat(node.rotation.data()); - localTransform *= glm::mat4(rotation); - } - - if (!node.scale.empty()) - { - const glm::vec3 scale = glm::make_vec3(node.scale.data()); - localTransform = glm::scale(localTransform, scale); - } - - auto [vertices, indices, primitives] = GetVertexData(model, model.meshes[meshIndex]); - m_Submeshes.emplace_back(node.name, vertices, indices, primitives, localTransform); - } - - for (size_t i = 0; i < node.children.size(); i++) - ProcessNode(model, model.nodes[i]); - } - - void Mesh::ProcessMaterials(const tinygltf::Model& model) - { - EPPO_PROFILE_FUNCTION("Mesh::ProcessMaterials"); - - m_Materials.resize(model.materials.size()); - for (size_t i = 0; i < model.materials.size(); i++) - { - const tinygltf::Material& mat = model.materials[i]; - - const auto material = CreateRef(); - material->Roughness = static_cast(mat.pbrMetallicRoughness.roughnessFactor); - material->Metallic = static_cast(mat.pbrMetallicRoughness.metallicFactor); - material->NormalMapIntensity = static_cast(mat.normalTexture.scale); - - // Diffuse color - if (mat.values.find("baseColorFactor") != mat.values.end()) - material->DiffuseColor = glm::make_vec4(mat.values.at("baseColorFactor").ColorFactor().data()); - - // Diffuse texture - if (mat.pbrMetallicRoughness.baseColorTexture.index != -1) - material->DiffuseMapIndex = model.textures[mat.pbrMetallicRoughness.baseColorTexture.index].source; - - // Normal texture - if (mat.normalTexture.index != -1) - material->NormalMapIndex = model.textures[mat.normalTexture.index].source; - - // Roughness/Metallic texture - if (mat.pbrMetallicRoughness.metallicRoughnessTexture.index != -1) - material->RoughnessMetallicMapIndex = model.textures[mat.pbrMetallicRoughness.metallicRoughnessTexture.index].source; - - m_Materials[i] = material; - } - } - - void Mesh::ProcessImages(const tinygltf::Model& model) - { - EPPO_PROFILE_FUNCTION("Mesh::ProcessImages"); - - for (const auto& image : model.images) - { - ImageSpecification imageSpec; - imageSpec.Width = image.width; - imageSpec.Height = image.height; - imageSpec.Usage = ImageUsage::Texture; - - if (image.component == 4) - { - imageSpec.Format = ImageFormat::RGBA8; - - Ref dstImage = Image::Create(imageSpec); - dstImage->SetData((void*)image.image.data()); - - m_Images.emplace_back(dstImage); - } - else - { + Mesh::Mesh(std::filesystem::path filepath) + : m_Filepath(std::move(filepath)) + { + EPPO_PROFILE_FUNCTION("Mesh::Mesh"); + + tinygltf::Model model; + std::string error; + std::string warning; + + { + EPPO_PROFILE_FUNCTION("LoadGLB"); + + tinygltf::TinyGLTF loader; + const bool result = loader.LoadBinaryFromFile(&model, &error, &warning, m_Filepath.string()); + + if (!warning.empty()) + EPPO_WARN(warning); + if (!error.empty()) + EPPO_ERROR(error); + + if (!result) + { + EPPO_ERROR("Failed to parse mesh file '{}'!", m_Filepath.string()); + return; + } + } + + ProcessMaterials(model); + ProcessImages(model); + + for (const auto& node : model.nodes) + ProcessNode(model, node); + } + + void Mesh::ProcessNode(const tinygltf::Model& model, const tinygltf::Node& node) + { + EPPO_PROFILE_FUNCTION("Mesh::ProcessNode"); + + if (const int32_t meshIndex = node.mesh; meshIndex > -1) + { + // Get local mesh transform + auto localTransform = glm::mat4(1.0f); + + if (!node.translation.empty()) + { + const glm::vec3 translation = glm::make_vec3(node.translation.data()); + localTransform = glm::translate(localTransform, translation); + } + + if (!node.rotation.empty()) + { + const glm::quat rotation = glm::make_quat(node.rotation.data()); + localTransform *= glm::mat4(rotation); + } + + if (!node.scale.empty()) + { + const glm::vec3 scale = glm::make_vec3(node.scale.data()); + localTransform = glm::scale(localTransform, scale); + } + + auto [vertices, indices, primitives] = GetVertexData(model, model.meshes[meshIndex]); + m_Submeshes.emplace_back(node.name, vertices, indices, primitives, localTransform); + } + + for (size_t i = 0; i < node.children.size(); i++) + ProcessNode(model, model.nodes[i]); + } + + void Mesh::ProcessMaterials(const tinygltf::Model& model) + { + EPPO_PROFILE_FUNCTION("Mesh::ProcessMaterials"); + + m_Materials.resize(model.materials.size()); + for (size_t i = 0; i < model.materials.size(); i++) + { + const tinygltf::Material& mat = model.materials[i]; + + const auto material = CreateRef(); + material->Roughness = static_cast(mat.pbrMetallicRoughness.roughnessFactor); + material->Metallic = static_cast(mat.pbrMetallicRoughness.metallicFactor); + material->NormalMapIntensity = static_cast(mat.normalTexture.scale); + + // Diffuse color + if (mat.values.find("baseColorFactor") != mat.values.end()) + material->DiffuseColor = glm::make_vec4(mat.values.at("baseColorFactor").ColorFactor().data()); + + // Diffuse texture + if (mat.pbrMetallicRoughness.baseColorTexture.index != -1) + material->DiffuseMapIndex = model.textures[mat.pbrMetallicRoughness.baseColorTexture.index].source; + + // Normal texture + if (mat.normalTexture.index != -1) + material->NormalMapIndex = model.textures[mat.normalTexture.index].source; + + // Roughness/Metallic texture + if (mat.pbrMetallicRoughness.metallicRoughnessTexture.index != -1) + material->RoughnessMetallicMapIndex = model.textures[mat.pbrMetallicRoughness.metallicRoughnessTexture. + index].source; + + m_Materials[i] = material; + } + } + + void Mesh::ProcessImages(const tinygltf::Model& model) + { + EPPO_PROFILE_FUNCTION("Mesh::ProcessImages"); + + for (const auto& image : model.images) + { + ImageSpecification imageSpec; + imageSpec.Width = image.width; + imageSpec.Height = image.height; + imageSpec.Usage = ImageUsage::Texture; + + if (image.component == 4) + { + imageSpec.Format = ImageFormat::RGBA8; + + Ref dstImage = Image::Create(imageSpec); + dstImage->SetData((void*)image.image.data()); + + m_Images.emplace_back(dstImage); + } + else + { EPPO_ASSERT(false); // TODO: not supported yet - } - } - } - - MeshData Mesh::GetVertexData(const tinygltf::Model& model, const tinygltf::Mesh& mesh) const - { - EPPO_PROFILE_FUNCTION("Mesh::GetVertexData"); - - MeshData meshData; - - for (const auto& primitive : mesh.primitives) - { - Primitive& p = meshData.Primitives.emplace_back(); - p.FirstVertex = static_cast(meshData.Vertices.size()); - p.FirstIndex = static_cast(meshData.Indices.size()); - - uint32_t vertexCount = 0; - uint32_t indexCount = 0; - - const float* positionData = nullptr; - const float* normalData = nullptr; - const float* texCoordData = nullptr; - - // Vertices - if (primitive.attributes.find("POSITION") != primitive.attributes.end()) - { - const auto& accessor = model.accessors[primitive.attributes.find("POSITION")->second]; - const auto& bufferView = model.bufferViews[accessor.bufferView]; - positionData = reinterpret_cast(&(model.buffers[bufferView.buffer].data[accessor.byteOffset + bufferView.byteOffset])); - vertexCount = static_cast(accessor.count); - } - - if (primitive.attributes.find("NORMAL") != primitive.attributes.end()) - { - const auto& accessor = model.accessors[primitive.attributes.find("NORMAL")->second]; - const auto& bufferView = model.bufferViews[accessor.bufferView]; - normalData = reinterpret_cast(&(model.buffers[bufferView.buffer].data[accessor.byteOffset + bufferView.byteOffset])); - } - - if (primitive.attributes.find("TEXCOORD_0") != primitive.attributes.end()) - { - const auto& accessor = model.accessors[primitive.attributes.find("TEXCOORD_0")->second]; - const auto& bufferView = model.bufferViews[accessor.bufferView]; - texCoordData = reinterpret_cast(&(model.buffers[bufferView.buffer].data[accessor.byteOffset + bufferView.byteOffset])); - } - - const size_t offset = meshData.Vertices.size(); - meshData.Vertices.resize(offset + vertexCount); - - for (size_t i = 0; i < vertexCount; i++) - { - Vertex& vertex = meshData.Vertices[offset + i]; - vertex.Position = glm::make_vec3(&positionData[i * 3]); - vertex.Normal = glm::make_vec3(&normalData[i * 3]); - vertex.TexCoord = glm::make_vec2(&texCoordData[i * 2]); - } - - // Indices - const auto& accessor = model.accessors[primitive.indices]; - const auto& bufferView = model.bufferViews[accessor.bufferView]; - const auto& buffer = model.buffers[bufferView.buffer]; - - meshData.Indices.reserve(accessor.count + meshData.Indices.size()); - - if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) - { - const auto* data = reinterpret_cast(&buffer.data[bufferView.byteOffset + accessor.byteOffset]); - for (size_t i = 0; i < accessor.count; i++) - meshData.Indices.push_back(data[i]); - } - else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) - { - const auto* data = reinterpret_cast(&buffer.data[bufferView.byteOffset + accessor.byteOffset]); - for (size_t i = 0; i < accessor.count; i++) - meshData.Indices.push_back(data[i]); - } - else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) - { - const auto* data = reinterpret_cast(&buffer.data[bufferView.byteOffset + accessor.byteOffset]); - for (size_t i = 0; i < accessor.count; i++) - meshData.Indices.push_back(data[i]); - } - - p.VertexCount = vertexCount; - p.IndexCount = static_cast(accessor.count); - - // Material - if (primitive.material != -1) - p.Material = m_Materials[primitive.material]; - } - - return meshData; - } + } + } + } + + MeshData Mesh::GetVertexData(const tinygltf::Model& model, const tinygltf::Mesh& mesh) const + { + EPPO_PROFILE_FUNCTION("Mesh::GetVertexData"); + + MeshData meshData; + + for (const auto& primitive : mesh.primitives) + { + Primitive& p = meshData.Primitives.emplace_back(); + p.FirstVertex = static_cast(meshData.Vertices.size()); + p.FirstIndex = static_cast(meshData.Indices.size()); + + uint32_t vertexCount = 0; + uint32_t indexCount = 0; + + const float* positionData = nullptr; + const float* normalData = nullptr; + const float* texCoordData = nullptr; + + // Vertices + if (primitive.attributes.find("POSITION") != primitive.attributes.end()) + { + const auto& accessor = model.accessors[primitive.attributes.find("POSITION")->second]; + const auto& bufferView = model.bufferViews[accessor.bufferView]; + positionData = reinterpret_cast(&(model.buffers[bufferView.buffer].data[accessor. + byteOffset + bufferView.byteOffset])); + vertexCount = static_cast(accessor.count); + } + + if (primitive.attributes.find("NORMAL") != primitive.attributes.end()) + { + const auto& accessor = model.accessors[primitive.attributes.find("NORMAL")->second]; + const auto& bufferView = model.bufferViews[accessor.bufferView]; + normalData = reinterpret_cast(&(model.buffers[bufferView.buffer].data[accessor.byteOffset + + bufferView.byteOffset])); + } + + if (primitive.attributes.find("TEXCOORD_0") != primitive.attributes.end()) + { + const auto& accessor = model.accessors[primitive.attributes.find("TEXCOORD_0")->second]; + const auto& bufferView = model.bufferViews[accessor.bufferView]; + texCoordData = reinterpret_cast(&(model.buffers[bufferView.buffer].data[accessor. + byteOffset + bufferView.byteOffset])); + } + + const size_t offset = meshData.Vertices.size(); + meshData.Vertices.resize(offset + vertexCount); + + for (size_t i = 0; i < vertexCount; i++) + { + Vertex& vertex = meshData.Vertices[offset + i]; + vertex.Position = glm::make_vec3(&positionData[i * 3]); + vertex.Normal = glm::make_vec3(&normalData[i * 3]); + vertex.TexCoord = glm::make_vec2(&texCoordData[i * 2]); + } + + // Indices + const auto& accessor = model.accessors[primitive.indices]; + const auto& bufferView = model.bufferViews[accessor.bufferView]; + const auto& buffer = model.buffers[bufferView.buffer]; + + meshData.Indices.reserve(accessor.count + meshData.Indices.size()); + + if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT) + { + const auto* data = reinterpret_cast(&buffer.data[bufferView.byteOffset + accessor. + byteOffset]); + for (size_t i = 0; i < accessor.count; i++) + meshData.Indices.push_back(data[i]); + } + else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_SHORT) + { + const auto* data = reinterpret_cast(&buffer.data[bufferView.byteOffset + accessor. + byteOffset]); + for (size_t i = 0; i < accessor.count; i++) + meshData.Indices.push_back(data[i]); + } + else if (accessor.componentType == TINYGLTF_COMPONENT_TYPE_UNSIGNED_BYTE) + { + const auto* data = reinterpret_cast(&buffer.data[bufferView.byteOffset + accessor. + byteOffset]); + for (size_t i = 0; i < accessor.count; i++) + meshData.Indices.push_back(data[i]); + } + + p.VertexCount = vertexCount; + p.IndexCount = static_cast(accessor.count); + + // Material + if (primitive.material != -1) + p.Material = m_Materials[primitive.material]; + } + + return meshData; + } } diff --git a/EppoEngine/Source/Renderer/Mesh/Mesh.h b/EppoEngine/Source/Renderer/Mesh/Mesh.h index 42f03ccb..f643b80c 100644 --- a/EppoEngine/Source/Renderer/Mesh/Mesh.h +++ b/EppoEngine/Source/Renderer/Mesh/Mesh.h @@ -8,47 +8,47 @@ namespace tinygltf { - class Model; - class Node; - struct Mesh; + class Model; + class Node; + struct Mesh; } namespace Eppo { - struct MeshData - { - std::vector Vertices; - std::vector Indices; - std::vector Primitives; - }; - - class Mesh : public Asset - { - public: - explicit Mesh(std::filesystem::path filepath); - ~Mesh() override = default; - - [[nodiscard]] const std::vector& GetSubmeshes() const { return m_Submeshes; } - [[nodiscard]] const std::vector>& GetImages() const { return m_Images; } - [[nodiscard]] const std::vector>& GetMaterials() const { return m_Materials; } - - Ref GetImage(const uint32_t materialIndex) { return m_Images[materialIndex]; } - - // Asset - static AssetType GetStaticType() { return AssetType::Mesh; } - - private: - void ProcessNode(const tinygltf::Model& model, const tinygltf::Node& node); - void ProcessMaterials(const tinygltf::Model& model); - void ProcessImages(const tinygltf::Model& model); - - [[nodiscard]] MeshData GetVertexData(const tinygltf::Model& model, const tinygltf::Mesh& mesh) const; - - private: - std::filesystem::path m_Filepath; - - std::vector m_Submeshes; - std::vector> m_Images; - std::vector> m_Materials; - }; + struct MeshData + { + std::vector Vertices; + std::vector Indices; + std::vector Primitives; + }; + + class Mesh : public Asset + { + public: + explicit Mesh(std::filesystem::path filepath); + ~Mesh() override = default; + + [[nodiscard]] const std::vector& GetSubmeshes() const { return m_Submeshes; } + [[nodiscard]] const std::vector>& GetImages() const { return m_Images; } + [[nodiscard]] const std::vector>& GetMaterials() const { return m_Materials; } + + Ref GetImage(const uint32_t materialIndex) { return m_Images[materialIndex]; } + + // Asset + static AssetType GetStaticType() { return AssetType::Mesh; } + + private: + void ProcessNode(const tinygltf::Model& model, const tinygltf::Node& node); + void ProcessMaterials(const tinygltf::Model& model); + void ProcessImages(const tinygltf::Model& model); + + [[nodiscard]] MeshData GetVertexData(const tinygltf::Model& model, const tinygltf::Mesh& mesh) const; + + private: + std::filesystem::path m_Filepath; + + std::vector m_Submeshes; + std::vector> m_Images; + std::vector> m_Materials; + }; } diff --git a/EppoEngine/Source/Renderer/Mesh/Submesh.cpp b/EppoEngine/Source/Renderer/Mesh/Submesh.cpp index 27ff65f8..8f6236fa 100644 --- a/EppoEngine/Source/Renderer/Mesh/Submesh.cpp +++ b/EppoEngine/Source/Renderer/Mesh/Submesh.cpp @@ -5,10 +5,11 @@ namespace Eppo { - Submesh::Submesh(std::string name, const std::vector& vertices, const std::vector& indices, const std::vector& primitives, const glm::mat4& transform) - : m_Primitives(primitives), m_Name(std::move(name)), m_LocalTransform(transform) - { - m_VertexBuffer = VertexBuffer::Create(vertices.data(), vertices.size() * sizeof(Vertex)); - m_IndexBuffer = IndexBuffer::Create(indices.data(), indices.size() * sizeof(uint32_t)); - } + Submesh::Submesh(std::string name, const std::vector& vertices, const std::vector& indices, + const std::vector& primitives, const glm::mat4& transform) + : m_Primitives(primitives), m_Name(std::move(name)), m_LocalTransform(transform) + { + m_VertexBuffer = VertexBuffer::Create(vertices.data(), vertices.size() * sizeof(Vertex)); + m_IndexBuffer = IndexBuffer::Create(indices.data(), indices.size() * sizeof(uint32_t)); + } } diff --git a/EppoEngine/Source/Renderer/Mesh/Submesh.h b/EppoEngine/Source/Renderer/Mesh/Submesh.h index 72470cd5..da551a73 100644 --- a/EppoEngine/Source/Renderer/Mesh/Submesh.h +++ b/EppoEngine/Source/Renderer/Mesh/Submesh.h @@ -7,35 +7,36 @@ namespace Eppo { - struct Primitive - { - uint32_t FirstVertex = 0; - uint32_t FirstIndex = 0; - uint32_t VertexCount = 0; - uint32_t IndexCount = 0; - - Ref Material = nullptr; - }; - - class Submesh - { - public: - Submesh(std::string name, const std::vector& vertices, const std::vector& indices, const std::vector& primitives, const glm::mat4& transform); - - [[nodiscard]] Ref GetVertexBuffer() const { return m_VertexBuffer; } - [[nodiscard]] Ref GetIndexBuffer() const { return m_IndexBuffer; } - - [[nodiscard]] const std::vector& GetPrimitives() const { return m_Primitives; } - - [[nodiscard]] const std::string& GetName() const { return m_Name; } - [[nodiscard]] const glm::mat4& GetLocalTransform() const { return m_LocalTransform; } - - private: - Ref m_VertexBuffer; - Ref m_IndexBuffer; - std::vector m_Primitives; - - std::string m_Name; - glm::mat4 m_LocalTransform; - }; + struct Primitive + { + uint32_t FirstVertex = 0; + uint32_t FirstIndex = 0; + uint32_t VertexCount = 0; + uint32_t IndexCount = 0; + + Ref Material = nullptr; + }; + + class Submesh + { + public: + Submesh(std::string name, const std::vector& vertices, const std::vector& indices, + const std::vector& primitives, const glm::mat4& transform); + + [[nodiscard]] Ref GetVertexBuffer() const { return m_VertexBuffer; } + [[nodiscard]] Ref GetIndexBuffer() const { return m_IndexBuffer; } + + [[nodiscard]] const std::vector& GetPrimitives() const { return m_Primitives; } + + [[nodiscard]] const std::string& GetName() const { return m_Name; } + [[nodiscard]] const glm::mat4& GetLocalTransform() const { return m_LocalTransform; } + + private: + Ref m_VertexBuffer; + Ref m_IndexBuffer; + std::vector m_Primitives; + + std::string m_Name; + glm::mat4 m_LocalTransform; + }; } diff --git a/EppoEngine/Source/Renderer/Pipeline.cpp b/EppoEngine/Source/Renderer/Pipeline.cpp index ccf723ad..3540a160 100644 --- a/EppoEngine/Source/Renderer/Pipeline.cpp +++ b/EppoEngine/Source/Renderer/Pipeline.cpp @@ -6,14 +6,15 @@ namespace Eppo { - Ref Pipeline::Create(const PipelineSpecification& specification) - { - switch (RendererContext::GetAPI()) - { - case RendererAPI::Vulkan: return CreateRef(specification); - } + Ref Pipeline::Create(const PipelineSpecification& specification) + { + switch (RendererContext::GetAPI()) + { + case RendererAPI::Vulkan: + return CreateRef(specification); + } - EPPO_ASSERT(false); - return nullptr; - } + EPPO_ASSERT(false); + return nullptr; + } } diff --git a/EppoEngine/Source/Renderer/Pipeline.h b/EppoEngine/Source/Renderer/Pipeline.h index c2c16d49..af5d5579 100644 --- a/EppoEngine/Source/Renderer/Pipeline.h +++ b/EppoEngine/Source/Renderer/Pipeline.h @@ -7,109 +7,110 @@ namespace Eppo { - struct RenderAttachment - { - Ref RenderImage; - bool Clear = true; - - union ClearValue - { - glm::vec4 Color; - float Depth = 1.0f; - } ClearValue; - - explicit RenderAttachment(const Ref& image, const bool clear = true, const glm::vec4& clearValue = glm::vec4(0.0f)) - : RenderImage(image), Clear(clear) - { - ClearValue.Color = clearValue; - } - - explicit RenderAttachment(const Ref& image, const bool clear = true, const float clearValue = 1.0f) - : RenderImage(image), Clear(clear) - { - ClearValue.Depth = clearValue; - } - }; - - enum class PrimitiveTopology : uint8_t - { - Lines, - Triangles - }; - - enum class PolygonMode : uint8_t - { - Fill, - Line - }; - - enum class CullMode : uint8_t - { - Back, - Front, - FrontAndBack - }; - - enum class CullFrontFace : uint8_t - { - Clockwise, - CounterClockwise - }; - - enum class DepthCompareOp : uint8_t - { - Less, - Equal, - LessOrEqual, - Greater, - NotEqual, - GreaterOrEqual, - - Always, - Never - }; - - struct PipelineSpecification - { - Ref Shader; - VertexBufferLayout Layout; - bool SwapchainTarget = false; - - uint32_t Width = 0; - uint32_t Height = 0; - - // Input Assembly - PrimitiveTopology Topology = PrimitiveTopology::Triangles; - - // Rasterization - Eppo::PolygonMode PolygonMode = PolygonMode::Fill; - Eppo::CullMode CullMode = CullMode::Back; - Eppo::CullFrontFace CullFrontFace = CullFrontFace::Clockwise; - - // Depth Stencil - bool CreateDepthImage = false; - bool TestDepth = false; - bool WriteDepth = false; - bool ClearDepthOnLoad = true; - float ClearDepth = 1.0f; - Eppo::DepthCompareOp DepthCompareOp = DepthCompareOp::Less; - - // Render Attachments - std::vector RenderAttachments; - bool CubeMap = false; - }; - - class Pipeline - { - public: - virtual ~Pipeline() = default; - - [[nodiscard]] virtual const PipelineSpecification& GetSpecification() const = 0; - virtual PipelineSpecification& GetSpecification() = 0; - - [[nodiscard]] virtual Ref GetImage(uint32_t index) const = 0; - [[nodiscard]] virtual Ref GetFinalImage() const = 0; - - static Ref Create(const PipelineSpecification& specification); - }; + struct RenderAttachment + { + Ref RenderImage; + bool Clear = true; + + union ClearValue + { + glm::vec4 Color; + float Depth = 1.0f; + } ClearValue; + + explicit RenderAttachment(const Ref& image, const bool clear = true, + const glm::vec4& clearValue = glm::vec4(0.0f)) + : RenderImage(image), Clear(clear) + { + ClearValue.Color = clearValue; + } + + explicit RenderAttachment(const Ref& image, const bool clear = true, const float clearValue = 1.0f) + : RenderImage(image), Clear(clear) + { + ClearValue.Depth = clearValue; + } + }; + + enum class PrimitiveTopology : uint8_t + { + Lines, + Triangles + }; + + enum class PolygonMode : uint8_t + { + Fill, + Line + }; + + enum class CullMode : uint8_t + { + Back, + Front, + FrontAndBack + }; + + enum class CullFrontFace : uint8_t + { + Clockwise, + CounterClockwise + }; + + enum class DepthCompareOp : uint8_t + { + Less, + Equal, + LessOrEqual, + Greater, + NotEqual, + GreaterOrEqual, + + Always, + Never + }; + + struct PipelineSpecification + { + Ref Shader; + VertexBufferLayout Layout; + bool SwapchainTarget = false; + + uint32_t Width = 0; + uint32_t Height = 0; + + // Input Assembly + PrimitiveTopology Topology = PrimitiveTopology::Triangles; + + // Rasterization + Eppo::PolygonMode PolygonMode = PolygonMode::Fill; + Eppo::CullMode CullMode = CullMode::Back; + Eppo::CullFrontFace CullFrontFace = CullFrontFace::Clockwise; + + // Depth Stencil + bool CreateDepthImage = false; + bool TestDepth = false; + bool WriteDepth = false; + bool ClearDepthOnLoad = true; + float ClearDepth = 1.0f; + Eppo::DepthCompareOp DepthCompareOp = DepthCompareOp::Less; + + // Render Attachments + std::vector RenderAttachments; + bool CubeMap = false; + }; + + class Pipeline + { + public: + virtual ~Pipeline() = default; + + [[nodiscard]] virtual const PipelineSpecification& GetSpecification() const = 0; + virtual PipelineSpecification& GetSpecification() = 0; + + [[nodiscard]] virtual Ref GetImage(uint32_t index) const = 0; + [[nodiscard]] virtual Ref GetFinalImage() const = 0; + + static Ref Create(const PipelineSpecification& specification); + }; } diff --git a/EppoEngine/Source/Renderer/RenderTypes.h b/EppoEngine/Source/Renderer/RenderTypes.h index 98d0985d..e45c600b 100644 --- a/EppoEngine/Source/Renderer/RenderTypes.h +++ b/EppoEngine/Source/Renderer/RenderTypes.h @@ -4,16 +4,16 @@ namespace Eppo { - enum class EntityType : uint8_t - { - Mesh, - PointLight - }; + enum class EntityType : uint8_t + { + Mesh, + PointLight + }; - struct PointLight - { - glm::mat4 View[6]; - glm::vec4 Position = glm::vec4(0.0f); - glm::vec4 Color = glm::vec4(0.0f); - }; + struct PointLight + { + glm::mat4 View[6]; + glm::vec4 Position = glm::vec4(0.0f); + glm::vec4 Color = glm::vec4(0.0f); + }; } diff --git a/EppoEngine/Source/Renderer/Renderer.cpp b/EppoEngine/Source/Renderer/Renderer.cpp index 6f300735..fd66a1db 100644 --- a/EppoEngine/Source/Renderer/Renderer.cpp +++ b/EppoEngine/Source/Renderer/Renderer.cpp @@ -6,14 +6,15 @@ namespace Eppo { - Ref Renderer::Create() - { - switch (RendererContext::GetAPI()) - { - case RendererAPI::Vulkan: return CreateRef(); - } + Ref Renderer::Create() + { + switch (RendererContext::GetAPI()) + { + case RendererAPI::Vulkan: + return CreateRef(); + } - EPPO_ASSERT(false); - return nullptr; - } + EPPO_ASSERT(false); + return nullptr; + } } diff --git a/EppoEngine/Source/Renderer/Renderer.h b/EppoEngine/Source/Renderer/Renderer.h index df26878e..1f94782e 100644 --- a/EppoEngine/Source/Renderer/Renderer.h +++ b/EppoEngine/Source/Renderer/Renderer.h @@ -7,25 +7,25 @@ namespace Eppo { - class Renderer - { - public: - virtual ~Renderer() = default; + class Renderer + { + public: + virtual ~Renderer() = default; - virtual void Shutdown() = 0; + virtual void Shutdown() = 0; - // Render queue commands - virtual void ExecuteRenderCommands() = 0; - virtual void SubmitCommand(RenderCommand command) = 0; + // Render queue commands + virtual void ExecuteRenderCommands() = 0; + virtual void SubmitCommand(RenderCommand command) = 0; - // Render passes - virtual void BeginRenderPass(const Ref& commandBuffer, const Ref& pipeline, bool bindPipeline = true) = 0; - virtual void EndRenderPass(const Ref& commandBuffer) = 0; + // Render passes + virtual void BeginRenderPass(const Ref& commandBuffer, const Ref& pipeline, bool bindPipeline = true) = 0; + virtual void EndRenderPass(const Ref& commandBuffer) = 0; - // Shaders - virtual Ref GetShader(const std::string& name) = 0; - virtual void* AllocateDescriptor(void* layout) = 0; + // Shaders + virtual Ref GetShader(const std::string& name) = 0; + virtual void* AllocateDescriptor(void* layout) = 0; - static Ref Create(); - }; + static Ref Create(); + }; } diff --git a/EppoEngine/Source/Renderer/RendererContext.cpp b/EppoEngine/Source/Renderer/RendererContext.cpp index 68ffa93d..e7d8b0b8 100644 --- a/EppoEngine/Source/Renderer/RendererContext.cpp +++ b/EppoEngine/Source/Renderer/RendererContext.cpp @@ -8,21 +8,22 @@ namespace Eppo { - RendererAPI RendererContext::s_API = RendererAPI::Vulkan; + RendererAPI RendererContext::s_API = RendererAPI::Vulkan; - Ref RendererContext::Get() - { - return Application::Get().GetWindow().GetRendererContext(); - } + Ref RendererContext::Get() + { + return Application::Get().GetWindow().GetRendererContext(); + } - Ref RendererContext::Create(GLFWwindow* windowHandle) - { - switch (s_API) - { - case RendererAPI::Vulkan: return CreateRef(windowHandle); - } + Ref RendererContext::Create(GLFWwindow* windowHandle) + { + switch (s_API) + { + case RendererAPI::Vulkan: + return CreateRef(windowHandle); + } - EPPO_ASSERT(false); - return nullptr; - } + EPPO_ASSERT(false); + return nullptr; + } } diff --git a/EppoEngine/Source/Renderer/RendererContext.h b/EppoEngine/Source/Renderer/RendererContext.h index 225dc87f..3ec14701 100644 --- a/EppoEngine/Source/Renderer/RendererContext.h +++ b/EppoEngine/Source/Renderer/RendererContext.h @@ -6,33 +6,33 @@ struct GLFWwindow; namespace Eppo { - enum class RendererAPI : uint8_t - { - Vulkan = 1 - }; + enum class RendererAPI : uint8_t + { + Vulkan = 1 + }; - class RendererContext - { - public: - virtual ~RendererContext() = default; + class RendererContext + { + public: + virtual ~RendererContext() = default; - virtual void Init() = 0; - virtual void Shutdown() = 0; + virtual void Init() = 0; + virtual void Shutdown() = 0; - [[nodiscard]] virtual uint32_t GetCurrentFrameIndex() const = 0; - virtual void BeginFrame() = 0; - virtual void PresentFrame() = 0; - virtual void WaitIdle() = 0; + [[nodiscard]] virtual uint32_t GetCurrentFrameIndex() const = 0; + virtual void BeginFrame() = 0; + virtual void PresentFrame() = 0; + virtual void WaitIdle() = 0; - [[nodiscard]] virtual Ref GetRenderer() const = 0; + [[nodiscard]] virtual Ref GetRenderer() const = 0; - virtual GLFWwindow* GetWindowHandle() = 0; + virtual GLFWwindow* GetWindowHandle() = 0; - static RendererAPI GetAPI() { return s_API; } - static Ref Get(); - static Ref Create(GLFWwindow* windowHandle); + static RendererAPI GetAPI() { return s_API; } + static Ref Get(); + static Ref Create(GLFWwindow* windowHandle); - private: - static RendererAPI s_API; - }; + private: + static RendererAPI s_API; + }; } diff --git a/EppoEngine/Source/Renderer/SceneRenderer.cpp b/EppoEngine/Source/Renderer/SceneRenderer.cpp index dfbf49ff..61f411db 100644 --- a/EppoEngine/Source/Renderer/SceneRenderer.cpp +++ b/EppoEngine/Source/Renderer/SceneRenderer.cpp @@ -6,14 +6,15 @@ namespace Eppo { - Ref SceneRenderer::Create(Ref scene, const RenderSpecification& renderSpec) - { - switch (RendererContext::GetAPI()) - { - case RendererAPI::Vulkan: return CreateRef(scene, renderSpec); - } + Ref SceneRenderer::Create(Ref scene, const RenderSpecification& renderSpec) + { + switch (RendererContext::GetAPI()) + { + case RendererAPI::Vulkan: + return CreateRef(scene, renderSpec); + } - EPPO_ASSERT(false); - return nullptr; - } + EPPO_ASSERT(false); + return nullptr; + } } diff --git a/EppoEngine/Source/Renderer/SceneRenderer.h b/EppoEngine/Source/Renderer/SceneRenderer.h index 5d7f9336..95fc8d0d 100644 --- a/EppoEngine/Source/Renderer/SceneRenderer.h +++ b/EppoEngine/Source/Renderer/SceneRenderer.h @@ -10,41 +10,41 @@ namespace Eppo { - class Scene; - using EntityHandle = entt::entity; - - // TODO: Move to renderer - struct RenderSpecification - { - uint32_t Width = 0; - uint32_t Height = 0; - - bool DebugRendering = false; - }; - - struct RenderStatistics - { - uint32_t DrawCalls = 0; - uint32_t Meshes = 0; - uint32_t Submeshes = 0; - uint32_t MeshInstances = 0; - }; - - class SceneRenderer - { - public: - virtual ~SceneRenderer() = default; - - virtual void RenderGui() = 0; - virtual void Resize(uint32_t width, uint32_t height) = 0; - - virtual void BeginScene(const EditorCamera& editorCamera) = 0; - virtual void BeginScene(const Camera& camera, const glm::mat4& transform) = 0; - virtual void EndScene() = 0; - - virtual void SubmitDrawCommand(EntityType type, Ref drawCommand) = 0; - virtual Ref GetFinalImage() = 0; - - static Ref Create(Ref scene, const RenderSpecification& renderSpec); - }; + class Scene; + using EntityHandle = entt::entity; + + // TODO: Move to renderer + struct RenderSpecification + { + uint32_t Width = 0; + uint32_t Height = 0; + + bool DebugRendering = false; + }; + + struct RenderStatistics + { + uint32_t DrawCalls = 0; + uint32_t Meshes = 0; + uint32_t Submeshes = 0; + uint32_t MeshInstances = 0; + }; + + class SceneRenderer + { + public: + virtual ~SceneRenderer() = default; + + virtual void RenderGui() = 0; + virtual void Resize(uint32_t width, uint32_t height) = 0; + + virtual void BeginScene(const EditorCamera& editorCamera) = 0; + virtual void BeginScene(const Camera& camera, const glm::mat4& transform) = 0; + virtual void EndScene() = 0; + + virtual void SubmitDrawCommand(EntityType type, Ref drawCommand) = 0; + virtual Ref GetFinalImage() = 0; + + static Ref Create(Ref scene, const RenderSpecification& renderSpec); + }; } diff --git a/EppoEngine/Source/Renderer/Shader.cpp b/EppoEngine/Source/Renderer/Shader.cpp index ab8fadd7..9bd70b99 100644 --- a/EppoEngine/Source/Renderer/Shader.cpp +++ b/EppoEngine/Source/Renderer/Shader.cpp @@ -7,52 +7,57 @@ namespace Eppo { - namespace Utils - { - std::filesystem::path GetOrCreateCacheDirectory() - { - if (!Filesystem::Exists("Resources/Shaders/Cache")) - std::filesystem::create_directories("Resources/Shaders/Cache"); - - return "Resources/Shaders/Cache"; - } - - std::string ShaderStageToString(const ShaderStage stage) - { - switch (stage) - { - case ShaderStage::Vertex: return "vert"; - case ShaderStage::Fragment: return "frag"; - } - - EPPO_ASSERT(false); - return "Invalid"; - } - - ShaderStage StringToShaderStage(const std::string_view stage) - { - if (stage == "vert") return ShaderStage::Vertex; - if (stage == "frag") return ShaderStage::Fragment; - - EPPO_ASSERT(false); - return ShaderStage::None; - } - } - - Shader::Shader(ShaderSpecification specification) - : m_Specification(std::move(specification)) - { - m_Name = m_Specification.Filepath.stem().string(); - } - - Ref Shader::Create(const ShaderSpecification& specification) - { - switch (RendererContext::GetAPI()) - { - case RendererAPI::Vulkan: return CreateRef(specification); - } - - EPPO_ASSERT(false); - return nullptr; - } + namespace Utils + { + std::filesystem::path GetOrCreateCacheDirectory() + { + if (!Filesystem::Exists("Resources/Shaders/Cache")) + std::filesystem::create_directories("Resources/Shaders/Cache"); + + return "Resources/Shaders/Cache"; + } + + std::string ShaderStageToString(const ShaderStage stage) + { + switch (stage) + { + case ShaderStage::Vertex: + return "vert"; + case ShaderStage::Fragment: + return "frag"; + } + + EPPO_ASSERT(false); + return "Invalid"; + } + + ShaderStage StringToShaderStage(const std::string_view stage) + { + if (stage == "vert") + return ShaderStage::Vertex; + if (stage == "frag") + return ShaderStage::Fragment; + + EPPO_ASSERT(false); + return ShaderStage::None; + } + } + + Shader::Shader(ShaderSpecification specification) + : m_Specification(std::move(specification)) + { + m_Name = m_Specification.Filepath.stem().string(); + } + + Ref Shader::Create(const ShaderSpecification& specification) + { + switch (RendererContext::GetAPI()) + { + case RendererAPI::Vulkan: + return CreateRef(specification); + } + + EPPO_ASSERT(false); + return nullptr; + } } diff --git a/EppoEngine/Source/Renderer/Shader.h b/EppoEngine/Source/Renderer/Shader.h index 955d60b8..a047adbf 100644 --- a/EppoEngine/Source/Renderer/Shader.h +++ b/EppoEngine/Source/Renderer/Shader.h @@ -2,62 +2,62 @@ namespace Eppo { - // For compatibility with all devices, we only use 4 different sets - // - // Set 0 = Per frame global data - // Set 1 = Per frame render pass data - // Set 2 = Per frame material data - // Set 3 = Per frame object data - - enum class ShaderStage : uint8_t - { - None = 0, - Vertex, - Fragment, - All - }; - - enum class ShaderResourceType : uint8_t - { - Sampler, - UniformBuffer - }; - - struct ShaderResource - { - ShaderStage Type; - ShaderResourceType ResourceType; - uint32_t Binding = 0; - uint32_t Size = 0; - uint32_t ArraySize = 0; - std::string Name; - }; - - struct ShaderSpecification - { - std::filesystem::path Filepath; - }; - - class Shader - { - public: - explicit Shader(ShaderSpecification specification); - virtual ~Shader() = default; - - [[nodiscard]] const ShaderSpecification& GetSpecification() const { return m_Specification; } - [[nodiscard]] const std::string& GetName() const { return m_Name; } - - static Ref Create(const ShaderSpecification& specification); - - private: - ShaderSpecification m_Specification; - std::string m_Name; - }; - - namespace Utils - { - std::filesystem::path GetOrCreateCacheDirectory(); - std::string ShaderStageToString(ShaderStage stage); - ShaderStage StringToShaderStage(std::string_view stage); - } + // For compatibility with all devices, we only use 4 different sets + // + // Set 0 = Per frame global data + // Set 1 = Per frame render pass data + // Set 2 = Per frame material data + // Set 3 = Per frame object data + + enum class ShaderStage : uint8_t + { + None = 0, + Vertex, + Fragment, + All + }; + + enum class ShaderResourceType : uint8_t + { + Sampler, + UniformBuffer + }; + + struct ShaderResource + { + ShaderStage Type; + ShaderResourceType ResourceType; + uint32_t Binding = 0; + uint32_t Size = 0; + uint32_t ArraySize = 0; + std::string Name; + }; + + struct ShaderSpecification + { + std::filesystem::path Filepath; + }; + + class Shader + { + public: + explicit Shader(ShaderSpecification specification); + virtual ~Shader() = default; + + [[nodiscard]] const ShaderSpecification& GetSpecification() const { return m_Specification; } + [[nodiscard]] const std::string& GetName() const { return m_Name; } + + static Ref Create(const ShaderSpecification& specification); + + private: + ShaderSpecification m_Specification; + std::string m_Name; + }; + + namespace Utils + { + std::filesystem::path GetOrCreateCacheDirectory(); + std::string ShaderStageToString(ShaderStage stage); + ShaderStage StringToShaderStage(std::string_view stage); + } } diff --git a/EppoEngine/Source/Renderer/ShaderIncluder.cpp b/EppoEngine/Source/Renderer/ShaderIncluder.cpp index 987f5673..279f90b0 100644 --- a/EppoEngine/Source/Renderer/ShaderIncluder.cpp +++ b/EppoEngine/Source/Renderer/ShaderIncluder.cpp @@ -5,31 +5,32 @@ namespace Eppo { - shaderc_include_result* ShaderIncluder::GetInclude(const char* requested_source, shaderc_include_type type, const char* requesting_source, size_t include_depth) - { - // Get requested file path - const std::filesystem::path requestingFile = requesting_source; - const std::filesystem::path requestedFile = requestingFile.parent_path() / std::filesystem::path(requested_source); + shaderc_include_result* ShaderIncluder::GetInclude(const char* requested_source, shaderc_include_type type, + const char* requesting_source, size_t include_depth) + { + // Get requested file path + const std::filesystem::path requestingFile = requesting_source; + const std::filesystem::path requestedFile = requestingFile.parent_path() / std::filesystem::path(requested_source); - const std::string source = Filesystem::ReadText(requestedFile); + const std::string source = Filesystem::ReadText(requestedFile); - const auto dataContainer = new std::array; - (*dataContainer)[0] = requestedFile.string(); - (*dataContainer)[1] = source; + const auto dataContainer = new std::array; + (*dataContainer)[0] = requestedFile.string(); + (*dataContainer)[1] = source; - const auto data = new shaderc_include_result; - data->source_name = (*dataContainer)[0].data(); - data->source_name_length = (*dataContainer)[0].size(); - data->content = (*dataContainer)[1].data(); - data->content_length = (*dataContainer)[1].size(); - data->user_data = dataContainer; + const auto data = new shaderc_include_result; + data->source_name = (*dataContainer)[0].data(); + data->source_name_length = (*dataContainer)[0].size(); + data->content = (*dataContainer)[1].data(); + data->content_length = (*dataContainer)[1].size(); + data->user_data = dataContainer; - return data; - } + return data; + } - void ShaderIncluder::ReleaseInclude(shaderc_include_result* data) - { - delete static_cast*>(data->user_data); - delete data; - } + void ShaderIncluder::ReleaseInclude(shaderc_include_result* data) + { + delete static_cast*>(data->user_data); + delete data; + } } diff --git a/EppoEngine/Source/Renderer/ShaderIncluder.h b/EppoEngine/Source/Renderer/ShaderIncluder.h index 1fe658b4..31b79b29 100644 --- a/EppoEngine/Source/Renderer/ShaderIncluder.h +++ b/EppoEngine/Source/Renderer/ShaderIncluder.h @@ -4,10 +4,11 @@ namespace Eppo { - class ShaderIncluder : public shaderc::CompileOptions::IncluderInterface - { - public: - shaderc_include_result* GetInclude(const char* requested_source, shaderc_include_type type, const char* requesting_source, size_t include_depth) override; - void ReleaseInclude(shaderc_include_result* data) override; - }; + class ShaderIncluder : public shaderc::CompileOptions::IncluderInterface + { + public: + shaderc_include_result* GetInclude(const char* requested_source, shaderc_include_type type, const char* requesting_source, + size_t include_depth) override; + void ReleaseInclude(shaderc_include_result* data) override; + }; } diff --git a/EppoEngine/Source/Renderer/ShaderLibrary.cpp b/EppoEngine/Source/Renderer/ShaderLibrary.cpp index 098e9dfe..bfd2d7c1 100644 --- a/EppoEngine/Source/Renderer/ShaderLibrary.cpp +++ b/EppoEngine/Source/Renderer/ShaderLibrary.cpp @@ -3,26 +3,26 @@ namespace Eppo { - void ShaderLibrary::Load(const std::string_view path) - { - EPPO_PROFILE_FUNCTION("ShaderLibrary::Load"); + void ShaderLibrary::Load(const std::string_view path) + { + EPPO_PROFILE_FUNCTION("ShaderLibrary::Load"); - ShaderSpecification spec; - spec.Filepath = path; + ShaderSpecification spec; + spec.Filepath = path; - const Ref shader = Shader::Create(spec); - const std::string& name = shader->GetName(); + const Ref shader = Shader::Create(spec); + const std::string& name = shader->GetName(); - std::scoped_lock lock(m_Mutex); + std::scoped_lock lock(m_Mutex); - m_Shaders[name] = shader; - } + m_Shaders[name] = shader; + } - const Ref& ShaderLibrary::Get(const std::string& name) - { - EPPO_PROFILE_FUNCTION("ShaderLibrary::Get"); + const Ref& ShaderLibrary::Get(const std::string& name) + { + EPPO_PROFILE_FUNCTION("ShaderLibrary::Get"); - EPPO_ASSERT(m_Shaders.find(name) != m_Shaders.end()); - return m_Shaders.at(name); - } + EPPO_ASSERT(m_Shaders.contains(name)); + return m_Shaders.at(name); + } } diff --git a/EppoEngine/Source/Renderer/ShaderLibrary.h b/EppoEngine/Source/Renderer/ShaderLibrary.h index 53e3a267..7c88b8a7 100644 --- a/EppoEngine/Source/Renderer/ShaderLibrary.h +++ b/EppoEngine/Source/Renderer/ShaderLibrary.h @@ -4,19 +4,19 @@ namespace Eppo { - class ShaderLibrary - { - public: - ShaderLibrary() = default; - ~ShaderLibrary() = default; - ShaderLibrary(ShaderLibrary&) = delete; - ShaderLibrary& operator=(const ShaderLibrary&) = delete; + class ShaderLibrary + { + public: + ShaderLibrary() = default; + ~ShaderLibrary() = default; + ShaderLibrary(ShaderLibrary&) = delete; + ShaderLibrary& operator=(const ShaderLibrary&) = delete; - void Load(std::string_view path); - const Ref& Get(const std::string& name); + void Load(std::string_view path); + const Ref& Get(const std::string& name); - private: - std::unordered_map> m_Shaders; - std::mutex m_Mutex; - }; + private: + std::unordered_map> m_Shaders; + std::mutex m_Mutex; + }; } diff --git a/EppoEngine/Source/Renderer/UniformBuffer.cpp b/EppoEngine/Source/Renderer/UniformBuffer.cpp index 0854ac85..bc2b09dc 100644 --- a/EppoEngine/Source/Renderer/UniformBuffer.cpp +++ b/EppoEngine/Source/Renderer/UniformBuffer.cpp @@ -6,14 +6,15 @@ namespace Eppo { - Ref UniformBuffer::Create(uint32_t size, uint32_t binding) - { - switch (RendererContext::GetAPI()) - { - case RendererAPI::Vulkan: return CreateRef(size, binding); - } + Ref UniformBuffer::Create(uint32_t size, uint32_t binding) + { + switch (RendererContext::GetAPI()) + { + case RendererAPI::Vulkan: + return CreateRef(size, binding); + } - EPPO_ASSERT(false); - return nullptr; - } + EPPO_ASSERT(false); + return nullptr; + } } diff --git a/EppoEngine/Source/Renderer/UniformBuffer.h b/EppoEngine/Source/Renderer/UniformBuffer.h index 91447d03..297b4170 100644 --- a/EppoEngine/Source/Renderer/UniformBuffer.h +++ b/EppoEngine/Source/Renderer/UniformBuffer.h @@ -2,14 +2,14 @@ namespace Eppo { - class UniformBuffer - { - public: - virtual ~UniformBuffer() = default; + class UniformBuffer + { + public: + virtual ~UniformBuffer() = default; - virtual void SetData(void* data, uint32_t size) = 0; - [[nodiscard]] virtual uint32_t GetBinding() const = 0; + virtual void SetData(void* data, uint32_t size) = 0; + [[nodiscard]] virtual uint32_t GetBinding() const = 0; - static Ref Create(uint32_t size, uint32_t binding); - }; + static Ref Create(uint32_t size, uint32_t binding); + }; } diff --git a/EppoEngine/Source/Renderer/Vertex.h b/EppoEngine/Source/Renderer/Vertex.h index 17c87e11..57b86e40 100644 --- a/EppoEngine/Source/Renderer/Vertex.h +++ b/EppoEngine/Source/Renderer/Vertex.h @@ -4,26 +4,28 @@ namespace Eppo { - struct Vertex - { - glm::vec3 Position = glm::vec3(0.0f); - glm::vec3 Normal = glm::vec3(0.0f); - glm::vec2 TexCoord = glm::vec2(0.0f); + struct Vertex + { + glm::vec3 Position = glm::vec3(0.0f); + glm::vec3 Normal = glm::vec3(0.0f); + glm::vec2 TexCoord = glm::vec2(0.0f); - Vertex() = default; - explicit Vertex(const glm::vec3& position) - : Position(position) - {} - }; + Vertex() = default; - struct LineVertex - { - glm::vec3 Position = glm::vec3(0.0f); - glm::vec4 Color = glm::vec4(0.0f); + explicit Vertex(const glm::vec3& position) + : Position(position) + {} + }; - LineVertex() = default; - LineVertex(const glm::vec3& position, const glm::vec4& color) - : Position(position), Color(color) - {} - }; + struct LineVertex + { + glm::vec3 Position = glm::vec3(0.0f); + glm::vec4 Color = glm::vec4(0.0f); + + LineVertex() = default; + + LineVertex(const glm::vec3& position, const glm::vec4& color) + : Position(position), Color(color) + {} + }; } diff --git a/EppoEngine/Source/Renderer/VertexBuffer.cpp b/EppoEngine/Source/Renderer/VertexBuffer.cpp index 455e408e..744f8a5b 100644 --- a/EppoEngine/Source/Renderer/VertexBuffer.cpp +++ b/EppoEngine/Source/Renderer/VertexBuffer.cpp @@ -6,32 +6,34 @@ namespace Eppo { - Ref VertexBuffer::Create(uint32_t size) - { - switch (RendererContext::GetAPI()) - { - case RendererAPI::Vulkan: return CreateRef(size); - } + Ref VertexBuffer::Create(uint32_t size) + { + switch (RendererContext::GetAPI()) + { + case RendererAPI::Vulkan: + return CreateRef(size); + } - EPPO_ASSERT(false); - return nullptr; - } + EPPO_ASSERT(false); + return nullptr; + } - Ref VertexBuffer::Create(const void* data, const uint32_t size) - { - const Buffer buffer = Buffer::Copy(data, size); + Ref VertexBuffer::Create(const void* data, const uint32_t size) + { + const Buffer buffer = Buffer::Copy(data, size); - return Create(buffer); - } + return Create(buffer); + } - Ref VertexBuffer::Create(Buffer buffer) - { - switch (RendererContext::GetAPI()) - { - case RendererAPI::Vulkan: return CreateRef(buffer); - } + Ref VertexBuffer::Create(Buffer buffer) + { + switch (RendererContext::GetAPI()) + { + case RendererAPI::Vulkan: + return CreateRef(buffer); + } - EPPO_ASSERT(false); - return nullptr; - } + EPPO_ASSERT(false); + return nullptr; + } } diff --git a/EppoEngine/Source/Renderer/VertexBuffer.h b/EppoEngine/Source/Renderer/VertexBuffer.h index b9893de9..02214569 100644 --- a/EppoEngine/Source/Renderer/VertexBuffer.h +++ b/EppoEngine/Source/Renderer/VertexBuffer.h @@ -5,15 +5,15 @@ namespace Eppo { - class VertexBuffer - { - public: - virtual ~VertexBuffer() = default; + class VertexBuffer + { + public: + virtual ~VertexBuffer() = default; - virtual void SetData(Buffer buffer) = 0; + virtual void SetData(Buffer buffer) = 0; - static Ref Create(uint32_t size); - static Ref Create(const void* data, uint32_t size); - static Ref Create(Buffer buffer); - }; + static Ref Create(uint32_t size); + static Ref Create(const void* data, uint32_t size); + static Ref Create(Buffer buffer); + }; } diff --git a/EppoEngine/Source/Renderer/VertexBufferLayout.cpp b/EppoEngine/Source/Renderer/VertexBufferLayout.cpp index bc2ec688..a7bd9e75 100644 --- a/EppoEngine/Source/Renderer/VertexBufferLayout.cpp +++ b/EppoEngine/Source/Renderer/VertexBufferLayout.cpp @@ -5,67 +5,87 @@ namespace Eppo { - namespace Utils - { - uint32_t ShaderDataTypeSize(const ShaderDataType type) - { - switch (type) - { - case ShaderDataType::Float: return 4; - case ShaderDataType::Float2: return 4 * 2; - case ShaderDataType::Float3: return 4 * 3; - case ShaderDataType::Float4: return 4 * 4; - case ShaderDataType::Mat3: return 4 * 3 * 3; - case ShaderDataType::Mat4: return 4 * 4 * 4; - case ShaderDataType::Int: return 4; - case ShaderDataType::Int2: return 4 * 2; - case ShaderDataType::Int3: return 4 * 3; - case ShaderDataType::Int4: return 4 * 4; - case ShaderDataType::Bool: return 1; - } + namespace Utils + { + uint32_t ShaderDataTypeSize(const ShaderDataType type) + { + switch (type) + { + case ShaderDataType::Float: + return 4; + case ShaderDataType::Float2: + return 4 * 2; + case ShaderDataType::Float3: + return 4 * 3; + case ShaderDataType::Float4: + return 4 * 4; + case ShaderDataType::Mat3: + return 4 * 3 * 3; + case ShaderDataType::Mat4: + return 4 * 4 * 4; + case ShaderDataType::Int: + return 4; + case ShaderDataType::Int2: + return 4 * 2; + case ShaderDataType::Int3: + return 4 * 3; + case ShaderDataType::Int4: + return 4 * 4; + case ShaderDataType::Bool: + return 1; + } - EPPO_ASSERT(false); - return 0; - } + EPPO_ASSERT(false); + return 0; + } - uint32_t ShaderDataTypeToVkFormat(const ShaderDataType type) - { - switch (type) - { - case ShaderDataType::Float: return VK_FORMAT_R32_SFLOAT; - case ShaderDataType::Float2: return VK_FORMAT_R32G32_SFLOAT; - case ShaderDataType::Float3: return VK_FORMAT_R32G32B32_SFLOAT; - case ShaderDataType::Float4: return VK_FORMAT_R32G32B32A32_SFLOAT; - //case ShaderDataType::Mat3: return 4 * 3 * 3; - //case ShaderDataType::Mat4: return 4 * 4 * 4; - case ShaderDataType::Int: return VK_FORMAT_R32_SINT; - case ShaderDataType::Int2: return VK_FORMAT_R32G32_SINT; - case ShaderDataType::Int3: return VK_FORMAT_R32G32B32_SINT; - case ShaderDataType::Int4: return VK_FORMAT_R32G32B32A32_SINT; - case ShaderDataType::Bool: return VK_FORMAT_R8_UINT; - } + uint32_t ShaderDataTypeToVkFormat(const ShaderDataType type) + { + switch (type) + { + case ShaderDataType::Float: + return VK_FORMAT_R32_SFLOAT; + case ShaderDataType::Float2: + return VK_FORMAT_R32G32_SFLOAT; + case ShaderDataType::Float3: + return VK_FORMAT_R32G32B32_SFLOAT; + case ShaderDataType::Float4: + return VK_FORMAT_R32G32B32A32_SFLOAT; + //case ShaderDataType::Mat3: return 4 * 3 * 3; + //case ShaderDataType::Mat4: return 4 * 4 * 4; + case ShaderDataType::Int: + return VK_FORMAT_R32_SINT; + case ShaderDataType::Int2: + return VK_FORMAT_R32G32_SINT; + case ShaderDataType::Int3: + return VK_FORMAT_R32G32B32_SINT; + case ShaderDataType::Int4: + return VK_FORMAT_R32G32B32A32_SINT; + case ShaderDataType::Bool: + return VK_FORMAT_R8_UINT; + } - EPPO_ASSERT(false); - return VK_FORMAT_UNDEFINED; - } - } + EPPO_ASSERT(false); + return VK_FORMAT_UNDEFINED; + } + } - VertexBufferLayout::VertexBufferLayout(const std::initializer_list elements) - : m_Elements(elements) - { - CalculateOffsetsAndStride(); - } + VertexBufferLayout::VertexBufferLayout(const std::initializer_list elements) + : m_Elements(elements) + { + CalculateOffsetsAndStride(); + } - void VertexBufferLayout::CalculateOffsetsAndStride() - { - size_t offset = 0; - m_Stride = 0; + void VertexBufferLayout::CalculateOffsetsAndStride() + { + size_t offset = 0; + m_Stride = 0; - for (auto& element : m_Elements) - { - element.Offset = offset; - offset += element.Size; - m_Stride += element.Size; - } - } + for (auto& element : m_Elements) + { + element.Offset = offset; + offset += element.Size; + m_Stride += element.Size; + } + } } diff --git a/EppoEngine/Source/Renderer/VertexBufferLayout.h b/EppoEngine/Source/Renderer/VertexBufferLayout.h index 0cfbac47..7843305e 100644 --- a/EppoEngine/Source/Renderer/VertexBufferLayout.h +++ b/EppoEngine/Source/Renderer/VertexBufferLayout.h @@ -2,71 +2,83 @@ namespace Eppo { - enum class ShaderDataType : uint8_t - { - None = 0, Float, Float2, Float3, Float4, Mat3, Mat4, Int, Int2, Int3, Int4, Bool - }; + enum class ShaderDataType : uint8_t + { + None = 0, Float, Float2, Float3, Float4, Mat3, Mat4, Int, Int2, Int3, Int4, Bool + }; - namespace Utils - { - uint32_t ShaderDataTypeSize(ShaderDataType type); - uint32_t ShaderDataTypeToVkFormat(ShaderDataType type); - } + namespace Utils + { + uint32_t ShaderDataTypeSize(ShaderDataType type); + uint32_t ShaderDataTypeToVkFormat(ShaderDataType type); + } - struct BufferElement - { - ShaderDataType Type; - std::string Name; - uint32_t Size; - size_t Offset; - bool Normalized; + struct BufferElement + { + ShaderDataType Type; + std::string Name; + uint32_t Size; + size_t Offset; + bool Normalized; - BufferElement() = default; - BufferElement(const ShaderDataType type, std::string name, const bool normalized = false) - : Type(type), Name(std::move(name)), Size(Utils::ShaderDataTypeSize(Type)), Offset(0), Normalized(normalized) - {} + BufferElement() = default; - [[nodiscard]] uint32_t GetComponentCount() const - { - switch (Type) - { - case ShaderDataType::Float: return 1; - case ShaderDataType::Float2: return 2; - case ShaderDataType::Float3: return 3; - case ShaderDataType::Float4: return 4; - case ShaderDataType::Mat3: return 3; - case ShaderDataType::Mat4: return 4; - case ShaderDataType::Int: return 1; - case ShaderDataType::Int2: return 2; - case ShaderDataType::Int3: return 3; - case ShaderDataType::Int4: return 4; - case ShaderDataType::Bool: return 1; - } + BufferElement(const ShaderDataType type, std::string name, const bool normalized = false) + : Type(type), Name(std::move(name)), Size(Utils::ShaderDataTypeSize(Type)), Offset(0), Normalized(normalized) + {} - EPPO_ASSERT(false); - return 0; - } - }; + [[nodiscard]] uint32_t GetComponentCount() const + { + switch (Type) + { + case ShaderDataType::Float: + return 1; + case ShaderDataType::Float2: + return 2; + case ShaderDataType::Float3: + return 3; + case ShaderDataType::Float4: + return 4; + case ShaderDataType::Mat3: + return 3; + case ShaderDataType::Mat4: + return 4; + case ShaderDataType::Int: + return 1; + case ShaderDataType::Int2: + return 2; + case ShaderDataType::Int3: + return 3; + case ShaderDataType::Int4: + return 4; + case ShaderDataType::Bool: + return 1; + } - class VertexBufferLayout - { - public: - VertexBufferLayout() = default; - VertexBufferLayout(std::initializer_list elements); + EPPO_ASSERT(false); + return 0; + } + }; - uint32_t GetStride() const { return m_Stride; } - const std::vector& GetElements() const { return m_Elements; } + class VertexBufferLayout + { + public: + VertexBufferLayout() = default; + VertexBufferLayout(std::initializer_list elements); - std::vector::iterator begin() { return m_Elements.begin(); } - std::vector::iterator end() { return m_Elements.end(); } - std::vector::const_iterator begin() const { return m_Elements.begin(); } - std::vector::const_iterator end() const { return m_Elements.end(); } + uint32_t GetStride() const { return m_Stride; } + const std::vector& GetElements() const { return m_Elements; } - private: - void CalculateOffsetsAndStride(); + std::vector::iterator begin() { return m_Elements.begin(); } + std::vector::iterator end() { return m_Elements.end(); } + std::vector::const_iterator begin() const { return m_Elements.begin(); } + std::vector::const_iterator end() const { return m_Elements.end(); } - private: - std::vector m_Elements; - uint32_t m_Stride = 0; - }; + private: + void CalculateOffsetsAndStride(); + + private: + std::vector m_Elements; + uint32_t m_Stride = 0; + }; } diff --git a/EppoEngine/Source/Scene/Components.h b/EppoEngine/Source/Scene/Components.h index 4822b9ae..a7d63064 100644 --- a/EppoEngine/Source/Scene/Components.h +++ b/EppoEngine/Source/Scene/Components.h @@ -14,103 +14,103 @@ namespace Eppo { - struct IDComponent - { - UUID ID; - - IDComponent() = default; - explicit IDComponent(const UUID uuid) - : ID(uuid) - {} - }; - - struct TagComponent - { - std::string Tag; - - TagComponent() = default; - explicit TagComponent(std::string tag) - : Tag(std::move(tag)) - {} - }; - - struct TransformComponent - { - glm::vec3 Translation = glm::vec3(0.0f); - glm::vec3 Rotation = glm::vec3(0.0f); - glm::vec3 Scale = glm::vec3(1.0f); - - TransformComponent() = default; - explicit TransformComponent(const glm::vec3& translation) - : Translation(translation) - {} - - [[nodiscard]] glm::mat4 GetTransform() const - { - return glm::translate(glm::mat4(1.0f), Translation) - * glm::toMat4(glm::quat(Rotation)) - * glm::scale(glm::mat4(1.0f), Scale); - } - }; - - struct SpriteComponent - { - AssetHandle TextureHandle = 0; - glm::vec4 Color = glm::vec4(1.0f); - - SpriteComponent() = default; - explicit SpriteComponent(const glm::vec4& color) - : Color(color) - {} - }; - - struct MeshComponent - { - AssetHandle MeshHandle = 0; - - MeshComponent() = default; - }; - - struct DirectionalLightComponent - { - glm::vec3 Direction = glm::vec3(0.0f); - glm::vec4 AlbedoColor = glm::vec4(1.0f); - glm::vec4 AmbientColor = glm::vec4(1.0f); - glm::vec4 SpecularColor = glm::vec4(1.0f); - - DirectionalLightComponent() = default; - }; - - struct ScriptComponent - { - std::string ClassName; - - ScriptComponent() = default; - }; - - struct RigidBodyComponent - { - enum class BodyType : uint8_t { Static, Dynamic, Kinematic }; - BodyType Type = BodyType::Static; - - float Mass = 1.0f; - - RigidBody RuntimeBody; - - RigidBodyComponent() = default; - }; - - struct CameraComponent - { - SceneCamera Camera; - - CameraComponent() = default; - }; - - struct PointLightComponent - { - glm::vec4 Color = glm::vec4(1.0f); - - PointLightComponent() = default; - }; + struct IDComponent + { + UUID ID; + + IDComponent() = default; + explicit IDComponent(const UUID uuid) + : ID(uuid) + {} + }; + + struct TagComponent + { + std::string Tag; + + TagComponent() = default; + explicit TagComponent(std::string tag) + : Tag(std::move(tag)) + {} + }; + + struct TransformComponent + { + glm::vec3 Translation = glm::vec3(0.0f); + glm::vec3 Rotation = glm::vec3(0.0f); + glm::vec3 Scale = glm::vec3(1.0f); + + TransformComponent() = default; + explicit TransformComponent(const glm::vec3& translation) + : Translation(translation) + {} + + [[nodiscard]] glm::mat4 GetTransform() const + { + return glm::translate(glm::mat4(1.0f), Translation) + * glm::toMat4(glm::quat(Rotation)) + * glm::scale(glm::mat4(1.0f), Scale); + } + }; + + struct SpriteComponent + { + AssetHandle TextureHandle = 0; + glm::vec4 Color = glm::vec4(1.0f); + + SpriteComponent() = default; + explicit SpriteComponent(const glm::vec4& color) + : Color(color) + {} + }; + + struct MeshComponent + { + AssetHandle MeshHandle = 0; + + MeshComponent() = default; + }; + + struct DirectionalLightComponent + { + glm::vec3 Direction = glm::vec3(0.0f); + glm::vec4 AlbedoColor = glm::vec4(1.0f); + glm::vec4 AmbientColor = glm::vec4(1.0f); + glm::vec4 SpecularColor = glm::vec4(1.0f); + + DirectionalLightComponent() = default; + }; + + struct ScriptComponent + { + std::string ClassName; + + ScriptComponent() = default; + }; + + struct RigidBodyComponent + { + enum class BodyType : uint8_t { Static, Dynamic, Kinematic }; + BodyType Type = BodyType::Static; + + float Mass = 1.0f; + + RigidBody RuntimeBody; + + RigidBodyComponent() = default; + }; + + struct CameraComponent + { + SceneCamera Camera; + + CameraComponent() = default; + }; + + struct PointLightComponent + { + glm::vec4 Color = glm::vec4(1.0f); + + PointLightComponent() = default; + }; } diff --git a/EppoEngine/Source/Scene/Entity.cpp b/EppoEngine/Source/Scene/Entity.cpp index 2db4604e..3bea642e 100644 --- a/EppoEngine/Source/Scene/Entity.cpp +++ b/EppoEngine/Source/Scene/Entity.cpp @@ -3,7 +3,7 @@ namespace Eppo { - Entity::Entity(const EntityHandle entityHandle, Scene* scene) - : m_EntityHandle(entityHandle), m_Scene(scene) - {} + Entity::Entity(const EntityHandle entityHandle, Scene* scene) + : m_EntityHandle(entityHandle), m_Scene(scene) + {} } diff --git a/EppoEngine/Source/Scene/Entity.h b/EppoEngine/Source/Scene/Entity.h index 2ce1a9b1..26bf48f7 100644 --- a/EppoEngine/Source/Scene/Entity.h +++ b/EppoEngine/Source/Scene/Entity.h @@ -7,68 +7,68 @@ namespace Eppo { - using EntityHandle = entt::entity; + using EntityHandle = entt::entity; - class Entity - { - public: - Entity() = default; - Entity(EntityHandle entityHandle, Scene* scene); - Entity(const Entity& other) = default; + class Entity + { + public: + Entity() = default; + Entity(EntityHandle entityHandle, Scene* scene); + Entity(const Entity& other) = default; - template - [[nodiscard]] bool HasComponent() const - { - return m_Scene->m_Registry.all_of(m_EntityHandle); - } + template + [[nodiscard]] bool HasComponent() const + { + return m_Scene->m_Registry.all_of(m_EntityHandle); + } - template - T& AddComponent(Args&&... args) - { - EPPO_ASSERT(!HasComponent()); - T& component = m_Scene->m_Registry.emplace(m_EntityHandle, std::forward(args)...); - return component; - } + template + T& AddComponent(Args&&... args) + { + EPPO_ASSERT(!HasComponent()); + T& component = m_Scene->m_Registry.emplace(m_EntityHandle, std::forward(args)...); + return component; + } - template - T& AddOrReplaceComponent(Args&&... args) - { - T& component = m_Scene->m_Registry.emplace_or_replace(m_EntityHandle, std::forward(args)...); - return component; - } + template + T& AddOrReplaceComponent(Args&&... args) + { + T& component = m_Scene->m_Registry.emplace_or_replace(m_EntityHandle, std::forward(args)...); + return component; + } - template - void RemoveComponent() const - { - EPPO_ASSERT(HasComponent()); - m_Scene->m_Registry.remove(m_EntityHandle); - } + template + void RemoveComponent() const + { + EPPO_ASSERT(HasComponent()); + m_Scene->m_Registry.remove(m_EntityHandle); + } - template - T& GetComponent() - { + template + T& GetComponent() + { EPPO_ASSERT(HasComponent()); - return m_Scene->m_Registry.get(m_EntityHandle); - } + return m_Scene->m_Registry.get(m_EntityHandle); + } - explicit operator bool() const { return m_EntityHandle != entt::null; } - explicit operator EntityHandle() const { return m_EntityHandle; } + explicit operator bool() const { return m_EntityHandle != entt::null; } + explicit operator EntityHandle() const { return m_EntityHandle; } - bool operator==(const Entity& other) const - { - return m_EntityHandle == other.m_EntityHandle && m_Scene == other.m_Scene; - } + bool operator==(const Entity& other) const + { + return m_EntityHandle == other.m_EntityHandle && m_Scene == other.m_Scene; + } - bool operator!=(const Entity& other) const - { - return !(*this == other); - } - - const std::string& GetName() { return GetComponent().Tag; } - const UUID& GetUUID() { return GetComponent().ID; } + bool operator!=(const Entity& other) const + { + return !(*this == other); + } + + const std::string& GetName() { return GetComponent().Tag; } + const UUID& GetUUID() { return GetComponent().ID; } - private: - EntityHandle m_EntityHandle = entt::null; - Scene* m_Scene; - }; + private: + EntityHandle m_EntityHandle = entt::null; + Scene* m_Scene; + }; } diff --git a/EppoEngine/Source/Scene/Scene.cpp b/EppoEngine/Source/Scene/Scene.cpp index 67fa8ef3..de6c0039 100644 --- a/EppoEngine/Source/Scene/Scene.cpp +++ b/EppoEngine/Source/Scene/Scene.cpp @@ -11,393 +11,372 @@ namespace Eppo { - namespace - { - auto* s_collisionConfig = new btDefaultCollisionConfiguration(); - auto* s_collisionDispatcher = new btCollisionDispatcher(s_collisionConfig); - btBroadphaseInterface* s_broadPhaseInterface = new btDbvtBroadphase(); - auto* s_Solver = new btSequentialImpulseConstraintSolver(); - - glm::vec3 BulletToGlm(const btVector3& v) - { - return { v.getX(), v.getY(), v.getZ() }; - } - - glm::quat BulletToGlm(const btQuaternion& q) - { - return { q.getW(), q.getX(), q.getY(), q.getZ() }; - } - - btVector3 GlmToBullet(const glm::vec3& v) - { - return { v.x, v.y, v.z }; - } - - btQuaternion GlmToBullet(const glm::quat& q) - { - return { q.x, q.y, q.z, q.w }; - } - } - - void Scene::SetViewportSize(const uint32_t width, const uint32_t height) - { - EPPO_PROFILE_FUNCTION("Scene::SetViewportSize"); - - const auto view = m_Registry.view(); - for (const auto e : view) - { - auto& component = m_Registry.get(e); - component.Camera.SetViewportSize(width, height); - } - } - - void Scene::OnUpdateRuntime(const float timestep) - { - EPPO_PROFILE_FUNCTION("Scene::OnUpdateRuntime"); - - // Scripts - { - const auto view = m_Registry.view(); - for (const auto e : view) - { - const Entity entity(e, this); - ScriptEngine::OnUpdateEntity(entity, timestep); - } - } - - // Physics - m_PhysicsWorld->stepSimulation(timestep, 10); - - const auto view = m_Registry.view(); - for (const auto e : view) - { - Entity entity(e, this); - auto& transform = entity.GetComponent(); - const auto& rigidbody = entity.GetComponent(); - - btRigidBody* body = rigidbody.RuntimeBody.Body; - btTransform trans; - - if (body && body->getMotionState()) - body->getMotionState()->getWorldTransform(trans); - - const auto& position = trans.getOrigin(); - transform.Translation = BulletToGlm(position); - - trans.getRotation().getEulerZYX(transform.Rotation.z, transform.Rotation.y, transform.Rotation.x); - } - } - - void Scene::OnRenderEditor(const Ref& sceneRenderer, const EditorCamera& editorCamera) - { - EPPO_PROFILE_FUNCTION("Scene::OnRenderEditor"); - - sceneRenderer->BeginScene(editorCamera); - - RenderScene(sceneRenderer); - - sceneRenderer->EndScene(); - } - - void Scene::OnRenderRuntime(const Ref& sceneRenderer) - { - EPPO_PROFILE_FUNCTION("Scene::OnRenderRuntime"); - - const SceneCamera* sceneCamera = nullptr; - glm::mat4 cameraTransform; - - const auto view = m_Registry.view(); - for (const auto e : view) - { - auto [transform, camera] = view.get(e); - sceneCamera = &camera.Camera; - cameraTransform = transform.GetTransform(); - - break; - } - - if (sceneCamera) - { - sceneRenderer->BeginScene(*sceneCamera, cameraTransform); - - RenderScene(sceneRenderer); - - sceneRenderer->EndScene(); - } - } - - void Scene::OnRuntimeStart() - { - EPPO_PROFILE_FUNCTION("Scene::OnRuntimeStart"); - - m_IsRunning = true; - - OnPhysicsStart(); - ScriptEngine::OnRuntimeStart(); - - const auto view = m_Registry.view(); - for (const auto e : view) - { - const Entity entity(e, this); - ScriptEngine::OnCreateEntity(entity); - } - } - - void Scene::OnRuntimeStop() - { - EPPO_PROFILE_FUNCTION("Scene::OnRuntimeStop"); - - m_IsRunning = false; - - OnPhysicsStop(); - ScriptEngine::OnRuntimeStop(); - } - - Ref Scene::Copy(const Ref& scene) - { - EPPO_PROFILE_FUNCTION("Scene::Copy"); - - // Create a new scene and get a reference to both entity registries - Ref newScene = CreateRef(); + namespace + { + auto* s_collisionConfig = new btDefaultCollisionConfiguration(); + auto* s_collisionDispatcher = new btCollisionDispatcher(s_collisionConfig); + btBroadphaseInterface* s_broadPhaseInterface = new btDbvtBroadphase(); + auto* s_Solver = new btSequentialImpulseConstraintSolver(); + + glm::vec3 BulletToGlm(const btVector3& v) + { + return { v.getX(), v.getY(), v.getZ() }; + } + + glm::quat BulletToGlm(const btQuaternion& q) + { + return { q.getW(), q.getX(), q.getY(), q.getZ() }; + } + + btVector3 GlmToBullet(const glm::vec3& v) + { + return { v.x, v.y, v.z }; + } + + btQuaternion GlmToBullet(const glm::quat& q) + { + return { q.x, q.y, q.z, q.w }; + } + } + + void Scene::SetViewportSize(const uint32_t width, const uint32_t height) + { + EPPO_PROFILE_FUNCTION("Scene::SetViewportSize"); + + for (const auto view = m_Registry.view(); const auto e : view) + { + auto& component = m_Registry.get(e); + component.Camera.SetViewportSize(width, height); + } + } + + void Scene::OnUpdateRuntime(const float timestep) + { + EPPO_PROFILE_FUNCTION("Scene::OnUpdateRuntime"); + + // Scripts + for (const auto view = m_Registry.view(); const auto e : view) + { + const Entity entity(e, this); + ScriptEngine::OnUpdateEntity(entity, timestep); + } + + // Physics + m_PhysicsWorld->stepSimulation(timestep, 10); + + for (const auto view = m_Registry.view(); const auto e : view) + { + Entity entity(e, this); + auto& transform = entity.GetComponent(); + const auto& rigidbody = entity.GetComponent(); + + btRigidBody* body = rigidbody.RuntimeBody.Body; + btTransform trans; + + if (body && body->getMotionState()) + body->getMotionState()->getWorldTransform(trans); + + const auto& position = trans.getOrigin(); + transform.Translation = BulletToGlm(position); + + trans.getRotation().getEulerZYX(transform.Rotation.z, transform.Rotation.y, transform.Rotation.x); + } + } + + void Scene::OnRenderEditor(const Ref& sceneRenderer, const EditorCamera& editorCamera) + { + EPPO_PROFILE_FUNCTION("Scene::OnRenderEditor"); + + sceneRenderer->BeginScene(editorCamera); + + RenderScene(sceneRenderer); + + sceneRenderer->EndScene(); + } + + void Scene::OnRenderRuntime(const Ref& sceneRenderer) + { + EPPO_PROFILE_FUNCTION("Scene::OnRenderRuntime"); + + const SceneCamera* sceneCamera = nullptr; + glm::mat4 cameraTransform; + + for (const auto view = m_Registry.view(); const auto e : view) + { + auto [transform, camera] = view.get(e); + sceneCamera = &camera.Camera; + cameraTransform = transform.GetTransform(); + + break; + } + + if (sceneCamera) + { + sceneRenderer->BeginScene(*sceneCamera, cameraTransform); + + RenderScene(sceneRenderer); + + sceneRenderer->EndScene(); + } + } + + void Scene::OnRuntimeStart() + { + EPPO_PROFILE_FUNCTION("Scene::OnRuntimeStart"); + + m_IsRunning = true; + + OnPhysicsStart(); + ScriptEngine::OnRuntimeStart(); + + const auto view = m_Registry.view(); + for (const auto e : view) + { + const Entity entity(e, this); + ScriptEngine::OnCreateEntity(entity); + } + } + + void Scene::OnRuntimeStop() + { + EPPO_PROFILE_FUNCTION("Scene::OnRuntimeStop"); + + m_IsRunning = false; - auto& srcRegistry = scene->m_Registry; - auto& dstRegistry = newScene->m_Registry; + OnPhysicsStop(); + ScriptEngine::OnRuntimeStop(); + } - // Every entity in the scene has an ID component - std::unordered_map entityMap; - const auto idView = srcRegistry.view(); + Ref Scene::Copy(const Ref& scene) + { + EPPO_PROFILE_FUNCTION("Scene::Copy"); - for (const auto entity : idView) - { - auto uuid = srcRegistry.get(entity).ID; - const auto& name = srcRegistry.get(entity).Tag; - Entity newEntity = newScene->CreateEntityWithUUID(uuid, name); - entityMap[uuid] = static_cast(newEntity); - } + // Create a new scene and get a reference to both entity registries + Ref newScene = CreateRef(); - CopyComponent(srcRegistry, dstRegistry, entityMap); - CopyComponent(srcRegistry, dstRegistry, entityMap); - CopyComponent(srcRegistry, dstRegistry, entityMap); - CopyComponent(srcRegistry, dstRegistry, entityMap); - CopyComponent(srcRegistry, dstRegistry, entityMap); - CopyComponent(srcRegistry, dstRegistry, entityMap); - CopyComponent(srcRegistry, dstRegistry, entityMap); - - return newScene; - } - - template - void Scene::TryCopyComponent(Entity srcEntity, Entity dstEntity) - { - EPPO_PROFILE_FUNCTION("Scene::TryCopyComponent"); - - if (srcEntity.HasComponent()) - dstEntity.AddOrReplaceComponent(srcEntity.GetComponent()); - } - - template - void Scene::CopyComponent(entt::registry& srcRegistry, entt::registry& dstRegistry, const std::unordered_map& entityMap) - { - EPPO_PROFILE_FUNCTION("Scene::CopyComponent"); - - auto view = srcRegistry.view(); - - for (auto srcEntity : view) - { - entt::entity dstEntity = entityMap.at(srcRegistry.get(srcEntity).ID); - auto& srcComponent = srcRegistry.get(srcEntity); - dstRegistry.emplace_or_replace(dstEntity, srcComponent); - } - } - - Entity Scene::CreateEntity(const std::string& name) - { - EPPO_PROFILE_FUNCTION("Scene::CreateEntity"); - - return CreateEntityWithUUID(UUID(), name); - } - - Entity Scene::CreateEntityWithUUID(UUID uuid, const std::string& name) - { - EPPO_PROFILE_FUNCTION("Scene::CreateEntityWithUUID"); - - Entity entity(m_Registry.create(), this); - - entity.AddComponent(uuid); - entity.AddComponent(); - - auto& tag = entity.AddComponent(); - tag.Tag = name.empty() ? "Entity" : name; - - m_EntityMap[uuid] = static_cast(entity); - - return entity; - } - - Entity Scene::DuplicateEntity(Entity entity) - { - EPPO_PROFILE_FUNCTION("Scene::DuplicateEntity"); - - const std::string name = entity.GetName(); - const Entity newEntity = CreateEntity(name); - - TryCopyComponent(entity, newEntity); - TryCopyComponent(entity, newEntity); - TryCopyComponent(entity, newEntity); - TryCopyComponent(entity, newEntity); - TryCopyComponent(entity, newEntity); - TryCopyComponent(entity, newEntity); - TryCopyComponent(entity, newEntity); - - return newEntity; - } - - void Scene::DestroyEntity(Entity entity) - { - EPPO_PROFILE_FUNCTION("Scene::DestroyEntity"); - - m_EntityMap.erase(entity.GetUUID()); - m_Registry.destroy(static_cast(entity)); - } - - Entity Scene::FindEntityByUUID(const UUID uuid) - { - EPPO_PROFILE_FUNCTION("Scene::FindEntityByUUID"); - - if (const auto it = m_EntityMap.find(uuid); - it != m_EntityMap.end()) - { - return { it->second, this }; - } - - return {}; - } - - Entity Scene::FindEntityByName(const std::string_view name) - { - EPPO_PROFILE_FUNCTION("Scene::FindEntityByName"); - - const auto view = m_Registry.view(); - for (auto e : view) - { - const auto& tc = view.get(e); - if (tc.Tag == name) - return { e, this }; - } - - return {}; - } - - void Scene::OnPhysicsStart() - { - EPPO_PROFILE_FUNCTION("Scene::OnPhysicsStart"); - - m_PhysicsWorld = new btDiscreteDynamicsWorld(s_collisionDispatcher, s_broadPhaseInterface, s_Solver, s_collisionConfig); - m_PhysicsWorld->setGravity(btVector3(0.0f, -9.81f, 0.0f)); - - const auto view = m_Registry.view(); - for (const auto e : view) - { - Entity entity(e, this); - const auto& transform = entity.GetComponent(); - auto& rigidbody = entity.GetComponent(); - - btCollisionShape* shape = new btBoxShape(btVector3(transform.Scale.x, transform.Scale.y, transform.Scale.z)); - - btTransform bTransform; - bTransform.setIdentity(); - bTransform.setOrigin(btVector3(transform.Translation.x, transform.Translation.y, transform.Translation.z)); - bTransform.setRotation(GlmToBullet(glm::quat(transform.Rotation))); - - const bool isDynamic = rigidbody.Type == RigidBodyComponent::BodyType::Dynamic; - btScalar mass(0.0f); - if (isDynamic) - mass = rigidbody.Mass; - - auto localInertia(btVector3(0.0f, 0.0f, 0.0f)); - if (isDynamic) - shape->calculateLocalInertia(mass, localInertia); - - auto* motionState = new btDefaultMotionState(bTransform); - btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, motionState, shape, localInertia); - auto* body = new btRigidBody(rbInfo); - - m_PhysicsWorld->addRigidBody(body); - rigidbody.RuntimeBody = RigidBody(body); - } - } - - void Scene::OnPhysicsStop() - { - EPPO_PROFILE_FUNCTION("Scene::OnPhysicsStop"); - - for (int i = m_PhysicsWorld->getNumCollisionObjects() - 1; i >= 0; i--) - { - btCollisionObject* obj = m_PhysicsWorld->getCollisionObjectArray()[i]; - btRigidBody* body = btRigidBody::upcast(obj); - - if (body && body->getMotionState()) - delete body->getMotionState(); - - if (body && body->getCollisionShape()) - delete body->getCollisionShape(); - - m_PhysicsWorld->removeCollisionObject(obj); - delete obj; - } - - const auto view = m_Registry.view(); - for (const auto e : view) - { - Entity entity(e, this); - auto& rigidbody = entity.GetComponent(); - - rigidbody.RuntimeBody.Body = nullptr; - } - - delete m_PhysicsWorld; - m_PhysicsWorld = nullptr; - } - - void Scene::RenderScene(const Ref& sceneRenderer) - { - EPPO_PROFILE_FUNCTION("Scene::RenderScene"); - - { - const auto view = m_Registry.view(); - - for (const EntityHandle entity : view) - { - if (auto [meshC, transform] = view.get(entity); - meshC.MeshHandle) - { - if (const Ref mesh = AssetManager::GetAsset(meshC.MeshHandle)) - { - Ref meshCommand = CreateRef(); - meshCommand->Handle = entity; - meshCommand->Mesh = mesh; - meshCommand->Transform = transform.GetTransform(); - - sceneRenderer->SubmitDrawCommand(EntityType::Mesh, meshCommand); - } - } - } - } - - { - const auto view = m_Registry.view(); - - for (const EntityHandle entity : view) - { - auto [pl, transform] = view.get(entity); - - Ref pointLightCommand = CreateRef(); - pointLightCommand->Handle = entity; - pointLightCommand->Position = transform.Translation; - pointLightCommand->Color = pl.Color; - - sceneRenderer->SubmitDrawCommand(EntityType::PointLight, pointLightCommand); - } - } - } + auto& srcRegistry = scene->m_Registry; + auto& dstRegistry = newScene->m_Registry; + + // Every entity in the scene has an ID component + std::unordered_map entityMap; + + for (const auto idView = srcRegistry.view(); const auto entity : idView) + { + auto uuid = srcRegistry.get(entity).ID; + const auto& name = srcRegistry.get(entity).Tag; + Entity newEntity = newScene->CreateEntityWithUUID(uuid, name); + entityMap[uuid] = static_cast(newEntity); + } + + CopyComponent(srcRegistry, dstRegistry, entityMap); + CopyComponent(srcRegistry, dstRegistry, entityMap); + CopyComponent(srcRegistry, dstRegistry, entityMap); + CopyComponent(srcRegistry, dstRegistry, entityMap); + CopyComponent(srcRegistry, dstRegistry, entityMap); + CopyComponent(srcRegistry, dstRegistry, entityMap); + CopyComponent(srcRegistry, dstRegistry, entityMap); + + return newScene; + } + + template + void Scene::TryCopyComponent(Entity srcEntity, Entity dstEntity) + { + EPPO_PROFILE_FUNCTION("Scene::TryCopyComponent"); + + if (srcEntity.HasComponent()) + dstEntity.AddOrReplaceComponent(srcEntity.GetComponent()); + } + + template + void Scene::CopyComponent(entt::registry& srcRegistry, entt::registry& dstRegistry, const std::unordered_map& entityMap) + { + EPPO_PROFILE_FUNCTION("Scene::CopyComponent"); + + for (auto view = srcRegistry.view(); auto srcEntity : view) + { + entt::entity dstEntity = entityMap.at(srcRegistry.get(srcEntity).ID); + auto& srcComponent = srcRegistry.get(srcEntity); + dstRegistry.emplace_or_replace(dstEntity, srcComponent); + } + } + + Entity Scene::CreateEntity(const std::string& name) + { + EPPO_PROFILE_FUNCTION("Scene::CreateEntity"); + + return CreateEntityWithUUID(UUID(), name); + } + + Entity Scene::CreateEntityWithUUID(UUID uuid, const std::string& name) + { + EPPO_PROFILE_FUNCTION("Scene::CreateEntityWithUUID"); + + Entity entity(m_Registry.create(), this); + + entity.AddComponent(uuid); + entity.AddComponent(); + + auto& tag = entity.AddComponent(); + tag.Tag = name.empty() ? "Entity" : name; + + m_EntityMap[uuid] = static_cast(entity); + + return entity; + } + + Entity Scene::DuplicateEntity(Entity entity) + { + EPPO_PROFILE_FUNCTION("Scene::DuplicateEntity"); + + const std::string name = entity.GetName(); + const Entity newEntity = CreateEntity(name); + + TryCopyComponent(entity, newEntity); + TryCopyComponent(entity, newEntity); + TryCopyComponent(entity, newEntity); + TryCopyComponent(entity, newEntity); + TryCopyComponent(entity, newEntity); + TryCopyComponent(entity, newEntity); + TryCopyComponent(entity, newEntity); + + return newEntity; + } + + void Scene::DestroyEntity(Entity entity) + { + EPPO_PROFILE_FUNCTION("Scene::DestroyEntity"); + + m_EntityMap.erase(entity.GetUUID()); + m_Registry.destroy(static_cast(entity)); + } + + Entity Scene::FindEntityByUUID(const UUID uuid) + { + EPPO_PROFILE_FUNCTION("Scene::FindEntityByUUID"); + + if (const auto it = m_EntityMap.find(uuid); + it != m_EntityMap.end()) + { + return { it->second, this }; + } + + return {}; + } + + Entity Scene::FindEntityByName(const std::string_view name) + { + EPPO_PROFILE_FUNCTION("Scene::FindEntityByName"); + + for (const auto view = m_Registry.view(); auto e : view) + { + const auto& tc = view.get(e); + if (tc.Tag == name) + return { e, this }; + } + + return {}; + } + + void Scene::OnPhysicsStart() + { + EPPO_PROFILE_FUNCTION("Scene::OnPhysicsStart"); + + m_PhysicsWorld = new btDiscreteDynamicsWorld(s_collisionDispatcher, s_broadPhaseInterface, s_Solver, s_collisionConfig); + m_PhysicsWorld->setGravity(btVector3(0.0f, -9.81f, 0.0f)); + + for (const auto view = m_Registry.view(); const auto e : view) + { + Entity entity(e, this); + const auto& transform = entity.GetComponent(); + auto& rigidbody = entity.GetComponent(); + + btCollisionShape* shape = new btBoxShape(btVector3(transform.Scale.x, transform.Scale.y, transform.Scale.z)); + + btTransform bTransform; + bTransform.setIdentity(); + bTransform.setOrigin(btVector3(transform.Translation.x, transform.Translation.y, transform.Translation.z)); + bTransform.setRotation(GlmToBullet(glm::quat(transform.Rotation))); + + const bool isDynamic = rigidbody.Type == RigidBodyComponent::BodyType::Dynamic; + btScalar mass(0.0f); + if (isDynamic) + mass = rigidbody.Mass; + + auto localInertia(btVector3(0.0f, 0.0f, 0.0f)); + if (isDynamic) + shape->calculateLocalInertia(mass, localInertia); + + auto* motionState = new btDefaultMotionState(bTransform); + btRigidBody::btRigidBodyConstructionInfo rbInfo(mass, motionState, shape, localInertia); + auto* body = new btRigidBody(rbInfo); + + m_PhysicsWorld->addRigidBody(body); + rigidbody.RuntimeBody = RigidBody(body); + } + } + + void Scene::OnPhysicsStop() + { + EPPO_PROFILE_FUNCTION("Scene::OnPhysicsStop"); + + for (int i = m_PhysicsWorld->getNumCollisionObjects() - 1; i >= 0; i--) + { + btCollisionObject* obj = m_PhysicsWorld->getCollisionObjectArray()[i]; + btRigidBody* body = btRigidBody::upcast(obj); + + if (body && body->getMotionState()) + delete body->getMotionState(); + + if (body && body->getCollisionShape()) + delete body->getCollisionShape(); + + m_PhysicsWorld->removeCollisionObject(obj); + delete obj; + } + + for (const auto view = m_Registry.view(); const auto e : view) + { + Entity entity(e, this); + auto& rigidbody = entity.GetComponent(); + + rigidbody.RuntimeBody.Body = nullptr; + } + + delete m_PhysicsWorld; + m_PhysicsWorld = nullptr; + } + + void Scene::RenderScene(const Ref& sceneRenderer) + { + EPPO_PROFILE_FUNCTION("Scene::RenderScene"); + + for (const auto view = m_Registry.view(); const EntityHandle entity : view) + { + if (auto [meshC, transform] = view.get(entity); meshC.MeshHandle) + { + if (const Ref mesh = AssetManager::GetAsset(meshC.MeshHandle)) + { + Ref meshCommand = CreateRef(); + meshCommand->Handle = entity; + meshCommand->Mesh = mesh; + meshCommand->Transform = transform.GetTransform(); + + sceneRenderer->SubmitDrawCommand(EntityType::Mesh, meshCommand); + } + } + } + + for (const auto view = m_Registry.view(); const EntityHandle entity : view) + { + auto [pl, transform] = view.get(entity); + + Ref pointLightCommand = CreateRef(); + pointLightCommand->Handle = entity; + pointLightCommand->Position = transform.Translation; + pointLightCommand->Color = pl.Color; + + sceneRenderer->SubmitDrawCommand(EntityType::PointLight, pointLightCommand); + } + } } diff --git a/EppoEngine/Source/Scene/Scene.h b/EppoEngine/Source/Scene/Scene.h index 79149977..907f14b3 100644 --- a/EppoEngine/Source/Scene/Scene.h +++ b/EppoEngine/Source/Scene/Scene.h @@ -10,59 +10,59 @@ class btDiscreteDynamicsWorld; namespace Eppo { - class Entity; - class SceneRenderer; + class Entity; + class SceneRenderer; - class Scene : public Asset - { - public: - Scene() = default; - ~Scene() override = default; + class Scene final : public Asset + { + public: + Scene() = default; + ~Scene() override = default; - void SetViewportSize(uint32_t width, uint32_t height); + void SetViewportSize(uint32_t width, uint32_t height); - void OnUpdateRuntime(float timestep); + void OnUpdateRuntime(float timestep); - void OnRenderEditor(const Ref& sceneRenderer, const EditorCamera& editorCamera); - void OnRenderRuntime(const Ref& sceneRenderer); + void OnRenderEditor(const Ref& sceneRenderer, const EditorCamera& editorCamera); + void OnRenderRuntime(const Ref& sceneRenderer); - void OnRuntimeStart(); - void OnRuntimeStop(); + void OnRuntimeStart(); + void OnRuntimeStop(); - static Ref Copy(const Ref& scene); + static Ref Copy(const Ref& scene); - template - static void TryCopyComponent(Entity srcEntity, Entity dstEntity); + template + static void TryCopyComponent(Entity srcEntity, Entity dstEntity); - template - static void CopyComponent(entt::registry& srcRegistry, entt::registry& dstRegistry, const std::unordered_map& entityMap); + template + static void CopyComponent(entt::registry& srcRegistry, entt::registry& dstRegistry, const std::unordered_map& entityMap); - Entity CreateEntity(const std::string& name = std::string()); - Entity CreateEntityWithUUID(UUID uuid, const std::string& name); - Entity DuplicateEntity(Entity entity); - void DestroyEntity(Entity entity); + Entity CreateEntity(const std::string& name = std::string()); + Entity CreateEntityWithUUID(UUID uuid, const std::string& name); + Entity DuplicateEntity(Entity entity); + void DestroyEntity(Entity entity); - Entity FindEntityByUUID(UUID uuid); - Entity FindEntityByName(std::string_view name); + Entity FindEntityByUUID(UUID uuid); + Entity FindEntityByName(std::string_view name); - [[nodiscard]] bool IsRunning() const { return m_IsRunning; } + [[nodiscard]] bool IsRunning() const { return m_IsRunning; } - private: - void OnPhysicsStart(); - void OnPhysicsStop(); + private: + void OnPhysicsStart(); + void OnPhysicsStop(); - void RenderScene(const Ref& sceneRenderer); + void RenderScene(const Ref& sceneRenderer); - private: - entt::registry m_Registry; - std::unordered_map m_EntityMap; + private: + entt::registry m_Registry; + std::unordered_map m_EntityMap; - btDiscreteDynamicsWorld* m_PhysicsWorld = nullptr; + btDiscreteDynamicsWorld* m_PhysicsWorld = nullptr; - bool m_IsRunning = false; + bool m_IsRunning = false; - friend class Entity; - friend class SceneHierarchyPanel; - friend class SceneSerializer; - }; + friend class Entity; + friend class SceneHierarchyPanel; + friend class SceneSerializer; + }; } diff --git a/EppoEngine/Source/Scene/SceneSerializer.cpp b/EppoEngine/Source/Scene/SceneSerializer.cpp index fd861107..99a86166 100644 --- a/EppoEngine/Source/Scene/SceneSerializer.cpp +++ b/EppoEngine/Source/Scene/SceneSerializer.cpp @@ -9,464 +9,463 @@ namespace YAML { - Emitter& operator<<(Emitter& out, const glm::vec2& v) - { - out << YAML::Flow; - out << YAML::BeginSeq << v.x << v.y << YAML::EndSeq; - return out; - } - - Emitter& operator<<(Emitter& out, const glm::vec3& v) - { - out << YAML::Flow; - out << YAML::BeginSeq << v.x << v.y << v.z << YAML::EndSeq; - return out; - } - - Emitter& operator<<(Emitter& out, const glm::vec4& v) - { - out << YAML::Flow; - out << YAML::BeginSeq << v.x << v.y << v.z << v.w << YAML::EndSeq; - return out; - } - - template<> - struct convert - { - static bool decode(const Node& node, glm::vec2& v) - { - if (!node.IsSequence() || node.size() != 2) - return false; - - v.x = node[0].as(); - v.y = node[1].as(); - - return true; - } - }; - - template<> - struct convert - { - static bool decode(const Node& node, glm::vec3& v) - { - if (!node.IsSequence() || node.size() != 3) - return false; - - v.x = node[0].as(); - v.y = node[1].as(); - v.z = node[2].as(); - - return true; - } - }; - - template<> - struct convert - { - static bool decode(const Node& node, glm::vec4& v) - { - if (!node.IsSequence() || node.size() != 4) - return false; - - v.x = node[0].as(); - v.y = node[1].as(); - v.z = node[2].as(); - v.w = node[3].as(); - - return true; - } - }; - - template<> - struct convert - { - static bool decode(const Node& node, Eppo::UUID& uuid) - { - if (node.IsSequence()) - return false; - - uuid = node[0].as(); - - return true; - } - }; + Emitter& operator<<(Emitter& out, const glm::vec2& v) + { + out << YAML::Flow; + out << YAML::BeginSeq << v.x << v.y << YAML::EndSeq; + return out; + } + + Emitter& operator<<(Emitter& out, const glm::vec3& v) + { + out << YAML::Flow; + out << YAML::BeginSeq << v.x << v.y << v.z << YAML::EndSeq; + return out; + } + + Emitter& operator<<(Emitter& out, const glm::vec4& v) + { + out << YAML::Flow; + out << YAML::BeginSeq << v.x << v.y << v.z << v.w << YAML::EndSeq; + return out; + } + + template<> + struct convert + { + static bool decode(const Node& node, glm::vec2& v) + { + if (!node.IsSequence() || node.size() != 2) + return false; + + v.x = node[0].as(); + v.y = node[1].as(); + + return true; + } + }; + + template<> + struct convert + { + static bool decode(const Node& node, glm::vec3& v) + { + if (!node.IsSequence() || node.size() != 3) + return false; + + v.x = node[0].as(); + v.y = node[1].as(); + v.z = node[2].as(); + + return true; + } + }; + + template<> + struct convert + { + static bool decode(const Node& node, glm::vec4& v) + { + if (!node.IsSequence() || node.size() != 4) + return false; + + v.x = node[0].as(); + v.y = node[1].as(); + v.z = node[2].as(); + v.w = node[3].as(); + + return true; + } + }; + + template<> + struct convert + { + static bool decode(const Node& node, Eppo::UUID& uuid) + { + if (node.IsSequence()) + return false; + + uuid = node[0].as(); + + return true; + } + }; } namespace Eppo { - #define WRITE_SCRIPT_FIELD(FieldType, Type) \ - case ScriptFieldType::FieldType: \ - out << scriptField.GetValue(); \ - break - - #define READ_SCRIPT_FIELD(FieldType, Type) \ - case ScriptFieldType::FieldType: \ - { \ - Type data = scriptField["Data"].as(); \ - fieldInstance.SetValue(data); \ - break; \ - } - - SceneSerializer::SceneSerializer(const Ref& scene) - : m_SceneContext(scene) - {} - - bool SceneSerializer::Serialize(const std::filesystem::path& filepath) - { - EPPO_PROFILE_FUNCTION("SceneSerializer:Serialize"); - - std::string sceneName = filepath.stem().string(); - - EPPO_INFO("Serializing scene '{}' ({})", sceneName, m_SceneContext->Handle); - - YAML::Emitter out; - out << YAML::BeginMap; - out << YAML::Key << "Scene" << YAML::Value << sceneName; - out << YAML::Key << "Entities" << YAML::Value << YAML::BeginSeq; - - m_SceneContext->m_Registry.sort([](const auto& lhs, const auto& rhs) { return lhs.ID < rhs.ID; }); - const auto view = m_SceneContext->m_Registry.view(); - for (const auto e : view) - { - const Entity entity(e, m_SceneContext.get()); - if (!entity) - continue; - - SerializeEntity(out, entity); - } - - out << YAML::EndSeq << YAML::EndMap; - - Filesystem::WriteText(filepath, out.c_str()); - - return true; - } - - bool SceneSerializer::Deserialize(const std::filesystem::path& filepath) const - { - EPPO_PROFILE_FUNCTION("SceneSerializer:Deserialize"); - - YAML::Node data; - - try - { - data = YAML::LoadFile(filepath.string()); - } - catch (YAML::ParserException& e) - { - EPPO_ERROR("Failed to load scene file '{}'!", filepath); - EPPO_ERROR("YAML Error: {}", e.what()); - return false; - } - - if (!data["Scene"]) - { - EPPO_ERROR("Failed to load scene file '{}'! Not a scene file!", filepath); - return false; - } - - auto sceneName = data["Scene"].as(); - EPPO_INFO("Deserializing scene '{}'", sceneName); - - auto entities = data["Entities"]; - - if (!entities) - { - EPPO_WARN("Scene '{}' has no entities, are you sure this is correct?", sceneName); - return true; - } - - for (auto entity : entities) - { - UUID uuid = entity["Entity"].as(); - std::string tag; - - if (auto tagComponent = entity["TagComponent"]; tagComponent) - tag = tagComponent["Tag"].as(); - - Entity newEntity = m_SceneContext->CreateEntityWithUUID(uuid, tag); - EPPO_INFO("Deserializing entity '{}' ({})", tag, uuid); - - if (auto c = entity["TransformComponent"]) - { - auto& nc = newEntity.GetComponent(); - nc.Translation = c["Translation"].as(); - nc.Rotation = c["Rotation"].as(); - nc.Scale = c["Scale"].as(); - } - - if (auto c = entity["SpriteComponent"]) - { - auto& nc = newEntity.AddComponent(); - nc.Color = c["Color"].as(); - nc.TextureHandle = c["TextureHandle"].as(); - } - - if (auto c = entity["MeshComponent"]) - { - auto& [meshHandle] = newEntity.AddComponent(); - meshHandle = c["MeshHandle"].as(); - } - - if (auto c = entity["DirectionalLightComponent"]) - { - auto& [direction, albedoColor, ambientColor, specularColor] = newEntity.AddComponent(); - direction = c["Direction"].as(); - albedoColor = c["Albedo"].as(); - ambientColor = c["Ambient"].as(); - specularColor = c["Specular"].as(); - } - - if (auto c = entity["ScriptComponent"]) - { - auto& [className] = newEntity.AddComponent(); - className = c["ClassName"].as(); - - if (auto scriptFields = c["Fields"]) - { - Ref entityClass = ScriptEngine::GetEntityClass(className); +#define WRITE_SCRIPT_FIELD(FieldType, Type) \ + case ScriptFieldType::FieldType: \ + out << scriptField.GetValue(); \ + break + +#define READ_SCRIPT_FIELD(FieldType, Type) \ + case ScriptFieldType::FieldType: \ + { \ + Type data = scriptField["Data"].as(); \ + fieldInstance.SetValue(data); \ + break; \ + } + + SceneSerializer::SceneSerializer(const Ref& scene) + : m_SceneContext(scene) + {} + + bool SceneSerializer::Serialize(const std::filesystem::path& filepath) + { + EPPO_PROFILE_FUNCTION("SceneSerializer:Serialize"); + + std::string sceneName = filepath.stem().string(); + + EPPO_INFO("Serializing scene '{}' ({})", sceneName, m_SceneContext->Handle); + + YAML::Emitter out; + out << YAML::BeginMap; + out << YAML::Key << "Scene" << YAML::Value << sceneName; + out << YAML::Key << "Entities" << YAML::Value << YAML::BeginSeq; + + m_SceneContext->m_Registry.sort([](const auto& lhs, const auto& rhs) { return lhs.ID < rhs.ID; }); + const auto view = m_SceneContext->m_Registry.view(); + for (const auto e : view) + { + const Entity entity(e, m_SceneContext.get()); + if (!entity) + continue; + + SerializeEntity(out, entity); + } + + out << YAML::EndSeq << YAML::EndMap; + + Filesystem::WriteText(filepath, out.c_str()); + + return true; + } + + bool SceneSerializer::Deserialize(const std::filesystem::path& filepath) const + { + EPPO_PROFILE_FUNCTION("SceneSerializer:Deserialize"); + + YAML::Node data; + + try + { + data = YAML::LoadFile(filepath.string()); + } + catch (YAML::ParserException& e) + { + EPPO_ERROR("Failed to load scene file '{}'!", filepath); + EPPO_ERROR("YAML Error: {}", e.what()); + return false; + } + + if (!data["Scene"]) + { + EPPO_ERROR("Failed to load scene file '{}'! Not a scene file!", filepath); + return false; + } + + auto sceneName = data["Scene"].as(); + EPPO_INFO("Deserializing scene '{}'", sceneName); + + auto entities = data["Entities"]; + + if (!entities) + { + EPPO_WARN("Scene '{}' has no entities, are you sure this is correct?", sceneName); + return true; + } + + for (auto entity : entities) + { + UUID uuid = entity["Entity"].as(); + std::string tag; + + if (auto tagComponent = entity["TagComponent"]; tagComponent) + tag = tagComponent["Tag"].as(); + + Entity newEntity = m_SceneContext->CreateEntityWithUUID(uuid, tag); + EPPO_INFO("Deserializing entity '{}' ({})", tag, uuid); + + if (auto c = entity["TransformComponent"]) + { + auto& nc = newEntity.GetComponent(); + nc.Translation = c["Translation"].as(); + nc.Rotation = c["Rotation"].as(); + nc.Scale = c["Scale"].as(); + } + + if (auto c = entity["SpriteComponent"]) + { + auto& nc = newEntity.AddComponent(); + nc.Color = c["Color"].as(); + nc.TextureHandle = c["TextureHandle"].as(); + } + + if (auto c = entity["MeshComponent"]) + { + auto& [meshHandle] = newEntity.AddComponent(); + meshHandle = c["MeshHandle"].as(); + } + + if (auto c = entity["DirectionalLightComponent"]) + { + auto& [direction, albedoColor, ambientColor, specularColor] = newEntity.AddComponent(); + direction = c["Direction"].as(); + albedoColor = c["Albedo"].as(); + ambientColor = c["Ambient"].as(); + specularColor = c["Specular"].as(); + } + + if (auto c = entity["ScriptComponent"]) + { + auto& [className] = newEntity.AddComponent(); + className = c["ClassName"].as(); + + if (auto scriptFields = c["Fields"]) + { + Ref entityClass = ScriptEngine::GetEntityClass(className); EPPO_ASSERT(entityClass); - const auto& fields = entityClass->GetFields(); - auto& entityFields = ScriptEngine::GetScriptFieldMap(uuid); - - for (auto scriptField : scriptFields) - { - auto name = scriptField["Name"].as(); - auto typeString = scriptField["Type"].as(); - ScriptFieldType type = Utils::ScriptFieldTypeFromString(typeString); - - ScriptFieldInstance& fieldInstance = entityFields[name]; - - if (fields.find(name) == fields.end()) - { - EPPO_ERROR("Mono field not found!"); - continue; - } - - fieldInstance.Field = fields.at(name); - - switch (type) - { - READ_SCRIPT_FIELD(Float, float) - READ_SCRIPT_FIELD(Double, double) - READ_SCRIPT_FIELD(Bool, bool) - READ_SCRIPT_FIELD(Char, int8_t) - READ_SCRIPT_FIELD(Int16, int16_t) - READ_SCRIPT_FIELD(Int32, int32_t) - READ_SCRIPT_FIELD(Int64, int64_t) - READ_SCRIPT_FIELD(Byte, uint8_t) - READ_SCRIPT_FIELD(UInt16, uint16_t) - READ_SCRIPT_FIELD(UInt32, uint32_t) - READ_SCRIPT_FIELD(UInt64, uint64_t) - READ_SCRIPT_FIELD(Vector2, glm::vec2) - READ_SCRIPT_FIELD(Vector3, glm::vec3) - READ_SCRIPT_FIELD(Vector4, glm::vec4) - READ_SCRIPT_FIELD(Entity, UUID) - } - } - } - } - - if (auto c = entity["RigidBodyComponent"]) - { - auto& rbc = newEntity.AddComponent(); - rbc.Type = static_cast(c["BodyType"].as()); - rbc.Mass = c["Mass"].as(); - } - - if (auto c = entity["CameraComponent"]) - { - auto& [camera] = newEntity.AddComponent(); - camera.SetProjectionType(static_cast(c["ProjectionType"].as())); - camera.SetPerspectiveFov(c["PerspectiveFov"].as()); - camera.SetPerspectiveNearClip(c["PerspectiveNearClip"].as()); - camera.SetPerspectiveFarClip(c["PerspectiveFarClip"].as()); - camera.SetOrthographicSize(c["OrthographicSize"].as()); - camera.SetOrthographicNearClip(c["OrthographicNearClip"].as()); - camera.SetOrthographicFarClip(c["OrthographicFarClip"].as()); - } - - if (auto c = entity["PointLightComponent"]) - { - auto& [color] = newEntity.AddComponent(); - color = c["Color"].as(); - } - } - - return true; - } - - void SceneSerializer::SerializeEntity(YAML::Emitter& out, Entity entity) - { - EPPO_ASSERT(entity.HasComponent() && entity.HasComponent()); - - EPPO_INFO("Serializing entity '{}' ({})", entity.GetName(), entity.GetUUID()); - - out << YAML::BeginMap; - - out << YAML::Key << "Entity" << YAML::Value << entity.GetUUID(); - - if (entity.HasComponent()) - { - out << YAML::Key << "TagComponent" << YAML::Value; - out << YAML::BeginMap; - - out << YAML::Key << "Tag" << YAML::Value << entity.GetName(); - - out << YAML::EndMap; - } - - if (entity.HasComponent()) - { - out << YAML::Key << "TransformComponent" << YAML::Value; - out << YAML::BeginMap; - - const auto& c = entity.GetComponent(); - out << YAML::Key << "Translation" << YAML::Value << c.Translation; - out << YAML::Key << "Rotation" << YAML::Value << c.Rotation; - out << YAML::Key << "Scale" << YAML::Value << c.Scale; - - out << YAML::EndMap; - } - - if (entity.HasComponent()) - { - out << YAML::Key << "SpriteComponent" << YAML::Value; - out << YAML::BeginMap; - - const auto& c = entity.GetComponent(); - out << YAML::Key << "Color" << YAML::Value << c.Color; - out << YAML::Key << "TextureHandle" << YAML::Value << c.TextureHandle; - - out << YAML::EndMap; - } - - if (entity.HasComponent()) - { - out << YAML::Key << "MeshComponent" << YAML::Value; - out << YAML::BeginMap; - - const auto& [meshHandle] = entity.GetComponent(); - out << YAML::Key << "MeshHandle" << YAML::Value << meshHandle; - - out << YAML::EndMap; - } - - if (entity.HasComponent()) - { - out << YAML::Key << "DirectionalLightComponent" << YAML::Value; - out << YAML::BeginMap; - - const auto& [direction, albedoColor, ambientColor, specularColor] = entity.GetComponent(); - out << YAML::Key << "Direction" << YAML::Value << direction; - out << YAML::Key << "Albedo" << YAML::Value << albedoColor; - out << YAML::Key << "Ambient" << YAML::Value << ambientColor; - out << YAML::Key << "Specular" << YAML::Value << specularColor; - - out << YAML::EndMap; - } - - if (entity.HasComponent()) - { - out << YAML::Key << "ScriptComponent" << YAML::Value; - out << YAML::BeginMap; - - const auto& [className] = entity.GetComponent(); - out << YAML::Key << "ClassName" << YAML::Value << className; - - // Fields - if (const auto entityClass = ScriptEngine::GetEntityClass(className)) - { - if (const auto& fields = entityClass->GetFields(); - !fields.empty()) - { - out << YAML::Key << "Fields" << YAML::Value; - out << YAML::BeginSeq; - - auto& entityFields = ScriptEngine::GetScriptFieldMap(entity.GetUUID()); - for (const auto& [name, field] : fields) - { - if (entityFields.find(name) == entityFields.end()) - continue; - - out << YAML::BeginMap; - out << YAML::Key << "Name" << YAML::Value << name; - out << YAML::Key << "Type" << YAML::Value << Utils::ScriptFieldTypeToString(field.Type); - out << YAML::Key << "Data" << YAML::Value; - - ScriptFieldInstance& scriptField = entityFields.at(name); - - switch (field.Type) - { - WRITE_SCRIPT_FIELD(Float, float); - WRITE_SCRIPT_FIELD(Double, double); - WRITE_SCRIPT_FIELD(Bool, bool); - WRITE_SCRIPT_FIELD(Char, int8_t); - WRITE_SCRIPT_FIELD(Int16, int16_t); - WRITE_SCRIPT_FIELD(Int32, int32_t); - WRITE_SCRIPT_FIELD(Int64, int64_t); - WRITE_SCRIPT_FIELD(Byte, uint8_t); - WRITE_SCRIPT_FIELD(UInt16, uint16_t); - WRITE_SCRIPT_FIELD(UInt32, uint32_t); - WRITE_SCRIPT_FIELD(UInt64, uint64_t); - WRITE_SCRIPT_FIELD(Vector2, glm::vec2); - WRITE_SCRIPT_FIELD(Vector3, glm::vec3); - WRITE_SCRIPT_FIELD(Vector4, glm::vec4); - WRITE_SCRIPT_FIELD(Entity, UUID); - } - out << YAML::EndMap; - } - out << YAML::EndSeq; - } - } - out << YAML::EndMap; - } - - if (entity.HasComponent()) - { - out << YAML::Key << "RigidBodyComponent" << YAML::Value; - out << YAML::BeginMap; - - const auto& c = entity.GetComponent(); - out << YAML::Key << "BodyType" << YAML::Value << static_cast(c.Type); - out << YAML::Key << "Mass" << YAML::Value << c.Mass; - - out << YAML::EndMap; - } - - if (entity.HasComponent()) - { - out << YAML::Key << "CameraComponent" << YAML::Value; - out << YAML::BeginMap; - - const auto& [camera] = entity.GetComponent(); - const auto& cc = camera; - - out << YAML::Key << "ProjectionType" << YAML::Value << static_cast(cc.GetProjectionType()); - out << YAML::Key << "PerspectiveFov" << YAML::Value << cc.GetPerspectiveFov(); - out << YAML::Key << "PerspectiveNearClip" << YAML::Value << cc.GetPerspectiveNearClip(); - out << YAML::Key << "PerspectiveFarClip" << YAML::Value << cc.GetPerspectiveFarClip(); - out << YAML::Key << "OrthographicSize" << YAML::Value << cc.GetOrthographicSize(); - out << YAML::Key << "OrthographicNearClip" << YAML::Value << cc.GetOrthographicNearClip(); - out << YAML::Key << "OrthographicFarClip" << YAML::Value << cc.GetOrthographicFarClip(); - - out << YAML::EndMap; - } - - if (entity.HasComponent()) - { - out << YAML::Key << "PointLightComponent" << YAML::Value; - out << YAML::BeginMap; - - const auto& [color] = entity.GetComponent(); - - out << YAML::Key << "Color" << YAML::Value << color; - - out << YAML::EndMap; - } - - out << YAML::EndMap; - } + const auto& fields = entityClass->GetFields(); + auto& entityFields = ScriptEngine::GetScriptFieldMap(uuid); + + for (auto scriptField : scriptFields) + { + auto name = scriptField["Name"].as(); + auto typeString = scriptField["Type"].as(); + ScriptFieldType type = Utils::ScriptFieldTypeFromString(typeString); + + ScriptFieldInstance& fieldInstance = entityFields[name]; + + if (fields.find(name) == fields.end()) + { + EPPO_ERROR("Mono field not found!"); + continue; + } + + fieldInstance.Field = fields.at(name); + + switch (type) + { + READ_SCRIPT_FIELD(Float, float) + READ_SCRIPT_FIELD(Double, double) + READ_SCRIPT_FIELD(Bool, bool) + READ_SCRIPT_FIELD(Char, int8_t) + READ_SCRIPT_FIELD(Int16, int16_t) + READ_SCRIPT_FIELD(Int32, int32_t) + READ_SCRIPT_FIELD(Int64, int64_t) + READ_SCRIPT_FIELD(Byte, uint8_t) + READ_SCRIPT_FIELD(UInt16, uint16_t) + READ_SCRIPT_FIELD(UInt32, uint32_t) + READ_SCRIPT_FIELD(UInt64, uint64_t) + READ_SCRIPT_FIELD(Vector2, glm::vec2) + READ_SCRIPT_FIELD(Vector3, glm::vec3) + READ_SCRIPT_FIELD(Vector4, glm::vec4) + READ_SCRIPT_FIELD(Entity, UUID) + } + } + } + } + + if (auto c = entity["RigidBodyComponent"]) + { + auto& rbc = newEntity.AddComponent(); + rbc.Type = static_cast(c["BodyType"].as()); + rbc.Mass = c["Mass"].as(); + } + + if (auto c = entity["CameraComponent"]) + { + auto& [camera] = newEntity.AddComponent(); + camera.SetProjectionType(static_cast(c["ProjectionType"].as())); + camera.SetPerspectiveFov(c["PerspectiveFov"].as()); + camera.SetPerspectiveNearClip(c["PerspectiveNearClip"].as()); + camera.SetPerspectiveFarClip(c["PerspectiveFarClip"].as()); + camera.SetOrthographicSize(c["OrthographicSize"].as()); + camera.SetOrthographicNearClip(c["OrthographicNearClip"].as()); + camera.SetOrthographicFarClip(c["OrthographicFarClip"].as()); + } + + if (auto c = entity["PointLightComponent"]) + { + auto& [color] = newEntity.AddComponent(); + color = c["Color"].as(); + } + } + + return true; + } + + void SceneSerializer::SerializeEntity(YAML::Emitter& out, Entity entity) + { + EPPO_ASSERT(entity.HasComponent() && entity.HasComponent()); + + EPPO_INFO("Serializing entity '{}' ({})", entity.GetName(), entity.GetUUID()); + + out << YAML::BeginMap; + + out << YAML::Key << "Entity" << YAML::Value << entity.GetUUID(); + + if (entity.HasComponent()) + { + out << YAML::Key << "TagComponent" << YAML::Value; + out << YAML::BeginMap; + + out << YAML::Key << "Tag" << YAML::Value << entity.GetName(); + + out << YAML::EndMap; + } + + if (entity.HasComponent()) + { + out << YAML::Key << "TransformComponent" << YAML::Value; + out << YAML::BeginMap; + + const auto& c = entity.GetComponent(); + out << YAML::Key << "Translation" << YAML::Value << c.Translation; + out << YAML::Key << "Rotation" << YAML::Value << c.Rotation; + out << YAML::Key << "Scale" << YAML::Value << c.Scale; + + out << YAML::EndMap; + } + + if (entity.HasComponent()) + { + out << YAML::Key << "SpriteComponent" << YAML::Value; + out << YAML::BeginMap; + + const auto& c = entity.GetComponent(); + out << YAML::Key << "Color" << YAML::Value << c.Color; + out << YAML::Key << "TextureHandle" << YAML::Value << c.TextureHandle; + + out << YAML::EndMap; + } + + if (entity.HasComponent()) + { + out << YAML::Key << "MeshComponent" << YAML::Value; + out << YAML::BeginMap; + + const auto& [meshHandle] = entity.GetComponent(); + out << YAML::Key << "MeshHandle" << YAML::Value << meshHandle; + + out << YAML::EndMap; + } + + if (entity.HasComponent()) + { + out << YAML::Key << "DirectionalLightComponent" << YAML::Value; + out << YAML::BeginMap; + + const auto& [direction, albedoColor, ambientColor, specularColor] = entity.GetComponent(); + out << YAML::Key << "Direction" << YAML::Value << direction; + out << YAML::Key << "Albedo" << YAML::Value << albedoColor; + out << YAML::Key << "Ambient" << YAML::Value << ambientColor; + out << YAML::Key << "Specular" << YAML::Value << specularColor; + + out << YAML::EndMap; + } + + if (entity.HasComponent()) + { + out << YAML::Key << "ScriptComponent" << YAML::Value; + out << YAML::BeginMap; + + const auto& [className] = entity.GetComponent(); + out << YAML::Key << "ClassName" << YAML::Value << className; + + // Fields + if (const auto entityClass = ScriptEngine::GetEntityClass(className)) + { + if (const auto& fields = entityClass->GetFields(); !fields.empty()) + { + out << YAML::Key << "Fields" << YAML::Value; + out << YAML::BeginSeq; + + auto& entityFields = ScriptEngine::GetScriptFieldMap(entity.GetUUID()); + for (const auto& [name, field] : fields) + { + if (entityFields.find(name) == entityFields.end()) + continue; + + out << YAML::BeginMap; + out << YAML::Key << "Name" << YAML::Value << name; + out << YAML::Key << "Type" << YAML::Value << Utils::ScriptFieldTypeToString(field.Type); + out << YAML::Key << "Data" << YAML::Value; + + ScriptFieldInstance& scriptField = entityFields.at(name); + + switch (field.Type) + { + WRITE_SCRIPT_FIELD(Float, float); + WRITE_SCRIPT_FIELD(Double, double); + WRITE_SCRIPT_FIELD(Bool, bool); + WRITE_SCRIPT_FIELD(Char, int8_t); + WRITE_SCRIPT_FIELD(Int16, int16_t); + WRITE_SCRIPT_FIELD(Int32, int32_t); + WRITE_SCRIPT_FIELD(Int64, int64_t); + WRITE_SCRIPT_FIELD(Byte, uint8_t); + WRITE_SCRIPT_FIELD(UInt16, uint16_t); + WRITE_SCRIPT_FIELD(UInt32, uint32_t); + WRITE_SCRIPT_FIELD(UInt64, uint64_t); + WRITE_SCRIPT_FIELD(Vector2, glm::vec2); + WRITE_SCRIPT_FIELD(Vector3, glm::vec3); + WRITE_SCRIPT_FIELD(Vector4, glm::vec4); + WRITE_SCRIPT_FIELD(Entity, UUID); + } + out << YAML::EndMap; + } + out << YAML::EndSeq; + } + } + out << YAML::EndMap; + } + + if (entity.HasComponent()) + { + out << YAML::Key << "RigidBodyComponent" << YAML::Value; + out << YAML::BeginMap; + + const auto& c = entity.GetComponent(); + out << YAML::Key << "BodyType" << YAML::Value << static_cast(c.Type); + out << YAML::Key << "Mass" << YAML::Value << c.Mass; + + out << YAML::EndMap; + } + + if (entity.HasComponent()) + { + out << YAML::Key << "CameraComponent" << YAML::Value; + out << YAML::BeginMap; + + const auto& [camera] = entity.GetComponent(); + const auto& cc = camera; + + out << YAML::Key << "ProjectionType" << YAML::Value << static_cast(cc.GetProjectionType()); + out << YAML::Key << "PerspectiveFov" << YAML::Value << cc.GetPerspectiveFov(); + out << YAML::Key << "PerspectiveNearClip" << YAML::Value << cc.GetPerspectiveNearClip(); + out << YAML::Key << "PerspectiveFarClip" << YAML::Value << cc.GetPerspectiveFarClip(); + out << YAML::Key << "OrthographicSize" << YAML::Value << cc.GetOrthographicSize(); + out << YAML::Key << "OrthographicNearClip" << YAML::Value << cc.GetOrthographicNearClip(); + out << YAML::Key << "OrthographicFarClip" << YAML::Value << cc.GetOrthographicFarClip(); + + out << YAML::EndMap; + } + + if (entity.HasComponent()) + { + out << YAML::Key << "PointLightComponent" << YAML::Value; + out << YAML::BeginMap; + + const auto& [color] = entity.GetComponent(); + + out << YAML::Key << "Color" << YAML::Value << color; + + out << YAML::EndMap; + } + + out << YAML::EndMap; + } } diff --git a/EppoEngine/Source/Scene/SceneSerializer.h b/EppoEngine/Source/Scene/SceneSerializer.h index 20abb2b1..7fdb4b11 100644 --- a/EppoEngine/Source/Scene/SceneSerializer.h +++ b/EppoEngine/Source/Scene/SceneSerializer.h @@ -5,23 +5,23 @@ namespace YAML { - class Emitter; + class Emitter; } namespace Eppo { - class SceneSerializer - { - public: - explicit SceneSerializer(const Ref& scene); + class SceneSerializer + { + public: + explicit SceneSerializer(const Ref& scene); - bool Serialize(const std::filesystem::path& filepath); - [[nodiscard]] bool Deserialize(const std::filesystem::path& filepath) const; + bool Serialize(const std::filesystem::path& filepath); + [[nodiscard]] bool Deserialize(const std::filesystem::path& filepath) const; - private: - void SerializeEntity(YAML::Emitter& out, Entity entity); + private: + void SerializeEntity(YAML::Emitter& out, Entity entity); - private: - Ref m_SceneContext; - }; + private: + Ref m_SceneContext; + }; } diff --git a/EppoEngine/Source/Scripting/ScriptClass.cpp b/EppoEngine/Source/Scripting/ScriptClass.cpp index 7a866fbd..0dbb1147 100644 --- a/EppoEngine/Source/Scripting/ScriptClass.cpp +++ b/EppoEngine/Source/Scripting/ScriptClass.cpp @@ -7,45 +7,45 @@ namespace Eppo { - ScriptClass::ScriptClass(std::string nameSpace, std::string name, const bool isCore) - : m_Namespace(std::move(nameSpace)), m_Name(std::move(name)) - { - EPPO_PROFILE_FUNCTION("ScriptClass::ScriptClass"); - - if (isCore) - m_MonoClass = mono_class_from_name(ScriptEngine::GetCoreAssemblyImage(), m_Namespace.c_str(), m_Name.c_str()); - else - m_MonoClass = mono_class_from_name(ScriptEngine::GetAppAssemblyImage(), m_Namespace.c_str(), m_Name.c_str()); - } - - ScriptClass::ScriptClass(MonoClass* monoClass) - : m_MonoClass(monoClass) - { - EPPO_PROFILE_FUNCTION("ScriptClass::ScriptClass"); - - m_Namespace = mono_class_get_namespace(m_MonoClass); - m_Name = mono_class_get_name(m_MonoClass); - } - - MonoObject* ScriptClass::Instantiate() const - { - EPPO_PROFILE_FUNCTION("ScriptClass::Instantiate"); - - return ScriptEngine::InstantiateClass(m_MonoClass); - } - - MonoMethod* ScriptClass::GetMethod(const std::string& name, const uint32_t paramCount) const - { - EPPO_PROFILE_FUNCTION("ScriptClass::GetMethod"); - - return mono_class_get_method_from_name(m_MonoClass, name.c_str(), static_cast(paramCount)); - } - - MonoObject* ScriptClass::InvokeMethod(MonoObject* instance, MonoMethod* method, void** params) - { - EPPO_PROFILE_FUNCTION("ScriptClass::InvokeMethod"); - - MonoObject* exception = nullptr; - return mono_runtime_invoke(method, instance, params, &exception); - } + ScriptClass::ScriptClass(std::string nameSpace, std::string name, const bool isCore) + : m_Namespace(std::move(nameSpace)), m_Name(std::move(name)) + { + EPPO_PROFILE_FUNCTION("ScriptClass::ScriptClass"); + + if (isCore) + m_MonoClass = mono_class_from_name(ScriptEngine::GetCoreAssemblyImage(), m_Namespace.c_str(), m_Name.c_str()); + else + m_MonoClass = mono_class_from_name(ScriptEngine::GetAppAssemblyImage(), m_Namespace.c_str(), m_Name.c_str()); + } + + ScriptClass::ScriptClass(MonoClass* monoClass) + : m_MonoClass(monoClass) + { + EPPO_PROFILE_FUNCTION("ScriptClass::ScriptClass"); + + m_Namespace = mono_class_get_namespace(m_MonoClass); + m_Name = mono_class_get_name(m_MonoClass); + } + + MonoObject* ScriptClass::Instantiate() const + { + EPPO_PROFILE_FUNCTION("ScriptClass::Instantiate"); + + return ScriptEngine::InstantiateClass(m_MonoClass); + } + + MonoMethod* ScriptClass::GetMethod(const std::string& name, const uint32_t paramCount) const + { + EPPO_PROFILE_FUNCTION("ScriptClass::GetMethod"); + + return mono_class_get_method_from_name(m_MonoClass, name.c_str(), static_cast(paramCount)); + } + + MonoObject* ScriptClass::InvokeMethod(MonoObject* instance, MonoMethod* method, void** params) + { + EPPO_PROFILE_FUNCTION("ScriptClass::InvokeMethod"); + + MonoObject* exception = nullptr; + return mono_runtime_invoke(method, instance, params, &exception); + } } diff --git a/EppoEngine/Source/Scripting/ScriptClass.h b/EppoEngine/Source/Scripting/ScriptClass.h index 149260a8..5d9a35eb 100644 --- a/EppoEngine/Source/Scripting/ScriptClass.h +++ b/EppoEngine/Source/Scripting/ScriptClass.h @@ -8,27 +8,27 @@ typedef struct _MonoObject MonoObject; namespace Eppo { - class ScriptClass - { - public: - ScriptClass() = default; - ScriptClass(std::string nameSpace, std::string name, bool isCore = false); - explicit ScriptClass(MonoClass* monoClass); + class ScriptClass + { + public: + ScriptClass() = default; + ScriptClass(std::string nameSpace, std::string name, bool isCore = false); + explicit ScriptClass(MonoClass* monoClass); - [[nodiscard]] MonoObject* Instantiate() const; - [[nodiscard]] MonoMethod* GetMethod(const std::string& name, uint32_t paramCount) const; - static MonoObject* InvokeMethod(MonoObject* instance, MonoMethod* method, void** params = nullptr); + [[nodiscard]] MonoObject* Instantiate() const; + [[nodiscard]] MonoMethod* GetMethod(const std::string& name, uint32_t paramCount) const; + static MonoObject* InvokeMethod(MonoObject* instance, MonoMethod* method, void** params = nullptr); - [[nodiscard]] const std::unordered_map& GetFields() const { return m_Fields; } + [[nodiscard]] const std::unordered_map& GetFields() const { return m_Fields; } - private: - std::string m_Namespace; - std::string m_Name; + private: + std::string m_Namespace; + std::string m_Name; - std::unordered_map m_Fields; + std::unordered_map m_Fields; - MonoClass* m_MonoClass = nullptr; + MonoClass* m_MonoClass = nullptr; - friend class ScriptEngine; - }; + friend class ScriptEngine; + }; } diff --git a/EppoEngine/Source/Scripting/ScriptEngine.cpp b/EppoEngine/Source/Scripting/ScriptEngine.cpp index 7319a43d..db149178 100644 --- a/EppoEngine/Source/Scripting/ScriptEngine.cpp +++ b/EppoEngine/Source/Scripting/ScriptEngine.cpp @@ -16,455 +16,449 @@ namespace Eppo { - struct ScriptEngineData - { - MonoDomain* RootDomain = nullptr; - MonoDomain* AppDomain = nullptr; + struct ScriptEngineData + { + MonoDomain* RootDomain = nullptr; + MonoDomain* AppDomain = nullptr; - MonoAssembly* CoreAssembly = nullptr; - MonoImage* CoreAssemblyImage = nullptr; - std::filesystem::path CoreAssemblyFilepath; + MonoAssembly* CoreAssembly = nullptr; + MonoImage* CoreAssemblyImage = nullptr; + std::filesystem::path CoreAssemblyFilepath; - MonoAssembly* AppAssembly = nullptr; - MonoImage* AppAssemblyImage = nullptr; - std::filesystem::path AppAssemblyFilepath; - Scope> AppAssemblyFileWatcher; - bool AppAssemblyReloadPending = false; + MonoAssembly* AppAssembly = nullptr; + MonoImage* AppAssemblyImage = nullptr; + std::filesystem::path AppAssemblyFilepath; + Scope> AppAssemblyFileWatcher; + bool AppAssemblyReloadPending = false; - Ref EntityClass; + Ref EntityClass; - std::unordered_map> EntityScriptClasses; - std::unordered_map> EntityScriptInstances; - std::unordered_map EntityScriptFields; + std::unordered_map> EntityScriptClasses; + std::unordered_map> EntityScriptInstances; + std::unordered_map EntityScriptFields; - Ref SceneContext; + Ref SceneContext; #if defined(EPPO_DEBUG) - bool EnableDebugging = true; + bool EnableDebugging = true; #else - bool EnableDebugging = false; + bool EnableDebugging = false; #endif - }; - - namespace - { - std::unordered_map s_ScriptFieldTypeMap { - { "System.Single", ScriptFieldType::Float }, - { "System.Double", ScriptFieldType::Double }, - { "System.Boolean", ScriptFieldType::Bool }, - { "System.Char", ScriptFieldType::Char }, - { "System.Int16", ScriptFieldType::Int16 }, - { "System.Int32", ScriptFieldType::Int32 }, - { "System.Int64", ScriptFieldType::Int64 }, - { "System.Byte", ScriptFieldType::Byte }, - { "System.UInt16", ScriptFieldType::UInt16 }, - { "System.UInt32", ScriptFieldType::UInt32 }, - { "System.UInt64", ScriptFieldType::UInt64 }, + }; + + namespace + { + std::unordered_map s_ScriptFieldTypeMap{ + { "System.Single", ScriptFieldType::Float }, + { "System.Double", ScriptFieldType::Double }, + { "System.Boolean", ScriptFieldType::Bool }, + { "System.Char", ScriptFieldType::Char }, + { "System.Int16", ScriptFieldType::Int16 }, + { "System.Int32", ScriptFieldType::Int32 }, + { "System.Int64", ScriptFieldType::Int64 }, + { "System.Byte", ScriptFieldType::Byte }, + { "System.UInt16", ScriptFieldType::UInt16 }, + { "System.UInt32", ScriptFieldType::UInt32 }, + { "System.UInt64", ScriptFieldType::UInt64 }, - { "Eppo.Vector2", ScriptFieldType::Vector2 }, - { "Eppo.Vector3", ScriptFieldType::Vector3 }, - { "Eppo.Vector4", ScriptFieldType::Vector4 }, + { "Eppo.Vector2", ScriptFieldType::Vector2 }, + { "Eppo.Vector3", ScriptFieldType::Vector3 }, + { "Eppo.Vector4", ScriptFieldType::Vector4 }, - { "Eppo.Entity", ScriptFieldType::Entity }, - }; + { "Eppo.Entity", ScriptFieldType::Entity }, + }; - ScriptEngineData* s_Data; + ScriptEngineData* s_Data; - MonoAssembly* LoadMonoAssembly(const std::filesystem::path& filepath, const bool loadPDB = false) - { - ScopedBuffer buffer(Filesystem::ReadBytes(filepath)); + MonoAssembly* LoadMonoAssembly(const std::filesystem::path& filepath, const bool loadPDB = false) + { + ScopedBuffer buffer(Filesystem::ReadBytes(filepath)); - MonoImageOpenStatus status; - MonoImage* image = mono_image_open_from_data_full(buffer.As(), buffer.Size(), 1, &status, 0); + MonoImageOpenStatus status; + MonoImage* image = mono_image_open_from_data_full(buffer.As(), buffer.Size(), 1, &status, 0); - if (status != MONO_IMAGE_OK) - { - const char* error = mono_image_strerror(status); - EPPO_ERROR(error); - return nullptr; - } + if (status != MONO_IMAGE_OK) + { + const char* error = mono_image_strerror(status); + EPPO_ERROR(error); + return nullptr; + } - if (loadPDB) - { - std::filesystem::path pdbPath = filepath; - pdbPath.replace_extension(".pdb"); + if (loadPDB) + { + std::filesystem::path pdbPath = filepath; + pdbPath.replace_extension(".pdb"); - if (Filesystem::Exists(pdbPath)) - { - ScopedBuffer pdbBuffer(Filesystem::ReadBytes(pdbPath)); - mono_debug_open_image_from_memory(image, pdbBuffer.As(), static_cast(pdbBuffer.Size())); - EPPO_INFO("Loaded PDB: {}", pdbPath); - } - } + if (Filesystem::Exists(pdbPath)) + { + ScopedBuffer pdbBuffer(Filesystem::ReadBytes(pdbPath)); + mono_debug_open_image_from_memory(image, pdbBuffer.As(), static_cast(pdbBuffer.Size())); + EPPO_INFO("Loaded PDB: {}", pdbPath); + } + } - MonoAssembly* assembly = mono_assembly_load_from_full(image, filepath.string().c_str(), &status, 0); - mono_image_close(image); + MonoAssembly* assembly = mono_assembly_load_from_full(image, filepath.string().c_str(), &status, 0); + mono_image_close(image); - return assembly; - } + return assembly; + } - ScriptFieldType MonoTypeToScriptFieldType(MonoType* monoType) - { - const std::string type = mono_type_get_name(monoType); + ScriptFieldType MonoTypeToScriptFieldType(MonoType* monoType) + { + const std::string type = mono_type_get_name(monoType); - if (const auto it = s_ScriptFieldTypeMap.find(type); - it != s_ScriptFieldTypeMap.end()) - { - return it->second; - } + if (const auto it = s_ScriptFieldTypeMap.find(type); it != s_ScriptFieldTypeMap.end()) + { + return it->second; + } - return ScriptFieldType::None; - } - } + return ScriptFieldType::None; + } + } - void ScriptEngine::Init() - { - EPPO_PROFILE_FUNCTION("ScriptEngine::Init"); + void ScriptEngine::Init() + { + EPPO_PROFILE_FUNCTION("ScriptEngine::Init"); - s_Data = new ScriptEngineData(); + s_Data = new ScriptEngineData(); - InitMono(); + InitMono(); - if (const bool status = LoadCoreAssembly("Resources/Scripts/EppoScripting.dll"); - !status) - { - EPPO_ERROR("Failed to load EppoScripting assembly!"); - } + if (const bool status = LoadCoreAssembly("Resources/Scripts/EppoScripting.dll"); !status) + { + EPPO_ERROR("Failed to load EppoScripting assembly!"); + } - LoadAppAssembly("Projects/Assets/Scripts/Binaries/Sandbox.dll"); - } + LoadAppAssembly("Projects/Assets/Scripts/Binaries/Sandbox.dll"); + } - void ScriptEngine::Shutdown() - { - EPPO_PROFILE_FUNCTION("ScriptEngine::Shutdown"); + void ScriptEngine::Shutdown() + { + EPPO_PROFILE_FUNCTION("ScriptEngine::Shutdown"); - mono_domain_set(mono_get_root_domain(), false); - - mono_domain_unload(s_Data->AppDomain); - s_Data->AppDomain = nullptr; + mono_domain_set(mono_get_root_domain(), false); - mono_jit_cleanup(s_Data->RootDomain); - s_Data->RootDomain = nullptr; - - delete s_Data; - } - - void ScriptEngine::ReloadAssembly() - { - EPPO_PROFILE_FUNCTION("ScriptEngine::ReloadAssembly"); + mono_domain_unload(s_Data->AppDomain); + s_Data->AppDomain = nullptr; - EPPO_INFO("Reloading app assembly"); + mono_jit_cleanup(s_Data->RootDomain); + s_Data->RootDomain = nullptr; - bool isRunning = false; + delete s_Data; + } - if (s_Data->SceneContext && s_Data->SceneContext->IsRunning()) - isRunning = s_Data->SceneContext->IsRunning(); + void ScriptEngine::ReloadAssembly() + { + EPPO_PROFILE_FUNCTION("ScriptEngine::ReloadAssembly"); - if (isRunning) - s_Data->SceneContext->OnRuntimeStop(); + EPPO_INFO("Reloading app assembly"); - // We get the active domain away from the one we are trying to reload - // App --> Root - mono_domain_set(mono_get_root_domain(), false); + bool isRunning = false; - // Unload the app domain which is now free to unload - mono_domain_unload(s_Data->AppDomain); + if (s_Data->SceneContext && s_Data->SceneContext->IsRunning()) + isRunning = s_Data->SceneContext->IsRunning(); - // Reload the assembly - LoadCoreAssembly(s_Data->CoreAssemblyFilepath); - LoadAppAssembly(s_Data->AppAssemblyFilepath); + if (isRunning) + s_Data->SceneContext->OnRuntimeStop(); - EPPO_INFO("Reloaded app assembly"); + // We get the active domain away from the one we are trying to reload + // App --> Root + mono_domain_set(mono_get_root_domain(), false); - if (isRunning) - s_Data->SceneContext->OnRuntimeStart(); - } + // Unload the app domain which is now free to unload + mono_domain_unload(s_Data->AppDomain); - bool ScriptEngine::LoadAppAssembly(const std::filesystem::path& filepath) - { - EPPO_PROFILE_FUNCTION("ScriptEngine::LoadAppAssembly"); + // Reload the assembly + LoadCoreAssembly(s_Data->CoreAssemblyFilepath); + LoadAppAssembly(s_Data->AppAssemblyFilepath); - // Load assembly - s_Data->AppAssemblyFilepath = filepath; - s_Data->AppAssembly = LoadMonoAssembly(filepath, s_Data->EnableDebugging); - if (s_Data->AppAssembly == nullptr) - return false; + EPPO_INFO("Reloaded app assembly"); - s_Data->AppAssemblyImage = mono_assembly_get_image(s_Data->AppAssembly); - s_Data->AppAssemblyFileWatcher = CreateScope>(filepath, OnAppAssemblyFileSystemEvent); - s_Data->AppAssemblyReloadPending = false; + if (isRunning) + s_Data->SceneContext->OnRuntimeStart(); + } - // Register internal calls - ScriptGlue::RegisterFunctions(); - ScriptGlue::RegisterComponents(); + bool ScriptEngine::LoadAppAssembly(const std::filesystem::path& filepath) + { + EPPO_PROFILE_FUNCTION("ScriptEngine::LoadAppAssembly"); - // Load assembly classes - LoadAssemblyClasses(); + // Load assembly + s_Data->AppAssemblyFilepath = filepath; + s_Data->AppAssembly = LoadMonoAssembly(filepath, s_Data->EnableDebugging); + if (s_Data->AppAssembly == nullptr) + return false; - // Create base entity class - s_Data->EntityClass = CreateRef("Eppo", "Entity", true); + s_Data->AppAssemblyImage = mono_assembly_get_image(s_Data->AppAssembly); + s_Data->AppAssemblyFileWatcher = CreateScope>(filepath, OnAppAssemblyFileSystemEvent); + s_Data->AppAssemblyReloadPending = false; - return true; - } + // Register internal calls + ScriptGlue::RegisterFunctions(); + ScriptGlue::RegisterComponents(); - void ScriptEngine::OnRuntimeStart() - { - EPPO_PROFILE_FUNCTION("ScriptEngine::OnRuntimeStart"); + // Load assembly classes + LoadAssemblyClasses(); - EPPO_ASSERT(s_Data->SceneContext); - } + // Create base entity class + s_Data->EntityClass = CreateRef("Eppo", "Entity", true); - void ScriptEngine::OnRuntimeStop() - { - EPPO_PROFILE_FUNCTION("ScriptEngine::OnRuntimeStop"); + return true; + } - s_Data->SceneContext = nullptr; - s_Data->EntityScriptInstances.clear(); - } + void ScriptEngine::OnRuntimeStart() + { + EPPO_PROFILE_FUNCTION("ScriptEngine::OnRuntimeStart"); - void ScriptEngine::OnCreateEntity(Entity entity) - { - EPPO_PROFILE_FUNCTION("ScriptEngine::OnCreateEntity"); + EPPO_ASSERT(s_Data->SceneContext); + } - if (const auto& [className] = entity.GetComponent(); - EntityClassExists(className)) - { - const UUID uuid = entity.GetUUID(); - const auto instance = CreateRef(s_Data->EntityScriptClasses.at(className), entity); - s_Data->EntityScriptInstances[uuid] = instance; + void ScriptEngine::OnRuntimeStop() + { + EPPO_PROFILE_FUNCTION("ScriptEngine::OnRuntimeStop"); - if (const auto it = s_Data->EntityScriptFields.find(uuid); - it != s_Data->EntityScriptFields.end()) - { - const ScriptFieldMap& fieldMap = it->second; - for (const auto& [name, fieldInstance] : fieldMap) - { - instance->SetFieldValue(name, fieldInstance.m_Buffer); - } - } + s_Data->SceneContext = nullptr; + s_Data->EntityScriptInstances.clear(); + } - instance->InvokeOnCreate(); - } - } + void ScriptEngine::OnCreateEntity(Entity entity) + { + EPPO_PROFILE_FUNCTION("ScriptEngine::OnCreateEntity"); - void ScriptEngine::OnUpdateEntity(Entity entity, const float timestep) - { - EPPO_PROFILE_FUNCTION("ScriptEngine::OnUpdateEntity"); + if (const auto& [className] = entity.GetComponent(); EntityClassExists(className)) + { + const UUID uuid = entity.GetUUID(); + const auto instance = CreateRef(s_Data->EntityScriptClasses.at(className), entity); + s_Data->EntityScriptInstances[uuid] = instance; - const UUID uuid = entity.GetUUID(); + if (const auto it = s_Data->EntityScriptFields.find(uuid); it != s_Data->EntityScriptFields.end()) + { + const ScriptFieldMap& fieldMap = it->second; + for (const auto& [name, fieldInstance] : fieldMap) + { + instance->SetFieldValue(name, fieldInstance.m_Buffer); + } + } + + instance->InvokeOnCreate(); + } + } + + void ScriptEngine::OnUpdateEntity(Entity entity, const float timestep) + { + EPPO_PROFILE_FUNCTION("ScriptEngine::OnUpdateEntity"); + + const UUID uuid = entity.GetUUID(); EPPO_ASSERT(s_Data->EntityScriptInstances.find(uuid) != s_Data->EntityScriptInstances.end()); - const auto instance = s_Data->EntityScriptInstances.at(uuid); - instance->InvokeOnUpdate(timestep); - } + const auto instance = s_Data->EntityScriptInstances.at(uuid); + instance->InvokeOnUpdate(timestep); + } - MonoObject* ScriptEngine::InstantiateClass(MonoClass* monoClass) - { - EPPO_PROFILE_FUNCTION("ScriptEngine::InstantiateClass"); + MonoObject* ScriptEngine::InstantiateClass(MonoClass* monoClass) + { + EPPO_PROFILE_FUNCTION("ScriptEngine::InstantiateClass"); - MonoObject* instance = mono_object_new(s_Data->AppDomain, monoClass); - mono_runtime_object_init(instance); + MonoObject* instance = mono_object_new(s_Data->AppDomain, monoClass); + mono_runtime_object_init(instance); - return instance; - } + return instance; + } - bool ScriptEngine::EntityClassExists(const std::string& fullName) - { - EPPO_PROFILE_FUNCTION("ScriptEngine::EntityClassExists"); + bool ScriptEngine::EntityClassExists(const std::string& fullName) + { + EPPO_PROFILE_FUNCTION("ScriptEngine::EntityClassExists"); - return s_Data->EntityScriptClasses.find(fullName) != s_Data->EntityScriptClasses.end(); - } + return s_Data->EntityScriptClasses.find(fullName) != s_Data->EntityScriptClasses.end(); + } - MonoDomain* ScriptEngine::GetAppDomain() - { - return s_Data->AppDomain; - } + MonoDomain* ScriptEngine::GetAppDomain() + { + return s_Data->AppDomain; + } - MonoImage* ScriptEngine::GetCoreAssemblyImage() - { - return s_Data->CoreAssemblyImage; - } + MonoImage* ScriptEngine::GetCoreAssemblyImage() + { + return s_Data->CoreAssemblyImage; + } - MonoImage* ScriptEngine::GetAppAssemblyImage() - { - return s_Data->AppAssemblyImage; - } + MonoImage* ScriptEngine::GetAppAssemblyImage() + { + return s_Data->AppAssemblyImage; + } - void ScriptEngine::SetSceneContext(const Ref& scene) - { - s_Data->SceneContext = scene; - } + void ScriptEngine::SetSceneContext(const Ref& scene) + { + s_Data->SceneContext = scene; + } - Ref ScriptEngine::GetSceneContext() - { - return s_Data->SceneContext; - } + Ref ScriptEngine::GetSceneContext() + { + return s_Data->SceneContext; + } - Ref ScriptEngine::GetEntityClass() - { - return s_Data->EntityClass; - } + Ref ScriptEngine::GetEntityClass() + { + return s_Data->EntityClass; + } - Ref ScriptEngine::GetEntityClass(const std::string& name) - { - EPPO_PROFILE_FUNCTION("ScriptEngine::GetEntityClass"); + Ref ScriptEngine::GetEntityClass(const std::string& name) + { + EPPO_PROFILE_FUNCTION("ScriptEngine::GetEntityClass"); - const auto it = s_Data->EntityScriptClasses.find(name); - if (it == s_Data->EntityScriptClasses.end()) - return nullptr; + const auto it = s_Data->EntityScriptClasses.find(name); + if (it == s_Data->EntityScriptClasses.end()) + return nullptr; - return it->second; - } + return it->second; + } - Ref ScriptEngine::GetEntityInstance(const UUID uuid) - { - EPPO_PROFILE_FUNCTION("ScriptEngine::GetEntityInstance"); + Ref ScriptEngine::GetEntityInstance(const UUID uuid) + { + EPPO_PROFILE_FUNCTION("ScriptEngine::GetEntityInstance"); - const auto it = s_Data->EntityScriptInstances.find(uuid); + const auto it = s_Data->EntityScriptInstances.find(uuid); EPPO_ASSERT(it != s_Data->EntityScriptInstances.end()); - return it->second; - } + return it->second; + } - ScriptFieldMap& ScriptEngine::GetScriptFieldMap(const UUID uuid) - { - return s_Data->EntityScriptFields[uuid]; - } + ScriptFieldMap& ScriptEngine::GetScriptFieldMap(const UUID uuid) + { + return s_Data->EntityScriptFields[uuid]; + } - std::unordered_map>& ScriptEngine::GetEntityClasses() - { - return s_Data->EntityScriptClasses; - } + std::unordered_map>& ScriptEngine::GetEntityClasses() + { + return s_Data->EntityScriptClasses; + } - MonoObject* ScriptEngine::GetManagedInstance(const UUID uuid) - { - EPPO_PROFILE_FUNCTION("ScriptEngine::GetManagedInstance"); + MonoObject* ScriptEngine::GetManagedInstance(const UUID uuid) + { + EPPO_PROFILE_FUNCTION("ScriptEngine::GetManagedInstance"); - const auto it = s_Data->EntityScriptInstances.find(uuid); + const auto it = s_Data->EntityScriptInstances.find(uuid); EPPO_ASSERT(it != s_Data->EntityScriptInstances.end()); - return it->second->GetManagedObject(); - } + return it->second->GetManagedObject(); + } - void ScriptEngine::InitMono() - { - EPPO_PROFILE_FUNCTION("ScriptEngine::InitMono"); + void ScriptEngine::InitMono() + { + EPPO_PROFILE_FUNCTION("ScriptEngine::InitMono"); - mono_set_assemblies_path("Mono/lib"); + mono_set_assemblies_path("Mono/lib"); - s_Data->RootDomain = mono_jit_init("EppoJITRuntime"); + s_Data->RootDomain = mono_jit_init("EppoJITRuntime"); EPPO_ASSERT(s_Data->RootDomain); - if (s_Data->EnableDebugging) - mono_debug_domain_create(s_Data->RootDomain); + if (s_Data->EnableDebugging) + mono_debug_domain_create(s_Data->RootDomain); + + mono_thread_set_main(mono_thread_current()); + } + + bool ScriptEngine::LoadCoreAssembly(const std::filesystem::path& filepath) + { + EPPO_PROFILE_FUNCTION("ScriptEngine::LoadCoreAssembly"); + + // Setup appdomain + s_Data->AppDomain = mono_domain_create_appdomain(const_cast("EppoScriptRuntime"), nullptr); + mono_domain_set(s_Data->AppDomain, true); + + // Setup core assembly + s_Data->CoreAssemblyFilepath = filepath; + s_Data->CoreAssembly = LoadMonoAssembly(filepath, s_Data->EnableDebugging); + if (s_Data->CoreAssembly == nullptr) + return false; + + s_Data->CoreAssemblyImage = mono_assembly_get_image(s_Data->CoreAssembly); + + return true; + } + + void ScriptEngine::LoadAssemblyClasses() + { + EPPO_PROFILE_FUNCTION("ScriptEngine::LoadAssemblyClasses"); + + const MonoTableInfo* typeDefinitionsTable = mono_image_get_table_info(s_Data->AppAssemblyImage, MONO_TABLE_TYPEDEF); + const int32_t numTypes = mono_table_info_get_rows(typeDefinitionsTable); + MonoClass* entityClass = mono_class_from_name(s_Data->CoreAssemblyImage, "Eppo", "Entity"); + + for (int32_t i = 0; i < numTypes; i++) + { + // Get namespace and class name from image + uint32_t cols[MONO_TYPEDEF_SIZE]; + mono_metadata_decode_row(typeDefinitionsTable, i, cols, MONO_TYPEDEF_SIZE); + + const char* nameSpace = mono_metadata_string_heap(s_Data->AppAssemblyImage, cols[MONO_TYPEDEF_NAMESPACE]); + const char* name = mono_metadata_string_heap(s_Data->AppAssemblyImage, cols[MONO_TYPEDEF_NAME]); + + std::string fullName; + if (strlen(nameSpace) != 0) + fullName = fmt::format("{}.{}", nameSpace, name); + else + fullName = name; + + // TodO: Filter out module? + + // Get mono class handle from name + MonoClass* monoClass = mono_class_from_name(s_Data->AppAssemblyImage, nameSpace, name); + + // We're looking for all classes EXCEPT the entity class + if (monoClass == entityClass) + continue; + + if (const bool isEntity = mono_class_is_subclass_of(monoClass, entityClass, false); !isEntity) + { + continue; + } + + // Create a reference to the class and process it's fields + Ref scriptClass = CreateRef(monoClass); + s_Data->EntityScriptClasses.insert_or_assign(fullName, scriptClass); + + uint32_t numFields = mono_class_num_fields(monoClass); + + void* gPointer = nullptr; + uint32_t publicFields = 0; + while (MonoClassField* field = mono_class_get_fields(monoClass, &gPointer)) + { + if (const uint32_t flags = mono_field_get_flags(field); flags & FIELD_ATTRIBUTE_PUBLIC) + { + publicFields++; + + MonoType* fieldType = mono_field_get_type(field); + std::string fieldName = mono_field_get_name(field); + + const ScriptFieldType scriptFieldType = MonoTypeToScriptFieldType(fieldType); + if (scriptFieldType == ScriptFieldType::None) + continue; + + ScriptField scriptField; + scriptField.Type = scriptFieldType; + scriptField.Name = fieldName; + scriptField.ClassField = field; + + EPPO_TRACE("{}::{}", Utils::ScriptFieldTypeToString(scriptField.Type), scriptField.Name); - mono_thread_set_main(mono_thread_current()); - } + scriptClass->m_Fields.insert_or_assign(fieldName, scriptField); + } + } - bool ScriptEngine::LoadCoreAssembly(const std::filesystem::path& filepath) - { - EPPO_PROFILE_FUNCTION("ScriptEngine::LoadCoreAssembly"); + EPPO_TRACE("{} has {} fields of which {} are public: ", fullName, numFields, publicFields); + } + } - // Setup appdomain - s_Data->AppDomain = mono_domain_create_appdomain(const_cast("EppoScriptRuntime"), nullptr); - mono_domain_set(s_Data->AppDomain, true); - - // Setup core assembly - s_Data->CoreAssemblyFilepath = filepath; - s_Data->CoreAssembly = LoadMonoAssembly(filepath, s_Data->EnableDebugging); - if (s_Data->CoreAssembly == nullptr) - return false; - - s_Data->CoreAssemblyImage = mono_assembly_get_image(s_Data->CoreAssembly); - - return true; - } - - void ScriptEngine::LoadAssemblyClasses() - { - EPPO_PROFILE_FUNCTION("ScriptEngine::LoadAssemblyClasses"); - - const MonoTableInfo* typeDefinitionsTable = mono_image_get_table_info(s_Data->AppAssemblyImage, MONO_TABLE_TYPEDEF); - const int32_t numTypes = mono_table_info_get_rows(typeDefinitionsTable); - MonoClass* entityClass = mono_class_from_name(s_Data->CoreAssemblyImage, "Eppo", "Entity"); - - for (int32_t i = 0; i < numTypes; i++) - { - // Get namespace and class name from image - uint32_t cols[MONO_TYPEDEF_SIZE]; - mono_metadata_decode_row(typeDefinitionsTable, i, cols, MONO_TYPEDEF_SIZE); - - const char* nameSpace = mono_metadata_string_heap(s_Data->AppAssemblyImage, cols[MONO_TYPEDEF_NAMESPACE]); - const char* name = mono_metadata_string_heap(s_Data->AppAssemblyImage, cols[MONO_TYPEDEF_NAME]); - - std::string fullName; - if (strlen(nameSpace) != 0) - fullName = fmt::format("{}.{}", nameSpace, name); - else - fullName = name; - - // TodO: Filter out module? - - // Get mono class handle from name - MonoClass* monoClass = mono_class_from_name(s_Data->AppAssemblyImage, nameSpace, name); - - // We're looking for all classes EXCEPT the entity class - if (monoClass == entityClass) - continue; - - if (const bool isEntity = mono_class_is_subclass_of(monoClass, entityClass, false); - !isEntity) - { - continue; - } - - // Create a reference to the class and process it's fields - Ref scriptClass = CreateRef(monoClass); - s_Data->EntityScriptClasses.insert_or_assign(fullName, scriptClass); - - uint32_t numFields = mono_class_num_fields(monoClass); - - void* gPointer = nullptr; - uint32_t publicFields = 0; - while (MonoClassField* field = mono_class_get_fields(monoClass, &gPointer)) - { - if (const uint32_t flags = mono_field_get_flags(field); - flags & FIELD_ATTRIBUTE_PUBLIC) - { - publicFields++; - - MonoType* fieldType = mono_field_get_type(field); - std::string fieldName = mono_field_get_name(field); - - const ScriptFieldType scriptFieldType = MonoTypeToScriptFieldType(fieldType); - if (scriptFieldType == ScriptFieldType::None) - continue; - - ScriptField scriptField; - scriptField.Type = scriptFieldType; - scriptField.Name = fieldName; - scriptField.ClassField = field; - - EPPO_TRACE("{}::{}", Utils::ScriptFieldTypeToString(scriptField.Type), scriptField.Name); - - scriptClass->m_Fields.insert_or_assign(fieldName, scriptField); - } - } - - EPPO_TRACE("{} has {} fields of which {} are public: ", fullName, numFields, publicFields); - } - } - - void ScriptEngine::OnAppAssemblyFileSystemEvent(const std::filesystem::path& filepath, const filewatch::Event changeType) - { - if (!s_Data->AppAssemblyReloadPending && changeType == filewatch::Event::added) - { - s_Data->AppAssemblyReloadPending = true; - - Application::Get().SubmitToMainThread([]() - { - ReloadAssembly(); - }); - } - } + void ScriptEngine::OnAppAssemblyFileSystemEvent(const std::filesystem::path& filepath, const filewatch::Event changeType) + { + if (!s_Data->AppAssemblyReloadPending && changeType == filewatch::Event::added) + { + s_Data->AppAssemblyReloadPending = true; + + Application::Get().SubmitToMainThread([]() + { + ReloadAssembly(); + }); + } + } } diff --git a/EppoEngine/Source/Scripting/ScriptEngine.h b/EppoEngine/Source/Scripting/ScriptEngine.h index 8ecaccec..530b5012 100644 --- a/EppoEngine/Source/Scripting/ScriptEngine.h +++ b/EppoEngine/Source/Scripting/ScriptEngine.h @@ -14,102 +14,132 @@ typedef struct _MonoObject MonoObject; namespace filewatch { - template - class FileWatch; + template + class FileWatch; - enum class Event; + enum class Event; } namespace Eppo { - using ScriptFieldMap = std::unordered_map; - - class ScriptEngine - { - public: - static void Init(); - static void Shutdown(); - - static void ReloadAssembly(); - static bool LoadAppAssembly(const std::filesystem::path& filepath); - - static void OnRuntimeStart(); - static void OnRuntimeStop(); - static void OnCreateEntity(Entity entity); - static void OnUpdateEntity(Entity entity, float timestep); - - static MonoObject* InstantiateClass(MonoClass* monoClass); - static bool EntityClassExists(const std::string& fullName); - - static MonoDomain* GetAppDomain(); - static MonoImage* GetCoreAssemblyImage(); - static MonoImage* GetAppAssemblyImage(); - static void SetSceneContext(const Ref& scene); - static Ref GetSceneContext(); - - static Ref GetEntityClass(); - static Ref GetEntityClass(const std::string& name); - static Ref GetEntityInstance(UUID uuid); - static ScriptFieldMap& GetScriptFieldMap(UUID uuid); - static std::unordered_map>& GetEntityClasses(); - - static MonoObject* GetManagedInstance(UUID uuid); - - private: - static void InitMono(); - static bool LoadCoreAssembly(const std::filesystem::path& filepath); - static void LoadAssemblyClasses(); - - static void OnAppAssemblyFileSystemEvent(const std::filesystem::path& filepath, filewatch::Event changeType); - }; - - namespace Utils - { - inline ScriptFieldType ScriptFieldTypeFromString(const std::string_view typeString) - { - if (typeString == "Float") return ScriptFieldType::Float; - if (typeString == "Double") return ScriptFieldType::Double; - if (typeString == "Bool") return ScriptFieldType::Bool; - if (typeString == "Char") return ScriptFieldType::Char; - if (typeString == "Int16") return ScriptFieldType::Int16; - if (typeString == "Int32") return ScriptFieldType::Int32; - if (typeString == "Int64") return ScriptFieldType::Int64; - if (typeString == "Byte") return ScriptFieldType::Byte; - if (typeString == "UInt16") return ScriptFieldType::UInt16; - if (typeString == "UInt32") return ScriptFieldType::UInt32; - if (typeString == "UInt64") return ScriptFieldType::UInt64; - if (typeString == "Vector2") return ScriptFieldType::Vector2; - if (typeString == "Vector3") return ScriptFieldType::Vector3; - if (typeString == "Vector4") return ScriptFieldType::Vector4; - if (typeString == "Entity") return ScriptFieldType::Entity; - - EPPO_ASSERT(false); - return ScriptFieldType::None; - } - - inline std::string ScriptFieldTypeToString(const ScriptFieldType type) - { - switch (type) - { - case ScriptFieldType::Float: return "Float"; - case ScriptFieldType::Double: return "Double"; - case ScriptFieldType::Bool: return "Bool"; - case ScriptFieldType::Char: return "Char"; - case ScriptFieldType::Int16: return "Int16"; - case ScriptFieldType::Int32: return "Int32"; - case ScriptFieldType::Int64: return "Int64"; - case ScriptFieldType::Byte: return "Byte"; - case ScriptFieldType::UInt16: return "UInt16"; - case ScriptFieldType::UInt32: return "UInt32"; - case ScriptFieldType::UInt64: return "UInt64"; - case ScriptFieldType::Vector2: return "Vector2"; - case ScriptFieldType::Vector3: return "Vector3"; - case ScriptFieldType::Vector4: return "Vector4"; - case ScriptFieldType::Entity: return "Entity"; - } - - EPPO_ASSERT(false); - return "None"; - } - } + using ScriptFieldMap = std::unordered_map; + + class ScriptEngine + { + public: + static void Init(); + static void Shutdown(); + + static void ReloadAssembly(); + static bool LoadAppAssembly(const std::filesystem::path& filepath); + + static void OnRuntimeStart(); + static void OnRuntimeStop(); + static void OnCreateEntity(Entity entity); + static void OnUpdateEntity(Entity entity, float timestep); + + static MonoObject* InstantiateClass(MonoClass* monoClass); + static bool EntityClassExists(const std::string& fullName); + + static MonoDomain* GetAppDomain(); + static MonoImage* GetCoreAssemblyImage(); + static MonoImage* GetAppAssemblyImage(); + static void SetSceneContext(const Ref& scene); + static Ref GetSceneContext(); + + static Ref GetEntityClass(); + static Ref GetEntityClass(const std::string& name); + static Ref GetEntityInstance(UUID uuid); + static ScriptFieldMap& GetScriptFieldMap(UUID uuid); + static std::unordered_map>& GetEntityClasses(); + + static MonoObject* GetManagedInstance(UUID uuid); + + private: + static void InitMono(); + static bool LoadCoreAssembly(const std::filesystem::path& filepath); + static void LoadAssemblyClasses(); + + static void OnAppAssemblyFileSystemEvent(const std::filesystem::path& filepath, filewatch::Event changeType); + }; + + namespace Utils + { + inline ScriptFieldType ScriptFieldTypeFromString(const std::string_view typeString) + { + if (typeString == "Float") + return ScriptFieldType::Float; + if (typeString == "Double") + return ScriptFieldType::Double; + if (typeString == "Bool") + return ScriptFieldType::Bool; + if (typeString == "Char") + return ScriptFieldType::Char; + if (typeString == "Int16") + return ScriptFieldType::Int16; + if (typeString == "Int32") + return ScriptFieldType::Int32; + if (typeString == "Int64") + return ScriptFieldType::Int64; + if (typeString == "Byte") + return ScriptFieldType::Byte; + if (typeString == "UInt16") + return ScriptFieldType::UInt16; + if (typeString == "UInt32") + return ScriptFieldType::UInt32; + if (typeString == "UInt64") + return ScriptFieldType::UInt64; + if (typeString == "Vector2") + return ScriptFieldType::Vector2; + if (typeString == "Vector3") + return ScriptFieldType::Vector3; + if (typeString == "Vector4") + return ScriptFieldType::Vector4; + if (typeString == "Entity") + return ScriptFieldType::Entity; + + EPPO_ASSERT(false); + return ScriptFieldType::None; + } + + inline std::string ScriptFieldTypeToString(const ScriptFieldType type) + { + switch (type) + { + case ScriptFieldType::Float: + return "Float"; + case ScriptFieldType::Double: + return "Double"; + case ScriptFieldType::Bool: + return "Bool"; + case ScriptFieldType::Char: + return "Char"; + case ScriptFieldType::Int16: + return "Int16"; + case ScriptFieldType::Int32: + return "Int32"; + case ScriptFieldType::Int64: + return "Int64"; + case ScriptFieldType::Byte: + return "Byte"; + case ScriptFieldType::UInt16: + return "UInt16"; + case ScriptFieldType::UInt32: + return "UInt32"; + case ScriptFieldType::UInt64: + return "UInt64"; + case ScriptFieldType::Vector2: + return "Vector2"; + case ScriptFieldType::Vector3: + return "Vector3"; + case ScriptFieldType::Vector4: + return "Vector4"; + case ScriptFieldType::Entity: + return "Entity"; + } + + EPPO_ASSERT(false); + return "None"; + } + } } diff --git a/EppoEngine/Source/Scripting/ScriptField.h b/EppoEngine/Source/Scripting/ScriptField.h index d9d4b999..fe9b5df7 100644 --- a/EppoEngine/Source/Scripting/ScriptField.h +++ b/EppoEngine/Source/Scripting/ScriptField.h @@ -4,53 +4,53 @@ typedef struct _MonoClassField MonoClassField; namespace Eppo { - enum class ScriptFieldType : uint8_t - { - None = 0, - Float, Double, - Bool, - Char, Int16, Int32, Int64, - Byte, UInt16, UInt32, UInt64, - Vector2, Vector3, Vector4, - Entity - }; - - struct ScriptField - { - ScriptFieldType Type; - std::string Name; - - MonoClassField* ClassField = nullptr; - }; - - class ScriptFieldInstance - { - public: - ScriptField Field{}; - - ScriptFieldInstance() - { - memset(m_Buffer, 0, sizeof(m_Buffer)); - } - - template - T GetValue() - { - static_assert(sizeof(T) <= 16, "Type too large!"); - return *(T*)m_Buffer; - } - - template - void SetValue(T value) - { - static_assert(sizeof(T) <= 16, "Type too large!"); - memcpy(m_Buffer, &value, sizeof(value)); - } - - private: - uint8_t m_Buffer[16]; - - friend class ScriptEngine; - friend class ScriptInstance; - }; + enum class ScriptFieldType : uint8_t + { + None = 0, + Float, Double, + Bool, + Char, Int16, Int32, Int64, + Byte, UInt16, UInt32, UInt64, + Vector2, Vector3, Vector4, + Entity + }; + + struct ScriptField + { + ScriptFieldType Type; + std::string Name; + + MonoClassField* ClassField = nullptr; + }; + + class ScriptFieldInstance + { + public: + ScriptField Field{}; + + ScriptFieldInstance() + { + memset(m_Buffer, 0, sizeof(m_Buffer)); + } + + template + T GetValue() + { + static_assert(sizeof(T) <= 16, "Type too large!"); + return *(T*)m_Buffer; + } + + template + void SetValue(T value) + { + static_assert(sizeof(T) <= 16, "Type too large!"); + memcpy(m_Buffer, &value, sizeof(value)); + } + + private: + uint8_t m_Buffer[16]; + + friend class ScriptEngine; + friend class ScriptInstance; + }; } diff --git a/EppoEngine/Source/Scripting/ScriptGlue.cpp b/EppoEngine/Source/Scripting/ScriptGlue.cpp index 992f41cf..bf971b53 100644 --- a/EppoEngine/Source/Scripting/ScriptGlue.cpp +++ b/EppoEngine/Source/Scripting/ScriptGlue.cpp @@ -11,235 +11,239 @@ namespace Eppo { - namespace - { - std::unordered_map> s_EntityHasComponentFns; - } - - #define EPPO_ADD_INTERNAL_CALL(fn) mono_add_internal_call("Eppo.InternalCalls::"#fn, reinterpret_cast(fn)); - - static void Log(const uint32_t logLevel, MonoString* message) - { - EPPO_PROFILE_FUNCTION("ScriptGlue::Log"); - - char* cStr = mono_string_to_utf8(message); - const std::string messageStr(cStr); - mono_free(cStr); - - switch (logLevel) - { - case 0: EPPO_SCRIPT_TRACE(messageStr); break; - case 1: EPPO_SCRIPT_INFO(messageStr); break; - case 2: EPPO_SCRIPT_WARN(messageStr); break; - case 3: EPPO_SCRIPT_ERROR(messageStr); break; - } - } - - static bool Input_IsKeyPressed(const KeyCode keyCode) - { - EPPO_PROFILE_FUNCTION("ScriptGlue::Input_IsKeyPressed"); - - return Input::IsKeyPressed(keyCode); - } - - static void Entity_AddComponent(const UUID uuid, MonoString* componentType) - { - EPPO_PROFILE_FUNCTION("ScriptGlue::Entity_AddComponent"); - - const Ref scene = ScriptEngine::GetSceneContext(); + namespace + { + std::unordered_map> s_EntityHasComponentFns; + } + +#define EPPO_ADD_INTERNAL_CALL(fn) mono_add_internal_call("Eppo.InternalCalls::"#fn, reinterpret_cast(fn)); + + static void Log(const uint32_t logLevel, MonoString* message) + { + EPPO_PROFILE_FUNCTION("ScriptGlue::Log"); + + char* cStr = mono_string_to_utf8(message); + const std::string messageStr(cStr); + mono_free(cStr); + + switch (logLevel) + { + case 0: EPPO_SCRIPT_TRACE(messageStr); + break; + case 1: EPPO_SCRIPT_INFO(messageStr); + break; + case 2: EPPO_SCRIPT_WARN(messageStr); + break; + case 3: EPPO_SCRIPT_ERROR(messageStr); + break; + } + } + + static bool Input_IsKeyPressed(const KeyCode keyCode) + { + EPPO_PROFILE_FUNCTION("ScriptGlue::Input_IsKeyPressed"); + + return Input::IsKeyPressed(keyCode); + } + + static void Entity_AddComponent(const UUID uuid, MonoString* componentType) + { + EPPO_PROFILE_FUNCTION("ScriptGlue::Entity_AddComponent"); + + const Ref scene = ScriptEngine::GetSceneContext(); EPPO_ASSERT(scene); - Entity entity = scene->FindEntityByUUID(uuid); + Entity entity = scene->FindEntityByUUID(uuid); EPPO_ASSERT(entity); - char* cStr = mono_string_to_utf8(componentType); - const std::string componentTypeStr(cStr); - mono_free(cStr); - - if (componentTypeStr == "TransformComponent") - entity.AddComponent(); - if (componentTypeStr == "SpriteComponent") - entity.AddComponent(); - if (componentTypeStr == "MeshComponent") - entity.AddComponent(); - if (componentTypeStr == "DirectionalLightComponent") - entity.AddComponent(); - if (componentTypeStr == "ScriptComponent") - entity.AddComponent(); - if (componentTypeStr == "RigidBodyComponent") - entity.AddComponent(); - } - - static uint64_t Entity_CreateNewEntity(MonoString* name) - { - EPPO_PROFILE_FUNCTION("ScriptGlue::Entity_CreateNewEntity"); - - const Ref scene = ScriptEngine::GetSceneContext(); + char* cStr = mono_string_to_utf8(componentType); + const std::string componentTypeStr(cStr); + mono_free(cStr); + + if (componentTypeStr == "TransformComponent") + entity.AddComponent(); + if (componentTypeStr == "SpriteComponent") + entity.AddComponent(); + if (componentTypeStr == "MeshComponent") + entity.AddComponent(); + if (componentTypeStr == "DirectionalLightComponent") + entity.AddComponent(); + if (componentTypeStr == "ScriptComponent") + entity.AddComponent(); + if (componentTypeStr == "RigidBodyComponent") + entity.AddComponent(); + } + + static uint64_t Entity_CreateNewEntity(MonoString* name) + { + EPPO_PROFILE_FUNCTION("ScriptGlue::Entity_CreateNewEntity"); + + const Ref scene = ScriptEngine::GetSceneContext(); EPPO_ASSERT(scene); - char* cStr = mono_string_to_utf8(name); - const std::string nameStr(cStr); - mono_free(cStr); + char* cStr = mono_string_to_utf8(name); + const std::string nameStr(cStr); + mono_free(cStr); - Entity entity = scene->CreateEntity(nameStr); + Entity entity = scene->CreateEntity(nameStr); EPPO_ASSERT(entity); - return entity.GetUUID(); - } + return entity.GetUUID(); + } - static uint64_t Entity_FindEntityByName(MonoString* name) - { - EPPO_PROFILE_FUNCTION("ScriptGlue::Entity_FindEntityByName"); + static uint64_t Entity_FindEntityByName(MonoString* name) + { + EPPO_PROFILE_FUNCTION("ScriptGlue::Entity_FindEntityByName"); - const Ref scene = ScriptEngine::GetSceneContext(); + const Ref scene = ScriptEngine::GetSceneContext(); EPPO_ASSERT(scene); - char* cStr = mono_string_to_utf8(name); - const std::string nameStr(cStr); - mono_free(cStr); + char* cStr = mono_string_to_utf8(name); + const std::string nameStr(cStr); + mono_free(cStr); - Entity entity = scene->FindEntityByName(nameStr); - if (!entity) - return 0; + Entity entity = scene->FindEntityByName(nameStr); + if (!entity) + return 0; - return entity.GetUUID(); - } - - static MonoString* Entity_GetName(const UUID uuid) - { - EPPO_PROFILE_FUNCTION("ScriptGlue::Entity_GetName"); + return entity.GetUUID(); + } - const Ref scene = ScriptEngine::GetSceneContext(); + static MonoString* Entity_GetName(const UUID uuid) + { + EPPO_PROFILE_FUNCTION("ScriptGlue::Entity_GetName"); + + const Ref scene = ScriptEngine::GetSceneContext(); EPPO_ASSERT(scene); - Entity entity = scene->FindEntityByUUID(uuid); + Entity entity = scene->FindEntityByUUID(uuid); EPPO_ASSERT(entity); - MonoString* monoStr = mono_string_new(ScriptEngine::GetAppDomain(), entity.GetName().c_str()); + MonoString* monoStr = mono_string_new(ScriptEngine::GetAppDomain(), entity.GetName().c_str()); - return monoStr; - } + return monoStr; + } - static bool Entity_HasComponent(const UUID uuid, MonoReflectionType* componentType) - { - EPPO_PROFILE_FUNCTION("ScriptGlue::Entity_HasComponent"); + static bool Entity_HasComponent(const UUID uuid, MonoReflectionType* componentType) + { + EPPO_PROFILE_FUNCTION("ScriptGlue::Entity_HasComponent"); - const Ref scene = ScriptEngine::GetSceneContext(); + const Ref scene = ScriptEngine::GetSceneContext(); EPPO_ASSERT(scene); - const Entity entity = scene->FindEntityByUUID(uuid); + const Entity entity = scene->FindEntityByUUID(uuid); EPPO_ASSERT(entity); - MonoType* managedType = mono_reflection_type_get_type(componentType); - const auto it = s_EntityHasComponentFns.find(managedType); + MonoType* managedType = mono_reflection_type_get_type(componentType); + const auto it = s_EntityHasComponentFns.find(managedType); EPPO_ASSERT(it != s_EntityHasComponentFns.end()); - return it->second(entity); - } + return it->second(entity); + } - static void TransformComponent_GetTranslation(const UUID uuid, glm::vec3* outTranslation) - { - EPPO_PROFILE_FUNCTION("ScriptGlue::TransformComponent_GetTranslation"); + static void TransformComponent_GetTranslation(const UUID uuid, glm::vec3* outTranslation) + { + EPPO_PROFILE_FUNCTION("ScriptGlue::TransformComponent_GetTranslation"); - const Ref scene = ScriptEngine::GetSceneContext(); + const Ref scene = ScriptEngine::GetSceneContext(); EPPO_ASSERT(scene); - Entity entity = scene->FindEntityByUUID(uuid); + Entity entity = scene->FindEntityByUUID(uuid); EPPO_ASSERT(entity); - *outTranslation = entity.GetComponent().Translation; - } + *outTranslation = entity.GetComponent().Translation; + } - static void TransformComponent_SetTranslation(const UUID uuid, const glm::vec3* translation) - { - EPPO_PROFILE_FUNCTION("ScriptGlue::TransformComponent_SetTranslation"); + static void TransformComponent_SetTranslation(const UUID uuid, const glm::vec3* translation) + { + EPPO_PROFILE_FUNCTION("ScriptGlue::TransformComponent_SetTranslation"); - const Ref scene = ScriptEngine::GetSceneContext(); + const Ref scene = ScriptEngine::GetSceneContext(); EPPO_ASSERT(scene); - Entity entity = scene->FindEntityByUUID(uuid); + Entity entity = scene->FindEntityByUUID(uuid); EPPO_ASSERT(entity); - entity.GetComponent().Translation = *translation; - } + entity.GetComponent().Translation = *translation; + } - static void RigidBodyComponent_ApplyLinearImpulse(const UUID uuid, const glm::vec3* impulse, const glm::vec3* worldPosition) - { - EPPO_PROFILE_FUNCTION("ScriptGlue::RigidBodyComponent_ApplyLinearImpulse"); + static void RigidBodyComponent_ApplyLinearImpulse(const UUID uuid, const glm::vec3* impulse, const glm::vec3* worldPosition) + { + EPPO_PROFILE_FUNCTION("ScriptGlue::RigidBodyComponent_ApplyLinearImpulse"); - const Ref scene = ScriptEngine::GetSceneContext(); + const Ref scene = ScriptEngine::GetSceneContext(); EPPO_ASSERT(scene); - Entity entity = scene->FindEntityByUUID(uuid); + Entity entity = scene->FindEntityByUUID(uuid); EPPO_ASSERT(entity); - const auto& rb = entity.GetComponent(); - rb.RuntimeBody.ApplyLinearImpulse(*impulse, *worldPosition); - } + const auto& rb = entity.GetComponent(); + rb.RuntimeBody.ApplyLinearImpulse(*impulse, *worldPosition); + } - static void RigidBodyComponent_ApplyLinearImpulseToCenter(const UUID uuid, const glm::vec3* impulse) - { - EPPO_PROFILE_FUNCTION("ScriptGlue::RigidBodyComponent_ApplyLinearImpulseToCenter"); + static void RigidBodyComponent_ApplyLinearImpulseToCenter(const UUID uuid, const glm::vec3* impulse) + { + EPPO_PROFILE_FUNCTION("ScriptGlue::RigidBodyComponent_ApplyLinearImpulseToCenter"); - const Ref scene = ScriptEngine::GetSceneContext(); + const Ref scene = ScriptEngine::GetSceneContext(); EPPO_ASSERT(scene); - Entity entity = scene->FindEntityByUUID(uuid); + Entity entity = scene->FindEntityByUUID(uuid); EPPO_ASSERT(entity); - const auto& rb = entity.GetComponent(); - rb.RuntimeBody.ApplyLinearImpulse(*impulse); - } - - static MonoObject* GetScriptInstance(const UUID uuid) - { - EPPO_PROFILE_FUNCTION("ScriptGlue::GetScriptInstance"); - - return ScriptEngine::GetManagedInstance(uuid); - } - - void ScriptGlue::RegisterFunctions() - { - EPPO_PROFILE_FUNCTION("ScriptGlue::RegisterFunctions"); - - EPPO_ADD_INTERNAL_CALL(Log) - EPPO_ADD_INTERNAL_CALL(Input_IsKeyPressed) - EPPO_ADD_INTERNAL_CALL(Entity_AddComponent) - EPPO_ADD_INTERNAL_CALL(Entity_CreateNewEntity) - EPPO_ADD_INTERNAL_CALL(Entity_FindEntityByName) - EPPO_ADD_INTERNAL_CALL(Entity_GetName) - EPPO_ADD_INTERNAL_CALL(Entity_HasComponent) - EPPO_ADD_INTERNAL_CALL(TransformComponent_GetTranslation) - EPPO_ADD_INTERNAL_CALL(TransformComponent_SetTranslation) - EPPO_ADD_INTERNAL_CALL(RigidBodyComponent_ApplyLinearImpulse) - EPPO_ADD_INTERNAL_CALL(RigidBodyComponent_ApplyLinearImpulseToCenter) - EPPO_ADD_INTERNAL_CALL(GetScriptInstance) - } - - void ScriptGlue::RegisterComponents() - { - EPPO_PROFILE_FUNCTION("ScriptGlue::RegisterComponents"); - - s_EntityHasComponentFns.clear(); - - RegisterComponent(); - RegisterComponent(); - RegisterComponent(); - RegisterComponent(); - RegisterComponent(); - RegisterComponent(); - } - - template - void ScriptGlue::RegisterComponent() - { - EPPO_PROFILE_FUNCTION("ScriptGlue::RegisterComponent"); - - const std::string_view typeName = typeid(T).name(); - const size_t pos = typeName.find_last_of(':'); - std::string_view structName = typeName.substr(pos + 1); - std::string managedTypeName = fmt::format("Eppo.{}", structName); - - MonoType* managedType = mono_reflection_type_from_name(managedTypeName.data(), ScriptEngine::GetCoreAssemblyImage()); - if (!managedType) - { - EPPO_ERROR("Could not find component type {}", managedTypeName); - return; - } - - auto fn = [](Entity entity) { return entity.HasComponent(); }; - s_EntityHasComponentFns.insert_or_assign(managedType, fn); - } + const auto& rb = entity.GetComponent(); + rb.RuntimeBody.ApplyLinearImpulse(*impulse); + } + + static MonoObject* GetScriptInstance(const UUID uuid) + { + EPPO_PROFILE_FUNCTION("ScriptGlue::GetScriptInstance"); + + return ScriptEngine::GetManagedInstance(uuid); + } + + void ScriptGlue::RegisterFunctions() + { + EPPO_PROFILE_FUNCTION("ScriptGlue::RegisterFunctions"); + + EPPO_ADD_INTERNAL_CALL(Log) + EPPO_ADD_INTERNAL_CALL(Input_IsKeyPressed) + EPPO_ADD_INTERNAL_CALL(Entity_AddComponent) + EPPO_ADD_INTERNAL_CALL(Entity_CreateNewEntity) + EPPO_ADD_INTERNAL_CALL(Entity_FindEntityByName) + EPPO_ADD_INTERNAL_CALL(Entity_GetName) + EPPO_ADD_INTERNAL_CALL(Entity_HasComponent) + EPPO_ADD_INTERNAL_CALL(TransformComponent_GetTranslation) + EPPO_ADD_INTERNAL_CALL(TransformComponent_SetTranslation) + EPPO_ADD_INTERNAL_CALL(RigidBodyComponent_ApplyLinearImpulse) + EPPO_ADD_INTERNAL_CALL(RigidBodyComponent_ApplyLinearImpulseToCenter) + EPPO_ADD_INTERNAL_CALL(GetScriptInstance) + } + + void ScriptGlue::RegisterComponents() + { + EPPO_PROFILE_FUNCTION("ScriptGlue::RegisterComponents"); + + s_EntityHasComponentFns.clear(); + + RegisterComponent(); + RegisterComponent(); + RegisterComponent(); + RegisterComponent(); + RegisterComponent(); + RegisterComponent(); + } + + template + void ScriptGlue::RegisterComponent() + { + EPPO_PROFILE_FUNCTION("ScriptGlue::RegisterComponent"); + + const std::string_view typeName = typeid(T).name(); + const size_t pos = typeName.find_last_of(':'); + std::string_view structName = typeName.substr(pos + 1); + std::string managedTypeName = fmt::format("Eppo.{}", structName); + + MonoType* managedType = mono_reflection_type_from_name(managedTypeName.data(), ScriptEngine::GetCoreAssemblyImage()); + if (!managedType) + { + EPPO_ERROR("Could not find component type {}", managedTypeName); + return; + } + + auto fn = [](Entity entity) { return entity.HasComponent(); }; + s_EntityHasComponentFns.insert_or_assign(managedType, fn); + } } diff --git a/EppoEngine/Source/Scripting/ScriptGlue.h b/EppoEngine/Source/Scripting/ScriptGlue.h index f60064cd..8e8a35bc 100644 --- a/EppoEngine/Source/Scripting/ScriptGlue.h +++ b/EppoEngine/Source/Scripting/ScriptGlue.h @@ -2,14 +2,14 @@ namespace Eppo { - class ScriptGlue - { - public: - static void RegisterFunctions(); - static void RegisterComponents(); + class ScriptGlue + { + public: + static void RegisterFunctions(); + static void RegisterComponents(); - private: - template - static void RegisterComponent(); - }; + private: + template + static void RegisterComponent(); + }; } diff --git a/EppoEngine/Source/Scripting/ScriptInstance.cpp b/EppoEngine/Source/Scripting/ScriptInstance.cpp index e02070dc..03839e2b 100644 --- a/EppoEngine/Source/Scripting/ScriptInstance.cpp +++ b/EppoEngine/Source/Scripting/ScriptInstance.cpp @@ -7,68 +7,68 @@ namespace Eppo { - ScriptInstance::ScriptInstance(const Ref& scriptClass, Entity entity) - : m_ScriptClass(scriptClass) - { - EPPO_PROFILE_FUNCTION("ScriptInstance::ScriptInstance"); - - m_Instance = m_ScriptClass->Instantiate(); - - m_Constructor = ScriptEngine::GetEntityClass()->GetMethod(".ctor", 1); - m_OnCreate = m_ScriptClass->GetMethod("OnCreate", 0); - m_OnUpdate = m_ScriptClass->GetMethod("OnUpdate", 1); - - UUID uuid = entity.GetUUID(); - void* param = &uuid; - ScriptClass::InvokeMethod(m_Instance, m_Constructor, ¶m); - } - - void ScriptInstance::InvokeOnCreate() const - { - EPPO_PROFILE_FUNCTION("ScriptInstance::InvokeOnCreate"); - - if (m_OnCreate) - ScriptClass::InvokeMethod(m_Instance, m_OnCreate); - } - - void ScriptInstance::InvokeOnUpdate(float timestep) const - { - EPPO_PROFILE_FUNCTION("ScriptInstance::InvokeOnUpdate"); - - if (m_OnUpdate) - { - void* params = ×tep; - ScriptClass::InvokeMethod(m_Instance, m_OnUpdate, ¶ms); - } - } - - bool ScriptInstance::GetFieldValueInternal(const std::string& name, void* buffer) const - { - EPPO_PROFILE_FUNCTION("ScriptInstance::GetFieldValueInternal"); - - const auto& fields = m_ScriptClass->GetFields(); - const auto it = fields.find(name); - if (it == fields.end()) - return false; - - const ScriptField& field = it->second; - mono_field_get_value(m_Instance, field.ClassField, buffer); - - return true; - } - - bool ScriptInstance::SetFieldValueInternal(const std::string& name, const void* value) const - { - EPPO_PROFILE_FUNCTION("ScriptInstance::SetFieldValueInternal"); - - const auto& fields = m_ScriptClass->GetFields(); - const auto it = fields.find(name); - if (it == fields.end()) - return false; - - const ScriptField& field = it->second; - mono_field_set_value(m_Instance, field.ClassField, const_cast(value)); - - return true; - } + ScriptInstance::ScriptInstance(const Ref& scriptClass, Entity entity) + : m_ScriptClass(scriptClass) + { + EPPO_PROFILE_FUNCTION("ScriptInstance::ScriptInstance"); + + m_Instance = m_ScriptClass->Instantiate(); + + m_Constructor = ScriptEngine::GetEntityClass()->GetMethod(".ctor", 1); + m_OnCreate = m_ScriptClass->GetMethod("OnCreate", 0); + m_OnUpdate = m_ScriptClass->GetMethod("OnUpdate", 1); + + UUID uuid = entity.GetUUID(); + void* param = &uuid; + ScriptClass::InvokeMethod(m_Instance, m_Constructor, ¶m); + } + + void ScriptInstance::InvokeOnCreate() const + { + EPPO_PROFILE_FUNCTION("ScriptInstance::InvokeOnCreate"); + + if (m_OnCreate) + ScriptClass::InvokeMethod(m_Instance, m_OnCreate); + } + + void ScriptInstance::InvokeOnUpdate(float timestep) const + { + EPPO_PROFILE_FUNCTION("ScriptInstance::InvokeOnUpdate"); + + if (m_OnUpdate) + { + void* params = ×tep; + ScriptClass::InvokeMethod(m_Instance, m_OnUpdate, ¶ms); + } + } + + bool ScriptInstance::GetFieldValueInternal(const std::string& name, void* buffer) const + { + EPPO_PROFILE_FUNCTION("ScriptInstance::GetFieldValueInternal"); + + const auto& fields = m_ScriptClass->GetFields(); + const auto it = fields.find(name); + if (it == fields.end()) + return false; + + const ScriptField& field = it->second; + mono_field_get_value(m_Instance, field.ClassField, buffer); + + return true; + } + + bool ScriptInstance::SetFieldValueInternal(const std::string& name, const void* value) const + { + EPPO_PROFILE_FUNCTION("ScriptInstance::SetFieldValueInternal"); + + const auto& fields = m_ScriptClass->GetFields(); + const auto it = fields.find(name); + if (it == fields.end()) + return false; + + const ScriptField& field = it->second; + mono_field_set_value(m_Instance, field.ClassField, const_cast(value)); + + return true; + } } diff --git a/EppoEngine/Source/Scripting/ScriptInstance.h b/EppoEngine/Source/Scripting/ScriptInstance.h index 803f193f..ec0a0ee5 100644 --- a/EppoEngine/Source/Scripting/ScriptInstance.h +++ b/EppoEngine/Source/Scripting/ScriptInstance.h @@ -8,49 +8,49 @@ typedef struct _MonoObject MonoObject; namespace Eppo { - class ScriptInstance - { - public: - ScriptInstance(const Ref& scriptClass, Entity entity); - - void InvokeOnCreate() const; - void InvokeOnUpdate(float timestep) const; - - Ref GetScriptClass() { return m_ScriptClass; } - [[nodiscard]] MonoObject* GetManagedObject() const { return m_Instance; } - - template - T GetFieldValue(const std::string& name) - { - static_assert(sizeof(T) <= 16, "Type too large!"); - - if (!GetFieldValueInternal(name, s_FieldValueBuffer)) - return T(); - - return *(T*)s_FieldValueBuffer; - } - - template - void SetFieldValue(const std::string& name, const T& value) - { - static_assert(sizeof(T) <= 16, "Type too large!"); - SetFieldValueInternal(name, &value); - } - - private: - bool GetFieldValueInternal(const std::string& name, void* buffer) const; - bool SetFieldValueInternal(const std::string& name, const void* value) const; - - private: - Ref m_ScriptClass; - MonoObject* m_Instance = nullptr; - MonoMethod* m_Constructor = nullptr; - MonoMethod* m_OnCreate = nullptr; - MonoMethod* m_OnUpdate = nullptr; - - inline static char s_FieldValueBuffer[16]; - - friend class ScriptEngine; - friend class ScriptFieldInstance; - }; + class ScriptInstance + { + public: + ScriptInstance(const Ref& scriptClass, Entity entity); + + void InvokeOnCreate() const; + void InvokeOnUpdate(float timestep) const; + + Ref GetScriptClass() { return m_ScriptClass; } + [[nodiscard]] MonoObject* GetManagedObject() const { return m_Instance; } + + template + T GetFieldValue(const std::string& name) + { + static_assert(sizeof(T) <= 16, "Type too large!"); + + if (!GetFieldValueInternal(name, s_FieldValueBuffer)) + return T(); + + return *(T*)s_FieldValueBuffer; + } + + template + void SetFieldValue(const std::string& name, const T& value) + { + static_assert(sizeof(T) <= 16, "Type too large!"); + SetFieldValueInternal(name, &value); + } + + private: + bool GetFieldValueInternal(const std::string& name, void* buffer) const; + bool SetFieldValueInternal(const std::string& name, const void* value) const; + + private: + Ref m_ScriptClass; + MonoObject* m_Instance = nullptr; + MonoMethod* m_Constructor = nullptr; + MonoMethod* m_OnCreate = nullptr; + MonoMethod* m_OnUpdate = nullptr; + + inline static char s_FieldValueBuffer[16]; + + friend class ScriptEngine; + friend class ScriptFieldInstance; + }; } diff --git a/EppoEngine/Source/Utility/Random.h b/EppoEngine/Source/Utility/Random.h index 20029fff..983829fc 100644 --- a/EppoEngine/Source/Utility/Random.h +++ b/EppoEngine/Source/Utility/Random.h @@ -4,35 +4,35 @@ namespace Eppo::Utility { - static std::random_device s_RandomDevice; - static std::mt19937 s_Engine32(s_RandomDevice()); - static std::mt19937_64 s_Engine64(s_RandomDevice()); + static std::random_device s_RandomDevice; + static std::mt19937 s_Engine32(s_RandomDevice()); + static std::mt19937_64 s_Engine64(s_RandomDevice()); - // Generate a random 32 bit unsigned integer - inline uint32_t GenerateRandomUInt32(const uint32_t min = 0, const uint32_t max = UINT32_MAX) - { - std::uniform_int_distribution uniformDistribution(min, max); - return uniformDistribution(s_Engine32); - } + // Generate a random 32 bit unsigned integer + inline uint32_t GenerateRandomUInt32(const uint32_t min = 0, const uint32_t max = UINT32_MAX) + { + std::uniform_int_distribution uniformDistribution(min, max); + return uniformDistribution(s_Engine32); + } - // Generate a random 32 bit signed integer - inline int32_t GenerateRandomInt32(const int32_t min = INT32_MIN, const int32_t max = INT32_MAX) - { - std::uniform_int_distribution uniformDistribution(min, max); - return uniformDistribution(s_Engine32); - } + // Generate a random 32 bit signed integer + inline int32_t GenerateRandomInt32(const int32_t min = INT32_MIN, const int32_t max = INT32_MAX) + { + std::uniform_int_distribution uniformDistribution(min, max); + return uniformDistribution(s_Engine32); + } - // Generate a random 64 bit unsigned integer - inline uint64_t GenerateRandomUInt64(const uint64_t min = 0, const uint64_t max = UINT64_MAX) - { - std::uniform_int_distribution uniformDistribution(min, max); - return uniformDistribution(s_Engine64); - } + // Generate a random 64 bit unsigned integer + inline uint64_t GenerateRandomUInt64(const uint64_t min = 0, const uint64_t max = UINT64_MAX) + { + std::uniform_int_distribution uniformDistribution(min, max); + return uniformDistribution(s_Engine64); + } - // Generate a random 64 bit signed integer - inline int64_t GenerateRandomInt64(const int64_t min = INT64_MIN, const int64_t max = INT64_MAX) - { - std::uniform_int_distribution uniformDistribution(min, max); - return uniformDistribution(s_Engine64); - } + // Generate a random 64 bit signed integer + inline int64_t GenerateRandomInt64(const int64_t min = INT64_MIN, const int64_t max = INT64_MAX) + { + std::uniform_int_distribution uniformDistribution(min, max); + return uniformDistribution(s_Engine64); + } } diff --git a/EppoEngine/Source/pch.h b/EppoEngine/Source/pch.h index 5708fcbe..8f8977ae 100644 --- a/EppoEngine/Source/pch.h +++ b/EppoEngine/Source/pch.h @@ -19,9 +19,9 @@ #include #if defined(TRACY_ENABLE) - #include - #include - #include + #include + #include + #include #endif #include "Core/Base.h" diff --git a/EppoScripting/Source/Core/Input.cs b/EppoScripting/Source/Core/Input.cs index 4440b153..96d436e5 100644 --- a/EppoScripting/Source/Core/Input.cs +++ b/EppoScripting/Source/Core/Input.cs @@ -1,10 +1,10 @@ namespace Eppo { - public class Input - { - public static bool IsKeyPressed(KeyCode keyCode) - { - return InternalCalls.Input_IsKeyPressed(keyCode); - } - } + public class Input + { + public static bool IsKeyPressed(KeyCode keyCode) + { + return InternalCalls.Input_IsKeyPressed(keyCode); + } + } } diff --git a/EppoScripting/Source/Core/KeyCodes.cs b/EppoScripting/Source/Core/KeyCodes.cs index f3ed2461..54407b44 100644 --- a/EppoScripting/Source/Core/KeyCodes.cs +++ b/EppoScripting/Source/Core/KeyCodes.cs @@ -1,137 +1,137 @@ namespace Eppo { - public enum KeyCode - { - // From glfw3.h - Space = 32, - Apostrophe = 39, /* ' */ - Comma = 44, /* , */ - Minus = 45, /* - */ - Period = 46, /* . */ - Slash = 47, /* / */ + public enum KeyCode + { + // From glfw3.h + Space = 32, + Apostrophe = 39, /* ' */ + Comma = 44, /* , */ + Minus = 45, /* - */ + Period = 46, /* . */ + Slash = 47, /* / */ - D0 = 48, /* 0 */ - D1 = 49, /* 1 */ - D2 = 50, /* 2 */ - D3 = 51, /* 3 */ - D4 = 52, /* 4 */ - D5 = 53, /* 5 */ - D6 = 54, /* 6 */ - D7 = 55, /* 7 */ - D8 = 56, /* 8 */ - D9 = 57, /* 9 */ + D0 = 48, /* 0 */ + D1 = 49, /* 1 */ + D2 = 50, /* 2 */ + D3 = 51, /* 3 */ + D4 = 52, /* 4 */ + D5 = 53, /* 5 */ + D6 = 54, /* 6 */ + D7 = 55, /* 7 */ + D8 = 56, /* 8 */ + D9 = 57, /* 9 */ - Semicolon = 59, /* ; */ - Equal = 61, /* = */ + Semicolon = 59, /* ; */ + Equal = 61, /* = */ - A = 65, - B = 66, - C = 67, - D = 68, - E = 69, - F = 70, - G = 71, - H = 72, - I = 73, - J = 74, - K = 75, - L = 76, - M = 77, - N = 78, - O = 79, - P = 80, - Q = 81, - R = 82, - S = 83, - T = 84, - U = 85, - V = 86, - W = 87, - X = 88, - Y = 89, - Z = 90, + A = 65, + B = 66, + C = 67, + D = 68, + E = 69, + F = 70, + G = 71, + H = 72, + I = 73, + J = 74, + K = 75, + L = 76, + M = 77, + N = 78, + O = 79, + P = 80, + Q = 81, + R = 82, + S = 83, + T = 84, + U = 85, + V = 86, + W = 87, + X = 88, + Y = 89, + Z = 90, - LeftBracket = 91, /* [ */ - Backslash = 92, /* \ */ - RightBracket = 93, /* ] */ - GraveAccent = 96, /* ` */ + LeftBracket = 91, /* [ */ + Backslash = 92, /* \ */ + RightBracket = 93, /* ] */ + GraveAccent = 96, /* ` */ - World1 = 161, /* non-US #1 */ - World2 = 162, /* non-US #2 */ + World1 = 161, /* non-US #1 */ + World2 = 162, /* non-US #2 */ - /* Function keys */ - Escape = 256, - Enter = 257, - Tab = 258, - Backspace = 259, - Insert = 260, - Delete = 261, - Right = 262, - Left = 263, - Down = 264, - Up = 265, - PageUp = 266, - PageDown = 267, - Home = 268, - End = 269, - CapsLock = 280, - ScrollLock = 281, - NumLock = 282, - PrintScreen = 283, - Pause = 284, - F1 = 290, - F2 = 291, - F3 = 292, - F4 = 293, - F5 = 294, - F6 = 295, - F7 = 296, - F8 = 297, - F9 = 298, - F10 = 299, - F11 = 300, - F12 = 301, - F13 = 302, - F14 = 303, - F15 = 304, - F16 = 305, - F17 = 306, - F18 = 307, - F19 = 308, - F20 = 309, - F21 = 310, - F22 = 311, - F23 = 312, - F24 = 313, - F25 = 314, + /* Function keys */ + Escape = 256, + Enter = 257, + Tab = 258, + Backspace = 259, + Insert = 260, + Delete = 261, + Right = 262, + Left = 263, + Down = 264, + Up = 265, + PageUp = 266, + PageDown = 267, + Home = 268, + End = 269, + CapsLock = 280, + ScrollLock = 281, + NumLock = 282, + PrintScreen = 283, + Pause = 284, + F1 = 290, + F2 = 291, + F3 = 292, + F4 = 293, + F5 = 294, + F6 = 295, + F7 = 296, + F8 = 297, + F9 = 298, + F10 = 299, + F11 = 300, + F12 = 301, + F13 = 302, + F14 = 303, + F15 = 304, + F16 = 305, + F17 = 306, + F18 = 307, + F19 = 308, + F20 = 309, + F21 = 310, + F22 = 311, + F23 = 312, + F24 = 313, + F25 = 314, - /* Keypad */ - KP0 = 320, - KP1 = 321, - KP2 = 322, - KP3 = 323, - KP4 = 324, - KP5 = 325, - KP6 = 326, - KP7 = 327, - KP8 = 328, - KP9 = 329, - KPDecimal = 330, - KPDivide = 331, - KPMultiply = 332, - KPSubtract = 333, - KPAdd = 334, - KPEnter = 335, - KPEqual = 336, + /* Keypad */ + KP0 = 320, + KP1 = 321, + KP2 = 322, + KP3 = 323, + KP4 = 324, + KP5 = 325, + KP6 = 326, + KP7 = 327, + KP8 = 328, + KP9 = 329, + KPDecimal = 330, + KPDivide = 331, + KPMultiply = 332, + KPSubtract = 333, + KPAdd = 334, + KPEnter = 335, + KPEqual = 336, - LeftShift = 340, - LeftControl = 341, - LeftAlt = 342, - LeftSuper = 343, - RightShift = 344, - RightControl = 345, - RightAlt = 346, - RightSuper = 347, - Menu = 348 - } + LeftShift = 340, + LeftControl = 341, + LeftAlt = 342, + LeftSuper = 343, + RightShift = 344, + RightControl = 345, + RightAlt = 346, + RightSuper = 347, + Menu = 348 + } } diff --git a/EppoScripting/Source/Core/Log.cs b/EppoScripting/Source/Core/Log.cs index 369890c5..d3c62d45 100644 --- a/EppoScripting/Source/Core/Log.cs +++ b/EppoScripting/Source/Core/Log.cs @@ -1,33 +1,33 @@ namespace Eppo { - public enum LogLevel - { - Trace = 0, - Info, - Warn, - Error - } + public enum LogLevel + { + Trace = 0, + Info, + Warn, + Error + } - public class Log - { - public static void Trace(string message) - { - InternalCalls.Log(LogLevel.Trace, message); - } + public class Log + { + public static void Trace(string message) + { + InternalCalls.Log(LogLevel.Trace, message); + } - public static void Info(string message) - { - InternalCalls.Log(LogLevel.Info, message); - } + public static void Info(string message) + { + InternalCalls.Log(LogLevel.Info, message); + } - public static void Warn(string message) - { - InternalCalls.Log(LogLevel.Warn, message); - } + public static void Warn(string message) + { + InternalCalls.Log(LogLevel.Warn, message); + } - public static void Error(string message) - { - InternalCalls.Log(LogLevel.Error, message); - } - } + public static void Error(string message) + { + InternalCalls.Log(LogLevel.Error, message); + } + } } diff --git a/EppoScripting/Source/InternalCalls.cs b/EppoScripting/Source/InternalCalls.cs index 95fda17e..cc3d7785 100644 --- a/EppoScripting/Source/InternalCalls.cs +++ b/EppoScripting/Source/InternalCalls.cs @@ -3,41 +3,41 @@ namespace Eppo { - public static class InternalCalls - { - // Core - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal extern static void Log(LogLevel logLevel, string message); + public static class InternalCalls + { + // Core + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void Log(LogLevel logLevel, string message); - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal extern static bool Input_IsKeyPressed(KeyCode keyCode); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static bool Input_IsKeyPressed(KeyCode keyCode); - // Scene - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal extern static void Entity_AddComponent(ulong uuid, string componentType); - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal extern static ulong Entity_CreateNewEntity(); - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal extern static ulong Entity_CreateNewEntity(string name); - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal extern static string Entity_GetName(ulong uuid); - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal extern static ulong Entity_FindEntityByName(string name); - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal extern static bool Entity_HasComponent(ulong uuid, Type componentType); + // Scene + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void Entity_AddComponent(ulong uuid, string componentType); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static ulong Entity_CreateNewEntity(); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static ulong Entity_CreateNewEntity(string name); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static string Entity_GetName(ulong uuid); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static ulong Entity_FindEntityByName(string name); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static bool Entity_HasComponent(ulong uuid, Type componentType); - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal extern static void TransformComponent_GetTranslation(ulong uuid, out Vector3 translation); - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal extern static void TransformComponent_SetTranslation(ulong uuid, ref Vector3 translation); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void TransformComponent_GetTranslation(ulong uuid, out Vector3 translation); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void TransformComponent_SetTranslation(ulong uuid, ref Vector3 translation); - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal extern static void RigidBodyComponent_ApplyLinearImpulse(ulong uuid, ref Vector3 impulse, ref Vector3 worldPosition); - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal extern static void RigidBodyComponent_ApplyLinearImpulseToCenter(ulong uuid, ref Vector3 impulse); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void RigidBodyComponent_ApplyLinearImpulse(ulong uuid, ref Vector3 impulse, ref Vector3 worldPosition); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void RigidBodyComponent_ApplyLinearImpulseToCenter(ulong uuid, ref Vector3 impulse); - // ScriptEngine - [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal extern static object GetScriptInstance(ulong uuid); - } + // ScriptEngine + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static object GetScriptInstance(ulong uuid); + } } diff --git a/EppoScripting/Source/Math/Vector2.cs b/EppoScripting/Source/Math/Vector2.cs index e15476e3..3cc1fb2b 100644 --- a/EppoScripting/Source/Math/Vector2.cs +++ b/EppoScripting/Source/Math/Vector2.cs @@ -1,35 +1,35 @@ namespace Eppo { - public struct Vector2 - { - public float X, Y; + public struct Vector2 + { + public float X, Y; - public Vector2(float scalar) - { - X = scalar; - Y = scalar; - } + public Vector2(float scalar) + { + X = scalar; + Y = scalar; + } - public Vector2(float x, float y) - { - X = x; - Y = y; - } + public Vector2(float x, float y) + { + X = x; + Y = y; + } - public override string ToString() - { - return $"(X: {X}, Y: {Y})"; - } + public override string ToString() + { + return $"(X: {X}, Y: {Y})"; + } - public static Vector2 Zero => new Vector2(0.0f); + public static Vector2 Zero => new Vector2(0.0f); - public static Vector2 operator +(Vector2 lhs, Vector2 rhs) => new Vector2(lhs.X + rhs.X, lhs.Y + rhs.Y); - public static Vector2 operator +(Vector2 lhs, float scalar) => new Vector2(lhs.X + scalar, lhs.Y + scalar); - public static Vector2 operator -(Vector2 lhs, Vector2 rhs) => new Vector2(lhs.X - rhs.X, lhs.Y - rhs.Y); - public static Vector2 operator -(Vector2 lhs, float scalar) => new Vector2(lhs.X - scalar, lhs.Y - scalar); - public static Vector2 operator *(Vector2 lhs, Vector2 rhs) => new Vector2(lhs.X * rhs.X, lhs.Y * rhs.Y); - public static Vector2 operator *(Vector2 lhs, float scalar) => new Vector2(lhs.X * scalar, lhs.Y * scalar); - public static Vector2 operator /(Vector2 lhs, Vector2 rhs) => new Vector2(lhs.X / rhs.X, lhs.Y / rhs.Y); - public static Vector2 operator /(Vector2 lhs, float scalar) => new Vector2(lhs.X / scalar, lhs.Y / scalar); - } + public static Vector2 operator +(Vector2 lhs, Vector2 rhs) => new Vector2(lhs.X + rhs.X, lhs.Y + rhs.Y); + public static Vector2 operator +(Vector2 lhs, float scalar) => new Vector2(lhs.X + scalar, lhs.Y + scalar); + public static Vector2 operator -(Vector2 lhs, Vector2 rhs) => new Vector2(lhs.X - rhs.X, lhs.Y - rhs.Y); + public static Vector2 operator -(Vector2 lhs, float scalar) => new Vector2(lhs.X - scalar, lhs.Y - scalar); + public static Vector2 operator *(Vector2 lhs, Vector2 rhs) => new Vector2(lhs.X * rhs.X, lhs.Y * rhs.Y); + public static Vector2 operator *(Vector2 lhs, float scalar) => new Vector2(lhs.X * scalar, lhs.Y * scalar); + public static Vector2 operator /(Vector2 lhs, Vector2 rhs) => new Vector2(lhs.X / rhs.X, lhs.Y / rhs.Y); + public static Vector2 operator /(Vector2 lhs, float scalar) => new Vector2(lhs.X / scalar, lhs.Y / scalar); + } } diff --git a/EppoScripting/Source/Math/Vector3.cs b/EppoScripting/Source/Math/Vector3.cs index 363616bf..c06945ae 100644 --- a/EppoScripting/Source/Math/Vector3.cs +++ b/EppoScripting/Source/Math/Vector3.cs @@ -1,54 +1,54 @@ namespace Eppo { - public struct Vector3 - { - public float X, Y, Z; + public struct Vector3 + { + public float X, Y, Z; - public Vector3(float scalar) - { - X = scalar; - Y = scalar; - Z = scalar; - } + public Vector3(float scalar) + { + X = scalar; + Y = scalar; + Z = scalar; + } - public Vector3(float x, float y, float z) - { - X = x; - Y = y; - Z = z; - } + public Vector3(float x, float y, float z) + { + X = x; + Y = y; + Z = z; + } - public Vector3(Vector2 xy, float z) - { - X = xy.X; - Y = xy.Y; - Z = z; - } + public Vector3(Vector2 xy, float z) + { + X = xy.X; + Y = xy.Y; + Z = z; + } - public override string ToString() - { - return $"(X: {X}, Y: {Y}, Z: {Z})"; - } + public override string ToString() + { + return $"(X: {X}, Y: {Y}, Z: {Z})"; + } - public Vector2 XY - { - get => new Vector2(X, Y); - set - { - X = value.X; - Y = value.Y; - } - } + public Vector2 XY + { + get => new Vector2(X, Y); + set + { + X = value.X; + Y = value.Y; + } + } - public static Vector3 Zero => new Vector3(0.0f); + public static Vector3 Zero => new Vector3(0.0f); - public static Vector3 operator +(Vector3 lhs, Vector3 rhs) => new Vector3(lhs.X + rhs.X, lhs.Y + rhs.Y, lhs.Z + rhs.Z); - public static Vector3 operator +(Vector3 lhs, float scalar) => new Vector3(lhs.X + scalar, lhs.Y + scalar, lhs.Z + scalar); - public static Vector3 operator -(Vector3 lhs, Vector3 rhs) => new Vector3(lhs.X - rhs.X, lhs.Y - rhs.Y, lhs.Z - rhs.Z); - public static Vector3 operator -(Vector3 lhs, float scalar) => new Vector3(lhs.X - scalar, lhs.Y - scalar, lhs.Z - scalar); - public static Vector3 operator *(Vector3 lhs, Vector3 rhs) => new Vector3(lhs.X * rhs.X, lhs.Y * rhs.Y, lhs.Z * rhs.Z); - public static Vector3 operator *(Vector3 lhs, float scalar) => new Vector3(lhs.X * scalar, lhs.Y * scalar, lhs.Z * scalar); - public static Vector3 operator /(Vector3 lhs, Vector3 rhs) => new Vector3(lhs.X / rhs.X, lhs.Y / rhs.Y, lhs.Z / rhs.Z); - public static Vector3 operator /(Vector3 lhs, float scalar) => new Vector3(lhs.X / scalar, lhs.Y / scalar, lhs.Z / scalar); - } + public static Vector3 operator +(Vector3 lhs, Vector3 rhs) => new Vector3(lhs.X + rhs.X, lhs.Y + rhs.Y, lhs.Z + rhs.Z); + public static Vector3 operator +(Vector3 lhs, float scalar) => new Vector3(lhs.X + scalar, lhs.Y + scalar, lhs.Z + scalar); + public static Vector3 operator -(Vector3 lhs, Vector3 rhs) => new Vector3(lhs.X - rhs.X, lhs.Y - rhs.Y, lhs.Z - rhs.Z); + public static Vector3 operator -(Vector3 lhs, float scalar) => new Vector3(lhs.X - scalar, lhs.Y - scalar, lhs.Z - scalar); + public static Vector3 operator *(Vector3 lhs, Vector3 rhs) => new Vector3(lhs.X * rhs.X, lhs.Y * rhs.Y, lhs.Z * rhs.Z); + public static Vector3 operator *(Vector3 lhs, float scalar) => new Vector3(lhs.X * scalar, lhs.Y * scalar, lhs.Z * scalar); + public static Vector3 operator /(Vector3 lhs, Vector3 rhs) => new Vector3(lhs.X / rhs.X, lhs.Y / rhs.Y, lhs.Z / rhs.Z); + public static Vector3 operator /(Vector3 lhs, float scalar) => new Vector3(lhs.X / scalar, lhs.Y / scalar, lhs.Z / scalar); + } } diff --git a/EppoScripting/Source/Math/Vector4.cs b/EppoScripting/Source/Math/Vector4.cs index ed227888..884c0e59 100644 --- a/EppoScripting/Source/Math/Vector4.cs +++ b/EppoScripting/Source/Math/Vector4.cs @@ -1,68 +1,68 @@ namespace Eppo { - public struct Vector4 - { - public float X, Y, Z, W; + public struct Vector4 + { + public float X, Y, Z, W; - public Vector4(float scalar) - { - X = scalar; - Y = scalar; - Z = scalar; - W = scalar; - } + public Vector4(float scalar) + { + X = scalar; + Y = scalar; + Z = scalar; + W = scalar; + } - public Vector4(float x, float y, float z, float w) - { - X = x; - Y = y; - Z = z; - W = w; - } + public Vector4(float x, float y, float z, float w) + { + X = x; + Y = y; + Z = z; + W = w; + } - public Vector4(Vector3 xyz, float w) - { - X = xyz.X; - Y = xyz.Y; - Z = xyz.Z; - W = w; - } + public Vector4(Vector3 xyz, float w) + { + X = xyz.X; + Y = xyz.Y; + Z = xyz.Z; + W = w; + } - public override string ToString() - { - return $"(X: {X}, Y: {Y}, Z: {Z})"; - } + public override string ToString() + { + return $"(X: {X}, Y: {Y}, Z: {Z})"; + } - public Vector2 XY - { - get => new Vector2(X, Y); - set - { - X = value.X; - Y = value.Y; - } - } + public Vector2 XY + { + get => new Vector2(X, Y); + set + { + X = value.X; + Y = value.Y; + } + } - public Vector3 XYZ - { - get => new Vector3(X, Y, Z); - set - { - X = value.X; - Y = value.Y; - Z = value.Z; - } - } + public Vector3 XYZ + { + get => new Vector3(X, Y, Z); + set + { + X = value.X; + Y = value.Y; + Z = value.Z; + } + } - public static Vector4 Zero => new Vector4(0.0f); + public static Vector4 Zero => new Vector4(0.0f); - public static Vector4 operator +(Vector4 lhs, Vector4 rhs) => new Vector4(lhs.X + rhs.X, lhs.Y + rhs.Y, lhs.Z + rhs.Z, lhs.W + rhs.W); - public static Vector4 operator +(Vector4 lhs, float scalar) => new Vector4(lhs.X + scalar, lhs.Y + scalar, lhs.Z + scalar, lhs.W + scalar); - public static Vector4 operator -(Vector4 lhs, Vector4 rhs) => new Vector4(lhs.X - rhs.X, lhs.Y - rhs.Y, lhs.Z - rhs.Z, lhs.W - rhs.W); - public static Vector4 operator -(Vector4 lhs, float scalar) => new Vector4(lhs.X - scalar, lhs.Y - scalar, lhs.Z - scalar, lhs.W - scalar); - public static Vector4 operator *(Vector4 lhs, Vector4 rhs) => new Vector4(lhs.X * rhs.X, lhs.Y * rhs.Y, lhs.Z * rhs.Z, lhs.W * rhs.W); - public static Vector4 operator *(Vector4 lhs, float scalar) => new Vector4(lhs.X * scalar, lhs.Y * scalar, lhs.Z * scalar, lhs.W * scalar); - public static Vector4 operator /(Vector4 lhs, Vector4 rhs) => new Vector4(lhs.X / rhs.X, lhs.Y / rhs.Y, lhs.Z / rhs.Z, lhs.W / rhs.W); - public static Vector4 operator /(Vector4 lhs, float scalar) => new Vector4(lhs.X / scalar, lhs.Y / scalar, lhs.Z / scalar, lhs.W / scalar); - } + public static Vector4 operator +(Vector4 lhs, Vector4 rhs) => new Vector4(lhs.X + rhs.X, lhs.Y + rhs.Y, lhs.Z + rhs.Z, lhs.W + rhs.W); + public static Vector4 operator +(Vector4 lhs, float scalar) => new Vector4(lhs.X + scalar, lhs.Y + scalar, lhs.Z + scalar, lhs.W + scalar); + public static Vector4 operator -(Vector4 lhs, Vector4 rhs) => new Vector4(lhs.X - rhs.X, lhs.Y - rhs.Y, lhs.Z - rhs.Z, lhs.W - rhs.W); + public static Vector4 operator -(Vector4 lhs, float scalar) => new Vector4(lhs.X - scalar, lhs.Y - scalar, lhs.Z - scalar, lhs.W - scalar); + public static Vector4 operator *(Vector4 lhs, Vector4 rhs) => new Vector4(lhs.X * rhs.X, lhs.Y * rhs.Y, lhs.Z * rhs.Z, lhs.W * rhs.W); + public static Vector4 operator *(Vector4 lhs, float scalar) => new Vector4(lhs.X * scalar, lhs.Y * scalar, lhs.Z * scalar, lhs.W * scalar); + public static Vector4 operator /(Vector4 lhs, Vector4 rhs) => new Vector4(lhs.X / rhs.X, lhs.Y / rhs.Y, lhs.Z / rhs.Z, lhs.W / rhs.W); + public static Vector4 operator /(Vector4 lhs, float scalar) => new Vector4(lhs.X / scalar, lhs.Y / scalar, lhs.Z / scalar, lhs.W / scalar); + } } diff --git a/EppoScripting/Source/Scene/Components.cs b/EppoScripting/Source/Scene/Components.cs index 0f0a37f4..15f9ebde 100644 --- a/EppoScripting/Source/Scene/Components.cs +++ b/EppoScripting/Source/Scene/Components.cs @@ -1,33 +1,33 @@ namespace Eppo { - public abstract class Component - { - public Entity Entity { get; internal set; } + public abstract class Component + { + public Entity Entity { get; internal set; } - public string ComponentTypeName => GetType().Name; - } + public string ComponentTypeName => GetType().Name; + } - public class MeshComponent : Component - { - - } + public class MeshComponent : Component + { + + } - public class TransformComponent : Component - { - public Vector3 Translation - { - get - { - InternalCalls.TransformComponent_GetTranslation(Entity.ID, out Vector3 translation); - return translation; - } - set => InternalCalls.TransformComponent_SetTranslation(Entity.ID, ref value); - } - } + public class TransformComponent : Component + { + public Vector3 Translation + { + get + { + InternalCalls.TransformComponent_GetTranslation(Entity.ID, out Vector3 translation); + return translation; + } + set => InternalCalls.TransformComponent_SetTranslation(Entity.ID, ref value); + } + } - public class RigidBodyComponent : Component - { - public void ApplyLinearImpulse(Vector3 impulse, Vector3 worldPosition) => InternalCalls.RigidBodyComponent_ApplyLinearImpulse(Entity.ID, ref impulse, ref worldPosition); - public void ApplyLinearImpulse(Vector3 impulse) => InternalCalls.RigidBodyComponent_ApplyLinearImpulseToCenter(Entity.ID, ref impulse); - } + public class RigidBodyComponent : Component + { + public void ApplyLinearImpulse(Vector3 impulse, Vector3 worldPosition) => InternalCalls.RigidBodyComponent_ApplyLinearImpulse(Entity.ID, ref impulse, ref worldPosition); + public void ApplyLinearImpulse(Vector3 impulse) => InternalCalls.RigidBodyComponent_ApplyLinearImpulseToCenter(Entity.ID, ref impulse); + } } diff --git a/EppoScripting/Source/Scene/Entity.cs b/EppoScripting/Source/Scene/Entity.cs index c6c960ad..0ecb1d11 100644 --- a/EppoScripting/Source/Scene/Entity.cs +++ b/EppoScripting/Source/Scene/Entity.cs @@ -2,117 +2,117 @@ namespace Eppo { - public class Entity - { - public readonly ulong ID; - public string Name => InternalCalls.Entity_GetName(ID); - - protected Entity() - { - ID = 0; - } - - internal Entity(ulong id) - { - ID = id; - } - - public override bool Equals(object obj) - { - if (obj == null) - return false; - if (!(obj is Entity)) - return false; - - return ((Entity)obj).ID == this.ID; - } - - public override int GetHashCode() - { - return ID.GetHashCode(); - } - - public static bool operator==(Entity a, Entity b) - { - if (a == null) - if (b == null) - return true; - else - return false; - return a.Equals(b); - } - - public static bool operator!=(Entity a, Entity b) - { - return !(a == b); - } - - public Vector3 Translation - { - get - { - InternalCalls.TransformComponent_GetTranslation(ID, out Vector3 translation); - return translation; - } - set => InternalCalls.TransformComponent_SetTranslation(ID, ref value); - } - - public T AddComponent() where T : Component, new() - { - if (HasComponent()) - return null; - - T component = new T() - { - Entity = this - }; - - InternalCalls.Entity_AddComponent(ID, component.ComponentTypeName); - - return component; - } - - public bool HasComponent() where T : Component, new() - { - Type componentType = typeof(T); - return InternalCalls.Entity_HasComponent(ID, componentType); - } - - public T GetComponent() where T : Component, new() - { - if (!HasComponent()) - return null; - - T component = new T() - { - Entity = this - }; - - return component; - } - - public T As() where T : Entity, new() - { - object instance = InternalCalls.GetScriptInstance(ID); - return instance as T; - } - - public static Entity FindEntityByName(string name) - { - ulong uuid = InternalCalls.Entity_FindEntityByName(name); - if (uuid == 0) - return null; - - return new Entity(uuid); - } - - public static Entity CreateNewEntity(string name = "") - { - ulong uuid = InternalCalls.Entity_CreateNewEntity(name); - if (uuid == 0) - return null; - - return new Entity(uuid); - } - } + public class Entity + { + public readonly ulong ID; + public string Name => InternalCalls.Entity_GetName(ID); + + protected Entity() + { + ID = 0; + } + + internal Entity(ulong id) + { + ID = id; + } + + public override bool Equals(object obj) + { + if (obj == null) + return false; + if (!(obj is Entity)) + return false; + + return ((Entity)obj).ID == this.ID; + } + + public override int GetHashCode() + { + return ID.GetHashCode(); + } + + public static bool operator==(Entity a, Entity b) + { + if (a == null) + if (b == null) + return true; + else + return false; + return a.Equals(b); + } + + public static bool operator!=(Entity a, Entity b) + { + return !(a == b); + } + + public Vector3 Translation + { + get + { + InternalCalls.TransformComponent_GetTranslation(ID, out Vector3 translation); + return translation; + } + set => InternalCalls.TransformComponent_SetTranslation(ID, ref value); + } + + public T AddComponent() where T : Component, new() + { + if (HasComponent()) + return null; + + T component = new T() + { + Entity = this + }; + + InternalCalls.Entity_AddComponent(ID, component.ComponentTypeName); + + return component; + } + + public bool HasComponent() where T : Component, new() + { + Type componentType = typeof(T); + return InternalCalls.Entity_HasComponent(ID, componentType); + } + + public T GetComponent() where T : Component, new() + { + if (!HasComponent()) + return null; + + T component = new T() + { + Entity = this + }; + + return component; + } + + public T As() where T : Entity, new() + { + object instance = InternalCalls.GetScriptInstance(ID); + return instance as T; + } + + public static Entity FindEntityByName(string name) + { + ulong uuid = InternalCalls.Entity_FindEntityByName(name); + if (uuid == 0) + return null; + + return new Entity(uuid); + } + + public static Entity CreateNewEntity(string name = "") + { + ulong uuid = InternalCalls.Entity_CreateNewEntity(name); + if (uuid == 0) + return null; + + return new Entity(uuid); + } + } } diff --git a/EppoTesting/Source/Core/Buffer.cpp b/EppoTesting/Source/Core/Buffer.cpp index 673e32b2..1110805b 100644 --- a/EppoTesting/Source/Core/Buffer.cpp +++ b/EppoTesting/Source/Core/Buffer.cpp @@ -2,194 +2,194 @@ namespace Eppo { - // - // Buffer - // - class BufferTestFixture : public testing::TestWithParam - {}; + // + // Buffer + // + class BufferTestFixture : public testing::TestWithParam + {}; - INSTANTIATE_TEST_SUITE_P(BufferTest, BufferTestFixture, - testing::Values(4, 20, 1024, 2024)); + INSTANTIATE_TEST_SUITE_P(BufferTest, BufferTestFixture, + testing::Values(4, 20, 1024, 2024)); - TEST_P(BufferTestFixture, Constructor) - { - Buffer buffer(GetParam()); + TEST_P(BufferTestFixture, Constructor) + { + Buffer buffer(GetParam()); - EXPECT_EQ(GetParam(), buffer.Size); - EXPECT_TRUE(buffer.Data); + EXPECT_EQ(GetParam(), buffer.Size); + EXPECT_TRUE(buffer.Data); - buffer.Release(); - } + buffer.Release(); + } - TEST(BufferTest, ZeroInitialize) - { - // Default - { - Buffer buffer; + TEST(BufferTest, ZeroInitialize) + { + // Default + { + Buffer buffer; - EXPECT_EQ(0, buffer.Size); - EXPECT_FALSE(buffer.Data); + EXPECT_EQ(0, buffer.Size); + EXPECT_FALSE(buffer.Data); - buffer.Release(); - } + buffer.Release(); + } - // Zero initialize - { - Buffer buffer(0); + // Zero initialize + { + Buffer buffer(0); - EXPECT_EQ(0, buffer.Size); - // Technically a new allocation with a size 0 can have a valid pointer + EXPECT_EQ(0, buffer.Size); + // Technically a new allocation with a size 0 can have a valid pointer - buffer.Release(); - } - } + buffer.Release(); + } + } - TEST_P(BufferTestFixture, Allocate) - { - Buffer buffer; - buffer.Allocate(GetParam()); + TEST_P(BufferTestFixture, Allocate) + { + Buffer buffer; + buffer.Allocate(GetParam()); - EXPECT_EQ(GetParam(), buffer.Size); - EXPECT_TRUE(buffer.Data); + EXPECT_EQ(GetParam(), buffer.Size); + EXPECT_TRUE(buffer.Data); - buffer.Release(); - } + buffer.Release(); + } - TEST_P(BufferTestFixture, Release) - { - Buffer buffer(GetParam()); + TEST_P(BufferTestFixture, Release) + { + Buffer buffer(GetParam()); - EXPECT_EQ(GetParam(), buffer.Size); - EXPECT_TRUE(buffer.Data); + EXPECT_EQ(GetParam(), buffer.Size); + EXPECT_TRUE(buffer.Data); - buffer.Release(); + buffer.Release(); - EXPECT_EQ(0, buffer.Size); - EXPECT_FALSE(buffer.Data); - } + EXPECT_EQ(0, buffer.Size); + EXPECT_FALSE(buffer.Data); + } - TEST_P(BufferTestFixture, Copy_Buffer) - { - Buffer buffer(GetParam()); - memset(buffer.Data, 5, buffer.Size); + TEST_P(BufferTestFixture, Copy_Buffer) + { + Buffer buffer(GetParam()); + memset(buffer.Data, 5, buffer.Size); - EXPECT_EQ(GetParam(), buffer.Size); - EXPECT_TRUE(buffer.Data); + EXPECT_EQ(GetParam(), buffer.Size); + EXPECT_TRUE(buffer.Data); - Buffer targetBuffer = Buffer::Copy(buffer); + Buffer targetBuffer = Buffer::Copy(buffer); - EXPECT_EQ(GetParam(), targetBuffer.Size); - EXPECT_TRUE(targetBuffer.Data); + EXPECT_EQ(GetParam(), targetBuffer.Size); + EXPECT_TRUE(targetBuffer.Data); - for (uint32_t i = 0; i < targetBuffer.Size; i++) - EXPECT_EQ(5, targetBuffer.Data[i]); + for (uint32_t i = 0; i < targetBuffer.Size; i++) + EXPECT_EQ(5, targetBuffer.Data[i]); - buffer.Release(); - targetBuffer.Release(); - } + buffer.Release(); + targetBuffer.Release(); + } - TEST_P(BufferTestFixture, Copy_DataAndSize) - { - uint8_t* data = new uint8_t[GetParam()]; - memset(data, 5, GetParam()); + TEST_P(BufferTestFixture, Copy_DataAndSize) + { + uint8_t* data = new uint8_t[GetParam()]; + memset(data, 5, GetParam()); - Buffer targetBuffer = Buffer::Copy(data, GetParam()); + Buffer targetBuffer = Buffer::Copy(data, GetParam()); - delete[] data; - data = nullptr; + delete[] data; + data = nullptr; - EXPECT_EQ(GetParam(), targetBuffer.Size); - EXPECT_TRUE(targetBuffer.Data); + EXPECT_EQ(GetParam(), targetBuffer.Size); + EXPECT_TRUE(targetBuffer.Data); - for (uint32_t i = 0; i < targetBuffer.Size; i++) - EXPECT_EQ(5, targetBuffer.Data[i]); + for (uint32_t i = 0; i < targetBuffer.Size; i++) + EXPECT_EQ(5, targetBuffer.Data[i]); - targetBuffer.Release(); - } + targetBuffer.Release(); + } - TEST_P(BufferTestFixture, Copy_VoidDataAndSize) - { - void* data = new uint8_t[GetParam()]; - memset(data, 5, GetParam()); + TEST_P(BufferTestFixture, Copy_VoidDataAndSize) + { + void* data = new uint8_t[GetParam()]; + memset(data, 5, GetParam()); - Buffer targetBuffer = Buffer::Copy(data, GetParam()); + Buffer targetBuffer = Buffer::Copy(data, GetParam()); - EXPECT_EQ(GetParam(), targetBuffer.Size); - EXPECT_TRUE(targetBuffer.Data); + EXPECT_EQ(GetParam(), targetBuffer.Size); + EXPECT_TRUE(targetBuffer.Data); - for (uint32_t i = 0; i < targetBuffer.Size; i++) - EXPECT_EQ(5, targetBuffer.Data[i]); + for (uint32_t i = 0; i < targetBuffer.Size; i++) + EXPECT_EQ(5, targetBuffer.Data[i]); - targetBuffer.Release(); - } + targetBuffer.Release(); + } - TEST_P(BufferTestFixture, SetData) - { - Buffer buffer(100); - - buffer.SetData(GetParam()); - EXPECT_EQ(100, buffer.Size); - EXPECT_TRUE(buffer.Data); - EXPECT_EQ(GetParam(), buffer.As()[0]); + TEST_P(BufferTestFixture, SetData) + { + Buffer buffer(100); + + buffer.SetData(GetParam()); + EXPECT_EQ(100, buffer.Size); + EXPECT_TRUE(buffer.Data); + EXPECT_EQ(GetParam(), buffer.As()[0]); - buffer.SetData(GetParam(), 50); - EXPECT_EQ(100, buffer.Size); - EXPECT_TRUE(buffer.Data); - EXPECT_EQ(GetParam(), buffer.As()[25]); + buffer.SetData(GetParam(), 50); + EXPECT_EQ(100, buffer.Size); + EXPECT_TRUE(buffer.Data); + EXPECT_EQ(GetParam(), buffer.As()[25]); - buffer.Release(); - } + buffer.Release(); + } - // - // ScopedBuffer - // - class ScopedBufferTestFixture : public testing::TestWithParam - {}; + // + // ScopedBuffer + // + class ScopedBufferTestFixture : public testing::TestWithParam + {}; - INSTANTIATE_TEST_SUITE_P(ScopedBufferTest, ScopedBufferTestFixture, - testing::Values(4, 20, 1024, 2024)); + INSTANTIATE_TEST_SUITE_P(ScopedBufferTest, ScopedBufferTestFixture, + testing::Values(4, 20, 1024, 2024)); - TEST(ScopedBufferTest, Constructor) - { - ScopedBuffer buffer; + TEST(ScopedBufferTest, Constructor) + { + ScopedBuffer buffer; - EXPECT_EQ(0, buffer.Size()); - EXPECT_FALSE(buffer.Data()); - } + EXPECT_EQ(0, buffer.Size()); + EXPECT_FALSE(buffer.Data()); + } - TEST_P(ScopedBufferTestFixture, Constructor_Int) - { - ScopedBuffer buffer(GetParam()); + TEST_P(ScopedBufferTestFixture, Constructor_Int) + { + ScopedBuffer buffer(GetParam()); - EXPECT_EQ(GetParam(), buffer.Size()); - EXPECT_TRUE(buffer.Data()); - } + EXPECT_EQ(GetParam(), buffer.Size()); + EXPECT_TRUE(buffer.Data()); + } - TEST_P(ScopedBufferTestFixture, Constructor_Buffer) - { - Buffer buffer(GetParam()); - - EXPECT_EQ(GetParam(), buffer.Size); - EXPECT_TRUE(buffer.Data); + TEST_P(ScopedBufferTestFixture, Constructor_Buffer) + { + Buffer buffer(GetParam()); + + EXPECT_EQ(GetParam(), buffer.Size); + EXPECT_TRUE(buffer.Data); - ScopedBuffer scopedBuffer(buffer); + ScopedBuffer scopedBuffer(buffer); - EXPECT_EQ(GetParam(), scopedBuffer.Size()); - EXPECT_TRUE(scopedBuffer.Data()); - } + EXPECT_EQ(GetParam(), scopedBuffer.Size()); + EXPECT_TRUE(scopedBuffer.Data()); + } - TEST_P(ScopedBufferTestFixture, SetData) - { - ScopedBuffer buffer(100); + TEST_P(ScopedBufferTestFixture, SetData) + { + ScopedBuffer buffer(100); - buffer.SetData(GetParam()); - EXPECT_EQ(100, buffer.Size()); - EXPECT_TRUE(buffer.Data()); - EXPECT_EQ(GetParam(), buffer.As()[0]); + buffer.SetData(GetParam()); + EXPECT_EQ(100, buffer.Size()); + EXPECT_TRUE(buffer.Data()); + EXPECT_EQ(GetParam(), buffer.As()[0]); - buffer.SetData(GetParam(), 50); - EXPECT_EQ(100, buffer.Size()); - EXPECT_TRUE(buffer.Data()); - EXPECT_EQ(GetParam(), buffer.As()[25]); - } + buffer.SetData(GetParam(), 50); + EXPECT_EQ(100, buffer.Size()); + EXPECT_TRUE(buffer.Data()); + EXPECT_EQ(GetParam(), buffer.As()[25]); + } } diff --git a/EppoTesting/Source/Core/Hash.cpp b/EppoTesting/Source/Core/Hash.cpp index b722861b..f8b70727 100644 --- a/EppoTesting/Source/Core/Hash.cpp +++ b/EppoTesting/Source/Core/Hash.cpp @@ -2,35 +2,35 @@ namespace Eppo { - TEST(HashTest, GenerateFnv_String) - { - uint64_t hash = 0; + TEST(HashTest, GenerateFnv_String) + { + uint64_t hash = 0; - hash = Hash::GenerateFnv("abcde"); - EXPECT_EQ(12133862286523975779, hash); + hash = Hash::GenerateFnv("abcde"); + EXPECT_EQ(12133862286523975779, hash); - hash = Hash::GenerateFnv("12345"); - EXPECT_EQ(17908862145884878309, hash); + hash = Hash::GenerateFnv("12345"); + EXPECT_EQ(17908862145884878309, hash); - hash = Hash::GenerateFnv("abcdefghijklmnopqrstuvwxyz1234567890!"); - EXPECT_EQ(14272954169027804443, hash); - } + hash = Hash::GenerateFnv("abcdefghijklmnopqrstuvwxyz1234567890!"); + EXPECT_EQ(14272954169027804443, hash); + } - TEST(HashTest, GenerateFnv_Buffer) - { - uint64_t hash = 0; - Buffer buffer; + TEST(HashTest, GenerateFnv_Buffer) + { + uint64_t hash = 0; + Buffer buffer; - buffer = Buffer::Copy("abcde", 5); - hash = Hash::GenerateFnv(buffer); - EXPECT_EQ(12133862286523975779, hash); + buffer = Buffer::Copy("abcde", 5); + hash = Hash::GenerateFnv(buffer); + EXPECT_EQ(12133862286523975779, hash); - buffer = Buffer::Copy("12345", 5); - hash = Hash::GenerateFnv(buffer); - EXPECT_EQ(17908862145884878309, hash); + buffer = Buffer::Copy("12345", 5); + hash = Hash::GenerateFnv(buffer); + EXPECT_EQ(17908862145884878309, hash); - buffer = Buffer::Copy("abcdefghijklmnopqrstuvwxyz1234567890!", 37); - hash = Hash::GenerateFnv(buffer); - EXPECT_EQ(14272954169027804443, hash); - } + buffer = Buffer::Copy("abcdefghijklmnopqrstuvwxyz1234567890!", 37); + hash = Hash::GenerateFnv(buffer); + EXPECT_EQ(14272954169027804443, hash); + } } diff --git a/EppoTesting/Source/Core/LayerStack.cpp b/EppoTesting/Source/Core/LayerStack.cpp index 1bdfdfef..9beeb247 100644 --- a/EppoTesting/Source/Core/LayerStack.cpp +++ b/EppoTesting/Source/Core/LayerStack.cpp @@ -2,69 +2,69 @@ namespace Eppo { - TEST(LayerStackTest, PushLayer) - { - LayerStack layerStack; - Layer* layer = new Layer(); + TEST(LayerStackTest, PushLayer) + { + LayerStack layerStack; + Layer* layer = new Layer(); - ASSERT_EQ(layerStack.begin(), layerStack.end()); - ASSERT_EQ(layerStack.rbegin(), layerStack.rend()); + ASSERT_EQ(layerStack.begin(), layerStack.end()); + ASSERT_EQ(layerStack.rbegin(), layerStack.rend()); - layerStack.PushLayer(layer); + layerStack.PushLayer(layer); - ASSERT_NE(layerStack.begin(), layerStack.end()); - ASSERT_NE(layerStack.rbegin(), layerStack.rend()); - } + ASSERT_NE(layerStack.begin(), layerStack.end()); + ASSERT_NE(layerStack.rbegin(), layerStack.rend()); + } - TEST(LayerStackTest, PopLayer) - { - LayerStack layerStack; - Layer* layer = new Layer(); + TEST(LayerStackTest, PopLayer) + { + LayerStack layerStack; + Layer* layer = new Layer(); - ASSERT_EQ(layerStack.begin(), layerStack.end()); - ASSERT_EQ(layerStack.rbegin(), layerStack.rend()); + ASSERT_EQ(layerStack.begin(), layerStack.end()); + ASSERT_EQ(layerStack.rbegin(), layerStack.rend()); - layerStack.PushLayer(layer); + layerStack.PushLayer(layer); - ASSERT_NE(layerStack.begin(), layerStack.end()); - ASSERT_NE(layerStack.rbegin(), layerStack.rend()); + ASSERT_NE(layerStack.begin(), layerStack.end()); + ASSERT_NE(layerStack.rbegin(), layerStack.rend()); - layerStack.PopLayer(layer); + layerStack.PopLayer(layer); - ASSERT_EQ(layerStack.begin(), layerStack.end()); - ASSERT_EQ(layerStack.rbegin(), layerStack.rend()); - } + ASSERT_EQ(layerStack.begin(), layerStack.end()); + ASSERT_EQ(layerStack.rbegin(), layerStack.rend()); + } - TEST(LayerStackTest, PushOverlay) - { - LayerStack layerStack; - Layer* layer = new Layer(); + TEST(LayerStackTest, PushOverlay) + { + LayerStack layerStack; + Layer* layer = new Layer(); - ASSERT_EQ(layerStack.begin(), layerStack.end()); - ASSERT_EQ(layerStack.rbegin(), layerStack.rend()); + ASSERT_EQ(layerStack.begin(), layerStack.end()); + ASSERT_EQ(layerStack.rbegin(), layerStack.rend()); - layerStack.PushOverlay(layer); + layerStack.PushOverlay(layer); - ASSERT_NE(layerStack.begin(), layerStack.end()); - ASSERT_NE(layerStack.rbegin(), layerStack.rend()); - } + ASSERT_NE(layerStack.begin(), layerStack.end()); + ASSERT_NE(layerStack.rbegin(), layerStack.rend()); + } - TEST(LayerStackTest, PopOverlay) - { - LayerStack layerStack; - Layer* layer = new Layer(); + TEST(LayerStackTest, PopOverlay) + { + LayerStack layerStack; + Layer* layer = new Layer(); - ASSERT_EQ(layerStack.begin(), layerStack.end()); - ASSERT_EQ(layerStack.rbegin(), layerStack.rend()); + ASSERT_EQ(layerStack.begin(), layerStack.end()); + ASSERT_EQ(layerStack.rbegin(), layerStack.rend()); - layerStack.PushOverlay(layer); + layerStack.PushOverlay(layer); - ASSERT_NE(layerStack.begin(), layerStack.end()); - ASSERT_NE(layerStack.rbegin(), layerStack.rend()); + ASSERT_NE(layerStack.begin(), layerStack.end()); + ASSERT_NE(layerStack.rbegin(), layerStack.rend()); - layerStack.PopOverlay(layer); + layerStack.PopOverlay(layer); - ASSERT_EQ(layerStack.begin(), layerStack.end()); - ASSERT_EQ(layerStack.rbegin(), layerStack.rend()); - } + ASSERT_EQ(layerStack.begin(), layerStack.end()); + ASSERT_EQ(layerStack.rbegin(), layerStack.rend()); + } } diff --git a/EppoTesting/Source/Core/Ref.cpp b/EppoTesting/Source/Core/Ref.cpp index 1730c14b..89b8ae8a 100644 --- a/EppoTesting/Source/Core/Ref.cpp +++ b/EppoTesting/Source/Core/Ref.cpp @@ -2,170 +2,170 @@ // namespace Eppo // { -// // Dummy class -// class Base : public RefCounter -// { -// public: -// Base() = default; -// virtual ~Base() = default; - -// uint32_t GetVar() const { return m_UselessVar; } - -// private: -// uint32_t m_UselessVar = 27; -// }; - -// class Child : public Base -// { -// public: -// Child() = default; -// ~Child() = default; - -// uint32_t GetVar2() const { return m_UselessVar2; } - -// private: -// uint32_t m_UselessVar2 = 72; -// }; - -// // Tests -// TEST(RefTest, Constructor) -// { -// Ref2 ref = Ref2::Create(); - -// EXPECT_EQ(27, ref->GetVar()); -// EXPECT_EQ(1, ref.GetRefCount()); -// EXPECT_TRUE(ref.Raw()); -// } - -// TEST(RefTest, Destructor) -// { -// Ref2 ref = Ref2::Create(); - -// EXPECT_EQ(27, ref->GetVar()); -// EXPECT_EQ(1, ref.GetRefCount()); -// EXPECT_TRUE(ref.Raw()); - -// { -// Ref2 ref2 = ref; - -// EXPECT_EQ(27, ref->GetVar()); -// EXPECT_EQ(2, ref.GetRefCount()); -// EXPECT_TRUE(ref.Raw()); -// EXPECT_EQ(ref.Raw(), ref2.Raw()); -// } - -// EXPECT_EQ(27, ref->GetVar()); -// EXPECT_EQ(1, ref.GetRefCount()); -// EXPECT_TRUE(ref.Raw()); -// } - -// // TODO: What if ref count was higher? -// TEST(RefTest, CopyConstructor) -// { -// Ref2 ref = Ref2::Create(); - -// EXPECT_EQ(27, ref->GetVar()); -// EXPECT_EQ(1, ref.GetRefCount()); -// EXPECT_TRUE(ref.Raw()); - -// { -// Ref2 targetRef(ref); - -// EXPECT_EQ(27, ref->GetVar()); -// EXPECT_EQ(2, ref.GetRefCount()); -// EXPECT_TRUE(ref.Raw()); -// EXPECT_EQ(targetRef.Raw(), ref.Raw()); -// } - -// EXPECT_EQ(27, ref->GetVar()); -// EXPECT_EQ(1, ref.GetRefCount()); -// EXPECT_TRUE(ref.Raw()); -// } - -// // TODO: What if ref count was higher? -// TEST(RefTest, CopyAssignment) -// { -// Ref2 ref = Ref2::Create(); - -// EXPECT_EQ(27, ref->GetVar()); -// EXPECT_EQ(1, ref.GetRefCount()); -// EXPECT_TRUE(ref.Raw()); - -// { -// Ref2 targetRef = ref; - -// EXPECT_EQ(27, ref->GetVar()); -// EXPECT_EQ(2, ref.GetRefCount()); -// EXPECT_TRUE(ref.Raw()); -// EXPECT_EQ(targetRef.Raw(), ref.Raw()); -// } - -// EXPECT_EQ(27, ref->GetVar()); -// EXPECT_EQ(1, ref.GetRefCount()); -// EXPECT_TRUE(ref.Raw()); -// } - -// // TODO: What if ref count was higher? -// TEST(RefTest, MoveConstructor) -// { -// Ref2 ref = Ref2::Create(); - -// EXPECT_EQ(27, ref->GetVar()); -// EXPECT_EQ(1, ref.GetRefCount()); -// EXPECT_TRUE(ref.Raw()); - -// Ref2 targetRef(std::move(ref)); - -// EXPECT_EQ(27, targetRef->GetVar()); -// EXPECT_FALSE(ref.Raw()); -// EXPECT_EQ(1, targetRef.GetRefCount()); -// EXPECT_TRUE(targetRef.Raw()); -// } - -// TEST(RefTest, MoveAssignment) -// { -// Ref2 ref = Ref2::Create(); - -// EXPECT_EQ(27, ref->GetVar()); -// EXPECT_EQ(1, ref.GetRefCount()); -// EXPECT_TRUE(ref.Raw()); - -// Ref2 targetRef = std::move(ref); - -// EXPECT_EQ(27, targetRef->GetVar()); -// EXPECT_FALSE(ref.Raw()); -// EXPECT_EQ(1, targetRef.GetRefCount()); -// EXPECT_TRUE(targetRef.Raw()); -// } - -// TEST(RefTest, CastToPolymorphicType) -// { -// Ref2 ref; - -// EXPECT_EQ(0, ref.GetRefCount()); -// EXPECT_FALSE(ref.Raw()); - -// Ref2 childRef = Ref2::Create(); - -// EXPECT_EQ(27, childRef->GetVar()); -// EXPECT_EQ(72, childRef->GetVar2()); -// EXPECT_EQ(1, childRef.GetRefCount()); -// EXPECT_TRUE(childRef.Raw()); - -// ref = childRef; - -// EXPECT_EQ(27, ref->GetVar()); -// EXPECT_EQ(2, ref.GetRefCount()); -// EXPECT_TRUE(ref.Raw()); -// EXPECT_EQ(ref.Raw(), childRef.Raw()); - -// Ref2 childRef2 = ref.As(); - -// EXPECT_EQ(27, childRef2->GetVar()); -// EXPECT_EQ(72, childRef2->GetVar2()); -// EXPECT_EQ(3, ref.GetRefCount()); -// EXPECT_TRUE(ref.Raw()); -// EXPECT_EQ(ref.Raw(), childRef.Raw()); -// EXPECT_EQ(ref.Raw(), childRef2.Raw()); -// } +// // Dummy class +// class Base : public RefCounter +// { +// public: +// Base() = default; +// virtual ~Base() = default; + +// uint32_t GetVar() const { return m_UselessVar; } + +// private: +// uint32_t m_UselessVar = 27; +// }; + +// class Child : public Base +// { +// public: +// Child() = default; +// ~Child() = default; + +// uint32_t GetVar2() const { return m_UselessVar2; } + +// private: +// uint32_t m_UselessVar2 = 72; +// }; + +// // Tests +// TEST(RefTest, Constructor) +// { +// Ref2 ref = Ref2::Create(); + +// EXPECT_EQ(27, ref->GetVar()); +// EXPECT_EQ(1, ref.GetRefCount()); +// EXPECT_TRUE(ref.Raw()); +// } + +// TEST(RefTest, Destructor) +// { +// Ref2 ref = Ref2::Create(); + +// EXPECT_EQ(27, ref->GetVar()); +// EXPECT_EQ(1, ref.GetRefCount()); +// EXPECT_TRUE(ref.Raw()); + +// { +// Ref2 ref2 = ref; + +// EXPECT_EQ(27, ref->GetVar()); +// EXPECT_EQ(2, ref.GetRefCount()); +// EXPECT_TRUE(ref.Raw()); +// EXPECT_EQ(ref.Raw(), ref2.Raw()); +// } + +// EXPECT_EQ(27, ref->GetVar()); +// EXPECT_EQ(1, ref.GetRefCount()); +// EXPECT_TRUE(ref.Raw()); +// } + +// // TODO: What if ref count was higher? +// TEST(RefTest, CopyConstructor) +// { +// Ref2 ref = Ref2::Create(); + +// EXPECT_EQ(27, ref->GetVar()); +// EXPECT_EQ(1, ref.GetRefCount()); +// EXPECT_TRUE(ref.Raw()); + +// { +// Ref2 targetRef(ref); + +// EXPECT_EQ(27, ref->GetVar()); +// EXPECT_EQ(2, ref.GetRefCount()); +// EXPECT_TRUE(ref.Raw()); +// EXPECT_EQ(targetRef.Raw(), ref.Raw()); +// } + +// EXPECT_EQ(27, ref->GetVar()); +// EXPECT_EQ(1, ref.GetRefCount()); +// EXPECT_TRUE(ref.Raw()); +// } + +// // TODO: What if ref count was higher? +// TEST(RefTest, CopyAssignment) +// { +// Ref2 ref = Ref2::Create(); + +// EXPECT_EQ(27, ref->GetVar()); +// EXPECT_EQ(1, ref.GetRefCount()); +// EXPECT_TRUE(ref.Raw()); + +// { +// Ref2 targetRef = ref; + +// EXPECT_EQ(27, ref->GetVar()); +// EXPECT_EQ(2, ref.GetRefCount()); +// EXPECT_TRUE(ref.Raw()); +// EXPECT_EQ(targetRef.Raw(), ref.Raw()); +// } + +// EXPECT_EQ(27, ref->GetVar()); +// EXPECT_EQ(1, ref.GetRefCount()); +// EXPECT_TRUE(ref.Raw()); +// } + +// // TODO: What if ref count was higher? +// TEST(RefTest, MoveConstructor) +// { +// Ref2 ref = Ref2::Create(); + +// EXPECT_EQ(27, ref->GetVar()); +// EXPECT_EQ(1, ref.GetRefCount()); +// EXPECT_TRUE(ref.Raw()); + +// Ref2 targetRef(std::move(ref)); + +// EXPECT_EQ(27, targetRef->GetVar()); +// EXPECT_FALSE(ref.Raw()); +// EXPECT_EQ(1, targetRef.GetRefCount()); +// EXPECT_TRUE(targetRef.Raw()); +// } + +// TEST(RefTest, MoveAssignment) +// { +// Ref2 ref = Ref2::Create(); + +// EXPECT_EQ(27, ref->GetVar()); +// EXPECT_EQ(1, ref.GetRefCount()); +// EXPECT_TRUE(ref.Raw()); + +// Ref2 targetRef = std::move(ref); + +// EXPECT_EQ(27, targetRef->GetVar()); +// EXPECT_FALSE(ref.Raw()); +// EXPECT_EQ(1, targetRef.GetRefCount()); +// EXPECT_TRUE(targetRef.Raw()); +// } + +// TEST(RefTest, CastToPolymorphicType) +// { +// Ref2 ref; + +// EXPECT_EQ(0, ref.GetRefCount()); +// EXPECT_FALSE(ref.Raw()); + +// Ref2 childRef = Ref2::Create(); + +// EXPECT_EQ(27, childRef->GetVar()); +// EXPECT_EQ(72, childRef->GetVar2()); +// EXPECT_EQ(1, childRef.GetRefCount()); +// EXPECT_TRUE(childRef.Raw()); + +// ref = childRef; + +// EXPECT_EQ(27, ref->GetVar()); +// EXPECT_EQ(2, ref.GetRefCount()); +// EXPECT_TRUE(ref.Raw()); +// EXPECT_EQ(ref.Raw(), childRef.Raw()); + +// Ref2 childRef2 = ref.As(); + +// EXPECT_EQ(27, childRef2->GetVar()); +// EXPECT_EQ(72, childRef2->GetVar2()); +// EXPECT_EQ(3, ref.GetRefCount()); +// EXPECT_TRUE(ref.Raw()); +// EXPECT_EQ(ref.Raw(), childRef.Raw()); +// EXPECT_EQ(ref.Raw(), childRef2.Raw()); +// } // } diff --git a/EppoTesting/Source/Core/UUID.cpp b/EppoTesting/Source/Core/UUID.cpp index e1b14faa..4a713c96 100644 --- a/EppoTesting/Source/Core/UUID.cpp +++ b/EppoTesting/Source/Core/UUID.cpp @@ -3,38 +3,38 @@ // TODO: Fixed random number seed? namespace Eppo { - class UUIDTestFixture : public testing::TestWithParam - {}; + class UUIDTestFixture : public testing::TestWithParam + {}; - INSTANTIATE_TEST_SUITE_P(UUIDTest, UUIDTestFixture, - testing::Values(4, 20, 1024, 2024)); + INSTANTIATE_TEST_SUITE_P(UUIDTest, UUIDTestFixture, + testing::Values(4, 20, 1024, 2024)); - TEST(UUIDTest, Constructor) - { - UUID uuid; + TEST(UUIDTest, Constructor) + { + UUID uuid; - EXPECT_LT(0, uuid); - } + EXPECT_LT(0, uuid); + } - TEST(UUIDTest, Constructor_Zero) - { - UUID uuid(0); + TEST(UUIDTest, Constructor_Zero) + { + UUID uuid(0); - EXPECT_EQ(0, uuid); - } + EXPECT_EQ(0, uuid); + } - TEST_P(UUIDTestFixture, Constructor_UInt64) - { - UUID uuid(GetParam()); + TEST_P(UUIDTestFixture, Constructor_UInt64) + { + UUID uuid(GetParam()); - EXPECT_EQ(GetParam(), uuid); - } + EXPECT_EQ(GetParam(), uuid); + } - TEST_P(UUIDTestFixture, Constructor_Copy) - { - UUID uuid(GetParam()); - UUID targetUuid(uuid); + TEST_P(UUIDTestFixture, Constructor_Copy) + { + UUID uuid(GetParam()); + UUID targetUuid(uuid); - EXPECT_EQ(uuid, targetUuid); - } + EXPECT_EQ(uuid, targetUuid); + } } diff --git a/EppoTesting/Source/Core/Window.cpp b/EppoTesting/Source/Core/Window.cpp index 3c1c51a2..8a8d47f1 100644 --- a/EppoTesting/Source/Core/Window.cpp +++ b/EppoTesting/Source/Core/Window.cpp @@ -2,73 +2,73 @@ namespace Eppo { - TEST(WindowTest, ConstructorWithSpecification) - { - WindowSpecification specification - { - "Test Window", - 800, - 600, - 60, - false - }; + TEST(WindowTest, ConstructorWithSpecification) + { + WindowSpecification specification + { + "Test Window", + 800, + 600, + 60, + false + }; - // TODO: We can't do this apparently because it needs a window handle.... - // - //Window window(specification); - // - //EXPECT_EQ(window.GetRendererContext(), nullptr); - //EXPECT_EQ(window.GetSpecification().Title, "Test Window"); - //EXPECT_EQ(window.GetSpecification().Width, 800); - //EXPECT_EQ(window.GetSpecification().Height, 600); - //EXPECT_EQ(window.GetSpecification().RefreshRate, 60); - //EXPECT_EQ(window.GetSpecification().OverrideSpecification, false); - } + // TODO: We can't do this apparently because it needs a window handle.... + // + //Window window(specification); + // + //EXPECT_EQ(window.GetRendererContext(), nullptr); + //EXPECT_EQ(window.GetSpecification().Title, "Test Window"); + //EXPECT_EQ(window.GetSpecification().Width, 800); + //EXPECT_EQ(window.GetSpecification().Height, 600); + //EXPECT_EQ(window.GetSpecification().RefreshRate, 60); + //EXPECT_EQ(window.GetSpecification().OverrideSpecification, false); + } - // TODO: Test fixture - TEST(WindowTest, Init) - { - WindowSpecification specification - { - "Test Window", - 800, - 600, - 60, - false - }; + // TODO: Test fixture + TEST(WindowTest, Init) + { + WindowSpecification specification + { + "Test Window", + 800, + 600, + 60, + false + }; - // TODO: We can't do this apparently because it needs a window handle.... - // - //Window window(specification); - // - //window.Init(); - // - //EXPECT_NE(window.GetRendererContext(), nullptr); - } + // TODO: We can't do this apparently because it needs a window handle.... + // + //Window window(specification); + // + //window.Init(); + // + //EXPECT_NE(window.GetRendererContext(), nullptr); + } - // TODO: Test fixture - TEST(WindowTest, Shutdown) - { - WindowSpecification specification - { - "Test Window", - 800, - 600, - 60, - false - }; - } + // TODO: Test fixture + TEST(WindowTest, Shutdown) + { + WindowSpecification specification + { + "Test Window", + 800, + 600, + 60, + false + }; + } - // TODO: Test fixture - TEST(WindowTest, ProcessEvents) - { - WindowSpecification specification - { - "Test Window", - 800, - 600, - 60, - false - }; - } + // TODO: Test fixture + TEST(WindowTest, ProcessEvents) + { + WindowSpecification specification + { + "Test Window", + 800, + 600, + 60, + false + }; + } }