From c4e79c61ed222947ecf73464d159d1472a08efec Mon Sep 17 00:00:00 2001 From: antopilo Date: Sun, 26 Jan 2025 20:21:04 -0500 Subject: [PATCH] Multi-scene editing refactor --- Editor/src/Events/EditorRequests.h | 33 + Editor/src/Misc/ImGuiTextHelper.cpp | 26 + Editor/src/Misc/ImGuiTextHelper.h | 24 +- Editor/src/Windows/EditorInterface.cpp | 71 +- Editor/src/Windows/EditorInterface.h | 8 +- Editor/src/Windows/FileSystemUI.cpp | 17 +- .../src/Windows/SceneEditor/EditorContext.h | 2 +- .../Windows/SceneEditor/SceneEditorWindow.cpp | 47 +- .../Windows/SceneEditor/SceneEditorWindow.h | 1 + .../SceneEditor/Widgets/FileBrowserWidget.cpp | 920 +++++++ .../SceneEditor/Widgets/FileBrowserWidget.h | 39 + .../SceneEditor/Widgets/IEditorWidget.h | 12 +- .../SceneEditor/Widgets/LoggerWidget.cpp | 210 ++ .../SceneEditor/Widgets/LoggerWidget.h | 20 + .../Widgets/SceneHierarchyWidget.cpp | 4 +- .../Widgets/SelectionPropertyWidget.cpp | 2147 ++++++++++++++++- .../Widgets/SelectionPropertyWidget.h | 58 +- .../SceneEditor/Widgets/ViewportWidget.cpp | 151 ++ .../SceneEditor/Widgets/ViewportWidget.h | 24 + Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp | 11 +- Nuake/src/UI/ImUI.cpp | 12 + Nuake/src/UI/ImUI.h | 1 + Nuake/src/Window.cpp | 6 +- 23 files changed, 3755 insertions(+), 89 deletions(-) create mode 100644 Editor/src/Events/EditorRequests.h create mode 100644 Editor/src/Misc/ImGuiTextHelper.cpp create mode 100644 Editor/src/Windows/SceneEditor/Widgets/FileBrowserWidget.cpp create mode 100644 Editor/src/Windows/SceneEditor/Widgets/FileBrowserWidget.h create mode 100644 Editor/src/Windows/SceneEditor/Widgets/LoggerWidget.cpp create mode 100644 Editor/src/Windows/SceneEditor/Widgets/LoggerWidget.h create mode 100644 Editor/src/Windows/SceneEditor/Widgets/ViewportWidget.cpp create mode 100644 Editor/src/Windows/SceneEditor/Widgets/ViewportWidget.h diff --git a/Editor/src/Events/EditorRequests.h b/Editor/src/Events/EditorRequests.h new file mode 100644 index 00000000..fc567bc9 --- /dev/null +++ b/Editor/src/Events/EditorRequests.h @@ -0,0 +1,33 @@ +#include +#include + +namespace Nuake +{ + class Scene; + class File; +} + +// This is all the commands that the editor can receive from anywhere in the UI +class EditorRequests +{ +private: + MulticastDelegate> requestLoadScene; + + EditorRequests() = default; + ~EditorRequests() = default; + +public: + static EditorRequests& Get() + { + static EditorRequests instance; + return instance; + } + +public: + void RequestLoadScene(Ref sceneFile) + { + requestLoadScene.Broadcast(sceneFile); + } + + auto& OnRequestLoadScene() { return requestLoadScene; } +}; \ No newline at end of file diff --git a/Editor/src/Misc/ImGuiTextHelper.cpp b/Editor/src/Misc/ImGuiTextHelper.cpp new file mode 100644 index 00000000..9fe66f40 --- /dev/null +++ b/Editor/src/Misc/ImGuiTextHelper.cpp @@ -0,0 +1,26 @@ +#include "ImGuiTextHelper.h" + +#include + +void ImGuiTextSTD(const std::string& label, std::string& value) +{ + char buffer[256]; + memset(buffer, 0, sizeof(buffer)); + strncpy_s(buffer, value.c_str(), sizeof(buffer)); + if (ImGui::InputText(label.c_str(), buffer, sizeof(buffer))) + { + + value = std::string(buffer); + } +} + +void ImGuiTextMultiline(const std::string& label, std::string& value) +{ + char buffer[256]; + memset(buffer, 0, sizeof(buffer)); + strncpy_s(buffer, value.c_str(), sizeof(buffer)); + if (ImGui::InputTextMultiline(label.c_str(), buffer, sizeof(buffer))) + { + value = std::string(buffer); + } +} \ No newline at end of file diff --git a/Editor/src/Misc/ImGuiTextHelper.h b/Editor/src/Misc/ImGuiTextHelper.h index 1235abf5..20bbdad7 100644 --- a/Editor/src/Misc/ImGuiTextHelper.h +++ b/Editor/src/Misc/ImGuiTextHelper.h @@ -1,26 +1,6 @@ #pragma once #include -#include -void ImGuiTextSTD(const std::string& label, std::string& value) -{ - char buffer[256]; - memset(buffer, 0, sizeof(buffer)); - strncpy_s(buffer, value.c_str(), sizeof(buffer)); - if (ImGui::InputText(label.c_str(), buffer, sizeof(buffer))) - { - - value = std::string(buffer); - } -} +void ImGuiTextSTD(const std::string& label, std::string& value); -void ImGuiTextMultiline(const std::string& label, std::string& value) -{ - char buffer[256]; - memset(buffer, 0, sizeof(buffer)); - strncpy_s(buffer, value.c_str(), sizeof(buffer)); - if (ImGui::InputTextMultiline(label.c_str(), buffer, sizeof(buffer))) - { - value = std::string(buffer); - } -} +void ImGuiTextMultiline(const std::string& label, std::string& value); diff --git a/Editor/src/Windows/EditorInterface.cpp b/Editor/src/Windows/EditorInterface.cpp index 71d9125e..56a203cf 100644 --- a/Editor/src/Windows/EditorInterface.cpp +++ b/Editor/src/Windows/EditorInterface.cpp @@ -67,6 +67,8 @@ #include "src/Rendering/Vulkan/SceneRenderPipeline.h" #include +#include "../Events/EditorRequests.h" + namespace Nuake { ImFont* normalFont; @@ -126,6 +128,8 @@ namespace Nuake { Logger::Log("Creating editor windows", "window", VERBOSE); filesystem = new FileSystemUI(this); + //floatingFileBrowser = CreateScope(this); + _WelcomeWindow = new WelcomeWindow(this); _NewProjectWindow = new NewProjectWindow(this); _audioWindow = new AudioWindow(); @@ -147,6 +151,9 @@ namespace Nuake { hit = m_TitleBarHovered; }); + EditorRequests& requests = EditorRequests::Get(); + requests.OnRequestLoadScene().AddRaw(this, &EditorInterface::OnRequestLoadScene); + Engine::OnSceneLoaded.AddRaw(this, &EditorInterface::OnSceneLoaded); } @@ -946,6 +953,16 @@ namespace Nuake { if (ImGui::BeginViewportSideBar("##MainStatusBar", viewport, ImGuiDir_Down, height, window_flags)) { if (ImGui::BeginMenuBar()) { + if (ImGui::Button("File Browser")) + { + this->showFloatingFileBrowser = !this->showFloatingFileBrowser; + } + + if (ImGui::Button("Logger")) + { + this->showFloatingLogger = !this->showFloatingLogger; + } + ImGui::Text(m_StatusMessage.c_str()); ImGui::SameLine(); @@ -2112,6 +2129,11 @@ namespace Nuake { } } + void EditorInterface::OnRequestLoadScene(Ref file) + { + OpenSceneWindow(file->GetRelativePath()); + } + void EditorInterface::OpenPrefabWindow(const std::string& prefabPath) { if (!FileSystem::FileExists(prefabPath)) @@ -2500,6 +2522,10 @@ namespace Nuake { if (isLoadingProjectQueue) { _WelcomeWindow->LoadQueuedProject(); + + auto project = Engine::GetProject(); + OpenSceneWindow(project->DefaultScene->Path); + isLoadingProjectQueue = false; auto window = Window::Get(); @@ -2741,31 +2767,30 @@ namespace Nuake { ImGuiWindowClass top_level_class; top_level_class.ClassId = ImHashStr("SceneEditor"); top_level_class.DockingAllowUnclassed = false; - ImGui::DockSpace(ImGui::GetID("SceneEditorDockSpace"), {0, 0}, 0, &top_level_class); + + ImGuiDockNodeFlags flags = ImGuiDockNodeFlags_NoSplit; + ImGui::DockSpace(ImGui::GetID("SceneEditorDockSpace"), {0, 0}, flags, &top_level_class); ImGuiDockNode* node = (ImGuiDockNode*)GImGui->DockContext.Nodes.GetVoidPtr(ImGui::GetID("SceneEditorDockSpace")); - ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 32); - if(ImGui::DockNodeBeginAmendTabBar(node)) + if (node) { - ImGui::SetNextItemWidth(48); - if (ImGui::BeginTabItem("##logoPadding", 0, ImGuiTabItemFlags_Leading)) + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 32); + if (ImGui::DockNodeBeginAmendTabBar(node)) { + ImGui::SetNextItemWidth(48); + if (ImGui::BeginTabItem("##logoPadding", 0, ImGuiTabItemFlags_Leading)) + { - ImGui::EndTabItem(); + ImGui::EndTabItem(); + } + ImGui::DockNodeEndAmendTabBar(); } - ImGui::DockNodeEndAmendTabBar(); } - ImGui::SetNextWindowClass(&top_level_class); - ImGui::Begin("SceneEditor"); - { - ImGuiWindowClass inside_document_class; - inside_document_class.ClassId = ImHashStr("SceneEditor1"); - ImGui::DockSpace(ImGui::GetID("SceneEditorWindowDockspace"), ImGui::GetContentRegionAvail(), ImGuiDockNodeFlags_None, &inside_document_class); - } ImGui::End(); - ImGui::End(); + + //DrawMenuBar(); //DrawMenuBars(); @@ -2788,12 +2813,16 @@ namespace Nuake { } //pInterface.DrawEntitySettings(); - DrawViewport(); - DrawSceneTree(); - SelectionPanel->Draw(Selection); - DrawLogger(); - filesystem->Draw(); - filesystem->DrawDirectoryExplorer(); + //DrawViewport(); + //DrawSceneTree(); + //SelectionPanel->Draw(Selection); + //DrawLogger(); + // + //if (this->showFloatingFileBrowser) + //{ + // filesystem->Draw(); + // filesystem->DrawDirectoryExplorer(); + //} //auto node = ImGui::DockBuilderGetNode(1); //node->SizeRef = { node->Size.x, 50.0f }; diff --git a/Editor/src/Windows/EditorInterface.h b/Editor/src/Windows/EditorInterface.h index 7717c2c2..15f5b4eb 100644 --- a/Editor/src/Windows/EditorInterface.h +++ b/Editor/src/Windows/EditorInterface.h @@ -22,7 +22,6 @@ #include "SceneEditor/SceneEditorWindow.h" - using namespace NuakeEditor; namespace Nuake @@ -71,6 +70,10 @@ namespace Nuake Ref m_SelectedMaterial; Ref m_CurrentDirectory; + // Filebrowser + bool showFloatingFileBrowser; + bool showFloatingLogger; + bool m_IsMaterialSelected = false; std::string m_StatusMessage = ""; @@ -82,6 +85,8 @@ namespace Nuake AudioWindow* _audioWindow; FileSystemUI* filesystem; + + //Scope floatingFileBrowser; bool isNewProject = false; static EditorSelection Selection; EditorSelectionPanel* SelectionPanel; @@ -120,6 +125,7 @@ namespace Nuake void DrawProjectSettings(); void Overlay(); + void OnRequestLoadScene(Ref file); void OpenPrefabWindow(const std::string& prefabPath); void OpenSceneWindow(const std::string& scenePath); diff --git a/Editor/src/Windows/FileSystemUI.cpp b/Editor/src/Windows/FileSystemUI.cpp index fec33dea..8febca9a 100644 --- a/Editor/src/Windows/FileSystemUI.cpp +++ b/Editor/src/Windows/FileSystemUI.cpp @@ -267,7 +267,8 @@ namespace Nuake OS::OpenIn(file->GetAbsolutePath()); break; case FileType::Scene: - shouldOpenScene = true; + //shouldOpenScene = true; + this->Editor->OpenSceneWindow(file->GetRelativePath()); break; case FileType::Solution: OS::OpenIn(file->GetAbsolutePath()); @@ -633,18 +634,6 @@ namespace Nuake ImGui::PopFont(); } - bool Splitter(bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size = -1.0f) - { - using namespace ImGui; - ImGuiContext& g = *GImGui; - ImGuiWindow* window = g.CurrentWindow; - ImGuiID id = window->GetID("##Splitter"); - ImRect bb; - bb.Min = window->DC.CursorPos + (split_vertically ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1)); - bb.Max = bb.Min + CalcItemSize(split_vertically ? ImVec2(thickness, splitter_long_axis_size) : ImVec2(splitter_long_axis_size, thickness), 0.0f, 0.0f); - return SplitterBehavior(bb, id, split_vertically ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, min_size1, min_size2, 0.0f); - } - void FileSystemUI::DrawContextMenu() { if (!m_HasClickedOnFile && ImGui::IsMouseReleased(1) && ImGui::IsWindowHovered()) @@ -833,7 +822,7 @@ namespace Nuake return; ImVec2 avail = ImGui::GetContentRegionAvail(); - Splitter(true, 4.0f, &sz1, &sz2, 100, 8, avail.y); + UI::Splitter(true, 4.0f, &sz1, &sz2, 100, 8, avail.y); ImVec4* colors = ImGui::GetStyle().Colors; ImGui::PushStyleColor(ImGuiCol_ChildBg, colors[ImGuiCol_TitleBgCollapsed]); diff --git a/Editor/src/Windows/SceneEditor/EditorContext.h b/Editor/src/Windows/SceneEditor/EditorContext.h index b3bbe3a4..10bbcb94 100644 --- a/Editor/src/Windows/SceneEditor/EditorContext.h +++ b/Editor/src/Windows/SceneEditor/EditorContext.h @@ -33,7 +33,7 @@ public: const EditorSelection& GetSelection() const { return selection; } void SetSelection(EditorSelection inSelection) { - selection = selection; + selection = inSelection; OnSelectionChanged.Broadcast(selection); } diff --git a/Editor/src/Windows/SceneEditor/SceneEditorWindow.cpp b/Editor/src/Windows/SceneEditor/SceneEditorWindow.cpp index c581fa04..5bf21f8d 100644 --- a/Editor/src/Windows/SceneEditor/SceneEditorWindow.cpp +++ b/Editor/src/Windows/SceneEditor/SceneEditorWindow.cpp @@ -2,17 +2,25 @@ #include "Widgets/SceneHierarchyWidget.h" #include "Widgets/SelectionPropertyWidget.h" +#include "Widgets/LoggerWidget.h" +#include "Widgets/ViewportWidget.h" +#include "Widgets/FileBrowserWidget.h" -#include +#include "src/Scene/Scene.h" + +#include "src/UI/ImUI.h" using namespace Nuake; -SceneEditorWindow::SceneEditorWindow(Ref inScene) +SceneEditorWindow::SceneEditorWindow(Ref inScene) : + editorContext(inScene, inScene->Path), + layoutInitialized(false) { - editorContext = EditorContext(inScene, inScene->GetName()); - RegisterWidget(); RegisterWidget(); + RegisterWidget(); + RegisterWidget(); + RegisterWidget(); } void SceneEditorWindow::Update(float ts) @@ -26,27 +34,44 @@ void SceneEditorWindow::Update(float ts) void SceneEditorWindow::Draw() { Ref scene = editorContext.GetScene(); - const std::string sceneName = scene->GetName(); + const std::string sceneName = scene->Path; // This is to prevent other windows of other scene editors to dock ImGuiWindowClass windowClass; - windowClass.ClassId = ImHashStr(editorContext.GetWindowClass().data()); + windowClass.ClassId = ImHashStr("SceneEditor"); windowClass.DockingAllowUnclassed = false; ImGui::SetNextWindowClass(&windowClass); - if (ImGui::Begin(sceneName.c_str())) + ImGui::SetNextWindowSizeConstraints({1280, 720}, { FLT_MAX, FLT_MAX }); + if (ImGui::Begin(std::string(ICON_FA_WINDOW_MAXIMIZE + std::string(" ") + sceneName).c_str())) { ImGuiWindowClass localSceneEditorClass; localSceneEditorClass.ClassId = ImHashStr(sceneName.c_str()); - std::string dockspaceId = std::string("Dockspace##" + sceneName); - ImGui::DockSpace(ImGui::GetID(dockspaceId.c_str()), ImGui::GetContentRegionAvail(), ImGuiDockNodeFlags_None, &localSceneEditorClass); - + std::string dockspaceName = std::string("Dockspace##" + sceneName); + + ImGuiID dockspaceId = ImGui::GetID(dockspaceName.c_str()); + ImGui::DockSpace(dockspaceId, ImGui::GetContentRegionAvail(), ImGuiDockNodeFlags_None, &localSceneEditorClass); + for (auto& widget : widgets) { widget->Draw(); } - ImGui::End(); + // Build initial docking layout + if (!layoutInitialized) + { + auto dockbottomId = ImGui::DockBuilderSplitNode(dockspaceId, ImGuiDir_Down, 0.3f, nullptr, &dockspaceId); + auto dockLeftId = ImGui::DockBuilderSplitNode(dockspaceId, ImGuiDir_Left, 0.3f, nullptr, &dockspaceId); + auto dockRightId = ImGui::DockBuilderSplitNode(dockspaceId, ImGuiDir_Right, 0.5f, nullptr, &dockspaceId); + + widgets[0]->DockTo(dockLeftId); + widgets[1]->DockTo(dockRightId); + widgets[2]->DockTo(dockbottomId); + widgets[3]->DockTo(dockspaceId); + widgets[4]->DockTo(dockbottomId); + layoutInitialized = true; + } } + ImGui::End(); } diff --git a/Editor/src/Windows/SceneEditor/SceneEditorWindow.h b/Editor/src/Windows/SceneEditor/SceneEditorWindow.h index 49664939..20062788 100644 --- a/Editor/src/Windows/SceneEditor/SceneEditorWindow.h +++ b/Editor/src/Windows/SceneEditor/SceneEditorWindow.h @@ -22,6 +22,7 @@ concept DerivedFromEditorWidget = std::derived_from; class SceneEditorWindow { private: + bool layoutInitialized; std::string windowID; // This is used for imgui docking EditorContext editorContext; diff --git a/Editor/src/Windows/SceneEditor/Widgets/FileBrowserWidget.cpp b/Editor/src/Windows/SceneEditor/Widgets/FileBrowserWidget.cpp new file mode 100644 index 00000000..99c40469 --- /dev/null +++ b/Editor/src/Windows/SceneEditor/Widgets/FileBrowserWidget.cpp @@ -0,0 +1,920 @@ +#include "FileBrowserWidget.h" + +#include "../../../Misc/PopupHelper.h" +#include "../../../Events/EditorRequests.h" + +#include +#include +#include +#include + +#include + +using namespace Nuake; + +FileBrowserWidget::FileBrowserWidget(EditorContext& inCtx) : IEditorWidget(inCtx) +{ + +} + +void FileBrowserWidget::Update(float ts) +{ + +} + +void FileBrowserWidget::Draw() +{ + if (BeginWidgetWindow("File Browser")) + { + Ref rootDirectory = FileSystem::GetFileTree(); + + auto availableSpace = ImGui::GetContentRegionAvail(); + UI::Splitter(true, 4.0f, &splitterSizeLeft, &splitterSizeRight, 100, 8, availableSpace.y); + + ImVec4* colors = ImGui::GetStyle().Colors; + ImGui::PushStyleColor(ImGuiCol_ChildBg, colors[ImGuiCol_TitleBgCollapsed]); + ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 8); + + if (ImGui::BeginChild("Tree", ImVec2(splitterSizeLeft, availableSpace.y), true)) + { + ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_SpanAvailWidth | + ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_DefaultOpen | + ImGuiTreeNodeFlags_FramePadding; + + bool isSelected = this->currentDirectory == FileSystem::RootDirectory; + if (isSelected) + { + base_flags |= ImGuiTreeNodeFlags_Selected; + } + + // Header + { + UIFont boldFont = UIFont(Fonts::Bold); + bool open = ImGui::TreeNodeEx("PROJECT", base_flags); + if (ImGui::IsItemClicked()) + { + this->currentDirectory = FileSystem::RootDirectory; + } + } + + // Draw tree + for (auto& d : rootDirectory->Directories) + { + DrawFiletree(d); + } + + ImGui::TreePop(); + } + ImGui::PopStyleVar(); + ImGui::PopStyleColor(); + ImGui::EndChild(); + + ImGui::SameLine(); + + // Build file path buttons + auto paths = std::vector>(); + { + Ref currentParent = currentDirectory; + paths.push_back(currentDirectory); + + // Recursively build the path to the root + while (currentParent != nullptr) + { + paths.push_back(currentParent); + currentParent = currentParent->Parent; + } + } + + availableSpace = ImGui::GetContentRegionAvail(); + if (ImGui::BeginChild("Wrapper", availableSpace)) + { + availableSpace.y = 30; + + if (ImGui::BeginChild("Path", availableSpace, true)) + { + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, { 2, 4 }); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + + const auto buttonSize = ImVec2(26, 26); + + // Refresh button + std::string refreshIcon = ICON_FA_SYNC_ALT; + if (ImGui::Button((refreshIcon).c_str(), buttonSize)) + { + // RefreshFileBrowser(); + } + + ImGui::SameLine(); + + const auto cursorStart = ImGui::GetCursorPosX(); + { // Go back + if (ImGui::Button((std::string(ICON_FA_ANGLE_LEFT)).c_str(), buttonSize)) + { + if (currentDirectory != FileSystem::RootDirectory) + { + currentDirectory = currentDirectory->Parent; + } + } + } + + ImGui::SameLine(); + + const auto cursorEnd = ImGui::GetCursorPosX(); + const auto buttonWidth = cursorEnd - cursorStart; + + if (ImGui::Button((std::string(ICON_FA_ANGLE_RIGHT)).c_str(), buttonSize)) + { + if (editorContext.GetSelection().Type == EditorSelectionType::Directory) + { + currentDirectory = editorContext.GetSelection().Directory; + } + } + + const uint32_t numButtonAfterPathBrowser = 2; + const uint32_t searchBarSize = 6; + ImGui::SameLine(); + + // Draw path buttons + { + ImGui::PushStyleColor(ImGuiCol_ChildBg, colors[ImGuiCol_TitleBgCollapsed]); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4, 4)); + ImGui::BeginChild("pathBrowser", ImVec2((ImGui::GetContentRegionAvail().x - (numButtonAfterPathBrowser * buttonWidth * searchBarSize)) - 4.0, 24)); + for (int i = paths.size() - 1; i > 0; i--) + { + if (i != paths.size()) + { + ImGui::SameLine(); + } + + std::string pathLabel; + if (i == paths.size() - 1) + { + pathLabel = "Project files"; + } + else + { + pathLabel = paths[i]->Name; + } + + if (ImGui::Button(pathLabel.c_str())) + { + currentDirectory = paths[i]; + } + + ImGui::SameLine(); + ImGui::Text("/"); + } + ImGui::EndChild(); + ImGui::PopStyleVar(); + ImGui::PopStyleVar(); + ImGui::PopStyleColor(); + } + + ImGui::SameLine(); + + // Search bar + ImGui::BeginChild("searchBar", ImVec2(ImGui::GetContentRegionAvail().x - (numButtonAfterPathBrowser * buttonWidth), 24)); + char buffer[256]; + memset(buffer, 0, sizeof(buffer)); + std::strncpy(buffer, searchQuery.c_str(), sizeof(buffer)); + if (ImGui::InputTextEx("##Search", "Asset search & filter ..", buffer, sizeof(buffer), ImVec2(ImGui::GetContentRegionAvail().x, 24), ImGuiInputTextFlags_EscapeClearsAll)) + { + searchQuery = std::string(buffer); + } + ImGui::EndChild(); + + ImGui::SameLine(); + + if (ImGui::Button((std::string(ICON_FA_FOLDER_OPEN)).c_str(), buttonSize)) + { + OS::OpenIn(currentDirectory->FullPath); + } + ImGui::PopStyleColor(); // Button color + + ImGui::SameLine(); + ImGui::PopStyleVar(); + } + ImGui::EndChild(); + + ImDrawList* drawList = ImGui::GetWindowDrawList(); + ImGui::GetWindowDrawList()->AddLine(ImVec2(ImGui::GetCursorPosX(), ImGui::GetCursorPosY()), ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetCursorPosY()), IM_COL32(255, 0, 0, 255), 1.0f); + + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0, 0)); + availableSpace = ImGui::GetContentRegionAvail(); + + bool child = ImGui::BeginChild("Content", availableSpace); + ImGui::PopStyleVar(); + ImGui::SameLine(); + if (child) + { + int width = availableSpace.x; + ImVec2 buttonSize = ImVec2(80, 80); + int amount = (int)(width / 110); + if (amount <= 0) amount = 1; + + int i = 1; // current amount of item per row. + if (ImGui::BeginTable("ssss", amount)) + { + // Button to go up a level. + //if (m_CurrentDirectory && m_CurrentDirectory != FileSystem::RootDirectory && m_CurrentDirectory->Parent) + //{ + // ImGui::TableNextColumn(); + // if (ImGui::Button("..", buttonSize)) + // m_CurrentDirectory = m_CurrentDirectory->Parent; + // i++; + //} + + if (currentDirectory && currentDirectory->Directories.size() > 0) + { + for (Ref& d : currentDirectory->Directories) + { + if (d->GetName() == "bin" || d->GetName() == ".vs" || d->GetName() == "obj") + { + continue; + } + + if (Nuake::String::Sanitize(d->Name).find(Nuake::String::Sanitize(searchQuery)) != std::string::npos) + { + if (i + 1 % amount != 0) + ImGui::TableNextColumn(); + else + ImGui::TableNextRow(); + + DrawDirectory(d, i); + i++; + } + } + } + + if (currentDirectory && currentDirectory->Files.size() > 0) + { + for (auto& f : currentDirectory->Files) + { + if (searchQuery.empty() || f->GetName().find(String::Sanitize(searchQuery)) != std::string::npos) + { + if (f->GetFileType() == FileType::Unknown || f->GetFileType() == FileType::Assembly) + { + continue; + } + + if (i + 1 % amount != 0 || i == 1) + { + ImGui::TableNextColumn(); + } + else + { + ImGui::TableNextRow(); + } + + DrawFile(f, i); + i++; + } + } + } + + //DrawContextMenu(); + + //m_HasClickedOnFile = false; + + ImGui::EndTable(); + } + } + ImGui::EndChild(); + } + ImGui::EndChild(); + } + ImGui::End(); +} + +void FileBrowserWidget::DrawFiletree(Ref dir) +{ + ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | + ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_FramePadding; + + if (currentDirectory == dir) + { + base_flags |= ImGuiTreeNodeFlags_Selected; + } + + if (dir->Directories.size() <= 0) + { + base_flags |= ImGuiTreeNodeFlags_Leaf; + } + + std::string icon = ICON_FA_FOLDER; + bool open = ImGui::TreeNodeEx((icon + " " + dir->Name.c_str()).c_str(), base_flags); + + if (ImGui::IsItemClicked()) + { + currentDirectory = dir; + } + + if (open) + { + for (auto& d : dir->Directories) + { + DrawFiletree(d); + } + + ImGui::TreePop(); + } +} + +void FileBrowserWidget::DrawDirectory(Ref directory, uint32_t drawId) +{ + ImGui::PushFont(FontManager::GetFont(Icons)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f); + const char* icon = ICON_FA_FOLDER; + const std::string id = std::string("##") + directory->Name; + + ImVec2 prevCursor = ImGui::GetCursorPos(); + ImVec2 prevScreenPos = ImGui::GetCursorScreenPos(); + const bool selected = ImGui::Selectable(id.c_str(), editorContext.GetSelection().Directory == directory, ImGuiSelectableFlags_AllowOverlap | ImGuiSelectableFlags_AllowDoubleClick, ImVec2(100, 150)); + const std::string hoverMenuId = std::string("item_hover_menu") + std::to_string(drawId); + if (ImGui::IsItemHovered() && ImGui::IsMouseReleased(1)) + { + ImGui::OpenPopup(hoverMenuId.c_str()); + //m_HasClickedOnFile = true; + } + + const std::string renameId = "Rename" + std::string("##") + hoverMenuId; + bool shouldRename = false; + + const std::string deleteId = "Delete" + std::string("##") + hoverMenuId; + bool shouldDelete = false; + + if (selected) + { + if (ImGui::IsMouseDoubleClicked(0)) + { + currentDirectory = directory; + } + + //Editor->Selection = EditorSelection(directory); + } + + if (ImGui::IsItemHovered()) + ImGui::SetTooltip(directory->Name.c_str()); + + + ImGui::SetCursorPos(prevCursor); + ImGui::Image((ImTextureID)TextureManager::Get()->GetTexture2("Resources/Images/folder_icon.png")->GetImGuiDescriptorSet(), ImVec2(100, 100)); + + auto imguiStyle = ImGui::GetStyle(); + + ImVec2 startOffset = ImVec2(imguiStyle.CellPadding.x / 2.0f, 0); + ImVec2 offsetEnd = ImVec2(startOffset.x, imguiStyle.CellPadding.y / 2.0f); + ImU32 rectColor = IM_COL32(255, 255, 255, 16); + ImGui::GetWindowDrawList()->AddRectFilled(prevScreenPos + ImVec2(0, 100) - startOffset, prevScreenPos + ImVec2(100, 150) + offsetEnd, rectColor, 1.0f); + std::string visibleName = directory->Name; + const uint32_t MAX_CHAR_NAME = 34; + if (directory->Name.size() > MAX_CHAR_NAME) + { + visibleName = std::string(directory->Name.begin(), directory->Name.begin() + MAX_CHAR_NAME - 3) + "..."; + } + + ImGui::TextWrapped(visibleName.c_str()); + + ImGui::SetCursorPosY(prevCursor.y + 150 - ImGui::GetTextLineHeight()); + ImGui::TextColored({ 1, 1, 1, 0.5f }, "Folder"); + + ImGui::PopStyleVar(); + + + if (ImGui::BeginPopup(hoverMenuId.c_str())) + { + if (ImGui::MenuItem("Open")) + { + currentDirectory = directory; + } + + ImGui::Separator(); + + if (ImGui::BeginMenu("Copy")) + { + if (ImGui::MenuItem("Full Path")) + { + OS::CopyToClipboard(directory->FullPath); + } + + if (ImGui::MenuItem("Directory Name")) + { + OS::CopyToClipboard(String::Split(directory->Name, '/')[0]); + } + + ImGui::EndPopup(); + } + + if (ImGui::MenuItem("Delete")) + { + shouldDelete = true; + } + + if (ImGui::MenuItem("Rename")) + { + shouldRename = true; + } + + ImGui::Separator(); + + if (ImGui::MenuItem("Show in File Explorer")) + { + OS::OpenIn(directory->FullPath); + } + + ImGui::EndPopup(); + } + + // Rename Popup + + if (shouldRename) + { + //renameTempValue = directory->Name; + //PopupHelper::OpenPopup(renameId); + } + + //if (PopupHelper::DefineTextDialog(renameId, renameTempValue)) + //{ +// if (OS::RenameDirectory(directory, renameTempValue) != 0) +// { +// Logger::Log("Cannot rename directory: " + renameTempValue, "editor", CRITICAL); +// } +// //RefreshFileBrowser(); +// renameTempValue = ""; + //} + + // Delete Popup + + if (shouldDelete) + { + PopupHelper::OpenPopup(deleteId); + } + + if (PopupHelper::DefineConfirmationDialog(deleteId, " Are you sure you want to delete the folder and all its children?\n This action cannot be undone, and all data within the folder \n will be permanently lost.")) + { + if (FileSystem::DeleteFolder(directory->FullPath) != 0) + { + Logger::Log("Failed to remove directory: " + directory->Name, "editor", CRITICAL); + } + //RefreshFileBrowser(); + } + + ImGui::PopFont(); +} + +void FileBrowserWidget::DrawFile(Ref file, uint32_t drawId) +{ + //ImGui::PushFont(EditorInterface::bigIconFont); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f); + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, { 0.f, 0.f }); + std::string fileExtension = file->GetExtension(); + + ImVec2 prevCursor = ImGui::GetCursorPos(); + ImVec2 prevScreenPos = ImGui::GetCursorScreenPos(); + std::string id = std::string("##") + file->GetAbsolutePath(); + const bool selected = ImGui::Selectable(id.c_str(), editorContext.GetSelection().File == file, ImGuiSelectableFlags_AllowOverlap | ImGuiSelectableFlags_AllowDoubleClick, ImVec2(100, 150)); + + const std::string hoverMenuId = std::string("item_hover_menu") + std::to_string(drawId); + if (ImGui::IsItemHovered() && ImGui::IsMouseReleased(1)) + { + ImGui::OpenPopup(hoverMenuId.c_str()); + //m_HasClickedOnFile = true; + } + + bool shouldOpenScene = false; + if (selected) + { + if (ImGui::IsMouseDoubleClicked(0)) + { + switch (file->GetFileType()) + { + case FileType::Map: + OS::OpenTrenchbroomMap(file->GetAbsolutePath()); + break; + case FileType::NetScript: + case FileType::UI: + case FileType::CSS: + OS::OpenIn(file->GetAbsolutePath()); + break; + case FileType::Scene: + //shouldOpenScene = true; + EditorRequests::Get().RequestLoadScene(file); + //this->Editor->OpenSceneWindow(file->GetRelativePath()); + break; + case FileType::Solution: + OS::OpenIn(file->GetAbsolutePath()); + break; + case FileType::Prefab: + //this->Editor->OpenPrefabWindow(file->GetRelativePath()); + break; + } + } + + editorContext.SetSelection(EditorSelection(file)); + } + + if (ImGui::IsItemHovered()) + ImGui::SetTooltip(file->GetName().c_str()); + + if (ImGui::BeginDragDropSource()) + { + char pathBuffer[256]; + std::strncpy(pathBuffer, file->GetAbsolutePath().c_str(), sizeof(pathBuffer)); + std::string dragType; + if (fileExtension == ".wren") + { + dragType = "_Script"; + } + else if (fileExtension == ".cs") + { + dragType = "_NetScript"; + } + else if (fileExtension == ".map") + { + dragType = "_Map"; + } + else if (fileExtension == ".material") + { + dragType = "_Material"; + } + else if (fileExtension == ".nkmesh" || fileExtension == ".obj" || fileExtension == ".mdl" || fileExtension == ".gltf" || fileExtension == ".md3" || fileExtension == ".fbx" || fileExtension == ".glb") + { + dragType = "_Model"; + } + else if (fileExtension == ".interface") + { + dragType = "_Interface"; + } + else if (fileExtension == ".prefab") + { + dragType = "_Prefab"; + } + else if (fileExtension == ".png" || fileExtension == ".jpg") + { + dragType = "_Image"; + } + else if (fileExtension == ".wav" || fileExtension == ".ogg") + { + dragType = "_AudioFile"; + } + else if (fileExtension == ".html") + { + dragType = "_UIFile"; + } + else if (fileExtension == ".sky") + { + dragType = "_SkyFile"; + } + else if (fileExtension == ".env") + { + dragType = "_EnvFile"; + } + + ImGui::SetDragDropPayload(dragType.c_str(), (void*)(pathBuffer), sizeof(pathBuffer)); + ImGui::Text(file->GetName().c_str()); + ImGui::EndDragDropSource(); + } + + + Ref textureImage = TextureManager::Get()->GetTexture2("Resources/Images/file_icon.png"); + + const auto textureMgr = TextureManager::Get(); + const auto fileType = file->GetFileType(); + if (fileType == FileType::Material) + { + //auto image = ThumbnailManager::Get().GetThumbnail(file->GetRelativePath()); + //if (image) + //{ + // textureImage = image; + //} + } + else if (fileType == FileType::Image) + { + const std::string path = file->GetAbsolutePath(); + textureImage = textureMgr->GetTexture2(path); + } + else if (fileType == FileType::Project) + { + textureImage = textureMgr->GetTexture2("Resources/Images/project_icon.png"); + } + else if (fileType == FileType::NetScript) + { + textureImage = textureMgr->GetTexture2("Resources/Images/csharp_icon.png"); + } + else if (fileType == FileType::Scene) + { + textureImage = textureMgr->GetTexture2("Resources/Images/scene_icon.png"); + } + else if (fileType == FileType::Script) + { + textureImage = textureMgr->GetTexture2("Resources/Images/script_file_icon.png"); + } + else if (fileType == FileType::Audio) + { + textureImage = textureMgr->GetTexture2("Resources/Images/audio_file_icon.png"); + } + else if (fileType == FileType::Prefab) + { + //auto image = ThumbnailManager::Get().GetThumbnail(file->GetRelativePath()); + //if (image) + //{ + // textureImage = image; + //} + } + else if (fileType == FileType::Mesh) + { + //auto image = ThumbnailManager::Get().GetThumbnail(file->GetRelativePath()); + //if (image) + //{ + // textureImage = image; + //} + } + else if (fileType == FileType::Solution) + { + textureImage = textureMgr->GetTexture2("Resources/Images/sln_icon.png"); + } + else if (fileType == FileType::Map) + { + textureImage = textureMgr->GetTexture2("Resources/Images/trenchbroom_icon.png"); + } + else if (fileType == FileType::Env) + { + textureImage = textureMgr->GetTexture2("Resources/Images/env_file_icon.png"); + } + + ImGui::SetCursorPos(prevCursor); + ImGui::Image(reinterpret_cast(textureImage->GetImGuiDescriptorSet()), ImVec2(100, 100)); + ImGui::PopStyleVar(); + + auto& imguiStyle = ImGui::GetStyle(); + + ImVec2 startOffset = ImVec2(imguiStyle.CellPadding.x / 2.0f, 0); + ImVec2 offsetEnd = ImVec2(startOffset.x, imguiStyle.CellPadding.y / 2.0f); + ImU32 rectColor = IM_COL32(255, 255, 255, 16); + ImGui::GetWindowDrawList()->AddRectFilled(prevScreenPos + ImVec2(0, 100) - startOffset, prevScreenPos + ImVec2(100, 150) + offsetEnd, rectColor, 1.0f); + + ImU32 rectColor2 = UI::PrimaryCol; + Color fileTypeColor = GetColorByFileType(file->GetFileType()); + ImGui::GetWindowDrawList()->AddRectFilled(prevScreenPos + ImVec2(0, 100) - startOffset, prevScreenPos + ImVec2(100, 101) + offsetEnd, IM_COL32(fileTypeColor.r * 255.f, fileTypeColor.g * 255.f, fileTypeColor.b * 255.f, fileTypeColor.a * 255.f), 0.0f); + + std::string visibleName = file->GetName(); + const uint32_t MAX_CHAR_NAME = 32; + if (file->GetName().size() >= MAX_CHAR_NAME) + { + visibleName = std::string(visibleName.begin(), visibleName.begin() + MAX_CHAR_NAME - 3) + "..."; + } + + ImGui::TextWrapped(visibleName.c_str()); + + ImGui::SetCursorPosY(prevCursor.y + 150 - ImGui::GetTextLineHeight()); + ImGui::TextColored({ 1, 1, 1, 0.5f }, file->GetFileTypeAsString().c_str()); + + //if (fileExtension == ".png" || fileExtension == ".jpg") + //{ + // + //} + //else + //{ + // const char* icon = ICON_FA_FILE; + // if (fileExtension == ".shader" || fileExtension == ".wren") + // icon = ICON_FA_FILE_CODE; + // if (fileExtension == ".map") + // icon = ICON_FA_BROOM; + // if (fileExtension == ".ogg" || fileExtension == ".mp3" || fileExtension == ".wav") + // icon = ICON_FA_FILE_AUDIO; + // if (fileExtension == ".gltf" || fileExtension == ".obj") + // icon = ICON_FA_FILE_IMAGE; + // + // std::string fullName = icon + std::string("##") + file->GetAbsolutePath(); + // + // bool pressed = false; + // if (fileExtension == ".material") + // { + // ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + // pressed = ImGui::ImageButton(fullName.c_str(), (void*)ThumbnailManager::Get().GetThumbnail(file-//>GetRelativePath())->GetID(), ImVec2(100, 100), ImVec2(0, 1), ImVec2(1, 0)); + // ImGui::PopStyleVar(); + // } + // else + // { + // ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + // pressed = ImGui::Button(fullName.c_str(), ImVec2(100, 100)); + // ImGui::PopStyleVar(); + // } + // + if (editorContext.GetSelection().File == file && editorContext.GetSelection().File->GetFileType() != FileType::Prefab) + { + //ThumbnailManager::Get().MarkThumbnailAsDirty(file->GetRelativePath()); + } + + // if(pressed) + // { + // Editor->Selection = EditorSelection(file); + // } + // + // if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(0)) + // { + // OS::OpenTrenchbroomMap(file->GetAbsolutePath()); + // } + //} + ImGui::PopStyleVar(); + + const std::string openSceneId = "Open Scene" + std::string("##") + hoverMenuId; + + + const std::string renameId = "Rename" + std::string("##") + hoverMenuId; + bool shouldRename = false; + + const std::string deleteId = "Delete" + std::string("##") + hoverMenuId; + bool shouldDelete = false; + + if (ImGui::BeginPopup(hoverMenuId.c_str())) + { + if (file->GetExtension() != ".scene") + { + if (ImGui::MenuItem("Open in Editor")) + { + OS::OpenIn(file->GetAbsolutePath()); + } + } + else + { + if (ImGui::MenuItem("Load Scene")) + { + shouldOpenScene = true; + } + } + + ImGui::Separator(); + + if (ImGui::BeginMenu("Copy")) + { + if (ImGui::MenuItem("Full Path")) + { + OS::CopyToClipboard(file->GetAbsolutePath()); + } + + if (ImGui::MenuItem("File Name")) + { + OS::CopyToClipboard(file->GetName()); + } + + ImGui::EndPopup(); + } + + if (file->GetExtension() != ".project") + { + if (ImGui::MenuItem("Delete")) + { + shouldDelete = true; + } + } + else + { + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1, 1, 1, 0.2f)); + ImGui::MenuItem("Delete"); + ImGui::PopStyleColor(); + if (ImGui::IsItemHovered()) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted("The file you're trying to delete is currently loaded by the game engine."); + ImGui::PopTextWrapPos(); + ImGui::EndTooltip(); + } + } + + if (file->GetExtension() == ".wad") + { + if (ImGui::MenuItem("Convert to Materials")) + { + //Nuake::ExtractWad(file->GetAbsolutePath(), FileSystem::Root); + } + } + + if (ImGui::MenuItem("Rename")) + { + shouldRename = true; + } + + ImGui::Separator(); + + if (ImGui::MenuItem("Show in File Explorer")) + { + OS::ShowInFileExplorer(file->GetAbsolutePath()); + } + + ImGui::EndPopup(); + } + + // Open Scene Popup + + if (shouldOpenScene) + { + PopupHelper::OpenPopup(openSceneId); + } + + if (PopupHelper::DefineConfirmationDialog(openSceneId, " Open the scene? \n Changes will not be saved.")) + { + Ref scene = Scene::New(); + const std::string projectPath = file->GetAbsolutePath(); + if (!scene->Deserialize(json::parse(FileSystem::ReadFile(projectPath, true)))) + { + Logger::Log("Failed loading scene: " + projectPath, "editor", CRITICAL); + ImGui::PopFont(); + return; + } + + scene->Path = FileSystem::AbsoluteToRelative(projectPath); + Engine::SetCurrentScene(scene); + } + + // Rename Popup + + if (shouldRename) + { + //renameTempValue = file->GetName(); + PopupHelper::OpenPopup(renameId); + } + + //if (PopupHelper::DefineTextDialog(renameId, renameTempValue)) + //{ + // if (OS::RenameFile(file, renameTempValue) != 0) + // { + // Logger::Log("Cannot rename file: " + renameTempValue, "editor", CRITICAL); + // } + // RefreshFileBrowser(); + // renameTempValue = ""; + //} + + // Delete Popup + + if (shouldDelete) + { + PopupHelper::OpenPopup(deleteId); + } + + if (PopupHelper::DefineConfirmationDialog(deleteId, " Are you sure you want to delete the file?\n This action cannot be undone, and all data \n will be permanently lost.")) + { + if (FileSystem::DeleteFileFromPath(file->GetAbsolutePath()) != 0) + { + Logger::Log("Failed to remove file: " + file->GetRelativePath(), "editor", CRITICAL); + } + //RefreshFileBrowser(); + } + + //ImGui::PopFont(); +} + +Color FileBrowserWidget::GetColorByFileType(Nuake::FileType fileType) +{ + { + switch (fileType) + { + case Nuake::FileType::Unknown: + break; + case Nuake::FileType::Image: + break; + case Nuake::FileType::Material: + break; + case Nuake::FileType::Mesh: + break; + case Nuake::FileType::Script: + return { 1.0, 0.0, 0.0, 1.0 }; + break; + case Nuake::FileType::NetScript: + return { 1.0, 0.0, 0.0, 1.0 }; + break; + case Nuake::FileType::Project: + return Engine::GetProject()->Settings.PrimaryColor; + break; + case Nuake::FileType::Prefab: + break; + case Nuake::FileType::Scene: + return { 0, 1.0f, 1.0, 1.0 }; + break; + case Nuake::FileType::Wad: + break; + case Nuake::FileType::Map: + return { 0.0, 1.0, 0.0, 1.0 }; + break; + case Nuake::FileType::Assembly: + break; + case Nuake::FileType::Solution: + break; + case Nuake::FileType::Audio: + return { 0.0, 0.0, 1.0, 1.0 }; + break; + case Nuake::FileType::UI: + return { 1.0, 1.0, 0.0, 1.0 }; + break; + case Nuake::FileType::CSS: + return { 1.0, 0.0, 1.0, 1.0 }; + break; + default: + break; + } + + return Color(0, 0, 0, 0); + } +} diff --git a/Editor/src/Windows/SceneEditor/Widgets/FileBrowserWidget.h b/Editor/src/Windows/SceneEditor/Widgets/FileBrowserWidget.h new file mode 100644 index 00000000..cd645b39 --- /dev/null +++ b/Editor/src/Windows/SceneEditor/Widgets/FileBrowserWidget.h @@ -0,0 +1,39 @@ +#pragma once + +#include "src/Core/Core.h" +#include "src/Core/Maths.h" +#include "src/FileSystem/FileTypes.h" + +#include "IEditorWidget.h" + +namespace Nuake +{ + class Directory; + class File; +} + +class FileBrowserWidget : public IEditorWidget +{ +private: + float splitterSizeLeft = 300.0f; + float splitterSizeRight = 300.0f; + + Ref currentDirectory; + + std::string searchQuery; + +public: + FileBrowserWidget(EditorContext& inCtx); + ~FileBrowserWidget() = default; + +public: + void Update(float ts) override; + void Draw() override; + + void DrawFiletree(Ref dir); + void DrawDirectory(Ref dir, uint32_t drawId); + void DrawFile(Ref file, uint32_t drawId); + + Nuake::Color GetColorByFileType(Nuake::FileType fileType); + +}; \ No newline at end of file diff --git a/Editor/src/Windows/SceneEditor/Widgets/IEditorWidget.h b/Editor/src/Windows/SceneEditor/Widgets/IEditorWidget.h index c0c5c3ad..80b02345 100644 --- a/Editor/src/Windows/SceneEditor/Widgets/IEditorWidget.h +++ b/Editor/src/Windows/SceneEditor/Widgets/IEditorWidget.h @@ -9,6 +9,9 @@ class IEditorWidget protected: EditorContext& editorContext; +private: + std::string widgetName; + public: IEditorWidget(EditorContext& inContext) : editorContext(inContext) {} virtual ~IEditorWidget() {}; @@ -17,6 +20,11 @@ public: virtual void Update(float ts) = 0; virtual void Draw() = 0; + void DockTo(uint32_t dockId) + { + ImGui::DockBuilderDockWindow(widgetName.c_str(), dockId); + } + bool BeginWidgetWindow(const std::string_view& name) { return BeginWidgetWindow(name.data()); @@ -29,7 +37,7 @@ public: windowClass.DockingAllowUnclassed = false; ImGui::SetNextWindowClass(&windowClass); - std::string nameStr = std::string(name) + "##" + editorContext.GetScene()->GetName(); - return ImGui::Begin(nameStr.c_str()); + widgetName = std::string(name) + "##" + editorContext.GetScene()->Path; + return ImGui::Begin(widgetName.c_str()); } }; \ No newline at end of file diff --git a/Editor/src/Windows/SceneEditor/Widgets/LoggerWidget.cpp b/Editor/src/Windows/SceneEditor/Widgets/LoggerWidget.cpp new file mode 100644 index 00000000..3c167230 --- /dev/null +++ b/Editor/src/Windows/SceneEditor/Widgets/LoggerWidget.cpp @@ -0,0 +1,210 @@ +#include "LoggerWidget.h" + +#include "src/Core/Logger.h" + +#include "src/UI/ImUI.h" + +#include "src/Resource/Project.h" +#include "Engine.h" + +using namespace Nuake; + +void LoggerWidget::Update(float ts) +{ + +} + +void LoggerWidget::Draw() +{ + if (BeginWidgetWindow("Logger")) + { + if (ImGui::Button("Clear", ImVec2(60, 28))) + { + Logger::ClearLogs(); + //SetStatusMessage("Logs cleared."); + } + + ImGui::SameLine(); + + if (ImGui::Button(ICON_FA_FILTER, ImVec2(30, 28))) + { + ImGui::OpenPopup("filter_popup"); + } + + ImGui::SameLine(); + + bool isEnabled = LogErrors; + if (ImGui::BeginPopup("filter_popup")) + { + ImGui::SeparatorText("Filters"); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 2)); + ImGui::PushStyleColor(ImGuiCol_Button, IM_COL32(0, 0, 0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 100); + + if (isEnabled) + { + Color color = Engine::GetProject()->Settings.PrimaryColor; + ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f }); + } + + if (ImGui::Button((std::string(ICON_FA_BAN) + " Error").c_str())) + { + LogErrors = !LogErrors; + } + + UI::Tooltip("Display Errors"); + if (isEnabled) + { + ImGui::PopStyleColor(); + } + + isEnabled = LogWarnings; + if (isEnabled) + { + Color color = Engine::GetProject()->Settings.PrimaryColor; + ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f }); + } + + if (ImGui::Button((std::string(ICON_FA_EXCLAMATION_TRIANGLE) + " Warning").c_str())) + { + LogWarnings = !LogWarnings; + } + + UI::Tooltip("Display Warnings"); + if (isEnabled) + { + ImGui::PopStyleColor(); + } + + isEnabled = LogDebug; + if (isEnabled) + { + Color color = Engine::GetProject()->Settings.PrimaryColor; + ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f }); + } + + if (ImGui::Button((std::string(ICON_FA_INFO) + " Info").c_str())) + { + LogDebug = !LogDebug; + } + + UI::Tooltip("Display Verbose"); + if (isEnabled) + { + ImGui::PopStyleColor(); + } + + ImGui::PopStyleColor(); + ImGui::PopStyleVar(2); + + ImGui::EndPopup(); + } + + ImGui::SameLine(); + + isEnabled = AutoScroll; + if (isEnabled) + { + Color color = Engine::GetProject()->Settings.PrimaryColor; + ImGui::PushStyleColor(ImGuiCol_Button, { color.r, color.g, color.b, 1.0f }); + } + + if (ImGui::Button(ICON_FA_ARROW_DOWN, ImVec2(30, 28))) + { + AutoScroll = !AutoScroll; + } + + UI::Tooltip("Auto-Scroll"); + if (isEnabled) + { + ImGui::PopStyleColor(); + } + + //ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); + //if (ImGui::BeginChild("Log window", ImGui::GetContentRegionAvail(), false)) + //{ + //ImGui::PopStyleVar(); + ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_Hideable; + if (ImGui::BeginTable("LogTable", 3, flags)) + { + ImGui::TableSetupColumn("Severity", ImGuiTableColumnFlags_WidthFixed, 64.0f); + ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_WidthFixed, 64.0f); + ImGui::TableSetupColumn("Message", ImGuiTableColumnFlags_WidthStretch, 1.0f); + ImGui::TableNextColumn(); + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(4, 4)); + + for (auto& l : Logger::GetLogs()) + { + if (l.type == LOG_TYPE::VERBOSE && !LogDebug) + continue; + if (l.type == LOG_TYPE::WARNING && !LogWarnings) + continue; + if (l.type == LOG_TYPE::CRITICAL && !LogErrors) + continue; + + std::string severityText = ""; + if (l.type == LOG_TYPE::VERBOSE) + severityText = "verbose"; + else if (l.type == LOG_TYPE::WARNING) + severityText = "warning"; + else + severityText = "critical"; + + ImVec4 redColor = ImVec4(0.6, 0.1f, 0.1f, 0.2f); + ImVec4 yellowColor = ImVec4(0.6, 0.6f, 0.1f, 0.2f); + ImVec4 colorGreen = ImVec4(0.59, 0.76, 0.47, 1.0); + ImGui::PushStyleColor(ImGuiCol_Text, colorGreen); + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImVec4(0.59, 0.76, 0.47, 0.2)), -1); + const std::string timeString = " [" + l.time + "]"; + ImGui::Text(timeString.c_str()); + ImGui::PopStyleColor(); + + ImGui::TableNextColumn(); + + ImVec4 colorBlue = ImVec4(98 / 255.0, 174 / 255.0, 239 / 255.0, 1.); + ImGui::PushStyleColor(ImGuiCol_Text, colorBlue); + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImVec4(98 / 255.0, 174 / 255.0, 239 / 255.0, 0.2)), -1); + ImGui::Text(l.logger.c_str()); + ImGui::PopStyleColor(); + + ImGui::TableNextColumn(); + + ImVec4 color = ImVec4(1, 1, 1, 1.0); + ImGui::PushStyleColor(ImGuiCol_Text, color); + + if (l.type == CRITICAL) + { + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(redColor), -1); + } + else if (l.type == WARNING) + { + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(yellowColor), -1); + } + else + { + ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImVec4(1, 1, 1, 0.0)), -1); + } + + std::string displayMessage = l.message; + if (l.count > 0) + { + displayMessage += "(" + std::to_string(l.count) + ")"; + } + + ImGui::TextWrapped(displayMessage.c_str()); + ImGui::PopStyleColor(); + + ImGui::TableNextColumn(); + } + ImGui::PopStyleVar(); + + if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()) + { + ImGui::SetScrollHereY(1.0f); + } + + ImGui::EndTable(); + } + } + ImGui::End(); +} \ No newline at end of file diff --git a/Editor/src/Windows/SceneEditor/Widgets/LoggerWidget.h b/Editor/src/Windows/SceneEditor/Widgets/LoggerWidget.h new file mode 100644 index 00000000..f37bde11 --- /dev/null +++ b/Editor/src/Windows/SceneEditor/Widgets/LoggerWidget.h @@ -0,0 +1,20 @@ +#pragma once + +#include "IEditorWidget.h" + +class LoggerWidget : public IEditorWidget +{ +private: + bool LogErrors = true; + bool LogWarnings = true; + bool LogDebug = true; + bool AutoScroll = true; + +public: + LoggerWidget(EditorContext& inCtx) : IEditorWidget(inCtx) {} + ~LoggerWidget() = default; + +public: + void Update(float ts) override; + void Draw() override; +}; \ No newline at end of file diff --git a/Editor/src/Windows/SceneEditor/Widgets/SceneHierarchyWidget.cpp b/Editor/src/Windows/SceneEditor/Widgets/SceneHierarchyWidget.cpp index 7e7b909a..e3b60bf4 100644 --- a/Editor/src/Windows/SceneEditor/Widgets/SceneHierarchyWidget.cpp +++ b/Editor/src/Windows/SceneEditor/Widgets/SceneHierarchyWidget.cpp @@ -38,9 +38,8 @@ void SceneHierarchyWidget::Draw() DrawCreateEntityButton(); DrawEntityTree(); - - ImGui::End(); } + ImGui::End(); } void SceneHierarchyWidget::DrawSearchBar() @@ -202,7 +201,6 @@ void SceneHierarchyWidget::DrawEntityTree() ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_IndentDisable | ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("Script", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_IndentDisable | ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("Visibility ", ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_IndentDisable | ImGuiTableColumnFlags_WidthFixed); - ImGui::TableHeadersRow(); ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0, 0)); diff --git a/Editor/src/Windows/SceneEditor/Widgets/SelectionPropertyWidget.cpp b/Editor/src/Windows/SceneEditor/Widgets/SelectionPropertyWidget.cpp index 2248e975..d1202d45 100644 --- a/Editor/src/Windows/SceneEditor/Widgets/SelectionPropertyWidget.cpp +++ b/Editor/src/Windows/SceneEditor/Widgets/SelectionPropertyWidget.cpp @@ -1,23 +1,2152 @@ #include "SelectionPropertyWidget.h" +#include "src/Scene/Components.h" + #include "src/UI/ImUI.h" +#include "../../../ComponentsPanel/MaterialEditor.h" -SelectionPropertyWidget::SelectionPropertyWidget(EditorContext& inCtx) - : IEditorWidget(inCtx) +#include +#include +#include "../../../Misc/ImGuiTextHelper.h" + +using namespace Nuake; + +SelectionPropertyWidget::SelectionPropertyWidget(EditorContext& inCtx) : + IEditorWidget(inCtx) { + RegisterComponentDrawer(); + RegisterComponentDrawer(&meshPanel); + //RegisterComponentDrawer(&skinnedMeshPanel); + RegisterComponentDrawer(); + RegisterComponentDrawer(); + RegisterComponentDrawer(); + RegisterComponentDrawer(); + RegisterComponentDrawer(); + RegisterComponentDrawer(); + RegisterComponentDrawer(); + RegisterComponentDrawer(); + RegisterTypeDrawer(this); + RegisterTypeDrawer(this); + RegisterTypeDrawer(this); + RegisterTypeDrawer(this); + RegisterTypeDrawer(this); + RegisterTypeDrawer(this); + RegisterTypeDrawer(this); } void SelectionPropertyWidget::Update(float ts) { - if (BeginWidgetWindow("Selection Properties")) - { - ImGui::Text("Selection Properties"); - ImGui::End(); - } + } void SelectionPropertyWidget::Draw() { - -} \ No newline at end of file + EditorSelection selection = this->editorContext.GetSelection(); + if (BeginWidgetWindow("Selection Properties")) + { + switch (selection.Type) + { + case EditorSelectionType::None: + { + DrawNone(); + break; + } + + case EditorSelectionType::Entity: + { + DrawEntity(selection.Entity); + break; + } + case EditorSelectionType::File: + { + if (currentFile != selection.File) + { + ResolveFile(selection.File); + } + + if (!selection.File->Exist()) + { + std::string text = "File is invalid"; + auto windowWidth = ImGui::GetWindowSize().x; + auto windowHeight = ImGui::GetWindowSize().y; + + auto textWidth = ImGui::CalcTextSize(text.c_str()).x; + auto textHeight = ImGui::CalcTextSize(text.c_str()).y; + ImGui::SetCursorPosX((windowWidth - textWidth) * 0.5f); + ImGui::SetCursorPosY((windowHeight - textHeight) * 0.5f); + + ImGui::TextColored({ 1.f, 0.1f, 0.1f, 1.0f }, text.c_str()); + } + + DrawFile(selection.File); + break; + } + case EditorSelectionType::Resource: + { + DrawResource(selection.Resource); + break; + } + } + } + ImGui::End(); +} + +void SelectionPropertyWidget::ResolveFile(Ref file) +{ + using namespace Nuake; + + currentFile = file; + + if (currentFile->GetExtension() == ".project") + { + + } + + if (currentFile->GetExtension() == ".material") + { + Ref material = ResourceLoader::LoadMaterial(currentFile->GetRelativePath()); + selectedResource = material; + } + + if (currentFile->GetFileType() == FileType::Sky) + { + Ref sky = ResourceLoader::LoadSky(currentFile->GetRelativePath()); + selectedResource = sky; + } + + if (currentFile->GetFileType() == FileType::Env) + { + Ref env = ResourceLoader::LoadEnvironment(currentFile->GetRelativePath()); + selectedResource = env; + } +} + +void SelectionPropertyWidget::DrawNone() +{ + std::string text = "No selection"; + auto windowWidth = ImGui::GetWindowSize().x; + auto windowHeight = ImGui::GetWindowSize().y; + + auto textWidth = ImGui::CalcTextSize(text.c_str()).x; + auto textHeight = ImGui::CalcTextSize(text.c_str()).y; + ImGui::SetCursorPosX((windowWidth - textWidth) * 0.5f); + ImGui::SetCursorPosY((windowHeight - textHeight) * 0.5f); + + ImGui::Text(text.c_str()); +} + +void SelectionPropertyWidget::DrawEntity(Nuake::Entity entity) +{ + if (!entity.IsValid()) + { + return; + } + + DrawAddComponentMenu(entity); + + transformPanel.Draw(entity); + + entt::registry& registry = entity.GetScene()->m_Registry; + for (auto&& [componentTypeId, storage] : registry.storage()) + { + entt::type_info componentType = storage.type(); + + entt::entity entityId = static_cast(entity.GetHandle()); + if (storage.contains(entityId)) + { + entt::meta_type type = entt::resolve(componentType); + entt::meta_any component = type.from_void(storage.value(entityId)); + + ComponentTypeTrait typeTraits = type.traits(); + // Component not exposed as an inspector panel + if ((typeTraits & ComponentTypeTrait::InspectorExposed) == ComponentTypeTrait::None) + { + continue; + } + + DrawComponent(entity, component); + } + } + + using namespace Nuake; + + float availWidth = ImGui::GetContentRegionAvail().x; + const float buttonWidth = 200.f; + float posX = (availWidth / 2.f) - (buttonWidth / 2.f); + ImGui::SetCursorPosX(posX); + + if (UI::PrimaryButton("Add Component", { buttonWidth, 32 })) + { + ImGui::OpenPopup("ComponentPopup"); + } + + if (ImGui::BeginPopup("ComponentPopup")) + { + for (auto [fst, component] : entt::resolve()) + { + std::string componentName = Component::GetName(component); + if (ImGui::MenuItem(componentName.c_str())) + { + entity.AddComponent(component); + } + } + + ImGui::EndPopup(); + } + +} + +void SelectionPropertyWidget::DrawAddComponentMenu(Nuake::Entity entity) +{ + using namespace Nuake; + if (entity.HasComponent()) + { + UIFont* boldIconFont = new UIFont(Fonts::Icons); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 8.0f); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 4.0f); + ImGui::Text(ICON_FA_BOX); + delete boldIconFont; + + ImGui::SameLine(); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - 2.0f); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() - 4.0f); + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0, 0, 0, 0)); + UIFont* boldFont = new UIFont(Fonts::Bold); + auto& entityName = entity.GetComponent().Name; + + ImGuiTextSTD("##Name", entityName); + delete boldFont; + + ImGui::PopStyleColor(); + } +} + +void SelectionPropertyWidget::DrawFile(Ref file) +{ + using namespace Nuake; + switch (file->GetFileType()) + { + case FileType::Material: + { + MaterialEditor matEditor; + matEditor.Draw(std::static_pointer_cast(selectedResource)); + break; + } + case FileType::Project: + { + DrawProjectPanel(Nuake::Engine::GetProject()); + break; + } + case FileType::Script: + { + break; + } + case FileType::NetScript: + { + DrawNetScriptPanel(file); + break; + } + case FileType::Prefab: + { + //Ref prefab = CreateRef(file->GetRelativePath()); + //DrawPrefabPanel(prefab); + break; + } + case FileType::Sky: + { + auto sky = std::static_pointer_cast(selectedResource); + std::string skyName = sky->Path; + { + UIFont boldfont = UIFont(Fonts::SubTitle); + ImGui::Text(sky->Path.c_str()); + + } + ImGui::SameLine(); + { + UIFont boldfont = UIFont(Fonts::Icons); + if (ImGui::Button(ICON_FA_SAVE)) + { + if (ResourceManager::IsResourceLoaded(sky->ID)) + { + ResourceManager::RegisterResource(sky); + } + + std::string fileData = sky->Serialize().dump(4); + + FileSystem::BeginWriteFile(sky->Path); + FileSystem::WriteLine(fileData); + FileSystem::EndWriteFile(); + } + } + + int textureId = 0; + + // Top + ImGui::Text("Top"); + if (auto topTexture = sky->GetFaceTexture(SkyFaces::Top); + !topTexture.empty()) + { + textureId = TextureManager::Get()->GetTexture(FileSystem::RelativeToAbsolute(topTexture))->GetID(); + } + + if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#skytexture1"), (void*)textureId, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1))) + { + std::string texture = Nuake::FileDialog::OpenFile("*.png | *.jpg"); + if (!texture.empty()) + { + sky->SetTextureFace(SkyFaces::Top, FileSystem::AbsoluteToRelative(texture)); + } + } + + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::MenuItem("Clear Texture")) + { + sky->SetTextureFace(SkyFaces::Top, ""); + } + ImGui::EndPopup(); + } + + textureId = 0; + + ImGui::Text("Bottom"); + if (auto bottomTexture = sky->GetFaceTexture(SkyFaces::Bottom); + !bottomTexture.empty()) + { + textureId = TextureManager::Get()->GetTexture(FileSystem::RelativeToAbsolute(bottomTexture))->GetID(); + } + + if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#skytexture2"), (void*)textureId, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1))) + { + std::string texture = FileDialog::OpenFile("*.png | *.jpg"); + if (!texture.empty()) + { + sky->SetTextureFace(SkyFaces::Bottom, FileSystem::AbsoluteToRelative(texture)); + } + } + + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::MenuItem("Clear Texture")) + { + sky->SetTextureFace(SkyFaces::Bottom, ""); + } + ImGui::EndPopup(); + } + + textureId = 0; + + ImGui::Text("Left"); + if (auto bottomTexture = sky->GetFaceTexture(SkyFaces::Left); + !bottomTexture.empty()) + { + textureId = TextureManager::Get()->GetTexture(FileSystem::RelativeToAbsolute(bottomTexture))->GetID(); + } + + if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#skytexture3"), (void*)textureId, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1))) + { + std::string texture = FileDialog::OpenFile("*.png | *.jpg"); + if (!texture.empty()) + { + sky->SetTextureFace(SkyFaces::Left, FileSystem::AbsoluteToRelative(texture)); + } + } + + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::MenuItem("Clear Texture")) + { + sky->SetTextureFace(SkyFaces::Left, ""); + } + ImGui::EndPopup(); + } + + textureId = 0; + + ImGui::Text("Right"); + if (auto bottomTexture = sky->GetFaceTexture(SkyFaces::Right); + !bottomTexture.empty()) + { + textureId = TextureManager::Get()->GetTexture(FileSystem::RelativeToAbsolute(bottomTexture))->GetID(); + } + + if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#skytexture4"), (void*)textureId, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1))) + { + std::string texture = FileDialog::OpenFile("*.png | *.jpg"); + if (!texture.empty()) + { + sky->SetTextureFace(SkyFaces::Right, FileSystem::AbsoluteToRelative(texture)); + } + } + + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::MenuItem("Clear Texture")) + { + sky->SetTextureFace(SkyFaces::Right, ""); + } + ImGui::EndPopup(); + } + + textureId = 0; + + ImGui::Text("Front"); + if (auto bottomTexture = sky->GetFaceTexture(SkyFaces::Front); + !bottomTexture.empty()) + { + textureId = TextureManager::Get()->GetTexture(FileSystem::RelativeToAbsolute(bottomTexture))->GetID(); + } + + if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#skytexture5"), (void*)textureId, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1))) + { + std::string texture = FileDialog::OpenFile("*.png | *.jpg"); + if (!texture.empty()) + { + sky->SetTextureFace(SkyFaces::Front, FileSystem::AbsoluteToRelative(texture)); + } + } + + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::MenuItem("Clear Texture")) + { + sky->SetTextureFace(SkyFaces::Front, ""); + } + ImGui::EndPopup(); + } + + textureId = 0; + + ImGui::Text("Back"); + if (auto bottomTexture = sky->GetFaceTexture(SkyFaces::Back); + !bottomTexture.empty()) + { + textureId = TextureManager::Get()->GetTexture(FileSystem::RelativeToAbsolute(bottomTexture))->GetID(); + } + + if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#skytexture6"), (void*)textureId, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1))) + { + std::string texture = FileDialog::OpenFile("*.png | *.jpg"); + if (!texture.empty()) + { + sky->SetTextureFace(SkyFaces::Back, FileSystem::AbsoluteToRelative(texture)); + } + } + + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::MenuItem("Clear Texture")) + { + sky->SetTextureFace(SkyFaces::Back, ""); + } + ImGui::EndPopup(); + } + + + break; + } + case FileType::Env: + { + const Ref env = std::static_pointer_cast(selectedResource); + std::string skyName = env->Path; + { + UIFont boldfont = UIFont(Fonts::SubTitle); + ImGui::Text(env->Path.c_str()); + + } + ImGui::SameLine(); + { + UIFont boldfont = UIFont(Fonts::Icons); + if (ImGui::Button(ICON_FA_SAVE)) + { + if (!ResourceManager::IsResourceLoaded(env->ID)) + { + ResourceManager::RegisterResource(env); + } + + std::string fileData = env->Serialize().dump(4); + + FileSystem::BeginWriteFile(env->Path); + FileSystem::WriteLine(fileData); + FileSystem::EndWriteFile(); + } + } + + BEGIN_COLLAPSE_HEADER(SKY); + if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp)) + { + ImGui::TableSetupColumn("name", 0, 0.3f); + ImGui::TableSetupColumn("set", 0, 0.6f); + ImGui::TableSetupColumn("reset", 0, 0.1f); + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Sky Type"); + ImGui::TableNextColumn(); + + // Here we create a dropdown for every sky type. + const char* SkyTypes[] = { "Procedural Sky", "Color" }; + static int currentSkyType = (int)env->CurrentSkyType; + ImGui::Combo("##SkyType", ¤tSkyType, SkyTypes, IM_ARRAYSIZE(SkyTypes)); + env->CurrentSkyType = (SkyType)currentSkyType; + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string ResetType = ICON_FA_UNDO + std::string("##ResetType"); + if (ImGui::Button(ResetType.c_str())) env->CurrentSkyType = SkyType::ProceduralSky; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Gamma"); + ImGui::TableNextColumn(); + + // Here we create a dropdown for every sky type. + ImGui::DragFloat("##gamma", &env->Gamma, 0.001f, 0.0f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string ResetType = ICON_FA_UNDO + std::string("##ResetType"); + if (ImGui::Button(ResetType.c_str())) env->CurrentSkyType = SkyType::ProceduralSky; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Exposure"); + ImGui::TableNextColumn(); + + // Here we create a dropdown for every sky type. + ImGui::DragFloat("##exposure", &env->Exposure, 0.001f, 0.0f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string ResetType = ICON_FA_UNDO + std::string("##ResetType"); + if (ImGui::Button(ResetType.c_str())) env->CurrentSkyType = SkyType::ProceduralSky; + ImGui::PopStyleColor(); + } + + if (env->CurrentSkyType == SkyType::ProceduralSky) + { + ImGui::TableNextColumn(); + + { // Sun Intensity + ImGui::Text("Sun Intensity"); + ImGui::TableNextColumn(); + + ImGui::DragFloat("##Sun Intensity", &env->ProceduralSkybox->SunIntensity, 0.1f, 0.0f, 1000.0f); + ImGui::TableNextColumn(); + + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetSunIntensity = ICON_FA_UNDO + std::string("##ResetSunIntensity"); + if (ImGui::Button(resetSunIntensity.c_str())) env->ProceduralSkybox->SunIntensity = 100.0f; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { // Sun Direction + ImGui::Text("Sun Direction"); + ImGui::TableNextColumn(); + + Vector3 sunDirection = env->ProceduralSkybox->GetSunDirection(); + ImGuiHelper::DrawVec3("##Sun Direction", &sunDirection); + env->ProceduralSkybox->SunDirection = glm::mix(env->ProceduralSkybox->GetSunDirection(), glm::normalize(sunDirection), 0.1f); + ImGui::TableNextColumn(); + + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetSunDirection = ICON_FA_UNDO + std::string("##resetSunDirection"); + if (ImGui::Button(resetSunDirection.c_str())) env->ProceduralSkybox->SunDirection = Vector3(0.20000f, 0.95917f, 0.20000f); + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { // Surface Radius + ImGui::Text("Surface Radius"); + ImGui::TableNextColumn(); + + ImGui::DragFloat("##surfaceRadius", &env->ProceduralSkybox->SurfaceRadius, 100.f, 0.0f); + ImGui::TableNextColumn(); + + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetSurfaceRadius = ICON_FA_UNDO + std::string("##resetSurfaceRadius"); + if (ImGui::Button(resetSurfaceRadius.c_str())) env->ProceduralSkybox->SurfaceRadius = 6360e3f; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { // Atmosphere Radius + ImGui::Text("Atmosphere Radius"); + ImGui::TableNextColumn(); + + ImGui::DragFloat("##AtmosphereRadius", &env->ProceduralSkybox->AtmosphereRadius, 100.f, 0.0f); + ImGui::TableNextColumn(); + + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetAtmosphereRadius = ICON_FA_UNDO + std::string("##resetAtmosphereRadius"); + if (ImGui::Button(resetAtmosphereRadius.c_str())) env->ProceduralSkybox->AtmosphereRadius = 6380e3f; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { // Center point + ImGui::Text("Center Point"); + ImGui::TableNextColumn(); + + ImGuiHelper::DrawVec3("##Center Point", &env->ProceduralSkybox->CenterPoint, 0.0f, 100.0f, 100.0f); + ImGui::TableNextColumn(); + if (env->ProceduralSkybox->CenterPoint.y < -env->ProceduralSkybox->AtmosphereRadius) + env->ProceduralSkybox->CenterPoint.y = -env->ProceduralSkybox->AtmosphereRadius + 1.f; + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetCenterPoint = ICON_FA_UNDO + std::string("##resetAtmosphereRadius"); + if (ImGui::Button(resetCenterPoint.c_str())) env->ProceduralSkybox->CenterPoint = Vector3(0, -env->ProceduralSkybox->AtmosphereRadius, 0); + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { // Mie Scattering + ImGui::Text("Mie Scattering"); + ImGui::TableNextColumn(); + + Vector3 mieScattering = env->ProceduralSkybox->MieScattering * 10000.0f; + ImGuiHelper::DrawVec3("##Mie Scattering", &mieScattering, 0.0f, 100.0f, 0.01f); + if (mieScattering.x < 0) mieScattering.x = 0; + if (mieScattering.y < 0) mieScattering.y = 0; + if (mieScattering.z < 0) mieScattering.z = 0; + env->ProceduralSkybox->MieScattering = mieScattering / 10000.0f; + ImGui::TableNextColumn(); + + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetMieScattering = ICON_FA_UNDO + std::string("##resetMieScattering"); + if (ImGui::Button(resetMieScattering.c_str())) env->ProceduralSkybox->MieScattering = Vector3(2e-5f); + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { // RayleighScattering + ImGui::Text("Rayleigh Scattering"); + ImGui::TableNextColumn(); + + Vector3 rayleighScattering = env->ProceduralSkybox->RayleighScattering * 10000.0f; + ImGuiHelper::DrawVec3("##Ray Scattering", &rayleighScattering, 0.0f, 100.0f, 0.01f); + if (rayleighScattering.r < 0) rayleighScattering.r = 0; + if (rayleighScattering.g < 0) rayleighScattering.g = 0; + if (rayleighScattering.b < 0) rayleighScattering.b = 0; + env->ProceduralSkybox->RayleighScattering = rayleighScattering / 10000.0f; + ImGui::TableNextColumn(); + + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetRayScattering = ICON_FA_UNDO + std::string("##resetRayScattering"); + if (ImGui::Button(resetRayScattering.c_str())) env->ProceduralSkybox->RayleighScattering = Vector3(58e-7f, 135e-7f, 331e-7f); + ImGui::PopStyleColor(); + } + } + + if (env->CurrentSkyType == SkyType::ClearColor) + { + ImGui::TableNextColumn(); + + // Title + ImGui::Text("Clear color"); + ImGui::TableNextColumn(); + + // Color picker + ImGui::ColorEdit4("##clearColor", &env->AmbientColor.r, ImGuiColorEditFlags_NoAlpha); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetColor = ICON_FA_UNDO + std::string("##ResetColor"); + if (ImGui::Button(resetColor.c_str())) env->AmbientColor = Color(0, 0, 0, 1); + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Ambient Term"); + ImGui::TableNextColumn(); + + // Here we create a dropdown for every sky type. + ImGui::DragFloat("##AmbientTerm", &env->AmbientTerm, 0.001f, 0.00f, 1.0f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string ResetType = ICON_FA_UNDO + std::string("##ambient"); + if (ImGui::Button(ResetType.c_str())) env->AmbientTerm = 0.25f; + ImGui::PopStyleColor(); + } + + ImGui::EndTable(); + } + END_COLLAPSE_HEADER() + + BEGIN_COLLAPSE_HEADER(TAA) + if (ImGui::BeginTable("EnvTableTAA", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp)) + { + ImGui::TableSetupColumn("name", 0, 0.3f); + ImGui::TableSetupColumn("set", 0, 0.6f); + ImGui::TableSetupColumn("reset", 0, 0.1f); + + ImGui::TableNextColumn(); + { + auto& sceneRenderer = Engine::GetCurrentScene()->m_SceneRenderer; + + // Title + ImGui::Text("TAA Factor"); + ImGui::TableNextColumn(); + + ImGui::SliderFloat("##TAAFactor", &sceneRenderer->TAAFactor, 0.0f, 1.0f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetTAAFactor"); + if (ImGui::Button(resetVolumetric.c_str())) sceneRenderer->TAAFactor = 0.6f; + ImGui::PopStyleColor(); + } + ImGui::EndTable(); + } + END_COLLAPSE_HEADER() + BEGIN_COLLAPSE_HEADER(BLOOM) + if (ImGui::BeginTable("BloomTable", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp)) + { + ImGui::TableSetupColumn("name", 0, 0.3f); + ImGui::TableSetupColumn("set", 0, 0.6f); + ImGui::TableSetupColumn("reset", 0, 0.1f); + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Enabled"); + ImGui::TableNextColumn(); + + ImGui::Checkbox("##Enabled", &env->BloomEnabled); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetBloom = ICON_FA_UNDO + std::string("##resetBloom"); + if (ImGui::Button(resetBloom.c_str())) env->BloomEnabled = false; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Threshold"); + ImGui::TableNextColumn(); + + float threshold = env->mBloom->GetThreshold(); + ImGui::DragFloat("##Threshold", &threshold, 0.01f, 0.0f, 500.0f); + env->mBloom->SetThreshold(threshold); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetBloomThreshold = ICON_FA_UNDO + std::string("##resetBloomThreshold"); + if (ImGui::Button(resetBloomThreshold.c_str())) env->mBloom->SetThreshold(2.4f); + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Quality"); + ImGui::TableNextColumn(); + + int iteration = env->mBloom->GetIteration(); + int oldIteration = iteration; + ImGui::DragInt("##quality", &iteration, 1.0f, 0, 4); + + if (oldIteration != iteration) + { + env->mBloom->SetIteration(iteration); + } + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetQuality = ICON_FA_UNDO + std::string("##resetQuality"); + if (ImGui::Button(resetQuality.c_str())) env->mBloom->SetIteration(3); + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Lens Dirt"); + ImGui::TableNextColumn(); + + Ref lensTexture = env->mBloom->GetLensDirt(); + + std::string filePath = lensTexture == nullptr ? "None" : lensTexture->GetPath(); + std::string controlName = filePath + std::string("##") + filePath; + ImGui::Button(controlName.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)); + + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("_Image")) + { + const char* payloadFilePath = static_cast(payload->Data); + const std::string fullPath = std::string(payloadFilePath, 256); + const Ref file = FileSystem::GetFile(FileSystem::AbsoluteToRelative(fullPath)); + env->mBloom->SetLensDirt(TextureManager::Get()->GetTexture(file->GetAbsolutePath())); + Engine::GetProject()->IsDirty = true; + } + ImGui::EndDragDropTarget(); + } + + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetLens = ICON_FA_UNDO + std::string("##resetLens"); + if (ImGui::Button(resetLens.c_str())) env->mBloom->ClearLensDirt(); + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Lens Dirt Intensity"); + ImGui::TableNextColumn(); + + float lensDirtIntensity = env->mBloom->GetLensDirtIntensity(); + ImGui::SliderFloat("##lensDirtIntensity", &lensDirtIntensity, 0.0f, 1.0f); + + if (lensDirtIntensity != env->mBloom->GetLensDirtIntensity()) + { + env->mBloom->SetLensDirtIntensity(lensDirtIntensity); + } + + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetLensDirt = ICON_FA_UNDO + std::string("##resetLensDirtIntensity"); + if (ImGui::Button(resetLensDirt.c_str())) env->mBloom->SetLensDirtIntensity(1.0f); + ImGui::PopStyleColor(); + } + + ImGui::EndTable(); + } + END_COLLAPSE_HEADER() + + BEGIN_COLLAPSE_HEADER(VOLUMETRIC) + if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp)) + { + ImGui::TableSetupColumn("name", 0, 0.3f); + ImGui::TableSetupColumn("set", 0, 0.6f); + ImGui::TableSetupColumn("reset", 0, 0.1f); + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Enabled"); + ImGui::TableNextColumn(); + + ImGui::Checkbox("##VolumetricEnabled", &env->VolumetricEnabled); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Scattering"); + ImGui::TableNextColumn(); + + float fogAmount = env->mVolumetric->GetFogAmount(); + ImGui::DragFloat("##Volumetric Scattering", &fogAmount, .001f, 0.f, 1.0f); + env->mVolumetric->SetFogAmount(fogAmount); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetBloomThreshold = ICON_FA_UNDO + std::string("##resetBloomThreshold"); + if (ImGui::Button(resetBloomThreshold.c_str())) env->mBloom->SetThreshold(2.4f); + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Strength"); + ImGui::TableNextColumn(); + + float fogAmount = env->mVolumetric->GetFogExponant(); + ImGui::DragFloat("##Volumetric Strength", &fogAmount, .001f, 0.f, 1.0f); + env->mVolumetric->SetFogExponant(fogAmount); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetBloomThreshold = ICON_FA_UNDO + std::string("##resetFogExpo"); + if (ImGui::Button(resetBloomThreshold.c_str())) env->mBloom->SetThreshold(2.4f); + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Step count"); + ImGui::TableNextColumn(); + + int stepCount = env->mVolumetric->GetStepCount(); + ImGui::DragInt("##Volumetric Step Count", &stepCount, 1.f, 0.0f); + env->mVolumetric->SetStepCount(stepCount); + + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetQuality = ICON_FA_UNDO + std::string("##resetQuality"); + if (ImGui::Button(resetQuality.c_str())) env->VolumetricStepCount = 50.f; + ImGui::PopStyleColor(); + } + + ImGui::EndTable(); + } + END_COLLAPSE_HEADER() + + BEGIN_COLLAPSE_HEADER(SSAO) + if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp)) + { + ImGui::TableSetupColumn("name", 0, 0.3f); + ImGui::TableSetupColumn("set", 0, 0.6f); + ImGui::TableSetupColumn("reset", 0, 0.1f); + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Enabled"); + ImGui::TableNextColumn(); + + ImGui::Checkbox("##SSAOEnabled", &env->SSAOEnabled); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetSSAO = ICON_FA_UNDO + std::string("##resetSSAO"); + if (ImGui::Button(resetSSAO.c_str())) env->SSAOEnabled = false; + ImGui::PopStyleColor(); + } + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Strength"); + ImGui::TableNextColumn(); + + ImGui::DragFloat("##SSAOStrength", &env->mSSAO->Strength, 0.01f, 0.01f, 10.0f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetRadius = ICON_FA_UNDO + std::string("##resetStrength"); + if (ImGui::Button(resetRadius.c_str())) env->mSSAO->Strength = 2.0f; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Radius"); + ImGui::TableNextColumn(); + + ImGui::DragFloat("##SSAORadius", &env->mSSAO->Radius, 0.01f, 0.0f, 10.0f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetRadius = ICON_FA_UNDO + std::string("##resetRadius"); + if (ImGui::Button(resetRadius.c_str())) env->mSSAO->Radius = 1.0f; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Bias"); + ImGui::TableNextColumn(); + + ImGui::DragFloat("##SSAOBias", &env->mSSAO->Bias, 0.0001f, 0.00001f, 0.5f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetBloomThreshold = ICON_FA_UNDO + std::string("##resetSSAOBias"); + if (ImGui::Button(resetBloomThreshold.c_str())) env->mSSAO->Bias = 0.001f; + ImGui::PopStyleColor(); + } + + ImGui::EndTable(); + } + END_COLLAPSE_HEADER() + + BEGIN_COLLAPSE_HEADER(SSR) + if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp)) + { + ImGui::TableSetupColumn("name", 0, 0.3); + ImGui::TableSetupColumn("set", 0, 0.6); + ImGui::TableSetupColumn("reset", 0, 0.1); + + SSR* ssr = env->mSSR.get(); + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Enabled"); + ImGui::TableNextColumn(); + + ImGui::Checkbox("##SSREnabled", &env->SSREnabled); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetSSR = ICON_FA_UNDO + std::string("##resetSSR"); + if (ImGui::Button(resetSSR.c_str())) env->SSREnabled = false; + ImGui::PopStyleColor(); + } + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("RayStep"); + ImGui::TableNextColumn(); + ImGui::DragFloat("##SSRRS", &ssr->RayStep, 0.01f, 0.0f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Iteration Count"); + ImGui::TableNextColumn(); + ImGui::DragInt("##SSRRSi", &ssr->IterationCount, 1, 1); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Distance Bias"); + ImGui::TableNextColumn(); + ImGui::DragFloat("##SSRRSid", &ssr->DistanceBias, 0.01f, 0.f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Sample Count"); + ImGui::TableNextColumn(); + ImGui::DragInt("##SSRRSids", &ssr->SampleCount, 1, 0); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Sampling"); + ImGui::TableNextColumn(); + ImGui::Checkbox("##SSRRSidss", &ssr->SamplingEnabled); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Expo"); + ImGui::TableNextColumn(); + ImGui::Checkbox("##SSRRSidsse", &ssr->ExpoStep); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Adaptive Steps"); + ImGui::TableNextColumn(); + ImGui::Checkbox("##SSRRSidssse", &ssr->AdaptiveStep); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("Binary Search"); + ImGui::TableNextColumn(); + ImGui::Checkbox("##SSRRSidsssbe", &ssr->BinarySearch); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + ImGui::TableNextColumn(); + { + // Title + ImGui::Text("samplingCoefficient"); + ImGui::TableNextColumn(); + ImGui::DragFloat("##samplingCoefficient", &ssr->SampleingCoefficient, 0.001f, 0.0f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VolumetricEnabled = false; + ImGui::PopStyleColor(); + } + + ImGui::EndTable(); + } + END_COLLAPSE_HEADER() + + + BEGIN_COLLAPSE_HEADER(DOF) + if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp)) + { + ImGui::TableSetupColumn("name", 0, 0.3); + ImGui::TableSetupColumn("set", 0, 0.6); + ImGui::TableSetupColumn("reset", 0, 0.1); + + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Enabled"); + ImGui::TableNextColumn(); + + ImGui::Checkbox("##dofEnabled", &env->DOFEnabled); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetSSR = ICON_FA_UNDO + std::string("##resetrBarrelDistortionEnabled"); + if (ImGui::Button(resetSSR.c_str())) env->DOFEnabled = false; + ImGui::PopStyleColor(); + } + + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Auto focus"); + ImGui::TableNextColumn(); + + ImGui::Checkbox("##dofautofocus", &env->DOFAutoFocus); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetDOFFstop = ICON_FA_UNDO + std::string("##resetdofautofocus"); + if (ImGui::Button(resetDOFFstop.c_str())) env->DOFAutoFocus = false; + ImGui::PopStyleColor(); + } + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Display focus"); + ImGui::TableNextColumn(); + + ImGui::Checkbox("##dofshowautofocus", &env->DOFShowFocus); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetDOFShowautofocus = ICON_FA_UNDO + std::string("##resetdofshowautofocus"); + if (ImGui::Button(resetDOFShowautofocus.c_str())) env->DOFShowFocus = false; + ImGui::PopStyleColor(); + } + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Focus Distance"); + ImGui::TableNextColumn(); + + ImGui::DragFloat("##doffocalDepth", &env->DOFFocalDepth); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetdofFocalDepth = ICON_FA_UNDO + std::string("##resetdofFocalDepth"); + if (ImGui::Button(resetdofFocalDepth.c_str())) env->DOFFocalDepth = 1.0f; + ImGui::PopStyleColor(); + } + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Focus Size"); + ImGui::TableNextColumn(); + + ImGui::DragFloat("##dofstart", &env->DOFStart); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetDOFFstop = ICON_FA_UNDO + std::string("##resetdofstartp"); + if (ImGui::Button(resetDOFFstop.c_str())) env->DOFStart = 1.0f; + ImGui::PopStyleColor(); + } + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Focus Fade"); + ImGui::TableNextColumn(); + + ImGui::DragFloat("##dofdistance", &env->DOFDist); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetDOFDist = ICON_FA_UNDO + std::string("##resetDOFDist"); + if (ImGui::Button(resetDOFDist.c_str())) env->DOFDist = 1.0f; + ImGui::PopStyleColor(); + } + + ImGui::EndTable(); + } + END_COLLAPSE_HEADER() + + BEGIN_COLLAPSE_HEADER(BARREL_DISTORTION) + if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp)) + { + ImGui::TableSetupColumn("name", 0, 0.3f); + ImGui::TableSetupColumn("set", 0, 0.6f); + ImGui::TableSetupColumn("reset", 0, 0.1f); + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Enabled"); + ImGui::TableNextColumn(); + + ImGui::Checkbox("##BarrelEnabled", &env->BarrelDistortionEnabled); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetSSR = ICON_FA_UNDO + std::string("##resetrBarrelDistortionEnabled"); + if (ImGui::Button(resetSSR.c_str())) env->BarrelDistortionEnabled = false; + ImGui::PopStyleColor(); + } + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Distortion"); + ImGui::TableNextColumn(); + ImGui::DragFloat("##distortion", &env->BarrelDistortion, 0.01f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->BarrelDistortion = 0.0f; + ImGui::PopStyleColor(); + } + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Edge Distortion"); + ImGui::TableNextColumn(); + ImGui::DragFloat("##edgedistortion", &env->BarrelEdgeDistortion, 0.01f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->BarrelEdgeDistortion = 0.0f; + ImGui::PopStyleColor(); + } + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Scale Adjustement"); + ImGui::TableNextColumn(); + ImGui::DragFloat("##barrelScale", &env->BarrelScale, 0.01f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->BarrelScale = 1.0f; + ImGui::PopStyleColor(); + } + ImGui::EndTable(); + } + END_COLLAPSE_HEADER() + + BEGIN_COLLAPSE_HEADER(VIGNETTE) + if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp)) + { + ImGui::TableSetupColumn("name", 0, 0.3); + ImGui::TableSetupColumn("set", 0, 0.6); + ImGui::TableSetupColumn("reset", 0, 0.1); + + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Enabled"); + ImGui::TableNextColumn(); + + ImGui::Checkbox("##VignetteEnabled", &env->VignetteEnabled); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetSSR = ICON_FA_UNDO + std::string("##resetrBarrelDistortionEnabled"); + if (ImGui::Button(resetSSR.c_str())) env->VignetteEnabled = false; + ImGui::PopStyleColor(); + } + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Intensity"); + ImGui::TableNextColumn(); + ImGui::DragFloat("##vignetteIntensity", &env->VignetteIntensity, 0.1f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VignetteIntensity = 0.0f; + ImGui::PopStyleColor(); + } + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Extend"); + ImGui::TableNextColumn(); + ImGui::DragFloat("##vignetteExtend", &env->VignetteExtend, 0.01f, 0.0f); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetVolumetric = ICON_FA_UNDO + std::string("##resetVolumetric"); + if (ImGui::Button(resetVolumetric.c_str())) env->VignetteExtend = 0.0f; + ImGui::PopStyleColor(); + } + ImGui::EndTable(); + } + END_COLLAPSE_HEADER() + + BEGIN_COLLAPSE_HEADER(POSTERIZATION) + if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp)) + { + ImGui::TableSetupColumn("name", 0, 0.3); + ImGui::TableSetupColumn("set", 0, 0.6); + ImGui::TableSetupColumn("reset", 0, 0.1); + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Enabled"); + ImGui::TableNextColumn(); + + ImGui::Checkbox("##PosterizationEnabled", &env->PosterizationEnabled); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetPosterization = ICON_FA_UNDO + std::string("##resetPosterizationEnabled"); + if (ImGui::Button(resetPosterization.c_str())) env->PosterizationEnabled = false; + ImGui::PopStyleColor(); + } + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Levels"); + ImGui::TableNextColumn(); + ImGui::DragInt("##PosterizationLevels", &env->PosterizationLevels, 1, 4, 25); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetPosterizationLevels = ICON_FA_UNDO + std::string("##resetPosterizationLevels"); + if (ImGui::Button(resetPosterizationLevels.c_str())) env->PosterizationLevels = 10; + ImGui::PopStyleColor(); + } + + ImGui::EndTable(); + } + END_COLLAPSE_HEADER() + + BEGIN_COLLAPSE_HEADER(PIXELIZATION) + if (ImGui::BeginTable("EnvTable", 3, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp)) + { + ImGui::TableSetupColumn("name", 0, 0.3); + ImGui::TableSetupColumn("set", 0, 0.6); + ImGui::TableSetupColumn("reset", 0, 0.1); + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Enabled"); + ImGui::TableNextColumn(); + + ImGui::Checkbox("##PixelizationEnabled", &env->PixelizationEnabled); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetPixelization = ICON_FA_UNDO + std::string("##resetPixelizationEnabled"); + if (ImGui::Button(resetPixelization.c_str())) env->PixelizationEnabled = false; + ImGui::PopStyleColor(); + } + + { + ImGui::TableNextColumn(); + // Title + ImGui::Text("Pixel Size"); + ImGui::TableNextColumn(); + ImGui::DragInt("##PixelSize", &env->PixelSize, 1, 1, 25); + ImGui::TableNextColumn(); + + // Reset button + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(1, 1, 1, 0)); + std::string resetPixelSize = ICON_FA_UNDO + std::string("##resetPixelSize"); + if (ImGui::Button(resetPixelSize.c_str())) env->PixelSize = 4; + ImGui::PopStyleColor(); + } + + ImGui::EndTable(); + } + END_COLLAPSE_HEADER() + break; + } + } +} + +void SelectionPropertyWidget::DrawResource(Nuake::Resource resource) +{ + +} + +void SelectionPropertyWidget::DrawMaterialPanel(Ref material) +{ + using namespace Nuake; + + std::string materialTitle = material->Path; + { + UIFont boldfont = UIFont(Fonts::SubTitle); + ImGui::Text(material->Path.c_str()); + + } + ImGui::SameLine(); + { + UIFont boldfont = UIFont(Fonts::Icons); + if (ImGui::Button(ICON_FA_SAVE)) + { + std::string fileData = material->Serialize().dump(4); + + FileSystem::BeginWriteFile(material->Path); + FileSystem::WriteLine(fileData); + FileSystem::EndWriteFile(); + } + } + + bool flagsHeaderOpened; + { + UIFont boldfont = UIFont(Fonts::Bold); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, 0.f)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 8.f)); + flagsHeaderOpened = ImGui::CollapsingHeader(" FLAGS", ImGuiTreeNodeFlags_DefaultOpen); + ImGui::PopStyleVar(2); + } + + if (flagsHeaderOpened) + { + ImGui::BeginTable("##Flags", 3, ImGuiTableFlags_BordersInner); + { + ImGui::TableSetupColumn("name", 0, 0.3f); + ImGui::TableSetupColumn("set", 0, 0.6f); + ImGui::TableSetupColumn("reset", 0, 0.1f); + ImGui::TableNextColumn(); + + ImGui::Text("Unlit"); + ImGui::TableNextColumn(); + + bool unlit = material->data.u_Unlit == 1; + ImGui::Checkbox("Unlit", &unlit); + material->data.u_Unlit = (int)unlit; + } + ImGui::EndTable(); + } + + const auto TexturePanelHeight = 100; + const ImVec2 TexturePanelSize = ImVec2(0, TexturePanelHeight); + bool AlbedoOpened; + { + UIFont boldfont = UIFont(Fonts::Bold); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, 0.f)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 8.f)); + AlbedoOpened = ImGui::CollapsingHeader("Albedo", ImGuiTreeNodeFlags_DefaultOpen); + ImGui::PopStyleVar(2); + } + + if (AlbedoOpened) + { + ImGui::BeginChild("##albedo", TexturePanelSize, true); + { + uint32_t textureID = 0; + if (material->HasAlbedo()) + { + textureID = material->m_Albedo->GetID(); + } + + if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image1"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1))) + { + std::string texture = FileDialog::OpenFile("*.png | *.jpg"); + if (texture != "") + { + material->SetAlbedo(TextureManager::Get()->GetTexture(texture)); + } + } + + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::MenuItem("Clear Texture")) + { + material->m_Albedo = nullptr; + } + ImGui::EndPopup(); + } + + ImGui::SameLine(); + ImGui::ColorEdit3("Color", &material->data.m_AlbedoColor.r); + } + ImGui::EndChild(); + } + + if (ImGui::CollapsingHeader("Normal", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::BeginChild("##normal", TexturePanelSize, true); + { + uint32_t textureID = 0; + if (material->HasNormal()) + { + textureID = material->m_Normal->GetID(); + } + + if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image3"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 1), ImVec4(1, 1, 1, 1))) + { + std::string texture = FileDialog::OpenFile("*.png | *.jpg"); + if (texture != "") + { + material->SetNormal(TextureManager::Get()->GetTexture(texture)); + } + } + + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::MenuItem("Clear Texture")) + { + material->m_Normal = nullptr; + } + ImGui::EndPopup(); + } + } + ImGui::EndChild(); + } + + if (ImGui::CollapsingHeader("AO", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::BeginChild("##ao", TexturePanelSize, true); + { + uint32_t textureID = 0; + if (material->HasAO()) + { + textureID = material->m_AO->GetID(); + } + + if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image2"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(1, 1, 1, 1), ImVec4(1, 1, 1, 1))) + { + std::string texture = FileDialog::OpenFile("Image files (*.png) | *.png | Image files (*.jpg) | *.jpg"); + if (texture != "") + { + material->SetAO(TextureManager::Get()->GetTexture(texture)); + } + } + + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::MenuItem("Clear Texture")) + { + material->m_AO = nullptr; + } + ImGui::EndPopup(); + } + } + ImGui::EndChild(); + } + + if (ImGui::CollapsingHeader("Metalness", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::BeginChild("##metalness", TexturePanelSize, true); + { + uint32_t textureID = 0; + if (material->HasMetalness()) + { + textureID = material->m_Metalness->GetID(); + } + + if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image4"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 1), ImVec4(1, 1, 1, 1))) + { + std::string texture = FileDialog::OpenFile("*.png | *.jpg"); + if (texture != "") + { + material->SetMetalness(TextureManager::Get()->GetTexture(texture)); + } + } + + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::MenuItem("Clear Texture")) + { + material->m_Metalness = nullptr; + } + ImGui::EndPopup(); + } + + ImGui::SameLine(); + ImGui::DragFloat("Value##4", &material->data.u_MetalnessValue, 0.01f, 0.0f, 1.0f); + } + ImGui::EndChild(); + } + + if (ImGui::CollapsingHeader("Roughness", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::BeginChild("##roughness", TexturePanelSize, true); + { + uint32_t textureID = 0; + if (material->HasRoughness()) + { + textureID = material->m_Roughness->GetID(); + } + + if (ImGui::ImageButtonEx(ImGui::GetCurrentWindow()->GetID("#image5"), (void*)textureID, ImVec2(80, 80), ImVec2(0, 1), ImVec2(1, 0), ImVec4(0, 0, 0, 0), ImVec4(1, 1, 1, 1))) + { + std::string texture = FileDialog::OpenFile("*.png | *.jpg"); + if (texture != "") + { + material->SetRoughness(TextureManager::Get()->GetTexture(texture)); + } + } + + if (ImGui::BeginPopupContextWindow()) + { + if (ImGui::MenuItem("Clear Texture")) + { + material->m_Roughness = nullptr; + } + ImGui::EndPopup(); + } + } + ImGui::EndChild(); + } +} + +void SelectionPropertyWidget::DrawProjectPanel(Ref project) +{ + ImGui::InputText("Project Name", &project->Name); + ImGui::InputTextMultiline("Project Description", &project->Description); + + if (ImGui::Button("Locate")) + { + const std::string& locationPath = Nuake::FileDialog::OpenFile("TrenchBroom (.exe)\0TrenchBroom.exe\0"); + + if (!locationPath.empty()) + { + project->TrenchbroomPath = locationPath; + } + } + + ImGui::SameLine(); + ImGui::InputText("Trenchbroom Path", &project->TrenchbroomPath); +} + +void SelectionPropertyWidget::DrawNetScriptPanel(Ref file) +{ + auto filePath = file->GetRelativePath(); + std::string fileContent = Nuake::FileSystem::ReadFile(filePath); + + ImGui::Text("Content"); + ImGui::SameLine(ImGui::GetWindowWidth() - 90); + if (ImGui::Button("Open...")) + { + Nuake::OS::OpenIn(file->GetAbsolutePath()); + } + + ImGui::Separator(); + + ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + ImGui::GetWindowWidth()); + ImGui::Text(fileContent.c_str(), ImGui::GetWindowWidth()); + + ImGui::PopTextWrapPos(); +} + +void SelectionPropertyWidget::DrawComponent(Nuake::Entity& entity, entt::meta_any& component) +{ + // Call into custom component drawer if one is available for this component + + const auto componentIdHash = component.type().info().hash(); + if (ComponentTypeDrawers.contains(componentIdHash)) + { + const auto drawerFn = ComponentTypeDrawers[componentIdHash]; + drawerFn(entity, component); + + return; + } + + const entt::meta_type componentMeta = component.type(); + const std::string componentName = Component::GetName(componentMeta); + + UIFont* boldFont = new UIFont(Fonts::Bold); + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.f, 0.f)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.f, 8.f)); + ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.0f); + bool removed = false; + bool headerOpened = ImGui::CollapsingHeader(componentName.c_str(), ImGuiTreeNodeFlags_DefaultOpen); + + ImGui::PopStyleVar(); + if (strcmp(componentName.c_str(), "TRANSFORM") != 0 && ImGui::BeginPopupContextItem()) + { + if (ImGui::Selectable("Remove")) { removed = true; } + ImGui::EndPopup(); + } + + if (removed) + { + auto componentType = component.type(); + entity.RemoveComponent(componentType); + ImGui::PopStyleVar(); + delete boldFont; + Engine::GetProject()->IsDirty = true; + } + else if (headerOpened) + { + delete boldFont; + ImGui::PopStyleVar(); + ImGui::Indent(); + + if (ImGui::BeginTable(componentName.c_str(), 3, ImGuiTableFlags_SizingStretchProp)) + { + ImGui::TableSetupColumn("name", 0, 0.25f); + ImGui::TableSetupColumn("set", 0, 0.65f); + ImGui::TableSetupColumn("reset", 0, 0.1f); + + ImGui::TableNextRow(); + + DrawComponentContent(component); + + ImGui::EndTable(); + } + ImGui::Unindent(); + } + else + { + ImGui::PopStyleVar(); + delete boldFont; + } + ImGui::PopStyleVar(); +} + +void SelectionPropertyWidget::DrawComponentContent(entt::meta_any& component) +{ + entt::meta_type componentMeta = component.type(); + + // Draw component bound data + for (auto [fst, dataType] : componentMeta.data()) + { + const ComponentFieldTrait fieldTraits = dataType.traits(); + // Field marked as internal and thus not exposed to the inspector + if ((fieldTraits & ComponentFieldTrait::Internal) == ComponentFieldTrait::Internal) + { + continue; + } + + ImGui::TableSetColumnIndex(0); + + // Search for the appropriate drawer for the type + entt::id_type dataId = dataType.type().id(); + if (FieldTypeDrawers.contains(dataId)) + { + auto drawerFn = FieldTypeDrawers[dataId]; + drawerFn(dataType, component); + } + else + { + ImGui::Text("ERR"); + } + + ImGui::TableNextRow(); + } + + // Draw any actions bound to the component + for (auto [fst, funcMeta] : componentMeta.func()) + { + const ComponentFuncTrait funcTraits = funcMeta.traits(); + if ((funcTraits & ComponentFuncTrait::Action) == ComponentFuncTrait::Action) + { + ImGui::TableSetColumnIndex(0); + + std::string funcDisplayName = ""; + auto prop = funcMeta.prop(HashedName::DisplayName).value(); + if (prop) + { + funcDisplayName = std::string(*prop.try_cast()); + } + + std::string buttonName = funcDisplayName; + if (UI::SecondaryButton(buttonName.c_str())) + { + entt::meta_any result = funcMeta.invoke(component); + } + + ImGui::TableNextRow(); + } + } +} + +void SelectionPropertyWidget::DrawFieldTypeFloat(entt::meta_data& field, entt::meta_any& component) +{ + float stepSize = 1.f; + if (auto prop = field.prop(HashedFieldPropName::FloatStep)) + stepSize = *prop.value().try_cast(); + + float min = 0.f; + if (auto prop = field.prop(HashedFieldPropName::FloatMin)) + min = *prop.value().try_cast(); + + float max = 0.f; + if (auto prop = field.prop(HashedFieldPropName::FloatMax)) + max = *prop.value().try_cast(); + + auto propDisplayName = field.prop(HashedName::DisplayName); + const char* displayName = *propDisplayName.value().try_cast(); + if (displayName != nullptr) + { + ImGui::Text(displayName); + ImGui::TableNextColumn(); + + auto fieldVal = field.get(component); + float* floatPtr = fieldVal.try_cast(); + if (floatPtr != nullptr) + { + float floatProxy = *floatPtr; + const std::string controlId = std::string("##") + displayName; + if (ImGui::DragFloat(controlId.c_str(), &floatProxy, stepSize, min, max)) + { + field.set(component, floatProxy); + Engine::GetProject()->IsDirty = true; + } + } + else + { + ImGui::Text("ERR"); + } + } +} + +void SelectionPropertyWidget::DrawFieldTypeBool(entt::meta_data& field, entt::meta_any& component) +{ + auto prop = field.prop(HashedName::DisplayName); + auto propVal = prop.value(); + const char* displayName = *propVal.try_cast(); + + if (displayName != nullptr) + { + ImGui::Text(displayName); + ImGui::TableNextColumn(); + + auto fieldVal = field.get(component); + bool* boolPtr = fieldVal.try_cast(); + if (boolPtr != nullptr) + { + bool boolProxy = *boolPtr; + std::string controlId = std::string("##") + displayName; + if (ImGui::Checkbox(controlId.c_str(), &boolProxy)) + { + field.set(component, boolProxy); + Engine::GetProject()->IsDirty = true; + } + } + else + { + ImGui::Text("ERR"); + } + } +} + +void SelectionPropertyWidget::DrawFieldTypeVector3(entt::meta_data& field, entt::meta_any& component) +{ + auto prop = field.prop(HashedName::DisplayName); + auto propVal = prop.value(); + const char* displayName = *propVal.try_cast(); + + if (displayName != nullptr) + { + ImGui::Text(displayName); + ImGui::TableNextColumn(); + + auto fieldVal = field.get(component); + Vector3* vec3Ptr = fieldVal.try_cast(); + std::string controlId = std::string("##") + displayName; + ImGui::PushID(controlId.c_str()); + + if (ImGuiHelper::DrawVec3(controlId, vec3Ptr, 0.5f, 100.0, 0.01f)) + { + field.set(component, *vec3Ptr); + Engine::GetProject()->IsDirty = true; + } + + ImGui::PopID(); + } +} + +void SelectionPropertyWidget::DrawFieldTypeVector2(entt::meta_data& field, entt::meta_any& component) +{ + auto prop = field.prop(HashedName::DisplayName); + auto propVal = prop.value(); + const char* displayName = *propVal.try_cast(); + + if (displayName != nullptr) + { + ImGui::Text(displayName); + ImGui::TableNextColumn(); + + auto fieldVal = field.get(component); + Vector2* vec2Ptr = fieldVal.try_cast(); + std::string controlId = std::string("##") + displayName; + ImGui::PushID(controlId.c_str()); + + if (ImGuiHelper::DrawVec2(controlId, vec2Ptr, 0.5f, 100.0, 0.01f)) + { + field.set(component, *vec2Ptr); + Engine::GetProject()->IsDirty = true; + } + + ImGui::PopID(); + } +} + +void SelectionPropertyWidget::DrawFieldTypeString(entt::meta_data& field, entt::meta_any& component) +{ + auto prop = field.prop(HashedName::DisplayName); + auto propVal = prop.value(); + const char* displayName = *propVal.try_cast(); + + if (displayName != nullptr) + { + ImGui::Text(displayName); + ImGui::TableNextColumn(); + + auto fieldVal = field.get(component); + std::string* fieldValPtr = fieldVal.try_cast(); + if (fieldValPtr != nullptr) + { + std::string fieldValProxy = *fieldValPtr; + std::string controlId = std::string("##") + displayName; + ImGui::InputText(controlId.c_str(), &fieldValProxy); + + //if (fieldValProxy != fieldVal) + //{ + // Engine::GetProject()->IsDirty = true; + //} + } + else + { + ImGui::Text("ERR"); + } + } +} + +void SelectionPropertyWidget::DrawFieldTypeResourceFile(entt::meta_data& field, entt::meta_any& component) +{ + const char* resourceRestrictedType = nullptr; + if (auto prop = field.prop(HashedFieldPropName::ResourceFileType)) + resourceRestrictedType = *prop.value().try_cast(); + + auto propDisplayName = field.prop(HashedName::DisplayName); + const char* displayName = *propDisplayName.value().try_cast(); + if (displayName != nullptr) + { + ImGui::Text(displayName); + ImGui::TableNextColumn(); + + auto fieldVal = field.get(component); + auto fieldValPtr = fieldVal.try_cast(); + if (fieldValPtr != nullptr) + { + ImGui::SetNextItemAllowOverlap(); + + auto fieldValProxy = *fieldValPtr; + std::string filePath = fieldValProxy.file == nullptr ? "" : fieldValProxy.file->GetRelativePath(); + std::string controlName = filePath + std::string("##") + displayName; + ImGui::Button(controlName.c_str(), ImVec2(ImGui::GetContentRegionAvail().x, 0)); + + if (ImGui::BeginDragDropTarget()) + { + if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload(resourceRestrictedType)) + { + const char* payloadFilePath = static_cast(payload->Data); + const std::string fullPath = std::string(payloadFilePath, 256); + const Ref file = FileSystem::GetFile(FileSystem::AbsoluteToRelative(fullPath)); + field.set(component, ResourceFile{ file }); + Engine::GetProject()->IsDirty = true; + } + ImGui::EndDragDropTarget(); + } + + ImGui::SameLine(); + + bool showShortcutBtn = !filePath.empty(); + const int shortcutBtnWidth = 30; + ImGui::SetCursorPosX(ImGui::GetCursorPosX() - shortcutBtnWidth - ImGui::GetStyle().ItemSpacing.x); + if (ImGui::Button(">", ImVec2(shortcutBtnWidth, 0))) + { + if (FileSystem::FileExists(filePath)) + { + Ref file = FileSystem::GetFile(filePath); + if (file->GetFileType() == FileType::Map) + { + OS::OpenTrenchbroomMap(file->GetAbsolutePath()); + } + else + { + editorContext.SetSelection(FileSystem::GetFile(filePath)); + } + } + } + } + else + { + ImGui::Text("ERR"); + } + } +} + +void SelectionPropertyWidget::DrawFieldTypeDynamicItemList(entt::meta_data& field, entt::meta_any& component) +{ + auto propDisplayName = field.prop(HashedName::DisplayName); + const char* displayName = *propDisplayName.value().try_cast(); + if (displayName != nullptr) + { + ImGui::Text(displayName); + ImGui::TableNextColumn(); + + auto fieldVal = field.get(component); + auto fieldValPtr = fieldVal.try_cast(); + if (fieldValPtr == nullptr) + { + ImGui::Text("ERR"); + } + + const auto& items = fieldValPtr->items; + const int index = fieldValPtr->index; + + // Check first to see if we are within the bounds + std::string selectedStr = ""; + if (index >= 0 || index < items.size()) + { + selectedStr = items[index]; + } + + std::string controlName = std::string("##") + displayName; + if (ImGui::BeginCombo(controlName.c_str(), selectedStr.c_str())) + { + for (int i = 0; i < items.size(); i++) + { + bool isSelected = (index == i); + std::string name = items[i]; + + if (name.empty()) + { + name = "Empty"; + } + + if (ImGui::Selectable(name.c_str(), isSelected)) + { + field.set(component, i); + } + + if (isSelected) + { + ImGui::SetItemDefaultFocus(); + } + } + ImGui::EndCombo(); + } + } +} + diff --git a/Editor/src/Windows/SceneEditor/Widgets/SelectionPropertyWidget.h b/Editor/src/Windows/SceneEditor/Widgets/SelectionPropertyWidget.h index f2f0c219..ad310e4e 100644 --- a/Editor/src/Windows/SceneEditor/Widgets/SelectionPropertyWidget.h +++ b/Editor/src/Windows/SceneEditor/Widgets/SelectionPropertyWidget.h @@ -1,10 +1,20 @@ #pragma once #include "IEditorWidget.h" +#include "../../EditorSelectionPanel.h" class EditorContext; +using DrawComponentTypeFn = std::function; +using DrawFieldTypeFn = std::function; + class SelectionPropertyWidget : public IEditorWidget { +private: + TransformPanel transformPanel; + MeshPanel meshPanel; + SkinnedMeshPanel skinnedMeshPanel; + Ref currentFile; + Ref selectedResource; public: SelectionPropertyWidget(EditorContext& inCtx); ~SelectionPropertyWidget() = default; @@ -14,5 +24,51 @@ public: void Draw() override; private: - + void DrawNone(); + void DrawEntity(Nuake::Entity entity); + void DrawAddComponentMenu(Nuake::Entity entity); + void DrawFile(Ref file); + void DrawResource(Nuake::Resource resource); + + template + void RegisterComponentDrawer() + { + const auto t = entt::type_id(); + ComponentTypeDrawers[t.hash()] = std::bind(Func, std::placeholders::_1, std::placeholders::_2); + } + + template + void RegisterComponentDrawer(O* o) + { + ComponentTypeDrawers[entt::type_id().hash()] = std::bind(Func, o, std::placeholders::_1, std::placeholders::_2); + } + + template + void RegisterTypeDrawer(O* o) + { + FieldTypeDrawers[entt::type_id().hash()] = std::bind(Func, o, std::placeholders::_1, std::placeholders::_2); + } + +protected: + // Drawing functions for each component (for writing very specific inspectors for specific components) + std::unordered_map ComponentTypeDrawers; + + // List of functions to call for each component field type that needs to be drawn + std::unordered_map FieldTypeDrawers; + + void ResolveFile(Ref file); + void DrawMaterialPanel(Ref material); + void DrawProjectPanel(Ref project); + void DrawNetScriptPanel(Ref file); + + void DrawComponent(Nuake::Entity& entity, entt::meta_any& component); + void DrawComponentContent(entt::meta_any& component); + + void DrawFieldTypeFloat(entt::meta_data& field, entt::meta_any& component); + void DrawFieldTypeBool(entt::meta_data& field, entt::meta_any& component); + void DrawFieldTypeVector2(entt::meta_data& field, entt::meta_any& component); + void DrawFieldTypeVector3(entt::meta_data& field, entt::meta_any& component); + void DrawFieldTypeString(entt::meta_data& field, entt::meta_any& component); + void DrawFieldTypeResourceFile(entt::meta_data& field, entt::meta_any& component); + void DrawFieldTypeDynamicItemList(entt::meta_data& field, entt::meta_any& component); }; \ No newline at end of file diff --git a/Editor/src/Windows/SceneEditor/Widgets/ViewportWidget.cpp b/Editor/src/Windows/SceneEditor/Widgets/ViewportWidget.cpp new file mode 100644 index 00000000..b530e0b5 --- /dev/null +++ b/Editor/src/Windows/SceneEditor/Widgets/ViewportWidget.cpp @@ -0,0 +1,151 @@ +#include "ViewportWidget.h" + +#include +#include "src/Core/Input.h" + +#include "../../EditorInterface.h" + +#include + +using namespace Nuake; + +void ViewportWidget::Update(float ts) +{ + +} + +void ViewportWidget::Draw() +{ + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); + if (BeginWidgetWindow(ICON_FA_GAMEPAD + std::string("Viewport"))) + { + ImGui::PopStyleVar(); + + ImGuizmo::BeginFrame(); + ImGuizmo::SetOrthographic(false); + + ImVec2 regionAvail = ImGui::GetContentRegionAvail(); + Vector2 viewportPanelSize = glm::vec2(regionAvail.x, regionAvail.y); + + // This is important for make UI mouse coord relative to viewport + // Input::SetViewportDimensions(m_ViewportPos, viewportPanelSize); + + VkDescriptorSet textureDesc = VkRenderer::Get().DrawImage->GetImGuiDescriptorSet(); + + ImVec2 imagePos = ImGui::GetWindowPos() + ImGui::GetCursorPos(); + // Input::SetEditorViewportSize(m_ViewportPos, viewportPanelSize); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); + //m_ViewportPos = { imagePos.x, imagePos.y }; + ImGui::Image(textureDesc, regionAvail, { 0, 1 }, { 1, 0 }); + ImGui::PopStyleVar(); + + const Vector2& mousePos = Input::GetMousePosition(); + + const ImVec2& windowPos = ImGui::GetWindowPos(); + const auto windowPosNuake = Vector2(windowPos.x, windowPos.y); + const ImVec2& windowSize = ImGui::GetWindowSize(); + const bool isInsideWidth = mousePos.x > windowPos.x && mousePos.x < windowPos.x + windowSize.x; + const bool isInsideHeight = mousePos.y > windowPos.y && mousePos.y < windowPos.y + windowSize.y; + // m_IsHoveringViewport = isInsideWidth && isInsideHeight; + + // TODO(antopilo) drag n drop + ImGuizmo::SetDrawlist(); + ImGuizmo::AllowAxisFlip(true); + ImGuizmo::SetRect(imagePos.x, imagePos.y, viewportPanelSize.x, viewportPanelSize.y); + + // TODO(grid) + auto selection = editorContext.GetSelection(); + if (selection.Type == EditorSelectionType::Entity && !Engine::IsPlayMode()) + { + if (!selection.Entity.IsValid()) + { + editorContext.SetSelection(EditorSelection()); + } + else + { + TransformComponent& tc = selection.Entity.GetComponent(); + Matrix4 transform = tc.GetGlobalTransform(); + const auto& editorCam = Engine::GetCurrentScene()->GetCurrentCamera(); + Matrix4 cameraView = editorCam->GetTransform(); + + // Since imguizmo doesnt support reverse-Z, we need to create a new projection matrix + // With a normal near and far plane. + Matrix4 normalZProjection = glm::perspectiveFov(glm::radians(editorCam->Fov), 9.0f * editorCam->AspectRatio, 9.0f, editorCam->Far, editorCam->Near); + + static Vector3 camPreviousPos = Engine::GetCurrentScene()->m_EditorCamera->Translation; + static Vector3 camNewPos = Vector3(0, 0, 0); + Vector3 camDelta = camNewPos - camPreviousPos; + Vector3 previousGlobalPos = transform[3]; + // Imguizmo calculates the delta from the gizmo, + ImGuizmo::Manipulate( + glm::value_ptr(Engine::GetCurrentScene()->GetCurrentCamera()->GetTransform()), + glm::value_ptr(normalZProjection), + CurrentOperation, CurrentMode, + glm::value_ptr(transform), NULL, + UseSnapping ? &CurrentSnapping.x : NULL + ); + + if (ImGuizmo::IsUsing()) + { + // Since imguizmo returns a transform in global space and we want the local transform, + // we need to multiply by the inverse of the parent's global transform in order to revert + // the changes from the parent transform. + Matrix4 localTransform = Matrix4(transform); + + Vector3 newGlobalPos = transform[3]; + if (ImGui::IsKeyDown(ImGuiKey_LeftShift)) + { + Vector3 positionDelta = newGlobalPos - previousGlobalPos; + Engine::GetCurrentScene()->m_EditorCamera->Translation += positionDelta; + camNewPos = Engine::GetCurrentScene()->m_EditorCamera->Translation; + } + + ParentComponent& parent = selection.Entity.GetComponent(); + if (parent.HasParent) + { + const auto& parentTransformComponent = parent.Parent.GetComponent(); + const Matrix4& parentTransform = parentTransformComponent.GetGlobalTransform(); + localTransform = glm::inverse(parentTransform) * localTransform; + } + + // Decompose local transform + float decomposedPosition[3]; + float decomposedEuler[3]; + float decomposedScale[3]; + ImGuizmo::DecomposeMatrixToComponents(glm::value_ptr(localTransform), decomposedPosition, decomposedEuler, decomposedScale); + + const auto& localPosition = Vector3(decomposedPosition[0], decomposedPosition[1], decomposedPosition[2]); + const auto& localScale = Vector3(decomposedScale[0], decomposedScale[1], decomposedScale[2]); + + localTransform[0] /= localScale.x; + localTransform[1] /= localScale.y; + localTransform[2] /= localScale.z; + const auto& rotationMatrix = Matrix3(localTransform); + const Quat& localRotation = glm::normalize(Quat(rotationMatrix)); + + const Matrix4& rotationMatrix4 = glm::mat4_cast(localRotation); + const Matrix4& scaleMatrix = glm::scale(Matrix4(1.0f), localScale); + const Matrix4& translationMatrix = glm::translate(Matrix4(1.0f), localPosition); + const Matrix4& newLocalTransform = translationMatrix * rotationMatrix4 * scaleMatrix; + + tc.Translation = localPosition; + + if (CurrentOperation != ImGuizmo::SCALE) + { + tc.Rotation = localRotation; + } + + tc.Scale = localScale; + tc.LocalTransform = newLocalTransform; + tc.Dirty = true; + } + } + } + + } + else + { + ImGui::PopStyleVar(); + } + ImGui::End(); +} \ No newline at end of file diff --git a/Editor/src/Windows/SceneEditor/Widgets/ViewportWidget.h b/Editor/src/Windows/SceneEditor/Widgets/ViewportWidget.h new file mode 100644 index 00000000..e51d1585 --- /dev/null +++ b/Editor/src/Windows/SceneEditor/Widgets/ViewportWidget.h @@ -0,0 +1,24 @@ +#pragma once + +#include "IEditorWidget.h" + +#include + +class EditorContext; + +class ViewportWidget : public IEditorWidget +{ +private: + ImGuizmo::OPERATION CurrentOperation = ImGuizmo::TRANSLATE; + ImGuizmo::MODE CurrentMode = ImGuizmo::WORLD; + bool UseSnapping = true; + Nuake::Vector3 CurrentSnapping = { 0.05f, 0.05f, 0.05f }; + +public: + ViewportWidget(EditorContext& context) : IEditorWidget(context) {} + ~ViewportWidget() = default; + +public: + void Update(float ts) override; + void Draw() override; +}; \ No newline at end of file diff --git a/Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp b/Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp index fc6ba318..f4ff2b7c 100644 --- a/Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp +++ b/Nuake/src/Rendering/Vulkan/VulkanRenderer.cpp @@ -423,7 +423,7 @@ void VkRenderer::InitImgui() io.Fonts->AddFontFromMemoryTTF(StaticResources::Resources_Fonts_Poppins_Regular_ttf, StaticResources::Resources_Fonts_Poppins_Regular_ttf_len, 16.0); io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; - //io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; ImGui::StyleColorsDark(); ImGuiStyle& s = ImGui::GetStyle(); @@ -654,6 +654,15 @@ void VkRenderer::EndDraw() VK_CALL(vkQueuePresentKHR(GPUQueue, &presentInfo)); + auto& io = ImGui::GetIO(); + //io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; + //Update and Render additional Platform Windows + if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + ImGui::UpdatePlatformWindows(); + ImGui::RenderPlatformWindowsDefault(); + } + // Increase the number of frames drawn FrameNumber++; } diff --git a/Nuake/src/UI/ImUI.cpp b/Nuake/src/UI/ImUI.cpp index ac942e1f..0f8a1726 100644 --- a/Nuake/src/UI/ImUI.cpp +++ b/Nuake/src/UI/ImUI.cpp @@ -263,5 +263,17 @@ namespace Nuake { DrawButtonImage(image, image, image, tintNormal, tintHovered, tintPressed, ImGui::GetItemRectMin(), ImGui::GetItemRectMax()); }; + + bool Splitter(bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size) + { + using namespace ImGui; + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; + ImGuiID id = window->GetID("##Splitter"); + ImRect bb; + bb.Min = window->DC.CursorPos + (split_vertically ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1)); + bb.Max = bb.Min + CalcItemSize(split_vertically ? ImVec2(thickness, splitter_long_axis_size) : ImVec2(splitter_long_axis_size, thickness), 0.0f, 0.0f); + return SplitterBehavior(bb, id, split_vertically ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, min_size1, min_size2, 0.0f); + } } } diff --git a/Nuake/src/UI/ImUI.h b/Nuake/src/UI/ImUI.h index 0832a486..472a9e3e 100644 --- a/Nuake/src/UI/ImUI.h +++ b/Nuake/src/UI/ImUI.h @@ -79,5 +79,6 @@ namespace Nuake ImRect RectOffset(const ImRect& rect, ImVec2 xy); + bool Splitter(bool split_vertically, float thickness, float* size1, float* size2, float min_size1, float min_size2, float splitter_long_axis_size = -1.0f); } } \ No newline at end of file diff --git a/Nuake/src/Window.cpp b/Nuake/src/Window.cpp index ab7ad934..f55f8d66 100644 --- a/Nuake/src/Window.cpp +++ b/Nuake/src/Window.cpp @@ -258,8 +258,8 @@ void Window::EndDraw() if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { GLFWwindow* backup_current_context = glfwGetCurrentContext(); - ImGui::UpdatePlatformWindows(); - ImGui::RenderPlatformWindowsDefault(); + //ImGui::UpdatePlatformWindows(); + //ImGui::RenderPlatformWindowsDefault(); glfwMakeContextCurrent(backup_current_context); } @@ -471,7 +471,7 @@ void Window::InitImgui() io.Fonts->AddFontFromMemoryTTF(StaticResources::Resources_Fonts_Poppins_Regular_ttf, StaticResources::Resources_Fonts_Poppins_Regular_ttf_len, 16.0); io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; - //io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; + io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; ImGui::StyleColorsDark(); ImGuiStyle& s = ImGui::GetStyle();