From 675f4c6055acfbfb5ff6a16e0b64afc55020797f Mon Sep 17 00:00:00 2001 From: PrakarshPanwar Date: Fri, 11 Nov 2022 13:05:26 +0530 Subject: [PATCH 1/8] Added Texture Thumbnails - Earlier textures were represented by Standard File Icon - Now only .png will be presented as texture in Content Browser Panel --- Hazelnut/src/Panels/ContentBrowserPanel.cpp | 32 +++++++++++++++++++-- Hazelnut/src/Panels/ContentBrowserPanel.h | 1 + 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/Hazelnut/src/Panels/ContentBrowserPanel.cpp b/Hazelnut/src/Panels/ContentBrowserPanel.cpp index 201a458bc..fb6056dc3 100644 --- a/Hazelnut/src/Panels/ContentBrowserPanel.cpp +++ b/Hazelnut/src/Panels/ContentBrowserPanel.cpp @@ -5,6 +5,17 @@ namespace Hazel { + namespace Utils { + + bool IsImageFile(const std::filesystem::path& path) + { + if (path.extension() == ".png") + return true; + + return false; + } + + } // Once we have projects, change this extern const std::filesystem::path g_AssetPath = "assets"; @@ -13,6 +24,16 @@ namespace Hazel { { m_DirectoryIcon = Texture2D::Create("Resources/Icons/ContentBrowser/DirectoryIcon.png"); m_FileIcon = Texture2D::Create("Resources/Icons/ContentBrowser/FileIcon.png"); + + // Loading Textures + for (auto& directoryEntry : std::filesystem::recursive_directory_iterator(g_AssetPath)) + { + const auto& path = directoryEntry.path(); + const auto& filenameString = path.string(); + + if (Utils::IsImageFile(path)) + m_TextureIcons[filenameString] = Texture2D::Create(filenameString); + } } void ContentBrowserPanel::OnImGuiRender() @@ -21,7 +42,7 @@ namespace Hazel { if (m_CurrentDirectory != std::filesystem::path(g_AssetPath)) { - if (ImGui::Button("<-")) + if (ImGui::Button("Back")) { m_CurrentDirectory = m_CurrentDirectory.parent_path(); } @@ -44,7 +65,14 @@ namespace Hazel { std::string filenameString = path.filename().string(); ImGui::PushID(filenameString.c_str()); - Ref icon = directoryEntry.is_directory() ? m_DirectoryIcon : m_FileIcon; + Ref icon = nullptr; + + if (Utils::IsImageFile(path)) + icon = m_TextureIcons[path.string()]; + + else + icon = directoryEntry.is_directory() ? m_DirectoryIcon : m_FileIcon; + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); ImGui::ImageButton((ImTextureID)icon->GetRendererID(), { thumbnailSize, thumbnailSize }, { 0, 1 }, { 1, 0 }); diff --git a/Hazelnut/src/Panels/ContentBrowserPanel.h b/Hazelnut/src/Panels/ContentBrowserPanel.h index 0aa71c14c..2433fc9b6 100644 --- a/Hazelnut/src/Panels/ContentBrowserPanel.h +++ b/Hazelnut/src/Panels/ContentBrowserPanel.h @@ -17,6 +17,7 @@ namespace Hazel { Ref m_DirectoryIcon; Ref m_FileIcon; + std::unordered_map> m_TextureIcons; }; } From b7ef665de5525fdc632eac76aa35c16e486596f5 Mon Sep 17 00:00:00 2001 From: PrakarshPanwar Date: Mon, 14 Nov 2022 18:44:54 +0530 Subject: [PATCH 2/8] Replaced Texture Button as Image Button in SpriteRendererComponent Properties panel - Now on clicking on Entity will show texture in a button --- Hazelnut/src/EditorLayer.cpp | 2 ++ Hazelnut/src/Panels/SceneHierarchyPanel.cpp | 13 +++++++++++-- Hazelnut/src/Panels/SceneHierarchyPanel.h | 2 ++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Hazelnut/src/EditorLayer.cpp b/Hazelnut/src/EditorLayer.cpp index 4ea316963..ecb17f0ec 100644 --- a/Hazelnut/src/EditorLayer.cpp +++ b/Hazelnut/src/EditorLayer.cpp @@ -40,6 +40,8 @@ namespace Hazel { m_EditorScene = CreateRef(); m_ActiveScene = m_EditorScene; + m_SceneHierarchyPanel.Init(); + auto commandLineArgs = Application::Get().GetSpecification().CommandLineArgs; if (commandLineArgs.Count > 1) { diff --git a/Hazelnut/src/Panels/SceneHierarchyPanel.cpp b/Hazelnut/src/Panels/SceneHierarchyPanel.cpp index 7a2241ca7..fe0142a5d 100644 --- a/Hazelnut/src/Panels/SceneHierarchyPanel.cpp +++ b/Hazelnut/src/Panels/SceneHierarchyPanel.cpp @@ -26,6 +26,11 @@ namespace Hazel { SetContext(context); } + void SceneHierarchyPanel::Init() + { + m_DefaultTexture = Texture2D::Create(1, 1); + } + void SceneHierarchyPanel::SetContext(const Ref& context) { m_Context = context; @@ -401,11 +406,15 @@ namespace Hazel { ImGui::PopStyleColor(); }); - DrawComponent("Sprite Renderer", entity, [](auto& component) + DrawComponent("Sprite Renderer", entity, [this](auto& component) { ImGui::ColorEdit4("Color", glm::value_ptr(component.Color)); - ImGui::Button("Texture", ImVec2(100.0f, 0.0f)); + uint32_t buttonTex = component.Texture ? component.Texture->GetRendererID() + : m_DefaultTexture->GetRendererID(); + + ImGui::ImageButton((ImTextureID)buttonTex, ImVec2{ 100.0f, 100.0f }); + if (ImGui::BeginDragDropTarget()) { if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("CONTENT_BROWSER_ITEM")) diff --git a/Hazelnut/src/Panels/SceneHierarchyPanel.h b/Hazelnut/src/Panels/SceneHierarchyPanel.h index a63a284ff..30679efdc 100644 --- a/Hazelnut/src/Panels/SceneHierarchyPanel.h +++ b/Hazelnut/src/Panels/SceneHierarchyPanel.h @@ -12,6 +12,7 @@ namespace Hazel { SceneHierarchyPanel() = default; SceneHierarchyPanel(const Ref& scene); + void Init(); void SetContext(const Ref& scene); void OnImGuiRender(); @@ -27,6 +28,7 @@ namespace Hazel { private: Ref m_Context; Entity m_SelectionContext; + Ref m_DefaultTexture; }; } From adc13edf9e3a708042c96100f7f66e2cd428b54c Mon Sep 17 00:00:00 2001 From: PrakarshPanwar Date: Mon, 14 Nov 2022 22:39:39 +0530 Subject: [PATCH 3/8] Added FileWatch in ContentBrowserPanel - Also removed some previous methods and made default texture in SceneHierarchyPanel const - Editor crashes when adding new textures in asset directory --- Hazelnut/src/EditorLayer.cpp | 2 -- Hazelnut/src/Panels/ContentBrowserPanel.cpp | 28 +++++++++++++++++++-- Hazelnut/src/Panels/ContentBrowserPanel.h | 3 +++ Hazelnut/src/Panels/SceneHierarchyPanel.cpp | 5 ---- Hazelnut/src/Panels/SceneHierarchyPanel.h | 3 +-- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/Hazelnut/src/EditorLayer.cpp b/Hazelnut/src/EditorLayer.cpp index ecb17f0ec..4ea316963 100644 --- a/Hazelnut/src/EditorLayer.cpp +++ b/Hazelnut/src/EditorLayer.cpp @@ -40,8 +40,6 @@ namespace Hazel { m_EditorScene = CreateRef(); m_ActiveScene = m_EditorScene; - m_SceneHierarchyPanel.Init(); - auto commandLineArgs = Application::Get().GetSpecification().CommandLineArgs; if (commandLineArgs.Count > 1) { diff --git a/Hazelnut/src/Panels/ContentBrowserPanel.cpp b/Hazelnut/src/Panels/ContentBrowserPanel.cpp index fb6056dc3..2fb011a83 100644 --- a/Hazelnut/src/Panels/ContentBrowserPanel.cpp +++ b/Hazelnut/src/Panels/ContentBrowserPanel.cpp @@ -7,9 +7,9 @@ namespace Hazel { namespace Utils { - bool IsImageFile(const std::filesystem::path& path) + static bool IsImageFile(const std::filesystem::path& path) { - if (path.extension() == ".png") + if (path.extension() == ".png" || path.extension() == ".jpg") return true; return false; @@ -25,6 +25,30 @@ namespace Hazel { m_DirectoryIcon = Texture2D::Create("Resources/Icons/ContentBrowser/DirectoryIcon.png"); m_FileIcon = Texture2D::Create("Resources/Icons/ContentBrowser/FileIcon.png"); + auto FileAssetEvent = [this](const std::string& path, const filewatch::Event change_type) + { + std::filesystem::path texturePath = path; + texturePath = g_AssetPath / path; + + switch (change_type) + { + case filewatch::Event::added: + { + if (Utils::IsImageFile(texturePath)) + m_TextureIcons[texturePath.string()] = Texture2D::Create(texturePath.string()); + + HZ_WARN("{}: File Added", texturePath.string()); + } + case filewatch::Event::removed: + { + m_TextureIcons.erase(texturePath.string()); + HZ_WARN("{}: File Deleted", texturePath.string()); + } + } + }; + + m_ContentBrowserFileWatcher = CreateScope>(g_AssetPath.string(), FileAssetEvent); + // Loading Textures for (auto& directoryEntry : std::filesystem::recursive_directory_iterator(g_AssetPath)) { diff --git a/Hazelnut/src/Panels/ContentBrowserPanel.h b/Hazelnut/src/Panels/ContentBrowserPanel.h index 2433fc9b6..9115a1236 100644 --- a/Hazelnut/src/Panels/ContentBrowserPanel.h +++ b/Hazelnut/src/Panels/ContentBrowserPanel.h @@ -3,6 +3,7 @@ #include "Hazel/Renderer/Texture.h" #include +#include "FileWatch.h" namespace Hazel { @@ -18,6 +19,8 @@ namespace Hazel { Ref m_DirectoryIcon; Ref m_FileIcon; std::unordered_map> m_TextureIcons; + + Scope> m_ContentBrowserFileWatcher; }; } diff --git a/Hazelnut/src/Panels/SceneHierarchyPanel.cpp b/Hazelnut/src/Panels/SceneHierarchyPanel.cpp index fe0142a5d..2d445259e 100644 --- a/Hazelnut/src/Panels/SceneHierarchyPanel.cpp +++ b/Hazelnut/src/Panels/SceneHierarchyPanel.cpp @@ -26,11 +26,6 @@ namespace Hazel { SetContext(context); } - void SceneHierarchyPanel::Init() - { - m_DefaultTexture = Texture2D::Create(1, 1); - } - void SceneHierarchyPanel::SetContext(const Ref& context) { m_Context = context; diff --git a/Hazelnut/src/Panels/SceneHierarchyPanel.h b/Hazelnut/src/Panels/SceneHierarchyPanel.h index 30679efdc..ddfcb7fdb 100644 --- a/Hazelnut/src/Panels/SceneHierarchyPanel.h +++ b/Hazelnut/src/Panels/SceneHierarchyPanel.h @@ -12,7 +12,6 @@ namespace Hazel { SceneHierarchyPanel() = default; SceneHierarchyPanel(const Ref& scene); - void Init(); void SetContext(const Ref& scene); void OnImGuiRender(); @@ -28,7 +27,7 @@ namespace Hazel { private: Ref m_Context; Entity m_SelectionContext; - Ref m_DefaultTexture; + const Ref m_DefaultTexture = Texture2D::Create(1, 1); }; } From 47575dc6a109ac226e76e86c33b8697d39965fad Mon Sep 17 00:00:00 2001 From: PrakarshPanwar Date: Wed, 15 Feb 2023 14:59:32 +0530 Subject: [PATCH 4/8] Replaced Untitled in SceneSerializer with `std.filesystem.path.stem()` - This will help in distinguish Scene names --- Hazel/src/Hazel/Scene/SceneSerializer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Hazel/src/Hazel/Scene/SceneSerializer.cpp b/Hazel/src/Hazel/Scene/SceneSerializer.cpp index 0a959d301..baff8aa14 100644 --- a/Hazel/src/Hazel/Scene/SceneSerializer.cpp +++ b/Hazel/src/Hazel/Scene/SceneSerializer.cpp @@ -360,7 +360,7 @@ namespace Hazel { { YAML::Emitter out; out << YAML::BeginMap; - out << YAML::Key << "Scene" << YAML::Value << "Untitled"; + out << YAML::Key << "Scene" << YAML::Value << std::filesystem::path(filepath).stem().string(); out << YAML::Key << "Entities" << YAML::Value << YAML::BeginSeq; m_Scene->m_Registry.each([&](auto entityID) { From 7eaab6649d100de6e2623ae30a7200a9c0b5f84e Mon Sep 17 00:00:00 2001 From: PrakarshPanwar Date: Sun, 19 Mar 2023 13:07:50 +0530 Subject: [PATCH 5/8] Fixed Texture loading bug - This issue is still open to some extent - This can happen due to OpenGL unable to load multiple textures at once - This issue will gone after switching to Vulkan --- Hazelnut/src/Panels/ContentBrowserPanel.cpp | 39 +++++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/Hazelnut/src/Panels/ContentBrowserPanel.cpp b/Hazelnut/src/Panels/ContentBrowserPanel.cpp index 2fb011a83..921a22bf9 100644 --- a/Hazelnut/src/Panels/ContentBrowserPanel.cpp +++ b/Hazelnut/src/Panels/ContentBrowserPanel.cpp @@ -2,6 +2,7 @@ #include "ContentBrowserPanel.h" #include +#include "Hazel/Core/Application.h" namespace Hazel { @@ -16,6 +17,7 @@ namespace Hazel { } } + // Once we have projects, change this extern const std::filesystem::path g_AssetPath = "assets"; @@ -25,24 +27,38 @@ namespace Hazel { m_DirectoryIcon = Texture2D::Create("Resources/Icons/ContentBrowser/DirectoryIcon.png"); m_FileIcon = Texture2D::Create("Resources/Icons/ContentBrowser/FileIcon.png"); - auto FileAssetEvent = [this](const std::string& path, const filewatch::Event change_type) + auto FileAssetEvent = [this](const std::string& filepath, const filewatch::Event change_type) { - std::filesystem::path texturePath = path; - texturePath = g_AssetPath / path; - switch (change_type) { case filewatch::Event::added: { - if (Utils::IsImageFile(texturePath)) - m_TextureIcons[texturePath.string()] = Texture2D::Create(texturePath.string()); - - HZ_WARN("{}: File Added", texturePath.string()); + Application::Get().SubmitToMainThread([this, filepath]() + { + if (Utils::IsImageFile(filepath)) + { + std::filesystem::path texturePath = filepath; + texturePath = g_AssetPath / filepath; + + m_TextureIcons[texturePath.string()] = Texture2D::Create(texturePath.string()); + HZ_WARN("{}: File Added", texturePath.string()); + } + }); + + break; } case filewatch::Event::removed: { - m_TextureIcons.erase(texturePath.string()); - HZ_WARN("{}: File Deleted", texturePath.string()); + Application::Get().SubmitToMainThread([this, filepath]() + { + std::filesystem::path texturePath = filepath; + texturePath = g_AssetPath / filepath; + + m_TextureIcons.erase(texturePath.string()); + HZ_WARN("{}: File Deleted", texturePath.string()); + }); + + break; } } }; @@ -98,7 +114,8 @@ namespace Hazel { icon = directoryEntry.is_directory() ? m_DirectoryIcon : m_FileIcon; ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); - ImGui::ImageButton((ImTextureID)icon->GetRendererID(), { thumbnailSize, thumbnailSize }, { 0, 1 }, { 1, 0 }); + if (icon.get() != nullptr) + ImGui::ImageButton((ImTextureID)icon->GetRendererID(), { thumbnailSize, thumbnailSize }, { 0, 1 }, { 1, 0 }); if (ImGui::BeginDragDropSource()) { From 02f735404143de3b3c481049f6c3730a5eb295e9 Mon Sep 17 00:00:00 2001 From: PrakarshPanwar Date: Sun, 19 Mar 2023 13:41:23 +0530 Subject: [PATCH 6/8] Fixed Black Thumbnails issue - Reason for this issue was that the texture didn't load fully on the directory which resulted in black textures - Adding `std.this_thread.sleep_for` gave time for directory to load textures properly - However for large assets that can take longer than 0.02s to load on directory this method will not work --- Hazelnut/src/Panels/ContentBrowserPanel.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Hazelnut/src/Panels/ContentBrowserPanel.cpp b/Hazelnut/src/Panels/ContentBrowserPanel.cpp index 921a22bf9..96355493d 100644 --- a/Hazelnut/src/Panels/ContentBrowserPanel.cpp +++ b/Hazelnut/src/Panels/ContentBrowserPanel.cpp @@ -40,6 +40,12 @@ namespace Hazel { std::filesystem::path texturePath = filepath; texturePath = g_AssetPath / filepath; + // NOTE: Waiting for Texture to load fully on directory otherwise we'll get black thumbnails + // Waiting Time can vary depending on asset size + // To remove this we need a way to know if file has loaded completely or not + using namespace std::literals::chrono_literals; + std::this_thread::sleep_for(0.02s); + m_TextureIcons[texturePath.string()] = Texture2D::Create(texturePath.string()); HZ_WARN("{}: File Added", texturePath.string()); } From d6b6f06b9327ee6702f04447239c46c37ddf77a8 Mon Sep 17 00:00:00 2001 From: PrakarshPanwar Date: Sun, 19 Mar 2023 14:23:19 +0530 Subject: [PATCH 7/8] Added option to Remove Textures in SpriteRendererComponent - To do this right-click on Image Button in SpriteRendererComponent then click Remove Texture --- Hazelnut/src/Panels/ContentBrowserPanel.cpp | 2 +- Hazelnut/src/Panels/SceneHierarchyPanel.cpp | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Hazelnut/src/Panels/ContentBrowserPanel.cpp b/Hazelnut/src/Panels/ContentBrowserPanel.cpp index b34119419..667ba45bd 100644 --- a/Hazelnut/src/Panels/ContentBrowserPanel.cpp +++ b/Hazelnut/src/Panels/ContentBrowserPanel.cpp @@ -119,7 +119,7 @@ namespace Hazel { icon = directoryEntry.is_directory() ? m_DirectoryIcon : m_FileIcon; ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); - if (icon.get() != nullptr) + if (icon) ImGui::ImageButton((ImTextureID)icon->GetRendererID(), { thumbnailSize, thumbnailSize }, { 0, 1 }, { 1, 0 }); if (ImGui::BeginDragDropSource()) diff --git a/Hazelnut/src/Panels/SceneHierarchyPanel.cpp b/Hazelnut/src/Panels/SceneHierarchyPanel.cpp index 78e2e3073..db8204c3b 100644 --- a/Hazelnut/src/Panels/SceneHierarchyPanel.cpp +++ b/Hazelnut/src/Panels/SceneHierarchyPanel.cpp @@ -408,6 +408,17 @@ namespace Hazel { ImGui::ImageButton((ImTextureID)buttonTex, ImVec2{ 100.0f, 100.0f }); + if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) + ImGui::OpenPopup("RemoveTexture"); + + if (ImGui::BeginPopup("RemoveTexture")) + { + if (ImGui::MenuItem("Remove Texture")) + component.Texture = nullptr; + + ImGui::EndPopup(); + } + if (ImGui::BeginDragDropTarget()) { if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("CONTENT_BROWSER_ITEM")) @@ -420,6 +431,7 @@ namespace Hazel { else HZ_WARN("Could not load texture {0}", texturePath.filename().string()); } + ImGui::EndDragDropTarget(); } From 9b7d1b07b766677493d00d1785f9a5b9a5ffe83f Mon Sep 17 00:00:00 2001 From: PrakarshPanwar Date: Sun, 14 May 2023 18:36:04 +0530 Subject: [PATCH 8/8] Modified lambda in SpriteRendererComponent - Now instead of taking `this` it only takes default texture --- Hazelnut/src/Panels/SceneHierarchyPanel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Hazelnut/src/Panels/SceneHierarchyPanel.cpp b/Hazelnut/src/Panels/SceneHierarchyPanel.cpp index db8204c3b..37b402e98 100644 --- a/Hazelnut/src/Panels/SceneHierarchyPanel.cpp +++ b/Hazelnut/src/Panels/SceneHierarchyPanel.cpp @@ -399,12 +399,12 @@ namespace Hazel { } }); - DrawComponent("Sprite Renderer", entity, [this](auto& component) + DrawComponent("Sprite Renderer", entity, [defaultTexture = m_DefaultTexture](auto& component) { ImGui::ColorEdit4("Color", glm::value_ptr(component.Color)); uint32_t buttonTex = component.Texture ? component.Texture->GetRendererID() - : m_DefaultTexture->GetRendererID(); + : defaultTexture->GetRendererID(); ImGui::ImageButton((ImTextureID)buttonTex, ImVec2{ 100.0f, 100.0f });