diff --git a/Editor/Editor/EditorLayer.cpp b/Editor/Editor/EditorLayer.cpp index 78ef6cb..ce61a6a 100644 --- a/Editor/Editor/EditorLayer.cpp +++ b/Editor/Editor/EditorLayer.cpp @@ -15,6 +15,7 @@ #include "Prism/Physics/Physics3D.h" #include "Prism/Renderer/Renderer2D.h" #include "Prism/Script/ScriptEngine.h" +#include "Prism/Utilities/DragDropData.h" namespace Prism { @@ -171,6 +172,9 @@ namespace Prism m_SceneHierarchyPanel->SetEntityDeletedCallback(std::bind(&EditorLayer::OnEntityDeleted, this, std::placeholders::_1)); UpdateWindowTitle("untitled Scene"); + m_AssetManagerPanel = CreateScope(); + m_ObjectsPanel = CreateScope(); + // OpenScene("assets/scenes/FPSDemo.scene"); NewScene(); } @@ -654,6 +658,9 @@ namespace Prism if (m_UIShowBoundingBoxes && Property("On Top", m_UIShowBoundingBoxesOnTop)) ShowBoundingBoxes(m_UIShowBoundingBoxes, m_UIShowBoundingBoxesOnTop); + m_AssetManagerPanel->OnImGuiRender(); + m_ObjectsPanel->OnImGuiRender(); + const char* label = m_SelectionMode == SelectionMode::Entity ? "Entity" : "Mesh"; if (ImGui::Button(label)) { @@ -835,6 +842,44 @@ namespace Prism } } + if (ImGui::BeginDragDropTarget()) + { + auto payload = ImGui::AcceptDragDropPayload("scene_entity_objectP"); + if (payload) + { + const auto data = (DragDropData*)payload->Data; + if (std::string_view(data->Type) == "Mesh") + { + auto entity = m_EditorScene->CreateEntity(data->Name); + entity.AddComponent(Ref::Create(data->SourcePath)); + } + } + ImGui::EndDragDropTarget(); + } + + /* Payload Implementation For Getting Assets In The Viewport From Asset Manager */ + if (ImGui::BeginDragDropTarget()) + { + auto payload = ImGui::AcceptDragDropPayload("scene_entity_assetsP"); + if (payload) + { + auto data = (DragDropData*)payload->Data; + + if (std::string_view(data->Type) == "PrismScene") + { + auto sceneName = data->SourcePath; + OpenScene(sceneName); + } + + if (std::string_view(data->Type) == "Mesh") + { + auto entity = m_EditorScene->CreateEntity(data->Name); + entity.AddComponent(Ref::Create(data->SourcePath)); + } + } + ImGui::EndDragDropTarget(); + } + ImGui::End(); ImGui::PopStyleVar(); } diff --git a/Editor/Editor/EditorLayer.h b/Editor/Editor/EditorLayer.h index cc9a011..02bb0ef 100644 --- a/Editor/Editor/EditorLayer.h +++ b/Editor/Editor/EditorLayer.h @@ -6,6 +6,8 @@ #define EDITORLAYER_H #include "Prism.h" +#include "Prism/Editor/AssetsManagerPanel.h" +#include "Prism/Editor/ObjectsPanel.h" #include "Prism/Editor/SceneHierachyPanel.h" namespace Prism @@ -56,6 +58,8 @@ namespace Prism float GetSnapValue() const; private: Scope m_SceneHierarchyPanel; + Scope m_AssetManagerPanel; + Scope m_ObjectsPanel; Ref m_ActiveScene; Ref m_RuntimeScene, m_EditorScene; diff --git a/Editor/assets/editor/asset.png b/Editor/assets/editor/asset.png new file mode 100644 index 0000000..2e3d430 Binary files /dev/null and b/Editor/assets/editor/asset.png differ diff --git a/Editor/assets/editor/back.png b/Editor/assets/editor/back.png new file mode 100644 index 0000000..bc00e55 Binary files /dev/null and b/Editor/assets/editor/back.png differ diff --git a/Editor/assets/editor/blend.png b/Editor/assets/editor/blend.png new file mode 100644 index 0000000..eb5d649 Binary files /dev/null and b/Editor/assets/editor/blend.png differ diff --git a/Editor/assets/editor/btn_back.png b/Editor/assets/editor/btn_back.png new file mode 100644 index 0000000..9d36298 Binary files /dev/null and b/Editor/assets/editor/btn_back.png differ diff --git a/Editor/assets/editor/btn_fwrd.png b/Editor/assets/editor/btn_fwrd.png new file mode 100644 index 0000000..ad28796 Binary files /dev/null and b/Editor/assets/editor/btn_fwrd.png differ diff --git a/Editor/assets/editor/close.png b/Editor/assets/editor/close.png new file mode 100644 index 0000000..0e6da36 Binary files /dev/null and b/Editor/assets/editor/close.png differ diff --git a/Editor/assets/editor/csc.png b/Editor/assets/editor/csc.png new file mode 100644 index 0000000..5899194 Binary files /dev/null and b/Editor/assets/editor/csc.png differ diff --git a/Editor/assets/editor/favourites.png b/Editor/assets/editor/favourites.png new file mode 100644 index 0000000..57bad2b Binary files /dev/null and b/Editor/assets/editor/favourites.png differ diff --git a/Editor/assets/editor/fbx.png b/Editor/assets/editor/fbx.png new file mode 100644 index 0000000..6c29d23 Binary files /dev/null and b/Editor/assets/editor/fbx.png differ diff --git a/Editor/assets/editor/file.png b/Editor/assets/editor/file.png new file mode 100644 index 0000000..146e1e2 Binary files /dev/null and b/Editor/assets/editor/file.png differ diff --git a/Editor/assets/editor/folder.png b/Editor/assets/editor/folder.png new file mode 100644 index 0000000..62cff34 Binary files /dev/null and b/Editor/assets/editor/folder.png differ diff --git a/Editor/assets/editor/folder_hierarchy.png b/Editor/assets/editor/folder_hierarchy.png new file mode 100644 index 0000000..2324cbe Binary files /dev/null and b/Editor/assets/editor/folder_hierarchy.png differ diff --git a/Editor/assets/editor/grid.png b/Editor/assets/editor/grid.png new file mode 100644 index 0000000..7a0c80d Binary files /dev/null and b/Editor/assets/editor/grid.png differ diff --git a/Editor/assets/editor/list.png b/Editor/assets/editor/list.png new file mode 100644 index 0000000..d1e7932 Binary files /dev/null and b/Editor/assets/editor/list.png differ diff --git a/Editor/assets/editor/obj.png b/Editor/assets/editor/obj.png new file mode 100644 index 0000000..777cfa6 Binary files /dev/null and b/Editor/assets/editor/obj.png differ diff --git a/Editor/assets/editor/png.png b/Editor/assets/editor/png.png new file mode 100644 index 0000000..ff6a814 Binary files /dev/null and b/Editor/assets/editor/png.png differ diff --git a/Editor/assets/editor/resource.png b/Editor/assets/editor/resource.png new file mode 100644 index 0000000..feafb29 Binary files /dev/null and b/Editor/assets/editor/resource.png differ diff --git a/Editor/assets/editor/scene.png b/Editor/assets/editor/scene.png new file mode 100644 index 0000000..32f9d45 Binary files /dev/null and b/Editor/assets/editor/scene.png differ diff --git a/Editor/assets/editor/script.png b/Editor/assets/editor/script.png new file mode 100644 index 0000000..05f8240 Binary files /dev/null and b/Editor/assets/editor/script.png differ diff --git a/Editor/assets/editor/search.png b/Editor/assets/editor/search.png new file mode 100644 index 0000000..42fc35b Binary files /dev/null and b/Editor/assets/editor/search.png differ diff --git a/Editor/assets/editor/tags.png b/Editor/assets/editor/tags.png new file mode 100644 index 0000000..28ca63a Binary files /dev/null and b/Editor/assets/editor/tags.png differ diff --git a/Editor/assets/editor/wav.png b/Editor/assets/editor/wav.png new file mode 100644 index 0000000..58e8995 Binary files /dev/null and b/Editor/assets/editor/wav.png differ diff --git a/Editor/assets/meshes/Capsule.fbx b/Editor/assets/meshes/Default/Capsule.fbx similarity index 100% rename from Editor/assets/meshes/Capsule.fbx rename to Editor/assets/meshes/Default/Capsule.fbx diff --git a/Editor/assets/meshes/Default/Cone.fbx b/Editor/assets/meshes/Default/Cone.fbx new file mode 100644 index 0000000..5b03788 Binary files /dev/null and b/Editor/assets/meshes/Default/Cone.fbx differ diff --git a/Editor/assets/meshes/Default/Cube.fbx b/Editor/assets/meshes/Default/Cube.fbx new file mode 100644 index 0000000..b1a5bba Binary files /dev/null and b/Editor/assets/meshes/Default/Cube.fbx differ diff --git a/Editor/assets/meshes/Default/Cylinder.fbx b/Editor/assets/meshes/Default/Cylinder.fbx new file mode 100644 index 0000000..cd4c743 Binary files /dev/null and b/Editor/assets/meshes/Default/Cylinder.fbx differ diff --git a/Editor/assets/meshes/Default/Plane.fbx b/Editor/assets/meshes/Default/Plane.fbx new file mode 100644 index 0000000..359470b Binary files /dev/null and b/Editor/assets/meshes/Default/Plane.fbx differ diff --git a/Editor/assets/meshes/Default/Sphere.fbx b/Editor/assets/meshes/Default/Sphere.fbx new file mode 100644 index 0000000..981eefc Binary files /dev/null and b/Editor/assets/meshes/Default/Sphere.fbx differ diff --git a/Editor/assets/meshes/Default/Torus.fbx b/Editor/assets/meshes/Default/Torus.fbx new file mode 100644 index 0000000..398dc0f Binary files /dev/null and b/Editor/assets/meshes/Default/Torus.fbx differ diff --git a/Editor/imgui.ini b/Editor/imgui.ini new file mode 100644 index 0000000..ac066b7 --- /dev/null +++ b/Editor/imgui.ini @@ -0,0 +1,96 @@ +[Window][DockSpace Demo] +Pos=0,0 +Size=2066,1198 +Collapsed=0 + +[Window][Debug##Default] +Pos=60,60 +Size=400,400 +Collapsed=0 + +[Window][Scene Hierarchy] +Pos=1595,24 +Size=471,428 +Collapsed=0 +DockId=0x00000009,0 + +[Window][Properties] +Pos=1595,454 +Size=471,744 +Collapsed=0 +DockId=0x0000000A,0 + +[Window][Scene Renderer] +Pos=0,648 +Size=481,550 +Collapsed=0 +DockId=0x00000006,0 + +[Window][Materials] +Pos=0,24 +Size=481,622 +Collapsed=0 +DockId=0x00000005,0 + +[Window][Script Engine Debug] +Pos=1595,454 +Size=471,744 +Collapsed=0 +DockId=0x0000000A,2 + +[Window][Model] +Pos=1595,454 +Size=471,744 +Collapsed=0 +DockId=0x0000000A,3 + +[Window][Toolbar] +Pos=483,24 +Size=1110,32 +Collapsed=0 +DockId=0x00000001,0 + +[Window][Viewport] +Pos=483,58 +Size=1110,722 +Collapsed=0 +DockId=0x0000000B,0 + +[Window][Environment] +Pos=1595,454 +Size=471,744 +Collapsed=0 +DockId=0x0000000A,1 + +[Window][Project] +Pos=483,782 +Size=1110,416 +Collapsed=0 +DockId=0x0000000C,0 + +[Window][Objects] +Pos=483,782 +Size=1110,416 +Collapsed=0 +DockId=0x0000000C,1 + +[Window][Physics] +Pos=189,113 +Size=468,371 +Collapsed=0 + +[Docking][Data] +DockSpace ID=0xC0DFADC4 Window=0xD0388BC8 Pos=150,89 Size=2066,1174 Split=X Selected=0x0C01D6D5 + DockNode ID=0x00000007 Parent=0xC0DFADC4 SizeRef=1557,1542 Split=X + DockNode ID=0x00000003 Parent=0x00000007 SizeRef=481,1542 Split=Y Selected=0x5D711C2C + DockNode ID=0x00000005 Parent=0x00000003 SizeRef=481,817 Selected=0x5D711C2C + DockNode ID=0x00000006 Parent=0x00000003 SizeRef=481,723 Selected=0x68D924E0 + DockNode ID=0x00000004 Parent=0x00000007 SizeRef=1074,1542 Split=Y + DockNode ID=0x00000001 Parent=0x00000004 SizeRef=2560,32 CentralNode=1 HiddenTabBar=1 Selected=0x0C01D6D5 + DockNode ID=0x00000002 Parent=0x00000004 SizeRef=2560,1508 Split=Y Selected=0xC450F867 + DockNode ID=0x0000000B Parent=0x00000002 SizeRef=1401,669 HiddenTabBar=1 Selected=0xC450F867 + DockNode ID=0x0000000C Parent=0x00000002 SizeRef=1401,386 Selected=0x9C21DE82 + DockNode ID=0x00000008 Parent=0xC0DFADC4 SizeRef=471,1542 Split=Y Selected=0x8C72BEA8 + DockNode ID=0x00000009 Parent=0x00000008 SizeRef=315,563 Selected=0xB8729153 + DockNode ID=0x0000000A Parent=0x00000008 SizeRef=315,977 Selected=0x73E3D51F + diff --git a/Prism/src/Prism/Editor/AssetsManagerPanel.cpp b/Prism/src/Prism/Editor/AssetsManagerPanel.cpp new file mode 100644 index 0000000..5e0b3e4 --- /dev/null +++ b/Prism/src/Prism/Editor/AssetsManagerPanel.cpp @@ -0,0 +1,516 @@ +// +// Created by Atdunbg on 2026/1/20. +// + +#include "AssetsManagerPanel.h" + +#include + +#include "Prism/Core/Application.h" +#include "Prism/Utilities/DragDropData.h" + +namespace Prism +{ + AssetsManagerPanel::AssetsManagerPanel() + { + AssetTypes::Init(); + + m_FolderTex = Texture2D::Create("assets/editor/folder.png"); + m_FavoritesTex = Texture2D::Create("assets/editor/favourites.png"); + m_GoBackTex = Texture2D::Create("assets/editor/back.png"); + m_ScriptTex = Texture2D::Create("assets/editor/script.png"); + m_ResourceTex = Texture2D::Create("assets/editor/resource.png"); + m_SceneTex = Texture2D::Create("assets/editor/scene.png"); + + m_AssetIconMap[-1] = Texture2D::Create("assets/editor/file.png"); + m_AssetIconMap[AssetTypes::GetAssetTypeID("fbx")] = Texture2D::Create("assets/editor/fbx.png"); + m_AssetIconMap[AssetTypes::GetAssetTypeID("obj")] = Texture2D::Create("assets/editor/obj.png"); + m_AssetIconMap[AssetTypes::GetAssetTypeID("wav")] = Texture2D::Create("assets/editor/wav.png"); + m_AssetIconMap[AssetTypes::GetAssetTypeID("cs")] = Texture2D::Create("assets/editor/csc.png"); + m_AssetIconMap[AssetTypes::GetAssetTypeID("png")] = Texture2D::Create("assets/editor/png.png"); + m_AssetIconMap[AssetTypes::GetAssetTypeID("blend")] = Texture2D::Create("assets/editor/blend.png"); + + // TODO: get a logo for this project + m_AssetIconMap[AssetTypes::GetAssetTypeID("scene")] = Texture2D::Create("assets/editor/asset.png"); + + m_BackbtnTex = Texture2D::Create("assets/editor/btn_back.png"); + m_FwrdbtnTex = Texture2D::Create("assets/editor/btn_fwrd.png"); + m_FolderRightTex = Texture2D::Create("assets/editor/folder_hierarchy.png"); + m_SearchTex = Texture2D::Create("assets/editor/search.png"); + m_TagsTex = Texture2D::Create("assets/editor/tags.png"); + m_GridView = Texture2D::Create("assets/editor/grid.png"); + m_ListView = Texture2D::Create("assets/editor/list.png"); + + m_BaseDirPath = "assets"; + m_CurrentDirPath = m_BaseDirPath; + m_PrevDirPath = m_CurrentDirPath; + m_BaseProjectDir = m_AssetManager.GetFileSystemContents(); + m_CurrentDir = m_BaseProjectDir; + m_BasePathLen = static_cast(strlen(m_BaseDirPath.c_str())); + m_DirDataLen = 0; + + memset(m_InputBuffer, 0, sizeof(m_InputBuffer)); + } + + void AssetsManagerPanel::OnImGuiRender() + { + ImGui::Begin("Project", nullptr, ImGuiWindowFlags_MenuBar); + { + UI::BeginPropertyGrid(); + ImGui::SetColumnOffset(1, 200); + + // There happens to be recursive tree unfolding issue which doesn't show nested directories/files + ImGui::BeginChild("##folders_common"); + { + if (ImGui::CollapsingHeader("res://", nullptr, ImGuiTreeNodeFlags_DefaultOpen)) + { + if (ImGui::TreeNode("Contents")) + { + for (int i = 0; i < m_BaseProjectDir.size(); i++) + { + if (ImGui::TreeNode(m_BaseProjectDir[i].Filename.c_str())) + { + auto dirData = m_AssetManager.GetDirectoryContents(m_BaseProjectDir[i].AbsolutePath); + for (int j = 0; j < dirData.size(); j++) + { + if (!dirData[j].IsFile) + { + if (ImGui::TreeNode(dirData[j].Filename.c_str())) + ImGui::TreePop(); + } + else + { + std::string parentDir = m_AssetManager.GetParentPath(dirData[j].AbsolutePath); + ImGui::Indent(); + ImGui::Selectable(dirData[j].Filename.c_str(), false); + ImGui::Unindent(); + } + } + ImGui::TreePop(); + } + + if (m_IsDragging && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem)) + { + m_MovePath = m_BaseProjectDir[i].AbsolutePath.c_str(); + } + } + ImGui::TreePop(); + } + + if (ImGui::IsMouseDown(1)) + { + //ImGui::OpenPopup("window"); + } + } + + ImGui::EndChild(); + } + + if (ImGui::BeginDragDropTarget()) + { + const auto data = ImGui::AcceptDragDropPayload("selectable", ImGuiDragDropFlags_AcceptNoDrawDefaultRect); + if (data) + { + const std::filesystem::path file = static_cast(data->Data); + if (m_AssetManager.MoveFile(file, m_MovePath)) + { + PM_CORE_INFO("Moved File: " + file.string() + " to " + m_MovePath); + m_CurrentDir = m_AssetManager.GetDirectoryContents(m_CurrentDirPath); + } + m_IsDragging = false; + } + ImGui::EndDragDropTarget(); + } + + ImGui::NextColumn(); + + ImGui::BeginChild("##directory_structure", ImVec2(ImGui::GetColumnWidth() - 12, ImGui::GetWindowHeight() - 50)); + { + RenderBreadCrumbs(); + ImGui::SameLine(); + ImGui::Dummy(ImVec2(ImGui::GetColumnWidth() - 350, 0)); + ImGui::SameLine(); + RenderSearch(); + ImGui::EndChild(); + + ImGui::BeginChild("Scrolling"); + + if (!m_DisplayListView) + ImGui::Columns(10, nullptr, false); + + for (int i = 0; i < m_CurrentDir.size(); i++) + { + if (!m_CurrentDir.empty()) + { + if (!m_DisplayListView) + m_CurrentDir[i].IsFile ? RenderFileGridView(i) : RenderDirectoriesGridView(i); + else + m_CurrentDir[i].IsFile ? RenderFileListView(i) : RenderDirectoriesListView(i); + + ImGui::NextColumn(); + } + } + + if (ImGui::BeginPopupContextWindow("Creating")) + { + if (ImGui::BeginMenu("New")) + { + if (ImGui::MenuItem("Folder")) + { + PM_CORE_INFO("Creating Folder..."); + } + + if (ImGui::MenuItem("Scene")) + { + PM_CORE_INFO("Creating Scene..."); + } + + if (ImGui::MenuItem("Script")) + { + PM_CORE_INFO("Creating Script..."); + } + + if (ImGui::MenuItem("Prefab")) + { + PM_CORE_INFO("Creating Prefab..."); + } + + if (ImGui::BeginMenu("Shaders")) + { + if (ImGui::MenuItem("Shader")) + { + PM_CORE_INFO("Creating Shader File..."); + } + + if (ImGui::MenuItem("Shader Graph")) + { + PM_CORE_INFO("Creating Shader Graph..."); + } + + ImGui::EndMenu(); + } + + ImGui::EndMenu(); + } + + ImGui::EndPopup(); + } + + + ImGui::EndChild(); + ImGui::EndChild(); + } + + if (ImGui::BeginDragDropTarget()) + { + const auto data = ImGui::AcceptDragDropPayload("selectable", ImGuiDragDropFlags_AcceptNoDrawDefaultRect); + if (data) + { + const std::string a = static_cast(data->Data); + if (m_AssetManager.MoveFile(a, m_MovePath)) + { + PM_CORE_INFO("Moved File: " + a + " to " + m_MovePath); + } + m_IsDragging = false; + } + ImGui::EndDragDropTarget(); + } + + if (ImGui::BeginMenuBar()) + { + if (ImGui::BeginMenu("Create")) + { + if (ImGui::MenuItem("Import New Asset", "Ctrl + O")) + { + const std::string filename = Application::Get().OpenFile(""); + m_AssetManager.ProcessAsset(filename); + } + + if (ImGui::MenuItem("Refresh", "Ctrl + R")) + { + auto data = m_AssetManager.GetFileSystemContents(); + for (auto & i : data) + { + PM_CORE_INFO("{0}", i.Filename); + } + } + + ImGui::EndMenu(); + } + ImGui::EndMenuBar(); + } + + UI::EndPropertyGrid(); + ImGui::End(); + } + } + + void AssetsManagerPanel::RenderFileListView(const int dirIndex) + { + const size_t fileID = AssetTypes::GetAssetTypeID(m_CurrentDir[dirIndex].FileType); + const RendererID iconRef = m_AssetIconMap[fileID]->GetRendererID(); + ImGui::Image((ImTextureID)iconRef, ImVec2(20, 20)); + + ImGui::SameLine(); + + if (ImGui::Selectable((m_CurrentDir[dirIndex].Filename + std::to_string(dirIndex)).c_str(), false, ImGuiSelectableFlags_AllowDoubleClick)) + { + if (ImGui::IsMouseDoubleClicked(0)) + m_AssetManager.HandleAsset(m_CurrentDir[dirIndex].AbsolutePath); + } + + HandleDragDrop(iconRef, dirIndex); + } + + void AssetsManagerPanel::RenderFileGridView(const int dirIndex) + { + ImGui::BeginGroup(); + + const size_t fileID = AssetTypes::GetAssetTypeID(m_CurrentDir[dirIndex].FileType); + const RendererID iconRef = m_AssetIconMap[fileID]->GetRendererID(); + const float columnWidth = ImGui::GetColumnWidth(); + + ImGui::ImageButton(std::string_view("##FileGridView" + std::to_string(dirIndex)).data(), (ImTextureID)iconRef, { columnWidth - 10.0F, columnWidth - 10.0F }); + + HandleDragDrop(iconRef, dirIndex); + + const std::string newFileName = m_AssetManager.StripExtras(m_CurrentDir[dirIndex].Filename); + ImGui::TextWrapped(newFileName.c_str()); + ImGui::EndGroup(); + } + + void AssetsManagerPanel::HandleDragDrop(RendererID icon, int dirIndex) + { + // Drag 'n' Drop Implementation For File Moving + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) + { + ImGui::Image((ImTextureID)icon, ImVec2(20, 20)); + ImGui::SameLine(); + ImGui::Text(m_CurrentDir[dirIndex].Filename.c_str()); + const int size = static_cast(sizeof(const char*) + strlen(m_CurrentDir[dirIndex].AbsolutePath.c_str())); + ImGui::SetDragDropPayload("selectable", m_CurrentDir[dirIndex].AbsolutePath.c_str(), size); + m_IsDragging = true; + ImGui::EndDragDropSource(); + } + + // Drag 'n' Drop Implementation For Asset Handling In Scene Viewport + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) + { + ImGui::Image((ImTextureID)icon, ImVec2(20, 20)); + ImGui::SameLine(); + ImGui::Text(m_CurrentDir[dirIndex].Filename.c_str()); + + const AssetType assetType = AssetTypes::GetAssetTypeFromExtension(m_CurrentDir[dirIndex].FileType); + + if (assetType == AssetType::Mesh) + { + const char* sourceType = m_CurrentDir[dirIndex].AbsolutePath.c_str(); + const char* name = m_CurrentDir[dirIndex].Filename.c_str(); + const char* type = "Mesh"; + + const DragDropData d(type, sourceType, name); + ImGui::SetDragDropPayload("scene_entity_assetsP", &d, sizeof(d)); + m_IsDragging = true; + } + + if (assetType == AssetType::Scene) + { + const char* sourceType = m_CurrentDir[dirIndex].AbsolutePath.c_str(); + const char* name = m_CurrentDir[dirIndex].Filename.c_str(); + const char* type = "PrismScene"; + + const DragDropData d(type, sourceType, name); + ImGui::SetDragDropPayload("scene_entity_assetsP", &d, sizeof(d)); + m_IsDragging = true; + } + + ImGui::EndDragDropSource(); + } + } + + void AssetsManagerPanel::RenderDirectoriesListView(int dirIndex) + { + ImGui::Image((ImTextureID)m_FolderTex->GetRendererID(), ImVec2(20, 20)); + ImGui::SameLine(); + + if (ImGui::Selectable(m_CurrentDir[dirIndex].Filename.c_str(), false, ImGuiSelectableFlags_AllowDoubleClick)) + { + if (ImGui::IsMouseDoubleClicked(0)) + { + m_PrevDirPath = m_CurrentDir[dirIndex].AbsolutePath; + m_CurrentDirPath = m_CurrentDir[dirIndex].AbsolutePath; + m_CurrentDir = m_AssetManager.GetDirectoryContents(m_CurrentDir[dirIndex].AbsolutePath); + } + } + + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_AcceptNoDrawDefaultRect)) + { + ImGui::Image((ImTextureID)m_FolderTex->GetRendererID(), ImVec2(20, 20)); + ImGui::SameLine(); + ImGui::Text(m_CurrentDir[dirIndex].Filename.c_str()); + const int size = static_cast(sizeof(const char*) + strlen(m_CurrentDir[dirIndex].AbsolutePath.c_str())); + ImGui::SetDragDropPayload("selectable", m_CurrentDir[dirIndex].AbsolutePath.c_str(), size); + m_IsDragging = true; + ImGui::EndDragDropSource(); + } + } + + void AssetsManagerPanel::RenderDirectoriesGridView(int dirIndex) + { + ImGui::BeginGroup(); + + const float columnWidth = ImGui::GetColumnWidth(); + ImGui::ImageButton(std::string_view("##RenderDirectoriesGridView" + std::to_string(dirIndex)).data(), (ImTextureID)m_FolderTex->GetRendererID(), { columnWidth - 10.0F, columnWidth - 10.0F }); + + if (ImGui::IsMouseDoubleClicked(0) && ImGui::IsItemHovered()) + { + m_PrevDirPath = m_CurrentDir[dirIndex].AbsolutePath; + m_CurrentDirPath = m_CurrentDir[dirIndex].AbsolutePath; + m_CurrentDir = m_AssetManager.GetDirectoryContents(m_CurrentDir[dirIndex].AbsolutePath); + m_IsPathChanged = true; + m_DirDataLen = static_cast(m_CurrentDir.size()); + } + + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_AcceptNoDrawDefaultRect)) + { + ImGui::Image((ImTextureID)m_FolderTex->GetRendererID(), ImVec2(20, 20)); + ImGui::SameLine(); + ImGui::Text(m_CurrentDir[dirIndex].Filename.c_str()); + const int size = static_cast(sizeof(const char*) + strlen(m_CurrentDir[dirIndex].AbsolutePath.c_str())); + ImGui::SetDragDropPayload("selectable", m_CurrentDir[dirIndex].AbsolutePath.c_str(), size); + m_IsDragging = true; + ImGui::EndDragDropSource(); + } + + if (!m_IsPathChanged) + { + const auto fname = m_CurrentDir[dirIndex].Filename; + const auto newFname = m_AssetManager.StripExtras(fname); + ImGui::TextWrapped(newFname.c_str()); + } + else + { + for (int i = 0; i < m_DirDataLen; i++) + { + const auto fname = m_CurrentDir[i].Filename; + const auto newFname = m_AssetManager.StripExtras(fname); + ImGui::TextWrapped(newFname.c_str()); + m_IsPathChanged = false; + m_DirDataLen = 0; + } + } + + ImGui::EndGroup(); + + } + + void AssetsManagerPanel::RenderBreadCrumbs() + { + ImGui::BeginChild("##directory_breadcrumbs", ImVec2(ImGui::GetColumnWidth() - 100, 30)); + { + const RendererID viewTexture = m_DisplayListView ? m_ListView->GetRendererID() : m_GridView->GetRendererID(); + if (ImGui::ImageButton((const char*)&viewTexture, (ImTextureID)viewTexture, ImVec2(20, 18))) + { + m_DisplayListView = !m_DisplayListView; + } + + ImGui::SameLine(); + + const auto searchTexID = m_SearchTex->GetRendererID(); + + if (ImGui::ImageButton((const char*)&searchTexID,(ImTextureID)searchTexID, ImVec2(20, 18))) + m_ShowSearchBar = !m_ShowSearchBar; + + ImGui::SameLine(); + + if (m_ShowSearchBar) + { + ImGui::SameLine(); + ImGui::PushItemWidth(200); + + if (ImGui::InputTextWithHint("##Search", "Search...", m_InputBuffer, 100, ImGuiInputTextFlags_EnterReturnsTrue)) + { + m_CurrentDir = m_AssetManager.SearchFiles(m_InputBuffer, m_CurrentDirPath); + } + + ImGui::PopItemWidth(); + ImGui::SameLine(); + } + + const auto backBtnTexID = m_BackbtnTex->GetRendererID(); + if (ImGui::ImageButton((const char*)&backBtnTexID,(ImTextureID)backBtnTexID, ImVec2(20, 18))) + { + if (strlen(m_CurrentDirPath.c_str()) == m_BasePathLen) return; + m_ForwardPath = m_CurrentDirPath; + m_BackPath = m_AssetManager.GetParentPath(m_CurrentDirPath); + m_CurrentDir = m_AssetManager.GetDirectoryContents(m_BackPath); + m_CurrentDirPath = m_BackPath; + } + + ImGui::SameLine(); + + const auto FwrdBtnTexID = m_FwrdbtnTex->GetRendererID(); + if (ImGui::ImageButton((const char*)&FwrdBtnTexID,(ImTextureID)FwrdBtnTexID, ImVec2(20, 18))) + { + if (m_ForwardPath.empty()) return; + m_CurrentDir = m_AssetManager.GetDirectoryContents(m_ForwardPath); + m_CurrentDirPath = m_ForwardPath; + } + + ImGui::SameLine(); + + const auto data = m_AssetManager.GetDirectories(m_CurrentDirPath); + + for (int i = 0; i < data.size(); i++) + { + if (data[i] != m_BaseDirPath) + { + ImGui::Image((ImTextureID)m_FolderRightTex->GetRendererID(), ImVec2(22, 23)); + } + + ImGui::SameLine(); + + /* Multiply the size of the folder name with 7(magic number) to set the size of selectable widget properly */ + const auto size = (float)(strlen(data[i].c_str()) * 7); + + if (ImGui::Selectable(data[i].c_str(), false, 0, ImVec2(size, 22))) + { + /* Increament 1 to the existing index value to fully iterate the array */ + const int index = i + 1; + std::string path; + + /* Use the below loop to build a path from the selected folder from the breadcrumb to navigate to */ + for (int e = 0; e < index; e++) + { + path += data[e] + "/\\"; + } + + m_CurrentDir = m_AssetManager.GetDirectoryContents(path); + m_CurrentDirPath = path; + } + ImGui::SameLine(); + } + + ImGui::SameLine(); + + ImGui::Dummy(ImVec2(ImGui::GetColumnWidth() - 400, 0)); + + ImGui::SameLine(); + } + } + + void AssetsManagerPanel::RenderSearch() + { + // TODO: not implemented + } + + void AssetsManagerPanel::RenderBottom() + { + /* Will be used for object select indication. Ex. 3 folders 1 file selected */ + ImGui::BeginChild("##nav", ImVec2(ImGui::GetColumnWidth() - 12, 23)); + { + ImGui::EndChild(); + } + } + +} diff --git a/Prism/src/Prism/Editor/AssetsManagerPanel.h b/Prism/src/Prism/Editor/AssetsManagerPanel.h new file mode 100644 index 0000000..c32d037 --- /dev/null +++ b/Prism/src/Prism/Editor/AssetsManagerPanel.h @@ -0,0 +1,78 @@ +// +// Created by Atdunbg on 2026/1/20. +// + +#ifndef PRISM_ASSETSMANAGERPANEL_H +#define PRISM_ASSETSMANAGERPANEL_H + +#include "Prism/Utilities/AssetsManager.h" +#include "Prism/Renderer/Texture.h" +#include "Prism/Core/ImGui/ImGui.h" + +namespace Prism +{ + class PRISM_API AssetsManagerPanel + { + public: + AssetsManagerPanel(); + void OnImGuiRender(); + + private: + void RenderFileListView(int dirIndex); + void RenderFileGridView(int dirIndex); + void HandleDragDrop(RendererID icon, int dirIndex); + void RenderDirectoriesListView(int dirIndex); + void RenderDirectoriesGridView(int dirIndex); + void RenderBreadCrumbs(); + void RenderSearch(); + void RenderBottom(); + + ImGuiInputTextCallback SearchCallback(ImGuiInputTextCallbackData* data); + + private: + Ref m_FolderTex; + Ref m_FavoritesTex; + Ref m_FileTex; + Ref m_GoBackTex; + Ref m_ScriptTex; + Ref m_ResourceTex; + Ref m_SceneTex; + + Ref m_BackbtnTex; + Ref m_FwrdbtnTex; + Ref m_FolderRightTex; + Ref m_TagsTex; + Ref m_SearchTex; + Ref m_GridView; + Ref m_ListView; + + std::string m_CurrentDirPath; + std::string m_BaseDirPath; + std::string m_PrevDirPath; + std::string m_MovePath; + + std::string m_ForwardPath; + std::string m_BackPath; + + int m_BasePathLen; + int m_DirDataLen; + + bool m_IsDragging = false; + bool m_DisplayListView = false; + bool m_UpdateBreadCrumbs = true; + bool m_ShowSearchBar = false; + bool m_IsPathChanged = false; + + char m_InputBuffer[1024]{}; + + std::vector m_CurrentDir; + std::vector m_BaseProjectDir; + + ImGuiInputTextCallbackData m_Data; + std::map> m_AssetIconMap; + //NotificationManager nManager; + AssetsManager m_AssetManager; + }; +} + +#endif //PRISM_ASSETSMANAGERPANEL_H \ No newline at end of file diff --git a/Prism/src/Prism/Editor/ObjectsPanel.cpp b/Prism/src/Prism/Editor/ObjectsPanel.cpp new file mode 100644 index 0000000..0969137 --- /dev/null +++ b/Prism/src/Prism/Editor/ObjectsPanel.cpp @@ -0,0 +1,151 @@ +// +// Created by Atdunbg on 2026/1/20. +// + +#include "ObjectsPanel.h" + + +#include "imgui.h" +#include "Prism/Utilities/DragDropData.h" + +namespace Prism +{ + ObjectsPanel::ObjectsPanel() + { + m_CubeImage = Texture2D::Create("assets/editor/asset.png"); + } + + void ObjectsPanel::OnImGuiRender() + { + ImGui::Begin("Objects", nullptr, ImGuiWindowFlags_None); + { + char buff[100] = {}; + const auto inputText = "InputText"; + const auto inputHint = "Start Typing To Search"; + ImGui::PushItemWidth(ImGui::GetWindowWidth() - 20); + ImGui::InputTextWithHint(inputText, inputHint, buff, 100); + + ImGui::BeginChild("##objects_window"); + { + ImGui::Image(m_CubeImage->GetRendererID(), ImVec2(30, 30)); + ImGui::SameLine(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5); + ImGui::Selectable("Cube"); + + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) + { + ImGui::Image(m_CubeImage->GetRendererID(), ImVec2(20, 20)); + ImGui::SameLine(); + + ImGui::Text("Cube"); + + const DragDropData data("Mesh", "assets/meshes/Default/Cube.fbx", "Cube"); + ImGui::SetDragDropPayload("scene_entity_objectP", &data, sizeof(data)); + ImGui::EndDragDropSource(); + } + + ImGui::Image((ImTextureID)m_CubeImage->GetRendererID(), ImVec2(30, 30)); + ImGui::SameLine(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5); + ImGui::Selectable("Capsule"); + + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) + { + ImGui::Image((ImTextureID)m_CubeImage->GetRendererID(), ImVec2(20, 20)); + ImGui::SameLine(); + + ImGui::Text("Capsule"); + + const DragDropData data("Mesh", "assets/meshes/Default/Capsule.fbx", "Capsule"); + ImGui::SetDragDropPayload("scene_entity_objectP", &data, sizeof(data)); + ImGui::EndDragDropSource(); + } + + ImGui::Image(m_CubeImage->GetRendererID(), ImVec2(30, 30)); + ImGui::SameLine(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5); + ImGui::Selectable("Sphere"); + + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) + { + ImGui::Image(m_CubeImage->GetRendererID(), ImVec2(20, 20)); + ImGui::SameLine(); + + ImGui::Text("Sphere"); + const DragDropData data("Mesh", "assets/meshes/Default/Sphere.fbx", "Sphere"); + ImGui::SetDragDropPayload("scene_entity_objectP", &data, sizeof(data)); + ImGui::EndDragDropSource(); + } + + ImGui::Image(m_CubeImage->GetRendererID(), ImVec2(30, 30)); + ImGui::SameLine(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5); + ImGui::Selectable("Cylinder"); + + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) + { + ImGui::Image(m_CubeImage->GetRendererID(), ImVec2(20, 20)); + ImGui::SameLine(); + + ImGui::Text("Cylinder"); + const DragDropData data("Mesh", "assets/meshes/Default/Cylinder.fbx", "Cylinder"); + ImGui::SetDragDropPayload("scene_entity_objectP", &data, sizeof(data)); + ImGui::EndDragDropSource(); + } + + ImGui::Image(m_CubeImage->GetRendererID(), ImVec2(30, 30)); + ImGui::SameLine(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5); + ImGui::Selectable("Torus"); + + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) + { + ImGui::Image(m_CubeImage->GetRendererID(), ImVec2(20, 20)); + ImGui::SameLine(); + + ImGui::Text("Torus"); + const DragDropData data("Mesh", "assets/meshes/Default/Torus.fbx", "Torus"); + ImGui::SetDragDropPayload("scene_entity_objectP", &data, sizeof(data)); + ImGui::EndDragDropSource(); + } + + + ImGui::Image(m_CubeImage->GetRendererID(), ImVec2(30, 30)); + ImGui::SameLine(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5); + ImGui::Selectable("Plane"); + + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) + { + ImGui::Image(m_CubeImage->GetRendererID(), ImVec2(20, 20)); + ImGui::SameLine(); + + ImGui::Text("Plane"); + const DragDropData data("Mesh", "assets/meshes/Default/Plane.fbx", "Plane"); + ImGui::SetDragDropPayload("scene_entity_objectP", &data, sizeof(data)); + ImGui::EndDragDropSource(); + } + + ImGui::Image(m_CubeImage->GetRendererID(), ImVec2(30, 30)); + ImGui::SameLine(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5); + ImGui::Selectable("Cone"); + + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) + { + ImGui::Image(m_CubeImage->GetRendererID(), ImVec2(20, 20)); + ImGui::SameLine(); + + ImGui::Text("Cone"); + const DragDropData data("Mesh", "assets/meshes/Default/Cone.fbx", "Cone"); + ImGui::SetDragDropPayload("scene_entity_objectP", &data, sizeof(data)); + ImGui::EndDragDropSource(); + } + + ImGui::EndChild(); + } + } + + ImGui::End(); + } +} diff --git a/Prism/src/Prism/Editor/ObjectsPanel.h b/Prism/src/Prism/Editor/ObjectsPanel.h new file mode 100644 index 0000000..09facad --- /dev/null +++ b/Prism/src/Prism/Editor/ObjectsPanel.h @@ -0,0 +1,24 @@ +// +// Created by Atdunbg on 2026/1/20. +// + +#ifndef PRISM_OBJECTSPANEL_H +#define PRISM_OBJECTSPANEL_H +#include "Prism/Renderer/Texture.h" + +namespace Prism +{ + class PRISM_API ObjectsPanel + { + public: + ObjectsPanel(); + + void OnImGuiRender(); + + private: + Ref m_CubeImage; + }; +} + + +#endif //PRISM_OBJECTSPANEL_H diff --git a/Prism/src/Prism/Editor/SceneHierachyPanel.cpp b/Prism/src/Prism/Editor/SceneHierachyPanel.cpp index 903ea88..02d8a39 100644 --- a/Prism/src/Prism/Editor/SceneHierachyPanel.cpp +++ b/Prism/src/Prism/Editor/SceneHierachyPanel.cpp @@ -168,16 +168,42 @@ namespace Prism void SceneHierarchyPanel::OnImGuiRender() { ImGui::Begin("Scene Hierarchy"); + ImRect windowRect = { ImGui::GetWindowContentRegionMin(), ImGui::GetWindowContentRegionMax() }; + if (m_Context) { uint32_t entityCount = 0, meshCount = 0; m_Context->m_Registry.view().each([&](auto entity) { - const Entity e(entity, m_Context.Raw()); - if (e.HasComponent()) + Entity e(entity, m_Context.Raw()); + if (e.HasComponent() && e.GetParentUUID() == 0) DrawEntityNode(e); }); + if (ImGui::BeginDragDropTargetCustom(windowRect, ImGui::GetCurrentWindow()->ID)) + { + const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("scene_entity_hierarchy", ImGuiDragDropFlags_AcceptNoDrawDefaultRect); + + if (payload) + { + const UUID droppedHandle = *((UUID*)payload->Data); + Entity e = m_Context->FindEntityByUUID(droppedHandle); + Entity previousParent = m_Context->FindEntityByUUID(e.GetParentUUID()); + + if (previousParent) + { + auto& children = previousParent.Children(); + children.erase(std::remove(children.begin(), children.end(), droppedHandle), children.end()); + } + + e.SetParentUUID(0); + + PM_CORE_INFO("Unparented Entity!"); + } + + ImGui::EndDragDropTarget(); + } + if (ImGui::BeginPopupContextWindow()) { @@ -272,17 +298,53 @@ namespace Prism ImGui::EndPopup(); } + + if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) + { + UUID entityId = entity.GetUUID(); + ImGui::Text(entity.GetComponent().Tag.c_str()); + ImGui::SetDragDropPayload("scene_entity_hierarchy", &entityId, sizeof(UUID)); + ImGui::EndDragDropSource(); + } + + if (ImGui::BeginDragDropTarget()) + { + const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("scene_entity_hierarchy", ImGuiDragDropFlags_AcceptNoDrawDefaultRect); + + if (payload) + { + UUID droppedHandle = *static_cast(payload->Data); + Entity e = m_Context->FindEntityByUUID(droppedHandle); + + // Remove from previous parent + Entity previousParent = m_Context->FindEntityByUUID(e.GetParentUUID()); + if (previousParent) + { + auto& parentChildren = previousParent.Children(); + parentChildren.erase(std::remove(parentChildren.begin(), parentChildren.end(), droppedHandle), parentChildren.end()); + } + + e.SetParentUUID(entity.GetUUID()); + auto& children = entity.Children(); + children.push_back(droppedHandle); + + PM_CORE_INFO("Dropping Entity {0} on {1}", (uint64_t)droppedHandle, (uint64_t)entity.GetUUID()); + } + + ImGui::EndDragDropTarget(); + } + + if (opened) { // TODO: children - /* - if (entity.HasComponent()) + + for (const auto& child : entity.Children()) { - auto mesh = entity.GetComponent().Mesh; - // if (mesh) - // DrawMeshNode(mesh); + const Entity e = m_Context->FindEntityByUUID(child); + if (e) + DrawEntityNode(e); } - */ ImGui::TreePop(); } diff --git a/Prism/src/Prism/Physics/PhysicsActor.cpp b/Prism/src/Prism/Physics/PhysicsActor.cpp index 6ecb3bd..b2e7355 100644 --- a/Prism/src/Prism/Physics/PhysicsActor.cpp +++ b/Prism/src/Prism/Physics/PhysicsActor.cpp @@ -185,15 +185,18 @@ namespace Prism { physx::PxPhysics& physics = PhysicsWrappers::GetPhysics(); + Ref scene = Scene::GetScene(m_Entity.GetSceneUUID()); + glm::mat4 transform = scene->GetTransformRelativeToParent(m_Entity); + if (m_RigidBody.BodyType == RigidBodyComponent::Type::Static) { - m_ActorInternal = physics.createRigidStatic(ToPhysXTransform(m_Entity.Transform())); + m_ActorInternal = physics.createRigidStatic(ToPhysXTransform(transform)); } else { const PhysicsSettings& settings = Physics3D::GetSettings(); - physx::PxRigidDynamic* actor = physics.createRigidDynamic(ToPhysXTransform(m_Entity.Transform())); + physx::PxRigidDynamic* actor = physics.createRigidDynamic(ToPhysXTransform(transform)); actor->setLinearDamping(m_RigidBody.LinearDrag); actor->setAngularDamping(m_RigidBody.AngularDrag); actor->setRigidBodyFlag(physx::PxRigidBodyFlag::eKINEMATIC, m_RigidBody.IsKinematic); @@ -249,7 +252,8 @@ namespace Prism else { // Synchronize Physics Actor with static Entity - m_ActorInternal->setGlobalPose(ToPhysXTransform(m_Entity.Transform())); + Ref scene = Scene::GetScene(m_Entity.GetSceneUUID()); + m_ActorInternal->setGlobalPose(ToPhysXTransform(scene->GetTransformRelativeToParent(m_Entity))); } } diff --git a/Prism/src/Prism/Platform/OpenGL/OpenGLRendererAPI.cpp b/Prism/src/Prism/Platform/OpenGL/OpenGLRendererAPI.cpp index 803a546..06ba789 100644 --- a/Prism/src/Prism/Platform/OpenGL/OpenGLRendererAPI.cpp +++ b/Prism/src/Prism/Platform/OpenGL/OpenGLRendererAPI.cpp @@ -114,6 +114,7 @@ namespace Prism glEnable(GL_DEPTH_TEST); //glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); glFrontFace(GL_CCW); diff --git a/Prism/src/Prism/Renderer/Mesh.cpp b/Prism/src/Prism/Renderer/Mesh.cpp index 079c206..9251da9 100644 --- a/Prism/src/Prism/Renderer/Mesh.cpp +++ b/Prism/src/Prism/Renderer/Mesh.cpp @@ -262,6 +262,7 @@ namespace Prism if (aiMaterialName.Empty()) aiMaterialName = "Material_" + std::to_string(i); auto mi = Ref::Create(m_BaseMaterial, aiMaterialName.data); + mi->SetFlag(MaterialFlag::TwoSided, false); m_Materials[i] = mi; PM_MESH_LOG(" {0} (Index = {1})", aiMaterialName.data, i); diff --git a/Prism/src/Prism/Scene/Components.h b/Prism/src/Prism/Scene/Components.h index 822ba37..769dbfb 100644 --- a/Prism/src/Prism/Scene/Components.h +++ b/Prism/src/Prism/Scene/Components.h @@ -28,6 +28,24 @@ namespace Prism UUID ID = 0; }; + struct ParentComponent + { + UUID ParentHandle = 0; + + ParentComponent() = default; + ParentComponent(const ParentComponent& other) = default; + ParentComponent(const UUID& parent) + : ParentHandle(parent) {} + }; + + struct ChildrenComponent + { + std::vector Children; + + ChildrenComponent() = default; + ChildrenComponent(const ChildrenComponent& other) = default; + }; + struct TagComponent { std::string Tag; @@ -49,6 +67,10 @@ namespace Prism glm::vec3 Rotation = { 0.0f, 0.0f, 0.0f }; glm::vec3 Scale = { 1.0f, 1.0f, 1.0f }; + glm::vec3 Up = { 0.0f, 1.0f, 0.0f }; + glm::vec3 Right = { 1.0f, 0.0f, 0.0f }; + glm::vec3 Forward = {0.0f, 0.0f, -1.0f}; + TransformComponent() = default; TransformComponent(const TransformComponent& other) = default; TransformComponent(const glm::vec3& translation) diff --git a/Prism/src/Prism/Scene/Entity.h b/Prism/src/Prism/Scene/Entity.h index 51313c0..e16ad7e 100644 --- a/Prism/src/Prism/Scene/Entity.h +++ b/Prism/src/Prism/Scene/Entity.h @@ -67,6 +67,10 @@ namespace Prism return !(*this == other); } + void SetParentUUID(const UUID& parent) { GetComponent().ParentHandle = parent; } + UUID GetParentUUID() { return GetComponent().ParentHandle; } + std::vector& Children() { return GetComponent().Children; } + UUID GetUUID() { return GetComponent().ID; } UUID GetSceneUUID() const { return m_Scene->GetUUID(); } diff --git a/Prism/src/Prism/Scene/Scene.cpp b/Prism/src/Prism/Scene/Scene.cpp index a3ae2fe..7d03ad9 100644 --- a/Prism/src/Prism/Scene/Scene.cpp +++ b/Prism/src/Prism/Scene/Scene.cpp @@ -20,6 +20,7 @@ #include #include "Prism/Core/Input.h" +#include "Prism/Core/Math/Math.h" namespace Prism { @@ -189,6 +190,27 @@ namespace Prism } } + // update transformComponent internal direction + { + const auto view = m_Registry.view(); + for (const auto entity : view) + { + Entity e = { entity, this }; + auto& transformComponent = e.GetComponent(); + glm::mat4 transform = GetTransformRelativeToParent(Entity(entity, this)); + glm::vec3 translation; + glm::vec3 rotation; + glm::vec3 scale; + Math::DecomposeTransform(transform, translation, rotation, scale); + + auto rotationQuat = glm::quat(rotation); + transformComponent.Up = glm::normalize(glm::rotate(rotationQuat, glm::vec3(0.0f, 1.0f, 0.0f))); + transformComponent.Right = glm::normalize(glm::rotate(rotationQuat, glm::vec3(1.0f, 0.0f, 0.0f))); + transformComponent.Forward = glm::normalize(glm::rotate(rotationQuat, glm::vec3(0.0f, 0.0f, -1.0f))); + } + } + + Physics3D::Simulate(ts); // Update all entities @@ -212,7 +234,7 @@ namespace Prism if (!cameraEntity) return; - const glm::mat4 cameraViewMatrix = glm::inverse(cameraEntity.Transform().GetTransform()); + const glm::mat4 cameraViewMatrix = glm::inverse(GetTransformRelativeToParent(cameraEntity)); PM_CORE_ASSERT(cameraEntity, "Scene does not contain any cameras!"); SceneCamera& camera = cameraEntity.GetComponent(); camera.SetViewportSize(m_ViewportWidth, m_ViewportHeight); @@ -261,8 +283,10 @@ namespace Prism { meshComponent.Mesh->OnUpdate(ts); + glm::mat4 transform = GetTransformRelativeToParent(Entity(entity, this)); + // TODO: Should we render (logically) - SceneRenderer::SubmitMesh(meshComponent, transformComponent.GetTransform(), nullptr); + SceneRenderer::SubmitMesh(meshComponent, transform); } } SceneRenderer::EndScene(); @@ -338,11 +362,13 @@ namespace Prism { meshComponent.Mesh->OnUpdate(ts); + glm::mat4 transform = GetTransformRelativeToParent(Entity{ entity, this }); + // TODO: Should we render (logically) if (m_SelectedEntity == entity) - SceneRenderer::SubmitSelectedMesh(meshComponent, transformComponent.GetTransform()); + SceneRenderer::SubmitSelectedMesh(meshComponent, transform); else - SceneRenderer::SubmitMesh(meshComponent, transformComponent.GetTransform()); + SceneRenderer::SubmitMesh(meshComponent, transform); } } @@ -352,9 +378,10 @@ namespace Prism { Entity e = { entity, this }; auto& collider = e.GetComponent(); + glm::mat4 transform = GetTransformRelativeToParent(e); if (m_SelectedEntity == entity) - SceneRenderer::SubmitColliderMesh(collider, e.GetComponent().GetTransform()); + SceneRenderer::SubmitColliderMesh(collider, transform); } } @@ -364,9 +391,10 @@ namespace Prism { Entity e = { entity, this }; auto& collider = e.GetComponent(); + glm::mat4 transform = GetTransformRelativeToParent(e); if (m_SelectedEntity == entity) - SceneRenderer::SubmitColliderMesh(collider, e.GetComponent().GetTransform()); + SceneRenderer::SubmitColliderMesh(collider, transform); } } @@ -376,9 +404,10 @@ namespace Prism { Entity e = { entity, this }; auto& collider = e.GetComponent(); + glm::mat4 transform = GetTransformRelativeToParent(e); if (m_SelectedEntity == entity) - SceneRenderer::SubmitColliderMesh(collider, e.GetComponent().GetTransform()); + SceneRenderer::SubmitColliderMesh(collider, transform); } } @@ -388,11 +417,10 @@ namespace Prism { Entity e = { entity, this }; auto& collider = e.GetComponent(); + glm::mat4 transform = GetTransformRelativeToParent(e); if (m_SelectedEntity == entity) - { - SceneRenderer::SubmitColliderMesh(collider, e.GetComponent().GetTransform()); - } + SceneRenderer::SubmitColliderMesh(collider, transform); } } @@ -590,6 +618,9 @@ namespace Prism idComponent.ID = {}; entity.AddComponent(); + entity.AddComponent(); + entity.AddComponent(); + if (!name.empty()) entity.AddComponent(name); @@ -604,6 +635,9 @@ namespace Prism idComponent.ID = uuid; entity.AddComponent(); + entity.AddComponent(); + entity.AddComponent(); + if (!name.empty()) entity.AddComponent(name); @@ -646,6 +680,11 @@ namespace Prism newEntity = CreateEntity(); CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); + + // TODO: should copy parent + CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); + CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); + CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); CopyComponentIfExists(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry); @@ -676,6 +715,31 @@ namespace Prism return Entity{}; } + Entity Scene::FindEntityByUUID(UUID uuid) + { + + auto view = m_Registry.view(); + for (auto entity : view) + { + auto& idComponent = m_Registry.get(entity); + if (idComponent.ID == uuid) + return {entity, this}; + } + + return Entity{}; + } + + glm::mat4 Scene::GetTransformRelativeToParent(Entity entity) + { + glm::mat4 transform(1.0f); + + const Entity parent = FindEntityByUUID(entity.GetParentUUID()); + if (parent) + transform = GetTransformRelativeToParent(parent); + + return transform * entity.Transform().GetTransform(); + } + void Scene::CopyTo(Ref& target) { target->m_Light = m_Light; @@ -697,6 +761,10 @@ namespace Prism CopyComponent(target->m_Registry, m_Registry, enttMap); CopyComponent(target->m_Registry, m_Registry, enttMap); + + CopyComponent(target->m_Registry, m_Registry, enttMap); + CopyComponent(target->m_Registry, m_Registry, enttMap); + CopyComponent(target->m_Registry, m_Registry, enttMap); CopyComponent(target->m_Registry, m_Registry, enttMap); CopyComponent(target->m_Registry, m_Registry, enttMap); diff --git a/Prism/src/Prism/Scene/Scene.h b/Prism/src/Prism/Scene/Scene.h index b0c140a..8494ddc 100644 --- a/Prism/src/Prism/Scene/Scene.h +++ b/Prism/src/Prism/Scene/Scene.h @@ -90,6 +90,9 @@ namespace Prism } Entity FindEntityByTag(const std::string& tag); + Entity FindEntityByUUID(UUID uuid); + + glm::mat4 GetTransformRelativeToParent(Entity entity); const EntityMap& GetEntityMap() const { return m_EntityIDMap; } void CopyTo(Ref& target); diff --git a/Prism/src/Prism/Scene/SceneSerializer.cpp b/Prism/src/Prism/Scene/SceneSerializer.cpp index 08cc2e2..ef1b802 100644 --- a/Prism/src/Prism/Scene/SceneSerializer.cpp +++ b/Prism/src/Prism/Scene/SceneSerializer.cpp @@ -160,12 +160,33 @@ namespace Prism out << YAML::Key << "Entity"; out << YAML::Value << uuid; + if (entity.HasComponent()) + { + auto& parent = entity.GetComponent(); + out << YAML::Key << "Parent" << YAML::Value << parent.ParentHandle; + } + + if (entity.HasComponent()) + { + const auto& childrenComponent = entity.GetComponent(); + out << YAML::Key << "Children"; + out << YAML::Value << YAML::BeginSeq; + + for (auto child : childrenComponent.Children) + { + out << YAML::BeginMap; + out << YAML::Key << "Handle" << YAML::Value << child; + out << YAML::EndMap; + } + out << YAML::EndSeq; + } + if (entity.HasComponent()) { out << YAML::Key << "TagComponent"; out << YAML::BeginMap; // TagComponent - auto& tag = entity.GetComponent().Tag; + const auto& tag = entity.GetComponent().Tag; out << YAML::Key << "Tag" << YAML::Value << tag; out << YAML::EndMap; // TagComponent @@ -176,7 +197,7 @@ namespace Prism out << YAML::Key << "TransformComponent"; out << YAML::BeginMap; // TransformComponent - auto& transform = entity.GetComponent(); + const auto& transform = entity.GetComponent(); out << YAML::Key << "Position" << YAML::Value << transform.Translation; out << YAML::Key << "Rotation" << YAML::Value << transform.Rotation; out << YAML::Key << "Scale" << YAML::Value << transform.Scale; @@ -573,6 +594,20 @@ namespace Prism Entity deserializedEntity = m_Scene->CreateEntityWithID(uuid, name); + + uint64_t parentHandle = entity["Parent"] ? entity["Parent"].as() : 0; + deserializedEntity.GetComponent().ParentHandle = parentHandle; + + const auto children = entity["Children"]; + if (children) + { + for (auto child : children) + { + auto childHandle = child["Handle"].as(); + deserializedEntity.GetComponent().Children.emplace_back(childHandle); + } + } + auto transformComponent = entity["TransformComponent"]; if (transformComponent) { @@ -605,20 +640,20 @@ namespace Prism auto scriptComponent = entity["ScriptComponent"]; if (scriptComponent) { - std::string moduleName = scriptComponent["ModuleName"].as(); + const auto moduleName = scriptComponent["ModuleName"].as(); deserializedEntity.AddComponent(moduleName); PM_CORE_INFO(" Script Module: {0}", moduleName); if (ScriptEngine::ModuleExists(moduleName)) { - auto storedFields = scriptComponent["StoredFields"]; + const auto storedFields = scriptComponent["StoredFields"]; if (storedFields) { for (auto field : storedFields) { auto name = field["Name"].as(); - auto type = (FieldType)field["Type"].as(); + auto type = static_cast(field["Type"].as()); EntityInstanceData& data = ScriptEngine::GetEntityInstanceData(m_Scene->GetUUID(), uuid); auto& moduleFieldMap = data.ModuleFieldMap; auto& publicFields = moduleFieldMap[moduleName]; diff --git a/Prism/src/Prism/Script/ScriptWrappers.cpp b/Prism/src/Prism/Script/ScriptWrappers.cpp index 6b5c239..b6912c5 100644 --- a/Prism/src/Prism/Script/ScriptWrappers.cpp +++ b/Prism/src/Prism/Script/ScriptWrappers.cpp @@ -322,52 +322,8 @@ namespace Prism { namespace Script { } + /* - void Prism_TransformComponent_GetRelativeDirection(const uint64_t entityID, glm::vec3* outDirection, const glm::vec3* inAbsoluteDirection) - { - Ref scene = ScriptEngine::GetCurrentSceneContext(); - PM_CORE_ASSERT(scene, "No active scene!"); - const auto& entityMap = scene->GetEntityMap(); - PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); - - Entity entity = entityMap.at(entityID); - const auto& transformComponent = entity.GetComponent(); - - auto [position, rotation, scale] = GetTransformDecomposition(transformComponent.Transformation); - *outDirection = glm::rotate(rotation, *inAbsoluteDirection); - } - - void Prism_TransformComponent_GetRotation(const uint64_t entityID, glm::vec3* outRotation) - { - Ref scene = ScriptEngine::GetCurrentSceneContext(); - PM_CORE_ASSERT(scene, "No active scene!"); - const auto& entityMap = scene->GetEntityMap(); - PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); - - Entity entity = entityMap.at(entityID); - const auto& transformComponent = entity.GetComponent(); - - auto [position, rotation, scale] = GetTransformDecomposition(transformComponent.Transformation); - *outRotation = glm::degrees(glm::eulerAngles(rotation)); - } - - void Prism_TransformComponent_SetRotation(const uint64_t entityID, const glm::vec3* inRotation) - { - Ref scene = ScriptEngine::GetCurrentSceneContext(); - PM_CORE_ASSERT(scene, "No active scene!"); - const auto& entityMap = scene->GetEntityMap(); - PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); - - Entity entity = entityMap.at(entityID); - auto& transform = entity.Transformation(); - - auto [position, rotation, scale] = GetTransformDecomposition(transform); - transform = glm::translate(glm::mat4(1.0f), position) * - glm::toMat4(glm::quat(glm::radians(*inRotation))) * - glm::scale(glm::mat4(1.0f), scale); - } - */ - void Prism_TransformComponent_GetTransform(const uint64_t entityID, ScriptTransform* outTransform) { Ref scene = ScriptEngine::GetCurrentSceneContext(); @@ -406,6 +362,32 @@ namespace Prism { namespace Script { transform.Rotation = glm::radians(inTransform->Rotation); transform.Scale = inTransform->Scale; } + */ + + void Prism_TransformComponent_GetTransform(const uint64_t entityID, TransformComponent* outTransform) + { + Ref scene = ScriptEngine::GetCurrentSceneContext(); + PM_CORE_ASSERT(scene, "No active scene!"); + const auto& entityMap = scene->GetEntityMap(); + PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); + + Entity entity = entityMap.at(entityID); + *outTransform = entity.GetComponent(); + outTransform->Rotation = glm::degrees(outTransform->Rotation); + } + + void Prism_TransformComponent_SetTransform(const uint64_t entityID, const TransformComponent* inTransform) + { + Ref scene = ScriptEngine::GetCurrentSceneContext(); + PM_CORE_ASSERT(scene, "No active scene!"); + const auto& entityMap = scene->GetEntityMap(); + PM_CORE_ASSERT(entityMap.find(entityID) != entityMap.end(), "Invalid entity ID or entity doesn't exist in scene!"); + + Entity entity = entityMap.at(entityID); + + auto& transform = entity.GetComponent() = *inTransform; + transform.Rotation = glm::radians(transform.Rotation); + } /* void Prism_TransformComponent_GetTransform(const uint64_t entityID, TransformComponent* outTransform) diff --git a/Prism/src/Prism/Script/ScriptWrappers.h b/Prism/src/Prism/Script/ScriptWrappers.h index e7174e8..c44e60b 100644 --- a/Prism/src/Prism/Script/ScriptWrappers.h +++ b/Prism/src/Prism/Script/ScriptWrappers.h @@ -16,6 +16,7 @@ extern "C" { namespace Prism { namespace Script { + /* struct ScriptTransform { glm::vec3 Translation; @@ -23,6 +24,7 @@ namespace Prism { namespace Script { glm::vec3 Scale; glm::vec3 Up, Right, Forward; }; + */ // Math float Prism_Noise_PerlinNoise(float x, float y); @@ -57,8 +59,8 @@ namespace Prism { namespace Script { void Prism_TransformComponent_GetRotation(uint64_t entityID,glm::vec3* outRotation); void Prism_TransformComponent_SetRotation(uint64_t entityID,const glm::vec3* inRotation); */ - void Prism_TransformComponent_GetTransform(uint64_t entityID, ScriptTransform* outTransform); - void Prism_TransformComponent_SetTransform(uint64_t entityID, const ScriptTransform* inTransform); + void Prism_TransformComponent_GetTransform(uint64_t entityID, TransformComponent* outTransform); + void Prism_TransformComponent_SetTransform(uint64_t entityID, const TransformComponent* inTransform); void Prism_TransformComponent_GetTranslation(uint64_t entityID, glm::vec3* outTranslation); void Prism_TransformComponent_SetTranslation(uint64_t entityID, const glm::vec3* inTranslation); void Prism_TransformComponent_GetRotation(uint64_t entityID, glm::vec3* outRotation); diff --git a/Prism/src/Prism/Utilities/AssetsManager.cpp b/Prism/src/Prism/Utilities/AssetsManager.cpp new file mode 100644 index 0000000..db3d6cf --- /dev/null +++ b/Prism/src/Prism/Utilities/AssetsManager.cpp @@ -0,0 +1,264 @@ +// +// Created by Atdunbg on 2026/1/20. +// + +#include "AssetsManager.h" + +#include + +namespace Prism +{ + void AssetTypes::Init() + { + s_Types["scene"] = AssetType::Scene; + s_Types["fbx"] = AssetType::Mesh; + s_Types["obj"] = AssetType::Mesh; + s_Types["png"] = AssetType::Image; + s_Types["blend"] = AssetType::Mesh; + s_Types["wav"] = AssetType::Audio; + s_Types["ogg"] = AssetType::Audio; + s_Types["cs"] = AssetType::Script; + } + + size_t AssetTypes::GetAssetTypeID(const std::string& extension) + { + for (const auto& kv : s_Types) + { + if (kv.first == extension) + return std::hash()(extension); + } + + return -1; + } + + AssetType AssetTypes::GetAssetTypeFromExtension(const std::string& extension) + { + return s_Types.find(extension) != s_Types.end() ? s_Types[extension] : AssetType::Other; + } + + std::map AssetTypes::s_Types; + + AssetsManager::AssetsManager() + { + } + + std::string AssetsManager::ParseFilename(const std::string& filepath, const char& delim) + { + std::vector out; + size_t start; + size_t end = 0; + + while ((start = filepath.find_first_not_of(delim, end)) != std::string::npos) + { + end = filepath.find(delim, start); + out.push_back(filepath.substr(start, end - start)); + } + + return out[out.size() - 1]; + } + + std::string AssetsManager::ParseFileType(const std::string& filename) + { + size_t start; + size_t end = 0; + std::vector out; + + while ((start = filename.find_first_not_of('.', end)) != std::string::npos) + { + end = filename.find('.', start); + out.push_back(filename.substr(start, end - start)); + } + + return out[out.size() - 1]; + } + + void AssetsManager::HandleAsset(const std::string& filepath) + { + } + + void AssetsManager::ProcessAsset(const std::string& assetType) + { + std::string filename = ParseFilename(assetType, '/\\'); + const std::string filetype = ParseFileType(assetType); + + if (filetype == "blend") + { + // TODO: this actually unuse now + ConvertAsset(assetType, "fbx"); + } + } + + void AssetsManager::ConvertAsset(const std::string& assetPath, const std::string& conversionType) + { + // Create a filestream to write a blender python script for conversion of the asset + // The 'bpy.ops.export_scene.(asset-type-to-convert) function runs blender in background and exports the file' + std::string path = std::filesystem::temp_directory_path().string(); + std::ofstream fileStream(path + "export.py"); + + // Importing the python modules required for the export to work out + fileStream << "import bpy\n"; + fileStream << "import sys\n"; + + if (conversionType == "fbx") + fileStream << "bpy.ops.export_scene.fbx(filepath=r'" + path + "asset.fbx" + "', axis_forward='-Z', axis_up='Y')\n"; + + if (conversionType == "obj") + fileStream << "bpy.ops.export_scene.obj(filepath=r'" + path + "asset.obj" + "', axis_forward='-Z', axis_up='Y')\n"; + + fileStream.close(); + + // This section involves creating the command to export the .blend file to the required asset type + // The command goes something like this + // blender.exe path\to\files\cube.blend --background --python path\to\file\export.py + + std::string blender_base_path = R"(D:\Application\Blender5.0.1\blender.exe)"; + std::string p_asset_path = '"' + assetPath + '"'; + std::string p_blender_path = '"' + blender_base_path + '"'; + std::string p_script_path = '"' + path + "export.py" + '"'; + + // Creating the actual command that will execute + std::string convCommand = '"' + p_blender_path + " " + p_asset_path + " --background --python " + p_script_path + "" + '"'; + + // Just for debugging(it took me 1hr for this string literals n stuff! It better work!) + PM_CORE_INFO("{0}", convCommand); + + // Fire the above created command + + // TODO: Platform Abstraction! + system(convCommand.c_str()); + } + + std::vector AssetsManager::GetFileSystemContents() + { + const std::string path = "assets"; + std::vector directories; + + for (const auto& entry : std::filesystem::directory_iterator(path)) + { + const bool isDir = std::filesystem::is_directory(entry); + + std::string dir_data = ParseFilename(entry.path().string(), '/\\'); + std::string fileExt = ParseFileType(dir_data); + directories.emplace_back(dir_data, fileExt, entry.path().string(), !isDir); + } + + return directories; + } + + std::vector AssetsManager::GetDirectoryContents(const std::string& filepath, bool recursive) + { + std::vector directories; + + if (recursive) + { + for (const auto& entry : std::filesystem::recursive_directory_iterator(filepath)) + { + const bool isDir = std::filesystem::is_directory(entry); + std::string dir_data = ParseFilename(entry.path().string(), '/\\'); + directories.emplace_back(dir_data, ".scene", entry.path().string(), !isDir); + } + } + else + { + for (const auto& entry : std::filesystem::directory_iterator(filepath)) + { + const bool isDir = std::filesystem::is_directory(entry); + std::string dir_data = ParseFilename(entry.path().string(), '/\\'); + std::string fileExt = ParseFileType(dir_data); + directories.emplace_back(dir_data, fileExt, entry.path().string(), !isDir); + } + } + + return directories; + } + + std::vector AssetsManager::SearchFiles(const std::string& query, const std::string& searchPath) + { + std::vector result; + + if (!searchPath.empty()) + { + std::vector contents = GetDirectoryContents(searchPath, true); + + for (auto& entry : contents) + { + if (entry.Filename.find(query) != std::string::npos) + result.emplace_back(std::move(entry)); + } + } + + return result; + } + + std::string AssetsManager::GetParentPath(const std::string& path) + { + return std::filesystem::path(path).parent_path().string(); + } + + std::vector AssetsManager::GetDirectories(const std::string& filepath) + { + std::vector result; + size_t start; + size_t end = 0; + + while ((start = filepath.find_first_not_of("/\\", end)) != std::string::npos) + { + end = filepath.find("/\\", start); + result.push_back(filepath.substr(start, end - start)); + } + + return result; + } + + bool AssetsManager::MoveFile(const std::filesystem::path& originalPath, const std::filesystem::path& dest) + { + // TODO: fixeme: MoveFile cannot work + try + { + std::filesystem::rename(originalPath, dest); + const std::string newPath = dest.string() + "/" + ParseFilename(originalPath.string(), '/\\'); + return std::filesystem::exists(newPath); + }catch (const std::exception& e) + { + PM_CORE_ERROR("Move File error: {0}", e.what()); + return false; + } + } + + std::string AssetsManager::StripExtras(const std::string& filename) + { + std::vector out; + size_t start; + size_t end = 0; + + while ((start = filename.find_first_not_of('.', end)) != std::string::npos) + { + end = filename.find('.', start); + out.push_back(filename.substr(start, end - start)); + } + + if (out[0].length() >= 10) + { + auto cutFilename = out[0].substr(0, 9) + "..."; + return cutFilename; + } + + const auto filenameLength = out[0].length(); + const auto paddingToAdd = 9 - filenameLength; + + std::string newFileName; + + for (int i = 0; i <= paddingToAdd; i++) + { + newFileName += " "; + } + + newFileName += out[0]; + + return newFileName; + } + + void AssetsManager::ImportAsset(const std::string& assetPath, const std::string& assetName) + { + } +} diff --git a/Prism/src/Prism/Utilities/AssetsManager.h b/Prism/src/Prism/Utilities/AssetsManager.h new file mode 100644 index 0000000..7450031 --- /dev/null +++ b/Prism/src/Prism/Utilities/AssetsManager.h @@ -0,0 +1,94 @@ +// +// Created by Atdunbg on 2026/1/20. +// + +#ifndef PRISM_ASSETSMANAGER_H +#define PRISM_ASSETSMANAGER_H + +#include +#include + +namespace Prism +{ + enum class AssetType + { + Scene, Mesh, Image, Audio, Script, Other + }; + + class AssetTypes + { + public: + static void Init(); + static size_t GetAssetTypeID(const std::string& extension); + static AssetType GetAssetTypeFromExtension(const std::string& extension); + + private: + static std::map s_Types; + }; + + struct DirectoryInfo + { + std::string Filename; + std::string FileType; + std::string AbsolutePath; + bool IsFile; + + DirectoryInfo(std::string filename, std::string fileType, std::string absolutePath, const bool isFile) + : Filename(std::move(filename)), FileType(std::move(fileType)), AbsolutePath(std::move(absolutePath)), IsFile(isFile) + { + } + + DirectoryInfo(const DirectoryInfo& other) + : Filename(other.Filename), FileType(other.FileType), AbsolutePath(other.AbsolutePath), IsFile(other.IsFile) + { + } + + DirectoryInfo(DirectoryInfo&& other) + : Filename(std::move(other.Filename)), FileType(std::move(other.FileType)), AbsolutePath(std::move(other.AbsolutePath)), IsFile(other.IsFile) + { + } + + DirectoryInfo& operator=(const DirectoryInfo& other) + { + if (this != &other) + { + Filename = other.Filename; + FileType = other.FileType; + AbsolutePath = other.AbsolutePath; + IsFile = other.IsFile; + } + return *this; + } + }; + + class PRISM_API AssetsManager + { + public: + AssetsManager(); + + std::string ParseFilename(const std::string& filepath, const char& delim); + std::string ParseFileType(const std::string& filename); + + void HandleAsset(const std::string& filepath); + void ProcessAsset(const std::string& assetType); + void ConvertAsset(const std::string& assetPath, const std::string& conversionType); + + std::vector GetFileSystemContents(); + std::vector GetDirectoryContents(const std::string& filepath, bool recursive = false); + std::vector SearchFiles(const std::string& query, const std::string& searchPath); + + std::string GetParentPath(const std::string& path); + + std::vector GetDirectories(const std::string& filepath); + + bool MoveFile(const std::filesystem::path& originalPath, const std::filesystem::path& dest); + + std::string StripExtras(const std::string& filename); + + private: + void ImportAsset(const std::string& assetPath, const std::string& assetName); + }; +} + + +#endif //PRISM_ASSETSMANAGER_H \ No newline at end of file diff --git a/Prism/src/Prism/Utilities/DragDropData.h b/Prism/src/Prism/Utilities/DragDropData.h new file mode 100644 index 0000000..4467f53 --- /dev/null +++ b/Prism/src/Prism/Utilities/DragDropData.h @@ -0,0 +1,24 @@ +// +// Created by Atdunbg on 2026/1/20. +// + +#ifndef PRISM_DRAGDROPDATA_H +#define PRISM_DRAGDROPDATA_H + +namespace Prism +{ + struct DragDropData + { + public: + const char* Type; + const char* SourcePath; + const char* Name; + + DragDropData(const char* type, const char* sourcePath, const char* name) + : Type(type), SourcePath(sourcePath), Name(name) + { + } + }; +} + +#endif //PRISM_DRAGDROPDATA_H \ No newline at end of file