add trace for imgui.ini, add assets manager system and objects manager system, add some icons, add entity tree node for scene Hierachy's entities, add convert blend file process(but not actual use it, just implement) BUGS: file copy not work

This commit is contained in:
2026-01-21 12:30:47 +08:00
parent 2bfde2dfb0
commit cf3a46bae1
50 changed files with 1553 additions and 73 deletions

View File

@ -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<AssetsManagerPanel>();
m_ObjectsPanel = CreateScope<ObjectsPanel>();
// 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<MeshComponent>(Ref<Mesh>::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<MeshComponent>(Ref<Mesh>::Create(data->SourcePath));
}
}
ImGui::EndDragDropTarget();
}
ImGui::End();
ImGui::PopStyleVar();
}

View File

@ -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<SceneHierarchyPanel> m_SceneHierarchyPanel;
Scope<AssetsManagerPanel> m_AssetManagerPanel;
Scope<ObjectsPanel> m_ObjectsPanel;
Ref<Scene> m_ActiveScene;
Ref<Scene> m_RuntimeScene, m_EditorScene;

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

96
Editor/imgui.ini Normal file
View File

@ -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

View File

@ -0,0 +1,516 @@
//
// Created by Atdunbg on 2026/1/20.
//
#include "AssetsManagerPanel.h"
#include <filesystem>
#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<int>(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<char*>(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<char*>(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<int>(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<int>(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<int>(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<int>(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();
}
}
}

View File

@ -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<Texture2D> m_FolderTex;
Ref<Texture2D> m_FavoritesTex;
Ref<Texture2D> m_FileTex;
Ref<Texture2D> m_GoBackTex;
Ref<Texture2D> m_ScriptTex;
Ref<Texture2D> m_ResourceTex;
Ref<Texture2D> m_SceneTex;
Ref<Texture2D> m_BackbtnTex;
Ref<Texture2D> m_FwrdbtnTex;
Ref<Texture2D> m_FolderRightTex;
Ref<Texture2D> m_TagsTex;
Ref<Texture2D> m_SearchTex;
Ref<Texture2D> m_GridView;
Ref<Texture2D> 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<DirectoryInfo> m_CurrentDir;
std::vector<DirectoryInfo> m_BaseProjectDir;
ImGuiInputTextCallbackData m_Data;
std::map<size_t, Ref<Texture2D>> m_AssetIconMap;
//NotificationManager nManager;
AssetsManager m_AssetManager;
};
}
#endif //PRISM_ASSETSMANAGERPANEL_H

View File

@ -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();
}
}

View File

@ -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<Texture2D> m_CubeImage;
};
}
#endif //PRISM_OBJECTSPANEL_H

View File

@ -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<entt::entity>().each([&](auto entity)
{
const Entity e(entity, m_Context.Raw());
if (e.HasComponent<IDComponent>())
Entity e(entity, m_Context.Raw());
if (e.HasComponent<IDComponent>() && 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<TagComponent>().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<UUID*>(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<MeshComponent>())
for (const auto& child : entity.Children())
{
auto mesh = entity.GetComponent<MeshComponent>().Mesh;
// if (mesh)
// DrawMeshNode(mesh);
const Entity e = m_Context->FindEntityByUUID(child);
if (e)
DrawEntityNode(e);
}
*/
ImGui::TreePop();
}

View File

@ -185,15 +185,18 @@ namespace Prism
{
physx::PxPhysics& physics = PhysicsWrappers::GetPhysics();
Ref<Scene> 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 = Scene::GetScene(m_Entity.GetSceneUUID());
m_ActorInternal->setGlobalPose(ToPhysXTransform(scene->GetTransformRelativeToParent(m_Entity)));
}
}

View File

@ -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);

View File

@ -262,6 +262,7 @@ namespace Prism
if (aiMaterialName.Empty()) aiMaterialName = "Material_" + std::to_string(i);
auto mi = Ref<MaterialInstance>::Create(m_BaseMaterial, aiMaterialName.data);
mi->SetFlag(MaterialFlag::TwoSided, false);
m_Materials[i] = mi;
PM_MESH_LOG(" {0} (Index = {1})", aiMaterialName.data, i);

View File

@ -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<UUID> 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)

View File

@ -67,6 +67,10 @@ namespace Prism
return !(*this == other);
}
void SetParentUUID(const UUID& parent) { GetComponent<ParentComponent>().ParentHandle = parent; }
UUID GetParentUUID() { return GetComponent<ParentComponent>().ParentHandle; }
std::vector<UUID>& Children() { return GetComponent<ChildrenComponent>().Children; }
UUID GetUUID() { return GetComponent<IDComponent>().ID; }
UUID GetSceneUUID() const { return m_Scene->GetUUID(); }

View File

@ -20,6 +20,7 @@
#include <PxPhysicsAPI.h>
#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<TransformComponent>();
for (const auto entity : view)
{
Entity e = { entity, this };
auto& transformComponent = e.GetComponent<TransformComponent>();
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<CameraComponent>();
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<BoxColliderComponent>();
glm::mat4 transform = GetTransformRelativeToParent(e);
if (m_SelectedEntity == entity)
SceneRenderer::SubmitColliderMesh(collider, e.GetComponent<TransformComponent>().GetTransform());
SceneRenderer::SubmitColliderMesh(collider, transform);
}
}
@ -364,9 +391,10 @@ namespace Prism
{
Entity e = { entity, this };
auto& collider = e.GetComponent<SphereColliderComponent>();
glm::mat4 transform = GetTransformRelativeToParent(e);
if (m_SelectedEntity == entity)
SceneRenderer::SubmitColliderMesh(collider, e.GetComponent<TransformComponent>().GetTransform());
SceneRenderer::SubmitColliderMesh(collider, transform);
}
}
@ -376,9 +404,10 @@ namespace Prism
{
Entity e = { entity, this };
auto& collider = e.GetComponent<CapsuleColliderComponent>();
glm::mat4 transform = GetTransformRelativeToParent(e);
if (m_SelectedEntity == entity)
SceneRenderer::SubmitColliderMesh(collider, e.GetComponent<TransformComponent>().GetTransform());
SceneRenderer::SubmitColliderMesh(collider, transform);
}
}
@ -388,11 +417,10 @@ namespace Prism
{
Entity e = { entity, this };
auto& collider = e.GetComponent<MeshColliderComponent>();
glm::mat4 transform = GetTransformRelativeToParent(e);
if (m_SelectedEntity == entity)
{
SceneRenderer::SubmitColliderMesh(collider, e.GetComponent<TransformComponent>().GetTransform());
}
SceneRenderer::SubmitColliderMesh(collider, transform);
}
}
@ -590,6 +618,9 @@ namespace Prism
idComponent.ID = {};
entity.AddComponent<TransformComponent>();
entity.AddComponent<ParentComponent>();
entity.AddComponent<ChildrenComponent>();
if (!name.empty())
entity.AddComponent<TagComponent>(name);
@ -604,6 +635,9 @@ namespace Prism
idComponent.ID = uuid;
entity.AddComponent<TransformComponent>();
entity.AddComponent<ParentComponent>();
entity.AddComponent<ChildrenComponent>();
if (!name.empty())
entity.AddComponent<TagComponent>(name);
@ -646,6 +680,11 @@ namespace Prism
newEntity = CreateEntity();
CopyComponentIfExists<TransformComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
// TODO: should copy parent
CopyComponentIfExists<ParentComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<ChildrenComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<MeshComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<DirectionalLightComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
CopyComponentIfExists<SkyLightComponent>(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<IDComponent>();
for (auto entity : view)
{
auto& idComponent = m_Registry.get<IDComponent>(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<Scene>& target)
{
target->m_Light = m_Light;
@ -697,6 +761,10 @@ namespace Prism
CopyComponent<TagComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<TransformComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<ParentComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<ChildrenComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<MeshComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<DirectionalLightComponent>(target->m_Registry, m_Registry, enttMap);
CopyComponent<SkyLightComponent>(target->m_Registry, m_Registry, enttMap);

View File

@ -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<Scene>& target);

View File

@ -160,12 +160,33 @@ namespace Prism
out << YAML::Key << "Entity";
out << YAML::Value << uuid;
if (entity.HasComponent<ParentComponent>())
{
auto& parent = entity.GetComponent<ParentComponent>();
out << YAML::Key << "Parent" << YAML::Value << parent.ParentHandle;
}
if (entity.HasComponent<ChildrenComponent>())
{
const auto& childrenComponent = entity.GetComponent<ChildrenComponent>();
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<TagComponent>())
{
out << YAML::Key << "TagComponent";
out << YAML::BeginMap; // TagComponent
auto& tag = entity.GetComponent<TagComponent>().Tag;
const auto& tag = entity.GetComponent<TagComponent>().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<TransformComponent>();
const auto& transform = entity.GetComponent<TransformComponent>();
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<uint64_t>() : 0;
deserializedEntity.GetComponent<ParentComponent>().ParentHandle = parentHandle;
const auto children = entity["Children"];
if (children)
{
for (auto child : children)
{
auto childHandle = child["Handle"].as<uint64_t>();
deserializedEntity.GetComponent<ChildrenComponent>().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<std::string>();
const auto moduleName = scriptComponent["ModuleName"].as<std::string>();
deserializedEntity.AddComponent<ScriptComponent>(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<std::string>();
auto type = (FieldType)field["Type"].as<uint32_t>();
auto type = static_cast<FieldType>(field["Type"].as<uint32_t>());
EntityInstanceData& data = ScriptEngine::GetEntityInstanceData(m_Scene->GetUUID(), uuid);
auto& moduleFieldMap = data.ModuleFieldMap;
auto& publicFields = moduleFieldMap[moduleName];

View File

@ -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> 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<TransformComponent>();
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> 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<TransformComponent>();
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> 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> 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> 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<TransformComponent>();
outTransform->Rotation = glm::degrees(outTransform->Rotation);
}
void Prism_TransformComponent_SetTransform(const uint64_t entityID, const TransformComponent* inTransform)
{
Ref<Scene> 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<TransformComponent>() = *inTransform;
transform.Rotation = glm::radians(transform.Rotation);
}
/*
void Prism_TransformComponent_GetTransform(const uint64_t entityID, TransformComponent* outTransform)

View File

@ -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);

View File

@ -0,0 +1,264 @@
//
// Created by Atdunbg on 2026/1/20.
//
#include "AssetsManager.h"
#include <filesystem>
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<std::string>()(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<std::string, AssetType> AssetTypes::s_Types;
AssetsManager::AssetsManager()
{
}
std::string AssetsManager::ParseFilename(const std::string& filepath, const char& delim)
{
std::vector<std::string> 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<std::string> 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<DirectoryInfo> AssetsManager::GetFileSystemContents()
{
const std::string path = "assets";
std::vector<DirectoryInfo> 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<DirectoryInfo> AssetsManager::GetDirectoryContents(const std::string& filepath, bool recursive)
{
std::vector<DirectoryInfo> 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<DirectoryInfo> AssetsManager::SearchFiles(const std::string& query, const std::string& searchPath)
{
std::vector<DirectoryInfo> result;
if (!searchPath.empty())
{
std::vector<DirectoryInfo> 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<std::string> AssetsManager::GetDirectories(const std::string& filepath)
{
std::vector<std::string> 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<std::string> 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)
{
}
}

View File

@ -0,0 +1,94 @@
//
// Created by Atdunbg on 2026/1/20.
//
#ifndef PRISM_ASSETSMANAGER_H
#define PRISM_ASSETSMANAGER_H
#include <map>
#include <utility>
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<std::string, AssetType> 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<DirectoryInfo> GetFileSystemContents();
std::vector<DirectoryInfo> GetDirectoryContents(const std::string& filepath, bool recursive = false);
std::vector<DirectoryInfo> SearchFiles(const std::string& query, const std::string& searchPath);
std::string GetParentPath(const std::string& path);
std::vector<std::string> 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

View File

@ -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