add args for entry Application; using efsw to replace custom filewatcher; remove some useless code; move FileOpenSelector from Application to FileSystem;some tweaks
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -32,3 +32,6 @@
|
|||||||
[submodule "Prism/vendor/ImViewGuizmo"]
|
[submodule "Prism/vendor/ImViewGuizmo"]
|
||||||
path = Prism/vendor/ImViewGuizmo
|
path = Prism/vendor/ImViewGuizmo
|
||||||
url = https://github.com/Ka1serM/ImViewGuizmo
|
url = https://github.com/Ka1serM/ImViewGuizmo
|
||||||
|
[submodule "Prism/vendor/efsw"]
|
||||||
|
path = Prism/vendor/efsw
|
||||||
|
url = https://github.com/SpartanJ/efsw
|
||||||
|
|||||||
@ -2,7 +2,7 @@ project(PrismEditor)
|
|||||||
|
|
||||||
set(CMAKE_BINARY_DIR ${CMAKE_BINARY_DIR}/bin)
|
set(CMAKE_BINARY_DIR ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
|
||||||
file(GLOB ASSETS assets)
|
file(GLOB ASSETS "assets")
|
||||||
file(COPY ${ASSETS} DESTINATION ${CMAKE_BINARY_DIR})
|
file(COPY ${ASSETS} DESTINATION ${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
# imgui.ini file
|
# imgui.ini file
|
||||||
|
|||||||
@ -23,7 +23,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Prism::Application* Prism::CreateApplication()
|
Prism::Application* Prism::CreateApplication(const CommandArgs args)
|
||||||
{
|
{
|
||||||
return new Editor({"hello wrold", 1920, 1080});
|
return new Editor({"hello world", 1920, 1080, args});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -280,6 +280,31 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
auto& materials = mesh->GetMaterials();
|
auto& materials = mesh->GetMaterials();
|
||||||
static uint32_t selectedMaterialIndex = 0;
|
static uint32_t selectedMaterialIndex = 0;
|
||||||
|
{
|
||||||
|
ImGui::BeginChild("MaterialList", ImVec2(0, 150), ImGuiChildFlags_Borders);
|
||||||
|
|
||||||
|
static ImGuiTextFilter filter;
|
||||||
|
filter.Draw("Filter", ImGui::GetContentRegionAvail().x);
|
||||||
|
|
||||||
|
if (ImGui::BeginListBox("##MaterialsListBox", ImVec2(-FLT_MIN, -FLT_MIN)))
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < materials.size(); i++)
|
||||||
|
{
|
||||||
|
const auto& materialInstance = materials[i];
|
||||||
|
std::string name = materialInstance->GetName();
|
||||||
|
|
||||||
|
if (!filter.PassFilter(name.c_str()))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool isSelected = (selectedMaterialIndex == i);
|
||||||
|
if (ImGui::Selectable(name.c_str(), isSelected))
|
||||||
|
selectedMaterialIndex = i;
|
||||||
|
}
|
||||||
|
ImGui::EndListBox();
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
|
}
|
||||||
|
/*
|
||||||
for (uint32_t i = 0; i < materials.size(); i++)
|
for (uint32_t i = 0; i < materials.size(); i++)
|
||||||
{
|
{
|
||||||
const auto& materialInstance = materials[i];
|
const auto& materialInstance = materials[i];
|
||||||
@ -294,6 +319,7 @@ namespace Prism
|
|||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|
||||||
@ -327,8 +353,7 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
if (ImGui::IsItemClicked())
|
if (ImGui::IsItemClicked())
|
||||||
{
|
{
|
||||||
std::string filename = Application::Get().OpenFile("");
|
if (std::string filename = FileSystem::OpenFileSelector("*.png;*.tga;*.jpg;*.jpeg"); !filename.empty())
|
||||||
if (filename != "")
|
|
||||||
{
|
{
|
||||||
albedoMap = Texture2D::Create(filename, true/*m_AlbedoInput.SRGB*/);
|
albedoMap = Texture2D::Create(filename, true/*m_AlbedoInput.SRGB*/);
|
||||||
materialInstance->Set("u_AlbedoTexture", albedoMap);
|
materialInstance->Set("u_AlbedoTexture", albedoMap);
|
||||||
@ -374,8 +399,7 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
if (ImGui::IsItemClicked())
|
if (ImGui::IsItemClicked())
|
||||||
{
|
{
|
||||||
std::string filename = Application::Get().OpenFile("");
|
if (std::string filename = FileSystem::OpenFileSelector("*.png;*.tga;*.jpg;*.jpeg"); !filename.empty())
|
||||||
if (filename != "")
|
|
||||||
{
|
{
|
||||||
normalMap = Texture2D::Create(filename);
|
normalMap = Texture2D::Create(filename);
|
||||||
materialInstance->Set("u_NormalTexture", normalMap);
|
materialInstance->Set("u_NormalTexture", normalMap);
|
||||||
@ -412,8 +436,7 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
if (ImGui::IsItemClicked())
|
if (ImGui::IsItemClicked())
|
||||||
{
|
{
|
||||||
std::string filename = Application::Get().OpenFile("");
|
if (std::string filename = FileSystem::OpenFileSelector("*.png;*.tga;*.jpg;*.jpeg"); !filename.empty())
|
||||||
if (filename != "")
|
|
||||||
{
|
{
|
||||||
metalnessMap = Texture2D::Create(filename);
|
metalnessMap = Texture2D::Create(filename);
|
||||||
materialInstance->Set("u_MetalnessTexture", metalnessMap);
|
materialInstance->Set("u_MetalnessTexture", metalnessMap);
|
||||||
@ -451,8 +474,7 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
if (ImGui::IsItemClicked())
|
if (ImGui::IsItemClicked())
|
||||||
{
|
{
|
||||||
std::string filename = Application::Get().OpenFile("");
|
if (std::string filename = FileSystem::OpenFileSelector("*.png;*.tga;*.jpg;*.jpeg"); !filename.empty())
|
||||||
if (filename != "")
|
|
||||||
{
|
{
|
||||||
roughnessMap = Texture2D::Create(filename);
|
roughnessMap = Texture2D::Create(filename);
|
||||||
materialInstance->Set("u_RoughnessTexture", roughnessMap);
|
materialInstance->Set("u_RoughnessTexture", roughnessMap);
|
||||||
@ -493,32 +515,14 @@ namespace Prism
|
|||||||
UI::BeginPropertyGrid();
|
UI::BeginPropertyGrid();
|
||||||
ImGui::AlignTextToFramePadding();
|
ImGui::AlignTextToFramePadding();
|
||||||
|
|
||||||
auto& light = m_EditorScene->GetLight();
|
|
||||||
UI::PropertySlider("Light Direction", light.Direction, -1.0f, 1.0f);
|
|
||||||
UI::PropertyColor("Light Radiance", light.Radiance);
|
|
||||||
UI::PropertySlider("Light Multiplier", light.Multiplier, 0.0f, 5.0f);
|
|
||||||
|
|
||||||
UI::PropertySlider("Exposure", m_EditorCamera.GetExposure(), 0.0f, 5.0f);
|
UI::PropertySlider("Exposure", m_EditorCamera.GetExposure(), 0.0f, 5.0f);
|
||||||
|
|
||||||
UI::Property("Radiance Prefiltering", m_RadiancePrefilter);
|
|
||||||
UI::PropertySlider("Env Map Rotation", m_EnvMapRotation, -360.0f, 360.0f);
|
|
||||||
|
|
||||||
if (m_SceneState == SceneState::Edit)
|
|
||||||
{
|
|
||||||
float physics2DGravity = m_EditorScene->GetPhysics2DGravity();
|
float physics2DGravity = m_EditorScene->GetPhysics2DGravity();
|
||||||
if (UI::Property("2D World Gravity", physics2DGravity, -10000.0f, 10000.0f))
|
if (UI::Property("2D World Gravity", physics2DGravity, -100.0f, 100.0f))
|
||||||
{
|
{
|
||||||
m_EditorScene->SetPhysics2DGravity(physics2DGravity);
|
m_EditorScene->SetPhysics2DGravity(physics2DGravity);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (m_SceneState == SceneState::Play)
|
|
||||||
{
|
|
||||||
float physics2DGravity = m_RuntimeScene->GetPhysics2DGravity();
|
|
||||||
if (UI::Property("2D World Gravity", physics2DGravity, -10000.0f, 10000.0f))
|
|
||||||
{
|
|
||||||
m_RuntimeScene->SetPhysics2DGravity(physics2DGravity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UI::Property("Show Bounding Boxes", m_UIShowBoundingBoxes);
|
UI::Property("Show Bounding Boxes", m_UIShowBoundingBoxes);
|
||||||
|
|
||||||
@ -579,6 +583,15 @@ namespace Prism
|
|||||||
m_ViewportPanelHovered = ImGui::IsWindowHovered();
|
m_ViewportPanelHovered = ImGui::IsWindowHovered();
|
||||||
m_ViewportPanelFocused = ImGui::IsWindowFocused();
|
m_ViewportPanelFocused = ImGui::IsWindowFocused();
|
||||||
|
|
||||||
|
if (!m_ViewportPanelFocused && m_ViewportPanelHovered)
|
||||||
|
{
|
||||||
|
if (Input::IsMouseButtonPressed(MouseButton::Right))
|
||||||
|
{
|
||||||
|
ImGui::SetWindowFocus("Viewport");
|
||||||
|
m_ViewportPanelFocused = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto viewportOffset = ImGui::GetCursorPos(); // includes tab bar
|
auto viewportOffset = ImGui::GetCursorPos(); // includes tab bar
|
||||||
auto viewportSize = ImGui::GetContentRegionAvail();
|
auto viewportSize = ImGui::GetContentRegionAvail();
|
||||||
|
|
||||||
@ -693,7 +706,7 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
}else
|
}else
|
||||||
{
|
{
|
||||||
glm::mat4 transformBase = transform * selection.Mesh->Transform;
|
glm::mat4 transformBase = transform * selection.Mesh->LocalTransform;
|
||||||
ImGuizmo::Manipulate(glm::value_ptr(m_EditorCamera.GetViewMatrix()),
|
ImGuizmo::Manipulate(glm::value_ptr(m_EditorCamera.GetViewMatrix()),
|
||||||
glm::value_ptr(m_EditorCamera.GetProjectionMatrix()),
|
glm::value_ptr(m_EditorCamera.GetProjectionMatrix()),
|
||||||
(ImGuizmo::OPERATION)m_GizmoType,
|
(ImGuizmo::OPERATION)m_GizmoType,
|
||||||
@ -704,6 +717,7 @@ namespace Prism
|
|||||||
|
|
||||||
if (ImGuizmo::IsUsing())
|
if (ImGuizmo::IsUsing())
|
||||||
{
|
{
|
||||||
|
selection.Mesh->LocalTransform = glm::inverse(entityTransform.GetTransform()) * transformBase;
|
||||||
selection.Mesh->Transform = glm::inverse(entityTransform.GetTransform()) * transformBase;
|
selection.Mesh->Transform = glm::inverse(entityTransform.GetTransform()) * transformBase;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -950,7 +964,7 @@ namespace Prism
|
|||||||
case KeyCode::B:
|
case KeyCode::B:
|
||||||
// Toggle bounding boxes
|
// Toggle bounding boxes
|
||||||
m_UIShowBoundingBoxes = !m_UIShowBoundingBoxes;
|
m_UIShowBoundingBoxes = !m_UIShowBoundingBoxes;
|
||||||
ShowBoundingBoxes(m_UIShowBoundingBoxes,false);
|
ShowBoundingBoxes(m_UIShowBoundingBoxes);
|
||||||
break;
|
break;
|
||||||
case KeyCode::D:
|
case KeyCode::D:
|
||||||
if (m_SelectionContext.size())
|
if (m_SelectionContext.size())
|
||||||
@ -1059,9 +1073,9 @@ namespace Prism
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorLayer::ShowBoundingBoxes(bool show, bool onTop)
|
void EditorLayer::ShowBoundingBoxes(const bool show)
|
||||||
{
|
{
|
||||||
SceneRenderer::GetOptions().ShowBoundingBoxes = show && !onTop;
|
SceneRenderer::GetOptions().ShowBoundingBoxes = show;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorLayer::SelectEntity(Entity entity)
|
void EditorLayer::SelectEntity(Entity entity)
|
||||||
@ -1157,9 +1171,7 @@ namespace Prism
|
|||||||
|
|
||||||
void EditorLayer::OpenScene()
|
void EditorLayer::OpenScene()
|
||||||
{
|
{
|
||||||
const auto& app = Application::Get();
|
if (const std::string filepath = FileSystem::OpenFileSelector("*.scene"); !filepath.empty())
|
||||||
const std::string filepath = app.OpenFile("Hazel Scene (*.hsc)\0*.hsc\0");
|
|
||||||
if (!filepath.empty())
|
|
||||||
OpenScene(filepath);
|
OpenScene(filepath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1199,8 +1211,7 @@ namespace Prism
|
|||||||
void EditorLayer::SaveSceneAs()
|
void EditorLayer::SaveSceneAs()
|
||||||
{
|
{
|
||||||
const auto& app = Application::Get();
|
const auto& app = Application::Get();
|
||||||
const std::string filepath = app.SaveFile("Prism Scene (*.hsc)\0*.hsc\0");
|
if (const std::string filepath = FileSystem::SaveFileSelector("*.scene"); !filepath.empty())
|
||||||
if (!filepath.empty())
|
|
||||||
{
|
{
|
||||||
PM_CLIENT_INFO("Saving scene to: {0}", m_SceneFilePath);
|
PM_CLIENT_INFO("Saving scene to: {0}", m_SceneFilePath);
|
||||||
SceneSerializer serializer(m_EditorScene);
|
SceneSerializer serializer(m_EditorScene);
|
||||||
|
|||||||
@ -28,7 +28,7 @@ namespace Prism
|
|||||||
bool OnKeyPressedEvent(KeyPressedEvent& e);
|
bool OnKeyPressedEvent(KeyPressedEvent& e);
|
||||||
bool OnMouseButtonPressedEvent(MouseButtonPressedEvent& e);
|
bool OnMouseButtonPressedEvent(MouseButtonPressedEvent& e);
|
||||||
|
|
||||||
void ShowBoundingBoxes(bool show, bool onTop = false);
|
void ShowBoundingBoxes(bool show);
|
||||||
void SelectEntity(Entity entity);
|
void SelectEntity(Entity entity);
|
||||||
|
|
||||||
void UpdateWindowTitle(const std::string& sceneName);
|
void UpdateWindowTitle(const std::string& sceneName);
|
||||||
@ -126,10 +126,6 @@ namespace Prism
|
|||||||
|
|
||||||
|
|
||||||
// PBR params
|
// PBR params
|
||||||
bool m_RadiancePrefilter = false;
|
|
||||||
|
|
||||||
float m_EnvMapRotation = 0.0f;
|
|
||||||
|
|
||||||
|
|
||||||
// Editor resources
|
// Editor resources
|
||||||
Ref<Texture2D> m_CheckerboardTex;
|
Ref<Texture2D> m_CheckerboardTex;
|
||||||
|
|||||||
@ -18,6 +18,7 @@ add_subdirectory(vendor/mono EXCLUDE_FROM_ALL)
|
|||||||
add_subdirectory(vendor/FastNoise EXCLUDE_FROM_ALL)
|
add_subdirectory(vendor/FastNoise EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(vendor/yaml-cpp EXCLUDE_FROM_ALL)
|
add_subdirectory(vendor/yaml-cpp EXCLUDE_FROM_ALL)
|
||||||
add_subdirectory(vendor/Box2D EXCLUDE_FROM_ALL)
|
add_subdirectory(vendor/Box2D EXCLUDE_FROM_ALL)
|
||||||
|
add_subdirectory(vendor/efsw EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
|
|
||||||
# ------------- imgui -------------
|
# ------------- imgui -------------
|
||||||
@ -91,6 +92,7 @@ set(LINK_LIBRARIES_PRIVATE
|
|||||||
tinyFileDialogs
|
tinyFileDialogs
|
||||||
FastNoise
|
FastNoise
|
||||||
yaml-cpp
|
yaml-cpp
|
||||||
|
efsw
|
||||||
|
|
||||||
PhysXExtensions_static_64
|
PhysXExtensions_static_64
|
||||||
PhysX_static_64
|
PhysX_static_64
|
||||||
|
|||||||
@ -303,11 +303,11 @@ namespace Prism
|
|||||||
return newFileName;
|
return newFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetsManager::ImportAsset(const std::string& filepath, AssetHandle parentHandle)
|
Ref<Asset> AssetsManager::ImportAsset(const std::string& filepath, AssetHandle parentHandle)
|
||||||
{
|
{
|
||||||
const std::string extension = Utils::GetExtension(filepath);
|
const std::string extension = Utils::GetExtension(filepath);
|
||||||
if (extension == "meta")
|
if (extension == "meta")
|
||||||
return;
|
return Ref<Asset>();
|
||||||
|
|
||||||
const AssetType type = AssetTypes::GetAssetTypeFromExtension(extension);
|
const AssetType type = AssetTypes::GetAssetTypeFromExtension(extension);
|
||||||
Ref<Asset> asset = AssetSerializer::LoadAssetInfo(filepath, parentHandle, type);
|
Ref<Asset> asset = AssetSerializer::LoadAssetInfo(filepath, parentHandle, type);
|
||||||
@ -320,10 +320,12 @@ namespace Prism
|
|||||||
}
|
}
|
||||||
|
|
||||||
s_LoadedAssets[asset->Handle] = asset;
|
s_LoadedAssets[asset->Handle] = asset;
|
||||||
|
|
||||||
|
return asset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AssetHandle AssetsManager::ProcessDirectory(const std::string& directoryPath, AssetHandle parentHandle)
|
Ref<Asset> AssetsManager::ProcessDirectory(const std::string& directoryPath, AssetHandle parentHandle)
|
||||||
{
|
{
|
||||||
Ref<Directory> dirInfo = AssetSerializer::LoadAssetInfo(directoryPath, parentHandle, AssetType::Directory).As<Directory>();
|
Ref<Directory> dirInfo = AssetSerializer::LoadAssetInfo(directoryPath, parentHandle, AssetType::Directory).As<Directory>();
|
||||||
s_LoadedAssets[dirInfo->Handle] = dirInfo;
|
s_LoadedAssets[dirInfo->Handle] = dirInfo;
|
||||||
@ -336,15 +338,17 @@ namespace Prism
|
|||||||
if (entry.is_directory())
|
if (entry.is_directory())
|
||||||
ProcessDirectory(entry.path().string(), dirInfo->Handle);
|
ProcessDirectory(entry.path().string(), dirInfo->Handle);
|
||||||
else
|
else
|
||||||
ImportAsset(entry.path().string(), dirInfo->Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
return dirInfo->Handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AssetsManager::ReloadAssets()
|
|
||||||
{
|
{
|
||||||
ProcessDirectory("assets", 0);
|
Ref<Asset> asset = ImportAsset(entry.path().string(), dirInfo->Handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dirInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<Asset> AssetsManager::ReloadAssets()
|
||||||
|
{
|
||||||
|
return ProcessDirectory("assets", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetsManager::OnFileSystemChanged(FileSystemChangedEvent e)
|
void AssetsManager::OnFileSystemChanged(FileSystemChangedEvent e)
|
||||||
@ -363,35 +367,70 @@ namespace Prism
|
|||||||
if (e.IsDirectory)
|
if (e.IsDirectory)
|
||||||
ProcessDirectory(e.FilePath, parentHandle);
|
ProcessDirectory(e.FilePath, parentHandle);
|
||||||
else
|
else
|
||||||
ImportAsset(e.FilePath, parentHandle);
|
{
|
||||||
|
Ref<Asset> asset = ImportAsset(e.FilePath, parentHandle);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FileSystemAction::Modified:
|
case FileSystemAction::Modified:
|
||||||
{
|
{
|
||||||
if (!e.IsDirectory)
|
if (!e.IsDirectory)
|
||||||
ImportAsset(e.FilePath, parentHandle);
|
{
|
||||||
|
Ref<Asset> asset = ImportAsset(e.FilePath, parentHandle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FileSystemAction::Rename:
|
case FileSystemAction::Rename:
|
||||||
{
|
{
|
||||||
|
Ref<Asset> asset;
|
||||||
|
|
||||||
for (auto it = s_LoadedAssets.begin(); it != s_LoadedAssets.end(); it++)
|
for (auto it = s_LoadedAssets.begin(); it != s_LoadedAssets.end(); it++)
|
||||||
{
|
{
|
||||||
if (it->second->FileName == e.OldName)
|
if (it->second->FileName == e.OldName)
|
||||||
{
|
{
|
||||||
it->second->FilePath = e.FilePath;
|
asset = it->second;
|
||||||
it->second->FileName = e.NewName;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (asset)
|
||||||
|
{
|
||||||
|
if (asset->Type != AssetTypes::GetAssetTypeFromExtension(Utils::GetExtension(e.FilePath)))
|
||||||
|
{
|
||||||
|
RemoveAsset(asset->Handle);
|
||||||
|
FileSystem::PrismDeleteFile(asset->FilePath + ".meta");
|
||||||
|
asset = ImportAsset(e.FilePath, parentHandle);
|
||||||
|
}else
|
||||||
|
{
|
||||||
|
std::string oldMetaPath = asset->FilePath + ".meta";
|
||||||
|
std::string newMetaPath = e.FilePath + ".meta";
|
||||||
|
|
||||||
|
std::error_code ec;
|
||||||
|
std::filesystem::rename(oldMetaPath, newMetaPath, ec);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
PM_CORE_ERROR("Failed to rename meta file: {}", ec.message());
|
||||||
|
}
|
||||||
|
|
||||||
|
asset->FilePath = e.FilePath;
|
||||||
|
asset->FileName = e.NewName;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FileSystemAction::Delete:
|
case FileSystemAction::Delete:
|
||||||
{
|
{
|
||||||
for (auto it = s_LoadedAssets.begin(); it != s_LoadedAssets.end(); it++)
|
for (auto it = s_LoadedAssets.begin(); it != s_LoadedAssets.end(); it++)
|
||||||
{
|
{
|
||||||
if (it->second->FilePath != e.FilePath)
|
std::string filePath = Utils::NormalizePath(it->second->FilePath);
|
||||||
|
std::string eFilePath = Utils::NormalizePath(e.FilePath);
|
||||||
|
if (filePath != eFilePath)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
RemoveAsset(it->first);
|
RemoveAsset(it->first);
|
||||||
|
FileSystem::PrismDeleteFile(eFilePath + ".meta");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
#include "Asset.h"
|
#include "Asset.h"
|
||||||
#include "Prism/Utilities/FileSystem.h"
|
#include "Prism/Utilities/FileSystem.h"
|
||||||
#include "Prism/Core/Ref.h"
|
#include "Prism/Core/Ref.h"
|
||||||
|
#include "Prism/Project/Project.h"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
@ -66,9 +67,14 @@ namespace Prism
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static void ImportAsset(const std::string& filepath, AssetHandle parentHandle);
|
static Ref<Asset> ImportAsset(const std::string& filepath, AssetHandle parentHandle);
|
||||||
static AssetHandle ProcessDirectory(const std::string& directoryPath, AssetHandle parentHandle);
|
static Ref<Asset> ProcessDirectory(const std::string& directoryPath, AssetHandle parentHandle);
|
||||||
static void ReloadAssets();
|
/**
|
||||||
|
* this will load from projectPath all assets, and return the root Asset Ref
|
||||||
|
* @param projectPath assets path
|
||||||
|
* @return the root asset Ref
|
||||||
|
*/
|
||||||
|
static Ref<Asset> ReloadAssets();
|
||||||
|
|
||||||
static void OnFileSystemChanged(FileSystemChangedEvent e);
|
static void OnFileSystemChanged(FileSystemChangedEvent e);
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,6 @@
|
|||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
#include "Prism/Renderer/FrameBuffer.h"
|
#include "Prism/Renderer/FrameBuffer.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/Asset/AssetsManager.h"
|
#include "Prism/Asset/AssetsManager.h"
|
||||||
@ -28,6 +27,10 @@ namespace Prism
|
|||||||
|
|
||||||
Application::Application(const ApplicationProps& props)
|
Application::Application(const ApplicationProps& props)
|
||||||
{
|
{
|
||||||
|
if (s_Instance != nullptr)
|
||||||
|
{
|
||||||
|
PM_CORE_ASSERT(false, "Application already exists!");
|
||||||
|
}
|
||||||
s_Instance = this;
|
s_Instance = this;
|
||||||
|
|
||||||
m_Window = std::unique_ptr<Window>(Window::Create(WindowProps{props.Name, props.Width, props.Height}));
|
m_Window = std::unique_ptr<Window>(Window::Create(WindowProps{props.Name, props.Width, props.Height}));
|
||||||
@ -101,6 +104,9 @@ namespace Prism
|
|||||||
{
|
{
|
||||||
m_ImGuiLayer->Begin();
|
m_ImGuiLayer->Begin();
|
||||||
|
|
||||||
|
for (Layer* layer : m_LayerStack)
|
||||||
|
layer->OnImGuiRender();
|
||||||
|
|
||||||
ImGui::Begin("Renderer");
|
ImGui::Begin("Renderer");
|
||||||
const auto& caps = RendererAPI::GetCapabilities();
|
const auto& caps = RendererAPI::GetCapabilities();
|
||||||
ImGui::Text("Vendor: %s", caps.Vendor.c_str());
|
ImGui::Text("Vendor: %s", caps.Vendor.c_str());
|
||||||
@ -109,90 +115,9 @@ namespace Prism
|
|||||||
ImGui::Text("Frame Time: %.2fms\n", m_TimeStep.GetMilliseconds());
|
ImGui::Text("Frame Time: %.2fms\n", m_TimeStep.GetMilliseconds());
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
for (Layer* layer : m_LayerStack)
|
|
||||||
layer->OnImGuiRender();
|
|
||||||
|
|
||||||
m_ImGuiLayer->End();
|
m_ImGuiLayer->End();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: fix this to prase filter
|
|
||||||
std::string Application::OpenFile(const std::string& filter) const
|
|
||||||
{
|
|
||||||
// TODO: will move it to other folder
|
|
||||||
// 处理过滤器
|
|
||||||
std::vector<const char*> filterPatterns;
|
|
||||||
std::vector<std::string> patternStorage;
|
|
||||||
|
|
||||||
if (!filter.empty()) {
|
|
||||||
const char* ptr = filter.c_str();
|
|
||||||
bool isDescription = true;
|
|
||||||
|
|
||||||
while (*ptr) {
|
|
||||||
if (isDescription) {
|
|
||||||
// 跳过描述
|
|
||||||
isDescription = false;
|
|
||||||
} else {
|
|
||||||
// 添加模式
|
|
||||||
patternStorage.push_back(ptr);
|
|
||||||
isDescription = true;
|
|
||||||
}
|
|
||||||
ptr += strlen(ptr) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 转换为 C 字符串数组
|
|
||||||
for (const auto& pattern : patternStorage) {
|
|
||||||
filterPatterns.push_back(pattern.c_str());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果没有过滤器,添加默认值
|
|
||||||
if (filterPatterns.empty()) {
|
|
||||||
filterPatterns.push_back("*");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 构建过滤器描述
|
|
||||||
std::string filterDesc;
|
|
||||||
if (!patternStorage.empty()) {
|
|
||||||
std::stringstream ss;
|
|
||||||
ss << "Files (";
|
|
||||||
for (size_t i = 0; i < patternStorage.size(); ++i) {
|
|
||||||
if (i > 0) ss << ",";
|
|
||||||
ss << patternStorage[i];
|
|
||||||
}
|
|
||||||
ss << ")";
|
|
||||||
filterDesc = ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* result = tinyfd_openFileDialog(
|
|
||||||
"Open File", // 对话框标题
|
|
||||||
nullptr, // 初始路径,nullptr 表示使用默认
|
|
||||||
0, // 过滤器数量 (注意:这里需要根据解析情况调整,见下文)
|
|
||||||
nullptr, // 过滤器模式数组
|
|
||||||
nullptr, // 过滤器描述
|
|
||||||
0 // 是否允许多选:0 为单选,1 为多选
|
|
||||||
);
|
|
||||||
|
|
||||||
// 调用文件对话框
|
|
||||||
/*
|
|
||||||
const char* result = tinyfd_openFileDialog(
|
|
||||||
"Open File", // 标题
|
|
||||||
nullptr, // 初始目录
|
|
||||||
static_cast<int>(filterPatterns.size()), // 过滤器数量
|
|
||||||
filterPatterns.data(), // 过滤器模式
|
|
||||||
filterDesc.empty() ? nullptr : filterDesc.c_str(), // 描述
|
|
||||||
0 // 单选
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
|
|
||||||
return result ? std::string(result) : std::string();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string Application::SaveFile(const std::string& filter) const
|
|
||||||
{
|
|
||||||
return OpenFile(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
Application& Application::Get()
|
Application& Application::Get()
|
||||||
{
|
{
|
||||||
return *s_Instance;
|
return *s_Instance;
|
||||||
|
|||||||
@ -13,10 +13,29 @@
|
|||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
|
class Project;
|
||||||
|
|
||||||
|
struct CommandArgs
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
char** args = nullptr;
|
||||||
|
|
||||||
|
const char* operator[](const int index)
|
||||||
|
{
|
||||||
|
if (index >= count)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return args[count];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct ApplicationProps
|
struct ApplicationProps
|
||||||
{
|
{
|
||||||
std::string Name;
|
std::string Name;
|
||||||
uint32_t Width, Height;
|
uint32_t Width, Height;
|
||||||
|
CommandArgs CommandArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PRISM_API Application
|
class PRISM_API Application
|
||||||
@ -35,9 +54,6 @@ namespace Prism
|
|||||||
|
|
||||||
void RenderImGui();
|
void RenderImGui();
|
||||||
|
|
||||||
std::string OpenFile(const std::string& filter = "All\0*.*\0") const;
|
|
||||||
std::string SaveFile(const std::string& filter = "All\0*.*\0") const;
|
|
||||||
|
|
||||||
inline Window& GetWindow() { return *m_Window; }
|
inline Window& GetWindow() { return *m_Window; }
|
||||||
|
|
||||||
static Application& Get();
|
static Application& Get();
|
||||||
@ -70,7 +86,7 @@ namespace Prism
|
|||||||
|
|
||||||
|
|
||||||
// this function will implemented by client
|
// this function will implemented by client
|
||||||
Application* CreateApplication();
|
Application* CreateApplication(CommandArgs args);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_MSC_VER) && !defined(__clang__)
|
#if defined(_MSC_VER) && !defined(__clang__)
|
||||||
|
|||||||
@ -5,17 +5,26 @@
|
|||||||
#ifndef ENTRYPOINT_H
|
#ifndef ENTRYPOINT_H
|
||||||
#define ENTRYPOINT_H
|
#define ENTRYPOINT_H
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
|
||||||
extern Prism::Application* Prism::CreateApplication();
|
extern Prism::Application* Prism::CreateApplication(CommandArgs args);
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
|
//TODO: this will use other method to impl
|
||||||
|
std::cout << std::filesystem::current_path() << std::endl;
|
||||||
|
std::filesystem::current_path(std::filesystem::path(argv[0]).parent_path());
|
||||||
|
std::cout << std::filesystem::current_path() << std::endl;
|
||||||
|
|
||||||
#ifdef PRISM_STATIC
|
#ifdef PRISM_STATIC
|
||||||
Prism::InitializeCore();
|
Prism::InitializeCore();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Prism::Application* app = Prism::CreateApplication();
|
const Prism::CommandArgs args{ argc, argv };
|
||||||
|
|
||||||
|
Prism::Application* app = Prism::CreateApplication(args);
|
||||||
app->Run();
|
app->Run();
|
||||||
delete app;
|
delete app;
|
||||||
|
|
||||||
|
|||||||
@ -11,8 +11,10 @@
|
|||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#define LOG_LEVEL spdlog::level::trace
|
#define LOG_LEVEL spdlog::level::trace
|
||||||
|
#define LOG_PATTERN "%^[%@:%#][%Y-%m-%d %H:%M:%S.%e] [%l] %v%$"
|
||||||
#else
|
#else
|
||||||
#define LOG_LEVEL spdlog::level::trace
|
#define LOG_LEVEL spdlog::level::trace
|
||||||
|
#define LOG_PATTERN "%^[%Y-%m-%d %H:%M:%S.%e] [%l] %v%$"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
@ -40,11 +42,11 @@ namespace Prism
|
|||||||
|
|
||||||
s_CoreLogger = std::make_shared<spdlog::logger>("PRISM", prismSinks.begin(), prismSinks.end());
|
s_CoreLogger = std::make_shared<spdlog::logger>("PRISM", prismSinks.begin(), prismSinks.end());
|
||||||
s_CoreLogger->set_level(LOG_LEVEL);
|
s_CoreLogger->set_level(LOG_LEVEL);
|
||||||
s_CoreLogger->set_pattern("%^[%Y-%m-%d %H:%M:%S.%e] [%l] %v%$");
|
s_CoreLogger->set_pattern(LOG_PATTERN);
|
||||||
|
|
||||||
s_ClientLogger = std::make_shared<spdlog::logger>("APP", appSinks.begin(), appSinks.end());
|
s_ClientLogger = std::make_shared<spdlog::logger>("APP", appSinks.begin(), appSinks.end());
|
||||||
s_ClientLogger->set_level(LOG_LEVEL);
|
s_ClientLogger->set_level(LOG_LEVEL);
|
||||||
s_CoreLogger->set_pattern("%^[%Y-%m-%d %H:%M:%S.%e] [%l] %v%$");
|
s_ClientLogger->set_pattern(LOG_PATTERN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Log::Shutdown()
|
void Log::Shutdown()
|
||||||
|
|||||||
@ -25,13 +25,22 @@ namespace Prism
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#define PM_CORE_TRACE(...) SPDLOG_LOGGER_TRACE(::Prism::Log::GetCoreLogger(), __VA_ARGS__)
|
||||||
|
#define PM_CORE_DEBUG(...) SPDLOG_LOGGER_DEBUG(::Prism::Log::GetCoreLogger(), __VA_ARGS__)
|
||||||
|
#define PM_CORE_INFO(...) SPDLOG_LOGGER_INFO(::Prism::Log::GetCoreLogger(), __VA_ARGS__)
|
||||||
|
#define PM_CORE_WARN(...) SPDLOG_LOGGER_WARN(::Prism::Log::GetCoreLogger(), __VA_ARGS__)
|
||||||
|
#define PM_CORE_ERROR(...) SPDLOG_LOGGER_ERROR(::Prism::Log::GetCoreLogger(), __VA_ARGS__)
|
||||||
|
#define PM_CORE_FATAL(...) SPDLOG_LOGGER_CRITICAL(::Prism::Log::GetCoreLogger(), __VA_ARGS__)
|
||||||
|
#else
|
||||||
#define PM_CORE_TRACE(...) ::Prism::Log::GetCoreLogger()->trace(__VA_ARGS__)
|
#define PM_CORE_TRACE(...) ::Prism::Log::GetCoreLogger()->trace(__VA_ARGS__)
|
||||||
#define PM_CORE_DEBUG(...) ::Prism::Log::GetCoreLogger()->debug( __VA_ARGS__)
|
#define PM_CORE_DEBUG(...) ::Prism::Log::GetCoreLogger()->debug( __VA_ARGS__)
|
||||||
#define PM_CORE_INFO(...) ::Prism::Log::GetCoreLogger()->info(__VA_ARGS__)
|
#define PM_CORE_INFO(...) ::Prism::Log::GetCoreLogger()->info(__VA_ARGS__)
|
||||||
#define PM_CORE_WARN(...) ::Prism::Log::GetCoreLogger()->warn(__VA_ARGS__)
|
#define PM_CORE_WARN(...) ::Prism::Log::GetCoreLogger()->warn(__VA_ARGS__)
|
||||||
#define PM_CORE_ERROR(...) ::Prism::Log::GetCoreLogger()->error(__VA_ARGS__)
|
#define PM_CORE_ERROR(...) ::Prism::Log::GetCoreLogger()->error(__VA_ARGS__)
|
||||||
#define PM_CORE_FATAL(...) ::Prism::Log::GetCoreLogger()->critical(__VA_ARGS__)
|
#define PM_CORE_FATAL(...) ::Prism::Log::GetCoreLogger()->critical(__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define PM_CLIENT_TRACE(...) ::Prism::Log::GetClientLogger()->trace(__VA_ARGS__)
|
#define PM_CLIENT_TRACE(...) ::Prism::Log::GetClientLogger()->trace(__VA_ARGS__)
|
||||||
#define PM_CLIENT_DEBUG(...) ::Prism::Log::GetClientLogger()->debug(__VA_ARGS__)
|
#define PM_CLIENT_DEBUG(...) ::Prism::Log::GetClientLogger()->debug(__VA_ARGS__)
|
||||||
|
|||||||
@ -133,7 +133,7 @@ namespace Prism
|
|||||||
|
|
||||||
if (ImGui::MenuItem("Import"))
|
if (ImGui::MenuItem("Import"))
|
||||||
{
|
{
|
||||||
//std::string filename = Application::Get().OpenFile("");
|
// std::string filename = FileSystem::OpenFileSelector();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::MenuItem("Refresh"))
|
if (ImGui::MenuItem("Refresh"))
|
||||||
|
|||||||
@ -9,16 +9,158 @@
|
|||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
|
#include "tinyfiledialogs.h"
|
||||||
|
#include <sstream>
|
||||||
#include "Prism/Core/Log.h"
|
#include "Prism/Core/Log.h"
|
||||||
#include "Prism/Asset/AssetsManager.h"
|
#include "Prism/Asset/AssetsManager.h"
|
||||||
|
#include "Prism/Core/Application.h"
|
||||||
|
|
||||||
|
#include "efsw/efsw.hpp"
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
FileSystem::FileSystemChangedCallbackFn FileSystem::s_Callback;
|
FileSystem::FileSystemChangedCallbackFn FileSystem::s_Callback;
|
||||||
|
|
||||||
static bool s_Watching = true;
|
std::atomic<bool> FileSystem::s_IgnoreNextChange = false;
|
||||||
static bool s_IgnoreNextChange = false;
|
efsw::FileWatcher* FileSystem::s_FileWatcher = nullptr;
|
||||||
static HANDLE s_WatcherThread;
|
PrismFileWatcherListener* FileSystem::s_Listener = nullptr;
|
||||||
|
|
||||||
|
class PrismFileWatcherListener : public efsw::FileWatchListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void handleFileAction(efsw::WatchID watchid,
|
||||||
|
const std::string& dir,
|
||||||
|
const std::string& filename,
|
||||||
|
efsw::Action action,
|
||||||
|
std::string oldFilename = "") override
|
||||||
|
{
|
||||||
|
// 如果引擎自身操作设置了忽略标志,则跳过本次事件
|
||||||
|
if (FileSystem::s_IgnoreNextChange.load())
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::filesystem::path fullPath = std::filesystem::path(dir) / filename;
|
||||||
|
|
||||||
|
FileSystemChangedEvent e;
|
||||||
|
e.FilePath = fullPath.string();
|
||||||
|
e.NewName = filename;
|
||||||
|
e.OldName = oldFilename; // efsw 在重命名时会提供旧文件名
|
||||||
|
e.IsDirectory = false; // 稍后根据实际情况判断
|
||||||
|
|
||||||
|
// 判断是否为目录(可能抛出异常,使用 error_code 版本)
|
||||||
|
std::error_code ec;
|
||||||
|
if (std::filesystem::is_directory(fullPath, ec))
|
||||||
|
e.IsDirectory = true;
|
||||||
|
// 如果 ec 有错误(文件可能已被删除),保持 false
|
||||||
|
|
||||||
|
// 映射 efsw 动作到你的枚举
|
||||||
|
switch (action)
|
||||||
|
{
|
||||||
|
case efsw::Actions::Add:
|
||||||
|
e.Action = FileSystemAction::Added;
|
||||||
|
break;
|
||||||
|
case efsw::Actions::Delete:
|
||||||
|
e.Action = FileSystemAction::Delete;
|
||||||
|
break;
|
||||||
|
case efsw::Actions::Modified:
|
||||||
|
e.Action = FileSystemAction::Modified;
|
||||||
|
break;
|
||||||
|
case efsw::Actions::Moved:
|
||||||
|
e.Action = FileSystemAction::Rename;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return; // 忽略未知事件
|
||||||
|
}
|
||||||
|
|
||||||
|
// 调用外部回调(需确保线程安全)
|
||||||
|
if (FileSystem::s_Callback)
|
||||||
|
FileSystem::s_Callback(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
std::string FileSystem::OpenFileSelector(const std::string& filter)
|
||||||
|
{
|
||||||
|
std::vector<const char*> patternCstrs;
|
||||||
|
std::vector<std::string> patterns;
|
||||||
|
std::string description = "All files (*.*)";
|
||||||
|
|
||||||
|
if (!filter.empty() && filter != "*.*") {
|
||||||
|
std::istringstream iss(filter);
|
||||||
|
std::string token;
|
||||||
|
while (std::getline(iss, token, ';')) {
|
||||||
|
if (!token.empty()) {
|
||||||
|
patterns.push_back(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建描述文字
|
||||||
|
if (!patterns.empty()) {
|
||||||
|
description = "Custom files (";
|
||||||
|
for (size_t i = 0; i < patterns.size(); ++i) {
|
||||||
|
if (i > 0) description += "; ";
|
||||||
|
description += patterns[i];
|
||||||
|
}
|
||||||
|
description += ")";
|
||||||
|
|
||||||
|
// 准备 C 字符串数组
|
||||||
|
for (const auto& p : patterns) {
|
||||||
|
patternCstrs.push_back(p.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* result = tinyfd_openFileDialog(
|
||||||
|
"Open File", // title
|
||||||
|
"", // default open path
|
||||||
|
static_cast<int>(patternCstrs.size()), // filter count
|
||||||
|
patternCstrs.empty() ? nullptr : patternCstrs.data(), // filter pattern
|
||||||
|
description.c_str(), // filter description
|
||||||
|
0 // 0 is single select, 1 is Multiple select
|
||||||
|
);
|
||||||
|
|
||||||
|
return result ? std::string(result) : std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string FileSystem::SaveFileSelector(const std::string& filter)
|
||||||
|
{
|
||||||
|
std::vector<const char*> patternCstrs;
|
||||||
|
std::string description = "All files (*.*)";
|
||||||
|
std::vector<std::string> patterns;
|
||||||
|
|
||||||
|
if (!filter.empty() && filter != "*.*") {
|
||||||
|
std::istringstream iss(filter);
|
||||||
|
std::string token;
|
||||||
|
while (std::getline(iss, token, ';')) {
|
||||||
|
if (!token.empty()) {
|
||||||
|
patterns.push_back(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!patterns.empty()) {
|
||||||
|
description = "Custom files (";
|
||||||
|
for (size_t i = 0; i < patterns.size(); ++i) {
|
||||||
|
if (i > 0) description += "; ";
|
||||||
|
description += patterns[i];
|
||||||
|
}
|
||||||
|
description += ")";
|
||||||
|
|
||||||
|
for (const auto& p : patterns) {
|
||||||
|
patternCstrs.push_back(p.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* result = tinyfd_saveFileDialog(
|
||||||
|
"Save File",
|
||||||
|
"",
|
||||||
|
static_cast<int>(patternCstrs.size()),
|
||||||
|
patternCstrs.empty() ? nullptr : patternCstrs.data(),
|
||||||
|
description.c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
return result ? std::string(result) : std::string();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool FileSystem::CreateFolder(const std::filesystem::path& filepath)
|
bool FileSystem::CreateFolder(const std::filesystem::path& filepath)
|
||||||
{
|
{
|
||||||
@ -54,57 +196,29 @@ namespace Prism
|
|||||||
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)
|
|
||||||
{
|
|
||||||
if (!input) return {};
|
|
||||||
|
|
||||||
const int bufferSize = WideCharToMultiByte(CP_UTF8, 0, input, -1, nullptr, 0, nullptr, nullptr);
|
|
||||||
if (bufferSize == 0) return {};
|
|
||||||
|
|
||||||
std::string result(bufferSize, 0);
|
|
||||||
WideCharToMultiByte(CP_UTF8, 0, input, -1, &result[0], bufferSize, nullptr, nullptr);
|
|
||||||
|
|
||||||
// 移除末尾的null终止符
|
|
||||||
result.pop_back();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string FileSystem::Rename(const std::string& filepath, const std::string& newName)
|
std::string FileSystem::Rename(const std::string& filepath, const std::string& newName)
|
||||||
{
|
{
|
||||||
s_IgnoreNextChange = true;
|
s_IgnoreNextChange = true;
|
||||||
std::filesystem::path p = filepath;
|
const std::filesystem::path p = filepath;
|
||||||
std::string newFilePath = p.parent_path().string() + "/" + newName + p.extension().string();
|
std::string newFilePath = p.parent_path().string() + "/" + newName + p.extension().string();
|
||||||
MoveFileA(filepath.c_str(), newFilePath.c_str());
|
MoveFileA(filepath.c_str(), newFilePath.c_str());
|
||||||
s_IgnoreNextChange = false;
|
s_IgnoreNextChange = false;
|
||||||
return newFilePath;
|
return newFilePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool FileSystem::PrismDeleteFile(const std::string& filepath)
|
bool FileSystem::PrismDeleteFile(const std::string& filepath)
|
||||||
{
|
{
|
||||||
s_IgnoreNextChange = true;
|
s_IgnoreNextChange = true;
|
||||||
std::string fp = filepath;
|
std::error_code ec;
|
||||||
fp.append(1, '\0');
|
const bool removed = std::filesystem::remove(filepath, ec);
|
||||||
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;
|
s_IgnoreNextChange = false;
|
||||||
return result == 0;
|
if (!removed || ec)
|
||||||
|
{
|
||||||
|
PM_CORE_ERROR("Delete failed: {}", ec.message());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FileSystem::PrismMoveFile(const std::string& filepath, const std::string& dest)
|
bool FileSystem::PrismMoveFile(const std::string& filepath, const std::string& dest)
|
||||||
@ -120,139 +234,41 @@ namespace Prism
|
|||||||
|
|
||||||
void FileSystem::StartWatching()
|
void FileSystem::StartWatching()
|
||||||
{
|
{
|
||||||
DWORD threadId;
|
if (s_FileWatcher) return;
|
||||||
s_WatcherThread = CreateThread(NULL, 0, Watch, NULL, 0, &threadId);
|
|
||||||
PM_CORE_ASSERT(s_WatcherThread != NULL);
|
s_FileWatcher = new efsw::FileWatcher();
|
||||||
PM_CORE_TRACE("Starting file watching services");
|
|
||||||
|
s_Listener = new PrismFileWatcherListener();
|
||||||
|
|
||||||
|
efsw::WatchID watchID = s_FileWatcher->addWatch("assets", s_Listener, true);
|
||||||
|
if (watchID < 0)
|
||||||
|
{
|
||||||
|
PM_CORE_ERROR("Failed to add watch for {}", "assets");
|
||||||
|
delete s_FileWatcher;
|
||||||
|
s_FileWatcher = nullptr;
|
||||||
|
delete s_Listener;
|
||||||
|
s_Listener = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s_FileWatcher->watch();
|
||||||
|
|
||||||
|
PM_CORE_TRACE("Started file watching services on {}", "assets");
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileSystem::StopWatching()
|
void FileSystem::StopWatching()
|
||||||
{
|
{
|
||||||
// TODO: this delay is too long
|
if (s_FileWatcher)
|
||||||
s_Watching = false;
|
|
||||||
const DWORD result = WaitForSingleObject(s_WatcherThread, 1000);
|
|
||||||
if (result == WAIT_TIMEOUT)
|
|
||||||
TerminateThread(s_WatcherThread, 0);
|
|
||||||
CloseHandle(s_WatcherThread);
|
|
||||||
PM_CORE_TRACE("closing file watching services");
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned long FileSystem::Watch(void* param)
|
|
||||||
{
|
{
|
||||||
const LPCSTR filepath = "assets";
|
delete s_FileWatcher;
|
||||||
BYTE* buffer = new BYTE[10 * 1024]; // 1 MB
|
s_FileWatcher = nullptr;
|
||||||
OVERLAPPED overlapped = { 0 };
|
}
|
||||||
HANDLE handle = NULL;
|
if (s_Listener)
|
||||||
DWORD bytesReturned = 0;
|
|
||||||
|
|
||||||
handle = CreateFile(
|
|
||||||
filepath,
|
|
||||||
FILE_LIST_DIRECTORY,
|
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
|
||||||
NULL,
|
|
||||||
OPEN_EXISTING,
|
|
||||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
|
|
||||||
NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
ZeroMemory(&overlapped, sizeof(overlapped));
|
|
||||||
|
|
||||||
if (handle == INVALID_HANDLE_VALUE)
|
|
||||||
PM_CORE_ERROR("Unable to accquire directory handle: {0}", GetLastError());
|
|
||||||
|
|
||||||
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
||||||
|
|
||||||
if (overlapped.hEvent == NULL)
|
|
||||||
{
|
{
|
||||||
PM_CORE_ERROR("CreateEvent failed!");
|
delete s_Listener;
|
||||||
return 0;
|
s_Listener = nullptr;
|
||||||
|
}
|
||||||
|
PM_CORE_TRACE("Stopped file watching services");
|
||||||
}
|
}
|
||||||
|
|
||||||
while (s_Watching)
|
|
||||||
{
|
|
||||||
DWORD status = ReadDirectoryChangesW(
|
|
||||||
handle,
|
|
||||||
buffer,
|
|
||||||
10 * 1024 * sizeof(BYTE),
|
|
||||||
TRUE,
|
|
||||||
FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME,
|
|
||||||
&bytesReturned,
|
|
||||||
&overlapped,
|
|
||||||
NULL
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!status)
|
|
||||||
PM_CORE_ERROR("{0}", GetLastError());
|
|
||||||
|
|
||||||
const DWORD waitOperation = WaitForSingleObject(overlapped.hEvent, 2000);
|
|
||||||
if (waitOperation != WAIT_OBJECT_0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (s_IgnoreNextChange)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
std::string oldName;
|
|
||||||
char fileName[MAX_PATH * 10] = "";
|
|
||||||
|
|
||||||
FILE_NOTIFY_INFORMATION* current = (FILE_NOTIFY_INFORMATION*)buffer;
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
ZeroMemory(fileName, sizeof(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;
|
|
||||||
e.FilePath = filePath.string();
|
|
||||||
e.NewName = filePath.filename().string();
|
|
||||||
e.OldName = filePath.filename().string();
|
|
||||||
e.IsDirectory = std::filesystem::is_directory(filePath);
|
|
||||||
|
|
||||||
switch (current->Action)
|
|
||||||
{
|
|
||||||
case FILE_ACTION_ADDED:
|
|
||||||
{
|
|
||||||
e.Action = FileSystemAction::Added;
|
|
||||||
s_Callback(e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FILE_ACTION_REMOVED:
|
|
||||||
{
|
|
||||||
e.IsDirectory = AssetsManager::IsDirectory(e.FilePath);
|
|
||||||
e.Action = FileSystemAction::Delete;
|
|
||||||
s_Callback(e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FILE_ACTION_MODIFIED:
|
|
||||||
{
|
|
||||||
e.Action = FileSystemAction::Modified;
|
|
||||||
s_Callback(e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FILE_ACTION_RENAMED_OLD_NAME:
|
|
||||||
{
|
|
||||||
oldName = filePath.filename().string();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case FILE_ACTION_RENAMED_NEW_NAME:
|
|
||||||
{
|
|
||||||
e.OldName = oldName;
|
|
||||||
e.Action = FileSystemAction::Rename;
|
|
||||||
s_Callback(e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!current->NextEntryOffset)
|
|
||||||
break;
|
|
||||||
|
|
||||||
current += current->NextEntryOffset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -163,7 +163,7 @@ namespace Prism
|
|||||||
//////////////// BloomPass ////////////////
|
//////////////// BloomPass ////////////////
|
||||||
{
|
{
|
||||||
FramebufferSpecification bloomBlurFramebufferSpec;
|
FramebufferSpecification bloomBlurFramebufferSpec;
|
||||||
bloomBlurFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F , FramebufferTextureFormat::RGBA8};
|
bloomBlurFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F , FramebufferTextureFormat::RGBA16F};
|
||||||
bloomBlurFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
bloomBlurFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
||||||
|
|
||||||
RenderPassSpecification bloomBlurRenderPassSpec;
|
RenderPassSpecification bloomBlurRenderPassSpec;
|
||||||
@ -173,7 +173,7 @@ namespace Prism
|
|||||||
s_Data.BloomBlurPass[1] = RenderPass::Create(bloomBlurRenderPassSpec);
|
s_Data.BloomBlurPass[1] = RenderPass::Create(bloomBlurRenderPassSpec);
|
||||||
|
|
||||||
FramebufferSpecification bloomBlendFramebufferSpec;
|
FramebufferSpecification bloomBlendFramebufferSpec;
|
||||||
bloomBlendFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA8 };
|
bloomBlendFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F };
|
||||||
bloomBlendFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
bloomBlendFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
||||||
|
|
||||||
RenderPassSpecification bloomBlendRenderPassSpec;
|
RenderPassSpecification bloomBlendRenderPassSpec;
|
||||||
@ -275,7 +275,6 @@ namespace Prism
|
|||||||
s_Data.SceneData.SkyboxMaterial = scene->m_SkyboxMaterial;
|
s_Data.SceneData.SkyboxMaterial = scene->m_SkyboxMaterial;
|
||||||
s_Data.SceneData.SceneEnvironment = scene->m_Environment;
|
s_Data.SceneData.SceneEnvironment = scene->m_Environment;
|
||||||
s_Data.SceneData.SceneEnvironmentIntensity = scene->m_EnvironmentIntensity;
|
s_Data.SceneData.SceneEnvironmentIntensity = scene->m_EnvironmentIntensity;
|
||||||
s_Data.SceneData.ActiveLight = scene->m_Light;
|
|
||||||
s_Data.SceneData.SceneLightEnvironment = scene->m_LightEnvironment;
|
s_Data.SceneData.SceneLightEnvironment = scene->m_LightEnvironment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,7 @@ namespace Prism
|
|||||||
void SceneRenderer::Init()
|
void SceneRenderer::Init()
|
||||||
{
|
{
|
||||||
FramebufferSpecification finalFramebufferSpec;
|
FramebufferSpecification finalFramebufferSpec;
|
||||||
finalFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA8, FramebufferTextureFormat::Depth};
|
finalFramebufferSpec.Attachments = { FramebufferTextureFormat::RGBA16F, FramebufferTextureFormat::Depth};
|
||||||
finalFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
finalFramebufferSpec.ClearColor = { 0.1f, 0.1f, 0.1f, 1.0f };
|
||||||
|
|
||||||
RenderPassSpecification finalRenderPassSpec;
|
RenderPassSpecification finalRenderPassSpec;
|
||||||
|
|||||||
@ -594,9 +594,6 @@ namespace Prism
|
|||||||
|
|
||||||
void Scene::CopyTo(Ref<Scene>& target)
|
void Scene::CopyTo(Ref<Scene>& target)
|
||||||
{
|
{
|
||||||
target->m_Light = m_Light;
|
|
||||||
target->m_LightMultiplier = m_LightMultiplier;
|
|
||||||
|
|
||||||
target->m_Environment = m_Environment;
|
target->m_Environment = m_Environment;
|
||||||
target->m_SkyboxTexture = m_SkyboxTexture;
|
target->m_SkyboxTexture = m_SkyboxTexture;
|
||||||
target->m_SkyboxMaterial = m_SkyboxMaterial;
|
target->m_SkyboxMaterial = m_SkyboxMaterial;
|
||||||
@ -658,6 +655,11 @@ namespace Prism
|
|||||||
return gravity.y;
|
return gravity.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Scene::SetPhysics2DGravity(const glm::vec2& vec)
|
||||||
|
{
|
||||||
|
b2World_SetGravity(m_Registry.get<Box2DWorldComponent>(m_SceneEntity).World, {vec.x, vec.y});
|
||||||
|
}
|
||||||
|
|
||||||
void Scene::SetPhysics2DGravity(const float gravity)
|
void Scene::SetPhysics2DGravity(const float gravity)
|
||||||
{
|
{
|
||||||
b2World_SetGravity(m_Registry.get<Box2DWorldComponent>(m_SceneEntity).World, {0.0f, gravity});
|
b2World_SetGravity(m_Registry.get<Box2DWorldComponent>(m_SceneEntity).World, {0.0f, gravity});
|
||||||
|
|||||||
@ -75,9 +75,6 @@ namespace Prism
|
|||||||
|
|
||||||
float& GetSkyboxLod() { return m_SkyboxLod; }
|
float& GetSkyboxLod() { return m_SkyboxLod; }
|
||||||
|
|
||||||
Light& GetLight() { return m_Light; }
|
|
||||||
const Light& GetLight() const { return m_Light; }
|
|
||||||
|
|
||||||
Entity GetMainCameraEntity();
|
Entity GetMainCameraEntity();
|
||||||
|
|
||||||
void AddEntity(Entity* entity);
|
void AddEntity(Entity* entity);
|
||||||
@ -107,6 +104,16 @@ namespace Prism
|
|||||||
static Ref<Scene> GetScene(const UUID& uuid);
|
static Ref<Scene> GetScene(const UUID& uuid);
|
||||||
|
|
||||||
float GetPhysics2DGravity() const;
|
float GetPhysics2DGravity() const;
|
||||||
|
/**
|
||||||
|
* set 2D gravity two directions
|
||||||
|
* @param vec (x,y) two directory
|
||||||
|
*/
|
||||||
|
void SetPhysics2DGravity(const glm::vec2& vec);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* only set y-axis gravity
|
||||||
|
* @param gravity y gravity
|
||||||
|
*/
|
||||||
void SetPhysics2DGravity(float gravity);
|
void SetPhysics2DGravity(float gravity);
|
||||||
|
|
||||||
// Editor-specific
|
// Editor-specific
|
||||||
@ -129,8 +136,6 @@ namespace Prism
|
|||||||
Entity* m_Physics2DBodyEntityBuffer = nullptr;
|
Entity* m_Physics2DBodyEntityBuffer = nullptr;
|
||||||
Entity* m_Physics3DBodyEntityBuffer = nullptr;
|
Entity* m_Physics3DBodyEntityBuffer = nullptr;
|
||||||
|
|
||||||
Light m_Light;
|
|
||||||
float m_LightMultiplier = 0.3f;
|
|
||||||
LightEnvironment m_LightEnvironment;
|
LightEnvironment m_LightEnvironment;
|
||||||
|
|
||||||
bool m_IsPlaying = false;
|
bool m_IsPlaying = false;
|
||||||
|
|||||||
@ -588,13 +588,6 @@ namespace Prism
|
|||||||
out << YAML::Value;
|
out << YAML::Value;
|
||||||
out << YAML::BeginMap; // Environment
|
out << YAML::BeginMap; // Environment
|
||||||
out << YAML::Key << "AssetHandle" << YAML::Value << scene->GetEnvironment()->Handle;
|
out << YAML::Key << "AssetHandle" << YAML::Value << scene->GetEnvironment()->Handle;
|
||||||
const auto& light = scene->GetLight();
|
|
||||||
out << YAML::Key << "Light" << YAML::Value;
|
|
||||||
out << YAML::BeginMap; // Light
|
|
||||||
out << YAML::Key << "Direction" << YAML::Value << light.Direction;
|
|
||||||
out << YAML::Key << "Radiance" << YAML::Value << light.Radiance;
|
|
||||||
out << YAML::Key << "Multiplier" << YAML::Value << light.Multiplier;
|
|
||||||
out << YAML::EndMap; // Light
|
|
||||||
out << YAML::EndMap; // Environment
|
out << YAML::EndMap; // Environment
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,12 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
|
||||||
|
namespace efsw
|
||||||
|
{
|
||||||
|
class FileWatcher;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Prism
|
namespace Prism
|
||||||
{
|
{
|
||||||
enum class FileSystemAction
|
enum class FileSystemAction
|
||||||
@ -29,6 +35,9 @@ namespace Prism
|
|||||||
using FileSystemChangedCallbackFn = std::function<void(FileSystemChangedEvent)>;
|
using FileSystemChangedCallbackFn = std::function<void(FileSystemChangedEvent)>;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
static std::string OpenFileSelector(const std::string& filter = "");
|
||||||
|
static std::string SaveFileSelector(const std::string& filter = "");
|
||||||
|
|
||||||
static bool CreateFolder(const std::filesystem::path& filepath);
|
static bool CreateFolder(const std::filesystem::path& filepath);
|
||||||
static bool Exists(const std::string& filepath);
|
static bool Exists(const std::string& filepath);
|
||||||
static std::string Rename(const std::string& filepath, const std::string& newName);
|
static std::string Rename(const std::string& filepath, const std::string& newName);
|
||||||
@ -40,10 +49,13 @@ namespace Prism
|
|||||||
static void StopWatching();
|
static void StopWatching();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static unsigned long Watch(void* param);
|
static std::atomic<bool> s_IgnoreNextChange;
|
||||||
|
static efsw::FileWatcher* s_FileWatcher;
|
||||||
|
static class PrismFileWatcherListener* s_Listener;
|
||||||
|
static FileSystemChangedCallbackFn s_Callback;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static FileSystemChangedCallbackFn s_Callback;
|
friend class PrismFileWatcherListener;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,13 +17,10 @@ namespace Prism::Utils
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetExtension(const std::string& filename)
|
std::string GetExtension(const std::string& filename, const bool includeDot)
|
||||||
{
|
{
|
||||||
std::vector<std::string> parts = SplitString(filename, '.');
|
if (const std::vector<std::string> parts = SplitString(filename, '.'); parts.size() > 1)
|
||||||
|
return parts[ includeDot ? parts.size() - 1 : parts.size()];
|
||||||
if (parts.size() > 1)
|
|
||||||
return parts[parts.size() - 1];
|
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
namespace Prism::Utils
|
namespace Prism::Utils
|
||||||
{
|
{
|
||||||
std::string GetFilename(const std::string& filepath);
|
std::string GetFilename(const std::string& filepath);
|
||||||
std::string GetExtension(const std::string& filename);
|
std::string GetExtension(const std::string& filename, bool includeDot = true);
|
||||||
std::string RemoveExtension(const std::string& filename);
|
std::string RemoveExtension(const std::string& filename);
|
||||||
std::string NormalizePath(std::string path);
|
std::string NormalizePath(std::string path);
|
||||||
std::string StringToLower(const std::string& str);
|
std::string StringToLower(const std::string& str);
|
||||||
|
|||||||
1
Prism/vendor/efsw
vendored
Submodule
1
Prism/vendor/efsw
vendored
Submodule
Submodule Prism/vendor/efsw added at 22f17a0bcd
Reference in New Issue
Block a user