From d6d735900ab14861e7f6345fe8e358843be21c73 Mon Sep 17 00:00:00 2001 From: Atdunbg Date: Wed, 8 Apr 2026 23:30:33 +0800 Subject: [PATCH] add simple node editor(use ImGui-Node-Editor), some tweaks --- .gitmodules | 3 + Editor/Editor/EditorLayer.cpp | 42 +- Prism/CMakeLists.txt | 14 + Prism/src/Prism/Editor/AssetEditorPanel.cpp | 4 +- .../src/Prism/Editor/DefaultAssetEditors.cpp | 284 ------- Prism/src/Prism/Editor/DefaultAssetEditors.h | 62 -- .../PBRMaterialAssetEditor.cpp | 718 ++++++++++++++++++ .../PBRMaterialAssetEditor.h | 94 +++ .../PhysicsMaterialEditor.cpp | 35 + .../PhysicsMaterialEditor.h | 32 + .../TextureAssetEditor.cpp | 46 ++ .../DefaultAssetEditors/TextureAssetEditor.h | 31 + Prism/vendor/imgui-node-editor | 1 + 13 files changed, 1000 insertions(+), 366 deletions(-) delete mode 100644 Prism/src/Prism/Editor/DefaultAssetEditors.cpp delete mode 100644 Prism/src/Prism/Editor/DefaultAssetEditors.h create mode 100644 Prism/src/Prism/Editor/DefaultAssetEditors/PBRMaterialAssetEditor.cpp create mode 100644 Prism/src/Prism/Editor/DefaultAssetEditors/PBRMaterialAssetEditor.h create mode 100644 Prism/src/Prism/Editor/DefaultAssetEditors/PhysicsMaterialEditor.cpp create mode 100644 Prism/src/Prism/Editor/DefaultAssetEditors/PhysicsMaterialEditor.h create mode 100644 Prism/src/Prism/Editor/DefaultAssetEditors/TextureAssetEditor.cpp create mode 100644 Prism/src/Prism/Editor/DefaultAssetEditors/TextureAssetEditor.h create mode 160000 Prism/vendor/imgui-node-editor diff --git a/.gitmodules b/.gitmodules index da10699..f7879ba 100644 --- a/.gitmodules +++ b/.gitmodules @@ -35,3 +35,6 @@ [submodule "Prism/vendor/efsw"] path = Prism/vendor/efsw url = https://github.com/SpartanJ/efsw +[submodule "Prism/vendor/imgui-node-editor"] + path = Prism/vendor/imgui-node-editor + url = https://github.com/thedmd/imgui-node-editor.git diff --git a/Editor/Editor/EditorLayer.cpp b/Editor/Editor/EditorLayer.cpp index 83627e5..081c3cb 100644 --- a/Editor/Editor/EditorLayer.cpp +++ b/Editor/Editor/EditorLayer.cpp @@ -719,7 +719,7 @@ namespace Prism m_ViewportBounds[1] = { maxBound.x, maxBound.y }; // ImGuizmo - if (m_GizmoType != -1 && !m_SelectionContext.empty() && m_SceneState == SceneState::Edit) + if ((m_ViewportPanelFocused || m_ViewportPanelHovered) && m_GizmoType != -1 && !m_SelectionContext.empty() && m_SceneState == SceneState::Edit) { auto& selection = m_SelectionContext[0]; @@ -921,15 +921,19 @@ namespace Prism if (ImViewGuizmo::Rotate(cameraPos, cameraRot, glm::vec3(0.0f), gizmoCenter)) { + if (m_ViewportPanelFocused || m_ViewportPanelHovered) + { + glm::vec3 forward = cameraRot * glm::vec3(0.0f, 0.0f, -1.0f); + float newPitch = glm::asin(glm::clamp(-forward.y, -1.0f, 1.0f)); + float newYaw = -glm::atan(forward.x, -forward.z); - glm::vec3 forward = cameraRot * glm::vec3(0.0f, 0.0f, -1.0f); - float newPitch = glm::asin(glm::clamp(-forward.y, -1.0f, 1.0f)); - float newYaw = -glm::atan(forward.x, -forward.z); + float distance = glm::length(cameraPos - focusPosition); + m_EditorCamera.SetDistance(distance); + m_EditorCamera.SetFocusPosition(focusPosition); + m_EditorCamera.SetYawPitch(newYaw, newPitch); + + } - float distance = glm::length(cameraPos - focusPosition); - m_EditorCamera.SetDistance(distance); - m_EditorCamera.SetFocusPosition(focusPosition); - m_EditorCamera.SetYawPitch(newYaw, newPitch); } } @@ -994,20 +998,20 @@ namespace Prism break; } } - } - switch (e.GetKeyCode()) - { - case KeyCode::DELETE: - if (m_SelectionContext.size()) + switch (e.GetKeyCode()) { - const Entity selectedEntity = m_SelectionContext[0].Entity; - m_EditorScene->DestroyEntity(selectedEntity); - m_SelectionContext.clear(); - m_EditorScene->SetSelectedEntity({}); - m_SceneHierarchyPanel->SetSelected({}); + case KeyCode::DELETE: + if (m_SelectionContext.size()) + { + const Entity selectedEntity = m_SelectionContext[0].Entity; + m_EditorScene->DestroyEntity(selectedEntity); + m_SelectionContext.clear(); + m_EditorScene->SetSelectedEntity({}); + m_SceneHierarchyPanel->SetSelected({}); + } + break; } - break; } if (Input::IsKeyPressed(KeyCode::LEFT_CONTROL)) diff --git a/Prism/CMakeLists.txt b/Prism/CMakeLists.txt index f1b7cec..850bee2 100644 --- a/Prism/CMakeLists.txt +++ b/Prism/CMakeLists.txt @@ -50,6 +50,19 @@ list(APPEND SRC_SOURCE ${IMGUIZMO_SOURCE}) # ----------- ImViewGuizmo ------------- set(IMVIEWGUIZMO_DIR vendor/ImViewGuizmo) +# ----------- ImGui-Node-Editor ------------- +set(IMGUI_NODE_EDITOR_DIR vendor/imgui-node-editor) +set(IMGUI_NODE_EDITOR_SOURCES + ${IMGUI_NODE_EDITOR_DIR}/imgui_node_editor.cpp + ${IMGUI_NODE_EDITOR_DIR}/imgui_node_editor_api.cpp + ${IMGUI_NODE_EDITOR_DIR}/imgui_canvas.cpp + ${IMGUI_NODE_EDITOR_DIR}/crude_json.cpp + + ${IMGUI_NODE_EDITOR_DIR}/examples/blueprints-example/utilities/widgets.cpp + ${IMGUI_NODE_EDITOR_DIR}/examples/blueprints-example/utilities/drawing.cpp +) +list(APPEND SRC_SOURCE ${IMGUI_NODE_EDITOR_SOURCES}) + # ------------- NVIDIA PhysX ------------- # PhysX/physx/buildtools/presets/*.xml @@ -125,6 +138,7 @@ set(TARGET_INCLUDE_DIR ${IMGUI_DIR} ${IMGUIZMO_DIR} ${IMVIEWGUIZMO_DIR} + ${IMGUI_NODE_EDITOR_DIR} ) # ------------- debug Defines ------------- diff --git a/Prism/src/Prism/Editor/AssetEditorPanel.cpp b/Prism/src/Prism/Editor/AssetEditorPanel.cpp index 3bddd59..af5e026 100644 --- a/Prism/src/Prism/Editor/AssetEditorPanel.cpp +++ b/Prism/src/Prism/Editor/AssetEditorPanel.cpp @@ -4,7 +4,9 @@ #include "AssetEditorPanel.h" -#include "DefaultAssetEditors.h" +#include "DefaultAssetEditors/PBRMaterialAssetEditor.h" +#include "DefaultAssetEditors/PhysicsMaterialEditor.h" +#include "DefaultAssetEditors/TextureAssetEditor.h" #include "Prism/Asset/AssetSerializer.h" #include "Prism/Core/Log.h" diff --git a/Prism/src/Prism/Editor/DefaultAssetEditors.cpp b/Prism/src/Prism/Editor/DefaultAssetEditors.cpp deleted file mode 100644 index 3f65755..0000000 --- a/Prism/src/Prism/Editor/DefaultAssetEditors.cpp +++ /dev/null @@ -1,284 +0,0 @@ -// -// Created by Atdunbg on 2026/2/14. -// - -#include "DefaultAssetEditors.h" - -#include "Prism/Asset/AssetSerializer.h" -#include "Prism/Core/Log.h" - -namespace Prism -{ - - // MaterialEditor - PhysicsMaterialEditor::PhysicsMaterialEditor() - : AssetEditor("Edit Physics Material") {} - - void PhysicsMaterialEditor::SetAsset(const Ref& asset) - { - if (m_Asset) AssetSerializer::SerializeAsset(m_Asset); - m_Asset = static_cast>(asset); - } - - void PhysicsMaterialEditor::Render() - { - if (!m_Asset) - SetOpen(false); - - UI::BeginPropertyGrid(); - UI::Property("Static Friction", m_Asset->StaticFriction); - UI::Property("Dynamic Friction", m_Asset->DynamicFriction); - UI::Property("Bounciness", m_Asset->Bounciness); - UI::EndPropertyGrid(); - - if (ImGui::Button("Save")) - AssetSerializer::SerializeAsset(m_Asset); - } - - - // MaterialEditor - TextureViewer::TextureViewer() - : AssetEditor("Edit Texture") - { - SetMinSize(200, 600); - SetMaxSize(500, 1000); - } - - void TextureViewer::SetAsset(const Ref& asset) - { - if (m_Asset) AssetSerializer::SerializeAsset(m_Asset); - m_Asset = static_cast>(asset); - } - - void TextureViewer::Render() - { - if (!m_Asset) - SetOpen(false); - - float textureWidth = (float)m_Asset->GetWidth(); - float textureHeight = (float)m_Asset->GetHeight(); - float bitsPerPixel = (float)Texture::GetBPP(m_Asset->GetFormat()); - float imageSize = ImGui::GetWindowWidth() - 40; - imageSize = glm::min(imageSize, 500.0f); - - ImGui::SetCursorPosX(20); - ImGui::Image((ImTextureID)m_Asset->GetRendererID(), { imageSize, imageSize }); - - UI::BeginPropertyGrid(); - UI::Property("Width", textureWidth, 0.1f, 0.0f, 0.0f, true); - UI::Property("Height", textureHeight, 0.1f, 0.0f, 0.0f, true); - UI::Property("Bits", bitsPerPixel, 0.1f, 0.0f, 0.0f, true); - UI::EndPropertyGrid(); - } - - PBRMaterialEditor::PBRMaterialEditor() : AssetEditor("Material Editor") - { - } - - - // 辅助函数:绘制纹理拖拽槽 - void DrawTextureSlot(Ref& texture, const std::function)>& onDrop) - { - static Ref s_Checkerboard = nullptr; - if (!s_Checkerboard) - s_Checkerboard = AssetsManager::GetAsset("assets/editor/Checkerboard.tga"); - - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10)); - ImGui::Image(texture ? (ImTextureID)(intptr_t)texture->GetRendererID() : (ImTextureID)(intptr_t)s_Checkerboard->GetRendererID(), - ImVec2(64, 64)); - ImGui::PopStyleVar(); - - if (ImGui::BeginDragDropTarget()) - { - if (const auto data = ImGui::AcceptDragDropPayload("asset_payload")) - { - AssetHandle assetHandle = *(AssetHandle*)data->Data; - if (AssetsManager::IsAssetType(assetHandle, AssetType::Texture)) - { - Ref newTex = AssetsManager::GetAsset(assetHandle); - if (onDrop) onDrop(newTex); - } - } - ImGui::EndDragDropTarget(); - } - - if (ImGui::IsItemHovered()) - { - if (texture) - { - ImGui::BeginTooltip(); - ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); - ImGui::TextUnformatted(texture->GetPath().c_str()); - ImGui::PopTextWrapPos(); - ImGui::Image((ImTextureID)(intptr_t)texture->GetRendererID(), ImVec2(384, 384)); - ImGui::EndTooltip(); - } - - /* - // TODO: how to solve this - if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) - { - std::string filename = FileSystem::OpenFileSelector("*.png;*.tga;*.jpg;*.jpeg"); - if (!filename.empty()) - { - Ref newTex = Texture2D::Create(filename); - if (onDrop) onDrop(newTex); - } - } - */ - } - } - - - void PBRMaterialEditor::SetAsset(const Ref& asset) - { - if (m_Asset) - { - if (m_Asset->Handle == asset->Handle) return; - if (AssetsManager::IsAssetHandleValid(m_Asset->Handle)) - AssetSerializer::SerializeAsset(m_Asset); - } - m_Asset = static_cast>(asset); - } - - void PBRMaterialEditor::Render() - { - if (!m_Asset) return; - - auto& material = m_Asset; - - if (ImGui::BeginTabBar("MaterialProperties", ImGuiTabBarFlags_None)) - { - // ==================== Parameters ==================== - if (ImGui::BeginTabItem("Parameters")) - { - ImGui::Spacing(); - - if (ImGui::CollapsingHeader("Albedo", ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::Indent(); - - if (ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(material->AlbedoColor))) - { - m_Asset->IsDirty = true; - } - - bool useAlbedoMap = (material->AlbedoTexToggle > 0.5f); - if (ImGui::Checkbox("Use Texture##Albedo", &useAlbedoMap)) - { - material->AlbedoTexToggle = useAlbedoMap ? 1.0f : 0.0f; - m_Asset->IsDirty = true; - } - - DrawTextureSlot(material->AlbedoTexture, [&](const Ref& newTex) { - material->AlbedoTexture = newTex; - material->AlbedoTexToggle = true; - m_Asset->IsDirty = true; - }); - ImGui::SameLine(); - ImGui::Text("Albedo Texture"); - - ImGui::Unindent(); - } - - // Normal Map - if (ImGui::CollapsingHeader("Normal Map", ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::Indent(); - - bool useNormalMap = (material->NormalTexToggle > 0.5f); - if (ImGui::Checkbox("Use Texture##Normal", &useNormalMap)) - { - material->NormalTexToggle = useNormalMap ? 1.0f : 0.0f; - m_Asset->IsDirty = true; - } - - DrawTextureSlot(material->NormalTexture, [&](const Ref& newTex) { - material->NormalTexture = newTex; - material->NormalTexToggle = true; - m_Asset->IsDirty = true; - }); - ImGui::SameLine(); - ImGui::Text("Normal Texture"); - - ImGui::Unindent(); - } - - // Metalness - if (ImGui::CollapsingHeader("Metalness", ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::Indent(); - - if (ImGui::SliderFloat("Value##Metalness", &material->Metalness, 0.0f, 1.0f)) - { - // 自动保存 - m_Asset->IsDirty = true; - } - - bool useMetalnessMap = (material->MetalnessTexToggle > 0.5f); - if (ImGui::Checkbox("Use Texture##Metalness", &useMetalnessMap)) - { - material->MetalnessTexToggle = useMetalnessMap ? 1.0f : 0.0f; - m_Asset->IsDirty = true; - } - - DrawTextureSlot(material->MetalnessTexture, [&](const Ref& newTex) { - material->MetalnessTexture = newTex; - material->MetalnessTexToggle = true; - m_Asset->IsDirty = true; - }); - ImGui::SameLine(); - ImGui::Text("Metalness Texture"); - - ImGui::Unindent(); - } - - // Roughness - if (ImGui::CollapsingHeader("Roughness", ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::Indent(); - - if (ImGui::SliderFloat("Value##Roughness", &material->Roughness, 0.0f, 1.0f)) - { - // 自动保存 - m_Asset->IsDirty = true; - } - - bool useRoughnessMap = (material->RoughnessTexToggle > 0.5f); - if (ImGui::Checkbox("Use Texture##Roughness", &useRoughnessMap)) - { - material->RoughnessTexToggle = useRoughnessMap ? 1.0f : 0.0f; - m_Asset->IsDirty = true; - } - - DrawTextureSlot(material->RoughnessTexture, [&](const Ref& newTex) { - material->RoughnessTexture = newTex; - material->RoughnessTexToggle = true; - m_Asset->IsDirty = true; - }); - ImGui::SameLine(); - ImGui::Text("Roughness Texture"); - - ImGui::Unindent(); - } - - ImGui::EndTabItem(); - } - - // ==================== 预览 ==================== - if (ImGui::BeginTabItem("Preview")) - { - // 简单显示纹理预览 - if (material->AlbedoTexture) - { - ImGui::Text("Albedo Preview"); - ImGui::Image((ImTextureID)(intptr_t)material->AlbedoTexture->GetRendererID(), ImVec2(128, 128)); - } - ImGui::EndTabItem(); - } - - ImGui::EndTabBar(); - } - } - -} diff --git a/Prism/src/Prism/Editor/DefaultAssetEditors.h b/Prism/src/Prism/Editor/DefaultAssetEditors.h deleted file mode 100644 index c7c4825..0000000 --- a/Prism/src/Prism/Editor/DefaultAssetEditors.h +++ /dev/null @@ -1,62 +0,0 @@ -// -// Created by Atdunbg on 2026/2/14. -// - -#ifndef PRISM_DEFAULTASSETEDITORS_H -#define PRISM_DEFAULTASSETEDITORS_H -#include "AssetEditorPanel.h" -#include "Prism/Renderer/Texture.h" - - -namespace Prism -{ - class RenderPass; - - class PhysicsMaterialEditor : public AssetEditor - { - public: - PhysicsMaterialEditor(); - - Ref GetAsset() override { return m_Asset; } - void SetAsset(const Ref& asset) override; - - private: - void Render() override; - - private: - Ref m_Asset; - }; - - class TextureViewer : public AssetEditor - { - public: - TextureViewer(); - - Ref GetAsset() override { return m_Asset; } - void SetAsset(const Ref& asset) override; - - private: - void Render() override; - - private: - Ref m_Asset; - }; - - class PBRMaterialEditor : public AssetEditor - { - public: - PBRMaterialEditor(); - - Ref GetAsset() override { return m_Asset; } - void SetAsset(const Ref& asset) override; - - private: - void Render() override; - - private: - Ref m_Asset; - }; - -} - -#endif //PRISM_DEFAULTASSETEDITORS_H \ No newline at end of file diff --git a/Prism/src/Prism/Editor/DefaultAssetEditors/PBRMaterialAssetEditor.cpp b/Prism/src/Prism/Editor/DefaultAssetEditors/PBRMaterialAssetEditor.cpp new file mode 100644 index 0000000..5d3451a --- /dev/null +++ b/Prism/src/Prism/Editor/DefaultAssetEditors/PBRMaterialAssetEditor.cpp @@ -0,0 +1,718 @@ +// +// Created by Atdunbg on 2026/2/14. +// + +#include "PBRMaterialAssetEditor.h" + +#include "examples/blueprints-example/utilities/widgets.h" +#include "Prism/Asset/AssetSerializer.h" +#include "Prism/Core/Log.h" + +namespace Prism +{ + PBRMaterialEditor::PBRMaterialEditor() : AssetEditor("Material Editor") + { + ed::Config config; + config.SettingsFile = ""; + m_EditorContext = ed::CreateEditor(&config); + } + + PBRMaterialEditor::~PBRMaterialEditor() + { + if (m_EditorContext) + { + ed::DestroyEditor(m_EditorContext); + m_EditorContext = nullptr; + } + } + + // 辅助函数:绘制纹理拖拽槽 + void DrawTextureSlot(Ref& texture, const std::function)>& onDrop) + { + static Ref s_Checkerboard = nullptr; + if (!s_Checkerboard) + s_Checkerboard = AssetsManager::GetAsset("assets/editor/Checkerboard.tga"); + + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(10, 10)); + ImGui::Image(texture + ? (ImTextureID)(intptr_t)texture->GetRendererID() + : (ImTextureID)(intptr_t)s_Checkerboard->GetRendererID(), + ImVec2(64, 64)); + ImGui::PopStyleVar(); + + if (ImGui::BeginDragDropTarget()) + { + if (const auto data = ImGui::AcceptDragDropPayload("asset_payload")) + { + AssetHandle assetHandle = *(AssetHandle*)data->Data; + if (AssetsManager::IsAssetType(assetHandle, AssetType::Texture)) + { + Ref newTex = AssetsManager::GetAsset(assetHandle); + if (onDrop) onDrop(newTex); + } + } + ImGui::EndDragDropTarget(); + } + + if (ImGui::IsItemHovered()) + { + if (texture) + { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); + ImGui::TextUnformatted(texture->GetPath().c_str()); + ImGui::PopTextWrapPos(); + ImGui::Image((ImTextureID)(intptr_t)texture->GetRendererID(), ImVec2(384, 384)); + ImGui::EndTooltip(); + } + + /* + // TODO: how to solve this + if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) + { + std::string filename = FileSystem::OpenFileSelector("*.png;*.tga;*.jpg;*.jpeg"); + if (!filename.empty()) + { + Ref newTex = Texture2D::Create(filename); + if (onDrop) onDrop(newTex); + } + } + */ + } + } + + + void PBRMaterialEditor::SetAsset(const Ref& asset) + { + if (m_Asset) + { + if (m_Asset->Handle == asset->Handle) return; + if (AssetsManager::IsAssetHandleValid(m_Asset->Handle)) + AssetSerializer::SerializeAsset(m_Asset); + } + m_Asset = static_cast>(asset); + LoadAssetToGraph(); // 加载资产数据到节点图 + } + + void PBRMaterialEditor::Render() + { + if (!m_Asset) return; + + if (ImGui::BeginTabBar("MaterialProperties", ImGuiTabBarFlags_None)) + { + if (ImGui::BeginTabItem("Basic Edit panel")) + { + RenderBasicEditorPanel(); + ImGui::EndTabItem(); + } + + if (ImGui::BeginTabItem("Graph Node Edit")) + { + // TODO: using ImGui Node Editor impl + RenderNodeEditorPanel(); + ImGui::EndTabItem(); + } + + ImGui::EndTabBar(); + } + } + + + void PBRMaterialEditor::RenderBasicEditorPanel() + { + auto& material = m_Asset; + // ==================== Parameters ==================== + { + ImGui::Spacing(); + + if (ImGui::CollapsingHeader("Albedo", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::Indent(); + + if (ImGui::ColorEdit3("Color##Albedo", glm::value_ptr(material->AlbedoColor))) + { + m_Asset->IsDirty = true; + } + + bool useAlbedoMap = (material->AlbedoTexToggle > 0.5f); + if (ImGui::Checkbox("Use Texture##Albedo", &useAlbedoMap)) + { + material->AlbedoTexToggle = useAlbedoMap ? 1.0f : 0.0f; + m_Asset->IsDirty = true; + } + + DrawTextureSlot(material->AlbedoTexture, [&](const Ref& newTex) + { + material->AlbedoTexture = newTex; + material->AlbedoTexToggle = true; + m_Asset->IsDirty = true; + }); + ImGui::SameLine(); + ImGui::Text("Albedo Texture"); + + ImGui::Unindent(); + } + + // Normal Map + if (ImGui::CollapsingHeader("Normal Map", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::Indent(); + + bool useNormalMap = (material->NormalTexToggle > 0.5f); + if (ImGui::Checkbox("Use Texture##Normal", &useNormalMap)) + { + material->NormalTexToggle = useNormalMap ? 1.0f : 0.0f; + m_Asset->IsDirty = true; + } + + DrawTextureSlot(material->NormalTexture, [&](const Ref& newTex) + { + material->NormalTexture = newTex; + material->NormalTexToggle = true; + m_Asset->IsDirty = true; + }); + ImGui::SameLine(); + ImGui::Text("Normal Texture"); + + ImGui::Unindent(); + } + + // Metalness + if (ImGui::CollapsingHeader("Metalness", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::Indent(); + + if (ImGui::SliderFloat("Value##Metalness", &material->Metalness, 0.0f, 1.0f)) + { + // 自动保存 + m_Asset->IsDirty = true; + } + + bool useMetalnessMap = (material->MetalnessTexToggle > 0.5f); + if (ImGui::Checkbox("Use Texture##Metalness", &useMetalnessMap)) + { + material->MetalnessTexToggle = useMetalnessMap ? 1.0f : 0.0f; + m_Asset->IsDirty = true; + } + + DrawTextureSlot(material->MetalnessTexture, [&](const Ref& newTex) + { + material->MetalnessTexture = newTex; + material->MetalnessTexToggle = true; + m_Asset->IsDirty = true; + }); + ImGui::SameLine(); + ImGui::Text("Metalness Texture"); + + ImGui::Unindent(); + } + + // Roughness + if (ImGui::CollapsingHeader("Roughness", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::Indent(); + + if (ImGui::SliderFloat("Value##Roughness", &material->Roughness, 0.0f, 1.0f)) + { + // 自动保存 + m_Asset->IsDirty = true; + } + + bool useRoughnessMap = (material->RoughnessTexToggle > 0.5f); + if (ImGui::Checkbox("Use Texture##Roughness", &useRoughnessMap)) + { + material->RoughnessTexToggle = useRoughnessMap ? 1.0f : 0.0f; + m_Asset->IsDirty = true; + } + + DrawTextureSlot(material->RoughnessTexture, [&](const Ref& newTex) + { + material->RoughnessTexture = newTex; + material->RoughnessTexToggle = true; + m_Asset->IsDirty = true; + }); + ImGui::SameLine(); + ImGui::Text("Roughness Texture"); + + ImGui::Unindent(); + } + } + } + + ImColor PBRMaterialEditor::GetPinColor(int pinType) + { + switch (pinType) + { + case Albedo: return ImColor(220, 48, 48); + case Normal: return ImColor(68, 201, 156); + case Metallic: return ImColor(147, 226, 74); + case Roughness: return ImColor(124, 21, 153); + case AO: return ImColor(51, 150, 215); + default: return ImColor(255, 255, 255); + } + } + + void PBRMaterialEditor::DrawPinIcon(bool connected, int alpha, int pinType) + { + ImColor color = GetPinColor(pinType); + color.Value.w = alpha / 255.0f; + ax::Widgets::Icon(ImVec2(24, 24), ax::Drawing::IconType::Circle, connected, color, ImColor(32, 32, 32, alpha)); + } + + void PBRMaterialEditor::DrawOutputPinIcon(bool connected, int alpha) + { + ax::Widgets::Icon(ImVec2(24, 24), ax::Drawing::IconType::Circle, connected, ImColor(255, 255, 255, alpha), + ImColor(32, 32, 32, alpha)); + } + + float PBRMaterialEditor::DrawNodeHeader(const char* title, float minWidth) + { + ImGui::TextUnformatted(title); + ImGui::Dummy(ImVec2(minWidth, 4.0f)); + float headerBottomY = ImGui::GetCursorScreenPos().y; + ImGui::Dummy(ImVec2(0, 6.0f)); + return headerBottomY; + } + + + // 节点编辑器面板 + void PBRMaterialEditor::RenderNodeEditorPanel() + { + ed::SetCurrentEditor(m_EditorContext); + + // 顶部工具栏 + if (ImGui::Button("Add Texture Node")) + { + int newId = m_NextNodeId++; + float yOffset = m_TextureNodes.size() * 170.0f; + m_TextureNodes.push_back({newId, AssetHandle(0), 50.0f, yOffset}); + m_FirstFrame = true; + } + ImGui::SameLine(); + if (ImGui::Button("Compile to Asset")) + { + CompileMaterialToAsset(); + m_Asset->IsDirty = true; + } + + ed::Begin("MaterialNodeEditor"); + + if (m_FirstFrame) + { + // 定位节点 + ed::SetNodePosition(ed::NodeId(OUTPUT_NODE_ID), ImVec2(400, 100)); + for (auto& node : m_TextureNodes) + ed::SetNodePosition(ed::NodeId(node.ID), ImVec2(node.PosX, node.PosY)); + ed::NavigateToContent(); + m_FirstFrame = false; + } + + // 绘制输出节点 + DrawOutputNode(); + + // 绘制所有纹理节点 + for (auto& node : m_TextureNodes) + DrawTextureNode(node.ID, node.TextureHandle); + + // 绘制连线 + for (const auto& link : m_Links) + { + int endPinIndex = link.EndPinID % 100; + ImColor linkColor = GetPinColor(endPinIndex); + ed::Link(ed::LinkId(link.ID), ed::PinId(link.StartPinID), ed::PinId(link.EndPinID), linkColor, 2.0f); + } + + // 处理交互 + HandleNodeEditorInteractions(); + + + ed::End(); + ed::SetCurrentEditor(nullptr); + } + + void PBRMaterialEditor::DrawOutputNode() + { + const float nodeWidth = 240.0f; + + ed::PushStyleVar(ed::StyleVar_NodePadding, ImVec4(8, 4, 8, 8)); + ed::BeginNode(ed::NodeId(OUTPUT_NODE_ID)); + + ImVec2 headerMin = ImGui::GetCursorScreenPos(); + ImGui::BeginGroup(); + float headerMaxY = DrawNodeHeader("PBR Material Output", nodeWidth); + + // TODO: this will add preview texture + ImGui::Dummy(ImVec2(nodeWidth, 128)); + ImGui::Spacing(); + + // 输入引脚 + auto drawInputPin = [&](PinType pinType, const char* label, auto valueWidget) + { + int pinId = InputPinID(pinType); + ed::BeginPin(ed::PinId(pinId), ed::PinKind::Input); + DrawPinIcon(IsPinLinked(pinId), 255, pinType); + ed::EndPin(); + ImGui::SameLine(); + ImGui::TextUnformatted(label); + if (!IsPinLinked(pinId)) + { + ImGui::SameLine(); + valueWidget(); + } + }; + + drawInputPin(Albedo, "Albedo", [&]() + { + ImGui::SetNextItemWidth(80); + ImVec2 btnPos = ImGui::GetCursorScreenPos(); + if (ImGui::ColorButton( + "##albedo", ImVec4(m_Asset->AlbedoColor.r, m_Asset->AlbedoColor.g, m_Asset->AlbedoColor.b, 1.0f), + ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoBorder, ImVec2(20, 20))) + { + m_OpenAlbedoPicker = true; + m_AlbedoPickerPos = btnPos; + } + }); + + drawInputPin(Normal, "Normal", []() { ImGui::NewLine(); }); + + drawInputPin(Metallic, "Metallic", [&]() + { + ImGui::SetNextItemWidth(80); + if (ImGui::SliderFloat("##metallic", &m_Asset->Metalness, 0.0f, 1.0f)) + m_Asset->IsDirty = true; + }); + + drawInputPin(Roughness, "Roughness", [&]() + { + ImGui::SetNextItemWidth(80); + if (ImGui::SliderFloat("##roughness", &m_Asset->Roughness, 0.0f, 1.0f)) + m_Asset->IsDirty = true; + }); + + drawInputPin(AO, "AO", [&]() + { + ImGui::SetNextItemWidth(80); + float ao = 1.0f; // 如果资产没有 AO 字段可以忽略 + if (ImGui::SliderFloat("##ao", &ao, 0.0f, 1.0f)) + { + } + }); + + ImGui::EndGroup(); + ImVec2 groupMin = ImGui::GetItemRectMin(); + ImVec2 groupMax = ImGui::GetItemRectMax(); + ed::EndNode(); + + // 绘制标题栏背景 + float pad = 7.0f; + auto* drawList = ed::GetNodeBackgroundDrawList(ed::NodeId(OUTPUT_NODE_ID)); + drawList->AddRectFilled( + ImVec2(groupMin.x - pad, headerMin.y - 3.0f), + ImVec2(groupMax.x + pad, headerMaxY), + IM_COL32(128, 16, 16, 230), 12.0f, ImDrawFlags_RoundCornersTop); + + ed::PopStyleVar(); + } + + void PBRMaterialEditor::DrawTextureNode(int nodeId, AssetHandle& textureHandle) + { + const float nodeWidth = 120.0f; + + ImGui::PushID(nodeId); + ed::PushStyleVar(ed::StyleVar_NodePadding, ImVec4(8, 4, 8, 8)); + ed::BeginNode(ed::NodeId(nodeId)); + + ImVec2 headerMin = ImGui::GetCursorScreenPos(); + ImGui::BeginGroup(); + float headerMaxY = DrawNodeHeader("Texture2D", nodeWidth); + + // 纹理预览 + bool hasTexture = (textureHandle != 0); + float previewSize = 80.0f; + float offsetX = (nodeWidth - previewSize) * 0.5f; + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offsetX); + + if (hasTexture) + { + Ref tex = AssetsManager::GetAsset(textureHandle); + if (tex) + ImGui::Image((ImTextureID)(intptr_t)tex->GetRendererID(), ImVec2(previewSize, previewSize), ImVec2(0,1), ImVec2(1,0)); + else + ImGui::Dummy(ImVec2(previewSize, previewSize)); + } + else + { + ImVec2 pos = ImGui::GetCursorScreenPos(); + ImDrawList* dl = ImGui::GetWindowDrawList(); + // 修正:显式构造 ImVec2,避免依赖运算符重载 + ImVec2 pos_end = ImVec2(pos.x + previewSize, pos.y + previewSize); + dl->AddRectFilled(pos, pos_end, IM_COL32(50,50,50,255), 4.0f); + dl->AddRect(pos, pos_end, IM_COL32(90,90,90,255), 4.0f); + ImGui::Dummy(ImVec2(previewSize, previewSize)); + } + + // 拖拽接收 + if (ImGui::BeginDragDropTarget()) + { + if (const auto* payload = ImGui::AcceptDragDropPayload("asset_payload")) + { + AssetHandle handle = *(AssetHandle*)payload->Data; + if (AssetsManager::IsAssetType(handle, AssetType::Texture)) + { + textureHandle = handle; + m_Asset->IsDirty = true; + } + } + ImGui::EndDragDropTarget(); + } + + ImGui::Spacing(); + + // 输出引脚(右对齐) + float pinOffset = nodeWidth - 50.0f; + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + pinOffset); + ImGui::TextUnformatted("Out"); + ImGui::SameLine(); + int outPinId = OutputPinID(nodeId); + ed::BeginPin(ed::PinId(outPinId), ed::PinKind::Output); + DrawOutputPinIcon(IsPinLinked(outPinId), 255); + ed::EndPin(); + + ImGui::EndGroup(); + ImVec2 groupMin = ImGui::GetItemRectMin(); + ImVec2 groupMax = ImGui::GetItemRectMax(); + ed::EndNode(); + + float pad = 8.0f; + auto* bgDrawList = ed::GetNodeBackgroundDrawList(ed::NodeId(nodeId)); + bgDrawList->AddRectFilled( + ImVec2(groupMin.x - pad, headerMin.y - 4.0f), + ImVec2(groupMax.x + pad, headerMaxY), + IM_COL32(0, 80, 120, 230), 12.0f, ImDrawFlags_RoundCornersTop); + + ed::PopStyleVar(); + ImGui::PopID(); + } + + void PBRMaterialEditor::HandleNodeEditorInteractions() +{ + // ========== 1. 创建连线 ========== + if (ed::BeginCreate()) + { + ed::PinId startId, endId; + if (ed::QueryNewLink(&startId, &endId)) + { + if (startId && endId) + { + int start = (int)startId.Get(); + int end = (int)endId.Get(); + + bool startIsOutput = (start / 100 >= 2) && (start % 100 == 1); + bool endIsInput = (end / 100 == OUTPUT_NODE_ID) && (end % 100 >= 1 && end % 100 <= 5); + + if (!startIsOutput || !endIsInput) + { + std::swap(start, end); + startIsOutput = (start / 100 >= 2) && (start % 100 == 1); + endIsInput = (end / 100 == OUTPUT_NODE_ID) && (end % 100 >= 1 && end % 100 <= 5); + } + + if (startIsOutput && endIsInput) + { + int pinType = end % 100; + if (!IsPinLinked(end)) + { + if (ed::AcceptNewItem(GetPinColor(pinType), 2.0f)) + { + m_Links.push_back({m_NextLinkId++, start, end}); + m_Asset->IsDirty = true; + } + } + else + ed::RejectNewItem(ImVec4(1, 0, 0, 1), 2.0f); + } + else + ed::RejectNewItem(ImVec4(1, 0, 0, 1), 2.0f); + } + } + } + ed::EndCreate(); + + // ========== 2. 删除连线/节点 ========== + if (ed::BeginDelete()) + { + ed::LinkId linkId; + while (ed::QueryDeletedLink(&linkId)) + { + if (ed::AcceptDeletedItem()) + { + int id = (int)linkId.Get(); + m_Links.erase(std::remove_if(m_Links.begin(), m_Links.end(), + [id](const Link& l) { return l.ID == id; }), m_Links.end()); + m_Asset->IsDirty = true; + } + } + + ed::NodeId nodeId; + while (ed::QueryDeletedNode(&nodeId)) + { + int id = (int)nodeId.Get(); + if (id == OUTPUT_NODE_ID) + ed::RejectDeletedItem(); + else if (ed::AcceptDeletedItem()) + { + int outPin = OutputPinID(id); + m_Links.erase(std::remove_if(m_Links.begin(), m_Links.end(), + [outPin](const Link& l) { return l.StartPinID == outPin; }), + m_Links.end()); + m_TextureNodes.erase(std::remove_if(m_TextureNodes.begin(), m_TextureNodes.end(), + [id](const TextureNode& n) { return n.ID == id; }), + m_TextureNodes.end()); + m_Asset->IsDirty = true; + } + } + } + ed::EndDelete(); + + + ed::Suspend(); + + if (ed::ShowBackgroundContextMenu()) + ImGui::OpenPopup("NodeEditorContextMenu"); + + ed::NodeId contextNodeId; + if (ed::ShowNodeContextMenu(&contextNodeId)) + { + m_ContextMenuNodeId = (int)contextNodeId.Get(); + ImGui::OpenPopup("NodeContextMenu"); + } + + + if (ImGui::BeginPopup("NodeEditorContextMenu")) + { + if (ImGui::MenuItem("Add Texture2D Node")) + { + int newId = m_NextNodeId++; + float yOffset = m_TextureNodes.size() * 170.0f; + m_TextureNodes.push_back({newId, AssetHandle(0), 50.0f, yOffset}); + m_FirstFrame = true; + } + ImGui::EndPopup(); + } + + if (ImGui::BeginPopup("NodeContextMenu")) + { + int id = m_ContextMenuNodeId; + if (id != OUTPUT_NODE_ID) + { + if (ImGui::MenuItem("Delete Node")) + { + int outPin = OutputPinID(id); + m_Links.erase(std::remove_if(m_Links.begin(), m_Links.end(), + [outPin](const Link& l) { return l.StartPinID == outPin; }), + m_Links.end()); + m_TextureNodes.erase(std::remove_if(m_TextureNodes.begin(), m_TextureNodes.end(), + [id](const TextureNode& n) { return n.ID == id; }), + m_TextureNodes.end()); + m_Asset->IsDirty = true; + } + } + else + ImGui::TextDisabled("Cannot delete output node"); + ImGui::EndPopup(); + } + + if (m_OpenAlbedoPicker) + { + ImGui::OpenPopup("AlbedoColorPicker"); + m_OpenAlbedoPicker = false; + } + if (ImGui::BeginPopup("AlbedoColorPicker")) + { + if (ImGui::ColorPicker3("##picker", glm::value_ptr(m_Asset->AlbedoColor))) + m_Asset->IsDirty = true; + ImGui::EndPopup(); + } + + ed::Resume(); +} + + bool PBRMaterialEditor::IsPinLinked(int pinId) const + { + for (const auto& link : m_Links) + if (link.StartPinID == pinId || link.EndPinID == pinId) + return true; + return false; + } + + AssetHandle PBRMaterialEditor::GetLinkedTextureHandle(int inputPinId) const + { + for (const auto& link : m_Links) + { + if (link.EndPinID == inputPinId) + { + int nodeId = link.StartPinID / 100; + for (const auto& node : m_TextureNodes) + if (node.ID == nodeId) + return node.TextureHandle; + } + } + return AssetHandle(0); + } + + void PBRMaterialEditor::CompileMaterialToAsset() + { + if (!m_Asset) return; + + auto getTexture = [](AssetHandle handle) -> Ref { + if (handle == 0) return nullptr; + return AssetsManager::GetAsset(handle); + }; + + m_Asset->AlbedoTexture = getTexture(GetLinkedTextureHandle(InputPinID(Albedo))); + m_Asset->AlbedoTexToggle = m_Asset->AlbedoTexture ? 1.0f : 0.0f; + + m_Asset->NormalTexture = getTexture(GetLinkedTextureHandle(InputPinID(Normal))); + m_Asset->NormalTexToggle = m_Asset->NormalTexture ? 1.0f : 0.0f; + + m_Asset->MetalnessTexture = getTexture(GetLinkedTextureHandle(InputPinID(Metallic))); + m_Asset->MetalnessTexToggle = m_Asset->MetalnessTexture ? 1.0f : 0.0f; + + m_Asset->RoughnessTexture = getTexture(GetLinkedTextureHandle(InputPinID(Roughness))); + m_Asset->RoughnessTexToggle = m_Asset->RoughnessTexture ? 1.0f : 0.0f; + + m_Asset->IsDirty = true; + } + + void PBRMaterialEditor::LoadAssetToGraph() + { + if (!m_Asset) return; + + m_TextureNodes.clear(); + m_Links.clear(); + m_NextNodeId = 2; + m_NextLinkId = 1; + + // 辅助 lambda:从 Ref 获取 AssetHandle + auto getHandle = [](const Ref& tex) -> AssetHandle { + return tex ? tex->Handle : AssetHandle(0); + }; + + auto addTextureNode = [&](AssetHandle handle, PinType pinType, float yPos) { + if (handle != 0) + { + int id = m_NextNodeId++; + m_TextureNodes.push_back({id, handle, 50.0f, yPos}); + m_Links.push_back({m_NextLinkId++, OutputPinID(id), InputPinID(pinType)}); + } + }; + + addTextureNode(getHandle(m_Asset->AlbedoTexture), Albedo, 0.0f); + addTextureNode(getHandle(m_Asset->NormalTexture), Normal, 150.0f); + addTextureNode(getHandle(m_Asset->MetalnessTexture), Metallic, 300.0f); + addTextureNode(getHandle(m_Asset->RoughnessTexture), Roughness, 450.0f); + + m_FirstFrame = true; + } +} diff --git a/Prism/src/Prism/Editor/DefaultAssetEditors/PBRMaterialAssetEditor.h b/Prism/src/Prism/Editor/DefaultAssetEditors/PBRMaterialAssetEditor.h new file mode 100644 index 0000000..4c1ed31 --- /dev/null +++ b/Prism/src/Prism/Editor/DefaultAssetEditors/PBRMaterialAssetEditor.h @@ -0,0 +1,94 @@ +// +// Created by Atdunbg on 2026/2/14. +// + +#ifndef PRISM_PBRMATERIALASSETEDITOR_H +#define PRISM_PBRMATERIALASSETEDITOR_H + +#include "../AssetEditorPanel.h" +#include "Prism/Renderer/Texture.h" +#include "imgui_node_editor.h" + +namespace ed = ax::NodeEditor; + +namespace Prism +{ + class PBRMaterialEditor : public AssetEditor + { + public: + PBRMaterialEditor(); + ~PBRMaterialEditor(); + + Ref GetAsset() override { return m_Asset; } + void SetAsset(const Ref& asset) override; + + private: + // 原有成员 + Ref m_Asset; + ed::EditorContext* m_EditorContext = nullptr; + + // 原有渲染函数 + void Render() override; + void RenderBasicEditorPanel(); + + // ---------- 节点编辑器相关 ---------- + void RenderNodeEditorPanel(); // 新的节点编辑器面板 + void DrawOutputNode(); + void DrawTextureNode(int nodeId, AssetHandle& textureHandle); + void HandleNodeEditorInteractions(); + bool IsPinLinked(int pinId) const; + AssetHandle GetLinkedTextureHandle(int inputPinId) const; + void CompileMaterialToAsset(); // 将节点图数据写回 m_Asset + void LoadAssetToGraph(); // 从 m_Asset 加载数据到节点图 + + // 节点编辑器数据 + static constexpr int OUTPUT_NODE_ID = 1; + int m_NextNodeId = 2; + int m_NextLinkId = 1; + + struct TextureNode + { + int ID; + AssetHandle TextureHandle; + float PosX, PosY; + }; + + std::vector m_TextureNodes; + + struct Link + { + int ID; + int StartPinID; + int EndPinID; + }; + std::vector m_Links; + + // 编辑器状态 + bool m_FirstFrame = true; + bool m_OpenAlbedoPicker = false; + ImVec2 m_AlbedoPickerPos; + int m_ContextMenuNodeId = 0; + + // 引脚ID辅助函数 + static int InputPinID(int type) { return OUTPUT_NODE_ID * 100 + type; } + static int OutputPinID(int nodeId) { return nodeId * 100 + 1; } + + // 引脚类型枚举(与PBR材质对应) + enum PinType + { + Albedo = 1, + Normal, + Metallic, + Roughness, + AO + }; + + // 从 MaterialEditorPanel 借用的工具函数 + static ImColor GetPinColor(int pinType); + static void DrawPinIcon(bool connected, int alpha, int pinType); + static void DrawOutputPinIcon(bool connected, int alpha); + float DrawNodeHeader(const char* title, float minWidth); + }; +} + +#endif //PRISM_PBRMATERIALASSETEDITOR_H \ No newline at end of file diff --git a/Prism/src/Prism/Editor/DefaultAssetEditors/PhysicsMaterialEditor.cpp b/Prism/src/Prism/Editor/DefaultAssetEditors/PhysicsMaterialEditor.cpp new file mode 100644 index 0000000..20cf63b --- /dev/null +++ b/Prism/src/Prism/Editor/DefaultAssetEditors/PhysicsMaterialEditor.cpp @@ -0,0 +1,35 @@ +// +// Created by Atdunbg on 2026/4/8. +// + +#include "PhysicsMaterialEditor.h" + +#include "Prism/Asset/AssetSerializer.h" + +namespace Prism +{ + + PhysicsMaterialEditor::PhysicsMaterialEditor() + : AssetEditor("Edit Physics Material") {} + + void PhysicsMaterialEditor::SetAsset(const Ref& asset) + { + if (m_Asset) AssetSerializer::SerializeAsset(m_Asset); + m_Asset = static_cast>(asset); + } + + void PhysicsMaterialEditor::Render() + { + if (!m_Asset) + SetOpen(false); + + UI::BeginPropertyGrid(); + UI::Property("Static Friction", m_Asset->StaticFriction); + UI::Property("Dynamic Friction", m_Asset->DynamicFriction); + UI::Property("Bounciness", m_Asset->Bounciness); + UI::EndPropertyGrid(); + + if (ImGui::Button("Save")) + AssetSerializer::SerializeAsset(m_Asset); + } +} diff --git a/Prism/src/Prism/Editor/DefaultAssetEditors/PhysicsMaterialEditor.h b/Prism/src/Prism/Editor/DefaultAssetEditors/PhysicsMaterialEditor.h new file mode 100644 index 0000000..93f1efd --- /dev/null +++ b/Prism/src/Prism/Editor/DefaultAssetEditors/PhysicsMaterialEditor.h @@ -0,0 +1,32 @@ +// +// Created by Atdunbg on 2026/4/8. +// + +#ifndef PRISM_PHYSICSMATERIALEDITOR_H +#define PRISM_PHYSICSMATERIALEDITOR_H +#include "Prism/Core/Ref.h" +#include "Prism/Editor/AssetEditorPanel.h" + + +namespace Prism +{ + class PhysicsMaterialAsset; + + class PhysicsMaterialEditor : public AssetEditor + { + public: + PhysicsMaterialEditor(); + + Ref GetAsset() override { return m_Asset; } + void SetAsset(const Ref& asset) override; + + private: + void Render() override; + + private: + Ref m_Asset; + }; +} + + +#endif //PRISM_PHYSICSMATERIALEDITOR_H \ No newline at end of file diff --git a/Prism/src/Prism/Editor/DefaultAssetEditors/TextureAssetEditor.cpp b/Prism/src/Prism/Editor/DefaultAssetEditors/TextureAssetEditor.cpp new file mode 100644 index 0000000..021637c --- /dev/null +++ b/Prism/src/Prism/Editor/DefaultAssetEditors/TextureAssetEditor.cpp @@ -0,0 +1,46 @@ +// +// Created by Atdunbg on 2026/4/8. +// + +#include "TextureAssetEditor.h" + +#include "Prism/Renderer/Texture.h" +#include "Prism/Asset/AssetSerializer.h" + +namespace Prism +{ + + TextureViewer::TextureViewer() + : AssetEditor("Edit Texture") + { + SetMinSize(200, 600); + SetMaxSize(500, 1000); + } + + void TextureViewer::SetAsset(const Ref& asset) + { + if (m_Asset) AssetSerializer::SerializeAsset(m_Asset); + m_Asset = static_cast>(asset); + } + + void TextureViewer::Render() + { + if (!m_Asset) + SetOpen(false); + + float textureWidth = (float)m_Asset->GetWidth(); + float textureHeight = (float)m_Asset->GetHeight(); + float bitsPerPixel = (float)Texture::GetBPP(m_Asset->GetFormat()); + float imageSize = ImGui::GetWindowWidth() - 40; + imageSize = glm::min(imageSize, 500.0f); + + ImGui::SetCursorPosX(20); + ImGui::Image((ImTextureID)m_Asset->GetRendererID(), {imageSize, imageSize}); + + UI::BeginPropertyGrid(); + UI::Property("Width", textureWidth, 0.1f, 0.0f, 0.0f, true); + UI::Property("Height", textureHeight, 0.1f, 0.0f, 0.0f, true); + UI::Property("Bits", bitsPerPixel, 0.1f, 0.0f, 0.0f, true); + UI::EndPropertyGrid(); + } +} diff --git a/Prism/src/Prism/Editor/DefaultAssetEditors/TextureAssetEditor.h b/Prism/src/Prism/Editor/DefaultAssetEditors/TextureAssetEditor.h new file mode 100644 index 0000000..55801c1 --- /dev/null +++ b/Prism/src/Prism/Editor/DefaultAssetEditors/TextureAssetEditor.h @@ -0,0 +1,31 @@ +// +// Created by Atdunbg on 2026/4/8. +// + +#ifndef PRISM_TEXTUREASSETEDITOR_H +#define PRISM_TEXTUREASSETEDITOR_H +#include "Prism/Editor/AssetEditorPanel.h" + +namespace Prism +{ + class Texture; + + class TextureViewer : public AssetEditor + { + public: + TextureViewer(); + + Ref GetAsset() override { return m_Asset; } + void SetAsset(const Ref& asset) override; + + private: + void Render() override; + + private: + Ref m_Asset; + }; + +} + + +#endif //PRISM_TEXTUREASSETEDITOR_H \ No newline at end of file diff --git a/Prism/vendor/imgui-node-editor b/Prism/vendor/imgui-node-editor new file mode 160000 index 0000000..021aa0e --- /dev/null +++ b/Prism/vendor/imgui-node-editor @@ -0,0 +1 @@ +Subproject commit 021aa0ea4da13fed864bafb2a92d4c5205076866