lots of asset manager changes. using meta to manage asset, add twoside material flag for grid
This commit is contained in:
@ -10,7 +10,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
|||||||
# set MSVC output directory
|
# set MSVC output directory
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
# config
|
# config
|
||||||
|
string(REPLACE "/showIncludes" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||||
# temp config
|
# temp config
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4251")
|
||||||
|
|
||||||
|
|||||||
@ -11,11 +11,11 @@
|
|||||||
|
|
||||||
#include "Prism/Core/Input.h"
|
#include "Prism/Core/Input.h"
|
||||||
#include "Prism/Core/Math/Math.h"
|
#include "Prism/Core/Math/Math.h"
|
||||||
|
#include "Prism/Editor/AssetEditorPanel.h"
|
||||||
#include "Prism/Editor/PhysicsSettingsWindow.h"
|
#include "Prism/Editor/PhysicsSettingsWindow.h"
|
||||||
#include "Prism/Physics/Physics3D.h"
|
#include "Prism/Physics/Physics3D.h"
|
||||||
#include "Prism/Renderer/Renderer2D.h"
|
#include "Prism/Renderer/Renderer2D.h"
|
||||||
#include "Prism/Script/ScriptEngine.h"
|
#include "Prism/Script/ScriptEngine.h"
|
||||||
#include "Prism/Utilities/DragDropData.h"
|
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
@ -178,12 +178,13 @@ namespace Prism
|
|||||||
// OpenScene("assets/scenes/FPSDemo.scene");
|
// OpenScene("assets/scenes/FPSDemo.scene");
|
||||||
NewScene();
|
NewScene();
|
||||||
|
|
||||||
FileSystemWatcher::StartWatching();
|
AssetEditorPanel::RegisterDefaultEditors();
|
||||||
|
FileSystem::StartWatching();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorLayer::OnDetach()
|
void EditorLayer::OnDetach()
|
||||||
{
|
{
|
||||||
FileSystemWatcher::StopWatching();
|
FileSystem::StopWatching();
|
||||||
m_EditorScene->OnShutdown();
|
m_EditorScene->OnShutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -404,10 +405,6 @@ namespace Prism
|
|||||||
ImGui::EndMenuBar();
|
ImGui::EndMenuBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_SceneHierarchyPanel->OnImGuiRender();
|
|
||||||
PhysicsSettingsWindow::OnImGuiRender(m_ShowPhysicsSettings);
|
|
||||||
SceneRenderer::OnImGuiRender();
|
|
||||||
// m_EditorCamera.OnImGuiRender();
|
|
||||||
|
|
||||||
ImGui::Begin("Materials");
|
ImGui::Begin("Materials");
|
||||||
|
|
||||||
@ -616,7 +613,6 @@ namespace Prism
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
ScriptEngine::OnImGuiRender();
|
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
@ -661,6 +657,12 @@ namespace Prism
|
|||||||
if (m_UIShowBoundingBoxes && Property("On Top", m_UIShowBoundingBoxesOnTop))
|
if (m_UIShowBoundingBoxes && Property("On Top", m_UIShowBoundingBoxesOnTop))
|
||||||
ShowBoundingBoxes(m_UIShowBoundingBoxes, m_UIShowBoundingBoxesOnTop);
|
ShowBoundingBoxes(m_UIShowBoundingBoxes, m_UIShowBoundingBoxesOnTop);
|
||||||
|
|
||||||
|
m_SceneHierarchyPanel->OnImGuiRender();
|
||||||
|
PhysicsSettingsWindow::OnImGuiRender(m_ShowPhysicsSettings);
|
||||||
|
SceneRenderer::OnImGuiRender();
|
||||||
|
AssetEditorPanel::OnImGuiRender();
|
||||||
|
ScriptEngine::OnImGuiRender();
|
||||||
|
|
||||||
m_AssetManagerPanel->OnImGuiRender();
|
m_AssetManagerPanel->OnImGuiRender();
|
||||||
m_ObjectsPanel->OnImGuiRender();
|
m_ObjectsPanel->OnImGuiRender();
|
||||||
|
|
||||||
@ -772,7 +774,7 @@ namespace Prism
|
|||||||
m_EditorScene->SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
m_EditorScene->SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||||
if (m_RuntimeScene)
|
if (m_RuntimeScene)
|
||||||
m_RuntimeScene->SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
m_RuntimeScene->SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||||
m_EditorCamera.SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 1000.0f));
|
m_EditorCamera.SetProjectionMatrix(glm::perspectiveFov(glm::radians(45.0f), viewportSize.x, viewportSize.y, 0.1f, 10000.0f));
|
||||||
m_EditorCamera.SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
m_EditorCamera.SetViewportSize((uint32_t)viewportSize.x, (uint32_t)viewportSize.y);
|
||||||
ImGui::Image((ImTextureRef)SceneRenderer::GetFinalColorBufferRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
|
ImGui::Image((ImTextureRef)SceneRenderer::GetFinalColorBufferRendererID(), viewportSize, { 0, 1 }, { 1, 0 });
|
||||||
|
|
||||||
@ -847,37 +849,28 @@ namespace Prism
|
|||||||
|
|
||||||
if (ImGui::BeginDragDropTarget())
|
if (ImGui::BeginDragDropTarget())
|
||||||
{
|
{
|
||||||
auto payload = ImGui::AcceptDragDropPayload("scene_entity_objectP");
|
auto payload = ImGui::AcceptDragDropPayload("asset_payload");
|
||||||
if (payload)
|
if (payload)
|
||||||
{
|
{
|
||||||
const auto data = (DragDropData*)payload->Data;
|
int count = payload->DataSize / sizeof(AssetHandle);
|
||||||
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 */
|
for (int i = 0; i < count; i++)
|
||||||
if (ImGui::BeginDragDropTarget())
|
|
||||||
{
|
|
||||||
auto payload = ImGui::AcceptDragDropPayload("scene_entity_assetsP");
|
|
||||||
if (payload)
|
|
||||||
{
|
|
||||||
UUID assetId = *(UUID*)payload->Data;
|
|
||||||
Asset& asset = AssetsManager::GetAssetFromId(assetId);
|
|
||||||
|
|
||||||
if (asset.Type == AssetType::Scene)
|
|
||||||
{
|
{
|
||||||
OpenScene(asset.FilePath);
|
AssetHandle assetHandle = *(((AssetHandle*)payload->Data) + i);
|
||||||
}
|
Ref<Asset> asset = AssetsManager::GetAsset<Asset>(assetHandle);
|
||||||
|
|
||||||
if (asset.Type == AssetType::Mesh)
|
// We can't really support dragging and dropping scenes when we're dropping multiple assets
|
||||||
{
|
if (count == 1 && asset->Type == AssetType::Scene)
|
||||||
Entity entity = m_EditorScene->CreateEntity(asset.FileName);
|
{
|
||||||
entity.AddComponent<MeshComponent>(AssetsManager::InstantiateAsset<Mesh>(assetId));
|
OpenScene(asset->FilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asset->Type == AssetType::Mesh)
|
||||||
|
{
|
||||||
|
Entity entity = m_EditorScene->CreateEntity(asset->FileName);
|
||||||
|
entity.AddComponent<MeshComponent>(Ref<Mesh>(asset));
|
||||||
|
SelectEntity(entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndDragDropTarget();
|
ImGui::EndDragDropTarget();
|
||||||
|
|||||||
@ -118,7 +118,7 @@ namespace Prism
|
|||||||
|
|
||||||
struct RoughnessInput
|
struct RoughnessInput
|
||||||
{
|
{
|
||||||
float Value = 0.5f;
|
float Value = 1.0f;
|
||||||
Ref<Texture2D> TextureMap;
|
Ref<Texture2D> TextureMap;
|
||||||
bool UseTexture = false;
|
bool UseTexture = false;
|
||||||
};
|
};
|
||||||
|
|||||||
64
Prism/src/Prism/Asset/Asset.h
Normal file
64
Prism/src/Prism/Asset/Asset.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
//
|
||||||
|
// Created by Atdunbg on 2026/2/3.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef PRISM_ASSET_H
|
||||||
|
#define PRISM_ASSET_H
|
||||||
|
|
||||||
|
#include "Prism/Core/UUID.h"
|
||||||
|
#include "Prism/Core/Ref.h"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
enum class AssetType
|
||||||
|
{
|
||||||
|
Scene, Mesh, Texture, EnvMap, Audio, Script, PhysicsMat, Directory, Other
|
||||||
|
};
|
||||||
|
|
||||||
|
using AssetHandle = UUID;
|
||||||
|
|
||||||
|
class PRISM_API Asset : public RefCounted
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AssetHandle Handle;
|
||||||
|
AssetType Type;
|
||||||
|
|
||||||
|
std::string FilePath;
|
||||||
|
std::string FileName;
|
||||||
|
std::string Extension;
|
||||||
|
AssetHandle ParentDirectory;
|
||||||
|
|
||||||
|
bool IsDataLoaded = false;
|
||||||
|
|
||||||
|
virtual ~Asset()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class PRISM_API PhysicsMaterial : public Asset
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
float StaticFriction;
|
||||||
|
float DynamicFriction;
|
||||||
|
float Bounciness;
|
||||||
|
|
||||||
|
PhysicsMaterial() = default;
|
||||||
|
|
||||||
|
PhysicsMaterial(float staticFriction, float dynamicFriction, float bounciness)
|
||||||
|
: StaticFriction(staticFriction), DynamicFriction(dynamicFriction), Bounciness(bounciness)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Treating directories as assets simplifies the asset manager window rendering by a lot
|
||||||
|
class Directory : public Asset
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::vector<AssetHandle> ChildDirectories;
|
||||||
|
|
||||||
|
Directory() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //PRISM_ASSET_H
|
||||||
198
Prism/src/Prism/Asset/AssetSerializer.cpp
Normal file
198
Prism/src/Prism/Asset/AssetSerializer.cpp
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
//
|
||||||
|
// Created by Atdunbg on 2026/2/13.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AssetSerializer.h"
|
||||||
|
|
||||||
|
#include "Prism/Utilities/StringUtils.h"
|
||||||
|
#include "Prism/Utilities/FileSystem.h"
|
||||||
|
#include "Prism/Renderer/Mesh.h"
|
||||||
|
#include "Prism/Renderer/SceneEnvironment.h"
|
||||||
|
#include "Prism/Renderer/SceneRenderer.h"
|
||||||
|
|
||||||
|
#include "yaml-cpp/yaml.h"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
void AssetSerializer::SerializeAsset(const Ref<Asset>& asset, AssetType type)
|
||||||
|
{
|
||||||
|
YAML::Emitter out;
|
||||||
|
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case Prism::AssetType::PhysicsMat:
|
||||||
|
{
|
||||||
|
Ref<PhysicsMaterial> material = Ref<PhysicsMaterial>(asset);
|
||||||
|
out << YAML::Key << "StaticFriction" << material->StaticFriction;
|
||||||
|
out << YAML::Key << "DynamicFriction" << material->DynamicFriction;
|
||||||
|
out << YAML::Key << "Bounciness" << material->Bounciness;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
std::ofstream fout(asset->FilePath);
|
||||||
|
fout << out.c_str();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Asset> AssetSerializer::DeserializeYAML(const Ref<Asset>& asset)
|
||||||
|
{
|
||||||
|
const std::ifstream stream(asset->FilePath);
|
||||||
|
std::stringstream strStream;
|
||||||
|
strStream << stream.rdbuf();
|
||||||
|
|
||||||
|
YAML::Node data = YAML::Load(strStream.str());
|
||||||
|
|
||||||
|
if (asset->Type == AssetType::PhysicsMat)
|
||||||
|
{
|
||||||
|
float staticFriction = data["StaticFriction"].as<float>();
|
||||||
|
float dynamicFriction = data["DynamicFriction"].as<float>();
|
||||||
|
float bounciness = data["Bounciness"].as<float>();
|
||||||
|
|
||||||
|
return Ref<PhysicsMaterial>::Create(staticFriction, dynamicFriction, bounciness);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Ref<Asset> AssetSerializer::LoadAssetInfo(const std::string& filepath, AssetHandle parentHandle, AssetType type)
|
||||||
|
{
|
||||||
|
Ref<Asset> asset;
|
||||||
|
|
||||||
|
if (type == AssetType::Directory)
|
||||||
|
asset = Ref<Directory>::Create();
|
||||||
|
else
|
||||||
|
asset = Ref<Asset>::Create();
|
||||||
|
|
||||||
|
|
||||||
|
const std::string extension = Utils::GetExtension(filepath);
|
||||||
|
|
||||||
|
asset->FilePath = filepath;
|
||||||
|
std::replace(asset->FilePath.begin(), asset->FilePath.end(), '\\', '/');
|
||||||
|
|
||||||
|
const bool hasMeta = FileSystem::Exists(asset->FilePath + ".meta");
|
||||||
|
if (hasMeta)
|
||||||
|
{
|
||||||
|
LoadMetaData(asset);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (filepath == "assets")
|
||||||
|
asset->Handle = 0;
|
||||||
|
else
|
||||||
|
asset->Handle = AssetHandle();
|
||||||
|
|
||||||
|
asset->FileName = Utils::RemoveExtension(Utils::GetFilename(filepath));
|
||||||
|
asset->Extension = Utils::GetExtension(filepath);
|
||||||
|
asset->Type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
asset->ParentDirectory = parentHandle;
|
||||||
|
asset->IsDataLoaded = false;
|
||||||
|
|
||||||
|
if (!hasMeta)
|
||||||
|
CreateMetaFile(asset);
|
||||||
|
|
||||||
|
return asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Asset> AssetSerializer::LoadAssetData(Ref<Asset>& asset)
|
||||||
|
{
|
||||||
|
if (asset->Type == AssetType::Directory)
|
||||||
|
return asset;
|
||||||
|
|
||||||
|
Ref<Asset> temp = asset;
|
||||||
|
bool loadYAMLData = true;
|
||||||
|
|
||||||
|
switch (asset->Type)
|
||||||
|
{
|
||||||
|
case AssetType::Mesh:
|
||||||
|
{
|
||||||
|
if (asset->Extension != "blend")
|
||||||
|
asset = Ref<Mesh>::Create(asset->FilePath);
|
||||||
|
loadYAMLData = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AssetType::Texture:
|
||||||
|
{
|
||||||
|
asset = Texture2D::Create(asset->FilePath);
|
||||||
|
loadYAMLData = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AssetType::EnvMap:
|
||||||
|
{
|
||||||
|
auto [radiance, irradiance] = SceneRenderer::CreateEnvironmentMap(asset->FilePath);
|
||||||
|
asset = Ref<Environment>::Create(radiance, irradiance);
|
||||||
|
loadYAMLData = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AssetType::Scene:
|
||||||
|
case AssetType::Audio:
|
||||||
|
case AssetType::Script:
|
||||||
|
case AssetType::Other:
|
||||||
|
{
|
||||||
|
loadYAMLData = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AssetType::PhysicsMat:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loadYAMLData)
|
||||||
|
{
|
||||||
|
asset = DeserializeYAML(asset);
|
||||||
|
PM_CORE_ASSERT(asset, "Failed to load asset");
|
||||||
|
}
|
||||||
|
|
||||||
|
asset->Handle = temp->Handle;
|
||||||
|
asset->FilePath = temp->FilePath;
|
||||||
|
asset->FileName = temp->FileName;
|
||||||
|
asset->Extension = temp->Extension;
|
||||||
|
asset->ParentDirectory = temp->ParentDirectory;
|
||||||
|
asset->Type = temp->Type;
|
||||||
|
asset->IsDataLoaded = true;
|
||||||
|
|
||||||
|
return asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AssetSerializer::LoadMetaData(Ref<Asset>& asset)
|
||||||
|
{
|
||||||
|
std::ifstream stream(asset->FilePath + ".meta");
|
||||||
|
std::stringstream strStream;
|
||||||
|
strStream << stream.rdbuf();
|
||||||
|
|
||||||
|
YAML::Node data = YAML::Load(strStream.str());
|
||||||
|
if (!data["Asset"])
|
||||||
|
{
|
||||||
|
PM_CORE_ASSERT("Invalid File Format");
|
||||||
|
}
|
||||||
|
|
||||||
|
asset->Handle = data["Asset"].as<uint64_t>();
|
||||||
|
asset->FileName = data["FileName"].as<std::string>();
|
||||||
|
asset->FilePath = data["FilePath"].as<std::string>();
|
||||||
|
asset->Extension = data["Extension"].as<std::string>();
|
||||||
|
asset->Type = (AssetType)data["Type"].as<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetSerializer::CreateMetaFile(const Ref<Asset>& asset)
|
||||||
|
{
|
||||||
|
YAML::Emitter out;
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "Asset" << YAML::Value << asset->Handle;
|
||||||
|
out << YAML::Key << "FileName" << YAML::Value << asset->FileName;
|
||||||
|
out << YAML::Key << "FilePath" << YAML::Value << asset->FilePath;
|
||||||
|
out << YAML::Key << "Extension" << YAML::Value << asset->Extension;
|
||||||
|
out << YAML::Key << "Directory" << YAML::Value << asset->ParentDirectory;
|
||||||
|
out << YAML::Key << "Type" << YAML::Value << (int)asset->Type;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
|
std::ofstream fout(asset->FilePath + ".meta");
|
||||||
|
fout << out.c_str();
|
||||||
|
}
|
||||||
|
}
|
||||||
38
Prism/src/Prism/Asset/AssetSerializer.h
Normal file
38
Prism/src/Prism/Asset/AssetSerializer.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// Created by Atdunbg on 2026/2/13.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef PRISM_ASSETSERIALIZER_H
|
||||||
|
#define PRISM_ASSETSERIALIZER_H
|
||||||
|
|
||||||
|
#include "Asset.h"
|
||||||
|
#include "Prism/Core/Ref.h"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
class PRISM_API AssetSerializer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<typename T>
|
||||||
|
static void SerializeAsset(const Ref<T>& asset)
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of<Asset, T>::value, "SerializeAsset only accepts types that inherit from Asset");
|
||||||
|
SerializeAsset(asset, asset->Type);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Ref<Asset> LoadAssetInfo(const std::string& filepath, AssetHandle parentHandle, AssetType type);
|
||||||
|
static Ref<Asset> LoadAssetData(Ref<Asset>& asset);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void SerializeAsset(const Ref<Asset>& asset, AssetType type);
|
||||||
|
static Ref<Asset> DeserializeYAML(const Ref<Asset>& asset);
|
||||||
|
static void LoadMetaData(Ref<Asset>& asset);
|
||||||
|
static void CreateMetaFile(const Ref<Asset>& asset);
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend class AssetsManager;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //PRISM_ASSETSERIALIZER_H
|
||||||
450
Prism/src/Prism/Asset/AssetsManager.cpp
Normal file
450
Prism/src/Prism/Asset/AssetsManager.cpp
Normal file
@ -0,0 +1,450 @@
|
|||||||
|
//
|
||||||
|
// Created by Atdunbg on 2026/1/20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AssetsManager.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "Prism/Core/Log.h"
|
||||||
|
#include "Prism/Renderer/Mesh.h"
|
||||||
|
|
||||||
|
#include <yaml-cpp/yaml.h>
|
||||||
|
|
||||||
|
#include "AssetSerializer.h"
|
||||||
|
#include "Prism/Renderer/SceneEnvironment.h"
|
||||||
|
#include "Prism/Utilities/StringUtils.h"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
void AssetTypes::Init()
|
||||||
|
{
|
||||||
|
s_Types["scene"] = AssetType::Scene;
|
||||||
|
s_Types["pmx"] = AssetType::Mesh;
|
||||||
|
s_Types["fbx"] = AssetType::Mesh;
|
||||||
|
s_Types["obj"] = AssetType::Mesh;
|
||||||
|
s_Types["png"] = AssetType::Texture;
|
||||||
|
s_Types["hdr"] = AssetType::EnvMap;
|
||||||
|
s_Types["blend"] = AssetType::Mesh;
|
||||||
|
s_Types["hpm"] = AssetType::PhysicsMat;
|
||||||
|
s_Types["wav"] = AssetType::Audio;
|
||||||
|
s_Types["ogg"] = AssetType::Audio;
|
||||||
|
s_Types["cs"] = AssetType::Script;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AssetTypes::GetAssetTypeID(const std::string& extension)
|
||||||
|
{
|
||||||
|
if (extension.empty())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
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::AssetsChangeEventFn AssetsManager::s_AssetsChangeCallback;
|
||||||
|
std::unordered_map<AssetHandle, Ref<Asset>> AssetsManager::s_LoadedAssets;
|
||||||
|
|
||||||
|
void AssetsManager::Init()
|
||||||
|
{
|
||||||
|
FileSystem::SetChangeCallback(OnFileSystemChanged);
|
||||||
|
ReloadAssets();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetsManager::SetAssetChangeCallback(const AssetsChangeEventFn& callback)
|
||||||
|
{
|
||||||
|
s_AssetsChangeCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetsManager::Shutdown()
|
||||||
|
{
|
||||||
|
s_LoadedAssets.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Ref<Asset>> AssetsManager::GetAssetsInDirectory(AssetHandle directoryHandle)
|
||||||
|
{
|
||||||
|
std::vector<Ref<Asset>> results;
|
||||||
|
|
||||||
|
for (const auto& asset : s_LoadedAssets)
|
||||||
|
{
|
||||||
|
if (asset.second && asset.second->ParentDirectory == directoryHandle && asset.second->Handle != directoryHandle)
|
||||||
|
results.push_back(asset.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<Ref<Asset>> AssetsManager::SearchFiles(const std::string& query, const std::string& searchPath)
|
||||||
|
{
|
||||||
|
std::vector<Ref<Asset>> results;
|
||||||
|
|
||||||
|
if (!searchPath.empty())
|
||||||
|
{
|
||||||
|
for (const auto&[key, asset] : s_LoadedAssets)
|
||||||
|
{
|
||||||
|
if (asset->FileName.find(query) != std::string::npos && asset->FilePath.find(searchPath) != std::string::npos)
|
||||||
|
{
|
||||||
|
results.push_back(asset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::string AssetsManager::GetParentPath(const std::string& path)
|
||||||
|
{
|
||||||
|
return std::filesystem::path(path).parent_path().string();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssetsManager::IsDirectory(const std::string& filepath)
|
||||||
|
{
|
||||||
|
for (auto&[handle, asset] : s_LoadedAssets)
|
||||||
|
{
|
||||||
|
if (asset->Type == AssetType::Directory && asset->FilePath == filepath)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetHandle AssetsManager::GetAssetIDForFile(const std::string& filepath)
|
||||||
|
{
|
||||||
|
for (auto&[id, asset] : s_LoadedAssets)
|
||||||
|
{
|
||||||
|
if (asset->FilePath == filepath)
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AssetsManager::IsAssetHandleValid(const AssetHandle& assetHandle)
|
||||||
|
{
|
||||||
|
return s_LoadedAssets.find(assetHandle) != s_LoadedAssets.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetsManager::Rename(Ref<Asset>& asset, const std::string& newName)
|
||||||
|
{
|
||||||
|
const std::string newFilePath = FileSystem::Rename(asset->FilePath, newName);
|
||||||
|
const std::string oldFilePath = asset->FilePath;
|
||||||
|
asset->FilePath = newFilePath;
|
||||||
|
asset->FileName = newName;
|
||||||
|
|
||||||
|
if (FileSystem::Exists(oldFilePath + ".meta"))
|
||||||
|
{
|
||||||
|
std::string metaFileName = oldFilePath;
|
||||||
|
|
||||||
|
if (!asset->Extension.empty())
|
||||||
|
metaFileName += "." + asset->Extension;
|
||||||
|
|
||||||
|
FileSystem::Rename(oldFilePath + ".meta", metaFileName);
|
||||||
|
AssetSerializer::CreateMetaFile(asset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Ref<T> AssetsManager::GetAsset(const AssetHandle assetHandle)
|
||||||
|
{
|
||||||
|
PM_CORE_ASSERT(s_LoadedAssets.find(assetHandle) != s_LoadedAssets.end());
|
||||||
|
Ref<Asset> asset = s_LoadedAssets[assetHandle];
|
||||||
|
|
||||||
|
if (!asset->IsDataLoaded)
|
||||||
|
asset = AssetSerializer::LoadAssetData(asset);
|
||||||
|
|
||||||
|
return asset.As<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template PRISM_API Ref<Asset> AssetsManager::GetAsset(AssetHandle);
|
||||||
|
template PRISM_API Ref<Mesh> AssetsManager::GetAsset(AssetHandle);
|
||||||
|
template PRISM_API Ref<PhysicsMaterial> AssetsManager::GetAsset(AssetHandle);
|
||||||
|
template PRISM_API Ref<Environment> AssetsManager::GetAsset(AssetHandle);
|
||||||
|
template PRISM_API Ref<Directory> AssetsManager::GetAsset(AssetHandle);
|
||||||
|
|
||||||
|
// temp
|
||||||
|
Ref<PhysicsMaterial> AssetsManager::CreateAssetPhysicsMaterial(const std::string& filename, const AssetType type, const AssetHandle& directoryHandle, float v1, float v2, float v3)
|
||||||
|
{
|
||||||
|
|
||||||
|
const auto& directory = GetAsset<Directory>(directoryHandle);
|
||||||
|
|
||||||
|
Ref<PhysicsMaterial> asset = Ref<PhysicsMaterial>::Create(v1, v2, v3);
|
||||||
|
asset->Type = type;
|
||||||
|
asset->FilePath = directory->FilePath + "/" + filename;
|
||||||
|
asset->FileName = Utils::RemoveExtension(Utils::GetFilename(asset->FilePath));
|
||||||
|
asset->Extension = Utils::GetFilename(filename);
|
||||||
|
asset->ParentDirectory = directoryHandle;
|
||||||
|
asset->Handle = std::hash<std::string>()(asset->FilePath);
|
||||||
|
s_LoadedAssets[asset->Handle] = asset;
|
||||||
|
|
||||||
|
AssetSerializer::SerializeAsset(asset);
|
||||||
|
|
||||||
|
return asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetsManager::RemoveAsset(AssetHandle assetHandle)
|
||||||
|
{
|
||||||
|
Ref<Asset> asset = s_LoadedAssets[assetHandle];
|
||||||
|
if (asset->Type == AssetType::Directory)
|
||||||
|
{
|
||||||
|
if (IsAssetHandleValid(asset->ParentDirectory))
|
||||||
|
{
|
||||||
|
auto& childList = s_LoadedAssets[asset->ParentDirectory].As<Directory>()->ChildDirectories;
|
||||||
|
childList.erase(std::remove(childList.begin(), childList.end(), assetHandle), childList.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto child : asset.As<Directory>()->ChildDirectories)
|
||||||
|
RemoveAsset(child);
|
||||||
|
|
||||||
|
for (auto it = s_LoadedAssets.begin(); it != s_LoadedAssets.end(); )
|
||||||
|
{
|
||||||
|
if (it->second->ParentDirectory != assetHandle)
|
||||||
|
{
|
||||||
|
++it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
it = s_LoadedAssets.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_LoadedAssets.erase(assetHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
Ref<T> AssetsManager::CreateAsset(const std::string& filename, AssetType type, AssetHandle directoryHandle, Args&&... args)
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of_v<Asset, T>, "CreateAsset only works for types derived from Asset");
|
||||||
|
|
||||||
|
const auto& directory = GetAsset<Directory>(directoryHandle);
|
||||||
|
|
||||||
|
Ref<T> asset = Ref<T>::Create(std::forward<Args>(args)...);
|
||||||
|
asset->Type = type;
|
||||||
|
asset->FilePath = directory->FilePath + "/" + filename;
|
||||||
|
asset->FileName = Utils::RemoveExtension(Utils::GetFilename(asset->FilePath));
|
||||||
|
asset->Extension = Utils::GetFilename(filename);
|
||||||
|
asset->ParentDirectory = directoryHandle;
|
||||||
|
asset->Handle = std::hash<std::string>()(asset->FilePath);
|
||||||
|
asset->IsDataLoaded = true;
|
||||||
|
s_LoadedAssets[asset->Handle] = asset;
|
||||||
|
|
||||||
|
AssetSerializer::SerializeAsset(asset);
|
||||||
|
|
||||||
|
return asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool AssetsManager::IsAssetType(const AssetHandle assetHandle, const AssetType type)
|
||||||
|
{
|
||||||
|
return s_LoadedAssets.find(assetHandle) != s_LoadedAssets.end() && s_LoadedAssets[assetHandle]->Type == type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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& filepath, AssetHandle parentHandle)
|
||||||
|
{
|
||||||
|
const std::string extension = Utils::GetExtension(filepath);
|
||||||
|
if (extension == "meta")
|
||||||
|
return;
|
||||||
|
|
||||||
|
const AssetType type = AssetTypes::GetAssetTypeFromExtension(extension);
|
||||||
|
Ref<Asset> asset = AssetSerializer::LoadAssetInfo(filepath, parentHandle, type);
|
||||||
|
|
||||||
|
if (s_LoadedAssets.find(asset->Handle) != s_LoadedAssets.end())
|
||||||
|
{
|
||||||
|
if (s_LoadedAssets[asset->Handle]->IsDataLoaded)
|
||||||
|
{
|
||||||
|
asset = AssetSerializer::LoadAssetData(asset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s_LoadedAssets[asset->Handle] = asset;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
system(convCommand.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetHandle AssetsManager::ProcessDirectory(const std::string& directoryPath, AssetHandle parentHandle)
|
||||||
|
{
|
||||||
|
Ref<Directory> dirInfo = AssetSerializer::LoadAssetInfo(directoryPath, parentHandle, AssetType::Directory).As<Directory>();
|
||||||
|
s_LoadedAssets[dirInfo->Handle] = dirInfo;
|
||||||
|
|
||||||
|
if (parentHandle != dirInfo->Handle && IsAssetHandleValid(parentHandle))
|
||||||
|
s_LoadedAssets[parentHandle].As<Directory>()->ChildDirectories.push_back(dirInfo->Handle);
|
||||||
|
|
||||||
|
for (const auto& entry : std::filesystem::directory_iterator(directoryPath))
|
||||||
|
{
|
||||||
|
if (entry.is_directory())
|
||||||
|
ProcessDirectory(entry.path().string(), dirInfo->Handle);
|
||||||
|
else
|
||||||
|
ImportAsset(entry.path().string(), dirInfo->Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dirInfo->Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetsManager::ReloadAssets()
|
||||||
|
{
|
||||||
|
ProcessDirectory("assets", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetsManager::OnFileSystemChanged(FileSystemChangedEvent e)
|
||||||
|
{
|
||||||
|
e.NewName = Utils::RemoveExtension(e.NewName);
|
||||||
|
e.OldName = Utils::RemoveExtension(e.OldName);
|
||||||
|
|
||||||
|
AssetHandle parentHandle = FindParentHandle(e.FilePath);
|
||||||
|
|
||||||
|
switch (e.Action)
|
||||||
|
{
|
||||||
|
case FileSystemAction::Added:
|
||||||
|
{
|
||||||
|
if (e.IsDirectory)
|
||||||
|
ProcessDirectory(e.FilePath, parentHandle);
|
||||||
|
else
|
||||||
|
ImportAsset(e.FilePath, parentHandle);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FileSystemAction::Modified:
|
||||||
|
{
|
||||||
|
if (!e.IsDirectory)
|
||||||
|
ImportAsset(e.FilePath, parentHandle);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FileSystemAction::Rename:
|
||||||
|
{
|
||||||
|
for (auto it = s_LoadedAssets.begin(); it != s_LoadedAssets.end(); it++)
|
||||||
|
{
|
||||||
|
if (it->second->FileName == e.OldName)
|
||||||
|
{
|
||||||
|
it->second->FilePath = e.FilePath;
|
||||||
|
it->second->FileName = e.NewName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FileSystemAction::Delete:
|
||||||
|
{
|
||||||
|
for (auto it = s_LoadedAssets.begin(); it != s_LoadedAssets.end(); it++)
|
||||||
|
{
|
||||||
|
if (it->second->FilePath != e.FilePath)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
RemoveAsset(it->first);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (s_AssetsChangeCallback)
|
||||||
|
s_AssetsChangeCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetHandle AssetsManager::FindParentHandleInChildren(Ref<Directory>& dir, const std::string& dirName)
|
||||||
|
{
|
||||||
|
if (dir->FileName == dirName)
|
||||||
|
return dir->Handle;
|
||||||
|
|
||||||
|
for (const AssetHandle& childHandle : dir->ChildDirectories)
|
||||||
|
{
|
||||||
|
Ref<Directory> child = GetAsset<Directory>(childHandle);
|
||||||
|
AssetHandle dirHandle = FindParentHandleInChildren(child, dirName);
|
||||||
|
|
||||||
|
if (IsAssetHandleValid(dirHandle))
|
||||||
|
return dirHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
AssetHandle AssetsManager::FindParentHandle(const std::string& filepath)
|
||||||
|
{
|
||||||
|
const std::vector<std::string> parts = Utils::SplitString(filepath, "/\\");
|
||||||
|
const std::string& parentFolder = parts[parts.size() - 2];
|
||||||
|
Ref<Directory> assetsDirectory = GetAsset<Directory>(0);
|
||||||
|
return FindParentHandleInChildren(assetsDirectory, parentFolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
86
Prism/src/Prism/Asset/AssetsManager.h
Normal file
86
Prism/src/Prism/Asset/AssetsManager.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
//
|
||||||
|
// Created by Atdunbg on 2026/1/20.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef PRISM_ASSETSMANAGER_H
|
||||||
|
#define PRISM_ASSETSMANAGER_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "Asset.h"
|
||||||
|
#include "Prism/Utilities/FileSystem.h"
|
||||||
|
#include "Prism/Core/Ref.h"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PRISM_API AssetsManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using AssetsChangeEventFn = std::function<void()>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static void Init();
|
||||||
|
static void SetAssetChangeCallback(const AssetsChangeEventFn& callback);
|
||||||
|
static void Shutdown();
|
||||||
|
|
||||||
|
static std::vector<Ref<Asset>> GetAssetsInDirectory(AssetHandle directoryHandle);
|
||||||
|
|
||||||
|
static std::vector<Ref<Asset>> SearchFiles(const std::string& query, const std::string& searchPath);
|
||||||
|
|
||||||
|
static std::string GetParentPath(const std::string& path);
|
||||||
|
|
||||||
|
static bool IsDirectory(const std::string& filepath);
|
||||||
|
|
||||||
|
static AssetHandle GetAssetIDForFile(const std::string& filepath);
|
||||||
|
static bool IsAssetHandleValid(const AssetHandle& assetHandle);
|
||||||
|
|
||||||
|
static void Rename(Ref<Asset>& asset, const std::string& newName);
|
||||||
|
|
||||||
|
static Ref<PhysicsMaterial> CreateAssetPhysicsMaterial(const std::string& filename, AssetType type, const AssetHandle& directoryHandle, float v1, float v2, float v3);
|
||||||
|
|
||||||
|
static void RemoveAsset(AssetHandle assetHandle);
|
||||||
|
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
static Ref<T> CreateAsset(const std::string& filename, AssetType type, AssetHandle directoryHandle, Args&&... args);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static Ref<T> GetAsset(AssetHandle assetHandle);
|
||||||
|
|
||||||
|
static bool IsAssetType(AssetHandle assetHandle, AssetType type);
|
||||||
|
|
||||||
|
static std::string StripExtras(const std::string& filename);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static void ImportAsset(const std::string& filepath, AssetHandle parentHandle);
|
||||||
|
static void ConvertAsset(const std::string& assetPath, const std::string& conversionType);
|
||||||
|
static AssetHandle ProcessDirectory(const std::string& directoryPath, AssetHandle parentHandle);
|
||||||
|
static void ReloadAssets();
|
||||||
|
|
||||||
|
static void OnFileSystemChanged(FileSystemChangedEvent e);
|
||||||
|
|
||||||
|
static AssetHandle FindParentHandleInChildren(Ref<Directory>& dir, const std::string& dirName);
|
||||||
|
static AssetHandle FindParentHandle(const std::string& filepath);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::unordered_map<AssetHandle, Ref<Asset>> s_LoadedAssets;
|
||||||
|
static AssetsChangeEventFn s_AssetsChangeCallback;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //PRISM_ASSETSMANAGER_H
|
||||||
@ -13,7 +13,7 @@
|
|||||||
#include "tinyfiledialogs.h"
|
#include "tinyfiledialogs.h"
|
||||||
#include "Prism/Physics/Physics3D.h"
|
#include "Prism/Physics/Physics3D.h"
|
||||||
#include "Prism/Script/ScriptEngine.h"
|
#include "Prism/Script/ScriptEngine.h"
|
||||||
#include "Prism/Utilities/AssetsManager.h"
|
#include "Prism/Asset/AssetsManager.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
@ -55,6 +55,7 @@ namespace Prism
|
|||||||
|
|
||||||
Physics3D::Shutdown();
|
Physics3D::Shutdown();
|
||||||
ScriptEngine::Shutdown();
|
ScriptEngine::Shutdown();
|
||||||
|
AssetsManager::Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::Run()
|
void Application::Run()
|
||||||
|
|||||||
@ -9,6 +9,9 @@
|
|||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
|
#include "../../Asset/Asset.h"
|
||||||
|
#include "../../Asset/AssetsManager.h"
|
||||||
|
|
||||||
namespace Prism::UI {
|
namespace Prism::UI {
|
||||||
|
|
||||||
static int s_UIContextID = 0;
|
static int s_UIContextID = 0;
|
||||||
@ -143,7 +146,7 @@ namespace Prism::UI {
|
|||||||
return modified;
|
return modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool Property(const char* label, float& value, const float delta = 0.1f, const float min = 0.0f, const float max = 0.0f)
|
static bool Property(const char* label, float& value, const float delta = 0.1f, const float min = 0.0f, const float max = 0.0f, const bool readOnly = false)
|
||||||
{
|
{
|
||||||
bool modified = false;
|
bool modified = false;
|
||||||
|
|
||||||
@ -155,8 +158,16 @@ namespace Prism::UI {
|
|||||||
s_IDBuffer[1] = '#';
|
s_IDBuffer[1] = '#';
|
||||||
memset(s_IDBuffer + 2, 0, 14);
|
memset(s_IDBuffer + 2, 0, 14);
|
||||||
snprintf(s_IDBuffer + 2, 14, "%x", s_Counter++);
|
snprintf(s_IDBuffer + 2, 14, "%x", s_Counter++);
|
||||||
if (ImGui::DragFloat(s_IDBuffer, &value, delta, min, max))
|
|
||||||
modified = true;
|
if (!readOnly)
|
||||||
|
{
|
||||||
|
if (ImGui::DragFloat(s_IDBuffer, &value, delta, min, max))
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui::InputFloat(s_IDBuffer, &value, 0.0f, 0.0f, "%.3f", ImGuiInputTextFlags_ReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
@ -248,6 +259,46 @@ namespace Prism::UI {
|
|||||||
return modified;
|
return modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static bool PropertyAssetReference(const char* label, Ref<T>& object, AssetType supportedType)
|
||||||
|
{
|
||||||
|
bool modified = false;
|
||||||
|
|
||||||
|
ImGui::Text("%s", label);
|
||||||
|
ImGui::NextColumn();
|
||||||
|
ImGui::PushItemWidth(-1);
|
||||||
|
|
||||||
|
if (object)
|
||||||
|
{
|
||||||
|
char* assetName = ((Ref<Asset>&)object)->FileName.data();
|
||||||
|
ImGui::InputText("##assetRef", assetName, 256, ImGuiInputTextFlags_ReadOnly);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ImGui::InputText("##assetRef", (char*)"Null", 256, ImGuiInputTextFlags_ReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (ImGui::BeginDragDropTarget())
|
||||||
|
{
|
||||||
|
auto data = ImGui::AcceptDragDropPayload("asset_payload");
|
||||||
|
|
||||||
|
if (data)
|
||||||
|
{
|
||||||
|
AssetHandle assetHandle = *(AssetHandle*)data->Data;
|
||||||
|
if (AssetsManager::IsAssetType(assetHandle, supportedType))
|
||||||
|
{
|
||||||
|
object = AssetsManager::GetAsset<T>(assetHandle);
|
||||||
|
modified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopItemWidth();
|
||||||
|
ImGui::NextColumn();
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
static void EndPropertyGrid()
|
static void EndPropertyGrid()
|
||||||
{
|
{
|
||||||
ImGui::Columns(1);
|
ImGui::Columns(1);
|
||||||
|
|||||||
@ -123,6 +123,12 @@ namespace Prism
|
|||||||
m_Instance = instance;
|
m_Instance = instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T2>
|
||||||
|
Ref<T2> As()
|
||||||
|
{
|
||||||
|
return Ref<T2>(*this);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static Ref<T> Create(Args&&... args)
|
static Ref<T> Create(Args&&... args)
|
||||||
{
|
{
|
||||||
|
|||||||
85
Prism/src/Prism/Editor/AssetEditorPanel.cpp
Normal file
85
Prism/src/Prism/Editor/AssetEditorPanel.cpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
//
|
||||||
|
// Created by Atdunbg on 2026/2/14.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AssetEditorPanel.h"
|
||||||
|
|
||||||
|
#include "DefaultAssetEditors.h"
|
||||||
|
#include "Prism/Core/Log.h"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
AssetEditor::AssetEditor(const char* title)
|
||||||
|
: m_Title(title), m_MinSize(200, 400), m_MaxSize(2000, 2000)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetEditor::OnImGuiRender()
|
||||||
|
{
|
||||||
|
if (!m_IsOpen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// NOTE(Peter): SetNextWindowSizeConstraints requires a max constraint that's above 0. For now we're just setting it to a large value
|
||||||
|
ImGui::SetNextWindowSizeConstraints(m_MinSize, m_MaxSize);
|
||||||
|
ImGui::Begin(m_Title, &m_IsOpen, m_Flags);
|
||||||
|
Render();
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetEditor::SetMinSize(uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
if (width <= 0) width = 200;
|
||||||
|
if (height <= 0) height = 400;
|
||||||
|
|
||||||
|
m_MinSize = ImVec2((float)width, (float)height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetEditor::SetMaxSize(uint32_t width, uint32_t height)
|
||||||
|
{
|
||||||
|
if (width <= 0) width = 2000;
|
||||||
|
if (height <= 0) height = 2000;
|
||||||
|
if (width <= (uint32_t)m_MinSize.x) width = (uint32_t)m_MinSize.x * 2;
|
||||||
|
if (height <= (uint32_t)m_MinSize.y) height = (uint32_t)m_MinSize.y * 2;
|
||||||
|
|
||||||
|
m_MaxSize = ImVec2((float)width, (float)height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetEditorPanel::RegisterDefaultEditors()
|
||||||
|
{
|
||||||
|
RegisterEditor<TextureEditor>(AssetType::Texture);
|
||||||
|
RegisterEditor<PhysicsMaterialEditor>(AssetType::PhysicsMat);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetEditorPanel::OnImGuiRender()
|
||||||
|
{
|
||||||
|
for (const auto& kv : s_Editors)
|
||||||
|
kv.second->OnImGuiRender();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetEditorPanel::OpenEditor(const Ref<Asset>& asset)
|
||||||
|
{
|
||||||
|
if (s_Editors.find(asset->Type) == s_Editors.end())
|
||||||
|
{
|
||||||
|
PM_CORE_WARN("No editor registered for {0} assets", asset->Extension);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_Editors[asset->Type]->SetOpen(true);
|
||||||
|
s_Editors[asset->Type]->SetAsset(asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void AssetEditorPanel::RegisterEditor(const AssetType type)
|
||||||
|
{
|
||||||
|
static_assert(std::is_base_of_v<AssetEditor, T>, "AssetEditorPanel::RegisterEditor requires template type to inherit from AssetEditor");
|
||||||
|
PM_CORE_ASSERT(s_Editors.find(type) == s_Editors.end(), "There's already an editor for that asset!");
|
||||||
|
s_Editors[type] = CreateScope<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template PRISM_API void AssetEditorPanel::RegisterEditor<TextureEditor>(AssetType);
|
||||||
|
template PRISM_API void AssetEditorPanel::RegisterEditor<PhysicsMaterialEditor>(AssetType);
|
||||||
|
|
||||||
|
std::unordered_map<AssetType, Scope<AssetEditor>> AssetEditorPanel::s_Editors;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
56
Prism/src/Prism/Editor/AssetEditorPanel.h
Normal file
56
Prism/src/Prism/Editor/AssetEditorPanel.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
//
|
||||||
|
// Created by Atdunbg on 2026/2/14.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef PRISM_ASSETEDITORPANEL_H
|
||||||
|
#define PRISM_ASSETEDITORPANEL_H
|
||||||
|
|
||||||
|
#include "Prism/Core/ImGui/ImGui.h"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
class AssetEditor
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~AssetEditor(){}
|
||||||
|
|
||||||
|
void OnImGuiRender();
|
||||||
|
void SetOpen(const bool isOpen) { m_IsOpen = isOpen; }
|
||||||
|
virtual void SetAsset(const Ref<Asset>& asset) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AssetEditor(const char* title);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void SetMinSize(uint32_t width, uint32_t height);
|
||||||
|
void SetMaxSize(uint32_t width, uint32_t height);
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void Render() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* m_Title;
|
||||||
|
bool m_IsOpen = false;
|
||||||
|
|
||||||
|
ImGuiWindowFlags m_Flags = 0;
|
||||||
|
ImVec2 m_MinSize, m_MaxSize;
|
||||||
|
};
|
||||||
|
class PRISM_API AssetEditorPanel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void RegisterDefaultEditors();
|
||||||
|
static void OnImGuiRender();
|
||||||
|
static void OpenEditor(const Ref<Asset>& asset);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static void RegisterEditor(AssetType type);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static std::unordered_map<AssetType, Scope<AssetEditor>> s_Editors;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //PRISM_ASSETEDITORPANEL_H
|
||||||
@ -6,7 +6,9 @@
|
|||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include "AssetEditorPanel.h"
|
||||||
#include "Prism/Core/Application.h"
|
#include "Prism/Core/Application.h"
|
||||||
|
#include "Prism/Core/Input.h"
|
||||||
#include "Prism/Core/Log.h"
|
#include "Prism/Core/Log.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
@ -15,17 +17,13 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
AssetsManager::SetAssetChangeCallback([&]()
|
AssetsManager::SetAssetChangeCallback([&]()
|
||||||
{
|
{
|
||||||
UpdateCurrentDirectory(m_CurrentDirIndex);
|
UpdateCurrentDirectory(m_CurrentDirHandle);
|
||||||
});
|
});
|
||||||
|
|
||||||
m_FolderTex = Texture2D::Create("assets/editor/folder.png");
|
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[-1] = Texture2D::Create("assets/editor/file.png");
|
||||||
|
m_AssetIconMap[0] = m_FolderTex;
|
||||||
m_AssetIconMap[AssetTypes::GetAssetTypeID("hdr")] = Texture2D::Create("assets/editor/file.png");
|
m_AssetIconMap[AssetTypes::GetAssetTypeID("hdr")] = Texture2D::Create("assets/editor/file.png");
|
||||||
m_AssetIconMap[AssetTypes::GetAssetTypeID("fbx")] = Texture2D::Create("assets/editor/fbx.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("obj")] = Texture2D::Create("assets/editor/obj.png");
|
||||||
@ -41,361 +39,371 @@ namespace Prism
|
|||||||
m_FwrdbtnTex = Texture2D::Create("assets/editor/btn_fwrd.png");
|
m_FwrdbtnTex = Texture2D::Create("assets/editor/btn_fwrd.png");
|
||||||
m_FolderRightTex = Texture2D::Create("assets/editor/folder_hierarchy.png");
|
m_FolderRightTex = Texture2D::Create("assets/editor/folder_hierarchy.png");
|
||||||
m_SearchTex = Texture2D::Create("assets/editor/search.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_BaseDirIndex = 0;
|
m_BaseDirectoryHandle = 0;
|
||||||
m_CurrentDirIndex = 0;
|
m_BaseDirectory = AssetsManager::GetAsset<Directory>(m_BaseDirectoryHandle);
|
||||||
m_PrevDirIndex = 0;
|
UpdateCurrentDirectory(m_BaseDirectoryHandle);
|
||||||
m_NextDirIndex = 0;
|
|
||||||
|
|
||||||
m_BaseProjectDir = AssetsManager::GetDirectoryInfo(m_BaseDirIndex);
|
memset(m_InputBuffer, 0, MAX_INPUT_BUFFER_LENGTH);
|
||||||
UpdateCurrentDirectory(m_BaseDirIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int s_ColumnCount = 10;
|
||||||
|
|
||||||
void AssetsManagerPanel::OnImGuiRender()
|
void AssetsManagerPanel::OnImGuiRender()
|
||||||
{
|
{
|
||||||
ImGui::Begin("Project", nullptr, ImGuiWindowFlags_MenuBar);
|
ImGui::Begin("Project", nullptr, ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_MenuBar);
|
||||||
{
|
{
|
||||||
|
// list folder (Contents)
|
||||||
UI::BeginPropertyGrid();
|
UI::BeginPropertyGrid();
|
||||||
ImGui::SetColumnOffset(1, 250);
|
|
||||||
|
|
||||||
ImGui::BeginChild("##folders_common");
|
|
||||||
{
|
{
|
||||||
if (ImGui::CollapsingHeader("Contents", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
|
ImGui::SetColumnOffset(1, 250);
|
||||||
|
|
||||||
|
ImGui::BeginChild("##folders_common");
|
||||||
{
|
{
|
||||||
for (const int ChildrenIndice : m_BaseProjectDir.ChildrenIndices)
|
if (ImGui::CollapsingHeader("Contents", nullptr, ImGuiTreeNodeFlags_DefaultOpen))
|
||||||
{
|
{
|
||||||
DrawDirectoryInfo(AssetsManager::GetDirectoryInfo(ChildrenIndice));
|
for (const AssetHandle& child : m_BaseDirectory->ChildDirectories)
|
||||||
|
{
|
||||||
|
DrawDirectoryInfo(child);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
ImGui::EndChild();
|
||||||
ImGui::EndChild();
|
|
||||||
|
|
||||||
|
|
||||||
if (ImGui::BeginDragDropTarget())
|
ImGui::NextColumn();
|
||||||
{
|
|
||||||
const auto payload = ImGui::AcceptDragDropPayload("selectable", ImGuiDragDropFlags_AcceptNoDrawDefaultRect);
|
// Grid and list files
|
||||||
if (payload)
|
ImGui::BeginChild("##directory_structure", ImVec2(ImGui::GetColumnWidth() - 12, ImGui::GetWindowHeight() - 60));
|
||||||
|
// ImGui::BeginChild("##directory_structure", ImVec2(ImGui::GetColumnWidth() - 12, ImGui::GetContentRegionAvail().y));
|
||||||
{
|
{
|
||||||
const std::string file = static_cast<char*>(payload->Data);
|
ImGui::BeginChild("##directory_breadcrumbs", ImVec2(ImGui::GetColumnWidth() - 100, 30));
|
||||||
if (AssetsManager::MoveFile(file, m_MovePath))
|
RenderBreadCrumbs();
|
||||||
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
ImGui::BeginChild("Scrolling");
|
||||||
{
|
{
|
||||||
PM_CORE_INFO("Moved File: " + file + " to " + m_MovePath);
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.0f, 0.0f, 0.0f, 0.0f));
|
||||||
UpdateCurrentDirectory(m_CurrentDirIndex);
|
|
||||||
|
if (Input::IsKeyPressed(KeyCode::ESCAPE) || (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !m_IsAnyItemHovered))
|
||||||
|
{
|
||||||
|
m_SelectedAssets.Clear();
|
||||||
|
m_RenamingSelected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_IsAnyItemHovered = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (ImGui::BeginPopupContextWindow())
|
||||||
|
{
|
||||||
|
if (ImGui::BeginMenu("Create"))
|
||||||
|
{
|
||||||
|
if (ImGui::MenuItem("Folder"))
|
||||||
|
{
|
||||||
|
PM_CORE_INFO("Creating Folder...");
|
||||||
|
const bool created = FileSystem::CreateFolder(m_CurrentDirectory->FilePath + "/New Folder");
|
||||||
|
if (created)
|
||||||
|
{
|
||||||
|
UpdateCurrentDirectory(m_CurrentDirHandle);
|
||||||
|
const auto& createdDirectory = AssetsManager::GetAsset<Directory>(AssetsManager::GetAssetIDForFile(m_CurrentDirectory->FilePath + "/New Folder"));
|
||||||
|
m_SelectedAssets.Select(createdDirectory->Handle);
|
||||||
|
memset(m_InputBuffer, 0, MAX_INPUT_BUFFER_LENGTH);
|
||||||
|
memcpy(m_InputBuffer, createdDirectory->FileName.c_str(), createdDirectory->FileName.size());
|
||||||
|
m_RenamingSelected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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...");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("Import"))
|
||||||
|
{
|
||||||
|
//std::string filename = Application::Get().OpenFile("");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("Refresh"))
|
||||||
|
{
|
||||||
|
UpdateCurrentDirectory(m_CurrentDirHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("Physics Material"))
|
||||||
|
{
|
||||||
|
// TODO: use template
|
||||||
|
AssetsManager::CreateAssetPhysicsMaterial("New Physics Material.hpm", AssetType::PhysicsMat, m_CurrentDirHandle, 0.6f, 0.6f, 0.0f);
|
||||||
|
UpdateCurrentDirectory(m_CurrentDirHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Columns(s_ColumnCount, nullptr, false);
|
||||||
|
|
||||||
|
if (!m_CurrentDirAssets.empty())
|
||||||
|
{
|
||||||
|
for (Ref<Asset>& asset : m_CurrentDirAssets)
|
||||||
|
{
|
||||||
|
if (m_SkipRenderingThisFrame)
|
||||||
|
{
|
||||||
|
m_SkipRenderingThisFrame = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
RenderAsset(asset);
|
||||||
|
ImGui::NextColumn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_IsDragging && !ImGui::IsMouseDragging(ImGuiMouseButton_Left, 0.1f))
|
||||||
|
{
|
||||||
|
m_IsDragging = false;
|
||||||
|
m_DraggedAssetId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::PopStyleColor();
|
||||||
}
|
}
|
||||||
m_IsDragging = false;
|
ImGui::EndChild();
|
||||||
}
|
}
|
||||||
ImGui::EndDragDropTarget();
|
ImGui::EndChild();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::BeginChild("##panel_controls", ImVec2(ImGui::GetColumnWidth() - 12, 20), false, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse);
|
||||||
|
ImGui::Columns(4, 0, false);
|
||||||
ImGui::NextColumn();
|
ImGui::NextColumn();
|
||||||
|
ImGui::NextColumn();
|
||||||
ImGui::BeginChild("##directory_structure", ImVec2(ImGui::GetColumnWidth() - 12, ImGui::GetWindowHeight() - 50));
|
ImGui::NextColumn();
|
||||||
{
|
ImGui::SetNextItemWidth(ImGui::GetColumnWidth());
|
||||||
ImGui::BeginChild("##directory_breadcrumbs", ImVec2(ImGui::GetColumnWidth() - 100, 30));
|
ImGui::SliderInt("##column_count", &s_ColumnCount, 2, 15);
|
||||||
RenderBreadCrumbs();
|
|
||||||
ImGui::EndChild();
|
|
||||||
|
|
||||||
ImGui::BeginChild("Scrolling");
|
|
||||||
|
|
||||||
if (!m_DisplayListView)
|
|
||||||
ImGui::Columns(10, nullptr, false);
|
|
||||||
|
|
||||||
for (const DirectoryInfo& dir : m_CurrentDirChildren)
|
|
||||||
{
|
|
||||||
if (m_DisplayListView)
|
|
||||||
RenderDirectoriesListView(dir.DirectoryIndex);
|
|
||||||
else
|
|
||||||
RenderDirectoriesGridView(dir.DirectoryIndex);
|
|
||||||
|
|
||||||
ImGui::NextColumn();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Asset& asset : m_CurrentDirAssets)
|
|
||||||
{
|
|
||||||
if (m_DisplayListView)
|
|
||||||
RenderFileListView(asset);
|
|
||||||
else
|
|
||||||
RenderFileGridView(asset);
|
|
||||||
|
|
||||||
ImGui::NextColumn();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::BeginPopupContextWindow())
|
|
||||||
{
|
|
||||||
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...");
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
ImGui::EndChild();
|
|
||||||
}
|
|
||||||
ImGui::EndChild();
|
ImGui::EndChild();
|
||||||
|
|
||||||
|
|
||||||
if (ImGui::BeginDragDropTarget())
|
|
||||||
{
|
|
||||||
const auto payload = ImGui::AcceptDragDropPayload("selectable", ImGuiDragDropFlags_AcceptNoDrawDefaultRect);
|
|
||||||
if (payload)
|
|
||||||
{
|
|
||||||
const std::string data = static_cast<char*>(payload->Data);
|
|
||||||
if (AssetsManager::MoveFile(data, m_MovePath))
|
|
||||||
{
|
|
||||||
PM_CORE_INFO("Moved File: " + data + " to " + m_MovePath);
|
|
||||||
UpdateCurrentDirectory(m_CurrentDirIndex);
|
|
||||||
}
|
|
||||||
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("");
|
|
||||||
// TODO:
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::MenuItem("Refresh", "Ctrl + R"))
|
|
||||||
{
|
|
||||||
m_BaseProjectDir = AssetsManager::GetDirectoryInfo(m_BaseDirIndex);
|
|
||||||
UpdateCurrentDirectory(m_CurrentDirIndex);
|
|
||||||
}
|
|
||||||
ImGui::EndMenu();
|
|
||||||
|
|
||||||
}
|
|
||||||
ImGui::EndMenuBar();
|
|
||||||
}
|
|
||||||
UI::EndPropertyGrid();
|
UI::EndPropertyGrid();
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetsManagerPanel::DrawDirectoryInfo(const DirectoryInfo& dir)
|
void AssetsManagerPanel::DrawDirectoryInfo(const AssetHandle& directory)
|
||||||
{
|
{
|
||||||
if (ImGui::TreeNode(dir.DirectoryName.c_str()))
|
const Ref<Directory>& dir = AssetsManager::GetAsset<Directory>(directory);
|
||||||
|
|
||||||
|
if (ImGui::TreeNode(dir->FileName.c_str()))
|
||||||
{
|
{
|
||||||
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
|
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
|
||||||
UpdateCurrentDirectory(dir.DirectoryIndex);
|
UpdateCurrentDirectory(directory);
|
||||||
|
|
||||||
for (const int ChildrenIndice : dir.ChildrenIndices)
|
for (AssetHandle child : dir->ChildDirectories)
|
||||||
{
|
{
|
||||||
DirectoryInfo& child = AssetsManager::GetDirectoryInfo(ChildrenIndice);
|
|
||||||
DrawDirectoryInfo(child);
|
DrawDirectoryInfo(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_IsDragging && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
|
|
||||||
{
|
|
||||||
m_MovePath = dir.FilePath;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetsManagerPanel::RenderFileListView(Asset& asset)
|
|
||||||
|
void AssetsManagerPanel::RenderAsset(Ref<Asset>& asset)
|
||||||
{
|
{
|
||||||
const size_t fileID = AssetTypes::GetAssetTypeID(asset.Extension);
|
// These caches are currently required for when we change directories
|
||||||
const RendererID iconRef = m_AssetIconMap[fileID]->GetRendererID();
|
AssetHandle assetHandle = asset->Handle;
|
||||||
ImGui::Image((ImTextureID)iconRef, ImVec2(20, 20));
|
std::string filename = asset->FileName;
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::PushID(&asset->Handle);
|
||||||
|
|
||||||
if (ImGui::Selectable(asset.FilePath.c_str(), false, ImGuiSelectableFlags_AllowDoubleClick))
|
|
||||||
{
|
|
||||||
// if (ImGui::IsMouseDoubleClicked(0))
|
|
||||||
// m_AssetManager.HandleAsset(m_CurrentDir[dirIndex].AbsolutePath);
|
|
||||||
// TODO:
|
|
||||||
}
|
|
||||||
|
|
||||||
HandleDragDrop(iconRef, asset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsManagerPanel::RenderFileGridView(Asset& asset)
|
|
||||||
{
|
|
||||||
ImGui::BeginGroup();
|
ImGui::BeginGroup();
|
||||||
|
|
||||||
const size_t fileID = AssetTypes::GetAssetTypeID(asset.Extension);
|
size_t fileID = AssetTypes::GetAssetTypeID(asset->Extension);
|
||||||
|
fileID = m_AssetIconMap.find(fileID) != m_AssetIconMap.end() ? fileID : -1;
|
||||||
const RendererID iconRef = m_AssetIconMap[fileID]->GetRendererID();
|
const RendererID iconRef = m_AssetIconMap[fileID]->GetRendererID();
|
||||||
const float columnWidth = ImGui::GetColumnWidth();
|
|
||||||
|
|
||||||
ImGui::ImageButton(asset.FilePath.c_str(), (ImTextureID)iconRef, { columnWidth - 10.0f, columnWidth - 10.0f });
|
if (m_SelectedAssets.IsSelected(assetHandle))
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.25f, 0.25f, 0.25f, 0.75f));
|
||||||
|
|
||||||
|
float buttonWidth = ImGui::GetColumnWidth() - 15.0F;
|
||||||
|
ImGui::ImageButton("##AssetButton", (ImTextureID)iconRef, { buttonWidth, buttonWidth });
|
||||||
|
|
||||||
|
if (m_SelectedAssets.IsSelected(assetHandle))
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
HandleDragDrop(iconRef, asset);
|
HandleDragDrop(iconRef, asset);
|
||||||
|
|
||||||
const std::string newFileName = AssetsManager::StripExtras(asset.FileName);
|
if (ImGui::IsItemHovered())
|
||||||
ImGui::PushTextWrapPos(ImGui::GetCursorPos().x + columnWidth - 10.0f);
|
|
||||||
ImGui::TextWrapped("%s", newFileName.c_str());
|
|
||||||
ImGui::PopTextWrapPos();
|
|
||||||
ImGui::EndGroup();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsManagerPanel::HandleDragDrop(const RendererID icon, const Asset& asset)
|
|
||||||
{
|
|
||||||
// Drag 'n' Drop Implementation For File Moving
|
|
||||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID))
|
|
||||||
{
|
{
|
||||||
ImGui::Image((ImTextureID)icon, ImVec2(20, 20));
|
m_IsAnyItemHovered = true;
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::Text("%s", asset.FilePath.c_str());
|
|
||||||
ImGui::SetDragDropPayload("selectable", asset.FilePath.c_str(), asset.FilePath.length());
|
|
||||||
m_IsDragging = true;
|
|
||||||
ImGui::EndDragDropSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drag 'n' Drop Implementation For Asset Handling In Scene Viewport
|
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
|
||||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID))
|
|
||||||
{
|
|
||||||
ImGui::Image((ImTextureID)icon, ImVec2(20, 20));
|
|
||||||
ImGui::SameLine();
|
|
||||||
|
|
||||||
ImGui::Text("%s", asset.FilePath.c_str());
|
|
||||||
ImGui::SetDragDropPayload("scene_entity_assetsP", &asset.ID, sizeof(UUID));
|
|
||||||
m_IsDragging = true;
|
|
||||||
|
|
||||||
ImGui::EndDragDropSource();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsManagerPanel::RenderDirectoriesListView(int dirIndex)
|
|
||||||
{
|
|
||||||
ImGui::Image((ImTextureID)m_FolderTex->GetRendererID(), ImVec2(20, 20));
|
|
||||||
ImGui::SameLine();
|
|
||||||
|
|
||||||
const auto& folderData = AssetsManager::GetDirectoryInfo(dirIndex);
|
|
||||||
|
|
||||||
if (ImGui::Selectable(folderData.DirectoryName.c_str(), false, ImGuiSelectableFlags_AllowDoubleClick))
|
|
||||||
{
|
|
||||||
if (ImGui::IsMouseDoubleClicked(0))
|
|
||||||
{
|
{
|
||||||
m_PrevDirIndex = m_CurrentDirIndex;
|
if (asset->Type == AssetType::Directory)
|
||||||
UpdateCurrentDirectory(dirIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_AcceptNoDrawDefaultRect))
|
|
||||||
{
|
|
||||||
ImGui::Image((ImTextureID)m_FolderTex->GetRendererID(), ImVec2(20, 20));
|
|
||||||
ImGui::SameLine();
|
|
||||||
|
|
||||||
ImGui::Text("%s", folderData.DirectoryName.c_str());
|
|
||||||
ImGui::SetDragDropPayload("selectable", &dirIndex, sizeof(int));
|
|
||||||
|
|
||||||
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 });
|
|
||||||
|
|
||||||
const auto& folderData = AssetsManager::GetDirectoryInfo(dirIndex);
|
|
||||||
|
|
||||||
if (ImGui::IsMouseDoubleClicked(0) && ImGui::IsItemHovered())
|
|
||||||
{
|
|
||||||
m_PrevDirIndex = m_CurrentDirIndex;
|
|
||||||
UpdateCurrentDirectory(dirIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_AcceptNoDrawDefaultRect))
|
|
||||||
{
|
|
||||||
ImGui::Image((ImTextureID)m_FolderTex->GetRendererID(), ImVec2(20, 20));
|
|
||||||
ImGui::SameLine();
|
|
||||||
|
|
||||||
ImGui::Text("%s", folderData.DirectoryName.c_str());
|
|
||||||
ImGui::SetDragDropPayload("selectable_directory", &dirIndex, sizeof(int));
|
|
||||||
|
|
||||||
m_IsDragging = true;
|
|
||||||
ImGui::EndDragDropSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::TextWrapped("%s", folderData.DirectoryName.c_str());
|
|
||||||
ImGui::EndGroup();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsManagerPanel::RenderBreadCrumbs()
|
|
||||||
{
|
|
||||||
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)))
|
|
||||||
{
|
|
||||||
if (m_CurrentDirIndex == m_BaseDirIndex) return;
|
|
||||||
m_NextDirIndex = m_CurrentDirIndex;
|
|
||||||
m_PrevDirIndex = AssetsManager::GetDirectoryInfo(m_CurrentDirIndex).ParentIndex;
|
|
||||||
UpdateCurrentDirectory(m_PrevDirIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
|
|
||||||
const auto backbtnTexID = m_BackbtnTex->GetRendererID();
|
|
||||||
if (ImGui::ImageButton((const char*)&backbtnTexID,(ImTextureID)backbtnTexID, ImVec2(20, 18)))
|
|
||||||
{
|
|
||||||
if (m_CurrentDirIndex == m_BaseDirIndex) return;
|
|
||||||
m_NextDirIndex = m_CurrentDirIndex;
|
|
||||||
m_PrevDirIndex = AssetsManager::GetDirectoryInfo(m_CurrentDirIndex).ParentIndex;
|
|
||||||
UpdateCurrentDirectory(m_PrevDirIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
const auto fwrdbtnTexID = m_FwrdbtnTex->GetRendererID();
|
|
||||||
if (ImGui::ImageButton((const char*)&fwrdbtnTexID,(ImTextureID)fwrdbtnTexID, ImVec2(20, 18)))
|
|
||||||
{
|
|
||||||
UpdateCurrentDirectory(m_NextDirIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
{
|
|
||||||
ImGui::PushItemWidth(200);
|
|
||||||
|
|
||||||
if (ImGui::InputTextWithHint("##Search", "Search...", m_InputBuffer, 100))
|
|
||||||
{
|
|
||||||
const SearchResults results = AssetsManager::SearchFiles(m_InputBuffer, m_CurrentDir.FilePath);
|
|
||||||
|
|
||||||
if (strlen(m_InputBuffer) == 0)
|
|
||||||
{
|
{
|
||||||
UpdateCurrentDirectory(m_CurrentDirIndex);
|
m_PrevDirHandle = m_CurrentDirHandle;
|
||||||
|
UpdateCurrentDirectory(assetHandle);
|
||||||
|
m_SkipRenderingThisFrame = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_CurrentDirChildren = results.Directories;
|
AssetEditorPanel::OpenEditor(asset);
|
||||||
m_CurrentDirAssets = results.Assets;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !m_IsDragging)
|
||||||
|
{
|
||||||
|
if (!Input::IsKeyPressed(KeyCode::LEFT_CONTROL))
|
||||||
|
m_SelectedAssets.Clear();
|
||||||
|
|
||||||
|
if (m_SelectedAssets.IsSelected(assetHandle))
|
||||||
|
m_SelectedAssets.Deselect(assetHandle);
|
||||||
|
else
|
||||||
|
m_SelectedAssets.Select(assetHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool shouldOpenDeleteModal = false;
|
||||||
|
|
||||||
|
if (ImGui::BeginPopupContextItem())
|
||||||
|
{
|
||||||
|
if (ImGui::MenuItem("Rename"))
|
||||||
|
{
|
||||||
|
m_SelectedAssets.Select(assetHandle);
|
||||||
|
memset(m_InputBuffer, 0, MAX_INPUT_BUFFER_LENGTH);
|
||||||
|
memcpy(m_InputBuffer, filename.c_str(), filename.size());
|
||||||
|
m_RenamingSelected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::MenuItem("Delete"))
|
||||||
|
shouldOpenDeleteModal = true;
|
||||||
|
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shouldOpenDeleteModal)
|
||||||
|
{
|
||||||
|
ImGui::OpenPopup("Delete Asset");
|
||||||
|
shouldOpenDeleteModal = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool deleted = false;
|
||||||
|
if (ImGui::BeginPopupModal("Delete Asset", nullptr, ImGuiWindowFlags_AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
if (asset->Type == AssetType::Directory)
|
||||||
|
ImGui::Text("Are you sure you want to delete %s and everything within it?", filename.c_str());
|
||||||
|
else
|
||||||
|
ImGui::Text("Are you sure you want to delete %s?", filename.c_str());
|
||||||
|
|
||||||
|
const float columnWidth = ImGui::GetContentRegionAvail().x / 4.0f;
|
||||||
|
|
||||||
|
ImGui::Columns(4, 0, false);
|
||||||
|
ImGui::SetColumnWidth(0, columnWidth);
|
||||||
|
ImGui::SetColumnWidth(1, columnWidth);
|
||||||
|
ImGui::SetColumnWidth(2, columnWidth);
|
||||||
|
ImGui::SetColumnWidth(3, columnWidth);
|
||||||
|
ImGui::NextColumn();
|
||||||
|
if (ImGui::Button("Yes", ImVec2(columnWidth, 0)))
|
||||||
|
{
|
||||||
|
// Cache this so that we can delete the meta file if the asset was deleted successfully
|
||||||
|
std::string filepath = asset->FilePath;
|
||||||
|
deleted = FileSystem::PrismDeleteFile(filepath);
|
||||||
|
if (deleted)
|
||||||
|
{
|
||||||
|
FileSystem::PrismDeleteFile(filepath + ".meta");
|
||||||
|
AssetsManager::RemoveAsset(assetHandle);
|
||||||
|
m_SkipRenderingThisFrame = true;
|
||||||
|
UpdateCurrentDirectory(m_CurrentDirHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::NextColumn();
|
||||||
|
ImGui::SetItemDefaultFocus();
|
||||||
|
if (ImGui::Button("No", ImVec2(columnWidth, 0)))
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
|
||||||
|
ImGui::NextColumn();
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!deleted)
|
||||||
|
{
|
||||||
|
ImGui::SetNextItemWidth(buttonWidth);
|
||||||
|
|
||||||
|
if (!m_SelectedAssets.IsSelected(assetHandle) || !m_RenamingSelected)
|
||||||
|
ImGui::TextWrapped("%s", filename.c_str());
|
||||||
|
|
||||||
|
if (m_SelectedAssets.IsSelected(assetHandle))
|
||||||
|
HandleRenaming(asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndGroup();
|
||||||
|
ImGui::PopID();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AssetsManagerPanel::HandleDragDrop(const RendererID icon, const Ref<Asset>& asset)
|
||||||
|
{
|
||||||
|
if (!m_SelectedAssets.IsSelected(asset->Handle) || m_IsDragging)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenOverlapped) && ImGui::IsItemClicked(ImGuiMouseButton_Left))
|
||||||
|
m_IsDragging = true;
|
||||||
|
|
||||||
|
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID))
|
||||||
|
{
|
||||||
|
ImGui::Image((ImTextureID)icon, ImVec2(20, 20));
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::Text("%s", asset->FileName.c_str());
|
||||||
|
ImGui::SetDragDropPayload("asset_payload", m_SelectedAssets.GetSelectionData(), m_SelectedAssets.SelectionCount() * sizeof(AssetHandle));
|
||||||
|
|
||||||
|
m_IsDragging = true;
|
||||||
|
ImGui::EndDragDropSource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AssetsManagerPanel::RenderBreadCrumbs()
|
||||||
|
{
|
||||||
|
if (ImGui::ImageButton("##backbtn", (ImTextureID)m_BackbtnTex->GetRendererID(), ImVec2(20, 18)))
|
||||||
|
{
|
||||||
|
if (m_CurrentDirHandle == m_BaseDirectoryHandle) return;
|
||||||
|
m_NextDirHandle = m_CurrentDirHandle;
|
||||||
|
m_PrevDirHandle = m_CurrentDirectory->ParentDirectory;
|
||||||
|
UpdateCurrentDirectory(m_PrevDirHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
if (ImGui::ImageButton("##fwrdbtn", (ImTextureID)m_FwrdbtnTex->GetRendererID(), ImVec2(20, 18)))
|
||||||
|
{
|
||||||
|
UpdateCurrentDirectory(m_NextDirHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
{
|
||||||
|
ImGui::PushItemWidth(200);
|
||||||
|
char* buf = m_InputBuffer;
|
||||||
|
if (m_RenamingSelected)
|
||||||
|
buf = '\0';
|
||||||
|
|
||||||
|
if (ImGui::InputTextWithHint("##asset_panel_search", "Search...", buf, MAX_INPUT_BUFFER_LENGTH))
|
||||||
|
{
|
||||||
|
if (strlen(m_InputBuffer) == 0)
|
||||||
|
{
|
||||||
|
UpdateCurrentDirectory(m_CurrentDirHandle);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_CurrentDirAssets = AssetsManager::SearchFiles(m_InputBuffer, m_CurrentDirectory->FilePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,18 +411,20 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
if (m_UpdateBreadCrumbs)
|
if (m_UpdateBreadCrumbs)
|
||||||
{
|
{
|
||||||
m_BreadCrumbData.clear();
|
m_BreadCrumbData.clear();
|
||||||
|
|
||||||
int currentDirIndex = m_CurrentDirIndex;
|
AssetHandle currentHandle = m_CurrentDirHandle;
|
||||||
while (currentDirIndex != -1)
|
while (currentHandle != 0)
|
||||||
{
|
{
|
||||||
DirectoryInfo& dirInfo = AssetsManager::GetDirectoryInfo(currentDirIndex);
|
const Ref<Directory>& dirInfo = AssetsManager::GetAsset<Directory>(currentHandle);
|
||||||
m_BreadCrumbData.push_back(dirInfo);
|
m_BreadCrumbData.push_back(dirInfo);
|
||||||
currentDirIndex = dirInfo.ParentIndex;
|
currentHandle = dirInfo->ParentDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_BreadCrumbData.push_back(m_BaseDirectory);
|
||||||
std::reverse(m_BreadCrumbData.begin(), m_BreadCrumbData.end());
|
std::reverse(m_BreadCrumbData.begin(), m_BreadCrumbData.end());
|
||||||
|
|
||||||
m_UpdateBreadCrumbs = false;
|
m_UpdateBreadCrumbs = false;
|
||||||
@ -422,16 +432,16 @@ namespace Prism
|
|||||||
|
|
||||||
for (auto & i : m_BreadCrumbData)
|
for (auto & i : m_BreadCrumbData)
|
||||||
{
|
{
|
||||||
if (i.DirectoryName != "assets")
|
if (i->FileName != "assets")
|
||||||
ImGui::Text("/");
|
ImGui::Text("/");
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
const int size = (int)i.DirectoryName.length() * 7;
|
const float size = (float)strlen(i->FileName.c_str()) * 7;
|
||||||
|
|
||||||
if (ImGui::Selectable(i.DirectoryName.c_str(), false, 0, ImVec2((float)size, 22)))
|
if (ImGui::Selectable(i->FileName.c_str(), false, 0, ImVec2(size, 22)))
|
||||||
{
|
{
|
||||||
UpdateCurrentDirectory(i.DirectoryIndex);
|
UpdateCurrentDirectory(i->Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
@ -441,31 +451,45 @@ namespace Prism
|
|||||||
|
|
||||||
ImGui::Dummy(ImVec2(ImGui::GetColumnWidth() - 400, 0));
|
ImGui::Dummy(ImVec2(ImGui::GetColumnWidth() - 400, 0));
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetsManagerPanel::RenderBottom()
|
void AssetsManagerPanel::HandleRenaming(Ref<Asset>& asset)
|
||||||
{
|
{
|
||||||
/* Will be used for object select indication. Ex. 3 folders 1 file selected */
|
if (m_SelectedAssets.SelectionCount() > 1)
|
||||||
ImGui::BeginChild("##nav", ImVec2(ImGui::GetColumnWidth() - 12, 23));
|
return;
|
||||||
|
|
||||||
|
if (!m_RenamingSelected && Input::IsKeyPressed(KeyCode::F2))
|
||||||
{
|
{
|
||||||
ImGui::EndChild();
|
memset(m_InputBuffer, 0, MAX_INPUT_BUFFER_LENGTH);
|
||||||
|
memcpy(m_InputBuffer, asset->FileName.c_str(), asset->FileName.size());
|
||||||
|
m_RenamingSelected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_RenamingSelected)
|
||||||
|
{
|
||||||
|
ImGui::SetKeyboardFocusHere();
|
||||||
|
if (ImGui::InputText("##rename_dummy", m_InputBuffer, MAX_INPUT_BUFFER_LENGTH, ImGuiInputTextFlags_EnterReturnsTrue))
|
||||||
|
{
|
||||||
|
PM_CORE_INFO("Renaming to {0}", m_InputBuffer);
|
||||||
|
AssetsManager::Rename(asset, m_InputBuffer);
|
||||||
|
m_RenamingSelected = false;
|
||||||
|
m_SelectedAssets.Clear();
|
||||||
|
m_SkipRenderingThisFrame = true;
|
||||||
|
UpdateCurrentDirectory(m_CurrentDirHandle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetsManagerPanel::UpdateCurrentDirectory(int dirIndex)
|
|
||||||
|
void AssetsManagerPanel::UpdateCurrentDirectory(AssetHandle directoryHandle)
|
||||||
{
|
{
|
||||||
if (m_CurrentDirIndex != dirIndex)
|
if (m_CurrentDirHandle != directoryHandle)
|
||||||
m_UpdateBreadCrumbs = true;
|
m_UpdateBreadCrumbs = true;
|
||||||
|
|
||||||
m_CurrentDirChildren.clear();
|
|
||||||
m_CurrentDirAssets.clear();
|
m_CurrentDirAssets.clear();
|
||||||
|
m_CurrentDirHandle = directoryHandle;
|
||||||
m_CurrentDirIndex = dirIndex;
|
m_CurrentDirectory = AssetsManager::GetAsset<Directory>(m_CurrentDirHandle);
|
||||||
m_CurrentDir = AssetsManager::GetDirectoryInfo(m_CurrentDirIndex);
|
m_CurrentDirAssets = AssetsManager::GetAssetsInDirectory(m_CurrentDirHandle);
|
||||||
|
|
||||||
for (const int childIndex : m_CurrentDir.ChildrenIndices)
|
|
||||||
m_CurrentDirChildren.push_back(AssetsManager::GetDirectoryInfo(childIndex));
|
|
||||||
|
|
||||||
m_CurrentDirAssets = AssetsManager::GetAssetsInDirectory(m_CurrentDirIndex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,12 +5,65 @@
|
|||||||
#ifndef PRISM_ASSETSMANAGERPANEL_H
|
#ifndef PRISM_ASSETSMANAGERPANEL_H
|
||||||
#define PRISM_ASSETSMANAGERPANEL_H
|
#define PRISM_ASSETSMANAGERPANEL_H
|
||||||
|
|
||||||
#include "Prism/Utilities/AssetsManager.h"
|
#include "Prism/Asset/AssetsManager.h"
|
||||||
#include "Prism/Renderer/Texture.h"
|
#include "Prism/Renderer/Texture.h"
|
||||||
#include "Prism/Core/ImGui/ImGui.h"
|
#include "Prism/Core/ImGui/ImGui.h"
|
||||||
|
|
||||||
|
#define MAX_INPUT_BUFFER_LENGTH 128
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
|
template<typename T>
|
||||||
|
struct SelectionStack
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Select(T item)
|
||||||
|
{
|
||||||
|
m_Selections.push_back(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Deselect(T item)
|
||||||
|
{
|
||||||
|
for (auto it = m_Selections.begin(); it != m_Selections.end(); it++)
|
||||||
|
{
|
||||||
|
if (*it == item)
|
||||||
|
{
|
||||||
|
m_Selections.erase(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsSelected(T item) const
|
||||||
|
{
|
||||||
|
for (auto selection : m_Selections)
|
||||||
|
{
|
||||||
|
if (selection == item)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
m_Selections.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SelectionCount() const
|
||||||
|
{
|
||||||
|
return m_Selections.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
T* GetSelectionData()
|
||||||
|
{
|
||||||
|
return m_Selections.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<T> m_Selections;
|
||||||
|
};
|
||||||
|
|
||||||
class PRISM_API AssetsManagerPanel
|
class PRISM_API AssetsManagerPanel
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -18,61 +71,47 @@ namespace Prism
|
|||||||
void OnImGuiRender();
|
void OnImGuiRender();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void DrawDirectoryInfo(const DirectoryInfo& dir);
|
void DrawDirectoryInfo(const AssetHandle& directory);
|
||||||
|
|
||||||
void RenderFileListView(Asset& asset);
|
void RenderAsset(Ref<Asset>& asset);
|
||||||
void RenderFileGridView(Asset& asset);
|
void HandleDragDrop(RendererID icon, const Ref<Asset>& asset);
|
||||||
void HandleDragDrop(RendererID icon, const Asset& asset);
|
|
||||||
|
|
||||||
void RenderDirectoriesListView(int dirIndex);
|
|
||||||
void RenderDirectoriesGridView(int dirIndex);
|
|
||||||
void RenderBreadCrumbs();
|
void RenderBreadCrumbs();
|
||||||
void RenderBottom();
|
|
||||||
|
|
||||||
void UpdateCurrentDirectory(int dirIndex);
|
void HandleRenaming(Ref<Asset>& asset);
|
||||||
|
|
||||||
// ImGuiInputTextCallback SearchCallback(ImGuiInputTextCallbackData* data);
|
void UpdateCurrentDirectory(AssetHandle directoryHandle);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ref<Texture2D> m_FolderTex;
|
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_BackbtnTex;
|
||||||
Ref<Texture2D> m_FwrdbtnTex;
|
Ref<Texture2D> m_FwrdbtnTex;
|
||||||
Ref<Texture2D> m_FolderRightTex;
|
Ref<Texture2D> m_FolderRightTex;
|
||||||
Ref<Texture2D> m_TagsTex;
|
|
||||||
Ref<Texture2D> m_SearchTex;
|
Ref<Texture2D> m_SearchTex;
|
||||||
Ref<Texture2D> m_GridView;
|
|
||||||
Ref<Texture2D> m_ListView;
|
|
||||||
|
|
||||||
std::string m_MovePath;
|
std::string m_MovePath;
|
||||||
|
|
||||||
int m_BaseDirIndex;
|
|
||||||
int m_CurrentDirIndex;
|
|
||||||
int m_PrevDirIndex;
|
|
||||||
int m_NextDirIndex;
|
|
||||||
|
|
||||||
bool m_IsDragging = false;
|
bool m_IsDragging = false;
|
||||||
bool m_DisplayListView = false;
|
|
||||||
bool m_UpdateBreadCrumbs = true;
|
bool m_UpdateBreadCrumbs = true;
|
||||||
bool m_ShowSearchBar = false;
|
bool m_IsAnyItemHovered = false;
|
||||||
bool m_DirectoryChanged = false;
|
bool m_SkipRenderingThisFrame = false;
|
||||||
|
|
||||||
char m_InputBuffer[1024]{};
|
char m_InputBuffer[MAX_INPUT_BUFFER_LENGTH];
|
||||||
|
|
||||||
DirectoryInfo m_CurrentDir;
|
AssetHandle m_CurrentDirHandle;
|
||||||
DirectoryInfo m_BaseProjectDir;
|
AssetHandle m_BaseDirectoryHandle;
|
||||||
std::vector<DirectoryInfo> m_CurrentDirChildren;
|
AssetHandle m_PrevDirHandle;
|
||||||
std::vector<Asset> m_CurrentDirAssets;
|
AssetHandle m_NextDirHandle;
|
||||||
|
Ref<Directory> m_CurrentDirectory;
|
||||||
|
Ref<Directory> m_BaseDirectory;
|
||||||
|
std::vector<Ref<Asset>> m_CurrentDirAssets;
|
||||||
|
|
||||||
std::vector<DirectoryInfo> m_BreadCrumbData;
|
std::vector<Ref<Directory>> m_BreadCrumbData;
|
||||||
|
|
||||||
|
AssetHandle m_DraggedAssetId = 0;
|
||||||
|
SelectionStack<AssetHandle> m_SelectedAssets;
|
||||||
|
|
||||||
|
bool m_RenamingSelected = false;
|
||||||
|
|
||||||
ImGuiInputTextCallbackData m_Data;
|
|
||||||
std::map<size_t, Ref<Texture2D>> m_AssetIconMap;
|
std::map<size_t, Ref<Texture2D>> m_AssetIconMap;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
56
Prism/src/Prism/Editor/DefaultAssetEditors.cpp
Normal file
56
Prism/src/Prism/Editor/DefaultAssetEditors.cpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
//
|
||||||
|
// Created by Atdunbg on 2026/2/14.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "DefaultAssetEditors.h"
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
|
||||||
|
// MaterialEditor
|
||||||
|
PhysicsMaterialEditor::PhysicsMaterialEditor()
|
||||||
|
: AssetEditor("Edit Physics Material") {}
|
||||||
|
|
||||||
|
void PhysicsMaterialEditor::Render()
|
||||||
|
{
|
||||||
|
if (!m_Asset)
|
||||||
|
SetOpen(false);
|
||||||
|
|
||||||
|
UI::BeginPropertyGrid();
|
||||||
|
UI::Property("Static Friction", m_Asset->StaticFriction);
|
||||||
|
UI::Property("Dynamic Friction", m_Asset->DynamicFriction);
|
||||||
|
UI::Property("Bounciness", m_Asset->Bounciness);
|
||||||
|
UI::EndPropertyGrid();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MaterialEditor
|
||||||
|
TextureEditor::TextureEditor()
|
||||||
|
: AssetEditor("Edit Texture")
|
||||||
|
{
|
||||||
|
SetMinSize(200, 600);
|
||||||
|
SetMaxSize(500, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextureEditor::Render()
|
||||||
|
{
|
||||||
|
if (!m_Asset)
|
||||||
|
SetOpen(false);
|
||||||
|
|
||||||
|
float textureWidth = (float)m_Asset->GetWidth();
|
||||||
|
float textureHeight = (float)m_Asset->GetHeight();
|
||||||
|
float bitsPerPixel = (float)Texture::GetBPP(m_Asset->GetFormat());
|
||||||
|
float imageSize = ImGui::GetWindowWidth() - 40;
|
||||||
|
imageSize = glm::min(imageSize, 500.0f);
|
||||||
|
|
||||||
|
ImGui::SetCursorPosX(20);
|
||||||
|
ImGui::Image((ImTextureID)m_Asset->GetRendererID(), { imageSize, imageSize });
|
||||||
|
|
||||||
|
UI::BeginPropertyGrid();
|
||||||
|
UI::Property("Width", textureWidth, 0.1f, 0.0f, 0.0f, true);
|
||||||
|
UI::Property("Height", textureHeight, 0.1f, 0.0f, 0.0f, true);
|
||||||
|
UI::Property("Bits", bitsPerPixel, 0.1f, 0.0f, 0.0f, true);
|
||||||
|
UI::EndPropertyGrid();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
43
Prism/src/Prism/Editor/DefaultAssetEditors.h
Normal file
43
Prism/src/Prism/Editor/DefaultAssetEditors.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
//
|
||||||
|
// Created by Atdunbg on 2026/2/14.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef PRISM_DEFAULTASSETEDITORS_H
|
||||||
|
#define PRISM_DEFAULTASSETEDITORS_H
|
||||||
|
#include "AssetEditorPanel.h"
|
||||||
|
#include "Prism/Renderer/Texture.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Prism
|
||||||
|
{
|
||||||
|
class PhysicsMaterialEditor : public AssetEditor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PhysicsMaterialEditor();
|
||||||
|
|
||||||
|
virtual void SetAsset(const Ref<Asset>& asset) override { m_Asset = (Ref<PhysicsMaterial>)asset; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void Render() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ref<PhysicsMaterial> m_Asset;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TextureEditor : public AssetEditor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TextureEditor();
|
||||||
|
|
||||||
|
virtual void SetAsset(const Ref<Asset>& asset) override { m_Asset = static_cast<Ref<Texture>>(asset); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void Render() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ref<Texture> m_Asset;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //PRISM_DEFAULTASSETEDITORS_H
|
||||||
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
#include "Prism/Utilities/DragDropData.h"
|
#include "../Asset/AssetsManager.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
@ -17,135 +17,46 @@ namespace Prism
|
|||||||
|
|
||||||
void ObjectsPanel::OnImGuiRender()
|
void ObjectsPanel::OnImGuiRender()
|
||||||
{
|
{
|
||||||
ImGui::Begin("Objects", nullptr, ImGuiWindowFlags_None);
|
static const AssetHandle CubeHandle = AssetsManager::GetAssetIDForFile("assets/meshes/Default/Cube.fbx");
|
||||||
{
|
static const AssetHandle CapsuleHandle = AssetsManager::GetAssetIDForFile("assets/meshes/Default/Capsule.fbx");
|
||||||
char buff[100] = {};
|
static const AssetHandle SphereHandle = AssetsManager::GetAssetIDForFile("assets/meshes/Default/Sphere.fbx");
|
||||||
const auto inputText = "InputText";
|
static const AssetHandle CylinderHandle = AssetsManager::GetAssetIDForFile("assets/meshes/Default/Cylinder.fbx");
|
||||||
const auto inputHint = "Start Typing To Search";
|
static const AssetHandle TorusHandle = AssetsManager::GetAssetIDForFile("assets/meshes/Default/Torus.fbx");
|
||||||
ImGui::PushItemWidth(ImGui::GetWindowWidth() - 20);
|
static const AssetHandle PlaneHandle = AssetsManager::GetAssetIDForFile("assets/meshes/Default/Plane.fbx");
|
||||||
ImGui::InputTextWithHint(inputText, inputHint, buff, 100);
|
static const AssetHandle ConeHandle = AssetsManager::GetAssetIDForFile("assets/meshes/Default/Cone.fbx");
|
||||||
|
|
||||||
ImGui::BeginChild("##objects_window");
|
ImGui::Begin("Objects");
|
||||||
{
|
{
|
||||||
ImGui::Image(m_CubeImage->GetRendererID(), ImVec2(30, 30));
|
ImGui::BeginChild("##objects_window");
|
||||||
ImGui::SameLine();
|
DrawObject("Cube", CubeHandle);
|
||||||
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5);
|
DrawObject("Capsule", CapsuleHandle);
|
||||||
ImGui::Selectable("Cube");
|
DrawObject("Sphere", SphereHandle);
|
||||||
|
DrawObject("Cylinder", CylinderHandle);
|
||||||
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID))
|
DrawObject("Torus", TorusHandle);
|
||||||
{
|
DrawObject("Plane", PlaneHandle);
|
||||||
ImGui::Image(m_CubeImage->GetRendererID(), ImVec2(20, 20));
|
DrawObject("Cone", ConeHandle);
|
||||||
ImGui::SameLine();
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
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();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ObjectsPanel::DrawObject(const char* label, const AssetHandle handle)
|
||||||
|
{
|
||||||
|
ImGui::Image((ImTextureID)m_CubeImage->GetRendererID(), ImVec2(30, 30));
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5);
|
||||||
|
ImGui::Selectable(label);
|
||||||
|
|
||||||
|
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID))
|
||||||
|
{
|
||||||
|
ImGui::Image((ImTextureID)m_CubeImage->GetRendererID(), ImVec2(20, 20));
|
||||||
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
ImGui::Text("%s", label);
|
||||||
|
|
||||||
|
ImGui::SetDragDropPayload("asset_payload", &handle, sizeof(AssetHandle));
|
||||||
|
ImGui::EndDragDropSource();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#ifndef PRISM_OBJECTSPANEL_H
|
#ifndef PRISM_OBJECTSPANEL_H
|
||||||
#define PRISM_OBJECTSPANEL_H
|
#define PRISM_OBJECTSPANEL_H
|
||||||
#include "Prism/Renderer/Texture.h"
|
#include "Prism/Renderer/Texture.h"
|
||||||
|
#include "Prism/Asset/AssetsManager.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
@ -15,6 +16,9 @@ namespace Prism
|
|||||||
|
|
||||||
void OnImGuiRender();
|
void OnImGuiRender();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void DrawObject(const char* label, AssetHandle handle);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ref<Texture2D> m_CubeImage;
|
Ref<Texture2D> m_CubeImage;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -282,6 +282,9 @@ namespace Prism
|
|||||||
|
|
||||||
ImGuiTreeNodeFlags node_flags = (entity == m_SelectionContext ? ImGuiTreeNodeFlags_Selected : 0) | ImGuiTreeNodeFlags_OpenOnArrow;
|
ImGuiTreeNodeFlags node_flags = (entity == m_SelectionContext ? ImGuiTreeNodeFlags_Selected : 0) | ImGuiTreeNodeFlags_OpenOnArrow;
|
||||||
node_flags |= ImGuiTreeNodeFlags_SpanAvailWidth;
|
node_flags |= ImGuiTreeNodeFlags_SpanAvailWidth;
|
||||||
|
if (entity.Children().empty())
|
||||||
|
node_flags |= ImGuiTreeNodeFlags_Leaf;
|
||||||
|
|
||||||
const bool opened = ImGui::TreeNodeEx((const void*)(uintptr_t)(uint32_t)entity, node_flags, name);
|
const bool opened = ImGui::TreeNodeEx((const void*)(uintptr_t)(uint32_t)entity, node_flags, name);
|
||||||
if (ImGui::IsItemClicked())
|
if (ImGui::IsItemClicked())
|
||||||
{
|
{
|
||||||
@ -316,18 +319,21 @@ namespace Prism
|
|||||||
UUID droppedHandle = *static_cast<UUID*>(payload->Data);
|
UUID droppedHandle = *static_cast<UUID*>(payload->Data);
|
||||||
Entity e = m_Context->FindEntityByUUID(droppedHandle);
|
Entity e = m_Context->FindEntityByUUID(droppedHandle);
|
||||||
|
|
||||||
// Remove from previous parent
|
if (!entity.IsDescendantOf(e))
|
||||||
Entity previousParent = m_Context->FindEntityByUUID(e.GetParentUUID());
|
|
||||||
if (previousParent)
|
|
||||||
{
|
{
|
||||||
auto& parentChildren = previousParent.Children();
|
// Remove from previous parent
|
||||||
parentChildren.erase(std::remove(parentChildren.begin(), parentChildren.end(), droppedHandle), parentChildren.end());
|
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());
|
||||||
|
entity.Children().push_back(droppedHandle);
|
||||||
|
|
||||||
|
PM_CORE_INFO("Dropping Entity {0} on {1}", (uint64_t)droppedHandle, (uint64_t)entity.GetUUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
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());
|
PM_CORE_INFO("Dropping Entity {0} on {1}", (uint64_t)droppedHandle, (uint64_t)entity.GetUUID());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,7 +520,6 @@ namespace Prism
|
|||||||
AddComponentPopup<BoxCollider2DComponent>("BoxCollider2D");
|
AddComponentPopup<BoxCollider2DComponent>("BoxCollider2D");
|
||||||
AddComponentPopup<CircleCollider2DComponent>("CircleCollider2D");
|
AddComponentPopup<CircleCollider2DComponent>("CircleCollider2D");
|
||||||
AddComponentPopup<RigidBodyComponent>("RigidBody");
|
AddComponentPopup<RigidBodyComponent>("RigidBody");
|
||||||
AddComponentPopup<PhysicsMaterialComponent>("PhysicsMaterial");
|
|
||||||
AddComponentPopup<BoxColliderComponent>("BoxCollider");
|
AddComponentPopup<BoxColliderComponent>("BoxCollider");
|
||||||
AddComponentPopup<SphereColliderComponent>("SphereCollider");
|
AddComponentPopup<SphereColliderComponent>("SphereCollider");
|
||||||
AddComponentPopup<CapsuleColliderComponent>("CapsuleCollider");
|
AddComponentPopup<CapsuleColliderComponent>("CapsuleCollider");
|
||||||
@ -559,6 +564,12 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
|
|
||||||
DrawComponent<MeshComponent>("Mesh", entity, [](MeshComponent& meshComponent) {
|
DrawComponent<MeshComponent>("Mesh", entity, [](MeshComponent& meshComponent) {
|
||||||
|
|
||||||
|
UI::BeginPropertyGrid();
|
||||||
|
UI::PropertyAssetReference("Mesh", meshComponent.Mesh, AssetType::Mesh);
|
||||||
|
UI::EndPropertyGrid();
|
||||||
|
|
||||||
|
/*
|
||||||
ImGui::Columns(3);
|
ImGui::Columns(3);
|
||||||
ImGui::SetColumnWidth(0, 100);
|
ImGui::SetColumnWidth(0, 100);
|
||||||
ImGui::SetColumnWidth(1, 300);
|
ImGui::SetColumnWidth(1, 300);
|
||||||
@ -581,6 +592,7 @@ namespace Prism
|
|||||||
meshComponent.Mesh = Ref<Mesh>::Create(file);
|
meshComponent.Mesh = Ref<Mesh>::Create(file);
|
||||||
}
|
}
|
||||||
ImGui::Columns(1);
|
ImGui::Columns(1);
|
||||||
|
*/
|
||||||
});
|
});
|
||||||
|
|
||||||
DrawComponent<CameraComponent>("Camera", entity, [](CameraComponent& cameraComponent) {
|
DrawComponent<CameraComponent>("Camera", entity, [](CameraComponent& cameraComponent) {
|
||||||
@ -651,28 +663,9 @@ namespace Prism
|
|||||||
|
|
||||||
DrawComponent<SkyLightComponent>("Sky Light", entity, [](SkyLightComponent& slc)
|
DrawComponent<SkyLightComponent>("Sky Light", entity, [](SkyLightComponent& slc)
|
||||||
{
|
{
|
||||||
ImGui::Columns(3);
|
|
||||||
ImGui::SetColumnWidth(0, 100);
|
|
||||||
ImGui::SetColumnWidth(1, 300);
|
|
||||||
ImGui::SetColumnWidth(2, 40);
|
|
||||||
ImGui::Text("File Path");
|
|
||||||
ImGui::NextColumn();
|
|
||||||
ImGui::PushItemWidth(-1);
|
|
||||||
if (!slc.SceneEnvironment.FilePath.empty())
|
|
||||||
ImGui::InputText("##envfilepath", (char*)slc.SceneEnvironment.FilePath.c_str(), 256, ImGuiInputTextFlags_ReadOnly);
|
|
||||||
else
|
|
||||||
ImGui::InputText("##envfilepath", (char*)"Empty", 256, ImGuiInputTextFlags_ReadOnly);
|
|
||||||
ImGui::PopItemWidth();
|
|
||||||
ImGui::NextColumn();
|
|
||||||
if (ImGui::Button("...##openenv"))
|
|
||||||
{
|
|
||||||
std::string file = Application::Get().OpenFile("*.hdr");
|
|
||||||
if (!file.empty())
|
|
||||||
slc.SceneEnvironment = Environment::Load(file);
|
|
||||||
}
|
|
||||||
ImGui::Columns(1);
|
|
||||||
|
|
||||||
UI::BeginPropertyGrid();
|
UI::BeginPropertyGrid();
|
||||||
|
UI::PropertyAssetReference("Environment Map", slc.SceneEnvironment, AssetType::EnvMap);
|
||||||
UI::Property("Intensity", slc.Intensity, 0.01f, 0.0f, 5.0f);
|
UI::Property("Intensity", slc.Intensity, 0.01f, 0.0f, 5.0f);
|
||||||
UI::EndPropertyGrid();
|
UI::EndPropertyGrid();
|
||||||
});
|
});
|
||||||
@ -916,17 +909,6 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
DrawComponent<PhysicsMaterialComponent>("Physics Material", entity, [](PhysicsMaterialComponent& pmc)
|
|
||||||
{
|
|
||||||
UI::BeginPropertyGrid();
|
|
||||||
|
|
||||||
UI::Property("Static Friction", pmc.StaticFriction, 0.01f, 0.0f, 1.0f);
|
|
||||||
UI::Property("Dynamic Friction", pmc.DynamicFriction, 0.01f, 0.0f, 1.0f);
|
|
||||||
UI::Property("Bounciness", pmc.Bounciness, 0.01f, 0.0f, 1.0f);
|
|
||||||
|
|
||||||
UI::EndPropertyGrid();
|
|
||||||
});
|
|
||||||
|
|
||||||
DrawComponent<BoxColliderComponent>("Box Collider", entity, [](BoxColliderComponent& bcc)
|
DrawComponent<BoxColliderComponent>("Box Collider", entity, [](BoxColliderComponent& bcc)
|
||||||
{
|
{
|
||||||
UI::BeginPropertyGrid();
|
UI::BeginPropertyGrid();
|
||||||
@ -937,6 +919,7 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
|
|
||||||
UI::Property("IsTrigger", bcc.IsTrigger);
|
UI::Property("IsTrigger", bcc.IsTrigger);
|
||||||
|
UI::PropertyAssetReference("Material", bcc.Material, AssetType::PhysicsMat);
|
||||||
|
|
||||||
UI::EndPropertyGrid();
|
UI::EndPropertyGrid();
|
||||||
});
|
});
|
||||||
@ -951,6 +934,7 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
|
|
||||||
UI::Property("IsTrigger", scc.IsTrigger);
|
UI::Property("IsTrigger", scc.IsTrigger);
|
||||||
|
UI::PropertyAssetReference("Material", scc.Material, AssetType::PhysicsMat);
|
||||||
|
|
||||||
UI::EndPropertyGrid();
|
UI::EndPropertyGrid();
|
||||||
});
|
});
|
||||||
@ -965,6 +949,7 @@ namespace Prism
|
|||||||
if (UI::Property("Height", ccc.Height)) changed = true;
|
if (UI::Property("Height", ccc.Height)) changed = true;
|
||||||
|
|
||||||
UI::Property("Is Trigger", ccc.IsTrigger);
|
UI::Property("Is Trigger", ccc.IsTrigger);
|
||||||
|
UI::PropertyAssetReference("Material", ccc.Material, AssetType::PhysicsMat);
|
||||||
|
|
||||||
if (changed)
|
if (changed)
|
||||||
{
|
{
|
||||||
@ -976,8 +961,18 @@ namespace Prism
|
|||||||
|
|
||||||
DrawComponent<MeshColliderComponent>("Mesh Collider", entity, [&](MeshColliderComponent& mcc)
|
DrawComponent<MeshColliderComponent>("Mesh Collider", entity, [&](MeshColliderComponent& mcc)
|
||||||
{
|
{
|
||||||
|
UI::BeginPropertyGrid();
|
||||||
|
|
||||||
if (mcc.OverrideMesh)
|
if (mcc.OverrideMesh)
|
||||||
{
|
{
|
||||||
|
if (UI::PropertyAssetReference("Mesh", mcc.CollisionMesh, AssetType::Mesh))
|
||||||
|
{
|
||||||
|
if (mcc.IsConvex)
|
||||||
|
PhysicsWrappers::CreateConvexMesh(mcc, glm::vec3(1.0f));
|
||||||
|
else
|
||||||
|
PhysicsWrappers::CreateTriangleMesh(mcc, glm::vec3(1.0f));
|
||||||
|
}
|
||||||
|
/*
|
||||||
ImGui::Columns(3);
|
ImGui::Columns(3);
|
||||||
ImGui::SetColumnWidth(0, 100);
|
ImGui::SetColumnWidth(0, 100);
|
||||||
ImGui::SetColumnWidth(1, 250);
|
ImGui::SetColumnWidth(1, 250);
|
||||||
@ -1004,9 +999,9 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::EndColumns();
|
ImGui::EndColumns();
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
UI::BeginPropertyGrid();
|
|
||||||
if (UI::Property("Is Convex", mcc.IsConvex))
|
if (UI::Property("Is Convex", mcc.IsConvex))
|
||||||
{
|
{
|
||||||
if (mcc.CollisionMesh)
|
if (mcc.CollisionMesh)
|
||||||
@ -1019,6 +1014,8 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
|
|
||||||
UI::Property("Is Trigger", mcc.IsTrigger);
|
UI::Property("Is Trigger", mcc.IsTrigger);
|
||||||
|
UI::PropertyAssetReference("Material", mcc.Material, AssetType::PhysicsMat);
|
||||||
|
|
||||||
if (UI::Property("Override Mesh", mcc.OverrideMesh))
|
if (UI::Property("Override Mesh", mcc.OverrideMesh))
|
||||||
{
|
{
|
||||||
if (!mcc.OverrideMesh && entity.HasComponent<MeshComponent>())
|
if (!mcc.OverrideMesh && entity.HasComponent<MeshComponent>())
|
||||||
|
|||||||
@ -16,17 +16,6 @@ namespace Prism
|
|||||||
PhysicsActor::PhysicsActor(Entity entity)
|
PhysicsActor::PhysicsActor(Entity entity)
|
||||||
: m_Entity(entity), m_RigidBody(entity.GetComponent<RigidBodyComponent>())
|
: m_Entity(entity), m_RigidBody(entity.GetComponent<RigidBodyComponent>())
|
||||||
{
|
{
|
||||||
if (!m_Entity.HasComponent<PhysicsMaterialComponent>())
|
|
||||||
{
|
|
||||||
m_Material.StaticFriction = 1.0f;
|
|
||||||
m_Material.DynamicFriction = 1.0f;
|
|
||||||
m_Material.Bounciness = 0.0f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_Material = entity.GetComponent<PhysicsMaterialComponent>();
|
|
||||||
}
|
|
||||||
|
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,7 +202,6 @@ namespace Prism
|
|||||||
m_ActorInternal = actor;
|
m_ActorInternal = actor;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_MaterialInternal = physics.createMaterial(m_Material.StaticFriction, m_Material.DynamicFriction, m_Material.Bounciness);
|
|
||||||
if (m_Entity.HasComponent<BoxColliderComponent>()) PhysicsWrappers::AddBoxCollider(*this);
|
if (m_Entity.HasComponent<BoxColliderComponent>()) PhysicsWrappers::AddBoxCollider(*this);
|
||||||
if (m_Entity.HasComponent<SphereColliderComponent>()) PhysicsWrappers::AddSphereCollider(*this);
|
if (m_Entity.HasComponent<SphereColliderComponent>()) PhysicsWrappers::AddSphereCollider(*this);
|
||||||
if (m_Entity.HasComponent<CapsuleColliderComponent>()) PhysicsWrappers::AddCapsuleCollider(*this);
|
if (m_Entity.HasComponent<CapsuleColliderComponent>()) PhysicsWrappers::AddCapsuleCollider(*this);
|
||||||
|
|||||||
@ -61,10 +61,8 @@ namespace Prism
|
|||||||
private:
|
private:
|
||||||
Entity m_Entity;
|
Entity m_Entity;
|
||||||
RigidBodyComponent& m_RigidBody;
|
RigidBodyComponent& m_RigidBody;
|
||||||
PhysicsMaterialComponent m_Material;
|
|
||||||
|
|
||||||
physx::PxRigidActor* m_ActorInternal;
|
physx::PxRigidActor* m_ActorInternal;
|
||||||
physx::PxMaterial* m_MaterialInternal;
|
|
||||||
|
|
||||||
friend class Physics3D;
|
friend class Physics3D;
|
||||||
friend class PhysicsWrappers;
|
friend class PhysicsWrappers;
|
||||||
|
|||||||
@ -181,7 +181,11 @@ namespace Prism
|
|||||||
void PhysicsWrappers::AddBoxCollider(PhysicsActor& actor)
|
void PhysicsWrappers::AddBoxCollider(PhysicsActor& actor)
|
||||||
{
|
{
|
||||||
|
|
||||||
const auto& collider = actor.m_Entity.GetComponent<BoxColliderComponent>();
|
auto& collider = actor.m_Entity.GetComponent<BoxColliderComponent>();
|
||||||
|
|
||||||
|
if (!collider.Material)
|
||||||
|
collider.Material = Ref<PhysicsMaterial>::Create(0.6F, 0.6F, 0.0f);
|
||||||
|
|
||||||
const glm::vec3 scale = actor.m_Entity.Transform().Scale;
|
const glm::vec3 scale = actor.m_Entity.Transform().Scale;
|
||||||
glm::vec3 colliderSize = collider.Size;
|
glm::vec3 colliderSize = collider.Size;
|
||||||
|
|
||||||
@ -190,8 +194,9 @@ namespace Prism
|
|||||||
if (scale.z != 0.0f) colliderSize.z *= scale.z;
|
if (scale.z != 0.0f) colliderSize.z *= scale.z;
|
||||||
|
|
||||||
const auto boxGeometry = physx::PxBoxGeometry(colliderSize.x / 2.0f, colliderSize.y / 2.0f, colliderSize.z / 2.0f);
|
const auto boxGeometry = physx::PxBoxGeometry(colliderSize.x / 2.0f, colliderSize.y / 2.0f, colliderSize.z / 2.0f);
|
||||||
|
const physx::PxMaterial* material = s_Physics->createMaterial(collider.Material->StaticFriction, collider.Material->DynamicFriction, collider.Material->Bounciness);
|
||||||
|
physx::PxShape* shape = physx::PxRigidActorExt::createExclusiveShape(*actor.m_ActorInternal, boxGeometry, *material);
|
||||||
|
|
||||||
physx::PxShape* shape = physx::PxRigidActorExt::createExclusiveShape(*actor.m_ActorInternal, boxGeometry, *actor.m_MaterialInternal);
|
|
||||||
shape->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE, !collider.IsTrigger);
|
shape->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE, !collider.IsTrigger);
|
||||||
shape->setFlag(physx::PxShapeFlag::eTRIGGER_SHAPE, collider.IsTrigger);
|
shape->setFlag(physx::PxShapeFlag::eTRIGGER_SHAPE, collider.IsTrigger);
|
||||||
|
|
||||||
@ -200,7 +205,10 @@ namespace Prism
|
|||||||
|
|
||||||
void PhysicsWrappers::AddSphereCollider(PhysicsActor& actor)
|
void PhysicsWrappers::AddSphereCollider(PhysicsActor& actor)
|
||||||
{
|
{
|
||||||
const auto& collider = actor.m_Entity.GetComponent<SphereColliderComponent>();
|
auto& collider = actor.m_Entity.GetComponent<SphereColliderComponent>();
|
||||||
|
if (!collider.Material)
|
||||||
|
collider.Material = Ref<PhysicsMaterial>::Create(0.6F, 0.6F, 0.0f);
|
||||||
|
|
||||||
const glm::vec3 scale = actor.m_Entity.Transform().Scale;
|
const glm::vec3 scale = actor.m_Entity.Transform().Scale;
|
||||||
float colliderRadius = collider.Radius;
|
float colliderRadius = collider.Radius;
|
||||||
|
|
||||||
@ -208,15 +216,19 @@ namespace Prism
|
|||||||
|
|
||||||
const auto sphereGeometry = physx::PxSphereGeometry(colliderRadius);
|
const auto sphereGeometry = physx::PxSphereGeometry(colliderRadius);
|
||||||
|
|
||||||
physx::PxShape* shape = physx::PxRigidActorExt::createExclusiveShape(*actor.m_ActorInternal, sphereGeometry, *actor.m_MaterialInternal);
|
const physx::PxMaterial* material = s_Physics->createMaterial(collider.Material->StaticFriction, collider.Material->DynamicFriction, collider.Material->Bounciness);
|
||||||
// physx::PxShape* shape = physx::PxRigidActorExt::createExclusiveShape(actor, sphereGeometry, material);
|
physx::PxShape* shape = physx::PxRigidActorExt::createExclusiveShape(*actor.m_ActorInternal, sphereGeometry, *material);
|
||||||
|
|
||||||
shape->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE, !collider.IsTrigger);
|
shape->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE, !collider.IsTrigger);
|
||||||
shape->setFlag(physx::PxShapeFlag::eTRIGGER_SHAPE, collider.IsTrigger);
|
shape->setFlag(physx::PxShapeFlag::eTRIGGER_SHAPE, collider.IsTrigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsWrappers::AddCapsuleCollider(PhysicsActor& actor)
|
void PhysicsWrappers::AddCapsuleCollider(PhysicsActor& actor)
|
||||||
{
|
{
|
||||||
const auto& collider = actor.m_Entity.GetComponent<CapsuleColliderComponent>();
|
auto& collider = actor.m_Entity.GetComponent<CapsuleColliderComponent>();
|
||||||
|
if (!collider.Material)
|
||||||
|
collider.Material = Ref<PhysicsMaterial>::Create(0.6F, 0.6F, 0.0f);
|
||||||
|
|
||||||
const glm::vec3 scale = actor.m_Entity.Transform().Scale;
|
const glm::vec3 scale = actor.m_Entity.Transform().Scale;
|
||||||
float colliderRadius = collider.Radius;
|
float colliderRadius = collider.Radius;
|
||||||
float colliderHeight = collider.Height;
|
float colliderHeight = collider.Height;
|
||||||
@ -227,7 +239,14 @@ namespace Prism
|
|||||||
|
|
||||||
const auto capsuleGeometry = physx::PxCapsuleGeometry(colliderRadius, colliderHeight * 0.5f);
|
const auto capsuleGeometry = physx::PxCapsuleGeometry(colliderRadius, colliderHeight * 0.5f);
|
||||||
|
|
||||||
physx::PxShape* shape = physx::PxRigidActorExt::createExclusiveShape(*actor.m_ActorInternal, capsuleGeometry, *actor.m_MaterialInternal);
|
const physx::PxQuat rotation(physx::PxHalfPi, physx::PxVec3(0.0f, 0.0f, 1.0f));
|
||||||
|
const physx::PxTransform localPose(physx::PxVec3(0.0f), rotation);
|
||||||
|
|
||||||
|
const physx::PxMaterial* material = s_Physics->createMaterial(collider.Material->StaticFriction, collider.Material->DynamicFriction, collider.Material->Bounciness);
|
||||||
|
physx::PxShape* shape = physx::PxRigidActorExt::createExclusiveShape(*actor.m_ActorInternal, capsuleGeometry, *material);
|
||||||
|
|
||||||
|
shape->setLocalPose(localPose);
|
||||||
|
|
||||||
shape->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE, !collider.IsTrigger);
|
shape->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE, !collider.IsTrigger);
|
||||||
shape->setFlag(physx::PxShapeFlag::eTRIGGER_SHAPE, collider.IsTrigger);
|
shape->setFlag(physx::PxShapeFlag::eTRIGGER_SHAPE, collider.IsTrigger);
|
||||||
}
|
}
|
||||||
@ -235,7 +254,12 @@ namespace Prism
|
|||||||
void PhysicsWrappers::AddMeshCollider(PhysicsActor& actor)
|
void PhysicsWrappers::AddMeshCollider(PhysicsActor& actor)
|
||||||
{
|
{
|
||||||
auto& collider = actor.m_Entity.GetComponent<MeshColliderComponent>();
|
auto& collider = actor.m_Entity.GetComponent<MeshColliderComponent>();
|
||||||
|
if (!collider.Material)
|
||||||
|
collider.Material = Ref<PhysicsMaterial>::Create(0.6F, 0.6F, 0.0f);
|
||||||
|
|
||||||
glm::vec3 scale = actor.m_Entity.Transform().Scale;
|
glm::vec3 scale = actor.m_Entity.Transform().Scale;
|
||||||
|
physx::PxMaterial* material = s_Physics->createMaterial(collider.Material->StaticFriction, collider.Material->DynamicFriction, collider.Material->Bounciness);
|
||||||
|
physx::PxMaterial* materials[] = { material };
|
||||||
|
|
||||||
if (collider.IsConvex)
|
if (collider.IsConvex)
|
||||||
{
|
{
|
||||||
@ -243,7 +267,6 @@ namespace Prism
|
|||||||
|
|
||||||
for (const auto shape : shapes)
|
for (const auto shape : shapes)
|
||||||
{
|
{
|
||||||
physx::PxMaterial* materials[] = { actor.m_MaterialInternal };
|
|
||||||
shape->setMaterials(materials, 1);
|
shape->setMaterials(materials, 1);
|
||||||
shape->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE, !collider.IsTrigger);
|
shape->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE, !collider.IsTrigger);
|
||||||
shape->setFlag(physx::PxShapeFlag::eTRIGGER_SHAPE, collider.IsTrigger);
|
shape->setFlag(physx::PxShapeFlag::eTRIGGER_SHAPE, collider.IsTrigger);
|
||||||
@ -257,7 +280,6 @@ namespace Prism
|
|||||||
|
|
||||||
for (const auto shape : shapes)
|
for (const auto shape : shapes)
|
||||||
{
|
{
|
||||||
physx::PxMaterial* materials[] = { actor.m_MaterialInternal };
|
|
||||||
shape->setMaterials(materials, 1);
|
shape->setMaterials(materials, 1);
|
||||||
|
|
||||||
shape->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE, !collider.IsTrigger);
|
shape->setFlag(physx::PxShapeFlag::eSIMULATION_SHAPE, !collider.IsTrigger);
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "Prism/Core/Log.h"
|
#include "Prism/Core/Log.h"
|
||||||
#include "Prism/Renderer/Renderer.h"
|
#include "Prism/Renderer/Renderer.h"
|
||||||
|
#include "Prism/Utilities/StringUtils.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
@ -284,41 +285,19 @@ namespace Prism
|
|||||||
return FindToken(string.c_str(), token);
|
return FindToken(string.c_str(), token);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> SplitString(const std::string& string, const std::string& delimiters)
|
|
||||||
{
|
|
||||||
size_t start = 0;
|
|
||||||
size_t end = string.find_first_of(delimiters);
|
|
||||||
|
|
||||||
std::vector<std::string> result;
|
|
||||||
|
|
||||||
while (end <= std::string::npos)
|
|
||||||
{
|
|
||||||
std::string token = string.substr(start, end - start);
|
|
||||||
if (!token.empty())
|
|
||||||
result.push_back(token);
|
|
||||||
|
|
||||||
if (end == std::string::npos)
|
|
||||||
break;
|
|
||||||
|
|
||||||
start = end + 1;
|
|
||||||
end = string.find_first_of(delimiters, start);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
std::vector<std::string> SplitString(const std::string& string, const char delimiter)
|
std::vector<std::string> SplitString(const std::string& string, const char delimiter)
|
||||||
{
|
{
|
||||||
return SplitString(string, std::string(1, delimiter));
|
return Utils::SplitString(string, std::string(1, delimiter));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> Tokenize(const std::string& string)
|
std::vector<std::string> Tokenize(const std::string& string)
|
||||||
{
|
{
|
||||||
return SplitString(string, " \t\n\r");
|
return Utils::SplitString(string, " \t\n\r");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> GetLines(const std::string& string)
|
std::vector<std::string> GetLines(const std::string& string)
|
||||||
{
|
{
|
||||||
return SplitString(string, "\n");
|
return Utils::SplitString(string, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetBlock(const char* str, const char** outPosition)
|
std::string GetBlock(const char* str, const char** outPosition)
|
||||||
@ -345,11 +324,6 @@ namespace Prism
|
|||||||
return std::string(str, length);
|
return std::string(str, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StartsWith(const std::string& string, const std::string& start)
|
|
||||||
{
|
|
||||||
return string.find(start) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenGLShader::Parse()
|
void OpenGLShader::Parse()
|
||||||
{
|
{
|
||||||
const char* token;
|
const char* token;
|
||||||
@ -461,7 +435,7 @@ namespace Prism
|
|||||||
declaration = new OpenGLShaderUniformDeclaration(domain, t, name, count);
|
declaration = new OpenGLShaderUniformDeclaration(domain, t, name, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StartsWith(name, "r_"))
|
if (Utils::StartsWith(name, "r_"))
|
||||||
{
|
{
|
||||||
if (domain == ShaderDomain::Vertex)
|
if (domain == ShaderDomain::Vertex)
|
||||||
((OpenGLShaderUniformBufferDeclaration*)m_VSRendererUniformBuffers.front())->PushUniform(declaration);
|
((OpenGLShaderUniformBufferDeclaration*)m_VSRendererUniformBuffers.front())->PushUniform(declaration);
|
||||||
|
|||||||
@ -204,7 +204,7 @@ namespace Prism
|
|||||||
const uint32_t faceHeight = m_Height / 3;
|
const uint32_t faceHeight = m_Height / 3;
|
||||||
PM_CORE_ASSERT(faceWidth == faceHeight, "Non-square faces!");
|
PM_CORE_ASSERT(faceWidth == faceHeight, "Non-square faces!");
|
||||||
|
|
||||||
std::array<uint8_t*, 6> faces;
|
std::array<uint8_t*, 6> faces{};
|
||||||
for (size_t i = 0; i < faces.size(); i++)
|
for (size_t i = 0; i < faces.size(); i++)
|
||||||
faces[i] = new uint8_t[faceWidth * faceHeight * 3]; // 3 BPP
|
faces[i] = new uint8_t[faceWidth * faceHeight * 3]; // 3 BPP
|
||||||
|
|
||||||
@ -214,10 +214,10 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
for (size_t y = 0; y < faceHeight; y++)
|
for (size_t y = 0; y < faceHeight; y++)
|
||||||
{
|
{
|
||||||
size_t yOffset = y + faceHeight;
|
const size_t yOffset = y + faceHeight;
|
||||||
for (size_t x = 0; x < faceWidth; x++)
|
for (size_t x = 0; x < faceWidth; x++)
|
||||||
{
|
{
|
||||||
size_t xOffset = x + i * faceWidth;
|
const size_t xOffset = x + i * faceWidth;
|
||||||
faces[faceIndex][(x + y * faceWidth) * 3 + 0] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 0];
|
faces[faceIndex][(x + y * faceWidth) * 3 + 0] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 0];
|
||||||
faces[faceIndex][(x + y * faceWidth) * 3 + 1] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 1];
|
faces[faceIndex][(x + y * faceWidth) * 3 + 1] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 1];
|
||||||
faces[faceIndex][(x + y * faceWidth) * 3 + 2] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 2];
|
faces[faceIndex][(x + y * faceWidth) * 3 + 2] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 2];
|
||||||
@ -234,10 +234,10 @@ namespace Prism
|
|||||||
|
|
||||||
for (size_t y = 0; y < faceHeight; y++)
|
for (size_t y = 0; y < faceHeight; y++)
|
||||||
{
|
{
|
||||||
size_t yOffset = y + i * faceHeight;
|
const size_t yOffset = y + i * faceHeight;
|
||||||
for (size_t x = 0; x < faceWidth; x++)
|
for (size_t x = 0; x < faceWidth; x++)
|
||||||
{
|
{
|
||||||
size_t xOffset = x + faceWidth;
|
const size_t xOffset = x + faceWidth;
|
||||||
faces[faceIndex][(x + y * faceWidth) * 3 + 0] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 0];
|
faces[faceIndex][(x + y * faceWidth) * 3 + 0] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 0];
|
||||||
faces[faceIndex][(x + y * faceWidth) * 3 + 1] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 1];
|
faces[faceIndex][(x + y * faceWidth) * 3 + 1] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 1];
|
||||||
faces[faceIndex][(x + y * faceWidth) * 3 + 2] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 2];
|
faces[faceIndex][(x + y * faceWidth) * 3 + 2] = m_ImageData[(xOffset + yOffset * m_Width) * 3 + 2];
|
||||||
|
|||||||
@ -87,7 +87,7 @@ namespace Prism
|
|||||||
TextureFormat m_Format;
|
TextureFormat m_Format;
|
||||||
uint32_t m_Width, m_Height;
|
uint32_t m_Width, m_Height;
|
||||||
|
|
||||||
uint8_t* m_ImageData;
|
uint8_t* m_ImageData = nullptr;
|
||||||
|
|
||||||
std::string m_FilePath;
|
std::string m_FilePath;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,25 +4,65 @@
|
|||||||
|
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
|
|
||||||
#include "Prism/Utilities/FileSystemWatcher.h"
|
#include "Prism/Utilities/FileSystem.h"
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
#include "Prism/Core/Log.h"
|
#include "Prism/Core/Log.h"
|
||||||
|
#include "Prism/Asset/AssetsManager.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
FileSystemWatcher::FileSystemChangedCallbackFn FileSystemWatcher::s_Callback;
|
FileSystem::FileSystemChangedCallbackFn FileSystem::s_Callback;
|
||||||
|
|
||||||
static bool s_Watching = true;
|
static bool s_Watching = true;
|
||||||
|
static bool s_IgnoreNextChange = false;
|
||||||
static HANDLE s_WatcherThread;
|
static HANDLE s_WatcherThread;
|
||||||
|
|
||||||
void FileSystemWatcher::SetChangeCallback(const FileSystemChangedCallbackFn& callback)
|
bool FileSystem::CreateFolder(const std::filesystem::path& filepath)
|
||||||
|
{
|
||||||
|
const BOOL created = CreateDirectoryA(filepath.string().c_str(), NULL);
|
||||||
|
if (!created)
|
||||||
|
{
|
||||||
|
const DWORD error = GetLastError();
|
||||||
|
|
||||||
|
if (error == ERROR_ALREADY_EXISTS)
|
||||||
|
PM_CORE_ERROR("{0} already exists!", filepath.string());
|
||||||
|
|
||||||
|
if (error == ERROR_PATH_NOT_FOUND)
|
||||||
|
PM_CORE_ERROR("{0}: One or more directories don't exist.", filepath.string());
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileSystem::Exists(const std::string& filepath)
|
||||||
|
{
|
||||||
|
const DWORD attribs = GetFileAttributesA(filepath.c_str());
|
||||||
|
|
||||||
|
if (attribs == INVALID_FILE_ATTRIBUTES)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileSystem::SetChangeCallback(const FileSystemChangedCallbackFn& callback)
|
||||||
{
|
{
|
||||||
s_Callback = callback;
|
s_Callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
static std::string wchar_to_string(wchar_t* input)
|
||||||
|
{
|
||||||
|
std::wstring string_input(input);
|
||||||
|
std::string converted(string_input.begin(), string_input.end());
|
||||||
|
return converted;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
static std::string wchar_to_string(const wchar_t* input)
|
static std::string wchar_to_string(const wchar_t* input)
|
||||||
{
|
{
|
||||||
if (!input) return {};
|
if (!input) return {};
|
||||||
@ -38,7 +78,37 @@ namespace Prism
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSystemWatcher::StartWatching()
|
std::string FileSystem::Rename(const std::string& filepath, const std::string& newName)
|
||||||
|
{
|
||||||
|
s_IgnoreNextChange = true;
|
||||||
|
std::filesystem::path p = filepath;
|
||||||
|
std::string newFilePath = p.parent_path().string() + "/" + newName + p.extension().string();
|
||||||
|
MoveFileA(filepath.c_str(), newFilePath.c_str());
|
||||||
|
s_IgnoreNextChange = false;
|
||||||
|
return newFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileSystem::PrismDeleteFile(const std::string& filepath)
|
||||||
|
{
|
||||||
|
s_IgnoreNextChange = true;
|
||||||
|
std::string fp = filepath;
|
||||||
|
fp.append(1, '\0');
|
||||||
|
SHFILEOPSTRUCTA file_op;
|
||||||
|
file_op.hwnd = NULL;
|
||||||
|
file_op.wFunc = FO_DELETE;
|
||||||
|
file_op.pFrom = fp.c_str();
|
||||||
|
file_op.pTo = "";
|
||||||
|
file_op.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT;
|
||||||
|
file_op.fAnyOperationsAborted = false;
|
||||||
|
file_op.hNameMappings = 0;
|
||||||
|
file_op.lpszProgressTitle = "";
|
||||||
|
const int result = SHFileOperationA(&file_op);
|
||||||
|
s_IgnoreNextChange = false;
|
||||||
|
return result == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FileSystem::StartWatching()
|
||||||
{
|
{
|
||||||
DWORD threadId;
|
DWORD threadId;
|
||||||
s_WatcherThread = CreateThread(NULL, 0, Watch, NULL, 0, &threadId);
|
s_WatcherThread = CreateThread(NULL, 0, Watch, NULL, 0, &threadId);
|
||||||
@ -46,7 +116,7 @@ namespace Prism
|
|||||||
PM_CORE_TRACE("Starting file watching services");
|
PM_CORE_TRACE("Starting file watching services");
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSystemWatcher::StopWatching()
|
void FileSystem::StopWatching()
|
||||||
{
|
{
|
||||||
// TODO: this delay is too long
|
// TODO: this delay is too long
|
||||||
s_Watching = false;
|
s_Watching = false;
|
||||||
@ -57,16 +127,14 @@ namespace Prism
|
|||||||
PM_CORE_TRACE("closing file watching services");
|
PM_CORE_TRACE("closing file watching services");
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long FileSystemWatcher::Watch(void* param)
|
unsigned long FileSystem::Watch(void* param)
|
||||||
{
|
{
|
||||||
const LPCSTR filepath = "assets";
|
const LPCSTR filepath = "assets";
|
||||||
char* buffer = new char[1024];
|
BYTE* buffer = new BYTE[10 * 1024]; // 1 MB
|
||||||
OVERLAPPED overlapped = { 0 };
|
OVERLAPPED overlapped = { 0 };
|
||||||
HANDLE handle = NULL;
|
HANDLE handle = NULL;
|
||||||
DWORD bytesReturned = 0;
|
DWORD bytesReturned = 0;
|
||||||
|
|
||||||
ZeroMemory(buffer, 1024);
|
|
||||||
|
|
||||||
handle = CreateFile(
|
handle = CreateFile(
|
||||||
filepath,
|
filepath,
|
||||||
FILE_LIST_DIRECTORY,
|
FILE_LIST_DIRECTORY,
|
||||||
@ -95,7 +163,7 @@ namespace Prism
|
|||||||
DWORD status = ReadDirectoryChangesW(
|
DWORD status = ReadDirectoryChangesW(
|
||||||
handle,
|
handle,
|
||||||
buffer,
|
buffer,
|
||||||
1024,
|
10 * 1024 * sizeof(BYTE),
|
||||||
TRUE,
|
TRUE,
|
||||||
FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME,
|
FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME,
|
||||||
&bytesReturned,
|
&bytesReturned,
|
||||||
@ -106,28 +174,32 @@ namespace Prism
|
|||||||
if (!status)
|
if (!status)
|
||||||
PM_CORE_ERROR("{0}", GetLastError());
|
PM_CORE_ERROR("{0}", GetLastError());
|
||||||
|
|
||||||
// NOTE(Peter): We can't use 'INFINITE' here since that will prevent the thread from closing when we close the editor
|
|
||||||
const DWORD waitOperation = WaitForSingleObject(overlapped.hEvent, 2000);
|
const DWORD waitOperation = WaitForSingleObject(overlapped.hEvent, 2000);
|
||||||
|
|
||||||
// If nothing changed, just continue
|
|
||||||
if (waitOperation != WAIT_OBJECT_0)
|
if (waitOperation != WAIT_OBJECT_0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (s_IgnoreNextChange)
|
||||||
|
continue;
|
||||||
|
|
||||||
std::string oldName;
|
std::string oldName;
|
||||||
|
char fileName[MAX_PATH * 10] = "";
|
||||||
|
|
||||||
|
FILE_NOTIFY_INFORMATION* current = (FILE_NOTIFY_INFORMATION*)buffer;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
auto& fni = (FILE_NOTIFY_INFORMATION&)*buffer;
|
ZeroMemory(fileName, sizeof(fileName));
|
||||||
std::filesystem::path filePath;
|
|
||||||
filePath = "assets/" + wchar_to_string(fni.FileName);
|
WideCharToMultiByte(CP_ACP, 0, current->FileName, current->FileNameLength / sizeof(WCHAR), fileName, sizeof(fileName), NULL, NULL);
|
||||||
|
std::filesystem::path filePath = std::filesystem::path("assets") / std::string(fileName);
|
||||||
|
|
||||||
FileSystemChangedEvent e;
|
FileSystemChangedEvent e;
|
||||||
e.Filepath = filePath.string();
|
e.FilePath = filePath.string();
|
||||||
e.NewName = filePath.filename().string();
|
e.NewName = filePath.filename().string();
|
||||||
e.OldName = filePath.filename().string();
|
e.OldName = filePath.filename().string();
|
||||||
e.IsDirectory = std::filesystem::is_directory(filePath);
|
e.IsDirectory = std::filesystem::is_directory(filePath);
|
||||||
|
|
||||||
switch (fni.Action)
|
switch (current->Action)
|
||||||
{
|
{
|
||||||
case FILE_ACTION_ADDED:
|
case FILE_ACTION_ADDED:
|
||||||
{
|
{
|
||||||
@ -137,6 +209,7 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
case FILE_ACTION_REMOVED:
|
case FILE_ACTION_REMOVED:
|
||||||
{
|
{
|
||||||
|
e.IsDirectory = AssetsManager::IsDirectory(e.FilePath);
|
||||||
e.Action = FileSystemAction::Delete;
|
e.Action = FileSystemAction::Delete;
|
||||||
s_Callback(e);
|
s_Callback(e);
|
||||||
break;
|
break;
|
||||||
@ -161,13 +234,10 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fni.NextEntryOffset)
|
if (!current->NextEntryOffset)
|
||||||
{
|
|
||||||
ZeroMemory(buffer, 1024);
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
buffer += fni.NextEntryOffset;
|
current += current->NextEntryOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -276,7 +276,7 @@ namespace Prism
|
|||||||
|
|
||||||
float shininess, metalness;
|
float shininess, metalness;
|
||||||
if (aiMaterial->Get(AI_MATKEY_SHININESS, shininess) != aiReturn_SUCCESS)
|
if (aiMaterial->Get(AI_MATKEY_SHININESS, shininess) != aiReturn_SUCCESS)
|
||||||
shininess = 80.0f; // Default value
|
shininess = 0.0f; // Default value
|
||||||
aiMaterial->Get(AI_MATKEY_REFLECTIVITY, metalness);
|
aiMaterial->Get(AI_MATKEY_REFLECTIVITY, metalness);
|
||||||
if (aiMaterial->Get(AI_MATKEY_REFLECTIVITY, metalness) != aiReturn_SUCCESS)
|
if (aiMaterial->Get(AI_MATKEY_REFLECTIVITY, metalness) != aiReturn_SUCCESS)
|
||||||
metalness = 0.0f;
|
metalness = 0.0f;
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
#include "VertexArray.h"
|
#include "VertexArray.h"
|
||||||
#include "Prism/Core/TimeStep.h"
|
#include "Prism/Core/TimeStep.h"
|
||||||
#include "Prism/Core/Math/AABB.h"
|
#include "Prism/Core/Math/AABB.h"
|
||||||
|
#include "../Asset/Asset.h"
|
||||||
|
|
||||||
struct aiNode;
|
struct aiNode;
|
||||||
struct aiAnimation;
|
struct aiAnimation;
|
||||||
@ -103,7 +104,7 @@ namespace Prism
|
|||||||
std::string NodeName, MeshName;
|
std::string NodeName, MeshName;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PRISM_API Mesh : public RefCounted
|
class PRISM_API Mesh : public Asset
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -181,7 +182,7 @@ namespace Prism
|
|||||||
float m_AnimationTime = 0.0f;
|
float m_AnimationTime = 0.0f;
|
||||||
float m_WorldTime = 0.0f;
|
float m_WorldTime = 0.0f;
|
||||||
float m_TimeMultiplier = 1.0f;
|
float m_TimeMultiplier = 1.0f;
|
||||||
bool m_AnimationPlaying = true;
|
bool m_AnimationPlaying = false;
|
||||||
|
|
||||||
std::string m_FilePath;
|
std::string m_FilePath;
|
||||||
private:
|
private:
|
||||||
|
|||||||
@ -7,9 +7,4 @@
|
|||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
Environment Environment::Load(const std::string& filepath)
|
|
||||||
{
|
|
||||||
auto [radiance, irradiance] = SceneRenderer::CreateEnvironmentMap(filepath);
|
|
||||||
return { filepath, radiance, irradiance };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,13 +10,16 @@
|
|||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
struct Environment
|
class PRISM_API Environment : public Asset
|
||||||
{
|
{
|
||||||
std::string FilePath;
|
public:
|
||||||
|
Environment() = default;
|
||||||
|
Environment(const Ref<TextureCube>& radianceMap, const Ref<TextureCube>& irradianceMap)
|
||||||
|
: RadianceMap(radianceMap), IrradianceMap(irradianceMap) {}
|
||||||
|
|
||||||
Ref<TextureCube> RadianceMap;
|
Ref<TextureCube> RadianceMap;
|
||||||
Ref<TextureCube> IrradianceMap;
|
Ref<TextureCube> IrradianceMap;
|
||||||
|
|
||||||
static PRISM_API Environment Load(const std::string& filepath);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ namespace Prism
|
|||||||
|
|
||||||
// Resources
|
// Resources
|
||||||
Ref<MaterialInstance> SkyboxMaterial;
|
Ref<MaterialInstance> SkyboxMaterial;
|
||||||
Environment SceneEnvironment;
|
Ref<Environment> SceneEnvironment;
|
||||||
Light ActiveLight;
|
Light ActiveLight;
|
||||||
} SceneData;
|
} SceneData;
|
||||||
|
|
||||||
@ -148,6 +148,7 @@ namespace Prism
|
|||||||
constexpr float gridSize = 0.025f;
|
constexpr float gridSize = 0.025f;
|
||||||
s_Data.GridMaterial->Set("u_Scale", gridScale);
|
s_Data.GridMaterial->Set("u_Scale", gridScale);
|
||||||
s_Data.GridMaterial->Set("u_Res", gridSize);
|
s_Data.GridMaterial->Set("u_Res", gridSize);
|
||||||
|
s_Data.GridMaterial->SetFlag(MaterialFlag::TwoSided, true);
|
||||||
|
|
||||||
// outline
|
// outline
|
||||||
const auto outlineShader = Shader::Create("assets/shaders/Outline.glsl");
|
const auto outlineShader = Shader::Create("assets/shaders/Outline.glsl");
|
||||||
@ -465,8 +466,8 @@ namespace Prism
|
|||||||
baseMaterial->Set("u_IBLContribution", s_Data.SceneData.SceneEnvironmentIntensity);
|
baseMaterial->Set("u_IBLContribution", s_Data.SceneData.SceneEnvironmentIntensity);
|
||||||
|
|
||||||
// Environment (TODO: don't do this per mesh)
|
// Environment (TODO: don't do this per mesh)
|
||||||
baseMaterial->Set("u_EnvRadianceTex", s_Data.SceneData.SceneEnvironment.RadianceMap);
|
baseMaterial->Set("u_EnvRadianceTex", s_Data.SceneData.SceneEnvironment->RadianceMap);
|
||||||
baseMaterial->Set("u_EnvIrradianceTex", s_Data.SceneData.SceneEnvironment.IrradianceMap);
|
baseMaterial->Set("u_EnvIrradianceTex", s_Data.SceneData.SceneEnvironment->IrradianceMap);
|
||||||
baseMaterial->Set("u_BRDFLUTTexture", s_Data.BRDFLUT);
|
baseMaterial->Set("u_BRDFLUTTexture", s_Data.BRDFLUT);
|
||||||
|
|
||||||
// Set lights (TODO: move to light environment and don't do per mesh)
|
// Set lights (TODO: move to light environment and don't do per mesh)
|
||||||
@ -530,8 +531,8 @@ namespace Prism
|
|||||||
baseMaterial->Set("u_IBLContribution", s_Data.SceneData.SceneEnvironmentIntensity);
|
baseMaterial->Set("u_IBLContribution", s_Data.SceneData.SceneEnvironmentIntensity);
|
||||||
|
|
||||||
// Environment (TODO: don't do this per mesh)
|
// Environment (TODO: don't do this per mesh)
|
||||||
baseMaterial->Set("u_EnvRadianceTex", s_Data.SceneData.SceneEnvironment.RadianceMap);
|
baseMaterial->Set("u_EnvRadianceTex", s_Data.SceneData.SceneEnvironment->RadianceMap);
|
||||||
baseMaterial->Set("u_EnvIrradianceTex", s_Data.SceneData.SceneEnvironment.IrradianceMap);
|
baseMaterial->Set("u_EnvIrradianceTex", s_Data.SceneData.SceneEnvironment->IrradianceMap);
|
||||||
baseMaterial->Set("u_BRDFLUTTexture", s_Data.BRDFLUT);
|
baseMaterial->Set("u_BRDFLUTTexture", s_Data.BRDFLUT);
|
||||||
|
|
||||||
baseMaterial->Set("u_LightMatrixCascade0", s_Data.LightMatrices[0]);
|
baseMaterial->Set("u_LightMatrixCascade0", s_Data.LightMatrices[0]);
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
#include "RendererAPI.h"
|
#include "RendererAPI.h"
|
||||||
#include "Prism/Core/Buffer.h"
|
#include "Prism/Core/Buffer.h"
|
||||||
#include "Prism/Core/Ref.h"
|
#include "Prism/Core/Ref.h"
|
||||||
|
#include "../Asset/Asset.h"
|
||||||
|
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
@ -27,7 +28,7 @@ namespace Prism
|
|||||||
Repeat = 2
|
Repeat = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
class PRISM_API Texture : public RefCounted
|
class PRISM_API Texture : public Asset
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~Texture() {}
|
virtual ~Texture() {}
|
||||||
|
|||||||
@ -28,13 +28,14 @@ namespace Prism
|
|||||||
UUID ID = 0;
|
UUID ID = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ParentComponent
|
struct RelationshipComponent
|
||||||
{
|
{
|
||||||
UUID ParentHandle = 0;
|
UUID ParentHandle = 0;
|
||||||
|
std::vector<UUID> Children;
|
||||||
|
|
||||||
ParentComponent() = default;
|
RelationshipComponent() = default;
|
||||||
ParentComponent(const ParentComponent& other) = default;
|
RelationshipComponent(const RelationshipComponent& other) = default;
|
||||||
ParentComponent(const UUID& parent)
|
RelationshipComponent(UUID parent)
|
||||||
: ParentHandle(parent) {}
|
: ParentHandle(parent) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -178,6 +179,7 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
float Radius = 0.5f;
|
float Radius = 0.5f;
|
||||||
bool IsTrigger = false;
|
bool IsTrigger = false;
|
||||||
|
Ref<PhysicsMaterial> Material;
|
||||||
|
|
||||||
// The mesh that will be drawn in the editor to show the collision bounds
|
// The mesh that will be drawn in the editor to show the collision bounds
|
||||||
Ref<Mesh> DebugMesh;
|
Ref<Mesh> DebugMesh;
|
||||||
@ -211,22 +213,12 @@ namespace Prism
|
|||||||
RigidBodyComponent(const RigidBodyComponent& other) = default;
|
RigidBodyComponent(const RigidBodyComponent& other) = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: This will eventually be a resource, but that requires object referencing through the editor
|
|
||||||
struct PhysicsMaterialComponent
|
|
||||||
{
|
|
||||||
float StaticFriction = 1.0f;
|
|
||||||
float DynamicFriction = 1.0f;
|
|
||||||
float Bounciness = 1.0f;
|
|
||||||
|
|
||||||
PhysicsMaterialComponent() = default;
|
|
||||||
PhysicsMaterialComponent(const PhysicsMaterialComponent& other) = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct BoxColliderComponent
|
struct BoxColliderComponent
|
||||||
{
|
{
|
||||||
glm::vec3 Size = { 1.0f, 1.0f, 1.0f };
|
glm::vec3 Size = { 1.0f, 1.0f, 1.0f };
|
||||||
glm::vec3 Offset = { 0.0f, 0.0f, 0.0f };
|
glm::vec3 Offset = { 0.0f, 0.0f, 0.0f };
|
||||||
bool IsTrigger = false;
|
bool IsTrigger = false;
|
||||||
|
Ref<PhysicsMaterial> Material;
|
||||||
|
|
||||||
// The mesh that will be drawn in the editor to show the collision bounds
|
// The mesh that will be drawn in the editor to show the collision bounds
|
||||||
Ref<Mesh> DebugMesh;
|
Ref<Mesh> DebugMesh;
|
||||||
@ -240,6 +232,7 @@ namespace Prism
|
|||||||
float Radius = 0.5f;
|
float Radius = 0.5f;
|
||||||
float Height = 1.0f;
|
float Height = 1.0f;
|
||||||
bool IsTrigger = false;
|
bool IsTrigger = false;
|
||||||
|
Ref<PhysicsMaterial> Material;
|
||||||
|
|
||||||
Ref<Mesh> DebugMesh;
|
Ref<Mesh> DebugMesh;
|
||||||
|
|
||||||
@ -254,6 +247,7 @@ namespace Prism
|
|||||||
bool IsConvex = false;
|
bool IsConvex = false;
|
||||||
bool IsTrigger = false;
|
bool IsTrigger = false;
|
||||||
bool OverrideMesh = false;
|
bool OverrideMesh = false;
|
||||||
|
Ref<PhysicsMaterial> Material;
|
||||||
|
|
||||||
MeshColliderComponent() = default;
|
MeshColliderComponent() = default;
|
||||||
MeshColliderComponent(const MeshColliderComponent& other) = default;
|
MeshColliderComponent(const MeshColliderComponent& other) = default;
|
||||||
@ -284,9 +278,14 @@ namespace Prism
|
|||||||
|
|
||||||
struct SkyLightComponent
|
struct SkyLightComponent
|
||||||
{
|
{
|
||||||
Environment SceneEnvironment;
|
Ref<Environment> SceneEnvironment;
|
||||||
float Intensity = 1.0f;
|
float Intensity = 1.0f;
|
||||||
float Angle = 0.0f;
|
float Angle = 0.0f;
|
||||||
|
|
||||||
|
SkyLightComponent()
|
||||||
|
: SceneEnvironment(Ref<Environment>::Create())
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,4 +6,30 @@
|
|||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
|
bool Entity::IsAncesterOf(Entity entity)
|
||||||
|
{
|
||||||
|
const auto& children = Children();
|
||||||
|
|
||||||
|
if (children.size() == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (UUID child : children)
|
||||||
|
{
|
||||||
|
if (child == entity.GetUUID())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UUID child : children)
|
||||||
|
{
|
||||||
|
if (m_Scene->FindEntityByUUID(child).IsAncesterOf(entity))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Entity::IsDescendantOf(Entity entity) const
|
||||||
|
{
|
||||||
|
return entity.IsAncesterOf(*this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -67,9 +67,13 @@ namespace Prism
|
|||||||
return !(*this == other);
|
return !(*this == other);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetParentUUID(const UUID& parent) { GetComponent<ParentComponent>().ParentHandle = parent; }
|
void SetParentUUID(UUID parent) { GetComponent<RelationshipComponent>().ParentHandle = parent; }
|
||||||
UUID GetParentUUID() { return GetComponent<ParentComponent>().ParentHandle; }
|
UUID GetParentUUID() { return GetComponent<RelationshipComponent>().ParentHandle; }
|
||||||
std::vector<UUID>& Children() { return GetComponent<ChildrenComponent>().Children; }
|
std::vector<UUID>& Children() { return GetComponent<RelationshipComponent>().Children; }
|
||||||
|
|
||||||
|
bool IsAncesterOf(Entity entity);
|
||||||
|
bool IsDescendantOf(Entity entity) const;
|
||||||
|
|
||||||
|
|
||||||
UUID GetUUID() { return GetComponent<IDComponent>().ID; }
|
UUID GetUUID() { return GetComponent<IDComponent>().ID; }
|
||||||
UUID GetSceneUUID() const { return m_Scene->GetUUID(); }
|
UUID GetSceneUUID() const { return m_Scene->GetUUID(); }
|
||||||
|
|||||||
@ -260,14 +260,14 @@ namespace Prism
|
|||||||
|
|
||||||
// TODO: only one sky light at the moment!
|
// TODO: only one sky light at the moment!
|
||||||
{
|
{
|
||||||
m_Environment = Environment();
|
m_Environment = Ref<Environment>::Create();
|
||||||
const auto lights = m_Registry.group<SkyLightComponent>(entt::get<TransformComponent>);
|
const auto lights = m_Registry.group<SkyLightComponent>(entt::get<TransformComponent>);
|
||||||
for (const auto entity : lights)
|
for (const auto entity : lights)
|
||||||
{
|
{
|
||||||
auto [transformComponent, skyLightComponent] = lights.get<TransformComponent, SkyLightComponent>(entity);
|
auto [transformComponent, skyLightComponent] = lights.get<TransformComponent, SkyLightComponent>(entity);
|
||||||
m_Environment = skyLightComponent.SceneEnvironment;
|
m_Environment = skyLightComponent.SceneEnvironment;
|
||||||
m_EnvironmentIntensity = skyLightComponent.Intensity;
|
m_EnvironmentIntensity = skyLightComponent.Intensity;
|
||||||
SetSkybox(m_Environment.RadianceMap);
|
SetSkybox(m_Environment->RadianceMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,14 +339,14 @@ namespace Prism
|
|||||||
|
|
||||||
// TODO: only one sky light at the moment!
|
// TODO: only one sky light at the moment!
|
||||||
{
|
{
|
||||||
m_Environment = Environment();
|
m_Environment = Ref<Environment>::Create();
|
||||||
auto lights = m_Registry.group<SkyLightComponent>(entt::get<TransformComponent>);
|
auto lights = m_Registry.group<SkyLightComponent>(entt::get<TransformComponent>);
|
||||||
for (auto entity : lights)
|
for (auto entity : lights)
|
||||||
{
|
{
|
||||||
auto [transformComponent, skyLightComponent] = lights.get<TransformComponent, SkyLightComponent>(entity);
|
auto [transformComponent, skyLightComponent] = lights.get<TransformComponent, SkyLightComponent>(entity);
|
||||||
m_Environment = skyLightComponent.SceneEnvironment;
|
m_Environment = skyLightComponent.SceneEnvironment;
|
||||||
m_EnvironmentIntensity = skyLightComponent.Intensity;
|
m_EnvironmentIntensity = skyLightComponent.Intensity;
|
||||||
SetSkybox(m_Environment.RadianceMap);
|
SetSkybox(m_Environment->RadianceMap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -618,7 +618,7 @@ namespace Prism
|
|||||||
idComponent.ID = {};
|
idComponent.ID = {};
|
||||||
|
|
||||||
entity.AddComponent<TransformComponent>();
|
entity.AddComponent<TransformComponent>();
|
||||||
entity.AddComponent<ParentComponent>();
|
entity.AddComponent<RelationshipComponent>();
|
||||||
entity.AddComponent<ChildrenComponent>();
|
entity.AddComponent<ChildrenComponent>();
|
||||||
|
|
||||||
if (!name.empty())
|
if (!name.empty())
|
||||||
@ -635,7 +635,7 @@ namespace Prism
|
|||||||
idComponent.ID = uuid;
|
idComponent.ID = uuid;
|
||||||
|
|
||||||
entity.AddComponent<TransformComponent>();
|
entity.AddComponent<TransformComponent>();
|
||||||
entity.AddComponent<ParentComponent>();
|
entity.AddComponent<RelationshipComponent>();
|
||||||
entity.AddComponent<ChildrenComponent>();
|
entity.AddComponent<ChildrenComponent>();
|
||||||
|
|
||||||
if (!name.empty())
|
if (!name.empty())
|
||||||
@ -681,9 +681,7 @@ namespace Prism
|
|||||||
|
|
||||||
CopyComponentIfExists<TransformComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
CopyComponentIfExists<TransformComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
||||||
|
|
||||||
// TODO: should copy parent
|
CopyComponentIfExists<RelationshipComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
||||||
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<MeshComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
||||||
CopyComponentIfExists<DirectionalLightComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
CopyComponentIfExists<DirectionalLightComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
||||||
@ -695,7 +693,6 @@ namespace Prism
|
|||||||
CopyComponentIfExists<BoxCollider2DComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
CopyComponentIfExists<BoxCollider2DComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
||||||
CopyComponentIfExists<CircleCollider2DComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
CopyComponentIfExists<CircleCollider2DComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
||||||
CopyComponentIfExists<RigidBodyComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
CopyComponentIfExists<RigidBodyComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
||||||
CopyComponentIfExists<PhysicsMaterialComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
|
||||||
CopyComponentIfExists<BoxColliderComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
CopyComponentIfExists<BoxColliderComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
||||||
CopyComponentIfExists<SphereColliderComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
CopyComponentIfExists<SphereColliderComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
||||||
CopyComponentIfExists<CapsuleColliderComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
CopyComponentIfExists<CapsuleColliderComponent>(newEntity.m_EntityHandle, entity.m_EntityHandle, m_Registry);
|
||||||
@ -762,8 +759,7 @@ namespace Prism
|
|||||||
CopyComponent<TagComponent>(target->m_Registry, m_Registry, enttMap);
|
CopyComponent<TagComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
CopyComponent<TransformComponent>(target->m_Registry, m_Registry, enttMap);
|
CopyComponent<TransformComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
|
|
||||||
CopyComponent<ParentComponent>(target->m_Registry, m_Registry, enttMap);
|
CopyComponent<RelationshipComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
CopyComponent<ChildrenComponent>(target->m_Registry, m_Registry, enttMap);
|
|
||||||
|
|
||||||
CopyComponent<MeshComponent>(target->m_Registry, m_Registry, enttMap);
|
CopyComponent<MeshComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
CopyComponent<DirectionalLightComponent>(target->m_Registry, m_Registry, enttMap);
|
CopyComponent<DirectionalLightComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
@ -775,7 +771,6 @@ namespace Prism
|
|||||||
CopyComponent<BoxCollider2DComponent>(target->m_Registry, m_Registry, enttMap);
|
CopyComponent<BoxCollider2DComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
CopyComponent<CircleCollider2DComponent>(target->m_Registry, m_Registry, enttMap);
|
CopyComponent<CircleCollider2DComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
CopyComponent<RigidBodyComponent>(target->m_Registry, m_Registry, enttMap);
|
CopyComponent<RigidBodyComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
CopyComponent<PhysicsMaterialComponent>(target->m_Registry, m_Registry, enttMap);
|
|
||||||
CopyComponent<BoxColliderComponent>(target->m_Registry, m_Registry, enttMap);
|
CopyComponent<BoxColliderComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
CopyComponent<SphereColliderComponent>(target->m_Registry, m_Registry, enttMap);
|
CopyComponent<SphereColliderComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
CopyComponent<CapsuleColliderComponent>(target->m_Registry, m_Registry, enttMap);
|
CopyComponent<CapsuleColliderComponent>(target->m_Registry, m_Registry, enttMap);
|
||||||
|
|||||||
@ -65,7 +65,7 @@ namespace Prism
|
|||||||
|
|
||||||
void SetViewportSize(uint32_t width, uint32_t height);
|
void SetViewportSize(uint32_t width, uint32_t height);
|
||||||
|
|
||||||
const Environment& GetEnvironment() const { return m_Environment; }
|
const Ref<Environment>& GetEnvironment() const { return m_Environment; }
|
||||||
void SetSkybox(const Ref<TextureCube>& skybox);
|
void SetSkybox(const Ref<TextureCube>& skybox);
|
||||||
|
|
||||||
float& GetSkyboxLod() { return m_SkyboxLod; }
|
float& GetSkyboxLod() { return m_SkyboxLod; }
|
||||||
@ -130,7 +130,7 @@ namespace Prism
|
|||||||
|
|
||||||
bool m_IsPlaying = false;
|
bool m_IsPlaying = false;
|
||||||
|
|
||||||
Environment m_Environment;
|
Ref<Environment> m_Environment;
|
||||||
float m_EnvironmentIntensity = 1.0f;
|
float m_EnvironmentIntensity = 1.0f;
|
||||||
Ref<TextureCube> m_SkyboxTexture;
|
Ref<TextureCube> m_SkyboxTexture;
|
||||||
Ref<MaterialInstance> m_SkyboxMaterial;
|
Ref<MaterialInstance> m_SkyboxMaterial;
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
#include "Prism/Physics/PhysicsLayer.h"
|
#include "Prism/Physics/PhysicsLayer.h"
|
||||||
#include "Prism/Physics/PhysicsWrappers.h"
|
#include "Prism/Physics/PhysicsWrappers.h"
|
||||||
#include "Prism/Renderer/Meshfactory.h"
|
#include "Prism/Renderer/Meshfactory.h"
|
||||||
|
#include "../Asset/AssetsManager.h"
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
@ -160,19 +161,15 @@ namespace Prism
|
|||||||
out << YAML::Key << "Entity";
|
out << YAML::Key << "Entity";
|
||||||
out << YAML::Value << uuid;
|
out << YAML::Value << uuid;
|
||||||
|
|
||||||
if (entity.HasComponent<ParentComponent>())
|
if (entity.HasComponent<RelationshipComponent>())
|
||||||
{
|
{
|
||||||
auto& parent = entity.GetComponent<ParentComponent>();
|
auto& relationshipComponent = entity.GetComponent<RelationshipComponent>();
|
||||||
out << YAML::Key << "Parent" << YAML::Value << parent.ParentHandle;
|
out << YAML::Key << "Parent" << YAML::Value << relationshipComponent.ParentHandle;
|
||||||
}
|
|
||||||
|
|
||||||
if (entity.HasComponent<ChildrenComponent>())
|
|
||||||
{
|
|
||||||
const auto& childrenComponent = entity.GetComponent<ChildrenComponent>();
|
|
||||||
out << YAML::Key << "Children";
|
out << YAML::Key << "Children";
|
||||||
out << YAML::Value << YAML::BeginSeq;
|
out << YAML::Value << YAML::BeginSeq;
|
||||||
|
|
||||||
for (auto child : childrenComponent.Children)
|
for (auto child : relationshipComponent.Children)
|
||||||
{
|
{
|
||||||
out << YAML::BeginMap;
|
out << YAML::BeginMap;
|
||||||
out << YAML::Key << "Handle" << YAML::Value << child;
|
out << YAML::Key << "Handle" << YAML::Value << child;
|
||||||
@ -262,7 +259,10 @@ namespace Prism
|
|||||||
out << YAML::BeginMap; // MeshComponent
|
out << YAML::BeginMap; // MeshComponent
|
||||||
|
|
||||||
const auto mesh = entity.GetComponent<MeshComponent>().Mesh;
|
const auto mesh = entity.GetComponent<MeshComponent>().Mesh;
|
||||||
out << YAML::Key << "AssetPath" << YAML::Value << mesh->GetFilePath();
|
if (mesh)
|
||||||
|
out << YAML::Key << "AssetID" << YAML::Value << mesh->Handle;
|
||||||
|
else
|
||||||
|
out << YAML::Key << "AssetID" << YAML::Value << 0;
|
||||||
|
|
||||||
out << YAML::EndMap; // MeshComponent
|
out << YAML::EndMap; // MeshComponent
|
||||||
}
|
}
|
||||||
@ -287,7 +287,7 @@ namespace Prism
|
|||||||
out << YAML::BeginMap; // SkyLightComponent
|
out << YAML::BeginMap; // SkyLightComponent
|
||||||
|
|
||||||
const auto& skyLightComponent = entity.GetComponent<SkyLightComponent>();
|
const auto& skyLightComponent = entity.GetComponent<SkyLightComponent>();
|
||||||
out << YAML::Key << "EnvironmentAssetPath" << YAML::Value << skyLightComponent.SceneEnvironment.FilePath;
|
out << YAML::Key << "EnvironmentMap" << YAML::Value << skyLightComponent.SceneEnvironment->Handle;
|
||||||
out << YAML::Key << "Intensity" << YAML::Value << skyLightComponent.Intensity;
|
out << YAML::Key << "Intensity" << YAML::Value << skyLightComponent.Intensity;
|
||||||
out << YAML::Key << "Angle" << YAML::Value << skyLightComponent.Angle;
|
out << YAML::Key << "Angle" << YAML::Value << skyLightComponent.Angle;
|
||||||
|
|
||||||
@ -401,19 +401,6 @@ namespace Prism
|
|||||||
out << YAML::EndMap; // RigidBodyComponent
|
out << YAML::EndMap; // RigidBodyComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entity.HasComponent<PhysicsMaterialComponent>())
|
|
||||||
{
|
|
||||||
out << YAML::Key << "PhysicsMaterialComponent";
|
|
||||||
out << YAML::BeginMap; // PhysicsMaterialComponent
|
|
||||||
|
|
||||||
const auto& physicsMaterial = entity.GetComponent<PhysicsMaterialComponent>();
|
|
||||||
out << YAML::Key << "StaticFriction" << YAML::Value << physicsMaterial.StaticFriction;
|
|
||||||
out << YAML::Key << "DynamicFriction" << YAML::Value << physicsMaterial.DynamicFriction;
|
|
||||||
out << YAML::Key << "Bounciness" << YAML::Value << physicsMaterial.Bounciness;
|
|
||||||
|
|
||||||
out << YAML::EndMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entity.HasComponent<BoxColliderComponent>())
|
if (entity.HasComponent<BoxColliderComponent>())
|
||||||
{
|
{
|
||||||
out << YAML::Key << "BoxColliderComponent";
|
out << YAML::Key << "BoxColliderComponent";
|
||||||
@ -424,6 +411,11 @@ namespace Prism
|
|||||||
out << YAML::Key << "Size" << YAML::Value << boxColliderComponent.Size;
|
out << YAML::Key << "Size" << YAML::Value << boxColliderComponent.Size;
|
||||||
out << YAML::Key << "IsTrigger" << YAML::Value << boxColliderComponent.IsTrigger;
|
out << YAML::Key << "IsTrigger" << YAML::Value << boxColliderComponent.IsTrigger;
|
||||||
|
|
||||||
|
if (boxColliderComponent.Material)
|
||||||
|
out << YAML::Key << "Material" << YAML::Value << boxColliderComponent.Material->Handle;
|
||||||
|
else
|
||||||
|
out << YAML::Key << "Material" << YAML::Value << 0;
|
||||||
|
|
||||||
out << YAML::EndMap; // BoxColliderComponent
|
out << YAML::EndMap; // BoxColliderComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,6 +428,11 @@ namespace Prism
|
|||||||
out << YAML::Key << "Radius" << YAML::Value << sphereColliderComponent.Radius;
|
out << YAML::Key << "Radius" << YAML::Value << sphereColliderComponent.Radius;
|
||||||
out << YAML::Key << "IsTrigger" << YAML::Value << sphereColliderComponent.IsTrigger;
|
out << YAML::Key << "IsTrigger" << YAML::Value << sphereColliderComponent.IsTrigger;
|
||||||
|
|
||||||
|
if (sphereColliderComponent.Material)
|
||||||
|
out << YAML::Key << "Material" << YAML::Value << sphereColliderComponent.Material->Handle;
|
||||||
|
else
|
||||||
|
out << YAML::Key << "Material" << YAML::Value << 0;
|
||||||
|
|
||||||
out << YAML::EndMap; // SphereColliderComponent
|
out << YAML::EndMap; // SphereColliderComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,6 +446,11 @@ namespace Prism
|
|||||||
out << YAML::Key << "Height" << YAML::Value << capsuleColliderComponent.Height;
|
out << YAML::Key << "Height" << YAML::Value << capsuleColliderComponent.Height;
|
||||||
out << YAML::Key << "IsTrigger" << YAML::Value << capsuleColliderComponent.IsTrigger;
|
out << YAML::Key << "IsTrigger" << YAML::Value << capsuleColliderComponent.IsTrigger;
|
||||||
|
|
||||||
|
if (capsuleColliderComponent.Material)
|
||||||
|
out << YAML::Key << "Material" << YAML::Value << capsuleColliderComponent.Material->Handle;
|
||||||
|
else
|
||||||
|
out << YAML::Key << "Material" << YAML::Value << 0;
|
||||||
|
|
||||||
out << YAML::EndMap; // CapsuleColliderComponent
|
out << YAML::EndMap; // CapsuleColliderComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -460,12 +462,17 @@ namespace Prism
|
|||||||
auto meshColliderComponent = entity.GetComponent<MeshColliderComponent>();
|
auto meshColliderComponent = entity.GetComponent<MeshColliderComponent>();
|
||||||
|
|
||||||
if (meshColliderComponent.OverrideMesh)
|
if (meshColliderComponent.OverrideMesh)
|
||||||
out << YAML::Key << "AssetPath" << YAML::Value << meshColliderComponent.CollisionMesh->GetFilePath();
|
out << YAML::Key << "AssetID" << YAML::Value << meshColliderComponent.CollisionMesh->Handle;
|
||||||
|
|
||||||
out << YAML::Key << "IsConvex" << YAML::Value << meshColliderComponent.IsConvex;
|
out << YAML::Key << "IsConvex" << YAML::Value << meshColliderComponent.IsConvex;
|
||||||
out << YAML::Key << "IsTrigger" << YAML::Value << meshColliderComponent.IsTrigger;
|
out << YAML::Key << "IsTrigger" << YAML::Value << meshColliderComponent.IsTrigger;
|
||||||
out << YAML::Key << "OverrideMesh" << YAML::Value << meshColliderComponent.OverrideMesh;
|
out << YAML::Key << "OverrideMesh" << YAML::Value << meshColliderComponent.OverrideMesh;
|
||||||
|
|
||||||
|
if (meshColliderComponent.Material)
|
||||||
|
out << YAML::Key << "Material" << YAML::Value << meshColliderComponent.Material->Handle;
|
||||||
|
else
|
||||||
|
out << YAML::Key << "Material" << YAML::Value << 0;
|
||||||
|
|
||||||
out << YAML::EndMap; // MeshColliderComponent
|
out << YAML::EndMap; // MeshColliderComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,7 +484,7 @@ namespace Prism
|
|||||||
out << YAML::Key << "Environment";
|
out << YAML::Key << "Environment";
|
||||||
out << YAML::Value;
|
out << YAML::Value;
|
||||||
out << YAML::BeginMap; // Environment
|
out << YAML::BeginMap; // Environment
|
||||||
out << YAML::Key << "AssetPath" << YAML::Value << scene->GetEnvironment().FilePath;
|
out << YAML::Key << "AssetHandle" << YAML::Value << scene->GetEnvironment()->Handle;
|
||||||
const auto& light = scene->GetLight();
|
const auto& light = scene->GetLight();
|
||||||
out << YAML::Key << "Light" << YAML::Value;
|
out << YAML::Key << "Light" << YAML::Value;
|
||||||
out << YAML::BeginMap; // Light
|
out << YAML::BeginMap; // Light
|
||||||
@ -598,8 +605,9 @@ namespace Prism
|
|||||||
Entity deserializedEntity = m_Scene->CreateEntityWithID(uuid, name);
|
Entity deserializedEntity = m_Scene->CreateEntityWithID(uuid, name);
|
||||||
|
|
||||||
|
|
||||||
|
auto& relationshipComponent = deserializedEntity.GetComponent<RelationshipComponent>();
|
||||||
uint64_t parentHandle = entity["Parent"] ? entity["Parent"].as<uint64_t>() : 0;
|
uint64_t parentHandle = entity["Parent"] ? entity["Parent"].as<uint64_t>() : 0;
|
||||||
deserializedEntity.GetComponent<ParentComponent>().ParentHandle = parentHandle;
|
relationshipComponent.ParentHandle = parentHandle;
|
||||||
|
|
||||||
const auto children = entity["Children"];
|
const auto children = entity["Children"];
|
||||||
if (children)
|
if (children)
|
||||||
@ -607,7 +615,7 @@ namespace Prism
|
|||||||
for (auto child : children)
|
for (auto child : children)
|
||||||
{
|
{
|
||||||
auto childHandle = child["Handle"].as<uint64_t>();
|
auto childHandle = child["Handle"].as<uint64_t>();
|
||||||
deserializedEntity.GetComponent<ChildrenComponent>().Children.emplace_back(childHandle);
|
relationshipComponent.Children.push_back(childHandle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -711,22 +719,24 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto meshComponent = entity["MeshComponent"])
|
auto meshComponent = entity["MeshComponent"];
|
||||||
|
if (meshComponent)
|
||||||
{
|
{
|
||||||
const std::string meshPath = meshComponent["AssetPath"].as<std::string>();
|
UUID assetID;
|
||||||
// TEMP (because script creates mesh component...)
|
if (meshComponent["AssetPath"])
|
||||||
if (!deserializedEntity.HasComponent<MeshComponent>())
|
|
||||||
{
|
{
|
||||||
Ref<Mesh> mesh;
|
const std::string assetFilePath = meshComponent["AssetPath"].as<std::string>();
|
||||||
if (!CheckPath(meshPath))
|
assetID = AssetsManager::GetAssetIDForFile(assetFilePath);
|
||||||
missingPaths.emplace_back(meshPath);
|
}
|
||||||
else
|
else
|
||||||
mesh = Ref<Mesh>::Create(meshPath);
|
{
|
||||||
|
assetID = meshComponent["AssetID"].as<uint64_t>();
|
||||||
deserializedEntity.AddComponent<MeshComponent>(mesh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PM_CORE_INFO(" Mesh Asset Path: {0}", meshPath);
|
if (AssetsManager::IsAssetHandleValid(assetID) && !deserializedEntity.HasComponent<MeshComponent>())
|
||||||
|
{
|
||||||
|
deserializedEntity.AddComponent<MeshComponent>(AssetsManager::GetAsset<Mesh>(assetID));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto directionalLightComponent = entity["DirectionalLightComponent"])
|
if (auto directionalLightComponent = entity["DirectionalLightComponent"])
|
||||||
@ -741,18 +751,23 @@ namespace Prism
|
|||||||
if (auto skyLightComponent = entity["SkyLightComponent"])
|
if (auto skyLightComponent = entity["SkyLightComponent"])
|
||||||
{
|
{
|
||||||
auto& component = deserializedEntity.AddComponent<SkyLightComponent>();
|
auto& component = deserializedEntity.AddComponent<SkyLightComponent>();
|
||||||
const std::string env = skyLightComponent["EnvironmentAssetPath"].as<std::string>();
|
|
||||||
if (!env.empty())
|
AssetHandle assetHandle;
|
||||||
|
if (skyLightComponent["EnvironmentAssetPath"])
|
||||||
{
|
{
|
||||||
if (!CheckPath(env))
|
const std::string filePath = skyLightComponent["EnvironmentAssetPath"].as<std::string>();
|
||||||
{
|
assetHandle = AssetsManager::GetAssetIDForFile(filePath);
|
||||||
missingPaths.emplace_back(env);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
component.SceneEnvironment = Environment::Load(env);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assetHandle = skyLightComponent["EnvironmentMap"].as<uint64_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AssetsManager::IsAssetHandleValid(assetHandle))
|
||||||
|
{
|
||||||
|
component.SceneEnvironment = AssetsManager::GetAsset<Environment>(assetHandle);
|
||||||
|
}
|
||||||
|
|
||||||
component.Intensity = skyLightComponent["Intensity"].as<float>();
|
component.Intensity = skyLightComponent["Intensity"].as<float>();
|
||||||
component.Angle = skyLightComponent["Angle"].as<float>();
|
component.Angle = skyLightComponent["Angle"].as<float>();
|
||||||
}
|
}
|
||||||
@ -837,20 +852,19 @@ namespace Prism
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto physicsMaterialComponent = entity["PhysicsMaterialComponent"])
|
|
||||||
{
|
|
||||||
auto& component = deserializedEntity.AddComponent<PhysicsMaterialComponent>();
|
|
||||||
component.StaticFriction = physicsMaterialComponent["StaticFriction"].as<float>();
|
|
||||||
component.DynamicFriction = physicsMaterialComponent["DynamicFriction"].as<float>();
|
|
||||||
component.Bounciness = physicsMaterialComponent["Bounciness"].as<float>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto boxColliderComponent = entity["BoxColliderComponent"])
|
if (auto boxColliderComponent = entity["BoxColliderComponent"])
|
||||||
{
|
{
|
||||||
auto& component = deserializedEntity.AddComponent<BoxColliderComponent>();
|
auto& component = deserializedEntity.AddComponent<BoxColliderComponent>();
|
||||||
component.Offset = boxColliderComponent["Offset"].as<glm::vec3>();
|
component.Offset = boxColliderComponent["Offset"].as<glm::vec3>();
|
||||||
component.Size = boxColliderComponent["Size"].as<glm::vec3>();
|
component.Size = boxColliderComponent["Size"].as<glm::vec3>();
|
||||||
component.IsTrigger = boxColliderComponent["IsTrigger"] ? boxColliderComponent["IsTrigger"].as<bool>() : false;
|
component.IsTrigger = boxColliderComponent["IsTrigger"] ? boxColliderComponent["IsTrigger"].as<bool>() : false;
|
||||||
|
|
||||||
|
auto material = boxColliderComponent["Material"];
|
||||||
|
if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>()))
|
||||||
|
{
|
||||||
|
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(material.as<uint64_t>());
|
||||||
|
}
|
||||||
|
|
||||||
component.DebugMesh = MeshFactory::CreateBox(component.Size);
|
component.DebugMesh = MeshFactory::CreateBox(component.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -859,6 +873,11 @@ namespace Prism
|
|||||||
auto& component = deserializedEntity.AddComponent<SphereColliderComponent>();
|
auto& component = deserializedEntity.AddComponent<SphereColliderComponent>();
|
||||||
component.Radius = sphereColliderComponent["Radius"].as<float>();
|
component.Radius = sphereColliderComponent["Radius"].as<float>();
|
||||||
component.IsTrigger = sphereColliderComponent["IsTrigger"] ? sphereColliderComponent["IsTrigger"].as<bool>() : false;
|
component.IsTrigger = sphereColliderComponent["IsTrigger"] ? sphereColliderComponent["IsTrigger"].as<bool>() : false;
|
||||||
|
|
||||||
|
auto material = sphereColliderComponent["Material"];
|
||||||
|
if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>()))
|
||||||
|
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(material.as<uint64_t>());
|
||||||
|
|
||||||
component.DebugMesh = MeshFactory::CreateSphere(component.Radius);
|
component.DebugMesh = MeshFactory::CreateSphere(component.Radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -868,6 +887,11 @@ namespace Prism
|
|||||||
component.Radius = capsuleColliderComponent["Radius"].as<float>();
|
component.Radius = capsuleColliderComponent["Radius"].as<float>();
|
||||||
component.Height = capsuleColliderComponent["Height"].as<float>();
|
component.Height = capsuleColliderComponent["Height"].as<float>();
|
||||||
component.IsTrigger = capsuleColliderComponent["IsTrigger"] ? capsuleColliderComponent["IsTrigger"].as<bool>() : false;
|
component.IsTrigger = capsuleColliderComponent["IsTrigger"] ? capsuleColliderComponent["IsTrigger"].as<bool>() : false;
|
||||||
|
|
||||||
|
auto material = capsuleColliderComponent["Material"];
|
||||||
|
if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>()))
|
||||||
|
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(material.as<uint64_t>());
|
||||||
|
|
||||||
component.DebugMesh = MeshFactory::CreateCapsule(component.Radius, component.Height);
|
component.DebugMesh = MeshFactory::CreateCapsule(component.Radius, component.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -878,16 +902,19 @@ namespace Prism
|
|||||||
|
|
||||||
if (overrideMesh)
|
if (overrideMesh)
|
||||||
{
|
{
|
||||||
auto meshPath = meshColliderComponent["AssetPath"].as<std::string>();
|
UUID assetID;
|
||||||
if (!CheckPath(meshPath))
|
if (meshComponent["AssetPath"])
|
||||||
{
|
{
|
||||||
missingPaths.emplace_back(meshPath);
|
const auto assetFilePath = meshComponent["AssetPath"].as<std::string>();
|
||||||
|
assetID = AssetsManager::GetAssetIDForFile(assetFilePath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
collisionMesh = Ref<Mesh>::Create(meshPath);
|
assetID = meshComponent["AssetID"].as<uint64_t>();
|
||||||
}
|
}
|
||||||
collisionMesh = Ref<Mesh>::Create(meshPath);
|
|
||||||
|
if (AssetsManager::IsAssetHandleValid(assetID))
|
||||||
|
collisionMesh = AssetsManager::GetAsset<Mesh>(assetID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collisionMesh)
|
if (collisionMesh)
|
||||||
@ -897,16 +924,46 @@ namespace Prism
|
|||||||
component.IsTrigger = meshColliderComponent["IsTrigger"] ? meshColliderComponent["IsTrigger"].as<bool>() : false;
|
component.IsTrigger = meshColliderComponent["IsTrigger"] ? meshColliderComponent["IsTrigger"].as<bool>() : false;
|
||||||
component.OverrideMesh = overrideMesh;
|
component.OverrideMesh = overrideMesh;
|
||||||
|
|
||||||
if (component.IsConvex)
|
auto material = meshColliderComponent["Material"];
|
||||||
PhysicsWrappers::CreateConvexMesh(component, deserializedEntity.Transform().Scale);
|
if (material && AssetsManager::IsAssetHandleValid(material.as<uint64_t>()))
|
||||||
else
|
{
|
||||||
PhysicsWrappers::CreateTriangleMesh(component, deserializedEntity.Transform().Scale);
|
component.Material = AssetsManager::GetAsset<PhysicsMaterial>(material.as<uint64_t>());
|
||||||
|
|
||||||
|
if (component.IsConvex)
|
||||||
|
PhysicsWrappers::CreateConvexMesh(component, deserializedEntity.Transform().Scale);
|
||||||
|
else
|
||||||
|
PhysicsWrappers::CreateTriangleMesh(component, deserializedEntity.Transform().Scale);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PM_CORE_WARN("MeshColliderComponent in use without valid mesh!");
|
PM_CORE_WARN("MeshColliderComponent in use without valid mesh!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// NOTE: Compatibility fix for older scenes
|
||||||
|
auto physicsMaterialComponent = entity["PhysicsMaterialComponent"];
|
||||||
|
if (physicsMaterialComponent)
|
||||||
|
{
|
||||||
|
//auto& component = deserializedEntity.AddComponent<PhysicsMaterialComponent>();
|
||||||
|
Ref<PhysicsMaterial> material = Ref<PhysicsMaterial>::Create();
|
||||||
|
material->StaticFriction = physicsMaterialComponent["StaticFriction"].as<float>();
|
||||||
|
material->DynamicFriction = physicsMaterialComponent["DynamicFriction"].as<float>();
|
||||||
|
material->Bounciness = physicsMaterialComponent["Bounciness"].as<float>();
|
||||||
|
|
||||||
|
if (deserializedEntity.HasComponent<BoxColliderComponent>())
|
||||||
|
deserializedEntity.GetComponent<BoxColliderComponent>().Material = material;
|
||||||
|
|
||||||
|
if (deserializedEntity.HasComponent<SphereColliderComponent>())
|
||||||
|
deserializedEntity.GetComponent<SphereColliderComponent>().Material = material;
|
||||||
|
|
||||||
|
if (deserializedEntity.HasComponent<CapsuleColliderComponent>())
|
||||||
|
deserializedEntity.GetComponent<CapsuleColliderComponent>().Material = material;
|
||||||
|
|
||||||
|
if (deserializedEntity.HasComponent<MeshColliderComponent>())
|
||||||
|
deserializedEntity.GetComponent<MeshColliderComponent>().Material = material;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,423 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Atdunbg on 2026/1/20.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "AssetsManager.h"
|
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "Prism/Core/Log.h"
|
|
||||||
#include "Prism/Renderer/Mesh.h"
|
|
||||||
|
|
||||||
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["hdr"] = AssetType::EnvMap;
|
|
||||||
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::AssetsChangeEventFn AssetsManager::s_AssetsChangeCallback;
|
|
||||||
std::unordered_map<size_t, Asset> AssetsManager::s_LoadedAssets;
|
|
||||||
std::vector<DirectoryInfo> AssetsManager::s_Directories;
|
|
||||||
|
|
||||||
void AssetsManager::Init()
|
|
||||||
{
|
|
||||||
FileSystemWatcher::SetChangeCallback(OnFileSystemChanged);
|
|
||||||
ReloadAssets();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsManager::SetAssetChangeCallback(const AssetsChangeEventFn& callback)
|
|
||||||
{
|
|
||||||
s_AssetsChangeCallback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DirectoryInfo& AssetsManager::GetDirectoryInfo(const int index)
|
|
||||||
{
|
|
||||||
PM_CORE_ASSERT(index >= 0 && index < s_Directories.size());
|
|
||||||
return s_Directories[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<Asset> AssetsManager::GetAssetsInDirectory(const int dirIndex)
|
|
||||||
{
|
|
||||||
std::vector<Asset> results;
|
|
||||||
|
|
||||||
for (const auto& asset : s_LoadedAssets)
|
|
||||||
{
|
|
||||||
if (asset.second.ParentDirectory == dirIndex)
|
|
||||||
results.push_back(asset.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> AssetsManager::GetDirectoryNames(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;
|
|
||||||
}
|
|
||||||
|
|
||||||
SearchResults AssetsManager::SearchFiles(const std::string& query, const std::string& searchPath)
|
|
||||||
{
|
|
||||||
SearchResults results;
|
|
||||||
|
|
||||||
if (!searchPath.empty())
|
|
||||||
{
|
|
||||||
for (const auto& dir : s_Directories)
|
|
||||||
{
|
|
||||||
if (dir.DirectoryName.find(query) != std::string::npos && dir.FilePath.find(searchPath) != std::string::npos)
|
|
||||||
{
|
|
||||||
results.Directories.push_back(dir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto&[key, asset] : s_LoadedAssets)
|
|
||||||
{
|
|
||||||
if (asset.FileName.find(query) != std::string::npos && asset.FilePath.find(searchPath) != std::string::npos)
|
|
||||||
{
|
|
||||||
results.Assets.push_back(asset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
std::string AssetsManager::GetParentPath(const std::string& path)
|
|
||||||
{
|
|
||||||
return std::filesystem::path(path).parent_path().string();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
Ref<T> AssetsManager::InstantiateAsset(UUID assetId)
|
|
||||||
{
|
|
||||||
PM_CORE_ASSERT(s_LoadedAssets.find(assetId) != s_LoadedAssets.end());
|
|
||||||
return Ref<T>(static_cast<T*>(s_LoadedAssets[assetId].Data));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scene, Mesh, Texture, EnvMap, Image, Audio, Script, Other
|
|
||||||
template<>
|
|
||||||
Ref<Mesh> AssetsManager::InstantiateAsset(UUID assetId)
|
|
||||||
{
|
|
||||||
PM_CORE_ASSERT(s_LoadedAssets.find(assetId) != s_LoadedAssets.end());
|
|
||||||
return Ref<Mesh>(static_cast<Mesh*>(s_LoadedAssets[assetId].Data));
|
|
||||||
}
|
|
||||||
|
|
||||||
template PRISM_API Ref<Mesh> AssetsManager::InstantiateAsset(UUID assetId);
|
|
||||||
|
|
||||||
|
|
||||||
Asset& AssetsManager::GetAssetFromId(UUID assetId)
|
|
||||||
{
|
|
||||||
PM_CORE_ASSERT(s_LoadedAssets.find(assetId) != s_LoadedAssets.end());
|
|
||||||
return s_LoadedAssets[assetId];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AssetsManager::MoveFile(const std::string& originalPath, const std::string& dest)
|
|
||||||
{
|
|
||||||
// TODO: fixeme: MoveFile cannot work
|
|
||||||
try
|
|
||||||
{
|
|
||||||
std::filesystem::rename(originalPath, dest);
|
|
||||||
const std::string newPath = dest + "/" + ParseFilename(originalPath, "/\\");
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string AssetsManager::ParseFilename(const std::string& filepath, const std::string_view& delim)
|
|
||||||
{
|
|
||||||
const size_t pos = filepath.find_last_of(delim);
|
|
||||||
if (pos == std::string::npos)
|
|
||||||
return filepath;
|
|
||||||
return filepath.substr(pos + 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];
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string AssetsManager::RemoveExtension(const std::string& filename)
|
|
||||||
{
|
|
||||||
const size_t end = filename.find_last_of('.');
|
|
||||||
std::string newName = filename.substr(0, end);
|
|
||||||
|
|
||||||
return newName;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AssetsManager::ImportAsset(const std::string& filepath, bool reimport, int parentIndex)
|
|
||||||
{
|
|
||||||
Asset asset{};
|
|
||||||
asset.ID = UUID();
|
|
||||||
asset.FilePath = filepath;
|
|
||||||
asset.FileName = ParseFilename(filepath, "/\\");
|
|
||||||
asset.Extension = ParseFileType(asset.FileName);
|
|
||||||
asset.Type = AssetTypes::GetAssetTypeFromExtension(asset.Extension);
|
|
||||||
asset.ParentDirectory = parentIndex;
|
|
||||||
|
|
||||||
switch (asset.Type)
|
|
||||||
{
|
|
||||||
case AssetType::Scene:
|
|
||||||
{
|
|
||||||
asset.Data = nullptr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AssetType::Mesh:
|
|
||||||
{
|
|
||||||
if (asset.Extension == "blend")
|
|
||||||
break;
|
|
||||||
|
|
||||||
Ref<Mesh> mesh = Ref<Mesh>::Create(filepath);
|
|
||||||
// NOTE(Peter): Required to make sure that the asset doesn't get destroyed when Ref goes out of scope
|
|
||||||
mesh->IncRefCount();
|
|
||||||
asset.Data = mesh.Raw();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AssetType::Texture:
|
|
||||||
{
|
|
||||||
Ref<Texture2D> texture = Texture2D::Create(filepath);
|
|
||||||
texture->IncRefCount();
|
|
||||||
asset.Data = texture.Raw();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AssetType::EnvMap:
|
|
||||||
{
|
|
||||||
// TODO
|
|
||||||
/*Ref<TextureCube> texture = Ref<TextureCube>::Create(filepath);
|
|
||||||
texture->IncRefCount();
|
|
||||||
asset.Data = texture.Raw();*/
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AssetType::Audio:
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AssetType::Script:
|
|
||||||
{
|
|
||||||
asset.Data = &asset.FilePath;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AssetType::Other:
|
|
||||||
{
|
|
||||||
asset.Data = &asset.FilePath;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reimport)
|
|
||||||
{
|
|
||||||
for (auto it = s_LoadedAssets.begin(); it != s_LoadedAssets.end(); ++it)
|
|
||||||
{
|
|
||||||
if (it->second.FilePath == filepath)
|
|
||||||
{
|
|
||||||
if (it->second.Data != nullptr)
|
|
||||||
delete it->second.Data;
|
|
||||||
it->second.Data = asset.Data;
|
|
||||||
asset.Data = nullptr;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s_LoadedAssets[asset.ID] = asset;
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
int AssetsManager::ProcessDirectory(const std::string& directoryPath,const int parentIndex)
|
|
||||||
{
|
|
||||||
DirectoryInfo dirInfo;
|
|
||||||
dirInfo.DirectoryName = std::filesystem::path(directoryPath).filename().string();
|
|
||||||
dirInfo.ParentIndex = parentIndex;
|
|
||||||
dirInfo.FilePath = directoryPath;
|
|
||||||
s_Directories.push_back(dirInfo);
|
|
||||||
int currentIndex = (int)s_Directories.size() - 1;
|
|
||||||
s_Directories[currentIndex].DirectoryIndex = currentIndex;
|
|
||||||
|
|
||||||
for (auto entry : std::filesystem::directory_iterator(directoryPath))
|
|
||||||
{
|
|
||||||
if (entry.is_directory())
|
|
||||||
{
|
|
||||||
int childIndex = ProcessDirectory(entry.path().string(), currentIndex);
|
|
||||||
s_Directories[currentIndex].ChildrenIndices.push_back(childIndex);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ImportAsset(entry.path().string(), false, currentIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsManager::ReloadAssets()
|
|
||||||
{
|
|
||||||
ProcessDirectory("assets");
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsManager::OnFileSystemChanged(FileSystemChangedEvent e)
|
|
||||||
{
|
|
||||||
e.NewName = RemoveExtension(e.NewName);
|
|
||||||
e.OldName = RemoveExtension(e.OldName);
|
|
||||||
|
|
||||||
if (e.Action == FileSystemAction::Added)
|
|
||||||
{
|
|
||||||
if (!e.IsDirectory)
|
|
||||||
ImportAsset(e.Filepath);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.Action == FileSystemAction::Modified)
|
|
||||||
{
|
|
||||||
if (!e.IsDirectory)
|
|
||||||
ImportAsset(e.Filepath, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.Action == FileSystemAction::Rename)
|
|
||||||
{
|
|
||||||
for (auto& kv : s_LoadedAssets)
|
|
||||||
{
|
|
||||||
if (kv.second.FileName == e.OldName)
|
|
||||||
kv.second.FileName = e.NewName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.Action == FileSystemAction::Delete)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
for (auto it = m_LoadedAssets.begin(); it != m_LoadedAssets.end(); it++)
|
|
||||||
{
|
|
||||||
if (it->DirectoryName != e.NewName)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
m_LoadedAssets.erase(it);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_AssetsChangeCallback)
|
|
||||||
s_AssetsChangeCallback();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,105 +0,0 @@
|
|||||||
//
|
|
||||||
// Created by Atdunbg on 2026/1/20.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef PRISM_ASSETSMANAGER_H
|
|
||||||
#define PRISM_ASSETSMANAGER_H
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
|
|
||||||
#include "FileSystemWatcher.h"
|
|
||||||
#include "Prism/Core/Ref.h"
|
|
||||||
#include "Prism/Core/UUID.h"
|
|
||||||
|
|
||||||
namespace Prism
|
|
||||||
{
|
|
||||||
enum class AssetType
|
|
||||||
{
|
|
||||||
Scene, Mesh, Texture, EnvMap, 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 DirectoryName;
|
|
||||||
std::string FilePath;
|
|
||||||
int DirectoryIndex;
|
|
||||||
int ParentIndex;
|
|
||||||
std::vector<int> ChildrenIndices;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Asset
|
|
||||||
{
|
|
||||||
UUID ID;
|
|
||||||
std::string FilePath;
|
|
||||||
std::string FileName;
|
|
||||||
std::string Extension;
|
|
||||||
AssetType Type;
|
|
||||||
int ParentDirectory;
|
|
||||||
void* Data;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SearchResults
|
|
||||||
{
|
|
||||||
std::vector<DirectoryInfo> Directories;
|
|
||||||
std::vector<Asset> Assets;
|
|
||||||
};
|
|
||||||
|
|
||||||
class PRISM_API AssetsManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using AssetsChangeEventFn = std::function<void()>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static void Init();
|
|
||||||
static void SetAssetChangeCallback(const AssetsChangeEventFn& callback);
|
|
||||||
static DirectoryInfo& GetDirectoryInfo(int index);
|
|
||||||
static std::vector<Asset> GetAssetsInDirectory(int dirIndex);
|
|
||||||
static std::vector<std::string> GetDirectoryNames(const std::string& filepath);
|
|
||||||
|
|
||||||
static SearchResults SearchFiles(const std::string& query, const std::string& searchPath);
|
|
||||||
static std::string GetParentPath(const std::string& path);
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static Ref<T> InstantiateAsset(UUID assetId);
|
|
||||||
|
|
||||||
static Asset& GetAssetFromId(UUID assetId);
|
|
||||||
|
|
||||||
// TODO: This will NOT live here
|
|
||||||
static bool MoveFile(const std::string& originalPath, const std::string& dest);
|
|
||||||
|
|
||||||
static std::string StripExtras(const std::string& filename);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static std::string ParseFilename(const std::string& filepath, const std::string_view& delim);
|
|
||||||
static std::string ParseFileType(const std::string& filename);
|
|
||||||
static std::string RemoveExtension(const std::string& filename);
|
|
||||||
|
|
||||||
static void ImportAsset(const std::string& filepath, bool reimport = false, int parentIndex = -1);
|
|
||||||
static void ConvertAsset(const std::string& assetPath, const std::string& conversionType);
|
|
||||||
static int ProcessDirectory(const std::string& directoryPath, int parentIndex = -1);
|
|
||||||
static void ReloadAssets();
|
|
||||||
// static void WriteAssetsToDisk();
|
|
||||||
|
|
||||||
static void OnFileSystemChanged(FileSystemChangedEvent e);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static std::unordered_map<size_t, Asset> s_LoadedAssets;
|
|
||||||
static std::vector<DirectoryInfo> s_Directories;
|
|
||||||
static AssetsChangeEventFn s_AssetsChangeCallback;
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#endif //PRISM_ASSETSMANAGER_H
|
|
||||||
@ -1,24 +0,0 @@
|
|||||||
//
|
|
||||||
// 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
|
|
||||||
@ -2,8 +2,8 @@
|
|||||||
// Created by Atdunbg on 2026/1/21.
|
// Created by Atdunbg on 2026/1/21.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef PRISM_FILESYSTEMWATCHER_H
|
#ifndef PRISM_FILESYSTEM_H
|
||||||
#define PRISM_FILESYSTEMWATCHER_H
|
#define PRISM_FILESYSTEM_H
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
@ -17,17 +17,23 @@ namespace Prism
|
|||||||
struct FileSystemChangedEvent
|
struct FileSystemChangedEvent
|
||||||
{
|
{
|
||||||
FileSystemAction Action;
|
FileSystemAction Action;
|
||||||
std::string Filepath;
|
std::string FilePath;
|
||||||
std::string OldName;
|
std::string OldName;
|
||||||
std::string NewName;
|
std::string NewName;
|
||||||
bool IsDirectory;
|
bool IsDirectory;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PRISM_API FileSystemWatcher
|
class PRISM_API FileSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using FileSystemChangedCallbackFn = std::function<void(FileSystemChangedEvent)>;
|
using FileSystemChangedCallbackFn = std::function<void(FileSystemChangedEvent)>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static bool CreateFolder(const std::filesystem::path& filepath);
|
||||||
|
static bool Exists(const std::string& filepath);
|
||||||
|
static std::string Rename(const std::string& filepath, const std::string& newName);
|
||||||
|
static bool PrismDeleteFile(const std::string& filepath);
|
||||||
|
|
||||||
static void SetChangeCallback(const FileSystemChangedCallbackFn& callback);
|
static void SetChangeCallback(const FileSystemChangedCallbackFn& callback);
|
||||||
static void StartWatching();
|
static void StartWatching();
|
||||||
static void StopWatching();
|
static void StopWatching();
|
||||||
@ -41,4 +47,4 @@ namespace Prism
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //PRISM_FILESYSTEMWATCHER_H
|
#endif //PRISM_FILESYSTEM_H
|
||||||
69
Prism/src/Prism/Utilities/StringUtils.cpp
Normal file
69
Prism/src/Prism/Utilities/StringUtils.cpp
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
//
|
||||||
|
// Created by Atdunbg on 2026/2/13.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "StringUtils.h"
|
||||||
|
|
||||||
|
namespace Prism::Utils
|
||||||
|
{
|
||||||
|
|
||||||
|
std::string GetFilename(const std::string& filepath)
|
||||||
|
{
|
||||||
|
std::vector<std::string> parts = SplitString(filepath, "/\\");
|
||||||
|
|
||||||
|
if (!parts.empty())
|
||||||
|
return parts[parts.size() - 1];
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetExtension(const std::string& filename)
|
||||||
|
{
|
||||||
|
std::vector<std::string> parts = SplitString(filename, '.');
|
||||||
|
|
||||||
|
if (parts.size() > 1)
|
||||||
|
return parts[parts.size() - 1];
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string RemoveExtension(const std::string& filename)
|
||||||
|
{
|
||||||
|
return filename.substr(0, filename.find_last_of('.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StartsWith(const std::string& string, const std::string& start)
|
||||||
|
{
|
||||||
|
return string.find(start) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> SplitString(const std::string& string, const std::string& delimiters)
|
||||||
|
{
|
||||||
|
size_t start = 0;
|
||||||
|
size_t end = string.find_first_of(delimiters);
|
||||||
|
|
||||||
|
std::vector<std::string> result;
|
||||||
|
|
||||||
|
while (end <= std::string::npos)
|
||||||
|
{
|
||||||
|
const std::string token = string.substr(start, end - start);
|
||||||
|
if (!token.empty())
|
||||||
|
result.push_back(token);
|
||||||
|
|
||||||
|
if (end == std::string::npos)
|
||||||
|
break;
|
||||||
|
|
||||||
|
start = end + 1;
|
||||||
|
end = string.find_first_of(delimiters, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> SplitString(const std::string& string, const char delimiter)
|
||||||
|
{
|
||||||
|
return SplitString(string, std::string(1, delimiter));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
22
Prism/src/Prism/Utilities/StringUtils.h
Normal file
22
Prism/src/Prism/Utilities/StringUtils.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
//
|
||||||
|
// Created by Atdunbg on 2026/2/13.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef PRISM_STRINGUTILS_H
|
||||||
|
#define PRISM_STRINGUTILS_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Prism::Utils
|
||||||
|
{
|
||||||
|
std::string GetFilename(const std::string& filepath);
|
||||||
|
std::string GetExtension(const std::string& filename);
|
||||||
|
std::string RemoveExtension(const std::string& filename);
|
||||||
|
bool StartsWith(const std::string& string, const std::string& start);
|
||||||
|
std::vector<std::string> SplitString(const std::string& string, const std::string& delimiters);
|
||||||
|
std::vector<std::string> SplitString(const std::string& string, const char delimiter);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif //PRISM_STRINGUTILS_H
|
||||||
Reference in New Issue
Block a user