diff --git a/.gitignore b/.gitignore index eac150c9..ff33e148 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,7 @@ install_manifest.txt # ========================================== # Binaries, Intermediates, and Compiled Objects # ========================================== +Assets/ Binaries/ Intermediates/ [Dd]ebug/ diff --git a/.gitmodules b/.gitmodules index 9d652b94..81590dcc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -8,8 +8,8 @@ path = External/ImGuiFileDialog url = https://github.com/aiekick/ImGuiFileDialog [submodule "External/imgui-node-editor"] - path = External/imgui-node-editor - url = https://github.com/thedmd/imgui-node-editor.git + path = External/imgui-node-editor + url = https://github.com/TamasPetii/imgui-node-editor [submodule "External/IconFontCppHeaders"] path = External/IconFontCppHeaders url = https://github.com/juliettef/IconFontCppHeaders.git diff --git a/Docs/Images/MaterialWorkspace.png b/Docs/Images/MaterialWorkspace.png new file mode 100644 index 00000000..f96033b0 --- /dev/null +++ b/Docs/Images/MaterialWorkspace.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:954a4ebd0e2e0f38002ec71a8e33fac6d7c3cac22c6972b74af7c169b3933514 +size 428719 diff --git a/Docs/Images/ModelWorkspace.png b/Docs/Images/ModelWorkspace.png new file mode 100644 index 00000000..2be62db0 --- /dev/null +++ b/Docs/Images/ModelWorkspace.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9fb953f423539f5c7b0f05e7e0b82a0d2d5f6822e6f60d9c9ddeee21afef3f51 +size 858287 diff --git a/Docs/Images/SceneWorkspace.png b/Docs/Images/SceneWorkspace.png new file mode 100644 index 00000000..b37184de --- /dev/null +++ b/Docs/Images/SceneWorkspace.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5e20e689ac6eee3505472f5f6ff2b0a0b86d7f639fdaabfd3c4dde1d8f13291d +size 1512680 diff --git a/Docs/Images/TextureWorkspace.png b/Docs/Images/TextureWorkspace.png new file mode 100644 index 00000000..acee0d64 --- /dev/null +++ b/Docs/Images/TextureWorkspace.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ecc8fda13dfd5cdf4fe88e8aff33e469fc15592b3bb37da5449687d7d52faa09 +size 1501260 diff --git a/External/IconFontCppHeaders b/External/IconFontCppHeaders index 3ee7f3d2..210b5a39 160000 --- a/External/IconFontCppHeaders +++ b/External/IconFontCppHeaders @@ -1 +1 @@ -Subproject commit 3ee7f3d295ae773c0046db8d7b89b886eb2526de +Subproject commit 210b5a399a64270674560d633638952d1e8d804d diff --git a/External/imgui-node-editor b/External/imgui-node-editor index 021aa0ea..6975a131 160000 --- a/External/imgui-node-editor +++ b/External/imgui-node-editor @@ -1 +1 @@ -Subproject commit 021aa0ea4da13fed864bafb2a92d4c5205076866 +Subproject commit 6975a1318873c52e43779b41e59dcb8022ff4922 diff --git a/External/vcpkg b/External/vcpkg index 64e1fbee..930ecc42 160000 --- a/External/vcpkg +++ b/External/vcpkg @@ -1 +1 @@ -Subproject commit 64e1fbee7d9f40eab5d112aaff648c4dcffe9e47 +Subproject commit 930ecc42b512b564571d767f70775d284a6fa307 diff --git a/README.md b/README.md index 17ae3804..a3d8b13f 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,17 @@ Synapse Engine is a research-oriented real-time rendering engine focusing on eli The system integrates a segmented data-oriented ECS with a hierarchical GPU culling architecture, modern mesh shader support, and an advanced virtualized shadow map system for directional, spot, and point lights (supporting both CPU and GPU-driven paths). The engine now utilizes an MVI architecture for its tooling and features a robust cross-platform build system using `xmake` for Windows and Linux. -![Synapse Engine Editor UI](Docs/Images/EditorUI.png) -*Synapse Engine running with the integrated ImGui editor, showcasing the MVI architecture.* +![Synapse Engine Scene Workspace](Docs/Images/SceneWorkspace.png) +*Synapse Engine running with the integrated ImGui editor (Scene Workspace), showcasing the MVI architecture.* + +![Synapse Engine Model Workspace](Docs/Images/ModelWorkspace.png) +*Model Workspace* + +![Synapse Engine Material Workspace](Docs/Images/MaterialWorkspace.png) +*Material Workspace* + +![Synapse Engine Texture Workspace](Docs/Images/TextureWorkspace.png) +*Texture Workspace* ## Core Concepts diff --git a/SynapseEngine/Assets/CameraIcon.png b/SynapseEngine/Assets/CameraIcon.png deleted file mode 100644 index 0f885a5a..00000000 --- a/SynapseEngine/Assets/CameraIcon.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3a28d8dcfff2516bc29a40ab840adea3cfcaa44b491ed7839e5fdca95d8b77ba -size 7900 diff --git a/SynapseEngine/Assets/DirectionLightIcon.png b/SynapseEngine/Assets/DirectionLightIcon.png deleted file mode 100644 index dfbb8708..00000000 --- a/SynapseEngine/Assets/DirectionLightIcon.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ffff23df9928e88eb27c05fa031ad99dc44fe91fa4667796345e72a1e1afd603 -size 7016 diff --git a/SynapseEngine/Assets/Editor/Fonts/Font Awesome 5 Brands-Regular-400.otf b/SynapseEngine/Assets/Editor/Fonts/Font Awesome 5 Brands-Regular-400.otf deleted file mode 100644 index 1840b935..00000000 Binary files a/SynapseEngine/Assets/Editor/Fonts/Font Awesome 5 Brands-Regular-400.otf and /dev/null differ diff --git a/SynapseEngine/Assets/Editor/Fonts/Font Awesome 5 Free-Regular-400.otf b/SynapseEngine/Assets/Editor/Fonts/Font Awesome 5 Free-Regular-400.otf deleted file mode 100644 index 0f558089..00000000 Binary files a/SynapseEngine/Assets/Editor/Fonts/Font Awesome 5 Free-Regular-400.otf and /dev/null differ diff --git a/SynapseEngine/Assets/Editor/Fonts/Font Awesome 5 Free-Solid-900.otf b/SynapseEngine/Assets/Editor/Fonts/Font Awesome 5 Free-Solid-900.otf deleted file mode 100644 index fb8c079b..00000000 Binary files a/SynapseEngine/Assets/Editor/Fonts/Font Awesome 5 Free-Solid-900.otf and /dev/null differ diff --git a/SynapseEngine/Assets/Editor/Icons/code.png b/SynapseEngine/Assets/Editor/Icons/code.png deleted file mode 100644 index 0c4362a2..00000000 --- a/SynapseEngine/Assets/Editor/Icons/code.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8e2a1078757e0566459e27394ca5e36e4a59eec5a737abb63fcb0095755ecada -size 15480 diff --git a/SynapseEngine/Assets/Editor/Icons/folder.png b/SynapseEngine/Assets/Editor/Icons/folder.png deleted file mode 100644 index 8965dd5f..00000000 --- a/SynapseEngine/Assets/Editor/Icons/folder.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f6c43bda684b309eb886117418cddad521beffe59a892f3b2c6690c08f0dfeda -size 8657 diff --git a/SynapseEngine/Assets/Editor/Icons/mp3.png b/SynapseEngine/Assets/Editor/Icons/mp3.png deleted file mode 100644 index b1f8e790..00000000 --- a/SynapseEngine/Assets/Editor/Icons/mp3.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b2bc2a76fae8ef1f296c37a2d2934ab614189b01a14c64aa5d5a71791aa8cfd5 -size 16791 diff --git a/SynapseEngine/Assets/Editor/Icons/obj.png b/SynapseEngine/Assets/Editor/Icons/obj.png deleted file mode 100644 index 5f996903..00000000 --- a/SynapseEngine/Assets/Editor/Icons/obj.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bcc299821c53746d54617c02f9c00f832cabad2558ae82b3c7b39e1f65104c75 -size 18174 diff --git a/SynapseEngine/Assets/Editor/Icons/png.png b/SynapseEngine/Assets/Editor/Icons/png.png deleted file mode 100644 index 88459687..00000000 --- a/SynapseEngine/Assets/Editor/Icons/png.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:83b86222b7064e34356b17a637dc194933d7ce145efd1349000f101e38d4cdbc -size 15353 diff --git a/SynapseEngine/Assets/Editor/Icons/txt.png b/SynapseEngine/Assets/Editor/Icons/txt.png deleted file mode 100644 index 5c848144..00000000 --- a/SynapseEngine/Assets/Editor/Icons/txt.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4801890d69f2362b4507465d707381da48c61bd314ca6222de16bdc338d1a8a1 -size 11731 diff --git a/SynapseEngine/Assets/PointLightIcon.png b/SynapseEngine/Assets/PointLightIcon.png deleted file mode 100644 index 0b5f7b55..00000000 --- a/SynapseEngine/Assets/PointLightIcon.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3cc5d77039903ca064955f1cf7a906793c6dae19229a3186bc45169638b4b650 -size 3947 diff --git a/SynapseEngine/Assets/SpotLightIcon.png b/SynapseEngine/Assets/SpotLightIcon.png deleted file mode 100644 index f3ade7e7..00000000 --- a/SynapseEngine/Assets/SpotLightIcon.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8e3449201b9173d193e52235483e12c28463372530aa7ea4bf40e9323f722027 -size 5252 diff --git a/SynapseEngine/Editor/Core/Windows/GlfwWindow.cpp b/SynapseEngine/Editor/Core/Windows/GlfwWindow.cpp index 37fbd795..1246920b 100644 --- a/SynapseEngine/Editor/Core/Windows/GlfwWindow.cpp +++ b/SynapseEngine/Editor/Core/Windows/GlfwWindow.cpp @@ -160,4 +160,15 @@ namespace Syn { void GlfwWindow::SetCallbacks(const WindowCallbacks& callbacks) { _data.callbacks = callbacks; } + + void GlfwWindow::SetIcon(uint32_t width, uint32_t height, const uint8_t* pixels) { + if (!_window || !pixels) return; + + GLFWimage image; + image.width = static_cast(width); + image.height = static_cast(height); + image.pixels = const_cast(pixels); + + glfwSetWindowIcon(_window, 1, &image); + } } \ No newline at end of file diff --git a/SynapseEngine/Editor/Core/Windows/GlfwWindow.h b/SynapseEngine/Editor/Core/Windows/GlfwWindow.h index f0995baf..cabba29c 100644 --- a/SynapseEngine/Editor/Core/Windows/GlfwWindow.h +++ b/SynapseEngine/Editor/Core/Windows/GlfwWindow.h @@ -22,7 +22,7 @@ namespace Syn { void CreateSurface(VkInstance instance, VkSurfaceKHR* surface) override; void SetCallbacks(const WindowCallbacks& callbacks) override; - + void SetIcon(uint32_t width, uint32_t height, const uint8_t* pixels) override; void* GetNativePointer() const override { return _window; } private: void Init(const WindowConfig& config); diff --git a/SynapseEngine/Editor/Core/Windows/Window.h b/SynapseEngine/Editor/Core/Windows/Window.h index e122d9ab..c39a9560 100644 --- a/SynapseEngine/Editor/Core/Windows/Window.h +++ b/SynapseEngine/Editor/Core/Windows/Window.h @@ -47,7 +47,7 @@ namespace Syn virtual void CreateSurface(VkInstance instance, VkSurfaceKHR* surface) = 0; virtual void SetCallbacks(const WindowCallbacks& callbacks) = 0; - + virtual void SetIcon(uint32_t width, uint32_t height, const uint8_t* pixels) = 0; virtual void* GetNativePointer() const = 0; static std::unique_ptr Create(const WindowConfig& config); diff --git a/SynapseEngine/Editor/EditorApi/EditorApiUtils.h b/SynapseEngine/Editor/EditorApi/EditorApiUtils.h index 0b7ef5c3..877f2472 100644 --- a/SynapseEngine/Editor/EditorApi/EditorApiUtils.h +++ b/SynapseEngine/Editor/EditorApi/EditorApiUtils.h @@ -2,8 +2,16 @@ #include "Engine/Scene/SceneManager.h" #include "Engine/Scene/Scene.h" #include "EditorCore/Types/EntityHandle.h" +#include +#include namespace Syn { + + template + concept HasStorageCategory = requires(T pool, EntityID entity) { + pool->SetCategory(entity, pool->GetCategory(entity)); + }; + class EditorApiUtils { public: template @@ -44,5 +52,35 @@ namespace Syn { auto registry = scene->GetRegistry(); return registry && registry->HasComponent(entity); } + + + template + static void CloneEntityComponents(SceneManager* sm, EntityID src, EntityID dst) { + auto scene = sm->GetActiveScene(); + if (!scene) return; + + auto registry = scene->GetRegistry(); + if (!registry) return; + + ( + [&]() { + auto pool = registry->GetPool(); + if (pool && pool->Has(src)) { + + if constexpr (std::is_empty_v) { + pool->Add(dst); + } + else { + registry->AddComponent(dst); + registry->GetComponent(dst) = registry->GetComponent(src); + } + + if constexpr (HasStorageCategory) { + pool->SetCategory(dst, pool->GetCategory(src)); + } + } + }(), ... + ); + } }; } \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/EditorContext.cpp b/SynapseEngine/Editor/EditorApi/EditorContext.cpp index e9d84e4f..aa3d519c 100644 --- a/SynapseEngine/Editor/EditorApi/EditorContext.cpp +++ b/SynapseEngine/Editor/EditorApi/EditorContext.cpp @@ -12,25 +12,49 @@ #include "Impl/SelectionApiImpl.h" #include "Impl/PointLightApiImpl.h" #include "Impl/SpotLightApiImpl.h" +#include "Impl/TextureApiImpl.h" +#include "Impl/ModelApiImpl.h" +#include "Impl/CameraApiImpl.h" +#include "Impl/BoxColliderApiImpl.h" +#include "Impl/SphereColliderApiImpl.h" +#include "Impl/CapsuleColliderApiImpl.h" +#include "Impl/ConvexColliderApiImpl.h" +#include "Impl/MeshColliderApiImpl.h" +#include "Impl/RigidBodyApiImpl.h" +#include "Impl/ModelComponentApiImpl.h" +#include "Impl/AnimationApiImpl.h" +#include "Impl/MaterialOverrideApiImpl.h" +#include "Impl/PreviewApiImpl.h" namespace Syn { EditorContext::EditorContext(Engine* engine, GuiTextureManager* textureManager) { SceneManager* sm = engine->GetSceneManager(); - _selectionApi = std::make_unique(sm); - _tagApi = std::make_unique(sm); - _transformApi = std::make_unique(sm); - _directionLightApi = std::make_unique(sm); - _fileSystemApi = std::make_unique(); - _hierarchyApi = std::make_unique(sm); - _loggerApi = std::make_unique(engine); - _materialApi = std::make_unique(engine); - _renderApi = std::make_unique(engine, textureManager, sm); - _sceneApi = std::make_unique(sm); - _settingsApi = std::make_unique(sm); - _pointLightApi = std::make_unique(sm); - _spotLightApi = std::make_unique(sm); + RegisterApi(sm); + RegisterApi(sm); + RegisterApi(sm); + RegisterApi(sm); + RegisterApi(); + RegisterApi(sm, engine->GetModelManager()); + RegisterApi(engine); + RegisterApi(engine->GetMaterialManager(), sm); + RegisterApi(engine, textureManager, sm); + RegisterApi(sm); + RegisterApi(sm); + RegisterApi(sm); + RegisterApi(sm); + RegisterApi(engine->GetImageManager(), textureManager); + RegisterApi(engine->GetModelManager(), sm); + RegisterApi(sm); + RegisterApi(sm); + RegisterApi(sm); + RegisterApi(sm); + RegisterApi(sm); + RegisterApi(sm); + RegisterApi(sm); + RegisterApi(sm); + RegisterApi(sm); + RegisterApi(sm); + RegisterApi(engine->GetPreviewManager(), textureManager, engine->GetImageManager()); } - - EditorContext::~EditorContext() = default; } \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/EditorContext.h b/SynapseEngine/Editor/EditorApi/EditorContext.h index d520b59c..e4d79ac0 100644 --- a/SynapseEngine/Editor/EditorApi/EditorContext.h +++ b/SynapseEngine/Editor/EditorApi/EditorContext.h @@ -1,8 +1,11 @@ #pragma once #include +#include +#include #include "Engine/Engine.h" #include "Editor/Manager/GuiTextureManager.h" +#include "EditorCore/Api/IApi.h" #include "EditorCore/Api/ISelectionApi.h" #include "EditorCore/Api/ITagApi.h" #include "EditorCore/Api/ITransformApi.h" @@ -16,39 +19,42 @@ #include "EditorCore/Api/ISettingsApi.h" #include "EditorCore/Api/IPointLightApi.h" #include "EditorCore/Api/ISpotLightApi.h" +#include "EditorCore/Api/ITextureApi.h" +#include "EditorCore/Api/IModelApi.h" +#include "EditorCore/Api/ICameraApi.h" +#include "EditorCore/Api/IBoxColliderApi.h" +#include "EditorCore/Api/ISphereColliderApi.h" +#include "EditorCore/Api/ICapsuleColliderApi.h" +#include "EditorCore/Api/IConvexColliderApi.h" +#include "EditorCore/Api/IMeshColliderApi.h" +#include "EditorCore/Api/IRigidBodyApi.h" +#include "EditorCore/Api/IModelComponentApi.h" +#include "EditorCore/Api/IAnimationApi.h" +#include "EditorCore/Api/IMaterialOverrideApi.h" +#include "EditorCore/Api/IPreviewApi.h" namespace Syn { class EditorContext { public: EditorContext(Engine* engine, GuiTextureManager* textureManager); - ~EditorContext(); - ISelectionApi* GetSelectionApi() const { return _selectionApi.get(); } - ITagApi* GetTagApi() const { return _tagApi.get(); } - ITransformApi* GetTransformApi() const { return _transformApi.get(); } - IDirectionLightApi* GetDirectionLightApi() const { return _directionLightApi.get(); } - IFileSystemApi* GetFileSystemApi() const { return _fileSystemApi.get(); } - IHierarchyApi* GetHierarchyApi() const { return _hierarchyApi.get(); } - ILoggerApi* GetLoggerApi() const { return _loggerApi.get(); } - IMaterialApi* GetMaterialApi() const { return _materialApi.get(); } - IRenderApi* GetRenderApi() const { return _renderApi.get(); } - ISceneApi* GetSceneApi() const { return _sceneApi.get(); } - ISettingsApi* GetSettingsApi() const { return _settingsApi.get(); } - IPointLightApi* GetPointLightApi() const { return _pointLightApi.get(); } - ISpotLightApi* GetSpotLightApi() const { return _spotLightApi.get(); } + template + T* GetApi() const { + auto it = _apis.find(std::type_index(typeid(T))); + + if (it != _apis.end()) { + return static_cast(it->second.get()); + } + + return nullptr; + } + private: - std::unique_ptr _selectionApi; - std::unique_ptr _tagApi; - std::unique_ptr _transformApi; - std::unique_ptr _fileSystemApi; - std::unique_ptr _hierarchyApi; - std::unique_ptr _loggerApi; - std::unique_ptr _materialApi; - std::unique_ptr _renderApi; - std::unique_ptr _sceneApi; - std::unique_ptr _settingsApi; - std::unique_ptr _directionLightApi; - std::unique_ptr _pointLightApi; - std::unique_ptr _spotLightApi; + template + void RegisterApi(Args&&... args) { + _apis[std::type_index(typeid(Interface))] = std::make_unique(std::forward(args)...); + } + + std::unordered_map> _apis; }; } \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/AnimationApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/AnimationApiImpl.cpp new file mode 100644 index 00000000..a9dffc07 --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/AnimationApiImpl.cpp @@ -0,0 +1,49 @@ +#include "AnimationApiImpl.h" +#include "../EditorApiUtils.h" +#include "Engine/Component/Rendering/AnimationComponent.h" +#include "Engine/ServiceLocator.h" +#include "Engine/Animation/AnimationManager.h" + +namespace Syn { + bool AnimationApiImpl::HasAnimation(EntityID entity) const { + return EditorApiUtils::HasComponent(_sceneManager, entity); + } + + float AnimationApiImpl::GetAnimationSpeed(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.speed; }, 1.0f); + } + + uint32_t AnimationApiImpl::GetAnimationIndex(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.animationIndex; }, UINT32_MAX); + } + + void AnimationApiImpl::SetAnimationSpeed(EntityID entity, float speed) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.speed = speed; }); + } + + void AnimationApiImpl::SetAnimationIndex(EntityID entity, uint32_t index) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { + c.animationIndex = index; + }); + } + + std::vector> AnimationApiImpl::GetAvailableAnimations() const { + std::vector> result; + + auto animManager = ServiceLocator::GetAnimationManager(); + if (!animManager) { + return result; + } + + auto paths = animManager->GetResourcePaths(); + auto snapshots = animManager->GetResourceSnapshot(); + + for (uint32_t i = 0; i < paths.size(); ++i) { + if (snapshots[i].state == ResourceState::Ready) { + result.push_back({ i, paths[i] }); + } + } + + return result; + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/AnimationApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/AnimationApiImpl.h new file mode 100644 index 00000000..aee179ac --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/AnimationApiImpl.h @@ -0,0 +1,21 @@ +#pragma once +#include "EditorCore/Api/IAnimationApi.h" +#include "Engine/Scene/SceneManager.h" + +namespace Syn { + class AnimationApiImpl : public IAnimationApi { + public: + AnimationApiImpl(SceneManager* sm) : _sceneManager(sm) {} + + bool HasAnimation(EntityID entity) const override; + float GetAnimationSpeed(EntityID entity) const override; + uint32_t GetAnimationIndex(EntityID entity) const override; + + void SetAnimationSpeed(EntityID entity, float speed) override; + void SetAnimationIndex(EntityID entity, uint32_t index) override; + + std::vector> GetAvailableAnimations() const override; + private: + SceneManager* _sceneManager; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/BoxColliderApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/BoxColliderApiImpl.cpp new file mode 100644 index 00000000..d1e98c0b --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/BoxColliderApiImpl.cpp @@ -0,0 +1,26 @@ +#include "BoxColliderApiImpl.h" +#include "../EditorApiUtils.h" +#include "Engine/Component/Physics/BoxColliderComponent.h" + +namespace Syn { + + bool BoxColliderApiImpl::HasBoxCollider(EntityID entity) const { + return EditorApiUtils::HasComponent(_sceneManager, entity); + } + + glm::vec3 BoxColliderApiImpl::GetBoxColliderHalfExtents(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.halfExtents; }, glm::vec3(0.5f)); + } + + glm::vec3 BoxColliderApiImpl::GetBoxColliderLocalOffset(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.localOffset; }, glm::vec3(0.0f)); + } + + void BoxColliderApiImpl::SetBoxColliderHalfExtents(EntityID entity, const glm::vec3& halfExtents) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.halfExtents = halfExtents; }); + } + + void BoxColliderApiImpl::SetBoxColliderLocalOffset(EntityID entity, const glm::vec3& localOffset) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.localOffset = localOffset; }); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/BoxColliderApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/BoxColliderApiImpl.h new file mode 100644 index 00000000..af40e0bb --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/BoxColliderApiImpl.h @@ -0,0 +1,21 @@ +#pragma once +#include "EditorCore/Api/IBoxColliderApi.h" +#include "Engine/Scene/SceneManager.h" + +namespace Syn { + class BoxColliderApiImpl : public IBoxColliderApi { + public: + BoxColliderApiImpl(SceneManager* sm) : _sceneManager(sm) {} + + bool HasBoxCollider(EntityID entity) const override; + + glm::vec3 GetBoxColliderHalfExtents(EntityID entity) const override; + glm::vec3 GetBoxColliderLocalOffset(EntityID entity) const override; + + void SetBoxColliderHalfExtents(EntityID entity, const glm::vec3& halfExtents) override; + void SetBoxColliderLocalOffset(EntityID entity, const glm::vec3& localOffset) override; + + private: + SceneManager* _sceneManager; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/CameraApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/CameraApiImpl.cpp new file mode 100644 index 00000000..3d0b61b6 --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/CameraApiImpl.cpp @@ -0,0 +1,80 @@ +#include "CameraApiImpl.h" +#include "../EditorApiUtils.h" +#include "Engine/Component/Core/CameraComponent.h" + +namespace Syn { + + bool CameraApiImpl::HasCamera(EntityID entity) const { + return EditorApiUtils::HasComponent(_sceneManager, entity); + } + + bool CameraApiImpl::GetCameraIsOrthographic(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.isOrthographic; }, false); + } + float CameraApiImpl::GetCameraOrthoSize(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.orthoSize; }, 10.0f); + } + bool CameraApiImpl::GetCameraUseOrbit(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.useOrbit; }, false); + } + + float CameraApiImpl::GetCameraYaw(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.yaw; }, 0.0f); + } + float CameraApiImpl::GetCameraPitch(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.pitch; }, 0.0f); + } + float CameraApiImpl::GetCameraNearPlane(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.nearPlane; }, 0.1f); + } + float CameraApiImpl::GetCameraFarPlane(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.farPlane; }, 1000.0f); + } + float CameraApiImpl::GetCameraFov(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.fov; }, 45.0f); + } + float CameraApiImpl::GetCameraSpeed(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.speed; }, 1.0f); + } + float CameraApiImpl::GetCameraSensitivity(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.sensitivity; }, 0.1f); + } + float CameraApiImpl::GetCameraDistance(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.distance; }, 10.0f); + } + + void CameraApiImpl::SetCameraIsOrthographic(EntityID entity, bool isOrthographic) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.isOrthographic = isOrthographic; }); + } + void CameraApiImpl::SetCameraOrthoSize(EntityID entity, float orthoSize) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.orthoSize = orthoSize; }); + } + void CameraApiImpl::SetCameraUseOrbit(EntityID entity, bool useOrbit) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.useOrbit = useOrbit; }); + } + + void CameraApiImpl::SetCameraYaw(EntityID entity, float yaw) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.yaw = yaw; }); + } + void CameraApiImpl::SetCameraPitch(EntityID entity, float pitch) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.pitch = pitch; }); + } + void CameraApiImpl::SetCameraNearPlane(EntityID entity, float nearPlane) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.nearPlane = nearPlane; }); + } + void CameraApiImpl::SetCameraFarPlane(EntityID entity, float farPlane) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.farPlane = farPlane; }); + } + void CameraApiImpl::SetCameraFov(EntityID entity, float fov) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.fov = fov; }); + } + void CameraApiImpl::SetCameraSpeed(EntityID entity, float speed) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.speed = speed; }); + } + void CameraApiImpl::SetCameraSensitivity(EntityID entity, float sensitivity) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.sensitivity = sensitivity; }); + } + void CameraApiImpl::SetCameraDistance(EntityID entity, float distance) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.distance = distance; }); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/CameraApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/CameraApiImpl.h new file mode 100644 index 00000000..674c8cb2 --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/CameraApiImpl.h @@ -0,0 +1,41 @@ +#pragma once +#include "EditorCore/Api/ICameraApi.h" +#include "Engine/Scene/SceneManager.h" + +namespace Syn { + class CameraApiImpl : public ICameraApi { + public: + CameraApiImpl(SceneManager* sm) : _sceneManager(sm) {} + + bool HasCamera(EntityID entity) const override; + + bool GetCameraIsOrthographic(EntityID entity) const override; + float GetCameraOrthoSize(EntityID entity) const override; + bool GetCameraUseOrbit(EntityID entity) const override; + + float GetCameraYaw(EntityID entity) const override; + float GetCameraPitch(EntityID entity) const override; + float GetCameraNearPlane(EntityID entity) const override; + float GetCameraFarPlane(EntityID entity) const override; + float GetCameraFov(EntityID entity) const override; + float GetCameraSpeed(EntityID entity) const override; + float GetCameraSensitivity(EntityID entity) const override; + float GetCameraDistance(EntityID entity) const override; + + void SetCameraIsOrthographic(EntityID entity, bool isOrthographic) override; + void SetCameraOrthoSize(EntityID entity, float orthoSize) override; + void SetCameraUseOrbit(EntityID entity, bool useOrbit) override; + + void SetCameraYaw(EntityID entity, float yaw) override; + void SetCameraPitch(EntityID entity, float pitch) override; + void SetCameraNearPlane(EntityID entity, float nearPlane) override; + void SetCameraFarPlane(EntityID entity, float farPlane) override; + void SetCameraFov(EntityID entity, float fov) override; + void SetCameraSpeed(EntityID entity, float speed) override; + void SetCameraSensitivity(EntityID entity, float sensitivity) override; + void SetCameraDistance(EntityID entity, float distance) override; + + private: + SceneManager* _sceneManager; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/CapsuleColliderApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/CapsuleColliderApiImpl.cpp new file mode 100644 index 00000000..ea90897d --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/CapsuleColliderApiImpl.cpp @@ -0,0 +1,34 @@ +#include "CapsuleColliderApiImpl.h" +#include "../EditorApiUtils.h" +#include "Engine/Component/Physics/CapsuleColliderComponent.h" + +namespace Syn { + + bool CapsuleColliderApiImpl::HasCapsuleCollider(EntityID entity) const { + return EditorApiUtils::HasComponent(_sceneManager, entity); + } + + float CapsuleColliderApiImpl::GetCapsuleColliderRadius(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.radius; }, 0.5f); + } + + float CapsuleColliderApiImpl::GetCapsuleColliderHalfHeight(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.halfHeight; }, 1.0f); + } + + glm::vec3 CapsuleColliderApiImpl::GetCapsuleColliderLocalOffset(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.localOffset; }, glm::vec3(0.0f)); + } + + void CapsuleColliderApiImpl::SetCapsuleColliderRadius(EntityID entity, float radius) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.radius = radius; }); + } + + void CapsuleColliderApiImpl::SetCapsuleColliderHalfHeight(EntityID entity, float halfHeight) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.halfHeight = halfHeight; }); + } + + void CapsuleColliderApiImpl::SetCapsuleColliderLocalOffset(EntityID entity, const glm::vec3& localOffset) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.localOffset = localOffset; }); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/CapsuleColliderApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/CapsuleColliderApiImpl.h new file mode 100644 index 00000000..82e3df2b --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/CapsuleColliderApiImpl.h @@ -0,0 +1,23 @@ +#pragma once +#include "EditorCore/Api/ICapsuleColliderApi.h" +#include "Engine/Scene/SceneManager.h" + +namespace Syn { + class CapsuleColliderApiImpl : public ICapsuleColliderApi { + public: + CapsuleColliderApiImpl(SceneManager* sm) : _sceneManager(sm) {} + + bool HasCapsuleCollider(EntityID entity) const override; + + float GetCapsuleColliderRadius(EntityID entity) const override; + float GetCapsuleColliderHalfHeight(EntityID entity) const override; + glm::vec3 GetCapsuleColliderLocalOffset(EntityID entity) const override; + + void SetCapsuleColliderRadius(EntityID entity, float radius) override; + void SetCapsuleColliderHalfHeight(EntityID entity, float halfHeight) override; + void SetCapsuleColliderLocalOffset(EntityID entity, const glm::vec3& localOffset) override; + + private: + SceneManager* _sceneManager; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/ConvexColliderApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/ConvexColliderApiImpl.cpp new file mode 100644 index 00000000..083b31fa --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/ConvexColliderApiImpl.cpp @@ -0,0 +1,26 @@ +#include "ConvexColliderApiImpl.h" +#include "../EditorApiUtils.h" +#include "Engine/Component/Physics/ConvexColliderComponent.h" + +namespace Syn { + + bool ConvexColliderApiImpl::HasConvexCollider(EntityID entity) const { + return EditorApiUtils::HasComponent(_sceneManager, entity); + } + + uint32_t ConvexColliderApiImpl::GetConvexColliderTargetLodLevel(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.targetLodLevel; }, 0u); + } + + glm::vec3 ConvexColliderApiImpl::GetConvexColliderLocalOffset(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.localOffset; }, glm::vec3(0.0f)); + } + + void ConvexColliderApiImpl::SetConvexColliderTargetLodLevel(EntityID entity, uint32_t targetLodLevel) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.targetLodLevel = targetLodLevel; }); + } + + void ConvexColliderApiImpl::SetConvexColliderLocalOffset(EntityID entity, const glm::vec3& localOffset) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.localOffset = localOffset; }); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/ConvexColliderApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/ConvexColliderApiImpl.h new file mode 100644 index 00000000..b805e0fa --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/ConvexColliderApiImpl.h @@ -0,0 +1,21 @@ +#pragma once +#include "EditorCore/Api/IConvexColliderApi.h" +#include "Engine/Scene/SceneManager.h" + +namespace Syn { + class ConvexColliderApiImpl : public IConvexColliderApi { + public: + ConvexColliderApiImpl(SceneManager* sm) : _sceneManager(sm) {} + + bool HasConvexCollider(EntityID entity) const override; + + uint32_t GetConvexColliderTargetLodLevel(EntityID entity) const override; + glm::vec3 GetConvexColliderLocalOffset(EntityID entity) const override; + + void SetConvexColliderTargetLodLevel(EntityID entity, uint32_t targetLodLevel) override; + void SetConvexColliderLocalOffset(EntityID entity, const glm::vec3& localOffset) override; + + private: + SceneManager* _sceneManager; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/HierarchyApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/HierarchyApiImpl.cpp index d30898f5..abf47a5c 100644 --- a/SynapseEngine/Editor/EditorApi/Impl/HierarchyApiImpl.cpp +++ b/SynapseEngine/Editor/EditorApi/Impl/HierarchyApiImpl.cpp @@ -9,6 +9,8 @@ #include "Engine/Component/Light/Point/PointLightComponent.h" #include "Engine/Component/Light/Spot/SpotLightComponent.h" #include "Engine/Component/Rendering/AnimationComponent.h" +#include "Engine/Component/Components.h" +#include "Engine/Mesh/MeshSourceNames.h" namespace Syn { uint64_t HierarchyApiImpl::GetVersion() const { @@ -60,7 +62,7 @@ namespace Syn { else scene->GetHierarchyManager()->AttachChild(parent, child); } - EntityID HierarchyApiImpl::CreateEntity(const std::string& name, EntityID parent) { + EntityID HierarchyApiImpl::CreateEntity(EntityTemplate templateType, EntityID parent) { auto scene = _sceneManager->GetActiveScene(); if (!scene || !scene->GetRegistry()) return NULL_ENTITY; @@ -68,10 +70,224 @@ namespace Syn { auto registry = scene->GetRegistry(); registry->AddComponent(newEntity); - registry->GetComponent(newEntity).name = name; registry->AddComponent(newEntity); - if (parent != NULL_ENTITY) SetParent(newEntity, parent); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + + std::string name = "Entity"; + + switch (templateType) { + case EntityTemplate::Empty: + name = "Empty Entity"; + break; + + case EntityTemplate::Camera: + name = "Camera"; + registry->AddComponent(newEntity); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Stream); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Stream); + break; + + case EntityTemplate::DirectionalLight: + name = "Directional Light"; + registry->AddComponent(newEntity); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Stream); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Stream); + registry->GetPool()->SetBit(newEntity); + registry->GetPool()->SetBit(newEntity); + break; + case EntityTemplate::PointLight: + name = "Point Light"; + registry->AddComponent(newEntity); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Stream); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Stream); + registry->GetPool()->SetBit(newEntity); + registry->GetPool()->SetBit(newEntity); + break; + case EntityTemplate::SpotLight: + name = "Spot Light"; + registry->AddComponent(newEntity); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Stream); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Stream); + registry->GetPool()->SetBit(newEntity); + registry->GetPool()->SetBit(newEntity); + break; + + case EntityTemplate::BoxCollider: + name = "Box Collider"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->GetComponent(newEntity).modelIndex = _modelManager->GetResourceIndex(MeshSourceNames::Cube); + + registry->GetPool()->SetCategory(newEntity, StorageCategory::Stream); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + case EntityTemplate::SphereCollider: + name = "Sphere Collider"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->GetComponent(newEntity).modelIndex = _modelManager->GetResourceIndex(MeshSourceNames::Sphere); + + registry->GetPool()->SetCategory(newEntity, StorageCategory::Stream); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + case EntityTemplate::CapsuleCollider: + name = "Capsule Collider"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->GetComponent(newEntity).modelIndex = _modelManager->GetResourceIndex(MeshSourceNames::Capsule); + + registry->GetPool()->SetCategory(newEntity, StorageCategory::Stream); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + case EntityTemplate::ConvexCollider: + name = "Convex Collider"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + + registry->GetPool()->SetCategory(newEntity, StorageCategory::Stream); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + case EntityTemplate::MeshCollider: + name = "Mesh Collider"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + + registry->GetPool()->SetCategory(newEntity, StorageCategory::Stream); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Stream); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + + case EntityTemplate::ShapeCube: + name = "Cube"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->GetComponent(newEntity).modelIndex = _modelManager->GetResourceIndex(MeshSourceNames::Cube); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + case EntityTemplate::ShapeSphere: + name = "Sphere"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->GetComponent(newEntity).modelIndex = _modelManager->GetResourceIndex(MeshSourceNames::Sphere); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + case EntityTemplate::ShapeQuad: + name = "Quad"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->GetComponent(newEntity).modelIndex = _modelManager->GetResourceIndex(MeshSourceNames::Quad); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + case EntityTemplate::ShapeCylinder: + name = "Cylinder"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->GetComponent(newEntity).modelIndex = _modelManager->GetResourceIndex(MeshSourceNames::Cylinder); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + case EntityTemplate::ShapeCone: + name = "Cone"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->GetComponent(newEntity).modelIndex = _modelManager->GetResourceIndex(MeshSourceNames::Cone); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + case EntityTemplate::ShapeCapsule: + name = "Capsule"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->GetComponent(newEntity).modelIndex = _modelManager->GetResourceIndex(MeshSourceNames::Capsule); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + case EntityTemplate::ShapeHemisphere: + name = "Hemisphere"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->GetComponent(newEntity).modelIndex = _modelManager->GetResourceIndex(MeshSourceNames::Hemisphere); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + case EntityTemplate::ShapePyramid: + name = "Pyramid"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->GetComponent(newEntity).modelIndex = _modelManager->GetResourceIndex(MeshSourceNames::Pyramid); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + case EntityTemplate::ShapeGrid: + name = "Grid"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->GetComponent(newEntity).modelIndex = _modelManager->GetResourceIndex(MeshSourceNames::Grid); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + case EntityTemplate::ShapeTorus: + name = "Torus"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->GetComponent(newEntity).modelIndex = _modelManager->GetResourceIndex(MeshSourceNames::Torus); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + + case EntityTemplate::Model: + name = "Model"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + case EntityTemplate::Animation: + name = "Animation"; + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + registry->AddComponent(newEntity); + + registry->GetPool()->SetCategory(newEntity, StorageCategory::Stream); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + registry->GetPool()->SetCategory(newEntity, StorageCategory::Static); + break; + } + + registry->GetComponent(newEntity).name = name; + + if (parent != NULL_ENTITY) { + SetParent(newEntity, parent); + } return newEntity; } @@ -83,9 +299,83 @@ namespace Syn { if (scene->GetSelectedEntity() == entity) { scene->SetSelectedEntity(NULL_ENTITY); } + scene->DestroyEntity(entity); } + void HierarchyApiImpl::DestroyEntityRecursive(EntityID entity) { + auto children = GetChildren(entity); + for (EntityID child : children) { + DestroyEntityRecursive(child); + } + DestroyEntity(entity); + } + + void HierarchyApiImpl::DestroyEntityKeepChildren(EntityID entity) { + EntityID parent = GetParent(entity); + auto children = GetChildren(entity); + + for (EntityID child : children) { + SetParent(child, parent); + } + + DestroyEntity(entity); + } + + EntityID HierarchyApiImpl::CopyEntity(EntityID entity, EntityID parent) { + auto scene = _sceneManager->GetActiveScene(); + if (!scene || !scene->GetRegistry()) return NULL_ENTITY; + + EntityID newEntity = scene->CreateEntity(); + auto registry = scene->GetRegistry(); + + EditorApiUtils::CloneEntityComponents< + TagComponent, + TransformComponent, + CameraComponent, + ModelComponent, + AnimationComponent, + MaterialOverrideComponent, + DirectionLightComponent, + PointLightComponent, + SpotLightComponent, + DirectionLightShadowComponent, + PointLightShadowComponent, + SpotLightShadowComponent, + BoxColliderComponent, + SphereColliderComponent, + CapsuleColliderComponent, + ConvexColliderComponent, + MeshColliderComponent, + RigidBodyComponent + >(_sceneManager, entity, newEntity); + + if (registry->HasComponent(newEntity)) { + registry->GetComponent(newEntity).name += " (Copy)"; + } + + if (registry->HasComponent(newEntity)) { + registry->GetPool()->SetBit(newEntity); + } + + if (parent != NULL_ENTITY) { + SetParent(newEntity, parent); + } + + return newEntity; + } + + EntityID HierarchyApiImpl::FullCopyEntity(EntityID entity, EntityID parent) { + EntityID newEntity = CopyEntity(entity, parent); + + auto children = GetChildren(entity); + for (EntityID child : children) { + FullCopyEntity(child, newEntity); + } + + return newEntity; + } + EntityID HierarchyApiImpl::GetParent(EntityID entity) const { auto scene = _sceneManager->GetActiveScene(); if (!scene || !scene->GetRegistry()) return NULL_ENTITY; diff --git a/SynapseEngine/Editor/EditorApi/Impl/HierarchyApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/HierarchyApiImpl.h index 16ce7776..6bb9cd1e 100644 --- a/SynapseEngine/Editor/EditorApi/Impl/HierarchyApiImpl.h +++ b/SynapseEngine/Editor/EditorApi/Impl/HierarchyApiImpl.h @@ -2,10 +2,11 @@ #include "EditorCore/Api/IHierarchyApi.h" #include "Engine/Scene/SceneManager.h" + namespace Syn { class HierarchyApiImpl : public IHierarchyApi { public: - HierarchyApiImpl(SceneManager* sm) : _sceneManager(sm) {} + HierarchyApiImpl(SceneManager* sm, ModelManager* modelManager) : _sceneManager(sm), _modelManager(modelManager) {} uint64_t GetVersion() const override; std::vector GetRootEntities() const override; @@ -14,9 +15,14 @@ namespace Syn { bool HasChildren(EntityID entity) const override; EntityID GetParent(EntityID entity) const override; void SetParent(EntityID child, EntityID parent) override; - EntityID CreateEntity(const std::string& name, EntityID parent = NULL_ENTITY) override; + EntityID CreateEntity(EntityTemplate templateType, EntityID parent = NULL_ENTITY) override; + void DestroyEntityRecursive(EntityID entity) override; + void DestroyEntityKeepChildren(EntityID entity) override; + EntityID CopyEntity(EntityID entity, EntityID parent = NULL_ENTITY) override; + EntityID FullCopyEntity(EntityID entity, EntityID parent = NULL_ENTITY) override; void DestroyEntity(EntityID entity) override; private: SceneManager* _sceneManager; + ModelManager* _modelManager; }; } \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/MaterialApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/MaterialApiImpl.cpp index 44ee45f7..03ddf867 100644 --- a/SynapseEngine/Editor/EditorApi/Impl/MaterialApiImpl.cpp +++ b/SynapseEngine/Editor/EditorApi/Impl/MaterialApiImpl.cpp @@ -1,67 +1,140 @@ #include "MaterialApiImpl.h" -#include "Engine/Material/MaterialManager.h" -#include "Engine/Image/ImageManager.h" +#include "EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphState.h" +#include "Engine/Scene/Insiders/SceneInsider.h" +#include "Engine/Component/Core/TagComponent.h" +#include "Engine/Component/Rendering/MaterialOverrideComponent.h" #include "Engine/Logger/SynLog.h" +#include "Editor/EditorApi/EditorApiUtils.h" +#include namespace Syn { - std::vector MaterialApiImpl::GetAllMaterials() const { - std::vector result; - auto materialManager = _engine->GetMaterialManager(); - if (!materialManager) return result; - for (const auto& path : materialManager->GetResourcePaths()) { - result.push_back({ materialManager->GetResourceIndex(path), path }); + std::vector MaterialApiImpl::GetAllMaterials() const { + if (!_materialManager) return {}; + + std::vector result; + auto paths = _materialManager->GetResourcePaths(); + + for (uint32_t i = 0; i < paths.size(); ++i) { + if (_materialManager->GetEntryState(i) == ResourceState::Ready) { + std::filesystem::path p(paths[i]); + result.push_back({ i, p.filename().string(), paths[i] }); + } } return result; } - std::vector MaterialApiImpl::GetAllTextures() const { - std::vector result; - auto imageManager = _engine->GetImageManager(); - if (!imageManager) return result; + uint32_t MaterialApiImpl::GetSelectedMaterial() const { + return _selectedMaterial; + } + + void MaterialApiImpl::SetSelectedMaterial(uint32_t id) { + _selectedMaterial = id; + } + + uint64_t MaterialApiImpl::GetVersion() const { + return _materialManager ? _materialManager->GetVersion() : 0; + } - for (const auto& path : imageManager->GetResourcePaths()) { - result.push_back({ imageManager->GetResourceIndex(path), path }); + std::string MaterialApiImpl::GetMaterialName(uint32_t materialId) const { + auto mats = GetAllMaterials(); + for (const auto& m : mats) { + if (m.id == materialId) return m.name; + } + return "Unknown Material"; + } + + uint32_t MaterialApiImpl::GetLinkedTexture(uint32_t materialId, uint32_t textureType) const { + if (!_materialManager || materialId == INVALID_MATERIAL_ID) return INVALID_MATERIAL_ID; + + auto mat = _materialManager->GetResource(materialId); + if (!mat) return INVALID_MATERIAL_ID; + + switch (static_cast(textureType)) { + case GraphPinType::Albedo: return mat->albedoTexture; + case GraphPinType::Normal: return mat->normalTexture; + case GraphPinType::Metalness: return mat->metalnessTexture; + case GraphPinType::Roughness: return mat->roughnessTexture; + case GraphPinType::MetallicRoughness: return mat->metallicRoughnessTexture; + case GraphPinType::Emissive: return mat->emissiveTexture; + case GraphPinType::AmbientOcclusion: return mat->ambientOcclusionTexture; + default: return INVALID_MATERIAL_ID; } - return result; } void MaterialApiImpl::LinkTextureToMaterial(uint32_t materialId, uint32_t textureType, uint32_t textureId) { - auto materialManager = _engine->GetMaterialManager(); - if (!materialManager) return; - auto material = materialManager->GetResource(materialId); - if (!material) return; - - switch (textureType) { - case 0: material->albedoTexture = textureId; break; - case 1: material->normalTexture = textureId; break; - case 2: material->metalnessTexture = textureId; break; - case 3: material->roughnessTexture = textureId; break; - case 4: material->metallicRoughnessTexture = textureId; break; - case 5: material->emissiveTexture = textureId; break; - case 6: material->ambientOcclusionTexture = textureId; break; - default: - Syn::Warning("MaterialApiImpl: Ismeretlen textúra slot ({}) a {} azonosítójú materialhoz!", textureType, materialId); - return; + if (!_materialManager || materialId == INVALID_MATERIAL_ID) return; + + auto mat = _materialManager->GetResource(materialId); + if (!mat) return; + + switch (static_cast(textureType)) { + case GraphPinType::Albedo: mat->albedoTexture = textureId; break; + case GraphPinType::Normal: mat->normalTexture = textureId; break; + case GraphPinType::Metalness: mat->metalnessTexture = textureId; break; + case GraphPinType::Roughness: mat->roughnessTexture = textureId; break; + case GraphPinType::MetallicRoughness: mat->metallicRoughnessTexture = textureId; break; + case GraphPinType::Emissive: mat->emissiveTexture = textureId; break; + case GraphPinType::AmbientOcclusion: mat->ambientOcclusionTexture = textureId; break; + default: break; } - Syn::Info("MaterialApiImpl: Textúra ({}) bekötve a Material ({}) {} slotjába.", textureId, materialId, textureType); } void MaterialApiImpl::UnlinkTextureFromMaterial(uint32_t materialId, uint32_t textureType) { - auto materialManager = _engine->GetMaterialManager(); - if (!materialManager) return; - auto material = materialManager->GetResource(materialId); - if (!material) return; - - switch (textureType) { - case 0: material->albedoTexture = UINT32_MAX; break; - case 1: material->normalTexture = UINT32_MAX; break; - case 2: material->metalnessTexture = UINT32_MAX; break; - case 3: material->roughnessTexture = UINT32_MAX; break; - case 4: material->metallicRoughnessTexture = UINT32_MAX; break; - case 5: material->emissiveTexture = UINT32_MAX; break; - case 6: material->ambientOcclusionTexture = UINT32_MAX; break; + LinkTextureToMaterial(materialId, textureType, 0xFFFFFFFF); + } + + bool MaterialApiImpl::GetMaterialData(uint32_t materialId, Material& outMaterial) const { + if (!_materialManager || materialId == INVALID_MATERIAL_ID) return false; + + auto resource = _materialManager->GetResource(materialId); + if (resource) { + outMaterial = *resource; + return true; + } + return false; + } + + void MaterialApiImpl::UpdateMaterialData(uint32_t materialId, const Material& material) { + if (!_materialManager || materialId == INVALID_MATERIAL_ID) return; + auto resource = _materialManager->GetResource(materialId); + + if (resource) { + *resource = material; + _materialManager->MarkDirty(materialId); } - Syn::Info("MaterialApiImpl: Textúra kikötve a Material ({}) {} slotjából.", materialId, textureType); + } + + void MaterialApiImpl::ApplyMaterialToPreviewObjects(uint32_t materialId) { + if (!_sceneManager) return; + auto scene = _sceneManager->GetActiveScene(); + if (!scene) return; + + auto& registry = SceneInsider::GetRegistry(*scene, SceneInsider::GetKey()); + + auto tagPool = registry.GetPool(); + if (!tagPool) return; + + for (EntityID entity : tagPool->GetDenseEntities()) { + if (registry.HasComponent(entity)) { + const auto& tag = tagPool->Get(entity); + + if (tag.tag == "Preview") { + + EditorApiUtils::ModifyComponent( + _sceneManager, + entity, + [materialId](auto& matOverride, auto pool) { + matOverride.materials.clear(); + if (materialId != 0xFFFFFFFF) { + matOverride.materials.push_back(materialId); + } + } + ); + } + } + } + + Info("MaterialApiImpl: Applied material {} to preview objects.", materialId); } } \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/MaterialApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/MaterialApiImpl.h index a99878fb..ef60e973 100644 --- a/SynapseEngine/Editor/EditorApi/Impl/MaterialApiImpl.h +++ b/SynapseEngine/Editor/EditorApi/Impl/MaterialApiImpl.h @@ -1,16 +1,34 @@ #pragma once #include "EditorCore/Api/IMaterialApi.h" -#include "Engine/Engine.h" +#include "Engine/Material/MaterialManager.h" +#include "Engine/Scene/SceneManager.h" namespace Syn { + enum class GraphPinType; + class MaterialApiImpl : public IMaterialApi { public: - MaterialApiImpl(Engine* engine) : _engine(engine) {} - std::vector GetAllMaterials() const override; - std::vector GetAllTextures() const override; + MaterialApiImpl(MaterialManager* materialManager, SceneManager* sceneManager) + : _materialManager(materialManager), _sceneManager(sceneManager) {} + + std::vector GetAllMaterials() const override; + uint32_t GetSelectedMaterial() const override; + void SetSelectedMaterial(uint32_t id) override; + uint64_t GetVersion() const override; + + std::string GetMaterialName(uint32_t materialId) const override; + uint32_t GetLinkedTexture(uint32_t materialId, uint32_t textureType) const override; + void LinkTextureToMaterial(uint32_t materialId, uint32_t textureType, uint32_t textureId) override; void UnlinkTextureFromMaterial(uint32_t materialId, uint32_t textureType) override; + + bool GetMaterialData(uint32_t materialId, Material& outMaterial) const override; + void UpdateMaterialData(uint32_t materialId, const Material& material) override; + + void ApplyMaterialToPreviewObjects(uint32_t materialId) override; private: - Engine* _engine; + SceneManager* _sceneManager; + MaterialManager* _materialManager; + uint32_t _selectedMaterial = INVALID_MATERIAL_ID; }; } \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/MaterialOverrideApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/MaterialOverrideApiImpl.cpp new file mode 100644 index 00000000..7dad6fa3 --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/MaterialOverrideApiImpl.cpp @@ -0,0 +1,112 @@ +#include "MaterialOverrideApiImpl.h" +#include "../EditorApiUtils.h" +#include "Engine/Component/Rendering/MaterialOverrideComponent.h" +#include "Engine/Component/Rendering/ModelComponent.h" +#include "Engine/ServiceLocator.h" +#include "Engine/Mesh/ModelManager.h" +#include "Engine/Material/MaterialManager.h" +#include "Engine/Component/Core/TagComponent.h" + +namespace Syn { + bool MaterialOverrideApiImpl::HasMaterialOverride(EntityID entity) const { + return EditorApiUtils::HasComponent(_sceneManager, entity); + } + + uint32_t MaterialOverrideApiImpl::GetExpectedSlotCount(EntityID entity) const { + if (!EditorApiUtils::HasComponent(_sceneManager, entity)) return 0; + + uint32_t modelIdx = EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.modelIndex; }, UINT32_MAX); + if (modelIdx == UINT32_MAX) return 0; + + auto modelManager = ServiceLocator::GetModelManager(); + if (!modelManager) return 0; + + auto snapshots = modelManager->GetResourceSnapshot(); + if (modelIdx < snapshots.size() && snapshots[modelIdx].state == ResourceState::Ready && snapshots[modelIdx].resource) { + return static_cast(snapshots[modelIdx].resource->cpuData.meshMaterialIndices.size()); + } + return 0; + } + + uint32_t MaterialOverrideApiImpl::GetMaterialAtSlot(EntityID entity, uint32_t slotIndex) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [slotIndex](const auto& c) { + if (slotIndex < c.materials.size()) { + return c.materials[slotIndex]; + } + return UINT32_MAX; + }, UINT32_MAX); + } + + void MaterialOverrideApiImpl::SetMaterialAtSlot(EntityID entity, uint32_t slotIndex, uint32_t materialId) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { + uint32_t expectedSize = GetExpectedSlotCount(entity); + if (c.materials.size() != expectedSize) { + c.materials.resize(expectedSize, UINT32_MAX); + } + if (slotIndex < c.materials.size()) { + c.materials[slotIndex] = materialId; + pool->template SetBit(entity); + } + }); + } + + EntityID MaterialOverrideApiImpl::GetSharedMaterialEntity(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.sharedMaterialEntity; }, NULL_ENTITY); + } + + void MaterialOverrideApiImpl::SetSharedMaterialEntity(EntityID entity, EntityID sharedEntity) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { + c.sharedMaterialEntity = sharedEntity; + pool->template SetBit(entity); + }); + } + + std::vector> MaterialOverrideApiImpl::GetAvailableMaterials() const { + std::vector> result; + + auto matManager = ServiceLocator::GetMaterialManager(); + if (!matManager) return result; + + auto paths = matManager->GetResourcePaths(); + auto snapshots = matManager->GetResourceSnapshot(); + + for (uint32_t i = 0; i < paths.size(); ++i) { + if (snapshots[i].state == ResourceState::Ready) { + result.push_back({ i, paths[i] }); + } + } + + return result; + } + + std::vector> MaterialOverrideApiImpl::GetCompatibleSharedEntities(EntityID targetEntity) const { + std::vector> result; + + auto scene = _sceneManager->GetActiveScene(); + if (!scene || !scene->GetRegistry()) return result; + + uint32_t targetSlotCount = GetExpectedSlotCount(targetEntity); + if (targetSlotCount == 0) return result; + + auto registry = scene->GetRegistry(); + + for (EntityID entity : registry->GetActiveEntities().GetDenseEntities()) { + if (entity == targetEntity) continue; + + if (registry->HasComponent(entity)) { + uint32_t currentSlotCount = GetExpectedSlotCount(entity); + + if (currentSlotCount == targetSlotCount) { + std::string entityName = "Entity " + std::to_string(entity); + if (registry->HasComponent(entity)) { + entityName = registry->GetComponent(entity).name; + } + + result.push_back({ entity, entityName + " (ID: " + std::to_string(entity) + ")" }); + } + } + } + + return result; + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/MaterialOverrideApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/MaterialOverrideApiImpl.h new file mode 100644 index 00000000..fa187bd2 --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/MaterialOverrideApiImpl.h @@ -0,0 +1,24 @@ +#pragma once +#include "EditorCore/Api/IMaterialOverrideApi.h" +#include "Engine/Scene/SceneManager.h" + +namespace Syn { + class MaterialOverrideApiImpl : public IMaterialOverrideApi { + public: + MaterialOverrideApiImpl(SceneManager* sm) : _sceneManager(sm) {} + + bool HasMaterialOverride(EntityID entity) const override; + + uint32_t GetExpectedSlotCount(EntityID entity) const override; + uint32_t GetMaterialAtSlot(EntityID entity, uint32_t slotIndex) const override; + void SetMaterialAtSlot(EntityID entity, uint32_t slotIndex, uint32_t materialId) override; + + EntityID GetSharedMaterialEntity(EntityID entity) const override; + void SetSharedMaterialEntity(EntityID entity, EntityID sharedEntity) override; + + std::vector> GetCompatibleSharedEntities(EntityID entity) const override; + std::vector> GetAvailableMaterials() const override; + private: + SceneManager* _sceneManager; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/MeshColliderApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/MeshColliderApiImpl.cpp new file mode 100644 index 00000000..685bf75a --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/MeshColliderApiImpl.cpp @@ -0,0 +1,26 @@ +#include "MeshColliderApiImpl.h" +#include "../EditorApiUtils.h" +#include "Engine/Component/Physics/MeshColliderComponent.h" + +namespace Syn { + + bool MeshColliderApiImpl::HasMeshCollider(EntityID entity) const { + return EditorApiUtils::HasComponent(_sceneManager, entity); + } + + uint32_t MeshColliderApiImpl::GetMeshColliderTargetLodLevel(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.targetLodLevel; }, 0u); + } + + glm::vec3 MeshColliderApiImpl::GetMeshColliderLocalOffset(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.localOffset; }, glm::vec3(0.0f)); + } + + void MeshColliderApiImpl::SetMeshColliderTargetLodLevel(EntityID entity, uint32_t targetLodLevel) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.targetLodLevel = targetLodLevel; }); + } + + void MeshColliderApiImpl::SetMeshColliderLocalOffset(EntityID entity, const glm::vec3& localOffset) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.localOffset = localOffset; }); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/MeshColliderApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/MeshColliderApiImpl.h new file mode 100644 index 00000000..57c9e736 --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/MeshColliderApiImpl.h @@ -0,0 +1,21 @@ +#pragma once +#include "EditorCore/Api/IMeshColliderApi.h" +#include "Engine/Scene/SceneManager.h" + +namespace Syn { + class MeshColliderApiImpl : public IMeshColliderApi { + public: + MeshColliderApiImpl(SceneManager* sm) : _sceneManager(sm) {} + + bool HasMeshCollider(EntityID entity) const override; + + uint32_t GetMeshColliderTargetLodLevel(EntityID entity) const override; + glm::vec3 GetMeshColliderLocalOffset(EntityID entity) const override; + + void SetMeshColliderTargetLodLevel(EntityID entity, uint32_t targetLodLevel) override; + void SetMeshColliderLocalOffset(EntityID entity, const glm::vec3& localOffset) override; + + private: + SceneManager* _sceneManager; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/ModelApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/ModelApiImpl.cpp new file mode 100644 index 00000000..103af020 --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/ModelApiImpl.cpp @@ -0,0 +1,125 @@ +#include "ModelApiImpl.h" +#include "Engine/Scene/Insiders/SceneInsider.h" +#include "Engine/Component/Core/TagComponent.h" +#include "Engine/Component/Core/TransformComponent.h" +#include "Engine/Component/Core/CameraComponent.h" +#include "Engine/Component/Rendering/ModelComponent.h" +#include "Editor/EditorApi/EditorApiUtils.h" +#include "Engine/Logger/SynLog.h" +#include +#include + +namespace Syn { + + std::vector ModelApiImpl::GetAllModels() const { + if (!_modelManager) return {}; + + std::vector result; + auto paths = _modelManager->GetResourcePaths(); + + for (uint32_t i = 0; i < paths.size(); ++i) { + if (_modelManager->GetEntryState(i) == ResourceState::Ready) { + std::filesystem::path p(paths[i]); + result.push_back({ i, p.filename().string(), paths[i] }); + } + } + return result; + } + + uint64_t ModelApiImpl::GetVersion() const { + return _modelManager ? _modelManager->GetVersion() : 0; + } + + void ModelApiImpl::SetSelected(uint32_t modelId, int32_t nodeIndex) { + _selectedModelId = modelId; + _selectedNodeIndex = nodeIndex; + } + + std::pair ModelApiImpl::GetSelected() const { + return { _selectedModelId, _selectedNodeIndex }; + } + + const CpuModelData* ModelApiImpl::GetModelCpuData(uint32_t modelId) const { + if (!_modelManager || modelId == INVALID_MODEL_ID) return nullptr; + + auto resource = _modelManager->GetResource(modelId); + if (resource) { + return &resource->cpuData; + } + + return nullptr; + } + + std::string ModelApiImpl::GetNodeName(uint32_t modelId, uint16_t nodeIndex) const { + if (!_modelManager || modelId == INVALID_MODEL_ID) + return "Node_" + std::to_string(nodeIndex); + + auto resource = _modelManager->GetResource(modelId); + return resource->cpuData.meshNodeDescriptors[nodeIndex].name; + } + + void ModelApiImpl::ApplyModelToPreviewObject(uint32_t modelId) { + if (!_sceneManager) return; + auto scene = _sceneManager->GetActiveScene(); + if (!scene) return; + + auto& registry = SceneInsider::GetRegistry(*scene, SceneInsider::GetKey()); + auto tagPool = registry.GetPool(); + if (!tagPool) return; + + for (EntityID entity : tagPool->GetDenseEntities()) { + const auto& tag = tagPool->Get(entity); + if (tag.tag == "Preview" && registry.HasComponent(entity)) { + EditorApiUtils::ModifyComponent( + _sceneManager, + entity, + [modelId](auto& modelComp, auto pool) { + modelComp.modelIndex = modelId; + } + ); + } + } + + if (modelId != INVALID_MODEL_ID && _modelManager) { + auto resource = _modelManager->GetResource(modelId); + if (resource) { + glm::vec3 center = resource->cpuData.globalCollider.center; + float radius = resource->cpuData.globalCollider.radius * 1.05f; + + float targetSize = radius; + + if (targetSize > 100) + targetSize = 100.0f; + + float scaleFactor = targetSize / (radius * 2.0f); + + for (EntityID entity : tagPool->GetDenseEntities()) { + const auto& tag = tagPool->Get(entity); + + if (tag.tag == "Preview" && registry.HasComponent(entity)) { + EditorApiUtils::ModifyComponent( + _sceneManager, + entity, + [center, scaleFactor](auto& transformComp, auto pool) { + transformComp.scale = glm::vec3(scaleFactor); + } + ); + } + + if (tag.tag == "Camera" && registry.HasComponent(entity)) { + EditorApiUtils::ModifyComponent( + _sceneManager, + entity, + [targetSize](auto& camComp, auto pool) { + camComp.target = glm::vec3(0.0f); + camComp.distance = targetSize * 1.25f; + } + ); + } + } + } + } + + Syn::Info("ModelApiImpl: Applied model {} to preview object and adjusted camera.", modelId); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/ModelApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/ModelApiImpl.h new file mode 100644 index 00000000..5f7c750b --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/ModelApiImpl.h @@ -0,0 +1,28 @@ +#pragma once +#include "EditorCore/Api/IModelApi.h" +#include "Engine/Mesh/ModelManager.h" +#include "Engine/Scene/SceneManager.h" + +namespace Syn { + class ModelApiImpl : public IModelApi { + public: + ModelApiImpl(ModelManager* modelManager, SceneManager* sceneManager) + : _modelManager(modelManager), _sceneManager(sceneManager) {} + + std::vector GetAllModels() const override; + uint64_t GetVersion() const override; + + void SetSelected(uint32_t modelId, int32_t nodeIndex) override; + std::pair GetSelected() const override; + + const CpuModelData* GetModelCpuData(uint32_t modelId) const override; + std::string GetNodeName(uint32_t modelId, uint16_t nodeIndex) const override; + + void ApplyModelToPreviewObject(uint32_t modelId) override; + private: + ModelManager* _modelManager; + SceneManager* _sceneManager; + uint32_t _selectedModelId = INVALID_MODEL_ID; + int32_t _selectedNodeIndex = INVALID_NODE_INDEX; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/ModelComponentApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/ModelComponentApiImpl.cpp new file mode 100644 index 00000000..93ed7e21 --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/ModelComponentApiImpl.cpp @@ -0,0 +1,53 @@ +#include "ModelComponentApiImpl.h" +#include "../EditorApiUtils.h" +#include "Engine/Component/Rendering/ModelComponent.h" +#include "Engine/ServiceLocator.h" +#include "Engine/Mesh/ModelManager.h" + +namespace Syn { + bool ModelComponentApiImpl::HasModelComponent(EntityID entity) const { + return EditorApiUtils::HasComponent(_sceneManager, entity); + } + + bool ModelComponentApiImpl::GetCastShadow(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.castShadow; }, true); + } + + bool ModelComponentApiImpl::GetReceiveShadow(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.receiveShadow; }, true); + } + + uint32_t ModelComponentApiImpl::GetModelIndex(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.modelIndex; }, UINT32_MAX); + } + + void ModelComponentApiImpl::SetCastShadow(EntityID entity, bool cast) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.castShadow = cast; }); + } + + void ModelComponentApiImpl::SetReceiveShadow(EntityID entity, bool receive) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.receiveShadow = receive; }); + } + + void ModelComponentApiImpl::SetModelIndex(EntityID entity, uint32_t index) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.modelIndex = index; }); + } + + std::vector> ModelComponentApiImpl::GetAvailableModels() const { + std::vector> result; + + auto modelManager = ServiceLocator::GetModelManager(); + if (!modelManager) return result; + + auto paths = modelManager->GetResourcePaths(); + auto snapshots = modelManager->GetResourceSnapshot(); + + for (uint32_t i = 0; i < paths.size(); ++i) { + if (snapshots[i].state == ResourceState::Ready) { + result.push_back({ i, paths[i] }); + } + } + + return result; + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/ModelComponentApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/ModelComponentApiImpl.h new file mode 100644 index 00000000..6d26270c --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/ModelComponentApiImpl.h @@ -0,0 +1,24 @@ +#pragma once +#include "EditorCore/Api/IModelComponentApi.h" +#include "Engine/Scene/SceneManager.h" + +namespace Syn { + class ModelComponentApiImpl : public IModelComponentApi { + public: + ModelComponentApiImpl(SceneManager* sm) : _sceneManager(sm) {} + + bool HasModelComponent(EntityID entity) const override; + + bool GetCastShadow(EntityID entity) const override; + bool GetReceiveShadow(EntityID entity) const override; + uint32_t GetModelIndex(EntityID entity) const override; + + void SetCastShadow(EntityID entity, bool cast) override; + void SetReceiveShadow(EntityID entity, bool receive) override; + void SetModelIndex(EntityID entity, uint32_t index) override; + + std::vector> GetAvailableModels() const override; + private: + SceneManager* _sceneManager; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/PreviewApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/PreviewApiImpl.cpp new file mode 100644 index 00000000..0f3b58ba --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/PreviewApiImpl.cpp @@ -0,0 +1,72 @@ +#include "PreviewApiImpl.h" +#include "Engine/Image/SamplerNames.h" + +namespace Syn { + + PreviewApiImpl::PreviewApiImpl(PreviewManager* previewManager, GuiTextureManager* guiTextureManager, ImageManager* imageManager) + : _previewManager(previewManager), _guiTextureManager(guiTextureManager), _imageManager(imageManager) + {} + + TextureHandle PreviewApiImpl::GetAtlasHandle() { + if (!_previewManager || !_guiTextureManager || !_imageManager) + return InvalidTextureHandle; + + auto* atlasImage = _previewManager->GetAtlasImage(); + if (!atlasImage) + return InvalidTextureHandle; + + uint32_t currentRes = _previewManager->GetResolution(); + + if (_lastAtlasResolution != currentRes) { + auto sampler = _imageManager->GetSampler(SamplerNames::LinearClampEdge); + _atlasTextureHandle = _guiTextureManager->RegisterTexture( + atlasImage->GetView(), + sampler->Handle() + ); + + _lastAtlasResolution = currentRes; + } + + return _guiTextureManager->GetImGuiTextureID(_atlasTextureHandle); + } + + bool PreviewApiImpl::GetPreviewUVs(PreviewResourceType type, uint32_t resourceId, glm::vec2& outUv0, glm::vec2& outUv1) const { + if (!_previewManager) return false; + + if (_previewManager->HasTile(type, resourceId)) { + _previewManager->GetNormalizedUVs(type, resourceId, outUv0, outUv1); + return true; + } + + outUv0 = glm::vec2(0.0f); + outUv1 = glm::vec2(1.0f); + return false; + } + + bool PreviewApiImpl::HasPreview(PreviewResourceType type, uint32_t resourceId) const { + if (!_previewManager) return false; + return _previewManager->HasTile(type, resourceId); + } + + void PreviewApiImpl::RequestPreview(PreviewResourceType type, uint32_t resourceId) { + if (!_previewManager) return; + _previewManager->AllocateTile(type, resourceId); + _previewManager->MarkDirty(type, resourceId); + } + + std::vector PreviewApiImpl::GetAllPreviews(PreviewResourceType type) const { + if (!_previewManager) return {}; + + std::vector result; + auto activeIds = _previewManager->GetActiveResources(type); + result.reserve(activeIds.size()); + + for (uint32_t id : activeIds) { + glm::vec2 uv0, uv1; + _previewManager->GetNormalizedUVs(type, id, uv0, uv1); + result.push_back({ id, uv0, uv1 }); + } + + return result; + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/PreviewApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/PreviewApiImpl.h new file mode 100644 index 00000000..e632c8de --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/PreviewApiImpl.h @@ -0,0 +1,27 @@ +#pragma once +#include "EditorCore/Api/IPreviewApi.h" +#include "Engine/Manager/PreviewManager.h" +#include "Editor/Manager/GuiTextureManager.h" +#include "Engine/Image/ImageManager.h" + +namespace Syn { + + class PreviewApiImpl : public IPreviewApi { + public: + PreviewApiImpl(PreviewManager* previewManager, GuiTextureManager* guiTextureManager, ImageManager* imageManager); + ~PreviewApiImpl() override = default; + + TextureHandle GetAtlasHandle() override; + bool GetPreviewUVs(PreviewResourceType type, uint32_t resourceId, glm::vec2& outUv0, glm::vec2& outUv1) const override; + bool HasPreview(PreviewResourceType type, uint32_t resourceId) const override; + void RequestPreview(PreviewResourceType type, uint32_t resourceId) override; + std::vector GetAllPreviews(PreviewResourceType type) const override; + private: + PreviewManager* _previewManager; + GuiTextureManager* _guiTextureManager; + ImageManager* _imageManager; + + uint32_t _lastAtlasResolution = 0; + TextureHandle _atlasTextureHandle; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/RenderApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/RenderApiImpl.cpp index 968ebeab..7a34b57c 100644 --- a/SynapseEngine/Editor/EditorApi/Impl/RenderApiImpl.cpp +++ b/SynapseEngine/Editor/EditorApi/Impl/RenderApiImpl.cpp @@ -7,6 +7,7 @@ #include "Engine/Component/Core/CameraComponent.h" #include "Engine/Vk/Image/ImageUtils.h" #include "Engine/Vk/Rendering/GpuUploader.h" +#include "Engine/Manager/PreviewManager.h" #include namespace Syn { @@ -46,6 +47,15 @@ namespace Syn { ); _viewportTextures[cacheKey] = handle; } + else if (targetName == RenderTargetNames::PreviewAtlas) { + auto imageView = ServiceLocator::GetPreviewManager()->GetAtlasImage()->GetView(viewName); + auto sampler = ServiceLocator::GetImageManager()->GetSampler(SamplerNames::LinearClampEdge); + TextureHandle handle = _textureManager->RegisterTexture( + imageView, + sampler->Handle() + ); + _viewportTextures[cacheKey] = handle; + } else { auto rtManager = renderManager->GetRenderTargetManager(); auto group = rtManager->GetGroup(groupName, currentFrame); @@ -62,6 +72,7 @@ namespace Syn { _viewportTextures[cacheKey] = handle; } } + return _textureManager->GetImGuiTextureID(_viewportTextures[cacheKey]); } @@ -94,22 +105,23 @@ namespace Syn { return EditorApiUtils::ReadComponent(_sceneManager, cameraEntity, [](const auto& c) { return c.proj; }, glm::mat4(1.0f)); } - EntityID RenderApiImpl::ReadEntityIdAtPixel(uint32_t x, uint32_t y) { + + std::pair RenderApiImpl::ReadEntityAndMeshIdAtPixel(uint32_t x, uint32_t y) { auto renderManager = _engine->GetRenderManager(); - if (!renderManager) return NULL_ENTITY; + if (!renderManager) return { NULL_ENTITY, 0 }; auto rtManager = renderManager->GetRenderTargetManager(); auto frameCtx = ServiceLocator::GetFrameContext(); uint32_t currentFrame = frameCtx ? frameCtx->currentFrameIndex : 0; - auto group = rtManager->GetGroup(RenderTargetGroupNames::Deferred, currentFrame); - if (!group) return NULL_ENTITY; + auto group = rtManager->GetGroup(RenderTargetGroupNames::Main, currentFrame); + if (!group) return { NULL_ENTITY, 0 }; auto entityImage = group->GetImage(RenderTargetNames::EntityIndex); - if (!entityImage) return NULL_ENTITY; + if (!entityImage) return { NULL_ENTITY, 0 }; auto extent = entityImage->GetExtent(); - if (x >= extent.width || y >= extent.height) return NULL_ENTITY; + if (x >= extent.width || y >= extent.height) return { NULL_ENTITY, 0 }; Vk::BufferConfig readbackConfig{}; readbackConfig.size = sizeof(uint32_t) * 2; @@ -143,15 +155,24 @@ namespace Syn { ServiceLocator::GetGpuUploader()->UploadSync(std::move(request)); EntityID selectedEntity = NULL_ENTITY; + uint32_t selectedMesh = 0; + void* mappedData = readbackBuffer->Map(); if (mappedData) { uint32_t pixelData[2] = { 0, 0 }; std::memcpy(pixelData, mappedData, sizeof(uint32_t) * 2); readbackBuffer->Unmap(); - uint32_t packedEntity = pixelData[0]; - selectedEntity = packedEntity & ~(1u << 31); + uint32_t word0 = pixelData[0]; + selectedEntity = word0 & ~(1u << 31); + + uint32_t word1 = pixelData[1]; + selectedMesh = (word1 >> 22) & 0x3FFu; } - return selectedEntity; + return { selectedEntity, selectedMesh }; + } + + EntityID RenderApiImpl::ReadEntityIdAtPixel(uint32_t x, uint32_t y) { + return ReadEntityAndMeshIdAtPixel(x, y).first; } } \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/RenderApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/RenderApiImpl.h index ded10a4d..aaf13e4e 100644 --- a/SynapseEngine/Editor/EditorApi/Impl/RenderApiImpl.h +++ b/SynapseEngine/Editor/EditorApi/Impl/RenderApiImpl.h @@ -14,6 +14,7 @@ namespace Syn { void ResizeRenderTargets(uint32_t width, uint32_t height) override; TextureHandle GetViewportTexture(const std::string& groupName, const std::string& targetName, const std::string& viewName) override; EntityID ReadEntityIdAtPixel(uint32_t x, uint32_t y) override; + std::pair ReadEntityAndMeshIdAtPixel(uint32_t x, uint32_t y) override; glm::mat4 GetEditorCameraView() const override; glm::mat4 GetEditorCameraProjection() const override; private: diff --git a/SynapseEngine/Editor/EditorApi/Impl/RigidBodyApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/RigidBodyApiImpl.cpp new file mode 100644 index 00000000..4b28df2c --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/RigidBodyApiImpl.cpp @@ -0,0 +1,50 @@ +#include "RigidBodyApiImpl.h" +#include "../EditorApiUtils.h" +#include "Engine/Component/Physics/RigidBodyComponent.h" + +namespace Syn { + + bool RigidBodyApiImpl::HasRigidBody(EntityID entity) const { + return EditorApiUtils::HasComponent(_sceneManager, entity); + } + + PhysicsMotionType RigidBodyApiImpl::GetRigidBodyMotionType(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.motionType; }, PhysicsMotionType::Dynamic); + } + + float RigidBodyApiImpl::GetRigidBodyMass(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.mass; }, 1.0f); + } + + float RigidBodyApiImpl::GetRigidBodyFriction(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.friction; }, 0.2f); + } + + float RigidBodyApiImpl::GetRigidBodyRestitution(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.restitution; }, 0.0f); + } + + uint32_t RigidBodyApiImpl::GetRigidBodyLayer(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.layer; }, 1u); + } + + void RigidBodyApiImpl::SetRigidBodyMotionType(EntityID entity, PhysicsMotionType motionType) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.motionType = motionType; }); + } + + void RigidBodyApiImpl::SetRigidBodyMass(EntityID entity, float mass) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.mass = mass; }); + } + + void RigidBodyApiImpl::SetRigidBodyFriction(EntityID entity, float friction) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.friction = friction; }); + } + + void RigidBodyApiImpl::SetRigidBodyRestitution(EntityID entity, float restitution) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.restitution = restitution; }); + } + + void RigidBodyApiImpl::SetRigidBodyLayer(EntityID entity, uint32_t layer) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.layer = layer; }); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/RigidBodyApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/RigidBodyApiImpl.h new file mode 100644 index 00000000..b85ffe1f --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/RigidBodyApiImpl.h @@ -0,0 +1,27 @@ +#pragma once +#include "EditorCore/Api/IRigidBodyApi.h" +#include "Engine/Scene/SceneManager.h" + +namespace Syn { + class RigidBodyApiImpl : public IRigidBodyApi { + public: + RigidBodyApiImpl(SceneManager* sm) : _sceneManager(sm) {} + + bool HasRigidBody(EntityID entity) const override; + + PhysicsMotionType GetRigidBodyMotionType(EntityID entity) const override; + float GetRigidBodyMass(EntityID entity) const override; + float GetRigidBodyFriction(EntityID entity) const override; + float GetRigidBodyRestitution(EntityID entity) const override; + uint32_t GetRigidBodyLayer(EntityID entity) const override; + + void SetRigidBodyMotionType(EntityID entity, PhysicsMotionType motionType) override; + void SetRigidBodyMass(EntityID entity, float mass) override; + void SetRigidBodyFriction(EntityID entity, float friction) override; + void SetRigidBodyRestitution(EntityID entity, float restitution) override; + void SetRigidBodyLayer(EntityID entity, uint32_t layer) override; + + private: + SceneManager* _sceneManager; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/SceneApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/SceneApiImpl.cpp index 74714d1c..c2510392 100644 --- a/SynapseEngine/Editor/EditorApi/Impl/SceneApiImpl.cpp +++ b/SynapseEngine/Editor/EditorApi/Impl/SceneApiImpl.cpp @@ -27,4 +27,11 @@ namespace Syn { _sceneManager->SaveActiveScene(savePath.string()); Syn::Info("SceneApiImpl: Scene saved to {}", savePath.string()); } + + void SceneApiImpl::ActivateScene(const std::string& sceneName) { + if (_sceneManager) { + _sceneManager->LoadScene(sceneName); + Syn::Info("SceneApiImpl: Activated registered scene: {}", sceneName); + } + } } \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/SceneApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/SceneApiImpl.h index 4b0a5c61..ee4209dc 100644 --- a/SynapseEngine/Editor/EditorApi/Impl/SceneApiImpl.h +++ b/SynapseEngine/Editor/EditorApi/Impl/SceneApiImpl.h @@ -9,6 +9,7 @@ namespace Syn { void NewScene() override; void LoadScene(const std::string& filepath = "") override; void SaveScene(const std::string& filepath = "") override; + void ActivateScene(const std::string& sceneName) override; private: SceneManager* _sceneManager; }; diff --git a/SynapseEngine/Editor/EditorApi/Impl/SettingsApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/SettingsApiImpl.cpp index 158ff68e..22d07d48 100644 --- a/SynapseEngine/Editor/EditorApi/Impl/SettingsApiImpl.cpp +++ b/SynapseEngine/Editor/EditorApi/Impl/SettingsApiImpl.cpp @@ -1,5 +1,6 @@ #include "SettingsApiImpl.h" #include "Engine/Scene/Scene.h" +#include "Engine/Image/ImageManager.h" namespace Syn { SceneSettings SettingsApiImpl::GetSceneSettings() const { @@ -13,4 +14,21 @@ namespace Syn { *(scene->GetSettings()) = settings; } } + + std::vector> SettingsApiImpl::GetAvailableSkyTextures() const { + std::vector> result; + + auto imageManager = ServiceLocator::GetImageManager(); + if (!imageManager) return result; + + auto paths = imageManager->GetResourcePaths(); + for (uint32_t i = 0; i < paths.size(); ++i) { + if (imageManager->GetEntryState(i) == ResourceState::Ready) { + std::filesystem::path p(paths[i]); + result.push_back({ i, p.filename().string() }); + } + } + + return result; + } } \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/SettingsApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/SettingsApiImpl.h index abb500e9..3eb8b66e 100644 --- a/SynapseEngine/Editor/EditorApi/Impl/SettingsApiImpl.h +++ b/SynapseEngine/Editor/EditorApi/Impl/SettingsApiImpl.h @@ -8,6 +8,7 @@ namespace Syn { SettingsApiImpl(SceneManager* sm) : _sceneManager(sm) {} SceneSettings GetSceneSettings() const override; void SetSceneSettings(const SceneSettings& settings) override; + std::vector> GetAvailableSkyTextures() const override; private: SceneManager* _sceneManager; }; diff --git a/SynapseEngine/Editor/EditorApi/Impl/SphereColliderApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/SphereColliderApiImpl.cpp new file mode 100644 index 00000000..fd3676e7 --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/SphereColliderApiImpl.cpp @@ -0,0 +1,26 @@ +#include "SphereColliderApiImpl.h" +#include "../EditorApiUtils.h" +#include "Engine/Component/Physics/SphereColliderComponent.h" + +namespace Syn { + + bool SphereColliderApiImpl::HasSphereCollider(EntityID entity) const { + return EditorApiUtils::HasComponent(_sceneManager, entity); + } + + float SphereColliderApiImpl::GetSphereColliderRadius(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.radius; }, 0.5f); + } + + glm::vec3 SphereColliderApiImpl::GetSphereColliderLocalOffset(EntityID entity) const { + return EditorApiUtils::ReadComponent(_sceneManager, entity, [](const auto& c) { return c.localOffset; }, glm::vec3(0.0f)); + } + + void SphereColliderApiImpl::SetSphereColliderRadius(EntityID entity, float radius) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.radius = radius; }); + } + + void SphereColliderApiImpl::SetSphereColliderLocalOffset(EntityID entity, const glm::vec3& localOffset) { + EditorApiUtils::ModifyComponent(_sceneManager, entity, [&](auto& c, auto pool) { c.localOffset = localOffset; }); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/SphereColliderApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/SphereColliderApiImpl.h new file mode 100644 index 00000000..8ecd5add --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/SphereColliderApiImpl.h @@ -0,0 +1,21 @@ +#pragma once +#include "EditorCore/Api/ISphereColliderApi.h" +#include "Engine/Scene/SceneManager.h" + +namespace Syn { + class SphereColliderApiImpl : public ISphereColliderApi { + public: + SphereColliderApiImpl(SceneManager* sm) : _sceneManager(sm) {} + + bool HasSphereCollider(EntityID entity) const override; + + float GetSphereColliderRadius(EntityID entity) const override; + glm::vec3 GetSphereColliderLocalOffset(EntityID entity) const override; + + void SetSphereColliderRadius(EntityID entity, float radius) override; + void SetSphereColliderLocalOffset(EntityID entity, const glm::vec3& localOffset) override; + + private: + SceneManager* _sceneManager; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/TagApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/TagApiImpl.cpp index 6a926998..d0d79add 100644 --- a/SynapseEngine/Editor/EditorApi/Impl/TagApiImpl.cpp +++ b/SynapseEngine/Editor/EditorApi/Impl/TagApiImpl.cpp @@ -25,11 +25,11 @@ namespace Syn { bool TagApiImpl::IsEntityEnabled(EntityID entity) const { return EditorApiUtils::ReadComponent(_sceneManager, entity, - [](const auto& c) { return c.enabled; }, true); + [](const auto& c) { return c.localEnabled; }, true); } void TagApiImpl::SetEntityEnabled(EntityID entity, bool enabled) { EditorApiUtils::ModifyComponent(_sceneManager, entity, - [&](auto& c, auto pool) { c.enabled = enabled; }); + [&](auto& c, auto pool) { c.localEnabled = enabled; }); } } \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/TextureApiImpl.cpp b/SynapseEngine/Editor/EditorApi/Impl/TextureApiImpl.cpp new file mode 100644 index 00000000..f7636d84 --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/TextureApiImpl.cpp @@ -0,0 +1,93 @@ +#include "TextureApiImpl.h" +#include "Engine/Image/SamplerNames.h" +#include + +namespace Syn { + + std::vector TextureApiImpl::GetAllTextures() { + if (!_imageManager) return {}; + + std::vector result; + auto paths = _imageManager->GetResourcePaths(); + + for (uint32_t i = 0; i < paths.size(); ++i) { + if (_imageManager->GetEntryState(i) == ResourceState::Ready) { + TextureItemData data; + data.id = i; + data.path = paths[i]; + + std::filesystem::path p(paths[i]); + data.name = p.filename().string(); + data.handle = GetTextureHandle(i); + + result.push_back(data); + } + } + + return result; + } + + std::vector TextureApiImpl::GetAllSamplers() const { + if (!_imageManager) return {}; + + std::vector result; + const auto& samplers = _imageManager->GetAvailableSamplers(); + + for (const auto& [name, id] : samplers) { + result.push_back({ id, name }); + } + + std::sort(result.begin(), result.end(), [](const SamplerItemData& a, const SamplerItemData& b) { + return a.id < b.id; + }); + + return result; + } + + uint32_t TextureApiImpl::GetSelectedTexture() const { + return _selectedTexture; + } + + void TextureApiImpl::SetSelectedTexture(uint32_t id) { + _selectedTexture = id; + } + + bool TextureApiImpl::GetTextureData(uint32_t id, CpuTextureData& outData) const { + if (!_imageManager || id == INVALID_TEXTURE_ID) return false; + + auto resource = _imageManager->GetResource(id); + if (resource) { + outData = resource->cpuData; + return true; + } + + return false; + } + + uint64_t TextureApiImpl::GetVersion() const { + return _imageManager ? _imageManager->GetVersion() : 0; + } + + TextureHandle TextureApiImpl::GetTextureHandle(uint32_t id) { + if (!_imageManager || id == INVALID_TEXTURE_ID) { + return InvalidTextureHandle; + } + + if (_textureHandleCache.find(id) == _textureHandleCache.end()) { + auto resource = _imageManager->GetResource(id); + if (!resource || !resource->image) { + return InvalidTextureHandle; + } + + auto sampler = _imageManager->GetSampler(SamplerNames::LinearClampEdge); + TextureHandle handle = _guiTextureManager->RegisterTexture( + resource->image->GetView(), + sampler->Handle() + ); + + _textureHandleCache[id] = handle; + } + + return _guiTextureManager->GetImGuiTextureID(_textureHandleCache[id]); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/EditorApi/Impl/TextureApiImpl.h b/SynapseEngine/Editor/EditorApi/Impl/TextureApiImpl.h new file mode 100644 index 00000000..f591187f --- /dev/null +++ b/SynapseEngine/Editor/EditorApi/Impl/TextureApiImpl.h @@ -0,0 +1,27 @@ +#pragma once +#include "EditorCore/Api/ITextureApi.h" +#include "Engine/Image/ImageManager.h" +#include "Editor/Manager/GuiTextureManager.h" + +namespace Syn { + class TextureApiImpl : public ITextureApi { + public: + TextureApiImpl(ImageManager* imageManager, GuiTextureManager* guiTextureManager) + : _imageManager(imageManager), _guiTextureManager(guiTextureManager) {} + + std::vector GetAllTextures() override; + std::vector GetAllSamplers() const override; + + uint32_t GetSelectedTexture() const override; + void SetSelectedTexture(uint32_t id) override; + + bool GetTextureData(uint32_t id, CpuTextureData& outData) const override; + uint64_t GetVersion() const override; + TextureHandle GetTextureHandle(uint32_t id) override; + private: + ImageManager* _imageManager; + GuiTextureManager* _guiTextureManager; + uint32_t _selectedTexture = INVALID_TEXTURE_ID; + std::unordered_map _textureHandleCache; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Manager/EditorIcons.h b/SynapseEngine/Editor/Manager/EditorIcons.h index 6f16a235..b409c6a1 100644 --- a/SynapseEngine/Editor/Manager/EditorIcons.h +++ b/SynapseEngine/Editor/Manager/EditorIcons.h @@ -28,6 +28,7 @@ constexpr const char* ASSET_PATH = "Assets"; #define SYN_ICON_CUBES ICON_FA_CUBES #define SYN_ICON_VIDEO ICON_FA_VIDEO #define SYN_ICON_TRASH ICON_FA_TRASH +#define SYN_ICON_COPY ICON_FA_COPY #define SYN_ICON_EXPAND_ALL ICON_FA_ANGLE_DOUBLE_DOWN #define SYN_ICON_COLLAPSE_ALL ICON_FA_ANGLE_DOUBLE_UP @@ -56,15 +57,31 @@ constexpr const char* ASSET_PATH = "Assets"; #define SYN_ICON_RUNNING ICON_FA_RUNNING #define SYN_ICON_SPOTLIGHT ICON_FA_BULLHORN #define SYN_ICON_FILTER ICON_FA_FILTER +#define SYN_ICON_CAMERA ICON_FA_CAMERA #define SYN_ICON_INFO_CIRCLE ICON_FA_INFO_CIRCLE #define SYN_ICON_TAG ICON_FA_TAG #define SYN_ICON_TERMINAL ICON_FA_TERMINAL #define SYN_ICON_LEVEL_DOWN_ALT ICON_FA_LEVEL_DOWN_ALT #define SYN_ICON_DRAW_POLYGON ICON_FA_DRAW_POLYGON - +#define SYN_ICON_SYNC ICON_FA_SYNC +#define SYN_ICON_PROJECT_DIAGRAM ICON_FA_PROJECT_DIAGRAM +#define SYN_ICON_BRUSH ICON_FA_BRUSH // Workspace Labels #define SYN_WS_SCENE SYN_ICON_GLOBE " Scene" #define SYN_WS_MODEL SYN_ICON_DRAW_POLYGON " Model" #define SYN_WS_MATERIAL SYN_ICON_MAGIC " Material" -#define SYN_WS_TEXTURE SYN_ICON_IMAGE " Texture" \ No newline at end of file +#define SYN_WS_TEXTURE SYN_ICON_IMAGE " Texture" + +#define SYN_ICON_MODEL ICON_FA_SHAPES +#define SYN_ICON_ANIMATION ICON_FA_RUNNING +#define SYN_ICON_BOX_COLLIDER ICON_FA_BOX +#define SYN_ICON_CAPSULE_COLLIDER ICON_FA_CAPSULES +#define SYN_ICON_CONVEX_COLLIDER ICON_FA_GEM +#define SYN_ICON_SPHERE_COLLIDER ICON_FA_CIRCLE +#define SYN_ICON_MESH_COLLIDER ICON_FA_DRAW_POLYGON +#define SYN_ICON_RIGID_BODY ICON_FA_WEIGHT_HANGING + +#define SYN_ICON_TH ICON_FA_TH +#define SYN_ICON_TH_LARGE ICON_FA_TH_LARGE +#define SYN_ICON_BORDER_ALL ICON_FA_BORDER_ALL \ No newline at end of file diff --git a/SynapseEngine/Editor/Manager/GuiManager.cpp b/SynapseEngine/Editor/Manager/GuiManager.cpp index 6ebf5759..b6f2a198 100644 --- a/SynapseEngine/Editor/Manager/GuiManager.cpp +++ b/SynapseEngine/Editor/Manager/GuiManager.cpp @@ -1,9 +1,9 @@ #include "GuiManager.h" #include #include - #include #include +#include #include "GuiTextureManager.h" #include #include "Engine/ServiceLocator.h" @@ -31,11 +31,25 @@ namespace Syn { ImGui_ImplGlfw_InitForVulkan(window, false); - VkDescriptorPoolSize poolSizes[] = { { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 } }; + VkDescriptorPoolSize poolSizes[] = + { + { VK_DESCRIPTOR_TYPE_SAMPLER, 1000 }, + { VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1000 }, + { VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_IMAGE, 1000 }, + { VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1000 }, + { VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1000 }, + { VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC, 1000 }, + { VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 1000 } + }; + VkDescriptorPoolCreateInfo poolInfo = { .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; poolInfo.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT; - poolInfo.maxSets = 1000; - poolInfo.poolSizeCount = 1; + poolInfo.maxSets = 1000 * IM_ARRAYSIZE(poolSizes); + poolInfo.poolSizeCount = (uint32_t)IM_ARRAYSIZE(poolSizes); poolInfo.pPoolSizes = poolSizes; vkCreateDescriptorPool(device, &poolInfo, nullptr, &_imguiPool); @@ -48,11 +62,11 @@ namespace Syn { init_info.DescriptorPool = _imguiPool; init_info.MinImageCount = imageCount; init_info.ImageCount = imageCount; - init_info.MSAASamples = VK_SAMPLE_COUNT_1_BIT; init_info.UseDynamicRendering = true; - init_info.PipelineRenderingCreateInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO }; - init_info.PipelineRenderingCreateInfo.colorAttachmentCount = 1; - init_info.PipelineRenderingCreateInfo.pColorAttachmentFormats = &_colorFormat; + init_info.PipelineInfoMain.MSAASamples = VK_SAMPLE_COUNT_1_BIT; + init_info.PipelineInfoMain.PipelineRenderingCreateInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO }; + init_info.PipelineInfoMain.PipelineRenderingCreateInfo.colorAttachmentCount = 1; + init_info.PipelineInfoMain.PipelineRenderingCreateInfo.pColorAttachmentFormats = &_colorFormat; ImGui_ImplVulkan_LoadFunctions(VK_API_VERSION_1_4, [](const char* function_name, void* user_data) { return vkGetInstanceProcAddr(reinterpret_cast(user_data), function_name); @@ -90,6 +104,7 @@ namespace Syn { ImGui_ImplVulkan_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); + ImGuizmo::BeginFrame(); } void GuiManager::UpdateAndDraw() { @@ -128,7 +143,18 @@ namespace Syn { } if (ImGui::Button(label)) { - _currentWorkspace = ws; + if (_currentWorkspace != ws) + { + if (_workspaces.contains(_currentWorkspace)) { + _workspaces[_currentWorkspace]->OnDeactivate(); + } + + _currentWorkspace = ws; + + if (_workspaces.contains(_currentWorkspace)) { + _workspaces[_currentWorkspace]->OnActivate(); + } + } } ImGui::PopStyleColor(2); @@ -303,8 +329,4 @@ namespace Syn { colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f); colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f); } - - void GuiManager::CreateFontTexture() { - ImGui_ImplVulkan_CreateFontsTexture(); - } } \ No newline at end of file diff --git a/SynapseEngine/Editor/Manager/GuiManager.h b/SynapseEngine/Editor/Manager/GuiManager.h index 202a8a7e..d0dc2c26 100644 --- a/SynapseEngine/Editor/Manager/GuiManager.h +++ b/SynapseEngine/Editor/Manager/GuiManager.h @@ -4,7 +4,7 @@ #include #include "GuiTextureManager.h" #include "EditorCore/Api/IFileDialogApi.h" -#include "Editor/View/IGuiWindow.h" +#include "Editor/Workspace/IGuiWindow.h" #include "Editor/Workspace/IWorkspace.h" #include @@ -35,7 +35,6 @@ namespace Syn { GuiTextureManager* GetTextureManager() const { return _textureManager.get(); } IFileDialogApi* GetFileDialog() const { return _fileDialog.get(); } - void CreateFontTexture(); void SetWorkspace(EditorWorkspace workspace) { _currentWorkspace = workspace; } EditorWorkspace GetWorkspace() const { return _currentWorkspace; } diff --git a/SynapseEngine/Editor/Synapse.cpp b/SynapseEngine/Editor/Synapse.cpp index cfba5c59..13b569e8 100644 --- a/SynapseEngine/Editor/Synapse.cpp +++ b/SynapseEngine/Editor/Synapse.cpp @@ -4,18 +4,21 @@ #include #include -#include "Editor/Workspace/SceneWorkspace.h" -#include "Editor/Workspace/ModelWorkspace.h" -#include "Editor/Workspace/MaterialWorkspace.h" -#include "Editor/Workspace/TextureWorkspace.h" +#include "Editor/Workspace/SceneWorkspace/SceneWorkspace.h" +#include "Editor/Workspace/ModelWorkspace/ModelWorkspace.h" +#include "Editor/Workspace/MaterialWorkspace/MaterialWorkspace.h" +#include "Editor/Workspace/TextureWorkspace/TextureWorkspace.h" -#include "Editor/View/MainMenu/MainMenuView.h" -#include "EditorCore/ViewModels/MainMenu/MainMenuViewModel.h" +#include "Editor/Workspace/Common/MainMenu/MainMenuView.h" +#include "EditorCore/ViewModels/Common/MainMenu/MainMenuViewModel.h" #include "Manager/GuiTextureManager.h" #include "Manager/EditorIcons.h" #include "Engine/Utils/PathUtils.h" -#include "Editor/View/IGuiWindow.h" +#include "Editor/Workspace/IGuiWindow.h" + +#include "Engine/Image/Loader/SvgImageLoader.h" +#include "Engine/Logger/SynLog.h" Synapse::Synapse(const Syn::ApplicationConfig& config) : Syn::Application(config) @@ -64,6 +67,16 @@ void Synapse::OnInit() { _engine = std::make_unique(params); + std::string iconPath = Syn::PathUtils::GetAbsolutePathString(std::string(ASSET_PATH) + "/dark_icon.svg"); + Syn::SvgImageLoader svgLoader; + if (auto rawImageOpt = svgLoader.LoadFile(iconPath)) { + const auto& rawImage = rawImageOpt.value(); + GetWindow().SetIcon(rawImage.width, rawImage.height, rawImage.pixels.data()); + } + else { + Syn::Error("Failed to load window icon from: {}", iconPath); + } + #ifndef SYN_PERFORMANCE auto vkContext = _engine->GetVkContext(); @@ -89,9 +102,11 @@ void Synapse::OnInit() { ); ImGuiIO& io = ImGui::GetIO(); - io.Fonts->AddFontDefault(); + ImFontConfig defaultConfig; + defaultConfig.SizePixels = 13.0f; + io.Fonts->AddFontDefault(&defaultConfig); + _iconManager->InitializeFontAwesome(io, Syn::PathUtils::GetAbsolutePathString(FONT_PATH), 16.0f); - _guiManager->CreateFontTexture(); _iconManager->LoadEngineIcons(Syn::PathUtils::GetAbsolutePathString(ICON_PATH)); std::string absoluteAssetsPath = std::filesystem::absolute(ASSET_PATH).generic_string(); @@ -99,7 +114,7 @@ void Synapse::OnInit() { using MainMenuWin = Syn::EditorWindow; _guiManager->AddGlobalWindow( Syn::MainMenuView{}, - Syn::MainMenuViewModel{ _editorContext->GetSceneApi(), _guiManager->GetFileDialog() } + Syn::MainMenuViewModel{ _editorContext->GetApi(), _guiManager->GetFileDialog() } ); _guiManager->AddWorkspace(Syn::EditorWorkspace::Scene, std::make_unique( diff --git a/SynapseEngine/Editor/View/Component/ComponentView.h b/SynapseEngine/Editor/View/Component/ComponentView.h deleted file mode 100644 index bff5e463..00000000 --- a/SynapseEngine/Editor/View/Component/ComponentView.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include "Editor/View/IView.h" -#include "EditorCore/ViewModels/Component/ComponentViewModel.h" -#include -#include - -#include "Core/TagView.h" -#include "Core/TransformView.h" -#include "Light/DirectionLightView.h" -#include "Light/PointLightView.h" -#include "Light/SpotLightView.h" - -namespace Syn { - class ComponentView : public IView { - public: - void Draw(ComponentViewModel& vm) override; - private: - TagView _tagView; - TransformView _transformView; - DirectionLightView _directionLightView; - PointLightView _pointLightView; - SpotLightView _spotLightView; - }; -} \ No newline at end of file diff --git a/SynapseEngine/Editor/View/MainMenu/MainMenuView.cpp b/SynapseEngine/Editor/View/MainMenu/MainMenuView.cpp deleted file mode 100644 index f9efde2a..00000000 --- a/SynapseEngine/Editor/View/MainMenu/MainMenuView.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "MainMenuView.h" diff --git a/SynapseEngine/Editor/View/MainMenu/MainMenuView.h b/SynapseEngine/Editor/View/MainMenu/MainMenuView.h deleted file mode 100644 index 77e9a761..00000000 --- a/SynapseEngine/Editor/View/MainMenu/MainMenuView.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include "../IView.h" -#include "EditorCore/ViewModels/MainMenu/MainMenuViewModel.h" -#include - -namespace Syn { - class MainMenuView : public IView { - public: - void Draw(MainMenuViewModel& vm) override { - - if (ImGui::BeginMainMenuBar()) { - - if (ImGui::BeginMenu("File")) { - - if (ImGui::MenuItem("New Scene", "Ctrl+N")) { - vm.Dispatch(NewSceneIntent{}); - } - - if (ImGui::MenuItem("Load Scene...", "Ctrl+O")) { - vm.Dispatch(LoadSceneIntent{}); - } - - if (ImGui::MenuItem("Save Scene", "Ctrl+S")) { - vm.Dispatch(SaveSceneIntent{}); - } - - ImGui::EndMenu(); - } - - ImGui::EndMainMenuBar(); - } - } - }; -} \ No newline at end of file diff --git a/SynapseEngine/Editor/View/MaterialGraph/MaterialGraphView.cpp b/SynapseEngine/Editor/View/MaterialGraph/MaterialGraphView.cpp deleted file mode 100644 index 00c87ca5..00000000 --- a/SynapseEngine/Editor/View/MaterialGraph/MaterialGraphView.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "MaterialGraphView.h" -#include -#include - -namespace ed = ax::NodeEditor; - -namespace Syn { - - MaterialGraphView::MaterialGraphView() { - ed::Config config; - config.SettingsFile = nullptr; - config.SettingsFile = "Synapse_MaterialGraph.json"; - _context = ed::CreateEditor(&config); - } - - MaterialGraphView::~MaterialGraphView() { - if (_context) { - ed::DestroyEditor(_context); - } - } - - MaterialGraphView::MaterialGraphView(MaterialGraphView&& other) noexcept - : _context(other._context) - { - other._context = nullptr; - } - - MaterialGraphView& MaterialGraphView::operator=(MaterialGraphView&& other) noexcept { - if (this != &other) { - if (_context) { - ed::DestroyEditor(_context); - } - - _context = other._context; - other._context = nullptr; - } - return *this; - } - - void MaterialGraphView::Draw(MaterialGraphViewModel& vm) { - const auto& state = vm.GetState(); - - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); - - ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; - bool isVisible = ImGui::Begin("Material Graph", nullptr, windowFlags); - - ImGui::PopStyleVar(); - - if (isVisible) { - ImVec2 startPos = ImGui::GetCursorStartPos(); - ImGui::SetCursorPos(startPos); - - ed::SetCurrentEditor(_context); - - ImVec2 canvasSize = ImGui::GetContentRegionAvail(); - if (canvasSize.x <= 0.0f) canvasSize.x = 1.0f; - if (canvasSize.y <= 0.0f) canvasSize.y = 1.0f; - - ed::Begin("Material Editor Canvas", canvasSize); - - for (const auto& node : state.nodes) { - ed::BeginNode(ed::NodeId(node.id)); - - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.2f, 1.0f)); - ImGui::TextUnformatted(node.name.c_str()); - ImGui::PopStyleColor(); - - if (node.type == GraphNodeType::Material) { - for (const auto& pin : node.pins) { - ed::BeginPin(ed::PinId(pin.id), ed::PinKind::Input); - ImGui::Text("-> %s", GetPinName(pin.type)); - ed::EndPin(); - } - } - else if (node.type == GraphNodeType::Texture) { - for (const auto& pin : node.pins) { - ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 20.0f); - ed::BeginPin(ed::PinId(pin.id), ed::PinKind::Output); - ImGui::Text("RGB ->"); - ed::EndPin(); - } - } - - ed::EndNode(); - } - - for (const auto& link : state.links) { - ed::Link(ed::LinkId(link.id), ed::PinId(link.startPinId), ed::PinId(link.endPinId)); - } - - if (ed::BeginCreate()) { - ed::PinId inputPinId, outputPinId; - if (ed::QueryNewLink(&inputPinId, &outputPinId)) { - if (inputPinId && outputPinId) { - if (ed::AcceptNewItem(ImVec4(0.2f, 1.0f, 0.2f, 1.0f), 2.0f)) { - GraphID startId = static_cast(inputPinId.Get()); - GraphID endId = static_cast(outputPinId.Get()); - - vm.Dispatch(CreateLinkIntent{ startId, endId }); - } - } - } - } - ed::EndCreate(); - - if (ed::BeginDelete()) { - ed::LinkId deletedLinkId; - while (ed::QueryDeletedLink(&deletedLinkId)) { - if (ed::AcceptDeletedItem()) { - vm.Dispatch(DeleteLinkIntent{ static_cast(deletedLinkId.Get()) }); - } - } - } - ed::EndDelete(); - - ed::End(); - ed::SetCurrentEditor(nullptr); - } - - ImGui::End(); - } - - const char* MaterialGraphView::GetPinName(GraphPinType type) { - switch (type) { - case GraphPinType::Albedo: return "Albedo"; - case GraphPinType::Normal: return "Normal"; - case GraphPinType::Metalness: return "Metalness"; - case GraphPinType::Roughness: return "Roughness"; - case GraphPinType::MetallicRoughness: return "MetallicRoughness"; - case GraphPinType::Emissive: return "Emissive"; - case GraphPinType::AmbientOcclusion: return "Ambient Occlusion"; - default: return "Unknown"; - } - } -} \ No newline at end of file diff --git a/SynapseEngine/Editor/Widgets/CardWidget.cpp b/SynapseEngine/Editor/Widgets/CardWidget.cpp index 0e4a8a57..b417e7c0 100644 --- a/SynapseEngine/Editor/Widgets/CardWidget.cpp +++ b/SynapseEngine/Editor/Widgets/CardWidget.cpp @@ -9,7 +9,7 @@ namespace Syn::UI { ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 6.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(12.0f, 12.0f)); - ImGuiChildFlags childFlags = ImGuiChildFlags_Borders; + ImGuiChildFlags childFlags = ImGuiChildFlags_Borders | ImGuiChildFlags_AlwaysUseWindowPadding; if (isOpen) { childFlags |= ImGuiChildFlags_AutoResizeY; @@ -20,7 +20,7 @@ namespace Syn::UI { float height = isOpen ? 0.0f : closedHeight; std::string childId = std::string("##Card_") + label; - ImGui::BeginChild(childId.c_str(), ImVec2(0, height), childFlags, ImGuiWindowFlags_AlwaysUseWindowPadding | ImGuiWindowFlags_NoScrollbar); + ImGui::BeginChild(childId.c_str(), ImVec2(0, height), childFlags, ImGuiWindowFlags_NoScrollbar); ImVec2 startPos = ImGui::GetCursorPos(); float availX = ImGui::GetContentRegionAvail().x; diff --git a/SynapseEngine/Editor/Widgets/ItemCardContainerWidget.cpp b/SynapseEngine/Editor/Widgets/ItemCardContainerWidget.cpp new file mode 100644 index 00000000..7b41fe69 --- /dev/null +++ b/SynapseEngine/Editor/Widgets/ItemCardContainerWidget.cpp @@ -0,0 +1,46 @@ +#include "ItemCardContainerWidget.h" +#include "ItemCardWidget.h" +#include +#include + +namespace Syn::UI { + + void ItemCardContainer(const char* strId, + int itemCount, + float thumbnailSize, + const std::function& drawItem, + float spacing) + { + if (itemCount <= 0 || !drawItem) return; + + ImGui::PushID(strId); + + const float cardW = ItemCardWidth(thumbnailSize); + const float cardH = ItemCardHeight(thumbnailSize); + const float avail = ImGui::GetContentRegionAvail().x; + + int columns = static_cast((avail + spacing) / (cardW + spacing)); + columns = std::max(1, columns); + + const int rows = (itemCount + columns - 1) / columns; + + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(spacing, spacing)); + + ImGuiListClipper clipper; + clipper.Begin(rows, cardH + spacing); + while (clipper.Step()) { + for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; ++row) { + for (int col = 0; col < columns; ++col) { + const int index = row * columns + col; + if (index >= itemCount) break; + if (col > 0) ImGui::SameLine(); + drawItem(index); + } + } + } + clipper.End(); + + ImGui::PopStyleVar(); + ImGui::PopID(); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Widgets/ItemCardContainerWidget.h b/SynapseEngine/Editor/Widgets/ItemCardContainerWidget.h new file mode 100644 index 00000000..5422358e --- /dev/null +++ b/SynapseEngine/Editor/Widgets/ItemCardContainerWidget.h @@ -0,0 +1,11 @@ +#pragma once +#include + +namespace Syn::UI +{ + void ItemCardContainer(const char* strId, + int itemCount, + float thumbnailSize, + const std::function& drawItem, + float spacing = 12.0f); +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Widgets/ItemCardWidget.cpp b/SynapseEngine/Editor/Widgets/ItemCardWidget.cpp new file mode 100644 index 00000000..59d6233e --- /dev/null +++ b/SynapseEngine/Editor/Widgets/ItemCardWidget.cpp @@ -0,0 +1,191 @@ +#include "ItemCardWidget.h" +#include +#include + +namespace Syn::UI { + + namespace { + constexpr float kPadding = 6.0f; + constexpr float kRounding = 6.0f; + constexpr float kImageRounding = 4.0f; + constexpr float kTextGap = 4.0f; + constexpr int kMaxTitleLines = 2; + + constexpr ImU32 kColBg = IM_COL32(36, 36, 40, 255); + constexpr ImU32 kColBgHovered = IM_COL32(50, 50, 56, 255); + constexpr ImU32 kColBgActive = IM_COL32(58, 62, 70, 255); + constexpr ImU32 kColBgSelected = IM_COL32(38, 56, 80, 255); + constexpr ImU32 kColAccent = IM_COL32(66, 150, 250, 255); + constexpr ImU32 kColBorder = IM_COL32(255, 255, 255, 18); + constexpr ImU32 kColText = IM_COL32(230, 230, 230, 255); + constexpr ImU32 kColPlaceholder = IM_COL32(20, 20, 22, 255); + + const char* Utf8Next(const char* s, const char* end) { + if (s >= end) return end; + unsigned char c = static_cast(*s); + int len = 1; + if (c >= 0xF0) len = 4; + else if (c >= 0xE0) len = 3; + else if (c >= 0xC0) len = 2; + const char* n = s + len; + return n > end ? end : n; + } + + const char* ComputeLineEnd(const char* lineStart, const char* textEnd, + float maxWidth, const char** outNextStart) { + const char* s = lineStart; + const char* lastSpace = nullptr; + while (s < textEnd) { + const char* next = Utf8Next(s, textEnd); + if (ImGui::CalcTextSize(lineStart, next).x > maxWidth && s > lineStart) { + if (lastSpace && lastSpace > lineStart) { + *outNextStart = lastSpace + 1; + return lastSpace; + } + *outNextStart = s; + return s; + } + if (*s == ' ') lastSpace = s; + s = next; + } + *outNextStart = textEnd; + return textEnd; + } + } + + float ItemCardWidth(float thumbnailSize) { + return thumbnailSize + kPadding * 2.0f; + } + + float ItemCardHeight(float thumbnailSize) { + return kPadding + thumbnailSize + kTextGap + ImGui::GetTextLineHeight() * kMaxTitleLines + kPadding; + } + + bool ItemCard(const ItemCardDesc& desc, float thumbnailSize) { + const char* idStr = desc.id ? desc.id : desc.title; + ImGui::PushID(idStr); + + const ImVec2 size(ItemCardWidth(thumbnailSize), ItemCardHeight(thumbnailSize)); + const ImVec2 min = ImGui::GetCursorScreenPos(); + const ImVec2 max(min.x + size.x, min.y + size.y); + + bool clicked = ImGui::InvisibleButton("##ItemCard", size); + const bool hovered = ImGui::IsItemHovered(); + const bool active = ImGui::IsItemActive(); + const bool doubleClicked = hovered && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left); + + if (desc.events.onDragDropSource) { + if (ImGui::BeginDragDropSource()) { + desc.events.onDragDropSource(); + ImGui::EndDragDropSource(); + } + } + + ImDrawList* dl = ImGui::GetWindowDrawList(); + + { + const float yOffset = 2.0f; + const int layers = 3; + const int alpha = hovered ? 20 : 13; + for (int i = 0; i < layers; ++i) { + const float expand = 1.5f * static_cast(i + 1); + dl->AddRectFilled( + ImVec2(min.x - expand, min.y - expand + yOffset), + ImVec2(max.x + expand, max.y + expand + yOffset), + IM_COL32(0, 0, 0, alpha), kRounding + expand); + } + } + + // Background + ImU32 bgCol = kColBg; + if (desc.selected) bgCol = kColBgSelected; + if (hovered) bgCol = desc.selected ? kColBgSelected : kColBgHovered; + if (active) bgCol = kColBgActive; + dl->AddRectFilled(min, max, bgCol, kRounding); + + // Border + if (desc.selected) { + dl->AddRect(min, max, kColAccent, kRounding, 0, 2.0f); + } + else { + dl->AddRect(min, max, kColBorder, kRounding, 0, 1.0f); + } + + // Thumbnail + const ImVec2 imgMin(min.x + kPadding, min.y + kPadding); + const ImVec2 imgMax(imgMin.x + thumbnailSize, imgMin.y + thumbnailSize); + if (desc.texture) { + dl->AddImageRounded(desc.texture, imgMin, imgMax, + desc.uv0, desc.uv1, + ImGui::ColorConvertFloat4ToU32(desc.imageTint), + kImageRounding); + } + else { + dl->AddRectFilled(imgMin, imgMax, kColPlaceholder, kImageRounding); + } + + const char* text = desc.title; + const char* textEnd = text + std::strlen(text); + const float maxTextWidth = thumbnailSize; + const float lineHeight = ImGui::GetTextLineHeight(); + float textY = imgMax.y + kTextGap; + + bool truncated = false; + const char* lineStart = text; + + for (int line = 0; line < kMaxTitleLines && lineStart < textEnd; ++line) { + const bool lastLine = (line == kMaxTitleLines - 1); + + if (!lastLine) { + const char* nextStart = textEnd; + const char* lineEnd = ComputeLineEnd(lineStart, textEnd, + maxTextWidth, &nextStart); + const float w = ImGui::CalcTextSize(lineStart, lineEnd).x; + const float x = min.x + kPadding + + std::max(0.0f, (maxTextWidth - w) * 0.5f); + dl->AddText(ImVec2(x, textY), kColText, lineStart, lineEnd); + lineStart = nextStart; + } + else { + float w = ImGui::CalcTextSize(lineStart, textEnd).x; + const char* lineEnd = textEnd; + + if (w > maxTextWidth) { + truncated = true; + const float ellipsisW = ImGui::CalcTextSize("...").x; + const char* s = lineStart; + lineEnd = lineStart; + while (s < textEnd) { + const char* next = Utf8Next(s, textEnd); + if (ImGui::CalcTextSize(lineStart, next).x + ellipsisW + > maxTextWidth) break; + lineEnd = next; + s = next; + } + w = ImGui::CalcTextSize(lineStart, lineEnd).x + ellipsisW; + } + + const float x = min.x + kPadding + + std::max(0.0f, (maxTextWidth - w) * 0.5f); + dl->AddText(ImVec2(x, textY), kColText, lineStart, lineEnd); + if (truncated) { + const float usedW = ImGui::CalcTextSize(lineStart, lineEnd).x; + dl->AddText(ImVec2(x + usedW, textY), kColText, "..."); + } + lineStart = textEnd; + } + textY += lineHeight; + } + if (lineStart < textEnd) truncated = true; + + if (truncated && hovered && !active) { + ImGui::SetTooltip("%s", desc.title); + } + + if (doubleClicked && desc.events.onDoubleClick) desc.events.onDoubleClick(); + else if (clicked && desc.events.onClick) desc.events.onClick(); + + ImGui::PopID(); + return clicked; + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Widgets/ItemCardWidget.h b/SynapseEngine/Editor/Widgets/ItemCardWidget.h new file mode 100644 index 00000000..3d8c8997 --- /dev/null +++ b/SynapseEngine/Editor/Widgets/ItemCardWidget.h @@ -0,0 +1,28 @@ +#pragma once +#include +#include + +namespace Syn::UI { + struct ItemCardEvents { + std::function onClick; + std::function onDoubleClick; + std::function onDragDropSource; + }; + + struct ItemCardDesc { + const char* id = nullptr; + const char* title = ""; + + ImTextureID texture = 0; + ImVec2 uv0 = ImVec2(0.0f, 0.0f); + ImVec2 uv1 = ImVec2(1.0f, 1.0f); + ImVec4 imageTint = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); + + bool selected = false; + ItemCardEvents events; + }; + + bool ItemCard(const ItemCardDesc& desc, float thumbnailSize); + float ItemCardWidth(float thumbnailSize); + float ItemCardHeight(float thumbnailSize); +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Widgets/PropertyGrid.cpp b/SynapseEngine/Editor/Widgets/PropertyGrid.cpp index 69e139ce..9dd043ac 100644 --- a/SynapseEngine/Editor/Widgets/PropertyGrid.cpp +++ b/SynapseEngine/Editor/Widgets/PropertyGrid.cpp @@ -10,7 +10,7 @@ namespace Syn::UI { bool isOpen = ImGui::BeginTable(id, 2, flags); if (isOpen) { - ImGui::TableSetupColumn("Label", ImGuiTableColumnFlags_WidthFixed, 100.0f); + ImGui::TableSetupColumn("Label", ImGuiTableColumnFlags_WidthFixed); ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch); } else { @@ -59,61 +59,83 @@ namespace Syn::UI { bool PropertyDragFloat(const char* label, float& value, float v_speed, float v_min, float v_max, const char* format, int indentLevel) { BeginProperty(label, indentLevel); std::string widgetId = std::string("##") + label; - return ImGui::DragFloat(widgetId.c_str(), &value, v_speed, v_min, v_max, format); + bool changed = ImGui::DragFloat(widgetId.c_str(), &value, v_speed, v_min, v_max, format); + return changed || ImGui::IsItemDeactivatedAfterEdit(); } bool PropertyDragFloat2(const char* label, glm::vec2& values, float v_speed, float v_min, float v_max, const char* format, int indentLevel) { BeginProperty(label, indentLevel); std::string widgetId = std::string("##") + label; - return ImGui::DragFloat2(widgetId.c_str(), &values.x, v_speed, v_min, v_max, format); + ImGui::BeginGroup(); + bool changed = ImGui::DragFloat2(widgetId.c_str(), &values.x, v_speed, v_min, v_max, format); + ImGui::EndGroup(); + return changed || ImGui::IsItemDeactivatedAfterEdit(); } bool PropertyDragFloat3(const char* label, glm::vec3& values, float v_speed, float v_min, float v_max, const char* format, int indentLevel) { BeginProperty(label, indentLevel); std::string widgetId = std::string("##") + label; - return ImGui::DragFloat3(widgetId.c_str(), &values.x, v_speed, v_min, v_max, format); + ImGui::BeginGroup(); + bool changed = ImGui::DragFloat3(widgetId.c_str(), &values.x, v_speed, v_min, v_max, format); + ImGui::EndGroup(); + return changed || ImGui::IsItemDeactivatedAfterEdit(); } bool PropertyDragFloat4(const char* label, glm::vec4& values, float v_speed, float v_min, float v_max, const char* format, int indentLevel) { BeginProperty(label, indentLevel); std::string widgetId = std::string("##") + label; - return ImGui::DragFloat4(widgetId.c_str(), &values.x, v_speed, v_min, v_max, format); + ImGui::BeginGroup(); + bool changed = ImGui::DragFloat4(widgetId.c_str(), &values.x, v_speed, v_min, v_max, format); + ImGui::EndGroup(); + return changed || ImGui::IsItemDeactivatedAfterEdit(); } bool PropertySliderFloat(const char* label, float& value, float v_min, float v_max, const char* format, int indentLevel) { BeginProperty(label, indentLevel); std::string widgetId = std::string("##") + label; - return ImGui::SliderFloat(widgetId.c_str(), &value, v_min, v_max, format); + bool changed = ImGui::SliderFloat(widgetId.c_str(), &value, v_min, v_max, format); + return changed || ImGui::IsItemDeactivatedAfterEdit(); } bool PropertySliderFloat2(const char* label, glm::vec2& values, float v_min, float v_max, const char* format, int indentLevel) { BeginProperty(label, indentLevel); std::string widgetId = std::string("##") + label; - return ImGui::SliderFloat2(widgetId.c_str(), &values.x, v_min, v_max, format); + ImGui::BeginGroup(); + bool changed = ImGui::SliderFloat2(widgetId.c_str(), &values.x, v_min, v_max, format); + ImGui::EndGroup(); + return changed || ImGui::IsItemDeactivatedAfterEdit(); } bool PropertySliderFloat3(const char* label, glm::vec3& values, float v_min, float v_max, const char* format, int indentLevel) { BeginProperty(label, indentLevel); std::string widgetId = std::string("##") + label; - return ImGui::SliderFloat3(widgetId.c_str(), &values.x, v_min, v_max, format); + ImGui::BeginGroup(); + bool changed = ImGui::SliderFloat3(widgetId.c_str(), &values.x, v_min, v_max, format); + ImGui::EndGroup(); + return changed || ImGui::IsItemDeactivatedAfterEdit(); } bool PropertySliderFloat4(const char* label, glm::vec4& values, float v_min, float v_max, const char* format, int indentLevel) { BeginProperty(label, indentLevel); std::string widgetId = std::string("##") + label; - return ImGui::SliderFloat4(widgetId.c_str(), &values.x, v_min, v_max, format); + ImGui::BeginGroup(); + bool changed = ImGui::SliderFloat4(widgetId.c_str(), &values.x, v_min, v_max, format); + ImGui::EndGroup(); + return changed || ImGui::IsItemDeactivatedAfterEdit(); } bool PropertyColor3(const char* label, glm::vec3& color, int indentLevel) { BeginProperty(label, indentLevel); std::string widgetId = std::string("##") + label; - return ImGui::ColorEdit3(widgetId.c_str(), &color.x); + bool changed = ImGui::ColorEdit3(widgetId.c_str(), &color.x); + return changed || ImGui::IsItemDeactivatedAfterEdit(); } bool PropertyColor4(const char* label, glm::vec4& color, int indentLevel) { BeginProperty(label, indentLevel); std::string widgetId = std::string("##") + label; - return ImGui::ColorEdit4(widgetId.c_str(), &color.x); + bool changed = ImGui::ColorEdit4(widgetId.c_str(), &color.x); + return changed || ImGui::IsItemDeactivatedAfterEdit(); } bool PropertyCheckbox(const char* label, bool& value, int indentLevel) { @@ -122,4 +144,18 @@ namespace Syn::UI { return ImGui::Checkbox(widgetId.c_str(), &value); } + bool BeginPropertyCombo(const char* label, const char* preview_value, int indentLevel) { + BeginProperty(label, indentLevel); + std::string widgetId = std::string("##") + label; + return ImGui::BeginCombo(widgetId.c_str(), preview_value); + } + + void EndPropertyCombo() { + ImGui::EndCombo(); + } + + void PropertyText(const char* label, const char* text, int indentLevel) { + BeginProperty(label, indentLevel); + ImGui::TextUnformatted(text); + } } \ No newline at end of file diff --git a/SynapseEngine/Editor/Widgets/PropertyGrid.h b/SynapseEngine/Editor/Widgets/PropertyGrid.h index d476921c..2b29a86a 100644 --- a/SynapseEngine/Editor/Widgets/PropertyGrid.h +++ b/SynapseEngine/Editor/Widgets/PropertyGrid.h @@ -24,4 +24,9 @@ namespace Syn::UI { bool PropertyColor4(const char* label, glm::vec4& color, int indentLevel = 0); bool PropertyCheckbox(const char* label, bool& value, int indentLevel = 0); + + bool BeginPropertyCombo(const char* label, const char* preview_value, int indentLevel = 0); + void EndPropertyCombo(); + + void PropertyText(const char* label, const char* text, int indentLevel = 0); } \ No newline at end of file diff --git a/SynapseEngine/Editor/Widgets/Vector3Widget.cpp b/SynapseEngine/Editor/Widgets/Vector3Widget.cpp index 4276f6fe..49aa50b0 100644 --- a/SynapseEngine/Editor/Widgets/Vector3Widget.cpp +++ b/SynapseEngine/Editor/Widgets/Vector3Widget.cpp @@ -12,7 +12,7 @@ namespace Syn::UI { ImGui::PushID(id.c_str()); - float lineHeight = GImGui->Font->FontSize + GImGui->Style.FramePadding.y * 2.0f; + float lineHeight = ImGui::GetFontSize() + GImGui->Style.FramePadding.y * 2.0f; ImVec2 buttonSize = { lineHeight + 3.0f, lineHeight }; float availWidth = ImGui::GetContentRegionAvail().x; diff --git a/SynapseEngine/Editor/View/ContentBrowser/ContentBrowserView.cpp b/SynapseEngine/Editor/Workspace/Common/ContentBrowser/ContentBrowserView.cpp similarity index 73% rename from SynapseEngine/Editor/View/ContentBrowser/ContentBrowserView.cpp rename to SynapseEngine/Editor/Workspace/Common/ContentBrowser/ContentBrowserView.cpp index 32cfa734..97f26fb9 100644 --- a/SynapseEngine/Editor/View/ContentBrowser/ContentBrowserView.cpp +++ b/SynapseEngine/Editor/Workspace/Common/ContentBrowser/ContentBrowserView.cpp @@ -1,6 +1,8 @@ #include "ContentBrowserView.h" #include "Editor/Manager/EditorIcons.h" #include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/ItemCardWidget.h" +#include "Editor/Widgets/ItemCardContainerWidget.h" #include #include #include @@ -47,7 +49,7 @@ namespace Syn { float treeHeight = mainContentBottomY - ImGui::GetCursorScreenPos().y - 12.0f; if (treeHeight < 50.0f) treeHeight = 50.0f; - ImGui::BeginChild("FolderTreeScroll", ImVec2(0, treeHeight), ImGuiChildFlags_Borders, ImGuiWindowFlags_AlwaysUseWindowPadding); + ImGui::BeginChild("FolderTreeScroll", ImVec2(0, treeHeight), ImGuiChildFlags_Borders | ImGuiChildFlags_AlwaysUseWindowPadding, 0); RenderFolderTree(vm, state); ImGui::EndChild(); @@ -86,7 +88,7 @@ namespace Syn { float gridHeight = mainContentBottomY - ImGui::GetCursorScreenPos().y - 12.0f; if (gridHeight < 50.0f) gridHeight = 50.0f; - ImGui::BeginChild("ContentGridScroll", ImVec2(0, gridHeight), ImGuiChildFlags_Borders, ImGuiWindowFlags_AlwaysUseWindowPadding); + ImGui::BeginChild("ContentGridScroll", ImVec2(0, gridHeight), ImGuiChildFlags_Borders | ImGuiChildFlags_AlwaysUseWindowPadding, 0); RenderContentArea(vm, state); ImGui::EndChild(); @@ -223,105 +225,33 @@ namespace Syn { } void ContentBrowserView::RenderContentArea(ContentBrowserViewModel& vm, const ContentBrowserState& state) { - float panelWidth = ImGui::GetContentRegionAvail().x; - float padding = 16.0f; - float cellSize = state.thumbnailSize + padding; - int columnCount = std::max(1, static_cast(panelWidth / cellSize)); - - ImGui::Columns(columnCount, "FileSystemGrid", false); - - for (const auto& entry : state.currentEntries) { - RenderFileCard(vm, state, entry); - ImGui::NextColumn(); - } - - ImGui::Columns(1); - } - - void ContentBrowserView::RenderFileCard(ContentBrowserViewModel& vm, const ContentBrowserState& state, const FileEntry& entry) { - ImGui::PushID(entry.path.c_str()); - - bool isSelected = (state.selectedPath == entry.path); - ImVec4 baseCol = isSelected ? ImVec4(0.26f, 0.59f, 0.98f, 0.4f) : ImVec4(0, 0, 0, 0); - ImVec4 hoverCol = isSelected ? ImVec4(0.26f, 0.59f, 0.98f, 0.5f) : ImVec4(1.0f, 1.0f, 1.0f, 0.05f); - - ImGui::PushStyleColor(ImGuiCol_Button, baseCol); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, hoverCol); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.26f, 0.59f, 0.98f, 0.7f)); - ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f); - - float cardSize = state.thumbnailSize; - float textHeight = ImGui::GetTextLineHeightWithSpacing() * 2; - ImVec2 totalSize = ImVec2(cardSize, cardSize + textHeight); - - if (ImGui::Button("##CardButton", totalSize)) { - vm.Dispatch(SelectEntryIntent{ entry.path }); - } - - if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { - if (entry.isDirectory) { - vm.Dispatch(ChangeDirectoryIntent{ entry.path }); - } - } - - if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_SourceAllowNullID)) { - std::string payloadType = GetPayloadType(entry.extension); - ImGui::SetDragDropPayload(payloadType.c_str(), entry.path.c_str(), entry.path.size() + 1); - ImGui::TextUnformatted(entry.name.c_str()); - ImGui::EndDragDropSource(); - } - - ImVec2 itemMin = ImGui::GetItemRectMin(); - ImGui::SetItemAllowOverlap(); - - ImTextureID iconID = GetIconForEntry(entry); - if (iconID) { - ImGui::SetCursorScreenPos(itemMin); - ImGui::Image(iconID, ImVec2(cardSize, cardSize)); - } - - float currentY = itemMin.y + cardSize + 2.0f; - float lineHeight = ImGui::GetTextLineHeight(); - - const char* text = entry.name.c_str(); - const char* textEnd = text + entry.name.length(); - const char* lineStart = text; - - float maxTextWidth = cardSize - 4.0f; - - int lineCount = 0; - while (lineStart < textEnd && lineCount < 2) { - const char* lineEnd = lineStart; - - while (lineEnd < textEnd) { - float w = ImGui::CalcTextSize(lineStart, lineEnd + 1).x; - if (w > maxTextWidth) { - break; - } - lineEnd++; - } - - if (lineEnd == lineStart) lineEnd++; - - float lineWidth = ImGui::CalcTextSize(lineStart, lineEnd).x; - float textIndent = std::max(0.0f, (cardSize - lineWidth) * 0.5f); - - ImGui::SetCursorScreenPos(ImVec2(itemMin.x + textIndent, currentY)); - ImGui::TextUnformatted(lineStart, lineEnd); - - currentY += lineHeight; - lineStart = lineEnd; - - if (lineStart < textEnd && *lineStart == ' ') { - lineStart++; - } - - lineCount++; - } - - ImGui::PopStyleVar(); - ImGui::PopStyleColor(3); - ImGui::PopID(); + const auto entries = state.currentEntries; + Syn::UI::ItemCardContainer("ContentGrid", (int)entries.size(), state.thumbnailSize, + [&](int index) { + const FileEntry& entry = entries[index]; + + Syn::UI::ItemCardDesc desc; + desc.id = entry.path.c_str(); + desc.title = entry.name.c_str(); + desc.texture = GetIconForEntry(entry); + desc.selected = (state.selectedPath == entry.path); + + desc.events.onClick = [&vm, &entry] { + vm.Dispatch(SelectEntryIntent{ entry.path }); + }; + + desc.events.onDoubleClick = [&vm, &entry] { + if (entry.isDirectory) vm.Dispatch(ChangeDirectoryIntent{ entry.path }); + }; + + desc.events.onDragDropSource = [this, &entry] { + std::string payloadType = GetPayloadType(entry.extension); + ImGui::SetDragDropPayload(payloadType.c_str(), entry.path.c_str(), entry.path.size() + 1); + ImGui::TextUnformatted(entry.name.c_str()); + }; + + Syn::UI::ItemCard(desc, state.thumbnailSize); + }); } ImTextureID ContentBrowserView::GetIconForEntry(const FileEntry& entry) const { diff --git a/SynapseEngine/Editor/View/ContentBrowser/ContentBrowserView.h b/SynapseEngine/Editor/Workspace/Common/ContentBrowser/ContentBrowserView.h similarity index 85% rename from SynapseEngine/Editor/View/ContentBrowser/ContentBrowserView.h rename to SynapseEngine/Editor/Workspace/Common/ContentBrowser/ContentBrowserView.h index 288788b0..ed94eb0f 100644 --- a/SynapseEngine/Editor/View/ContentBrowser/ContentBrowserView.h +++ b/SynapseEngine/Editor/Workspace/Common/ContentBrowser/ContentBrowserView.h @@ -1,6 +1,6 @@ #pragma once -#include "Editor/View/IView.h" -#include "EditorCore/ViewModels/ContentBrowser/ContentBrowserViewModel.h" +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserViewModel.h" #include "Editor/Manager/IIconManager.h" #include #include @@ -19,7 +19,6 @@ namespace Syn { void RenderFolderTree(ContentBrowserViewModel& vm, const ContentBrowserState& state); void RenderContentArea(ContentBrowserViewModel& vm, const ContentBrowserState& state); - void RenderFileCard(ContentBrowserViewModel& vm, const ContentBrowserState& state, const FileEntry& entry); ImTextureID GetIconForEntry(const FileEntry& entry) const; std::string GetPayloadType(const std::string& extension) const; diff --git a/SynapseEngine/Editor/Workspace/Common/MainMenu/MainMenuView.cpp b/SynapseEngine/Editor/Workspace/Common/MainMenu/MainMenuView.cpp new file mode 100644 index 00000000..0e563c42 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/Common/MainMenu/MainMenuView.cpp @@ -0,0 +1,29 @@ +#include "MainMenuView.h" + +namespace Syn +{ + void MainMenuView::Draw(MainMenuViewModel& vm) { + + if (ImGui::BeginMainMenuBar()) { + + if (ImGui::BeginMenu("File")) { + + if (ImGui::MenuItem("New Scene", "Ctrl+N")) { + vm.Dispatch(NewSceneIntent{}); + } + + if (ImGui::MenuItem("Load Scene...", "Ctrl+O")) { + vm.Dispatch(LoadSceneIntent{}); + } + + if (ImGui::MenuItem("Save Scene", "Ctrl+S")) { + vm.Dispatch(SaveSceneIntent{}); + } + + ImGui::EndMenu(); + } + + ImGui::EndMainMenuBar(); + } + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/Common/MainMenu/MainMenuView.h b/SynapseEngine/Editor/Workspace/Common/MainMenu/MainMenuView.h new file mode 100644 index 00000000..2bd26ffc --- /dev/null +++ b/SynapseEngine/Editor/Workspace/Common/MainMenu/MainMenuView.h @@ -0,0 +1,11 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/Common/MainMenu/MainMenuViewModel.h" +#include + +namespace Syn { + class MainMenuView : public IView { + public: + void Draw(MainMenuViewModel& vm) override; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/View/IGuiWindow.cpp b/SynapseEngine/Editor/Workspace/IGuiWindow.cpp similarity index 100% rename from SynapseEngine/Editor/View/IGuiWindow.cpp rename to SynapseEngine/Editor/Workspace/IGuiWindow.cpp diff --git a/SynapseEngine/Editor/View/IGuiWindow.h b/SynapseEngine/Editor/Workspace/IGuiWindow.h similarity index 100% rename from SynapseEngine/Editor/View/IGuiWindow.h rename to SynapseEngine/Editor/Workspace/IGuiWindow.h diff --git a/SynapseEngine/Editor/View/IView.cpp b/SynapseEngine/Editor/Workspace/IView.cpp similarity index 100% rename from SynapseEngine/Editor/View/IView.cpp rename to SynapseEngine/Editor/Workspace/IView.cpp diff --git a/SynapseEngine/Editor/View/IView.h b/SynapseEngine/Editor/Workspace/IView.h similarity index 100% rename from SynapseEngine/Editor/View/IView.h rename to SynapseEngine/Editor/Workspace/IView.h diff --git a/SynapseEngine/Editor/Workspace/IWorkspace.h b/SynapseEngine/Editor/Workspace/IWorkspace.h index 66fdd828..d59b3788 100644 --- a/SynapseEngine/Editor/Workspace/IWorkspace.h +++ b/SynapseEngine/Editor/Workspace/IWorkspace.h @@ -1,7 +1,7 @@ #pragma once #include #include -#include "Editor/View/IGuiWindow.h" +#include "Editor/Workspace/IGuiWindow.h" namespace Syn { @@ -17,6 +17,8 @@ namespace Syn virtual ~IWorkspace() = default; virtual void Initialize() = 0; + virtual void OnActivate() {} + virtual void OnDeactivate() {} virtual void UpdateAndDraw() { for (auto& window : _windows) { diff --git a/SynapseEngine/Editor/Workspace/MaterialWorkspace.cpp b/SynapseEngine/Editor/Workspace/MaterialWorkspace.cpp deleted file mode 100644 index 6367b1af..00000000 --- a/SynapseEngine/Editor/Workspace/MaterialWorkspace.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "MaterialWorkspace.h" -#include "Editor/Manager/EditorIcons.h" - -#include "Editor/View/ContentBrowser/ContentBrowserView.h" -#include "EditorCore/ViewModels/ContentBrowser/ContentBrowserViewModel.h" -#include "Editor/View/MaterialGraph/MaterialGraphView.h" -#include "EditorCore/ViewModels/MaterialGraph/MaterialGraphViewModel.h" - -namespace Syn { - - MaterialWorkspace::MaterialWorkspace(EditorContext* context, IconManager* iconManager, const std::string& assetPath) - : _context(context), _iconManager(iconManager), _assetPath(assetPath) {} - - void MaterialWorkspace::Initialize() { - using ContentBrowserWin = EditorWindow; - AddWindow( - ContentBrowserView{ _iconManager, SYN_ICON_FOLDER_OPEN " Content Browser###Content_Material" }, - ContentBrowserViewModel{ _context->GetFileSystemApi(), _assetPath } - ); - - using MaterialGraphWin = EditorWindow; - AddWindow( - MaterialGraphView{}, - MaterialGraphViewModel{ _context->GetMaterialApi() } - ); - } - -} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/MaterialWorkspace/MaterialWorkspace.cpp b/SynapseEngine/Editor/Workspace/MaterialWorkspace/MaterialWorkspace.cpp new file mode 100644 index 00000000..4d577f7b --- /dev/null +++ b/SynapseEngine/Editor/Workspace/MaterialWorkspace/MaterialWorkspace.cpp @@ -0,0 +1,64 @@ +#include "MaterialWorkspace.h" +#include "Editor/Manager/EditorIcons.h" + +#include "Editor/Workspace/Common/ContentBrowser/ContentBrowserView.h" +#include "EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserViewModel.h" + +#include "View/MaterialGraph/MaterialGraphView.h" +#include "EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphViewModel.h" + +#include "View/MaterialHierarchy/MaterialHierarchyView.h" +#include "EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyViewModel.h" + +#include "View/MaterialProperties/MaterialPropertiesView.h" +#include "EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesViewModel.h" + +#include "View/MaterialViewport/MaterialViewportView.h" +#include "EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportViewModel.h" + +#include "Engine/Scene/SceneNames.h" + +namespace Syn { + + MaterialWorkspace::MaterialWorkspace(EditorContext* context, IconManager* iconManager, const std::string& assetPath) + : _context(context), _iconManager(iconManager), _assetPath(assetPath) {} + + void MaterialWorkspace::OnActivate() { + if (_context && _context->GetApi()) { + _context->GetApi()->ActivateScene(SceneNames::MaterialPreview); + } + } + + void MaterialWorkspace::Initialize() { + using ContentBrowserWin = EditorWindow; + AddWindow( + ContentBrowserView{ _iconManager, SYN_ICON_FOLDER_OPEN " Content Browser###Content_Material" }, + ContentBrowserViewModel{ _context->GetApi(), _assetPath } + ); + + using MaterialHierarchyWin = EditorWindow; + AddWindow( + MaterialHierarchyView{}, + MaterialHierarchyViewModel{ _context->GetApi(), _context->GetApi() } + ); + + using MaterialGraphWin = EditorWindow; + AddWindow( + MaterialGraphView{}, + MaterialGraphViewModel{ _context->GetApi(), _context->GetApi() } + ); + + using MaterialPropertiesWin = EditorWindow; + AddWindow( + MaterialPropertiesView{}, + MaterialPropertiesViewModel{ _context->GetApi(), _context->GetApi() } + ); + + using MaterialViewportWin = EditorWindow; + AddWindow( + MaterialViewportView{}, + MaterialViewportViewModel{ _context->GetApi() } + ); + } + +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/MaterialWorkspace.h b/SynapseEngine/Editor/Workspace/MaterialWorkspace/MaterialWorkspace.h similarity index 86% rename from SynapseEngine/Editor/Workspace/MaterialWorkspace.h rename to SynapseEngine/Editor/Workspace/MaterialWorkspace/MaterialWorkspace.h index c14b251f..c177ef07 100644 --- a/SynapseEngine/Editor/Workspace/MaterialWorkspace.h +++ b/SynapseEngine/Editor/Workspace/MaterialWorkspace/MaterialWorkspace.h @@ -1,5 +1,5 @@ #pragma once -#include "IWorkspace.h" +#include "Editor/Workspace/IWorkspace.h" #include "Editor/EditorApi/EditorContext.h" #include "Editor/Manager/IconManager.h" #include @@ -12,7 +12,7 @@ namespace Syn { ~MaterialWorkspace() override = default; void Initialize() override; - + void OnActivate() override; private: EditorContext* _context; IconManager* _iconManager; diff --git a/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialGraph/MaterialGraphView.cpp b/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialGraph/MaterialGraphView.cpp new file mode 100644 index 00000000..fa5d010d --- /dev/null +++ b/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialGraph/MaterialGraphView.cpp @@ -0,0 +1,184 @@ +#include "MaterialGraphView.h" +#include "Editor/Manager/EditorIcons.h" +#include +#include + +namespace ed = ax::NodeEditor; + +namespace Syn { + + MaterialGraphView::MaterialGraphView() { + ed::Config config; + config.SettingsFile = "Synapse_MaterialGraph.json"; + _context = ed::CreateEditor(&config); + } + + MaterialGraphView::~MaterialGraphView() { + if (_context) { + ed::DestroyEditor(_context); + } + } + + MaterialGraphView::MaterialGraphView(MaterialGraphView&& other) noexcept + : _context(other._context) + { + other._context = nullptr; + } + + MaterialGraphView& MaterialGraphView::operator=(MaterialGraphView&& other) noexcept { + if (this != &other) { + if (_context) ed::DestroyEditor(_context); + _context = other._context; + other._context = nullptr; + } + return *this; + } + + void MaterialGraphView::Draw(MaterialGraphViewModel& vm) { + const auto& state = vm.GetState(); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); + ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; + + bool isVisible = ImGui::Begin(SYN_ICON_PROJECT_DIAGRAM " Material Graph", nullptr, windowFlags); + ImGui::PopStyleVar(); + + if (isVisible) { + ed::SetCurrentEditor(_context); + + ImVec2 canvasSize = ImGui::GetContentRegionAvail(); + if (canvasSize.x <= 0.0f) canvasSize.x = 1.0f; + if (canvasSize.y <= 0.0f) canvasSize.y = 1.0f; + + ed::Begin("Material Editor Canvas", canvasSize); + + if (!state.isMaterialSelected) { + ImGui::SetCursorPos(ImVec2(canvasSize.x * 0.5f - 80.0f, canvasSize.y * 0.5f)); + ImGui::TextDisabled("No Material Selected"); + } + else { + for (const auto& node : state.nodes) { + if (node.type == GraphNodeType::Material) { + DrawMaterialNode(node); + } + else if (node.type == GraphNodeType::Texture) { + DrawTextureNode(node); + } + } + + for (const auto& link : state.links) { + ed::Link(ed::LinkId(link.id), ed::PinId(link.startPinId), ed::PinId(link.endPinId)); + } + + if (ed::BeginCreate()) { + ed::PinId inputPinId, outputPinId; + if (ed::QueryNewLink(&inputPinId, &outputPinId)) { + if (inputPinId && outputPinId) { + if (ed::AcceptNewItem(ImVec4(0.2f, 1.0f, 0.2f, 1.0f), 2.0f)) { + GraphID startId = static_cast(inputPinId.Get()); + GraphID endId = static_cast(outputPinId.Get()); + vm.Dispatch(CreateLinkIntent{ startId, endId }); + } + } + } + } + ed::EndCreate(); + + if (ed::BeginDelete()) { + ed::LinkId deletedLinkId; + while (ed::QueryDeletedLink(&deletedLinkId)) { + if (ed::AcceptDeletedItem()) { + vm.Dispatch(DeleteLinkIntent{ static_cast(deletedLinkId.Get()) }); + } + } + } + ed::EndDelete(); + } + + ed::End(); + ed::SetCurrentEditor(nullptr); + } + + ImGui::End(); + } + + void MaterialGraphView::DrawMaterialNode(const GraphNodeData& node) { + ed::BeginNode(ed::NodeId(node.id)); + + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.2f, 1.0f)); + ImGui::TextUnformatted((SYN_ICON_BRUSH " " + node.name).c_str()); + ImGui::PopStyleColor(); + ImGui::Spacing(); + + ImVec2 previewSize(256.0f, 256.0f); + ImVec2 cursorPos = ImGui::GetCursorScreenPos(); + ImDrawList* drawList = ImGui::GetWindowDrawList(); + + drawList->AddRectFilled(cursorPos, ImVec2(cursorPos.x + previewSize.x, cursorPos.y + previewSize.y), IM_COL32(25, 25, 25, 255), 4.0f); + + const char* previewText = "Material\nPreview"; + ImVec2 textSize = ImGui::CalcTextSize(previewText); + drawList->AddText(ImVec2(cursorPos.x + (previewSize.x - textSize.x) * 0.5f, cursorPos.y + (previewSize.y - textSize.y) * 0.5f), IM_COL32(120, 120, 120, 255), previewText); + ImGui::Dummy(previewSize); + + ImGui::Spacing(); + + for (const auto& pin : node.pins) { + ed::BeginPin(ed::PinId(pin.id), ed::PinKind::Input); + ImGui::Text("-> %s", GetPinName(pin.type)); + ed::EndPin(); + } + + ed::EndNode(); + } + + void MaterialGraphView::DrawTextureNode(const GraphNodeData& node) { + ed::BeginNode(ed::NodeId(node.id)); + + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.4f, 0.8f, 1.0f, 1.0f)); + ImGui::TextUnformatted((SYN_ICON_IMAGE " " + node.name).c_str()); + ImGui::PopStyleColor(); + ImGui::Spacing(); + + ImVec2 previewSize(256.0f, 256.0f); + if (node.textureHandle != InvalidTextureHandle) { + ImGui::Image(node.textureHandle, previewSize); + } + else { + ImVec2 cursorPos = ImGui::GetCursorScreenPos(); + ImDrawList* drawList = ImGui::GetWindowDrawList(); + drawList->AddRectFilled(cursorPos, ImVec2(cursorPos.x + previewSize.x, cursorPos.y + previewSize.y), IM_COL32(25, 25, 25, 255), 4.0f); + const char* previewText = "No Image"; + ImVec2 textSize = ImGui::CalcTextSize(previewText); + drawList->AddText(ImVec2(cursorPos.x + (previewSize.x - textSize.x) * 0.5f, cursorPos.y + (previewSize.y - textSize.y) * 0.5f), IM_COL32(255, 100, 100, 255), previewText); + ImGui::Dummy(previewSize); + } + + ImGui::Spacing(); + + for (const auto& pin : node.pins) { + ImVec2 pinTextSize = ImGui::CalcTextSize("RGB ->"); + + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + previewSize.x - pinTextSize.x); + + ed::BeginPin(ed::PinId(pin.id), ed::PinKind::Output); + ImGui::Text("RGB ->"); + ed::EndPin(); + } + + ed::EndNode(); + } + + const char* MaterialGraphView::GetPinName(GraphPinType type) { + switch (type) { + case GraphPinType::Albedo: return "Albedo"; + case GraphPinType::Normal: return "Normal"; + case GraphPinType::Metalness: return "Metalness"; + case GraphPinType::Roughness: return "Roughness"; + case GraphPinType::MetallicRoughness: return "MetallicRoughness"; + case GraphPinType::Emissive: return "Emissive"; + case GraphPinType::AmbientOcclusion: return "Ambient Occlusion"; + default: return "Unknown"; + } + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/View/MaterialGraph/MaterialGraphView.h b/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialGraph/MaterialGraphView.h similarity index 75% rename from SynapseEngine/Editor/View/MaterialGraph/MaterialGraphView.h rename to SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialGraph/MaterialGraphView.h index ab39a798..8102f202 100644 --- a/SynapseEngine/Editor/View/MaterialGraph/MaterialGraphView.h +++ b/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialGraph/MaterialGraphView.h @@ -1,6 +1,6 @@ #pragma once -#include "Editor/View/IView.h" -#include "EditorCore/ViewModels/MaterialGraph/MaterialGraphViewModel.h" +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphViewModel.h" namespace ax { namespace NodeEditor { @@ -23,6 +23,8 @@ namespace Syn { void Draw(MaterialGraphViewModel& vm) override; private: const char* GetPinName(GraphPinType type); + void DrawMaterialNode(const GraphNodeData& node); + void DrawTextureNode(const GraphNodeData& node); private: ax::NodeEditor::EditorContext* _context = nullptr; }; diff --git a/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialHierarchy/MaterialHierarchyView.cpp b/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialHierarchy/MaterialHierarchyView.cpp new file mode 100644 index 00000000..ce63b4a0 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialHierarchy/MaterialHierarchyView.cpp @@ -0,0 +1,115 @@ +#include "MaterialHierarchyView.h" +#include "Editor/Manager/EditorIcons.h" +#include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/ItemCardWidget.h" +#include "Editor/Widgets/ItemCardContainerWidget.h" +#include + +namespace Syn { + void MaterialHierarchyView::Draw(MaterialHierarchyViewModel& vm) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 8)); + ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; + + if (ImGui::Begin(SYN_ICON_BRUSH " Materials", nullptr, windowFlags)) { + + auto getCardState = [this](const char* name) -> bool& { + std::string key(name); + if (_cardStates.find(key) == _cardStates.end()) _cardStates[key] = true; + return _cardStates[key]; + }; + + float mainContentBottomY = ImGui::GetWindowPos().y + ImGui::GetWindowContentRegionMax().y; + constexpr const char* CardMaterialsTitle = "MaterialListCard"; + + if (Syn::UI::BeginCard(CardMaterialsTitle, SYN_ICON_BRUSH, getCardState(CardMaterialsTitle))) { + + RenderTopBar(vm); + + float currentY = ImGui::GetCursorScreenPos().y; + float gridHeight = mainContentBottomY - currentY - 12.0f; + if (gridHeight < 150.0f) gridHeight = 150.0f; + + ImGui::BeginChild("MaterialGridContainer", ImVec2(0, gridHeight), false, ImGuiWindowFlags_NoScrollbar); + + const auto& state = vm.GetState(); + const auto entries = state.filteredNodes; + const float thumbnailSize = 100.0f; + + Syn::UI::ItemCardContainer("MaterialGrid", (int)entries.size(), thumbnailSize, + [&](int index) { + const auto& entry = entries[index]; + + Syn::UI::ItemCardDesc desc; + desc.id = entry.path.c_str(); + desc.title = entry.name.c_str(); + + if (entry.hasPreview && state.atlasHandle) { + desc.texture = state.atlasHandle; + desc.uv0 = ImVec2(entry.uv0.x, entry.uv0.y); + desc.uv1 = ImVec2(entry.uv1.x, entry.uv1.y); + } + else { + desc.texture = InvalidTextureHandle; + } + + desc.selected = (state.selectedMaterial == entry.id); + + desc.events.onClick = [&vm, &entry] { + vm.Dispatch(MaterialSelectIntent{ entry.id }); + }; + + desc.events.onDoubleClick = [&vm, &entry] { + }; + + desc.events.onDragDropSource = [&entry] { + }; + + Syn::UI::ItemCard(desc, thumbnailSize); + }); + + ImGui::EndChild(); + } + Syn::UI::EndCard(); + + if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && ImGui::IsWindowHovered()) { + vm.Dispatch(MaterialSelectIntent{ INVALID_MATERIAL_ID }); + } + } + ImGui::End(); + ImGui::PopStyleVar(); + } + + void MaterialHierarchyView::RenderTopBar(MaterialHierarchyViewModel& vm) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(8, 6)); + + float barHeight = ImGui::GetFrameHeight(); + ImGui::BeginChild("MaterialTopBar", ImVec2(0, barHeight), false, ImGuiWindowFlags_NoScrollbar); + + if (ImGui::Button(SYN_ICON_SYNC " Refresh")) { + vm.Dispatch(MaterialRefreshIntent{}); + } + + ImGui::SameLine(); + ImGui::Dummy(ImVec2(8.0f, 0.0f)); + ImGui::SameLine(); + + ImGui::AlignTextToFramePadding(); + ImGui::TextDisabled(SYN_ICON_SEARCH); + ImGui::SameLine(); + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + + const auto& state = vm.GetState(); + char searchBuffer[256]; + strncpy(searchBuffer, state.searchQuery.c_str(), sizeof(searchBuffer)); + searchBuffer[sizeof(searchBuffer) - 1] = '\0'; + + if (ImGui::InputTextWithHint("##SearchMaterials", "Search...", searchBuffer, IM_ARRAYSIZE(searchBuffer))) { + vm.Dispatch(MaterialSetSearchQueryIntent{ std::string(searchBuffer) }); + } + + ImGui::EndChild(); + ImGui::PopStyleVar(); + ImGui::Spacing(); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialHierarchy/MaterialHierarchyView.h b/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialHierarchy/MaterialHierarchyView.h new file mode 100644 index 00000000..6d2eaccb --- /dev/null +++ b/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialHierarchy/MaterialHierarchyView.h @@ -0,0 +1,16 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyViewModel.h" +#include +#include + +namespace Syn { + class MaterialHierarchyView : public IView { + public: + void Draw(MaterialHierarchyViewModel& vm) override; + private: + void RenderTopBar(MaterialHierarchyViewModel& vm); + private: + std::unordered_map _cardStates; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialProperties/MaterialPropertiesView.cpp b/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialProperties/MaterialPropertiesView.cpp new file mode 100644 index 00000000..33338a93 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialProperties/MaterialPropertiesView.cpp @@ -0,0 +1,156 @@ +#include "MaterialPropertiesView.h" +#include "Editor/Manager/EditorIcons.h" +#include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/PropertyGrid.h" +#include + +namespace Syn { + void MaterialPropertiesView::Draw(MaterialPropertiesViewModel& vm) { + const auto& state = vm.GetState(); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 8)); + ImGuiWindowFlags windowFlags = ImGuiWindowFlags_None; + + if (ImGui::Begin(SYN_ICON_INFO_CIRCLE " Material Properties", nullptr, windowFlags)) { + + auto getCardState = [this](const char* name) -> bool& { + std::string key(name); + if (_cardStates.find(key) == _cardStates.end()) _cardStates[key] = true; + return _cardStates[key]; + }; + + if (!state.hasSelection) { + ImGui::TextDisabled("No material selected."); + ImGui::End(); + ImGui::PopStyleVar(); + return; + } + + Material editedMat = state.materialData; + bool isModified = false; + + constexpr const char* BasicPropsCard = "MatBasicPropsCard"; + if (Syn::UI::BeginCard(BasicPropsCard, SYN_ICON_SLIDERS_H, getCardState(BasicPropsCard))) { + if (Syn::UI::BeginPropertyGrid("MatPropsGrid")) { + if (Syn::UI::PropertyColor4("Color", editedMat.color)) isModified = true; + if (Syn::UI::PropertyColor3("Emissive Color", editedMat.emissiveColor)) isModified = true; + if (Syn::UI::PropertyDragFloat("Emissive Intensity", editedMat.emissiveIntensity, 0.1f, 0.0f, 1000.0f, "%.2f")) isModified = true; + if (Syn::UI::PropertyDragFloat2("UV Scale", editedMat.uvScale, 0.05f, 0.0f, 0.0f, "%.2f")) isModified = true; + + Syn::UI::PropertySeparator(); + + if (Syn::UI::PropertyDragFloat("Metalness", editedMat.metalness, 0.01f, 0.0f, 1.0f, "%.2f")) isModified = true; + if (Syn::UI::PropertyDragFloat("Roughness", editedMat.roughness, 0.01f, 0.0f, 1.0f, "%.2f")) isModified = true; + if (Syn::UI::PropertyDragFloat("AO Strength", editedMat.aoStrength, 0.01f, 0.0f, 1.0f, "%.2f")) isModified = true; + + Syn::UI::PropertySeparator(); + + if (Syn::UI::PropertyCheckbox("Double Sided", editedMat.doubleSided)) isModified = true; + if (Syn::UI::PropertyCheckbox("Transparent", editedMat.isTransparent)) isModified = true; + + Syn::UI::EndPropertyGrid(); + } + } + Syn::UI::EndCard(); + + ImGui::Spacing(); + + constexpr const char* TexturesCard = "MatTexturesCard"; + if (Syn::UI::BeginCard(TexturesCard, SYN_ICON_IMAGE, getCardState(TexturesCard))) { + if (Syn::UI::BeginPropertyGrid("MatTexGrid")) { + + DrawTextureSlot("Albedo", + editedMat.albedoTexture, state.albedoName, state.availableTextures, + editedMat.albedoSampler, state.albedoSamplerName, state.availableSamplers, isModified); + + DrawTextureSlot("Normal", + editedMat.normalTexture, state.normalName, state.availableTextures, + editedMat.normalSampler, state.normalSamplerName, state.availableSamplers, isModified); + + DrawTextureSlot("Metalness", + editedMat.metalnessTexture, state.metalnessName, state.availableTextures, + editedMat.metalnessSampler, state.metalnessSamplerName, state.availableSamplers, isModified); + + DrawTextureSlot("Roughness", + editedMat.roughnessTexture, state.roughnessName, state.availableTextures, + editedMat.roughnessSampler, state.roughnessSamplerName, state.availableSamplers, isModified); + + DrawTextureSlot("MetallicRoughness", + editedMat.metallicRoughnessTexture, state.metallicRoughnessName, state.availableTextures, + editedMat.metallicRoughnessSampler, state.metallicRoughnessSamplerName, state.availableSamplers, isModified); + + DrawTextureSlot("Emissive", + editedMat.emissiveTexture, state.emissiveName, state.availableTextures, + editedMat.emissiveSampler, state.emissiveSamplerName, state.availableSamplers, isModified); + + DrawTextureSlot("AO", + editedMat.ambientOcclusionTexture, state.aoName, state.availableTextures, + editedMat.ambientOcclusionSampler, state.aoSamplerName, state.availableSamplers, isModified); + + Syn::UI::EndPropertyGrid(); + } + } + Syn::UI::EndCard(); + + if (isModified) { + vm.Dispatch(UpdateMaterialPropertyIntent{ editedMat }); + } + } + + ImGui::End(); + ImGui::PopStyleVar(); + } + + void MaterialPropertiesView::DrawTextureSlot( + const char* label, + uint32_t& currentTexId, const std::string& currentTexName, const std::vector& texOptions, + uint32_t& currentSampId, const std::string& currentSampName, const std::vector& sampOptions, + bool& changed) + { + std::string texLabel = std::string(label) + " Tex"; + if (Syn::UI::BeginPropertyCombo(texLabel.c_str(), currentTexName.c_str())) { + if (ImGui::Selectable("None", currentTexId == 0xFFFFFFFF)) { + if (currentTexId != 0xFFFFFFFF) { + currentTexId = 0xFFFFFFFF; + changed = true; + } + } + for (const auto& opt : texOptions) { + bool isSelected = (currentTexId == opt.id); + if (ImGui::Selectable(opt.name.c_str(), isSelected)) { + if (currentTexId != opt.id) { + currentTexId = opt.id; + changed = true; + } + } + if (isSelected) ImGui::SetItemDefaultFocus(); + } + Syn::UI::EndPropertyCombo(); + } + + std::string sampLabel = std::string(label) + " Sampler"; + if (Syn::UI::BeginPropertyCombo(sampLabel.c_str(), currentSampName.c_str())) { + + if (ImGui::Selectable("Default", currentSampId == 0xFFFFFFFF)) { + if (currentSampId != 0xFFFFFFFF) { + currentSampId = 0xFFFFFFFF; + changed = true; + } + } + + for (const auto& opt : sampOptions) { + bool isSelected = (currentSampId == opt.id); + if (ImGui::Selectable(opt.name.c_str(), isSelected)) { + if (currentSampId != opt.id) { + currentSampId = opt.id; + changed = true; + } + } + if (isSelected) ImGui::SetItemDefaultFocus(); + } + Syn::UI::EndPropertyCombo(); + } + + Syn::UI::PropertySeparator(); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialProperties/MaterialPropertiesView.h b/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialProperties/MaterialPropertiesView.h new file mode 100644 index 00000000..aa238cfc --- /dev/null +++ b/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialProperties/MaterialPropertiesView.h @@ -0,0 +1,19 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesViewModel.h" +#include +#include + +namespace Syn { + class MaterialPropertiesView : public IView { + public: + void Draw(MaterialPropertiesViewModel& vm) override; + private: + void DrawTextureSlot(const char* label, + uint32_t& currentTexId, const std::string& currentTexName, const std::vector& texOptions, + uint32_t& currentSampId, const std::string& currentSampName, const std::vector& sampOptions, + bool& changed); + private: + std::unordered_map _cardStates; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialViewport/MaterialViewportView.cpp b/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialViewport/MaterialViewportView.cpp new file mode 100644 index 00000000..244b827a --- /dev/null +++ b/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialViewport/MaterialViewportView.cpp @@ -0,0 +1,42 @@ +#include "MaterialViewportView.h" +#include "Editor/Manager/EditorIcons.h" +#include + +namespace Syn { + + void MaterialViewportView::Draw(MaterialViewportViewModel& vm) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{ 0, 0 }); + + ImGui::Begin(SYN_ICON_LAYER_GROUP " Material Viewport", nullptr); + + MaterialViewportState state = vm.GetState(); + + ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail(); + uint32_t currentWidth = static_cast(viewportPanelSize.x); + uint32_t currentHeight = static_cast(viewportPanelSize.y); + + bool isResizing = (currentWidth > 0 && currentHeight > 0 && + (currentWidth != state.width || currentHeight != state.height)); + + vm.Dispatch(ResizeMaterialViewportIntent{ currentWidth, currentHeight }); + + if (viewportPanelSize.x <= 0.0f) viewportPanelSize.x = 1.0f; + if (viewportPanelSize.y <= 0.0f) viewportPanelSize.y = 1.0f; + + if (state.textureId && !isResizing) { + ImGui::GetWindowDrawList()->AddCallback(ImGui::GetPlatformIO().DrawCallback_SetSamplerNearest, nullptr); + ImGui::Image(state.textureId, viewportPanelSize); + ImGui::GetWindowDrawList()->AddCallback(ImGui::GetPlatformIO().DrawCallback_SetSamplerLinear, nullptr); + } + else { + ImGui::Dummy(viewportPanelSize); + } + + state.isHovered = ImGui::IsWindowHovered(); + state.isFocused = ImGui::IsWindowFocused(); + + ImGui::End(); + ImGui::PopStyleVar(); + } + +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialViewport/MaterialViewportView.h b/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialViewport/MaterialViewportView.h new file mode 100644 index 00000000..39138a46 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/MaterialWorkspace/View/MaterialViewport/MaterialViewportView.h @@ -0,0 +1,11 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportViewModel.h" +#include + +namespace Syn { + class MaterialViewportView : public IView { + public: + void Draw(MaterialViewportViewModel& vm) override; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/ModelWorkspace.cpp b/SynapseEngine/Editor/Workspace/ModelWorkspace.cpp deleted file mode 100644 index fc3fe9bd..00000000 --- a/SynapseEngine/Editor/Workspace/ModelWorkspace.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "ModelWorkspace.h" -#include "Editor/Manager/EditorIcons.h" - -#include "Editor/View/ContentBrowser/ContentBrowserView.h" -#include "EditorCore/ViewModels/ContentBrowser/ContentBrowserViewModel.h" - -namespace Syn { - - ModelWorkspace::ModelWorkspace(EditorContext* context, IconManager* iconManager, const std::string& assetPath) - : _context(context), _iconManager(iconManager), _assetPath(assetPath) {} - - void ModelWorkspace::Initialize() { - using ContentBrowserWin = EditorWindow; - AddWindow( - ContentBrowserView{ _iconManager, SYN_ICON_FOLDER_OPEN " Content Browser###Content_Model" }, - ContentBrowserViewModel{ _context->GetFileSystemApi(), _assetPath } - ); - } - -} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/ModelWorkspace/ModelWorkspace.cpp b/SynapseEngine/Editor/Workspace/ModelWorkspace/ModelWorkspace.cpp new file mode 100644 index 00000000..56926149 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/ModelWorkspace/ModelWorkspace.cpp @@ -0,0 +1,61 @@ +#include "ModelWorkspace.h" +#include "Editor/Manager/EditorIcons.h" + +#include "Editor/Workspace/Common/ContentBrowser/ContentBrowserView.h" +#include "EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserViewModel.h" + +#include "View/ModelHierarchy/ModelHierarchyView.h" +#include "EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyViewModel.h" + +#include "View/ModelProperties/ModelPropertiesView.h" +#include "EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesViewModel.h" + +#include "View/ModelViewport/ModelViewportView.h" +#include "EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportViewModel.h" + +#include "Engine/Scene/SceneNames.h" + +namespace Syn { + + ModelWorkspace::ModelWorkspace(EditorContext* context, IconManager* iconManager, const std::string& assetPath) + : _context(context), _iconManager(iconManager), _assetPath(assetPath) {} + + void ModelWorkspace::OnActivate() { + if (_context && _context->GetApi()) { + _context->GetApi()->ActivateScene(SceneNames::ModelPreview); + } + } + + void ModelWorkspace::Initialize() { + + using ContentBrowserWin = EditorWindow; + AddWindow( + ContentBrowserView{ _iconManager, SYN_ICON_FOLDER_OPEN " Content Browser###Content_Model" }, + ContentBrowserViewModel{ _context->GetApi(), _assetPath } + ); + + using ModelHierarchyWin = EditorWindow; + AddWindow( + ModelHierarchyView{}, + ModelHierarchyViewModel{ _context->GetApi(), _context->GetApi() } + ); + + using ModelPropertiesWin = EditorWindow; + AddWindow( + ModelPropertiesView{}, + ModelPropertiesViewModel{ _context->GetApi() } + ); + + using ModelViewportWin = EditorWindow; + AddWindow( + ModelViewportView{}, + ModelViewportViewModel{ + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi() + } + ); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/ModelWorkspace.h b/SynapseEngine/Editor/Workspace/ModelWorkspace/ModelWorkspace.h similarity index 86% rename from SynapseEngine/Editor/Workspace/ModelWorkspace.h rename to SynapseEngine/Editor/Workspace/ModelWorkspace/ModelWorkspace.h index 60722461..5fd3216d 100644 --- a/SynapseEngine/Editor/Workspace/ModelWorkspace.h +++ b/SynapseEngine/Editor/Workspace/ModelWorkspace/ModelWorkspace.h @@ -1,5 +1,5 @@ #pragma once -#include "IWorkspace.h" +#include "Editor/Workspace/IWorkspace.h" #include "Editor/EditorApi/EditorContext.h" #include "Editor/Manager/IconManager.h" #include @@ -12,6 +12,7 @@ namespace Syn { ~ModelWorkspace() override = default; void Initialize() override; + void OnActivate() override; private: EditorContext* _context; IconManager* _iconManager; diff --git a/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelHierarchy/ModelHierarchyView.cpp b/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelHierarchy/ModelHierarchyView.cpp new file mode 100644 index 00000000..cf3a594b --- /dev/null +++ b/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelHierarchy/ModelHierarchyView.cpp @@ -0,0 +1,212 @@ +#include "ModelHierarchyView.h" +#include "Editor/Manager/EditorIcons.h" +#include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/ItemCardWidget.h" +#include "Editor/Widgets/ItemCardContainerWidget.h" +#include + +namespace Syn +{ + void ModelHierarchyView::Draw(ModelHierarchyViewModel& vm) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 8)); + ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; + + const auto& state = vm.GetState(); + + auto getCardState = [this](const char* name) -> bool& { + std::string key(name); + if (_cardStates.find(key) == _cardStates.end()) _cardStates[key] = true; + return _cardStates[key]; + }; + + if (ImGui::Begin(SYN_ICON_CUBE " Models", nullptr, windowFlags)) { + + float mainContentBottomY = ImGui::GetWindowPos().y + ImGui::GetWindowContentRegionMax().y; + constexpr const char* CardModelTitle = "ModelListCard"; + + if (Syn::UI::BeginCard(CardModelTitle, SYN_ICON_CUBE, getCardState(CardModelTitle))) { + RenderTopBar(vm); + + float currentY = ImGui::GetCursorScreenPos().y; + float gridHeight = mainContentBottomY - currentY - 12.0f; + if (gridHeight < 150.0f) gridHeight = 150.0f; + + ImGui::BeginChild("ModelGridContainer", ImVec2(0, gridHeight), false, ImGuiWindowFlags_NoScrollbar); + + const auto& entries = state.filteredModels; + const float thumbnailSize = 100.0f; + + Syn::UI::ItemCardContainer("ModelGrid", (int)entries.size(), thumbnailSize, + [&](int index) { + const auto& entry = entries[index]; + + Syn::UI::ItemCardDesc desc; + std::string idStr = std::to_string(entry.id); + desc.id = idStr.c_str(); + desc.title = entry.name.c_str(); + + if (entry.hasPreview && state.atlasHandle) { + desc.texture = state.atlasHandle; + desc.uv0 = ImVec2(entry.uv0.x, entry.uv0.y); + desc.uv1 = ImVec2(entry.uv1.x, entry.uv1.y); + } + else { + desc.texture = InvalidTextureHandle; + } + + desc.selected = (state.selectedModelId == entry.id); + + desc.events.onClick = [&vm, &entry] { + vm.Dispatch(ModelHierarchySelectIntent{ entry.id, -1 }); + }; + + desc.events.onDoubleClick = [&vm, &entry] {}; + desc.events.onDragDropSource = [&entry] {}; + + Syn::UI::ItemCard(desc, thumbnailSize); + }); + + ImGui::EndChild(); + } + Syn::UI::EndCard(); + + if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && ImGui::IsWindowHovered()) { + vm.Dispatch(ModelHierarchySelectIntent{ 0xFFFFFFFF, -1 }); + } + } + ImGui::End(); + + + if (ImGui::Begin(SYN_ICON_LIST " Internal Hierarchy", nullptr, windowFlags)) { + + float mainContentBottomY = ImGui::GetWindowPos().y + ImGui::GetWindowContentRegionMax().y; + constexpr const char* CardHierarchyTitle = "Internal Hierarchy Card"; + + if (Syn::UI::BeginCard(CardHierarchyTitle, SYN_ICON_LIST, getCardState(CardHierarchyTitle))) { + + if (state.selectedModelId != 0xFFFFFFFF) { + ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.08f, 0.08f, 0.08f, 0.6f)); + ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 8.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); + + float currentY = ImGui::GetCursorScreenPos().y; + float tableHeight = mainContentBottomY - currentY - 12.0f; + if (tableHeight < 100.0f) tableHeight = 100.0f; + + ImGui::BeginChild("ModelHierarchyTableContainer", ImVec2(0, tableHeight), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoScrollbar); + + if (ImGui::BeginTable("ModelTable", 1, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Resizable)) { + ImGui::TableSetupScrollFreeze(0, 1); + ImGui::TableSetupColumn("Hierarchy", ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableSetColumnIndex(0); + + float cellWidth = ImGui::GetColumnWidth(); + float textWidth = ImGui::CalcTextSize("Hierarchy").x; + ImVec2 startPos = ImGui::GetCursorPos(); + + ImGui::TableHeader("##ColHierarchy"); + ImGui::SetCursorPos(ImVec2(startPos.x + (cellWidth - textWidth) * 0.5f, startPos.y + 3.0f)); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); + ImGui::Text("Hierarchy"); + ImGui::PopStyleColor(); + + ImGuiListClipper clipper; + clipper.Begin(static_cast(state.flatNodes.size())); + + while (clipper.Step()) { + for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; ++row) { + RenderNodeRow(vm, state.flatNodes[row]); + } + } + + ImGui::EndTable(); + } + ImGui::EndChild(); + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(); + } + else { + ImGui::Spacing(); + ImGui::Indent(8.0f); + ImGui::TextDisabled("Select a model to view its internal hierarchy."); + ImGui::Unindent(8.0f); + } + } + Syn::UI::EndCard(); + } + ImGui::End(); + + ImGui::PopStyleVar(); + } + + void ModelHierarchyView::RenderTopBar(ModelHierarchyViewModel& vm) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(8, 6)); + + float barHeight = ImGui::GetFrameHeight(); + ImGui::BeginChild("ModelTopBar", ImVec2(0, barHeight), false, ImGuiWindowFlags_NoScrollbar); + + if (ImGui::Button(SYN_ICON_SYNC " Refresh##ModelHierarchy")) { + vm.Dispatch(ModelHierarchyRefreshIntent{}); + } + + ImGui::SameLine(); + ImGui::Dummy(ImVec2(8.0f, 0.0f)); + ImGui::SameLine(); + + ImGui::AlignTextToFramePadding(); + ImGui::TextDisabled(SYN_ICON_SEARCH); + ImGui::SameLine(); + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + + const auto& state = vm.GetState(); + char searchBuffer[256]; + strncpy(searchBuffer, state.searchQuery.c_str(), sizeof(searchBuffer)); + searchBuffer[sizeof(searchBuffer) - 1] = '\0'; + + if (ImGui::InputTextWithHint("##SearchModels", "Search...", searchBuffer, IM_ARRAYSIZE(searchBuffer))) { + vm.Dispatch(ModelHierarchySetSearchIntent{ std::string(searchBuffer) }); + } + + ImGui::EndChild(); + ImGui::PopStyleVar(); + ImGui::Spacing(); + } + + void ModelHierarchyView::RenderNodeRow(ModelHierarchyViewModel& vm, const ModelHierarchyNode& node) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_FramePadding | ImGuiTreeNodeFlags_NoTreePushOnOpen; + + if (!node.hasChildren) { + flags |= ImGuiTreeNodeFlags_Leaf; + } + + const auto& state = vm.GetState(); + if (state.selectedModelId == node.modelId && state.selectedDescriptorIndex == node.descriptorIndex) { + flags |= ImGuiTreeNodeFlags_Selected; + } + + ImGui::SetNextItemOpen(node.isExpanded, ImGuiCond_Always); + + float indentStep = 16.0f; + ImGui::Indent(node.depth * indentStep); + + std::string label = node.icon + " " + node.name + "##NodeID_" + std::to_string(node.modelId) + "_" + std::to_string(node.descriptorIndex); + + ImGui::TreeNodeEx(label.c_str(), flags); + + ImGui::Unindent(node.depth * indentStep); + + if (ImGui::IsItemClicked(ImGuiMouseButton_Left) && !ImGui::IsItemToggledOpen()) { + vm.Dispatch(ModelHierarchySelectIntent{ node.modelId, node.descriptorIndex }); + } + + if (ImGui::IsItemToggledOpen()) { + vm.Dispatch(ModelHierarchyToggleExpandIntent{ node.modelId, node.descriptorIndex, !node.isExpanded }); + } + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelHierarchy/ModelHierarchyView.h b/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelHierarchy/ModelHierarchyView.h new file mode 100644 index 00000000..f736a2f9 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelHierarchy/ModelHierarchyView.h @@ -0,0 +1,17 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyViewModel.h" +#include +#include + +namespace Syn { + class ModelHierarchyView : public IView { + public: + void Draw(ModelHierarchyViewModel& vm) override; + private: + void RenderTopBar(ModelHierarchyViewModel& vm); + void RenderNodeRow(ModelHierarchyViewModel& vm, const ModelHierarchyNode& node); + private: + std::unordered_map _cardStates; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelProperties/ModelPropertiesView.cpp b/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelProperties/ModelPropertiesView.cpp new file mode 100644 index 00000000..2229cb92 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelProperties/ModelPropertiesView.cpp @@ -0,0 +1,65 @@ +#include "ModelPropertiesView.h" +#include "Editor/Manager/EditorIcons.h" +#include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/PropertyGrid.h" +#include + +namespace Syn { + void ModelPropertiesView::Draw(ModelPropertiesViewModel& vm) { + const auto& state = vm.GetState(); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 8)); + + if (ImGui::Begin(SYN_ICON_INFO_CIRCLE " Model Properties##ModelPropsWindow", nullptr)) { + + if (!state.hasSelection) { + ImGui::TextDisabled("No model or mesh selected."); + ImGui::End(); + ImGui::PopStyleVar(); + return; + } + + auto getCardState = [this](const char* name) -> bool& { + std::string key(name); + if (_cardStates.find(key) == _cardStates.end()) _cardStates[key] = true; + return _cardStates[key]; + }; + + if (Syn::UI::BeginCard("ModelGlobalPropsCard", SYN_ICON_CUBE, getCardState("ModelGlobalPropsCard"))) { + ImGui::Text("Model: "); ImGui::SameLine(); + ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f), "%s", state.modelName.c_str()); + + if (Syn::UI::BeginPropertyGrid("GlobalGrid")) { + DrawPropertyRow("Vertices", std::to_string(state.globalVertexCount)); + DrawPropertyRow("Indices", std::to_string(state.globalIndexCount)); + DrawPropertyRow("Triangles", std::to_string(state.globalIndexCount / 3)); + Syn::UI::EndPropertyGrid(); + } + } + Syn::UI::EndCard(); + + if (state.isNodeSelected) { + ImGui::Spacing(); + if (Syn::UI::BeginCard("NodePropsCard", SYN_ICON_PROJECT_DIAGRAM, getCardState("NodePropsCard"))) { + ImGui::Text("Node: "); ImGui::SameLine(); + ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.6f, 1.0f), "%s", state.nodeName.c_str()); + + if (Syn::UI::BeginPropertyGrid("NodeGrid")) { + DrawPropertyRow("Mesh Index", state.meshIndex == 0xFFFF ? "None" : std::to_string(state.meshIndex)); + DrawPropertyRow("Triangles", std::to_string(state.nodeIndexCount / 3)); + DrawPropertyRow("Meshlets", std::to_string(state.nodeMeshletCount)); + Syn::UI::EndPropertyGrid(); + } + } + Syn::UI::EndCard(); + } + } + + ImGui::End(); + ImGui::PopStyleVar(); + } + + void ModelPropertiesView::DrawPropertyRow(const char* label, const std::string& value) { + Syn::UI::PropertyText(label, value.c_str()); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelProperties/ModelPropertiesView.h b/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelProperties/ModelPropertiesView.h new file mode 100644 index 00000000..c4218e85 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelProperties/ModelPropertiesView.h @@ -0,0 +1,16 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesViewModel.h" +#include +#include + +namespace Syn { + class ModelPropertiesView : public IView { + public: + void Draw(ModelPropertiesViewModel& vm) override; + private: + void DrawPropertyRow(const char* label, const std::string& value); + private: + std::unordered_map _cardStates; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelViewport/ModelViewportView.cpp b/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelViewport/ModelViewportView.cpp new file mode 100644 index 00000000..4f4a90f3 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelViewport/ModelViewportView.cpp @@ -0,0 +1,261 @@ +#include "ModelViewportView.h" +#include "Engine/Vk/Image/ImageUtils.h" +#include "Editor/Manager/EditorIcons.h" +#include +#include +#include +#include +#include "Engine/Scene/DrawData/SceneDrawData.h" + +namespace Syn { + + void ModelViewportView::Draw(ModelViewportViewModel& vm) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{ 0, 0 }); + + ImGui::Begin(SYN_ICON_CUBES " Model Viewport", nullptr); + + ModelViewportState state = vm.GetState(); + + ImVec2 viewportPanelSize = ImGui::GetContentRegionAvail(); + uint32_t currentWidth = static_cast(viewportPanelSize.x); + uint32_t currentHeight = static_cast(viewportPanelSize.y); + + bool isResizing = (currentWidth > 0 && currentHeight > 0 && (currentWidth != state.width || currentHeight != state.height)); + + vm.Dispatch(ResizeModelViewportIntent{ currentWidth, currentHeight }); + + ImVec2 imageStartPos = ImGui::GetCursorScreenPos(); + + if (viewportPanelSize.x <= 0.0f) viewportPanelSize.x = 1.0f; + if (viewportPanelSize.y <= 0.0f) viewportPanelSize.y = 1.0f; + + if (state.textureId && !isResizing) { + ImGui::GetWindowDrawList()->AddCallback(ImGui::GetPlatformIO().DrawCallback_SetSamplerNearest, nullptr); + ImGui::Image(state.textureId, viewportPanelSize); + ImGui::GetWindowDrawList()->AddCallback(ImGui::GetPlatformIO().DrawCallback_SetSamplerLinear, nullptr); + } + else { + ImGui::Dummy(viewportPanelSize); + } + + bool isImageHovered = ImGui::IsItemHovered(); + + RenderFloatingToolbar(vm, state, imageStartPos, viewportPanelSize); + + DrawGizmo(vm, state, imageStartPos, viewportPanelSize); + + if (!ImGuizmo::IsUsing()) { + if (isImageHovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGuizmo::IsOver() && !ImGui::IsAnyItemHovered()) { + ImVec2 mousePos = ImGui::GetMousePos(); + uint32_t x = static_cast(mousePos.x - imageStartPos.x); + uint32_t y = static_cast(mousePos.y - imageStartPos.y); + vm.Dispatch(PickMeshIntent{ x, y }); + } + } + + HandleShortcuts(vm); + + ImGui::End(); + ImGui::PopStyleVar(); + } + + void ModelViewportView::RenderFloatingToolbar(ModelViewportViewModel& vm, const ModelViewportState& state, ImVec2 startPos, ImVec2 size) { + float toolbarWidth = 40.0f; + float toolbarHeight = 110.0f; + + ImGui::SetCursorScreenPos(ImVec2(startPos.x + size.x - toolbarWidth - 8.0f, startPos.y + 8.0f)); + + ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.1f, 0.1f, 0.1f, 0.85f)); + ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 6.0f); + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(4.0f, 6.0f)); + + if (ImGui::BeginChild("##ModelFloatingToolbar", ImVec2(toolbarWidth, toolbarHeight), ImGuiChildFlags_AlwaysUseWindowPadding, ImGuiWindowFlags_NoScrollbar)) { + + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4.0f, 6.0f)); + + if (ImGui::Button(SYN_ICON_ARROWS_ALT, ImVec2(32, 28))) ImGui::OpenPopup("GizmoPopup"); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Gizmo Settings"); + + if (ImGui::Button(SYN_ICON_LAYER_GROUP, ImVec2(32, 28))) ImGui::OpenPopup("ImagePopup"); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Render Targets & View Modes"); + + if (ImGui::Button(SYN_ICON_BUG, ImVec2(32, 28))) ImGui::OpenPopup("DebugPopup"); + if (ImGui::IsItemHovered()) ImGui::SetTooltip("Debug Visibility"); + + ImGui::PopStyleVar(); + ImGui::PopStyleColor(); + + DrawGizmoPopup(vm, state); + DrawImagePopup(vm, state); + DrawDebugPopup(vm, state); + } + ImGui::EndChild(); + + ImGui::PopStyleVar(2); + ImGui::PopStyleColor(); + } + + void ModelViewportView::DrawGizmoPopup(ModelViewportViewModel& vm, const ModelViewportState& state) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.0f, 8.0f)); + if (ImGui::BeginPopup("GizmoPopup")) { + if (ImGui::BeginChild("##GizmoWindow", ImVec2(240, 210), false)) { + + ImGui::SeparatorText("Operation"); + + int mode = static_cast(state.gizmoMode); + if (ImGui::RadioButton("Local##Gizmo", &mode, ImGuizmo::LOCAL)) + vm.Dispatch(ChangeModelGizmoModeIntent{ ImGuizmo::LOCAL }); + + ImGui::SameLine(); + if (ImGui::RadioButton("World##Gizmo", &mode, ImGuizmo::WORLD)) + vm.Dispatch(ChangeModelGizmoModeIntent{ ImGuizmo::WORLD }); + + int op = static_cast(state.gizmoOperation); + if (ImGui::RadioButton("Translate##Gizmo", &op, ImGuizmo::TRANSLATE)) + vm.Dispatch(ChangeModelGizmoOperationIntent{ ImGuizmo::TRANSLATE }); + ImGui::SameLine(); + if (ImGui::RadioButton("Rotate##Gizmo", &op, ImGuizmo::ROTATE)) + vm.Dispatch(ChangeModelGizmoOperationIntent{ ImGuizmo::ROTATE }); + ImGui::SameLine(); + if (ImGui::RadioButton("Scale##Gizmo", &op, ImGuizmo::SCALE)) + vm.Dispatch(ChangeModelGizmoOperationIntent{ ImGuizmo::SCALE }); + + ImGui::SeparatorText("Snapping"); + + bool snap = state.useSnap; + if (ImGui::Checkbox("Enable##Snap", &snap)) + vm.Dispatch(ToggleModelSnapIntent{ snap }); + + glm::vec3 snapTrans = state.snapTranslate; + if (ImGui::DragFloat3("Translate##Snap", glm::value_ptr(snapTrans), 0.1f)) + vm.Dispatch(ChangeModelSnapTranslateIntent{ snapTrans }); + + float snapRot = state.snapAngle; + if (ImGui::DragFloat("Rotate##Snap", &snapRot, 1.0f)) + vm.Dispatch(ChangeModelSnapRotateIntent{ snapRot }); + + float snapScl = state.snapScale; + if (ImGui::DragFloat("Scale##Snap", &snapScl, 0.1f)) + vm.Dispatch(ChangeModelSnapScaleIntent{ snapScl }); + + } + ImGui::EndChild(); + ImGui::EndPopup(); + } + ImGui::PopStyleVar(); + } + + void ModelViewportView::DrawImagePopup(ModelViewportViewModel& vm, const ModelViewportState& state) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.0f, 8.0f)); + if (ImGui::BeginPopup("ImagePopup")) { + if (ImGui::BeginChild("##ViewportImage", ImVec2(280, 200), false)) { + + auto RadioButton = [&](const char* label, const std::string& group, const std::string& target, const std::string& view) { + bool isActive = (state.currentTarget == target && state.currentView == view); + if (ImGui::RadioButton(label, isActive)) { + vm.Dispatch(ChangeModelTargetIntent{ group, target, view }); + } + return isActive; + }; + + RadioButton("Main", RenderTargetGroupNames::Main, RenderTargetNames::Main, Vk::ImageViewNames::Default); + + ImGui::SeparatorText("GBuffer Textures"); + + RadioButton("Color", RenderTargetGroupNames::Main, RenderTargetNames::ColorMetallic, RenderTargetViewNames::Color); + RadioButton("Metallic", RenderTargetGroupNames::Main, RenderTargetNames::ColorMetallic, RenderTargetViewNames::Metallic); + RadioButton("Normal", RenderTargetGroupNames::Main, RenderTargetNames::NormalRoughness, RenderTargetViewNames::Normal); + RadioButton("Roughness", RenderTargetGroupNames::Main, RenderTargetNames::NormalRoughness, RenderTargetViewNames::Roughness); + } + ImGui::EndChild(); + ImGui::EndPopup(); + } + ImGui::PopStyleVar(); + } + + void ModelViewportView::DrawDebugPopup(ModelViewportViewModel& vm, const ModelViewportState& state) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.0f, 8.0f)); + if (ImGui::BeginPopup("DebugPopup")) { + if (ImGui::BeginChild("##VisualizationWindow", ImVec2(220, 280), false)) { + + ImGui::SeparatorText("Debug Visibility"); + + bool enabled = state.enableDebugVisibility; + if (ImGui::Checkbox("Enable", &enabled)) { + vm.Dispatch(ToggleModelDebugVisibilityIntent{ enabled }); + } + + ImGui::BeginDisabled(!state.enableDebugVisibility); + + ImGui::SeparatorText("Mode"); + + int mode = static_cast(state.debugVisibilityMode); + auto RadioButton = [&](const char* label, int targetMode) { + if (ImGui::RadioButton(label, &mode, targetMode)) { + vm.Dispatch(ChangeModelDebugVisibilityModeIntent{ static_cast(targetMode) }); + } + }; + + RadioButton("Entity ID", 0); + RadioButton("Pipeline Type", 1); + RadioButton("LOD Level", 2); + RadioButton("Mesh Index", 3); + RadioButton("Meshlet Index", 4); + RadioButton("Triangle Index", 5); + RadioButton("All Combined", 6); + RadioButton("Material Type", 7); + + ImGui::EndDisabled(); + + } + ImGui::EndChild(); + ImGui::EndPopup(); + } + ImGui::PopStyleVar(); + } + + void ModelViewportView::DrawGizmo(ModelViewportViewModel& vm, const ModelViewportState& state, ImVec2 startPos, ImVec2 size) { + if (state.activeEntity == NULL_ENTITY) + return; + + ImGuizmo::SetOrthographic(false); + ImGuizmo::SetDrawlist(); + ImGuizmo::SetRect(startPos.x, startPos.y, size.x, size.y); + + glm::mat4 cameraView = state.cameraView; + glm::mat4 cameraProj = state.cameraProj; + glm::mat4 transform = state.entityWorldTransform; + + float* snapValue = nullptr; + if (state.useSnap) { + switch (state.gizmoOperation) { + case ImGuizmo::TRANSLATE: snapValue = const_cast(glm::value_ptr(state.snapTranslate)); break; + case ImGuizmo::ROTATE: snapValue = const_cast(&state.snapAngle); break; + case ImGuizmo::SCALE: snapValue = const_cast(&state.snapScale); break; + } + } + + ImGuizmo::Manipulate( + glm::value_ptr(cameraView), + glm::value_ptr(cameraProj), + state.gizmoOperation, + state.gizmoMode, + glm::value_ptr(transform), + nullptr, snapValue + ); + + if (ImGuizmo::IsUsing()) { + vm.Dispatch(ApplyModelGizmoTransformIntent{ transform }); + } + } + + void ModelViewportView::HandleShortcuts(ModelViewportViewModel& vm) { + if (ImGui::IsWindowFocused() || ImGui::IsWindowHovered()) { + if (ImGui::IsKeyPressed(ImGuiKey_1)) vm.Dispatch(ChangeModelGizmoOperationIntent{ ImGuizmo::TRANSLATE }); + if (ImGui::IsKeyPressed(ImGuiKey_2)) vm.Dispatch(ChangeModelGizmoOperationIntent{ ImGuizmo::ROTATE }); + if (ImGui::IsKeyPressed(ImGuiKey_3)) vm.Dispatch(ChangeModelGizmoOperationIntent{ ImGuizmo::SCALE }); + } + } + +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelViewport/ModelViewportView.h b/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelViewport/ModelViewportView.h new file mode 100644 index 00000000..c48e8608 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/ModelWorkspace/View/ModelViewport/ModelViewportView.h @@ -0,0 +1,20 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportViewModel.h" +#include + +namespace Syn { + class ModelViewportView : public IView { + public: + void Draw(ModelViewportViewModel& vm) override; + private: + void RenderFloatingToolbar(ModelViewportViewModel& vm, const ModelViewportState& state, ImVec2 startPos, ImVec2 size); + + void DrawGizmoPopup(ModelViewportViewModel& vm, const ModelViewportState& state); + void DrawImagePopup(ModelViewportViewModel& vm, const ModelViewportState& state); + void DrawDebugPopup(ModelViewportViewModel& vm, const ModelViewportState& state); + + void DrawGizmo(ModelViewportViewModel& vm, const ModelViewportState& state, ImVec2 startPos, ImVec2 size); + void HandleShortcuts(ModelViewportViewModel& vm); + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace.cpp deleted file mode 100644 index ca378eaa..00000000 --- a/SynapseEngine/Editor/Workspace/SceneWorkspace.cpp +++ /dev/null @@ -1,78 +0,0 @@ -#include "SceneWorkspace.h" -#include "Editor/Manager/EditorIcons.h" - -#include "Editor/View/ContentBrowser/ContentBrowserView.h" -#include "EditorCore/ViewModels/ContentBrowser/ContentBrowserViewModel.h" -#include "Editor/View/Component/ComponentView.h" -#include "EditorCore/ViewModels/Component/ComponentViewModel.h" -#include "Editor/View/Viewport/ViewportView.h" -#include "EditorCore/ViewModels/Viewport/ViewportViewModel.h" -#include "Editor/View/Settings/SettingsView.h" -#include "EditorCore/ViewModels/Settings/SettingsViewModel.h" -#include "Editor/View/Hierarchy/HierarchyView.h" -#include "EditorCore/ViewModels/Hierarchy/HierarchyViewModel.h" -#include "Editor/View/Benchmark/BenchmarkView.h" -#include "EditorCore/ViewModels/Benchmark/BenchmarkViewModel.h" -#include "Editor/View/Logger/LoggerView.h" -#include "EditorCore/ViewModels/Logger/LoggerViewModel.h" - -namespace Syn { - - SceneWorkspace::SceneWorkspace(EditorContext* context, IconManager* iconManager, const std::string& assetPath) - : _context(context), _iconManager(iconManager), _assetPath(assetPath) {} - - void SceneWorkspace::Initialize() - { - using ContentBrowserWin = EditorWindow; - AddWindow( - ContentBrowserView{ _iconManager, SYN_ICON_FOLDER_OPEN " Content Browser###Content_Scene" }, - ContentBrowserViewModel{ _context->GetFileSystemApi(), _assetPath } - ); - - using ComponentWin = EditorWindow; - AddWindow( - ComponentView{}, - ComponentViewModel{ - _context->GetSelectionApi(), _context->GetTagApi(), _context->GetTransformApi(), - _context->GetHierarchyApi(), _context->GetDirectionLightApi(), - _context->GetPointLightApi(), _context->GetSpotLightApi() - } - ); - - using ViewportWin = EditorWindow; - AddWindow( - ViewportView{}, - ViewportViewModel{ - _context->GetRenderApi(), _context->GetSelectionApi(), _context->GetTransformApi(), - _context->GetSettingsApi(), _context->GetHierarchyApi() - } - ); - - using SettingsWin = EditorWindow; - AddWindow( - SettingsView{}, - SettingsViewModel{ _context->GetSettingsApi() } - ); - - using HierarchyWin = EditorWindow; - AddWindow( - HierarchyView{}, - HierarchyViewModel{ _context->GetHierarchyApi(), _context->GetSelectionApi(), _context->GetTagApi() } - ); - - using BenchmarkWin = EditorWindow; - AddWindow( - BenchmarkView{}, - BenchmarkViewModel{} - ); - - using LoggerWin = EditorWindow; - AddWindow( - LoggerView{}, - LoggerViewModel{ - _context->GetLoggerApi() - } - ); - } - -} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/SceneWorkspace.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/SceneWorkspace.cpp new file mode 100644 index 00000000..d25b2949 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/SceneWorkspace.cpp @@ -0,0 +1,113 @@ +#include "SceneWorkspace.h" +#include "Editor/Manager/EditorIcons.h" + +#include "Editor/Workspace/Common/ContentBrowser/ContentBrowserView.h" +#include "EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserViewModel.h" + +#include "View/Component/ComponentView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/ComponentViewModel.h" + +#include "View/Viewport/ViewportView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Viewport/ViewportViewModel.h" + +#include "View/Settings/SettingsView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Settings/SettingsViewModel.h" + +#include "View/Hierarchy/HierarchyView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Hierarchy/HierarchyViewModel.h" + +#include "View/Benchmark/BenchmarkView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Benchmark/BenchmarkViewModel.h" + +#include "View/Logger/LoggerView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Logger/LoggerViewModel.h" + +#include "Engine/Scene/SceneNames.h" + +namespace Syn { + + SceneWorkspace::SceneWorkspace(EditorContext* context, IconManager* iconManager, const std::string& assetPath) + : _context(context), _iconManager(iconManager), _assetPath(assetPath) {} + + void SceneWorkspace::OnActivate() { + if (_context && _context->GetApi()) { + _context->GetApi()->ActivateScene(SceneNames::Main); + } + } + + void SceneWorkspace::Initialize() + { + using ContentBrowserWin = EditorWindow; + AddWindow( + ContentBrowserView{ _iconManager, SYN_ICON_FOLDER_OPEN " Content Browser###Content_Scene" }, + ContentBrowserViewModel{ _context->GetApi(), _assetPath } + ); + + using ComponentWin = EditorWindow; + AddWindow( + ComponentView{}, + ComponentViewModel{ + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi() + } + ); + + using ViewportWin = EditorWindow; + AddWindow( + ViewportView{}, + ViewportViewModel{ + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi(), + _context->GetApi() + } + ); + + using SettingsWin = EditorWindow; + AddWindow( + SettingsView{}, + SettingsViewModel{ _context->GetApi() } + ); + + using HierarchyWin = EditorWindow; + AddWindow( + HierarchyView{}, + HierarchyViewModel{ + _context->GetApi(), + _context->GetApi(), + _context->GetApi() + } + ); + + using BenchmarkWin = EditorWindow; + AddWindow( + BenchmarkView{}, + BenchmarkViewModel{} + ); + + using LoggerWin = EditorWindow; + AddWindow( + LoggerView{}, + LoggerViewModel{ + _context->GetApi() + } + ); + } + +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/SceneWorkspace.h similarity index 86% rename from SynapseEngine/Editor/Workspace/SceneWorkspace.h rename to SynapseEngine/Editor/Workspace/SceneWorkspace/SceneWorkspace.h index 797ec55a..787f285d 100644 --- a/SynapseEngine/Editor/Workspace/SceneWorkspace.h +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/SceneWorkspace.h @@ -1,5 +1,5 @@ #pragma once -#include "IWorkspace.h" +#include "Editor/Workspace/IWorkspace.h" #include "Editor/EditorApi/EditorContext.h" #include "Editor/Manager/IconManager.h" #include @@ -12,7 +12,7 @@ namespace Syn { ~SceneWorkspace() override = default; void Initialize() override; - + void OnActivate() override; private: EditorContext* _context; IconManager* _iconManager; diff --git a/SynapseEngine/Editor/View/Benchmark/BenchmarkView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Benchmark/BenchmarkView.cpp similarity index 99% rename from SynapseEngine/Editor/View/Benchmark/BenchmarkView.cpp rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Benchmark/BenchmarkView.cpp index 2d6e8064..c2ab46c3 100644 --- a/SynapseEngine/Editor/View/Benchmark/BenchmarkView.cpp +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Benchmark/BenchmarkView.cpp @@ -6,8 +6,6 @@ #include #include -#include "EditorCore/ViewModels/Benchmark/BenchmarkViewModel.h" - namespace Syn { void BenchmarkView::Draw(BenchmarkViewModel& vm) { diff --git a/SynapseEngine/Editor/View/Benchmark/BenchmarkView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Benchmark/BenchmarkView.h similarity index 88% rename from SynapseEngine/Editor/View/Benchmark/BenchmarkView.h rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Benchmark/BenchmarkView.h index b67a0598..d7a4be44 100644 --- a/SynapseEngine/Editor/View/Benchmark/BenchmarkView.h +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Benchmark/BenchmarkView.h @@ -1,6 +1,6 @@ #pragma once -#include "Editor/View/IView.h" -#include "EditorCore/ViewModels/Benchmark/BenchmarkViewModel.h" +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Benchmark/BenchmarkViewModel.h" #include #include diff --git a/SynapseEngine/Editor/View/Component/ComponentView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/ComponentView.cpp similarity index 71% rename from SynapseEngine/Editor/View/Component/ComponentView.cpp rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/ComponentView.cpp index 2beebf9d..2ed0e349 100644 --- a/SynapseEngine/Editor/View/Component/ComponentView.cpp +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/ComponentView.cpp @@ -20,22 +20,30 @@ namespace Syn { return; } - //Tag + //Core _tagView.SetActiveEntity(state.activeEntityId); _tagView.Draw(vm.GetTagViewModel()); - - //Transform _transformView.Draw(vm.GetTransformViewModel()); + _cameraView.Draw(vm.GetCameraViewModel()); - //DirectionLight - _directionLightView.Draw(vm.GetDirectionLightViewModel()); + //Rendering + _modelComponentView.Draw(vm.GetModelComponentViewModel()); + _materialOverrideView.Draw(vm.GetMaterialOverrideViewModel()); + _animationView.Draw(vm.GetAnimationViewModel()); - //PointLight + //Lights + _directionLightView.Draw(vm.GetDirectionLightViewModel()); _pointLightView.Draw(vm.GetPointLightViewModel()); - - //SpotLight _spotLightView.Draw(vm.GetSpotLightViewModel()); + //Physics + _boxColliderView.Draw(vm.GetBoxColliderViewModel()); + _sphereColliderView.Draw(vm.GetSphereColliderViewModel()); + _capsuleColliderView.Draw(vm.GetCapsuleColliderViewModel()); + _convexColliderView.Draw(vm.GetConvexColliderViewModel()); + _meshColliderView.Draw(vm.GetMeshColliderViewModel()); + _rigidBodyView.Draw(vm.GetRigidBodyViewModel()); + ImGui::Spacing(); ImGui::Separator(); ImGui::Spacing(); diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/ComponentView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/ComponentView.h new file mode 100644 index 00000000..68d2f5e5 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/ComponentView.h @@ -0,0 +1,46 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/ComponentViewModel.h" +#include +#include + +#include "Core/TagView.h" +#include "Core/TransformView.h" +#include "Core/CameraView.h" +#include "Light/DirectionLightView.h" +#include "Light/PointLightView.h" +#include "Light/SpotLightView.h" + +#include "Physics/BoxColliderView.h" +#include "Physics/SphereColliderView.h" +#include "Physics/CapsuleColliderView.h" +#include "Physics/ConvexColliderView.h" +#include "Physics/MeshColliderView.h" +#include "Physics/RigidBodyView.h" + +#include "Rendering/ModelComponentView.h" +#include "Rendering/AnimationView.h" +#include "Rendering/MaterialOverrideView.h" + +namespace Syn { + class ComponentView : public IView { + public: + void Draw(ComponentViewModel& vm) override; + private: + TagView _tagView; + CameraView _cameraView; + TransformView _transformView; + DirectionLightView _directionLightView; + PointLightView _pointLightView; + SpotLightView _spotLightView; + BoxColliderView _boxColliderView; + SphereColliderView _sphereColliderView; + CapsuleColliderView _capsuleColliderView; + ConvexColliderView _convexColliderView; + MeshColliderView _meshColliderView; + RigidBodyView _rigidBodyView; + ModelComponentView _modelComponentView; + AnimationView _animationView; + MaterialOverrideView _materialOverrideView; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Core/CameraView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Core/CameraView.cpp new file mode 100644 index 00000000..d2e75dab --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Core/CameraView.cpp @@ -0,0 +1,80 @@ +#include "CameraView.h" +#include "Editor/Manager/EditorIcons.h" +#include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/PropertyGrid.h" +#include + +namespace Syn { + + void CameraView::Draw(CameraViewModel& vm) { + CameraState state = vm.GetState(); + + if (!state.hasComponent) return; + + constexpr const char* CardTitle = "Camera"; + + if (Syn::UI::BeginCard(CardTitle, SYN_ICON_CAMERA, _isCardOpen)) + { + if (Syn::UI::BeginPropertyGrid("CameraGrid")) + { + if (Syn::UI::PropertyCheckbox("Orthographic", state.isOrthographic)) { + vm.Dispatch(SetCameraIsOrthographicIntent{ state.isOrthographic }); + } + + if (Syn::UI::PropertyCheckbox("Orbit Camera", state.useOrbit)) { + vm.Dispatch(SetCameraUseOrbitIntent{ state.useOrbit }); + } + + Syn::UI::PropertySeparator(); + + if (Syn::UI::PropertyDragFloat("Yaw", state.yaw, 0.1f, -360.0f, 360.0f, "%.2f")) { + vm.Dispatch(SetCameraYawIntent{ state.yaw, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + if (Syn::UI::PropertyDragFloat("Pitch", state.pitch, 0.1f, -89.0f, 89.0f, "%.2f")) { + vm.Dispatch(SetCameraPitchIntent{ state.pitch, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + Syn::UI::PropertySeparator(); + + if (state.isOrthographic) + { + if (Syn::UI::PropertyDragFloat("Ortho Size", state.orthoSize, 0.1f, 1.0f, 1000.0f, "%.2f")) { + vm.Dispatch(SetCameraOrthoSizeIntent{ state.orthoSize, !ImGui::IsItemDeactivatedAfterEdit() }); + } + } + else + { + if (Syn::UI::PropertyDragFloat("FOV", state.fov, 0.1f, 1.0f, 179.0f, "%.2f")) { + vm.Dispatch(SetCameraFovIntent{ state.fov, !ImGui::IsItemDeactivatedAfterEdit() }); + } + } + + if (Syn::UI::PropertyDragFloat("Near Plane", state.nearPlane, 0.01f, 0.001f, 100.0f, "%.3f")) { + vm.Dispatch(SetCameraNearPlaneIntent{ state.nearPlane, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + if (Syn::UI::PropertyDragFloat("Far Plane", state.farPlane, 1.0f, 1.0f, 10000.0f, "%.1f")) { + vm.Dispatch(SetCameraFarPlaneIntent{ state.farPlane, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + Syn::UI::PropertySeparator(); + + if (Syn::UI::PropertyDragFloat("Speed", state.speed, 0.1f, 0.0f, 100.0f, "%.2f")) { + vm.Dispatch(SetCameraSpeedIntent{ state.speed, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + if (Syn::UI::PropertyDragFloat("Sensitivity", state.sensitivity, 0.01f, 0.0f, 10.0f, "%.3f")) { + vm.Dispatch(SetCameraSensitivityIntent{ state.sensitivity, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + if (Syn::UI::PropertyDragFloat("Distance", state.distance, 0.1f, 0.0f, 500.0f, "%.2f")) { + vm.Dispatch(SetCameraDistanceIntent{ state.distance, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + Syn::UI::EndPropertyGrid(); + } + } + Syn::UI::EndCard(); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Core/CameraView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Core/CameraView.h new file mode 100644 index 00000000..9e57e0bf --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Core/CameraView.h @@ -0,0 +1,12 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraViewModel.h" + +namespace Syn { + class CameraView : public IView { + public: + void Draw(CameraViewModel& vm) override; + private: + bool _isCardOpen = true; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/View/Component/Core/TagView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Core/TagView.cpp similarity index 100% rename from SynapseEngine/Editor/View/Component/Core/TagView.cpp rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Core/TagView.cpp diff --git a/SynapseEngine/Editor/View/Component/Core/TagView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Core/TagView.h similarity index 71% rename from SynapseEngine/Editor/View/Component/Core/TagView.h rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Core/TagView.h index 622b5755..ee8e63aa 100644 --- a/SynapseEngine/Editor/View/Component/Core/TagView.h +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Core/TagView.h @@ -1,6 +1,6 @@ #pragma once -#include "Editor/View/IView.h" -#include "EditorCore/ViewModels/Component/Core/Tag/TagViewModel.h" +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/Core/Tag/TagViewModel.h" namespace Syn { class TagView : public IView { diff --git a/SynapseEngine/Editor/View/Component/Core/TransformView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Core/TransformView.cpp similarity index 100% rename from SynapseEngine/Editor/View/Component/Core/TransformView.cpp rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Core/TransformView.cpp diff --git a/SynapseEngine/Editor/View/Component/Core/TransformView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Core/TransformView.h similarity index 61% rename from SynapseEngine/Editor/View/Component/Core/TransformView.h rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Core/TransformView.h index 4855288a..831e23e6 100644 --- a/SynapseEngine/Editor/View/Component/Core/TransformView.h +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Core/TransformView.h @@ -1,6 +1,6 @@ #pragma once -#include "Editor/View/IView.h" -#include "EditorCore/ViewModels/Component/Core/Transform/TransformViewModel.h" +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformViewModel.h" namespace Syn { class TransformView : public IView { diff --git a/SynapseEngine/Editor/View/Component/Light/DirectionLightView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Light/DirectionLightView.cpp similarity index 100% rename from SynapseEngine/Editor/View/Component/Light/DirectionLightView.cpp rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Light/DirectionLightView.cpp diff --git a/SynapseEngine/Editor/View/Component/Light/DirectionLightView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Light/DirectionLightView.h similarity index 61% rename from SynapseEngine/Editor/View/Component/Light/DirectionLightView.h rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Light/DirectionLightView.h index 73ccb025..77135da7 100644 --- a/SynapseEngine/Editor/View/Component/Light/DirectionLightView.h +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Light/DirectionLightView.h @@ -1,6 +1,6 @@ #pragma once -#include "Editor/View/IView.h" -#include "EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightViewModel.h" +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightViewModel.h" namespace Syn { class DirectionLightView : public IView { diff --git a/SynapseEngine/Editor/View/Component/Light/PointLightView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Light/PointLightView.cpp similarity index 100% rename from SynapseEngine/Editor/View/Component/Light/PointLightView.cpp rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Light/PointLightView.cpp diff --git a/SynapseEngine/Editor/View/Component/Light/PointLightView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Light/PointLightView.h similarity index 61% rename from SynapseEngine/Editor/View/Component/Light/PointLightView.h rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Light/PointLightView.h index 7d02c096..268f7d20 100644 --- a/SynapseEngine/Editor/View/Component/Light/PointLightView.h +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Light/PointLightView.h @@ -1,6 +1,6 @@ #pragma once -#include "Editor/View/IView.h" -#include "EditorCore/ViewModels/Component/Light/PointLight/PointLightViewModel.h" +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightViewModel.h" namespace Syn { class PointLightView : public IView { diff --git a/SynapseEngine/Editor/View/Component/Light/SpotLightView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Light/SpotLightView.cpp similarity index 100% rename from SynapseEngine/Editor/View/Component/Light/SpotLightView.cpp rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Light/SpotLightView.cpp diff --git a/SynapseEngine/Editor/View/Component/Light/SpotLightView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Light/SpotLightView.h similarity index 61% rename from SynapseEngine/Editor/View/Component/Light/SpotLightView.h rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Light/SpotLightView.h index 744c4a67..4ef82466 100644 --- a/SynapseEngine/Editor/View/Component/Light/SpotLightView.h +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Light/SpotLightView.h @@ -1,6 +1,6 @@ #pragma once -#include "Editor/View/IView.h" -#include "EditorCore/ViewModels/Component/Light/SpotLight/SpotLightViewModel.h" +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightViewModel.h" namespace Syn { class SpotLightView : public IView { diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/BoxColliderView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/BoxColliderView.cpp new file mode 100644 index 00000000..d707458c --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/BoxColliderView.cpp @@ -0,0 +1,33 @@ +#include "BoxColliderView.h" +#include "Editor/Manager/EditorIcons.h" +#include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/PropertyGrid.h" +#include + +namespace Syn { + + void BoxColliderView::Draw(BoxColliderViewModel& vm) { + BoxColliderState state = vm.GetState(); + + if (!state.hasComponent) return; + + constexpr const char* CardTitle = "Box Collider"; + + if (Syn::UI::BeginCard(CardTitle, SYN_ICON_BOX_COLLIDER, _isCardOpen)) + { + if (Syn::UI::BeginPropertyGrid("BoxColliderGrid")) + { + if (Syn::UI::PropertyDragFloat3("Half Extents", state.halfExtents, 0.1f, 0.0f, 1000.0f, "%.2f")) { + vm.Dispatch(SetBoxColliderHalfExtentsIntent{ state.halfExtents, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + if (Syn::UI::PropertyDragFloat3("Local Offset", state.localOffset, 0.1f, -1000.0f, 1000.0f, "%.2f")) { + vm.Dispatch(SetBoxColliderLocalOffsetIntent{ state.localOffset, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + Syn::UI::EndPropertyGrid(); + } + } + Syn::UI::EndCard(); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/BoxColliderView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/BoxColliderView.h new file mode 100644 index 00000000..28f17113 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/BoxColliderView.h @@ -0,0 +1,12 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderViewModel.h" + +namespace Syn { + class BoxColliderView : public IView { + public: + void Draw(BoxColliderViewModel& vm) override; + private: + bool _isCardOpen = true; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/CapsuleColliderView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/CapsuleColliderView.cpp new file mode 100644 index 00000000..c0fc8ee8 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/CapsuleColliderView.cpp @@ -0,0 +1,37 @@ +#include "CapsuleColliderView.h" +#include "Editor/Manager/EditorIcons.h" +#include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/PropertyGrid.h" +#include + +namespace Syn { + + void CapsuleColliderView::Draw(CapsuleColliderViewModel& vm) { + CapsuleColliderState state = vm.GetState(); + + if (!state.hasComponent) return; + + constexpr const char* CardTitle = "Capsule Collider"; + + if (Syn::UI::BeginCard(CardTitle, SYN_ICON_CAPSULE_COLLIDER, _isCardOpen)) + { + if (Syn::UI::BeginPropertyGrid("CapsuleColliderGrid")) + { + if (Syn::UI::PropertyDragFloat("Radius", state.radius, 0.1f, 0.0f, 1000.0f, "%.2f")) { + vm.Dispatch(SetCapsuleColliderRadiusIntent{ state.radius, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + if (Syn::UI::PropertyDragFloat("Half Height", state.halfHeight, 0.1f, 0.0f, 1000.0f, "%.2f")) { + vm.Dispatch(SetCapsuleColliderHalfHeightIntent{ state.halfHeight, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + if (Syn::UI::PropertyDragFloat3("Local Offset", state.localOffset, 0.1f, -1000.0f, 1000.0f, "%.2f")) { + vm.Dispatch(SetCapsuleColliderLocalOffsetIntent{ state.localOffset, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + Syn::UI::EndPropertyGrid(); + } + } + Syn::UI::EndCard(); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/CapsuleColliderView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/CapsuleColliderView.h new file mode 100644 index 00000000..5b5745b7 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/CapsuleColliderView.h @@ -0,0 +1,12 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderViewModel.h" + +namespace Syn { + class CapsuleColliderView : public IView { + public: + void Draw(CapsuleColliderViewModel& vm) override; + private: + bool _isCardOpen = true; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/ConvexColliderView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/ConvexColliderView.cpp new file mode 100644 index 00000000..3f47a83f --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/ConvexColliderView.cpp @@ -0,0 +1,37 @@ +#include "ConvexColliderView.h" +#include "Editor/Manager/EditorIcons.h" +#include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/PropertyGrid.h" +#include + +namespace Syn { + + void ConvexColliderView::Draw(ConvexColliderViewModel& vm) { + ConvexColliderState state = vm.GetState(); + + if (!state.hasComponent) return; + + constexpr const char* CardTitle = "Convex Collider"; + + if (Syn::UI::BeginCard(CardTitle, SYN_ICON_CONVEX_COLLIDER, _isCardOpen)) + { + if (Syn::UI::BeginPropertyGrid("ConvexColliderGrid")) + { + Syn::UI::BeginProperty("Target LOD"); + int lodLevel = static_cast(state.targetLodLevel); + if (ImGui::SliderInt("##TargetLOD", &lodLevel, 0, 3)) { + vm.Dispatch(SetConvexColliderTargetLodLevelIntent{ static_cast(lodLevel) }); + } + + Syn::UI::PropertySeparator(); + + if (Syn::UI::PropertyDragFloat3("Local Offset", state.localOffset, 0.1f, -1000.0f, 1000.0f, "%.2f")) { + vm.Dispatch(SetConvexColliderLocalOffsetIntent{ state.localOffset, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + Syn::UI::EndPropertyGrid(); + } + } + Syn::UI::EndCard(); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/ConvexColliderView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/ConvexColliderView.h new file mode 100644 index 00000000..cd78ae71 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/ConvexColliderView.h @@ -0,0 +1,12 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderViewModel.h" + +namespace Syn { + class ConvexColliderView : public IView { + public: + void Draw(ConvexColliderViewModel& vm) override; + private: + bool _isCardOpen = true; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/MeshColliderView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/MeshColliderView.cpp new file mode 100644 index 00000000..c7d1df02 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/MeshColliderView.cpp @@ -0,0 +1,37 @@ +#include "MeshColliderView.h" +#include "Editor/Manager/EditorIcons.h" +#include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/PropertyGrid.h" +#include + +namespace Syn { + + void MeshColliderView::Draw(MeshColliderViewModel& vm) { + MeshColliderState state = vm.GetState(); + + if (!state.hasComponent) return; + + constexpr const char* CardTitle = "Mesh Collider"; + + if (Syn::UI::BeginCard(CardTitle, SYN_ICON_MESH_COLLIDER, _isCardOpen)) + { + if (Syn::UI::BeginPropertyGrid("MeshColliderGrid")) + { + Syn::UI::BeginProperty("Target LOD"); + int lodLevel = static_cast(state.targetLodLevel); + if (ImGui::SliderInt("##TargetLOD", &lodLevel, 0, 3)) { + vm.Dispatch(SetMeshColliderTargetLodLevelIntent{ static_cast(lodLevel) }); + } + + Syn::UI::PropertySeparator(); + + if (Syn::UI::PropertyDragFloat3("Local Offset", state.localOffset, 0.1f, -1000.0f, 1000.0f, "%.2f")) { + vm.Dispatch(SetMeshColliderLocalOffsetIntent{ state.localOffset, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + Syn::UI::EndPropertyGrid(); + } + } + Syn::UI::EndCard(); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/MeshColliderView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/MeshColliderView.h new file mode 100644 index 00000000..2c37376f --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/MeshColliderView.h @@ -0,0 +1,12 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderViewModel.h" + +namespace Syn { + class MeshColliderView : public IView { + public: + void Draw(MeshColliderViewModel& vm) override; + private: + bool _isCardOpen = true; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/RigidBodyView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/RigidBodyView.cpp new file mode 100644 index 00000000..9cf41c50 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/RigidBodyView.cpp @@ -0,0 +1,64 @@ +#include "RigidBodyView.h" +#include "Editor/Manager/EditorIcons.h" +#include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/PropertyGrid.h" +#include + +namespace Syn { + + void RigidBodyView::Draw(RigidBodyViewModel& vm) { + RigidBodyState state = vm.GetState(); + + if (!state.hasComponent) return; + + constexpr const char* CardTitle = "Rigid Body"; + + if (Syn::UI::BeginCard(CardTitle, SYN_ICON_RIGID_BODY, _isCardOpen)) + { + if (Syn::UI::BeginPropertyGrid("RigidBodyGrid")) + { + const char* currentMotionString = "Dynamic"; + if (state.motionType == PhysicsMotionType::Static) currentMotionString = "Static"; + else if (state.motionType == PhysicsMotionType::Kinematic) currentMotionString = "Kinematic"; + + if (Syn::UI::BeginPropertyCombo("Motion Type", currentMotionString)) { + if (ImGui::Selectable("Static", state.motionType == PhysicsMotionType::Static)) { + vm.Dispatch(SetRigidBodyMotionTypeIntent{ PhysicsMotionType::Static }); + } + if (ImGui::Selectable("Kinematic", state.motionType == PhysicsMotionType::Kinematic)) { + vm.Dispatch(SetRigidBodyMotionTypeIntent{ PhysicsMotionType::Kinematic }); + } + if (ImGui::Selectable("Dynamic", state.motionType == PhysicsMotionType::Dynamic)) { + vm.Dispatch(SetRigidBodyMotionTypeIntent{ PhysicsMotionType::Dynamic }); + } + Syn::UI::EndPropertyCombo(); + } + + Syn::UI::PropertySeparator(); + + if (Syn::UI::PropertyDragFloat("Mass", state.mass, 0.1f, 0.0f, 10000.0f, "%.2f")) { + vm.Dispatch(SetRigidBodyMassIntent{ state.mass, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + if (Syn::UI::PropertyDragFloat("Friction", state.friction, 0.01f, 0.0f, 1.0f, "%.2f")) { + vm.Dispatch(SetRigidBodyFrictionIntent{ state.friction, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + if (Syn::UI::PropertyDragFloat("Restitution", state.restitution, 0.01f, 0.0f, 1.0f, "%.2f")) { + vm.Dispatch(SetRigidBodyRestitutionIntent{ state.restitution, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + Syn::UI::PropertySeparator(); + + Syn::UI::BeginProperty("Layer"); + int layerInt = static_cast(state.layer); + if (ImGui::DragInt("##Layer", &layerInt, 1.0f, 0, 31)) { + vm.Dispatch(SetRigidBodyLayerIntent{ static_cast(layerInt) }); + } + + Syn::UI::EndPropertyGrid(); + } + } + Syn::UI::EndCard(); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/RigidBodyView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/RigidBodyView.h new file mode 100644 index 00000000..aa7b64f1 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/RigidBodyView.h @@ -0,0 +1,12 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyViewModel.h" + +namespace Syn { + class RigidBodyView : public IView { + public: + void Draw(RigidBodyViewModel& vm) override; + private: + bool _isCardOpen = true; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/SphereColliderView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/SphereColliderView.cpp new file mode 100644 index 00000000..c7d770ff --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/SphereColliderView.cpp @@ -0,0 +1,33 @@ +#include "SphereColliderView.h" +#include "Editor/Manager/EditorIcons.h" +#include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/PropertyGrid.h" +#include + +namespace Syn { + + void SphereColliderView::Draw(SphereColliderViewModel& vm) { + SphereColliderState state = vm.GetState(); + + if (!state.hasComponent) return; + + constexpr const char* CardTitle = "Sphere Collider"; + + if (Syn::UI::BeginCard(CardTitle, SYN_ICON_SPHERE_COLLIDER, _isCardOpen)) + { + if (Syn::UI::BeginPropertyGrid("SphereColliderGrid")) + { + if (Syn::UI::PropertyDragFloat("Radius", state.radius, 0.1f, 0.0f, 1000.0f, "%.2f")) { + vm.Dispatch(SetSphereColliderRadiusIntent{ state.radius, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + if (Syn::UI::PropertyDragFloat3("Local Offset", state.localOffset, 0.1f, -1000.0f, 1000.0f, "%.2f")) { + vm.Dispatch(SetSphereColliderLocalOffsetIntent{ state.localOffset, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + Syn::UI::EndPropertyGrid(); + } + } + Syn::UI::EndCard(); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/SphereColliderView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/SphereColliderView.h new file mode 100644 index 00000000..4277a81b --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Physics/SphereColliderView.h @@ -0,0 +1,12 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderViewModel.h" + +namespace Syn { + class SphereColliderView : public IView { + public: + void Draw(SphereColliderViewModel& vm) override; + private: + bool _isCardOpen = true; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/AnimationView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/AnimationView.cpp new file mode 100644 index 00000000..0e7f7404 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/AnimationView.cpp @@ -0,0 +1,49 @@ +#include "AnimationView.h" +#include "Editor/Manager/EditorIcons.h" +#include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/PropertyGrid.h" +#include + +namespace Syn { + void AnimationView::Draw(AnimationViewModel& vm) { + AnimationState state = vm.GetState(); + if (!state.hasComponent) return; + + constexpr const char* CardTitle = "Animation Component"; + if (Syn::UI::BeginCard(CardTitle, SYN_ICON_ANIMATION, _isCardOpen)) { + + if (Syn::UI::BeginPropertyGrid("AnimationGrid")) + { + if (Syn::UI::PropertyDragFloat("Speed", state.speed, 0.05f, 0.0f, 10.0f, "%.2f x")) { + vm.Dispatch(SetAnimationSpeedIntent{ state.speed, !ImGui::IsItemDeactivatedAfterEdit() }); + } + + std::string previewName = "None"; + for (const auto& anim : state.availableAnimations) { + if (anim.first == state.animationIndex) { + previewName = anim.second; + break; + } + } + + if (Syn::UI::BeginPropertyCombo("Animation", previewName.c_str())) { + for (const auto& anim : state.availableAnimations) { + bool isSelected = (state.animationIndex == anim.first); + + if (ImGui::Selectable(anim.second.c_str(), isSelected)) { + vm.Dispatch(SetAnimationIndexIntent{ anim.first }); + } + + if (isSelected) { + ImGui::SetItemDefaultFocus(); + } + } + Syn::UI::EndPropertyCombo(); + } + + Syn::UI::EndPropertyGrid(); + } + } + Syn::UI::EndCard(); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/AnimationView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/AnimationView.h new file mode 100644 index 00000000..9c865624 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/AnimationView.h @@ -0,0 +1,12 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationViewModel.h" + +namespace Syn { + class AnimationView : public IView { + public: + void Draw(AnimationViewModel& vm) override; + private: + bool _isCardOpen = true; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/MaterialOverrideView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/MaterialOverrideView.cpp new file mode 100644 index 00000000..919f6c31 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/MaterialOverrideView.cpp @@ -0,0 +1,102 @@ +#include "MaterialOverrideView.h" +#include "Editor/Manager/EditorIcons.h" +#include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/PropertyGrid.h" +#include +#include + +namespace Syn { + void MaterialOverrideView::Draw(MaterialOverrideViewModel& vm) { + MaterialOverrideState state = vm.GetState(); + if (!state.hasComponent) return; + + constexpr const char* CardTitle = "Material Override"; + if (Syn::UI::BeginCard(CardTitle, SYN_ICON_MAGIC, _isCardOpen)) { + if (Syn::UI::BeginPropertyGrid("MaterialOverrideGrid")) + { + std::string sharedPreview = "None"; + if (state.sharedMaterialEntity != NULL_ENTITY) { + for (const auto& ent : state.compatibleSharedEntities) { + if (ent.first == state.sharedMaterialEntity) { + sharedPreview = ent.second; + break; + } + } + } + + if (Syn::UI::BeginPropertyCombo("Shared Entity", sharedPreview.c_str())) + { + if (ImGui::Selectable("None", state.sharedMaterialEntity == NULL_ENTITY)) { + vm.Dispatch(SetSharedMaterialEntityIntent{ NULL_ENTITY }); + } + + ImGuiListClipper clipper; + clipper.Begin(static_cast(state.compatibleSharedEntities.size())); + + while (clipper.Step()) { + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; ++i) { + const auto& ent = state.compatibleSharedEntities[i]; + bool isSelected = (state.sharedMaterialEntity == ent.first); + + ImGui::PushID(ent.first); + if (ImGui::Selectable(ent.second.c_str(), isSelected)) { + vm.Dispatch(SetSharedMaterialEntityIntent{ ent.first }); + } + if (isSelected) { + ImGui::SetItemDefaultFocus(); + } + ImGui::PopID(); + } + } + + Syn::UI::EndPropertyCombo(); + } + + Syn::UI::PropertySeparator(); + + if (state.expectedSlotCount == 0) { + Syn::UI::PropertyText("Info", "No valid ModelComponent found or Model has 0 meshes."); + } + else { + for (uint32_t i = 0; i < state.expectedSlotCount; ++i) { + uint32_t currentMatId = state.overrides[i]; + std::string label = "Slot " + std::to_string(i); + + std::string previewName = "-"; + if (currentMatId != UINT32_MAX) { + for (const auto& mat : state.availableMaterials) { + if (mat.first == currentMatId) { + previewName = mat.second; + break; + } + } + } + + if (Syn::UI::BeginPropertyCombo(label.c_str(), previewName.c_str())) { + bool isNoneSelected = (currentMatId == UINT32_MAX); + if (ImGui::Selectable("-", isNoneSelected)) { + vm.Dispatch(SetMaterialOverrideSlotIntent{ i, UINT32_MAX }); + } + + for (const auto& mat : state.availableMaterials) { + bool isSelected = (currentMatId == mat.first); + + if (ImGui::Selectable(mat.second.c_str(), isSelected)) { + vm.Dispatch(SetMaterialOverrideSlotIntent{ i, mat.first }); + } + + if (isSelected) { + ImGui::SetItemDefaultFocus(); + } + } + Syn::UI::EndPropertyCombo(); + } + } + } + + Syn::UI::EndPropertyGrid(); + } + } + Syn::UI::EndCard(); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/MaterialOverrideView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/MaterialOverrideView.h new file mode 100644 index 00000000..c7d0da19 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/MaterialOverrideView.h @@ -0,0 +1,12 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideViewModel.h" + +namespace Syn { + class MaterialOverrideView : public IView { + public: + void Draw(MaterialOverrideViewModel& vm) override; + private: + bool _isCardOpen = true; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/ModelComponentView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/ModelComponentView.cpp new file mode 100644 index 00000000..c11aba7a --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/ModelComponentView.cpp @@ -0,0 +1,59 @@ +#include "ModelComponentView.h" +#include "Editor/Manager/EditorIcons.h" +#include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/PropertyGrid.h" +#include + +namespace Syn { + void ModelComponentView::Draw(ModelComponentViewModel& vm) { + ModelComponentState state = vm.GetState(); + if (!state.hasComponent) return; + + constexpr const char* CardTitle = "Model Component"; + + if (Syn::UI::BeginCard(CardTitle, SYN_ICON_MODEL, _isCardOpen)) { + if (Syn::UI::BeginPropertyGrid("ModelGrid")) + { + std::string previewName = "None (UINT32_MAX)"; + if (state.modelIndex != UINT32_MAX) { + for (const auto& model : state.availableModels) { + if (model.first == state.modelIndex) { + previewName = model.second; + break; + } + } + } + + if (Syn::UI::BeginPropertyCombo("Model", previewName.c_str())) { + for (const auto& model : state.availableModels) { + bool isSelected = (state.modelIndex == model.first); + + if (ImGui::Selectable(model.second.c_str(), isSelected)) { + vm.Dispatch(SetModelIndexIntent{ model.first }); + } + + if (isSelected) { + ImGui::SetItemDefaultFocus(); + } + } + Syn::UI::EndPropertyCombo(); + } + + Syn::UI::PropertySeparator(); + + bool castShadow = state.castShadow; + if (Syn::UI::PropertyCheckbox("Cast Shadow", castShadow)) { + vm.Dispatch(SetModelCastShadowIntent{ castShadow }); + } + + bool receiveShadow = state.receiveShadow; + if (Syn::UI::PropertyCheckbox("Receive Shadow", receiveShadow)) { + vm.Dispatch(SetModelReceiveShadowIntent{ receiveShadow }); + } + + Syn::UI::EndPropertyGrid(); + } + } + Syn::UI::EndCard(); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/ModelComponentView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/ModelComponentView.h new file mode 100644 index 00000000..5ba2b6e0 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Component/Rendering/ModelComponentView.h @@ -0,0 +1,12 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentViewModel.h" + +namespace Syn { + class ModelComponentView : public IView { + public: + void Draw(ModelComponentViewModel& vm) override; + private: + bool _isCardOpen = true; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/View/Hierarchy/HierarchyView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Hierarchy/HierarchyView.cpp similarity index 69% rename from SynapseEngine/Editor/View/Hierarchy/HierarchyView.cpp rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Hierarchy/HierarchyView.cpp index 8d7d59aa..63c81d72 100644 --- a/SynapseEngine/Editor/View/Hierarchy/HierarchyView.cpp +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Hierarchy/HierarchyView.cpp @@ -34,7 +34,7 @@ namespace Syn { ImGui::BeginChild("HierarchyTableContainer", ImVec2(0, tableHeight), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoScrollbar); - if (ImGui::BeginTable("HierarchyTable", 2, ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_ScrollY | ImGuiTableFlags_Resizable)) { + if (ImGui::BeginTable("HierarchyTable", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Resizable)) { ImGui::TableSetupScrollFreeze(0, 1); ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch); @@ -234,21 +234,85 @@ namespace Syn { } void HierarchyView::RenderContextMenu(HierarchyViewModel& vm, EntityID contextEntity) { + ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(8.0f, 8.0f)); + + auto DrawStyledSeparator = []() { + ImGui::PushStyleColor(ImGuiCol_Separator, ImVec4(0.35f, 0.35f, 0.35f, 1.0f)); + ImGui::Separator(); + ImGui::PopStyleColor(); + }; + if (ImGui::MenuItem(SYN_ICON_CUBE " Empty Entity")) { - vm.Dispatch(HierarchyCreateEntityIntent{ "Empty Entity", contextEntity }); + vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::Empty, contextEntity }); } - ImGui::Separator(); - if (ImGui::MenuItem(SYN_ICON_VIDEO " Camera")) { - vm.Dispatch(HierarchyCreateEntityIntent{ "Camera", contextEntity }); + vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::Camera, contextEntity }); + } + + DrawStyledSeparator(); + + if (ImGui::BeginMenu(SYN_ICON_LIGHTBULB " Lights")) { + if (ImGui::MenuItem("Directional Light")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::DirectionalLight, contextEntity }); + if (ImGui::MenuItem("Point Light")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::PointLight, contextEntity }); + if (ImGui::MenuItem("Spot Light")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::SpotLight, contextEntity }); + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu(SYN_ICON_CUBE " Shape")) { + if (ImGui::MenuItem("Cube")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::ShapeCube, contextEntity }); + if (ImGui::MenuItem("Sphere")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::ShapeSphere, contextEntity }); + if (ImGui::MenuItem("Quad")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::ShapeQuad, contextEntity }); + if (ImGui::MenuItem("Cylinder")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::ShapeCylinder, contextEntity }); + if (ImGui::MenuItem("Cone")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::ShapeCone, contextEntity }); + if (ImGui::MenuItem("Capsule")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::ShapeCapsule, contextEntity }); + if (ImGui::MenuItem("Hemisphere")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::ShapeHemisphere, contextEntity }); + if (ImGui::MenuItem("Pyramid")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::ShapePyramid, contextEntity }); + if (ImGui::MenuItem("Grid")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::ShapeGrid, contextEntity }); + if (ImGui::MenuItem("Torus")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::ShapeTorus, contextEntity }); + ImGui::EndMenu(); + } + + if (ImGui::BeginMenu(SYN_ICON_CUBE " Collider")) { + if (ImGui::MenuItem("Box Collider")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::BoxCollider, contextEntity }); + if (ImGui::MenuItem("Sphere Collider")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::SphereCollider, contextEntity }); + if (ImGui::MenuItem("Capsule Collider")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::CapsuleCollider, contextEntity }); + if (ImGui::MenuItem("Convex Collider")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::ConvexCollider, contextEntity }); + if (ImGui::MenuItem("Mesh Collider")) vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::MeshCollider, contextEntity }); + ImGui::EndMenu(); + } + + DrawStyledSeparator(); + + if (ImGui::MenuItem(SYN_ICON_CUBE " Model")) { + vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::Model, contextEntity }); + } + + if (ImGui::MenuItem(SYN_ICON_RUNNING " Animation")) { + vm.Dispatch(HierarchyCreateEntityIntent{ EntityTemplate::Animation, contextEntity }); } if (contextEntity != NULL_ENTITY) { - ImGui::Separator(); + DrawStyledSeparator(); + + if (ImGui::MenuItem(SYN_ICON_COPY " Copy")) { + vm.Dispatch(HierarchyCopyEntityIntent{ contextEntity }); + } + if (ImGui::MenuItem(SYN_ICON_COPY " Full Copy")) { + vm.Dispatch(HierarchyFullCopyEntityIntent{ contextEntity }); + } + + DrawStyledSeparator(); + if (ImGui::MenuItem(SYN_ICON_TRASH " Delete")) { vm.Dispatch(HierarchyDestroyEntityIntent{ contextEntity }); } + + if (ImGui::MenuItem(SYN_ICON_TRASH " Delete (Keep Children)")) { + vm.Dispatch(HierarchyDestroyKeepChildrenIntent{ contextEntity }); + } } + + ImGui::PopStyleVar(); } } \ No newline at end of file diff --git a/SynapseEngine/Editor/View/Hierarchy/HierarchyView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Hierarchy/HierarchyView.h similarity index 83% rename from SynapseEngine/Editor/View/Hierarchy/HierarchyView.h rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Hierarchy/HierarchyView.h index ccdc4158..eb38ad29 100644 --- a/SynapseEngine/Editor/View/Hierarchy/HierarchyView.h +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Hierarchy/HierarchyView.h @@ -1,6 +1,6 @@ #pragma once -#include "Editor/View/IView.h" -#include "EditorCore/ViewModels/Hierarchy/HierarchyViewModel.h" +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Hierarchy/HierarchyViewModel.h" #include #include diff --git a/SynapseEngine/Editor/View/Logger/LoggerView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Logger/LoggerView.cpp similarity index 63% rename from SynapseEngine/Editor/View/Logger/LoggerView.cpp rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Logger/LoggerView.cpp index 754c7af1..88f5a8af 100644 --- a/SynapseEngine/Editor/View/Logger/LoggerView.cpp +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Logger/LoggerView.cpp @@ -4,6 +4,7 @@ #include "Engine/Logger/LogUtils.h" #include #include +#include namespace Syn { @@ -47,46 +48,31 @@ namespace Syn { void LoggerView::RenderTopBar(LoggerViewModel& vm, const LoggerState& state) { - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.8f, 0.8f, 0.8f, 1.0f)); - if (ImGui::Button(SYN_ICON_FILTER " Filters")) { - ImGui::OpenPopup("LogLevelFilterPopup"); - } - ImGui::PopStyleColor(2); - - if (ImGui::BeginPopup("LogLevelFilterPopup")) { - ImGui::TextDisabled("Log Levels"); - ImGui::Separator(); - - bool showInfo = state.filters.showInfo; - ImGui::PushStyleColor(ImGuiCol_Text, GetColorForLevel(LogLevel::Info)); - if (ImGui::Checkbox("Info", &showInfo)) vm.Dispatch(LoggerToggleLevelIntent{ LogLevel::Info, showInfo }); - ImGui::PopStyleColor(); - - bool showWarn = state.filters.showWarning; - ImGui::PushStyleColor(ImGuiCol_Text, GetColorForLevel(LogLevel::Warning)); - if (ImGui::Checkbox("Warning", &showWarn)) vm.Dispatch(LoggerToggleLevelIntent{ LogLevel::Warning, showWarn }); - ImGui::PopStyleColor(); - - bool showError = state.filters.showError; - ImGui::PushStyleColor(ImGuiCol_Text, GetColorForLevel(LogLevel::Error)); - if (ImGui::Checkbox("Error", &showError)) vm.Dispatch(LoggerToggleLevelIntent{ LogLevel::Error, showError }); - ImGui::PopStyleColor(); + auto DrawFilterToggle = [&](const char* label, LogLevel level, bool& currentVal) { + ImGui::PushStyleColor(ImGuiCol_Text, currentVal ? GetColorForLevel(level) : ImVec4(0.4f, 0.4f, 0.4f, 1.0f)); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(1, 1, 1, 0.1f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(1, 1, 1, 0.2f)); + + if (ImGui::Button(label)) { + bool newVal = !currentVal; + vm.Dispatch(LoggerToggleLevelIntent{ level, newVal }); + } - bool showCrit = state.filters.showCritical; - ImGui::PushStyleColor(ImGuiCol_Text, GetColorForLevel(LogLevel::Critical)); - if (ImGui::Checkbox("Critical", &showCrit)) vm.Dispatch(LoggerToggleLevelIntent{ LogLevel::Critical, showCrit }); - ImGui::PopStyleColor(); + ImGui::PopStyleColor(4); + }; - ImGui::EndPopup(); - } + bool showInfo = state.filters.showInfo; + bool showWarn = state.filters.showWarning; + bool showError = state.filters.showError; + bool showCrit = state.filters.showCritical; - ImGui::SameLine(); + DrawFilterToggle("Info", LogLevel::Info, showInfo); ImGui::SameLine(); + DrawFilterToggle("Warn", LogLevel::Warning, showWarn); ImGui::SameLine(); + DrawFilterToggle("Error", LogLevel::Error, showError); ImGui::SameLine(); + DrawFilterToggle("Crit", LogLevel::Critical, showCrit); - float autoScrollWidth = ImGui::CalcTextSize("Auto-Scroll").x + 35.0f; - float clearBtnWidth = ImGui::CalcTextSize(SYN_ICON_TRASH " Clear").x + ImGui::GetStyle().FramePadding.x * 2.0f; - float spacing = ImGui::GetStyle().ItemSpacing.x; - float rightItemsTotalWidth = autoScrollWidth + clearBtnWidth + spacing * 3.0f; + ImGui::SameLine(0, 15.0f); ImGui::AlignTextToFramePadding(); ImGui::TextDisabled(SYN_ICON_SEARCH); @@ -96,6 +82,8 @@ namespace Syn { strncpy(searchBuffer, state.filters.searchQuery.c_str(), sizeof(searchBuffer)); searchBuffer[sizeof(searchBuffer) - 1] = '\0'; + float rightItemsTotalWidth = ImGui::CalcTextSize("Auto-Scroll").x + ImGui::CalcTextSize(SYN_ICON_TRASH " Clear").x + 70.0f; + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x - rightItemsTotalWidth); if (ImGui::InputTextWithHint("##LogSearch", "Filter logs by message or file...", searchBuffer, IM_ARRAYSIZE(searchBuffer))) { vm.Dispatch(LoggerSetSearchQueryIntent{ std::string(searchBuffer) }); @@ -113,11 +101,9 @@ namespace Syn { void LoggerView::RenderLogTable(const LoggerState& state, float tableHeight) { ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(4, 4)); ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 8.0f); - ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); - ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.08f, 0.08f, 0.08f, 0.6f)); - ImGui::BeginChild("LogTableContainer", ImVec2(0, tableHeight), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoScrollbar); + ImGui::BeginChild("LogTableContainer", ImVec2(0, tableHeight), false, ImGuiWindowFlags_NoScrollbar); if (state.filteredLogs.empty()) { ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 8.0f); @@ -125,34 +111,22 @@ namespace Syn { ImGui::TextDisabled("No logs match the current filters."); } else { - ImGuiTableFlags flags = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg; + ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY | ImGuiTableFlags_ScrollX | ImGuiTableFlags_PadOuterX; if (ImGui::BeginTable("LogTable", 4, flags)) { ImGui::TableSetupScrollFreeze(0, 1); - ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_WidthFixed, 140.0f); - ImGui::TableSetupColumn("Level", ImGuiTableColumnFlags_WidthFixed, 60.0f); - ImGui::TableSetupColumn("Source", ImGuiTableColumnFlags_WidthFixed, 150.0f); + ImGui::TableSetupColumn("Time", ImGuiTableColumnFlags_WidthFixed, 100.0f); + ImGui::TableSetupColumn("Level", ImGuiTableColumnFlags_WidthFixed, 50.0f); + ImGui::TableSetupColumn("Source", ImGuiTableColumnFlags_WidthFixed, 130.0f); ImGui::TableSetupColumn("Message", ImGuiTableColumnFlags_WidthStretch); ImGui::TableNextRow(ImGuiTableRowFlags_Headers); for (int column = 0; column < 4; column++) { ImGui::TableSetColumnIndex(column); const char* columnName = ImGui::TableGetColumnName(column); - - ImGui::PushID(column); - - float cellWidth = ImGui::GetColumnWidth(); - float textWidth = ImGui::CalcTextSize(columnName).x; - ImVec2 startPos = ImGui::GetCursorPos(); - - ImGui::TableHeader(""); - - ImGui::SetCursorPos(ImVec2(startPos.x + (cellWidth - textWidth) * 0.5f, startPos.y + 3.0f)); - ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); - ImGui::Text("%s", columnName); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.6f, 0.6f, 0.6f, 1.0f)); + ImGui::TableHeader(columnName); ImGui::PopStyleColor(); - - ImGui::PopID(); } ImGuiListClipper clipper; @@ -176,7 +150,17 @@ namespace Syn { ImGui::Text("%s:%d", filenameStr.c_str(), log.line); ImGui::TableNextColumn(); - ImGui::TextWrapped("%.*s", static_cast(log.message.length()), log.message.data()); + + std::string singleLineMsg = std::string(log.message.data(), log.message.length()); + std::replace(singleLineMsg.begin(), singleLineMsg.end(), '\n', ' '); + + ImGui::TextUnformatted(singleLineMsg.c_str()); + + if (ImGui::IsItemHovered() && log.message.find('\n') != std::string::npos) { + ImGui::BeginTooltip(); + ImGui::TextUnformatted(log.message.data()); + ImGui::EndTooltip(); + } ImGui::PopStyleColor(); } @@ -191,17 +175,16 @@ namespace Syn { } ImGui::EndChild(); - ImGui::PopStyleColor(); - ImGui::PopStyleVar(3); + ImGui::PopStyleVar(2); } ImVec4 LoggerView::GetColorForLevel(LogLevel level) const { switch (level) { - case LogLevel::Info: return ImVec4(1.0f, 1.0f, 1.0f, 1.0f); - case LogLevel::Warning: return ImVec4(0.8f, 0.4f, 1.0f, 1.0f); - case LogLevel::Error: return ImVec4(1.0f, 0.2f, 0.2f, 1.0f); - case LogLevel::Critical: return ImVec4(1.0f, 0.6f, 0.0f, 1.0f); + case LogLevel::Info: return ImVec4(0.9f, 0.9f, 0.9f, 1.0f); + case LogLevel::Warning: return ImVec4(0.9f, 0.7f, 0.0f, 1.0f); + case LogLevel::Error: return ImVec4(1.0f, 0.3f, 0.3f, 1.0f); + case LogLevel::Critical: return ImVec4(1.0f, 0.1f, 0.1f, 1.0f); default: return ImGui::GetStyleColorVec4(ImGuiCol_Text); } } diff --git a/SynapseEngine/Editor/View/Logger/LoggerView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Logger/LoggerView.h similarity index 82% rename from SynapseEngine/Editor/View/Logger/LoggerView.h rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Logger/LoggerView.h index f148731b..4e55e869 100644 --- a/SynapseEngine/Editor/View/Logger/LoggerView.h +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Logger/LoggerView.h @@ -1,6 +1,6 @@ #pragma once -#include "Editor/View/IView.h" -#include "EditorCore/ViewModels/Logger/LoggerViewModel.h" +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Logger/LoggerViewModel.h" #include #include #include diff --git a/SynapseEngine/Editor/View/Settings/SettingsView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Settings/SettingsView.cpp similarity index 70% rename from SynapseEngine/Editor/View/Settings/SettingsView.cpp rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Settings/SettingsView.cpp index 71d5db30..f006c738 100644 --- a/SynapseEngine/Editor/View/Settings/SettingsView.cpp +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Settings/SettingsView.cpp @@ -3,6 +3,7 @@ #include "Engine/Render/ComputeGroupSize.h" #include "Editor/Widgets/CardWidget.h" #include "Editor/Widgets/PropertyGrid.h" +#include "Editor/Widgets/Vector3Widget.h" #include #include #include @@ -217,6 +218,81 @@ namespace Syn { } Syn::UI::EndCard(); + constexpr const char* CardEnvironmentTitle = "Environment Settings"; + if (Syn::UI::BeginCard(CardEnvironmentTitle, SYN_ICON_SUN, getCardState(CardEnvironmentTitle))) { + if (Syn::UI::BeginPropertyGrid("EnvironmentGrid")) { + drawSectionHeader("Skybox Render"); + + changed |= Syn::UI::PropertyCheckbox("Enable Sky", settings.environment.enableSky); + + if (settings.environment.enableSky) { + const char* skyModes[] = { "None", "Equirectangular", "Octahedral", "Procedural" }; + int currentMode = (int)settings.environment.skyMode; + Syn::UI::BeginProperty("Sky Mode"); + if (ImGui::Combo("##SkyMode", ¤tMode, skyModes, IM_ARRAYSIZE(skyModes))) { + settings.environment.skyMode = (SkyMode)currentMode; + changed = true; + } + + if (settings.environment.skyMode == SkyMode::EquirectangularTexture || settings.environment.skyMode == SkyMode::OctahedralTexture) { + + const auto& textures = state.availableSkyTextures; + std::vector textureNames; + int currentTextureIdx = -1; + + textureNames.push_back("None"); + if (settings.environment.skyTextureId == UINT32_MAX) currentTextureIdx = 0; + + for (int i = 0; i < textures.size(); ++i) { + textureNames.push_back(textures[i].second.c_str()); + if (textures[i].first == settings.environment.skyTextureId) { + currentTextureIdx = i + 1; + } + } + + Syn::UI::BeginProperty("Sky Texture"); + if (ImGui::Combo("##SkyTexture", ¤tTextureIdx, textureNames.data(), textureNames.size())) { + if (currentTextureIdx == 0) { + settings.environment.skyTextureId = UINT32_MAX; + } + else { + settings.environment.skyTextureId = textures[currentTextureIdx - 1].first; + } + changed = true; + } + } + + changed |= Syn::UI::PropertyDragFloat("Intensity", settings.environment.skyIntensity, 0.05f, 0.0f, 100.0f, "%.2f", 1); + changed |= Syn::UI::PropertyDragFloat("Exposure", settings.environment.skyExposureEV, 0.05f, -100.0f, 100.0f, "%.2f", 1); + + Syn::UI::BeginProperty("Tint"); + if (ImGui::ColorEdit3("##SkyTint", glm::value_ptr(settings.environment.skyTint), ImGuiColorEditFlags_NoInputs)) { + changed = true; + } + + Syn::UI::BeginProperty("Rotation"); + bool rotDeactivated = false; + if (Syn::UI::DrawVec3Control("SkyRot", settings.environment.skyRotation, 0.0f, rotDeactivated)) { + changed = true; + } + } + + Syn::UI::PropertySeparator(); + drawSectionHeader("Fog & Atmospherics"); + changed |= Syn::UI::PropertyCheckbox("Enable Fog", settings.environment.enableFog); + if (settings.environment.enableFog) { + Syn::UI::BeginProperty("Fog Color"); + if (ImGui::ColorEdit3("##FogColor", glm::value_ptr(settings.environment.fogColor), ImGuiColorEditFlags_NoInputs)) { + changed = true; + } + changed |= Syn::UI::PropertyDragFloat("Fog Density", settings.environment.fogDensity, 0.001f, 0.0f, 1.0f, "%.4f", 1); + } + + Syn::UI::EndPropertyGrid(); + } + } + Syn::UI::EndCard(); + constexpr const char* CardDebugTitle = "Debug & Visualization"; if (Syn::UI::BeginCard(CardDebugTitle, SYN_ICON_BUG, getCardState(CardDebugTitle))) { @@ -282,6 +358,62 @@ namespace Syn { } Syn::UI::EndCard(); + constexpr const char* CardGridTitle = "Infinite Grid & Axes"; + if (Syn::UI::BeginCard(CardGridTitle, SYN_ICON_TH, getCardState(CardGridTitle))) { + + if (Syn::UI::BeginPropertyGrid("InfiniteGridGrid")) { + + changed |= Syn::UI::PropertyCheckbox("Enable Infinite Grid", settings.debug.enableInfiniteGrid); + + if (settings.debug.enableInfiniteGrid) { + changed |= Syn::UI::PropertyDragFloat("Grid Scale", settings.debug.gridScale, 0.1f, 0.1f, 100.0f, "%.1f", 1); + changed |= Syn::UI::PropertyDragFloat("Fade Distance", settings.debug.fadeDistance, 1.0f, 10.0f, 1000.0f, "%.1f", 1); + + // Új vastagság beállítások + changed |= Syn::UI::PropertyDragFloat("Grid Line Thickness", settings.debug.gridThickness, 0.05f, 0.1f, 10.0f, "%.2f", 1); + changed |= Syn::UI::PropertyDragFloat("Axis Line Thickness", settings.debug.axisThickness, 0.05f, 0.1f, 10.0f, "%.2f", 1); + + Syn::UI::PropertySeparator(); + + drawSectionHeader("Grid Planes & Main Color"); + + Syn::UI::BeginProperty("Grid Color"); + if (ImGui::ColorEdit4("##GridColorPicker", glm::value_ptr(settings.debug.gridColor), ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_AlphaPreview)) { + changed = true; + } + + changed |= Syn::UI::PropertyCheckbox("Show XZ Plane (Floor)", settings.debug.gridShowXZ); + changed |= Syn::UI::PropertyCheckbox("Show XY Plane (Wall)", settings.debug.gridShowXY); + changed |= Syn::UI::PropertyCheckbox("Show YZ Plane (Wall)", settings.debug.gridShowYZ); + + Syn::UI::PropertySeparator(); + + drawSectionHeader("World Axes & Custom Colors"); + + changed |= Syn::UI::PropertyCheckbox("Show X Axis", settings.debug.gridShowAxisX); + ImGui::SameLine(); + if (ImGui::ColorEdit4("##AxisXColorPicker", glm::value_ptr(settings.debug.axisXColor), ImGuiColorEditFlags_NoInputs)) { + changed = true; + } + + changed |= Syn::UI::PropertyCheckbox("Show Y Axis", settings.debug.gridShowAxisY); + ImGui::SameLine(); + if (ImGui::ColorEdit4("##AxisYColorPicker", glm::value_ptr(settings.debug.axisYColor), ImGuiColorEditFlags_NoInputs)) { + changed = true; + } + + changed |= Syn::UI::PropertyCheckbox("Show Z Axis", settings.debug.gridShowAxisZ); + ImGui::SameLine(); + if (ImGui::ColorEdit4("##AxisZColorPicker", glm::value_ptr(settings.debug.axisZColor), ImGuiColorEditFlags_NoInputs)) { + changed = true; + } + } + + Syn::UI::EndPropertyGrid(); + } + } + Syn::UI::EndCard(); + if (changed) { vm.Dispatch(UpdateSceneSettingsIntent{ settings }); } diff --git a/SynapseEngine/Editor/View/Settings/SettingsView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Settings/SettingsView.h similarity index 70% rename from SynapseEngine/Editor/View/Settings/SettingsView.h rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Settings/SettingsView.h index 29a3327e..9c1d2bb4 100644 --- a/SynapseEngine/Editor/View/Settings/SettingsView.h +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Settings/SettingsView.h @@ -1,6 +1,6 @@ #pragma once -#include "Editor/View/IView.h" -#include "EditorCore/ViewModels/Settings/SettingsViewModel.h" +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Settings/SettingsViewModel.h" #include #include diff --git a/SynapseEngine/Editor/View/Viewport/ViewportView.cpp b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Viewport/ViewportView.cpp similarity index 85% rename from SynapseEngine/Editor/View/Viewport/ViewportView.cpp rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Viewport/ViewportView.cpp index c3805347..6121870b 100644 --- a/SynapseEngine/Editor/View/Viewport/ViewportView.cpp +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Viewport/ViewportView.cpp @@ -30,7 +30,9 @@ namespace Syn { if (viewportPanelSize.y <= 0.0f) viewportPanelSize.y = 1.0f; if (state.textureId && !isResizing) { + ImGui::GetWindowDrawList()->AddCallback(ImGui::GetPlatformIO().DrawCallback_SetSamplerNearest, nullptr); ImGui::Image(state.textureId, viewportPanelSize); + ImGui::GetWindowDrawList()->AddCallback(ImGui::GetPlatformIO().DrawCallback_SetSamplerLinear, nullptr); } else { ImGui::Dummy(viewportPanelSize); @@ -43,14 +45,22 @@ namespace Syn { RenderFloatingToolbar(vm, state, imageStartPos, viewportPanelSize); RenderSimulationToolbar(vm, state, imageStartPos, viewportPanelSize); - if (isImageHovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGuizmo::IsOver() && !ImGui::IsAnyItemHovered()) { - ImVec2 mousePos = ImGui::GetMousePos(); - uint32_t x = static_cast(mousePos.x - vMin.x); - uint32_t y = static_cast(mousePos.y - vMin.y); - vm.Dispatch(PickEntityIntent{ x, y }); + DrawGizmo(vm, state, imageStartPos, viewportPanelSize); + + if (!ImGuizmo::IsUsing()) { + + if (isImageHovered && ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !ImGuizmo::IsOver() && !ImGui::IsAnyItemHovered()) { + ImVec2 mousePos = ImGui::GetMousePos(); + uint32_t x = static_cast(mousePos.x - imageStartPos.x); + uint32_t y = static_cast(mousePos.y - imageStartPos.y); + vm.Dispatch(PickEntityIntent{ x, y }); + } + + if (isImageHovered && ImGui::IsMouseDown(ImGuiMouseButton_Right)) { + + } } - DrawGizmo(vm, state, imageStartPos, viewportPanelSize); HandleShortcuts(vm); ImGui::End(); @@ -67,7 +77,7 @@ namespace Syn { ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 6.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.0f, 6.0f)); - if (ImGui::BeginChild("##SimulationToolbar", ImVec2(toolbarWidth, toolbarHeight), false, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_AlwaysUseWindowPadding)) { + if (ImGui::BeginChild("##SimulationToolbar", ImVec2(toolbarWidth, toolbarHeight), ImGuiChildFlags_AlwaysUseWindowPadding, ImGuiWindowFlags_NoScrollbar)) { ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4.0f, 6.0f)); @@ -121,7 +131,7 @@ namespace Syn { ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 6.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(4.0f, 6.0f)); - if (ImGui::BeginChild("##FloatingToolbar", ImVec2(toolbarWidth, toolbarHeight), false, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_AlwaysUseWindowPadding)) { + if (ImGui::BeginChild("##FloatingToolbar", ImVec2(toolbarWidth, toolbarHeight), ImGuiChildFlags_AlwaysUseWindowPadding, ImGuiWindowFlags_NoScrollbar)) { ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(4.0f, 6.0f)); @@ -211,22 +221,22 @@ namespace Syn { return isActive; }; - RadioButton("Main", RenderTargetGroupNames::Deferred, RenderTargetNames::Main, Vk::ImageViewNames::Default); + RadioButton("Main", RenderTargetGroupNames::Main, RenderTargetNames::Main, Vk::ImageViewNames::Default); ImGui::SeparatorText("GBuffer Textures"); - RadioButton("Color", RenderTargetGroupNames::Deferred, RenderTargetNames::ColorMetallic, RenderTargetViewNames::Color); - RadioButton("Metallic", RenderTargetGroupNames::Deferred, RenderTargetNames::ColorMetallic, RenderTargetViewNames::Metallic); - RadioButton("Normal", RenderTargetGroupNames::Deferred, RenderTargetNames::NormalRoughness, RenderTargetViewNames::Normal); - RadioButton("Roughness", RenderTargetGroupNames::Deferred, RenderTargetNames::NormalRoughness, RenderTargetViewNames::Roughness); - RadioButton("Emissive", RenderTargetGroupNames::Deferred, RenderTargetNames::EmissiveAo, RenderTargetViewNames::Emissive); - RadioButton("Ambient Occlusion", RenderTargetGroupNames::Deferred, RenderTargetNames::EmissiveAo, RenderTargetViewNames::AmbientOcclusion); - RadioButton("Ssao", RenderTargetGroupNames::Deferred, RenderTargetNames::SsaoAo, Vk::ImageViewNames::Default); + RadioButton("Color", RenderTargetGroupNames::Main, RenderTargetNames::ColorMetallic, RenderTargetViewNames::Color); + RadioButton("Metallic", RenderTargetGroupNames::Main, RenderTargetNames::ColorMetallic, RenderTargetViewNames::Metallic); + RadioButton("Normal", RenderTargetGroupNames::Main, RenderTargetNames::NormalRoughness, RenderTargetViewNames::Normal); + RadioButton("Roughness", RenderTargetGroupNames::Main, RenderTargetNames::NormalRoughness, RenderTargetViewNames::Roughness); + RadioButton("Emissive", RenderTargetGroupNames::Main, RenderTargetNames::EmissiveAo, RenderTargetViewNames::Emissive); + RadioButton("Ambient Occlusion", RenderTargetGroupNames::Main, RenderTargetNames::EmissiveAo, RenderTargetViewNames::AmbientOcclusion); + RadioButton("Ssao", RenderTargetGroupNames::Main, RenderTargetNames::SsaoAo, Vk::ImageViewNames::Default); ImGui::SeparatorText("Wboit Textures"); - RadioButton("Transparent Accum", RenderTargetGroupNames::Deferred, RenderTargetNames::TransparentAccum, Vk::ImageViewNames::Default); - RadioButton("Transparent Reveal", RenderTargetGroupNames::Deferred, RenderTargetNames::TransparentReveal, Vk::ImageViewNames::Default); + RadioButton("Transparent Accum", RenderTargetGroupNames::Main, RenderTargetNames::TransparentAccum, Vk::ImageViewNames::Default); + RadioButton("Transparent Reveal", RenderTargetGroupNames::Main, RenderTargetNames::TransparentReveal, Vk::ImageViewNames::Default); ImGui::SeparatorText("Mipchain Textures"); @@ -239,13 +249,13 @@ namespace Syn { static int bloomMip = 0; bloomMip = std::min(bloomMip, maxMipIndex); std::string bloomView = std::string(Vk::ImageViewNames::Default) + Vk::ImageViewNames::Mip + std::to_string(bloomMip); - RadioButton("Bloom", RenderTargetGroupNames::Deferred, RenderTargetNames::Bloom, bloomView); + RadioButton("Bloom", RenderTargetGroupNames::Main, RenderTargetNames::Bloom, bloomView); if (state.currentTarget == RenderTargetNames::Bloom) { ImGui::Indent(); if (ImGui::SliderInt("Mip##Bloom", &bloomMip, 0, maxMipIndex)) { bloomView = std::string(Vk::ImageViewNames::Default) + Vk::ImageViewNames::Mip + std::to_string(bloomMip); - vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Deferred, RenderTargetNames::Bloom, bloomView }); + vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Main, RenderTargetNames::Bloom, bloomView }); } ImGui::Unindent(); } @@ -253,13 +263,13 @@ namespace Syn { static int depthMipMax = 0; depthMipMax = std::min(depthMipMax, maxMipIndex); std::string depthMaxView = std::string(RenderTargetViewNames::DepthOpaqueMax) + Vk::ImageViewNames::Mip + std::to_string(depthMipMax); - RadioButton("Depth Pyramid Max", RenderTargetGroupNames::Deferred, RenderTargetNames::DepthPyramid, depthMaxView); + RadioButton("Depth Pyramid Max", RenderTargetGroupNames::Main, RenderTargetNames::DepthPyramid, depthMaxView); if (state.currentView.contains(RenderTargetViewNames::DepthOpaqueMax)) { ImGui::Indent(); if (ImGui::SliderInt("Mip##DepthMax", &depthMipMax, 0, maxMipIndex)) { depthMaxView = std::string(RenderTargetViewNames::DepthOpaqueMax) + Vk::ImageViewNames::Mip + std::to_string(depthMipMax); - vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Deferred, RenderTargetNames::DepthPyramid, depthMaxView }); + vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Main, RenderTargetNames::DepthPyramid, depthMaxView }); } ImGui::Unindent(); } @@ -267,13 +277,13 @@ namespace Syn { static int depthMipMin = 0; depthMipMin = std::min(depthMipMin, maxMipIndex); std::string depthMinView = std::string(RenderTargetViewNames::DepthTransparentMin) + Vk::ImageViewNames::Mip + std::to_string(depthMipMin); - RadioButton("Depth Pyramid Min", RenderTargetGroupNames::Deferred, RenderTargetNames::DepthPyramid, depthMinView); + RadioButton("Depth Pyramid Min", RenderTargetGroupNames::Main, RenderTargetNames::DepthPyramid, depthMinView); if (state.currentView.contains(RenderTargetViewNames::DepthTransparentMin)) { ImGui::Indent(); if (ImGui::SliderInt("Mip##DepthMin", &depthMipMin, 0, maxMipIndex)) { depthMinView = std::string(RenderTargetViewNames::DepthTransparentMin) + Vk::ImageViewNames::Mip + std::to_string(depthMipMin); - vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Deferred, RenderTargetNames::DepthPyramid, depthMinView }); + vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Main, RenderTargetNames::DepthPyramid, depthMinView }); } ImGui::Unindent(); } @@ -285,13 +295,13 @@ namespace Syn { std::string shadowMaxBaseView = RenderTargetViewNames::DirectionLightShadowDepthPyramidMax; std::string shadowMaxView = shadowMaxBaseView + Vk::ImageViewNames::Mip + std::to_string(shadowHzbMaxMip); - RadioButton("DirLight HZB Max (R)", RenderTargetGroupNames::Deferred, RenderTargetNames::DirectionLightShadowDepthPyramid, shadowMaxView); + RadioButton("DirLight HZB Max (R)", RenderTargetGroupNames::Main, RenderTargetNames::DirectionLightShadowDepthPyramid, shadowMaxView); if (state.currentView.contains(shadowMaxBaseView)) { ImGui::Indent(); if (ImGui::SliderInt("Mip##ShadowHzbMax", &shadowHzbMaxMip, 0, SHADOW_HIZ_MIP_LEVELS - 1)) { shadowMaxView = shadowMaxBaseView + Vk::ImageViewNames::Mip + std::to_string(shadowHzbMaxMip); - vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Deferred, RenderTargetNames::DirectionLightShadowDepthPyramid, shadowMaxView }); + vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Main, RenderTargetNames::DirectionLightShadowDepthPyramid, shadowMaxView }); } ImGui::Unindent(); } @@ -301,13 +311,13 @@ namespace Syn { std::string shadowMinBaseView = RenderTargetViewNames::DirectionLightShadowDepthPyramidMin; std::string shadowMinView = shadowMinBaseView + Vk::ImageViewNames::Mip + std::to_string(shadowHzbMinMip); - RadioButton("DirLight HZB Min (G)", RenderTargetGroupNames::Deferred, RenderTargetNames::DirectionLightShadowDepthPyramid, shadowMinView); + RadioButton("DirLight HZB Min (G)", RenderTargetGroupNames::Main, RenderTargetNames::DirectionLightShadowDepthPyramid, shadowMinView); if (state.currentView.contains(shadowMinBaseView)) { ImGui::Indent(); if (ImGui::SliderInt("Mip##ShadowHzbMin", &shadowHzbMinMip, 0, SHADOW_HIZ_MIP_LEVELS - 1)) { shadowMinView = shadowMinBaseView + Vk::ImageViewNames::Mip + std::to_string(shadowHzbMinMip); - vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Deferred, RenderTargetNames::DirectionLightShadowDepthPyramid, shadowMinView }); + vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Main, RenderTargetNames::DirectionLightShadowDepthPyramid, shadowMinView }); } ImGui::Unindent(); } @@ -317,13 +327,13 @@ namespace Syn { std::string spotShadowMaxBaseView = RenderTargetViewNames::SpotLightShadowDepthPyramidMax; std::string spotShadowMaxView = spotShadowMaxBaseView + Vk::ImageViewNames::Mip + std::to_string(spotShadowHzbMaxMip); - RadioButton("SpotLight HZB Max (R)", RenderTargetGroupNames::Deferred, RenderTargetNames::SpotLightShadowDepthPyramid, spotShadowMaxView); + RadioButton("SpotLight HZB Max (R)", RenderTargetGroupNames::Main, RenderTargetNames::SpotLightShadowDepthPyramid, spotShadowMaxView); if (state.currentView.contains(spotShadowMaxBaseView)) { ImGui::Indent(); if (ImGui::SliderInt("Mip##SpotShadowHzbMax", &spotShadowHzbMaxMip, 0, SPOT_SHADOW_HIZ_MIP_LEVELS - 1)) { spotShadowMaxView = spotShadowMaxBaseView + Vk::ImageViewNames::Mip + std::to_string(spotShadowHzbMaxMip); - vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Deferred, RenderTargetNames::SpotLightShadowDepthPyramid, spotShadowMaxView }); + vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Main, RenderTargetNames::SpotLightShadowDepthPyramid, spotShadowMaxView }); } ImGui::Unindent(); } @@ -333,13 +343,13 @@ namespace Syn { std::string spotShadowMinBaseView = RenderTargetViewNames::SpotLightShadowDepthPyramidMin; std::string spotShadowMinView = spotShadowMinBaseView + Vk::ImageViewNames::Mip + std::to_string(spotShadowHzbMinMip); - RadioButton("SpotLight HZB Min (G)", RenderTargetGroupNames::Deferred, RenderTargetNames::SpotLightShadowDepthPyramid, spotShadowMinView); + RadioButton("SpotLight HZB Min (G)", RenderTargetGroupNames::Main, RenderTargetNames::SpotLightShadowDepthPyramid, spotShadowMinView); if (state.currentView.contains(spotShadowMinBaseView)) { ImGui::Indent(); if (ImGui::SliderInt("Mip##SpotShadowHzbMin", &spotShadowHzbMinMip, 0, SPOT_SHADOW_HIZ_MIP_LEVELS - 1)) { spotShadowMinView = spotShadowMinBaseView + Vk::ImageViewNames::Mip + std::to_string(spotShadowHzbMinMip); - vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Deferred, RenderTargetNames::SpotLightShadowDepthPyramid, spotShadowMinView }); + vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Main, RenderTargetNames::SpotLightShadowDepthPyramid, spotShadowMinView }); } ImGui::Unindent(); } @@ -349,12 +359,12 @@ namespace Syn { std::string pointShadowMaxBaseView = RenderTargetViewNames::PointLightShadowDepthPyramidMax; std::string pointShadowMaxView = pointShadowMaxBaseView + Vk::ImageViewNames::Mip + std::to_string(pointShadowHzbMaxMip); - RadioButton("PointLight HZB Max (R)", RenderTargetGroupNames::Deferred, RenderTargetNames::PointLightShadowDepthPyramid, pointShadowMaxView); + RadioButton("PointLight HZB Max (R)", RenderTargetGroupNames::Main, RenderTargetNames::PointLightShadowDepthPyramid, pointShadowMaxView); if (state.currentView.contains(pointShadowMaxBaseView)) { ImGui::Indent(); if (ImGui::SliderInt("Mip##PointShadowHzbMax", &pointShadowHzbMaxMip, 0, POINT_SHADOW_HIZ_MIP_LEVELS - 1)) { pointShadowMaxView = pointShadowMaxBaseView + Vk::ImageViewNames::Mip + std::to_string(pointShadowHzbMaxMip); - vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Deferred, RenderTargetNames::PointLightShadowDepthPyramid, pointShadowMaxView }); + vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Main, RenderTargetNames::PointLightShadowDepthPyramid, pointShadowMaxView }); } ImGui::Unindent(); } @@ -364,15 +374,17 @@ namespace Syn { std::string pointShadowMinBaseView = RenderTargetViewNames::PointLightShadowDepthPyramidMin; std::string pointShadowMinView = pointShadowMinBaseView + Vk::ImageViewNames::Mip + std::to_string(pointShadowHzbMinMip); - RadioButton("PointLight HZB Min (G)", RenderTargetGroupNames::Deferred, RenderTargetNames::PointLightShadowDepthPyramid, pointShadowMinView); + RadioButton("PointLight HZB Min (G)", RenderTargetGroupNames::Main, RenderTargetNames::PointLightShadowDepthPyramid, pointShadowMinView); if (state.currentView.contains(pointShadowMinBaseView)) { ImGui::Indent(); if (ImGui::SliderInt("Mip##PointShadowHzbMin", &pointShadowHzbMinMip, 0, POINT_SHADOW_HIZ_MIP_LEVELS - 1)) { pointShadowMinView = pointShadowMinBaseView + Vk::ImageViewNames::Mip + std::to_string(pointShadowHzbMinMip); - vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Deferred, RenderTargetNames::PointLightShadowDepthPyramid, pointShadowMinView }); + vm.Dispatch(ChangeTargetIntent{ RenderTargetGroupNames::Main, RenderTargetNames::PointLightShadowDepthPyramid, pointShadowMinView }); } ImGui::Unindent(); } + + RadioButton("PreviewAtlas", RenderTargetGroupNames::Main, RenderTargetNames::PreviewAtlas, Vk::ImageViewNames::Default); } ImGui::EndChild(); ImGui::EndPopup(); diff --git a/SynapseEngine/Editor/View/Viewport/ViewportView.h b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Viewport/ViewportView.h similarity index 88% rename from SynapseEngine/Editor/View/Viewport/ViewportView.h rename to SynapseEngine/Editor/Workspace/SceneWorkspace/View/Viewport/ViewportView.h index 1c86aca1..0b0efcf3 100644 --- a/SynapseEngine/Editor/View/Viewport/ViewportView.h +++ b/SynapseEngine/Editor/Workspace/SceneWorkspace/View/Viewport/ViewportView.h @@ -1,7 +1,7 @@ #pragma once -#include "../IView.h" -#include "EditorCore/ViewModels/Viewport/ViewportViewModel.h" +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/SceneWorkspace/Viewport/ViewportViewModel.h" #include namespace Syn { diff --git a/SynapseEngine/Editor/Workspace/TextureWorkspace.cpp b/SynapseEngine/Editor/Workspace/TextureWorkspace.cpp deleted file mode 100644 index 91e39a71..00000000 --- a/SynapseEngine/Editor/Workspace/TextureWorkspace.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "TextureWorkspace.h" -#include "Editor/Manager/EditorIcons.h" - -#include "Editor/View/ContentBrowser/ContentBrowserView.h" -#include "EditorCore/ViewModels/ContentBrowser/ContentBrowserViewModel.h" - -namespace Syn { - - TextureWorkspace::TextureWorkspace(EditorContext* context, IconManager* iconManager, const std::string& assetPath) - : _context(context), _iconManager(iconManager), _assetPath(assetPath) {} - - void TextureWorkspace::Initialize() { - using ContentBrowserWin = EditorWindow; - AddWindow( - ContentBrowserView{ _iconManager, SYN_ICON_FOLDER_OPEN " Content Browser###Content_Texture" }, - ContentBrowserViewModel{ _context->GetFileSystemApi(), _assetPath } - ); - } - -} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/TextureWorkspace/TextureWorkspace.cpp b/SynapseEngine/Editor/Workspace/TextureWorkspace/TextureWorkspace.cpp new file mode 100644 index 00000000..c8b60a97 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/TextureWorkspace/TextureWorkspace.cpp @@ -0,0 +1,47 @@ +#include "TextureWorkspace.h" +#include "Editor/Manager/EditorIcons.h" + +#include "Editor/Workspace/Common/ContentBrowser/ContentBrowserView.h" +#include "EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserViewModel.h" + +#include "View/TextureHierarchy/TextureHierarchyView.h" +#include "EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyViewModel.h" + +#include "View/TextureProperties/TexturePropertiesView.h" +#include "EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesViewModel.h" + +#include "View/TextureGraph/TextureGraphView.h" +#include "EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphViewModel.h" + +namespace Syn { + + TextureWorkspace::TextureWorkspace(EditorContext* context, IconManager* iconManager, const std::string& assetPath) + : _context(context), _iconManager(iconManager), _assetPath(assetPath) {} + + void TextureWorkspace::Initialize() + { + using ContentBrowserWin = EditorWindow; + AddWindow( + ContentBrowserView{ _iconManager, SYN_ICON_FOLDER_OPEN " Content Browser###Content_Texture" }, + ContentBrowserViewModel{ _context->GetApi(), _assetPath } + ); + + using TextureHierarchyWin = EditorWindow; + AddWindow( + TextureHierarchyView{}, + TextureHierarchyViewModel{ _context->GetApi() } + ); + + using TexturePropertiesWin = EditorWindow; + AddWindow( + TexturePropertiesView{}, + TexturePropertiesViewModel{ _context->GetApi() } + ); + + using TextureGraphWin = EditorWindow; + AddWindow( + TextureGraphView{}, + TextureGraphViewModel{ _context->GetApi() } + ); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/TextureWorkspace.h b/SynapseEngine/Editor/Workspace/TextureWorkspace/TextureWorkspace.h similarity index 92% rename from SynapseEngine/Editor/Workspace/TextureWorkspace.h rename to SynapseEngine/Editor/Workspace/TextureWorkspace/TextureWorkspace.h index 391b21ea..3bb82497 100644 --- a/SynapseEngine/Editor/Workspace/TextureWorkspace.h +++ b/SynapseEngine/Editor/Workspace/TextureWorkspace/TextureWorkspace.h @@ -1,5 +1,5 @@ #pragma once -#include "IWorkspace.h" +#include "Editor/Workspace/IWorkspace.h" #include "Editor/EditorApi/EditorContext.h" #include "Editor/Manager/IconManager.h" #include diff --git a/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureGraph/TextureGraphView.cpp b/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureGraph/TextureGraphView.cpp new file mode 100644 index 00000000..d39785c0 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureGraph/TextureGraphView.cpp @@ -0,0 +1,92 @@ +#include "TextureGraphView.h" +#include "Editor/Manager/EditorIcons.h" +#include +#include +#include + +namespace ed = ax::NodeEditor; + +namespace Syn { + + TextureGraphView::TextureGraphView() { + ed::Config config; + config.SettingsFile = "Synapse_TextureGraph.json"; + _context = ed::CreateEditor(&config); + } + + TextureGraphView::~TextureGraphView() { + if (_context) ed::DestroyEditor(_context); + } + + TextureGraphView::TextureGraphView(TextureGraphView&& other) noexcept : _context(other._context) { + other._context = nullptr; + } + + TextureGraphView& TextureGraphView::operator=(TextureGraphView&& other) noexcept { + if (this != &other) { + if (_context) ed::DestroyEditor(_context); + _context = other._context; + other._context = nullptr; + } + return *this; + } + + void TextureGraphView::Draw(TextureGraphViewModel& vm) { + const auto& state = vm.GetState(); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); + ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; + + bool isVisible = ImGui::Begin(SYN_ICON_PROJECT_DIAGRAM " Texture Graph", nullptr, windowFlags); + ImGui::PopStyleVar(); + + if (isVisible) { + ed::SetCurrentEditor(_context); + + ImVec2 canvasSize = ImGui::GetContentRegionAvail(); + if (canvasSize.x <= 0.0f) canvasSize.x = 1.0f; + if (canvasSize.y <= 0.0f) canvasSize.y = 1.0f; + + ed::Begin("Texture Node Canvas", canvasSize); + + if (state.previewNode.isVisible) { + ed::BeginNode(ed::NodeId(1)); + + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.4f, 0.8f, 1.0f, 1.0f)); + ImGui::Text(SYN_ICON_IMAGE " %s", state.previewNode.name.empty() ? "Selected Texture" : state.previewNode.name.c_str()); + ImGui::PopStyleColor(); + ImGui::Dummy(ImVec2(0, 4.0f)); + + float maxPreviewSize = 512.0f; + ImVec2 imageSize(512.0f, 512.0f); + if (state.previewNode.width > 0 && state.previewNode.height > 0) { + float aspect = (float)state.previewNode.width / (float)state.previewNode.height; + if (aspect > 1.0f) { + imageSize.x = maxPreviewSize; + imageSize.y = maxPreviewSize / aspect; + } + else { + imageSize.y = maxPreviewSize; + imageSize.x = maxPreviewSize * aspect; + } + } + + if (state.previewNode.textureHandle != InvalidTextureHandle) { + ImGui::Image(state.previewNode.textureHandle, imageSize); + } + else { + ImGui::Button("No Preview\nAvailable", imageSize); + } + + ImGui::Dummy(ImVec2(0, 8.0f)); + + ed::EndNode(); + } + + ed::End(); + ed::SetCurrentEditor(nullptr); + } + + ImGui::End(); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureGraph/TextureGraphView.h b/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureGraph/TextureGraphView.h new file mode 100644 index 00000000..f6e05771 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureGraph/TextureGraphView.h @@ -0,0 +1,26 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphViewModel.h" + +namespace ax { + namespace NodeEditor { + struct EditorContext; + } +} + +namespace Syn { + class TextureGraphView : public IView { + public: + TextureGraphView(); + ~TextureGraphView() override; + + TextureGraphView(const TextureGraphView&) = delete; + TextureGraphView& operator=(const TextureGraphView&) = delete; + TextureGraphView(TextureGraphView&& other) noexcept; + TextureGraphView& operator=(TextureGraphView&& other) noexcept; + + void Draw(TextureGraphViewModel& vm) override; + private: + ax::NodeEditor::EditorContext* _context = nullptr; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureHierarchy/TextureHierarchyView.cpp b/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureHierarchy/TextureHierarchyView.cpp new file mode 100644 index 00000000..d4486016 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureHierarchy/TextureHierarchyView.cpp @@ -0,0 +1,108 @@ +#include "TextureHierarchyView.h" +#include "Editor/Manager/EditorIcons.h" +#include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/ItemCardWidget.h" +#include "Editor/Widgets/ItemCardContainerWidget.h" +#include + +namespace Syn { + void TextureHierarchyView::Draw(TextureHierarchyViewModel& vm) { + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 8)); + ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; + + if (ImGui::Begin(SYN_ICON_IMAGE " Textures", nullptr, windowFlags)) { + + auto getCardState = [this](const char* name) -> bool& { + std::string key(name); + if (_cardStates.find(key) == _cardStates.end()) _cardStates[key] = true; + return _cardStates[key]; + }; + + float mainContentBottomY = ImGui::GetWindowPos().y + ImGui::GetWindowContentRegionMax().y; + constexpr const char* CardTexturesTitle = "TextureListCard"; + + if (Syn::UI::BeginCard(CardTexturesTitle, SYN_ICON_IMAGE, getCardState(CardTexturesTitle))) { + + RenderTopBar(vm); + + float currentY = ImGui::GetCursorScreenPos().y; + float gridHeight = mainContentBottomY - currentY - 12.0f; + if (gridHeight < 150.0f) gridHeight = 150.0f; + + ImGui::BeginChild("TextureGridContainer", ImVec2(0, gridHeight), false, ImGuiWindowFlags_NoScrollbar); + + const auto& state = vm.GetState(); + + const auto entries = state.filteredNodes; + const float thumbnailSize = 100; + Syn::UI::ItemCardContainer("ContentGrid", (int)entries.size(), thumbnailSize, + [&](int index) { + const auto& entry = entries[index]; + + Syn::UI::ItemCardDesc desc; + desc.id = entry.path.c_str(); + desc.title = entry.name.c_str(); + desc.texture = entry.handle; + desc.selected = (state.selectedTexture == entry.id); + + desc.events.onClick = [&vm, &entry] { + vm.Dispatch(TextureSelectIntent{ entry.id }); + }; + + desc.events.onDoubleClick = [&vm, &entry] { + //Todo? + }; + + desc.events.onDragDropSource = [this, &entry] { + //Todo? + }; + + Syn::UI::ItemCard(desc, thumbnailSize); + }); + + ImGui::EndChild(); + } + Syn::UI::EndCard(); + + if (ImGui::IsMouseDown(ImGuiMouseButton_Left) && ImGui::IsWindowHovered()) { + vm.Dispatch(TextureSelectIntent{ INVALID_TEXTURE_ID }); + } + } + ImGui::End(); + ImGui::PopStyleVar(); + } + + void TextureHierarchyView::RenderTopBar(TextureHierarchyViewModel& vm) { + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(8, 6)); + + float barHeight = ImGui::GetFrameHeight(); + ImGui::BeginChild("TextureTopBar", ImVec2(0, barHeight), false, ImGuiWindowFlags_NoScrollbar); + + if (ImGui::Button(SYN_ICON_SYNC " Refresh")) { + vm.Dispatch(TextureRefreshIntent{}); + } + + ImGui::SameLine(); + ImGui::Dummy(ImVec2(8.0f, 0.0f)); + ImGui::SameLine(); + + ImGui::AlignTextToFramePadding(); + ImGui::TextDisabled(SYN_ICON_SEARCH); + ImGui::SameLine(); + + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + + const auto& state = vm.GetState(); + char searchBuffer[256]; + strncpy(searchBuffer, state.searchQuery.c_str(), sizeof(searchBuffer)); + searchBuffer[sizeof(searchBuffer) - 1] = '\0'; + + if (ImGui::InputTextWithHint("##SearchTextures", "Search...", searchBuffer, IM_ARRAYSIZE(searchBuffer))) { + vm.Dispatch(TextureSetSearchQueryIntent{ std::string(searchBuffer) }); + } + + ImGui::EndChild(); + ImGui::PopStyleVar(); + ImGui::Spacing(); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureHierarchy/TextureHierarchyView.h b/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureHierarchy/TextureHierarchyView.h new file mode 100644 index 00000000..fd6792b3 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureHierarchy/TextureHierarchyView.h @@ -0,0 +1,17 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyViewModel.h" +#include +#include + +namespace Syn { + class TextureHierarchyView : public IView { + public: + void Draw(TextureHierarchyViewModel& vm) override; + private: + void RenderTopBar(TextureHierarchyViewModel& vm); + void RenderTextureRow(TextureHierarchyViewModel& vm, const TextureNode& node); + private: + std::unordered_map _cardStates; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureProperties/TexturePropertiesView.cpp b/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureProperties/TexturePropertiesView.cpp new file mode 100644 index 00000000..8f2cf709 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureProperties/TexturePropertiesView.cpp @@ -0,0 +1,65 @@ +#include "TexturePropertiesView.h" +#include "Editor/Manager/EditorIcons.h" +#include "Editor/Widgets/CardWidget.h" +#include "Editor/Widgets/PropertyGrid.h" +#include +#include + +namespace Syn { + void TexturePropertiesView::Draw(TexturePropertiesViewModel& vm) { + const TexturePropertiesState& state = vm.GetState(); + + ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8, 8)); + ImGuiWindowFlags windowFlags = ImGuiWindowFlags_None; + + if (ImGui::Begin(SYN_ICON_INFO_CIRCLE " Texture Properties", nullptr, windowFlags)) { + + auto getCardState = [this](const char* name) -> bool& { + std::string key(name); + if (_cardStates.find(key) == _cardStates.end()) _cardStates[key] = true; + return _cardStates[key]; + }; + + constexpr const char* CardTitle = "TextureDetailsCard"; + if (Syn::UI::BeginCard(CardTitle, SYN_ICON_IMAGE, getCardState(CardTitle))) { + + if (!state.hasSelection) { + ImGui::TextDisabled("No texture selected."); + } + else { + if (Syn::UI::BeginPropertyGrid("TexturePropsGrid")) + { + std::string dimensions = std::to_string(state.width) + " x " + std::to_string(state.height); + if (state.depth > 1) { + dimensions += " x " + std::to_string(state.depth); + } + DrawReadOnlyProperty("Dimensions", dimensions.c_str()); + DrawReadOnlyProperty("Mip Levels", std::to_string(state.mipLevels).c_str()); + + std::string formatStr = "VkFormat(" + std::to_string(state.format) + ")"; + DrawReadOnlyProperty("Format", formatStr.c_str()); + DrawReadOnlyProperty("Compressed", state.isCompressed ? "Yes" : "No"); + + Syn::UI::EndPropertyGrid(); + } + } + } + Syn::UI::EndCard(); + } + + ImGui::End(); + ImGui::PopStyleVar(); + } + + void TexturePropertiesView::DrawReadOnlyProperty(const char* label, const char* value) { + ImGui::TableNextRow(); + + ImGui::TableNextColumn(); + ImGui::TextUnformatted(label); + + ImGui::TableNextColumn(); + ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.7f, 0.7f, 0.7f, 1.0f)); + ImGui::TextUnformatted(value); + ImGui::PopStyleColor(); + } +} \ No newline at end of file diff --git a/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureProperties/TexturePropertiesView.h b/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureProperties/TexturePropertiesView.h new file mode 100644 index 00000000..45e9fd50 --- /dev/null +++ b/SynapseEngine/Editor/Workspace/TextureWorkspace/View/TextureProperties/TexturePropertiesView.h @@ -0,0 +1,16 @@ +#pragma once +#include "Editor/Workspace/IView.h" +#include "EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesViewModel.h" +#include +#include + +namespace Syn { + class TexturePropertiesView : public IView { + public: + void Draw(TexturePropertiesViewModel& vm) override; + private: + void DrawReadOnlyProperty(const char* label, const char* value); + private: + std::unordered_map _cardStates; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/IAnimationApi.h b/SynapseEngine/EditorCore/Api/IAnimationApi.h new file mode 100644 index 00000000..ddc1c81e --- /dev/null +++ b/SynapseEngine/EditorCore/Api/IAnimationApi.h @@ -0,0 +1,23 @@ +#pragma once +#include "IApi.h" +#include "EditorCore/Types/EntityHandle.h" +#include +#include +#include + +namespace Syn { + class IAnimationApi : public IApi { + public: + virtual ~IAnimationApi() = default; + + virtual bool HasAnimation(EntityID entity) const = 0; + + virtual float GetAnimationSpeed(EntityID entity) const = 0; + virtual uint32_t GetAnimationIndex(EntityID entity) const = 0; + + virtual void SetAnimationSpeed(EntityID entity, float speed) = 0; + virtual void SetAnimationIndex(EntityID entity, uint32_t index) = 0; + + virtual std::vector> GetAvailableAnimations() const = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/IApi.h b/SynapseEngine/EditorCore/Api/IApi.h new file mode 100644 index 00000000..bde147cf --- /dev/null +++ b/SynapseEngine/EditorCore/Api/IApi.h @@ -0,0 +1,9 @@ +#pragma once + +namespace Syn +{ + class IApi { + public: + virtual ~IApi() = default; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/IBoxColliderApi.h b/SynapseEngine/EditorCore/Api/IBoxColliderApi.h new file mode 100644 index 00000000..98531478 --- /dev/null +++ b/SynapseEngine/EditorCore/Api/IBoxColliderApi.h @@ -0,0 +1,19 @@ +#pragma once +#include +#include "IApi.h" +#include "EditorCore/Types/EntityHandle.h" + +namespace Syn { + class IBoxColliderApi : public IApi { + public: + virtual ~IBoxColliderApi() = default; + + virtual bool HasBoxCollider(EntityID entity) const = 0; + + virtual glm::vec3 GetBoxColliderHalfExtents(EntityID entity) const = 0; + virtual glm::vec3 GetBoxColliderLocalOffset(EntityID entity) const = 0; + + virtual void SetBoxColliderHalfExtents(EntityID entity, const glm::vec3& halfExtents) = 0; + virtual void SetBoxColliderLocalOffset(EntityID entity, const glm::vec3& localOffset) = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/ICameraApi.h b/SynapseEngine/EditorCore/Api/ICameraApi.h new file mode 100644 index 00000000..2b638f10 --- /dev/null +++ b/SynapseEngine/EditorCore/Api/ICameraApi.h @@ -0,0 +1,38 @@ +#pragma once +#include "IApi.h" +#include "EditorCore/Types/EntityHandle.h" + +namespace Syn { + class ICameraApi : public IApi { + public: + virtual ~ICameraApi() = default; + + virtual bool HasCamera(EntityID entity) const = 0; + + virtual bool GetCameraIsOrthographic(EntityID entity) const = 0; + virtual float GetCameraOrthoSize(EntityID entity) const = 0; + virtual bool GetCameraUseOrbit(EntityID entity) const = 0; + + virtual float GetCameraYaw(EntityID entity) const = 0; + virtual float GetCameraPitch(EntityID entity) const = 0; + virtual float GetCameraNearPlane(EntityID entity) const = 0; + virtual float GetCameraFarPlane(EntityID entity) const = 0; + virtual float GetCameraFov(EntityID entity) const = 0; + virtual float GetCameraSpeed(EntityID entity) const = 0; + virtual float GetCameraSensitivity(EntityID entity) const = 0; + virtual float GetCameraDistance(EntityID entity) const = 0; + + virtual void SetCameraIsOrthographic(EntityID entity, bool isOrthographic) = 0; + virtual void SetCameraOrthoSize(EntityID entity, float orthoSize) = 0; + virtual void SetCameraUseOrbit(EntityID entity, bool useOrbit) = 0; + + virtual void SetCameraYaw(EntityID entity, float yaw) = 0; + virtual void SetCameraPitch(EntityID entity, float pitch) = 0; + virtual void SetCameraNearPlane(EntityID entity, float nearPlane) = 0; + virtual void SetCameraFarPlane(EntityID entity, float farPlane) = 0; + virtual void SetCameraFov(EntityID entity, float fov) = 0; + virtual void SetCameraSpeed(EntityID entity, float speed) = 0; + virtual void SetCameraSensitivity(EntityID entity, float sensitivity) = 0; + virtual void SetCameraDistance(EntityID entity, float distance) = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/ICapsuleColliderApi.h b/SynapseEngine/EditorCore/Api/ICapsuleColliderApi.h new file mode 100644 index 00000000..bf2f43b0 --- /dev/null +++ b/SynapseEngine/EditorCore/Api/ICapsuleColliderApi.h @@ -0,0 +1,21 @@ +#pragma once +#include "IApi.h" +#include +#include "EditorCore/Types/EntityHandle.h" + +namespace Syn { + class ICapsuleColliderApi : public IApi { + public: + virtual ~ICapsuleColliderApi() = default; + + virtual bool HasCapsuleCollider(EntityID entity) const = 0; + + virtual float GetCapsuleColliderRadius(EntityID entity) const = 0; + virtual float GetCapsuleColliderHalfHeight(EntityID entity) const = 0; + virtual glm::vec3 GetCapsuleColliderLocalOffset(EntityID entity) const = 0; + + virtual void SetCapsuleColliderRadius(EntityID entity, float radius) = 0; + virtual void SetCapsuleColliderHalfHeight(EntityID entity, float halfHeight) = 0; + virtual void SetCapsuleColliderLocalOffset(EntityID entity, const glm::vec3& localOffset) = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/IConvexColliderApi.h b/SynapseEngine/EditorCore/Api/IConvexColliderApi.h new file mode 100644 index 00000000..310d0658 --- /dev/null +++ b/SynapseEngine/EditorCore/Api/IConvexColliderApi.h @@ -0,0 +1,20 @@ +#pragma once +#include "IApi.h" +#include +#include "EditorCore/Types/EntityHandle.h" +#include + +namespace Syn { + class IConvexColliderApi : public IApi { + public: + virtual ~IConvexColliderApi() = default; + + virtual bool HasConvexCollider(EntityID entity) const = 0; + + virtual uint32_t GetConvexColliderTargetLodLevel(EntityID entity) const = 0; + virtual glm::vec3 GetConvexColliderLocalOffset(EntityID entity) const = 0; + + virtual void SetConvexColliderTargetLodLevel(EntityID entity, uint32_t targetLodLevel) = 0; + virtual void SetConvexColliderLocalOffset(EntityID entity, const glm::vec3& localOffset) = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/IDirectionLightApi.h b/SynapseEngine/EditorCore/Api/IDirectionLightApi.h index b472318e..a5250fe7 100644 --- a/SynapseEngine/EditorCore/Api/IDirectionLightApi.h +++ b/SynapseEngine/EditorCore/Api/IDirectionLightApi.h @@ -1,9 +1,10 @@ #pragma once +#include "IApi.h" #include #include "EditorCore/Types/EntityHandle.h" namespace Syn { - class IDirectionLightApi { + class IDirectionLightApi : public IApi { public: virtual ~IDirectionLightApi() = default; diff --git a/SynapseEngine/EditorCore/Api/IFileDialogApi.h b/SynapseEngine/EditorCore/Api/IFileDialogApi.h index e03b067f..8735a5c2 100644 --- a/SynapseEngine/EditorCore/Api/IFileDialogApi.h +++ b/SynapseEngine/EditorCore/Api/IFileDialogApi.h @@ -1,4 +1,5 @@ #pragma once +#include "IApi.h" #include #include @@ -10,7 +11,7 @@ namespace Syn { std::string DefaultPath; }; - class IFileDialogApi { + class IFileDialogApi : public IApi { public: virtual ~IFileDialogApi() = default; diff --git a/SynapseEngine/EditorCore/Api/IFileSystemApi.h b/SynapseEngine/EditorCore/Api/IFileSystemApi.h index 00857997..fd406961 100644 --- a/SynapseEngine/EditorCore/Api/IFileSystemApi.h +++ b/SynapseEngine/EditorCore/Api/IFileSystemApi.h @@ -1,11 +1,12 @@ #pragma once +#include "IApi.h" #include #include #include "EditorCore/Types/FileEntry.h" namespace Syn { - class IFileSystemApi { + class IFileSystemApi : public IApi { public: virtual ~IFileSystemApi() = default; diff --git a/SynapseEngine/EditorCore/Api/IHierarchyApi.h b/SynapseEngine/EditorCore/Api/IHierarchyApi.h index bbac6c69..ee188652 100644 --- a/SynapseEngine/EditorCore/Api/IHierarchyApi.h +++ b/SynapseEngine/EditorCore/Api/IHierarchyApi.h @@ -1,10 +1,37 @@ #pragma once +#include "IApi.h" #include #include #include "EditorCore/Types/EntityHandle.h" -namespace Syn { - class IHierarchyApi { +namespace Syn +{ + enum class EntityTemplate { + Empty, + Camera, + DirectionalLight, + PointLight, + SpotLight, + BoxCollider, + SphereCollider, + CapsuleCollider, + ConvexCollider, + MeshCollider, + ShapeCube, + ShapeSphere, + ShapeQuad, + ShapeCylinder, + ShapeCone, + ShapeCapsule, + ShapeHemisphere, + ShapePyramid, + ShapeGrid, + ShapeTorus, + Model, + Animation + }; + + class IHierarchyApi : public IApi { public: virtual ~IHierarchyApi() = default; @@ -17,7 +44,11 @@ namespace Syn { virtual EntityID GetParent(EntityID entity) const = 0; virtual void SetParent(EntityID child, EntityID parent) = 0; - virtual EntityID CreateEntity(const std::string& name, EntityID parent = NULL_ENTITY) = 0; + virtual EntityID CreateEntity(EntityTemplate templateType, EntityID parent = NULL_ENTITY) = 0; + virtual void DestroyEntityRecursive(EntityID entity) = 0; + virtual void DestroyEntityKeepChildren(EntityID entity) = 0; + virtual EntityID CopyEntity(EntityID entity, EntityID parent = NULL_ENTITY) = 0; + virtual EntityID FullCopyEntity(EntityID entity, EntityID parent = NULL_ENTITY) = 0; virtual void DestroyEntity(EntityID entity) = 0; virtual uint64_t GetVersion() const = 0; diff --git a/SynapseEngine/EditorCore/Api/ILoggerApi.h b/SynapseEngine/EditorCore/Api/ILoggerApi.h index 33811858..79cd4950 100644 --- a/SynapseEngine/EditorCore/Api/ILoggerApi.h +++ b/SynapseEngine/EditorCore/Api/ILoggerApi.h @@ -1,9 +1,10 @@ #pragma once +#include "IApi.h" #include "Engine/Logger/LogMessage.h" #include namespace Syn { - class ILoggerApi { + class ILoggerApi : public IApi { public: virtual ~ILoggerApi() = default; virtual const std::vector& GetLogs() const = 0; diff --git a/SynapseEngine/EditorCore/Api/IMaterialApi.h b/SynapseEngine/EditorCore/Api/IMaterialApi.h index c3dfbd53..10212a91 100644 --- a/SynapseEngine/EditorCore/Api/IMaterialApi.h +++ b/SynapseEngine/EditorCore/Api/IMaterialApi.h @@ -1,28 +1,38 @@ #pragma once +#include "IApi.h" #include #include #include +#include "Engine/Material/Material.h" +//Todo: Domain Material!! namespace Syn { - struct MaterialApiDesc { - uint32_t id; - std::string name; - }; + constexpr uint32_t INVALID_MATERIAL_ID = 0xFFFFFFFF; - struct TextureApiDesc { + struct MaterialItemData { uint32_t id; std::string name; + std::string path; }; - class IMaterialApi { + class IMaterialApi : public IApi { public: virtual ~IMaterialApi() = default; - virtual std::vector GetAllMaterials() const = 0; - virtual std::vector GetAllTextures() const = 0; + virtual std::vector GetAllMaterials() const = 0; + virtual uint32_t GetSelectedMaterial() const = 0; + virtual void SetSelectedMaterial(uint32_t id) = 0; + virtual uint64_t GetVersion() const = 0; + virtual std::string GetMaterialName(uint32_t materialId) const = 0; + virtual uint32_t GetLinkedTexture(uint32_t materialId, uint32_t textureType) const = 0; virtual void LinkTextureToMaterial(uint32_t materialId, uint32_t textureType, uint32_t textureId) = 0; virtual void UnlinkTextureFromMaterial(uint32_t materialId, uint32_t textureType) = 0; + + virtual bool GetMaterialData(uint32_t materialId, Material& outMaterial) const = 0; + virtual void UpdateMaterialData(uint32_t materialId, const Material& material) = 0; + + virtual void ApplyMaterialToPreviewObjects(uint32_t materialId) = 0; }; } \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/IMaterialOverrideApi.h b/SynapseEngine/EditorCore/Api/IMaterialOverrideApi.h new file mode 100644 index 00000000..7bc3ac1e --- /dev/null +++ b/SynapseEngine/EditorCore/Api/IMaterialOverrideApi.h @@ -0,0 +1,26 @@ +#pragma once +#include "IApi.h" +#include "EditorCore/Types/EntityHandle.h" +#include +#include +#include + +namespace Syn { + class IMaterialOverrideApi : public IApi { + public: + virtual ~IMaterialOverrideApi() = default; + + virtual bool HasMaterialOverride(EntityID entity) const = 0; + + virtual uint32_t GetExpectedSlotCount(EntityID entity) const = 0; + + virtual uint32_t GetMaterialAtSlot(EntityID entity, uint32_t slotIndex) const = 0; + virtual void SetMaterialAtSlot(EntityID entity, uint32_t slotIndex, uint32_t materialId) = 0; + + virtual EntityID GetSharedMaterialEntity(EntityID entity) const = 0; + virtual void SetSharedMaterialEntity(EntityID entity, EntityID sharedEntity) = 0; + + virtual std::vector> GetCompatibleSharedEntities(EntityID entity) const = 0; + virtual std::vector> GetAvailableMaterials() const = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/IMeshColliderApi.h b/SynapseEngine/EditorCore/Api/IMeshColliderApi.h new file mode 100644 index 00000000..3c2568db --- /dev/null +++ b/SynapseEngine/EditorCore/Api/IMeshColliderApi.h @@ -0,0 +1,20 @@ +#pragma once +#include +#include "IApi.h" +#include "EditorCore/Types/EntityHandle.h" +#include + +namespace Syn { + class IMeshColliderApi : public IApi { + public: + virtual ~IMeshColliderApi() = default; + + virtual bool HasMeshCollider(EntityID entity) const = 0; + + virtual uint32_t GetMeshColliderTargetLodLevel(EntityID entity) const = 0; + virtual glm::vec3 GetMeshColliderLocalOffset(EntityID entity) const = 0; + + virtual void SetMeshColliderTargetLodLevel(EntityID entity, uint32_t targetLodLevel) = 0; + virtual void SetMeshColliderLocalOffset(EntityID entity, const glm::vec3& localOffset) = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/IModelApi.h b/SynapseEngine/EditorCore/Api/IModelApi.h new file mode 100644 index 00000000..4a7415a1 --- /dev/null +++ b/SynapseEngine/EditorCore/Api/IModelApi.h @@ -0,0 +1,34 @@ +#pragma once +#include +#include +#include +#include "IApi.h" +#include "Engine/Mesh/Data/Cpu/CpuModelData.h" + +namespace Syn +{ + constexpr uint32_t INVALID_MODEL_ID = 0xFFFFFFFF; + constexpr int32_t INVALID_NODE_INDEX = -1; + + struct ModelItemData { + uint32_t id; + std::string name; + std::string path; + }; + + class IModelApi : public IApi { + public: + virtual ~IModelApi() = default; + + virtual std::vector GetAllModels() const = 0; + virtual uint64_t GetVersion() const = 0; + + virtual void SetSelected(uint32_t modelId, int32_t nodeIndex) = 0; + virtual std::pair GetSelected() const = 0; + + virtual const CpuModelData* GetModelCpuData(uint32_t modelId) const = 0; + virtual std::string GetNodeName(uint32_t modelId, uint16_t nodeIndex) const = 0; + + virtual void ApplyModelToPreviewObject(uint32_t modelId) = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/IModelComponentApi.h b/SynapseEngine/EditorCore/Api/IModelComponentApi.h new file mode 100644 index 00000000..d1f1266a --- /dev/null +++ b/SynapseEngine/EditorCore/Api/IModelComponentApi.h @@ -0,0 +1,25 @@ +#pragma once +#include "IApi.h" +#include "EditorCore/Types/EntityHandle.h" +#include +#include +#include + +namespace Syn { + class IModelComponentApi : public IApi { + public: + virtual ~IModelComponentApi() = default; + + virtual bool HasModelComponent(EntityID entity) const = 0; + + virtual bool GetCastShadow(EntityID entity) const = 0; + virtual bool GetReceiveShadow(EntityID entity) const = 0; + virtual uint32_t GetModelIndex(EntityID entity) const = 0; + + virtual void SetCastShadow(EntityID entity, bool cast) = 0; + virtual void SetReceiveShadow(EntityID entity, bool receive) = 0; + virtual void SetModelIndex(EntityID entity, uint32_t index) = 0; + + virtual std::vector> GetAvailableModels() const = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/IPointLightApi.h b/SynapseEngine/EditorCore/Api/IPointLightApi.h index 6fff0362..1a1e43c0 100644 --- a/SynapseEngine/EditorCore/Api/IPointLightApi.h +++ b/SynapseEngine/EditorCore/Api/IPointLightApi.h @@ -1,9 +1,10 @@ #pragma once #include +#include "IApi.h" #include "EditorCore/Types/EntityHandle.h" namespace Syn { - class IPointLightApi { + class IPointLightApi : public IApi { public: virtual ~IPointLightApi() = default; diff --git a/SynapseEngine/EditorCore/Api/IPreviewApi.h b/SynapseEngine/EditorCore/Api/IPreviewApi.h new file mode 100644 index 00000000..da87bc8c --- /dev/null +++ b/SynapseEngine/EditorCore/Api/IPreviewApi.h @@ -0,0 +1,28 @@ +#pragma once +#include +#include +#include + +#include "IApi.h" +#include "EditorCore/Types/TextureHandle.h" +#include "Engine/Manager/PreviewManager.h" + +namespace Syn { + + struct PreviewItemData { + uint32_t resourceId; + glm::vec2 uv0; + glm::vec2 uv1; + }; + + class IPreviewApi : public IApi { + public: + virtual ~IPreviewApi() = default; + + virtual TextureHandle GetAtlasHandle() = 0; + virtual bool GetPreviewUVs(PreviewResourceType type, uint32_t resourceId, glm::vec2& outUv0, glm::vec2& outUv1) const = 0; + virtual bool HasPreview(PreviewResourceType type, uint32_t resourceId) const = 0; + virtual void RequestPreview(PreviewResourceType type, uint32_t resourceId) = 0; + virtual std::vector GetAllPreviews(PreviewResourceType type) const = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/IRenderApi.h b/SynapseEngine/EditorCore/Api/IRenderApi.h index 5c39d682..776e2e24 100644 --- a/SynapseEngine/EditorCore/Api/IRenderApi.h +++ b/SynapseEngine/EditorCore/Api/IRenderApi.h @@ -4,15 +4,17 @@ #include #include "EditorCore/Types/TextureHandle.h" #include "EditorCore/Types/EntityHandle.h" +#include "IApi.h" namespace Syn { - class IRenderApi { + class IRenderApi : public IApi { public: virtual ~IRenderApi() = default; virtual void ResizeRenderTargets(uint32_t width, uint32_t height) = 0; virtual TextureHandle GetViewportTexture(const std::string& groupName, const std::string& targetName, const std::string& viewName) = 0; virtual EntityID ReadEntityIdAtPixel(uint32_t x, uint32_t y) = 0; + virtual std::pair ReadEntityAndMeshIdAtPixel(uint32_t x, uint32_t y) = 0; virtual glm::mat4 GetEditorCameraView() const = 0; virtual glm::mat4 GetEditorCameraProjection() const = 0; diff --git a/SynapseEngine/EditorCore/Api/IRigidBodyApi.h b/SynapseEngine/EditorCore/Api/IRigidBodyApi.h new file mode 100644 index 00000000..0dbb9e8b --- /dev/null +++ b/SynapseEngine/EditorCore/Api/IRigidBodyApi.h @@ -0,0 +1,26 @@ +#pragma once +#include "EditorCore/Types/EntityHandle.h" +#include "Engine/Physics/PhysicsTypes.h" +#include "IApi.h" +#include + +namespace Syn { + class IRigidBodyApi : public IApi { + public: + virtual ~IRigidBodyApi() = default; + + virtual bool HasRigidBody(EntityID entity) const = 0; + + virtual PhysicsMotionType GetRigidBodyMotionType(EntityID entity) const = 0; + virtual float GetRigidBodyMass(EntityID entity) const = 0; + virtual float GetRigidBodyFriction(EntityID entity) const = 0; + virtual float GetRigidBodyRestitution(EntityID entity) const = 0; + virtual uint32_t GetRigidBodyLayer(EntityID entity) const = 0; + + virtual void SetRigidBodyMotionType(EntityID entity, PhysicsMotionType motionType) = 0; + virtual void SetRigidBodyMass(EntityID entity, float mass) = 0; + virtual void SetRigidBodyFriction(EntityID entity, float friction) = 0; + virtual void SetRigidBodyRestitution(EntityID entity, float restitution) = 0; + virtual void SetRigidBodyLayer(EntityID entity, uint32_t layer) = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/ISceneApi.h b/SynapseEngine/EditorCore/Api/ISceneApi.h index 5e762ca0..072e6e21 100644 --- a/SynapseEngine/EditorCore/Api/ISceneApi.h +++ b/SynapseEngine/EditorCore/Api/ISceneApi.h @@ -1,13 +1,15 @@ #pragma once +#include "IApi.h" #include namespace Syn { - class ISceneApi { + class ISceneApi : public IApi { public: virtual ~ISceneApi() = default; virtual void NewScene() = 0; virtual void LoadScene(const std::string& filepath = "") = 0; virtual void SaveScene(const std::string& filepath = "") = 0; + virtual void ActivateScene(const std::string& sceneName) = 0; }; } \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/ISelectionApi.h b/SynapseEngine/EditorCore/Api/ISelectionApi.h index f4e8937e..ce5f9011 100644 --- a/SynapseEngine/EditorCore/Api/ISelectionApi.h +++ b/SynapseEngine/EditorCore/Api/ISelectionApi.h @@ -1,8 +1,9 @@ #pragma once +#include "IApi.h" #include "EditorCore/Types/EntityHandle.h" namespace Syn { - class ISelectionApi { + class ISelectionApi : public IApi { public: virtual ~ISelectionApi() = default; virtual EntityID GetSelectedEntity() const = 0; diff --git a/SynapseEngine/EditorCore/Api/ISettingsApi.h b/SynapseEngine/EditorCore/Api/ISettingsApi.h index 4d0a981b..72d25a28 100644 --- a/SynapseEngine/EditorCore/Api/ISettingsApi.h +++ b/SynapseEngine/EditorCore/Api/ISettingsApi.h @@ -1,12 +1,17 @@ #pragma once +#include "IApi.h" #include "Engine/Scene/Settings/SceneSettings.h" +#include +#include +#include namespace Syn { - class ISettingsApi { + class ISettingsApi : public IApi { public: virtual ~ISettingsApi() = default; virtual SceneSettings GetSceneSettings() const = 0; virtual void SetSceneSettings(const SceneSettings& settings) = 0; + virtual std::vector> GetAvailableSkyTextures() const = 0; }; } \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/ISphereColliderApi.h b/SynapseEngine/EditorCore/Api/ISphereColliderApi.h new file mode 100644 index 00000000..8e6deaca --- /dev/null +++ b/SynapseEngine/EditorCore/Api/ISphereColliderApi.h @@ -0,0 +1,19 @@ +#pragma once +#include +#include "IApi.h" +#include "EditorCore/Types/EntityHandle.h" + +namespace Syn { + class ISphereColliderApi : public IApi { + public: + virtual ~ISphereColliderApi() = default; + + virtual bool HasSphereCollider(EntityID entity) const = 0; + + virtual float GetSphereColliderRadius(EntityID entity) const = 0; + virtual glm::vec3 GetSphereColliderLocalOffset(EntityID entity) const = 0; + + virtual void SetSphereColliderRadius(EntityID entity, float radius) = 0; + virtual void SetSphereColliderLocalOffset(EntityID entity, const glm::vec3& localOffset) = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/ISpotLightApi.h b/SynapseEngine/EditorCore/Api/ISpotLightApi.h index f23b3f07..bd554c9f 100644 --- a/SynapseEngine/EditorCore/Api/ISpotLightApi.h +++ b/SynapseEngine/EditorCore/Api/ISpotLightApi.h @@ -1,9 +1,10 @@ #pragma once #include +#include "IApi.h" #include "EditorCore/Types/EntityHandle.h" namespace Syn { - class ISpotLightApi { + class ISpotLightApi : public IApi { public: virtual ~ISpotLightApi() = default; diff --git a/SynapseEngine/EditorCore/Api/ITagApi.h b/SynapseEngine/EditorCore/Api/ITagApi.h index 368374ae..b8f12499 100644 --- a/SynapseEngine/EditorCore/Api/ITagApi.h +++ b/SynapseEngine/EditorCore/Api/ITagApi.h @@ -1,9 +1,10 @@ #pragma once #include +#include "IApi.h" #include "EditorCore/Types/EntityHandle.h" namespace Syn { - class ITagApi { + class ITagApi : public IApi { public: virtual ~ITagApi() = default; diff --git a/SynapseEngine/EditorCore/Api/ITextureApi.h b/SynapseEngine/EditorCore/Api/ITextureApi.h new file mode 100644 index 00000000..303001ee --- /dev/null +++ b/SynapseEngine/EditorCore/Api/ITextureApi.h @@ -0,0 +1,37 @@ +#pragma once +#include +#include +#include "IApi.h" +#include "Engine/Image/Data/Cpu/CpuTextureData.h" +#include "EditorCore/Types/TextureHandle.h" + +namespace Syn { + constexpr uint32_t INVALID_TEXTURE_ID = 0xFFFFFFFF; + constexpr uint32_t INVALID_SAMPLER_ID = 0xFFFFFFFF; + + struct TextureItemData { + uint32_t id; + std::string name; + std::string path; + TextureHandle handle; + }; + + struct SamplerItemData { + uint32_t id; + std::string name; + }; + + class ITextureApi : public IApi { + public: + virtual ~ITextureApi() = default; + + virtual std::vector GetAllTextures() = 0; + virtual std::vector GetAllSamplers() const = 0; + + virtual uint32_t GetSelectedTexture() const = 0; + virtual void SetSelectedTexture(uint32_t id) = 0; + virtual bool GetTextureData(uint32_t id, CpuTextureData& outData) const = 0; + virtual uint64_t GetVersion() const = 0; + virtual TextureHandle GetTextureHandle(uint32_t id) = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/Api/ITransformApi.h b/SynapseEngine/EditorCore/Api/ITransformApi.h index b6545f23..b3f4ce53 100644 --- a/SynapseEngine/EditorCore/Api/ITransformApi.h +++ b/SynapseEngine/EditorCore/Api/ITransformApi.h @@ -1,9 +1,10 @@ #pragma once #include +#include "IApi.h" #include "EditorCore/Types/EntityHandle.h" namespace Syn { - class ITransformApi { + class ITransformApi : public IApi { public: virtual ~ITransformApi() = default; diff --git a/SynapseEngine/EditorCore/ViewModels/ContentBrowser/ContentBrowserIntent.cpp b/SynapseEngine/EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserIntent.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/ContentBrowser/ContentBrowserIntent.cpp rename to SynapseEngine/EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserIntent.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/ContentBrowser/ContentBrowserIntent.h b/SynapseEngine/EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserIntent.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/ContentBrowser/ContentBrowserIntent.h rename to SynapseEngine/EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserIntent.h diff --git a/SynapseEngine/EditorCore/ViewModels/ContentBrowser/ContentBrowserState.cpp b/SynapseEngine/EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserState.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/ContentBrowser/ContentBrowserState.cpp rename to SynapseEngine/EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserState.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/ContentBrowser/ContentBrowserState.h b/SynapseEngine/EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserState.h similarity index 88% rename from SynapseEngine/EditorCore/ViewModels/ContentBrowser/ContentBrowserState.h rename to SynapseEngine/EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserState.h index 6c2b196b..1d7b58a1 100644 --- a/SynapseEngine/EditorCore/ViewModels/ContentBrowser/ContentBrowserState.h +++ b/SynapseEngine/EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserState.h @@ -9,7 +9,7 @@ namespace Syn { std::string selectedPath; std::vector currentEntries; - float thumbnailSize = 54.0f; + float thumbnailSize = 100.0f; bool isLoading = false; }; } \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ContentBrowser/ContentBrowserViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserViewModel.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/ContentBrowser/ContentBrowserViewModel.cpp rename to SynapseEngine/EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserViewModel.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/ContentBrowser/ContentBrowserViewModel.h b/SynapseEngine/EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserViewModel.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/ContentBrowser/ContentBrowserViewModel.h rename to SynapseEngine/EditorCore/ViewModels/Common/ContentBrowser/ContentBrowserViewModel.h diff --git a/SynapseEngine/EditorCore/ViewModels/MainMenu/MainMenuIntent.cpp b/SynapseEngine/EditorCore/ViewModels/Common/MainMenu/MainMenuIntent.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/MainMenu/MainMenuIntent.cpp rename to SynapseEngine/EditorCore/ViewModels/Common/MainMenu/MainMenuIntent.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/MainMenu/MainMenuIntent.h b/SynapseEngine/EditorCore/ViewModels/Common/MainMenu/MainMenuIntent.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/MainMenu/MainMenuIntent.h rename to SynapseEngine/EditorCore/ViewModels/Common/MainMenu/MainMenuIntent.h diff --git a/SynapseEngine/EditorCore/ViewModels/MainMenu/MainMenuState.cpp b/SynapseEngine/EditorCore/ViewModels/Common/MainMenu/MainMenuState.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/MainMenu/MainMenuState.cpp rename to SynapseEngine/EditorCore/ViewModels/Common/MainMenu/MainMenuState.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/MainMenu/MainMenuState.h b/SynapseEngine/EditorCore/ViewModels/Common/MainMenu/MainMenuState.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/MainMenu/MainMenuState.h rename to SynapseEngine/EditorCore/ViewModels/Common/MainMenu/MainMenuState.h diff --git a/SynapseEngine/EditorCore/ViewModels/MainMenu/MainMenuViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/Common/MainMenu/MainMenuViewModel.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/MainMenu/MainMenuViewModel.cpp rename to SynapseEngine/EditorCore/ViewModels/Common/MainMenu/MainMenuViewModel.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/MainMenu/MainMenuViewModel.h b/SynapseEngine/EditorCore/ViewModels/Common/MainMenu/MainMenuViewModel.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/MainMenu/MainMenuViewModel.h rename to SynapseEngine/EditorCore/ViewModels/Common/MainMenu/MainMenuViewModel.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/ComponentIntent.h b/SynapseEngine/EditorCore/ViewModels/Component/ComponentIntent.h deleted file mode 100644 index b12771e6..00000000 --- a/SynapseEngine/EditorCore/ViewModels/Component/ComponentIntent.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once -#include "Core/Tag/TagIntent.h" -#include "Core/Transform/TransformIntent.h" -#include "Light/DirectionLight/DirectionLightIntent.h" -#include "Light/PointLight/PointLightIntent.h" -#include "Light/SpotLight/SpotLightIntent.h" -#include - -namespace Syn { - using ComponentIntent = std::variant< - TagIntent, - TransformIntent, - DirectionLightIntent, - PointLightIntent, - SpotLightIntent - >; -} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/Component/ComponentViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/Component/ComponentViewModel.cpp deleted file mode 100644 index 5d44aa72..00000000 --- a/SynapseEngine/EditorCore/ViewModels/Component/ComponentViewModel.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "ComponentViewModel.h" - -namespace Syn -{ - ComponentViewModel::ComponentViewModel( - ISelectionApi* selectionApi, - ITagApi* tagApi, - ITransformApi* transformApi, - IHierarchyApi* hierarchyApi, - IDirectionLightApi* directionLightApi, - IPointLightApi* pointLightApi, - ISpotLightApi* spotLightApi) - : - _selectionApi(selectionApi), - _tagViewModel(selectionApi, tagApi), - _transformViewModel(selectionApi, transformApi, hierarchyApi), - _directionLightViewModel(selectionApi, directionLightApi), - _pointLightViewModel(selectionApi, pointLightApi), - _spotLightViewModel(selectionApi, spotLightApi) - {} - - const ComponentState& ComponentViewModel::GetState() const { - return _state; - } - - void ComponentViewModel::SyncWithEngine() { - if (!_selectionApi) return; - - EntityID activeEntity = _selectionApi->GetSelectedEntity(); - - _state.activeEntityId = activeEntity; - _state.hasSelection = (activeEntity != NULL_ENTITY); - - if (_state.hasSelection) { - _tagViewModel.SyncWithEngine(); - _transformViewModel.SyncWithEngine(); - _directionLightViewModel.SyncWithEngine(); - _pointLightViewModel.SyncWithEngine(); - _spotLightViewModel.SyncWithEngine(); - } - } - - void ComponentViewModel::Dispatch(const ComponentIntent& intent) { - std::visit([this](auto&& arg) { - using T = std::decay_t; - - if constexpr (std::is_same_v) { - _tagViewModel.Dispatch(arg); - } - else if constexpr (std::is_same_v) { - _transformViewModel.Dispatch(arg); - } - else if constexpr (std::is_same_v) { - _directionLightViewModel.Dispatch(arg); - } - else if constexpr (std::is_same_v) { - _pointLightViewModel.Dispatch(arg); - } - else if constexpr (std::is_same_v) { - _spotLightViewModel.Dispatch(arg); - } - }, intent); - } -} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/Component/ComponentViewModel.h b/SynapseEngine/EditorCore/ViewModels/Component/ComponentViewModel.h deleted file mode 100644 index 343ebddc..00000000 --- a/SynapseEngine/EditorCore/ViewModels/Component/ComponentViewModel.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once -#include "EditorCore/ViewModels/IViewModel.h" -#include "ComponentState.h" -#include "ComponentIntent.h" - -#include "Core/Tag/TagViewModel.h" -#include "Core/Transform/TransformViewModel.h" -#include "Light/DirectionLight/DirectionLightViewModel.h" -#include "Light/PointLight/PointLightViewModel.h" -#include "Light/SpotLight/SpotLightViewModel.h" - -#include "EditorCore/Api/ISelectionApi.h" -#include "EditorCore/Api/ITagApi.h" -#include "EditorCore/Api/ITransformApi.h" -#include "EditorCore/Api/IDirectionLightApi.h" -#include "EditorCore/Api/IPointLightApi.h" - -namespace Syn { - class ComponentViewModel : public IViewModel { - public: - ComponentViewModel( - ISelectionApi* selectionApi, - ITagApi* tagApi, - ITransformApi* transformApi, - IHierarchyApi* hierarchyApi, - IDirectionLightApi* directionLightApi, - IPointLightApi* pointLightApi, - ISpotLightApi* spotLightApi - ); - - ~ComponentViewModel() override = default; - - const ComponentState& GetState() const override; - void SyncWithEngine() override; - void Dispatch(const ComponentIntent& intent) override; - - TagViewModel& GetTagViewModel() { return _tagViewModel; } - TransformViewModel& GetTransformViewModel() { return _transformViewModel; } - DirectionLightViewModel& GetDirectionLightViewModel() { return _directionLightViewModel; } - PointLightViewModel& GetPointLightViewModel() { return _pointLightViewModel; } - SpotLightViewModel& GetSpotLightViewModel() { return _spotLightViewModel; } - private: - ISelectionApi* _selectionApi = nullptr; - ComponentState _state; - - TagViewModel _tagViewModel;; - TransformViewModel _transformViewModel; - DirectionLightViewModel _directionLightViewModel; - PointLightViewModel _pointLightViewModel; - SpotLightViewModel _spotLightViewModel; - }; -} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialGraph/MaterialGraphViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/MaterialGraph/MaterialGraphViewModel.cpp deleted file mode 100644 index 3a43a37e..00000000 --- a/SynapseEngine/EditorCore/ViewModels/MaterialGraph/MaterialGraphViewModel.cpp +++ /dev/null @@ -1,116 +0,0 @@ -#include "MaterialGraphViewModel.h" -#include - -namespace Syn { - - MaterialGraphViewModel::MaterialGraphViewModel(IMaterialApi* materialApi) - : _materialApi(materialApi) - { - BuildGraphFromEngine(); - } - - void MaterialGraphViewModel::SyncWithEngine() { - - } - - void MaterialGraphViewModel::Dispatch(const MaterialGraphIntent& intent) { - std::visit([this](auto&& arg) { - using T = std::decay_t; - - if constexpr (std::is_same_v) { - HandleCreateLink(arg); - } - else if constexpr (std::is_same_v) { - HandleDeleteLink(arg); - } - }, intent); - } - - void MaterialGraphViewModel::BuildGraphFromEngine() { - _state.nodes.clear(); - _state.links.clear(); - _state.nextId = 1; - - auto materials = _materialApi->GetAllMaterials(); - for (const auto& mat : materials) { - GraphID matNodeId = _state.nextId++; - GraphNodeData matNode{ matNodeId, GraphNodeType::Material, mat.id, mat.name, {} }; - - matNode.pins.push_back({ _state.nextId++, matNodeId, GraphPinType::Albedo, true }); - matNode.pins.push_back({ _state.nextId++, matNodeId, GraphPinType::Normal, true }); - matNode.pins.push_back({ _state.nextId++, matNodeId, GraphPinType::Metalness, true }); - matNode.pins.push_back({ _state.nextId++, matNodeId, GraphPinType::Roughness, true }); - matNode.pins.push_back({ _state.nextId++, matNodeId, GraphPinType::Emissive, true }); - matNode.pins.push_back({ _state.nextId++, matNodeId, GraphPinType::AmbientOcclusion, true }); - _state.nodes.push_back(matNode); - } - - auto textures = _materialApi->GetAllTextures(); - - for (const auto& tex : textures) { - GraphID texNodeId = _state.nextId++; - GraphNodeData texNode{ texNodeId, GraphNodeType::Texture, tex.id, tex.name, {} }; - - texNode.pins.push_back({ _state.nextId++, texNodeId, GraphPinType::TextureOutput, false }); - _state.nodes.push_back(texNode); - } - } - - void MaterialGraphViewModel::HandleCreateLink(const CreateLinkIntent& intent) { - const GraphPinData* startPin = nullptr; - const GraphNodeData* startNode = nullptr; - - const GraphPinData* endPin = nullptr; - const GraphNodeData* endNode = nullptr; - - for (const auto& node : _state.nodes) { - for (const auto& pin : node.pins) { - if (pin.id == intent.startPinId) { - startPin = &pin; - startNode = &node; - } - if (pin.id == intent.endPinId) { - endPin = &pin; - endNode = &node; - } - } - } - - if (startNode && endNode && startPin && endPin) { - if (startNode->type == GraphNodeType::Texture && - endNode->type == GraphNodeType::Material) - { - _materialApi->LinkTextureToMaterial( - endNode->engineResourceId, - static_cast(endPin->type), - startNode->engineResourceId - ); - - _state.links.push_back({ _state.nextId++, intent.startPinId, intent.endPinId }); - } - } - } - - void MaterialGraphViewModel::HandleDeleteLink(const DeleteLinkIntent& intent) { - auto it = std::find_if(_state.links.begin(), _state.links.end(), [&](const GraphLinkData& link) { - return link.id == intent.linkId; - }); - - if (it != _state.links.end()) { - GraphID endPinId = it->endPinId; - - for (const auto& node : _state.nodes) { - if (node.type == GraphNodeType::Material) { - for (const auto& pin : node.pins) { - if (pin.id == endPinId) { - _materialApi->UnlinkTextureFromMaterial(node.engineResourceId, static_cast(pin.type)); - break; - } - } - } - } - - _state.links.erase(it); - } - } -} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialGraph/MaterialGraphIntent.cpp b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphIntent.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/MaterialGraph/MaterialGraphIntent.cpp rename to SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphIntent.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialGraph/MaterialGraphIntent.h b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphIntent.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/MaterialGraph/MaterialGraphIntent.h rename to SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphIntent.h diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialGraph/MaterialGraphState.cpp b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphState.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/MaterialGraph/MaterialGraphState.cpp rename to SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphState.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialGraph/MaterialGraphState.h b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphState.h similarity index 62% rename from SynapseEngine/EditorCore/ViewModels/MaterialGraph/MaterialGraphState.h rename to SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphState.h index 6e537f89..365941fc 100644 --- a/SynapseEngine/EditorCore/ViewModels/MaterialGraph/MaterialGraphState.h +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphState.h @@ -2,25 +2,26 @@ #include #include #include +#include "EditorCore/Types/TextureHandle.h" namespace Syn { using GraphID = uint64_t; - enum class GraphNodeType { + enum class GraphNodeType { Material, Texture }; enum class GraphPinType { - Albedo, - Normal, - Metalness, - Roughness, - MetallicRoughness, - Emissive, - AmbientOcclusion, - TextureOutput + Albedo = 0, + Normal = 1, + Metalness = 2, + Roughness = 3, + MetallicRoughness = 4, + Emissive = 5, + AmbientOcclusion = 6, + TextureOutput = 99 }; struct GraphPinData { @@ -36,6 +37,7 @@ namespace Syn { uint32_t engineResourceId; std::string name; std::vector pins; + TextureHandle textureHandle = InvalidTextureHandle; }; struct GraphLinkData { @@ -45,6 +47,10 @@ namespace Syn { }; struct MaterialGraphState { + bool isMaterialSelected = false; + uint32_t selectedMaterialId = 0xFFFFFFFF; + std::string selectedMaterialName = ""; + std::vector nodes; std::vector links; GraphID nextId = 1; diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphViewModel.cpp new file mode 100644 index 00000000..14223065 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphViewModel.cpp @@ -0,0 +1,138 @@ +#include "MaterialGraphViewModel.h" +#include + +namespace Syn { + + MaterialGraphViewModel::MaterialGraphViewModel(IMaterialApi* materialApi, ITextureApi* textureApi) + : _materialApi(materialApi), _textureApi(textureApi) + {} + + void MaterialGraphViewModel::SyncWithEngine() { + if (!_materialApi) return; + + uint32_t currentSel = _materialApi->GetSelectedMaterial(); + uint64_t currentVer = _materialApi->GetVersion(); + + if (currentSel != _lastSelectedMaterial || currentVer != _lastEngineVersion) { + RebuildGraphForSelectedMaterial(currentSel); + _lastSelectedMaterial = currentSel; + _lastEngineVersion = currentVer; + } + } + + void MaterialGraphViewModel::Dispatch(const MaterialGraphIntent& intent) { + std::visit([this](auto&& arg) { + using T = std::decay_t; + + if constexpr (std::is_same_v) { + HandleCreateLink(arg); + } + else if constexpr (std::is_same_v) { + HandleDeleteLink(arg); + } + }, intent); + } + + void MaterialGraphViewModel::RebuildGraphForSelectedMaterial(uint32_t materialId) { + _state.nodes.clear(); + _state.links.clear(); + _state.nextId = 1; + + if (materialId == INVALID_MATERIAL_ID) { + _state.isMaterialSelected = false; + return; + } + + _state.isMaterialSelected = true; + _state.selectedMaterialId = materialId; + _state.selectedMaterialName = _materialApi->GetMaterialName(materialId); + + GraphID matNodeId = _state.nextId++; + GraphNodeData matNode{ matNodeId, GraphNodeType::Material, materialId, _state.selectedMaterialName, {} }; + + std::vector pinTypes = { + GraphPinType::Albedo, GraphPinType::Normal, GraphPinType::Metalness, + GraphPinType::Roughness, GraphPinType::MetallicRoughness, + GraphPinType::Emissive, GraphPinType::AmbientOcclusion + }; + + auto allTextures = _textureApi ? _textureApi->GetAllTextures() : std::vector(); + + for (auto pType : pinTypes) { + GraphID pinId = _state.nextId++; + matNode.pins.push_back({ pinId, matNodeId, pType, true }); + + uint32_t linkedTexId = _materialApi->GetLinkedTexture(materialId, static_cast(pType)); + + if (linkedTexId != 0xFFFFFFFF) { + + std::string texName = "Unknown Texture"; + for (const auto& t : allTextures) { + if (t.id == linkedTexId) { + texName = t.name; + break; + } + } + + GraphID texNodeId = _state.nextId++; + GraphNodeData texNode{ texNodeId, GraphNodeType::Texture, linkedTexId, texName, {} }; + + if (_textureApi) { + texNode.textureHandle = _textureApi->GetTextureHandle(linkedTexId); + } + + GraphID texOutPinId = _state.nextId++; + texNode.pins.push_back({ texOutPinId, texNodeId, GraphPinType::TextureOutput, false }); + + _state.nodes.push_back(texNode); + _state.links.push_back({ _state.nextId++, texOutPinId, pinId }); + } + } + + matNode.textureHandle = InvalidTextureHandle; + _state.nodes.push_back(matNode); + } + + void MaterialGraphViewModel::HandleCreateLink(const CreateLinkIntent& intent) { + const GraphPinData* startPin = nullptr; const GraphNodeData* startNode = nullptr; + const GraphPinData* endPin = nullptr; const GraphNodeData* endNode = nullptr; + + for (const auto& node : _state.nodes) { + for (const auto& pin : node.pins) { + if (pin.id == intent.startPinId) { startPin = &pin; startNode = &node; } + if (pin.id == intent.endPinId) { endPin = &pin; endNode = &node; } + } + } + + if (startNode && endNode && startPin && endPin) { + if (startNode->type == GraphNodeType::Texture && endNode->type == GraphNodeType::Material) { + _materialApi->LinkTextureToMaterial( + endNode->engineResourceId, + static_cast(endPin->type), + startNode->engineResourceId + ); + } + } + } + + void MaterialGraphViewModel::HandleDeleteLink(const DeleteLinkIntent& intent) { + auto it = std::find_if(_state.links.begin(), _state.links.end(), [&](const GraphLinkData& link) { + return link.id == intent.linkId; + }); + + if (it != _state.links.end()) { + GraphID endPinId = it->endPinId; + + for (const auto& node : _state.nodes) { + if (node.type == GraphNodeType::Material) { + for (const auto& pin : node.pins) { + if (pin.id == endPinId) { + _materialApi->UnlinkTextureFromMaterial(node.engineResourceId, static_cast(pin.type)); + break; + } + } + } + } + } + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialGraph/MaterialGraphViewModel.h b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphViewModel.h similarity index 67% rename from SynapseEngine/EditorCore/ViewModels/MaterialGraph/MaterialGraphViewModel.h rename to SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphViewModel.h index 6f144e66..3bd60ded 100644 --- a/SynapseEngine/EditorCore/ViewModels/MaterialGraph/MaterialGraphViewModel.h +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialGraph/MaterialGraphViewModel.h @@ -3,23 +3,28 @@ #include "MaterialGraphState.h" #include "MaterialGraphIntent.h" #include "EditorCore/Api/IMaterialApi.h" - +#include "EditorCore/Api/ITextureApi.h" namespace Syn { class MaterialGraphViewModel : public IViewModel { public: - MaterialGraphViewModel(IMaterialApi* materialApi); + MaterialGraphViewModel(IMaterialApi* materialApi, ITextureApi* textureApi); const MaterialGraphState& GetState() const override { return _state; } void SyncWithEngine() override; void Dispatch(const MaterialGraphIntent& intent) override; private: - void BuildGraphFromEngine(); + void RebuildGraphForSelectedMaterial(uint32_t materialId); void HandleCreateLink(const CreateLinkIntent& intent); void HandleDeleteLink(const DeleteLinkIntent& intent); private: IMaterialApi* _materialApi = nullptr; + ITextureApi* _textureApi = nullptr; + MaterialGraphState _state; + + uint32_t _lastSelectedMaterial = INVALID_MATERIAL_ID; + uint64_t _lastEngineVersion = 0; }; } \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyIntent.cpp b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyIntent.cpp new file mode 100644 index 00000000..7b9a9728 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyIntent.cpp @@ -0,0 +1 @@ +#include "MaterialHierarchyIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyIntent.h b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyIntent.h new file mode 100644 index 00000000..1bb0bae7 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyIntent.h @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include + +namespace Syn { + struct MaterialSelectIntent { + uint32_t materialId; + }; + + struct MaterialSetSearchQueryIntent { + std::string query; + }; + + struct MaterialRefreshIntent {}; + + using MaterialHierarchyIntent = std::variant< + MaterialSelectIntent, + MaterialSetSearchQueryIntent, + MaterialRefreshIntent + >; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyState.cpp b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyState.cpp new file mode 100644 index 00000000..f05862df --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyState.cpp @@ -0,0 +1 @@ +#include "MaterialHierarchyState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyState.h b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyState.h new file mode 100644 index 00000000..ace94a28 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyState.h @@ -0,0 +1,25 @@ +#pragma once +#include +#include +#include +#include +#include "EditorCore/Types/TextureHandle.h" + +namespace Syn { + struct MaterialNode { + uint32_t id; + std::string name; + std::string path; + std::string icon; + glm::vec2 uv0{ 0.0f, 0.0f }; + glm::vec2 uv1{ 1.0f, 1.0f }; + bool hasPreview = false; + }; + + struct MaterialHierarchyState { + std::vector filteredNodes; + uint32_t selectedMaterial = 0xFFFFFFFF; + std::string searchQuery = ""; + TextureHandle atlasHandle = InvalidTextureHandle; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyViewModel.cpp new file mode 100644 index 00000000..b4122099 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyViewModel.cpp @@ -0,0 +1,95 @@ +#include "MaterialHierarchyViewModel.h" +#include "Editor/Manager/EditorIcons.h" //Todo! +#include + +namespace Syn { + MaterialHierarchyViewModel::MaterialHierarchyViewModel(IMaterialApi* materialApi, IPreviewApi* previewApi) + : _materialApi(materialApi), _previewApi(previewApi) + {} + + void MaterialHierarchyViewModel::SyncWithEngine() { + if (!_materialApi) return; + + uint64_t currentVersion = _materialApi->GetVersion(); + uint32_t currentSelection = _materialApi->GetSelectedMaterial(); + + if (currentVersion != _lastEngineVersion || _isDirty) { + RebuildList(); + _lastEngineVersion = currentVersion; + _isDirty = false; + } + + if (_state.selectedMaterial != currentSelection) { + _state.selectedMaterial = currentSelection; + } + + if (_previewApi) { + _state.atlasHandle = _previewApi->GetAtlasHandle(); + + for (auto& node : _state.filteredNodes) { + if (!node.hasPreview) { + if (_previewApi->GetPreviewUVs(PreviewResourceType::Material, node.id, node.uv0, node.uv1)) { + node.hasPreview = true; + } + } + } + } + } + + void MaterialHierarchyViewModel::Dispatch(const MaterialHierarchyIntent& intent) { + std::visit([this](auto&& arg) { + using T = std::decay_t; + + if constexpr (std::is_same_v) { + if (_materialApi) { + _materialApi->SetSelectedMaterial(arg.materialId); + _materialApi->ApplyMaterialToPreviewObjects(arg.materialId); + } + } + else if constexpr (std::is_same_v) { + if (_state.searchQuery != arg.query) { + _state.searchQuery = arg.query; + _isDirty = true; + } + } + else if constexpr (std::is_same_v) { + _isDirty = true; + } + }, intent); + } + + void MaterialHierarchyViewModel::RebuildList() { + if (!_materialApi) return; + + _state.filteredNodes.clear(); + auto allMaterials = _materialApi->GetAllMaterials(); + + std::string searchLower = _state.searchQuery; + std::transform(searchLower.begin(), searchLower.end(), searchLower.begin(), ::tolower); + + for (const auto& mat : allMaterials) { + std::string nameLower = mat.name; + std::transform(nameLower.begin(), nameLower.end(), nameLower.begin(), ::tolower); + + if (searchLower.empty() || nameLower.find(searchLower) != std::string::npos) { + MaterialNode node; + node.id = mat.id; + node.name = mat.name; + node.path = mat.path; + node.icon = SYN_ICON_BRUSH; + + if (_previewApi) { + if (_previewApi->GetPreviewUVs(PreviewResourceType::Material, mat.id, node.uv0, node.uv1)) { + node.hasPreview = true; + } + else { + node.hasPreview = false; + _previewApi->RequestPreview(PreviewResourceType::Material, mat.id); + } + } + + _state.filteredNodes.push_back(node); + } + } + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyViewModel.h b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyViewModel.h new file mode 100644 index 00000000..205f2cca --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialHierarchy/MaterialHierarchyViewModel.h @@ -0,0 +1,29 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "MaterialHierarchyState.h" +#include "MaterialHierarchyIntent.h" +#include "EditorCore/Api/IPreviewApi.h" +#include "EditorCore/Api/IMaterialApi.h" + +namespace Syn { + class MaterialHierarchyViewModel : public IViewModel { + public: + MaterialHierarchyViewModel(IMaterialApi* materialApi, IPreviewApi* previewApi); + ~MaterialHierarchyViewModel() override = default; + + const MaterialHierarchyState& GetState() const override { return _state; } + void SyncWithEngine() override; + void Dispatch(const MaterialHierarchyIntent& intent) override; + + private: + void RebuildList(); + private: + IMaterialApi* _materialApi = nullptr; + IPreviewApi* _previewApi = nullptr; + + MaterialHierarchyState _state; + + bool _isDirty = true; + uint64_t _lastEngineVersion = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesIntent.cpp b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesIntent.cpp new file mode 100644 index 00000000..31fdf889 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesIntent.cpp @@ -0,0 +1 @@ +#include "MaterialPropertiesIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesIntent.h b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesIntent.h new file mode 100644 index 00000000..5db0df6d --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesIntent.h @@ -0,0 +1,16 @@ +#pragma once +#include +#include +#include "Engine/Material/Material.h" + +namespace Syn { + //Todo intents + + struct UpdateMaterialPropertyIntent { + Material updatedMaterial; + }; + + using MaterialPropertiesIntent = std::variant< + UpdateMaterialPropertyIntent + >; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesState.cpp b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesState.cpp new file mode 100644 index 00000000..2675de15 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesState.cpp @@ -0,0 +1 @@ +#include "MaterialPropertiesState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesState.h b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesState.h new file mode 100644 index 00000000..6282bc4d --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesState.h @@ -0,0 +1,49 @@ +#pragma once +#include +#include +#include +#include "Engine/Material/Material.h" + +namespace Syn +{ + struct TextureOption { + uint32_t id; + std::string name; + }; + + struct SamplerOption { + uint32_t id; + std::string name; + }; + + struct MaterialPropertiesState { + bool hasSelection = false; + uint32_t selectedMaterialId = 0xFFFFFFFF; + std::string materialName = ""; + + Material materialData; + std::vector availableTextures; + std::vector availableSamplers; + + std::string albedoName = "None"; + std::string albedoSamplerName = "Default"; + + std::string normalName = "None"; + std::string normalSamplerName = "Default"; + + std::string metalnessName = "None"; + std::string metalnessSamplerName = "Default"; + + std::string roughnessName = "None"; + std::string roughnessSamplerName = "Default"; + + std::string metallicRoughnessName = "None"; + std::string metallicRoughnessSamplerName = "Default"; + + std::string emissiveName = "None"; + std::string emissiveSamplerName = "Default"; + + std::string aoName = "None"; + std::string aoSamplerName = "Default"; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesViewModel.cpp new file mode 100644 index 00000000..7dfbf902 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesViewModel.cpp @@ -0,0 +1,91 @@ +#include "MaterialPropertiesViewModel.h" + +namespace Syn { + MaterialPropertiesViewModel::MaterialPropertiesViewModel(IMaterialApi* materialApi, ITextureApi* textureApi) + : _materialApi(materialApi), _textureApi(textureApi) + {} + + void MaterialPropertiesViewModel::SyncWithEngine() { + if (!_materialApi) return; + + uint32_t selectedId = _materialApi->GetSelectedMaterial(); + + if (selectedId == 0xFFFFFFFF) { + _state.hasSelection = false; + return; + } + + Material matData; + if (_materialApi->GetMaterialData(selectedId, matData)) { + _state.hasSelection = true; + _state.selectedMaterialId = selectedId; + _state.materialName = _materialApi->GetMaterialName(selectedId); + _state.materialData = matData; + + _state.availableTextures.clear(); + auto texs = _textureApi ? _textureApi->GetAllTextures() : std::vector(); + for (const auto& t : texs) { + _state.availableTextures.push_back({ t.id, t.name }); + } + + _state.availableSamplers.clear(); + auto samps = _textureApi ? _textureApi->GetAllSamplers() : std::vector(); + for (const auto& s : samps) { + _state.availableSamplers.push_back({ s.id, s.name }); + } + + auto getTexName = [&](uint32_t id) -> std::string { + if (id == 0xFFFFFFFF) return "None"; + for (const auto& t : texs) { + if (t.id == id) return t.name; + } + return "Unknown"; + }; + + auto getSamplerName = [&](uint32_t id) -> std::string { + if (id == 0xFFFFFFFF || id == 0xFF) return "Default"; + for (const auto& s : samps) { + if (s.id == id) return s.name; + } + return "Unknown"; + }; + + _state.albedoName = getTexName(matData.albedoTexture); + _state.albedoSamplerName = getSamplerName(matData.albedoSampler); + + _state.normalName = getTexName(matData.normalTexture); + _state.normalSamplerName = getSamplerName(matData.normalSampler); + + _state.metalnessName = getTexName(matData.metalnessTexture); + _state.metalnessSamplerName = getSamplerName(matData.metalnessSampler); + + _state.roughnessName = getTexName(matData.roughnessTexture); + _state.roughnessSamplerName = getSamplerName(matData.roughnessSampler); + + _state.metallicRoughnessName = getTexName(matData.metallicRoughnessTexture); + _state.metallicRoughnessSamplerName = getSamplerName(matData.metallicRoughnessSampler); + + _state.emissiveName = getTexName(matData.emissiveTexture); + _state.emissiveSamplerName = getSamplerName(matData.emissiveSampler); + + _state.aoName = getTexName(matData.ambientOcclusionTexture); + _state.aoSamplerName = getSamplerName(matData.ambientOcclusionSampler); + } + else { + _state.hasSelection = false; + } + } + + void MaterialPropertiesViewModel::Dispatch(const MaterialPropertiesIntent& intent) { + std::visit([this](auto&& arg) { + using T = std::decay_t; + + if constexpr (std::is_same_v) { + if (_state.hasSelection) { + _materialApi->UpdateMaterialData(_state.selectedMaterialId, arg.updatedMaterial); + _state.materialData = arg.updatedMaterial; + } + } + }, intent); + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesViewModel.h b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesViewModel.h new file mode 100644 index 00000000..b8d90d47 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialProperties/MaterialPropertiesViewModel.h @@ -0,0 +1,22 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "MaterialPropertiesState.h" +#include "MaterialPropertiesIntent.h" +#include "EditorCore/Api/IMaterialApi.h" +#include "EditorCore/Api/ITextureApi.h" + +namespace Syn { + class MaterialPropertiesViewModel : public IViewModel { + public: + MaterialPropertiesViewModel(IMaterialApi* materialApi, ITextureApi* textureApi); + ~MaterialPropertiesViewModel() override = default; + + const MaterialPropertiesState& GetState() const override { return _state; } + void SyncWithEngine() override; + void Dispatch(const MaterialPropertiesIntent& intent) override; + private: + IMaterialApi* _materialApi = nullptr; + ITextureApi* _textureApi = nullptr; + MaterialPropertiesState _state; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportIntent.cpp b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportIntent.cpp new file mode 100644 index 00000000..9d0e494f --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportIntent.cpp @@ -0,0 +1 @@ +#include "MaterialViewportIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportIntent.h b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportIntent.h new file mode 100644 index 00000000..a44d8fe9 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportIntent.h @@ -0,0 +1,14 @@ +#pragma once +#include +#include + +namespace Syn { + struct ResizeMaterialViewportIntent { + uint32_t width; + uint32_t height; + }; + + using MaterialViewportIntent = std::variant< + ResizeMaterialViewportIntent + >; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportState.cpp b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportState.cpp new file mode 100644 index 00000000..ac86b1e5 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportState.cpp @@ -0,0 +1 @@ +#include "MaterialViewportState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportState.h b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportState.h new file mode 100644 index 00000000..45cf8fe1 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportState.h @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include "EditorCore/Types/TextureHandle.h" +#include "Engine/Vk/Image/ImageViewNames.h" +#include "Engine/Render/RenderNames.h" + +namespace Syn { + struct MaterialViewportState { + uint32_t width = 0; + uint32_t height = 0; + + TextureHandle textureId = InvalidTextureHandle; + + std::string currentGroup = RenderTargetGroupNames::Main; + std::string currentTarget = RenderTargetNames::Main; + std::string currentView = Vk::ImageViewNames::Default; + + bool isHovered = false; + bool isFocused = false; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportViewModel.cpp new file mode 100644 index 00000000..414f454c --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportViewModel.cpp @@ -0,0 +1,42 @@ +#include "MaterialViewportViewModel.h" + +namespace Syn { + + MaterialViewportViewModel::MaterialViewportViewModel(IRenderApi* renderApi) + : _renderApi(renderApi) {} + + const MaterialViewportState& MaterialViewportViewModel::GetState() const { + return _state; + } + + void MaterialViewportViewModel::SyncWithEngine() { + if (!_renderApi) return; + + _state.textureId = _renderApi->GetViewportTexture( + _state.currentGroup, + _state.currentTarget, + _state.currentView + ); + } + + void MaterialViewportViewModel::Dispatch(const MaterialViewportIntent& intent) { + std::visit([this](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + HandleResize(arg); + } + }, intent); + } + + void MaterialViewportViewModel::HandleResize(const ResizeMaterialViewportIntent& intent) { + if (intent.width > 0 && intent.height > 0 && + (_state.width != intent.width || _state.height != intent.height)) + { + _state.width = intent.width; + _state.height = intent.height; + + _renderApi->ResizeRenderTargets(_state.width, _state.height); + } + } + +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportViewModel.h b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportViewModel.h new file mode 100644 index 00000000..2794e01b --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/MaterialWorkspace/MaterialViewport/MaterialViewportViewModel.h @@ -0,0 +1,25 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "MaterialViewportState.h" +#include "MaterialViewportIntent.h" +#include "EditorCore/Api/IRenderApi.h" + +namespace Syn { + class MaterialViewportViewModel : public IViewModel { + public: + explicit MaterialViewportViewModel(IRenderApi* renderApi); + ~MaterialViewportViewModel() override = default; + + const MaterialViewportState& GetState() const override; + + void SyncWithEngine() override; + void Dispatch(const MaterialViewportIntent& intent) override; + + private: + void HandleResize(const ResizeMaterialViewportIntent& intent); + + private: + IRenderApi* _renderApi = nullptr; + MaterialViewportState _state; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyIntent.cpp b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyIntent.cpp new file mode 100644 index 00000000..f6027834 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyIntent.cpp @@ -0,0 +1 @@ +#include "ModelHierarchyIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyIntent.h b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyIntent.h new file mode 100644 index 00000000..d6ddc749 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyIntent.h @@ -0,0 +1,30 @@ +#pragma once +#include +#include +#include + +namespace Syn { + struct ModelHierarchySelectIntent { + uint32_t modelId; + int32_t descriptorIndex; + }; + + struct ModelHierarchyToggleExpandIntent { + uint32_t modelId; + int32_t descriptorIndex; + bool expand; + }; + + struct ModelHierarchySetSearchIntent { + std::string query; + }; + + struct ModelHierarchyRefreshIntent {}; + + using ModelHierarchyIntent = std::variant< + ModelHierarchySelectIntent, + ModelHierarchyToggleExpandIntent, + ModelHierarchySetSearchIntent, + ModelHierarchyRefreshIntent + >; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyState.cpp b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyState.cpp new file mode 100644 index 00000000..4c8aadad --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyState.cpp @@ -0,0 +1 @@ +#include "ModelHierarchyState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyState.h b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyState.h new file mode 100644 index 00000000..e4a8c827 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyState.h @@ -0,0 +1,45 @@ +#pragma once +#include +#include +#include +#include +#include "EditorCore/Types/TextureHandle.h" + +namespace Syn +{ + struct ModelNode { + uint32_t id; + std::string name; + std::string path; + std::string icon; + glm::vec2 uv0{ 0.0f, 0.0f }; + glm::vec2 uv1{ 1.0f, 1.0f }; + bool hasPreview = false; + }; + + struct ModelHierarchyNode { + uint32_t modelId = 0xFFFFFFFF; + int32_t descriptorIndex = -1; + + std::string name; + std::string icon; + + uint32_t triangleCount = 0; + bool isMeshNode = false; + + int depth = 0; + bool isExpanded = true; + bool hasChildren = false; + }; + + struct ModelHierarchyState { + std::vector filteredModels; + std::vector flatNodes; + + uint32_t selectedModelId = 0xFFFFFFFF; + int32_t selectedDescriptorIndex = -1; + std::string searchQuery = ""; + + TextureHandle atlasHandle = InvalidTextureHandle; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyViewModel.cpp new file mode 100644 index 00000000..6558a37e --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyViewModel.cpp @@ -0,0 +1,200 @@ +#include "ModelHierarchyViewModel.h" +#include "Editor/Manager/EditorIcons.h" +#include +#include + +namespace Syn { + ModelHierarchyViewModel::ModelHierarchyViewModel(IModelApi* modelApi, IPreviewApi* previewApi) + : _modelApi(modelApi), _previewApi(previewApi) + {} + + uint64_t ModelHierarchyViewModel::GetNodeKey(uint32_t modelId, int32_t descriptorIndex) const { + return (static_cast(modelId) << 32) | static_cast(descriptorIndex); + } + + void ModelHierarchyViewModel::SyncWithEngine() { + if (!_modelApi) return; + + uint64_t currentVersion = _modelApi->GetVersion(); + auto selection = _modelApi->GetSelected(); + + if (currentVersion != _lastEngineVersion || _isDirty) { + RebuildModelList(); + RebuildFlatList(); + _lastEngineVersion = currentVersion; + _isDirty = false; + } + + if (_state.selectedModelId != selection.first || _state.selectedDescriptorIndex != selection.second) { + _state.selectedModelId = selection.first; + _state.selectedDescriptorIndex = selection.second; + } + + if (_previewApi) { + _state.atlasHandle = _previewApi->GetAtlasHandle(); + + for (auto& node : _state.filteredModels) { + if (!node.hasPreview) { + if (_previewApi->GetPreviewUVs(PreviewResourceType::Model, node.id, node.uv0, node.uv1)) { + node.hasPreview = true; + } + } + } + } + } + + void ModelHierarchyViewModel::Dispatch(const ModelHierarchyIntent& intent) { + std::visit([this](auto&& arg) { + using T = std::decay_t; + + if constexpr (std::is_same_v) { + if (_modelApi) { + _modelApi->SetSelected(arg.modelId, arg.descriptorIndex); + _modelApi->ApplyModelToPreviewObject(arg.modelId); + } + + if (_state.selectedModelId != arg.modelId) { + _state.selectedModelId = arg.modelId; + _state.selectedDescriptorIndex = arg.descriptorIndex; + _isDirty = true; + } + else { + _state.selectedDescriptorIndex = arg.descriptorIndex; + } + } + else if constexpr (std::is_same_v) { + uint64_t key = GetNodeKey(arg.modelId, arg.descriptorIndex); + if (arg.expand) _expandedNodes.insert(key); + else _expandedNodes.erase(key); + _isDirty = true; + } + else if constexpr (std::is_same_v) { + if (_state.searchQuery != arg.query) { + _state.searchQuery = arg.query; + _isDirty = true; + } + } + else if constexpr (std::is_same_v) { + _isDirty = true; + } + }, intent); + } + + void ModelHierarchyViewModel::RebuildModelList() { + if (!_modelApi) return; + + _state.filteredModels.clear(); + auto allModels = _modelApi->GetAllModels(); + + std::string searchLower = _state.searchQuery; + std::transform(searchLower.begin(), searchLower.end(), searchLower.begin(), ::tolower); + + for (const auto& mod : allModels) { + std::string nameLower = mod.name; + std::transform(nameLower.begin(), nameLower.end(), nameLower.begin(), ::tolower); + + if (searchLower.empty() || nameLower.find(searchLower) != std::string::npos) { + ModelNode node; + node.id = mod.id; + node.name = mod.name; + node.path = mod.path; + node.icon = SYN_ICON_CUBE; + + if (_previewApi) { + if (_previewApi->GetPreviewUVs(PreviewResourceType::Model, mod.id, node.uv0, node.uv1)) { + node.hasPreview = true; + } + else { + node.hasPreview = false; + _previewApi->RequestPreview(PreviewResourceType::Model, mod.id); + } + } + + _state.filteredModels.push_back(node); + } + } + } + + void ModelHierarchyViewModel::RebuildFlatList() { + _state.flatNodes.clear(); + if (!_modelApi || _state.selectedModelId == 0xFFFFFFFF) return; + + if (const CpuModelData* cpuData = _modelApi->GetModelCpuData(_state.selectedModelId)) { + + std::unordered_map> childMap; + for (uint32_t i = 0; i < cpuData->meshNodeDescriptors.size(); ++i) { + childMap[cpuData->meshNodeDescriptors[i].parentNodeIndex].push_back(i); + } + + std::string modelName = "Selected Model"; + auto allModels = _modelApi->GetAllModels(); + for (const auto& mod : allModels) { + if (mod.id == _state.selectedModelId) { + modelName = mod.name; + break; + } + } + + TraverseAndFlatten(_state.selectedModelId, -1, 0xFFFF, 0, *cpuData, childMap, modelName); + } + } + + bool ModelHierarchyViewModel::TraverseAndFlatten(uint32_t modelId, int32_t descriptorIndex, uint16_t currentTransformIndex, int depth, const CpuModelData& cpuData, const std::unordered_map>& childMap, const std::string& nodeName) { + + bool matchesSearch = _state.searchQuery.empty() || + std::search(nodeName.begin(), nodeName.end(), _state.searchQuery.begin(), _state.searchQuery.end(), + [](char c1, char c2) { return std::tolower(static_cast(c1)) == std::tolower(static_cast(c2)); }) != nodeName.end(); + + bool hasChildren = childMap.contains(currentTransformIndex); + + uint64_t key = GetNodeKey(modelId, descriptorIndex); + bool isExpanded = _expandedNodes.contains(key) || !_state.searchQuery.empty(); + + size_t flattenIndex = _state.flatNodes.size(); + + ModelHierarchyNode node; + node.modelId = modelId; + node.descriptorIndex = descriptorIndex; + node.name = nodeName; + node.depth = depth; + node.hasChildren = hasChildren; + node.isExpanded = isExpanded; + + if (descriptorIndex == -1) { + node.icon = SYN_ICON_CUBE; + node.isMeshNode = false; + node.triangleCount = cpuData.globalIndexCount / 3; + } + else { + const auto& desc = cpuData.meshNodeDescriptors[descriptorIndex]; + node.icon = (desc.meshIndex != 0xFFFF) ? SYN_ICON_DRAW_POLYGON : SYN_ICON_PROJECT_DIAGRAM; + node.isMeshNode = (desc.meshIndex != 0xFFFF); + node.triangleCount = desc.indexCount / 3; + } + + _state.flatNodes.push_back(node); + + bool anyChildMatches = false; + + if (isExpanded && hasChildren) { + for (uint32_t childDescIdx : childMap.at(currentTransformIndex)) { + const auto& childDesc = cpuData.meshNodeDescriptors[childDescIdx]; + std::string childName = childDesc.name; + + if (childName.empty()) + childName = "Node_" + std::to_string(childDescIdx); + + if (TraverseAndFlatten(modelId, childDescIdx, childDesc.nodeIndex, depth + 1, cpuData, childMap, childName)) { + anyChildMatches = true; + } + } + } + + if (!_state.searchQuery.empty() && !matchesSearch && !anyChildMatches) { + _state.flatNodes.resize(flattenIndex); + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyViewModel.h b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyViewModel.h new file mode 100644 index 00000000..87ccb272 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelHierarchy/ModelHierarchyViewModel.h @@ -0,0 +1,34 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "ModelHierarchyState.h" +#include "ModelHierarchyIntent.h" +#include "EditorCore/Api/IModelApi.h" +#include "EditorCore/Api/IPreviewApi.h" +#include +#include + +namespace Syn { + class ModelHierarchyViewModel : public IViewModel { + public: + ModelHierarchyViewModel(IModelApi* modelApi, IPreviewApi* previewApi); + ~ModelHierarchyViewModel() override = default; + + const ModelHierarchyState& GetState() const override { return _state; } + void SyncWithEngine() override; + void Dispatch(const ModelHierarchyIntent& intent) override; + + private: + void RebuildModelList(); + void RebuildFlatList(); + bool TraverseAndFlatten(uint32_t modelId, int32_t descriptorIndex, uint16_t currentTransformIndex, int depth, const CpuModelData& cpuData, const std::unordered_map>& childMap, const std::string& nodeName); + uint64_t GetNodeKey(uint32_t modelId, int32_t descriptorIndex) const; + private: + IModelApi* _modelApi = nullptr; + IPreviewApi* _previewApi = nullptr; + ModelHierarchyState _state; + + bool _isDirty = true; + uint64_t _lastEngineVersion = 0; + std::unordered_set _expandedNodes; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesIntent.cpp b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesIntent.cpp new file mode 100644 index 00000000..fe1ec0e2 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesIntent.cpp @@ -0,0 +1 @@ +#include "ModelPropertiesIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesIntent.h b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesIntent.h new file mode 100644 index 00000000..6daa7999 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesIntent.h @@ -0,0 +1,10 @@ +#pragma once +#include + +namespace Syn { + struct ModelPropertiesRefreshIntent {}; + + using ModelPropertiesIntent = std::variant< + ModelPropertiesRefreshIntent + >; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesState.cpp b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesState.cpp new file mode 100644 index 00000000..7c515e26 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesState.cpp @@ -0,0 +1 @@ +#include "ModelPropertiesState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesState.h b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesState.h new file mode 100644 index 00000000..5e120cde --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesState.h @@ -0,0 +1,34 @@ +#pragma once +#include +#include + +namespace Syn { + struct ModelPropertiesState { + bool hasSelection = false; + uint32_t selectedModelId = 0xFFFFFFFF; + int32_t selectedDescriptorIndex = -1; + std::string modelName = ""; + + uint32_t globalVertexCount = 0; + uint32_t globalIndexCount = 0; + uint32_t globalMeshCount = 0; + glm::vec3 globalAabbMin = glm::vec3(0.0f); + glm::vec3 globalAabbMax = glm::vec3(0.0f); + glm::vec3 globalCenter = glm::vec3(0.0f); + float globalRadius = 0.0f; + + bool isNodeSelected = false; + std::string nodeName = ""; + uint32_t nodeVertexCount = 0; + uint32_t nodeIndexCount = 0; + int32_t meshIndex = -1; + int32_t nodeIndex = -1; + int32_t parentNodeIndex = -1; + + uint32_t nodeMeshletCount = 0; + uint32_t nodeMaterialIndex = 0; + glm::vec3 nodeAabbMin = glm::vec3(0.0f); + glm::vec3 nodeAabbMax = glm::vec3(0.0f); + float nodeRadius = 0.0f; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesViewModel.cpp new file mode 100644 index 00000000..382e4b5d --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesViewModel.cpp @@ -0,0 +1,91 @@ +#include "ModelPropertiesViewModel.h" + +namespace Syn { + ModelPropertiesViewModel::ModelPropertiesViewModel(IModelApi* modelApi) + : _modelApi(modelApi) {} + + void ModelPropertiesViewModel::SyncWithEngine() { + if (!_modelApi) return; + + auto selection = _modelApi->GetSelected(); + if (selection.first != _lastModelId || selection.second != _lastDescriptorIndex) { + _lastModelId = selection.first; + _lastDescriptorIndex = selection.second; + UpdateState(); + } + } + + void ModelPropertiesViewModel::Dispatch(const ModelPropertiesIntent& intent) { + + } + + void ModelPropertiesViewModel::UpdateState() { + _state.hasSelection = (_lastModelId != 0xFFFFFFFF); + _state.selectedModelId = _lastModelId; + _state.selectedDescriptorIndex = _lastDescriptorIndex; + + if (!_state.hasSelection) return; + + const CpuModelData* cpuData = _modelApi->GetModelCpuData(_lastModelId); + if (!cpuData) { + _state.hasSelection = false; + return; + } + + auto models = _modelApi->GetAllModels(); + for (const auto& m : models) { + if (m.id == _lastModelId) { + _state.modelName = m.name; + break; + } + } + + _state.globalVertexCount = cpuData->globalVertexCount; + _state.globalIndexCount = cpuData->globalIndexCount; + _state.globalMeshCount = cpuData->globalMeshCount; + _state.globalAabbMin = cpuData->globalCollider.aabbMin; + _state.globalAabbMax = cpuData->globalCollider.aabbMax; + _state.globalCenter = cpuData->globalCollider.center; + _state.globalRadius = cpuData->globalCollider.radius; + + if (_lastDescriptorIndex >= 0 && _lastDescriptorIndex < cpuData->meshNodeDescriptors.size()) { + _state.isNodeSelected = true; + const auto& desc = cpuData->meshNodeDescriptors[_lastDescriptorIndex]; + + _state.nodeName = desc.name.empty() ? "Node_" + std::to_string(_lastDescriptorIndex) : desc.name; + _state.nodeVertexCount = desc.vertexCount; + _state.nodeIndexCount = desc.indexCount; + _state.meshIndex = desc.meshIndex; + _state.nodeIndex = desc.nodeIndex; + _state.parentNodeIndex = desc.parentNodeIndex; + + if (desc.meshIndex != 0xFFFF) { + uint32_t validMeshCounter = 0; + + for (int32_t i = 0; i < _lastDescriptorIndex; ++i) { + if (cpuData->meshNodeDescriptors[i].meshIndex != 0xFFFF) { + validMeshCounter++; + } + } + + uint32_t lod0Index = validMeshCounter * 4; + + if (lod0Index < cpuData->meshletDrawDescriptors.size()) { + _state.nodeMeshletCount = cpuData->meshletDrawDescriptors[lod0Index].meshletCount; + } + if (lod0Index < cpuData->meshDescriptors.size()) { + _state.nodeMaterialIndex = cpuData->meshDescriptors[lod0Index].materialIndex; + } + if (validMeshCounter < cpuData->meshColliders.size()) + { + _state.nodeAabbMin = cpuData->meshColliders[validMeshCounter].aabbMin; + _state.nodeAabbMax = cpuData->meshColliders[validMeshCounter].aabbMax; + _state.nodeRadius = cpuData->meshColliders[validMeshCounter].radius; + } + } + } + else { + _state.isNodeSelected = false; + } + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesViewModel.h b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesViewModel.h new file mode 100644 index 00000000..a98aea05 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelProperties/ModelPropertiesViewModel.h @@ -0,0 +1,27 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "ModelPropertiesState.h" +#include "ModelPropertiesIntent.h" +#include "EditorCore/Api/IModelApi.h" + +namespace Syn { + class ModelPropertiesViewModel : public IViewModel { + public: + ModelPropertiesViewModel(IModelApi* modelApi); + ~ModelPropertiesViewModel() override = default; + + const ModelPropertiesState& GetState() const override { return _state; } + void SyncWithEngine() override; + void Dispatch(const ModelPropertiesIntent& intent) override; + + private: + void UpdateState(); + + private: + IModelApi* _modelApi = nullptr; + ModelPropertiesState _state; + + uint32_t _lastModelId = 0xFFFFFFFF; + int32_t _lastDescriptorIndex = -1; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportIntent.cpp b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportIntent.cpp new file mode 100644 index 00000000..f83cb4ef --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportIntent.cpp @@ -0,0 +1 @@ +#include "ModelViewportIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportIntent.h b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportIntent.h new file mode 100644 index 00000000..5e4b8177 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportIntent.h @@ -0,0 +1,40 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace Syn { + struct ResizeModelViewportIntent { uint32_t width; uint32_t height; }; + struct ChangeModelTargetIntent { std::string currentGroup; std::string targetName; std::string viewName; }; + + struct ChangeModelGizmoOperationIntent { ImGuizmo::OPERATION op; }; + struct ChangeModelGizmoModeIntent { ImGuizmo::MODE mode; }; + struct ToggleModelSnapIntent { bool useSnap; }; + struct ChangeModelSnapTranslateIntent { glm::vec3 snap; }; + struct ChangeModelSnapRotateIntent { float angle; }; + struct ChangeModelSnapScaleIntent { float scale; }; + struct ApplyModelGizmoTransformIntent { glm::mat4 newWorldMatrix; }; + + struct PickMeshIntent { uint32_t x; uint32_t y; }; + + struct ToggleModelDebugVisibilityIntent { bool enabled; }; + struct ChangeModelDebugVisibilityModeIntent { uint32_t mode; }; + + using ModelViewportIntent = std::variant< + ResizeModelViewportIntent, + ChangeModelTargetIntent, + ChangeModelGizmoOperationIntent, + ChangeModelGizmoModeIntent, + ToggleModelSnapIntent, + ApplyModelGizmoTransformIntent, + PickMeshIntent, + ToggleModelDebugVisibilityIntent, + ChangeModelDebugVisibilityModeIntent, + ChangeModelSnapTranslateIntent, + ChangeModelSnapRotateIntent, + ChangeModelSnapScaleIntent + >; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportState.cpp b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportState.cpp new file mode 100644 index 00000000..c135f3bf --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportState.cpp @@ -0,0 +1 @@ +#include "ModelViewportState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportState.h b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportState.h new file mode 100644 index 00000000..a646710b --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportState.h @@ -0,0 +1,43 @@ +#pragma once +#include +#include +#include +#include +#include +#include "EditorCore/Types/TextureHandle.h" +#include "Engine/Vk/Image/ImageViewNames.h" +#include "Engine/Render/RenderNames.h" + +namespace Syn { + struct ModelViewportState { + uint32_t width = 0; + uint32_t height = 0; + + TextureHandle textureId = InvalidTextureHandle; + std::string currentGroup = RenderTargetGroupNames::Main; + std::string currentTarget = RenderTargetNames::Main; + std::string currentView = Vk::ImageViewNames::Default; + + bool isHovered = false; + bool isFocused = false; + + ImGuizmo::OPERATION gizmoOperation = ImGuizmo::TRANSLATE; + ImGuizmo::MODE gizmoMode = ImGuizmo::LOCAL; + bool useSnap = false; + + glm::vec3 snapTranslate{ 1.0f, 1.0f, 1.0f }; + float snapAngle = 45.0f; + float snapScale = 0.5f; + + uint32_t activeEntity = 0; + uint32_t activeModelId = 0xFFFFFFFF; + int32_t activeNodeIndex = -1; + + glm::mat4 cameraView{ 1.0f }; + glm::mat4 cameraProj{ 1.0f }; + glm::mat4 entityWorldTransform{ 1.0f }; + + bool enableDebugVisibility = false; + uint32_t debugVisibilityMode = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportViewModel.cpp new file mode 100644 index 00000000..559e6622 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportViewModel.cpp @@ -0,0 +1,117 @@ +#include "ModelViewportViewModel.h" +#include + +namespace Syn { + + ModelViewportViewModel::ModelViewportViewModel(IRenderApi* renderApi, ISelectionApi* selectionApi, ITransformApi* transformApi, ISettingsApi* settingsApi, IModelApi* modelApi) + : _renderApi(renderApi), _selectionApi(selectionApi), _transformApi(transformApi), _settingsApi(settingsApi), _modelApi(modelApi) {} + + const ModelViewportState& ModelViewportViewModel::GetState() const { + return _state; + } + + void ModelViewportViewModel::SyncWithEngine() { + if (!_renderApi) return; + + _state.textureId = _renderApi->GetViewportTexture(_state.currentGroup, _state.currentTarget, _state.currentView); + _state.cameraView = _renderApi->GetEditorCameraView(); + _state.cameraProj = _renderApi->GetEditorCameraProjection(); + + if (_modelApi) { + auto [mId, nIdx] = _modelApi->GetSelected(); + _state.activeModelId = mId; + _state.activeNodeIndex = nIdx; + } + + _state.activeEntity = _selectionApi->GetSelectedEntity(); + if (_state.activeEntity != NULL_ENTITY) { + _state.entityWorldTransform = _transformApi->GetEntityWorldMatrix(_state.activeEntity); + } + + if (_settingsApi) { + SceneSettings settings = _settingsApi->GetSceneSettings(); + _state.enableDebugVisibility = settings.debug.enableDebugVisibility; + _state.debugVisibilityMode = static_cast(settings.debug.debugVisibilityMode); + } + } + + void ModelViewportViewModel::Dispatch(const ModelViewportIntent& intent) { + std::visit([this](auto&& arg) { + using T = std::decay_t; + if constexpr (std::is_same_v) HandleResize(arg); + else if constexpr (std::is_same_v) HandleChangeTarget(arg); + else if constexpr (std::is_same_v) _state.gizmoOperation = arg.op; + else if constexpr (std::is_same_v) _state.gizmoMode = arg.mode; + else if constexpr (std::is_same_v) _state.useSnap = arg.useSnap; + else if constexpr (std::is_same_v) HandleGizmoTransform(arg); + else if constexpr (std::is_same_v) HandlePickMesh(arg); + else if constexpr (std::is_same_v) HandleToggleDebugVisibility(arg); + else if constexpr (std::is_same_v) HandleChangeDebugVisibilityMode(arg); + else if constexpr (std::is_same_v) _state.snapTranslate = arg.snap; + else if constexpr (std::is_same_v) _state.snapAngle = arg.angle; + else if constexpr (std::is_same_v) _state.snapScale = arg.scale; + }, intent); + } + + void ModelViewportViewModel::HandlePickMesh(const PickMeshIntent& intent) { + auto [entityId, meshIndex] = _renderApi->ReadEntityAndMeshIdAtPixel(intent.x, intent.y); + + if (entityId != NULL_ENTITY) { + _selectionApi->SetSelectedEntity(entityId); + + if (_modelApi) { + auto [currentModel, currentNode] = _modelApi->GetSelected(); + if (currentModel != INVALID_MODEL_ID) { + _modelApi->SetSelected(currentModel, static_cast(meshIndex)); + } + } + } + } + + void ModelViewportViewModel::HandleResize(const ResizeModelViewportIntent& intent) { + if (intent.width > 0 && intent.height > 0 && + (_state.width != intent.width || _state.height != intent.height)) + { + _state.width = intent.width; + _state.height = intent.height; + _renderApi->ResizeRenderTargets(_state.width, _state.height); + } + } + + void ModelViewportViewModel::HandleChangeTarget(const ChangeModelTargetIntent& intent) { + _state.currentGroup = intent.currentGroup; + _state.currentTarget = intent.targetName; + _state.currentView = intent.viewName; + } + + void ModelViewportViewModel::HandleGizmoTransform(const ApplyModelGizmoTransformIntent& intent) { + if (_state.activeEntity == NULL_ENTITY) + return; + + glm::vec3 translation, rotation, scale; + ImGuizmo::DecomposeMatrixToComponents(glm::value_ptr(intent.newWorldMatrix), glm::value_ptr(translation), glm::value_ptr(rotation), glm::value_ptr(scale)); + + _transformApi->SetEntityPosition(_state.activeEntity, translation); + _transformApi->SetEntityRotation(_state.activeEntity, rotation); + _transformApi->SetEntityScale(_state.activeEntity, scale); + } + + void ModelViewportViewModel::HandleToggleDebugVisibility(const ToggleModelDebugVisibilityIntent& intent) { + _state.enableDebugVisibility = intent.enabled; + if (_settingsApi) { + SceneSettings settings = _settingsApi->GetSceneSettings(); + settings.debug.enableDebugVisibility = intent.enabled; + _settingsApi->SetSceneSettings(settings); + } + } + + void ModelViewportViewModel::HandleChangeDebugVisibilityMode(const ChangeModelDebugVisibilityModeIntent& intent) { + _state.debugVisibilityMode = intent.mode; + if (_settingsApi) { + SceneSettings settings = _settingsApi->GetSceneSettings(); + settings.debug.debugVisibilityMode = static_cast(intent.mode); + _settingsApi->SetSceneSettings(settings); + } + } + +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportViewModel.h b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportViewModel.h new file mode 100644 index 00000000..4bc7ae1e --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/ModelWorkspace/ModelViewport/ModelViewportViewModel.h @@ -0,0 +1,36 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "ModelViewportState.h" +#include "ModelViewportIntent.h" +#include "EditorCore/Api/IRenderApi.h" +#include "EditorCore/Api/ISelectionApi.h" +#include "EditorCore/Api/ITransformApi.h" +#include "EditorCore/Api/ISettingsApi.h" +#include "EditorCore/Api/IModelApi.h" + +namespace Syn { + class ModelViewportViewModel : public IViewModel { + public: + ModelViewportViewModel(IRenderApi* renderApi, ISelectionApi* selectionApi, ITransformApi* transformApi, ISettingsApi* settingsApi, IModelApi* modelApi); + ~ModelViewportViewModel() override = default; + + const ModelViewportState& GetState() const override; + + void SyncWithEngine() override; + void Dispatch(const ModelViewportIntent& intent) override; + private: + void HandlePickMesh(const PickMeshIntent& intent); + void HandleResize(const ResizeModelViewportIntent& intent); + void HandleChangeTarget(const ChangeModelTargetIntent& intent); + void HandleGizmoTransform(const ApplyModelGizmoTransformIntent& intent); + void HandleToggleDebugVisibility(const ToggleModelDebugVisibilityIntent& intent); + void HandleChangeDebugVisibilityMode(const ChangeModelDebugVisibilityModeIntent& intent); + private: + IRenderApi* _renderApi = nullptr; + ISelectionApi* _selectionApi = nullptr; + ITransformApi* _transformApi = nullptr; + ISettingsApi* _settingsApi = nullptr; + IModelApi* _modelApi = nullptr; + ModelViewportState _state; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/Benchmark/BenchmarkIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Benchmark/BenchmarkIntent.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Benchmark/BenchmarkIntent.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Benchmark/BenchmarkIntent.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Benchmark/BenchmarkIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Benchmark/BenchmarkIntent.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Benchmark/BenchmarkIntent.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Benchmark/BenchmarkIntent.h diff --git a/SynapseEngine/EditorCore/ViewModels/Benchmark/BenchmarkState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Benchmark/BenchmarkState.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Benchmark/BenchmarkState.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Benchmark/BenchmarkState.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Benchmark/BenchmarkState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Benchmark/BenchmarkState.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Benchmark/BenchmarkState.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Benchmark/BenchmarkState.h diff --git a/SynapseEngine/EditorCore/ViewModels/Benchmark/BenchmarkViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Benchmark/BenchmarkViewModel.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Benchmark/BenchmarkViewModel.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Benchmark/BenchmarkViewModel.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Benchmark/BenchmarkViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Benchmark/BenchmarkViewModel.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Benchmark/BenchmarkViewModel.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Benchmark/BenchmarkViewModel.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/ComponentIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/ComponentIntent.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/ComponentIntent.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/ComponentIntent.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/ComponentIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/ComponentIntent.h new file mode 100644 index 00000000..5c76623f --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/ComponentIntent.h @@ -0,0 +1,37 @@ +#pragma once +#include "Core/Tag/TagIntent.h" +#include "Core/Camera/CameraIntent.h" +#include "Core/Transform/TransformIntent.h" +#include "Light/DirectionLight/DirectionLightIntent.h" +#include "Light/PointLight/PointLightIntent.h" +#include "Light/SpotLight/SpotLightIntent.h" +#include "Rendering/Model/ModelComponentIntent.h" +#include "Rendering/Animation/AnimationIntent.h" +#include "Rendering/MaterialOverride/MaterialOverrideIntent.h" +#include "Physics/BoxCollider/BoxColliderIntent.h" +#include "Physics/SphereCollider/SphereColliderIntent.h" +#include "Physics/CapsuleCollider/CapsuleColliderIntent.h" +#include "Physics/ConvexCollider/ConvexColliderIntent.h" +#include "Physics/MeshCollider/MeshColliderIntent.h" +#include "Physics/RigidBody/RigidBodyIntent.h" +#include + +namespace Syn { + using ComponentIntent = std::variant< + TagIntent, + CameraIntent, + TransformIntent, + DirectionLightIntent, + PointLightIntent, + SpotLightIntent, + ModelComponentIntent, + AnimationIntent, + BoxColliderIntent, + SphereColliderIntent, + CapsuleColliderIntent, + ConvexColliderIntent, + MeshColliderIntent, + RigidBodyIntent, + MaterialOverrideIntent + >; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/Component/ComponentState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/ComponentState.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/ComponentState.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/ComponentState.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/ComponentState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/ComponentState.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/ComponentState.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/ComponentState.h diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/ComponentViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/ComponentViewModel.cpp new file mode 100644 index 00000000..7ffca385 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/ComponentViewModel.cpp @@ -0,0 +1,125 @@ +#include "ComponentViewModel.h" + +namespace Syn +{ + ComponentViewModel::ComponentViewModel( + ISelectionApi* selectionApi, + ITagApi* tagApi, + ITransformApi* transformApi, + IHierarchyApi* hierarchyApi, + IDirectionLightApi* directionLightApi, + IPointLightApi* pointLightApi, + ISpotLightApi* spotLightApi, + ICameraApi* cameraApi, + IBoxColliderApi* boxColliderApi, + ISphereColliderApi* sphereColliderApi, + ICapsuleColliderApi* capsuleColliderApi, + IConvexColliderApi* convexColliderApi, + IMeshColliderApi* meshColliderApi, + IRigidBodyApi* rigidBodyApi, + IModelComponentApi* modelComponentApi, + IAnimationApi* animationApi, + IMaterialOverrideApi* materialOverrideApi + ) + : + _selectionApi(selectionApi), + _tagViewModel(selectionApi, tagApi), + _transformViewModel(selectionApi, transformApi, hierarchyApi), + _directionLightViewModel(selectionApi, directionLightApi), + _pointLightViewModel(selectionApi, pointLightApi), + _spotLightViewModel(selectionApi, spotLightApi), + _cameraViewModel(selectionApi, cameraApi), + _boxColliderViewModel(selectionApi, boxColliderApi), + _sphereColliderViewModel(selectionApi, sphereColliderApi), + _capsuleColliderViewModel(selectionApi, capsuleColliderApi), + _convexColliderViewModel(selectionApi, convexColliderApi), + _meshColliderViewModel(selectionApi, meshColliderApi), + _rigidBodyViewModel(selectionApi, rigidBodyApi), + _modelComponentViewModel(selectionApi, modelComponentApi), + _animationViewModel(selectionApi, animationApi), + _materialOverrideViewModel(selectionApi, materialOverrideApi) + {} + + const ComponentState& ComponentViewModel::GetState() const { + return _state; + } + + void ComponentViewModel::SyncWithEngine() { + if (!_selectionApi) return; + + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + + _state.activeEntityId = activeEntity; + _state.hasSelection = (activeEntity != NULL_ENTITY); + + if (_state.hasSelection) { + _tagViewModel.SyncWithEngine(); + _transformViewModel.SyncWithEngine(); + _directionLightViewModel.SyncWithEngine(); + _pointLightViewModel.SyncWithEngine(); + _spotLightViewModel.SyncWithEngine(); + _cameraViewModel.SyncWithEngine(); + _boxColliderViewModel.SyncWithEngine(); + _sphereColliderViewModel.SyncWithEngine(); + _capsuleColliderViewModel.SyncWithEngine(); + _convexColliderViewModel.SyncWithEngine(); + _meshColliderViewModel.SyncWithEngine(); + _rigidBodyViewModel.SyncWithEngine(); + _modelComponentViewModel.SyncWithEngine(); + _animationViewModel.SyncWithEngine(); + _materialOverrideViewModel.SyncWithEngine(); + } + } + + void ComponentViewModel::Dispatch(const ComponentIntent& intent) { + std::visit([this](auto&& arg) { + using T = std::decay_t; + + if constexpr (std::is_same_v) { + _tagViewModel.Dispatch(arg); + } + else if constexpr (std::is_same_v) { + _transformViewModel.Dispatch(arg); + } + else if constexpr (std::is_same_v) { + _directionLightViewModel.Dispatch(arg); + } + else if constexpr (std::is_same_v) { + _pointLightViewModel.Dispatch(arg); + } + else if constexpr (std::is_same_v) { + _spotLightViewModel.Dispatch(arg); + } + else if constexpr (std::is_same_v) { + _cameraViewModel.Dispatch(arg); + } + else if constexpr (std::is_same_v) { + _boxColliderViewModel.Dispatch(arg); + } + else if constexpr (std::is_same_v) { + _sphereColliderViewModel.Dispatch(arg); + } + else if constexpr (std::is_same_v) { + _capsuleColliderViewModel.Dispatch(arg); + } + else if constexpr (std::is_same_v) { + _convexColliderViewModel.Dispatch(arg); + } + else if constexpr (std::is_same_v) { + _meshColliderViewModel.Dispatch(arg); + } + else if constexpr (std::is_same_v) { + _rigidBodyViewModel.Dispatch(arg); + } + else if constexpr (std::is_same_v) { + _modelComponentViewModel.Dispatch(arg); + } + else if constexpr (std::is_same_v) { + _animationViewModel.Dispatch(arg); + } + else if constexpr (std::is_same_v) { + _materialOverrideViewModel.Dispatch(arg); + } + }, intent); + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/ComponentViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/ComponentViewModel.h new file mode 100644 index 00000000..09e1a37f --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/ComponentViewModel.h @@ -0,0 +1,106 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "ComponentState.h" +#include "ComponentIntent.h" + +#include "Core/Tag/TagViewModel.h" +#include "Core/Transform/TransformViewModel.h" +#include "Light/DirectionLight/DirectionLightViewModel.h" +#include "Light/PointLight/PointLightViewModel.h" +#include "Light/SpotLight/SpotLightViewModel.h" +#include "Core/Camera/CameraViewModel.h" + +#include "Physics/BoxCollider/BoxColliderViewModel.h" +#include "Physics/SphereCollider/SphereColliderViewModel.h" +#include "Physics/CapsuleCollider/CapsuleColliderViewModel.h" +#include "Physics/ConvexCollider/ConvexColliderViewModel.h" +#include "Physics/MeshCollider/MeshColliderViewModel.h" +#include "Physics/RigidBody/RigidBodyViewModel.h" + +#include "Rendering/Model/ModelComponentViewModel.h" +#include "Rendering/Animation/AnimationViewModel.h" +#include "Rendering/MaterialOverride/MaterialOverrideViewModel.h" + +#include "EditorCore/Api/ISelectionApi.h" +#include "EditorCore/Api/ITagApi.h" +#include "EditorCore/Api/ITransformApi.h" +#include "EditorCore/Api/IDirectionLightApi.h" +#include "EditorCore/Api/IPointLightApi.h" +#include "EditorCore/Api/ICameraApi.h" +#include "EditorCore/Api/IBoxColliderApi.h" +#include "EditorCore/Api/ISphereColliderApi.h" +#include "EditorCore/Api/ICapsuleColliderApi.h" +#include "EditorCore/Api/IConvexColliderApi.h" +#include "EditorCore/Api/IMeshColliderApi.h" +#include "EditorCore/Api/IRigidBodyApi.h" +#include "EditorCore/Api/IModelComponentApi.h" +#include "EditorCore/Api/IAnimationApi.h" +#include "EditorCore/Api/IMaterialOverrideApi.h" + +namespace Syn { + class ComponentViewModel : public IViewModel { + public: + ComponentViewModel( + ISelectionApi* selectionApi, + ITagApi* tagApi, + ITransformApi* transformApi, + IHierarchyApi* hierarchyApi, + IDirectionLightApi* directionLightApi, + IPointLightApi* pointLightApi, + ISpotLightApi* spotLightApi, + ICameraApi* cameraApi, + IBoxColliderApi* boxColliderApi, + ISphereColliderApi* sphereColliderApi, + ICapsuleColliderApi* capsuleColliderApi, + IConvexColliderApi* convexColliderApi, + IMeshColliderApi* meshColliderApi, + IRigidBodyApi* rigidBodyApi, + IModelComponentApi* modelComponentApi, + IAnimationApi* animationApi, + IMaterialOverrideApi* materialOverrideApi + ); + + ~ComponentViewModel() override = default; + + const ComponentState& GetState() const override; + void SyncWithEngine() override; + void Dispatch(const ComponentIntent& intent) override; + + TagViewModel& GetTagViewModel() { return _tagViewModel; } + TransformViewModel& GetTransformViewModel() { return _transformViewModel; } + DirectionLightViewModel& GetDirectionLightViewModel() { return _directionLightViewModel; } + PointLightViewModel& GetPointLightViewModel() { return _pointLightViewModel; } + SpotLightViewModel& GetSpotLightViewModel() { return _spotLightViewModel; } + CameraViewModel& GetCameraViewModel() { return _cameraViewModel; } + BoxColliderViewModel& GetBoxColliderViewModel() { return _boxColliderViewModel; } + SphereColliderViewModel& GetSphereColliderViewModel() { return _sphereColliderViewModel; } + CapsuleColliderViewModel& GetCapsuleColliderViewModel() { return _capsuleColliderViewModel; } + ConvexColliderViewModel& GetConvexColliderViewModel() { return _convexColliderViewModel; } + MeshColliderViewModel& GetMeshColliderViewModel() { return _meshColliderViewModel; } + RigidBodyViewModel& GetRigidBodyViewModel() { return _rigidBodyViewModel; } + ModelComponentViewModel& GetModelComponentViewModel() { return _modelComponentViewModel; } + AnimationViewModel& GetAnimationViewModel() { return _animationViewModel; } + MaterialOverrideViewModel& GetMaterialOverrideViewModel() { return _materialOverrideViewModel; } + private: + ISelectionApi* _selectionApi = nullptr; + ComponentState _state; + + TagViewModel _tagViewModel; + CameraViewModel _cameraViewModel; + TransformViewModel _transformViewModel; + DirectionLightViewModel _directionLightViewModel; + PointLightViewModel _pointLightViewModel; + SpotLightViewModel _spotLightViewModel; + + BoxColliderViewModel _boxColliderViewModel; + SphereColliderViewModel _sphereColliderViewModel; + CapsuleColliderViewModel _capsuleColliderViewModel; + ConvexColliderViewModel _convexColliderViewModel; + MeshColliderViewModel _meshColliderViewModel; + RigidBodyViewModel _rigidBodyViewModel; + + ModelComponentViewModel _modelComponentViewModel; + AnimationViewModel _animationViewModel; + MaterialOverrideViewModel _materialOverrideViewModel; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraCommands.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraCommands.cpp new file mode 100644 index 00000000..9552621f --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraCommands.cpp @@ -0,0 +1 @@ +#include "CameraCommands.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraCommands.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraCommands.h new file mode 100644 index 00000000..44b99c2a --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraCommands.h @@ -0,0 +1,18 @@ +#pragma once +#include "EditorCore/Command/ComponentChangeCommand.h" +#include "EditorCore/Api/ICameraApi.h" + +namespace Syn +{ + using ChangeCameraIsOrthographicCommand = ComponentChangeCommand; + using ChangeCameraOrthoSizeCommand = ComponentChangeCommand; + using ChangeCameraUseOrbitCommand = ComponentChangeCommand; + using ChangeCameraYawCommand = ComponentChangeCommand; + using ChangeCameraPitchCommand = ComponentChangeCommand; + using ChangeCameraNearPlaneCommand = ComponentChangeCommand; + using ChangeCameraFarPlaneCommand = ComponentChangeCommand; + using ChangeCameraFovCommand = ComponentChangeCommand; + using ChangeCameraSpeedCommand = ComponentChangeCommand; + using ChangeCameraSensitivityCommand = ComponentChangeCommand; + using ChangeCameraDistanceCommand = ComponentChangeCommand; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraIntent.cpp new file mode 100644 index 00000000..06f0b168 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraIntent.cpp @@ -0,0 +1 @@ +#include "CameraIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraIntent.h new file mode 100644 index 00000000..10824c37 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraIntent.h @@ -0,0 +1,31 @@ +#pragma once +#include + +namespace Syn +{ + struct SetCameraIsOrthographicIntent { bool isOrthographic; }; + struct SetCameraOrthoSizeIntent { float orthoSize; bool isDragging; }; + struct SetCameraUseOrbitIntent { bool useOrbit; }; + + struct SetCameraYawIntent { float yaw; bool isDragging; }; + struct SetCameraPitchIntent { float pitch; bool isDragging; }; + struct SetCameraNearPlaneIntent { float nearPlane; bool isDragging; }; + struct SetCameraFarPlaneIntent { float farPlane; bool isDragging; }; + struct SetCameraFovIntent { float fov; bool isDragging; }; + struct SetCameraSpeedIntent { float speed; bool isDragging; }; + struct SetCameraSensitivityIntent { float sensitivity; bool isDragging; }; + struct SetCameraDistanceIntent { float distance; bool isDragging; }; + + using CameraIntent = std::variant< + SetCameraIsOrthographicIntent, + SetCameraOrthoSizeIntent, + SetCameraUseOrbitIntent, + SetCameraYawIntent, + SetCameraPitchIntent, + SetCameraNearPlaneIntent, + SetCameraFarPlaneIntent, + SetCameraFovIntent, + SetCameraSpeedIntent, + SetCameraSensitivityIntent, + SetCameraDistanceIntent>; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraState.cpp new file mode 100644 index 00000000..85baba58 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraState.cpp @@ -0,0 +1 @@ +#include "CameraState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraState.h new file mode 100644 index 00000000..a7716a16 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraState.h @@ -0,0 +1,20 @@ +#pragma once + +namespace Syn { + struct CameraState { + bool hasComponent = false; + + bool isOrthographic; + float orthoSize; + bool useOrbit; + + float yaw; + float pitch; + float nearPlane; + float farPlane; + float fov; + float speed; + float sensitivity; + float distance; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraViewModel.cpp new file mode 100644 index 00000000..5c7ca3dc --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraViewModel.cpp @@ -0,0 +1,165 @@ +#include "CameraViewModel.h" + +namespace Syn +{ + CameraViewModel::CameraViewModel(ISelectionApi* selectionApi, ICameraApi* cameraApi) + : _selectionApi(selectionApi), _cameraApi(cameraApi) + {} + + const CameraState& CameraViewModel::GetState() const + { + return _state; + } + + void CameraViewModel::SyncWithEngine() + { + if (!_selectionApi || !_cameraApi) + return; + + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + + if (activeEntity != NULL_ENTITY && _cameraApi->HasCamera(activeEntity)) + { + _state.hasComponent = true; + + _state.isOrthographic = _cameraApi->GetCameraIsOrthographic(activeEntity); + _state.useOrbit = _cameraApi->GetCameraUseOrbit(activeEntity); + + if (!_orthoSizeDrag.IsDragging()) _state.orthoSize = _cameraApi->GetCameraOrthoSize(activeEntity); + + if (!_yawDrag.IsDragging()) _state.yaw = _cameraApi->GetCameraYaw(activeEntity); + if (!_pitchDrag.IsDragging()) _state.pitch = _cameraApi->GetCameraPitch(activeEntity); + if (!_nearPlaneDrag.IsDragging()) _state.nearPlane = _cameraApi->GetCameraNearPlane(activeEntity); + if (!_farPlaneDrag.IsDragging()) _state.farPlane = _cameraApi->GetCameraFarPlane(activeEntity); + if (!_fovDrag.IsDragging()) _state.fov = _cameraApi->GetCameraFov(activeEntity); + if (!_speedDrag.IsDragging()) _state.speed = _cameraApi->GetCameraSpeed(activeEntity); + if (!_sensitivityDrag.IsDragging()) _state.sensitivity = _cameraApi->GetCameraSensitivity(activeEntity); + if (!_distanceDrag.IsDragging()) _state.distance = _cameraApi->GetCameraDistance(activeEntity); + } + else + { + _state.hasComponent = false; + } + } + + void CameraViewModel::Dispatch(const CameraIntent& intent) + { + std::visit([this](auto&& arg) + { + using T = std::decay_t; + + // Új Dispatchek + if constexpr (std::is_same_v) HandleSetIsOrthographic(arg); + else if constexpr (std::is_same_v) HandleSetOrthoSize(arg); + else if constexpr (std::is_same_v) HandleSetUseOrbit(arg); + + else if constexpr (std::is_same_v) HandleSetYaw(arg); + else if constexpr (std::is_same_v) HandleSetPitch(arg); + else if constexpr (std::is_same_v) HandleSetNearPlane(arg); + else if constexpr (std::is_same_v) HandleSetFarPlane(arg); + else if constexpr (std::is_same_v) HandleSetFov(arg); + else if constexpr (std::is_same_v) HandleSetSpeed(arg); + else if constexpr (std::is_same_v) HandleSetSensitivity(arg); + else if constexpr (std::is_same_v) HandleSetDistance(arg); + }, intent); + } + + void CameraViewModel::HandleSetIsOrthographic(const SetCameraIsOrthographicIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _state.isOrthographic = intent.isOrthographic; + _cameraApi->SetCameraIsOrthographic(activeEntity, intent.isOrthographic); + } + + void CameraViewModel::HandleSetUseOrbit(const SetCameraUseOrbitIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _state.useOrbit = intent.useOrbit; + _cameraApi->SetCameraUseOrbit(activeEntity, intent.useOrbit); + } + + void CameraViewModel::HandleSetOrthoSize(const SetCameraOrthoSizeIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + _orthoSizeDrag.Handle(intent.isDragging, intent.orthoSize, _state.orthoSize, + [&](const float& v) { _cameraApi->SetCameraOrthoSize(activeEntity, v); }, + [&](const float& s, const float& e) { return std::make_shared(_cameraApi, activeEntity, s, e); }); + } + + void CameraViewModel::HandleSetYaw(const SetCameraYawIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + _yawDrag.Handle(intent.isDragging, intent.yaw, _state.yaw, + [&](const float& v) { _cameraApi->SetCameraYaw(activeEntity, v); }, + [&](const float& s, const float& e) { return std::make_shared(_cameraApi, activeEntity, s, e); }); + } + + void CameraViewModel::HandleSetPitch(const SetCameraPitchIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + _pitchDrag.Handle(intent.isDragging, intent.pitch, _state.pitch, + [&](const float& v) { _cameraApi->SetCameraPitch(activeEntity, v); }, + [&](const float& s, const float& e) { return std::make_shared(_cameraApi, activeEntity, s, e); }); + } + + void CameraViewModel::HandleSetNearPlane(const SetCameraNearPlaneIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + _nearPlaneDrag.Handle(intent.isDragging, intent.nearPlane, _state.nearPlane, + [&](const float& v) { _cameraApi->SetCameraNearPlane(activeEntity, v); }, + [&](const float& s, const float& e) { return std::make_shared(_cameraApi, activeEntity, s, e); }); + } + + void CameraViewModel::HandleSetFarPlane(const SetCameraFarPlaneIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + _farPlaneDrag.Handle(intent.isDragging, intent.farPlane, _state.farPlane, + [&](const float& v) { _cameraApi->SetCameraFarPlane(activeEntity, v); }, + [&](const float& s, const float& e) { return std::make_shared(_cameraApi, activeEntity, s, e); }); + } + + void CameraViewModel::HandleSetFov(const SetCameraFovIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + _fovDrag.Handle(intent.isDragging, intent.fov, _state.fov, + [&](const float& v) { _cameraApi->SetCameraFov(activeEntity, v); }, + [&](const float& s, const float& e) { return std::make_shared(_cameraApi, activeEntity, s, e); }); + } + + void CameraViewModel::HandleSetSpeed(const SetCameraSpeedIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + _speedDrag.Handle(intent.isDragging, intent.speed, _state.speed, + [&](const float& v) { _cameraApi->SetCameraSpeed(activeEntity, v); }, + [&](const float& s, const float& e) { return std::make_shared(_cameraApi, activeEntity, s, e); }); + } + + void CameraViewModel::HandleSetSensitivity(const SetCameraSensitivityIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + _sensitivityDrag.Handle(intent.isDragging, intent.sensitivity, _state.sensitivity, + [&](const float& v) { _cameraApi->SetCameraSensitivity(activeEntity, v); }, + [&](const float& s, const float& e) { return std::make_shared(_cameraApi, activeEntity, s, e); }); + } + + void CameraViewModel::HandleSetDistance(const SetCameraDistanceIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + _distanceDrag.Handle(intent.isDragging, intent.distance, _state.distance, + [&](const float& v) { _cameraApi->SetCameraDistance(activeEntity, v); }, + [&](const float& s, const float& e) { return std::make_shared(_cameraApi, activeEntity, s, e); }); + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraViewModel.h new file mode 100644 index 00000000..6d7b1d60 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Camera/CameraViewModel.h @@ -0,0 +1,47 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "EditorCore/Interaction/DragInteraction.h" +#include "CameraState.h" +#include "CameraIntent.h" +#include "CameraCommands.h" +#include "EditorCore/Api/ISelectionApi.h" +#include "EditorCore/Api/ICameraApi.h" + +namespace Syn { + class CameraViewModel : public IViewModel { + public: + CameraViewModel(ISelectionApi* selectionApi, ICameraApi* cameraApi); + ~CameraViewModel() override = default; + + const CameraState& GetState() const override; + void SyncWithEngine() override; + void Dispatch(const CameraIntent& intent) override; + + private: + void HandleSetIsOrthographic(const SetCameraIsOrthographicIntent& intent); + void HandleSetOrthoSize(const SetCameraOrthoSizeIntent& intent); + void HandleSetUseOrbit(const SetCameraUseOrbitIntent& intent); + void HandleSetYaw(const SetCameraYawIntent& intent); + void HandleSetPitch(const SetCameraPitchIntent& intent); + void HandleSetNearPlane(const SetCameraNearPlaneIntent& intent); + void HandleSetFarPlane(const SetCameraFarPlaneIntent& intent); + void HandleSetFov(const SetCameraFovIntent& intent); + void HandleSetSpeed(const SetCameraSpeedIntent& intent); + void HandleSetSensitivity(const SetCameraSensitivityIntent& intent); + void HandleSetDistance(const SetCameraDistanceIntent& intent); + private: + ISelectionApi* _selectionApi = nullptr; + ICameraApi* _cameraApi = nullptr; + CameraState _state; + + DragInteraction _orthoSizeDrag; + DragInteraction _yawDrag; + DragInteraction _pitchDrag; + DragInteraction _nearPlaneDrag; + DragInteraction _farPlaneDrag; + DragInteraction _fovDrag; + DragInteraction _speedDrag; + DragInteraction _sensitivityDrag; + DragInteraction _distanceDrag; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Core/Tag/TagIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Tag/TagIntent.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Core/Tag/TagIntent.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Tag/TagIntent.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Core/Tag/TagIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Tag/TagIntent.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Core/Tag/TagIntent.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Tag/TagIntent.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Core/Tag/TagState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Tag/TagState.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Core/Tag/TagState.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Tag/TagState.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Core/Tag/TagState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Tag/TagState.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Core/Tag/TagState.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Tag/TagState.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Core/Tag/TagViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Tag/TagViewModel.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Core/Tag/TagViewModel.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Tag/TagViewModel.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Core/Tag/TagViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Tag/TagViewModel.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Core/Tag/TagViewModel.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Tag/TagViewModel.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Core/Transform/TransformCommands.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformCommands.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Core/Transform/TransformCommands.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformCommands.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Core/Transform/TransformCommands.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformCommands.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Core/Transform/TransformCommands.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformCommands.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Core/Transform/TransformIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformIntent.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Core/Transform/TransformIntent.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformIntent.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Core/Transform/TransformIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformIntent.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Core/Transform/TransformIntent.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformIntent.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Core/Transform/TransformState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformState.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Core/Transform/TransformState.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformState.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Core/Transform/TransformState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformState.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Core/Transform/TransformState.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformState.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Core/Transform/TransformViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformViewModel.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Core/Transform/TransformViewModel.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformViewModel.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Core/Transform/TransformViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformViewModel.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Core/Transform/TransformViewModel.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Core/Transform/TransformViewModel.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightCommands.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightCommands.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightCommands.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightCommands.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightCommands.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightCommands.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightCommands.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightCommands.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightIntent.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightIntent.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightIntent.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightIntent.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightIntent.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightIntent.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightState.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightState.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightState.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightState.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightState.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightState.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightViewModel.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightViewModel.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightViewModel.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightViewModel.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/DirectionLight/DirectionLightViewModel.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/DirectionLight/DirectionLightViewModel.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/PointLight/PointLightCommands.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightCommands.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/PointLight/PointLightCommands.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightCommands.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/PointLight/PointLightCommands.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightCommands.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/PointLight/PointLightCommands.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightCommands.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/PointLight/PointLightIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightIntent.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/PointLight/PointLightIntent.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightIntent.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/PointLight/PointLightIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightIntent.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/PointLight/PointLightIntent.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightIntent.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/PointLight/PointLightState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightState.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/PointLight/PointLightState.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightState.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/PointLight/PointLightState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightState.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/PointLight/PointLightState.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightState.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/PointLight/PointLightViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightViewModel.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/PointLight/PointLightViewModel.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightViewModel.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/PointLight/PointLightViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightViewModel.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/PointLight/PointLightViewModel.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/PointLight/PointLightViewModel.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/SpotLight/SpotLightCommands.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightCommands.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/SpotLight/SpotLightCommands.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightCommands.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/SpotLight/SpotLightCommands.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightCommands.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/SpotLight/SpotLightCommands.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightCommands.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/SpotLight/SpotLightIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightIntent.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/SpotLight/SpotLightIntent.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightIntent.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/SpotLight/SpotLightIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightIntent.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/SpotLight/SpotLightIntent.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightIntent.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/SpotLight/SpotLightState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightState.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/SpotLight/SpotLightState.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightState.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/SpotLight/SpotLightState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightState.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/SpotLight/SpotLightState.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightState.h diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/SpotLight/SpotLightViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightViewModel.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/SpotLight/SpotLightViewModel.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightViewModel.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Component/Light/SpotLight/SpotLightViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightViewModel.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Component/Light/SpotLight/SpotLightViewModel.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Light/SpotLight/SpotLightViewModel.h diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderCommands.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderCommands.cpp new file mode 100644 index 00000000..57ac8f2b --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderCommands.cpp @@ -0,0 +1 @@ +#include "BoxColliderCommands.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderCommands.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderCommands.h new file mode 100644 index 00000000..fc94f30f --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderCommands.h @@ -0,0 +1,10 @@ +#pragma once +#include "EditorCore/Command/ComponentChangeCommand.h" +#include "EditorCore/Api/IBoxColliderApi.h" +#include + +namespace Syn +{ + using ChangeBoxColliderHalfExtentsCommand = ComponentChangeCommand; + using ChangeBoxColliderLocalOffsetCommand = ComponentChangeCommand; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderIntent.cpp new file mode 100644 index 00000000..b828172a --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderIntent.cpp @@ -0,0 +1 @@ +#include "BoxColliderIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderIntent.h new file mode 100644 index 00000000..7c661fab --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderIntent.h @@ -0,0 +1,20 @@ +#pragma once +#include +#include + +namespace Syn +{ + struct SetBoxColliderHalfExtentsIntent { + glm::vec3 halfExtents; + bool isDragging; + }; + + struct SetBoxColliderLocalOffsetIntent { + glm::vec3 localOffset; + bool isDragging; + }; + + using BoxColliderIntent = std::variant< + SetBoxColliderHalfExtentsIntent, + SetBoxColliderLocalOffsetIntent>; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderState.cpp new file mode 100644 index 00000000..68bfb01d --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderState.cpp @@ -0,0 +1 @@ +#include "BoxColliderState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderState.h new file mode 100644 index 00000000..24d96d65 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderState.h @@ -0,0 +1,11 @@ +#pragma once +#include + +namespace Syn { + struct BoxColliderState { + bool hasComponent = false; + + glm::vec3 halfExtents; + glm::vec3 localOffset; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderViewModel.cpp new file mode 100644 index 00000000..8a4f6469 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderViewModel.cpp @@ -0,0 +1,65 @@ +#include "BoxColliderViewModel.h" + +namespace Syn +{ + BoxColliderViewModel::BoxColliderViewModel(ISelectionApi* selectionApi, IBoxColliderApi* colliderApi) + : _selectionApi(selectionApi), _colliderApi(colliderApi) + {} + + const BoxColliderState& BoxColliderViewModel::GetState() const + { + return _state; + } + + void BoxColliderViewModel::SyncWithEngine() + { + if (!_selectionApi || !_colliderApi) + return; + + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + + if (activeEntity != NULL_ENTITY && _colliderApi->HasBoxCollider(activeEntity)) + { + _state.hasComponent = true; + + if (!_halfExtentsDrag.IsDragging()) + _state.halfExtents = _colliderApi->GetBoxColliderHalfExtents(activeEntity); + if (!_localOffsetDrag.IsDragging()) + _state.localOffset = _colliderApi->GetBoxColliderLocalOffset(activeEntity); + } + else + { + _state.hasComponent = false; + } + } + + void BoxColliderViewModel::Dispatch(const BoxColliderIntent& intent) + { + std::visit([this](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) HandleSetHalfExtents(arg); + else if constexpr (std::is_same_v) HandleSetLocalOffset(arg); }, intent); + } + + void BoxColliderViewModel::HandleSetHalfExtents(const SetBoxColliderHalfExtentsIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _halfExtentsDrag.Handle(intent.isDragging, intent.halfExtents, _state.halfExtents, + [&](const glm::vec3& v) { _colliderApi->SetBoxColliderHalfExtents(activeEntity, v); }, + [&](const glm::vec3& s, const glm::vec3& e) { return std::make_shared(_colliderApi, activeEntity, s, e); }); + } + + void BoxColliderViewModel::HandleSetLocalOffset(const SetBoxColliderLocalOffsetIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _localOffsetDrag.Handle(intent.isDragging, intent.localOffset, _state.localOffset, + [&](const glm::vec3& v) { _colliderApi->SetBoxColliderLocalOffset(activeEntity, v); }, + [&](const glm::vec3& s, const glm::vec3& e) { return std::make_shared(_colliderApi, activeEntity, s, e); }); + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderViewModel.h new file mode 100644 index 00000000..50e9fa37 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/BoxCollider/BoxColliderViewModel.h @@ -0,0 +1,32 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "EditorCore/Interaction/DragInteraction.h" +#include "BoxColliderState.h" +#include "BoxColliderIntent.h" +#include "BoxColliderCommands.h" +#include "EditorCore/Api/ISelectionApi.h" +#include "EditorCore/Api/IBoxColliderApi.h" + +namespace Syn { + class BoxColliderViewModel : public IViewModel { + public: + BoxColliderViewModel(ISelectionApi* selectionApi, IBoxColliderApi* colliderApi); + ~BoxColliderViewModel() override = default; + + const BoxColliderState& GetState() const override; + void SyncWithEngine() override; + void Dispatch(const BoxColliderIntent& intent) override; + + private: + void HandleSetHalfExtents(const SetBoxColliderHalfExtentsIntent& intent); + void HandleSetLocalOffset(const SetBoxColliderLocalOffsetIntent& intent); + + private: + ISelectionApi* _selectionApi = nullptr; + IBoxColliderApi* _colliderApi = nullptr; + BoxColliderState _state; + + DragInteraction _halfExtentsDrag; + DragInteraction _localOffsetDrag; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderCommands.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderCommands.cpp new file mode 100644 index 00000000..31842310 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderCommands.cpp @@ -0,0 +1 @@ +#include "CapsuleColliderCommands.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderCommands.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderCommands.h new file mode 100644 index 00000000..fdaed01a --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderCommands.h @@ -0,0 +1,11 @@ +#pragma once +#include "EditorCore/Command/ComponentChangeCommand.h" +#include "EditorCore/Api/ICapsuleColliderApi.h" +#include + +namespace Syn +{ + using ChangeCapsuleColliderRadiusCommand = ComponentChangeCommand; + using ChangeCapsuleColliderHalfHeightCommand = ComponentChangeCommand; + using ChangeCapsuleColliderLocalOffsetCommand = ComponentChangeCommand; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderIntent.cpp new file mode 100644 index 00000000..03d0c1db --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderIntent.cpp @@ -0,0 +1 @@ +#include "CapsuleColliderIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderIntent.h new file mode 100644 index 00000000..e4e8efc0 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderIntent.h @@ -0,0 +1,26 @@ +#pragma once +#include +#include + +namespace Syn +{ + struct SetCapsuleColliderRadiusIntent { + float radius; + bool isDragging; + }; + + struct SetCapsuleColliderHalfHeightIntent { + float halfHeight; + bool isDragging; + }; + + struct SetCapsuleColliderLocalOffsetIntent { + glm::vec3 localOffset; + bool isDragging; + }; + + using CapsuleColliderIntent = std::variant< + SetCapsuleColliderRadiusIntent, + SetCapsuleColliderHalfHeightIntent, + SetCapsuleColliderLocalOffsetIntent>; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderState.cpp new file mode 100644 index 00000000..2f21bedc --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderState.cpp @@ -0,0 +1 @@ +#include "CapsuleColliderState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderState.h new file mode 100644 index 00000000..fd19b987 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderState.h @@ -0,0 +1,12 @@ +#pragma once +#include + +namespace Syn { + struct CapsuleColliderState { + bool hasComponent = false; + + float radius; + float halfHeight; + glm::vec3 localOffset; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderViewModel.cpp new file mode 100644 index 00000000..d2db61a6 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderViewModel.cpp @@ -0,0 +1,78 @@ +#include "CapsuleColliderViewModel.h" + +namespace Syn +{ + CapsuleColliderViewModel::CapsuleColliderViewModel(ISelectionApi* selectionApi, ICapsuleColliderApi* colliderApi) + : _selectionApi(selectionApi), _colliderApi(colliderApi) + {} + + const CapsuleColliderState& CapsuleColliderViewModel::GetState() const + { + return _state; + } + + void CapsuleColliderViewModel::SyncWithEngine() + { + if (!_selectionApi || !_colliderApi) + return; + + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + + if (activeEntity != NULL_ENTITY && _colliderApi->HasCapsuleCollider(activeEntity)) + { + _state.hasComponent = true; + + if (!_radiusDrag.IsDragging()) + _state.radius = _colliderApi->GetCapsuleColliderRadius(activeEntity); + if (!_halfHeightDrag.IsDragging()) + _state.halfHeight = _colliderApi->GetCapsuleColliderHalfHeight(activeEntity); + if (!_localOffsetDrag.IsDragging()) + _state.localOffset = _colliderApi->GetCapsuleColliderLocalOffset(activeEntity); + } + else + { + _state.hasComponent = false; + } + } + + void CapsuleColliderViewModel::Dispatch(const CapsuleColliderIntent& intent) + { + std::visit([this](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) HandleSetRadius(arg); + else if constexpr (std::is_same_v) HandleSetHalfHeight(arg); + else if constexpr (std::is_same_v) HandleSetLocalOffset(arg); }, intent); + } + + void CapsuleColliderViewModel::HandleSetRadius(const SetCapsuleColliderRadiusIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _radiusDrag.Handle(intent.isDragging, intent.radius, _state.radius, + [&](const float& v) { _colliderApi->SetCapsuleColliderRadius(activeEntity, v); }, + [&](const float& s, const float& e) { return std::make_shared(_colliderApi, activeEntity, s, e); }); + } + + void CapsuleColliderViewModel::HandleSetHalfHeight(const SetCapsuleColliderHalfHeightIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _halfHeightDrag.Handle(intent.isDragging, intent.halfHeight, _state.halfHeight, + [&](const float& v) { _colliderApi->SetCapsuleColliderHalfHeight(activeEntity, v); }, + [&](const float& s, const float& e) { return std::make_shared(_colliderApi, activeEntity, s, e); }); + } + + void CapsuleColliderViewModel::HandleSetLocalOffset(const SetCapsuleColliderLocalOffsetIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _localOffsetDrag.Handle(intent.isDragging, intent.localOffset, _state.localOffset, + [&](const glm::vec3& v) { _colliderApi->SetCapsuleColliderLocalOffset(activeEntity, v); }, + [&](const glm::vec3& s, const glm::vec3& e) { return std::make_shared(_colliderApi, activeEntity, s, e); }); + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderViewModel.h new file mode 100644 index 00000000..780a85dd --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/CapsuleCollider/CapsuleColliderViewModel.h @@ -0,0 +1,34 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "EditorCore/Interaction/DragInteraction.h" +#include "CapsuleColliderState.h" +#include "CapsuleColliderIntent.h" +#include "CapsuleColliderCommands.h" +#include "EditorCore/Api/ISelectionApi.h" +#include "EditorCore/Api/ICapsuleColliderApi.h" + +namespace Syn { + class CapsuleColliderViewModel : public IViewModel { + public: + CapsuleColliderViewModel(ISelectionApi* selectionApi, ICapsuleColliderApi* colliderApi); + ~CapsuleColliderViewModel() override = default; + + const CapsuleColliderState& GetState() const override; + void SyncWithEngine() override; + void Dispatch(const CapsuleColliderIntent& intent) override; + + private: + void HandleSetRadius(const SetCapsuleColliderRadiusIntent& intent); + void HandleSetHalfHeight(const SetCapsuleColliderHalfHeightIntent& intent); + void HandleSetLocalOffset(const SetCapsuleColliderLocalOffsetIntent& intent); + + private: + ISelectionApi* _selectionApi = nullptr; + ICapsuleColliderApi* _colliderApi = nullptr; + CapsuleColliderState _state; + + DragInteraction _radiusDrag; + DragInteraction _halfHeightDrag; + DragInteraction _localOffsetDrag; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderCommands.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderCommands.cpp new file mode 100644 index 00000000..2f662026 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderCommands.cpp @@ -0,0 +1 @@ +#include "ConvexColliderCommands.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderCommands.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderCommands.h new file mode 100644 index 00000000..afe95a4a --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderCommands.h @@ -0,0 +1,10 @@ +#pragma once +#include "EditorCore/Command/ComponentChangeCommand.h" +#include "EditorCore/Api/IConvexColliderApi.h" +#include + +namespace Syn +{ + using ChangeConvexColliderLocalOffsetCommand = ComponentChangeCommand; + using ChangeConvexColliderTargetLodCommand = ComponentChangeCommand; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderIntent.cpp new file mode 100644 index 00000000..627ab102 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderIntent.cpp @@ -0,0 +1 @@ +#include "ConvexColliderIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderIntent.h new file mode 100644 index 00000000..94dd25a8 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderIntent.h @@ -0,0 +1,20 @@ +#pragma once +#include +#include +#include + +namespace Syn +{ + struct SetConvexColliderTargetLodLevelIntent { + uint32_t targetLodLevel; + }; + + struct SetConvexColliderLocalOffsetIntent { + glm::vec3 localOffset; + bool isDragging; + }; + + using ConvexColliderIntent = std::variant< + SetConvexColliderTargetLodLevelIntent, + SetConvexColliderLocalOffsetIntent>; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderState.cpp new file mode 100644 index 00000000..5df60a64 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderState.cpp @@ -0,0 +1 @@ +#include "ConvexColliderState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderState.h new file mode 100644 index 00000000..1b7bc0b0 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderState.h @@ -0,0 +1,12 @@ +#pragma once +#include +#include + +namespace Syn { + struct ConvexColliderState { + bool hasComponent = false; + + uint32_t targetLodLevel; + glm::vec3 localOffset; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderViewModel.cpp new file mode 100644 index 00000000..ae12c53f --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderViewModel.cpp @@ -0,0 +1,64 @@ +#include "ConvexColliderViewModel.h" + +namespace Syn +{ + ConvexColliderViewModel::ConvexColliderViewModel(ISelectionApi* selectionApi, IConvexColliderApi* colliderApi) + : _selectionApi(selectionApi), _colliderApi(colliderApi) + {} + + const ConvexColliderState& ConvexColliderViewModel::GetState() const + { + return _state; + } + + void ConvexColliderViewModel::SyncWithEngine() + { + if (!_selectionApi || !_colliderApi) + return; + + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + + if (activeEntity != NULL_ENTITY && _colliderApi->HasConvexCollider(activeEntity)) + { + _state.hasComponent = true; + + _state.targetLodLevel = _colliderApi->GetConvexColliderTargetLodLevel(activeEntity); + + if (!_localOffsetDrag.IsDragging()) + _state.localOffset = _colliderApi->GetConvexColliderLocalOffset(activeEntity); + } + else + { + _state.hasComponent = false; + } + } + + void ConvexColliderViewModel::Dispatch(const ConvexColliderIntent& intent) + { + std::visit([this](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) HandleSetTargetLodLevel(arg); + else if constexpr (std::is_same_v) HandleSetLocalOffset(arg); }, intent); + } + + void ConvexColliderViewModel::HandleSetTargetLodLevel(const SetConvexColliderTargetLodLevelIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _state.targetLodLevel = intent.targetLodLevel; + _colliderApi->SetConvexColliderTargetLodLevel(activeEntity, intent.targetLodLevel); + } + + void ConvexColliderViewModel::HandleSetLocalOffset(const SetConvexColliderLocalOffsetIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _localOffsetDrag.Handle(intent.isDragging, intent.localOffset, _state.localOffset, + [&](const glm::vec3& v) { _colliderApi->SetConvexColliderLocalOffset(activeEntity, v); }, + [&](const glm::vec3& s, const glm::vec3& e) { return std::make_shared(_colliderApi, activeEntity, s, e); }); + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderViewModel.h new file mode 100644 index 00000000..b30b2d9e --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/ConvexCollider/ConvexColliderViewModel.h @@ -0,0 +1,31 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "EditorCore/Interaction/DragInteraction.h" +#include "ConvexColliderState.h" +#include "ConvexColliderIntent.h" +#include "ConvexColliderCommands.h" +#include "EditorCore/Api/ISelectionApi.h" +#include "EditorCore/Api/IConvexColliderApi.h" + +namespace Syn { + class ConvexColliderViewModel : public IViewModel { + public: + ConvexColliderViewModel(ISelectionApi* selectionApi, IConvexColliderApi* colliderApi); + ~ConvexColliderViewModel() override = default; + + const ConvexColliderState& GetState() const override; + void SyncWithEngine() override; + void Dispatch(const ConvexColliderIntent& intent) override; + + private: + void HandleSetTargetLodLevel(const SetConvexColliderTargetLodLevelIntent& intent); + void HandleSetLocalOffset(const SetConvexColliderLocalOffsetIntent& intent); + + private: + ISelectionApi* _selectionApi = nullptr; + IConvexColliderApi* _colliderApi = nullptr; + ConvexColliderState _state; + + DragInteraction _localOffsetDrag; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderCommands.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderCommands.cpp new file mode 100644 index 00000000..60b570ed --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderCommands.cpp @@ -0,0 +1 @@ +#include "MeshColliderCommands.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderCommands.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderCommands.h new file mode 100644 index 00000000..91e8ba59 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderCommands.h @@ -0,0 +1,10 @@ +#pragma once +#include "EditorCore/Command/ComponentChangeCommand.h" +#include "EditorCore/Api/IMeshColliderApi.h" +#include + +namespace Syn +{ + using ChangeMeshColliderLocalOffsetCommand = ComponentChangeCommand; + using ChangeMeshColliderTargetLodCommand = ComponentChangeCommand; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderIntent.cpp new file mode 100644 index 00000000..efa5bff1 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderIntent.cpp @@ -0,0 +1 @@ +#include "MeshColliderIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderIntent.h new file mode 100644 index 00000000..9a790c24 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderIntent.h @@ -0,0 +1,20 @@ +#pragma once +#include +#include +#include + +namespace Syn +{ + struct SetMeshColliderTargetLodLevelIntent { + uint32_t targetLodLevel; + }; + + struct SetMeshColliderLocalOffsetIntent { + glm::vec3 localOffset; + bool isDragging; + }; + + using MeshColliderIntent = std::variant< + SetMeshColliderTargetLodLevelIntent, + SetMeshColliderLocalOffsetIntent>; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderState.cpp new file mode 100644 index 00000000..eee2b409 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderState.cpp @@ -0,0 +1 @@ +#include "MeshColliderState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderState.h new file mode 100644 index 00000000..052e432c --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderState.h @@ -0,0 +1,12 @@ +#pragma once +#include +#include + +namespace Syn { + struct MeshColliderState { + bool hasComponent = false; + + uint32_t targetLodLevel; + glm::vec3 localOffset; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderViewModel.cpp new file mode 100644 index 00000000..509866c6 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderViewModel.cpp @@ -0,0 +1,64 @@ +#include "MeshColliderViewModel.h" + +namespace Syn +{ + MeshColliderViewModel::MeshColliderViewModel(ISelectionApi* selectionApi, IMeshColliderApi* colliderApi) + : _selectionApi(selectionApi), _colliderApi(colliderApi) + {} + + const MeshColliderState& MeshColliderViewModel::GetState() const + { + return _state; + } + + void MeshColliderViewModel::SyncWithEngine() + { + if (!_selectionApi || !_colliderApi) + return; + + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + + if (activeEntity != NULL_ENTITY && _colliderApi->HasMeshCollider(activeEntity)) + { + _state.hasComponent = true; + + _state.targetLodLevel = _colliderApi->GetMeshColliderTargetLodLevel(activeEntity); + + if (!_localOffsetDrag.IsDragging()) + _state.localOffset = _colliderApi->GetMeshColliderLocalOffset(activeEntity); + } + else + { + _state.hasComponent = false; + } + } + + void MeshColliderViewModel::Dispatch(const MeshColliderIntent& intent) + { + std::visit([this](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) HandleSetTargetLodLevel(arg); + else if constexpr (std::is_same_v) HandleSetLocalOffset(arg); }, intent); + } + + void MeshColliderViewModel::HandleSetTargetLodLevel(const SetMeshColliderTargetLodLevelIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _state.targetLodLevel = intent.targetLodLevel; + _colliderApi->SetMeshColliderTargetLodLevel(activeEntity, intent.targetLodLevel); + } + + void MeshColliderViewModel::HandleSetLocalOffset(const SetMeshColliderLocalOffsetIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _localOffsetDrag.Handle(intent.isDragging, intent.localOffset, _state.localOffset, + [&](const glm::vec3& v) { _colliderApi->SetMeshColliderLocalOffset(activeEntity, v); }, + [&](const glm::vec3& s, const glm::vec3& e) { return std::make_shared(_colliderApi, activeEntity, s, e); }); + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderViewModel.h new file mode 100644 index 00000000..20b2a7f1 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/MeshCollider/MeshColliderViewModel.h @@ -0,0 +1,31 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "EditorCore/Interaction/DragInteraction.h" +#include "MeshColliderState.h" +#include "MeshColliderIntent.h" +#include "MeshColliderCommands.h" +#include "EditorCore/Api/ISelectionApi.h" +#include "EditorCore/Api/IMeshColliderApi.h" + +namespace Syn { + class MeshColliderViewModel : public IViewModel { + public: + MeshColliderViewModel(ISelectionApi* selectionApi, IMeshColliderApi* colliderApi); + ~MeshColliderViewModel() override = default; + + const MeshColliderState& GetState() const override; + void SyncWithEngine() override; + void Dispatch(const MeshColliderIntent& intent) override; + + private: + void HandleSetTargetLodLevel(const SetMeshColliderTargetLodLevelIntent& intent); + void HandleSetLocalOffset(const SetMeshColliderLocalOffsetIntent& intent); + + private: + ISelectionApi* _selectionApi = nullptr; + IMeshColliderApi* _colliderApi = nullptr; + MeshColliderState _state; + + DragInteraction _localOffsetDrag; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyCommands.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyCommands.cpp new file mode 100644 index 00000000..66760059 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyCommands.cpp @@ -0,0 +1 @@ +#include "RigidBodyCommands.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyCommands.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyCommands.h new file mode 100644 index 00000000..412b1854 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyCommands.h @@ -0,0 +1,10 @@ +#pragma once +#include "EditorCore/Command/ComponentChangeCommand.h" +#include "EditorCore/Api/IRigidBodyApi.h" + +namespace Syn +{ + using ChangeRigidBodyMassCommand = ComponentChangeCommand; + using ChangeRigidBodyFrictionCommand = ComponentChangeCommand; + using ChangeRigidBodyRestitutionCommand = ComponentChangeCommand; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyIntent.cpp new file mode 100644 index 00000000..46c8a1a2 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyIntent.cpp @@ -0,0 +1 @@ +#include "RigidBodyIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyIntent.h new file mode 100644 index 00000000..3231eba9 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyIntent.h @@ -0,0 +1,37 @@ +#pragma once +#include "Engine/Physics/PhysicsTypes.h" +#include +#include + +namespace Syn +{ + struct SetRigidBodyMotionTypeIntent { + PhysicsMotionType motionType; + }; + + struct SetRigidBodyMassIntent { + float mass; + bool isDragging; + }; + + struct SetRigidBodyFrictionIntent { + float friction; + bool isDragging; + }; + + struct SetRigidBodyRestitutionIntent { + float restitution; + bool isDragging; + }; + + struct SetRigidBodyLayerIntent { + uint32_t layer; + }; + + using RigidBodyIntent = std::variant< + SetRigidBodyMotionTypeIntent, + SetRigidBodyMassIntent, + SetRigidBodyFrictionIntent, + SetRigidBodyRestitutionIntent, + SetRigidBodyLayerIntent>; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyState.cpp new file mode 100644 index 00000000..5abe9de2 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyState.cpp @@ -0,0 +1 @@ +#include "RigidBodyState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyState.h new file mode 100644 index 00000000..ae8e04f9 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyState.h @@ -0,0 +1,15 @@ +#pragma once +#include "Engine/Physics/PhysicsTypes.h" +#include + +namespace Syn { + struct RigidBodyState { + bool hasComponent = false; + + PhysicsMotionType motionType; + float mass; + float friction; + float restitution; + uint32_t layer; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyViewModel.cpp new file mode 100644 index 00000000..9816d7fb --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyViewModel.cpp @@ -0,0 +1,101 @@ +#include "RigidBodyViewModel.h" + +namespace Syn +{ + RigidBodyViewModel::RigidBodyViewModel(ISelectionApi* selectionApi, IRigidBodyApi* rigidBodyApi) + : _selectionApi(selectionApi), _rigidBodyApi(rigidBodyApi) + {} + + const RigidBodyState& RigidBodyViewModel::GetState() const + { + return _state; + } + + void RigidBodyViewModel::SyncWithEngine() + { + if (!_selectionApi || !_rigidBodyApi) + return; + + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + + if (activeEntity != NULL_ENTITY && _rigidBodyApi->HasRigidBody(activeEntity)) + { + _state.hasComponent = true; + + _state.motionType = _rigidBodyApi->GetRigidBodyMotionType(activeEntity); + _state.layer = _rigidBodyApi->GetRigidBodyLayer(activeEntity); + + if (!_massDrag.IsDragging()) + _state.mass = _rigidBodyApi->GetRigidBodyMass(activeEntity); + if (!_frictionDrag.IsDragging()) + _state.friction = _rigidBodyApi->GetRigidBodyFriction(activeEntity); + if (!_restitutionDrag.IsDragging()) + _state.restitution = _rigidBodyApi->GetRigidBodyRestitution(activeEntity); + } + else + { + _state.hasComponent = false; + } + } + + void RigidBodyViewModel::Dispatch(const RigidBodyIntent& intent) + { + std::visit([this](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) HandleSetMotionType(arg); + else if constexpr (std::is_same_v) HandleSetMass(arg); + else if constexpr (std::is_same_v) HandleSetFriction(arg); + else if constexpr (std::is_same_v) HandleSetRestitution(arg); + else if constexpr (std::is_same_v) HandleSetLayer(arg); }, intent); + } + + void RigidBodyViewModel::HandleSetMotionType(const SetRigidBodyMotionTypeIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _state.motionType = intent.motionType; + _rigidBodyApi->SetRigidBodyMotionType(activeEntity, intent.motionType); + } + + void RigidBodyViewModel::HandleSetLayer(const SetRigidBodyLayerIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _state.layer = intent.layer; + _rigidBodyApi->SetRigidBodyLayer(activeEntity, intent.layer); + } + + void RigidBodyViewModel::HandleSetMass(const SetRigidBodyMassIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _massDrag.Handle(intent.isDragging, intent.mass, _state.mass, + [&](const float& v) { _rigidBodyApi->SetRigidBodyMass(activeEntity, v); }, + [&](const float& s, const float& e) { return std::make_shared(_rigidBodyApi, activeEntity, s, e); }); + } + + void RigidBodyViewModel::HandleSetFriction(const SetRigidBodyFrictionIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _frictionDrag.Handle(intent.isDragging, intent.friction, _state.friction, + [&](const float& v) { _rigidBodyApi->SetRigidBodyFriction(activeEntity, v); }, + [&](const float& s, const float& e) { return std::make_shared(_rigidBodyApi, activeEntity, s, e); }); + } + + void RigidBodyViewModel::HandleSetRestitution(const SetRigidBodyRestitutionIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _restitutionDrag.Handle(intent.isDragging, intent.restitution, _state.restitution, + [&](const float& v) { _rigidBodyApi->SetRigidBodyRestitution(activeEntity, v); }, + [&](const float& s, const float& e) { return std::make_shared(_rigidBodyApi, activeEntity, s, e); }); + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyViewModel.h new file mode 100644 index 00000000..529408b0 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/RigidBody/RigidBodyViewModel.h @@ -0,0 +1,36 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "EditorCore/Interaction/DragInteraction.h" +#include "RigidBodyState.h" +#include "RigidBodyIntent.h" +#include "RigidBodyCommands.h" +#include "EditorCore/Api/ISelectionApi.h" +#include "EditorCore/Api/IRigidBodyApi.h" + +namespace Syn { + class RigidBodyViewModel : public IViewModel { + public: + RigidBodyViewModel(ISelectionApi* selectionApi, IRigidBodyApi* rigidBodyApi); + ~RigidBodyViewModel() override = default; + + const RigidBodyState& GetState() const override; + void SyncWithEngine() override; + void Dispatch(const RigidBodyIntent& intent) override; + + private: + void HandleSetMotionType(const SetRigidBodyMotionTypeIntent& intent); + void HandleSetMass(const SetRigidBodyMassIntent& intent); + void HandleSetFriction(const SetRigidBodyFrictionIntent& intent); + void HandleSetRestitution(const SetRigidBodyRestitutionIntent& intent); + void HandleSetLayer(const SetRigidBodyLayerIntent& intent); + + private: + ISelectionApi* _selectionApi = nullptr; + IRigidBodyApi* _rigidBodyApi = nullptr; + RigidBodyState _state; + + DragInteraction _massDrag; + DragInteraction _frictionDrag; + DragInteraction _restitutionDrag; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderCommands.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderCommands.cpp new file mode 100644 index 00000000..e18db9f8 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderCommands.cpp @@ -0,0 +1 @@ +#include "SphereColliderCommands.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderCommands.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderCommands.h new file mode 100644 index 00000000..642f66df --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderCommands.h @@ -0,0 +1,10 @@ +#pragma once +#include "EditorCore/Command/ComponentChangeCommand.h" +#include "EditorCore/Api/ISphereColliderApi.h" +#include + +namespace Syn +{ + using ChangeSphereColliderRadiusCommand = ComponentChangeCommand; + using ChangeSphereColliderLocalOffsetCommand = ComponentChangeCommand; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderIntent.cpp new file mode 100644 index 00000000..9f0c196d --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderIntent.cpp @@ -0,0 +1 @@ +#include "SphereColliderIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderIntent.h new file mode 100644 index 00000000..f38509e0 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderIntent.h @@ -0,0 +1,20 @@ +#pragma once +#include +#include + +namespace Syn +{ + struct SetSphereColliderRadiusIntent { + float radius; + bool isDragging; + }; + + struct SetSphereColliderLocalOffsetIntent { + glm::vec3 localOffset; + bool isDragging; + }; + + using SphereColliderIntent = std::variant< + SetSphereColliderRadiusIntent, + SetSphereColliderLocalOffsetIntent>; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderState.cpp new file mode 100644 index 00000000..967632f7 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderState.cpp @@ -0,0 +1 @@ +#include "SphereColliderState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderState.h new file mode 100644 index 00000000..8b5e2593 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderState.h @@ -0,0 +1,11 @@ +#pragma once +#include + +namespace Syn { + struct SphereColliderState { + bool hasComponent = false; + + float radius; + glm::vec3 localOffset; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderViewModel.cpp new file mode 100644 index 00000000..7145e681 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderViewModel.cpp @@ -0,0 +1,65 @@ +#include "SphereColliderViewModel.h" + +namespace Syn +{ + SphereColliderViewModel::SphereColliderViewModel(ISelectionApi* selectionApi, ISphereColliderApi* colliderApi) + : _selectionApi(selectionApi), _colliderApi(colliderApi) + {} + + const SphereColliderState& SphereColliderViewModel::GetState() const + { + return _state; + } + + void SphereColliderViewModel::SyncWithEngine() + { + if (!_selectionApi || !_colliderApi) + return; + + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + + if (activeEntity != NULL_ENTITY && _colliderApi->HasSphereCollider(activeEntity)) + { + _state.hasComponent = true; + + if (!_radiusDrag.IsDragging()) + _state.radius = _colliderApi->GetSphereColliderRadius(activeEntity); + if (!_localOffsetDrag.IsDragging()) + _state.localOffset = _colliderApi->GetSphereColliderLocalOffset(activeEntity); + } + else + { + _state.hasComponent = false; + } + } + + void SphereColliderViewModel::Dispatch(const SphereColliderIntent& intent) + { + std::visit([this](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) HandleSetRadius(arg); + else if constexpr (std::is_same_v) HandleSetLocalOffset(arg); }, intent); + } + + void SphereColliderViewModel::HandleSetRadius(const SetSphereColliderRadiusIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _radiusDrag.Handle(intent.isDragging, intent.radius, _state.radius, + [&](const float& v) { _colliderApi->SetSphereColliderRadius(activeEntity, v); }, + [&](const float& s, const float& e) { return std::make_shared(_colliderApi, activeEntity, s, e); }); + } + + void SphereColliderViewModel::HandleSetLocalOffset(const SetSphereColliderLocalOffsetIntent& intent) + { + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + if (activeEntity == NULL_ENTITY) return; + + _localOffsetDrag.Handle(intent.isDragging, intent.localOffset, _state.localOffset, + [&](const glm::vec3& v) { _colliderApi->SetSphereColliderLocalOffset(activeEntity, v); }, + [&](const glm::vec3& s, const glm::vec3& e) { return std::make_shared(_colliderApi, activeEntity, s, e); }); + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderViewModel.h new file mode 100644 index 00000000..000f489f --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Physics/SphereCollider/SphereColliderViewModel.h @@ -0,0 +1,32 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "EditorCore/Interaction/DragInteraction.h" +#include "SphereColliderState.h" +#include "SphereColliderIntent.h" +#include "SphereColliderCommands.h" +#include "EditorCore/Api/ISelectionApi.h" +#include "EditorCore/Api/ISphereColliderApi.h" + +namespace Syn { + class SphereColliderViewModel : public IViewModel { + public: + SphereColliderViewModel(ISelectionApi* selectionApi, ISphereColliderApi* colliderApi); + ~SphereColliderViewModel() override = default; + + const SphereColliderState& GetState() const override; + void SyncWithEngine() override; + void Dispatch(const SphereColliderIntent& intent) override; + + private: + void HandleSetRadius(const SetSphereColliderRadiusIntent& intent); + void HandleSetLocalOffset(const SetSphereColliderLocalOffsetIntent& intent); + + private: + ISelectionApi* _selectionApi = nullptr; + ISphereColliderApi* _colliderApi = nullptr; + SphereColliderState _state; + + DragInteraction _radiusDrag; + DragInteraction _localOffsetDrag; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationCommands.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationCommands.cpp new file mode 100644 index 00000000..afe978e6 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationCommands.cpp @@ -0,0 +1 @@ +#include "AnimationCommands.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationCommands.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationCommands.h new file mode 100644 index 00000000..cc635cd2 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationCommands.h @@ -0,0 +1,9 @@ +#pragma once +#include "EditorCore/Command/ComponentChangeCommand.h" +#include "EditorCore/Api/IAnimationApi.h" + +namespace Syn +{ + using ChangeAnimationSpeedCommand = ComponentChangeCommand; + using ChangeAnimationIndexCommand = ComponentChangeCommand; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationIntent.cpp new file mode 100644 index 00000000..f30b86d7 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationIntent.cpp @@ -0,0 +1 @@ +#include "AnimationIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationIntent.h new file mode 100644 index 00000000..bcaaee0c --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationIntent.h @@ -0,0 +1,19 @@ +#pragma once +#include +#include + +namespace Syn +{ + struct SetAnimationSpeedIntent + { + float speed; + bool isDragging; + }; + + struct SetAnimationIndexIntent + { + uint32_t animationIndex; + }; + + using AnimationIntent = std::variant; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationState.cpp new file mode 100644 index 00000000..56e2f782 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationState.cpp @@ -0,0 +1 @@ +#include "AnimationState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationState.h new file mode 100644 index 00000000..d429c759 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationState.h @@ -0,0 +1,14 @@ +#pragma once +#include +#include +#include + +namespace Syn { + struct AnimationState { + bool hasComponent = false; + float speed; + uint32_t animationIndex; + + std::vector> availableAnimations; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationViewModel.cpp new file mode 100644 index 00000000..93d1cebd --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationViewModel.cpp @@ -0,0 +1,56 @@ +#include "AnimationViewModel.h" + +namespace Syn +{ + AnimationViewModel::AnimationViewModel(ISelectionApi* selectionApi, IAnimationApi* animApi) + : _selectionApi(selectionApi), _animApi(animApi) {} + + const AnimationState& AnimationViewModel::GetState() const { return _state; } + + void AnimationViewModel::SyncWithEngine() + { + if (!_selectionApi || !_animApi) + return; + + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + + if (activeEntity != NULL_ENTITY && _animApi->HasAnimation(activeEntity)) + { + _state.hasComponent = true; + + if (!_speedDrag.IsDragging()) + _state.speed = _animApi->GetAnimationSpeed(activeEntity); + + _state.animationIndex = _animApi->GetAnimationIndex(activeEntity); + _state.availableAnimations = _animApi->GetAvailableAnimations(); + } + else + { + _state.hasComponent = false; + } + } + + void AnimationViewModel::Dispatch(const AnimationIntent& intent) + { + EntityID active = _selectionApi->GetSelectedEntity(); + if (active == NULL_ENTITY) + return; + + std::visit([this, active](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) { + _speedDrag.Handle(arg.isDragging, arg.speed, _state.speed, + [&](const float& v) { _animApi->SetAnimationSpeed(active, v); }, + [&](const float& s, const float& e) { return std::make_shared(_animApi, active, s, e); }); + } + else if constexpr (std::is_same_v) { + if (_state.animationIndex != arg.animationIndex) { + _state.animationIndex = arg.animationIndex; + _animApi->SetAnimationIndex(active, arg.animationIndex); + } + } + }, intent); + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationViewModel.h new file mode 100644 index 00000000..9e583e32 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Animation/AnimationViewModel.h @@ -0,0 +1,27 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "EditorCore/Interaction/DragInteraction.h" +#include "AnimationState.h" +#include "AnimationIntent.h" +#include "AnimationCommands.h" +#include "EditorCore/Api/ISelectionApi.h" +#include "EditorCore/Api/IAnimationApi.h" + +namespace Syn { + class AnimationViewModel : public IViewModel { + public: + AnimationViewModel(ISelectionApi* selectionApi, IAnimationApi* animApi); + ~AnimationViewModel() override = default; + + const AnimationState& GetState() const override; + void SyncWithEngine() override; + void Dispatch(const AnimationIntent& intent) override; + + private: + ISelectionApi* _selectionApi = nullptr; + IAnimationApi* _animApi = nullptr; + AnimationState _state; + + DragInteraction _speedDrag; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideIntent.cpp new file mode 100644 index 00000000..995d205e --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideIntent.cpp @@ -0,0 +1 @@ +#include "MaterialOverrideIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideIntent.h new file mode 100644 index 00000000..a43d2b6a --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideIntent.h @@ -0,0 +1,21 @@ +#pragma once +#include +#include +#include "EditorCore/Types/EntityHandle.h" + +namespace Syn +{ + struct SetMaterialOverrideSlotIntent { + uint32_t slotIndex; + uint32_t materialId; + }; + + struct SetSharedMaterialEntityIntent { + EntityID sharedEntity; + }; + + using MaterialOverrideIntent = std::variant< + SetMaterialOverrideSlotIntent, + SetSharedMaterialEntityIntent + >; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideState.cpp new file mode 100644 index 00000000..414a88e0 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideState.cpp @@ -0,0 +1 @@ +#include "MaterialOverrideState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideState.h new file mode 100644 index 00000000..3d748cdc --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideState.h @@ -0,0 +1,18 @@ +#pragma once +#include +#include +#include +#include "EditorCore/Types/EntityHandle.h" + +namespace Syn { + struct MaterialOverrideState { + bool hasComponent = false; + + uint32_t expectedSlotCount = 0; + std::vector overrides; + EntityID sharedMaterialEntity = NULL_ENTITY; + + std::vector> availableMaterials; + std::vector> compatibleSharedEntities; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideViewModel.cpp new file mode 100644 index 00000000..07e7c3a6 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideViewModel.cpp @@ -0,0 +1,60 @@ +#include "MaterialOverrideViewModel.h" + +namespace Syn +{ + MaterialOverrideViewModel::MaterialOverrideViewModel(ISelectionApi* selectionApi, IMaterialOverrideApi* overrideApi) + : _selectionApi(selectionApi), _overrideApi(overrideApi) {} + + const MaterialOverrideState& MaterialOverrideViewModel::GetState() const { return _state; } + + void MaterialOverrideViewModel::SyncWithEngine() + { + if (!_selectionApi || !_overrideApi) + return; + + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + + if (activeEntity != NULL_ENTITY && _overrideApi->HasMaterialOverride(activeEntity)) + { + _state.hasComponent = true; + + _state.expectedSlotCount = _overrideApi->GetExpectedSlotCount(activeEntity); + _state.sharedMaterialEntity = _overrideApi->GetSharedMaterialEntity(activeEntity); + _state.availableMaterials = _overrideApi->GetAvailableMaterials(); + //_state.compatibleSharedEntities = _overrideApi->GetCompatibleSharedEntities(activeEntity); + + _state.overrides.clear(); + _state.overrides.reserve(_state.expectedSlotCount); + for (uint32_t i = 0; i < _state.expectedSlotCount; ++i) { + _state.overrides.push_back(_overrideApi->GetMaterialAtSlot(activeEntity, i)); + } + } + else + { + _state.hasComponent = false; + } + } + + void MaterialOverrideViewModel::Dispatch(const MaterialOverrideIntent& intent) + { + EntityID active = _selectionApi->GetSelectedEntity(); + if (active == NULL_ENTITY) + return; + + std::visit([this, active](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) { + if (arg.slotIndex < _state.overrides.size()) { + _state.overrides[arg.slotIndex] = arg.materialId; + _overrideApi->SetMaterialAtSlot(active, arg.slotIndex, arg.materialId); + } + } + else if constexpr (std::is_same_v) { + _state.sharedMaterialEntity = arg.sharedEntity; + _overrideApi->SetSharedMaterialEntity(active, arg.sharedEntity); + } + }, intent); + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideViewModel.h new file mode 100644 index 00000000..9b72bf60 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/MaterialOverride/MaterialOverrideViewModel.h @@ -0,0 +1,23 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "MaterialOverrideState.h" +#include "MaterialOverrideIntent.h" +#include "EditorCore/Api/ISelectionApi.h" +#include "EditorCore/Api/IMaterialOverrideApi.h" + +namespace Syn { + class MaterialOverrideViewModel : public IViewModel { + public: + MaterialOverrideViewModel(ISelectionApi* selectionApi, IMaterialOverrideApi* overrideApi); + ~MaterialOverrideViewModel() override = default; + + const MaterialOverrideState& GetState() const override; + void SyncWithEngine() override; + void Dispatch(const MaterialOverrideIntent& intent) override; + + private: + ISelectionApi* _selectionApi = nullptr; + IMaterialOverrideApi* _overrideApi = nullptr; + MaterialOverrideState _state; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentCommands.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentCommands.cpp new file mode 100644 index 00000000..a07393a3 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentCommands.cpp @@ -0,0 +1 @@ +#include "ModelComponentCommands.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentCommands.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentCommands.h new file mode 100644 index 00000000..1bcdab54 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentCommands.h @@ -0,0 +1,10 @@ +#pragma once +#include "EditorCore/Command/ComponentChangeCommand.h" +#include "EditorCore/Api/IModelComponentApi.h" + +namespace Syn +{ + using ChangeModelCastShadowCommand = ComponentChangeCommand; + using ChangeModelReceiveShadowCommand = ComponentChangeCommand; + using ChangeModelIndexCommand = ComponentChangeCommand; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentIntent.cpp new file mode 100644 index 00000000..7d69b986 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentIntent.cpp @@ -0,0 +1 @@ +#include "ModelComponentIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentIntent.h new file mode 100644 index 00000000..08781419 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentIntent.h @@ -0,0 +1,24 @@ +#pragma once +#include +#include + +namespace Syn +{ + struct SetModelCastShadowIntent { + bool castShadow; + }; + + struct SetModelReceiveShadowIntent { + bool receiveShadow; + }; + + struct SetModelIndexIntent { + uint32_t modelIndex; + }; + + using ModelComponentIntent = std::variant< + SetModelCastShadowIntent, + SetModelReceiveShadowIntent, + SetModelIndexIntent + >; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentState.cpp new file mode 100644 index 00000000..1f182972 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentState.cpp @@ -0,0 +1 @@ +#include "ModelComponentState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentState.h new file mode 100644 index 00000000..e1dd4397 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentState.h @@ -0,0 +1,15 @@ +#pragma once +#include +#include +#include + +namespace Syn { + struct ModelComponentState { + bool hasComponent = false; + bool castShadow; + bool receiveShadow; + uint32_t modelIndex; + + std::vector> availableModels; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentViewModel.cpp new file mode 100644 index 00000000..5b7cc850 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentViewModel.cpp @@ -0,0 +1,59 @@ +#include "ModelComponentViewModel.h" + +namespace Syn +{ + ModelComponentViewModel::ModelComponentViewModel(ISelectionApi* selectionApi, IModelComponentApi* modelApi) + : _selectionApi(selectionApi), _modelApi(modelApi) {} + + const ModelComponentState& ModelComponentViewModel::GetState() const { return _state; } + + void ModelComponentViewModel::SyncWithEngine() + { + if (!_selectionApi || !_modelApi) + return; + + EntityID activeEntity = _selectionApi->GetSelectedEntity(); + + if (activeEntity != NULL_ENTITY && _modelApi->HasModelComponent(activeEntity)) + { + _state.hasComponent = true; + + _state.castShadow = _modelApi->GetCastShadow(activeEntity); + _state.receiveShadow = _modelApi->GetReceiveShadow(activeEntity); + _state.modelIndex = _modelApi->GetModelIndex(activeEntity); + + _state.availableModels = _modelApi->GetAvailableModels(); + } + else + { + _state.hasComponent = false; + } + } + + void ModelComponentViewModel::Dispatch(const ModelComponentIntent& intent) + { + EntityID active = _selectionApi->GetSelectedEntity(); + if (active == NULL_ENTITY) + return; + + std::visit([this, active](auto&& arg) + { + using T = std::decay_t; + + if constexpr (std::is_same_v) { + _state.castShadow = arg.castShadow; + _modelApi->SetCastShadow(active, arg.castShadow); + } + else if constexpr (std::is_same_v) { + _state.receiveShadow = arg.receiveShadow; + _modelApi->SetReceiveShadow(active, arg.receiveShadow); + } + else if constexpr (std::is_same_v) { + if (_state.modelIndex != arg.modelIndex) { + _state.modelIndex = arg.modelIndex; + _modelApi->SetModelIndex(active, arg.modelIndex); + } + } + }, intent); + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentViewModel.h new file mode 100644 index 00000000..447ab425 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Component/Rendering/Model/ModelComponentViewModel.h @@ -0,0 +1,24 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "ModelComponentState.h" +#include "ModelComponentIntent.h" +#include "ModelComponentCommands.h" +#include "EditorCore/Api/ISelectionApi.h" +#include "EditorCore/Api/IModelComponentApi.h" + +namespace Syn { + class ModelComponentViewModel : public IViewModel { + public: + ModelComponentViewModel(ISelectionApi* selectionApi, IModelComponentApi* modelApi); + ~ModelComponentViewModel() override = default; + + const ModelComponentState& GetState() const override; + void SyncWithEngine() override; + void Dispatch(const ModelComponentIntent& intent) override; + + private: + ISelectionApi* _selectionApi = nullptr; + IModelComponentApi* _modelApi = nullptr; + ModelComponentState _state; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/Hierarchy/HierarchyIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Hierarchy/HierarchyIntent.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Hierarchy/HierarchyIntent.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Hierarchy/HierarchyIntent.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Hierarchy/HierarchyIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Hierarchy/HierarchyIntent.h similarity index 76% rename from SynapseEngine/EditorCore/ViewModels/Hierarchy/HierarchyIntent.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Hierarchy/HierarchyIntent.h index 28be95ac..bea9211f 100644 --- a/SynapseEngine/EditorCore/ViewModels/Hierarchy/HierarchyIntent.h +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Hierarchy/HierarchyIntent.h @@ -3,6 +3,7 @@ #include #include #include "EditorCore/Types/EntityHandle.h" +#include "EditorCore/Api/IHierarchyApi.h" namespace Syn { @@ -26,14 +27,26 @@ namespace Syn }; struct HierarchyCreateEntityIntent { - std::string name; + EntityTemplate type; EntityID parent; }; + struct HierarchyCopyEntityIntent { + EntityID entity; + }; + + struct HierarchyFullCopyEntityIntent { + EntityID entity; + }; + struct HierarchyDestroyEntityIntent { EntityID entity; }; + struct HierarchyDestroyKeepChildrenIntent { + EntityID entity; + }; + struct HierarchyRefreshHierarchyIntent { }; @@ -53,7 +66,10 @@ namespace Syn HierarchyToggleVisibilityIntent, HierarchyReparentEntityIntent, HierarchyCreateEntityIntent, + HierarchyCopyEntityIntent, + HierarchyFullCopyEntityIntent, HierarchyDestroyEntityIntent, + HierarchyDestroyKeepChildrenIntent, HierarchyRefreshHierarchyIntent, HierarchySetSearchQueryIntent, HierarchyExpandAllIntent, diff --git a/SynapseEngine/EditorCore/ViewModels/Hierarchy/HierarchyState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Hierarchy/HierarchyState.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Hierarchy/HierarchyState.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Hierarchy/HierarchyState.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Hierarchy/HierarchyState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Hierarchy/HierarchyState.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Hierarchy/HierarchyState.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Hierarchy/HierarchyState.h diff --git a/SynapseEngine/EditorCore/ViewModels/Hierarchy/HierarchyViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Hierarchy/HierarchyViewModel.cpp similarity index 85% rename from SynapseEngine/EditorCore/ViewModels/Hierarchy/HierarchyViewModel.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Hierarchy/HierarchyViewModel.cpp index 48a198b6..ecdb88d3 100644 --- a/SynapseEngine/EditorCore/ViewModels/Hierarchy/HierarchyViewModel.cpp +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Hierarchy/HierarchyViewModel.cpp @@ -50,14 +50,28 @@ namespace Syn { _hierarchyApi->SetParent(arg.child, arg.newParent); } else if constexpr (std::is_same_v) { - EntityID newEnt = _hierarchyApi->CreateEntity(arg.name, arg.parent); + EntityID newEnt = _hierarchyApi->CreateEntity(arg.type, arg.parent); if (arg.parent != NULL_ENTITY) { _expandedNodes.insert(arg.parent); } _selectionApi->SetSelectedEntity(newEnt); } + else if constexpr (std::is_same_v) { + EntityID newEnt = _hierarchyApi->CopyEntity(arg.entity, _hierarchyApi->GetParent(arg.entity)); + _selectionApi->SetSelectedEntity(newEnt); + } + else if constexpr (std::is_same_v) { + EntityID newEnt = _hierarchyApi->FullCopyEntity(arg.entity, _hierarchyApi->GetParent(arg.entity)); + _selectionApi->SetSelectedEntity(newEnt); + } else if constexpr (std::is_same_v) { - _hierarchyApi->DestroyEntity(arg.entity); + _hierarchyApi->DestroyEntityRecursive(arg.entity); + if (_state.selectedEntity == arg.entity) { + _selectionApi->SetSelectedEntity(NULL_ENTITY); + } + } + else if constexpr (std::is_same_v) { + _hierarchyApi->DestroyEntityKeepChildren(arg.entity); if (_state.selectedEntity == arg.entity) { _selectionApi->SetSelectedEntity(NULL_ENTITY); } diff --git a/SynapseEngine/EditorCore/ViewModels/Hierarchy/HierarchyViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Hierarchy/HierarchyViewModel.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Hierarchy/HierarchyViewModel.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Hierarchy/HierarchyViewModel.h diff --git a/SynapseEngine/EditorCore/ViewModels/Logger/LoggerIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Logger/LoggerIntent.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Logger/LoggerIntent.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Logger/LoggerIntent.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Logger/LoggerIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Logger/LoggerIntent.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Logger/LoggerIntent.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Logger/LoggerIntent.h diff --git a/SynapseEngine/EditorCore/ViewModels/Logger/LoggerState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Logger/LoggerState.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Logger/LoggerState.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Logger/LoggerState.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Logger/LoggerState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Logger/LoggerState.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Logger/LoggerState.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Logger/LoggerState.h diff --git a/SynapseEngine/EditorCore/ViewModels/Logger/LoggerViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Logger/LoggerViewModel.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Logger/LoggerViewModel.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Logger/LoggerViewModel.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Logger/LoggerViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Logger/LoggerViewModel.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Logger/LoggerViewModel.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Logger/LoggerViewModel.h diff --git a/SynapseEngine/EditorCore/ViewModels/Settings/SettingsIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Settings/SettingsIntent.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Settings/SettingsIntent.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Settings/SettingsIntent.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Settings/SettingsIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Settings/SettingsIntent.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Settings/SettingsIntent.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Settings/SettingsIntent.h diff --git a/SynapseEngine/EditorCore/ViewModels/Settings/SettingsState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Settings/SettingsState.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Settings/SettingsState.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Settings/SettingsState.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Settings/SettingsState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Settings/SettingsState.h similarity index 54% rename from SynapseEngine/EditorCore/ViewModels/Settings/SettingsState.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Settings/SettingsState.h index a7fc8f75..78fa34e8 100644 --- a/SynapseEngine/EditorCore/ViewModels/Settings/SettingsState.h +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Settings/SettingsState.h @@ -1,10 +1,14 @@ #pragma once #include "Engine/Scene/Settings/SceneSettings.h" +#include +#include +#include namespace Syn { struct SettingsState { SceneSettings sceneSettings; + std::vector> availableSkyTextures; }; } \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/Settings/SettingsViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Settings/SettingsViewModel.cpp similarity index 92% rename from SynapseEngine/EditorCore/ViewModels/Settings/SettingsViewModel.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Settings/SettingsViewModel.cpp index 5237897a..797e0ec9 100644 --- a/SynapseEngine/EditorCore/ViewModels/Settings/SettingsViewModel.cpp +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Settings/SettingsViewModel.cpp @@ -13,6 +13,7 @@ namespace Syn { void SettingsViewModel::SyncWithEngine() { if (_api) { _state.sceneSettings = _api->GetSceneSettings(); + _state.availableSkyTextures = _api->GetAvailableSkyTextures(); } } diff --git a/SynapseEngine/EditorCore/ViewModels/Settings/SettingsViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Settings/SettingsViewModel.h similarity index 99% rename from SynapseEngine/EditorCore/ViewModels/Settings/SettingsViewModel.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Settings/SettingsViewModel.h index e05b4282..c79058f6 100644 --- a/SynapseEngine/EditorCore/ViewModels/Settings/SettingsViewModel.h +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Settings/SettingsViewModel.h @@ -14,7 +14,6 @@ namespace Syn { void SyncWithEngine() override; void Dispatch(const SettingsIntent& intent) override; - private: ISettingsApi* _api = nullptr; SettingsState _state; diff --git a/SynapseEngine/EditorCore/ViewModels/Viewport/ViewportIntent.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Viewport/ViewportIntent.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Viewport/ViewportIntent.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Viewport/ViewportIntent.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Viewport/ViewportIntent.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Viewport/ViewportIntent.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Viewport/ViewportIntent.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Viewport/ViewportIntent.h diff --git a/SynapseEngine/EditorCore/ViewModels/Viewport/ViewportState.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Viewport/ViewportState.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Viewport/ViewportState.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Viewport/ViewportState.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Viewport/ViewportState.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Viewport/ViewportState.h similarity index 91% rename from SynapseEngine/EditorCore/ViewModels/Viewport/ViewportState.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Viewport/ViewportState.h index 3396ef9c..1a5ba680 100644 --- a/SynapseEngine/EditorCore/ViewModels/Viewport/ViewportState.h +++ b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Viewport/ViewportState.h @@ -20,7 +20,7 @@ namespace Syn { uint32_t height = 0; TextureHandle textureId = InvalidTextureHandle; - std::string currentGroup = RenderTargetGroupNames::Deferred; + std::string currentGroup = RenderTargetGroupNames::Main; std::string currentTarget = RenderTargetNames::Main; std::string currentView = Vk::ImageViewNames::Default; @@ -28,7 +28,7 @@ namespace Syn { bool isFocused = false; ImGuizmo::OPERATION gizmoOperation = ImGuizmo::TRANSLATE; - ImGuizmo::MODE gizmoMode = ImGuizmo::LOCAL; + ImGuizmo::MODE gizmoMode = ImGuizmo::WORLD; bool useSnap = false; glm::vec3 snapTranslate{ 1.0f, 1.0f, 1.0f }; diff --git a/SynapseEngine/EditorCore/ViewModels/Viewport/ViewportViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Viewport/ViewportViewModel.cpp similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Viewport/ViewportViewModel.cpp rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Viewport/ViewportViewModel.cpp diff --git a/SynapseEngine/EditorCore/ViewModels/Viewport/ViewportViewModel.h b/SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Viewport/ViewportViewModel.h similarity index 100% rename from SynapseEngine/EditorCore/ViewModels/Viewport/ViewportViewModel.h rename to SynapseEngine/EditorCore/ViewModels/SceneWorkspace/Viewport/ViewportViewModel.h diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphIntent.cpp b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphIntent.cpp new file mode 100644 index 00000000..d528c720 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphIntent.cpp @@ -0,0 +1 @@ +#include "TextureGraphIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphIntent.h b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphIntent.h new file mode 100644 index 00000000..6704968c --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphIntent.h @@ -0,0 +1,10 @@ +#pragma once +#include + +namespace Syn { + struct DummyTextureGraphIntent {}; + + using TextureGraphIntent = std::variant< + DummyTextureGraphIntent + >; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphState.cpp b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphState.cpp new file mode 100644 index 00000000..54a6ac26 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphState.cpp @@ -0,0 +1 @@ +#include "TextureGraphState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphState.h b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphState.h new file mode 100644 index 00000000..77a25865 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphState.h @@ -0,0 +1,21 @@ +#pragma once +#include +#include +#include "EditorCore/Types/TextureHandle.h" + +namespace Syn { + struct TextureNodeState { + bool isVisible = false; + std::string name = ""; + + uint32_t width = 0; + uint32_t height = 0; + + uint32_t engineTextureId = 0xFFFFFFFF; + TextureHandle textureHandle = InvalidTextureHandle; + }; + + struct TextureGraphState { + TextureNodeState previewNode; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphViewModel.cpp new file mode 100644 index 00000000..47754daa --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphViewModel.cpp @@ -0,0 +1,36 @@ +#include "TextureGraphViewModel.h" + +namespace Syn { + TextureGraphViewModel::TextureGraphViewModel(ITextureApi* textureApi) + : _textureApi(textureApi) + {} + + void TextureGraphViewModel::SyncWithEngine() { + if (!_textureApi) return; + + uint32_t selectedId = _textureApi->GetSelectedTexture(); + + if (selectedId != _lastSelectedId) { + _lastSelectedId = selectedId; + + if (selectedId == 0xFFFFFFFF) { + _state.previewNode.isVisible = false; + _state.previewNode.textureHandle = InvalidTextureHandle; + } + else { + CpuTextureData texData; + if (_textureApi->GetTextureData(selectedId, texData)) { + _state.previewNode.isVisible = true; + _state.previewNode.engineTextureId = selectedId; + _state.previewNode.width = texData.width; + _state.previewNode.height = texData.height; + _state.previewNode.textureHandle = _textureApi->GetTextureHandle(selectedId); + } + } + } + } + + void TextureGraphViewModel::Dispatch(const TextureGraphIntent& intent) { + + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphViewModel.h b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphViewModel.h new file mode 100644 index 00000000..f5c8eeb5 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureGraph/TextureGraphViewModel.h @@ -0,0 +1,22 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "TextureGraphState.h" +#include "TextureGraphIntent.h" +#include "EditorCore/Api/ITextureApi.h" + +namespace Syn { + class TextureGraphViewModel : public IViewModel { + public: + TextureGraphViewModel(ITextureApi* textureApi); + ~TextureGraphViewModel() override = default; + + const TextureGraphState& GetState() const override { return _state; } + + void SyncWithEngine() override; + void Dispatch(const TextureGraphIntent& intent) override; + private: + ITextureApi* _textureApi = nullptr; + uint32_t _lastSelectedId = 0xFFFFFFFF; + TextureGraphState _state; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyIntent.cpp b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyIntent.cpp new file mode 100644 index 00000000..b3141dd4 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyIntent.cpp @@ -0,0 +1 @@ +#include "TextureHierarchyIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyIntent.h b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyIntent.h new file mode 100644 index 00000000..03909a82 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyIntent.h @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include + +namespace Syn { + struct TextureSelectIntent { + uint32_t textureId; + }; + + struct TextureSetSearchQueryIntent { + std::string query; + }; + + struct TextureRefreshIntent {}; + + using TextureHierarchyIntent = std::variant< + TextureSelectIntent, + TextureSetSearchQueryIntent, + TextureRefreshIntent + >; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyState.cpp b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyState.cpp new file mode 100644 index 00000000..1a44fbf6 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyState.cpp @@ -0,0 +1 @@ +#include "TextureHierarchyState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyState.h b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyState.h new file mode 100644 index 00000000..26610592 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyState.h @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include + +#include "EditorCore/Types/TextureHandle.h" + +namespace Syn { + struct TextureNode { + uint32_t id; + std::string name; + std::string path; + std::string icon; + TextureHandle handle = InvalidTextureHandle; + }; + + struct TextureHierarchyState { + std::vector filteredNodes; + uint32_t selectedTexture = 0xFFFFFFFF; + std::string searchQuery = ""; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyViewModel.cpp new file mode 100644 index 00000000..0dfa348d --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyViewModel.cpp @@ -0,0 +1,72 @@ +#include "TextureHierarchyViewModel.h" +#include "Editor/Manager/EditorIcons.h" +#include + +namespace Syn { + TextureHierarchyViewModel::TextureHierarchyViewModel(ITextureApi* textureApi) + : _textureApi(textureApi) + {} + + void TextureHierarchyViewModel::SyncWithEngine() { + if (!_textureApi) return; + + uint64_t currentVersion = _textureApi->GetVersion(); + uint32_t currentSelection = _textureApi->GetSelectedTexture(); + + if (currentVersion != _lastEngineVersion || _isDirty) { + RebuildList(); + _lastEngineVersion = currentVersion; + _isDirty = false; + } + + if (_state.selectedTexture != currentSelection) { + _state.selectedTexture = currentSelection; + } + } + + void TextureHierarchyViewModel::Dispatch(const TextureHierarchyIntent& intent) { + std::visit([this](auto&& arg) { + using T = std::decay_t; + + if constexpr (std::is_same_v) { + if (_textureApi) { + _textureApi->SetSelectedTexture(arg.textureId); + } + } + else if constexpr (std::is_same_v) { + if (_state.searchQuery != arg.query) { + _state.searchQuery = arg.query; + _isDirty = true; + } + } + else if constexpr (std::is_same_v) { + _isDirty = true; + } + }, intent); + } + + void TextureHierarchyViewModel::RebuildList() { + if (!_textureApi) return; + + _state.filteredNodes.clear(); + auto allTextures = _textureApi->GetAllTextures(); + + std::string searchLower = _state.searchQuery; + std::transform(searchLower.begin(), searchLower.end(), searchLower.begin(), ::tolower); + + for (const auto& tex : allTextures) { + std::string nameLower = tex.name; + std::transform(nameLower.begin(), nameLower.end(), nameLower.begin(), ::tolower); + + if (searchLower.empty() || nameLower.find(searchLower) != std::string::npos) { + TextureNode node; + node.id = tex.id; + node.name = tex.name; + node.path = tex.path; + node.handle = tex.handle; + node.icon = SYN_ICON_IMAGE; + _state.filteredNodes.push_back(node); + } + } + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyViewModel.h b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyViewModel.h new file mode 100644 index 00000000..5496b281 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureHierarchy/TextureHierarchyViewModel.h @@ -0,0 +1,26 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "TextureHierarchyState.h" +#include "TextureHierarchyIntent.h" +#include "EditorCore/Api/ITextureApi.h" + +namespace Syn { + class TextureHierarchyViewModel : public IViewModel { + public: + TextureHierarchyViewModel(ITextureApi* textureApi); + ~TextureHierarchyViewModel() override = default; + + const TextureHierarchyState& GetState() const override { return _state; } + void SyncWithEngine() override; + void Dispatch(const TextureHierarchyIntent& intent) override; + + private: + void RebuildList(); + private: + ITextureApi* _textureApi = nullptr; + TextureHierarchyState _state; + + bool _isDirty = true; + uint64_t _lastEngineVersion = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesIntent.cpp b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesIntent.cpp new file mode 100644 index 00000000..56a0c90f --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesIntent.cpp @@ -0,0 +1 @@ +#include "TexturePropertiesIntent.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesIntent.h b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesIntent.h new file mode 100644 index 00000000..d3d6bd02 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesIntent.h @@ -0,0 +1,11 @@ +#pragma once +#include +#include + +namespace Syn { + struct DummyTexturePropertyIntent {}; + + using TexturePropertiesIntent = std::variant< + DummyTexturePropertyIntent + >; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesState.cpp b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesState.cpp new file mode 100644 index 00000000..dcf395b1 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesState.cpp @@ -0,0 +1 @@ +#include "TexturePropertiesState.h" \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesState.h b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesState.h new file mode 100644 index 00000000..e40fc250 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesState.h @@ -0,0 +1,18 @@ +#pragma once +#include "Engine/Image/Data/Cpu/CpuTextureData.h" +#include +#include + +namespace Syn { + struct TexturePropertiesState { + bool hasSelection = false; + std::string textureName = ""; + + uint32_t width = 0; + uint32_t height = 0; + uint32_t depth = 1; + uint32_t mipLevels = 1; + uint32_t format = 0; + bool isCompressed = false; + }; +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesViewModel.cpp b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesViewModel.cpp new file mode 100644 index 00000000..341a5a5f --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesViewModel.cpp @@ -0,0 +1,36 @@ +#include "TexturePropertiesViewModel.h" + +namespace Syn { + TexturePropertiesViewModel::TexturePropertiesViewModel(ITextureApi* textureApi) + : _textureApi(textureApi) + {} + + void TexturePropertiesViewModel::SyncWithEngine() { + if (!_textureApi) return; + + uint32_t selectedId = _textureApi->GetSelectedTexture(); + + if (selectedId == INVALID_TEXTURE_ID) { + _state.hasSelection = false; + return; + } + + CpuTextureData texData; + if (_textureApi->GetTextureData(selectedId, texData)) { + _state.hasSelection = true; + _state.width = texData.width; + _state.height = texData.height; + _state.depth = texData.depth; + _state.mipLevels = texData.mipLevels; + _state.format = static_cast(texData.format); + _state.isCompressed = texData.isCompressed; + } + else { + _state.hasSelection = false; + } + } + + void TexturePropertiesViewModel::Dispatch(const TexturePropertiesIntent& intent) { + + } +} \ No newline at end of file diff --git a/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesViewModel.h b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesViewModel.h new file mode 100644 index 00000000..ce8083b9 --- /dev/null +++ b/SynapseEngine/EditorCore/ViewModels/TextureWorkspace/TextureProperties/TexturePropertiesViewModel.h @@ -0,0 +1,20 @@ +#pragma once +#include "EditorCore/ViewModels/IViewModel.h" +#include "TexturePropertiesState.h" +#include "TexturePropertiesIntent.h" +#include "EditorCore/Api/ITextureApi.h" + +namespace Syn { + class TexturePropertiesViewModel : public IViewModel { + public: + TexturePropertiesViewModel(ITextureApi* textureApi); + ~TexturePropertiesViewModel() override = default; + + const TexturePropertiesState& GetState() const override { return _state; } + void SyncWithEngine() override; + void Dispatch(const TexturePropertiesIntent& intent) override; + private: + ITextureApi* _textureApi = nullptr; + TexturePropertiesState _state; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Animation/AnimationManager.cpp b/SynapseEngine/Engine/Animation/AnimationManager.cpp index aaf4063d..a0bc0fc0 100644 --- a/SynapseEngine/Engine/Animation/AnimationManager.cpp +++ b/SynapseEngine/Engine/Animation/AnimationManager.cpp @@ -79,7 +79,8 @@ namespace Syn { safeEntry.stagingBuffer.reset(); SetResourceState(entryId, ResourceState::Ready); - _version.fetch_add(1, std::memory_order_release); + MarkDirty(entryId); + Info("Animation loaded, extracted, and RAM freed: {}", safeEntry.path); }, .needsGraphics = false @@ -90,28 +91,32 @@ namespace Syn { void AnimationManager::FinalizeResource(EntryType& entry) { - uint32_t entryIndex = _pathToId.at(entry.path); - auto& gpuData = *(entry.resource->transientGpuData); auto& cpuData = entry.resource->cpuData; _cpuExtractor->Extract(gpuData, cpuData); - GpuAnimationAddresses addresses{}; - const auto& hw = entry.resource->hardwareBuffers; + entry.resource->transientGpuData.reset(); + entry.resource->transientCpuData.reset(); + } + + void AnimationManager::FlushDirtyResources() + { + ProcessDirtyReadyEntries([this](uint32_t index, const EntryType& entry) { + GpuAnimationAddresses addresses{}; + const auto& hw = entry.resource->hardwareBuffers; - addresses.vertexSkinData = hw.vertexSkinData->GetDeviceAddress(); - addresses.nodeTransforms = hw.nodeTransforms->GetDeviceAddress(); - addresses.frameGlobalColliders = hw.frameGlobalColliders->GetDeviceAddress(); - addresses.frameMeshColliders = hw.frameMeshColliders->GetDeviceAddress(); - addresses.frameMeshletColliders = hw.frameMeshletColliders->GetDeviceAddress(); - addresses.descriptor = entry.resource->cpuData.descriptor; - addresses.globalCollider = entry.resource->cpuData.globalCollider; - addresses.isReady = 1; + addresses.vertexSkinData = hw.vertexSkinData->GetDeviceAddress(); + addresses.nodeTransforms = hw.nodeTransforms->GetDeviceAddress(); + addresses.frameGlobalColliders = hw.frameGlobalColliders->GetDeviceAddress(); + addresses.frameMeshColliders = hw.frameMeshColliders->GetDeviceAddress(); + addresses.frameMeshletColliders = hw.frameMeshletColliders->GetDeviceAddress(); - WriteAddress(entryIndex, addresses); + addresses.descriptor = entry.resource->cpuData.descriptor; + addresses.globalCollider = entry.resource->cpuData.globalCollider; + addresses.isReady = 1; - entry.resource->transientGpuData.reset(); - entry.resource->transientCpuData.reset(); + WriteAddress(index, addresses); + }); } } \ No newline at end of file diff --git a/SynapseEngine/Engine/Animation/AnimationManager.h b/SynapseEngine/Engine/Animation/AnimationManager.h index 7f0cd44f..02edcbce 100644 --- a/SynapseEngine/Engine/Animation/AnimationManager.h +++ b/SynapseEngine/Engine/Animation/AnimationManager.h @@ -24,6 +24,7 @@ namespace Syn { protected: void StartGpuUpload(EntryType& entry) override; void FinalizeResource(EntryType& entry) override; + void FlushDirtyResources() override; private: std::shared_ptr _builder; std::unique_ptr _uploader; diff --git a/SynapseEngine/Engine/Component/Components.h b/SynapseEngine/Engine/Component/Components.h index 39822504..2b764475 100644 --- a/SynapseEngine/Engine/Component/Components.h +++ b/SynapseEngine/Engine/Component/Components.h @@ -11,6 +11,8 @@ #include "Physics/BoxColliderComponent.h" #include "Physics/SphereColliderComponent.h" #include "Physics/CapsuleColliderComponent.h" +#include "Physics/ConvexColliderComponent.h" +#include "Physics/MeshColliderComponent.h" #include "Physics/RigidBodyComponent.h" #include "Rendering/ModelComponent.h" #include "Rendering/MaterialOverrideComponent.h" diff --git a/SynapseEngine/Engine/Component/Core/CameraComponent.cpp b/SynapseEngine/Engine/Component/Core/CameraComponent.cpp index 96596f94..a8ba9ba7 100644 --- a/SynapseEngine/Engine/Component/Core/CameraComponent.cpp +++ b/SynapseEngine/Engine/Component/Core/CameraComponent.cpp @@ -15,6 +15,9 @@ namespace Syn , position{ 0.f, 0.f, 0.f } , target{ 0.f, 0.f, -1.f } , up{ 0.f, 1.f, 0.f } + , useOrbit(false) + , isOrthographic{ false } + , orthoSize{ 100.f } { direction = glm::normalize(target - position); right = glm::normalize(glm::cross(direction, up)); diff --git a/SynapseEngine/Engine/Component/Core/CameraComponent.h b/SynapseEngine/Engine/Component/Core/CameraComponent.h index b911a22b..496d69ee 100644 --- a/SynapseEngine/Engine/Component/Core/CameraComponent.h +++ b/SynapseEngine/Engine/Component/Core/CameraComponent.h @@ -22,6 +22,10 @@ namespace Syn float sensitivity; float distance; + bool isOrthographic; + float orthoSize; + bool useOrbit; + glm::vec3 up; glm::vec3 target; glm::vec3 position; diff --git a/SynapseEngine/Engine/Component/Core/TagComponent.cpp b/SynapseEngine/Engine/Component/Core/TagComponent.cpp index e85b4e14..267f3131 100644 --- a/SynapseEngine/Engine/Component/Core/TagComponent.cpp +++ b/SynapseEngine/Engine/Component/Core/TagComponent.cpp @@ -5,7 +5,8 @@ namespace Syn TagComponent::TagComponent() : name("Entity"), tag("Untagged"), - enabled(true) + localEnabled(true), + globalEnabled(true) {} TagComponent::TagComponent(const std::string& name, const std::string& tag) : diff --git a/SynapseEngine/Engine/Component/Core/TagComponent.h b/SynapseEngine/Engine/Component/Core/TagComponent.h index 2823bbe3..da52130d 100644 --- a/SynapseEngine/Engine/Component/Core/TagComponent.h +++ b/SynapseEngine/Engine/Component/Core/TagComponent.h @@ -12,6 +12,8 @@ namespace Syn std::string name; std::string tag; - bool enabled; + + bool localEnabled = true; + bool globalEnabled = true; }; } \ No newline at end of file diff --git a/SynapseEngine/Engine/Component/Rendering/ModelComponent.cpp b/SynapseEngine/Engine/Component/Rendering/ModelComponent.cpp index 05adb0d6..3cda4864 100644 --- a/SynapseEngine/Engine/Component/Rendering/ModelComponent.cpp +++ b/SynapseEngine/Engine/Component/Rendering/ModelComponent.cpp @@ -5,7 +5,6 @@ namespace Syn ModelComponent::ModelComponent() : castShadow(true), receiveShadow(true), - hasDirectxNormals(false), modelIndex(UINT32_MAX) {} @@ -17,7 +16,6 @@ namespace Syn uint32_t flags = 0; if (component.castShadow) flags |= (1 << 0); if (component.receiveShadow) flags |= (1 << 1); - if (component.hasDirectxNormals) flags |= (1 << 2); this->flags = flags; } } \ No newline at end of file diff --git a/SynapseEngine/Engine/Component/Rendering/ModelComponent.h b/SynapseEngine/Engine/Component/Rendering/ModelComponent.h index a72814d3..dd0185ff 100644 --- a/SynapseEngine/Engine/Component/Rendering/ModelComponent.h +++ b/SynapseEngine/Engine/Component/Rendering/ModelComponent.h @@ -11,7 +11,6 @@ namespace Syn bool castShadow; bool receiveShadow; - bool hasDirectxNormals; uint32_t modelIndex; uint32_t materialOffset = UINT32_MAX; }; diff --git a/SynapseEngine/Engine/Engine.cpp b/SynapseEngine/Engine/Engine.cpp index 84fc4ea1..6b9bcb3c 100644 --- a/SynapseEngine/Engine/Engine.cpp +++ b/SynapseEngine/Engine/Engine.cpp @@ -7,6 +7,7 @@ #include "Vk/Buffer/SynVkBuffer.h" #include "Vk/Rendering/GpuUploader.h" +#include "Engine/Scene/SceneNames.h" #include "Engine/Manager/ResourceManager.h" #include "Engine/Manager/ShaderManager.h" #include "Engine/Mesh/Builder/StaticMeshBuilder.h" @@ -26,7 +27,8 @@ #include "Engine/Logger/LogUtils.h" #include "Engine/Scene/SceneManager.h" #include "Engine/Scene/Source/Procedural/TestSceneSource.h" -#include "Engine/Scene/Source/Procedural/NatureSceneSource.h" +#include "Engine/Scene/Source/Procedural/MaterialPreviewSceneSource.h" +#include "Engine/Scene/Source/Procedural/ModelPreviewSceneSource.h" #include "Engine/Scene/Source/File/FileSceneSource.h" #include "Engine/Render/RendererFactory.h" @@ -34,6 +36,8 @@ #include "Engine/Profiler/DefaultGpuProfiler.h" #include "Engine/Profiler/DefaultCpuProfiler.h" +#include "Engine/Statistics/DefaultRenderStatCollector.h" +#include "Engine/Statistics/FrameStatisticsManager.h" #include "Engine/Serialization/Serializer.h" #include "Engine/Serialization/Archive/DefaultArchiveRegistry.h" @@ -75,10 +79,16 @@ namespace Syn ServiceLocator::GetCpuProfiler()->BeginFrame(currentFrame); + //Updates ServiceLocator::GetAnimationManager()->Update(); ServiceLocator::GetModelManager()->Update(); ServiceLocator::GetMaterialManager()->Update(); ServiceLocator::GetImageManager()->Update(); + + //Notifications + ServiceLocator::GetMaterialManager()->ProcessPendingNotifications(); + ServiceLocator::GetModelManager()->ProcessPendingNotifications(); + ServiceLocator::GetGpuUploader()->ProcessUploads(); _sceneManager->Update(_frameContext.deltaTime, currentFrame); @@ -96,6 +106,7 @@ namespace Syn _renderManager->WaitForFrame(currentFrame); ServiceLocator::GetGpuProfiler()->ResolveFrame(currentFrame); + ServiceLocator::GetFrameStatisticsManager()->ResolveFrame(currentFrame, ServiceLocator::GetRenderStatCollector()); if (_onGuiFlushCallback) _onGuiFlushCallback(currentFrame); @@ -107,6 +118,7 @@ namespace Syn _sceneManager->Finish(); ServiceLocator::GetCpuProfiler()->ResolveFrame(currentFrame); + ServiceLocator::GetPreviewManager()->ClearAllDirtyResources(); AdvanceFrameIndex(); } @@ -210,18 +222,17 @@ namespace Syn _cpuProfiler = std::make_unique(_frameContext.framesInFlight); ServiceLocator::ProvideCpuProfiler(_cpuProfiler.get()); + + _renderStatCollector = std::make_unique(_frameContext.framesInFlight); + ServiceLocator::ProvideRenderStatCollector(_renderStatCollector.get()); + + _frameStatisticsManager = std::make_unique(_frameContext.framesInFlight); + ServiceLocator::ProvideFrameStatisticsManager(_frameStatisticsManager.get()); } void Engine::InitRenderManager(const EngineInitParams& params) { - /* -#ifdef SYN_PERFORMANCE - _renderManager = std::move(RendererFactory::CreatePerformanceRenderer(_frameContext.framesInFlight)); -#else - _renderManager = std::move(RendererFactory::CreateDeferredRenderer(_frameContext.framesInFlight)); -#endif - */ - _renderManager = std::move(RendererFactory::CreateDeferredRenderer(_frameContext.framesInFlight)); + _renderManager = std::move(RendererFactory::CreateSceneRenderer(_frameContext.framesInFlight)); _renderManager->SetGuiRenderCallback(params.onRenderGuiCallback); } @@ -234,6 +245,8 @@ namespace Syn _inputManager.reset(); _gpuProfiler.reset(); _cpuProfiler.reset(); + _renderStatCollector.reset(); + _frameStatisticsManager.reset(); _resourceManager.reset(); _gpuUploader.reset(); _taskExecutor.reset(); @@ -320,17 +333,19 @@ namespace Syn _sceneManager = std::make_unique(std::move(writer), std::move(loader)); ServiceLocator::ProvideSceneManager(_sceneManager.get()); - _sceneManager->RegisterScene("TestLevel", [frames]() { + _sceneManager->RegisterScene(SceneNames::Main, [frames]() { return std::make_unique(frames, std::make_unique()); }); - /* - _sceneManager->RegisterScene("NatureLevel", [frames]() { - return std::make_unique(frames, std::make_unique()); + _sceneManager->RegisterScene(SceneNames::MaterialPreview, [frames]() { + return std::make_unique(frames, std::make_unique()); + }); + + _sceneManager->RegisterScene(SceneNames::ModelPreview, [frames]() { + return std::make_unique(frames, std::make_unique()); }); - */ - _sceneManager->LoadScene("TestLevel"); + _sceneManager->LoadScene(SceneNames::Main); } void Engine::InitPhysicsEngine() @@ -367,7 +382,21 @@ namespace Syn MaterialManager* Engine::GetMaterialManager() { return ServiceLocator::GetMaterialManager(); } + ImageManager* Engine::GetImageManager() { return ServiceLocator::GetImageManager(); } + + ModelManager* Engine::GetModelManager() { + return ServiceLocator::GetModelManager(); + } + + AnimationManager* Engine::GetAnimationManager() { + return ServiceLocator::GetAnimationManager(); + } + + PreviewManager* Engine::GetPreviewManager() + { + return ServiceLocator::GetPreviewManager(); + } } \ No newline at end of file diff --git a/SynapseEngine/Engine/Engine.h b/SynapseEngine/Engine/Engine.h index 8a91cde0..f91e88ae 100644 --- a/SynapseEngine/Engine/Engine.h +++ b/SynapseEngine/Engine/Engine.h @@ -27,6 +27,11 @@ namespace Syn { class Serializer; class MaterialManager; class ImageManager; + class ModelManager; + class AnimationManager; + class IRenderStatCollector; + class FrameStatisticsManager; + class PreviewManager; } namespace Syn @@ -62,6 +67,9 @@ namespace Syn public: MaterialManager* GetMaterialManager(); ImageManager* GetImageManager(); + ModelManager* GetModelManager(); + AnimationManager* GetAnimationManager(); + PreviewManager* GetPreviewManager(); std::shared_ptr GetMemorySink() const { return _memorySink; } private: void Init(const EngineInitParams& params); @@ -93,6 +101,8 @@ namespace Syn std::unique_ptr _cpuProfiler; std::unique_ptr _serializer; std::shared_ptr _memorySink; + std::unique_ptr _renderStatCollector; + std::unique_ptr _frameStatisticsManager; std::function _onGuiFlushCallback; }; diff --git a/SynapseEngine/Engine/Image/ImageManager.cpp b/SynapseEngine/Engine/Image/ImageManager.cpp index a1bc14a8..da1ed6b9 100644 --- a/SynapseEngine/Engine/Image/ImageManager.cpp +++ b/SynapseEngine/Engine/Image/ImageManager.cpp @@ -10,15 +10,20 @@ #include "Engine/Image/Source/Procedural/DefaultImageSource.h" #include "Engine/Vk/Descriptor/DescriptorLayoutBuilder.h"; -namespace Syn { - +namespace Syn +{ ImageManager::ImageManager( + uint32_t framesInFlight, std::shared_ptr builder, std::unique_ptr uploader, - std::unique_ptr cpuExtractor) - : _builder(builder), + std::unique_ptr cpuExtractor, + ImageReadyOrChangedCallback imageReadyCallback) + : AddressResourceManager(framesInFlight, 1024, 256, 512), + _framesInFlight(framesInFlight), + _builder(builder), _uploader(std::move(uploader)), - _cpuExtractor(std::move(cpuExtractor)) + _cpuExtractor(std::move(cpuExtractor)), + _imageReadyOrChangedCallback(std::move(imageReadyCallback)) { InitializeBindlessSetup(); } @@ -45,6 +50,41 @@ namespace Syn { LoadDefaultImageSync(); } + void ImageManager::Update() { + BaseResourceManager::Update(); + + std::lock_guard lock(_staleMutex); + + for (auto it = _staleGpuBuffers.begin(); it != _staleGpuBuffers.end();) { + if (it->framesToLive > 0) { + it->framesToLive--; + ++it; + } + else { + it = _staleGpuBuffers.erase(it); + } + } + + for (auto it = _staleMappedBuffers.begin(); it != _staleMappedBuffers.end();) { + if (it->framesToLive > 0) { + it->framesToLive--; + ++it; + } + else { + it = _staleMappedBuffers.erase(it); + } + } + } + + void ImageManager::RecordSync(VkCommandBuffer cmd) { + if (auto staleBuffers = _bindlessBuffer->RecordSync(cmd); staleBuffers.mapped || staleBuffers.gpu) { + std::lock_guard lock(_staleMutex); + + _staleMappedBuffers.push_back({ staleBuffers.mapped, _framesInFlight }); + _staleGpuBuffers.push_back({ staleBuffers.gpu, _framesInFlight }); + } + } + void ImageManager::CreateSamplers() { { // Linear Repeat @@ -176,6 +216,19 @@ namespace Syn { config.compareOp = VK_COMPARE_OP_LESS; RegisterSampler(SamplerNames::ShadowSampler, config); } + + { + Vk::SamplerConfig config{}; + config.magFilter = VK_FILTER_LINEAR; + config.minFilter = VK_FILTER_LINEAR; + config.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + config.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + config.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + config.borderColor = VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK; + config.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + config.anisotropyEnable = true; + RegisterSampler(SamplerNames::SkyboxSampler, config); + } } uint32_t ImageManager::RegisterSampler(const std::string& name, const Vk::SamplerConfig& config) { @@ -266,8 +319,8 @@ namespace Syn { entry.stagingBuffer.reset(); SetResourceState(entryId, ResourceState::Ready); + MarkDirty(entryId); - _version.fetch_add(1, std::memory_order_release); Info("Image '{}' is ready", entry.path); }, .needsGraphics = needsGraphics @@ -280,16 +333,42 @@ namespace Syn { { _cpuExtractor->Extract(*(entry.resource->transientGpuData), entry.resource->cpuData); - uint32_t descriptorIndex = _pathToId.at(entry.path); - if (descriptorIndex != 0) { - _bindlessBuffer->WriteSampledImage( - BINDING_TEXTURES, - descriptorIndex, - entry.resource->image->GetView() - ); - } - entry.resource->transientCpuData.reset(); entry.resource->transientGpuData.reset(); } + + void ImageManager::FlushDirtyResources() { + //Just to handle bistro test, this will be deleted!! + auto isNormalMap = [](const std::string& path) { + std::string lowerPath = path; + std::transform(lowerPath.begin(), lowerPath.end(), lowerPath.begin(), ::tolower); + return lowerPath.find("_normal") != std::string::npos; + }; + + ProcessDirtyReadyEntries( + [this, &isNormalMap](uint32_t index, const EntryType& entry) { + if (!entry.resource->image) return; + + _bindlessBuffer->WriteSampledImage( + BINDING_TEXTURES, + index, + entry.resource->image->GetView() + ); + + uint32_t samplerIndex = GetSamplerIndex("LinearAniso"); + bool invertTangent = isNormalMap(entry.path); + + uint32_t textureData = (samplerIndex & 0x7FFFFFFF); + if (invertTangent) { + textureData |= (1u << 31); + } + + WriteAddress(index, textureData); + + if (_imageReadyOrChangedCallback) { + _imageReadyOrChangedCallback(index); + } + } + ); + } } \ No newline at end of file diff --git a/SynapseEngine/Engine/Image/ImageManager.h b/SynapseEngine/Engine/Image/ImageManager.h index 71f374e4..e5dab8d3 100644 --- a/SynapseEngine/Engine/Image/ImageManager.h +++ b/SynapseEngine/Engine/Image/ImageManager.h @@ -11,11 +11,14 @@ #include "Engine/Vk/Image/Sampler.h" #include "Engine/Vk/Descriptor/DescriptorPool.h" +#include "Engine/Manager/AddressResourceManager.h" + namespace Syn { using ImageSourceFactory = std::function()>; + using ImageReadyOrChangedCallback = std::function; - class SYN_API ImageManager : public BaseResourceManager { + class SYN_API ImageManager : public AddressResourceManager { public: static constexpr uint32_t MAX_IMAGES = 2048; static constexpr uint32_t MAX_SAMPLERS = 32; @@ -23,12 +26,17 @@ namespace Syn { static constexpr uint32_t BINDING_TEXTURES = 1; ImageManager( + uint32_t framesInFlight, std::shared_ptr builder, std::unique_ptr uploader, - std::unique_ptr cpuExtractor); + std::unique_ptr cpuExtractor, + ImageReadyOrChangedCallback imageReadyCallback = nullptr); ~ImageManager(); + void Update() override; + void RecordSync(VkCommandBuffer cmd); + uint32_t LoadImageAsync(const std::string& filePath); uint32_t LoadImageFromSourceAsync(const std::string& name, ImageSourceFactory factory); @@ -39,7 +47,10 @@ namespace Syn { VkDescriptorSetLayout GetBindlessLayout() const { return _bindlessLayout; } Vk::Sampler* GetSampler(const std::string& name) const; uint32_t GetSamplerIndex(const std::string& name) const; + + const std::unordered_map& GetAvailableSamplers() const { return _samplerNameToIndex; } protected: + void FlushDirtyResources() override; void StartGpuUpload(EntryType& entry) override; void FinalizeResource(EntryType& entry) override; private: @@ -48,9 +59,16 @@ namespace Syn { void LoadDefaultImageSync(); uint32_t RegisterSampler(const std::string& name, const Vk::SamplerConfig& config); private: + ImageReadyOrChangedCallback _imageReadyOrChangedCallback; + std::shared_ptr _builder; std::unique_ptr _uploader; std::unique_ptr _cpuExtractor; + + uint32_t _framesInFlight; + std::mutex _staleMutex; + std::vector _staleGpuBuffers; + std::vector _staleMappedBuffers; VkDescriptorSetLayout _bindlessLayout = VK_NULL_HANDLE; std::unique_ptr _bindlessBuffer; diff --git a/SynapseEngine/Engine/Image/Loader/HdriImageLoader.cpp b/SynapseEngine/Engine/Image/Loader/HdriImageLoader.cpp new file mode 100644 index 00000000..d7138e8a --- /dev/null +++ b/SynapseEngine/Engine/Image/Loader/HdriImageLoader.cpp @@ -0,0 +1,72 @@ +#include "HdriImageLoader.h" +#include +#include +#include "Engine/Logger/SynLog.h" + +namespace Syn +{ + std::optional HdriImageLoader::LoadFile(const std::filesystem::path& path) { + int width, height, originalChannels; + + float* data = stbi_loadf(path.string().c_str(), &width, &height, &originalChannels, STBI_default); + + if (!data) { + Error("Failed to load HDR image: {} - {}", path.string(), stbi_failure_reason()); + return std::nullopt; + } + + return ProcessData(data, width, height, originalChannels); + } + + std::optional HdriImageLoader::LoadMemory(const std::vector& data) { + int width, height, originalChannels; + + float* stbiData = stbi_loadf_from_memory(data.data(), static_cast(data.size()), &width, &height, &originalChannels, STBI_default); + + if (!stbiData) { + Error("HdriImageLoader failed to load HDR image from memory - {}", stbi_failure_reason()); + return std::nullopt; + } + + return ProcessData(stbiData, width, height, originalChannels); + } + + std::optional HdriImageLoader::ProcessData(float* data, int width, int height, int originalChannels) { + + int desiredChannels = 4; + + RawImage rawImage{}; + rawImage.width = static_cast(width); + rawImage.height = static_cast(height); + rawImage.depth = 1; + rawImage.mipLevels = 1; + rawImage.isCompressed = false; + rawImage.format = VK_FORMAT_R32G32B32A32_SFLOAT; + + size_t numPixels = static_cast(width * height); + size_t imageSizeInBytes = numPixels * desiredChannels * sizeof(float); + + rawImage.pixels.resize(imageSizeInBytes); + float* destPixels = reinterpret_cast(rawImage.pixels.data()); + + if (originalChannels == 3) { + for (size_t i = 0; i < numPixels; ++i) { + destPixels[i * 4 + 0] = data[i * 3 + 0]; + destPixels[i * 4 + 1] = data[i * 3 + 1]; + destPixels[i * 4 + 2] = data[i * 3 + 2]; + destPixels[i * 4 + 3] = 1.0f; + } + } + else { + std::memcpy(destPixels, data, imageSizeInBytes); + } + + stbi_image_free(data); + return rawImage; + } + + std::vector HdriImageLoader::GetSupportedExtensions() const + { + return { ".hdr" }; + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Image/Loader/HdriImageLoader.h b/SynapseEngine/Engine/Image/Loader/HdriImageLoader.h new file mode 100644 index 00000000..745dfb9d --- /dev/null +++ b/SynapseEngine/Engine/Image/Loader/HdriImageLoader.h @@ -0,0 +1,19 @@ +#pragma once +#include "IImageLoader.h" +#include + +namespace Syn +{ + class SYN_API HdriImageLoader : public IImageLoader + { + public: + HdriImageLoader() = default; + ~HdriImageLoader() override = default; + + std::optional LoadFile(const std::filesystem::path& path) override; + std::optional LoadMemory(const std::vector& data) override; + std::vector GetSupportedExtensions() const override; + private: + std::optional ProcessData(float* data, int width, int height, int originalChannels); + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Image/Loader/SvgImageLoader.cpp b/SynapseEngine/Engine/Image/Loader/SvgImageLoader.cpp new file mode 100644 index 00000000..81ed8e91 --- /dev/null +++ b/SynapseEngine/Engine/Image/Loader/SvgImageLoader.cpp @@ -0,0 +1,74 @@ +#include "SvgImageLoader.h" +#include "Engine/Logger/SynLog.h" + +#define NANOSVG_IMPLEMENTATION +#include +#define NANOSVGRAST_IMPLEMENTATION +#include + +namespace Syn +{ + std::optional SvgImageLoader::LoadFile(const std::filesystem::path& path) + { + NSVGimage* image = nsvgParseFromFile(path.string().c_str(), "px", 96.0f); + + if (!image) { + Error("Failed to parse SVG file: {}", path.string()); + return std::nullopt; + } + + return ProcessImage(image); + } + + std::optional SvgImageLoader::LoadMemory(const std::vector& data) + { + if (data.empty()) return std::nullopt; + + std::vector mutableData(data.begin(), data.end()); + mutableData.push_back('\0'); + + NSVGimage* image = nsvgParse(mutableData.data(), "px", 96.0f); + + if (!image) { + Error("SvgImageLoader failed to parse SVG from memory"); + return std::nullopt; + } + + return ProcessImage(image); + } + + std::optional SvgImageLoader::ProcessImage(NSVGimage* image) + { + int width = static_cast(image->width); + int height = static_cast(image->height); + + NSVGrasterizer* rast = nsvgCreateRasterizer(); + if (!rast) { + Error("Could not create SVG rasterizer"); + nsvgDelete(image); + return std::nullopt; + } + + RawImage rawImage{}; + rawImage.width = static_cast(width); + rawImage.height = static_cast(height); + rawImage.depth = 1; + rawImage.mipLevels = 1; + rawImage.isCompressed = false; + rawImage.format = VK_FORMAT_R8G8B8A8_UNORM; + + size_t imageSize = static_cast(width * height * 4); + rawImage.pixels.resize(imageSize); + + nsvgRasterize(rast, image, 0.0f, 0.0f, 1.0f, rawImage.pixels.data(), width, height, width * 4); + nsvgDeleteRasterizer(rast); + nsvgDelete(image); + + return rawImage; + } + + std::vector SvgImageLoader::GetSupportedExtensions() const + { + return { ".svg" }; + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Image/Loader/SvgImageLoader.h b/SynapseEngine/Engine/Image/Loader/SvgImageLoader.h new file mode 100644 index 00000000..adcfb339 --- /dev/null +++ b/SynapseEngine/Engine/Image/Loader/SvgImageLoader.h @@ -0,0 +1,21 @@ +#pragma once +#include "IImageLoader.h" + +struct NSVGimage; + +namespace Syn +{ + class SYN_API SvgImageLoader : public IImageLoader + { + public: + SvgImageLoader() = default; + ~SvgImageLoader() override = default; + + std::optional LoadFile(const std::filesystem::path& path) override; + std::optional LoadMemory(const std::vector& data) override; + std::vector GetSupportedExtensions() const override; + + private: + std::optional ProcessImage(struct NSVGimage* image); + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Image/SamplerNames.h b/SynapseEngine/Engine/Image/SamplerNames.h index af02a149..bac61e8a 100644 --- a/SynapseEngine/Engine/Image/SamplerNames.h +++ b/SynapseEngine/Engine/Image/SamplerNames.h @@ -14,5 +14,6 @@ namespace Syn static constexpr const char* MaxReduction = "MaxReduction"; static constexpr const char* BloomSampler = "BloomSampler"; static constexpr const char* ShadowSampler = "ShadowSampler"; + static constexpr const char* SkyboxSampler = "SkyboxSampler"; }; } \ No newline at end of file diff --git a/SynapseEngine/Engine/Manager/BaseResourceManager.h b/SynapseEngine/Engine/Manager/BaseResourceManager.h index e03535c6..74da2200 100644 --- a/SynapseEngine/Engine/Manager/BaseResourceManager.h +++ b/SynapseEngine/Engine/Manager/BaseResourceManager.h @@ -52,11 +52,19 @@ namespace Syn { ResourceState state; }; + struct SnapshotResult { + std::vector snapshots; + uint32_t version; + }; + virtual ~BaseResourceManager() = default; virtual void Update(); + virtual void ProcessPendingNotifications() {} + void WaitForResource(uint32_t id) const; void SetResourceState(uint32_t id, ResourceState newState); + void MarkDirty(uint32_t id); size_t GetResourceCount() const; ResourceState GetEntryState(uint32_t id) const; @@ -64,13 +72,20 @@ namespace Syn { uint32_t GetResourceIndex(const std::string & name) const; std::shared_ptr GetResource(uint32_t id) const; std::shared_ptr GetResource(const std::string & name) const; - std::vector GetResourceSnapshot() const; std::vector GetResourcePaths() const; + + SnapshotResult GetSnapshotAndVersion() const; + std::vector GetResourceSnapshot() const; protected: uint32_t InternalLoadAsync(const std::string & key, std::function()> task); uint32_t InternalLoadSync(const std::string & key, std::function()> task); uint32_t InternalLoad(const std::string & key, std::function()> task, bool isAsync); std::shared_ptr GetResource(uint32_t id, bool internalCall) const; + + virtual void FlushDirtyResources() {} + + template + void ProcessDirtyReadyEntries(Func&& processFunc); protected: void SubmitGpuRequest(const EntryType & entry, Vk::GpuUploadRequest && request); virtual void StartGpuUpload(EntryType & entry) = 0; @@ -81,8 +96,39 @@ namespace Syn { std::vector _entries; std::unordered_map _pathToId; mutable std::recursive_mutex _mutex; + + std::vector _dirtyFlags; + bool _hasDirty = false; }; + template + template + void BaseResourceManager::ProcessDirtyReadyEntries(Func&& processFunc) { + uint32_t count = static_cast(_entries.size()); + if (count == 0) return; + + for (uint32_t i = count; i-- > 0; ) { + if (_dirtyFlags[i]) { + const auto& entry = _entries[i]; + + if (entry.state != ResourceState::Ready) continue; + + processFunc(i, entry); + } + } + } + + template + void BaseResourceManager::MarkDirty(uint32_t id) { + std::lock_guard lock(_mutex); + if (id >= _dirtyFlags.size()) { + _dirtyFlags.resize(id + 1, 0); + } + + _dirtyFlags[id] = 1; + _hasDirty = true; + } + template void BaseResourceManager::Update() { std::lock_guard lock(_mutex); @@ -102,6 +148,15 @@ namespace Syn { } } } + + if (_hasDirty) { + FlushDirtyResources(); + + std::fill(_dirtyFlags.begin(), _dirtyFlags.end(), 0); + _hasDirty = false; + + _version.fetch_add(1, std::memory_order_release); + } } template @@ -166,6 +221,8 @@ namespace Syn { } } + _dirtyFlags.resize(_entries.size(), 0); + return newId; } @@ -222,6 +279,20 @@ namespace Syn { return snapshot; } + template + typename BaseResourceManager::SnapshotResult BaseResourceManager::GetSnapshotAndVersion() const { + std::lock_guard lock(_mutex); + + std::vector snapshots; + snapshots.reserve(_entries.size()); + + for (const auto& entry : _entries) { + snapshots.push_back({ entry.resource, entry.state }); + } + + return { std::move(snapshots), _version.load(std::memory_order_acquire) }; + } + template std::vector BaseResourceManager::GetResourcePaths() const { std::lock_guard lock(_mutex); diff --git a/SynapseEngine/Engine/Manager/ComponentBufferManager.cpp b/SynapseEngine/Engine/Manager/ComponentBufferManager.cpp index 10763ed2..65a3814e 100644 --- a/SynapseEngine/Engine/Manager/ComponentBufferManager.cpp +++ b/SynapseEngine/Engine/Manager/ComponentBufferManager.cpp @@ -9,6 +9,7 @@ namespace Syn void ComponentBufferManager::RegisterBuffer(const std::string& name, uint32_t elementSize, std::function sizeCallback, std::function readyCallback, ComponentMemoryType memoryType) { Vk::BufferConfig config; + config.debugName = name; config.usage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; config.useDeviceAddress = true; diff --git a/SynapseEngine/Engine/Manager/PreviewManager.cpp b/SynapseEngine/Engine/Manager/PreviewManager.cpp new file mode 100644 index 00000000..8a06ba57 --- /dev/null +++ b/SynapseEngine/Engine/Manager/PreviewManager.cpp @@ -0,0 +1,212 @@ +#include "PreviewManager.h" +#include "Engine/Logger/SynLog.h" +#include "Engine/Vk/Image/ImageViewNames.h" + +namespace Syn { + + PreviewManager::PreviewManager(uint32_t initialResolution, uint32_t tileSize) + : _resolution(initialResolution), _tileSize(tileSize), _tilesPerRow(0) + { + CreateOrResizeAtlas(_resolution); + + Vk::ImageConfig colorConfig{}; + colorConfig.width = _tileSize; + colorConfig.height = _tileSize; + colorConfig.type = VK_IMAGE_TYPE_2D; + colorConfig.format = VK_FORMAT_R16G16B16A16_SFLOAT; + colorConfig.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + colorConfig.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + colorConfig.AddView(Vk::ImageViewNames::Default, { .viewType = VK_IMAGE_VIEW_TYPE_2D }); + _scratchColorImage = std::make_unique(colorConfig); + + Vk::ImageConfig bloomConfig{}; + bloomConfig.width = _tileSize; + bloomConfig.height = _tileSize; + bloomConfig.type = VK_IMAGE_TYPE_2D; + bloomConfig.format = VK_FORMAT_R16G16B16A16_SFLOAT; + bloomConfig.usage = VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + bloomConfig.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + bloomConfig.generateMipMaps = true; + bloomConfig.AddView(Vk::ImageViewNames::Default, { + .viewType = VK_IMAGE_VIEW_TYPE_2D, + .perMipViews = true + }); + _scratchBloomImage = std::make_unique(bloomConfig); + } + + uint64_t PreviewManager::GetUniqueId(PreviewResourceType type, uint32_t resourceId) const { + return (static_cast(type) << 32) | resourceId; + } + + void PreviewManager::CreateOrResizeAtlas(uint32_t newResolution) { + uint32_t oldTotalTiles = _tilesPerRow * _tilesPerRow; + + _resolution = newResolution; + _tilesPerRow = _resolution / _tileSize; + uint32_t newTotalTiles = _tilesPerRow * _tilesPerRow; + + Vk::ImageConfig config{}; + config.width = _resolution; + config.height = _resolution; + config.type = VK_IMAGE_TYPE_2D; + config.format = VK_FORMAT_R16G16B16A16_SFLOAT; + config.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + config.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + config.AddView(Vk::ImageViewNames::Default, { .viewType = VK_IMAGE_VIEW_TYPE_2D }); + + _atlasImage = std::make_unique(config); + + Vk::ImageConfig depthConfig{}; + depthConfig.width = _resolution; + depthConfig.height = _resolution; + depthConfig.type = VK_IMAGE_TYPE_2D; + depthConfig.format = VK_FORMAT_D32_SFLOAT; + depthConfig.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; + depthConfig.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + depthConfig.AddView(Vk::ImageViewNames::Default, { .viewType = VK_IMAGE_VIEW_TYPE_2D }); + + _atlasDepthImage = std::make_unique(depthConfig); + + for (uint32_t i = oldTotalTiles; i < newTotalTiles; ++i) { + _freeTiles.push(i); + } + + for (const auto& [id, tileIndex] : _resourceToTile) { + PreviewResourceType type = static_cast(id >> 32); + uint32_t resourceId = static_cast(id & 0xFFFFFFFF); + _dirtyResources[type].insert(resourceId); + } + + Info("PreviewManager: Atlas resized to {}x{}", _resolution, _resolution); + } + + bool PreviewManager::AllocateTile(PreviewResourceType type, uint32_t resourceId) { + std::lock_guard lock(_mutex); + uint64_t id = GetUniqueId(type, resourceId); + + if (_resourceToTile.find(id) != _resourceToTile.end()) return true; + + if (_freeTiles.empty()) { + CreateOrResizeAtlas(_resolution * 2); + } + + uint32_t tileIndex = _freeTiles.front(); + _freeTiles.pop(); + + _resourceToTile[id] = tileIndex; + return true; + } + + void PreviewManager::FreeTile(PreviewResourceType type, uint32_t resourceId) { + std::lock_guard lock(_mutex); + uint64_t id = GetUniqueId(type, resourceId); + auto it = _resourceToTile.find(id); + + if (it != _resourceToTile.end()) { + _freeTiles.push(it->second); + _resourceToTile.erase(it); + _dirtyResources[type].erase(resourceId); + } + } + + bool PreviewManager::HasTile(PreviewResourceType type, uint32_t resourceId) const { + std::lock_guard lock(_mutex); + return _resourceToTile.find(GetUniqueId(type, resourceId)) != _resourceToTile.end(); + } + + void PreviewManager::MarkDirty(PreviewResourceType type, uint32_t resourceId) { + std::lock_guard lock(_mutex); + _dirtyResources[type].insert(resourceId); + } + + std::vector PreviewManager::GetDirtyResources(PreviewResourceType type) { + std::lock_guard lock(_mutex); + auto& dirtySet = _dirtyResources[type]; + return std::vector(dirtySet.begin(), dirtySet.end()); + } + + void PreviewManager::ClearDirtyResources(PreviewResourceType type) { + std::lock_guard lock(_mutex); + _dirtyResources[type].clear(); + } + + void PreviewManager::ClearAllDirtyResources() { + std::lock_guard lock(_mutex); + for (auto& [type, set] : _dirtyResources) { + set.clear(); + } + + if (_warmupFramesRemaining > 0) { + --_warmupFramesRemaining; + for (const auto& [id, tile] : _resourceToTile) { + PreviewResourceType type = static_cast(id >> 32); + _dirtyResources[type].insert(static_cast(id & 0xFFFFFFFF)); + } + } + } + + void PreviewManager::GetViewportAndScissor(PreviewResourceType type, uint32_t resourceId, VkViewport& outViewport, VkRect2D& outScissor) const { + std::lock_guard lock(_mutex); + auto it = _resourceToTile.find(GetUniqueId(type, resourceId)); + if (it == _resourceToTile.end()) return; + + uint32_t tileIndex = it->second; + uint32_t col = tileIndex % _tilesPerRow; + uint32_t row = tileIndex / _tilesPerRow; + + float x = static_cast(col * _tileSize); + float y = static_cast(row * _tileSize); + + outViewport.x = x; + outViewport.y = y; + outViewport.width = static_cast(_tileSize); + outViewport.height = static_cast(_tileSize); + outViewport.minDepth = 0.0f; + outViewport.maxDepth = 1.0f; + + outScissor.offset = { static_cast(x), static_cast(y) }; + outScissor.extent = { _tileSize, _tileSize }; + } + + void PreviewManager::GetNormalizedUVs(PreviewResourceType type, uint32_t resourceId, glm::vec2& outUv0, glm::vec2& outUv1) const { + std::lock_guard lock(_mutex); + auto it = _resourceToTile.find(GetUniqueId(type, resourceId)); + if (it == _resourceToTile.end()) { + outUv0 = glm::vec2(0.0f); outUv1 = glm::vec2(1.0f); + return; + } + + uint32_t tileIndex = it->second; + uint32_t col = tileIndex % _tilesPerRow; + uint32_t row = tileIndex / _tilesPerRow; + + float normalizedTileSize = 1.0f / static_cast(_tilesPerRow); + + outUv0 = glm::vec2(col * normalizedTileSize, row * normalizedTileSize); + outUv1 = glm::vec2((col + 1) * normalizedTileSize, (row + 1) * normalizedTileSize); + } + + std::vector PreviewManager::GetActiveResources(PreviewResourceType type) const { + std::lock_guard lock(_mutex); + std::vector result; + + uint64_t typePrefix = static_cast(type) << 32; + uint64_t typeMask = 0xFFFFFFFF00000000; + + for (const auto& [id, tileIndex] : _resourceToTile) { + if ((id & typeMask) == typePrefix) { + result.push_back(static_cast(id & 0xFFFFFFFF)); + } + } + + return result; + } + + void PreviewManager::MarkAllActiveDirty() { + std::lock_guard lock(_mutex); + for (const auto& [id, tile] : _resourceToTile) { + PreviewResourceType type = static_cast(id >> 32); + _dirtyResources[type].insert(static_cast(id & 0xFFFFFFFF)); + } + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Manager/PreviewManager.h b/SynapseEngine/Engine/Manager/PreviewManager.h new file mode 100644 index 00000000..a238d3dd --- /dev/null +++ b/SynapseEngine/Engine/Manager/PreviewManager.h @@ -0,0 +1,68 @@ +#pragma once +#include "Engine/SynApi.h" +#include "Engine/Vk/Image/Image.h" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Syn { + + enum class PreviewResourceType : uint32_t { + Material = 0, + Model = 1, + Image = 2 + }; + + class SYN_API PreviewManager { + public: + using AtlasResizedCallback = std::function; + + PreviewManager(uint32_t initialResolution = 1024, uint32_t tileSize = 64); + virtual ~PreviewManager() = default; + + bool AllocateTile(PreviewResourceType type, uint32_t resourceId); + void FreeTile(PreviewResourceType type, uint32_t resourceId); + bool HasTile(PreviewResourceType type, uint32_t resourceId) const; + + void MarkAllActiveDirty(); + void MarkDirty(PreviewResourceType type, uint32_t resourceId); + std::vector GetDirtyResources(PreviewResourceType type); + void ClearDirtyResources(PreviewResourceType type); + void ClearAllDirtyResources(); + + void GetViewportAndScissor(PreviewResourceType type, uint32_t resourceId, VkViewport& outViewport, VkRect2D& outScissor) const; + void GetNormalizedUVs(PreviewResourceType type, uint32_t resourceId, glm::vec2& outUv0, glm::vec2& outUv1) const; + + Vk::Image* GetAtlasImage() const { return _atlasImage.get(); } + Vk::Image* GetAtlasDepthImage() const { return _atlasDepthImage.get(); } + Vk::Image* GetScratchColorImage() const { return _scratchColorImage.get(); } + Vk::Image* GetScratchBloomImage() const { return _scratchBloomImage.get(); } + + uint32_t GetResolution() const { return _resolution; } + std::vector GetActiveResources(PreviewResourceType type) const; + private: + void CreateOrResizeAtlas(uint32_t newResolution); + uint64_t GetUniqueId(PreviewResourceType type, uint32_t resourceId) const; + protected: + mutable std::mutex _mutex; + + uint32_t _resolution; + uint32_t _tileSize; + uint32_t _tilesPerRow; + uint32_t _warmupFramesRemaining = 1; + + std::unique_ptr _atlasImage; + std::unique_ptr _atlasDepthImage; + std::unique_ptr _scratchColorImage; + std::unique_ptr _scratchBloomImage; + + std::queue _freeTiles; + std::unordered_map _resourceToTile; + std::unordered_map> _dirtyResources; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Manager/ResourceManager.cpp b/SynapseEngine/Engine/Manager/ResourceManager.cpp index ba3c57ed..ba05b547 100644 --- a/SynapseEngine/Engine/Manager/ResourceManager.cpp +++ b/SynapseEngine/Engine/Manager/ResourceManager.cpp @@ -22,6 +22,8 @@ #include "Engine/Image/Converter/DefaultImageCooker.h" #include "Engine/Image/Loader/StbImageLoader.h" #include "Engine/Image/Loader/GliImageLoader.h" +#include "Engine/Image/Loader/SvgImageLoader.h" +#include "Engine/Image/Loader/HdriImageLoader.h" #include "Engine/Image/Uploader/DefaultGpuImageUploader.h" #include "Engine/Animation/Loader/AnimationLoaderRegistry.h" @@ -44,12 +46,18 @@ namespace Syn { ResourceManager::ResourceManager(uint32_t framesInFlight) : _framesInFlight(framesInFlight) { InitShaderManager(); + InitPreviewManager(); InitImageManager(); InitMaterialManager(); InitModelManager(); InitAnimationManager(); } + void ResourceManager::InitPreviewManager() { + _previewManager = std::make_unique(2048, 128); + ServiceLocator::ProvidePreviewManager(_previewManager.get()); + } + void ResourceManager::InitShaderManager() { _shaderManager = std::make_unique(); @@ -67,13 +75,22 @@ namespace Syn { _imageBuilder->RegisterLoader(std::make_shared(), 1); _imageBuilder->RegisterLoader(std::make_shared(), 1); + _imageBuilder->RegisterLoader(std::make_shared(), 1); + _imageBuilder->RegisterLoader(std::make_shared(), 1); ServiceLocator::ProvideImageBuilder(_imageBuilder.get()); _imageManager = std::make_unique( + _framesInFlight, _imageBuilder, std::make_unique(), - std::make_unique() + std::make_unique(), + [](uint32_t imageId) { + auto matManager = ServiceLocator::GetMaterialManager(); + if (matManager) { + matManager->NotifyImageReady(imageId); + } + } ); ServiceLocator::ProvideImageManager(_imageManager.get()); @@ -85,7 +102,6 @@ namespace Syn { _framesInFlight, [this](const TexturePayload& payload) -> uint32_t { if (payload.IsEmbedded()) { - size_t hash = payload.embeddedData.size(); if (hash > 0) { @@ -104,6 +120,18 @@ namespace Syn { else { return _imageManager->LoadImageAsync(payload.path); } + }, + [this](uint32_t id) { + if (_previewManager) _previewManager->AllocateTile(PreviewResourceType::Material, id); + }, + [this](uint32_t id) { + if (_previewManager) _previewManager->MarkDirty(PreviewResourceType::Material, id); + }, + [](uint32_t materialId) { + auto modelManager = ServiceLocator::GetModelManager(); + if (modelManager) { + modelManager->NotifyMaterialReady(materialId); + } } ); @@ -142,6 +170,12 @@ namespace Syn { std::make_unique(), [this](const std::string& name, const MaterialInfo& info) -> uint32_t { return _materialManager->LoadMaterial(name, info); + }, + [this](uint32_t id) { + if (_previewManager) _previewManager->AllocateTile(PreviewResourceType::Model, id); + }, + [this](uint32_t id) { + if (_previewManager) _previewManager->MarkDirty(PreviewResourceType::Model, id); } ); @@ -199,5 +233,6 @@ namespace Syn { ServiceLocator::ProvideImageBuilder(nullptr); ServiceLocator::ProvideImageManager(nullptr); ServiceLocator::ProvideMaterialManager(nullptr); + } } \ No newline at end of file diff --git a/SynapseEngine/Engine/Manager/ResourceManager.h b/SynapseEngine/Engine/Manager/ResourceManager.h index 0caec36c..2efbad9b 100644 --- a/SynapseEngine/Engine/Manager/ResourceManager.h +++ b/SynapseEngine/Engine/Manager/ResourceManager.h @@ -6,6 +6,7 @@ #include "Engine/Material/MaterialManager.h" #include "Engine/Animation/Builder/AnimationBuilder.h" #include "Engine/Animation/AnimationManager.h" +#include "PreviewManager.h" #include namespace Syn { @@ -23,6 +24,7 @@ namespace Syn { void InitImageManager(); void InitMaterialManager(); void InitAnimationManager(); + void InitPreviewManager(); private: std::unique_ptr _shaderManager; std::unique_ptr _materialManager; @@ -36,6 +38,8 @@ namespace Syn { std::shared_ptr _animationBuilder; std::unique_ptr _animationManager; + std::unique_ptr _previewManager; + uint32_t _framesInFlight; }; } \ No newline at end of file diff --git a/SynapseEngine/Engine/Material/Material.cpp b/SynapseEngine/Engine/Material/Material.cpp index 4c56a53f..7ee56024 100644 --- a/SynapseEngine/Engine/Material/Material.cpp +++ b/SynapseEngine/Engine/Material/Material.cpp @@ -1,4 +1,5 @@ #include "Material.h" +#include "Engine/SynMacro.h" #include namespace Syn { @@ -24,6 +25,20 @@ namespace Syn { { } + SYN_INLINE uint32_t PackTextureAndSampler(uint32_t textureIdx, uint32_t samplerIdx) { + if (textureIdx == UINT32_MAX) + return UINT32_MAX; + + uint32_t tex = textureIdx & 0x00FFFFFF; + uint32_t samp = INVALID_SAMPLER_INDEX; + + if (samplerIdx != UINT32_MAX) { + samp = samplerIdx & 0xFF; + } + + return (samp << 24) | tex; + } + GpuMaterial::GpuMaterial(const Material& material) : color(material.color) , emissiveColor(material.emissiveColor) @@ -32,13 +47,13 @@ namespace Syn { , metalness(material.metalness) , roughness(material.roughness) , aoStrength(material.aoStrength) - , albedoTexture(material.albedoTexture == UINT32_MAX ? UINT32_MAX : material.albedoTexture) - , normalTexture(material.normalTexture == UINT32_MAX ? UINT32_MAX : material.normalTexture) - , metalnessTexture(material.metalnessTexture == UINT32_MAX ? UINT32_MAX : material.metalnessTexture) - , roughnessTexture(material.roughnessTexture == UINT32_MAX ? UINT32_MAX : material.roughnessTexture) - , metallicRoughnessTexture(material.metallicRoughnessTexture == UINT32_MAX ? UINT32_MAX : material.metallicRoughnessTexture) - , emissiveTexture(material.emissiveTexture == UINT32_MAX ? UINT32_MAX : material.emissiveTexture) - , ambientOcclusionTexture(material.ambientOcclusionTexture == UINT32_MAX ? UINT32_MAX : material.ambientOcclusionTexture) + , albedoTexture(PackTextureAndSampler(material.albedoTexture, material.albedoSampler)) + , normalTexture(PackTextureAndSampler(material.normalTexture, material.normalSampler)) + , metalnessTexture(PackTextureAndSampler(material.metalnessTexture, material.metalnessSampler)) + , roughnessTexture(PackTextureAndSampler(material.roughnessTexture, material.roughnessSampler)) + , metallicRoughnessTexture(PackTextureAndSampler(material.metallicRoughnessTexture, material.metallicRoughnessSampler)) + , emissiveTexture(PackTextureAndSampler(material.emissiveTexture, material.emissiveSampler)) + , ambientOcclusionTexture(PackTextureAndSampler(material.ambientOcclusionTexture, material.ambientOcclusionSampler)) , padding0(0) , padding1(0) , padding2(0) @@ -50,5 +65,4 @@ namespace Syn { this->packedFlags = flags; } - } \ No newline at end of file diff --git a/SynapseEngine/Engine/Material/Material.h b/SynapseEngine/Engine/Material/Material.h index 2269ec3a..16b94fa8 100644 --- a/SynapseEngine/Engine/Material/Material.h +++ b/SynapseEngine/Engine/Material/Material.h @@ -6,6 +6,8 @@ namespace Syn { + constexpr uint32_t INVALID_SAMPLER_INDEX = 0xFF; + struct SYN_API Material { glm::vec4 color = glm::vec4(1.0f); glm::vec3 emissiveColor = glm::vec3(0.0f); @@ -18,12 +20,25 @@ namespace Syn bool isTransparent = false; uint32_t albedoTexture = UINT32_MAX; + uint32_t albedoSampler = UINT32_MAX; + uint32_t normalTexture = UINT32_MAX; + uint32_t normalSampler = UINT32_MAX; + uint32_t metalnessTexture = UINT32_MAX; + uint32_t metalnessSampler = UINT32_MAX; + uint32_t roughnessTexture = UINT32_MAX; + uint32_t roughnessSampler = UINT32_MAX; + uint32_t metallicRoughnessTexture = UINT32_MAX; + uint32_t metallicRoughnessSampler = UINT32_MAX; + uint32_t emissiveTexture = UINT32_MAX; + uint32_t emissiveSampler = UINT32_MAX; + uint32_t ambientOcclusionTexture = UINT32_MAX; + uint32_t ambientOcclusionSampler = UINT32_MAX; }; struct SYN_API GpuMaterial { diff --git a/SynapseEngine/Engine/Material/MaterialManager.cpp b/SynapseEngine/Engine/Material/MaterialManager.cpp index 61ee4f81..b7f41215 100644 --- a/SynapseEngine/Engine/Material/MaterialManager.cpp +++ b/SynapseEngine/Engine/Material/MaterialManager.cpp @@ -5,9 +5,17 @@ namespace Syn { - MaterialManager::MaterialManager(uint32_t framesInFlight, TextureLoadCallback textureLoadCallback) + MaterialManager::MaterialManager(uint32_t framesInFlight, + TextureLoadCallback textureLoadCallback, + PreviewAllocateCallback previewAllocateCallback, + PreviewMarkDirtyCallback previewMarkDirtyCallback, + MaterialReadyOrChangedCallback materialReadyOrChangedCallback + ) : AddressResourceManager(framesInFlight, 1024, 1024, 2048) , _textureLoadCallback(std::move(textureLoadCallback)) + , _previewAllocateCallback(std::move(previewAllocateCallback)) + , _previewMarkDirtyCallback(std::move(previewMarkDirtyCallback)) + , _materialReadyOrChangedCallback(std::move(materialReadyOrChangedCallback)) { Material emptyMat; WriteAddress(0, GpuMaterial(emptyMat)); @@ -54,27 +62,13 @@ namespace Syn { void MaterialManager::StartGpuUpload(EntryType& entry) { uint32_t entryIndex = _pathToId.at(entry.path); - size_t offset = entryIndex * sizeof(GpuMaterial); - auto materialGPU = GpuMaterial(*entry.resource); - WriteAddress(entryIndex, materialGPU); - - if (entryIndex >= _renderTypeCache.size()) { - _renderTypeCache.resize(entryIndex + 1, MaterialRenderType::Opaque1Sided); - } - - bool isTrans = entry.resource->isTransparent; - bool isDouble = entry.resource->doubleSided; - - if (isTrans && isDouble) _renderTypeCache[entryIndex] = MaterialRenderType::Transparent2Sided; - else if (isTrans && !isDouble) _renderTypeCache[entryIndex] = MaterialRenderType::Transparent1Sided; - else if (!isTrans && isDouble) _renderTypeCache[entryIndex] = MaterialRenderType::Opaque2Sided; - else _renderTypeCache[entryIndex] = MaterialRenderType::Opaque1Sided; + FinalizeResource(entry); entry.state = ResourceState::Ready; - _version.fetch_add(1, std::memory_order_release); + MarkDirty(entryIndex); - //Info("Material '{}' is ready", entry.path); + Info("Material '{}' is ready", entry.path); } void MaterialManager::LoadDefaultMaterialSync() @@ -84,5 +78,74 @@ namespace Syn { } void MaterialManager::FinalizeResource(EntryType& entry) { + uint32_t index = _pathToId.at(entry.path); + if (_previewAllocateCallback) _previewAllocateCallback(index); + if (_previewMarkDirtyCallback) _previewMarkDirtyCallback(index); + if (_materialReadyOrChangedCallback) _materialReadyOrChangedCallback(index); + } + + void MaterialManager::FlushDirtyResources() + { + ProcessDirtyReadyEntries( + [this](uint32_t index, const EntryType& entry) { + WriteAddress(index, GpuMaterial(*entry.resource)); + + if (_previewMarkDirtyCallback) + _previewMarkDirtyCallback(index); + + if (_materialReadyOrChangedCallback) + _materialReadyOrChangedCallback(index); + } + ); + } + + std::vector MaterialManager::GetMaterialsUsingTexture(uint32_t textureId) const { + std::lock_guard lock(_mutex); + std::vector result; + + for (uint32_t i = 0; i < _entries.size(); ++i) { + if (_entries[i].state == ResourceState::Ready && _entries[i].resource) { + const auto& mat = *_entries[i].resource; + + if (mat.albedoTexture == textureId || + mat.normalTexture == textureId || + mat.metalnessTexture == textureId || + mat.roughnessTexture == textureId || + mat.metallicRoughnessTexture == textureId || + mat.emissiveTexture == textureId || + mat.ambientOcclusionTexture == textureId) + { + result.push_back(i); + } + } + } + return result; + } + + void MaterialManager::NotifyImageReady(uint32_t imageId) { + std::lock_guard lock(_pendingImageMutex); + _pendingImages.insert(imageId); + } + + void MaterialManager::ProcessPendingNotifications() { + std::unordered_set imagesToProcess; + + { + std::lock_guard lock(_pendingImageMutex); + imagesToProcess.swap(_pendingImages); + } + + if (imagesToProcess.empty()) return; + + for (uint32_t imgId : imagesToProcess) { + for (uint32_t matId : GetMaterialsUsingTexture(imgId)) + { + if (_previewMarkDirtyCallback) + _previewMarkDirtyCallback(matId); + + if (_materialReadyOrChangedCallback) + _materialReadyOrChangedCallback(matId); + } + } } } \ No newline at end of file diff --git a/SynapseEngine/Engine/Material/MaterialManager.h b/SynapseEngine/Engine/Material/MaterialManager.h index ab67cca1..7992bf0a 100644 --- a/SynapseEngine/Engine/Material/MaterialManager.h +++ b/SynapseEngine/Engine/Material/MaterialManager.h @@ -6,24 +6,42 @@ #include "Engine/Mesh/Data/Common/MaterialInfo.h" #include "MaterialRenderType.h" +#include + namespace Syn { using TextureLoadCallback = std::function; + using PreviewAllocateCallback = std::function; + using PreviewMarkDirtyCallback = std::function; + using MaterialReadyOrChangedCallback = std::function; class SYN_API MaterialManager : public AddressResourceManager { public: - MaterialManager(uint32_t framesInFlight, TextureLoadCallback textureLoadCallback); + MaterialManager(uint32_t framesInFlight, + TextureLoadCallback textureLoadCallback, + PreviewAllocateCallback previewAllocateCallback = nullptr, + PreviewMarkDirtyCallback previewMarkDirtyCallback = nullptr, + MaterialReadyOrChangedCallback = nullptr + ); ~MaterialManager() = default; uint32_t LoadMaterial(const std::string& name, const MaterialInfo& info); uint32_t LoadMaterialDirect(const std::string& name, const Material& material); - std::span GetRenderTypeSnapshot() const { return _renderTypeCache; } + std::vector GetMaterialsUsingTexture(uint32_t textureId) const; + void NotifyImageReady(uint32_t imageId); + void ProcessPendingNotifications() override; protected: + void FlushDirtyResources() override; void StartGpuUpload(EntryType& entry) override; void FinalizeResource(EntryType& entry) override; private: void LoadDefaultMaterialSync(); private: TextureLoadCallback _textureLoadCallback; - std::vector _renderTypeCache; + PreviewAllocateCallback _previewAllocateCallback; + PreviewMarkDirtyCallback _previewMarkDirtyCallback; + MaterialReadyOrChangedCallback _materialReadyOrChangedCallback; + + std::mutex _pendingImageMutex; + std::unordered_set _pendingImages; }; } \ No newline at end of file diff --git a/SynapseEngine/Engine/Mesh/Converter/DefaultCpuModelExtractor.cpp b/SynapseEngine/Engine/Mesh/Converter/DefaultCpuModelExtractor.cpp index ef0e605c..02bd6f82 100644 --- a/SynapseEngine/Engine/Mesh/Converter/DefaultCpuModelExtractor.cpp +++ b/SynapseEngine/Engine/Mesh/Converter/DefaultCpuModelExtractor.cpp @@ -53,5 +53,6 @@ namespace Syn } outCpuData.indices = gpuData.indexedData.indices; + outCpuData.meshNodeDescriptors = gpuData.meshNodeDescriptors; } } \ No newline at end of file diff --git a/SynapseEngine/Engine/Mesh/Converter/DefaultGpuModelConverter.cpp b/SynapseEngine/Engine/Mesh/Converter/DefaultGpuModelConverter.cpp index 27c1924d..ccc415ac 100644 --- a/SynapseEngine/Engine/Mesh/Converter/DefaultGpuModelConverter.cpp +++ b/SynapseEngine/Engine/Mesh/Converter/DefaultGpuModelConverter.cpp @@ -40,16 +40,20 @@ namespace Syn } } + uint32_t validMeshCounter = 0; for (size_t instanceIdx = 0; instanceIdx < cookedModel.meshNodeDescriptors.size(); ++instanceIdx) { const auto& instanceDesc = cookedModel.meshNodeDescriptors[instanceIdx]; - const uint32_t globalMeshID = globalMeshIdOffset + static_cast(instanceIdx); + if (instanceDesc.meshIndex == 0xFFFF) { + continue; + } + + const uint32_t globalMeshID = globalMeshIdOffset + static_cast(validMeshCounter); const auto& cookedMesh = cookedModel.meshes[instanceDesc.meshIndex]; uint32_t globalNodeIndex = globalNodeOffset + instanceDesc.nodeIndex; const uint32_t currentMeshVertexOffset = static_cast(result.vertexData.vertexPositions.size()); - // MESH COLLIDER BEMÁSOLÁSA GpuMeshCollider localMeshCollider{}; localMeshCollider.center = cookedMesh.collider.sphere.center; localMeshCollider.radius = cookedMesh.collider.sphere.radius; @@ -62,7 +66,6 @@ namespace Syn GpuMeshCollider modelSpaceCollider = MeshUtils::TransformCollider(localMeshCollider, nodeTransform); result.indexedData.meshColliders.push_back(modelSpaceCollider); - // VERTEX ADATOK MÁSOLÁSA ÉS INDEXEK ELTOLÁSA for (const auto& v : cookedMesh.vertices) { GpuVertexPosition pos; @@ -87,7 +90,7 @@ namespace Syn { const auto& lodData = cookedMesh.lods[lodLevel]; - { //Normal + { GpuMeshDescriptor meshDesc{}; meshDesc.vertexOffset = currentMeshVertexOffset; meshDesc.vertexCount = static_cast(cookedMesh.vertices.size()); @@ -103,7 +106,7 @@ namespace Syn } } - { //Mesh Shader + { GpuMeshletDrawDescriptor meshletDrawDesc{}; meshletDrawDesc.meshletOffset = static_cast(result.meshletData.meshletDescriptors.size()); meshletDrawDesc.meshletCount = static_cast(lodData.meshlets.size()); @@ -112,7 +115,6 @@ namespace Syn result.meshletData.drawDescriptors.push_back(meshletDrawDesc); lastValidMeshletDrawDesc = meshletDrawDesc; - // Apró Meshletek Adatainak Másolása for (const auto& cookedMeshlet : lodData.meshlets) { GpuMeshletDescriptor meshletDesc{}; @@ -158,12 +160,15 @@ namespace Syn result.indexedData.lodDescriptors[i].meshCount++; result.indexedData.lodDescriptors[i].indexCount = static_cast(result.indexedData.indices.size()); } + + validMeshCounter++; } result.globalVertexCount = static_cast(result.vertexData.vertexPositions.size()); result.globalIndexCount = static_cast(result.indexedData.indices.size()); result.globalAverageLodIndexCount = result.globalIndexCount / MAX_LODS; result.globalMeshCount = static_cast(result.indexedData.meshDescriptors.size() / 4); + result.meshNodeDescriptors = cookedModel.meshNodeDescriptors; return result; } diff --git a/SynapseEngine/Engine/Mesh/Data/Common/MeshInstanceDescriptor.h b/SynapseEngine/Engine/Mesh/Data/Common/MeshInstanceDescriptor.h index e7223343..7518e073 100644 --- a/SynapseEngine/Engine/Mesh/Data/Common/MeshInstanceDescriptor.h +++ b/SynapseEngine/Engine/Mesh/Data/Common/MeshInstanceDescriptor.h @@ -1,11 +1,13 @@ #pragma once #include "Engine/SynApi.h" #include +#include namespace Syn { struct SYN_API MeshInstanceDescriptor { + std::string name; uint16_t meshIndex; uint16_t nodeIndex; uint16_t parentNodeIndex; diff --git a/SynapseEngine/Engine/Mesh/Data/Cpu/CpuModelData.h b/SynapseEngine/Engine/Mesh/Data/Cpu/CpuModelData.h index 9f60c914..ec5f50a2 100644 --- a/SynapseEngine/Engine/Mesh/Data/Cpu/CpuModelData.h +++ b/SynapseEngine/Engine/Mesh/Data/Cpu/CpuModelData.h @@ -20,6 +20,7 @@ namespace Syn std::vector meshDescriptors; std::vector meshletDrawDescriptors; std::vector lodDescriptors; + std::vector meshNodeDescriptors; std::vector baseDrawCommands; std::vector meshMaterialIndices; diff --git a/SynapseEngine/Engine/Mesh/Data/Gpu/GpuBatchedModel.h b/SynapseEngine/Engine/Mesh/Data/Gpu/GpuBatchedModel.h index 2c6deed2..e57924b4 100644 --- a/SynapseEngine/Engine/Mesh/Data/Gpu/GpuBatchedModel.h +++ b/SynapseEngine/Engine/Mesh/Data/Gpu/GpuBatchedModel.h @@ -5,6 +5,7 @@ #include "GpuMeshletDrawData.h" #include "GpuNodeTransform.h" #include "../Common/MaterialInfo.h" +#include "../Common/MeshInstanceDescriptor.h" namespace Syn { @@ -13,6 +14,7 @@ namespace Syn GpuVertexData vertexData; GpuIndexedDrawData indexedData; GpuMeshletDrawData meshletData; + std::vector meshMaterialIndices; std::vector materials; std::vector nodeTransforms; GpuMeshCollider globalCollider; @@ -20,6 +22,8 @@ namespace Syn uint32_t globalIndexCount = 0; uint32_t globalAverageLodIndexCount = 0; uint32_t globalMeshCount = 0; + + std::vector meshNodeDescriptors; }; } diff --git a/SynapseEngine/Engine/Mesh/Data/Gpu/GpuModelBuffers.h b/SynapseEngine/Engine/Mesh/Data/Gpu/GpuModelBuffers.h index d6d26c93..c487f1a6 100644 --- a/SynapseEngine/Engine/Mesh/Data/Gpu/GpuModelBuffers.h +++ b/SynapseEngine/Engine/Mesh/Data/Gpu/GpuModelBuffers.h @@ -12,6 +12,7 @@ namespace Syn std::unique_ptr vertexPositions; std::unique_ptr vertexAttributes; std::unique_ptr indices; + std::unique_ptr meshMaterialIndices; // Traditional Pipeline Buffers std::unique_ptr meshDescriptors; @@ -34,6 +35,7 @@ namespace Syn VkDeviceAddress vertexPositions; VkDeviceAddress vertexAttributes; VkDeviceAddress indices; + VkDeviceAddress meshMaterialIndices; VkDeviceAddress meshDescriptors; VkDeviceAddress meshColliders; VkDeviceAddress lodDescriptors; @@ -50,8 +52,6 @@ namespace Syn uint32_t averageLodIndexCount; uint32_t meshCount; uint32_t padding0; - uint32_t padding1; - uint32_t padding2; GpuMeshCollider globalCollider; }; diff --git a/SynapseEngine/Engine/Mesh/Loader/AssimpMeshLoader.cpp b/SynapseEngine/Engine/Mesh/Loader/AssimpMeshLoader.cpp index 9e64349f..cbf9aa3a 100644 --- a/SynapseEngine/Engine/Mesh/Loader/AssimpMeshLoader.cpp +++ b/SynapseEngine/Engine/Mesh/Loader/AssimpMeshLoader.cpp @@ -80,20 +80,40 @@ namespace Syn outModel.nodeTransforms.push_back(rawNode); - for (uint32_t i = 0; i < currentNode->mNumMeshes; ++i) + if (currentNode->mNumMeshes == 0) { - uint32_t meshIndex = currentNode->mMeshes[i]; - aiMesh* ai_mesh = scene->mMeshes[meshIndex]; - MeshInstanceDescriptor descriptor{}; - descriptor.meshIndex = static_cast(meshIndex); + descriptor.name = currentNode->mName.C_Str(); + descriptor.meshIndex = UINT16_MAX; descriptor.nodeIndex = nodeIndex; descriptor.parentNodeIndex = parentNodeIndex; - descriptor.vertexCount = ai_mesh->mNumVertices; - descriptor.indexCount = ai_mesh->mNumFaces * 3; - + descriptor.vertexCount = 0; + descriptor.indexCount = 0; outModel.meshNodeDescriptors.push_back(descriptor); } + else + { + for (uint32_t i = 0; i < currentNode->mNumMeshes; ++i) + { + uint32_t meshIndex = currentNode->mMeshes[i]; + aiMesh* ai_mesh = scene->mMeshes[meshIndex]; + MeshInstanceDescriptor descriptor{}; + + descriptor.name = currentNode->mName.C_Str(); + + if (currentNode->mNumMeshes > 1) { + descriptor.name += "_" + std::to_string(i); + } + + descriptor.meshIndex = static_cast(meshIndex); + descriptor.nodeIndex = nodeIndex; + descriptor.parentNodeIndex = parentNodeIndex; + descriptor.vertexCount = ai_mesh->mNumVertices; + descriptor.indexCount = ai_mesh->mNumFaces * 3; + outModel.meshNodeDescriptors.push_back(descriptor); + } + + } for (uint32_t i = 0; i < currentNode->mNumChildren; ++i) queue.push({ currentNode->mChildren[i], nodeIndex }); diff --git a/SynapseEngine/Engine/Mesh/ModelManager.cpp b/SynapseEngine/Engine/Mesh/ModelManager.cpp index 5c7ae925..5248e632 100644 --- a/SynapseEngine/Engine/Mesh/ModelManager.cpp +++ b/SynapseEngine/Engine/Mesh/ModelManager.cpp @@ -15,11 +15,16 @@ namespace Syn { ModelManager::ModelManager(uint32_t framesInFlight, std::shared_ptr builder, std::unique_ptr uploader, - MaterialLoadCallback materialLoadCallback) + MaterialLoadCallback materialLoadCallback, + PreviewAllocateCallback previewAllocateCallback, + PreviewMarkDirtyCallback previewMarkDirtyCallback + ) : AddressResourceManager(framesInFlight, 1024, 256, 512), _builder(builder), _uploader(std::move(uploader)), - _materialLoadCallback(std::move(materialLoadCallback)) + _materialLoadCallback(std::move(materialLoadCallback)), + _previewAllocateCallback(std::move(previewAllocateCallback)), + _previewMarkDirtyCallback(std::move(previewMarkDirtyCallback)) { } @@ -118,6 +123,7 @@ namespace Syn { uint32_t globalMatId = loadedMaterialIds[localMatIndex]; entry.resource->cpuData.meshMaterialIndices.push_back(globalMatId); + transientGpu.meshMaterialIndices.push_back(globalMatId); } } @@ -142,7 +148,8 @@ namespace Syn { safeEntry.stagingBuffer.reset(); SetResourceState(entryId, ResourceState::Ready); - _version.fetch_add(1, std::memory_order_release); + MarkDirty(entryId); + Info("Model loaded, hardware buffers ready and transient RAM freed: {}", safeEntry.path); }, .needsGraphics = false @@ -153,34 +160,89 @@ namespace Syn { void ModelManager::FinalizeResource(EntryType& entry) { - uint32_t entryIndex = _pathToId.at(entry.path); - - GpuModelAddresses addresses{}; - const auto& hw = entry.resource->hardwareBuffers; - const auto& cpuData = entry.resource->cpuData; - - addresses.vertexPositions = hw.vertexPositions->GetDeviceAddress(); - addresses.vertexAttributes = hw.vertexAttributes->GetDeviceAddress(); - addresses.indices = hw.indices->GetDeviceAddress(); - addresses.meshDescriptors = hw.meshDescriptors->GetDeviceAddress(); - addresses.meshColliders = hw.meshColliders->GetDeviceAddress(); - addresses.lodDescriptors = hw.lodDescriptors->GetDeviceAddress(); - addresses.meshletVertexIndices = hw.meshletVertexIndices->GetDeviceAddress(); - addresses.meshletTriangleIndices = hw.meshletTriangleIndices->GetDeviceAddress(); - addresses.meshletDescriptors = hw.meshletDescriptors->GetDeviceAddress(); - addresses.meshletDrawDescriptors = hw.meshletDrawDescriptors->GetDeviceAddress(); - addresses.meshletColliders = hw.meshletColliders->GetDeviceAddress(); - addresses.nodeTransforms = hw.nodeTransforms->GetDeviceAddress(); - addresses.globalCollider = cpuData.globalCollider; - addresses.vertexCount = cpuData.globalVertexCount; - addresses.indexCount = cpuData.globalIndexCount; - addresses.meshCount = cpuData.globalMeshCount; - addresses.averageLodIndexCount = cpuData.globalAverageLodIndexCount; - addresses.isReady = 1; - - WriteAddress(entryIndex, addresses); - + uint32_t index = _pathToId.at(entry.path); + if (_previewAllocateCallback) _previewAllocateCallback(index); entry.resource->transientGpuData.reset(); entry.resource->transientCpuData.reset(); } + + void ModelManager::FlushDirtyResources() + { + ProcessDirtyReadyEntries([this](uint32_t index, const EntryType& entry) { + + GpuModelAddresses addresses{}; + const auto& hw = entry.resource->hardwareBuffers; + const auto& cpuData = entry.resource->cpuData; + + addresses.vertexPositions = hw.vertexPositions->GetDeviceAddress(); + addresses.vertexAttributes = hw.vertexAttributes->GetDeviceAddress(); + addresses.indices = hw.indices->GetDeviceAddress(); + addresses.meshMaterialIndices = hw.meshMaterialIndices->GetDeviceAddress(); + addresses.meshDescriptors = hw.meshDescriptors->GetDeviceAddress(); + addresses.meshColliders = hw.meshColliders->GetDeviceAddress(); + addresses.lodDescriptors = hw.lodDescriptors->GetDeviceAddress(); + addresses.meshletVertexIndices = hw.meshletVertexIndices->GetDeviceAddress(); + addresses.meshletTriangleIndices = hw.meshletTriangleIndices->GetDeviceAddress(); + addresses.meshletDescriptors = hw.meshletDescriptors->GetDeviceAddress(); + addresses.meshletDrawDescriptors = hw.meshletDrawDescriptors->GetDeviceAddress(); + addresses.meshletColliders = hw.meshletColliders->GetDeviceAddress(); + addresses.nodeTransforms = hw.nodeTransforms->GetDeviceAddress(); + + addresses.globalCollider = cpuData.globalCollider; + addresses.vertexCount = cpuData.globalVertexCount; + addresses.indexCount = cpuData.globalIndexCount; + addresses.meshCount = cpuData.globalMeshCount; + addresses.averageLodIndexCount = cpuData.globalAverageLodIndexCount; + addresses.isReady = 1; + + WriteAddress(index, addresses); + + if (_previewMarkDirtyCallback) _previewMarkDirtyCallback(index); + }); + } + + std::vector ModelManager::GetModelsUsingMaterials(uint32_t materialId) const { + std::lock_guard lock(_mutex); + std::vector result; + + for (uint32_t i = 0; i < _entries.size(); ++i) { + if (_entries[i].state == ResourceState::Ready && _entries[i].resource) { + const auto& model = *_entries[i].resource; + + for (auto meshMaterialIndex : model.cpuData.meshMaterialIndices) + { + if (meshMaterialIndex == materialId) + { + result.push_back(i); + break; + } + } + } + } + + return result; + } + + void ModelManager::NotifyMaterialReady(uint32_t materialId) { + std::lock_guard lock(_pendingMaterialMutex); + _pendingMaterials.insert(materialId); + } + + void ModelManager::ProcessPendingNotifications() { + std::unordered_set materialsToProcess; + + { + std::lock_guard lock(_pendingMaterialMutex); + materialsToProcess.swap(_pendingMaterials); + } + + if (materialsToProcess.empty()) return; + + for (uint32_t materialId : materialsToProcess) { + for (uint32_t modelId : GetModelsUsingMaterials(materialId)) { + if (_previewMarkDirtyCallback) + _previewMarkDirtyCallback(modelId); + } + } + } } \ No newline at end of file diff --git a/SynapseEngine/Engine/Mesh/ModelManager.h b/SynapseEngine/Engine/Mesh/ModelManager.h index 3d1efcea..3d465bf9 100644 --- a/SynapseEngine/Engine/Mesh/ModelManager.h +++ b/SynapseEngine/Engine/Mesh/ModelManager.h @@ -9,18 +9,26 @@ #include "Engine/Vk/Command/CommandPool.h" #include "Engine/Utils/WindowedBuffer.h" +#include + namespace Syn { using MaterialLoadCallback = std::function; using MeshSourceFactory = std::function()>; using StaticMeshFactory = std::function()>; + using PreviewAllocateCallback = std::function; + using PreviewMarkDirtyCallback = std::function; class SYN_API ModelManager : public AddressResourceManager { public: ModelManager(uint32_t framesInFlight, std::shared_ptr builder, std::unique_ptr uploader, - MaterialLoadCallback materialLoadCallback = nullptr); + MaterialLoadCallback materialLoadCallback = nullptr, + PreviewAllocateCallback previewAllocateCallback = nullptr, + PreviewMarkDirtyCallback previewMarkDirtyCallback = nullptr + ); + ~ModelManager() = default; uint32_t LoadModelAsync(const std::string& filePath); @@ -30,12 +38,22 @@ namespace Syn { uint32_t LoadModelSync(const std::string& filePath); uint32_t LoadModelFromSourceSync(const std::string& name, MeshSourceFactory factory); uint32_t LoadModelFromStaticMeshSync(const std::string& name, StaticMeshFactory factory); + + std::vector GetModelsUsingMaterials(uint32_t materialId) const; + void NotifyMaterialReady(uint32_t materialId); + void ProcessPendingNotifications() override; protected: + void FlushDirtyResources() override; void StartGpuUpload(EntryType& entry) override; void FinalizeResource(EntryType& entry) override; private: MaterialLoadCallback _materialLoadCallback; + PreviewAllocateCallback _previewAllocateCallback; + PreviewMarkDirtyCallback _previewMarkDirtyCallback; std::shared_ptr _builder; std::unique_ptr _uploader; + + std::mutex _pendingMaterialMutex; + std::unordered_set _pendingMaterials; }; } \ No newline at end of file diff --git a/SynapseEngine/Engine/Mesh/Uploader/DefaultGpuModelUploader.cpp b/SynapseEngine/Engine/Mesh/Uploader/DefaultGpuModelUploader.cpp index 6320e4e2..508fd3f4 100644 --- a/SynapseEngine/Engine/Mesh/Uploader/DefaultGpuModelUploader.cpp +++ b/SynapseEngine/Engine/Mesh/Uploader/DefaultGpuModelUploader.cpp @@ -12,6 +12,7 @@ namespace Syn totalStagingSize += getAlignedSize(data.vertexData.vertexPositions.size() * sizeof(GpuVertexPosition)); totalStagingSize += getAlignedSize(data.vertexData.vertexAttributes.size() * sizeof(GpuVertexAttributes)); totalStagingSize += getAlignedSize(data.indexedData.indices.size() * sizeof(uint32_t)); + totalStagingSize += getAlignedSize(data.meshMaterialIndices.size() * sizeof(uint32_t)); totalStagingSize += getAlignedSize(data.indexedData.meshDescriptors.size() * sizeof(GpuMeshDescriptor)); totalStagingSize += getAlignedSize(data.indexedData.meshColliders.size() * sizeof(GpuMeshCollider)); totalStagingSize += getAlignedSize(data.indexedData.lodDescriptors.size() * sizeof(GpuMeshLodDescriptor)); @@ -64,6 +65,7 @@ namespace Syn uploadVector(data.vertexData.vertexPositions, vertexFlags, result.hardwareBuffers.vertexPositions); uploadVector(data.vertexData.vertexAttributes, vertexFlags, result.hardwareBuffers.vertexAttributes); uploadVector(data.indexedData.indices, indexFlags, result.hardwareBuffers.indices); + uploadVector(data.meshMaterialIndices, ssboFlags, result.hardwareBuffers.meshMaterialIndices); // Traditional Pipeline uploadVector(data.indexedData.meshDescriptors, ssboFlags, result.hardwareBuffers.meshDescriptors); diff --git a/SynapseEngine/Engine/Registry/BitFlag.h b/SynapseEngine/Engine/Registry/BitFlag.h index f2a8219a..db6d03aa 100644 --- a/SynapseEngine/Engine/Registry/BitFlag.h +++ b/SynapseEngine/Engine/Registry/BitFlag.h @@ -8,7 +8,8 @@ namespace Syn { constexpr uint32_t INDEX_CHANGED_BIT = 3; constexpr uint32_t DIRTY_STATIC_BIT = 4; constexpr uint32_t FORCE_STATIC_GPU_UPLOAD = 5; - constexpr uint32_t CUSTOM_CHANGED_BIT1 = 6; - constexpr uint32_t CUSTOM_CHANGED_BIT2 = 7; - constexpr uint32_t CUSTOM_CHANGED_BIT3 = 8; + constexpr uint32_t QUEUED_BIT = 6; + constexpr uint32_t CUSTOM_CHANGED_BIT1 = 7; + constexpr uint32_t CUSTOM_CHANGED_BIT2 = 8; + constexpr uint32_t CUSTOM_CHANGED_BIT3 = 9; } diff --git a/SynapseEngine/Engine/Registry/Pool/Pool.h b/SynapseEngine/Engine/Registry/Pool/Pool.h index bdb3f3b0..7fffde37 100644 --- a/SynapseEngine/Engine/Registry/Pool/Pool.h +++ b/SynapseEngine/Engine/Registry/Pool/Pool.h @@ -252,6 +252,13 @@ namespace Syn requires StorageConstraint&& MappingConstraint SYN_INLINE void Pool::EnsureEntityMapping(EntityID entity) { + size_t oldSize = _mapping.GetSparseIndices().size(); + _mapping.EnsureEntityMapping(entity); + + if (_mapping.GetSparseIndices().size() > oldSize) + { + IncrementMappingVersion(); + } } } \ No newline at end of file diff --git a/SynapseEngine/Engine/Registry/Pool/Storage/Core/SegmentedStorageImpl.h b/SynapseEngine/Engine/Registry/Pool/Storage/Core/SegmentedStorageImpl.h index 2fe26004..91235a51 100644 --- a/SynapseEngine/Engine/Registry/Pool/Storage/Core/SegmentedStorageImpl.h +++ b/SynapseEngine/Engine/Registry/Pool/Storage/Core/SegmentedStorageImpl.h @@ -200,10 +200,12 @@ namespace Syn { const DenseIndex swapTarget = static_cast(_staticEnd - 1); - Base::FlagIndexChanged(swapTarget); - Base::SwapBackend(index, swapTarget, onSwap); - - MarkStaticDirty(index); + if (index != swapTarget) + { + Base::FlagIndexChanged(swapTarget); + Base::SwapBackend(index, swapTarget, onSwap); + MarkStaticDirty(index); + } index = swapTarget; _staticEnd--; diff --git a/SynapseEngine/Engine/Registry/Registry.h b/SynapseEngine/Engine/Registry/Registry.h index 1758577d..c728599c 100644 --- a/SynapseEngine/Engine/Registry/Registry.h +++ b/SynapseEngine/Engine/Registry/Registry.h @@ -118,6 +118,7 @@ namespace Syn { auto* wrapper = new WrapperType(); _pools.Add(id, wrapper); + _pools.EnsureEntityMapping(_entityCounter); return wrapper; } diff --git a/SynapseEngine/Engine/Render/IRenderPass.h b/SynapseEngine/Engine/Render/IRenderPass.h index f4c11352..6e32e323 100644 --- a/SynapseEngine/Engine/Render/IRenderPass.h +++ b/SynapseEngine/Engine/Render/IRenderPass.h @@ -32,6 +32,7 @@ namespace Syn virtual void Initialize() {}; virtual void Execute(const RenderContext& context) {}; virtual bool ShouldExecute(const RenderContext& context) const { return true; } + virtual bool ShouldCollectStatistics() const { return false; } virtual std::string GetName() const = 0; virtual std::string GetGroup() const { return PassGroupNames::UndefinedPasses; } }; diff --git a/SynapseEngine/Engine/Render/PassGroupNames.h b/SynapseEngine/Engine/Render/PassGroupNames.h index fc4a7d09..f6a8a726 100644 --- a/SynapseEngine/Engine/Render/PassGroupNames.h +++ b/SynapseEngine/Engine/Render/PassGroupNames.h @@ -29,5 +29,6 @@ namespace Syn static constexpr const char* SsaoPasses = "SsaoPasses"; static constexpr const char* ShadowPasses = "ShadowPasses"; static constexpr const char* PostProcessPasses = "PostProcessPasses"; + static constexpr const char* UtilityPasses = "UtilityPasses"; }; } \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/Passes/Billboard/BillboardTransitionPass.cpp b/SynapseEngine/Engine/Render/Passes/Billboard/BillboardTransitionPass.cpp index 38b8c354..f7faf33c 100644 --- a/SynapseEngine/Engine/Render/Passes/Billboard/BillboardTransitionPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Billboard/BillboardTransitionPass.cpp @@ -4,7 +4,7 @@ namespace Syn { void BillboardTransitionPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); std::vector targets = { RenderTargetNames::Main, diff --git a/SynapseEngine/Engine/Render/Passes/Billboard/CameraBillboardPass.cpp b/SynapseEngine/Engine/Render/Passes/Billboard/CameraBillboardPass.cpp index 3bdc5ce2..2c3f24c7 100644 --- a/SynapseEngine/Engine/Render/Passes/Billboard/CameraBillboardPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Billboard/CameraBillboardPass.cpp @@ -70,11 +70,11 @@ namespace Syn { .colorAttachmentCount = 2 }; - _iconTexture = ServiceLocator::GetImageManager()->LoadImageSync(PathUtils::GetAbsolutePathString("Assets/CameraIcon.png")); + _iconTexture = ServiceLocator::GetImageManager()->LoadImageSync(PathUtils::GetAbsolutePathString("Assets/Engine/Icons/CameraIcon.png")); } void CameraBillboardPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Billboard/DirectionLightBillboardPass.cpp b/SynapseEngine/Engine/Render/Passes/Billboard/DirectionLightBillboardPass.cpp index ea3b2f67..f9a34c5a 100644 --- a/SynapseEngine/Engine/Render/Passes/Billboard/DirectionLightBillboardPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Billboard/DirectionLightBillboardPass.cpp @@ -69,11 +69,11 @@ namespace Syn { .colorAttachmentCount = 2 }; - _iconTexture = ServiceLocator::GetImageManager()->LoadImageSync(PathUtils::GetAbsolutePathString("Assets/DirectionLightIcon.png")); + _iconTexture = ServiceLocator::GetImageManager()->LoadImageSync(PathUtils::GetAbsolutePathString("Assets/Engine/Icons/DirectionLightIcon.png")); } void DirectionLightBillboardPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Billboard/PointLightBillboardPass.cpp b/SynapseEngine/Engine/Render/Passes/Billboard/PointLightBillboardPass.cpp index 840d7775..648c7f7b 100644 --- a/SynapseEngine/Engine/Render/Passes/Billboard/PointLightBillboardPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Billboard/PointLightBillboardPass.cpp @@ -69,11 +69,11 @@ namespace Syn { .colorAttachmentCount = 2, }; - _iconTexture = ServiceLocator::GetImageManager()->LoadImageSync(PathUtils::GetAbsolutePathString("Assets/PointLightIcon.png")); + _iconTexture = ServiceLocator::GetImageManager()->LoadImageSync(PathUtils::GetAbsolutePathString("Assets/Engine/Icons/PointLightIcon.png")); } void PointLightBillboardPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Billboard/SpotLightBillboardPass.cpp b/SynapseEngine/Engine/Render/Passes/Billboard/SpotLightBillboardPass.cpp index a1ca2744..ceb5bafc 100644 --- a/SynapseEngine/Engine/Render/Passes/Billboard/SpotLightBillboardPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Billboard/SpotLightBillboardPass.cpp @@ -69,11 +69,11 @@ namespace Syn { .colorAttachmentCount = 2 }; - _iconTexture = ServiceLocator::GetImageManager()->LoadImageSync(PathUtils::GetAbsolutePathString("Assets/SpotLightIcon.png")); + _iconTexture = ServiceLocator::GetImageManager()->LoadImageSync(PathUtils::GetAbsolutePathString("Assets/Engine/Icons/SpotLightIcon.png")); } void SpotLightBillboardPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryMeshCullingPass.cpp b/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryMeshCullingPass.cpp index 84554b07..a7c97b3f 100644 --- a/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryMeshCullingPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryMeshCullingPass.cpp @@ -55,7 +55,7 @@ namespace Syn { auto animationManager = ServiceLocator::GetAnimationManager(); auto materialManager = ServiceLocator::GetMaterialManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); uint32_t fIdx = context.frameIndex; @@ -69,7 +69,7 @@ namespace Syn { //Using prevous frame's depth pyramid! uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto depthPyramid = rtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryModelCullingPass.cpp b/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryModelCullingPass.cpp index 85e41213..e799e49b 100644 --- a/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryModelCullingPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryModelCullingPass.cpp @@ -63,7 +63,7 @@ namespace Syn { auto materialManager = ServiceLocator::GetMaterialManager(); auto animationManager = ServiceLocator::GetAnimationManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); uint32_t fIdx = context.frameIndex; @@ -77,7 +77,7 @@ namespace Syn { //Using prevous frame's depth pyramid! uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto depthPyramid = rtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryMortonChunkCullingPass.cpp b/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryMortonChunkCullingPass.cpp index 0f04f186..8ed29aa1 100644 --- a/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryMortonChunkCullingPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryMortonChunkCullingPass.cpp @@ -48,7 +48,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto depthPyramid = rtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryMortonModelCullingPass.cpp b/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryMortonModelCullingPass.cpp index 5bd7ebb3..bb50d576 100644 --- a/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryMortonModelCullingPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryMortonModelCullingPass.cpp @@ -48,7 +48,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto depthPyramid = rtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryStaticChunkCullingPass.cpp b/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryStaticChunkCullingPass.cpp index c5e9dcb9..8815b1e6 100644 --- a/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryStaticChunkCullingPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryStaticChunkCullingPass.cpp @@ -54,7 +54,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto depthPyramid = rtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryStaticModelCullingPass.cpp b/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryStaticModelCullingPass.cpp index 2e39baf2..eebacf5b 100644 --- a/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryStaticModelCullingPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryStaticModelCullingPass.cpp @@ -53,7 +53,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto depthPyramid = rtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryWorkGraphCullingPass.cpp b/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryWorkGraphCullingPass.cpp index f8bb0d33..bfd858ef 100644 --- a/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryWorkGraphCullingPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Culling/Geometry/GeometryWorkGraphCullingPass.cpp @@ -164,7 +164,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto depthPyramid = rtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Culling/PointLight/PointLightCullingPass.cpp b/SynapseEngine/Engine/Render/Passes/Culling/PointLight/PointLightCullingPass.cpp index 25eadd25..54552b4f 100644 --- a/SynapseEngine/Engine/Render/Passes/Culling/PointLight/PointLightCullingPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Culling/PointLight/PointLightCullingPass.cpp @@ -43,7 +43,7 @@ namespace Syn { if (_totalLightsToTest == 0) return; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto drawData = scene->GetSceneDrawData(); auto compManager = scene->GetComponentBufferManager(); uint32_t fIdx = context.frameIndex; @@ -57,7 +57,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto prevRtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto prevRtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto depthPyramid = prevRtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Culling/SpotLight/SpotLightCullingPass.cpp b/SynapseEngine/Engine/Render/Passes/Culling/SpotLight/SpotLightCullingPass.cpp index 27f200f2..58781269 100644 --- a/SynapseEngine/Engine/Render/Passes/Culling/SpotLight/SpotLightCullingPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Culling/SpotLight/SpotLightCullingPass.cpp @@ -38,7 +38,7 @@ namespace Syn { if (_totalLightsToTest == 0) return; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto drawData = scene->GetSceneDrawData(); auto compManager = scene->GetComponentBufferManager(); uint32_t fIdx = context.frameIndex; @@ -52,7 +52,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto prevRtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto prevRtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto depthPyramid = prevRtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Hiz/Geometry/GeometryHizDownsamplePass.cpp b/SynapseEngine/Engine/Render/Passes/Hiz/Geometry/GeometryHizDownsamplePass.cpp index 650a2e6c..f58eea90 100644 --- a/SynapseEngine/Engine/Render/Passes/Hiz/Geometry/GeometryHizDownsamplePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Hiz/Geometry/GeometryHizDownsamplePass.cpp @@ -30,7 +30,7 @@ namespace Syn { } void GeometryHizDownsamplePass::PrepareFrame(const RenderContext& context) { - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto depthPyramid = rtGroup->GetImage(RenderTargetNames::DepthPyramid); _imageTransitions.push_back({ @@ -46,7 +46,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); auto sampler = imageManager->GetSampler(SamplerNames::NearestClampEdge); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto depthPyramid = rtGroup->GetImage(RenderTargetNames::DepthPyramid); uint32_t mipLevels = depthPyramid->GetConfig().mipLevels; diff --git a/SynapseEngine/Engine/Render/Passes/Hiz/Geometry/GeometryHizLinearPreparePass.cpp b/SynapseEngine/Engine/Render/Passes/Hiz/Geometry/GeometryHizLinearPreparePass.cpp index f8b6ba6f..cf580201 100644 --- a/SynapseEngine/Engine/Render/Passes/Hiz/Geometry/GeometryHizLinearPreparePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Hiz/Geometry/GeometryHizLinearPreparePass.cpp @@ -33,7 +33,7 @@ namespace Syn { void GeometryHizLinearPreparePass::PrepareFrame(const RenderContext& context) { auto scene = context.scene; - auto currGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto currGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto depthOpaque = currGroup->GetImage(RenderTargetNames::OpaqueDepth); auto depthOpaqueTransparent = currGroup->GetImage(RenderTargetNames::TransparentDepth); @@ -71,7 +71,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); - auto currGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto currGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto depthOpaque = currGroup->GetImage(RenderTargetNames::OpaqueDepth); auto depthOpaqueTransparent = currGroup->GetImage(RenderTargetNames::TransparentDepth); @@ -112,7 +112,7 @@ namespace Syn { uint32_t fIdx = context.frameIndex; auto compManager = scene->GetComponentBufferManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, fIdx); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, fIdx); Vk::PushConstant pc; pc->frameGlobalContextBufferAddr = scene->GetSceneDrawData()->frameContextBuffer.GetAddress(fIdx); @@ -121,7 +121,7 @@ namespace Syn { } void GeometryHizLinearPreparePass::Dispatch(const RenderContext& context) { - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); uint32_t width = rtGroup->GetWidth(); uint32_t height = rtGroup->GetHeight(); diff --git a/SynapseEngine/Engine/Render/Passes/Hiz/HizInitPass.cpp b/SynapseEngine/Engine/Render/Passes/Hiz/HizInitPass.cpp index f1bf985a..e6b3236b 100644 --- a/SynapseEngine/Engine/Render/Passes/Hiz/HizInitPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Hiz/HizInitPass.cpp @@ -7,7 +7,7 @@ namespace Syn { void HizInitPass::PrepareFrame(const RenderContext& context) { //Using prevous frame's depth pyramid! uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto drawData = context.scene->GetSceneDrawData(); { diff --git a/SynapseEngine/Engine/Render/Passes/PostProcess/Bloom/BloomCompositePass.cpp b/SynapseEngine/Engine/Render/Passes/PostProcess/Bloom/BloomCompositePass.cpp index d27218d8..739d8970 100644 --- a/SynapseEngine/Engine/Render/Passes/PostProcess/Bloom/BloomCompositePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/PostProcess/Bloom/BloomCompositePass.cpp @@ -28,7 +28,7 @@ namespace Syn { } void BloomCompositePass::PrepareFrame(const RenderContext& context) { - auto rt = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rt = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto main = rt->GetImage(RenderTargetNames::Main); auto bloom = rt->GetImage(RenderTargetNames::Bloom); @@ -48,7 +48,7 @@ namespace Syn { } void BloomCompositePass::BindDescriptors(const RenderContext& context) { - auto rt = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rt = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto main = rt->GetImage(RenderTargetNames::Main); auto bloom = rt->GetImage(RenderTargetNames::Bloom); auto sampler = ServiceLocator::GetImageManager()->GetSampler(SamplerNames::LinearClampEdge); @@ -84,7 +84,7 @@ namespace Syn { } void BloomCompositePass::Dispatch(const RenderContext& context) { - auto rt = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rt = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); uint32_t width = rt->GetWidth(); uint32_t height = rt->GetHeight(); diff --git a/SynapseEngine/Engine/Render/Passes/PostProcess/Bloom/BloomDownsamplePass.cpp b/SynapseEngine/Engine/Render/Passes/PostProcess/Bloom/BloomDownsamplePass.cpp index a9d3273d..b5426915 100644 --- a/SynapseEngine/Engine/Render/Passes/PostProcess/Bloom/BloomDownsamplePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/PostProcess/Bloom/BloomDownsamplePass.cpp @@ -30,7 +30,7 @@ namespace Syn { } void BloomDownsamplePass::PrepareFrame(const RenderContext& context) { - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto bloom = rtGroup->GetImage(RenderTargetNames::Bloom); _imageTransitions.push_back({ @@ -46,7 +46,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); auto sampler = imageManager->GetSampler(SamplerNames::LinearClampEdge); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto bloom = rtGroup->GetImage(RenderTargetNames::Bloom); uint32_t mipLevels = bloom->GetConfig().mipLevels; diff --git a/SynapseEngine/Engine/Render/Passes/PostProcess/Bloom/BloomPrefilterPass.cpp b/SynapseEngine/Engine/Render/Passes/PostProcess/Bloom/BloomPrefilterPass.cpp index be623396..2a8f32b3 100644 --- a/SynapseEngine/Engine/Render/Passes/PostProcess/Bloom/BloomPrefilterPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/PostProcess/Bloom/BloomPrefilterPass.cpp @@ -28,7 +28,7 @@ namespace Syn { } void BloomPrefilterPass::PrepareFrame(const RenderContext& context) { - auto rt = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rt = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto main = rt->GetImage(RenderTargetNames::Main); auto bloom = rt->GetImage(RenderTargetNames::Bloom); @@ -48,7 +48,7 @@ namespace Syn { } void BloomPrefilterPass::BindDescriptors(const RenderContext& context) { - auto rt = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rt = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto main = rt->GetImage(RenderTargetNames::Main); auto bloom = rt->GetImage(RenderTargetNames::Bloom); auto sampler = ServiceLocator::GetImageManager()->GetSampler(SamplerNames::LinearClampEdge); @@ -81,7 +81,7 @@ namespace Syn { uint32_t fIdx = context.frameIndex; auto compManager = scene->GetComponentBufferManager(); - auto rt = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, fIdx); + auto rt = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, fIdx); uint32_t width = rt->GetWidth(); uint32_t height = rt->GetHeight(); @@ -95,7 +95,7 @@ namespace Syn { } void BloomPrefilterPass::Dispatch(const RenderContext& context) { - auto rt = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rt = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); uint32_t width = rt->GetWidth(); uint32_t height = rt->GetHeight(); diff --git a/SynapseEngine/Engine/Render/Passes/PostProcess/Bloom/BloomUpsamplePass.cpp b/SynapseEngine/Engine/Render/Passes/PostProcess/Bloom/BloomUpsamplePass.cpp index d834cbfa..224688f2 100644 --- a/SynapseEngine/Engine/Render/Passes/PostProcess/Bloom/BloomUpsamplePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/PostProcess/Bloom/BloomUpsamplePass.cpp @@ -30,7 +30,7 @@ namespace Syn { } void BloomUpsamplePass::PrepareFrame(const RenderContext& context) { - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto bloom = rtGroup->GetImage(RenderTargetNames::Bloom); _imageTransitions.push_back({ @@ -46,7 +46,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); auto sampler = imageManager->GetSampler(SamplerNames::LinearClampEdge); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto bloom = rtGroup->GetImage(RenderTargetNames::Bloom); uint32_t mipLevels = bloom->GetConfig().mipLevels; diff --git a/SynapseEngine/Engine/Render/Passes/PostProcess/InfiniteGrid/InfiniteGridPass.cpp b/SynapseEngine/Engine/Render/Passes/PostProcess/InfiniteGrid/InfiniteGridPass.cpp new file mode 100644 index 00000000..34f12178 --- /dev/null +++ b/SynapseEngine/Engine/Render/Passes/PostProcess/InfiniteGrid/InfiniteGridPass.cpp @@ -0,0 +1,120 @@ +#include "InfiniteGridPass.h" +#include "Engine/ServiceLocator.h" +#include "Engine/Manager/ShaderManager.h" +#include "Engine/Vk/Image/ImageViewNames.h" +#include "Engine/Render/RenderNames.h" +#include "Engine/Vk/Rendering/PushConstant.h" + +namespace Syn { + + #include "Engine/Shaders/Includes/PushConstants/InfiniteGridPC.glsl" + + bool InfiniteGridPass::ShouldExecute(const RenderContext& context) const + { + return context.scene->GetSettings()->debug.enableInfiniteGrid; + } + + void InfiniteGridPass::Initialize() { + auto shaderManager = ServiceLocator::GetShaderManager(); + + Vk::ShaderProgramConfig config; + config.useDescriptorBuffers = false; + + _shaderProgram = shaderManager->CreateProgram("InfiniteGridProgram", { + ShaderNames::FullscreenVert, + ShaderNames::InfiniteGridFrag + }, config); + + _graphicsState = { + .raster = { + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + .cullMode = VK_CULL_MODE_NONE, + .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, + .polygonMode = VK_POLYGON_MODE_FILL, + .lineWidth = 1.0f + }, + .depth = { + .testEnable = VK_TRUE, + .writeEnable = VK_FALSE, + .compareOp = VK_COMPARE_OP_LESS_OR_EQUAL + }, + .blendStates = { + { + .enable = VK_TRUE, + .srcColorFactor = VK_BLEND_FACTOR_SRC_ALPHA, + .dstColorFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaFactor = VK_BLEND_FACTOR_ZERO, + .alphaBlendOp = VK_BLEND_OP_ADD + } + }, + .colorAttachmentCount = 1, + .renderArea = std::nullopt + }; + } + + void InfiniteGridPass::PrepareFrame(const RenderContext& context) { + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); + VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; + _graphicsState.renderArea = extent; + + _colorAttachments.push_back(Vk::RenderUtils::CreateAttachment({ + .imageView = group->GetImage(RenderTargetNames::Main)->GetView(Vk::ImageViewNames::Default), + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE + })); + + _depthAttachment = Vk::RenderUtils::CreateAttachment({ + .imageView = group->GetImage(RenderTargetNames::OpaqueDepth)->GetView(Vk::ImageViewNames::Default), + .layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE + }); + + _renderInfo = Vk::RenderingInfoConfig{ + .renderArea = extent, + .colorAttachments = _colorAttachments, + .depthAttachment = &_depthAttachment.value(), + .layerCount = 1 + }; + } + + void InfiniteGridPass::PushConstants(const RenderContext& context) { + auto scene = context.scene; + auto settings = scene->GetSettings(); + uint32_t fIdx = context.frameIndex; + + Vk::PushConstant pc; + pc->frameGlobalContextBufferAddr = scene->GetSceneDrawData()->frameContextBuffer.GetAddress(fIdx); + + uint32_t planeFlags = 0; + if (settings->debug.gridShowXZ) planeFlags |= (1 << 0); + if (settings->debug.gridShowXY) planeFlags |= (1 << 1); + if (settings->debug.gridShowYZ) planeFlags |= (1 << 2); + pc->planeFlags = planeFlags; + + uint32_t axisFlags = 0; + if (settings->debug.gridShowAxisX) axisFlags |= (1 << 0); + if (settings->debug.gridShowAxisY) axisFlags |= (1 << 1); + if (settings->debug.gridShowAxisZ) axisFlags |= (1 << 2); + pc->axisFlags = axisFlags; + + pc->gridScale = settings->debug.gridScale; + pc->fadeDistance = settings->debug.fadeDistance; + pc->gridThickness = settings->debug.gridThickness; + pc->axisThickness = settings->debug.axisThickness; + + pc->gridColor = settings->debug.gridColor; + pc->axisXColor = settings->debug.axisXColor; + pc->axisYColor = settings->debug.axisYColor; + pc->axisZColor = settings->debug.axisZColor; + + pc.Push(context.cmd, _shaderProgram->GetLayout()); + } + + void InfiniteGridPass::Draw(const RenderContext& context) { + vkCmdDraw(context.cmd, 3, 1, 0, 0); + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/Passes/PostProcess/InfiniteGrid/InfiniteGridPass.h b/SynapseEngine/Engine/Render/Passes/PostProcess/InfiniteGrid/InfiniteGridPass.h new file mode 100644 index 00000000..6a28f6e0 --- /dev/null +++ b/SynapseEngine/Engine/Render/Passes/PostProcess/InfiniteGrid/InfiniteGridPass.h @@ -0,0 +1,20 @@ +#pragma once +#include "Engine/SynApi.h" +#include "Engine/Render/Passes/GraphicsPass.h" + +namespace Syn { + class SYN_API InfiniteGridPass : public GraphicsPass { + public: + InfiniteGridPass() = default; + + std::string GetName() const override { return "InfiniteGridPass"; } + std::string GetGroup() const override { return PassGroupNames::DebugPasses; } + void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } + protected: + bool ShouldExecute(const RenderContext& context) const override; + void PrepareFrame(const RenderContext& context) override; + void PushConstants(const RenderContext& context) override; + void Draw(const RenderContext& context) override; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/Passes/PostProcess/Outline/SelectionOutlinePass.cpp b/SynapseEngine/Engine/Render/Passes/PostProcess/Outline/SelectionOutlinePass.cpp index 28d90fcb..d9cebb4e 100644 --- a/SynapseEngine/Engine/Render/Passes/PostProcess/Outline/SelectionOutlinePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/PostProcess/Outline/SelectionOutlinePass.cpp @@ -55,7 +55,7 @@ namespace Syn void SelectionOutlinePass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); _graphicsState.renderArea = VkExtent2D{ group->GetWidth(), group->GetHeight() }; auto mainImage = group->GetImage(RenderTargetNames::Main); @@ -119,7 +119,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto entityTexture = rtGroup->GetImage(RenderTargetNames::EntityIndex); auto depthTexture = rtGroup->GetImage(RenderTargetNames::DepthPyramid); auto nearestSampler = imageManager->GetSampler(SamplerNames::NearestClampEdge); diff --git a/SynapseEngine/Engine/Render/Passes/PostProcess/SkySphere/SkySpherePass.cpp b/SynapseEngine/Engine/Render/Passes/PostProcess/SkySphere/SkySpherePass.cpp new file mode 100644 index 00000000..e172094b --- /dev/null +++ b/SynapseEngine/Engine/Render/Passes/PostProcess/SkySphere/SkySpherePass.cpp @@ -0,0 +1,143 @@ +#include "SkySpherePass.h" +#include "Engine/ServiceLocator.h" +#include "Engine/Vk/Context.h" +#include "Engine/Manager/ShaderManager.h" +#include "Engine/Vk/Image/ImageFactory.h" +#include "Engine/Scene/BufferNames.h" +#include "Engine/Vk/Image/ImageViewNames.h" +#include "Engine/Image/ImageManager.h" +#include "Engine/Render/RenderNames.h" +#include "Engine/Image/SamplerNames.h" +#include "Engine/Vk/Rendering/PushConstant.h" + +namespace Syn { + + #include "Engine/Shaders/Includes/PushConstants/SkySpherePC.glsl" + + SkySpherePass::SkySpherePass() {} + + bool SkySpherePass::ShouldExecute(const RenderContext& context) const + { + auto skyTextureId = context.scene->GetSettings()->environment.skyTextureId; + bool enabled = context.scene->GetSettings()->environment.enableSky; + return enabled && skyTextureId != UINT32_MAX && !context.scene->GetSettings()->debug.enableDebugVisibility; + } + + void SkySpherePass::Initialize() { + auto shaderManager = ServiceLocator::GetShaderManager(); + auto imageManager = ServiceLocator::GetImageManager(); + + Vk::ShaderProgramConfig config; + config.useDescriptorBuffers = true; + config.layoutOverride = [imageManager](uint32_t setIndex) { + if (setIndex == 0) return imageManager->GetBindlessLayout(); + return VkDescriptorSetLayout{}; + }; + + _shaderProgram = shaderManager->CreateProgram("SkySphereProgram", { + ShaderNames::SkySphereVert, + ShaderNames::SkySphereFrag + }, config); + + _graphicsState = { + .raster = { + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + .cullMode = VK_CULL_MODE_NONE, + .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, + .polygonMode = VK_POLYGON_MODE_FILL, + .lineWidth = 1.0f + }, + .depth = { + .testEnable = VK_TRUE, + .writeEnable = VK_FALSE, + .compareOp = VK_COMPARE_OP_LESS_OR_EQUAL + }, + .blendStates = { + { + .enable = VK_FALSE, + .srcColorFactor = VK_BLEND_FACTOR_ONE, + .dstColorFactor = VK_BLEND_FACTOR_ZERO, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaFactor = VK_BLEND_FACTOR_ZERO, + .alphaBlendOp = VK_BLEND_OP_ADD + } + }, + .colorAttachmentCount = 1, + .renderArea = std::nullopt + }; + } + + void SkySpherePass::PrepareFrame(const RenderContext& context) { + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); + VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; + _graphicsState.renderArea = extent; + + std::vector targets = { + RenderTargetNames::Main, + }; + + for (const auto& name : targets) + { + _colorAttachments.push_back(Vk::RenderUtils::CreateAttachment({ + .imageView = group->GetImage(name)->GetView(Vk::ImageViewNames::Default), + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE + })); + } + + _depthAttachment = Vk::RenderUtils::CreateAttachment({ + .imageView = group->GetImage(RenderTargetNames::OpaqueDepth)->GetView(Vk::ImageViewNames::Default), + .layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE + }); + + _renderInfo = Vk::RenderingInfoConfig{ + .renderArea = extent, + .colorAttachments = _colorAttachments, + .depthAttachment = &_depthAttachment.value(), + .layerCount = 1 + }; + } + + void SkySpherePass::PushConstants(const RenderContext& context) { + auto scene = context.scene; + auto imageManager = ServiceLocator::GetImageManager(); + uint32_t fIdx = context.frameIndex; + + const auto& envSettings = scene->GetSettings()->environment; + + glm::vec3 rotRads = glm::radians(envSettings.skyRotation); + glm::mat4 rotMat = glm::mat4(1.0f); + rotMat = glm::rotate(rotMat, rotRads.y, glm::vec3(0.0f, 1.0f, 0.0f)); + rotMat = glm::rotate(rotMat, rotRads.x, glm::vec3(1.0f, 0.0f, 0.0f)); + rotMat = glm::rotate(rotMat, rotRads.z, glm::vec3(0.0f, 0.0f, 1.0f)); + + Vk::PushConstant pc; + pc->frameGlobalContextBufferAddr = scene->GetSceneDrawData()->frameContextBuffer.GetAddress(fIdx); + pc->skyTextureIndex = envSettings.skyTextureId; + pc->samplerIndex = imageManager->GetSamplerIndex(SamplerNames::SkyboxSampler); + pc->mappingType = envSettings.skyMode == SkyMode::EquirectangularTexture ? 0 : 1; + pc->skyIntensity = envSettings.skyIntensity; + pc->skyRotationMatrix = rotMat; + pc->skyTint = envSettings.skyTint; + pc->skyExposureEV = envSettings.skyExposureEV; + + pc.Push(context.cmd, _shaderProgram->GetLayout()); + } + + void SkySpherePass::BindDescriptors(const RenderContext& context) + { + auto imageManager = ServiceLocator::GetImageManager(); + auto bindlessBuffer = imageManager->GetBindlessBuffer(); + + bindlessBuffer->Bind(context.cmd, _shaderProgram->GetLayout(), 0, VK_PIPELINE_BIND_POINT_GRAPHICS); + } + + void SkySpherePass::Draw(const RenderContext& context) + { + vkCmdDraw(context.cmd, 3, 1, 0, 0); + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/Passes/PostProcess/SkySphere/SkySpherePass.h b/SynapseEngine/Engine/Render/Passes/PostProcess/SkySphere/SkySpherePass.h new file mode 100644 index 00000000..724a56cd --- /dev/null +++ b/SynapseEngine/Engine/Render/Passes/PostProcess/SkySphere/SkySpherePass.h @@ -0,0 +1,20 @@ +#pragma once +#include "Engine/SynApi.h" +#include "Engine/Render/Passes/GraphicsPass.h" + +namespace Syn { + class SYN_API SkySpherePass : public GraphicsPass { + public: + SkySpherePass(); + + std::string GetName() const override { return "SkySpherePass"; } + std::string GetGroup() const override { return PassGroupNames::PostProcessPasses; } + void Initialize() override; + protected: + bool ShouldExecute(const RenderContext& context) const override; + void PrepareFrame(const RenderContext& context) override; + void PushConstants(const RenderContext& context) override; + void BindDescriptors(const RenderContext& context) override; + void Draw(const RenderContext& context) override; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/Passes/Ssao/SsaoBlurPass.cpp b/SynapseEngine/Engine/Render/Passes/PostProcess/Ssao/SsaoBlurPass.cpp similarity index 96% rename from SynapseEngine/Engine/Render/Passes/Ssao/SsaoBlurPass.cpp rename to SynapseEngine/Engine/Render/Passes/PostProcess/Ssao/SsaoBlurPass.cpp index 19b96788..d9f69379 100644 --- a/SynapseEngine/Engine/Render/Passes/Ssao/SsaoBlurPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/PostProcess/Ssao/SsaoBlurPass.cpp @@ -27,7 +27,7 @@ namespace Syn { } void SsaoBlurPass::PrepareFrame(const RenderContext& context) { - auto currGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto currGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto ssaoAo = currGroup->GetImage(RenderTargetNames::SsaoAo); auto ssaoAoInt = currGroup->GetImage(RenderTargetNames::SsaoAoIntermediate); @@ -57,7 +57,7 @@ namespace Syn { } void SsaoBlurPass::BindDescriptors(const RenderContext& context) { - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto imageManager = ServiceLocator::GetImageManager(); auto depthPyramid = rtGroup->GetImage(RenderTargetNames::DepthPyramid); @@ -84,7 +84,7 @@ namespace Syn { } void SsaoBlurPass::Dispatch(const RenderContext& context) { - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto imageManager = ServiceLocator::GetImageManager(); auto ssaoAo = rtGroup->GetImage(RenderTargetNames::SsaoAo); diff --git a/SynapseEngine/Engine/Render/Passes/Ssao/SsaoBlurPass.h b/SynapseEngine/Engine/Render/Passes/PostProcess/Ssao/SsaoBlurPass.h similarity index 100% rename from SynapseEngine/Engine/Render/Passes/Ssao/SsaoBlurPass.h rename to SynapseEngine/Engine/Render/Passes/PostProcess/Ssao/SsaoBlurPass.h diff --git a/SynapseEngine/Engine/Render/Passes/Ssao/SsaoInitPass.cpp b/SynapseEngine/Engine/Render/Passes/PostProcess/Ssao/SsaoInitPass.cpp similarity index 95% rename from SynapseEngine/Engine/Render/Passes/Ssao/SsaoInitPass.cpp rename to SynapseEngine/Engine/Render/Passes/PostProcess/Ssao/SsaoInitPass.cpp index b90272cd..f0ad50a0 100644 --- a/SynapseEngine/Engine/Render/Passes/Ssao/SsaoInitPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/PostProcess/Ssao/SsaoInitPass.cpp @@ -4,7 +4,7 @@ namespace Syn { void SsaoInitPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); if (!group) return; auto depthPyramid = group->GetImage(RenderTargetNames::DepthPyramid); diff --git a/SynapseEngine/Engine/Render/Passes/Ssao/SsaoInitPass.h b/SynapseEngine/Engine/Render/Passes/PostProcess/Ssao/SsaoInitPass.h similarity index 100% rename from SynapseEngine/Engine/Render/Passes/Ssao/SsaoInitPass.h rename to SynapseEngine/Engine/Render/Passes/PostProcess/Ssao/SsaoInitPass.h diff --git a/SynapseEngine/Engine/Render/Passes/Ssao/SsaoPass.cpp b/SynapseEngine/Engine/Render/Passes/PostProcess/Ssao/SsaoPass.cpp similarity index 95% rename from SynapseEngine/Engine/Render/Passes/Ssao/SsaoPass.cpp rename to SynapseEngine/Engine/Render/Passes/PostProcess/Ssao/SsaoPass.cpp index ccf8580b..e0240388 100644 --- a/SynapseEngine/Engine/Render/Passes/Ssao/SsaoPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/PostProcess/Ssao/SsaoPass.cpp @@ -16,7 +16,7 @@ namespace Syn { - #include "../../../Shaders/Includes/PushConstants/SsaoPC.glsl" + #include "Engine/Shaders/Includes/PushConstants/SsaoPC.glsl" bool SsaoPass::ShouldExecute(const RenderContext& context) const { @@ -36,7 +36,7 @@ namespace Syn { } void SsaoPass::BindDescriptors(const RenderContext& context) { - auto currGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto currGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto imageManager = ServiceLocator::GetImageManager(); auto noiseTexture = imageManager->GetResource(ImageNames::SsaoNoiseTexture); @@ -73,7 +73,7 @@ namespace Syn { void SsaoPass::PushConstants(const RenderContext& context) { auto scene = context.scene; uint32_t fIdx = context.frameIndex; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, fIdx); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, fIdx); auto imageManager = ServiceLocator::GetImageManager(); auto noiseTexture = imageManager->GetResource(ImageNames::SsaoNoiseTexture); @@ -91,7 +91,7 @@ namespace Syn { } void SsaoPass::Dispatch(const RenderContext& context) { - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); uint32_t width = rtGroup->GetWidth(); uint32_t height = rtGroup->GetHeight(); diff --git a/SynapseEngine/Engine/Render/Passes/Ssao/SsaoPass.h b/SynapseEngine/Engine/Render/Passes/PostProcess/Ssao/SsaoPass.h similarity index 100% rename from SynapseEngine/Engine/Render/Passes/Ssao/SsaoPass.h rename to SynapseEngine/Engine/Render/Passes/PostProcess/Ssao/SsaoPass.h diff --git a/SynapseEngine/Engine/Render/Passes/Present/CompositePass.cpp b/SynapseEngine/Engine/Render/Passes/Present/CompositePass.cpp index 51f924c1..ec799726 100644 --- a/SynapseEngine/Engine/Render/Passes/Present/CompositePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Present/CompositePass.cpp @@ -51,7 +51,7 @@ namespace Syn { void CompositePass::PrepareFrame(const RenderContext& context) { auto vkContext = ServiceLocator::GetVkContext(); auto swapChain = vkContext->GetSwapChain(); - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto inputImage = group->GetImage(RenderTargetNames::Main); auto swapchainImage = swapChain->GetImage(context.swapchainImageIndex); @@ -92,7 +92,7 @@ namespace Syn { void CompositePass::BindDescriptors(const RenderContext& context) { auto imageManager = ServiceLocator::GetImageManager(); - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto inputImage = group->GetImage(RenderTargetNames::Main); auto sampler = imageManager->GetSampler(SamplerNames::NearestClampEdge); diff --git a/SynapseEngine/Engine/Render/Passes/Present/GuiPass.cpp b/SynapseEngine/Engine/Render/Passes/Present/GuiPass.cpp index ad6d8f88..6c128bba 100644 --- a/SynapseEngine/Engine/Render/Passes/Present/GuiPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Present/GuiPass.cpp @@ -21,7 +21,7 @@ namespace Syn auto swapchainImage = swapChain->GetImage(context.swapchainImageIndex); VkExtent2D extent = { swapchainImage->GetExtent().width, swapchainImage->GetExtent().height }; - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); std::vector debugTargets = { RenderTargetNames::Main, diff --git a/SynapseEngine/Engine/Render/Passes/Present/PresentationTransitionPass.cpp b/SynapseEngine/Engine/Render/Passes/Present/PresentationTransitionPass.cpp index 79b42b9d..9ea2d644 100644 --- a/SynapseEngine/Engine/Render/Passes/Present/PresentationTransitionPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Present/PresentationTransitionPass.cpp @@ -4,7 +4,7 @@ namespace Syn { void PresentationTransitionPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); std::vector gBufferTargets = { RenderTargetNames::Main, diff --git a/SynapseEngine/Engine/Render/Passes/Preview/MaterialPreviewBloomPass.cpp b/SynapseEngine/Engine/Render/Passes/Preview/MaterialPreviewBloomPass.cpp new file mode 100644 index 00000000..d53e548a --- /dev/null +++ b/SynapseEngine/Engine/Render/Passes/Preview/MaterialPreviewBloomPass.cpp @@ -0,0 +1,358 @@ +#include "MaterialPreviewBloomPass.h" +#include "Engine/ServiceLocator.h" +#include "Engine/Manager/ShaderManager.h" +#include "Engine/Manager/PreviewManager.h" +#include "Engine/Image/ImageManager.h" +#include "Engine/Scene/Scene.h" +#include "Engine/Vk/Image/ImageUtils.h" +#include "Engine/Render/ComputeGroupSize.h" +#include "Engine/Vk/Rendering/PushConstant.h" +#include "Engine/Image/SamplerNames.h" +#include "Engine/Vk/Image/ImageViewNames.h" + +#include "Engine/Shaders/Includes/PushConstants/BloomPrefilterPC.glsl" +#include "Engine/Shaders/Includes/PushConstants/BloomDownSamplePC.glsl" +#include "Engine/Shaders/Includes/PushConstants/BloomUpSamplePC.glsl" +#include "Engine/Shaders/Includes/PushConstants/BloomCompositePC.glsl" + +namespace Syn { + + bool MaterialPreviewBloomPass::ShouldExecute(const RenderContext& context) const { + return context.scene->GetSettings()->postProcess.enableBloom + && !context.scene->GetSettings()->debug.enableDebugVisibility; + } + + void MaterialPreviewBloomPass::Initialize() { + auto sm = ServiceLocator::GetShaderManager(); + _prefilterProgram = sm->CreateProgram("PrevBloomPrefilter", { ShaderNames::BloomPrefilter }); + _downsampleProgram = sm->CreateProgram("PrevBloomDown", { ShaderNames::BloomDownsample }); + _upsampleProgram = sm->CreateProgram("PrevBloomUp", { ShaderNames::BloomUpsample }); + _compositeProgram = sm->CreateProgram("PrevBloomComp", { ShaderNames::BloomComposite }); + } + + void MaterialPreviewBloomPass::Execute(const RenderContext& context) { + auto pm = ServiceLocator::GetPreviewManager(); + + std::vector dirtyMaterials = pm->GetDirtyResources(PreviewResourceType::Material); + if (dirtyMaterials.empty()) return; + + auto atlas = pm->GetAtlasImage(); + auto scratchColor = pm->GetScratchColorImage(); + auto scratchBloom = pm->GetScratchBloomImage(); + + for (uint32_t matId : dirtyMaterials) { + + VkViewport vp; VkRect2D scissor; + pm->GetViewportAndScissor(PreviewResourceType::Material, matId, vp, scissor); + + // Copy Atlas Region to Scratch Color Texture + Vk::ImageBarrierInfo atlasToSrc{}; + atlasToSrc.image = atlas->Handle(); + atlasToSrc.srcStage = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; + atlasToSrc.srcAccess = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; + atlasToSrc.dstStage = VK_PIPELINE_STAGE_2_TRANSFER_BIT; + atlasToSrc.dstAccess = VK_ACCESS_2_TRANSFER_READ_BIT; + atlasToSrc.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + atlasToSrc.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + atlasToSrc.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + atlasToSrc.baseMipLevel = 0; + atlasToSrc.levelCount = 1; + atlasToSrc.baseArrayLayer = 0; + atlasToSrc.layerCount = 1; + Vk::ImageUtils::InsertBarrier(context.cmd, atlasToSrc); + + Vk::ImageBarrierInfo scratchToDst{}; + scratchToDst.image = scratchColor->Handle(); + scratchToDst.srcStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + scratchToDst.srcAccess = VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT; + scratchToDst.dstStage = VK_PIPELINE_STAGE_2_TRANSFER_BIT; + scratchToDst.dstAccess = VK_ACCESS_2_TRANSFER_WRITE_BIT; + scratchToDst.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + scratchToDst.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + scratchToDst.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + scratchToDst.baseMipLevel = 0; + scratchToDst.levelCount = 1; + scratchToDst.baseArrayLayer = 0; + scratchToDst.layerCount = 1; + Vk::ImageUtils::InsertBarrier(context.cmd, scratchToDst); + + VkImageCopy copyRegion{}; + copyRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; + copyRegion.srcOffset = { scissor.offset.x, scissor.offset.y, 0 }; + copyRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; + copyRegion.dstOffset = { 0, 0, 0 }; + copyRegion.extent = { (uint32_t)scissor.extent.width, (uint32_t)scissor.extent.height, 1 }; + vkCmdCopyImage(context.cmd, atlas->Handle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, scratchColor->Handle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©Region); + + // Bloom Prefilter + Vk::ImageBarrierInfo scratchToRead{}; + scratchToRead.image = scratchColor->Handle(); + scratchToRead.srcStage = VK_PIPELINE_STAGE_2_TRANSFER_BIT; + scratchToRead.srcAccess = VK_ACCESS_2_TRANSFER_WRITE_BIT; + scratchToRead.dstStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + scratchToRead.dstAccess = VK_ACCESS_2_SHADER_READ_BIT; + scratchToRead.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + scratchToRead.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + scratchToRead.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + scratchToRead.baseMipLevel = 0; + scratchToRead.levelCount = 1; + scratchToRead.baseArrayLayer = 0; + scratchToRead.layerCount = 1; + Vk::ImageUtils::InsertBarrier(context.cmd, scratchToRead); + + Vk::ImageBarrierInfo bloomSync{}; + bloomSync.image = scratchBloom->Handle(); + bloomSync.srcStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + bloomSync.srcAccess = VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT; + bloomSync.dstStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + bloomSync.dstAccess = VK_ACCESS_2_SHADER_WRITE_BIT; + bloomSync.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + bloomSync.newLayout = VK_IMAGE_LAYOUT_GENERAL; + bloomSync.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + bloomSync.baseMipLevel = 0; + bloomSync.levelCount = 1; + bloomSync.baseArrayLayer = 0; + bloomSync.layerCount = 1; + Vk::ImageUtils::InsertBarrier(context.cmd, bloomSync); + + DispatchPrefilter(context, scratchColor, scratchBloom); + + // Bloom down and up sample simulation + DispatchDownsample(context, scratchBloom); + DispatchUpsample(context, scratchBloom); + + // Bloom scratch composite pass + Vk::ImageBarrierInfo scratchToGen{}; + scratchToGen.image = scratchColor->Handle(); + scratchToGen.srcStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + scratchToGen.srcAccess = VK_ACCESS_2_SHADER_READ_BIT; + scratchToGen.dstStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + scratchToGen.dstAccess = VK_ACCESS_2_SHADER_WRITE_BIT; + scratchToGen.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + scratchToGen.newLayout = VK_IMAGE_LAYOUT_GENERAL; + scratchToGen.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + scratchToGen.baseMipLevel = 0; + scratchToGen.levelCount = 1; + scratchToGen.baseArrayLayer = 0; + scratchToGen.layerCount = 1; + Vk::ImageUtils::InsertBarrier(context.cmd, scratchToGen); + + DispatchComposite(context, scratchColor, scratchBloom); + + // Copy Scratch to Atlas Region + Vk::ImageBarrierInfo scratchToSrc{}; + scratchToSrc.image = scratchColor->Handle(); + scratchToSrc.srcStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + scratchToSrc.srcAccess = VK_ACCESS_2_SHADER_WRITE_BIT; + scratchToSrc.dstStage = VK_PIPELINE_STAGE_2_TRANSFER_BIT; + scratchToSrc.dstAccess = VK_ACCESS_2_TRANSFER_READ_BIT; + scratchToSrc.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + scratchToSrc.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + scratchToSrc.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + scratchToSrc.baseMipLevel = 0; + scratchToSrc.levelCount = 1; + scratchToSrc.baseArrayLayer = 0; + scratchToSrc.layerCount = 1; + Vk::ImageUtils::InsertBarrier(context.cmd, scratchToSrc); + + Vk::ImageBarrierInfo atlasToDst{}; + atlasToDst.image = atlas->Handle(); + atlasToDst.srcStage = VK_PIPELINE_STAGE_2_TRANSFER_BIT; + atlasToDst.srcAccess = VK_ACCESS_2_TRANSFER_READ_BIT; + atlasToDst.dstStage = VK_PIPELINE_STAGE_2_TRANSFER_BIT; + atlasToDst.dstAccess = VK_ACCESS_2_TRANSFER_WRITE_BIT; + atlasToDst.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + atlasToDst.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + atlasToDst.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + atlasToDst.baseMipLevel = 0; + atlasToDst.levelCount = 1; + atlasToDst.baseArrayLayer = 0; + atlasToDst.layerCount = 1; + Vk::ImageUtils::InsertBarrier(context.cmd, atlasToDst); + + VkImageCopy copyBackRegion{}; + copyBackRegion.srcSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; + copyBackRegion.srcOffset = { 0, 0, 0 }; + copyBackRegion.dstSubresource = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1 }; + copyBackRegion.dstOffset = { scissor.offset.x, scissor.offset.y, 0 }; + copyBackRegion.extent = { (uint32_t)scissor.extent.width, (uint32_t)scissor.extent.height, 1 }; + vkCmdCopyImage(context.cmd, scratchColor->Handle(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, atlas->Handle(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©BackRegion); + + // Post transition to prepare for rendering or iteration + Vk::ImageBarrierInfo atlasToColor{}; + atlasToColor.image = atlas->Handle(); + atlasToColor.srcStage = VK_PIPELINE_STAGE_2_TRANSFER_BIT; + atlasToColor.srcAccess = VK_ACCESS_2_TRANSFER_WRITE_BIT; + atlasToColor.dstStage = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT; + atlasToColor.dstAccess = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT; + atlasToColor.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + atlasToColor.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + atlasToColor.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + atlasToColor.baseMipLevel = 0; + atlasToColor.levelCount = 1; + atlasToColor.baseArrayLayer = 0; + atlasToColor.layerCount = 1; + Vk::ImageUtils::InsertBarrier(context.cmd, atlasToColor); + + // Scratch Color vissza Generalra a következő iterációnak + Vk::ImageBarrierInfo scratchBackToGen{}; + scratchBackToGen.image = scratchColor->Handle(); + scratchBackToGen.srcStage = VK_PIPELINE_STAGE_2_TRANSFER_BIT; + scratchBackToGen.srcAccess = VK_ACCESS_2_TRANSFER_READ_BIT; + scratchBackToGen.dstStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + scratchBackToGen.dstAccess = VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT; + scratchBackToGen.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + scratchBackToGen.newLayout = VK_IMAGE_LAYOUT_GENERAL; + scratchBackToGen.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + scratchBackToGen.baseMipLevel = 0; + scratchBackToGen.levelCount = 1; + scratchBackToGen.baseArrayLayer = 0; + scratchBackToGen.layerCount = 1; + Vk::ImageUtils::InsertBarrier(context.cmd, scratchBackToGen); + } + + pm->ClearDirtyResources(PreviewResourceType::Material); + } + + void MaterialPreviewBloomPass::DispatchPrefilter(const RenderContext& context, Vk::Image* colorImage, Vk::Image* bloomImage) { + _prefilterProgram->Bind(context.cmd); + + auto sampler = ServiceLocator::GetImageManager()->GetSampler(SamplerNames::LinearClampEdge); + + Vk::PushDescriptorWriter writer; + writer.AddCombinedImageSampler(0, colorImage->GetView(Vk::ImageViewNames::Default), sampler->Handle(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + writer.AddStorageImage(1, bloomImage->GetView(std::string(Vk::ImageViewNames::Default) + std::string(Vk::ImageViewNames::Mip) + "0"), VK_IMAGE_LAYOUT_GENERAL); + writer.Push(context.cmd, _prefilterProgram->GetLayout(), 2, VK_PIPELINE_BIND_POINT_COMPUTE); + + Vk::PushConstant pc; + pc->knee = context.scene->GetSettings()->postProcess.bloomKnee; + pc->threshold = context.scene->GetSettings()->postProcess.bloomThreshold; + pc->texelSize = 1.0f / glm::vec2(colorImage->GetExtent().width, colorImage->GetExtent().height); + pc.Push(context.cmd, _prefilterProgram->GetLayout()); + + uint32_t gx = ComputeGroupSize::CalculateDispatchCount(colorImage->GetExtent().width, ComputeGroupSize::Image8D); + uint32_t gy = ComputeGroupSize::CalculateDispatchCount(colorImage->GetExtent().height, ComputeGroupSize::Image8D); + vkCmdDispatch(context.cmd, gx, gy, 1); + } + + void MaterialPreviewBloomPass::DispatchDownsample(const RenderContext& context, Vk::Image* bloomImage) { + _downsampleProgram->Bind(context.cmd); + + auto sampler = ServiceLocator::GetImageManager()->GetSampler(SamplerNames::LinearClampEdge); + Vk::PushDescriptorWriter pushWriter; + glm::vec2 currentInSize = glm::vec2(bloomImage->GetExtent().width, bloomImage->GetExtent().height); + + for (uint32_t i = 1; i < bloomImage->GetConfig().mipLevels; ++i) { + glm::vec2 currentOutSize = glm::vec2(std::max(1.0f, std::floor(currentInSize.x / 2.0f)), std::max(1.0f, std::floor(currentInSize.y / 2.0f))); + std::string parentMip = std::string(Vk::ImageViewNames::Default) + std::string(Vk::ImageViewNames::Mip) + std::to_string(i - 1); + std::string currentMip = std::string(Vk::ImageViewNames::Default) + std::string(Vk::ImageViewNames::Mip) + std::to_string(i); + + Vk::ImageBarrierInfo barrier{}; + barrier.image = bloomImage->Handle(); + barrier.srcStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + barrier.srcAccess = VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_SHADER_WRITE_BIT; + barrier.dstStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + barrier.dstAccess = VK_ACCESS_2_SHADER_WRITE_BIT; + barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + barrier.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.baseMipLevel = i; + barrier.levelCount = 1; + barrier.baseArrayLayer = 0; + barrier.layerCount = 1; + Vk::ImageUtils::InsertBarrier(context.cmd, barrier); + + pushWriter.AddCombinedImageSampler(0, bloomImage->GetView(parentMip), sampler->Handle(), VK_IMAGE_LAYOUT_GENERAL); + pushWriter.AddStorageImage(1, bloomImage->GetView(currentMip), VK_IMAGE_LAYOUT_GENERAL); + pushWriter.Push(context.cmd, _downsampleProgram->GetLayout(), 2, VK_PIPELINE_BIND_POINT_COMPUTE); + + Vk::PushConstant pc; + pc->texelSize = 1.0f / currentInSize; + pc.Push(context.cmd, _downsampleProgram->GetLayout()); + + uint32_t groupCountX = ComputeGroupSize::CalculateDispatchCount((uint32_t)currentOutSize.x, ComputeGroupSize::Image8D); + uint32_t groupCountY = ComputeGroupSize::CalculateDispatchCount((uint32_t)currentOutSize.y, ComputeGroupSize::Image8D); + vkCmdDispatch(context.cmd, groupCountX, groupCountY, 1); + + Vk::ImageBarrierInfo readBarrier{}; + readBarrier.image = bloomImage->Handle(); + readBarrier.srcStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + readBarrier.srcAccess = VK_ACCESS_2_SHADER_WRITE_BIT; + readBarrier.dstStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + readBarrier.dstAccess = VK_ACCESS_2_SHADER_READ_BIT; + readBarrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + readBarrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + readBarrier.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + readBarrier.baseMipLevel = i; + readBarrier.levelCount = 1; + readBarrier.baseArrayLayer = 0; + readBarrier.layerCount = 1; + Vk::ImageUtils::InsertBarrier(context.cmd, readBarrier); + + currentInSize = currentOutSize; + } + } + + void MaterialPreviewBloomPass::DispatchUpsample(const RenderContext& context, Vk::Image* bloomImage) { + _upsampleProgram->Bind(context.cmd); + + auto sampler = ServiceLocator::GetImageManager()->GetSampler(SamplerNames::LinearClampEdge); + Vk::PushDescriptorWriter pushWriter; + glm::vec2 baseSize = glm::vec2(bloomImage->GetExtent().width, bloomImage->GetExtent().height); + + for (int32_t i = bloomImage->GetConfig().mipLevels - 1; i > 0; --i) { + glm::vec2 sourceSize = glm::vec2(std::max(1.0f, (float)std::floor(baseSize.x / std::pow(2.0f, i))), std::max(1.0f, (float)std::floor(baseSize.y / std::pow(2.0f, i)))); + glm::vec2 targetSize = glm::vec2(std::max(1.0f, (float)std::floor(baseSize.x / std::pow(2.0f, i - 1))), std::max(1.0f, (float)std::floor(baseSize.y / std::pow(2.0f, i - 1)))); + + std::string sourceMip = std::string(Vk::ImageViewNames::Default) + std::string(Vk::ImageViewNames::Mip) + std::to_string(i); + std::string targetMip = std::string(Vk::ImageViewNames::Default) + std::string(Vk::ImageViewNames::Mip) + std::to_string(i - 1); + + pushWriter.AddCombinedImageSampler(0, bloomImage->GetView(sourceMip), sampler->Handle(), VK_IMAGE_LAYOUT_GENERAL); + pushWriter.AddStorageImage(1, bloomImage->GetView(targetMip), VK_IMAGE_LAYOUT_GENERAL); + pushWriter.Push(context.cmd, _upsampleProgram->GetLayout(), 2, VK_PIPELINE_BIND_POINT_COMPUTE); + + Vk::PushConstant pc; + pc->texelSize = 1.0f / sourceSize; + pc->filterRadius = context.scene->GetSettings()->postProcess.bloomFilterRadius; + pc.Push(context.cmd, _upsampleProgram->GetLayout()); + + uint32_t groupCountX = ComputeGroupSize::CalculateDispatchCount((uint32_t)targetSize.x, ComputeGroupSize::Image8D); + uint32_t groupCountY = ComputeGroupSize::CalculateDispatchCount((uint32_t)targetSize.y, ComputeGroupSize::Image8D); + vkCmdDispatch(context.cmd, groupCountX, groupCountY, 1); + + Vk::ImageBarrierInfo barrier{}; + barrier.image = bloomImage->Handle(); + barrier.srcStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + barrier.srcAccess = VK_ACCESS_2_SHADER_WRITE_BIT; + barrier.dstStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + barrier.dstAccess = VK_ACCESS_2_SHADER_READ_BIT; + barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + barrier.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.baseMipLevel = i - 1; + barrier.levelCount = 1; + barrier.baseArrayLayer = 0; + barrier.layerCount = 1; + Vk::ImageUtils::InsertBarrier(context.cmd, barrier); + } + } + + void MaterialPreviewBloomPass::DispatchComposite(const RenderContext& context, Vk::Image* colorImage, Vk::Image* bloomImage) { + _compositeProgram->Bind(context.cmd); + + auto sampler = ServiceLocator::GetImageManager()->GetSampler(SamplerNames::LinearClampEdge); + Vk::PushDescriptorWriter writer; + writer.AddCombinedImageSampler(0, bloomImage->GetView(std::string(Vk::ImageViewNames::Default) + std::string(Vk::ImageViewNames::Mip) + "0"), sampler->Handle(), VK_IMAGE_LAYOUT_GENERAL); + writer.AddStorageImage(1, colorImage->GetView(Vk::ImageViewNames::Default), VK_IMAGE_LAYOUT_GENERAL); + writer.Push(context.cmd, _compositeProgram->GetLayout(), 2, VK_PIPELINE_BIND_POINT_COMPUTE); + + Vk::PushConstant pc; + pc->exposure = context.scene->GetSettings()->postProcess.bloomExposure; + pc->bloomStrength = context.scene->GetSettings()->postProcess.bloomStrength; + pc.Push(context.cmd, _compositeProgram->GetLayout()); + + uint32_t gx = ComputeGroupSize::CalculateDispatchCount(colorImage->GetExtent().width, ComputeGroupSize::Image8D); + uint32_t gy = ComputeGroupSize::CalculateDispatchCount(colorImage->GetExtent().height, ComputeGroupSize::Image8D); + vkCmdDispatch(context.cmd, gx, gy, 1); + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/Passes/Preview/MaterialPreviewBloomPass.h b/SynapseEngine/Engine/Render/Passes/Preview/MaterialPreviewBloomPass.h new file mode 100644 index 00000000..8562bccd --- /dev/null +++ b/SynapseEngine/Engine/Render/Passes/Preview/MaterialPreviewBloomPass.h @@ -0,0 +1,28 @@ +#pragma once +#include "Engine/Render/IRenderPass.h" +#include "Engine/Vk/Descriptor/PushDescriptorWriter.h" +#include "Engine/Vk/Shader/ShaderProgram.h" +#include +#include + +namespace Syn { + class MaterialPreviewBloomPass : public IRenderPass { + public: + void Initialize() override; + void Execute(const RenderContext& context) override; + bool ShouldExecute(const RenderContext& context) const override; + + std::string GetName() const override { return "MaterialPreviewBloomPass"; } + std::string GetGroup() const override { return PassGroupNames::UtilityPasses; } + private: + void DispatchPrefilter(const RenderContext& context, Vk::Image* colorImage, Vk::Image* bloomImage); + void DispatchDownsample(const RenderContext& context, Vk::Image* bloomImage); + void DispatchUpsample(const RenderContext& context, Vk::Image* bloomImage); + void DispatchComposite(const RenderContext& context, Vk::Image* colorImage, Vk::Image* bloomImage); + + Vk::ShaderProgram* _prefilterProgram; + Vk::ShaderProgram* _downsampleProgram; + Vk::ShaderProgram* _upsampleProgram; + Vk::ShaderProgram* _compositeProgram; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/Passes/Preview/MaterialPreviewPass.cpp b/SynapseEngine/Engine/Render/Passes/Preview/MaterialPreviewPass.cpp new file mode 100644 index 00000000..d64d5f30 --- /dev/null +++ b/SynapseEngine/Engine/Render/Passes/Preview/MaterialPreviewPass.cpp @@ -0,0 +1,135 @@ +#include "MaterialPreviewPass.h" +#include "Engine/ServiceLocator.h" +#include "Engine/Manager/ShaderManager.h" +#include "Engine/Image/ImageManager.h" +#include "Engine/Scene/Scene.h" +#include "Engine/Mesh/ModelManager.h" +#include "Engine/Mesh/Source/MeshSources.h" +#include "Engine/Vk/Image/ImageViewNames.h" +#include "Engine/Manager/PreviewManager.h" +#include "Engine/Vk/Rendering/PushConstant.h" +#include "Engine/Mesh/MeshSourceNames.h" +#include +#include + +namespace Syn { + + #include "Engine/Shaders/Includes/PushConstants/MaterialPreviewPC.glsl" + + void MaterialPreviewPass::Initialize() { + auto shaderManager = ServiceLocator::GetShaderManager(); + auto imageManager = ServiceLocator::GetImageManager(); + + Vk::ShaderProgramConfig config; + config.useDescriptorBuffers = true; + config.layoutOverride = [imageManager](uint32_t setIndex) { + if (setIndex == 0) return imageManager->GetBindlessLayout(); + return VkDescriptorSetLayout{}; + }; + + _shaderProgram = shaderManager->CreateProgram("MaterialPreviewProgram", { + ShaderNames::MaterialPreviewVert, + ShaderNames::MaterialPreviewFrag + }, config); + + _graphicsState = { + .raster = { + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + .cullMode = VK_CULL_MODE_NONE, + .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, + .polygonMode = VK_POLYGON_MODE_FILL, + .lineWidth = 1.0f + }, + .depth = { + .testEnable = VK_FALSE, + .writeEnable = VK_FALSE, + .compareOp = VK_COMPARE_OP_ALWAYS + }, + .blendStates = { + { + .enable = VK_FALSE, + .srcColorFactor = VK_BLEND_FACTOR_SRC_ALPHA, + .dstColorFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaFactor = VK_BLEND_FACTOR_ZERO, + .alphaBlendOp = VK_BLEND_OP_ADD + } + }, + .colorAttachmentCount = 1, + .renderArea = std::nullopt + }; + } + + void MaterialPreviewPass::PrepareFrame(const RenderContext& context) { + _dirtyMaterials.clear(); + _renderInfo.reset(); + + auto pm = ServiceLocator::GetPreviewManager(); + auto modelManager = ServiceLocator::GetModelManager(); + + _dirtyMaterials = pm->GetDirtyResources(PreviewResourceType::Material); + if (_dirtyMaterials.empty()) return; + + auto atlas = pm->GetAtlasImage(); + VkExtent2D extent = { atlas->GetExtent().width, atlas->GetExtent().height }; + _graphicsState.renderArea = std::nullopt; + + _colorAttachments.push_back(Vk::RenderUtils::CreateAttachment({ + .imageView = atlas->GetView(Vk::ImageViewNames::Default), + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE + })); + + _renderInfo = Vk::RenderingInfoConfig{ + .renderArea = extent, + .colorAttachments = _colorAttachments, + .layerCount = 1 + }; + } + + void MaterialPreviewPass::BindDescriptors(const RenderContext& context) { + if (_dirtyMaterials.empty()) return; + + auto imageManager = ServiceLocator::GetImageManager(); + auto bindlessBuffer = imageManager->GetBindlessBuffer(); + bindlessBuffer->Bind(context.cmd, _shaderProgram->GetLayout(), 0, VK_PIPELINE_BIND_POINT_GRAPHICS); + } + + void MaterialPreviewPass::Draw(const RenderContext& context) { + if (_dirtyMaterials.empty() || !_renderInfo.has_value()) return; + + auto pm = ServiceLocator::GetPreviewManager(); + auto modelManager = ServiceLocator::GetModelManager(); + + Vk::PushConstant pc; + pc->frameGlobalContextBufferAddr = context.scene->GetSceneDrawData()->frameContextBuffer.GetAddress(context.frameIndex); + + for (uint32_t matId : _dirtyMaterials) { + VkViewport viewport{}; + VkRect2D scissor{}; + pm->GetViewportAndScissor(PreviewResourceType::Material, matId, viewport, scissor); + + vkCmdSetViewportWithCount(context.cmd, 1, &viewport); + vkCmdSetScissorWithCount(context.cmd, 1, &scissor); + + VkClearAttachment clearAttachment{}; + clearAttachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + clearAttachment.colorAttachment = 0; + clearAttachment.clearValue.color = { {0.15f, 0.15f, 0.15f, 1.0f} }; + + VkClearRect clearRect{}; + clearRect.rect = scissor; + clearRect.baseArrayLayer = 0; + clearRect.layerCount = 1; + + vkCmdClearAttachments(context.cmd, 1, &clearAttachment, 1, &clearRect); + + pc->materialId = matId; + pc.Push(context.cmd, _shaderProgram->GetLayout()); + + vkCmdDraw(context.cmd, 3, 1, 0, 0); + } + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/Passes/Preview/MaterialPreviewPass.h b/SynapseEngine/Engine/Render/Passes/Preview/MaterialPreviewPass.h new file mode 100644 index 00000000..cfc0c76b --- /dev/null +++ b/SynapseEngine/Engine/Render/Passes/Preview/MaterialPreviewPass.h @@ -0,0 +1,23 @@ +#pragma once +#include "Engine/SynApi.h" +#include "Engine/Render/Passes/GraphicsPass.h" +#include + +namespace Syn { + class SYN_API MaterialPreviewPass : public GraphicsPass { + public: + MaterialPreviewPass() = default; + + std::string GetName() const override { return "MaterialPreviewPass"; } + std::string GetGroup() const override { return PassGroupNames::UtilityPasses; } + + void Initialize() override; + bool ShouldCollectStatistics() const override { return false; } + protected: + void PrepareFrame(const RenderContext& context) override; + void BindDescriptors(const RenderContext& context) override; + void Draw(const RenderContext& context) override; + private: + std::vector _dirtyMaterials; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/Passes/Preview/ModelPreviewPass.cpp b/SynapseEngine/Engine/Render/Passes/Preview/ModelPreviewPass.cpp new file mode 100644 index 00000000..d3da2d00 --- /dev/null +++ b/SynapseEngine/Engine/Render/Passes/Preview/ModelPreviewPass.cpp @@ -0,0 +1,184 @@ +#include "ModelPreviewPass.h" +#include "Engine/ServiceLocator.h" +#include "Engine/Manager/ShaderManager.h" +#include "Engine/Image/ImageManager.h" +#include "Engine/Scene/Scene.h" +#include "Engine/Mesh/ModelManager.h" +#include "Engine/Vk/Image/ImageViewNames.h" +#include "Engine/Manager/PreviewManager.h" +#include "Engine/Vk/Rendering/PushConstant.h" + +#include +#include + +namespace Syn { + +#include "Engine/Shaders/Includes/PushConstants/ModelPreviewPC.glsl" + + void ModelPreviewPass::Initialize() { + auto shaderManager = ServiceLocator::GetShaderManager(); + auto imageManager = ServiceLocator::GetImageManager(); + + Vk::ShaderProgramConfig config; + config.useDescriptorBuffers = true; + config.layoutOverride = [imageManager](uint32_t setIndex) { + if (setIndex == 0) return imageManager->GetBindlessLayout(); + return VkDescriptorSetLayout{}; + }; + + _shaderProgram = shaderManager->CreateProgram("ModelPreviewProgram", { + ShaderNames::ModelPreviewVert, + ShaderNames::ModelPreviewFrag, + }, config); + + _graphicsState = { + .raster = { + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + .cullMode = VK_CULL_MODE_BACK_BIT, + .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, + .polygonMode = VK_POLYGON_MODE_FILL, + .lineWidth = 1.0f + }, + .depth = { + .testEnable = VK_TRUE, + .writeEnable = VK_TRUE, + .compareOp = VK_COMPARE_OP_LESS + }, + .blendStates = { + { + .enable = VK_FALSE, + .srcColorFactor = VK_BLEND_FACTOR_SRC_ALPHA, + .dstColorFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, + .colorBlendOp = VK_BLEND_OP_ADD, + .srcAlphaFactor = VK_BLEND_FACTOR_ONE, + .dstAlphaFactor = VK_BLEND_FACTOR_ZERO, + .alphaBlendOp = VK_BLEND_OP_ADD + } + }, + .colorAttachmentCount = 1, + .renderArea = std::nullopt + }; + } + + void ModelPreviewPass::PrepareFrame(const RenderContext& context) { + _dirtyModels.clear(); + _renderInfo.reset(); + _colorAttachments.clear(); + + auto pm = ServiceLocator::GetPreviewManager(); + + _dirtyModels = pm->GetDirtyResources(PreviewResourceType::Model); + if (_dirtyModels.empty()) return; + + auto atlas = pm->GetAtlasImage(); + auto atlasDepth = pm->GetAtlasDepthImage(); + VkExtent2D extent = { atlas->GetExtent().width, atlas->GetExtent().height }; + _graphicsState.renderArea = std::nullopt; + + _colorAttachments.push_back(Vk::RenderUtils::CreateAttachment({ + .imageView = atlas->GetView(Vk::ImageViewNames::Default), + .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE + })); + + _depthAttachment = Vk::RenderUtils::CreateAttachment({ + .imageView = atlasDepth->GetView(Vk::ImageViewNames::Default), + .layout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, + .clearValue = VkClearValue{.depthStencil = {1.0f, 0}}, + .loadOp = VK_ATTACHMENT_LOAD_OP_LOAD, + .storeOp = VK_ATTACHMENT_STORE_OP_STORE, + }); + + _renderInfo = Vk::RenderingInfoConfig{ + .renderArea = extent, + .colorAttachments = _colorAttachments, + .depthAttachment = &_depthAttachment.value(), + .layerCount = 1 + }; + } + + void ModelPreviewPass::BindDescriptors(const RenderContext& context) { + if (_dirtyModels.empty()) return; + + auto imageManager = ServiceLocator::GetImageManager(); + auto bindlessBuffer = imageManager->GetBindlessBuffer(); + bindlessBuffer->Bind(context.cmd, _shaderProgram->GetLayout(), 0, VK_PIPELINE_BIND_POINT_GRAPHICS); + } + + void ModelPreviewPass::Draw(const RenderContext& context) { + if (_dirtyModels.empty() || !_renderInfo.has_value()) return; + + auto pm = ServiceLocator::GetPreviewManager(); + auto modelManager = ServiceLocator::GetModelManager(); + + Vk::PushConstant pc; + pc->frameGlobalContextBufferAddr = context.scene->GetSceneDrawData()->frameContextBuffer.GetAddress(context.frameIndex); + + auto modelSnapshot = modelManager->GetResourceSnapshot(); + + for (uint32_t modelId : _dirtyModels) + { + auto resource = modelSnapshot[modelId].resource; + if (resource == nullptr) continue; + + VkViewport viewport{}; + VkRect2D scissor{}; + pm->GetViewportAndScissor(PreviewResourceType::Model, modelId, viewport, scissor); + + vkCmdSetViewportWithCount(context.cmd, 1, &viewport); + vkCmdSetScissorWithCount(context.cmd, 1, &scissor); + + VkClearAttachment clearAttachments[2] = {}; + + clearAttachments[0].aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + clearAttachments[0].colorAttachment = 0; + clearAttachments[0].clearValue.color = { {0.15f, 0.15f, 0.15f, 1.0f} }; + + clearAttachments[1].aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + clearAttachments[1].clearValue.depthStencil = { 1.0f, 0 }; + + VkClearRect clearRect{}; + clearRect.rect = scissor; + clearRect.baseArrayLayer = 0; + clearRect.layerCount = 1; + vkCmdClearAttachments(context.cmd, 2, clearAttachments, 1, &clearRect); + + const auto& cpuData = resource->cpuData; + glm::vec3 center = cpuData.globalCollider.center; + float radius = cpuData.globalCollider.radius > 0.0f ? cpuData.globalCollider.radius * 1.05f : 1.0f; + + float targetSize = 10.0f; + float scaleFactor = targetSize / (radius * 2.0f); + float cameraDistance = targetSize * 1.25f; + + glm::vec3 camDir = glm::normalize(glm::vec3(1.0f, 0.75f, 1.0f)); + glm::vec3 camPos = camDir * cameraDistance; + glm::mat4 view = glm::lookAt(camPos, glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); + + float nearPlane = targetSize * 0.05f; + float farPlane = targetSize * 5.0f; + glm::mat4 proj = glm::perspective(glm::radians(45.0f), 1.0f, nearPlane, farPlane); + proj[1][1] *= -1.0f; + + glm::mat4 model = glm::scale(glm::mat4(1.0f), glm::vec3(scaleFactor)); + model = glm::translate(model, -center); + + pc->modelId = modelId; + pc->mvp = proj * view * model; + + const auto& drawCommands = cpuData.baseDrawCommands; + uint32_t meshCount = cpuData.globalMeshCount; + + for (uint32_t meshIdx = 0; meshIdx < meshCount; ++meshIdx) { + pc->meshIndex = meshIdx; + pc.Push(context.cmd, _shaderProgram->GetLayout()); + + uint32_t lod0CommandIndex = meshIdx * 4; + const auto& cmd = drawCommands[lod0CommandIndex]; + + vkCmdDraw(context.cmd, cmd.traditionalCmd.vertexCount, 1, cmd.traditionalCmd.firstVertex, cmd.traditionalCmd.firstInstance); + } + } + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/Passes/Preview/ModelPreviewPass.h b/SynapseEngine/Engine/Render/Passes/Preview/ModelPreviewPass.h new file mode 100644 index 00000000..1d8d2da1 --- /dev/null +++ b/SynapseEngine/Engine/Render/Passes/Preview/ModelPreviewPass.h @@ -0,0 +1,24 @@ +#pragma once +#include "Engine/SynApi.h" +#include "Engine/Render/Passes/GraphicsPass.h" +#include + +namespace Syn +{ + class SYN_API ModelPreviewPass : public GraphicsPass { + public: + ModelPreviewPass() = default; + + std::string GetName() const override { return "ModelPreviewPass"; } + std::string GetGroup() const override { return PassGroupNames::UtilityPasses; } + + void Initialize() override; + bool ShouldCollectStatistics() const override { return false; } + protected: + void PrepareFrame(const RenderContext& context) override; + void BindDescriptors(const RenderContext& context) override; + void Draw(const RenderContext& context) override; + private: + std::vector _dirtyModels; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/Passes/Preview/PreviewPostTransitionPass.cpp b/SynapseEngine/Engine/Render/Passes/Preview/PreviewPostTransitionPass.cpp new file mode 100644 index 00000000..0b71c770 --- /dev/null +++ b/SynapseEngine/Engine/Render/Passes/Preview/PreviewPostTransitionPass.cpp @@ -0,0 +1,42 @@ +#include "PreviewPostTransitionPass.h" +#include "Engine/ServiceLocator.h" +#include "Engine/Manager/PreviewManager.h" + +namespace Syn { + + void PreviewPostTransitionPass::PrepareFrame(const RenderContext& context) { + auto pm = ServiceLocator::GetPreviewManager(); + + _imageTransitions.push_back({ + .image = pm->GetAtlasImage(), + .newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + .dstStage = VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT, + .dstAccess = VK_ACCESS_2_SHADER_READ_BIT, + .discardContent = false + }); + + _imageTransitions.push_back({ + .image = pm->GetScratchColorImage(), + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .dstStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .dstAccess = VK_ACCESS_2_SHADER_WRITE_BIT | VK_ACCESS_2_SHADER_READ_BIT, + .discardContent = false + }); + + _imageTransitions.push_back({ + .image = pm->GetScratchBloomImage(), + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .dstStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .dstAccess = VK_ACCESS_2_SHADER_WRITE_BIT | VK_ACCESS_2_SHADER_READ_BIT, + .discardContent = false + }); + + _imageTransitions.push_back({ + .image = pm->GetAtlasDepthImage(), + .newLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, + .dstStage = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT, + .dstAccess = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT, + .discardContent = false + }); + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/Passes/Preview/PreviewPostTransitionPass.h b/SynapseEngine/Engine/Render/Passes/Preview/PreviewPostTransitionPass.h new file mode 100644 index 00000000..8acaefa4 --- /dev/null +++ b/SynapseEngine/Engine/Render/Passes/Preview/PreviewPostTransitionPass.h @@ -0,0 +1,13 @@ +#pragma once +#include "Engine/SynApi.h" +#include "Engine/Render/Passes/TransitionPass.h" + +namespace Syn { + class SYN_API PreviewPostTransitionPass : public TransitionPass { + public: + std::string GetName() const override { return "PreviewPostTransitionPass"; } + std::string GetGroup() const override { return PassGroupNames::UtilityPasses; } + protected: + void PrepareFrame(const RenderContext& context) override; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/Passes/Preview/PreviewPreTransitionPass.cpp b/SynapseEngine/Engine/Render/Passes/Preview/PreviewPreTransitionPass.cpp new file mode 100644 index 00000000..ecf3f3d1 --- /dev/null +++ b/SynapseEngine/Engine/Render/Passes/Preview/PreviewPreTransitionPass.cpp @@ -0,0 +1,42 @@ +#include "PreviewPreTransitionPass.h" +#include "Engine/ServiceLocator.h" +#include "Engine/Manager/PreviewManager.h" + +namespace Syn { + + void PreviewPreTransitionPass::PrepareFrame(const RenderContext& context) { + auto pm = ServiceLocator::GetPreviewManager(); + + _imageTransitions.push_back({ + .image = pm->GetAtlasImage(), + .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + .dstStage = VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT, + .dstAccess = VK_ACCESS_2_COLOR_ATTACHMENT_WRITE_BIT, + .discardContent = false + }); + + _imageTransitions.push_back({ + .image = pm->GetScratchColorImage(), + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .dstStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .dstAccess = VK_ACCESS_2_SHADER_WRITE_BIT | VK_ACCESS_2_SHADER_READ_BIT, + .discardContent = false + }); + + _imageTransitions.push_back({ + .image = pm->GetScratchBloomImage(), + .newLayout = VK_IMAGE_LAYOUT_GENERAL, + .dstStage = VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT, + .dstAccess = VK_ACCESS_2_SHADER_WRITE_BIT | VK_ACCESS_2_SHADER_READ_BIT, + .discardContent = false + }); + + _imageTransitions.push_back({ + .image = pm->GetAtlasDepthImage(), + .newLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, + .dstStage = VK_PIPELINE_STAGE_2_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_2_LATE_FRAGMENT_TESTS_BIT, + .dstAccess = VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_2_DEPTH_STENCIL_ATTACHMENT_READ_BIT, + .discardContent = false + }); + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/Passes/Preview/PreviewPreTransitionPass.h b/SynapseEngine/Engine/Render/Passes/Preview/PreviewPreTransitionPass.h new file mode 100644 index 00000000..552a70c9 --- /dev/null +++ b/SynapseEngine/Engine/Render/Passes/Preview/PreviewPreTransitionPass.h @@ -0,0 +1,13 @@ +#pragma once +#include "Engine/SynApi.h" +#include "Engine/Render/Passes/TransitionPass.h" + +namespace Syn { + class SYN_API PreviewPreTransitionPass : public TransitionPass { + public: + std::string GetName() const override { return "PreviewPreTransitionPass"; } + std::string GetGroup() const override { return PassGroupNames::UtilityPasses; } + protected: + void PrepareFrame(const RenderContext& context) override; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/Passes/Setup/GlobalFrameSetupPass.cpp b/SynapseEngine/Engine/Render/Passes/Setup/GlobalFrameSetupPass.cpp index 0b1bb0f5..2818d4c4 100644 --- a/SynapseEngine/Engine/Render/Passes/Setup/GlobalFrameSetupPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Setup/GlobalFrameSetupPass.cpp @@ -5,6 +5,7 @@ #include "Engine/Material/MaterialManager.h" #include "Engine/Mesh/ModelManager.h" #include "Engine/Animation/AnimationManager.h" +#include "Engine/Image/ImageManager.h" #include "Engine/Render/RenderNames.h" #include "Engine/Render/ComputeGroupSize.h" #include "Engine/Scene/BufferNames.h" @@ -25,7 +26,7 @@ namespace Syn { auto drawData = scene->GetSceneDrawData(); auto settings = scene->GetSettings(); auto compManager = scene->GetComponentBufferManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); uint32_t fIdx = context.frameIndex; uint32_t width = rtGroup->GetWidth(); @@ -36,9 +37,12 @@ namespace Syn { auto modelManager = ServiceLocator::GetModelManager(); auto materialManager = ServiceLocator::GetMaterialManager(); auto animationManager = ServiceLocator::GetAnimationManager(); + auto imageManager = ServiceLocator::GetImageManager(); FrameGlobalContext ctx = {}; + ctx.textureMetadataBufferAddr = imageManager->GetAddressBufferDeviceAddress(); + ctx.globalDrawCountBufferAddr = drawData->Models.drawCountBuffer.GetAddress(fIdx); ctx.globalInstanceIndexBufferAddr = drawData->Models.instanceBuffer.GetAddress(fIdx); ctx.globalIndirectCommandBufferAddr = drawData->Models.indirectBuffer.GetAddress(fIdx); @@ -49,11 +53,14 @@ namespace Syn { ctx.cameraVisibleIndexBufferAddr = compManager->GetBufferAddr(BufferNames::CameraVisibleData, fIdx); ctx.cameraBufferAddr = compManager->GetBufferAddr(BufferNames::CameraData, fIdx); ctx.cameraSparseMapBufferAddr = compManager->GetBufferAddr(BufferNames::CameraSparseMap, fIdx); - + ctx.transformBufferAddr = compManager->GetBufferAddr(BufferNames::TransformData, fIdx); ctx.transformSparseMapBufferAddr = compManager->GetBufferAddr(BufferNames::TransformSparseMap, fIdx); ctx.transformModelLinkBufferAddr = compManager->GetBufferAddr(BufferNames::TransformModelLinkData, fIdx); + ctx.tagSparseMapBufferAddr = compManager->GetBufferAddr(BufferNames::TagSparseMap, fIdx); + ctx.tagDataBufferAddr = compManager->GetBufferAddr(BufferNames::TagData, fIdx); + ctx.staticChunkDataBufferAddr = drawData->Chunks.chunkDataBuffer.GetAddress(fIdx); ctx.staticChunkVisibleIndexBufferAddr = drawData->Chunks.chunkVisibilityBuffer.GetAddress(fIdx); ctx.staticChunkCountBufferAddr = drawData->Chunks.chunkIndirectDispatchBuffer.GetAddress(fIdx); @@ -277,5 +284,22 @@ namespace Syn { ServiceLocator::GetAnimationManager()->RecordSync(context.cmd); ServiceLocator::GetModelManager()->RecordSync(context.cmd); ServiceLocator::GetMaterialManager()->RecordSync(context.cmd); + ServiceLocator::GetImageManager()->RecordSync(context.cmd); + + Vk::GlobalBarrierInfo globalBarrier{}; + + globalBarrier.srcStage = VK_PIPELINE_STAGE_2_TRANSFER_BIT | VK_PIPELINE_STAGE_2_HOST_BIT | VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT; + globalBarrier.srcAccess = VK_ACCESS_2_TRANSFER_WRITE_BIT | VK_ACCESS_2_HOST_WRITE_BIT | VK_ACCESS_2_SHADER_WRITE_BIT; + + globalBarrier.dstStage = VK_PIPELINE_STAGE_2_TASK_SHADER_BIT_EXT | + VK_PIPELINE_STAGE_2_MESH_SHADER_BIT_EXT | + VK_PIPELINE_STAGE_2_VERTEX_SHADER_BIT | + VK_PIPELINE_STAGE_2_FRAGMENT_SHADER_BIT | + VK_PIPELINE_STAGE_2_COMPUTE_SHADER_BIT | + VK_PIPELINE_STAGE_2_DRAW_INDIRECT_BIT; + + globalBarrier.dstAccess = VK_ACCESS_2_SHADER_READ_BIT | VK_ACCESS_2_INDIRECT_COMMAND_READ_BIT | VK_ACCESS_2_MEMORY_READ_BIT; + + Vk::BufferUtils::InsertGlobalBarrier(context.cmd, globalBarrier); } } \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Common/DepthCopyPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Common/DepthCopyPass.cpp index 49a32eee..73ca138c 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Common/DepthCopyPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Common/DepthCopyPass.cpp @@ -4,7 +4,7 @@ namespace Syn { void DepthCopyPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); if (!group) return; auto srcDepth = group->GetImage(RenderTargetNames::OpaqueDepth); @@ -29,7 +29,7 @@ namespace Syn } void DepthCopyPass::Transfer(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); if (!group) return; auto srcDepth = group->GetImage(RenderTargetNames::OpaqueDepth); diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Common/OpaqueInitPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Common/OpaqueInitPass.cpp index bac9851e..605d2ac5 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Common/OpaqueInitPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Common/OpaqueInitPass.cpp @@ -4,7 +4,7 @@ namespace Syn { void OpaqueInitPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); if (!group) return; VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Common/TransparentInitPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Common/TransparentInitPass.cpp index dc69a1a6..0748ff50 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Common/TransparentInitPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Common/TransparentInitPass.cpp @@ -4,7 +4,7 @@ namespace Syn { void TransparentInitPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/MeshletOpaqueDeferredPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/MeshletOpaqueDeferredPass.cpp index 03277c5b..cdd9afd6 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/MeshletOpaqueDeferredPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/MeshletOpaqueDeferredPass.cpp @@ -94,7 +94,7 @@ namespace Syn { } void MeshletOpaqueDeferredPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; @@ -137,7 +137,7 @@ namespace Syn { auto drawData = scene->GetSceneDrawData(); auto componentBufferManager = scene->GetComponentBufferManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto animationManager = ServiceLocator::GetAnimationManager(); @@ -157,7 +157,7 @@ namespace Syn { //Using prevous frame's depth pyramid! uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto depthPyramid = rtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/MeshletOpaqueDeferredPass.h b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/MeshletOpaqueDeferredPass.h index 02f335da..cc217788 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/MeshletOpaqueDeferredPass.h +++ b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/MeshletOpaqueDeferredPass.h @@ -13,6 +13,7 @@ namespace Syn std::string GetGroup() const override { return PassGroupNames::DeferredGBufferPasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/OpaqueDeferredTransitionPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/OpaqueDeferredTransitionPass.cpp index 319b67a1..502df2dd 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/OpaqueDeferredTransitionPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/OpaqueDeferredTransitionPass.cpp @@ -8,7 +8,7 @@ namespace Syn { } void OpaqueDeferredTransitionPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); std::vector targets = { RenderTargetNames::ColorMetallic, diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/TraditionalOpaqueDeferredPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/TraditionalOpaqueDeferredPass.cpp index dc6ee974..6c357c89 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/TraditionalOpaqueDeferredPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/TraditionalOpaqueDeferredPass.cpp @@ -87,7 +87,7 @@ namespace Syn { } void TraditionalOpaqueDeferredPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/TraditionalOpaqueDeferredPass.h b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/TraditionalOpaqueDeferredPass.h index dcfefcd5..3dcc9817 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/TraditionalOpaqueDeferredPass.h +++ b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/GBuffer/TraditionalOpaqueDeferredPass.h @@ -11,6 +11,7 @@ namespace Syn { std::string GetName() const override { return _passName; } std::string GetGroup() const override { return PassGroupNames::DeferredGBufferPasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void BindDescriptors(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredDirectionLightPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredDirectionLightPass.cpp index 56af814f..d0977bed 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredDirectionLightPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredDirectionLightPass.cpp @@ -59,7 +59,7 @@ namespace Syn { } void DeferredDirectionLightPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; @@ -81,7 +81,7 @@ namespace Syn { void DeferredDirectionLightPass::PushConstants(const RenderContext& context) { auto scene = context.scene; auto bufferManager = scene->GetComponentBufferManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); uint32_t fIdx = context.frameIndex; Vk::PushConstant pc; @@ -90,7 +90,7 @@ namespace Syn { } void DeferredDirectionLightPass::BindDescriptors(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto imageManager = ServiceLocator::GetImageManager(); auto sampler = imageManager->GetSampler(SamplerNames::NearestClampEdge)->Handle(); auto ssaoSampler = imageManager->GetSampler(SamplerNames::LinearClampEdge)->Handle(); diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredDirectionLightPass.h b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredDirectionLightPass.h index e31b4e3f..b710044c 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredDirectionLightPass.h +++ b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredDirectionLightPass.h @@ -10,6 +10,7 @@ namespace Syn { std::string GetName() const override { return "DeferredDirectionLightPass"; } std::string GetGroup() const override { return PassGroupNames::DeferredLightingPasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void BindDescriptors(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredEmissiveAoPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredEmissiveAoPass.cpp index a1a2dea3..91683464 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredEmissiveAoPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredEmissiveAoPass.cpp @@ -62,7 +62,7 @@ namespace Syn { } void DeferredEmissiveAoPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; @@ -94,7 +94,7 @@ namespace Syn { } void DeferredEmissiveAoPass::BindDescriptors(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto imageManager = ServiceLocator::GetImageManager(); auto nearestSampler = imageManager->GetSampler(SamplerNames::NearestClampEdge)->Handle(); auto ssaoSampler = imageManager->GetSampler(SamplerNames::LinearClampEdge)->Handle(); diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredLightTransitionPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredLightTransitionPass.cpp index 9d02eb21..3c3f34d3 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredLightTransitionPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredLightTransitionPass.cpp @@ -10,7 +10,7 @@ namespace Syn { } void DeferredLightTransitionPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); std::vector gBufferTargets = { RenderTargetNames::ColorMetallic, diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredPointLightPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredPointLightPass.cpp index 11d1fc70..47ef3420 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredPointLightPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredPointLightPass.cpp @@ -67,7 +67,7 @@ namespace Syn { } void DeferredPointLightPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; @@ -93,7 +93,7 @@ namespace Syn { auto scene = context.scene; auto bufferManager = scene->GetComponentBufferManager(); auto modelManager = ServiceLocator::GetModelManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); uint32_t fIdx = context.frameIndex; auto cube = modelManager->GetResource(MeshSourceNames::Cube); @@ -106,7 +106,7 @@ namespace Syn { } void DeferredPointLightPass::BindDescriptors(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto imageManager = ServiceLocator::GetImageManager(); auto sampler = imageManager->GetSampler(SamplerNames::NearestClampEdge)->Handle(); auto ssaoSampler = imageManager->GetSampler(SamplerNames::LinearClampEdge)->Handle(); diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredPointLightPass.h b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredPointLightPass.h index 60d36250..928c4967 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredPointLightPass.h +++ b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredPointLightPass.h @@ -10,6 +10,7 @@ namespace Syn { std::string GetName() const override { return "DeferredPointLightPass"; } std::string GetGroup() const override { return PassGroupNames::DeferredLightingPasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void BindDescriptors(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredSpotLightPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredSpotLightPass.cpp index 95d2ae8b..cf82d411 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredSpotLightPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredSpotLightPass.cpp @@ -67,7 +67,7 @@ namespace Syn { } void DeferredSpotLightPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; @@ -93,7 +93,7 @@ namespace Syn { auto scene = context.scene; auto bufferManager = scene->GetComponentBufferManager(); auto modelManager = ServiceLocator::GetModelManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); uint32_t fIdx = context.frameIndex; auto pyramid = modelManager->GetResource(MeshSourceNames::ProxyPyramid); @@ -106,7 +106,7 @@ namespace Syn { } void DeferredSpotLightPass::BindDescriptors(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto imageManager = ServiceLocator::GetImageManager(); auto sampler = imageManager->GetSampler(SamplerNames::NearestClampEdge)->Handle(); auto ssaoSampler = imageManager->GetSampler(SamplerNames::LinearClampEdge)->Handle(); diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredSpotLightPass.h b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredSpotLightPass.h index 1ebbc09c..2d24f5f1 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredSpotLightPass.h +++ b/SynapseEngine/Engine/Render/Passes/Shading/Deferred/Lighting/DeferredSpotLightPass.h @@ -10,6 +10,7 @@ namespace Syn { std::string GetName() const override { return "DeferredSpotLightPass"; } std::string GetGroup() const override { return PassGroupNames::DeferredLightingPasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void BindDescriptors(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterPointLightCountPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterPointLightCountPass.cpp index 28b241d4..d448a9b5 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterPointLightCountPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterPointLightCountPass.cpp @@ -27,7 +27,7 @@ namespace Syn { auto scene = context.scene; auto drawData = scene->GetSceneDrawData(); auto compManager = scene->GetComponentBufferManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); uint32_t fIdx = context.frameIndex; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterPointLightWritePass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterPointLightWritePass.cpp index 33eb99dd..87d415a7 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterPointLightWritePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterPointLightWritePass.cpp @@ -28,7 +28,7 @@ namespace Syn { auto scene = context.scene; auto drawData = scene->GetSceneDrawData(); auto compManager = scene->GetComponentBufferManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); uint32_t fIdx = context.frameIndex; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterSetupPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterSetupPass.cpp index 88ba0337..3c2f1884 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterSetupPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterSetupPass.cpp @@ -34,7 +34,7 @@ namespace Syn { auto scene = context.scene; auto drawData = scene->GetSceneDrawData(); auto compManager = scene->GetComponentBufferManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); uint32_t fIdx = context.frameIndex; @@ -48,7 +48,7 @@ namespace Syn { void ClusterSetupPass::BindDescriptors(const RenderContext& context) { auto imageManager = ServiceLocator::GetImageManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); //Using current frame's depth pyramid! auto depthPyramid = rtGroup->GetImage(RenderTargetNames::DepthPyramid); @@ -67,7 +67,7 @@ namespace Syn { void ClusterSetupPass::Dispatch(const RenderContext& context) { auto scene = context.scene; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto drawData = context.scene->GetSceneDrawData(); auto compManager = scene->GetComponentBufferManager(); uint32_t fIdx = context.frameIndex; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterSpotLightCountPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterSpotLightCountPass.cpp index bc4f5d4f..44c7f317 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterSpotLightCountPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterSpotLightCountPass.cpp @@ -28,7 +28,7 @@ namespace Syn auto scene = context.scene; auto drawData = scene->GetSceneDrawData(); auto compManager = scene->GetComponentBufferManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); uint32_t fIdx = context.frameIndex; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterSpotLightWritePass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterSpotLightWritePass.cpp index 852f08b5..052a4dcd 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterSpotLightWritePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Clustering/ClusterSpotLightWritePass.cpp @@ -27,7 +27,7 @@ namespace Syn { auto scene = context.scene; auto drawData = scene->GetSceneDrawData(); auto compManager = scene->GetComponentBufferManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); uint32_t fIdx = context.frameIndex; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/MeshletOpaqueDepthPrepass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/MeshletOpaqueDepthPrepass.cpp index fa106b5f..526fd3bc 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/MeshletOpaqueDepthPrepass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/MeshletOpaqueDepthPrepass.cpp @@ -91,7 +91,7 @@ namespace Syn { } void MeshletOpaqueDepthPrepass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; @@ -130,7 +130,7 @@ namespace Syn { auto materialManager = ServiceLocator::GetMaterialManager(); auto drawData = scene->GetSceneDrawData(); auto componentBufferManager = scene->GetComponentBufferManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto animationManager = ServiceLocator::GetAnimationManager(); uint32_t fIdx = context.frameIndex; @@ -149,7 +149,7 @@ namespace Syn { //Using prevous frame's depth pyramid! uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto depthPyramid = rtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/MeshletOpaqueDepthPrepass.h b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/MeshletOpaqueDepthPrepass.h index fd6acc96..d8b5c80b 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/MeshletOpaqueDepthPrepass.h +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/MeshletOpaqueDepthPrepass.h @@ -12,6 +12,7 @@ namespace Syn std::string GetName() const override { return _passName; } std::string GetGroup() const override { return PassGroupNames::ForwardPlusDepthPrePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/MeshletTransparentDepthPrepass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/MeshletTransparentDepthPrepass.cpp index c92786c8..d078a0fd 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/MeshletTransparentDepthPrepass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/MeshletTransparentDepthPrepass.cpp @@ -79,7 +79,7 @@ namespace Syn { } void MeshletTransparentDepthPrepass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; @@ -120,7 +120,7 @@ namespace Syn { auto materialManager = ServiceLocator::GetMaterialManager(); auto drawData = scene->GetSceneDrawData(); auto componentBufferManager = scene->GetComponentBufferManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto animationManager = ServiceLocator::GetAnimationManager(); uint32_t fIdx = context.frameIndex; @@ -140,7 +140,7 @@ namespace Syn { //Using prevous frame's depth pyramid! uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto depthPyramid = rtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/MeshletTransparentDepthPrepass.h b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/MeshletTransparentDepthPrepass.h index 2a8e8aa0..ff534c25 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/MeshletTransparentDepthPrepass.h +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/MeshletTransparentDepthPrepass.h @@ -11,6 +11,7 @@ namespace Syn { std::string GetName() const override { return _passName; } std::string GetGroup() const override { return PassGroupNames::ForwardPlusDepthPrePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: void PrepareFrame(const RenderContext& context) override; void PushConstants(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/OpaqueDepthTransitionPrepass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/OpaqueDepthTransitionPrepass.cpp index 1658a622..f7aa2bb7 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/OpaqueDepthTransitionPrepass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/OpaqueDepthTransitionPrepass.cpp @@ -9,7 +9,7 @@ namespace Syn { } void OpaqueDepthTransitionPrepass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); if (auto entityImg = group->GetImage(RenderTargetNames::EntityIndex)) { if (entityImg->GetLayout() != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalOpaqueDepthPrepass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalOpaqueDepthPrepass.cpp index 06f76b80..50455c14 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalOpaqueDepthPrepass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalOpaqueDepthPrepass.cpp @@ -85,7 +85,7 @@ namespace Syn { } void TraditionalOpaqueDepthPrepass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalOpaqueDepthPrepass.h b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalOpaqueDepthPrepass.h index 5429dbcf..08e18201 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalOpaqueDepthPrepass.h +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalOpaqueDepthPrepass.h @@ -11,6 +11,7 @@ namespace Syn { std::string GetName() const override { return _passName; } std::string GetGroup() const override { return PassGroupNames::ForwardPlusDepthPrePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalTransparentDepthPrepass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalTransparentDepthPrepass.cpp index 1acdd52b..d52a68e8 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalTransparentDepthPrepass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalTransparentDepthPrepass.cpp @@ -73,7 +73,7 @@ namespace Syn { } void TraditionalTransparentDepthPrepass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalTransparentDepthPrepass.h b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalTransparentDepthPrepass.h index f67da7c7..e99e0280 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalTransparentDepthPrepass.h +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalTransparentDepthPrepass.h @@ -11,6 +11,7 @@ namespace Syn { std::string GetName() const override { return _passName; } std::string GetGroup() const override { return PassGroupNames::ForwardPlusDepthPrePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: void PrepareFrame(const RenderContext& context) override; void PushConstants(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TransparentDepthTransitionPrepass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TransparentDepthTransitionPrepass.cpp index ecb1fac1..2e2f7e11 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TransparentDepthTransitionPrepass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/DepthPrepass/TransparentDepthTransitionPrepass.cpp @@ -3,7 +3,7 @@ namespace Syn { void TransparentDepthTransitionPrepass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); if (auto entityImg = group->GetImage(RenderTargetNames::EntityIndex)) { if (entityImg->GetLayout() != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/MeshletOpaqueForwardPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/MeshletOpaqueForwardPass.cpp index 40102b2e..d593ff62 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/MeshletOpaqueForwardPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/MeshletOpaqueForwardPass.cpp @@ -92,7 +92,7 @@ namespace Syn { } void MeshletOpaqueForwardPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; @@ -146,8 +146,8 @@ namespace Syn { //Using prevous frame's depth pyramid! uint fIdx = context.frameIndex; uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto prevRtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, fIdx); + auto prevRtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, fIdx); auto depthPyramid = prevRtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/MeshletOpaqueForwardPass.h b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/MeshletOpaqueForwardPass.h index 3541662b..e4cda329 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/MeshletOpaqueForwardPass.h +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/MeshletOpaqueForwardPass.h @@ -11,6 +11,7 @@ namespace Syn { std::string GetName() const override { return _passName; } std::string GetGroup() const override { return PassGroupNames::ForwardPlusLightingPasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/OpaqueForwardTransitionPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/OpaqueForwardTransitionPass.cpp index bb4adb9b..997f3dd9 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/OpaqueForwardTransitionPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/OpaqueForwardTransitionPass.cpp @@ -4,12 +4,11 @@ namespace Syn { bool OpaqueForwardTransitionPass::ShouldExecute(const RenderContext& context) const { - return context.scene->GetSettings()->lighting.pipelineType == PipelineType::ForwardPlus - && !context.scene->GetSettings()->debug.enableDebugVisibility;; + return !context.scene->GetSettings()->debug.enableDebugVisibility; } void OpaqueForwardTransitionPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); if (auto mainImg = group->GetImage(RenderTargetNames::Main)) { if (mainImg->GetLayout() != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) { diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/TraditionalOpaqueForwardPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/TraditionalOpaqueForwardPass.cpp index 744363a7..1c6c59bf 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/TraditionalOpaqueForwardPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/TraditionalOpaqueForwardPass.cpp @@ -89,7 +89,7 @@ namespace Syn { } void TraditionalOpaqueForwardPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; @@ -139,7 +139,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); uint fIdx = context.frameIndex; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, fIdx); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, fIdx); auto drawData = context.scene->GetSceneDrawData(); auto ssaoTexture = rtGroup->GetImage(RenderTargetNames::SsaoAo); diff --git a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/TraditionalOpaqueForwardPass.h b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/TraditionalOpaqueForwardPass.h index 10efa190..e558ac80 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/TraditionalOpaqueForwardPass.h +++ b/SynapseEngine/Engine/Render/Passes/Shading/ForwardPlus/Lighting/TraditionalOpaqueForwardPass.h @@ -11,6 +11,7 @@ namespace Syn { std::string GetName() const override { return _passName; } std::string GetGroup() const override { return PassGroupNames::ForwardPlusLightingPasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Visibility/DebugVisibilityPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Visibility/DebugVisibilityPass.cpp index 8bfee46a..17c25b0f 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Visibility/DebugVisibilityPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Visibility/DebugVisibilityPass.cpp @@ -70,7 +70,7 @@ namespace Syn void DebugVisibilityPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; @@ -122,7 +122,7 @@ namespace Syn void DebugVisibilityPass::BindDescriptors(const RenderContext& context) { auto imageManager = ServiceLocator::GetImageManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto visibilityTexture = rtGroup->GetImage(RenderTargetNames::EntityIndex); auto nearestSampler = imageManager->GetSampler(SamplerNames::NearestClampEdge); diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Wboit/MeshletTransparentForwardPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Wboit/MeshletTransparentForwardPass.cpp index 0fadb4e7..0bed9ab7 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Wboit/MeshletTransparentForwardPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Wboit/MeshletTransparentForwardPass.cpp @@ -99,7 +99,7 @@ namespace Syn { } void MeshletTransparentForwardPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; @@ -140,7 +140,7 @@ namespace Syn { auto drawData = scene->GetSceneDrawData(); auto componentBufferManager = scene->GetComponentBufferManager(); - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto animationManager = ServiceLocator::GetAnimationManager(); uint32_t fIdx = context.frameIndex; @@ -162,7 +162,7 @@ namespace Syn { //Using prevous frame's depth pyramid! uint fIdx = context.frameIndex; uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto depthPyramid = rtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Wboit/MeshletTransparentForwardPass.h b/SynapseEngine/Engine/Render/Passes/Shading/Wboit/MeshletTransparentForwardPass.h index df2d4cfc..8c0fcf9a 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Wboit/MeshletTransparentForwardPass.h +++ b/SynapseEngine/Engine/Render/Passes/Shading/Wboit/MeshletTransparentForwardPass.h @@ -11,6 +11,7 @@ namespace Syn { std::string GetName() const override { return _passName; } std::string GetGroup() const override { return PassGroupNames::WboitPasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TraditionalTransparentForwardPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TraditionalTransparentForwardPass.cpp index a9e06fc1..c4cb697a 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TraditionalTransparentForwardPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TraditionalTransparentForwardPass.cpp @@ -95,7 +95,7 @@ namespace Syn { } void TraditionalTransparentForwardPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; @@ -154,7 +154,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); uint fIdx = context.frameIndex; - auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, fIdx); + auto rtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, fIdx); auto drawData = context.scene->GetSceneDrawData(); auto dirShadowAtlas = drawData->DirectionLightShadow.shadowAtlas[fIdx].get(); diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TraditionalTransparentForwardPass.h b/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TraditionalTransparentForwardPass.h index 81437908..7e609818 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TraditionalTransparentForwardPass.h +++ b/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TraditionalTransparentForwardPass.h @@ -11,6 +11,7 @@ namespace Syn { std::string GetName() const override { return _passName; } std::string GetGroup() const override { return PassGroupNames::WboitPasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void BindDescriptors(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TransparentCompositePass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TransparentCompositePass.cpp index eb4c24af..ac428d76 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TransparentCompositePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TransparentCompositePass.cpp @@ -56,7 +56,7 @@ namespace Syn } void TransparentCompositePass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; @@ -76,7 +76,7 @@ namespace Syn } void TransparentCompositePass::BindDescriptors(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); auto imageManager = ServiceLocator::GetImageManager(); auto linearSampler = imageManager->GetSampler(SamplerNames::LinearClampEdge)->Handle(); diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TransparentCompositeTransitionPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TransparentCompositeTransitionPass.cpp index de430a69..5609c00f 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TransparentCompositeTransitionPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TransparentCompositeTransitionPass.cpp @@ -9,7 +9,7 @@ namespace Syn { } void TransparentCompositeTransitionPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); std::vector wboitTargets = { RenderTargetNames::TransparentAccum, diff --git a/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TransparentForwardTransitionPass.cpp b/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TransparentForwardTransitionPass.cpp index 5b1e3747..208e4e1b 100644 --- a/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TransparentForwardTransitionPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shading/Wboit/TransparentForwardTransitionPass.cpp @@ -8,7 +8,7 @@ namespace Syn { } void TransparentForwardTransitionPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); std::vector targets = { RenderTargetNames::TransparentAccum, diff --git a/SynapseEngine/Engine/Render/Passes/Shadow/DirectionLight/DirectionLightShadowMeshletOpaquePass.cpp b/SynapseEngine/Engine/Render/Passes/Shadow/DirectionLight/DirectionLightShadowMeshletOpaquePass.cpp index c75fc8b9..9f97d2b1 100644 --- a/SynapseEngine/Engine/Render/Passes/Shadow/DirectionLight/DirectionLightShadowMeshletOpaquePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shadow/DirectionLight/DirectionLightShadowMeshletOpaquePass.cpp @@ -103,6 +103,7 @@ namespace Syn { pc->frameGlobalContextBufferAddr = scene->GetSceneDrawData()->frameContextBuffer.GetAddress(fIdx); pc->baseDescriptorOffset = drawData->Models.activeTraditionalCount + drawData->Models.meshletCmdOffsets[_renderType]; pc->materialRenderType = static_cast(_renderType); + pc->disableConeCulling = _renderType == MaterialRenderType::Opaque2Sided ? 1 : 0; pc.Push(context.cmd, _shaderProgram->GetLayout()); } diff --git a/SynapseEngine/Engine/Render/Passes/Shadow/DirectionLight/DirectionLightShadowMeshletOpaquePass.h b/SynapseEngine/Engine/Render/Passes/Shadow/DirectionLight/DirectionLightShadowMeshletOpaquePass.h index e9942ae1..9653b6cd 100644 --- a/SynapseEngine/Engine/Render/Passes/Shadow/DirectionLight/DirectionLightShadowMeshletOpaquePass.h +++ b/SynapseEngine/Engine/Render/Passes/Shadow/DirectionLight/DirectionLightShadowMeshletOpaquePass.h @@ -12,6 +12,7 @@ namespace Syn { std::string GetGroup() const override { return PassGroupNames::ShadowPasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shadow/DirectionLight/DirectionLightShadowTraditionalOpaquePass.h b/SynapseEngine/Engine/Render/Passes/Shadow/DirectionLight/DirectionLightShadowTraditionalOpaquePass.h index d2d8203e..46e93afd 100644 --- a/SynapseEngine/Engine/Render/Passes/Shadow/DirectionLight/DirectionLightShadowTraditionalOpaquePass.h +++ b/SynapseEngine/Engine/Render/Passes/Shadow/DirectionLight/DirectionLightShadowTraditionalOpaquePass.h @@ -11,6 +11,7 @@ namespace Syn { std::string GetGroup() const override { return PassGroupNames::ShadowPasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shadow/PointLight/PointLightShadowMeshletOpaquePass.cpp b/SynapseEngine/Engine/Render/Passes/Shadow/PointLight/PointLightShadowMeshletOpaquePass.cpp index 73703f1a..a23a1b4b 100644 --- a/SynapseEngine/Engine/Render/Passes/Shadow/PointLight/PointLightShadowMeshletOpaquePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shadow/PointLight/PointLightShadowMeshletOpaquePass.cpp @@ -103,6 +103,7 @@ namespace Syn { pc->frameGlobalContextBufferAddr = scene->GetSceneDrawData()->frameContextBuffer.GetAddress(fIdx); pc->baseDescriptorOffset = drawData->Models.activeTraditionalCount + drawData->Models.meshletCmdOffsets[_renderType]; pc->materialRenderType = static_cast(_renderType); + pc->disableConeCulling = _renderType == MaterialRenderType::Opaque2Sided ? 1 : 0; pc.Push(context.cmd, _shaderProgram->GetLayout()); } diff --git a/SynapseEngine/Engine/Render/Passes/Shadow/PointLight/PointLightShadowMeshletOpaquePass.h b/SynapseEngine/Engine/Render/Passes/Shadow/PointLight/PointLightShadowMeshletOpaquePass.h index a46ebb32..5c2db956 100644 --- a/SynapseEngine/Engine/Render/Passes/Shadow/PointLight/PointLightShadowMeshletOpaquePass.h +++ b/SynapseEngine/Engine/Render/Passes/Shadow/PointLight/PointLightShadowMeshletOpaquePass.h @@ -12,6 +12,7 @@ namespace Syn { std::string GetGroup() const override { return PassGroupNames::ShadowPasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shadow/PointLight/PointLightShadowTraditionalOpaquePass.h b/SynapseEngine/Engine/Render/Passes/Shadow/PointLight/PointLightShadowTraditionalOpaquePass.h index 4013afd8..cc66369a 100644 --- a/SynapseEngine/Engine/Render/Passes/Shadow/PointLight/PointLightShadowTraditionalOpaquePass.h +++ b/SynapseEngine/Engine/Render/Passes/Shadow/PointLight/PointLightShadowTraditionalOpaquePass.h @@ -12,6 +12,7 @@ namespace Syn { std::string GetGroup() const override { return PassGroupNames::ShadowPasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shadow/SpotLight/SpotLightShadowMeshletOpaquePass.cpp b/SynapseEngine/Engine/Render/Passes/Shadow/SpotLight/SpotLightShadowMeshletOpaquePass.cpp index 78962374..ed4e3e7c 100644 --- a/SynapseEngine/Engine/Render/Passes/Shadow/SpotLight/SpotLightShadowMeshletOpaquePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Shadow/SpotLight/SpotLightShadowMeshletOpaquePass.cpp @@ -103,6 +103,7 @@ namespace Syn { pc->frameGlobalContextBufferAddr = scene->GetSceneDrawData()->frameContextBuffer.GetAddress(fIdx); pc->baseDescriptorOffset = drawData->Models.activeTraditionalCount + drawData->Models.meshletCmdOffsets[_renderType]; pc->materialRenderType = static_cast(_renderType); + pc->disableConeCulling = _renderType == MaterialRenderType::Opaque2Sided ? 1 : 0; pc.Push(context.cmd, _shaderProgram->GetLayout()); } diff --git a/SynapseEngine/Engine/Render/Passes/Shadow/SpotLight/SpotLightShadowMeshletOpaquePass.h b/SynapseEngine/Engine/Render/Passes/Shadow/SpotLight/SpotLightShadowMeshletOpaquePass.h index bac4b2e6..dd123983 100644 --- a/SynapseEngine/Engine/Render/Passes/Shadow/SpotLight/SpotLightShadowMeshletOpaquePass.h +++ b/SynapseEngine/Engine/Render/Passes/Shadow/SpotLight/SpotLightShadowMeshletOpaquePass.h @@ -12,6 +12,7 @@ namespace Syn { std::string GetGroup() const override { return PassGroupNames::ShadowPasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Shadow/SpotLight/SpotLightShadowTraditionalOpaquePass.h b/SynapseEngine/Engine/Render/Passes/Shadow/SpotLight/SpotLightShadowTraditionalOpaquePass.h index a0df3cda..7b385def 100644 --- a/SynapseEngine/Engine/Render/Passes/Shadow/SpotLight/SpotLightShadowTraditionalOpaquePass.h +++ b/SynapseEngine/Engine/Render/Passes/Shadow/SpotLight/SpotLightShadowTraditionalOpaquePass.h @@ -12,6 +12,7 @@ namespace Syn { std::string GetGroup() const override { return PassGroupNames::ShadowPasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Chunk/MortonChunkAabbWireframePass.cpp b/SynapseEngine/Engine/Render/Passes/Wireframe/Chunk/MortonChunkAabbWireframePass.cpp index b8aa7a0f..4209766e 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Chunk/MortonChunkAabbWireframePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Chunk/MortonChunkAabbWireframePass.cpp @@ -53,7 +53,7 @@ namespace Syn { } void MortonChunkAabbWireframePass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Chunk/MortonChunkAabbWireframePass.h b/SynapseEngine/Engine/Render/Passes/Wireframe/Chunk/MortonChunkAabbWireframePass.h index ecc87aac..62859a2d 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Chunk/MortonChunkAabbWireframePass.h +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Chunk/MortonChunkAabbWireframePass.h @@ -8,6 +8,7 @@ namespace Syn { std::string GetName() const override { return "MortonChunkAabbWireframePass"; } std::string GetGroup() const override { return PassGroupNames::WireframePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Chunk/StaticChunkAabbWireframePass.cpp b/SynapseEngine/Engine/Render/Passes/Wireframe/Chunk/StaticChunkAabbWireframePass.cpp index 25bfebd3..becf0a34 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Chunk/StaticChunkAabbWireframePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Chunk/StaticChunkAabbWireframePass.cpp @@ -53,7 +53,7 @@ namespace Syn { } void StaticChunkAabbWireframePass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Chunk/StaticChunkAabbWireframePass.h b/SynapseEngine/Engine/Render/Passes/Wireframe/Chunk/StaticChunkAabbWireframePass.h index 2bcf76d2..b68aec58 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Chunk/StaticChunkAabbWireframePass.h +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Chunk/StaticChunkAabbWireframePass.h @@ -8,6 +8,7 @@ namespace Syn { std::string GetName() const override { return "StaticChunkAabbWireframePass"; } std::string GetGroup() const override { return PassGroupNames::WireframePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/BoxColliderWireframePass.cpp b/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/BoxColliderWireframePass.cpp index 779b8db3..7d821997 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/BoxColliderWireframePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/BoxColliderWireframePass.cpp @@ -53,7 +53,7 @@ namespace Syn { } void BoxColliderWireframePass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/BoxColliderWireframePass.h b/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/BoxColliderWireframePass.h index f7bf3bf6..42a267c8 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/BoxColliderWireframePass.h +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/BoxColliderWireframePass.h @@ -8,6 +8,7 @@ namespace Syn { std::string GetName() const override { return "BoxColliderWireframePass"; } std::string GetGroup() const override { return PassGroupNames::WireframePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/CapsuleColliderWireframePass.cpp b/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/CapsuleColliderWireframePass.cpp index 27d72b13..af3102c1 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/CapsuleColliderWireframePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/CapsuleColliderWireframePass.cpp @@ -53,7 +53,7 @@ namespace Syn { } void CapsuleColliderWireframePass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/CapsuleColliderWireframePass.h b/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/CapsuleColliderWireframePass.h index 2f5bcc5d..4b4b2caa 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/CapsuleColliderWireframePass.h +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/CapsuleColliderWireframePass.h @@ -8,6 +8,7 @@ namespace Syn { std::string GetName() const override { return "CapsuleColliderWireframePass"; } std::string GetGroup() const override { return PassGroupNames::WireframePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/SphereColliderWireframePass.cpp b/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/SphereColliderWireframePass.cpp index 8c44a3bc..8d3e150c 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/SphereColliderWireframePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/SphereColliderWireframePass.cpp @@ -53,7 +53,7 @@ namespace Syn { } void SphereColliderWireframePass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/SphereColliderWireframePass.h b/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/SphereColliderWireframePass.h index 39f25e96..24a95ede 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/SphereColliderWireframePass.h +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Collider/SphereColliderWireframePass.h @@ -8,6 +8,7 @@ namespace Syn { std::string GetName() const override { return "SphereColliderWireframePass"; } std::string GetGroup() const override { return PassGroupNames::WireframePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/PointLightAabbWireframePass.cpp b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/PointLightAabbWireframePass.cpp index cc4ee833..09f2b85a 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/PointLightAabbWireframePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/PointLightAabbWireframePass.cpp @@ -52,7 +52,7 @@ namespace Syn { } void PointLightAabbWireframePass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/PointLightAabbWireframePass.h b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/PointLightAabbWireframePass.h index 3d72100c..77525ebc 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/PointLightAabbWireframePass.h +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/PointLightAabbWireframePass.h @@ -8,6 +8,7 @@ namespace Syn { std::string GetName() const override { return "PointLightAabbWireframePass"; } std::string GetGroup() const override { return PassGroupNames::WireframePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/PointLightSphereWireframePass.cpp b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/PointLightSphereWireframePass.cpp index 9af681a5..dbca0488 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/PointLightSphereWireframePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/PointLightSphereWireframePass.cpp @@ -52,7 +52,7 @@ namespace Syn { } void PointLightSphereWireframePass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/PointLightSphereWireframePass.h b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/PointLightSphereWireframePass.h index 138acd28..f94b528c 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/PointLightSphereWireframePass.h +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/PointLightSphereWireframePass.h @@ -8,6 +8,7 @@ namespace Syn { std::string GetName() const override { return "PointLightSphereWireframePass"; } std::string GetGroup() const override { return PassGroupNames::WireframePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightAabbWireframePass.cpp b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightAabbWireframePass.cpp index 152ed2c8..82d5b161 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightAabbWireframePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightAabbWireframePass.cpp @@ -52,7 +52,7 @@ namespace Syn { } void SpotLightAabbWireframePass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightAabbWireframePass.h b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightAabbWireframePass.h index 7e4fcd3c..3342824d 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightAabbWireframePass.h +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightAabbWireframePass.h @@ -8,6 +8,7 @@ namespace Syn { std::string GetName() const override { return "SpotLightAabbWireframePass"; } std::string GetGroup() const override { return PassGroupNames::WireframePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightConeWireframePass.cpp b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightConeWireframePass.cpp index f08f0bc6..fb19d804 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightConeWireframePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightConeWireframePass.cpp @@ -51,7 +51,7 @@ namespace Syn { } void SpotLightConeWireframePass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightConeWireframePass.h b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightConeWireframePass.h index 21be561b..f502d3d0 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightConeWireframePass.h +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightConeWireframePass.h @@ -8,6 +8,7 @@ namespace Syn { std::string GetName() const override { return "SpotLightConeWireframePass"; } std::string GetGroup() const override { return PassGroupNames::WireframePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightPyramidWireframePass.cpp b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightPyramidWireframePass.cpp index 65404466..6407fb85 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightPyramidWireframePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightPyramidWireframePass.cpp @@ -51,7 +51,7 @@ namespace Syn { } void SpotLightPyramidWireframePass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightPyramidWireframePass.h b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightPyramidWireframePass.h index 98510dc5..1f5b536e 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightPyramidWireframePass.h +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightPyramidWireframePass.h @@ -8,6 +8,7 @@ namespace Syn { std::string GetName() const override { return "SpotLightPyramidWireframePass"; } std::string GetGroup() const override { return PassGroupNames::WireframePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightSphereWireframePass.cpp b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightSphereWireframePass.cpp index 0032132c..53f242bd 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightSphereWireframePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightSphereWireframePass.cpp @@ -51,7 +51,7 @@ namespace Syn { } void SpotLightSphereWireframePass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightSphereWireframePass.h b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightSphereWireframePass.h index d6d7ca13..ac008624 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightSphereWireframePass.h +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Light/SpotLightSphereWireframePass.h @@ -8,6 +8,7 @@ namespace Syn { std::string GetName() const override { return "SpotLightSphereWireframePass"; } std::string GetGroup() const override { return PassGroupNames::WireframePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Mesh/WireframeMeshAabbPass.cpp b/SynapseEngine/Engine/Render/Passes/Wireframe/Mesh/WireframeMeshAabbPass.cpp index cfd17d6f..89ee6024 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Mesh/WireframeMeshAabbPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Mesh/WireframeMeshAabbPass.cpp @@ -57,7 +57,7 @@ namespace Syn { } void WireframeMeshAabbPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Mesh/WireframeMeshAabbPass.h b/SynapseEngine/Engine/Render/Passes/Wireframe/Mesh/WireframeMeshAabbPass.h index 96e83f35..26b5d115 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Mesh/WireframeMeshAabbPass.h +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Mesh/WireframeMeshAabbPass.h @@ -8,6 +8,7 @@ namespace Syn { std::string GetName() const override { return "WireframeMeshAabbPass"; } std::string GetGroup() const override { return PassGroupNames::WireframePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Mesh/WireframeMeshSpherePass.cpp b/SynapseEngine/Engine/Render/Passes/Wireframe/Mesh/WireframeMeshSpherePass.cpp index 47c01b43..34ba74c0 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Mesh/WireframeMeshSpherePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Mesh/WireframeMeshSpherePass.cpp @@ -57,7 +57,7 @@ namespace Syn { } void WireframeMeshSpherePass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Mesh/WireframeMeshSpherePass.h b/SynapseEngine/Engine/Render/Passes/Wireframe/Mesh/WireframeMeshSpherePass.h index 5966ae8b..b0181d08 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Mesh/WireframeMeshSpherePass.h +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Mesh/WireframeMeshSpherePass.h @@ -8,6 +8,7 @@ namespace Syn { std::string GetName() const override { return "WireframeMeshSpherePass"; } std::string GetGroup() const override { return PassGroupNames::WireframePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletAabbPass.cpp b/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletAabbPass.cpp index 62e5febd..0619dabc 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletAabbPass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletAabbPass.cpp @@ -62,7 +62,7 @@ namespace Syn { } void WireframeMeshletAabbPass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; @@ -116,7 +116,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto prevRtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto prevRtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto depthPyramid = prevRtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletAabbPass.h b/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletAabbPass.h index 4dd13499..2776ca8c 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletAabbPass.h +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletAabbPass.h @@ -8,6 +8,7 @@ namespace Syn { std::string GetName() const override { return "WireframeMeshletAabbPass"; } std::string GetGroup() const override { return PassGroupNames::WireframePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletConePass.cpp b/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletConePass.cpp index f2bcf1de..1a3777e4 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletConePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletConePass.cpp @@ -61,7 +61,7 @@ namespace Syn { } void WireframeMeshletConePass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; @@ -115,7 +115,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto prevRtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto prevRtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto depthPyramid = prevRtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletConePass.h b/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletConePass.h index 8bf9565c..258209b0 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletConePass.h +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletConePass.h @@ -8,6 +8,7 @@ namespace Syn { std::string GetName() const override { return "WireframeMeshletConePass"; } std::string GetGroup() const override { return PassGroupNames::WireframePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletSpherePass.cpp b/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletSpherePass.cpp index cf75af1e..cb27cfec 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletSpherePass.cpp +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletSpherePass.cpp @@ -61,7 +61,7 @@ namespace Syn { } void WireframeMeshletSpherePass::PrepareFrame(const RenderContext& context) { - auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, context.frameIndex); + auto group = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, context.frameIndex); VkExtent2D extent = { group->GetWidth(), group->GetHeight() }; _graphicsState.renderArea = extent; @@ -115,7 +115,7 @@ namespace Syn { auto imageManager = ServiceLocator::GetImageManager(); uint32_t prevFrameIndex = (context.frameIndex + context.framesInFlight - 1) % context.framesInFlight; - auto prevRtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Deferred, prevFrameIndex); + auto prevRtGroup = context.renderTargetManager->GetGroup(RenderTargetGroupNames::Main, prevFrameIndex); auto depthPyramid = prevRtGroup->GetImage(RenderTargetNames::DepthPyramid); auto maxSampler = imageManager->GetSampler(SamplerNames::MaxReduction); diff --git a/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletSpherePass.h b/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletSpherePass.h index c74066a8..dd8c84b4 100644 --- a/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletSpherePass.h +++ b/SynapseEngine/Engine/Render/Passes/Wireframe/Meshlet/WireframeMeshletSpherePass.h @@ -8,6 +8,7 @@ namespace Syn { std::string GetName() const override { return "WireframeMeshletSpherePass"; } std::string GetGroup() const override { return PassGroupNames::WireframePasses; } void Initialize() override; + bool ShouldCollectStatistics() const override { return true; } protected: bool ShouldExecute(const RenderContext& context) const override; void PrepareFrame(const RenderContext& context) override; diff --git a/SynapseEngine/Engine/Render/RenderManager.cpp b/SynapseEngine/Engine/Render/RenderManager.cpp index 25135f9f..eb00f1c8 100644 --- a/SynapseEngine/Engine/Render/RenderManager.cpp +++ b/SynapseEngine/Engine/Render/RenderManager.cpp @@ -5,6 +5,7 @@ #include "Engine/Vk/Context.h" #include "Engine/FrameContext.h" #include "Engine/Profiler/IGpuProfiler.h" +#include "Engine/Statistics/IRenderStatCollector.h" namespace Syn { @@ -51,6 +52,7 @@ namespace Syn { return; ServiceLocator::GetGpuProfiler()->BeginFrame(cmd->Handle(), frameIndex); + ServiceLocator::GetRenderStatCollector()->BeginFrame(cmd->Handle(), frameIndex); if (_preRenderCallback) { _preRenderCallback(cmd->Handle(), frameIndex, scene); diff --git a/SynapseEngine/Engine/Render/RenderNames.h b/SynapseEngine/Engine/Render/RenderNames.h index 4796829c..616576e3 100644 --- a/SynapseEngine/Engine/Render/RenderNames.h +++ b/SynapseEngine/Engine/Render/RenderNames.h @@ -5,12 +5,12 @@ namespace Syn { struct SYN_API RenderPipelineNames { - static constexpr const char* DeferredPipeline = "DeferredPipeline"; + static constexpr const char* ScenePipeline = "ScenePipeline"; }; struct SYN_API RenderTargetGroupNames { - static constexpr const char* Deferred = "Deferred"; + static constexpr const char* Main = "Main"; }; struct SYN_API RenderTargetNames @@ -38,6 +38,8 @@ namespace Syn static constexpr const char* PointLightShadowAtlas = "PointLightShadowAtlas"; static constexpr const char* PointLightShadowDepthPyramid = "PointLightShadowDepthPyramid"; + + static constexpr const char* PreviewAtlas = "PreviewAtlas"; }; struct SYN_API RenderTargetViewNames diff --git a/SynapseEngine/Engine/Render/RenderPipeline.cpp b/SynapseEngine/Engine/Render/RenderPipeline.cpp index 386a2a43..cea6b2ac 100644 --- a/SynapseEngine/Engine/Render/RenderPipeline.cpp +++ b/SynapseEngine/Engine/Render/RenderPipeline.cpp @@ -2,6 +2,7 @@ #include "Engine/ServiceLocator.h" #include "Engine/Vk/Context.h" #include "Engine/Profiler/IGpuProfiler.h" +#include "Engine/Statistics/IRenderStatCollector.h" namespace Syn { @@ -20,6 +21,7 @@ namespace Syn void RenderPipeline::Execute(const RenderContext& context) { auto profiler = ServiceLocator::GetGpuProfiler(); + auto statCollector = ServiceLocator::GetRenderStatCollector(); if (context.scene) { @@ -27,7 +29,20 @@ namespace Syn if (pass->ShouldExecute(context)) { uint32_t measureIdx = profiler->StartPass(context.cmd, context.frameIndex, pass->GetGroup(), pass->GetName()); + + bool collectStats = pass->ShouldCollectStatistics(); + uint32_t statIdx = 0; + + if (collectStats) { + statIdx = statCollector->StartPass(context.cmd, context.frameIndex, pass->GetGroup(), pass->GetName()); + } + pass->Execute(context); + + if (collectStats) { + statCollector->EndPass(context.cmd, context.frameIndex, statIdx); + } + profiler->EndPass(context.cmd, context.frameIndex, measureIdx); } } diff --git a/SynapseEngine/Engine/Render/RendererFactory.cpp b/SynapseEngine/Engine/Render/RendererFactory.cpp index 365c47f9..4384773c 100644 --- a/SynapseEngine/Engine/Render/RendererFactory.cpp +++ b/SynapseEngine/Engine/Render/RendererFactory.cpp @@ -12,6 +12,13 @@ #include "Engine/Render/Passes/PostProcess/Bloom/BloomDownsamplePass.h" #include "Engine/Render/Passes/PostProcess/Bloom/BloomCompositePass.h" #include "Engine/Render/Passes/PostProcess/Outline/SelectionOutlinePass.h" +#include "Engine/Render/Passes/PostProcess/SkySphere/SkySpherePass.h" + +#include "Engine/Render/Passes/Preview/PreviewPreTransitionPass.h" +#include "Engine/Render/Passes/Preview/PreviewPostTransitionPass.h" +#include "Engine/Render/Passes/Preview/ModelPreviewPass.h" +#include "Engine/Render/Passes/Preview/MaterialPreviewPass.h" +#include "Engine/Render/Passes/Preview/MaterialPreviewBloomPass.h" #include "Engine/Render/Passes/Culling/Geometry/GeometryModelCullingPass.h" #include "Engine/Render/Passes/Culling/Geometry/GeometryStaticModelCullingPass.h" @@ -156,10 +163,10 @@ #include "Engine/Render/Passes/Shadow/PointLight/PointLightShadowTraditionalOpaquePass.h" #include "Engine/Render/Passes/Shadow/PointLight/PointLightShadowMeshletOpaquePass.h" - -#include "Engine/Render/Passes/Ssao/SsaoInitPass.h" -#include "Engine/Render/Passes/Ssao/SsaoPass.h" -#include "Engine/Render/Passes/Ssao/SsaoBlurPass.h" +#include "Engine/Render/Passes/PostProcess/Ssao/SsaoInitPass.h" +#include "Engine/Render/Passes/PostProcess/Ssao/SsaoPass.h" +#include "Engine/Render/Passes/PostProcess/Ssao/SsaoBlurPass.h" +#include "Engine/Render/Passes/PostProcess/InfiniteGrid/InfiniteGridPass.h" #include "Engine/Render/Passes/Shading/Visibility/DebugVisibilityPass.h" @@ -168,7 +175,7 @@ namespace Syn { - std::unique_ptr RendererFactory::CreateDeferredRenderer(uint32_t framesInFlight) { + std::unique_ptr RendererFactory::CreateSceneRenderer(uint32_t framesInFlight) { auto renderManager = std::make_unique(framesInFlight); auto rtManager = renderManager->GetRenderTargetManager(); @@ -265,7 +272,7 @@ namespace Syn pipeline->AddPass(std::make_unique(MaterialRenderType::Opaque2Sided)); pipeline->AddPass(std::make_unique(MaterialRenderType::Opaque1Sided)); pipeline->AddPass(std::make_unique(MaterialRenderType::Opaque2Sided)); - + //Deferred Depth Opaque Prepasses pipeline->AddPass(std::make_unique()); pipeline->AddPass(std::make_unique(MaterialRenderType::Opaque1Sided)); @@ -297,7 +304,7 @@ namespace Syn */ pipeline->AddPass(std::make_unique()); - + //Ssao Passes pipeline->AddPass(std::make_unique()); pipeline->AddPass(std::make_unique()); @@ -329,6 +336,12 @@ namespace Syn pipeline->AddPass(std::make_unique(MaterialRenderType::Opaque1Sided)); pipeline->AddPass(std::make_unique(MaterialRenderType::Opaque2Sided)); + // SkySphere + pipeline->AddPass(std::make_unique()); + + //Grid + pipeline->AddPass(std::make_unique()); + // Wireframe Passes pipeline->AddPass(std::make_unique()); pipeline->AddPass(std::make_unique()); @@ -378,14 +391,21 @@ namespace Syn //Debug Visibility Pass pipeline->AddPass(std::make_unique()); + //Preview Passes + pipeline->AddPass(std::make_unique()); + pipeline->AddPass(std::make_unique()); + pipeline->AddPass(std::make_unique()); + pipeline->AddPass(std::make_unique()); + pipeline->AddPass(std::make_unique()); + //Gui and Present Passes pipeline->AddPass(std::make_unique()); pipeline->AddPass(std::make_unique()); pipeline->InitializeAll(); - renderManager->RegisterPipeline(RenderPipelineNames::DeferredPipeline, std::move(pipeline)); + renderManager->RegisterPipeline(RenderPipelineNames::ScenePipeline, std::move(pipeline)); - rtManager->CreateGroup(RenderTargetGroupNames::Deferred); + rtManager->CreateGroup(RenderTargetGroupNames::Main); uint32_t initWidth = 4; uint32_t initHeight = 4; @@ -397,7 +417,7 @@ namespace Syn mainImageSpec.format = VK_FORMAT_R16G16B16A16_SFLOAT; mainImageSpec.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT; mainImageSpec.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - rtManager->AddAttachment(RenderTargetGroupNames::Deferred, RenderTargetNames::Main, mainImageSpec); + rtManager->AddAttachment(RenderTargetGroupNames::Main, RenderTargetNames::Main, mainImageSpec); Vk::ImageConfig colorImageSpec{}; colorImageSpec.width = initWidth; @@ -418,8 +438,7 @@ namespace Syn .swizzle = { VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_ONE } }); - rtManager->AddAttachment(RenderTargetGroupNames::Deferred, RenderTargetNames::ColorMetallic, colorImageSpec); - + rtManager->AddAttachment(RenderTargetGroupNames::Main, RenderTargetNames::ColorMetallic, colorImageSpec); Vk::ImageConfig normalImageSpec{}; normalImageSpec.width = initWidth; @@ -441,7 +460,7 @@ namespace Syn .swizzle = { VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_ONE } }); - rtManager->AddAttachment(RenderTargetGroupNames::Deferred, RenderTargetNames::NormalRoughness, normalImageSpec); + rtManager->AddAttachment(RenderTargetGroupNames::Main, RenderTargetNames::NormalRoughness, normalImageSpec); Vk::ImageConfig emissiveAoImageSpec{}; emissiveAoImageSpec.width = initWidth; @@ -463,7 +482,7 @@ namespace Syn .swizzle = { VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_A, VK_COMPONENT_SWIZZLE_ONE } }); - rtManager->AddAttachment(RenderTargetGroupNames::Deferred, RenderTargetNames::EmissiveAo, emissiveAoImageSpec); + rtManager->AddAttachment(RenderTargetGroupNames::Main, RenderTargetNames::EmissiveAo, emissiveAoImageSpec); Vk::ImageConfig transparentAccumSpec{}; transparentAccumSpec.width = initWidth; @@ -472,7 +491,7 @@ namespace Syn transparentAccumSpec.format = VK_FORMAT_R16G16B16A16_SFLOAT; transparentAccumSpec.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; transparentAccumSpec.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - rtManager->AddAttachment(RenderTargetGroupNames::Deferred, RenderTargetNames::TransparentAccum, transparentAccumSpec); + rtManager->AddAttachment(RenderTargetGroupNames::Main, RenderTargetNames::TransparentAccum, transparentAccumSpec); Vk::ImageConfig transparentRevealSpec{}; transparentRevealSpec.width = initWidth; @@ -481,7 +500,7 @@ namespace Syn transparentRevealSpec.format = VK_FORMAT_R8_UNORM; transparentRevealSpec.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; transparentRevealSpec.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - rtManager->AddAttachment(RenderTargetGroupNames::Deferred, RenderTargetNames::TransparentReveal, transparentRevealSpec); + rtManager->AddAttachment(RenderTargetGroupNames::Main, RenderTargetNames::TransparentReveal, transparentRevealSpec); Vk::ImageConfig entityImageSpec{}; entityImageSpec.width = initWidth; @@ -490,7 +509,7 @@ namespace Syn entityImageSpec.format = VK_FORMAT_R32G32_UINT; entityImageSpec.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; entityImageSpec.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - rtManager->AddAttachment(RenderTargetGroupNames::Deferred, RenderTargetNames::EntityIndex, entityImageSpec); + rtManager->AddAttachment(RenderTargetGroupNames::Main, RenderTargetNames::EntityIndex, entityImageSpec); Vk::ImageConfig depthPyramidImageSpec{}; depthPyramidImageSpec.width = initWidth; @@ -518,7 +537,7 @@ namespace Syn .perMipViews = true }); - rtManager->AddAttachment(RenderTargetGroupNames::Deferred, RenderTargetNames::DepthPyramid, depthPyramidImageSpec); + rtManager->AddAttachment(RenderTargetGroupNames::Main, RenderTargetNames::DepthPyramid, depthPyramidImageSpec); Vk::ImageConfig bloomImageSpec{}; bloomImageSpec.width = initWidth; @@ -534,7 +553,7 @@ namespace Syn .perMipViews = true }); - rtManager->AddAttachment(RenderTargetGroupNames::Deferred, RenderTargetNames::Bloom, bloomImageSpec); + rtManager->AddAttachment(RenderTargetGroupNames::Main, RenderTargetNames::Bloom, bloomImageSpec); Vk::ImageConfig opaqueDepthSpec{}; opaqueDepthSpec.width = initWidth; @@ -543,7 +562,7 @@ namespace Syn opaqueDepthSpec.format = VK_FORMAT_D32_SFLOAT; opaqueDepthSpec.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; opaqueDepthSpec.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - rtManager->AddAttachment(RenderTargetGroupNames::Deferred, RenderTargetNames::OpaqueDepth, opaqueDepthSpec); + rtManager->AddAttachment(RenderTargetGroupNames::Main, RenderTargetNames::OpaqueDepth, opaqueDepthSpec); Vk::ImageConfig transparentDepthSpec{}; transparentDepthSpec.width = initWidth; @@ -552,7 +571,7 @@ namespace Syn transparentDepthSpec.format = VK_FORMAT_D32_SFLOAT; transparentDepthSpec.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; transparentDepthSpec.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - rtManager->AddAttachment(RenderTargetGroupNames::Deferred, RenderTargetNames::TransparentDepth, transparentDepthSpec); + rtManager->AddAttachment(RenderTargetGroupNames::Main, RenderTargetNames::TransparentDepth, transparentDepthSpec); Vk::ImageConfig volumetricAoImageSpec{}; volumetricAoImageSpec.width = initWidth; @@ -561,7 +580,7 @@ namespace Syn volumetricAoImageSpec.format = VK_FORMAT_R16_SFLOAT; volumetricAoImageSpec.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT; volumetricAoImageSpec.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - rtManager->AddAttachment(RenderTargetGroupNames::Deferred, RenderTargetNames::SsaoAo, volumetricAoImageSpec); + rtManager->AddAttachment(RenderTargetGroupNames::Main, RenderTargetNames::SsaoAo, volumetricAoImageSpec); Vk::ImageConfig volumetricAoIntermediateImageSpec{}; volumetricAoIntermediateImageSpec.width = initWidth; @@ -570,7 +589,7 @@ namespace Syn volumetricAoIntermediateImageSpec.format = VK_FORMAT_R16_SFLOAT; volumetricAoIntermediateImageSpec.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT; volumetricAoIntermediateImageSpec.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - rtManager->AddAttachment(RenderTargetGroupNames::Deferred, RenderTargetNames::SsaoAoIntermediate, volumetricAoIntermediateImageSpec); + rtManager->AddAttachment(RenderTargetGroupNames::Main, RenderTargetNames::SsaoAoIntermediate, volumetricAoIntermediateImageSpec); return renderManager; } diff --git a/SynapseEngine/Engine/Render/RendererFactory.h b/SynapseEngine/Engine/Render/RendererFactory.h index e5518324..f4557e07 100644 --- a/SynapseEngine/Engine/Render/RendererFactory.h +++ b/SynapseEngine/Engine/Render/RendererFactory.h @@ -6,7 +6,7 @@ namespace Syn { class SYN_API RendererFactory { public: - static std::unique_ptr CreateDeferredRenderer(uint32_t framesInFlight); + static std::unique_ptr CreateSceneRenderer(uint32_t framesInFlight); }; } \ No newline at end of file diff --git a/SynapseEngine/Engine/Render/ShaderNames.h b/SynapseEngine/Engine/Render/ShaderNames.h index b39eed42..203a49be 100644 --- a/SynapseEngine/Engine/Render/ShaderNames.h +++ b/SynapseEngine/Engine/Render/ShaderNames.h @@ -16,6 +16,9 @@ namespace Syn static constexpr const char* BloomDownsample = "Engine/Shaders/Passes/PostProcess/Bloom/BloomDownsample.comp"; static constexpr const char* BloomComposite = "Engine/Shaders/Passes/PostProcess/Bloom/BloomComposite.comp"; + static constexpr const char* SkySphereVert = "Engine/Shaders/Passes/PostProcess/SkySphere/SkySphere.vert"; + static constexpr const char* SkySphereFrag = "Engine/Shaders/Passes/PostProcess/SkySphere/SkySphere.frag"; + static constexpr const char* SelectionOutlineFrag = "Engine/Shaders/Passes/PostProcess/Outline/SelectionOutline.frag"; static constexpr const char* StaticSceneAABB = "Engine/Shaders/Passes/Morton/StaticSceneAABB.comp"; @@ -68,11 +71,13 @@ namespace Syn static constexpr const char* WireframeDebugVert = "Engine/Shaders/Passes/Wireframe/WireframeDebug.vert"; static constexpr const char* DebugVisibilityFrag = "Engine/Shaders/Passes/Shading/Visibility/DebugVisibility.frag"; - static constexpr const char* DpHvoComp = "Engine/Shaders/Passes/Ssao/DpHvo.comp"; - static constexpr const char* DpHvoBlurComp = "Engine/Shaders/Passes/Ssao/DpHvoBlur.comp"; - static constexpr const char* SsaoComp = "Engine/Shaders/Passes/Ssao/Ssao.comp"; - static constexpr const char* SsaoBlurComp = "Engine/Shaders/Passes/Ssao/SsaoBlur.comp"; + static constexpr const char* DpHvoComp = "Engine/Shaders/Passes/PostProcess/Ssao/DpHvo.comp"; + static constexpr const char* DpHvoBlurComp = "Engine/Shaders/Passes/PostProcess/Ssao/DpHvoBlur.comp"; + static constexpr const char* SsaoComp = "Engine/Shaders/Passes/PostProcess/Ssao/Ssao.comp"; + static constexpr const char* SsaoBlurComp = "Engine/Shaders/Passes/PostProcess/Ssao/SsaoBlur.comp"; + static constexpr const char* InfiniteGridFrag = "Engine/Shaders/Passes/PostProcess/InfiniteGrid/InfiniteGrid.frag"; + static constexpr const char* GeometryCullingCommandResetComp = "Engine/Shaders/Passes/Culling/Geometry/GeometryCullingCommandReset.comp"; static constexpr const char* GeometryMeshCullingComp = "Engine/Shaders/Passes/Culling/Geometry/GeometryMeshCulling.comp"; static constexpr const char* GeometryModelCullingComp = "Engine/Shaders/Passes/Culling/Geometry/GeometryModelCulling.comp"; @@ -141,5 +146,11 @@ namespace Syn static constexpr const char* PointLightShadowMortonModelCullingComp = "Engine/Shaders/Passes/Culling/PointLight/PointLightShadowMortonModelCulling.comp"; static constexpr const char* PointLightShadowStaticChunkCullingComp = "Engine/Shaders/Passes/Culling/PointLight/PointLightShadowStaticChunkCulling.comp"; static constexpr const char* PointLightShadowStaticModelCullingComp = "Engine/Shaders/Passes/Culling/PointLight/PointLightShadowStaticModelCulling.comp"; + + static constexpr const char* MaterialPreviewVert = "Engine/Shaders/Passes/Preview/MaterialPreview.vert"; + static constexpr const char* MaterialPreviewFrag = "Engine/Shaders/Passes/Preview/MaterialPreview.frag"; + + static constexpr const char* ModelPreviewVert = "Engine/Shaders/Passes/Preview/ModelPreview.vert"; + static constexpr const char* ModelPreviewFrag = "Engine/Shaders/Passes/Preview/ModelPreview.frag"; }; } \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/BufferNames.h b/SynapseEngine/Engine/Scene/BufferNames.h index 14a7aa7f..8970c1af 100644 --- a/SynapseEngine/Engine/Scene/BufferNames.h +++ b/SynapseEngine/Engine/Scene/BufferNames.h @@ -83,5 +83,8 @@ namespace Syn static constexpr const char* SelectionOutlineData = "SelectionOutlineData"; static constexpr const char* HierarchySparseMap = "HierarchySparseMap"; + + static constexpr const char* TagSparseMap = "TagSparseMap"; + static constexpr const char* TagData = "TagData"; }; } \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/DrawData/ChunkDrawGroup.cpp b/SynapseEngine/Engine/Scene/DrawData/ChunkDrawGroup.cpp index 3e8d6340..246ff5ac 100644 --- a/SynapseEngine/Engine/Scene/DrawData/ChunkDrawGroup.cpp +++ b/SynapseEngine/Engine/Scene/DrawData/ChunkDrawGroup.cpp @@ -22,34 +22,34 @@ namespace Syn VkBufferUsageFlags storageUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; VkBufferUsageFlags indirectUsage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - chunkDataBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(ChunkDataGPU), storageUsage }); + chunkDataBuffer.Initialize({ "ChunkDrawGroup_ChunkDataBuffer", BufferStrategy::Hybrid, frameCount, sizeof(ChunkDataGPU), storageUsage }); chunkDataBuffer.UpdateCapacityAll(1); - chunkVisibilityBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(uint32_t), storageUsage }); + chunkVisibilityBuffer.Initialize({ "ChunkDrawGroup_ChunkVisibilityBuffer", BufferStrategy::Hybrid, frameCount, sizeof(uint32_t), storageUsage }); chunkVisibilityBuffer.UpdateCapacityAll(1); - chunkAabbSingleCmdBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); + chunkAabbSingleCmdBuffer.Initialize({ "ChunkDrawGroup_ChunkAabbSingleCmdBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); chunkAabbSingleCmdBuffer.UpdateCapacityAll(1); - chunkIndirectDispatchBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(VkDispatchIndirectCommand), indirectUsage }); + chunkIndirectDispatchBuffer.Initialize({ "ChunkDrawGroup_ChunkIndirectDispatchBuffer", BufferStrategy::Hybrid, frameCount, sizeof(VkDispatchIndirectCommand), indirectUsage }); chunkIndirectDispatchBuffer.UpdateCapacityAll(1); - sceneAabbBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(SceneAABB), storageUsage }); + sceneAabbBuffer.Initialize({ "ChunkDrawGroup_SceneAabbBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(SceneAABB), storageUsage }); sceneAabbBuffer.UpdateCapacityAll(1); - mortonRadixSortTempBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, 1, storageUsage | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 10000, 20000 }); + mortonRadixSortTempBuffer.Initialize({ "ChunkDrawGroup_MortonRadixSortTempBuffer", BufferStrategy::GpuOnly, frameCount, 1, storageUsage | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 10000, 20000 }); mortonRadixSortTempBuffer.UpdateCapacityAll(1); - mortonIndirectDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectUsage }); + mortonIndirectDispatchBuffer.Initialize({ "ChunkDrawGroup_MortonIndirectDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectUsage }); mortonIndirectDispatchBuffer.UpdateCapacityAll(1); - mortonIndirectDrawBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); + mortonIndirectDrawBuffer.Initialize({ "ChunkDrawGroup_MortonIndirectDrawBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); mortonIndirectDrawBuffer.UpdateCapacityAll(1); - mortonChunkVisibleIndirectDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectUsage }); + mortonChunkVisibleIndirectDispatchBuffer.Initialize({ "ChunkDrawGroup_MortonChunkVisibleIndirectDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectUsage }); mortonChunkVisibleIndirectDispatchBuffer.UpdateCapacityAll(1); - mortonAabbSingleCmdBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); + mortonAabbSingleCmdBuffer.Initialize({ "ChunkDrawGroup_MortonAabbSingleCmdBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); mortonAabbSingleCmdBuffer.UpdateCapacityAll(1); for (uint32_t i = 0; i < frameCount; ++i) { diff --git a/SynapseEngine/Engine/Scene/DrawData/DebugDrawGroup.cpp b/SynapseEngine/Engine/Scene/DrawData/DebugDrawGroup.cpp index 4261da9e..31980195 100644 --- a/SynapseEngine/Engine/Scene/DrawData/DebugDrawGroup.cpp +++ b/SynapseEngine/Engine/Scene/DrawData/DebugDrawGroup.cpp @@ -43,19 +43,19 @@ namespace Syn VkBufferUsageFlags indirectUsage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; VkBufferUsageFlags storageUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - modelAabbIndirectBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand) * 8, indirectUsage, 1024, 2048 }); + modelAabbIndirectBuffer.Initialize({ "DebugDrawGroup_ModelAabbIndirectBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand) * 8, indirectUsage, 1024, 2048 }); modelAabbIndirectBuffer.UpdateCapacityAll(1); - modelSphereIndirectBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand) * 8, indirectUsage, 1024, 2048 }); + modelSphereIndirectBuffer.Initialize({ "DebugDrawGroup_ModelSphereIndirectBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand) * 8, indirectUsage, 1024, 2048 }); modelSphereIndirectBuffer.UpdateCapacityAll(1); - boxColliderIndirectBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); + boxColliderIndirectBuffer.Initialize({ "DebugDrawGroup_BoxColliderIndirectBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); boxColliderIndirectBuffer.UpdateCapacityAll(1); - sphereColliderIndirectBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); + sphereColliderIndirectBuffer.Initialize({ "DebugDrawGroup_SphereColliderIndirectBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); sphereColliderIndirectBuffer.UpdateCapacityAll(1); - capsuleColliderIndirectBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); + capsuleColliderIndirectBuffer.Initialize({ "DebugDrawGroup_CapsuleColliderIndirectBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); capsuleColliderIndirectBuffer.UpdateCapacityAll(1); for (uint32_t i = 0; i < frameCount; ++i) { diff --git a/SynapseEngine/Engine/Scene/DrawData/DirectionLightDrawGroup.cpp b/SynapseEngine/Engine/Scene/DrawData/DirectionLightDrawGroup.cpp index ae0783da..23c28dc5 100644 --- a/SynapseEngine/Engine/Scene/DrawData/DirectionLightDrawGroup.cpp +++ b/SynapseEngine/Engine/Scene/DrawData/DirectionLightDrawGroup.cpp @@ -17,10 +17,10 @@ namespace Syn VkBufferUsageFlags indirectUsage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - indirectBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); + indirectBuffer.Initialize({ "DirectionLightDrawGroup_IndirectBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); indirectBuffer.UpdateCapacityAll(1); - billboardSingleCmdBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); + billboardSingleCmdBuffer.Initialize({ "DirectionLightDrawGroup_BillboardSingleCmdBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); billboardSingleCmdBuffer.UpdateCapacityAll(1); for (uint32_t i = 0; i < frameCount; ++i) { diff --git a/SynapseEngine/Engine/Scene/DrawData/DirectionLightShadowDrawGroup.cpp b/SynapseEngine/Engine/Scene/DrawData/DirectionLightShadowDrawGroup.cpp index 92d15d94..e0e3ac3c 100644 --- a/SynapseEngine/Engine/Scene/DrawData/DirectionLightShadowDrawGroup.cpp +++ b/SynapseEngine/Engine/Scene/DrawData/DirectionLightShadowDrawGroup.cpp @@ -18,19 +18,19 @@ namespace Syn VkBufferUsageFlags storageUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; VkBufferUsageFlags indirectStorageUsage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - instanceBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(uint32_t), storageUsage, 16384 * SHADOW_MULTIPLIER, 32768 * SHADOW_MULTIPLIER }); + instanceBuffer.Initialize({ "DirectionLightShadowDrawGroup_InstanceBuffer", BufferStrategy::Hybrid, frameCount, sizeof(uint32_t), storageUsage, 16384 * SHADOW_MULTIPLIER, 32768 * SHADOW_MULTIPLIER}); instanceBuffer.UpdateCapacityAll(1); - indirectBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(VkDrawIndirectCommand) * 8, indirectStorageUsage, 1024, 2048 }); + indirectBuffer.Initialize({ "DirectionLightShadowDrawGroup_IndirectBuffer", BufferStrategy::Hybrid, frameCount, sizeof(VkDrawIndirectCommand) * 8, indirectStorageUsage, 1024, 2048 }); indirectBuffer.UpdateCapacityAll(1); - modelDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); + modelDispatchBuffer.Initialize({ "DirectionLightShadowDrawGroup_ModelDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); modelDispatchBuffer.UpdateCapacityAll(1); - staticChunkDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); + staticChunkDispatchBuffer.Initialize({ "DirectionLightShadowDrawGroup_StaticChunkDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); staticChunkDispatchBuffer.UpdateCapacityAll(1); - mortonChunkDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); + mortonChunkDispatchBuffer.Initialize({ "DirectionLightShadowDrawGroup_MortonChunkDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); mortonChunkDispatchBuffer.UpdateCapacityAll(1); Vk::ImageConfig atlasSpec{}; diff --git a/SynapseEngine/Engine/Scene/DrawData/DirectionLightShadowDrawGroup.h b/SynapseEngine/Engine/Scene/DrawData/DirectionLightShadowDrawGroup.h index 57a7c206..6e695e75 100644 --- a/SynapseEngine/Engine/Scene/DrawData/DirectionLightShadowDrawGroup.h +++ b/SynapseEngine/Engine/Scene/DrawData/DirectionLightShadowDrawGroup.h @@ -17,8 +17,8 @@ namespace Syn constexpr uint32_t CASCADES_PER_LIGHT = 4; constexpr uint32_t SHADOW_MULTIPLIER = MAX_DIR_LIGHTS * CASCADES_PER_LIGHT; - constexpr uint32_t SHADOW_ATLAS_SIZE = 2048; - constexpr uint32_t SHADOW_MIN_BLOCK_SIZE = 1024; + constexpr uint32_t SHADOW_ATLAS_SIZE = 4096; + constexpr uint32_t SHADOW_MIN_BLOCK_SIZE = 2048; constexpr uint32_t SHADOW_GRID_SIZE = SHADOW_ATLAS_SIZE / SHADOW_MIN_BLOCK_SIZE; constexpr uint32_t SHADOW_HIZ_MIP_LEVELS = std::countr_zero(SHADOW_MIN_BLOCK_SIZE) + 1; diff --git a/SynapseEngine/Engine/Scene/DrawData/ForwardPlusDrawGroup.cpp b/SynapseEngine/Engine/Scene/DrawData/ForwardPlusDrawGroup.cpp index bf9bbbc0..5575a47b 100644 --- a/SynapseEngine/Engine/Scene/DrawData/ForwardPlusDrawGroup.cpp +++ b/SynapseEngine/Engine/Scene/DrawData/ForwardPlusDrawGroup.cpp @@ -7,22 +7,22 @@ namespace Syn VkBufferUsageFlags storageUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; VkBufferUsageFlags indirectUsage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - tileGridBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, 16, storageUsage, 3000, 6000 }); + tileGridBuffer.Initialize({ "ForwardPlusDrawGroup_TileGridBuffer", BufferStrategy::GpuOnly, frameCount, 16, storageUsage, 3000, 6000 }); tileGridBuffer.UpdateCapacityAll(1); - clusterListBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, 32, storageUsage, 48000, 96000 }); + clusterListBuffer.Initialize({ "ForwardPlusDrawGroup_ClusterListBuffer", BufferStrategy::GpuOnly, frameCount, 32, storageUsage, 48000, 96000 }); clusterListBuffer.UpdateCapacityAll(1); - clusterCountBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectUsage, 1, 1}); + clusterCountBuffer.Initialize({ "ForwardPlusDrawGroup_ClusterCountBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectUsage, 1, 1}); clusterCountBuffer.UpdateCapacityAll(1); - dispatchArgsBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(ForwardPlusDispatchArgs), indirectUsage, 1, 1 }); + dispatchArgsBuffer.Initialize({ "ForwardPlusDrawGroup_DispatchArgsBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(ForwardPlusDispatchArgs), indirectUsage, 1, 1 }); dispatchArgsBuffer.UpdateCapacityAll(1); - pointLightIndexBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(uint32_t), storageUsage, 10000, 20000 }); + pointLightIndexBuffer.Initialize({ "ForwardPlusDrawGroup_PointLightIndexBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(uint32_t), storageUsage, 10000, 20000 }); pointLightIndexBuffer.UpdateCapacityAll(1); - spotLightIndexBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(uint32_t), storageUsage, 10000, 20000 }); + spotLightIndexBuffer.Initialize({ "ForwardPlusDrawGroup_SpotLightIndexBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(uint32_t), storageUsage, 10000, 20000 }); spotLightIndexBuffer.UpdateCapacityAll(1); } diff --git a/SynapseEngine/Engine/Scene/DrawData/ModelDrawGroup.cpp b/SynapseEngine/Engine/Scene/DrawData/ModelDrawGroup.cpp index 919092ce..359e0b76 100644 --- a/SynapseEngine/Engine/Scene/DrawData/ModelDrawGroup.cpp +++ b/SynapseEngine/Engine/Scene/DrawData/ModelDrawGroup.cpp @@ -22,29 +22,29 @@ namespace Syn VkBufferUsageFlags storageUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; VkBufferUsageFlags indirectStorageUsage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - instanceBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(uint32_t), storageUsage, 16384, 32768 }); + instanceBuffer.Initialize({ "ModelDrawGroup_InstanceBuffer", BufferStrategy::Hybrid, frameCount, sizeof(uint32_t), storageUsage, 16384, 32768}); instanceBuffer.UpdateCapacityAll(1); //VkDrawIndirectCommand + VkDrawMeshTasksIndirectCommandEXT - indirectBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(VkDrawIndirectCommand) * 8, indirectStorageUsage, 1024, 2048 }); + indirectBuffer.Initialize({ "ModelDrawGroup_IndirectBuffer", BufferStrategy::Hybrid, frameCount, sizeof(VkDrawIndirectCommand) * 8, indirectStorageUsage, 1024, 2048 }); indirectBuffer.UpdateCapacityAll(1); - descriptorBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(MeshDrawDescriptor), storageUsage, 1024, 2048 }); + descriptorBuffer.Initialize({ "ModelDrawGroup_DescriptorBuffer", BufferStrategy::Hybrid, frameCount, sizeof(MeshDrawDescriptor), storageUsage, 1024, 2048 }); descriptorBuffer.UpdateCapacityAll(1); - modelAllocBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(ModelAllocationInfo), storageUsage, 1024, 2048 }); + modelAllocBuffer.Initialize({ "ModelDrawGroup_ModelAllocBuffer", BufferStrategy::Hybrid, frameCount, sizeof(ModelAllocationInfo), storageUsage, 1024, 2048 }); modelAllocBuffer.UpdateCapacityAll(1); - meshAllocBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(MeshAllocationInfo), storageUsage, 1024, 2048 }); + meshAllocBuffer.Initialize({ "ModelDrawGroup_MeshAllocBuffer", BufferStrategy::Hybrid, frameCount, sizeof(MeshAllocationInfo), storageUsage, 1024, 2048 }); meshAllocBuffer.UpdateCapacityAll(1); - materialIndexBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(int32_t), storageUsage, 1024, 2048 }); + materialIndexBuffer.Initialize({ "ModelDrawGroup_MaterialIndexBuffer", BufferStrategy::Hybrid, frameCount, sizeof(int32_t), storageUsage, 4096, 8192 }); materialIndexBuffer.UpdateCapacityAll(1); - drawCountBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(uint32_t), indirectStorageUsage, 1, 1 }); + drawCountBuffer.Initialize({ "ModelDrawGroup_DrawCountBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(uint32_t), indirectStorageUsage, 1, 1 }); drawCountBuffer.UpdateCapacityAll(MaterialRenderType::Count * 2); - computeCountBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); + computeCountBuffer.Initialize({ "ModelDrawGroup_ComputeCountBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); computeCountBuffer.UpdateCapacityAll(1); } diff --git a/SynapseEngine/Engine/Scene/DrawData/PointLightDrawGroup.cpp b/SynapseEngine/Engine/Scene/DrawData/PointLightDrawGroup.cpp index 09cbf877..13d59850 100644 --- a/SynapseEngine/Engine/Scene/DrawData/PointLightDrawGroup.cpp +++ b/SynapseEngine/Engine/Scene/DrawData/PointLightDrawGroup.cpp @@ -33,16 +33,16 @@ namespace Syn VkBufferUsageFlags usage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT; - indirectBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), usage }); + indirectBuffer.Initialize({ "PointLightDrawGroup_IndirectBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), usage }); indirectBuffer.UpdateCapacityAll(1); - sphereSingleCmdBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), usage }); + sphereSingleCmdBuffer.Initialize({ "PointLightDrawGroup_SphereSingleCmdBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), usage }); sphereSingleCmdBuffer.UpdateCapacityAll(1); - aabbSingleCmdBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), usage }); + aabbSingleCmdBuffer.Initialize({ "PointLightDrawGroup_AabbSingleCmdBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), usage }); aabbSingleCmdBuffer.UpdateCapacityAll(1); - billboardSingleCmdBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), usage }); + billboardSingleCmdBuffer.Initialize({ "PointLightDrawGroup_BillboardSingleCmdBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), usage }); billboardSingleCmdBuffer.UpdateCapacityAll(1); for (uint32_t i = 0; i < frameCount; ++i) { diff --git a/SynapseEngine/Engine/Scene/DrawData/PointLightShadowDrawGroup.cpp b/SynapseEngine/Engine/Scene/DrawData/PointLightShadowDrawGroup.cpp index 274d9d77..e374b2e1 100644 --- a/SynapseEngine/Engine/Scene/DrawData/PointLightShadowDrawGroup.cpp +++ b/SynapseEngine/Engine/Scene/DrawData/PointLightShadowDrawGroup.cpp @@ -13,55 +13,55 @@ namespace Syn VkBufferUsageFlags storageUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; VkBufferUsageFlags indirectStorageUsage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - instanceBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(PointShadowInstancePayload), storageUsage, 65536, 131072 }); + instanceBuffer.Initialize({ "PointLightShadowDrawGroup_InstanceBuffer", BufferStrategy::Hybrid, frameCount, sizeof(PointShadowInstancePayload), storageUsage, 65536, 131072 }); instanceBuffer.UpdateCapacityAll(1); - unsortedInstanceBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(PointShadowInstancePayload), storageUsage, 65536, 131072 }); + unsortedInstanceBuffer.Initialize({ "PointLightShadowDrawGroup_UnsortedInstanceBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(PointShadowInstancePayload), storageUsage, 65536, 131072 }); unsortedInstanceBuffer.UpdateCapacityAll(1); - sortValuesBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(uint32_t), storageUsage, 65536, 131072 }); + sortValuesBuffer.Initialize({ "PointLightShadowDrawGroup_SortValuesBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(uint32_t), storageUsage, 65536, 131072 }); sortValuesBuffer.UpdateCapacityAll(1); - drawCallKeyBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(uint32_t), storageUsage, 65536, 131072 }); + drawCallKeyBuffer.Initialize({ "PointLightShadowDrawGroup_DrawCallKeyBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(uint32_t), storageUsage, 65536, 131072 }); drawCallKeyBuffer.UpdateCapacityAll(1); - indirectBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(VkDrawIndirectCommand) * 8, indirectStorageUsage, 1024, 2048 }); + indirectBuffer.Initialize({ "PointLightShadowDrawGroup_IndirectBuffer", BufferStrategy::Hybrid, frameCount, sizeof(VkDrawIndirectCommand) * 8, indirectStorageUsage, 1024, 2048 }); indirectBuffer.UpdateCapacityAll(1); - visibleCountDispatchBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(uint32_t), storageUsage, 1, 1 }); + visibleCountDispatchBuffer.Initialize({ "PointLightShadowDrawGroup_VisibleCountDispatchBuffer", BufferStrategy::Hybrid, frameCount, sizeof(uint32_t), storageUsage, 1, 1 }); visibleCountDispatchBuffer.UpdateCapacityAll(1); - visibleMeshCountDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(uint32_t), storageUsage, 1, 1 }); + visibleMeshCountDispatchBuffer.Initialize({ "PointLightShadowDrawGroup_VisibleMeshCountDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(uint32_t), storageUsage, 1, 1 }); visibleMeshCountDispatchBuffer.UpdateCapacityAll(1); - descriptorBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(MeshDrawDescriptor) * 8, storageUsage, 1024, 2048 }); + descriptorBuffer.Initialize({ "PointLightShadowDrawGroup_DescriptorBuffer", BufferStrategy::Hybrid, frameCount, sizeof(MeshDrawDescriptor) * 8, storageUsage, 1024, 2048 }); descriptorBuffer.UpdateCapacityAll(1); - modelCullingIndirectDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); + modelCullingIndirectDispatchBuffer.Initialize({ "PointLightShadowDrawGroup_ModelCullingIndirectDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); modelCullingIndirectDispatchBuffer.UpdateCapacityAll(1); - modelDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); + modelDispatchBuffer.Initialize({ "PointLightShadowDrawGroup_ModelDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); modelDispatchBuffer.UpdateCapacityAll(1); - finalizeDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); + finalizeDispatchBuffer.Initialize({ "PointLightShadowDrawGroup_FinalizeDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); finalizeDispatchBuffer.UpdateCapacityAll(1); - staticChunkDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); + staticChunkDispatchBuffer.Initialize({ "PointLightShadowDrawGroup_StaticChunkDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); staticChunkDispatchBuffer.UpdateCapacityAll(1); - mortonChunkDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); + mortonChunkDispatchBuffer.Initialize({ "PointLightShadowDrawGroup_MortonChunkDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); mortonChunkDispatchBuffer.UpdateCapacityAll(1); - atlasRadixSortTempBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, 1, storageUsage | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 10000, 20000 }); + atlasRadixSortTempBuffer.Initialize({ "PointLightShadowDrawGroup_AtlasRadixSortTempBuffer", BufferStrategy::GpuOnly, frameCount, 1, storageUsage | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 10000, 20000 }); atlasRadixSortTempBuffer.UpdateCapacityAll(1); - radixSortTempBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, 1, storageUsage | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 10000, 20000 }); + radixSortTempBuffer.Initialize({ "PointLightShadowDrawGroup_RadixSortTempBuffer", BufferStrategy::GpuOnly, frameCount, 1, storageUsage | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 10000, 20000 }); radixSortTempBuffer.UpdateCapacityAll(1); gridLookupData.Resize(POINT_SHADOW_GRID_SIZE * POINT_SHADOW_GRID_SIZE); std::fill(gridLookupData.Data(), gridLookupData.Data() + (POINT_SHADOW_GRID_SIZE * POINT_SHADOW_GRID_SIZE), 0xFFFFFFFF); - gridLookupBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(uint32_t) * POINT_SHADOW_GRID_SIZE * POINT_SHADOW_GRID_SIZE, storageUsage, 1, 1 }); + gridLookupBuffer.Initialize({ "PointLightShadowDrawGroup_GridLookupBuffer", BufferStrategy::Hybrid, frameCount, sizeof(uint32_t) * POINT_SHADOW_GRID_SIZE * POINT_SHADOW_GRID_SIZE, storageUsage, 1, 1 }); gridLookupBuffer.UpdateCapacityAll(1); Vk::ImageConfig atlasSpec{}; diff --git a/SynapseEngine/Engine/Scene/DrawData/SceneDrawData.cpp b/SynapseEngine/Engine/Scene/DrawData/SceneDrawData.cpp index 14ea7a90..4bf318bb 100644 --- a/SynapseEngine/Engine/Scene/DrawData/SceneDrawData.cpp +++ b/SynapseEngine/Engine/Scene/DrawData/SceneDrawData.cpp @@ -18,7 +18,7 @@ namespace Syn PointLightShadow(frameCount) { VkBufferUsageFlags contextUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - frameContextBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(FrameGlobalContext), contextUsage, 1, 1}); + frameContextBuffer.Initialize({ "SceneDrawData_FrameContextBuffer", BufferStrategy::Hybrid, frameCount, sizeof(FrameGlobalContext), contextUsage, 1, 1}); frameContextBuffer.UpdateCapacityAll(1); } diff --git a/SynapseEngine/Engine/Scene/DrawData/SpotLightDrawGroup.cpp b/SynapseEngine/Engine/Scene/DrawData/SpotLightDrawGroup.cpp index 5ff270b7..0cc1c4d3 100644 --- a/SynapseEngine/Engine/Scene/DrawData/SpotLightDrawGroup.cpp +++ b/SynapseEngine/Engine/Scene/DrawData/SpotLightDrawGroup.cpp @@ -47,22 +47,22 @@ namespace Syn VkBufferUsageFlags indirectUsage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - indirectBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); + indirectBuffer.Initialize({ "SpotLightDrawGroup_IndirectBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); indirectBuffer.UpdateCapacityAll(1); - sphereSingleCmdBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); + sphereSingleCmdBuffer.Initialize({ "SpotLightDrawGroup_SphereSingleCmdBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); sphereSingleCmdBuffer.UpdateCapacityAll(1); - coneSingleCmdBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); + coneSingleCmdBuffer.Initialize({ "SpotLightDrawGroup_ConeSingleCmdBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); coneSingleCmdBuffer.UpdateCapacityAll(1); - pyramidSingleCmdBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); + pyramidSingleCmdBuffer.Initialize({ "SpotLightDrawGroup_PyramidSingleCmdBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); pyramidSingleCmdBuffer.UpdateCapacityAll(1); - aabbSingleCmdBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); + aabbSingleCmdBuffer.Initialize({ "SpotLightDrawGroup_AABBSingleCmdBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); aabbSingleCmdBuffer.UpdateCapacityAll(1); - billboardSingleCmdBuffer.Initialize({ BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); + billboardSingleCmdBuffer.Initialize({ "SpotLightDrawGroup_BillboardSingleCmdBuffer", BufferStrategy::MappedOnly, frameCount, sizeof(VkDrawIndirectCommand), indirectUsage }); billboardSingleCmdBuffer.UpdateCapacityAll(1); for (uint32_t i = 0; i < frameCount; ++i) { diff --git a/SynapseEngine/Engine/Scene/DrawData/SpotLightShadowDrawGroup.cpp b/SynapseEngine/Engine/Scene/DrawData/SpotLightShadowDrawGroup.cpp index 7b5f0f0e..bbf6236a 100644 --- a/SynapseEngine/Engine/Scene/DrawData/SpotLightShadowDrawGroup.cpp +++ b/SynapseEngine/Engine/Scene/DrawData/SpotLightShadowDrawGroup.cpp @@ -13,55 +13,55 @@ namespace Syn VkBufferUsageFlags storageUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; VkBufferUsageFlags indirectStorageUsage = VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - instanceBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(SpotShadowInstancePayload), storageUsage, 65536, 131072 }); + instanceBuffer.Initialize({ "SpotLightShadowDrawGroup_InstanceBuffer", BufferStrategy::Hybrid, frameCount, sizeof(SpotShadowInstancePayload), storageUsage, 65536, 131072 }); instanceBuffer.UpdateCapacityAll(1); - unsortedInstanceBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(SpotShadowInstancePayload), storageUsage, 65536, 131072 }); + unsortedInstanceBuffer.Initialize({ "SpotLightShadowDrawGroup_UnsortedInstanceBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(SpotShadowInstancePayload), storageUsage, 65536, 131072 }); unsortedInstanceBuffer.UpdateCapacityAll(1); - sortValuesBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(uint32_t), storageUsage, 65536, 131072 }); + sortValuesBuffer.Initialize({ "SpotLightShadowDrawGroup_SortValuesBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(uint32_t), storageUsage, 65536, 131072 }); sortValuesBuffer.UpdateCapacityAll(1); - drawCallKeyBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(uint32_t), storageUsage, 65536, 131072 }); + drawCallKeyBuffer.Initialize({ "SpotLightShadowDrawGroup_DrawCallKeyBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(uint32_t), storageUsage, 65536, 131072 }); drawCallKeyBuffer.UpdateCapacityAll(1); - indirectBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(VkDrawIndirectCommand) * 8, indirectStorageUsage, 1024, 2048 }); + indirectBuffer.Initialize({ "SpotLightShadowDrawGroup_IndirectBuffer", BufferStrategy::Hybrid, frameCount, sizeof(VkDrawIndirectCommand) * 8, indirectStorageUsage, 1024, 2048 }); indirectBuffer.UpdateCapacityAll(1); - visibleCountDispatchBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(uint32_t), storageUsage, 1, 1 }); + visibleCountDispatchBuffer.Initialize({ "SpotLightShadowDrawGroup_VisibleCountDispatchBuffer", BufferStrategy::Hybrid, frameCount, sizeof(uint32_t), storageUsage, 1, 1 }); visibleCountDispatchBuffer.UpdateCapacityAll(1); - visibleMeshCountDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(uint32_t), storageUsage, 1, 1 }); + visibleMeshCountDispatchBuffer.Initialize({ "SpotLightShadowDrawGroup_VisibleMeshCountDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(uint32_t), storageUsage, 1, 1 }); visibleMeshCountDispatchBuffer.UpdateCapacityAll(1); - descriptorBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(MeshDrawDescriptor) * 8, storageUsage, 1024, 2048 }); + descriptorBuffer.Initialize({ "SpotLightShadowDrawGroup-DescriptorBuffer", BufferStrategy::Hybrid, frameCount, sizeof(MeshDrawDescriptor) * 8, storageUsage, 1024, 2048 }); descriptorBuffer.UpdateCapacityAll(1); - modelCullingIndirectDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); + modelCullingIndirectDispatchBuffer.Initialize({ "SpotLightShadowDrawGroup-ModelCullingIndirectDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); modelCullingIndirectDispatchBuffer.UpdateCapacityAll(1); - modelDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); + modelDispatchBuffer.Initialize({ "SpotLightShadowDrawGroup-ModelDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); modelDispatchBuffer.UpdateCapacityAll(1); - finalizeDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); + finalizeDispatchBuffer.Initialize({ "SpotLightShadowDrawGroup-FinalizeDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); finalizeDispatchBuffer.UpdateCapacityAll(1); - staticChunkDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); + staticChunkDispatchBuffer.Initialize({ "SpotLightShadowDrawGroup-StaticChunkDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); staticChunkDispatchBuffer.UpdateCapacityAll(1); - mortonChunkDispatchBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); + mortonChunkDispatchBuffer.Initialize({ "SpotLightShadowDrawGroup-MortonChunkDispatchBuffer", BufferStrategy::GpuOnly, frameCount, sizeof(VkDispatchIndirectCommand), indirectStorageUsage, 1, 1 }); mortonChunkDispatchBuffer.UpdateCapacityAll(1); - atlasRadixSortTempBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, 1, storageUsage | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 10000, 20000 }); + atlasRadixSortTempBuffer.Initialize({ "SpotLightShadowDrawGroup-AtlasRadixSortTempBuffer", BufferStrategy::GpuOnly, frameCount, 1, storageUsage | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 10000, 20000 }); atlasRadixSortTempBuffer.UpdateCapacityAll(1); - radixSortTempBuffer.Initialize({ BufferStrategy::GpuOnly, frameCount, 1, storageUsage | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 10000, 20000 }); + radixSortTempBuffer.Initialize({ "SpotLightShadowDrawGroup-RadixSortTempBuffer", BufferStrategy::GpuOnly, frameCount, 1, storageUsage | VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT, 10000, 20000 }); radixSortTempBuffer.UpdateCapacityAll(1); gridLookupData.Resize(SPOT_SHADOW_GRID_SIZE * SPOT_SHADOW_GRID_SIZE); std::fill(gridLookupData.Data(), gridLookupData.Data() + (SPOT_SHADOW_GRID_SIZE * SPOT_SHADOW_GRID_SIZE), 0xFFFFFFFF); - gridLookupBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(uint32_t) * SPOT_SHADOW_GRID_SIZE * SPOT_SHADOW_GRID_SIZE, storageUsage, 1, 1 }); + gridLookupBuffer.Initialize({ "SpotLightShadowDrawGroup-GridLookupBuffer", BufferStrategy::Hybrid, frameCount, sizeof(uint32_t) * SPOT_SHADOW_GRID_SIZE * SPOT_SHADOW_GRID_SIZE, storageUsage, 1, 1 }); gridLookupBuffer.UpdateCapacityAll(1); Vk::ImageConfig atlasSpec{}; diff --git a/SynapseEngine/Engine/Scene/DrawData/SsaoDrawGroup.cpp b/SynapseEngine/Engine/Scene/DrawData/SsaoDrawGroup.cpp index ffd8a51c..afe01f08 100644 --- a/SynapseEngine/Engine/Scene/DrawData/SsaoDrawGroup.cpp +++ b/SynapseEngine/Engine/Scene/DrawData/SsaoDrawGroup.cpp @@ -10,7 +10,7 @@ namespace Syn SsaoDrawGroup::SsaoDrawGroup(uint32_t frameCount) { VkBufferUsageFlags bufferUsage = VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT; - kernelBuffer.Initialize({ BufferStrategy::Hybrid, frameCount, sizeof(SsaoKernel), bufferUsage }); + kernelBuffer.Initialize({ "SsaoDrawGroup_KernelBuffer", BufferStrategy::Hybrid, frameCount, sizeof(SsaoKernel), bufferUsage }); kernelBuffer.UpdateCapacityAll(1); std::mt19937 generator; diff --git a/SynapseEngine/Engine/Scene/Hierarchy/HierarchyLevelData.cpp b/SynapseEngine/Engine/Scene/Hierarchy/HierarchyLevelData.cpp new file mode 100644 index 00000000..3943cb7c --- /dev/null +++ b/SynapseEngine/Engine/Scene/Hierarchy/HierarchyLevelData.cpp @@ -0,0 +1 @@ +#include "HierarchyLevelData.h" \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Hierarchy/HierarchyLevelData.h b/SynapseEngine/Engine/Scene/Hierarchy/HierarchyLevelData.h new file mode 100644 index 00000000..ff13cf92 --- /dev/null +++ b/SynapseEngine/Engine/Scene/Hierarchy/HierarchyLevelData.h @@ -0,0 +1,13 @@ +#pragma once +#include "Engine/SynApi.h" +#include + +namespace Syn +{ + struct SYN_API HierarchyLevelData + { + uint32_t startIndex = 0; + uint32_t capacity = 0; + uint32_t activeCount = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/HierarchyManager.cpp b/SynapseEngine/Engine/Scene/Hierarchy/HierarchyManager.cpp similarity index 100% rename from SynapseEngine/Engine/Scene/HierarchyManager.cpp rename to SynapseEngine/Engine/Scene/Hierarchy/HierarchyManager.cpp diff --git a/SynapseEngine/Engine/Scene/HierarchyManager.h b/SynapseEngine/Engine/Scene/Hierarchy/HierarchyManager.h similarity index 58% rename from SynapseEngine/Engine/Scene/HierarchyManager.h rename to SynapseEngine/Engine/Scene/Hierarchy/HierarchyManager.h index 288819bd..f62e9806 100644 --- a/SynapseEngine/Engine/Scene/HierarchyManager.h +++ b/SynapseEngine/Engine/Scene/Hierarchy/HierarchyManager.h @@ -2,23 +2,24 @@ #include "Engine/SynApi.h" #include "Engine/Registry/Registry.h" #include "Engine/Component/Core/HierarchyComponent.h" +#include "Engine/Registry/Type/TypeInfo.h" +#include "HierarchyWorkQueue.h" +#include "HierarchyLevelData.h" #include #include +#include +#include namespace Syn { - struct SYN_API HierarchyLevelData - { - uint32_t startIndex = 0; - uint32_t capacity = 0; - uint32_t activeCount = 0; - }; - class SYN_API HierarchyManager { public: HierarchyManager(Registry* registry); + HierarchyManager(const HierarchyManager&) = delete; + HierarchyManager& operator=(const HierarchyManager&) = delete; + void AttachChild(EntityID parent, EntityID child); void DetachChild(EntityID child); bool CanAttach(EntityID parent, EntityID child) const; @@ -30,16 +31,38 @@ namespace Syn uint32_t GetMaxActiveLevel() const { return static_cast(_levels.size()); } const std::span GetLevels() const { return std::span(_levels.data(), _levels.size()); } uint64_t GetVersion() const { return _version; } + + template + HierarchyWorkQueue* EnsureWorkQueue(); private: void InsertIntoLevel(EntityID entity, uint32_t level); void RemoveFromLevel(EntityID entity); void RebuildTopologicalArray(); void UpdateSubtreeLevels(EntityID root, int32_t levelDelta); - private: Registry* _registry; std::vector _topologicalArray; std::vector _levels; uint64_t _version = 0; + + std::unordered_map> _workQueues; }; + + template + HierarchyWorkQueue* HierarchyManager::EnsureWorkQueue() + { + const TypeID id = TypeInfo::ID; + auto it = _workQueues.find(id); + + [[unlikely]] + if (it == _workQueues.end()) + { + auto queue = std::make_unique(); + auto* rawPtr = queue.get(); + _workQueues[id] = std::move(queue); + return rawPtr; + } + + return it->second.get(); + } } \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Hierarchy/HierarchyWorkQueue.cpp b/SynapseEngine/Engine/Scene/Hierarchy/HierarchyWorkQueue.cpp new file mode 100644 index 00000000..3295c02c --- /dev/null +++ b/SynapseEngine/Engine/Scene/Hierarchy/HierarchyWorkQueue.cpp @@ -0,0 +1,21 @@ +#include "HierarchyWorkQueue.h" + +namespace Syn +{ + void HierarchyWorkQueue::Initialize(std::span levels) + { + uint32_t maxLevel = static_cast(levels.size()); + + if (_queues.size() < maxLevel) { + _queues.resize(maxLevel); + } + + for (uint32_t i = 0; i < maxLevel; ++i) { + if (_queues[i].entities.size() < levels[i].capacity) { + _queues[i].entities.resize(levels[i].capacity); + } + + _queues[i].count.store(0, std::memory_order_relaxed); + } + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Hierarchy/HierarchyWorkQueue.h b/SynapseEngine/Engine/Scene/Hierarchy/HierarchyWorkQueue.h new file mode 100644 index 00000000..d4688f7b --- /dev/null +++ b/SynapseEngine/Engine/Scene/Hierarchy/HierarchyWorkQueue.h @@ -0,0 +1,66 @@ +#pragma once +#include "Engine/SynApi.h" +#include "Engine/SynMacro.h" +#include "Engine/Registry/Entity.h" +#include "HierarchyLevelData.h" +#include +#include +#include + +namespace Syn +{ + struct alignas(64) SYN_API LevelQueue + { + std::vector entities; + std::atomic count{ 0 }; + + LevelQueue() = default; + + LevelQueue(LevelQueue&& other) noexcept + : entities(std::move(other.entities)) + { + count.store(other.count.load(std::memory_order_relaxed), std::memory_order_relaxed); + } + + LevelQueue& operator=(LevelQueue&& other) noexcept + { + if (this != &other) { + entities = std::move(other.entities); + count.store(other.count.load(std::memory_order_relaxed), std::memory_order_relaxed); + } + return *this; + } + + LevelQueue(const LevelQueue&) = delete; + LevelQueue& operator=(const LevelQueue&) = delete; + }; + + class SYN_API HierarchyWorkQueue + { + public: + HierarchyWorkQueue() = default; + + HierarchyWorkQueue(const HierarchyWorkQueue&) = delete; + HierarchyWorkQueue& operator=(const HierarchyWorkQueue&) = delete; + + HierarchyWorkQueue(HierarchyWorkQueue&&) = default; + HierarchyWorkQueue& operator=(HierarchyWorkQueue&&) = default; + + void Initialize(std::span levels); + + SYN_INLINE void Push(uint32_t level, EntityID entity) + { + size_t idx = _queues[level].count.fetch_add(1, std::memory_order_relaxed); + _queues[level].entities[idx] = entity; + } + + SYN_INLINE std::span GetQueue(uint32_t level) const + { + size_t activeCount = _queues[level].count.load(std::memory_order_relaxed); + return std::span(_queues[level].entities.data(), activeCount); + } + + private: + std::vector _queues; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Scene.cpp b/SynapseEngine/Engine/Scene/Scene.cpp index d91b1e67..4a05ab64 100644 --- a/SynapseEngine/Engine/Scene/Scene.cpp +++ b/SynapseEngine/Engine/Scene/Scene.cpp @@ -17,14 +17,18 @@ #include "Engine/Component/Rendering/MaterialOverrideComponent.h" #include "Engine/System/Core/TransformSystem.h" +#include "Engine/System/Core/TransformSetupSystem.h" #include "Engine/System/Core/HierarchySystem.h" #include "Engine/System/Core/SelectionOutlineSystem.h" -#include "Engine/System/Rendering/RenderSystem.h" +#include "Engine/System/Core/TagSystem.h" +#include "Engine/System/Core/TagSetupSystem.h" #include "Engine/System/Core/CameraSystem.h" +#include "Engine/System/Rendering/RenderSystem.h" #include "Engine/System/Rendering/ModelSystem.h" #include "Engine/System/Rendering/MaterialSystem.h" #include "Engine/System/Rendering/ModelFrustumCullingSystem.h" #include "Engine/System/Rendering/AnimationSystem.h" +#include "Engine/System/Rendering/MaterialOverrideSystem.h" #include "Engine/System/Physics/PhysicsSystem.h" #include "Engine/System/Light/Point/PointLightSystem.h" @@ -134,8 +138,13 @@ namespace Syn void Scene::InitializeSystems() { + RegisterSystem(); RegisterSystem(); RegisterSystem(); + + RegisterSystem(); + RegisterSystem(); + RegisterSystem(); RegisterSystem(); RegisterSystem(); @@ -143,6 +152,7 @@ namespace Syn RegisterSystem(); RegisterSystem(); RegisterSystem(); + RegisterSystem(); RegisterSystem(); RegisterSystem(); @@ -176,6 +186,7 @@ namespace Syn RegisterSystem(); RegisterSystem(); + } void Scene::InitializeComponentBuffers() @@ -230,6 +241,9 @@ namespace Syn RegisterComponentSparseMapBuffer(BufferNames::HierarchySparseMap); RegisterComponentBuffer(BufferNames::SelectionOutlineData); + RegisterComponentSparseMapBuffer(BufferNames::TagSparseMap); + RegisterComponentBuffer(BufferNames::TagData); + RegisterComponentSparseMapBuffer(BufferNames::TransformSparseMap); RegisterComponentBuffer(BufferNames::TransformData); RegisterComponentBuffer(BufferNames::TransformModelLinkData); @@ -486,6 +500,38 @@ namespace Syn _currentFrameIndex = frameIndex; _currentDeltaTime = deltaTime; + auto modelSnapshot = ServiceLocator::GetModelManager()->GetSnapshotAndVersion(); + auto animSnapshot = ServiceLocator::GetAnimationManager()->GetSnapshotAndVersion(); + auto materialSnapshot = ServiceLocator::GetMaterialManager()->GetSnapshotAndVersion(); + + _systemContext.deltaTime = deltaTime; + _systemContext.frameIndex = frameIndex; + + _systemContext.modelManagerVersion = modelSnapshot.version; + _systemContext.materialManagerVersion = materialSnapshot.version; + _systemContext.animationManagerVersion = animSnapshot.version; + + _systemContext.modelSnapshots = modelSnapshot.snapshots; + _systemContext.materialSnapshots = materialSnapshot.snapshots; + _systemContext.animationSnapshots = animSnapshot.snapshots; + + _systemContext.materialRenderTypes.clear(); + _systemContext.materialRenderTypes.resize(materialSnapshot.snapshots.size()); + + std::transform(materialSnapshot.snapshots.begin(), materialSnapshot.snapshots.end(), _systemContext.materialRenderTypes.begin(), + [](const auto& snapshot) -> MaterialRenderType { + if (!snapshot.resource) + return MaterialRenderType::Opaque1Sided; + + bool isTrans = snapshot.resource->isTransparent; + bool isDouble = snapshot.resource->doubleSided; + + if (isTrans && isDouble) return MaterialRenderType::Transparent2Sided; + if (isTrans) return MaterialRenderType::Transparent1Sided; + if (isDouble) return MaterialRenderType::Opaque2Sided; + return MaterialRenderType::Opaque1Sided; + }); + auto screenWidth = ServiceLocator::GetFrameContext()->screenWidth; auto screenHeight = ServiceLocator::GetFrameContext()->screenHeight; diff --git a/SynapseEngine/Engine/Scene/Scene.h b/SynapseEngine/Engine/Scene/Scene.h index 2dc31025..df04330b 100644 --- a/SynapseEngine/Engine/Scene/Scene.h +++ b/SynapseEngine/Engine/Scene/Scene.h @@ -16,7 +16,8 @@ #include "DrawData/SceneDrawData.h" #include "Engine/Scene/Source/ISceneSource.h" #include "Engine/Physics/IPhysicsEngine.h" -#include "HierarchyManager.h" +#include "Hierarchy/HierarchyManager.h" +#include "Engine/System/SystemContext.h" namespace Syn { @@ -53,6 +54,8 @@ namespace Syn EntityID GetSelectedEntity() const { return _selectedEntity; } void SetSelectedEntity(EntityID entity) { _selectedEntity = entity; } + + const SystemContext& GetSystemContext() const { return _systemContext; } private: void InitializeSystems(); void InitializeComponentBuffers(); @@ -90,6 +93,8 @@ namespace Syn float _currentDeltaTime = 0.0f; uint32_t _currentFrameIndex = 0; + + SystemContext _systemContext; private: friend class SceneInsider; }; diff --git a/SynapseEngine/Engine/Scene/SceneNames.h b/SynapseEngine/Engine/Scene/SceneNames.h new file mode 100644 index 00000000..bb939f61 --- /dev/null +++ b/SynapseEngine/Engine/Scene/SceneNames.h @@ -0,0 +1,12 @@ +#pragma once +#include "Engine/SynApi.h" + +namespace Syn +{ + struct SYN_API SceneNames + { + static constexpr const char* Main = "Main"; + static constexpr const char* MaterialPreview = "MaterialPreview"; + static constexpr const char* ModelPreview = "ModelPreview"; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Settings/CullingSettings.cpp b/SynapseEngine/Engine/Scene/Settings/CullingSettings.cpp index a793b9a0..cb42d1cb 100644 --- a/SynapseEngine/Engine/Scene/Settings/CullingSettings.cpp +++ b/SynapseEngine/Engine/Scene/Settings/CullingSettings.cpp @@ -3,10 +3,10 @@ namespace Syn { CullingSettings::CullingSettings() - : geometryCullingDevice(CullingDeviceType::CPU) + : geometryCullingDevice(CullingDeviceType::GPU) , spotLightCullingDevice(CullingDeviceType::CPU) , pointLightCullingDevice(CullingDeviceType::CPU) - , directionLightShadowCullingDevice(CullingDeviceType::CPU) + , directionLightShadowCullingDevice(CullingDeviceType::GPU) , spotLightShadowCullingDevice(CullingDeviceType::CPU) , pointLightShadowCullingDevice(CullingDeviceType::CPU) , geometrySpatialAcceleration(SpatialAccelerationType::None) @@ -14,7 +14,7 @@ namespace Syn , spotLightShadowSpatialAcceleration(SpatialAccelerationType::None) , pointLightShadowSpatialAcceleration(SpatialAccelerationType::None) , enableHiz(true) - , enableMeshletConeCulling(false) + , enableMeshletConeCulling(true) , enableFrustumCulling(true) , enableChunkFrustumCulling(true) , enableModelFrustumCulling(true) diff --git a/SynapseEngine/Engine/Scene/Settings/DebugSettings.cpp b/SynapseEngine/Engine/Scene/Settings/DebugSettings.cpp index 3ea959af..19681280 100644 --- a/SynapseEngine/Engine/Scene/Settings/DebugSettings.cpp +++ b/SynapseEngine/Engine/Scene/Settings/DebugSettings.cpp @@ -31,5 +31,20 @@ namespace Syn , outlinePrimaryColor(glm::vec4(1.0f, 0.60f, 0.0f, 1.0f)) , outlineSecondaryColor(glm::vec4(1.0f, 0.85f, 0.0f, 1.0f)) , outlineThickness(2.0f) + , enableInfiniteGrid(false) + , gridScale(1.0f) + , fadeDistance(250.0f) + , gridThickness(1.0f) + , axisThickness(2.0f) + , gridShowXZ(true) + , gridShowXY(false) + , gridShowYZ(false) + , gridShowAxisX(true) + , gridShowAxisY(true) + , gridShowAxisZ(true) + , gridColor(glm::vec4(0.5f, 0.5f, 0.5f, 1.0f)) + , axisXColor(glm::vec4(1.0f, 0.2f, 0.2f, 1.0f)) + , axisYColor(glm::vec4(0.2f, 1.0f, 0.2f, 1.0f)) + , axisZColor(glm::vec4(0.2f, 0.2f, 1.0f, 1.0f)) {} } \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Settings/DebugSettings.h b/SynapseEngine/Engine/Scene/Settings/DebugSettings.h index be8c4ab2..bca433b2 100644 --- a/SynapseEngine/Engine/Scene/Settings/DebugSettings.h +++ b/SynapseEngine/Engine/Scene/Settings/DebugSettings.h @@ -60,5 +60,22 @@ namespace Syn glm::vec4 outlinePrimaryColor; glm::vec4 outlineSecondaryColor; float outlineThickness; + + // Infinite grid + bool enableInfiniteGrid; + float gridScale; + float fadeDistance; + float gridThickness; + float axisThickness; + bool gridShowXZ; + bool gridShowXY; + bool gridShowYZ; + bool gridShowAxisX; + bool gridShowAxisY; + bool gridShowAxisZ; + glm::vec4 gridColor; + glm::vec4 axisXColor; + glm::vec4 axisYColor; + glm::vec4 axisZColor; }; } \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Settings/EnvironmentSettings.cpp b/SynapseEngine/Engine/Scene/Settings/EnvironmentSettings.cpp new file mode 100644 index 00000000..aea51014 --- /dev/null +++ b/SynapseEngine/Engine/Scene/Settings/EnvironmentSettings.cpp @@ -0,0 +1,21 @@ +#include "EnvironmentSettings.h" + +namespace Syn +{ + EnvironmentSettings::EnvironmentSettings() + : enableSky(true) + , skyMode(SkyMode::EquirectangularTexture) + , skyTextureId(UINT32_MAX) + , skyIntensity(1.0f) + , skyExposureEV(0.0f) + , skyTint(glm::vec3(1.0f)) + , skyRotation(glm::vec3(0.0f)) + , ambientIntensity(1.0f) + , irradianceTextureId(UINT32_MAX) + , prefilteredTextureId(UINT32_MAX) + , brdfLutTextureId(UINT32_MAX) + , enableFog(false) + , fogColor(glm::vec3(0.5f, 0.6f, 0.7f)) + , fogDensity(0.01f) + {} +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Settings/EnvironmentSettings.h b/SynapseEngine/Engine/Scene/Settings/EnvironmentSettings.h new file mode 100644 index 00000000..069b4061 --- /dev/null +++ b/SynapseEngine/Engine/Scene/Settings/EnvironmentSettings.h @@ -0,0 +1,37 @@ +#pragma once +#include "Engine/SynApi.h" +#include + +namespace Syn +{ + enum class SYN_API SkyMode + { + None = 0, + EquirectangularTexture = 1, + OctahedralTexture = 2, + Procedural = 3 + }; + + struct SYN_API EnvironmentSettings + { + EnvironmentSettings(); + + bool enableSky; + SkyMode skyMode; + + uint32_t skyTextureId; + float skyIntensity; + float skyExposureEV; + glm::vec3 skyTint; + glm::vec3 skyRotation; + + float ambientIntensity; + uint32_t irradianceTextureId; + uint32_t prefilteredTextureId; + uint32_t brdfLutTextureId; + + bool enableFog; + glm::vec3 fogColor; + float fogDensity; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Settings/PostProcessSettings.cpp b/SynapseEngine/Engine/Scene/Settings/PostProcessSettings.cpp index b22fa9a6..0f80e7f4 100644 --- a/SynapseEngine/Engine/Scene/Settings/PostProcessSettings.cpp +++ b/SynapseEngine/Engine/Scene/Settings/PostProcessSettings.cpp @@ -11,11 +11,11 @@ namespace Syn , bloomStrength(1.0f) , enableSsao(false) , enableSsaoLight(false) - , aoRadius(0.930f) - , aoIntensity(100.0f) - , maxOcclusionDistance(3.0f) + , aoRadius(0.95f) + , aoIntensity(5.0f) + , maxOcclusionDistance(10.0f) , depthSharpness(0.0f) - , bias(0.005f) - , sampleCount(32) + , bias(0.05f) + , sampleCount(64) {} } \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Settings/SceneSettings.h b/SynapseEngine/Engine/Scene/Settings/SceneSettings.h index 46e742de..c47dc358 100644 --- a/SynapseEngine/Engine/Scene/Settings/SceneSettings.h +++ b/SynapseEngine/Engine/Scene/Settings/SceneSettings.h @@ -4,6 +4,7 @@ #include "LightingSettings.h" #include "PostProcessSettings.h" #include "DebugSettings.h" +#include "EnvironmentSettings.h" namespace Syn { @@ -15,5 +16,6 @@ namespace Syn LightingSettings lighting; PostProcessSettings postProcess; DebugSettings debug; + EnvironmentSettings environment; }; } \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Source/Procedural/MaterialPreviewSceneSource.cpp b/SynapseEngine/Engine/Scene/Source/Procedural/MaterialPreviewSceneSource.cpp new file mode 100644 index 00000000..f15c88d2 --- /dev/null +++ b/SynapseEngine/Engine/Scene/Source/Procedural/MaterialPreviewSceneSource.cpp @@ -0,0 +1,181 @@ +#include "MaterialPreviewSceneSource.h" +#include "Engine/Scene/Scene.h" +#include "Engine/Scene/Insiders/SceneInsider.h" +#include "Engine/ServiceLocator.h" +#include "Engine/Component/Core/TransformComponent.h" +#include "Engine/Component/Core/CameraComponent.h" +#include "Engine/Component/Core/TagComponent.h" +#include "Engine/Component/Rendering/ModelComponent.h" +#include "Engine/Mesh/Factory/MeshFactory.h" +#include "Engine/Mesh/ModelManager.h" +#include "Engine/Component/Rendering/MaterialOverrideComponent.h" +#include "Engine/Material/MaterialManager.h" +#include "Engine/Component/Light/Point/PointLightComponent.h" +#include "Engine/Component/Light/Direction/DirectionLightComponent.h" +#include "Engine/Image/ImageManager.h" +#include "Engine/Mesh/MeshSourceNames.h" +#include "Engine/Logger/SynLog.h" +#include "Engine/Utils/PathUtils.h" + +#include +#include +#include + +namespace Syn +{ + bool MaterialPreviewSceneSource::Populate(Scene& scene) + { + Registry& registry = SceneInsider::GetRegistry(scene, SceneInsider::GetKey()); + EntityID& sceneCam = SceneInsider::GetSceneCameraEntity(scene, SceneInsider::GetKey()); + HierarchyManager* hm = scene.GetHierarchyManager(); + + auto modelManager = ServiceLocator::GetModelManager(); + auto materialManager = ServiceLocator::GetMaterialManager(); + + Syn::Info("Populating Material Preview Scene..."); + + // Root entities + EntityID rootCameras = scene.CreateEntity(); + registry.AddComponent(rootCameras); + registry.GetComponent(rootCameras).name = "Cameras"; + registry.GetComponent(rootCameras).tag = "Root"; + registry.AddComponent(rootCameras); + registry.GetPool()->SetCategory(rootCameras, StorageCategory::Static); + + EntityID rootEnvironment = scene.CreateEntity(); + registry.AddComponent(rootEnvironment); + registry.GetComponent(rootEnvironment).name = "Preview Objects"; + registry.GetComponent(rootEnvironment).tag = "Root"; + registry.AddComponent(rootEnvironment); + registry.GetPool()->SetCategory(rootEnvironment, StorageCategory::Static); + + EntityID rootLights = scene.CreateEntity(); + registry.AddComponent(rootLights); + registry.GetComponent(rootLights).name = "Studio Lights"; + registry.GetComponent(rootLights).tag = "Root"; + registry.AddComponent(rootLights); + registry.GetPool()->SetCategory(rootLights, StorageCategory::Static); + + // Orbit camera + sceneCam = scene.CreateEntity(); + registry.AddComponent(sceneCam); + registry.GetComponent(sceneCam).name = "Preview Camera"; + registry.GetComponent(sceneCam).tag = "Camera"; + + registry.AddComponent(sceneCam); + auto& camTransform = registry.GetComponent(sceneCam); + camTransform.rotation = glm::vec3(-25.0f, 45.0f, 0.0f); + + registry.AddComponent(sceneCam); + auto& camComp = registry.GetComponent(sceneCam); + camComp.useOrbit = true; + camComp.target = glm::vec3(0.0f); + camComp.distance = 12.0f; + camComp.speed = 20.0f; + + registry.GetPool()->SetCategory(sceneCam, StorageCategory::Stream); + registry.GetPool()->SetCategory(sceneCam, StorageCategory::Stream); + hm->AttachChild(rootCameras, sceneCam); + + // Studio lighting setup + + // 1. Key light (warm, casts shadows) + EntityID keyLight = scene.CreateEntity(); + registry.AddComponent(keyLight); + registry.GetComponent(keyLight).name = "Key Light"; + + registry.AddComponent(keyLight); + registry.GetComponent(keyLight).rotation = glm::vec3(-45.0f, -45.0f, 0.0f); + + registry.AddComponent(keyLight); + auto& dirKey = registry.GetComponent(keyLight); + dirKey.color = glm::vec3(1.0f, 0.95f, 0.9f); + dirKey.strength = 3.0f; + dirKey.useShadow = true; + + registry.GetPool()->SetBit(keyLight); + hm->AttachChild(rootLights, keyLight); + + // 2. Fill light (cool, no shadows) + EntityID fillLight = scene.CreateEntity(); + registry.AddComponent(fillLight); + registry.GetComponent(fillLight).name = "Fill Light"; + + registry.AddComponent(fillLight); + registry.GetComponent(fillLight).rotation = glm::vec3(30.0f, 135.0f, 0.0f); + + registry.AddComponent(fillLight); + auto& dirFill = registry.GetComponent(fillLight); + dirFill.color = glm::vec3(0.8f, 0.9f, 1.0f); + dirFill.strength = 1.0f; + dirFill.useShadow = false; + + hm->AttachChild(rootLights, fillLight); + + // Base materials + MaterialInfo floorMatInfo{}; + floorMatInfo.color = glm::vec4(0.15f, 0.15f, 0.15f, 1.0f); + floorMatInfo.roughnessFactor = 0.9f; + uint32_t floorMatId = materialManager->LoadMaterial("Preview_FloorMat", floorMatInfo); + + // Geometries + + // 1. Floor + EntityID floor = scene.CreateEntity(); + registry.AddComponent(floor); + registry.GetComponent(floor).name = "Studio_Floor"; + + registry.AddComponent(floor); + registry.GetComponent(floor).translation = glm::vec3(0.0f, -2.0f, 0.0f); + registry.GetComponent(floor).scale = glm::vec3(25.0f, 1.0f, 25.0f); + registry.GetPool()->SetCategory(floor, StorageCategory::Static); + + registry.AddComponent(floor); + registry.GetComponent(floor).modelIndex = modelManager->GetResourceIndex(MeshSourceNames::Cube); + registry.GetPool()->SetCategory(floor, StorageCategory::Static); + + registry.AddComponent(floor); + registry.GetComponent(floor).materials.push_back(floorMatId); + registry.GetPool()->SetCategory(floor, StorageCategory::Static); + + hm->AttachChild(rootEnvironment, floor); + + // Helper for preview objects + auto CreatePreviewObject = [&](const std::string& name, uint32_t modelIndex, glm::vec3 pos, glm::vec3 scale = glm::vec3(1.0f)) { + EntityID e = scene.CreateEntity(); + registry.AddComponent(e); + registry.GetComponent(e).name = name; + registry.GetComponent(e).tag = "Preview"; + registry.GetPool()->SetCategory(e, StorageCategory::Static); + + registry.AddComponent(e); + registry.GetComponent(e).translation = pos; + registry.GetComponent(e).scale = scale; + registry.GetPool()->SetCategory(e, StorageCategory::Static); + + registry.AddComponent(e); + registry.GetComponent(e).modelIndex = modelIndex; + registry.GetPool()->SetCategory(e, StorageCategory::Static); + + registry.AddComponent(e); + registry.GetPool()->SetCategory(e, StorageCategory::Static); + + hm->AttachChild(rootEnvironment, e); + }; + + // 2. Center object: Suzanne + auto skyTextureId = ServiceLocator::GetImageManager()->LoadImageSync(PathUtils::GetAbsolutePathString("Assets/Engine/Environment/MaterialPreview.hdr")); + scene.GetSettings()->environment.skyTextureId = skyTextureId; + + uint32_t monkeyId = modelManager->LoadModelAsync(PathUtils::GetAbsolutePathString("Assets/Engine/Models/Monkey/Untitled.obj")); + CreatePreviewObject("Center_Monkey", monkeyId, glm::vec3(0.0f, 0.5f, 0.0f), glm::vec3(1.5f)); + + uint32_t sphereId = modelManager->GetResourceIndex(MeshSourceNames::Sphere); + CreatePreviewObject("Preview_Sphere", sphereId, glm::vec3(-4.0f, 0.5f, 0.0f)); + + uint32_t cubeId = modelManager->GetResourceIndex(MeshSourceNames::Cube); + CreatePreviewObject("Preview_Cube", cubeId, glm::vec3(4.0f, 0.5f, 0.0f)); + + return true; + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Source/Procedural/MaterialPreviewSceneSource.h b/SynapseEngine/Engine/Scene/Source/Procedural/MaterialPreviewSceneSource.h new file mode 100644 index 00000000..d97bce47 --- /dev/null +++ b/SynapseEngine/Engine/Scene/Source/Procedural/MaterialPreviewSceneSource.h @@ -0,0 +1,13 @@ +#pragma once +#include "Engine/SynApi.h" +#include "Engine/Scene/Source/ISceneSource.h" + +namespace Syn +{ + class SYN_API MaterialPreviewSceneSource : public ISceneSource + { + public: + MaterialPreviewSceneSource() = default; + virtual bool Populate(Scene& scene) override; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Source/Procedural/ModelPreviewSceneSource.cpp b/SynapseEngine/Engine/Scene/Source/Procedural/ModelPreviewSceneSource.cpp new file mode 100644 index 00000000..6b025ecf --- /dev/null +++ b/SynapseEngine/Engine/Scene/Source/Procedural/ModelPreviewSceneSource.cpp @@ -0,0 +1,138 @@ +#include "ModelPreviewSceneSource.h" +#include "Engine/Scene/Scene.h" +#include "Engine/Scene/Insiders/SceneInsider.h" +#include "Engine/ServiceLocator.h" +#include "Engine/Component/Core/TransformComponent.h" +#include "Engine/Component/Core/CameraComponent.h" +#include "Engine/Component/Core/TagComponent.h" +#include "Engine/Component/Rendering/ModelComponent.h" +#include "Engine/Mesh/Factory/MeshFactory.h" +#include "Engine/Mesh/ModelManager.h" +#include "Engine/Component/Rendering/MaterialOverrideComponent.h" +#include "Engine/Material/MaterialManager.h" +#include "Engine/Component/Light/Point/PointLightComponent.h" +#include "Engine/Component/Light/Direction/DirectionLightComponent.h" +#include "Engine/Image/ImageManager.h" +#include "Engine/Mesh/MeshSourceNames.h" +#include "Engine/Logger/SynLog.h" +#include "Engine/Utils/PathUtils.h" + +#include +#include + +namespace Syn +{ + bool ModelPreviewSceneSource::Populate(Scene& scene) + { + Registry& registry = SceneInsider::GetRegistry(scene, SceneInsider::GetKey()); + EntityID& sceneCam = SceneInsider::GetSceneCameraEntity(scene, SceneInsider::GetKey()); + HierarchyManager* hm = scene.GetHierarchyManager(); + + auto modelManager = ServiceLocator::GetModelManager(); + auto materialManager = ServiceLocator::GetMaterialManager(); + + Syn::Info("Populating Model Preview Scene..."); + + // Root entities + EntityID rootCameras = scene.CreateEntity(); + registry.AddComponent(rootCameras); + registry.GetComponent(rootCameras).name = "Cameras"; + registry.GetComponent(rootCameras).tag = "Root"; + registry.AddComponent(rootCameras); + registry.GetPool()->SetCategory(rootCameras, StorageCategory::Static); + + EntityID rootEnvironment = scene.CreateEntity(); + registry.AddComponent(rootEnvironment); + registry.GetComponent(rootEnvironment).name = "Preview Objects"; + registry.GetComponent(rootEnvironment).tag = "Root"; + registry.AddComponent(rootEnvironment); + registry.GetPool()->SetCategory(rootEnvironment, StorageCategory::Static); + + EntityID rootLights = scene.CreateEntity(); + registry.AddComponent(rootLights); + registry.GetComponent(rootLights).name = "Studio Lights"; + registry.GetComponent(rootLights).tag = "Root"; + registry.AddComponent(rootLights); + registry.GetPool()->SetCategory(rootLights, StorageCategory::Static); + + // Orbit camera + sceneCam = scene.CreateEntity(); + registry.AddComponent(sceneCam); + registry.GetComponent(sceneCam).name = "Preview Camera"; + registry.GetComponent(sceneCam).tag = "Camera"; + + registry.AddComponent(sceneCam); + auto& camTransform = registry.GetComponent(sceneCam); + camTransform.rotation = glm::vec3(-25.0f, 45.0f, 0.0f); + + registry.AddComponent(sceneCam); + auto& camComp = registry.GetComponent(sceneCam); + camComp.useOrbit = true; + camComp.target = glm::vec3(0.0f, 0.5f, 0.0f); + camComp.distance = 12.0f; + camComp.speed = 20.0f; + + registry.GetPool()->SetCategory(sceneCam, StorageCategory::Stream); + registry.GetPool()->SetCategory(sceneCam, StorageCategory::Stream); + hm->AttachChild(rootCameras, sceneCam); + + // 1. Key light + EntityID keyLight = scene.CreateEntity(); + registry.AddComponent(keyLight); + registry.GetComponent(keyLight).name = "Key Light"; + + registry.AddComponent(keyLight); + registry.GetComponent(keyLight).rotation = glm::vec3(-45.0f, -45.0f, 0.0f); + + registry.AddComponent(keyLight); + auto& dirKey = registry.GetComponent(keyLight); + dirKey.color = glm::vec3(1.0f, 0.95f, 0.9f); + dirKey.strength = 3.0f; + dirKey.useShadow = true; + + registry.GetPool()->SetBit(keyLight); + hm->AttachChild(rootLights, keyLight); + + // 2. Fill light + EntityID fillLight = scene.CreateEntity(); + registry.AddComponent(fillLight); + registry.GetComponent(fillLight).name = "Fill Light"; + + registry.AddComponent(fillLight); + registry.GetComponent(fillLight).rotation = glm::vec3(30.0f, 135.0f, 0.0f); + + registry.AddComponent(fillLight); + auto& dirFill = registry.GetComponent(fillLight); + dirFill.color = glm::vec3(0.8f, 0.9f, 1.0f); + dirFill.strength = 1.0f; + dirFill.useShadow = false; + + hm->AttachChild(rootLights, fillLight); + + EntityID previewModel = scene.CreateEntity(); + registry.AddComponent(previewModel); + registry.GetComponent(previewModel).name = "Preview_Model"; + registry.GetComponent(previewModel).tag = "Preview"; + registry.GetPool()->SetCategory(previewModel, StorageCategory::Static); + + registry.AddComponent(previewModel); + registry.GetComponent(previewModel).translation = glm::vec3(0.0f, 0.0f, 0.0f); + registry.GetComponent(previewModel).scale = glm::vec3(1.0f); + registry.GetPool()->SetCategory(previewModel, StorageCategory::Static); + + registry.AddComponent(previewModel); + registry.GetComponent(previewModel).modelIndex = 0xFFFFFFFF; + registry.GetPool()->SetCategory(previewModel, StorageCategory::Static); + + registry.AddComponent(previewModel); + registry.GetPool()->SetCategory(previewModel, StorageCategory::Static); + + hm->AttachChild(rootEnvironment, previewModel); + + auto skyTextureId = ServiceLocator::GetImageManager()->LoadImageSync(PathUtils::GetAbsolutePathString("Assets/Engine/Environment/ModelPreview.hdr")); + scene.GetSettings()->environment.skyTextureId = skyTextureId; + scene.GetSettings()->debug.enableInfiniteGrid = true; + + return true; + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Source/Procedural/NatureSceneSource.h b/SynapseEngine/Engine/Scene/Source/Procedural/ModelPreviewSceneSource.h similarity index 62% rename from SynapseEngine/Engine/Scene/Source/Procedural/NatureSceneSource.h rename to SynapseEngine/Engine/Scene/Source/Procedural/ModelPreviewSceneSource.h index e958b37e..aa1d96c1 100644 --- a/SynapseEngine/Engine/Scene/Source/Procedural/NatureSceneSource.h +++ b/SynapseEngine/Engine/Scene/Source/Procedural/ModelPreviewSceneSource.h @@ -4,10 +4,10 @@ namespace Syn { - class SYN_API NatureSceneSource : public ISceneSource + class SYN_API ModelPreviewSceneSource : public ISceneSource { public: - NatureSceneSource() = default; + ModelPreviewSceneSource() = default; virtual bool Populate(Scene& scene) override; }; } \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Source/Procedural/NatureSceneSource.cpp b/SynapseEngine/Engine/Scene/Source/Procedural/NatureSceneSource.cpp deleted file mode 100644 index a6f7f69e..00000000 --- a/SynapseEngine/Engine/Scene/Source/Procedural/NatureSceneSource.cpp +++ /dev/null @@ -1,211 +0,0 @@ -#include "NatureSceneSource.h" -#include "Engine/Scene/Scene.h" -#include "Engine/Scene/Insiders/SceneInsider.h" -#include "Engine/ServiceLocator.h" -#include "Engine/Component/Core/TransformComponent.h" -#include "Engine/Component/Core/CameraComponent.h" -#include "Engine/Component/Rendering/ModelComponent.h" -#include "Engine/Mesh/Factory/MeshFactory.h" -#include "Engine/Mesh/ModelManager.h" -#include "Engine/Manager/ShaderManager.h" -#include "Engine/Mesh/MeshSourceNames.h" -#include "Engine/Component/Rendering/MaterialOverrideComponent.h" -#include "Engine/Material/MaterialManager.h" -#include "Engine/Animation/AnimationManager.h" -#include "Engine/Component/Rendering/AnimationComponent.h" -#include "Engine/Component/Light/Point/PointLightComponent.h" -#include "Engine/Component/Light/Spot/SpotLightComponent.h" -#include "Engine/Component/Light/Direction/DirectionLightComponent.h" -#include "Engine/Component/Physics/BoxColliderComponent.h" -#include "Engine/Component/Physics/SphereColliderComponent.h" -#include "Engine/Component/Physics/CapsuleColliderComponent.h" -#include "Engine/Component/Physics/RigidBodyComponent.h" -#include "Engine/Logger/SynLog.h" -#include "Engine/Utils/PathUtils.h" - -#include -#include -#include - -using json = nlohmann::json; - -namespace Syn -{ - bool NatureSceneSource::Populate(Scene& scene) - { - Registry& registry = SceneInsider::GetRegistry(scene, SceneInsider::GetKey()); - EntityID& sceneCam = SceneInsider::GetSceneCameraEntity(scene, SceneInsider::GetKey()); - EntityID& debugCam = SceneInsider::GetDebugCameraEntity(scene, SceneInsider::GetKey()); - - auto modelManager = ServiceLocator::GetModelManager(); - auto animationManager = ServiceLocator::GetAnimationManager(); - auto materialManager = ServiceLocator::GetMaterialManager(); - - json config; - std::string path = PathUtils::GetAbsolutePathString("Engine/Scene/Source/Procedural/nature_config.json"); - std::ifstream configFile(path); - - if (configFile.is_open()) - { - try { - configFile >> config; - Syn::Info("Nature Scene configuration loaded successfully!"); - } - catch (const json::parse_error& e) { - Syn::Error("JSON parsing error: {}. Using default settings.", e.what()); - } - } - else - { - Syn::Warning("nature_config.json not found, using default settings."); - } - - std::string basePath = config.value("/paths/base_model_path"_json_pointer, "C:/Users/User/Desktop/Models/"); - bool spawnFloor = config.value("/environment/spawn_floor"_json_pointer, true); - int staticGeoCount = config.value("/entities/static_geometry"_json_pointer, 100); - - int dirLightCount = config.value("/lights/directional_count"_json_pointer, 1); - int pointLightCount = config.value("/lights/point_count"_json_pointer, 10); - int pointShadowCount = config.value("/lights/point_shadow_count"_json_pointer, 5); - int spotLightCount = config.value("/lights/spot_count"_json_pointer, 10); - int spotShadowCount = config.value("/lights/spot_shadow_count"_json_pointer, 5); - - std::vector treeIds = { - modelManager->LoadModelAsync(basePath + "Nature/Tree/CommonTree_3.fbx"), - modelManager->LoadModelAsync(basePath + "Nature/Tree-aVOxaHRPWe/CommonTree_2.fbx"), - modelManager->LoadModelAsync(basePath + "Nature/Tree-qZtx0AHhcy/CommonTree_1.fbx"), - modelManager->LoadModelAsync(basePath + "Nature/Tree-t9KbsfYdXz/CommonTree_5.fbx"), - modelManager->LoadModelAsync(basePath + "Nature/Tree-YWjGDJ9F7g/CommonTree_4.fbx") - }; - - // Cameras (Main & Debug) - { - sceneCam = scene.CreateEntity(); - registry.AddComponent(sceneCam); - registry.AddComponent(sceneCam); - registry.GetPool()->SetCategory(sceneCam, StorageCategory::Stream); - registry.GetPool()->SetCategory(sceneCam, StorageCategory::Stream); - - debugCam = scene.CreateEntity(); - registry.AddComponent(debugCam); - registry.AddComponent(debugCam); - registry.GetPool()->SetCategory(debugCam, StorageCategory::Stream); - registry.GetPool()->SetCategory(debugCam, StorageCategory::Stream); - } - - if (spawnFloor) - { - EntityID floorEntity = scene.CreateEntity(); - registry.AddComponent(floorEntity); - registry.AddComponent(floorEntity); - registry.AddComponent(floorEntity); - registry.AddComponent(floorEntity); - registry.AddComponent(floorEntity); - - auto& floorTransform = registry.GetComponent(floorEntity); - floorTransform.translation = glm::vec3(0.0f, -1.0f, 0.0f); - floorTransform.scale = glm::vec3(500.0f, 1.0f, 500.0f); - - auto& floorModel = registry.GetComponent(floorEntity); - floorModel.modelIndex = modelManager->GetResourceIndex(MeshSourceNames::Cube); - - auto& floorRb = registry.GetComponent(floorEntity); - floorRb.motionType = PhysicsMotionType::Static; - - registry.GetPool()->SetCategory(floorEntity, StorageCategory::Static); - registry.GetPool()->SetCategory(floorEntity, StorageCategory::Static); - registry.GetPool()->SetCategory(floorEntity, StorageCategory::Static); - registry.GetPool()->SetCategory(floorEntity, StorageCategory::Static); - - MaterialInfo floorMatInfo{}; - floorMatInfo.color = glm::vec4(0.2f, 0.8f, 0.2f, 1.0f); - uint32_t floorMatId = materialManager->LoadMaterial("FloorMat", floorMatInfo); - registry.GetComponent(floorEntity).materials.push_back(floorMatId); - } - - // Static Geometry - for (int i = 0; i < staticGeoCount; i++) { - EntityID e = scene.CreateEntity(); - registry.AddComponent(e); - registry.AddComponent(e); - registry.AddComponent(e); - - auto& transform = registry.GetComponent(e); - transform.translation = glm::vec3((rand() % 1000) - 500.0f, 0, (rand() % 1000) - 500.0f); - transform.rotation = glm::vec3(0, rand() % 360, 0); - transform.scale = glm::vec3(0.01f); - - registry.GetComponent(e).modelIndex = treeIds[rand() % treeIds.size()]; - - registry.GetPool()->SetCategory(e, StorageCategory::Static); - registry.GetPool()->SetCategory(e, StorageCategory::Static); - } - - // Lights: Directional - for (int i = 0; i < dirLightCount; ++i) { - EntityID e = scene.CreateEntity(); - registry.AddComponent(e); - registry.AddComponent(e); - - registry.GetComponent(e).rotation = glm::vec3(-45.0f, 45.0f, 0.0f); - auto& light = registry.GetComponent(e); - light.color = glm::vec3(1.0f, 0.95f, 0.85f) * 0.55f; - light.strength = 5.0f; - light.useShadow = true; - - registry.GetPool()->SetCategory(e, StorageCategory::Stream); - registry.GetPool()->SetCategory(e, StorageCategory::Stream); - registry.GetPool()->SetBit(e); - registry.GetPool()->SetBit(e); - } - - // Lights: Point - for (int i = 0; i < pointLightCount; i++) { - EntityID e = scene.CreateEntity(); - registry.AddComponent(e); - registry.AddComponent(e); - - auto& transform = registry.GetComponent(e); - transform.translation = glm::vec3((rand() % 1000) - 500.0f, (rand() % 10) + 5.0f, (rand() % 1000) - 500.0f); - - auto& light = registry.GetComponent(e); - light.position = transform.translation; - light.color = glm::vec3(static_cast(rand()) / RAND_MAX, static_cast(rand()) / RAND_MAX, static_cast(rand()) / RAND_MAX); - light.radius = 2.0f + (rand() % 10); - light.strength = 5.0f + (rand() % 25); - light.useShadow = (i < pointShadowCount); - - registry.GetPool()->SetCategory(e, StorageCategory::Stream); - registry.GetPool()->SetCategory(e, StorageCategory::Stream); - registry.GetPool()->SetBit(e); - registry.GetPool()->SetBit(e); - } - - // Lights: Spot - for (int i = 0; i < spotLightCount; i++) { - EntityID e = scene.CreateEntity(); - registry.AddComponent(e); - registry.AddComponent(e); - - auto& transform = registry.GetComponent(e); - transform.translation = glm::vec3((rand() % 1000) - 500.0f, (rand() % 10) + 5.0f, (rand() % 1000) - 500.0f); - transform.rotation = glm::vec3(-45.0f - (rand() % 45), (float)(rand() % 360), 0.0f); - - auto& light = registry.GetComponent(e); - light.position = transform.translation; - light.color = glm::vec3(static_cast(rand()) / RAND_MAX, static_cast(rand()) / RAND_MAX, static_cast(rand()) / RAND_MAX); - light.range = 30.0f + (rand() % 30); - light.innerAngle = 15.0f + (rand() % 10); - light.outerAngle = light.innerAngle + 10.0f + (rand() % 15); - light.strength = 5.0f + (rand() % 25); - light.useShadow = (i < spotShadowCount); - - registry.GetPool()->SetCategory(e, StorageCategory::Stream); - registry.GetPool()->SetCategory(e, StorageCategory::Stream); - registry.GetPool()->SetBit(e); - registry.GetPool()->SetBit(e); - } - - return true; - } -} \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Source/Procedural/TestSceneSource.cpp b/SynapseEngine/Engine/Scene/Source/Procedural/TestSceneSource.cpp index fbecd010..36737501 100644 --- a/SynapseEngine/Engine/Scene/Source/Procedural/TestSceneSource.cpp +++ b/SynapseEngine/Engine/Scene/Source/Procedural/TestSceneSource.cpp @@ -23,6 +23,7 @@ #include "Engine/Component/Physics/ConvexColliderComponent.h" #include "Engine/Component/Physics/MeshColliderComponent.h" #include "Engine/Component/Physics/RigidBodyComponent.h" +#include "Engine/Image/ImageManager.h" #include "Engine/Logger/SynLog.h" #include "Engine/Utils/PathUtils.h" @@ -65,7 +66,9 @@ namespace Syn Syn::Warning("scene_config.json not found, using default settings."); } - std::string basePath = config.value("/paths/base_model_path"_json_pointer, "C:/Users/User/Desktop/Models/"); + const std::string modelPath = "Assets/Engine/Models/"; + const std::string envPath = "Assets/Engine/Environment/"; + bool spawnSponza = config.value("/environment/spawn_sponza"_json_pointer, true); bool spawnBistro = config.value("/environment/spawn_bistro"_json_pointer, false); bool spawnFloor = config.value("/environment/spawn_floor"_json_pointer, true); @@ -101,13 +104,16 @@ namespace Syn modelManager->GetResourceIndex(MeshSourceNames::Torus) }; - // --- ROOT CONTAINERS --- + auto skyTextureId = ServiceLocator::GetImageManager()->LoadImageSync(PathUtils::GetAbsolutePathString(envPath + "MainScene.hdr")); + scene.GetSettings()->environment.skyTextureId = skyTextureId; + EntityID rootCameras = scene.CreateEntity(); registry.AddComponent(rootCameras); registry.GetComponent(rootCameras).name = "Cameras"; registry.GetComponent(rootCameras).tag = "Root"; registry.AddComponent(rootCameras); registry.GetPool()->SetCategory(rootCameras, StorageCategory::Static); + registry.GetPool()->SetCategory(rootCameras, StorageCategory::Static); EntityID rootEnvironment = scene.CreateEntity(); registry.AddComponent(rootEnvironment); @@ -115,6 +121,7 @@ namespace Syn registry.GetComponent(rootEnvironment).tag = "Root"; registry.AddComponent(rootEnvironment); registry.GetPool()->SetCategory(rootEnvironment, StorageCategory::Static); + registry.GetPool()->SetCategory(rootEnvironment, StorageCategory::Static); EntityID rootCharacters = scene.CreateEntity(); registry.AddComponent(rootCharacters); @@ -122,6 +129,7 @@ namespace Syn registry.GetComponent(rootCharacters).tag = "Root"; registry.AddComponent(rootCharacters); registry.GetPool()->SetCategory(rootCharacters, StorageCategory::Static); + registry.GetPool()->SetCategory(rootCharacters, StorageCategory::Static); EntityID rootStaticGeo = scene.CreateEntity(); registry.AddComponent(rootStaticGeo); @@ -129,6 +137,7 @@ namespace Syn registry.GetComponent(rootStaticGeo).tag = "Root"; registry.AddComponent(rootStaticGeo); registry.GetPool()->SetCategory(rootStaticGeo, StorageCategory::Static); + registry.GetPool()->SetCategory(rootStaticGeo, StorageCategory::Static); EntityID rootPhysics = scene.CreateEntity(); registry.AddComponent(rootPhysics); @@ -136,6 +145,7 @@ namespace Syn registry.GetComponent(rootPhysics).tag = "Root"; registry.AddComponent(rootPhysics); registry.GetPool()->SetCategory(rootPhysics, StorageCategory::Static); + registry.GetPool()->SetCategory(rootPhysics, StorageCategory::Static); EntityID rootLights = scene.CreateEntity(); registry.AddComponent(rootLights); @@ -143,6 +153,7 @@ namespace Syn registry.GetComponent(rootLights).tag = "Root"; registry.AddComponent(rootLights); registry.GetPool()->SetCategory(rootLights, StorageCategory::Static); + registry.GetPool()->SetCategory(rootLights, StorageCategory::Static); // Cameras (Main & Debug) { @@ -154,6 +165,7 @@ namespace Syn registry.AddComponent(sceneCam); registry.GetPool()->SetCategory(sceneCam, StorageCategory::Stream); registry.GetPool()->SetCategory(sceneCam, StorageCategory::Stream); + registry.GetPool()->SetCategory(sceneCam, StorageCategory::Static); hm->AttachChild(rootCameras, sceneCam); debugCam = scene.CreateEntity(); @@ -164,15 +176,17 @@ namespace Syn registry.AddComponent(debugCam); registry.GetPool()->SetCategory(debugCam, StorageCategory::Stream); registry.GetPool()->SetCategory(debugCam, StorageCategory::Stream); + registry.GetPool()->SetCategory(debugCam, StorageCategory::Static); hm->AttachChild(rootCameras, debugCam); } if (spawnMonkey) { - uint32_t monkeyModelIndex = modelManager->LoadModelAsync(basePath + "Monkey/monkey.obj"); + uint32_t monkeyModelIndex = modelManager->LoadModelAsync(PathUtils::GetAbsolutePathString(modelPath + "Monkey/Untitled.obj")); EntityID monkeyId = scene.CreateEntity(); registry.AddComponent(monkeyId); + registry.AddComponent(monkeyId); registry.GetComponent(monkeyId).name = "Suzanne_Monkey"; registry.GetComponent(monkeyId).tag = "Model"; registry.AddComponent(monkeyId); @@ -184,16 +198,19 @@ namespace Syn registry.GetPool()->SetCategory(monkeyId, StorageCategory::Static); registry.GetPool()->SetCategory(monkeyId, StorageCategory::Static); + registry.GetPool()->SetCategory(monkeyId, StorageCategory::Static); + registry.GetPool()->SetCategory(monkeyId, StorageCategory::Static); hm->AttachChild(rootEnvironment, monkeyId); } if (spawnSponza) { - uint32_t sponzaId = modelManager->LoadModelAsync(basePath + "Sponza/sponza.obj"); + uint32_t sponzaId = modelManager->LoadModelAsync(PathUtils::GetAbsolutePathString(modelPath + "Sponza/sponza.obj")); EntityID sponzaEntity = scene.CreateEntity(); registry.AddComponent(sponzaEntity); + registry.AddComponent(sponzaEntity); registry.GetComponent(sponzaEntity).name = "Classic_Sponza"; registry.GetComponent(sponzaEntity).tag = "Model"; registry.AddComponent(sponzaEntity); @@ -210,31 +227,12 @@ namespace Syn registry.GetPool()->SetCategory(sponzaEntity, StorageCategory::Static); registry.GetPool()->SetCategory(sponzaEntity, StorageCategory::Stream); registry.GetPool()->SetCategory(sponzaEntity, StorageCategory::Stream); + registry.GetPool()->SetCategory(sponzaEntity, StorageCategory::Static); + registry.GetPool()->SetCategory(sponzaEntity, StorageCategory::Static); hm->AttachChild(rootEnvironment, sponzaEntity); } - if (spawnBistro) - { - uint32_t bistroId = modelManager->LoadModelAsync(basePath + "Bistro/BistroExterior.fbx"); - - EntityID bistroEntity = scene.CreateEntity(); - registry.AddComponent(bistroEntity); - registry.GetComponent(bistroEntity).name = "Amazon_Bistro"; - registry.GetComponent(bistroEntity).tag = "Model"; - registry.AddComponent(bistroEntity); - registry.AddComponent(bistroEntity); - - registry.GetComponent(bistroEntity).translation = glm::vec3(0.0f, 0.0f, 0.0f); - registry.GetComponent(bistroEntity).scale = glm::vec3(0.2f, 0.2f, 0.2f); - registry.GetComponent(bistroEntity).modelIndex = bistroId; - - registry.GetPool()->SetCategory(bistroEntity, StorageCategory::Static); - registry.GetPool()->SetCategory(bistroEntity, StorageCategory::Static); - - hm->AttachChild(rootEnvironment, bistroEntity); - } - if (spawnFloor) { EntityID floorEntity = scene.CreateEntity(); @@ -261,6 +259,8 @@ namespace Syn registry.GetPool()->SetCategory(floorEntity, StorageCategory::Static); registry.GetPool()->SetCategory(floorEntity, StorageCategory::Static); registry.GetPool()->SetCategory(floorEntity, StorageCategory::Static); + registry.GetPool()->SetCategory(floorEntity, StorageCategory::Static); + registry.GetPool()->SetCategory(floorEntity, StorageCategory::Static); MaterialInfo floorMatInfo{}; floorMatInfo.color = glm::vec4(0.2f, 0.2f, 0.2f, 1.0f); @@ -270,46 +270,16 @@ namespace Syn hm->AttachChild(rootEnvironment, floorEntity); } - if (spawnPbrSponza) - { - uint32_t sponzaPbr = modelManager->LoadModelAsync(basePath + "Sponza_Pbr/NewSponza_Main_Yup_003.fbx"); - uint32_t sponzaPbrCurtains = modelManager->LoadModelAsync(basePath + "Sponza_Pbr_Curtains/NewSponza_Curtains_FBX_YUp.fbx"); - uint32_t sponzaPbrFlowers = modelManager->LoadModelAsync(basePath + "Sponza_Pbr_Flowers/NewSponza_IvyGrowth_FBX_YUp.fbx"); - uint32_t sponzaPbrTree = modelManager->LoadModelAsync(basePath + "Sponza_Pbr_Tree/NewSponza_CypressTree_FBX_YUp.fbx"); - - std::array sponzaModels = { sponzaPbr, sponzaPbrCurtains, sponzaPbrFlowers, sponzaPbrTree }; - std::array sponzaNames = { "PBR_Sponza_Main", "PBR_Sponza_Curtains", "PBR_Sponza_Flowers", "PBR_Sponza_Tree" }; - - for (size_t i = 0; i < sponzaModels.size(); i++) - { - EntityID entity = scene.CreateEntity(); - registry.AddComponent(entity); - registry.GetComponent(entity).name = sponzaNames[i]; - registry.GetComponent(entity).tag = "Model"; - registry.AddComponent(entity); - registry.AddComponent(entity); - - registry.GetComponent(entity).translation = glm::vec3(0.0f, 0.0f, 0.0f); - registry.GetComponent(entity).scale = glm::vec3(0.2f, 0.2f, 0.2f); - registry.GetComponent(entity).modelIndex = sponzaModels[i]; - - registry.GetPool()->SetCategory(entity, StorageCategory::Static); - registry.GetPool()->SetCategory(entity, StorageCategory::Static); - - hm->AttachChild(rootEnvironment, entity); - } - } - if (charCount > 0) { - uint32_t mutantId = modelManager->LoadModelAsync(basePath + "Monster/Mutant/Mutant.dae"); + uint32_t mutantId = modelManager->LoadModelAsync(PathUtils::GetAbsolutePathString(modelPath + "Monster/Mutant/Mutant.dae")); std::vector animationIds; - animationIds.push_back(animationManager->LoadAnimationAsync(basePath + "Monster/Breakdance 1990/Breakdance 1990.dae", mutantId)); - animationIds.push_back(animationManager->LoadAnimationAsync(basePath + "Monster/Breakdance Ending 1/Breakdance Ending 1.dae", mutantId)); - animationIds.push_back(animationManager->LoadAnimationAsync(basePath + "Monster/Dancing/Dancing.dae", mutantId)); - animationIds.push_back(animationManager->LoadAnimationAsync(basePath + "Monster/Hip Hop Dancing/Hip Hop Dancing.dae", mutantId)); - animationIds.push_back(animationManager->LoadAnimationAsync(basePath + "Monster/Hip Hop Dancing_2/Hip Hop Dancing.dae", mutantId)); + animationIds.push_back(animationManager->LoadAnimationAsync(PathUtils::GetAbsolutePathString(modelPath + "Monster/Breakdance 1990/Breakdance 1990.dae"), mutantId)); + animationIds.push_back(animationManager->LoadAnimationAsync(PathUtils::GetAbsolutePathString(modelPath + "Monster/Breakdance Ending 1/Breakdance Ending 1.dae"), mutantId)); + animationIds.push_back(animationManager->LoadAnimationAsync(PathUtils::GetAbsolutePathString(modelPath + "Monster/Dancing/Dancing.dae"), mutantId)); + animationIds.push_back(animationManager->LoadAnimationAsync(PathUtils::GetAbsolutePathString(modelPath + "Monster/Hip Hop Dancing/Hip Hop Dancing.dae"), mutantId)); + animationIds.push_back(animationManager->LoadAnimationAsync(PathUtils::GetAbsolutePathString(modelPath + "Monster/Hip Hop Dancing_2/Hip Hop Dancing.dae"), mutantId)); // Animated Characters for (int i = 0; i < charCount; i++) @@ -321,6 +291,7 @@ namespace Syn registry.AddComponent(characterEntity); registry.AddComponent(characterEntity); registry.AddComponent(characterEntity); + registry.AddComponent(characterEntity); registry.GetComponent(characterEntity).translation = glm::vec3((rand() % 400) - 200.0f, 0.0f, (rand() % 400) - 200.0f); registry.GetComponent(characterEntity).scale = glm::vec3(5.f); @@ -330,6 +301,8 @@ namespace Syn animComp.animationIndex = animationIds[rand() % animationIds.size()]; animComp.speed = 0.5f + (static_cast(rand()) / static_cast(RAND_MAX)) * 1.5f; + registry.GetPool()->SetCategory(characterEntity, StorageCategory::Static); + registry.GetPool()->SetCategory(characterEntity, StorageCategory::Static); registry.GetPool()->SetCategory(characterEntity, StorageCategory::Static); registry.GetPool()->SetCategory(characterEntity, StorageCategory::Static); registry.GetPool()->SetCategory(characterEntity, StorageCategory::Stream); @@ -392,6 +365,8 @@ namespace Syn registry.GetComponent(e).modelIndex = geoIds[rand() % geoIds.size()]; + registry.GetPool()->SetCategory(e, StorageCategory::Static); + registry.GetPool()->SetCategory(e, StorageCategory::Static); registry.GetPool()->SetCategory(e, StorageCategory::Static); registry.GetPool()->SetCategory(e, StorageCategory::Static); @@ -418,6 +393,8 @@ namespace Syn registry.GetComponent(e).modelIndex = cubeMeshId; registry.GetComponent(e).motionType = PhysicsMotionType::Dynamic; + registry.GetPool()->SetCategory(e, StorageCategory::Static); + registry.GetPool()->SetCategory(e, StorageCategory::Static); registry.GetPool()->SetCategory(e, StorageCategory::Stream); registry.GetPool()->SetCategory(e, StorageCategory::Static); registry.GetPool()->SetCategory(e, StorageCategory::Static); @@ -442,6 +419,8 @@ namespace Syn registry.GetComponent(e).modelIndex = sphereMeshId; registry.GetComponent(e).motionType = PhysicsMotionType::Dynamic; + registry.GetPool()->SetCategory(e, StorageCategory::Static); + registry.GetPool()->SetCategory(e, StorageCategory::Static); registry.GetPool()->SetCategory(e, StorageCategory::Stream); registry.GetPool()->SetCategory(e, StorageCategory::Static); registry.GetPool()->SetCategory(e, StorageCategory::Static); @@ -468,6 +447,8 @@ namespace Syn registry.GetComponent(e).modelIndex = capsuleMeshId; registry.GetComponent(e).motionType = PhysicsMotionType::Dynamic; + registry.GetPool()->SetCategory(e, StorageCategory::Static); + registry.GetPool()->SetCategory(e, StorageCategory::Static); registry.GetPool()->SetCategory(e, StorageCategory::Stream); registry.GetPool()->SetCategory(e, StorageCategory::Static); registry.GetPool()->SetCategory(e, StorageCategory::Static); @@ -494,6 +475,7 @@ namespace Syn registry.GetPool()->SetCategory(e, StorageCategory::Stream); registry.GetPool()->SetCategory(e, StorageCategory::Stream); + registry.GetPool()->SetCategory(e, StorageCategory::Static); registry.GetPool()->SetBit(e); registry.GetPool()->SetBit(e); @@ -520,6 +502,7 @@ namespace Syn registry.GetPool()->SetCategory(e, StorageCategory::Stream); registry.GetPool()->SetCategory(e, StorageCategory::Stream); + registry.GetPool()->SetCategory(e, StorageCategory::Static); registry.GetPool()->SetBit(e); registry.GetPool()->SetBit(e); @@ -549,6 +532,7 @@ namespace Syn registry.GetPool()->SetCategory(e, StorageCategory::Stream); registry.GetPool()->SetCategory(e, StorageCategory::Stream); + registry.GetPool()->SetCategory(e, StorageCategory::Static); registry.GetPool()->SetBit(e); registry.GetPool()->SetBit(e); diff --git a/SynapseEngine/Engine/Scene/Source/Procedural/nature_config.json b/SynapseEngine/Engine/Scene/Source/Procedural/nature_config.json deleted file mode 100644 index 8c2138cf..00000000 --- a/SynapseEngine/Engine/Scene/Source/Procedural/nature_config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "paths": { - "base_model_path": "C:/Users/User/Desktop/Models/" - }, - "environment": { - "spawn_floor": true - }, - "entities": { - "static_geometry": 100000, - }, - "lights": { - "directional_count": 1, - "point_count": 256, - "point_shadow_count": 0, - "spot_count": 256, - "spot_shadow_count": 0 - } -} \ No newline at end of file diff --git a/SynapseEngine/Engine/Scene/Source/Procedural/test_config.json b/SynapseEngine/Engine/Scene/Source/Procedural/test_config.json index 9bafd2d3..945625f3 100644 --- a/SynapseEngine/Engine/Scene/Source/Procedural/test_config.json +++ b/SynapseEngine/Engine/Scene/Source/Procedural/test_config.json @@ -1,30 +1,25 @@ { - "paths": { - "base_model_path": "C:/Users/User/Desktop/Models/" - }, "environment": { "spawn_sponza": true, - "spawn_bistro": false, "spawn_floor": false, - "spawn_pbr_sponza": false, - "spawn_monkey": false + "spawn_monkey": true }, "materials": { "use_unique_materials": false, "shared_material_count": 100 }, "entities": { - "animated_characters": 1000, - "static_geometry": 25000, + "animated_characters": 500, + "static_geometry": 50000, "physics_boxes": 500, "physics_spheres": 500, "physics_capsules": 500 }, "lights": { "directional_count": 1, - "point_count": 128, + "point_count": 64, "point_shadow_count": 32, - "spot_count": 128, + "spot_count": 64, "spot_shadow_count": 32 } } \ No newline at end of file diff --git a/SynapseEngine/Engine/Serialization/Archive/Input/Binary/BinaryInputArchive.cpp b/SynapseEngine/Engine/Serialization/Archive/Input/Binary/BinaryInputArchive.cpp index 15dcbbd4..8f27764a 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Input/Binary/BinaryInputArchive.cpp +++ b/SynapseEngine/Engine/Serialization/Archive/Input/Binary/BinaryInputArchive.cpp @@ -17,6 +17,10 @@ namespace Syn _stream.ReadRaw(&value, sizeof(uint8_t)); } + void BinaryInputArchive::PropertyUint16(const char*, uint16_t& value) { + _stream.ReadRaw(&value, sizeof(uint16_t)); + } + void BinaryInputArchive::PropertyInt32(const char*, int32_t& value) { _stream.ReadRaw(&value, sizeof(int32_t)); } diff --git a/SynapseEngine/Engine/Serialization/Archive/Input/Binary/BinaryInputArchive.h b/SynapseEngine/Engine/Serialization/Archive/Input/Binary/BinaryInputArchive.h index cbb6a5fc..4c139132 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Input/Binary/BinaryInputArchive.h +++ b/SynapseEngine/Engine/Serialization/Archive/Input/Binary/BinaryInputArchive.h @@ -25,6 +25,7 @@ namespace Syn void PropertyBool(const char* name, bool& value) override; void PropertyUint8(const char* name, uint8_t& value) override; + void PropertyUint16(const char* name, uint16_t& value) override; void PropertyInt32(const char* name, int32_t& value) override; void PropertyUint32(const char* name, uint32_t& value) override; void PropertyInt64(const char* name, int64_t& value) override; diff --git a/SynapseEngine/Engine/Serialization/Archive/Input/IInputArchive.h b/SynapseEngine/Engine/Serialization/Archive/Input/IInputArchive.h index 5aa94d65..32bd07bc 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Input/IInputArchive.h +++ b/SynapseEngine/Engine/Serialization/Archive/Input/IInputArchive.h @@ -26,6 +26,7 @@ namespace Syn virtual void PropertyBool(const char* name, bool& value) = 0; virtual void PropertyUint8(const char* name, uint8_t& value) = 0; + virtual void PropertyUint16(const char* name, uint16_t& value) = 0; virtual void PropertyInt32(const char* name, int32_t& value) = 0; virtual void PropertyUint32(const char* name, uint32_t& value) = 0; virtual void PropertyInt64(const char* name, int64_t& value) = 0; @@ -46,6 +47,7 @@ namespace Syn { if constexpr (std::is_same_v) PropertyBool(name, value); else if constexpr (std::is_same_v) PropertyUint8(name, value); + else if constexpr (std::is_same_v) PropertyUint16(name, value); else if constexpr (std::is_same_v) PropertyInt32(name, value); else if constexpr (std::is_same_v) PropertyUint32(name, value); else if constexpr (std::is_same_v) PropertyInt64(name, value); diff --git a/SynapseEngine/Engine/Serialization/Archive/Input/Json/NlohmannJsonInputArchive.cpp b/SynapseEngine/Engine/Serialization/Archive/Input/Json/NlohmannJsonInputArchive.cpp index cec2cc06..006d750a 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Input/Json/NlohmannJsonInputArchive.cpp +++ b/SynapseEngine/Engine/Serialization/Archive/Input/Json/NlohmannJsonInputArchive.cpp @@ -79,6 +79,10 @@ namespace Syn ReadValue(name, value); } + void NlohmannJsonInputArchive::PropertyUint16(const char* name, uint16_t& value) { + ReadValue(name, value); + } + void NlohmannJsonInputArchive::PropertyInt32(const char* name, int32_t& value) { ReadValue(name, value); } diff --git a/SynapseEngine/Engine/Serialization/Archive/Input/Json/NlohmannJsonInputArchive.h b/SynapseEngine/Engine/Serialization/Archive/Input/Json/NlohmannJsonInputArchive.h index 9e909337..1b57304e 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Input/Json/NlohmannJsonInputArchive.h +++ b/SynapseEngine/Engine/Serialization/Archive/Input/Json/NlohmannJsonInputArchive.h @@ -25,6 +25,7 @@ namespace Syn void PropertyBool(const char* name, bool& value) override; void PropertyUint8(const char* name, uint8_t& value) override; + void PropertyUint16(const char* name, uint16_t& value) override; void PropertyInt32(const char* name, int32_t& value) override; void PropertyUint32(const char* name, uint32_t& value) override; void PropertyInt64(const char* name, int64_t& value) override; diff --git a/SynapseEngine/Engine/Serialization/Archive/Input/Toml/PlusPlusTomlInputArchive.cpp b/SynapseEngine/Engine/Serialization/Archive/Input/Toml/PlusPlusTomlInputArchive.cpp index 1195588f..a513151d 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Input/Toml/PlusPlusTomlInputArchive.cpp +++ b/SynapseEngine/Engine/Serialization/Archive/Input/Toml/PlusPlusTomlInputArchive.cpp @@ -77,6 +77,10 @@ namespace Syn value = static_cast(GetNextNode(name)->as_integer()->get()); } + void PlusPlusTomlInputArchive::PropertyUint16(const char* name, uint16_t& value) { + value = static_cast(GetNextNode(name)->as_integer()->get()); + } + void PlusPlusTomlInputArchive::PropertyInt32(const char* name, int32_t& value) { value = static_cast(GetNextNode(name)->as_integer()->get()); } diff --git a/SynapseEngine/Engine/Serialization/Archive/Input/Toml/PlusPlusTomlInputArchive.h b/SynapseEngine/Engine/Serialization/Archive/Input/Toml/PlusPlusTomlInputArchive.h index ce29f008..7c377262 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Input/Toml/PlusPlusTomlInputArchive.h +++ b/SynapseEngine/Engine/Serialization/Archive/Input/Toml/PlusPlusTomlInputArchive.h @@ -25,6 +25,7 @@ namespace Syn void PropertyBool(const char* name, bool& value) override; void PropertyUint8(const char* name, uint8_t& value) override; + void PropertyUint16(const char* name, uint16_t& value) override; void PropertyInt32(const char* name, int32_t& value) override; void PropertyUint32(const char* name, uint32_t& value) override; void PropertyInt64(const char* name, int64_t& value) override; diff --git a/SynapseEngine/Engine/Serialization/Archive/Input/Xml/TinyXmlInputArchive.cpp b/SynapseEngine/Engine/Serialization/Archive/Input/Xml/TinyXmlInputArchive.cpp index b36ca28d..51568afd 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Input/Xml/TinyXmlInputArchive.cpp +++ b/SynapseEngine/Engine/Serialization/Archive/Input/Xml/TinyXmlInputArchive.cpp @@ -88,6 +88,10 @@ namespace Syn value = static_cast(GetNextElement(name)->UnsignedText()); } + void TinyXmlInputArchive::PropertyUint16(const char* name, uint16_t& value) { + value = static_cast(GetNextElement(name)->UnsignedText()); + } + void TinyXmlInputArchive::PropertyInt32(const char* name, int32_t& value) { value = GetNextElement(name)->IntText(); } diff --git a/SynapseEngine/Engine/Serialization/Archive/Input/Xml/TinyXmlInputArchive.h b/SynapseEngine/Engine/Serialization/Archive/Input/Xml/TinyXmlInputArchive.h index 1c1484ff..f7478dfa 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Input/Xml/TinyXmlInputArchive.h +++ b/SynapseEngine/Engine/Serialization/Archive/Input/Xml/TinyXmlInputArchive.h @@ -25,6 +25,7 @@ namespace Syn void PropertyBool(const char* name, bool& value) override; void PropertyUint8(const char* name, uint8_t& value) override; + void PropertyUint16(const char* name, uint16_t& value) override; void PropertyInt32(const char* name, int32_t& value) override; void PropertyUint32(const char* name, uint32_t& value) override; void PropertyInt64(const char* name, int64_t& value) override; diff --git a/SynapseEngine/Engine/Serialization/Archive/Input/Yaml/YamlCppInputArchive.cpp b/SynapseEngine/Engine/Serialization/Archive/Input/Yaml/YamlCppInputArchive.cpp index ec02e79e..f72a3514 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Input/Yaml/YamlCppInputArchive.cpp +++ b/SynapseEngine/Engine/Serialization/Archive/Input/Yaml/YamlCppInputArchive.cpp @@ -78,6 +78,13 @@ namespace Syn value = static_cast(temp); } + void YamlCppInputArchive::PropertyUint16(const char* name, uint16_t& value) + { + uint32_t temp = 0; + ReadValue(name, temp); + value = static_cast(temp); + } + void YamlCppInputArchive::PropertyInt32(const char* name, int32_t& value) { ReadValue(name, value); } diff --git a/SynapseEngine/Engine/Serialization/Archive/Input/Yaml/YamlCppInputArchive.h b/SynapseEngine/Engine/Serialization/Archive/Input/Yaml/YamlCppInputArchive.h index 681f71ac..75ca78e5 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Input/Yaml/YamlCppInputArchive.h +++ b/SynapseEngine/Engine/Serialization/Archive/Input/Yaml/YamlCppInputArchive.h @@ -25,6 +25,7 @@ namespace Syn void PropertyBool(const char* name, bool& value) override; void PropertyUint8(const char* name, uint8_t& value) override; + void PropertyUint16(const char* name, uint16_t& value) override; void PropertyInt32(const char* name, int32_t& value) override; void PropertyUint32(const char* name, uint32_t& value) override; void PropertyInt64(const char* name, int64_t& value) override; diff --git a/SynapseEngine/Engine/Serialization/Archive/Output/Binary/BinaryOutputArchive.cpp b/SynapseEngine/Engine/Serialization/Archive/Output/Binary/BinaryOutputArchive.cpp index 9b952891..4efcc866 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Output/Binary/BinaryOutputArchive.cpp +++ b/SynapseEngine/Engine/Serialization/Archive/Output/Binary/BinaryOutputArchive.cpp @@ -23,6 +23,11 @@ namespace Syn _stream.WriteRaw(&value, sizeof(uint8_t)); } + void BinaryOutputArchive::PropertyUint16(const char*, uint16_t value) + { + _stream.WriteRaw(&value, sizeof(uint16_t)); + } + void BinaryOutputArchive::PropertyInt32(const char*, int32_t value) { _stream.WriteRaw(&value, sizeof(int32_t)); diff --git a/SynapseEngine/Engine/Serialization/Archive/Output/Binary/BinaryOutputArchive.h b/SynapseEngine/Engine/Serialization/Archive/Output/Binary/BinaryOutputArchive.h index 56a22b3c..74024d2b 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Output/Binary/BinaryOutputArchive.h +++ b/SynapseEngine/Engine/Serialization/Archive/Output/Binary/BinaryOutputArchive.h @@ -23,6 +23,7 @@ namespace Syn void PropertyBool(const char* name, bool value) override; void PropertyUint8(const char* name, uint8_t value) override; + void PropertyUint16(const char* name, uint16_t value) override; void PropertyInt32(const char* name, int32_t value) override; void PropertyUint32(const char* name, uint32_t value) override; void PropertyInt64(const char* name, int64_t value) override; diff --git a/SynapseEngine/Engine/Serialization/Archive/Output/IOutputArchive.h b/SynapseEngine/Engine/Serialization/Archive/Output/IOutputArchive.h index f99a6f70..25501ee1 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Output/IOutputArchive.h +++ b/SynapseEngine/Engine/Serialization/Archive/Output/IOutputArchive.h @@ -24,6 +24,7 @@ namespace Syn virtual void PropertyBool(const char* name, bool value) = 0; virtual void PropertyUint8(const char* name, uint8_t value) = 0; + virtual void PropertyUint16(const char* name, uint16_t value) = 0; virtual void PropertyInt32(const char* name, int32_t value) = 0; virtual void PropertyUint32(const char* name, uint32_t value) = 0; virtual void PropertyInt64(const char* name, int64_t value) = 0; @@ -43,6 +44,7 @@ namespace Syn void IOutputArchive::Property(const char* name, const T& value) { if constexpr (std::is_same_v) PropertyBool(name, value); else if constexpr (std::is_same_v) PropertyUint8(name, value); + else if constexpr (std::is_same_v) PropertyUint16(name, value); else if constexpr (std::is_same_v) PropertyInt32(name, value); else if constexpr (std::is_same_v) PropertyUint32(name, value); else if constexpr (std::is_same_v) PropertyInt64(name, value); diff --git a/SynapseEngine/Engine/Serialization/Archive/Output/Json/NlohmannJsonOutputArchive.cpp b/SynapseEngine/Engine/Serialization/Archive/Output/Json/NlohmannJsonOutputArchive.cpp index 758a8aca..e480d6b9 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Output/Json/NlohmannJsonOutputArchive.cpp +++ b/SynapseEngine/Engine/Serialization/Archive/Output/Json/NlohmannJsonOutputArchive.cpp @@ -67,6 +67,12 @@ namespace Syn else parent[name] = value; } + void NlohmannJsonOutputArchive::PropertyUint16(const char* name, uint16_t value) { + auto& parent = *_stack.back(); + if (parent.is_array()) parent.push_back(value); + else parent[name] = value; + } + void NlohmannJsonOutputArchive::PropertyInt32(const char* name, int32_t value) { auto& parent = *_stack.back(); if (parent.is_array()) parent.push_back(value); diff --git a/SynapseEngine/Engine/Serialization/Archive/Output/Json/NlohmannJsonOutputArchive.h b/SynapseEngine/Engine/Serialization/Archive/Output/Json/NlohmannJsonOutputArchive.h index fb3b0530..72e4eb99 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Output/Json/NlohmannJsonOutputArchive.h +++ b/SynapseEngine/Engine/Serialization/Archive/Output/Json/NlohmannJsonOutputArchive.h @@ -25,6 +25,7 @@ namespace Syn void PropertyBool(const char* name, bool value) override; void PropertyUint8(const char* name, uint8_t value) override; + void PropertyUint16(const char* name, uint16_t value) override; void PropertyInt32(const char* name, int32_t value) override; void PropertyUint32(const char* name, uint32_t value) override; void PropertyInt64(const char* name, int64_t value) override; diff --git a/SynapseEngine/Engine/Serialization/Archive/Output/Toml/PlusPlusTomlOutputArchive.cpp b/SynapseEngine/Engine/Serialization/Archive/Output/Toml/PlusPlusTomlOutputArchive.cpp index 07cfc89e..37b5d5cc 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Output/Toml/PlusPlusTomlOutputArchive.cpp +++ b/SynapseEngine/Engine/Serialization/Archive/Output/Toml/PlusPlusTomlOutputArchive.cpp @@ -73,6 +73,10 @@ namespace Syn WriteValue(name, static_cast(value)); } + void PlusPlusTomlOutputArchive::PropertyUint16(const char* name, uint16_t value) { + WriteValue(name, static_cast(value)); + } + void PlusPlusTomlOutputArchive::PropertyInt32(const char* name, int32_t value) { WriteValue(name, value); } diff --git a/SynapseEngine/Engine/Serialization/Archive/Output/Toml/PlusPlusTomlOutputArchive.h b/SynapseEngine/Engine/Serialization/Archive/Output/Toml/PlusPlusTomlOutputArchive.h index 469dac5a..8473de5e 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Output/Toml/PlusPlusTomlOutputArchive.h +++ b/SynapseEngine/Engine/Serialization/Archive/Output/Toml/PlusPlusTomlOutputArchive.h @@ -25,6 +25,7 @@ namespace Syn void PropertyBool(const char* name, bool value) override; void PropertyUint8(const char* name, uint8_t value) override; + void PropertyUint16(const char* name, uint16_t value) override; void PropertyInt32(const char* name, int32_t value) override; void PropertyUint32(const char* name, uint32_t value) override; void PropertyInt64(const char* name, int64_t value) override; diff --git a/SynapseEngine/Engine/Serialization/Archive/Output/Xml/TinyXmlOutputArchive.cpp b/SynapseEngine/Engine/Serialization/Archive/Output/Xml/TinyXmlOutputArchive.cpp index 599bbdc4..9908d4a0 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Output/Xml/TinyXmlOutputArchive.cpp +++ b/SynapseEngine/Engine/Serialization/Archive/Output/Xml/TinyXmlOutputArchive.cpp @@ -72,6 +72,10 @@ namespace Syn WriteValue(name, static_cast(value)); } + void TinyXmlOutputArchive::PropertyUint16(const char* name, uint16_t value) { + WriteValue(name, static_cast(value)); + } + void TinyXmlOutputArchive::PropertyInt32(const char* name, int32_t value) { WriteValue(name, value); } diff --git a/SynapseEngine/Engine/Serialization/Archive/Output/Xml/TinyXmlOutputArchive.h b/SynapseEngine/Engine/Serialization/Archive/Output/Xml/TinyXmlOutputArchive.h index 45ab0ed3..750f7c3f 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Output/Xml/TinyXmlOutputArchive.h +++ b/SynapseEngine/Engine/Serialization/Archive/Output/Xml/TinyXmlOutputArchive.h @@ -25,6 +25,7 @@ namespace Syn void PropertyBool(const char* name, bool value) override; void PropertyUint8(const char* name, uint8_t value) override; + void PropertyUint16(const char* name, uint16_t value) override; void PropertyInt32(const char* name, int32_t value) override; void PropertyUint32(const char* name, uint32_t value) override; void PropertyInt64(const char* name, int64_t value) override; diff --git a/SynapseEngine/Engine/Serialization/Archive/Output/Yaml/YamlCppOutputArchive.cpp b/SynapseEngine/Engine/Serialization/Archive/Output/Yaml/YamlCppOutputArchive.cpp index c33762c0..081353dc 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Output/Yaml/YamlCppOutputArchive.cpp +++ b/SynapseEngine/Engine/Serialization/Archive/Output/Yaml/YamlCppOutputArchive.cpp @@ -69,6 +69,10 @@ namespace Syn WriteValue(name, static_cast(value)); } + void YamlCppOutputArchive::PropertyUint16(const char* name, uint16_t value) { + WriteValue(name, static_cast(value)); + } + void YamlCppOutputArchive::PropertyInt32(const char* name, int32_t value) { WriteValue(name, value); } diff --git a/SynapseEngine/Engine/Serialization/Archive/Output/Yaml/YamlCppOutputArchive.h b/SynapseEngine/Engine/Serialization/Archive/Output/Yaml/YamlCppOutputArchive.h index 475aad7d..a323dd82 100644 --- a/SynapseEngine/Engine/Serialization/Archive/Output/Yaml/YamlCppOutputArchive.h +++ b/SynapseEngine/Engine/Serialization/Archive/Output/Yaml/YamlCppOutputArchive.h @@ -25,6 +25,7 @@ namespace Syn void PropertyBool(const char* name, bool value) override; void PropertyUint8(const char* name, uint8_t value) override; + void PropertyUint16(const char* name, uint16_t value) override; void PropertyInt32(const char* name, int32_t value) override; void PropertyUint32(const char* name, uint32_t value) override; void PropertyInt64(const char* name, int64_t value) override; diff --git a/SynapseEngine/Engine/Serialization/Schema/Component/Rendering/ModelComponentSchema.h b/SynapseEngine/Engine/Serialization/Schema/Component/Rendering/ModelComponentSchema.h index ac63a7d1..8035a434 100644 --- a/SynapseEngine/Engine/Serialization/Schema/Component/Rendering/ModelComponentSchema.h +++ b/SynapseEngine/Engine/Serialization/Schema/Component/Rendering/ModelComponentSchema.h @@ -17,7 +17,6 @@ namespace Syn ar.Property("castShadow", comp.castShadow); ar.Property("receiveShadow", comp.receiveShadow); - ar.Property("hasDirectxNormals", comp.hasDirectxNormals); ar.Property("modelIndex", comp.modelIndex); ar.Property("materialOffset", comp.materialOffset); } diff --git a/SynapseEngine/Engine/Serialization/Schema/Material/MaterialSchema.h b/SynapseEngine/Engine/Serialization/Schema/Material/MaterialSchema.h index 77a06a13..a917f54b 100644 --- a/SynapseEngine/Engine/Serialization/Schema/Material/MaterialSchema.h +++ b/SynapseEngine/Engine/Serialization/Schema/Material/MaterialSchema.h @@ -32,6 +32,14 @@ namespace Syn ar.Property("metallicRoughnessTexture", mat.metallicRoughnessTexture); ar.Property("emissiveTexture", mat.emissiveTexture); ar.Property("ambientOcclusionTexture", mat.ambientOcclusionTexture); + + ar.Property("albedoSampler", mat.albedoSampler); + ar.Property("normalSampler", mat.normalSampler); + ar.Property("metalnessSampler", mat.metalnessSampler); + ar.Property("roughnessSampler", mat.roughnessSampler); + ar.Property("metallicRoughnessSampler", mat.metallicRoughnessSampler); + ar.Property("emissiveSampler", mat.emissiveSampler); + ar.Property("ambientOcclusionSampler", mat.ambientOcclusionSampler); } }; } \ No newline at end of file diff --git a/SynapseEngine/Engine/Serialization/Schema/Models/CpuModelDataSchema.h b/SynapseEngine/Engine/Serialization/Schema/Models/CpuModelDataSchema.h index b6f73b37..48ced476 100644 --- a/SynapseEngine/Engine/Serialization/Schema/Models/CpuModelDataSchema.h +++ b/SynapseEngine/Engine/Serialization/Schema/Models/CpuModelDataSchema.h @@ -7,6 +7,7 @@ #include "GpuMeshletDrawDataSchema.h" #include "MaterialInfoSchema.h" #include "MeshDrawBlueprintSchema.h" +#include "MeshInstanceDescriptorSchema.h" #include "Engine/Mesh/Data/Cpu/CpuModelData.h" @@ -66,6 +67,8 @@ namespace Syn BlitVector mlDrawDescs{ m.meshletDrawDescriptors }; ar.Property("meshletDrawDescriptors", mlDrawDescs); + ar.Property("meshNodeDescriptors", m.meshNodeDescriptors); + auto serializeNestedBlit = [&ar](const char* arrayName, auto& nestedVec) { uint32_t outerSize = static_cast(nestedVec.size()); ar.EnterArray(arrayName, outerSize); @@ -103,6 +106,7 @@ namespace Syn ar.Property("batchedIndicesPerLod", m.batchedIndicesPerLod); ar.Property("physicsIndicesPerLod", m.physicsIndicesPerLod); + ar.Property("meshNodeDescriptors", m.meshNodeDescriptors); } } }; diff --git a/SynapseEngine/Engine/Serialization/Schema/Models/GpuBatchedModelSchema.h b/SynapseEngine/Engine/Serialization/Schema/Models/GpuBatchedModelSchema.h index f1c66d02..0ef864b1 100644 --- a/SynapseEngine/Engine/Serialization/Schema/Models/GpuBatchedModelSchema.h +++ b/SynapseEngine/Engine/Serialization/Schema/Models/GpuBatchedModelSchema.h @@ -6,6 +6,7 @@ #include "GpuIndexedDrawDataSchema.h" #include "GpuMeshletDrawDataSchema.h" #include "MaterialInfoSchema.h" +#include "MeshInstanceDescriptorSchema.h" #include "Engine/Mesh/Data/Gpu/GpuNodeTransform.h" #include "Engine/Mesh/Data/Gpu/GpuBatchedModel.h" @@ -54,6 +55,7 @@ namespace Syn ar.Property("globalIndexCount", m.globalIndexCount); ar.Property("globalAverageLodIndexCount", m.globalAverageLodIndexCount); ar.Property("globalMeshCount", m.globalMeshCount); + ar.Property("meshNodeDescriptors", m.meshNodeDescriptors); } }; } \ No newline at end of file diff --git a/SynapseEngine/Engine/Serialization/Schema/Models/MeshInstanceDescriptorSchema.h b/SynapseEngine/Engine/Serialization/Schema/Models/MeshInstanceDescriptorSchema.h new file mode 100644 index 00000000..c7114488 --- /dev/null +++ b/SynapseEngine/Engine/Serialization/Schema/Models/MeshInstanceDescriptorSchema.h @@ -0,0 +1,25 @@ +#pragma once +#include "Engine/Serialization/Schema/Schema.h" +#include "Engine/Mesh/Data/Common/MeshInstanceDescriptor.h" + +namespace Syn +{ + template <> + struct Schema { + static constexpr bool exists = true; + + template + static void Invoke(Archive& ar, const char* name, U& val) + { + ScopedArchiveObject obj(ar, name); + auto& d = const_cast&>(val); + + ar.Property("name", d.name); + ar.Property("meshIndex", d.meshIndex); + ar.Property("nodeIndex", d.nodeIndex); + ar.Property("parentNodeIndex", d.parentNodeIndex); + ar.Property("vertexCount", d.vertexCount); + ar.Property("indexCount", d.indexCount); + } + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Serialization/Schema/Scene/SceneSettingsSchema.h b/SynapseEngine/Engine/Serialization/Schema/Scene/SceneSettingsSchema.h index 4f4ab568..903977e0 100644 --- a/SynapseEngine/Engine/Serialization/Schema/Scene/SceneSettingsSchema.h +++ b/SynapseEngine/Engine/Serialization/Schema/Scene/SceneSettingsSchema.h @@ -20,7 +20,7 @@ namespace Syn ScopedArchiveObject obj(ar, name); auto& settings = const_cast&>(val); - // Hardware Devices (A frameworköd automatikusan kezeli az enumokat!) + // Hardware Devices ar.Property("geometryCullingDevice", settings.geometryCullingDevice); ar.Property("spotLightCullingDevice", settings.spotLightCullingDevice); ar.Property("pointLightCullingDevice", settings.pointLightCullingDevice); @@ -167,6 +167,23 @@ namespace Syn ar.Property("outlinePrimaryColor", settings.outlinePrimaryColor); ar.Property("outlineSecondaryColor", settings.outlineSecondaryColor); ar.Property("outlineThickness", settings.outlineThickness); + + // Infinite Grid + ar.Property("enableInfiniteGrid", settings.enableInfiniteGrid); + ar.Property("gridScale", settings.gridScale); + ar.Property("fadeDistance", settings.fadeDistance); + ar.Property("gridThickness", settings.gridThickness); + ar.Property("axisThickness", settings.axisThickness); + ar.Property("gridShowXZ", settings.gridShowXZ); + ar.Property("gridShowXY", settings.gridShowXY); + ar.Property("gridShowYZ", settings.gridShowYZ); + ar.Property("gridShowAxisX", settings.gridShowAxisX); + ar.Property("gridShowAxisY", settings.gridShowAxisY); + ar.Property("gridShowAxisZ", settings.gridShowAxisZ); + ar.Property("gridColor", settings.gridColor); + ar.Property("axisXColor", settings.axisXColor); + ar.Property("axisYColor", settings.axisYColor); + ar.Property("axisZColor", settings.axisZColor); } }; diff --git a/SynapseEngine/Engine/ServiceLocator.cpp b/SynapseEngine/Engine/ServiceLocator.cpp index 9f2ea300..0f07b0d5 100644 --- a/SynapseEngine/Engine/ServiceLocator.cpp +++ b/SynapseEngine/Engine/ServiceLocator.cpp @@ -20,6 +20,9 @@ namespace Syn { ICpuProfiler* ServiceLocator::_cpuProfiler = nullptr; Serializer* ServiceLocator::_serializer = nullptr; PhysicsFactory ServiceLocator::_physicsFactory = nullptr; + IRenderStatCollector* ServiceLocator::_renderStatCollector = nullptr; + FrameStatisticsManager* ServiceLocator::_frameStatisticsManager = nullptr; + PreviewManager* ServiceLocator::_previewManager = nullptr; void ServiceLocator::Shutdown() { @@ -41,5 +44,8 @@ namespace Syn { _gpuProfiler = nullptr; _cpuProfiler = nullptr; _serializer = nullptr; + _renderStatCollector = nullptr; + _frameStatisticsManager = nullptr; + _previewManager = nullptr; } } \ No newline at end of file diff --git a/SynapseEngine/Engine/ServiceLocator.h b/SynapseEngine/Engine/ServiceLocator.h index a530cfd6..97d573d6 100644 --- a/SynapseEngine/Engine/ServiceLocator.h +++ b/SynapseEngine/Engine/ServiceLocator.h @@ -28,6 +28,9 @@ namespace Syn { class IGpuProfiler; class ICpuProfiler; class Serializer; + class IRenderStatCollector; + class FrameStatisticsManager; + class PreviewManager; using PhysicsFactory = std::function()>; } @@ -99,6 +102,14 @@ namespace Syn static void ProvidePhysicsFactory(PhysicsFactory factory) { _physicsFactory = std::move(factory); } static PhysicsFactory& GetPhysicsFactory() { return _physicsFactory; } + static void ProvideRenderStatCollector(IRenderStatCollector* collector) { _renderStatCollector = collector; } + static IRenderStatCollector* GetRenderStatCollector() { return _renderStatCollector; } + + static void ProvideFrameStatisticsManager(FrameStatisticsManager* manager) { _frameStatisticsManager = manager; } + static FrameStatisticsManager* GetFrameStatisticsManager() { return _frameStatisticsManager; } + + static void ProvidePreviewManager(PreviewManager* manager) { _previewManager = manager; } + static PreviewManager* GetPreviewManager() { return _previewManager; } private: static Vk::Context* _vkContext; static Vk::GpuUploader* _gpuUploader; @@ -119,5 +130,8 @@ namespace Syn static ICpuProfiler* _cpuProfiler; static Serializer* _serializer; static PhysicsFactory _physicsFactory; + static IRenderStatCollector* _renderStatCollector; + static FrameStatisticsManager* _frameStatisticsManager; + static PreviewManager* _previewManager; }; } \ No newline at end of file diff --git a/SynapseEngine/Engine/Shaders/Includes/Common/FrameGlobalContext.glsl b/SynapseEngine/Engine/Shaders/Includes/Common/FrameGlobalContext.glsl index 5621c225..4619dea6 100644 --- a/SynapseEngine/Engine/Shaders/Includes/Common/FrameGlobalContext.glsl +++ b/SynapseEngine/Engine/Shaders/Includes/Common/FrameGlobalContext.glsl @@ -5,6 +5,8 @@ #include "../SharedGpuTypes.glsl" struct FrameGlobalContext { + uint64_t textureMetadataBufferAddr; + uint64_t globalDrawCountBufferAddr; uint64_t globalInstanceIndexBufferAddr; uint64_t globalIndirectCommandBufferAddr; @@ -16,6 +18,9 @@ struct FrameGlobalContext { uint64_t cameraBufferAddr; uint64_t cameraSparseMapBufferAddr; + uint64_t tagSparseMapBufferAddr; + uint64_t tagDataBufferAddr; + uint64_t transformBufferAddr; uint64_t transformSparseMapBufferAddr; uint64_t transformModelLinkBufferAddr; diff --git a/SynapseEngine/Engine/Shaders/Includes/Common/Material.glsl b/SynapseEngine/Engine/Shaders/Includes/Common/Material.glsl index 567c8333..98892944 100644 --- a/SynapseEngine/Engine/Shaders/Includes/Common/Material.glsl +++ b/SynapseEngine/Engine/Shaders/Includes/Common/Material.glsl @@ -9,10 +9,10 @@ struct Material { float emissiveIntensity; vec2 uvScale; float metalness; - float roughness; - float aoStrength; + float roughness; + float aoStrength; uint packedFlags; - uint albedoTexture; + uint albedoTexture; uint normalTexture; uint metalnessTexture; uint roughnessTexture; @@ -27,11 +27,16 @@ struct Material { layout(buffer_reference, std430) readonly restrict buffer MaterialBuffer { Material data[]; }; layout(buffer_reference, std430) readonly restrict buffer MaterialLookupBuffer { uint data[]; }; +#define INVALID_SAMPLER_INDEX 0xFF + #define GET_MATERIAL(addr, idx) MaterialBuffer(addr).data[idx] #define GET_MATERIAL_INDEX(addr, idx) MaterialLookupBuffer(addr).data[idx] #define HAS_VALID_TEXTURE(texIdx) ((texIdx) != INVALID_INDEX) +#define UNPACK_TEXTURE_ID(packedVal) ((packedVal) & 0x00FFFFFF) +#define UNPACK_SAMPLER_ID(packedVal) ((packedVal) >> 24) + #define IS_DOUBLE_SIDED(mat) HAS_FLAG((mat).packedFlags, 0) #define IS_TRANSPARENT(mat) HAS_FLAG((mat).packedFlags, 1) @@ -43,5 +48,4 @@ layout(buffer_reference, std430) readonly restrict buffer MaterialLookupBuffer { #define HAS_EMISSIVE_TEX(mat) HAS_VALID_TEXTURE((mat).emissiveTexture) #define HAS_AO_TEX(mat) HAS_VALID_TEXTURE((mat).ambientOcclusionTexture) -#endif - +#endif \ No newline at end of file diff --git a/SynapseEngine/Engine/Shaders/Includes/Common/Mesh.glsl b/SynapseEngine/Engine/Shaders/Includes/Common/Mesh.glsl index 506545f9..63da4d9d 100644 --- a/SynapseEngine/Engine/Shaders/Includes/Common/Mesh.glsl +++ b/SynapseEngine/Engine/Shaders/Includes/Common/Mesh.glsl @@ -41,6 +41,7 @@ struct GpuModelAddresses { uint64_t vertexPositions; uint64_t vertexAttributes; uint64_t indices; + uint64_t meshMaterialIndices; uint64_t meshDescriptors; uint64_t meshColliders; uint64_t lodDescriptors; @@ -56,9 +57,7 @@ struct GpuModelAddresses { uint indexCount; uint averageLodIndexCount; uint meshCount; - uint padding0; - uint padding1; - uint padding2; + uint padding; GpuMeshCollider globalCollider; }; @@ -105,10 +104,12 @@ layout(buffer_reference, std430) readonly restrict buffer MeshletColliderBuffer layout(buffer_reference, std430) readonly restrict buffer VertexIndicesBuffer { uint data[]; }; layout(buffer_reference, std430) readonly restrict buffer TriangleIndicesBuffer { uint8_t data[]; }; layout(buffer_reference, std430) readonly restrict buffer DebugMeshletInstanceBuffer { DebugMeshletInstance data[]; }; +layout(buffer_reference, std430) readonly restrict buffer MaterialIndices { uint data[]; }; #define GET_VERTEX_POS(addr, idx) PositionBuffer(addr).data[idx] #define GET_VERTEX_ATTR(addr, idx) AttributeBuffer(addr).data[idx] #define GET_INDEX(addr, idx) IndexBuffer(addr).data[idx] +#define GET_DEFUALT_MATERIAL_INDEX(addr, idx) MaterialIndices(addr).data[idx] #define GET_MODEL_ADDRESSES(addr, idx) ModelAddressBuffer(addr).data[idx] #define GET_DRAW_DESCRIPTOR(addr, idx) DescriptorBuffer(addr).data[idx] #define GET_MESHLET_DRAW_DESC(addr, idx) MeshletDrawDescBuffer(addr).data[idx] diff --git a/SynapseEngine/Engine/Shaders/Includes/Common/Tag.glsl b/SynapseEngine/Engine/Shaders/Includes/Common/Tag.glsl new file mode 100644 index 00000000..e1f7b87b --- /dev/null +++ b/SynapseEngine/Engine/Shaders/Includes/Common/Tag.glsl @@ -0,0 +1,12 @@ +#ifndef SYN_INCLUDES_COMMON_TAG_GLSL +#define SYN_INCLUDES_COMMON_TAG_GLSL + +#include "../Core.glsl" + +layout(buffer_reference, std430) readonly restrict buffer TagDataBuffer { + uint data[]; +}; + +#define GET_TAG_DATA(addr, idx) TagDataBuffer(addr).data[idx] + +#endif \ No newline at end of file diff --git a/SynapseEngine/Engine/Shaders/Includes/Common/Texture.glsl b/SynapseEngine/Engine/Shaders/Includes/Common/Texture.glsl index 04b54026..e360c3af 100644 --- a/SynapseEngine/Engine/Shaders/Includes/Common/Texture.glsl +++ b/SynapseEngine/Engine/Shaders/Includes/Common/Texture.glsl @@ -6,6 +6,21 @@ layout(set = 0, binding = 0) uniform sampler globalSamplers[]; layout(set = 0, binding = 1) uniform texture2D bindlessTextures[]; +layout(buffer_reference, std430, buffer_reference_align = 4) readonly restrict buffer TextureMetadataBuffer { + uint data[]; +}; + +#define GET_TEXTURE_METADATA(addr, texID) TextureMetadataBuffer(addr).data[texID] + +uint UnpackTextureMetadataSampler(uint meta) { + return meta & 0x7FFFFFFF; +} + +void UnpackTextureMetadata(uint meta, out uint samplerID, out bool invertTangent) { + samplerID = meta & 0x7FFFFFFF; + invertTangent = bool(meta >> 31); +} + #define SAMPLER_LINEAR_REPEAT 0 #define SAMPLER_LINEAR_CLAMP_EDGE 1 #define SAMPLER_NEAREST_REPEAT 2 diff --git a/SynapseEngine/Engine/Shaders/Includes/Payload/ShadowTaskPayload.glsl b/SynapseEngine/Engine/Shaders/Includes/Payload/ShadowTaskPayload.glsl index cdfb90f9..1601a03d 100644 --- a/SynapseEngine/Engine/Shaders/Includes/Payload/ShadowTaskPayload.glsl +++ b/SynapseEngine/Engine/Shaders/Includes/Payload/ShadowTaskPayload.glsl @@ -7,6 +7,7 @@ struct ShadowTaskPayload { uint transformDenseIdx; uint lightShadowDenseIdx; uint cascadeIdx; + uint modelDenseIndex; uint meshletIndices[32]; }; diff --git a/SynapseEngine/Engine/Shaders/Includes/Payload/TaskPayload.glsl b/SynapseEngine/Engine/Shaders/Includes/Payload/TaskPayload.glsl index 8425b0dc..182bdb47 100644 --- a/SynapseEngine/Engine/Shaders/Includes/Payload/TaskPayload.glsl +++ b/SynapseEngine/Engine/Shaders/Includes/Payload/TaskPayload.glsl @@ -6,6 +6,7 @@ struct TaskPayload { uint entityId; uint transformDenseIdx; uint activeCameraDenseIdx; + uint modelDenseIndex; uint meshletIndices[32]; }; diff --git a/SynapseEngine/Engine/Shaders/Includes/PushConstants/InfiniteGridPC.glsl b/SynapseEngine/Engine/Shaders/Includes/PushConstants/InfiniteGridPC.glsl new file mode 100644 index 00000000..fe21b367 --- /dev/null +++ b/SynapseEngine/Engine/Shaders/Includes/PushConstants/InfiniteGridPC.glsl @@ -0,0 +1,20 @@ +#ifndef SYN_INCLUDES_PUSH_CONSTANTS_HIZ_LINEARIZE_DEPTH_PC_GLSL +#define SYN_INCLUDES_PUSH_CONSTANTS_HIZ_LINEARIZE_DEPTH_PC_GLSL + +#include "../SharedGpuTypes.glsl" + +struct InfiniteGridPC { + uint64_t frameGlobalContextBufferAddr; + uint planeFlags; // Bit 0: XZ, Bit 1: XY, Bit 2: YZ + uint axisFlags; // Bit 0: X, Bit 1: Y, Bit 2: Z + float gridScale; + float fadeDistance; + float gridThickness; + float axisThickness; + vec4 gridColor; + vec4 axisXColor; + vec4 axisYColor; + vec4 axisZColor; +}; + +#endif \ No newline at end of file diff --git a/SynapseEngine/Engine/Shaders/Includes/PushConstants/MaterialPreviewPC.glsl b/SynapseEngine/Engine/Shaders/Includes/PushConstants/MaterialPreviewPC.glsl new file mode 100644 index 00000000..8f980c18 --- /dev/null +++ b/SynapseEngine/Engine/Shaders/Includes/PushConstants/MaterialPreviewPC.glsl @@ -0,0 +1,11 @@ +#ifndef SYN_INCLUDES_PC_MATERIAL_PREVIEW_GLSL +#define SYN_INCLUDES_PC_MATERIAL_PREVIEW_GLSL + +#include "../SharedGpuTypes.glsl" + +struct MaterialPreviewPC { + uint64_t frameGlobalContextBufferAddr; + uint materialId; +}; + +#endif \ No newline at end of file diff --git a/SynapseEngine/Engine/Shaders/Includes/PushConstants/ModelPreviewPC.glsl b/SynapseEngine/Engine/Shaders/Includes/PushConstants/ModelPreviewPC.glsl new file mode 100644 index 00000000..ba7f9a98 --- /dev/null +++ b/SynapseEngine/Engine/Shaders/Includes/PushConstants/ModelPreviewPC.glsl @@ -0,0 +1,13 @@ +#ifndef SYN_INCLUDES_PC_MODEL_PREVIEW_GLSL +#define SYN_INCLUDES_PC_MODEL_PREVIEW_GLSL + +#include "../SharedGpuTypes.glsl" + +struct ModelPreviewPC { + uint64_t frameGlobalContextBufferAddr; + uint modelId; + uint meshIndex; + mat4 mvp; +}; + +#endif \ No newline at end of file diff --git a/SynapseEngine/Engine/Shaders/Includes/PushConstants/SkySpherePC.glsl b/SynapseEngine/Engine/Shaders/Includes/PushConstants/SkySpherePC.glsl new file mode 100644 index 00000000..6e7fdbed --- /dev/null +++ b/SynapseEngine/Engine/Shaders/Includes/PushConstants/SkySpherePC.glsl @@ -0,0 +1,17 @@ +#ifndef SYN_INCLUDES_PUSH_CONSTANTS_SKY_SPHERE_PC_GLSL +#define SYN_INCLUDES_PUSH_CONSTANTS_SKY_SPHERE_PC_GLSL + +#include "../SharedGpuTypes.glsl" + +struct SkySpherePC { + mat4 skyRotationMatrix; + vec3 skyTint; + uint padding; + uint64_t frameGlobalContextBufferAddr; + uint skyTextureIndex; + uint samplerIndex; + uint mappingType; + float skyIntensity; + float skyExposureEV; +}; +#endif \ No newline at end of file diff --git a/SynapseEngine/Engine/Shaders/Includes/Utils/CullingMath.glsl b/SynapseEngine/Engine/Shaders/Includes/Utils/CullingMath.glsl index 4050370c..1a31e4fd 100644 --- a/SynapseEngine/Engine/Shaders/Includes/Utils/CullingMath.glsl +++ b/SynapseEngine/Engine/Shaders/Includes/Utils/CullingMath.glsl @@ -16,14 +16,14 @@ bool TestConeCulling(vec3 apex, vec3 axis, float cutoff, vec3 cameraEye) { return dot(view, axis) >= cutoff; } -bool TestConeCulling(GpuMeshletCollider collider, vec3 cameraEye) { - return TestConeCulling(collider.apex, collider.axis, collider.cutoff, cameraEye); -} - bool TestConeCulling(vec3 axis, float cutoff, vec3 lightDir) { return dot(lightDir, axis) >= cutoff; } +bool TestConeCulling(GpuMeshletCollider collider, vec3 cameraEye) { + return TestConeCulling(collider.apex, collider.axis, collider.cutoff, cameraEye); +} + bool TestConeCullingLight(GpuMeshletCollider collider, vec3 lightDir) { return TestConeCulling(collider.axis, collider.cutoff, lightDir); } diff --git a/SynapseEngine/Engine/Shaders/Includes/Utils/EnvironmentMath.glsl b/SynapseEngine/Engine/Shaders/Includes/Utils/EnvironmentMath.glsl new file mode 100644 index 00000000..abd4f78f --- /dev/null +++ b/SynapseEngine/Engine/Shaders/Includes/Utils/EnvironmentMath.glsl @@ -0,0 +1,17 @@ +#ifndef SYN_INCLUDES_UTILS_ENVIRONMENT_MATH_GLSL +#define SYN_INCLUDES_UTILS_ENVIRONMENT_MATH_GLSL + +vec2 SampleEquirectangular(vec3 v) { + vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); + uv *= vec2(0.15915494309, 0.31830988618); + uv += 0.5; + return uv; +} + +vec2 SampleOctahedral(vec3 v) { + v /= (abs(v.x) + abs(v.y) + abs(v.z)); + vec2 uv = v.z >= 0.0 ? v.xy : (1.0 - abs(v.yx)) * sign(v.xy); + return uv * 0.5 + 0.5; +} + +#endif \ No newline at end of file diff --git a/SynapseEngine/Engine/Shaders/Includes/Utils/MaterialMath.glsl b/SynapseEngine/Engine/Shaders/Includes/Utils/MaterialMath.glsl index a61b5cf1..3cbe2a79 100644 --- a/SynapseEngine/Engine/Shaders/Includes/Utils/MaterialMath.glsl +++ b/SynapseEngine/Engine/Shaders/Includes/Utils/MaterialMath.glsl @@ -4,45 +4,79 @@ #include "../Common/Texture.glsl" #include "../Common/Material.glsl" -vec4 EvaluateAlbedoAlpha(const Material mat, vec2 uv) { +uint ResolveSampler(uint64_t textureMetadataBufferAddr, uint packedTexData, uint texID) { + uint sampID = UNPACK_SAMPLER_ID(packedTexData); + if (sampID == INVALID_SAMPLER_INDEX) { + uint meta = GET_TEXTURE_METADATA(textureMetadataBufferAddr, texID); + return UnpackTextureMetadataSampler(meta); + } + return sampID; +} + +vec4 EvaluateAlbedoAlpha(uint64_t textureMetadataBufferAddr, const Material mat, vec2 uv) { vec4 finalColor = mat.color; + if (HAS_ALBEDO_TEX(mat)) { - finalColor *= SampleTexture2D(mat.albedoTexture, SAMPLER_LINEAR_ANISO, uv); + uint texID = UNPACK_TEXTURE_ID(mat.albedoTexture); + uint sampID = ResolveSampler(textureMetadataBufferAddr, mat.albedoTexture, texID); + finalColor *= SampleTexture2D(texID, sampID, uv); } return finalColor; } -vec3 EvaluateNormal(Material mat, vec2 uv, vec3 vertexNormal, vec4 vertexTangent) { +vec3 EvaluateNormal(uint64_t textureMetadataBufferAddr, Material mat, vec2 uv, vec3 vertexNormal, vec4 vertexTangent) { vec3 normal = normalize(vertexNormal); + if (!HAS_NORMAL_TEX(mat)) { return normal; } + uint texID = UNPACK_TEXTURE_ID(mat.normalTexture); + uint meta = GET_TEXTURE_METADATA(textureMetadataBufferAddr, texID); + + uint defaultSamplerID; + bool invertNormal; + UnpackTextureMetadata(meta, defaultSamplerID, invertNormal); + + uint sampID = UNPACK_SAMPLER_ID(mat.normalTexture); + if (sampID == INVALID_SAMPLER_INDEX) { + sampID = defaultSamplerID; + } + vec3 tangent = normalize(vertexTangent.xyz); tangent = normalize(tangent - normal * dot(normal, tangent)); + vec3 bitangent = cross(normal, tangent) * vertexTangent.w; mat3 TBN = mat3(tangent, bitangent, normal); - vec3 normalMapSample = SampleTexture2D(mat.normalTexture, SAMPLER_LINEAR_ANISO, uv).rgb; - vec3 tangentSpaceNormal = normalMapSample * 2.0 - 1.0; - + vec3 tangentSpaceNormal; + tangentSpaceNormal.xy = SampleTexture2D(texID, sampID, uv).xy * 2.0 - 1.0; + tangentSpaceNormal.z = sqrt(max(1.0 - dot(tangentSpaceNormal.xy, tangentSpaceNormal.xy), 0.0)); + tangentSpaceNormal.y *= invertNormal ? -1.0 : 1.0; + return normalize(TBN * tangentSpaceNormal); } -vec2 EvaluateMetallicRoughness(Material mat, vec2 uv) { +vec2 EvaluateMetallicRoughness(uint64_t textureMetadataBufferAddr, Material mat, vec2 uv) { float metalness = mat.metalness; float roughness = mat.roughness; - + if (HAS_METALNESS_TEX(mat)) { - metalness *= SampleTexture2D(mat.metalnessTexture, SAMPLER_LINEAR_ANISO, uv).r; + uint texID = UNPACK_TEXTURE_ID(mat.metalnessTexture); + uint sampID = ResolveSampler(textureMetadataBufferAddr, mat.metalnessTexture, texID); + metalness *= SampleTexture2D(texID, sampID, uv).r; } if (HAS_ROUGHNESS_TEX(mat)) { - roughness *= SampleTexture2D(mat.roughnessTexture, SAMPLER_LINEAR_ANISO, uv).r; + uint texID = UNPACK_TEXTURE_ID(mat.roughnessTexture); + uint sampID = ResolveSampler(textureMetadataBufferAddr, mat.roughnessTexture, texID); + roughness *= SampleTexture2D(texID, sampID, uv).r; } if (HAS_METALLIC_ROUGHNESS_TEX(mat)) { - vec4 mrSample = SampleTexture2D(mat.metallicRoughnessTexture, SAMPLER_LINEAR_ANISO, uv); + uint texID = UNPACK_TEXTURE_ID(mat.metallicRoughnessTexture); + uint sampID = ResolveSampler(textureMetadataBufferAddr, mat.metallicRoughnessTexture, texID); + vec4 mrSample = SampleTexture2D(texID, sampID, uv); roughness *= mrSample.g; metalness *= mrSample.b; } @@ -50,18 +84,24 @@ vec2 EvaluateMetallicRoughness(Material mat, vec2 uv) { return vec2(metalness, roughness); } -vec3 EvaluateEmissive(Material mat, vec2 uv) { +vec3 EvaluateEmissive(uint64_t textureMetadataBufferAddr, Material mat, vec2 uv) { vec3 emissive = mat.emissiveColor * mat.emissiveIntensity; + if (HAS_EMISSIVE_TEX(mat)) { - emissive *= SampleTexture2D(mat.emissiveTexture, SAMPLER_LINEAR_ANISO, uv).rgb; + uint texID = UNPACK_TEXTURE_ID(mat.emissiveTexture); + uint sampID = ResolveSampler(textureMetadataBufferAddr, mat.emissiveTexture, texID); + emissive *= SampleTexture2D(texID, sampID, uv).rgb; } return emissive; } -float EvaluateAO(Material mat, vec2 uv) { +float EvaluateAO(uint64_t textureMetadataBufferAddr, Material mat, vec2 uv) { float ao = mat.aoStrength; + if (HAS_AO_TEX(mat)) { - ao *= SampleTexture2D(mat.ambientOcclusionTexture, SAMPLER_LINEAR_ANISO, uv).r; + uint texID = UNPACK_TEXTURE_ID(mat.ambientOcclusionTexture); + uint sampID = ResolveSampler(textureMetadataBufferAddr, mat.ambientOcclusionTexture, texID); + ao *= SampleTexture2D(texID, sampID, uv).r; } return ao; } diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/DirectionLight/DirectionLightShadowModelCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/DirectionLight/DirectionLightShadowModelCulling.comp index 48c34df2..348c0e4f 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/DirectionLight/DirectionLightShadowModelCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/DirectionLight/DirectionLightShadowModelCulling.comp @@ -16,6 +16,7 @@ #include "../../../Includes/Common/DirectionLight.glsl" #include "../../../Includes/Utils/CullingMath.glsl" #include "../../../Includes/Utils/Occlusion.glsl" +#include "../../../Includes/Common/Tag.glsl" layout(local_size_x = 32, local_size_y = 1, local_size_z = 1) in; @@ -48,10 +49,19 @@ void main() // 2. Resolve Entity and Model Data TransformModelLink link = GET_TRANSFORM_MODEL_LINK(ctx.transformModelLinkBufferAddr, transformDenseIndex); if (link.modelDenseIndex == INVALID_INDEX) return; - uint entityId = link.entityIndex; + + uint tagSparseIndex = GET_SPARSE_INDEX(ctx.tagSparseMapBufferAddr, entityId); + if (tagSparseIndex == INVALID_INDEX) return; + + uint entityFlags = GET_TAG_DATA(ctx.tagDataBufferAddr, tagSparseIndex); + bool isActive = (entityFlags & (1u << 0)) != 0; + + if (!isActive) return; + ModelComponent modelComp = GET_MODEL_COMP(ctx.modelBufferAddr, link.modelDenseIndex); - if (modelComp.modelIndex == INVALID_INDEX) return; + bool castShadow = (modelComp.flags & (1u << 0)) != 0; + if (modelComp.modelIndex == INVALID_INDEX || !castShadow) return; // 3. Resolve Transform and Main Camera (Camera is required for LOD calculations) TransformComponent transform = GET_TRANSFORM(ctx.transformBufferAddr, transformDenseIndex); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/DirectionLight/DirectionLightShadowMortonModelCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/DirectionLight/DirectionLightShadowMortonModelCulling.comp index 3b5b8dce..074d6baa 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/DirectionLight/DirectionLightShadowMortonModelCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/DirectionLight/DirectionLightShadowMortonModelCulling.comp @@ -8,6 +8,7 @@ #include "../../../Includes/Common/FrameGlobalContext.glsl" #include "../../../Includes/Common/Camera.glsl" #include "../../../Includes/Common/Transform.glsl" +#include "../../../Includes/Common/Tag.glsl" #include "../../../Includes/Common/Model.glsl" #include "../../../Includes/Common/Mesh.glsl" #include "../../../Includes/Common/Material.glsl" @@ -70,12 +71,22 @@ void main() { TransformModelLink link = GET_TRANSFORM_MODEL_LINK(ctx.transformModelLinkBufferAddr, denseIndex); if (link.modelDenseIndex == INVALID_INDEX) continue; - uint entityId = link.entityIndex; + + uint tagSparseIndex = GET_SPARSE_INDEX(ctx.tagSparseMapBufferAddr, entityId); + if (tagSparseIndex == INVALID_INDEX) return; + + uint entityFlags = GET_TAG_DATA(ctx.tagDataBufferAddr, tagSparseIndex); + bool isActive = (entityFlags & (1u << 0)) != 0; + + if (!isActive) return; TransformComponent transform = GET_TRANSFORM(ctx.transformBufferAddr, denseIndex); ModelComponent modelComp = GET_MODEL_COMP(ctx.modelBufferAddr, link.modelDenseIndex); + bool castShadow = (modelComp.flags & (1u << 0)) != 0; + if (modelComp.modelIndex == INVALID_INDEX || !castShadow) return; + ModelAllocationInfo mAlloc = GET_MODEL_ALLOC(ctx.globalModelAllocationBufferAddr, modelComp.modelIndex); GpuModelAddresses addrs = GET_MODEL_ADDRESSES(ctx.modelAddressBufferAddr, modelComp.modelIndex); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/DirectionLight/DirectionLightShadowStaticModelCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/DirectionLight/DirectionLightShadowStaticModelCulling.comp index cf686a5f..8468e72b 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/DirectionLight/DirectionLightShadowStaticModelCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/DirectionLight/DirectionLightShadowStaticModelCulling.comp @@ -8,6 +8,7 @@ #include "../../../Includes/Common/FrameGlobalContext.glsl" #include "../../../Includes/Common/Camera.glsl" #include "../../../Includes/Common/Transform.glsl" +#include "../../../Includes/Common/Tag.glsl" #include "../../../Includes/Common/Model.glsl" #include "../../../Includes/Common/Mesh.glsl" #include "../../../Includes/Common/Material.glsl" @@ -63,14 +64,25 @@ void main() { for (uint i = gl_LocalInvocationID.x; i < chunk.entityCount; i += gl_WorkGroupSize.x) { uint denseIndex = chunk.firstEntityIndex + i; + TransformModelLink link = GET_TRANSFORM_MODEL_LINK(ctx.transformModelLinkBufferAddr, denseIndex); - if (link.modelDenseIndex == INVALID_INDEX) continue; uint entityId = link.entityIndex; + + uint tagSparseIndex = GET_SPARSE_INDEX(ctx.tagSparseMapBufferAddr, entityId); + if (tagSparseIndex == INVALID_INDEX) return; + + uint entityFlags = GET_TAG_DATA(ctx.tagDataBufferAddr, tagSparseIndex); + bool isActive = (entityFlags & (1u << 0)) != 0; + + if (!isActive) return; TransformComponent transform = GET_TRANSFORM(ctx.transformBufferAddr, denseIndex); ModelComponent modelComp = GET_MODEL_COMP(ctx.modelBufferAddr, link.modelDenseIndex); + bool castShadow = (modelComp.flags & (1u << 0)) != 0; + if (modelComp.modelIndex == INVALID_INDEX || !castShadow) return; + ModelAllocationInfo mAlloc = GET_MODEL_ALLOC(ctx.globalModelAllocationBufferAddr, modelComp.modelIndex); GpuModelAddresses addrs = GET_MODEL_ADDRESSES(ctx.modelAddressBufferAddr, modelComp.modelIndex); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/Geometry/GeometryModelCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/Geometry/GeometryModelCulling.comp index c67771b7..2325e131 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/Geometry/GeometryModelCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/Geometry/GeometryModelCulling.comp @@ -8,6 +8,7 @@ #include "../../../Includes/Common/FrameGlobalContext.glsl" #include "../../../Includes/Common/Camera.glsl" #include "../../../Includes/Common/Transform.glsl" +#include "../../../Includes/Common/Tag.glsl" #include "../../../Includes/Common/Model.glsl" #include "../../../Includes/Common/Mesh.glsl" #include "../../../Includes/Common/Animation.glsl" @@ -41,9 +42,15 @@ void main() TransformModelLink link = GET_TRANSFORM_MODEL_LINK(ctx.transformModelLinkBufferAddr, transformDenseIndex); if (link.modelDenseIndex == INVALID_INDEX) return; - uint entityId = link.entityIndex; + uint tagSparseIndex = GET_SPARSE_INDEX(ctx.tagSparseMapBufferAddr, entityId); + if (tagSparseIndex == INVALID_INDEX) return; + uint entityFlags = GET_TAG_DATA(ctx.tagDataBufferAddr, tagSparseIndex); + + bool isActive = (entityFlags & (1u << 0)) != 0; + if (!isActive) return; + // 2. Fetch Model component and Entity ID ModelComponent modelComp = GET_MODEL_COMP(ctx.modelBufferAddr, link.modelDenseIndex); if (modelComp.modelIndex == INVALID_INDEX) return; diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/Geometry/GeometryMortonModelCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/Geometry/GeometryMortonModelCulling.comp index bb938f0e..ec8a9c88 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/Geometry/GeometryMortonModelCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/Geometry/GeometryMortonModelCulling.comp @@ -8,6 +8,7 @@ #include "../../../Includes/Common/FrameGlobalContext.glsl" #include "../../../Includes/Common/Camera.glsl" #include "../../../Includes/Common/Transform.glsl" +#include "../../../Includes/Common/Tag.glsl" #include "../../../Includes/Common/Model.glsl" #include "../../../Includes/Common/Mesh.glsl" #include "../../../Includes/Common/Material.glsl" @@ -58,11 +59,17 @@ void main() { if (denseIndex == 0xFFFFFFFF) continue; - TransformModelLink link = GET_TRANSFORM_MODEL_LINK(ctx.transformModelLinkBufferAddr, denseIndex); - + TransformModelLink link = GET_TRANSFORM_MODEL_LINK(ctx.transformModelLinkBufferAddr, denseIndex); if (link.modelDenseIndex == INVALID_INDEX) continue; uint entityId = link.entityIndex; + uint tagSparseIndex = GET_SPARSE_INDEX(ctx.tagSparseMapBufferAddr, entityId); + if (tagSparseIndex == INVALID_INDEX) return; + uint entityFlags = GET_TAG_DATA(ctx.tagDataBufferAddr, tagSparseIndex); + + bool isActive = (entityFlags & (1u << 0)) != 0; + if (!isActive) return; + TransformComponent transform = GET_TRANSFORM(ctx.transformBufferAddr, denseIndex); ModelComponent modelComp = GET_MODEL_COMP(ctx.modelBufferAddr, link.modelDenseIndex); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/Geometry/GeometryStaticModelCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/Geometry/GeometryStaticModelCulling.comp index 3e7757d9..58ebd8bf 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/Geometry/GeometryStaticModelCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/Geometry/GeometryStaticModelCulling.comp @@ -8,6 +8,7 @@ #include "../../../Includes/Common/FrameGlobalContext.glsl" #include "../../../Includes/Common/Camera.glsl" #include "../../../Includes/Common/Transform.glsl" +#include "../../../Includes/Common/Tag.glsl" #include "../../../Includes/Common/Model.glsl" #include "../../../Includes/Common/Mesh.glsl" #include "../../../Includes/Common/Material.glsl" @@ -55,9 +56,15 @@ void main() { // Resolve dense entity index directly from the chunk uint denseIndex = chunk.firstEntityIndex + i; TransformModelLink link = GET_TRANSFORM_MODEL_LINK(ctx.transformModelLinkBufferAddr, denseIndex); - if (link.modelDenseIndex == INVALID_INDEX) continue; uint entityId = link.entityIndex; + + uint tagSparseIndex = GET_SPARSE_INDEX(ctx.tagSparseMapBufferAddr, entityId); + if (tagSparseIndex == INVALID_INDEX) return; + uint entityFlags = GET_TAG_DATA(ctx.tagDataBufferAddr, tagSparseIndex); + + bool isActive = (entityFlags & (1u << 0)) != 0; + if (!isActive) return; TransformComponent transform = GET_TRANSFORM(ctx.transformBufferAddr, denseIndex); ModelComponent modelComp = GET_MODEL_COMP(ctx.modelBufferAddr, link.modelDenseIndex); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightCulling.comp index 40f18ac1..016db1e9 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightCulling.comp @@ -9,6 +9,7 @@ #include "../../../Includes/Core.glsl" #include "../../../Includes/Common/FrameGlobalContext.glsl" +#include "../../../Includes/Common/Tag.glsl" #include "../../../Includes/Common/Camera.glsl" #include "../../../Includes/Common/PointLight.glsl" #include "../../../Includes/Utils/CullingMath.glsl" @@ -32,6 +33,13 @@ void main() { if (globalId >= ctx.pointLightCount) return; PointLightColliderGPU collider = GET_POINT_LIGHT_COLLIDER(ctx.pointLightColliderBufferAddr, globalId); + + uint tagSparseIndex = GET_SPARSE_INDEX(ctx.tagSparseMapBufferAddr, collider.entityIndex); + if (tagSparseIndex == INVALID_INDEX) return; + uint entityFlags = GET_TAG_DATA(ctx.tagDataBufferAddr, tagSparseIndex); + + bool isActive = (entityFlags & (1u << 0)) != 0; + if (!isActive) return; uint cameraIdx = GET_SPARSE_INDEX(ctx.cameraSparseMapBufferAddr, ctx.mainCameraEntity); CameraComponent camera = GET_CAMERA(ctx.cameraBufferAddr, cameraIdx); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowMeshCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowMeshCulling.comp index fd8e4f47..3514cefb 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowMeshCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowMeshCulling.comp @@ -120,11 +120,6 @@ void main() { float mainCamScreenSize = CalculateSphereScreenSizePerspective(worldCollider.center, worldCollider.radius, camera.view, camera.proj, cameraNear, screenRes); if (mainCamScreenSize < 1.0) continue; - if (ctx.enableChunkOcclusionCulling == 1) { - float shadowScreenSizePixels = 0.0; - // Todo: - } - uint rawLod = (mainCamScreenSize > 512.0) ? 0 : (mainCamScreenSize > 256.0) ? 1 : (mainCamScreenSize > 128.0) ? 2 : 3; uint lod = min(rawLod + ctx.pointLightShadowLodBias, 3u); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowModelCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowModelCulling.comp index 2c4ec2bb..0d5737c9 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowModelCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowModelCulling.comp @@ -8,6 +8,7 @@ #include "../../../Includes/Common/FrameGlobalContext.glsl" #include "../../../Includes/Common/Camera.glsl" #include "../../../Includes/Common/Transform.glsl" +#include "../../../Includes/Common/Tag.glsl" #include "../../../Includes/Common/Model.glsl" #include "../../../Includes/Common/Mesh.glsl" #include "../../../Includes/Common/Animation.glsl" @@ -45,10 +46,18 @@ void main() // 2. Resolve Entity and Model Data TransformModelLink link = GET_TRANSFORM_MODEL_LINK(ctx.transformModelLinkBufferAddr, transformDenseIndex); if (link.modelDenseIndex == INVALID_INDEX) return; - uint entityId = link.entityIndex; + + uint tagSparseIndex = GET_SPARSE_INDEX(ctx.tagSparseMapBufferAddr, entityId); + if (tagSparseIndex == INVALID_INDEX) return; + + uint entityFlags = GET_TAG_DATA(ctx.tagDataBufferAddr, tagSparseIndex); + bool isActive = (entityFlags & (1u << 0)) != 0; + if (!isActive) return; + ModelComponent modelComp = GET_MODEL_COMP(ctx.modelBufferAddr, link.modelDenseIndex); - if (modelComp.modelIndex == INVALID_INDEX) return; + bool castShadow = (modelComp.flags & (1u << 0)) != 0; + if (modelComp.modelIndex == INVALID_INDEX || !castShadow) return; // 3. Resolve Transform, Camera & Colliders TransformComponent transform = GET_TRANSFORM(ctx.transformBufferAddr, transformDenseIndex); @@ -94,11 +103,6 @@ void main() if (mainCamScreenSize < 1.0) return; - if (ctx.enableChunkOcclusionCulling == 1) { - float shadowScreenSizePixels = 0.0; - // Todo: - } - uint entityData = (entityId & 0x7FFFFFFF); entityData = SET_BIT_TO(entityData, 31, visibility == INTERSECTION_INSIDE); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowMortonChunkCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowMortonChunkCulling.comp index 343e7437..574e5cf1 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowMortonChunkCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowMortonChunkCulling.comp @@ -60,12 +60,6 @@ void main() { if (visibility == INTERSECTION_OUTSIDE) return; } - // 5. Occlusion Culling (Deferred for Point Lights / Atlas evaluation needed) - if (ctx.enableChunkOcclusionCulling == 1) { - float shadowScreenSizePixels = 0.0; - //Todo - } - // 6. Subgroup-optimized writes to the visible Morton chunk list uint needsWrite = 1; uint subgroupWriteCount = subgroupAdd(needsWrite); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowMortonModelCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowMortonModelCulling.comp index 9e8cd2d4..8be2c2c6 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowMortonModelCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowMortonModelCulling.comp @@ -8,6 +8,7 @@ #include "../../../Includes/Common/FrameGlobalContext.glsl" #include "../../../Includes/Common/Camera.glsl" #include "../../../Includes/Common/Transform.glsl" +#include "../../../Includes/Common/Tag.glsl" #include "../../../Includes/Common/Model.glsl" #include "../../../Includes/Common/Mesh.glsl" #include "../../../Includes/Common/Material.glsl" @@ -66,12 +67,22 @@ void main() { TransformModelLink link = GET_TRANSFORM_MODEL_LINK(ctx.transformModelLinkBufferAddr, denseIndex); if (link.modelDenseIndex == INVALID_INDEX) continue; - uint entityId = link.entityIndex; + uint tagSparseIndex = GET_SPARSE_INDEX(ctx.tagSparseMapBufferAddr, entityId); + if (tagSparseIndex == INVALID_INDEX) return; + + uint entityFlags = GET_TAG_DATA(ctx.tagDataBufferAddr, tagSparseIndex); + bool isActive = (entityFlags & (1u << 0)) != 0; + + if (!isActive) return; + TransformComponent transform = GET_TRANSFORM(ctx.transformBufferAddr, denseIndex); ModelComponent modelComp = GET_MODEL_COMP(ctx.modelBufferAddr, link.modelDenseIndex); + bool castShadow = (modelComp.flags & (1u << 0)) != 0; + if (modelComp.modelIndex == INVALID_INDEX || !castShadow) return; + ModelAllocationInfo mAlloc = GET_MODEL_ALLOC(ctx.globalModelAllocationBufferAddr, modelComp.modelIndex); GpuModelAddresses addrs = GET_MODEL_ADDRESSES(ctx.modelAddressBufferAddr, modelComp.modelIndex); @@ -106,12 +117,6 @@ void main() { float mainCamScreenSize = CalculateSphereScreenSizePerspective(worldCollider.center, worldCollider.radius, camera.view, camera.proj, cameraNear, screenRes); if (mainCamScreenSize < 1.0) continue; - // 7. Occlusion Culling using Spot Light HZB - if (ctx.enableModelOcclusionCulling == 1) { - float shadowScreenSizePixels = 0.0; - //Todo - } - // 7. Encode Payload for sort/draw phase uint entityData = (entityId & 0x7FFFFFFF); entityData = SET_BIT_TO(entityData, 31, visibility == INTERSECTION_INSIDE); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowStaticChunkCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowStaticChunkCulling.comp index dcb1afe6..2ad053e4 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowStaticChunkCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowStaticChunkCulling.comp @@ -56,12 +56,6 @@ void main() { if (visibility == INTERSECTION_OUTSIDE) return; } - // 5. Occlusion Culling (Deferred for Point Lights / Atlas evaluation needed) - if (ctx.enableChunkOcclusionCulling == 1) { - float shadowScreenSizePixels = 0.0; - // Todo - } - // 6. Subgroup-optimized writes to the visible chunk list uint needsWrite = 1; uint subgroupWriteCount = subgroupAdd(needsWrite); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowStaticModelCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowStaticModelCulling.comp index 0f7d5a7d..bcdd9f49 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowStaticModelCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/PointLight/PointLightShadowStaticModelCulling.comp @@ -8,6 +8,7 @@ #include "../../../Includes/Common/FrameGlobalContext.glsl" #include "../../../Includes/Common/Camera.glsl" #include "../../../Includes/Common/Transform.glsl" +#include "../../../Includes/Common/Tag.glsl" #include "../../../Includes/Common/Model.glsl" #include "../../../Includes/Common/Mesh.glsl" #include "../../../Includes/Common/Material.glsl" @@ -59,14 +60,25 @@ void main() { for (uint i = gl_LocalInvocationID.x; i < chunk.entityCount; i += gl_WorkGroupSize.x) { uint denseIndex = chunk.firstEntityIndex + i; - TransformModelLink link = GET_TRANSFORM_MODEL_LINK(ctx.transformModelLinkBufferAddr, denseIndex); - + + TransformModelLink link = GET_TRANSFORM_MODEL_LINK(ctx.transformModelLinkBufferAddr, denseIndex); if (link.modelDenseIndex == INVALID_INDEX) continue; uint entityId = link.entityIndex; + uint tagSparseIndex = GET_SPARSE_INDEX(ctx.tagSparseMapBufferAddr, entityId); + if (tagSparseIndex == INVALID_INDEX) return; + + uint entityFlags = GET_TAG_DATA(ctx.tagDataBufferAddr, tagSparseIndex); + bool isActive = (entityFlags & (1u << 0)) != 0; + + if (!isActive) return; + TransformComponent transform = GET_TRANSFORM(ctx.transformBufferAddr, denseIndex); ModelComponent modelComp = GET_MODEL_COMP(ctx.modelBufferAddr, link.modelDenseIndex); + bool castShadow = (modelComp.flags & (1u << 0)) != 0; + if (modelComp.modelIndex == INVALID_INDEX || !castShadow) return; + ModelAllocationInfo mAlloc = GET_MODEL_ALLOC(ctx.globalModelAllocationBufferAddr, modelComp.modelIndex); GpuModelAddresses addrs = GET_MODEL_ADDRESSES(ctx.modelAddressBufferAddr, modelComp.modelIndex); @@ -101,11 +113,6 @@ void main() { float mainCamScreenSize = CalculateSphereScreenSizePerspective(worldCollider.center, worldCollider.radius, camera.view, camera.proj, cameraNear, screenRes); if (mainCamScreenSize < 1.0) continue; - if (ctx.enableModelOcclusionCulling == 1) { - float shadowScreenSizePixels = 0.0; - //Todo - } - // 7. Encode Payload for sort/draw phase uint entityData = (entityId & 0x7FFFFFFF); entityData = SET_BIT_TO(entityData, 31, visibility == INTERSECTION_INSIDE); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightCulling.comp index 467d7fcd..6ccb515a 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightCulling.comp @@ -9,6 +9,7 @@ #include "../../../Includes/Core.glsl" #include "../../../Includes/Common/FrameGlobalContext.glsl" +#include "../../../Includes/Common/Tag.glsl" #include "../../../Includes/Common/Camera.glsl" #include "../../../Includes/Common/SpotLight.glsl" #include "../../../Includes/Utils/CullingMath.glsl" @@ -33,6 +34,13 @@ void main() { SpotLightColliderGPU collider = GET_SPOT_LIGHT_COLLIDER(ctx.spotLightColliderBufferAddr, globalId); + uint tagSparseIndex = GET_SPARSE_INDEX(ctx.tagSparseMapBufferAddr, collider.entityIndex); + if (tagSparseIndex == INVALID_INDEX) return; + uint entityFlags = GET_TAG_DATA(ctx.tagDataBufferAddr, tagSparseIndex); + + bool isActive = (entityFlags & (1u << 0)) != 0; + if (!isActive) return; + uint cameraIdx = GET_SPARSE_INDEX(ctx.cameraSparseMapBufferAddr, ctx.mainCameraEntity); CameraComponent camera = GET_CAMERA(ctx.cameraBufferAddr, cameraIdx); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowMeshCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowMeshCulling.comp index 84eeb8b3..38ca1856 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowMeshCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowMeshCulling.comp @@ -119,14 +119,6 @@ void main() { float mainCamScreenSize = CalculateSphereScreenSizePerspective(worldCollider.center, worldCollider.radius, camera.view, camera.proj, cameraNear, screenRes); if (mainCamScreenSize < 1.0) continue; - // 10. Precise Occlusion Culling (HZB) - if (ctx.enableMeshOcclusionCulling == 1) { - float shadowScreenSizePixels = 0.0; - if (false && IsSphereOccludedAtlasPerspective(worldCollider.center, worldCollider.radius, shadowComp.view, shadowComp.proj, shadowComp.planes.x, shadowComp.planes.y, shadowComp.atlasRect, shadowDepthPyramid, float(ctx.spotLightShadowAtlasSize), ctx.spotLightShadowHizMipLevels, shadowScreenSizePixels)) { - continue; - } - } - uint rawLod = (mainCamScreenSize > 512.0) ? 0 : (mainCamScreenSize > 256.0) ? 1 : (mainCamScreenSize > 128.0) ? 2 : 3; uint lod = min(rawLod + ctx.spotLightShadowLodBias, 3u); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowModelCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowModelCulling.comp index 7bfad68c..e3138536 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowModelCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowModelCulling.comp @@ -8,6 +8,7 @@ #include "../../../Includes/Common/FrameGlobalContext.glsl" #include "../../../Includes/Common/Camera.glsl" #include "../../../Includes/Common/Transform.glsl" +#include "../../../Includes/Common/Tag.glsl" #include "../../../Includes/Common/Model.glsl" #include "../../../Includes/Common/Mesh.glsl" #include "../../../Includes/Common/Animation.glsl" @@ -45,10 +46,19 @@ void main() // 2. Resolve Entity and Model Data TransformModelLink link = GET_TRANSFORM_MODEL_LINK(ctx.transformModelLinkBufferAddr, transformDenseIndex); if (link.modelDenseIndex == INVALID_INDEX) return; - uint entityId = link.entityIndex; + + uint tagSparseIndex = GET_SPARSE_INDEX(ctx.tagSparseMapBufferAddr, entityId); + if (tagSparseIndex == INVALID_INDEX) return; + + uint entityFlags = GET_TAG_DATA(ctx.tagDataBufferAddr, tagSparseIndex); + bool isActive = (entityFlags & (1u << 0)) != 0; + if (!isActive) return; + ModelComponent modelComp = GET_MODEL_COMP(ctx.modelBufferAddr, link.modelDenseIndex); - if (modelComp.modelIndex == INVALID_INDEX) return; + bool castShadow = (modelComp.flags & (1u << 0)) != 0; + if (modelComp.modelIndex == INVALID_INDEX || !castShadow) return; + // 3. Resolve Transform, Camera & Colliders TransformComponent transform = GET_TRANSFORM(ctx.transformBufferAddr, transformDenseIndex); @@ -97,14 +107,6 @@ void main() if (mainCamScreenSize < 1.0) return; - // 7. Occlusion Culling (HZB) - if (ctx.enableModelOcclusionCulling == 1) { - float shadowScreenSizePixels = 0.0; - if (false && IsSphereOccludedAtlasPerspective(worldCollider.center, worldCollider.radius, shadowComp.view, shadowComp.proj, shadowComp.planes.x, shadowComp.planes.y, shadowComp.atlasRect, shadowDepthPyramid, float(ctx.spotLightShadowAtlasSize), ctx.spotLightShadowHizMipLevels, shadowScreenSizePixels)) { - return; - } - } - uint entityData = (entityId & 0x7FFFFFFF); entityData = SET_BIT_TO(entityData, 31, visibility == INTERSECTION_INSIDE); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowMortonChunkCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowMortonChunkCulling.comp index 5dcb0036..4cccfe8b 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowMortonChunkCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowMortonChunkCulling.comp @@ -60,14 +60,6 @@ void main() { if (visibility == INTERSECTION_OUTSIDE) return; } - // 5. Occlusion Culling using Spot Light HZB - if (ctx.enableChunkOcclusionCulling == 1) { - float shadowScreenSizePixels = 0.0; - if (false && IsSphereOccludedAtlasPerspective(sphereCenter, sphereRadius, shadowComp.view, shadowComp.proj, shadowComp.planes.x, shadowComp.planes.y, shadowComp.atlasRect, shadowDepthPyramid, float(ctx.spotLightShadowAtlasSize), ctx.spotLightShadowHizMipLevels, shadowScreenSizePixels)) { - return; - } - } - // 6. Subgroup-optimized writes to the visible Morton chunk list uint needsWrite = 1; uint subgroupWriteCount = subgroupAdd(needsWrite); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowMortonModelCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowMortonModelCulling.comp index 9337bd4f..8a7b1303 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowMortonModelCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowMortonModelCulling.comp @@ -8,6 +8,7 @@ #include "../../../Includes/Common/FrameGlobalContext.glsl" #include "../../../Includes/Common/Camera.glsl" #include "../../../Includes/Common/Transform.glsl" +#include "../../../Includes/Common/Tag.glsl" #include "../../../Includes/Common/Model.glsl" #include "../../../Includes/Common/Mesh.glsl" #include "../../../Includes/Common/Material.glsl" @@ -70,9 +71,20 @@ void main() { if (link.modelDenseIndex == INVALID_INDEX) continue; uint entityId = link.entityIndex; + uint tagSparseIndex = GET_SPARSE_INDEX(ctx.tagSparseMapBufferAddr, entityId); + if (tagSparseIndex == INVALID_INDEX) return; + + uint entityFlags = GET_TAG_DATA(ctx.tagDataBufferAddr, tagSparseIndex); + bool isActive = (entityFlags & (1u << 0)) != 0; + + if (!isActive) return; + TransformComponent transform = GET_TRANSFORM(ctx.transformBufferAddr, denseIndex); ModelComponent modelComp = GET_MODEL_COMP(ctx.modelBufferAddr, link.modelDenseIndex); + bool castShadow = (modelComp.flags & (1u << 0)) != 0; + if (modelComp.modelIndex == INVALID_INDEX || !castShadow) return; + ModelAllocationInfo mAlloc = GET_MODEL_ALLOC(ctx.globalModelAllocationBufferAddr, modelComp.modelIndex); GpuModelAddresses addrs = GET_MODEL_ADDRESSES(ctx.modelAddressBufferAddr, modelComp.modelIndex); @@ -107,14 +119,6 @@ void main() { float mainCamScreenSize = CalculateSphereScreenSizePerspective(worldCollider.center, worldCollider.radius, camera.view, camera.proj, cameraNear, screenRes); if (mainCamScreenSize < 1.0) continue; - // 7. Occlusion Culling using Spot Light HZB - if (ctx.enableModelOcclusionCulling == 1) { - float shadowScreenSizePixels = 0.0; - if (false && IsSphereOccludedAtlasPerspective(worldCollider.center, worldCollider.radius, shadowComp.view, shadowComp.proj, shadowComp.planes.x, shadowComp.planes.y, shadowComp.atlasRect, shadowDepthPyramid, float(ctx.spotLightShadowAtlasSize), ctx.spotLightShadowHizMipLevels, shadowScreenSizePixels)) { - continue; - } - } - // 8. Encode Payload for sort/draw phase uint entityData = (entityId & 0x7FFFFFFF); entityData = SET_BIT_TO(entityData, 31, visibility == INTERSECTION_INSIDE); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowStaticChunkCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowStaticChunkCulling.comp index c6134dbe..35605d86 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowStaticChunkCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowStaticChunkCulling.comp @@ -56,14 +56,6 @@ void main() { if (visibility == INTERSECTION_OUTSIDE) return; } - // 5. Occlusion Culling using Spot Light HZB - if (ctx.enableChunkOcclusionCulling == 1) { - float shadowScreenSizePixels = 0.0; - if (false && IsSphereOccludedAtlasPerspective(sphereCenter, sphereRadius, shadowComp.view, shadowComp.proj, shadowComp.planes.x, shadowComp.planes.y, shadowComp.atlasRect, shadowDepthPyramid, float(ctx.spotLightShadowAtlasSize), ctx.spotLightShadowHizMipLevels, shadowScreenSizePixels)) { - return; - } - } - // 6. Subgroup-optimized writes to the visible chunk list uint needsWrite = 1; uint subgroupWriteCount = subgroupAdd(needsWrite); diff --git a/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowStaticModelCulling.comp b/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowStaticModelCulling.comp index 9a49ddff..d16e615b 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowStaticModelCulling.comp +++ b/SynapseEngine/Engine/Shaders/Passes/Culling/SpotLight/SpotLightShadowStaticModelCulling.comp @@ -8,6 +8,7 @@ #include "../../../Includes/Common/FrameGlobalContext.glsl" #include "../../../Includes/Common/Camera.glsl" #include "../../../Includes/Common/Transform.glsl" +#include "../../../Includes/Common/Tag.glsl" #include "../../../Includes/Common/Model.glsl" #include "../../../Includes/Common/Mesh.glsl" #include "../../../Includes/Common/Material.glsl" @@ -62,13 +63,22 @@ void main() { { uint denseIndex = chunk.firstEntityIndex + i; TransformModelLink link = GET_TRANSFORM_MODEL_LINK(ctx.transformModelLinkBufferAddr, denseIndex); - if (link.modelDenseIndex == INVALID_INDEX) continue; uint entityId = link.entityIndex; + + uint tagSparseIndex = GET_SPARSE_INDEX(ctx.tagSparseMapBufferAddr, entityId); + if (tagSparseIndex == INVALID_INDEX) return; + + uint entityFlags = GET_TAG_DATA(ctx.tagDataBufferAddr, tagSparseIndex); + bool isActive = (entityFlags & (1u << 0)) != 0; + if (!isActive) return; TransformComponent transform = GET_TRANSFORM(ctx.transformBufferAddr, denseIndex); ModelComponent modelComp = GET_MODEL_COMP(ctx.modelBufferAddr, link.modelDenseIndex); + bool castShadow = (modelComp.flags & (1u << 0)) != 0; + if (modelComp.modelIndex == INVALID_INDEX || !castShadow) return; + ModelAllocationInfo mAlloc = GET_MODEL_ALLOC(ctx.globalModelAllocationBufferAddr, modelComp.modelIndex); GpuModelAddresses addrs = GET_MODEL_ADDRESSES(ctx.modelAddressBufferAddr, modelComp.modelIndex); @@ -102,14 +112,6 @@ void main() { float mainCamScreenSize = CalculateSphereScreenSizePerspective(worldCollider.center, worldCollider.radius, camera.view, camera.proj, cameraNear, screenRes); if (mainCamScreenSize < 1.0) continue; - // 7. Occlusion Culling using Spot Light HZB - if (ctx.enableModelOcclusionCulling == 1) { - float shadowScreenSizePixels = 0.0; - if (false && IsSphereOccludedAtlasPerspective(worldCollider.center, worldCollider.radius, shadowComp.view, shadowComp.proj, shadowComp.planes.x, shadowComp.planes.y, shadowComp.atlasRect, shadowDepthPyramid, float(ctx.spotLightShadowAtlasSize), ctx.spotLightShadowHizMipLevels, shadowScreenSizePixels)) { - continue; - } - } - // 8. Encode Payload for sort/draw phase uint entityData = (entityId & 0x7FFFFFFF); entityData = SET_BIT_TO(entityData, 31, visibility == INTERSECTION_INSIDE); diff --git a/SynapseEngine/Engine/Shaders/Passes/PostProcess/InfiniteGrid/InfiniteGrid.frag b/SynapseEngine/Engine/Shaders/Passes/PostProcess/InfiniteGrid/InfiniteGrid.frag new file mode 100644 index 00000000..c5b47514 --- /dev/null +++ b/SynapseEngine/Engine/Shaders/Passes/PostProcess/InfiniteGrid/InfiniteGrid.frag @@ -0,0 +1,147 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_buffer_reference2 : require +#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require + +#include "../../../Includes/Core.glsl" +#include "../../../Includes/Common/FrameGlobalContext.glsl" +#include "../../../Includes/Common/Camera.glsl" +#include "../../../Includes/PushConstants/InfiniteGridPC.glsl" + +layout(location = 0) in vec2 inUV; +layout(location = 0) out vec4 outColor; + +layout(push_constant) uniform PushConstants { + InfiniteGridPC pc; +}; + +struct IntersectionData { + float t; + vec3 worldPos; + vec4 color; + bool valid; +}; + +float ComputeGrid(vec2 coord, float scale, float thickness) { + vec2 scaledCoord = coord / scale; + vec2 derivative = fwidth(scaledCoord); + + vec2 grid = abs(fract(scaledCoord - 0.5) - 0.5) / (derivative * thickness); + float line = min(grid.x, grid.y); + return 1.0 - min(line, 1.0); +} + +void main() { + FrameGlobalContext ctx = GET_FRAME_CONTEXT(pc.frameGlobalContextBufferAddr); + uint cameraDenseIndex = GET_SPARSE_INDEX(ctx.cameraSparseMapBufferAddr, ctx.activeCameraEntity); + CameraComponent camera = GET_CAMERA(ctx.cameraBufferAddr, cameraDenseIndex); + + vec3 ndcPos = vec3(inUV * 2.0 - 1.0, 1.0); + vec3 ndcNear = vec3(ndcPos.xy, 0.000001); + + vec4 worldFar4 = camera.viewProjVulkanInv * vec4(ndcPos, 1.0); + vec4 worldNear4 = camera.viewProjVulkanInv * vec4(ndcNear, 1.0); + vec3 worldFar = worldFar4.xyz / worldFar4.w; + vec3 worldNear = worldNear4.xyz / worldNear4.w; + + vec3 rayDir = normalize(worldFar - worldNear); + vec3 rayOrigin = worldNear; + + IntersectionData hits[3]; + for(int i = 0; i < 3; ++i) hits[i].valid = false; + + if (rayDir.y != 0.0) { + float t = -rayOrigin.y / rayDir.y; + if (t > 0.0) { + hits[0].t = t; hits[0].worldPos = rayOrigin + rayDir * t; hits[0].valid = true; + vec2 coord = hits[0].worldPos.xz; vec4 c = vec4(0.0); + + if ((pc.planeFlags & 1) != 0) { + float grid1m = ComputeGrid(coord, pc.gridScale, pc.gridThickness); + float grid10m = ComputeGrid(coord, pc.gridScale * 10.0, pc.gridThickness * 1.5); + float lodFade = 1.0 - smoothstep(10.0, 50.0, distance(camera.eye.xyz, hits[0].worldPos)); + c = mix(pc.gridColor * vec4(1.0, 1.0, 1.0, 0.5) * grid1m * lodFade, pc.gridColor * grid10m, grid10m); + } + + vec2 derivative = fwidth(coord); + vec2 axisLines = abs(coord) / (derivative * pc.axisThickness); + if ((pc.axisFlags & 1) != 0) c = mix(c, pc.axisXColor, 1.0 - min(axisLines.y, 1.0)); + if ((pc.axisFlags & 4) != 0) c = mix(c, pc.axisZColor, 1.0 - min(axisLines.x, 1.0)); + + c.a *= (1.0 - smoothstep(pc.fadeDistance * 0.1, pc.fadeDistance, t)); + hits[0].color = c; + } + } + + if (rayDir.z != 0.0) { + float t = -rayOrigin.z / rayDir.z; + if (t > 0.0) { + hits[1].t = t; hits[1].worldPos = rayOrigin + rayDir * t; hits[1].valid = true; + vec2 coord = hits[1].worldPos.xy; vec4 c = vec4(0.0); + + if ((pc.planeFlags & 2) != 0) { + float grid1m = ComputeGrid(coord, pc.gridScale, pc.gridThickness); + float grid10m = ComputeGrid(coord, pc.gridScale * 10.0, pc.gridThickness * 1.5); + float lodFade = 1.0 - smoothstep(10.0, 50.0, distance(camera.eye.xyz, hits[1].worldPos)); + c = mix(pc.gridColor * vec4(1.0, 1.0, 1.0, 0.5) * grid1m * lodFade, pc.gridColor * grid10m, grid10m); + } + + vec2 derivative = fwidth(coord); + vec2 axisLines = abs(coord) / (derivative * pc.axisThickness); + if ((pc.axisFlags & 1) != 0) c = mix(c, pc.axisXColor, 1.0 - min(axisLines.y, 1.0)); + if ((pc.axisFlags & 2) != 0) c = mix(c, pc.axisYColor, 1.0 - min(axisLines.x, 1.0)); + + c.a *= (1.0 - smoothstep(pc.fadeDistance * 0.1, pc.fadeDistance, t)); + hits[1].color = c; + } + } + + if (rayDir.x != 0.0) { + float t = -rayOrigin.x / rayDir.x; + if (t > 0.0) { + hits[2].t = t; hits[2].worldPos = rayOrigin + rayDir * t; hits[2].valid = true; + vec2 coord = hits[2].worldPos.yz; vec4 c = vec4(0.0); + + if ((pc.planeFlags & 4) != 0) { + float grid1m = ComputeGrid(coord, pc.gridScale, pc.gridThickness); + float grid10m = ComputeGrid(coord, pc.gridScale * 10.0, pc.gridThickness * 1.5); + float lodFade = 1.0 - smoothstep(10.0, 50.0, distance(camera.eye.xyz, hits[2].worldPos)); + c = mix(pc.gridColor * vec4(1.0, 1.0, 1.0, 0.5) * grid1m * lodFade, pc.gridColor * grid10m, grid10m); + } + + vec2 derivative = fwidth(coord); + vec2 axisLines = abs(coord) / (derivative * pc.axisThickness); + if ((pc.axisFlags & 2) != 0) c = mix(c, pc.axisYColor, 1.0 - min(axisLines.y, 1.0)); + if ((pc.axisFlags & 4) != 0) c = mix(c, pc.axisZColor, 1.0 - min(axisLines.x, 1.0)); + + c.a *= (1.0 - smoothstep(pc.fadeDistance * 0.1, pc.fadeDistance, t)); + hits[2].color = c; + } + } + + int sortIdx[3] = {0, 1, 2}; + if ((hits[sortIdx[0]].valid ? hits[sortIdx[0]].t : -1.0) < (hits[sortIdx[1]].valid ? hits[sortIdx[1]].t : -1.0)) { int tmp = sortIdx[0]; sortIdx[0] = sortIdx[1]; sortIdx[1] = tmp; } + if ((hits[sortIdx[1]].valid ? hits[sortIdx[1]].t : -1.0) < (hits[sortIdx[2]].valid ? hits[sortIdx[2]].t : -1.0)) { int tmp = sortIdx[1]; sortIdx[1] = sortIdx[2]; sortIdx[2] = tmp; } + if ((hits[sortIdx[0]].valid ? hits[sortIdx[0]].t : -1.0) < (hits[sortIdx[1]].valid ? hits[sortIdx[1]].t : -1.0)) { int tmp = sortIdx[0]; sortIdx[0] = sortIdx[1]; sortIdx[1] = tmp; } + + vec4 accumulatedColor = vec4(0.0); + float closestDepth = 1.0; + bool hashit = false; + + for(int i = 0; i < 3; ++i) { + int idx = sortIdx[i]; + if (hits[idx].valid && hits[idx].color.a > 0.001) { + accumulatedColor.rgb = mix(accumulatedColor.rgb, hits[idx].color.rgb, hits[idx].color.a); + accumulatedColor.a = mix(accumulatedColor.a, 1.0, hits[idx].color.a); + + vec4 clipPos = camera.viewProjVulkan * vec4(hits[idx].worldPos, 1.0); + closestDepth = clipPos.z / clipPos.w; + hashit = true; + } + } + + if (!hashit || accumulatedColor.a < 0.01) discard; + + gl_FragDepth = closestDepth; + outColor = accumulatedColor; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Shaders/Passes/PostProcess/SkySphere/SkySphere.frag b/SynapseEngine/Engine/Shaders/Passes/PostProcess/SkySphere/SkySphere.frag new file mode 100644 index 00000000..4eb37b30 --- /dev/null +++ b/SynapseEngine/Engine/Shaders/Passes/PostProcess/SkySphere/SkySphere.frag @@ -0,0 +1,46 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_nonuniform_qualifier : require +#extension GL_EXT_buffer_reference2 : require +#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require + +#include "../../../Includes/Core.glsl" +#include "../../../Includes/Common/FrameGlobalContext.glsl" +#include "../../../Includes/Common/Camera.glsl" +#include "../../../Includes/Common/Texture.glsl" +#include "../../../Includes/Utils/EnvironmentMath.glsl" + +layout(location = 0) in vec2 inUV; +layout(location = 0) out vec4 outColor; + +#include "../../../Includes/PushConstants/SkySpherePC.glsl" + +layout(push_constant) uniform PushConstants { + SkySpherePC pc; +}; + +void main() { + FrameGlobalContext ctx = GET_FRAME_CONTEXT(pc.frameGlobalContextBufferAddr); + + uint cameraDenseIndex = GET_SPARSE_INDEX(ctx.cameraSparseMapBufferAddr, ctx.activeCameraEntity); + CameraComponent camera = GET_CAMERA(ctx.cameraBufferAddr, cameraDenseIndex); + + vec2 ndc = inUV * 2.0 - 1.0; + vec4 clipPos = vec4(ndc, 1.0, 1.0); + vec4 viewPos = camera.projVulkanInv * clipPos; + vec3 viewRay = (camera.viewInv * vec4(viewPos.xyz, 0.0)).xyz; + vec3 viewDir = normalize(viewRay); + + vec3 rotatedDir = (pc.skyRotationMatrix * vec4(viewDir, 0.0)).xyz; + rotatedDir = normalize(rotatedDir); + + vec2 finalUV = pc.mappingType == 0 ? SampleEquirectangular(rotatedDir) : SampleOctahedral(rotatedDir); + finalUV.y = 1.0 - finalUV.y; + + vec3 skyColor = SampleTexture2DLod(pc.skyTextureIndex, pc.samplerIndex, finalUV, 0.0).rgb; + skyColor *= pc.skyTint; + skyColor *= pc.skyIntensity; + skyColor *= exp2(pc.skyExposureEV); + + outColor = vec4(skyColor, 1.0); +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Shaders/Passes/PostProcess/SkySphere/SkySphere.vert b/SynapseEngine/Engine/Shaders/Passes/PostProcess/SkySphere/SkySphere.vert new file mode 100644 index 00000000..150889f6 --- /dev/null +++ b/SynapseEngine/Engine/Shaders/Passes/PostProcess/SkySphere/SkySphere.vert @@ -0,0 +1,8 @@ +#version 460 + +layout(location = 0) out vec2 outUV; + +void main() { + outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); + gl_Position = vec4(outUV * 2.0 - 1.0, 1.0, 1.0); +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Shaders/Passes/Ssao/DpHvo.comp b/SynapseEngine/Engine/Shaders/Passes/PostProcess/Ssao/DpHvo.comp similarity index 94% rename from SynapseEngine/Engine/Shaders/Passes/Ssao/DpHvo.comp rename to SynapseEngine/Engine/Shaders/Passes/PostProcess/Ssao/DpHvo.comp index 5ffd7e2c..4b42a2a9 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Ssao/DpHvo.comp +++ b/SynapseEngine/Engine/Shaders/Passes/PostProcess/Ssao/DpHvo.comp @@ -4,17 +4,17 @@ #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require #extension GL_KHR_shader_subgroup_quad : require -#include "../../Includes/Core.glsl" -#include "../../Includes/Common/FrameGlobalContext.glsl" -#include "../../Includes/Common/Camera.glsl" -#include "../../Includes/Utils/DepthMath.glsl" +#include "../../../Includes/Core.glsl" +#include "../../../Includes/Common/FrameGlobalContext.glsl" +#include "../../../Includes/Common/Camera.glsl" +#include "../../../Includes/Utils/DepthMath.glsl" layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; layout(set = 2, binding = 0) uniform sampler2D inHizPyramid; layout(set = 2, binding = 1, r16f) uniform writeonly image2D outAoImage; -#include "../../Includes/PushConstants/DpHvoPC.glsl" +#include "../../../Includes/PushConstants/DpHvoPC.glsl" layout(push_constant) uniform PushConstants { DpHvoPC pc; diff --git a/SynapseEngine/Engine/Shaders/Passes/Ssao/DpHvoBlur.comp b/SynapseEngine/Engine/Shaders/Passes/PostProcess/Ssao/DpHvoBlur.comp similarity index 91% rename from SynapseEngine/Engine/Shaders/Passes/Ssao/DpHvoBlur.comp rename to SynapseEngine/Engine/Shaders/Passes/PostProcess/Ssao/DpHvoBlur.comp index 4ab9011b..1ef713e2 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Ssao/DpHvoBlur.comp +++ b/SynapseEngine/Engine/Shaders/Passes/PostProcess/Ssao/DpHvoBlur.comp @@ -3,9 +3,9 @@ #extension GL_EXT_buffer_reference2 : require #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#include "../../Includes/Core.glsl" -#include "../../Includes/Common/FrameGlobalContext.glsl" -#include "../../Includes/Common/Camera.glsl" +#include "../../../Includes/Core.glsl" +#include "../../../Includes/Common/FrameGlobalContext.glsl" +#include "../../../Includes/Common/Camera.glsl" layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; @@ -13,7 +13,7 @@ layout(set = 2, binding = 0) uniform sampler2D inAoImage; layout(set = 2, binding = 1) uniform sampler2D inHizPyramid; layout(set = 2, binding = 2, r16f) uniform writeonly image2D outAoImage; -#include "../../Includes/PushConstants/DpHvoBlurPC.glsl" +#include "../../../Includes/PushConstants/DpHvoBlurPC.glsl" layout(push_constant) uniform PushConstants { DpHvoBlurPC pc; diff --git a/SynapseEngine/Engine/Shaders/Passes/Ssao/Ssao.comp b/SynapseEngine/Engine/Shaders/Passes/PostProcess/Ssao/Ssao.comp similarity index 89% rename from SynapseEngine/Engine/Shaders/Passes/Ssao/Ssao.comp rename to SynapseEngine/Engine/Shaders/Passes/PostProcess/Ssao/Ssao.comp index 2f584e01..06b64ea9 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Ssao/Ssao.comp +++ b/SynapseEngine/Engine/Shaders/Passes/PostProcess/Ssao/Ssao.comp @@ -4,11 +4,11 @@ #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require #extension GL_KHR_shader_subgroup_quad : require -#include "../../Includes/Core.glsl" -#include "../../Includes/Common/FrameGlobalContext.glsl" -#include "../../Includes/Common/Ssao.glsl" -#include "../../Includes/Common/Camera.glsl" -#include "../../Includes/Utils/DepthMath.glsl" +#include "../../../Includes/Core.glsl" +#include "../../../Includes/Common/FrameGlobalContext.glsl" +#include "../../../Includes/Common/Ssao.glsl" +#include "../../../Includes/Common/Camera.glsl" +#include "../../../Includes/Utils/DepthMath.glsl" layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; @@ -16,7 +16,7 @@ layout(set = 2, binding = 0) uniform sampler2D inHizPyramid; layout(set = 2, binding = 1) uniform sampler2D inNoiseTexture; layout(set = 2, binding = 2, r16f) uniform writeonly image2D outAoImage; -#include "../../Includes/PushConstants/SsaoPC.glsl" +#include "../../../Includes/PushConstants/SsaoPC.glsl" layout(push_constant) uniform PushConstants { SsaoPC pc; @@ -46,8 +46,8 @@ void main() { vec2 offsetV = vec2(0.0, 1.0 / float(ctx.screenHeight)); // Reconstruct view-space normal from depth gradients - vec3 viewPosRight = GetViewPosFromLinearZ(uv + offsetU, textureOffset(inHizPyramid, uv, ivec2(1, 0)).x, camera); - vec3 viewPosDown = GetViewPosFromLinearZ(uv + offsetV, textureOffset(inHizPyramid, uv, ivec2(0, 1)).x, camera); + vec3 viewPosRight = GetViewPosFromLinearZ(uv + offsetU, textureLodOffset(inHizPyramid, uv, 0.0, ivec2(1, 0)).x, camera); + vec3 viewPosDown = GetViewPosFromLinearZ(uv + offsetV, textureLodOffset(inHizPyramid, uv, 0.0, ivec2(0, 1)).x, camera); vec3 viewNormal = normalize(cross(viewPosRight - viewPos, viewPos - viewPosDown)); vec2 noiseScale = vec2(ctx.screenWidth / pc.noiseTextureWidth, ctx.screenHeight / pc.noiseTextureHeight); diff --git a/SynapseEngine/Engine/Shaders/Passes/Ssao/SsaoBlur.comp b/SynapseEngine/Engine/Shaders/Passes/PostProcess/Ssao/SsaoBlur.comp similarity index 87% rename from SynapseEngine/Engine/Shaders/Passes/Ssao/SsaoBlur.comp rename to SynapseEngine/Engine/Shaders/Passes/PostProcess/Ssao/SsaoBlur.comp index 5fde550f..ac9682d9 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Ssao/SsaoBlur.comp +++ b/SynapseEngine/Engine/Shaders/Passes/PostProcess/Ssao/SsaoBlur.comp @@ -3,15 +3,15 @@ #extension GL_EXT_buffer_reference2 : require #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require -#include "../../Includes/Core.glsl" -#include "../../Includes/Common/FrameGlobalContext.glsl" +#include "../../../Includes/Core.glsl" +#include "../../../Includes/Common/FrameGlobalContext.glsl" layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; layout(set = 2, binding = 0) uniform sampler2D inAoImage; layout(set = 2, binding = 1, r16f) uniform writeonly image2D outAoImage; -#include "../../Includes/PushConstants/SsaoBlurPC.glsl" +#include "../../../Includes/PushConstants/SsaoBlurPC.glsl" layout(push_constant) uniform PushConstants { SsaoBlurPC pc; diff --git a/SynapseEngine/Engine/Shaders/Passes/Preview/MaterialPreview.frag b/SynapseEngine/Engine/Shaders/Passes/Preview/MaterialPreview.frag new file mode 100644 index 00000000..f8758ba7 --- /dev/null +++ b/SynapseEngine/Engine/Shaders/Passes/Preview/MaterialPreview.frag @@ -0,0 +1,98 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_nonuniform_qualifier : require +#extension GL_EXT_buffer_reference2 : require +#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require + +#include "../../Includes/Core.glsl" +#include "../../Includes/Common/FrameGlobalContext.glsl" +#include "../../Includes/Common/Material.glsl" +#include "../../Includes/Common/Texture.glsl" +#include "../../Includes/Utils/MaterialMath.glsl" +#include "../../Includes/Utils/PbrMath.glsl" +#include "../../Includes/Utils/LightMath.glsl" + +layout(location = 0) in vec2 inUV; +layout(location = 0) out vec4 outColor; + +#include "../../Includes/PushConstants/MaterialPreviewPC.glsl" + +layout(push_constant) uniform PushConstants { + MaterialPreviewPC pc; +}; + +void main() { + vec2 checkerUV = inUV * 10.0; + float checker = mod(floor(checkerUV.x) + floor(checkerUV.y), 2.0); + vec3 bgColor = mix(vec3(0.15), vec3(0.25), checker); + + vec2 p = inUV * 2.0 - 1.0; + float r2 = dot(p, p); + + if (r2 > 0.85) { + outColor = vec4(bgColor, 1.0); + return; + } + + float z = sqrt(1.0 - r2); + vec3 localNormal = vec3(p.x, -p.y, z); + + vec2 sphereUV = vec2( + atan(localNormal.x, localNormal.z) / (2.0 * PI) + 0.5, + asin(localNormal.y) / PI + 0.5 + ); + + vec3 t = cross(vec3(0.0, 1.0, 0.0), localNormal); + vec3 tangent = (dot(t, t) < 1e-6) ? vec3(1.0, 0.0, 0.0) : normalize(t); + vec4 inTangent = vec4(tangent, 1.0); + + float radius = 1.0; + vec3 inWorldPos = localNormal * radius; + vec3 viewDir = vec3(0.0, 0.0, 1.0); + + FrameGlobalContext ctx = GET_FRAME_CONTEXT(pc.frameGlobalContextBufferAddr); + Material mat = GET_MATERIAL(ctx.materialBufferAddr, pc.materialId); + + vec4 albedoAlpha = EvaluateAlbedoAlpha(ctx.textureMetadataBufferAddr, mat, sphereUV); + + if (albedoAlpha.a < ctx.alphaLimitDiscard) { + discard; + } + + vec3 finalNormal = EvaluateNormal(ctx.textureMetadataBufferAddr, mat, sphereUV, localNormal, inTangent); + vec2 metalRough = EvaluateMetallicRoughness(ctx.textureMetadataBufferAddr, mat, sphereUV); + vec3 emissive = EvaluateEmissive(ctx.textureMetadataBufferAddr, mat, sphereUV); + float ao = EvaluateAO(ctx.textureMetadataBufferAddr, mat, sphereUV); + + float finalMetalness = clamp(metalRough.x, 0.0, 1.0); + float finalRoughness = clamp(metalRough.y, 0.04, 1.0); + + vec3 totalRadiance = vec3(0.0); + + // Key Light + vec3 keyLightDir = normalize(vec3(1.0, 1.0, 1.0)); + vec3 keyLightColor = vec3(1.0, 1.0, 1.0); + float keyLightStrength = 2.5; + totalRadiance += ShadePhysicallyBased( + albedoAlpha.rgb, finalNormal, viewDir, keyLightDir, + finalRoughness, finalMetalness, keyLightColor, 1.0, keyLightStrength + ); + + // Fill Light + vec3 fillLightDir = normalize(vec3(-1.0, 0.2, -0.5)); + vec3 fillLightColor = vec3(0.5, 0.6, 0.8); + float fillLightStrength = 1.0; + totalRadiance += ShadePhysicallyBased( + albedoAlpha.rgb, finalNormal, viewDir, fillLightDir, + finalRoughness, finalMetalness, fillLightColor, 1.0, fillLightStrength + ); + + // Ambient & Bloom + totalRadiance += SimulateAmbientLight(albedoAlpha.rgb, ao, ctx.ambientStrength); + totalRadiance += SimulateBloom(emissive, 1.0, ctx.emissiveStrength); + + + + vec3 finalColor = mix(bgColor, totalRadiance, IS_TRANSPARENT(mat) ? albedoAlpha.a : 1.0); + outColor = vec4(finalColor, 1.0); +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Shaders/Passes/Preview/MaterialPreview.vert b/SynapseEngine/Engine/Shaders/Passes/Preview/MaterialPreview.vert new file mode 100644 index 00000000..631b4afc --- /dev/null +++ b/SynapseEngine/Engine/Shaders/Passes/Preview/MaterialPreview.vert @@ -0,0 +1,8 @@ +#version 460 + +layout(location = 0) out vec2 outUV; + +void main() { + outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); + gl_Position = vec4(outUV * 2.0f - 1.0f, 0.0f, 1.0f); +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Shaders/Passes/Preview/ModelPreview.frag b/SynapseEngine/Engine/Shaders/Passes/Preview/ModelPreview.frag new file mode 100644 index 00000000..3d40428a --- /dev/null +++ b/SynapseEngine/Engine/Shaders/Passes/Preview/ModelPreview.frag @@ -0,0 +1,74 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_nonuniform_qualifier : require +#extension GL_EXT_buffer_reference2 : require +#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require + +#include "../../Includes/Core.glsl" +#include "../../Includes/Common/FrameGlobalContext.glsl" +#include "../../Includes/Common/Material.glsl" +#include "../../Includes/Common/Texture.glsl" +#include "../../Includes/Utils/MaterialMath.glsl" +#include "../../Includes/Utils/PbrMath.glsl" +#include "../../Includes/Utils/LightMath.glsl" + +layout(location = 0) in vec3 inNormal; +layout(location = 1) in vec4 inTangent; +layout(location = 2) in vec2 inUV; +layout(location = 3) in flat uint inMaterialId; + +layout(location = 0) out vec4 outColor; + +#include "../../Includes/PushConstants/ModelPreviewPC.glsl" + +layout(push_constant) uniform PushConstants { + ModelPreviewPC pc; +}; + +void main() { + FrameGlobalContext ctx = GET_FRAME_CONTEXT(pc.frameGlobalContextBufferAddr); + Material mat = GET_MATERIAL(ctx.materialBufferAddr, inMaterialId); + + vec4 albedoAlpha = EvaluateAlbedoAlpha(ctx.textureMetadataBufferAddr, mat, inUV); + if (albedoAlpha.a < ctx.alphaLimitDiscard) { + discard; + } + + vec3 finalNormal = EvaluateNormal(ctx.textureMetadataBufferAddr, mat, inUV, inNormal, inTangent); + vec2 metalRough = EvaluateMetallicRoughness(ctx.textureMetadataBufferAddr, mat, inUV); + vec3 emissive = EvaluateEmissive(ctx.textureMetadataBufferAddr, mat, inUV); + float ao = EvaluateAO(ctx.textureMetadataBufferAddr, mat, inUV); + + float finalMetalness = clamp(metalRough.x, 0.0, 1.0); + float finalRoughness = clamp(metalRough.y, 0.04, 1.0); + + vec3 viewDir = vec3(0.0, 0.0, 1.0); + vec3 totalRadiance = vec3(0.0); + + // Key Light + vec3 keyLightDir = normalize(vec3(1.0, 1.0, 1.0)); + vec3 keyLightColor = vec3(1.0, 1.0, 1.0); + float keyLightStrength = 2.5; + totalRadiance += ShadePhysicallyBased( + albedoAlpha.rgb, finalNormal, viewDir, keyLightDir, + finalRoughness, finalMetalness, keyLightColor, 1.0, keyLightStrength + ); + + // Fill Light + vec3 fillLightDir = normalize(vec3(-1.0, 0.2, -0.5)); + vec3 fillLightColor = vec3(0.5, 0.6, 0.8); + float fillLightStrength = 1.0; + totalRadiance += ShadePhysicallyBased( + albedoAlpha.rgb, finalNormal, viewDir, fillLightDir, + finalRoughness, finalMetalness, fillLightColor, 1.0, fillLightStrength + ); + + // Ambient és Bloom + totalRadiance += SimulateAmbientLight(albedoAlpha.rgb, ao, ctx.ambientStrength); + totalRadiance += SimulateBloom(emissive, 1.0, ctx.emissiveStrength); + + vec3 bgColor = vec3(0.15); + vec3 finalColor = mix(bgColor, totalRadiance, IS_TRANSPARENT(mat) ? albedoAlpha.a : 1.0); + + outColor = vec4(finalColor, 1.0); +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Shaders/Passes/Preview/ModelPreview.vert b/SynapseEngine/Engine/Shaders/Passes/Preview/ModelPreview.vert new file mode 100644 index 00000000..886a922a --- /dev/null +++ b/SynapseEngine/Engine/Shaders/Passes/Preview/ModelPreview.vert @@ -0,0 +1,45 @@ +#version 460 +#extension GL_GOOGLE_include_directive : require +#extension GL_EXT_nonuniform_qualifier : require +#extension GL_EXT_buffer_reference2 : require +#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require + +#include "../../Includes/Core.glsl" +#include "../../Includes/Common/FrameGlobalContext.glsl" +#include "../../Includes/Common/Mesh.glsl" +#include "../../Includes/Common/Model.glsl" +#include "../../Includes/Common/Transform.glsl" + +layout(location = 0) out vec3 outNormal; +layout(location = 1) out vec4 outTangent; +layout(location = 2) out vec2 outUV; +layout(location = 3) out flat uint outMaterialId; + +#include "../../Includes/PushConstants/ModelPreviewPC.glsl" + +layout(push_constant) uniform PushConstants { + ModelPreviewPC pc; +}; + +void main() { + FrameGlobalContext ctx = GET_FRAME_CONTEXT(pc.frameGlobalContextBufferAddr); + GpuModelAddresses addrs = GET_MODEL_ADDRESSES(ctx.modelAddressBufferAddr, pc.modelId); + + uint realVertexIndex = GET_INDEX(addrs.indices, gl_VertexIndex); + GpuVertexPosition v = GET_VERTEX_POS(addrs.vertexPositions, realVertexIndex); + GpuVertexAttributes attr = GET_VERTEX_ATTR(addrs.vertexAttributes, realVertexIndex); + + uint nodeIndex = UNPACK_UINT16_X(v.packedIndex); + uint meshIndex = UNPACK_UINT16_Y(v.packedIndex); + + GpuNodeTransform staticNodeTransform = GET_NODE_TRANSFORM(addrs.nodeTransforms, nodeIndex); + mat4 finalModelMat = staticNodeTransform.globalTransform; + mat4 finalModelMatIT = staticNodeTransform.globalTransformIT; + + gl_Position = pc.mvp * finalModelMat * vec4(v.position, 1.0); + + outNormal = (finalModelMatIT * vec4(attr.normal, 0.0)).xyz; + outTangent = vec4((finalModelMat * vec4(attr.tangent, 0.0)).xyz, 1.0); + outUV = vec2(attr.uv_x, 1.0 - attr.uv_y); + outMaterialId = GET_DEFUALT_MATERIAL_INDEX(addrs.meshMaterialIndices, pc.meshIndex); +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Shaders/Passes/Shading/Common/Meshlet.mesh b/SynapseEngine/Engine/Shaders/Passes/Shading/Common/Meshlet.mesh index f52c05d3..0674f605 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Shading/Common/Meshlet.mesh +++ b/SynapseEngine/Engine/Shaders/Passes/Shading/Common/Meshlet.mesh @@ -103,13 +103,13 @@ void main() { // Material Resolution uint meshIndex = UNPACK_UINT16_Y(v.packedIndex); - ModelComponent modelComp = GET_MODEL_COMP(ctx.modelBufferAddr, GET_SPARSE_INDEX(ctx.modelSparseMapBufferAddr, entityId)); - uint materialId = GET_MATERIAL_INDEX(ctx.materialLookupBufferAddr, modelComp.materialOffset + meshIndex); + uint materialOffset = GET_MODEL_COMP(ctx.modelBufferAddr, payload.modelDenseIndex).materialOffset; + uint materialId = GET_MATERIAL_INDEX(ctx.materialLookupBufferAddr, materialOffset + meshIndex); // Final Transform and Output gl_MeshVerticesEXT[i].gl_Position = camera.viewProjVulkan * transform.transform * finalMat * vec4(v.position, 1.0); outNormal[i] = (transform.transformIT * finalMatIT * vec4(attr.normal, 0.0)).xyz; - outTangent[i] = vec4((transform.transform * finalMat * vec4(attr.tangent, 0.0)).xyz, 1.0); //Todo + outTangent[i] = vec4((transform.transform * finalMat * vec4(attr.tangent, 0.0)).xyz, 1.0); outUV[i] = vec2(attr.uv_x, 1.0 - attr.uv_y); uint packedEntity = PACK_VISIBILITY_ENTITY(entityId, VIS_PIPELINE_MESH_SHADER); diff --git a/SynapseEngine/Engine/Shaders/Passes/Shading/Common/Meshlet.task b/SynapseEngine/Engine/Shaders/Passes/Shading/Common/Meshlet.task index f9a39cfb..e3c5553c 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Shading/Common/Meshlet.task +++ b/SynapseEngine/Engine/Shaders/Passes/Shading/Common/Meshlet.task @@ -43,6 +43,7 @@ void main() { uint transformDenseIndex = GET_SPARSE_INDEX(ctx.transformSparseMapBufferAddr, entityId); uint mainCameraDenseIndex = GET_SPARSE_INDEX(ctx.cameraSparseMapBufferAddr, ctx.mainCameraEntity); uint activeCameraDenseIndex = GET_SPARSE_INDEX(ctx.cameraSparseMapBufferAddr, ctx.activeCameraEntity); + uint modelDenseIndex = GET_SPARSE_INDEX(ctx.modelSparseMapBufferAddr, entityId); // 1. Initialize shared memory and payload if (threadIdx == 0) { @@ -51,6 +52,7 @@ void main() { payload.entityId = entityId; payload.transformDenseIdx = transformDenseIndex; payload.activeCameraDenseIdx = activeCameraDenseIndex; + payload.modelDenseIndex = modelDenseIndex; } barrier(); @@ -67,7 +69,7 @@ void main() { uint currentMeshletIdx = meshletGroupOffset + threadIdx; bool isVisible = (currentMeshletIdx < submeshData.meshletCount); - if (transformDenseIndex == INVALID_INDEX || mainCameraDenseIndex == INVALID_INDEX) { + if (transformDenseIndex == INVALID_INDEX || mainCameraDenseIndex == INVALID_INDEX || modelDenseIndex == INVALID_INDEX) { isVisible = false; } diff --git a/SynapseEngine/Engine/Shaders/Passes/Shading/Common/Traditional.vert b/SynapseEngine/Engine/Shaders/Passes/Shading/Common/Traditional.vert index 0b64e33c..2e7b3834 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Shading/Common/Traditional.vert +++ b/SynapseEngine/Engine/Shaders/Passes/Shading/Common/Traditional.vert @@ -35,6 +35,15 @@ void main() { // 3. Fetch Model Component & Material Lookup uint modelDenseIndex = GET_SPARSE_INDEX(ctx.modelSparseMapBufferAddr, entityId); + uint transformDenseIndex = GET_SPARSE_INDEX(ctx.transformSparseMapBufferAddr, entityId); + + if (transformDenseIndex == INVALID_INDEX || modelDenseIndex == INVALID_INDEX) { + gl_Position = vec4(0.0, 0.0, 0.0, 0.0); + outUV = vec2(0.0); + outId = uvec3(0u); + return; + } + ModelComponent comp = GET_MODEL_COMP(ctx.modelBufferAddr, modelDenseIndex); // 4. Fetch Model Addresses & Raw Vertex Data @@ -45,7 +54,6 @@ void main() { GpuVertexAttributes attr = GET_VERTEX_ATTR(addrs.vertexAttributes, realVertexIndex); // 5. Fetch Transform and Camera - uint transformDenseIndex = GET_SPARSE_INDEX(ctx.transformSparseMapBufferAddr, entityId); TransformComponent transform = GET_TRANSFORM(ctx.transformBufferAddr, transformDenseIndex); uint cameraDenseIndex = GET_SPARSE_INDEX(ctx.cameraSparseMapBufferAddr, ctx.activeCameraEntity); @@ -108,7 +116,7 @@ void main() { gl_Position = camera.viewProjVulkan * transform.transform * finalModelMat * vec4(v.position, 1.0); outNormal = (transform.transformIT * finalModelMatIT * vec4(attr.normal, 0.0)).xyz; - outTangent = vec4((transform.transform * finalModelMat * vec4(attr.tangent, 0.0)).xyz, 1.0); // Todo: Invert Normal from model! + outTangent = vec4((transform.transform * finalModelMat * vec4(attr.tangent, 0.0)).xyz, 1.0); outUV = vec2(attr.uv_x, 1.0 - attr.uv_y); uint packedEntity = PACK_VISIBILITY_ENTITY(entityId, VIS_PIPELINE_TRADITIONAL); diff --git a/SynapseEngine/Engine/Shaders/Passes/Shading/Deferred/GBuffer/OpaqueDeferred.frag b/SynapseEngine/Engine/Shaders/Passes/Shading/Deferred/GBuffer/OpaqueDeferred.frag index 3d930dd6..ab192f3b 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Shading/Deferred/GBuffer/OpaqueDeferred.frag +++ b/SynapseEngine/Engine/Shaders/Passes/Shading/Deferred/GBuffer/OpaqueDeferred.frag @@ -42,24 +42,24 @@ void main() { vec2 finalUV = inUV * mat.uvScale; // 2. Evaluate Albedo & Alpha - vec4 albedoAlpha = EvaluateAlbedoAlpha(mat, finalUV); + vec4 albedoAlpha = EvaluateAlbedoAlpha(ctx.textureMetadataBufferAddr, mat, finalUV); if (albedoAlpha.a < ctx.alphaLimitDiscard) { discard; } // 3. Evaluate Normals & TBN - vec3 finalNormal = EvaluateNormal(mat, finalUV, inNormal, inTangent); + vec3 finalNormal = EvaluateNormal(ctx.textureMetadataBufferAddr, mat, finalUV, inNormal, inTangent); // 4. Evaluate Metalness & Roughness - vec2 metalRough = EvaluateMetallicRoughness(mat, finalUV); + vec2 metalRough = EvaluateMetallicRoughness(ctx.textureMetadataBufferAddr, mat, finalUV); float finalMetalness = metalRough.x; float finalRoughness = clamp(metalRough.y, 0.04, 1.0); // 5. Evaluate Emissive - vec3 finalEmissive = EvaluateEmissive(mat, finalUV); + vec3 finalEmissive = EvaluateEmissive(ctx.textureMetadataBufferAddr, mat, finalUV); // 6. Evaluate Ambient Occlusion - float finalAo = EvaluateAO(mat, finalUV); + float finalAo = EvaluateAO(ctx.textureMetadataBufferAddr, mat, finalUV); // 7. Write Standard Outputs outColorMetallic = vec4(albedoAlpha.rgb, finalMetalness); diff --git a/SynapseEngine/Engine/Shaders/Passes/Shading/ForwardPlus/DepthPrepass/MeshletPreDepth.mesh b/SynapseEngine/Engine/Shaders/Passes/Shading/ForwardPlus/DepthPrepass/MeshletPreDepth.mesh index 6d266f30..1d9e3478 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Shading/ForwardPlus/DepthPrepass/MeshletPreDepth.mesh +++ b/SynapseEngine/Engine/Shaders/Passes/Shading/ForwardPlus/DepthPrepass/MeshletPreDepth.mesh @@ -100,8 +100,8 @@ void main() { // Material Resolution uint meshIndex = UNPACK_UINT16_Y(v.packedIndex); - ModelComponent modelComp = GET_MODEL_COMP(ctx.modelBufferAddr, GET_SPARSE_INDEX(ctx.modelSparseMapBufferAddr, entityId)); - uint materialId = GET_MATERIAL_INDEX(ctx.materialLookupBufferAddr, modelComp.materialOffset + meshIndex); + uint materialOffset = GET_MODEL_COMP(ctx.modelBufferAddr, payload.modelDenseIndex).materialOffset; + uint materialId = GET_MATERIAL_INDEX(ctx.materialLookupBufferAddr, materialOffset + meshIndex); // Final Transform and Output gl_MeshVerticesEXT[i].gl_Position = camera.viewProjVulkan * transform.transform * finalMat * vec4(v.position, 1.0); diff --git a/SynapseEngine/Engine/Shaders/Passes/Shading/ForwardPlus/DepthPrepass/PreDepth.frag b/SynapseEngine/Engine/Shaders/Passes/Shading/ForwardPlus/DepthPrepass/PreDepth.frag index 48d61fa2..4d9ad8b1 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Shading/ForwardPlus/DepthPrepass/PreDepth.frag +++ b/SynapseEngine/Engine/Shaders/Passes/Shading/ForwardPlus/DepthPrepass/PreDepth.frag @@ -31,13 +31,14 @@ void main() { uint finalPayload = pipelineFlag == VIS_PIPELINE_MESH_SHADER ? FINALIZE_VIS_MS(partial, gl_PrimitiveID) : FINALIZE_VIS_TRADITIONAL(partial, gl_PrimitiveID); - + // 1. Fetch Material Material mat = GET_MATERIAL(ctx.materialBufferAddr, materialId); vec2 finalUV = inUV * mat.uvScale; // 2. Evaluate Albedo & Alpha - vec4 albedoAlpha = EvaluateAlbedoAlpha(mat, finalUV); + vec4 albedoAlpha = EvaluateAlbedoAlpha(ctx.textureMetadataBufferAddr, mat, finalUV); + if (albedoAlpha.a < ctx.alphaLimitDiscard) { discard; } diff --git a/SynapseEngine/Engine/Shaders/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalPreDepth.vert b/SynapseEngine/Engine/Shaders/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalPreDepth.vert index 53975616..7a881114 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalPreDepth.vert +++ b/SynapseEngine/Engine/Shaders/Passes/Shading/ForwardPlus/DepthPrepass/TraditionalPreDepth.vert @@ -33,6 +33,8 @@ void main() { // 3. Fetch Model Component & Material Lookup uint modelDenseIndex = GET_SPARSE_INDEX(ctx.modelSparseMapBufferAddr, entityId); + uint transformDenseIndex = GET_SPARSE_INDEX(ctx.transformSparseMapBufferAddr, entityId); + ModelComponent comp = GET_MODEL_COMP(ctx.modelBufferAddr, modelDenseIndex); // 4. Fetch Model Addresses & Raw Vertex Data @@ -43,7 +45,6 @@ void main() { GpuVertexAttributes attr = GET_VERTEX_ATTR(addrs.vertexAttributes, realVertexIndex); // 5. Fetch Transform and Camera - uint transformDenseIndex = GET_SPARSE_INDEX(ctx.transformSparseMapBufferAddr, entityId); TransformComponent transform = GET_TRANSFORM(ctx.transformBufferAddr, transformDenseIndex); uint cameraDenseIndex = GET_SPARSE_INDEX(ctx.cameraSparseMapBufferAddr, ctx.activeCameraEntity); diff --git a/SynapseEngine/Engine/Shaders/Passes/Shading/ForwardPlus/Lighting/OpaqueForward.frag b/SynapseEngine/Engine/Shaders/Passes/Shading/ForwardPlus/Lighting/OpaqueForward.frag index 141880f7..5cffc709 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Shading/ForwardPlus/Lighting/OpaqueForward.frag +++ b/SynapseEngine/Engine/Shaders/Passes/Shading/ForwardPlus/Lighting/OpaqueForward.frag @@ -49,21 +49,21 @@ void main() { vec2 finalUV = inUV * mat.uvScale; // 2. Evaluate Albedo & Alpha - vec4 albedoAlpha = EvaluateAlbedoAlpha(mat, finalUV); + vec4 albedoAlpha = EvaluateAlbedoAlpha(ctx.textureMetadataBufferAddr, mat, finalUV); if (albedoAlpha.a < ctx.alphaLimitDiscard) { discard; } // 3. Evaluate Normals & TBN - vec3 finalNormal = EvaluateNormal(mat, finalUV, inNormal, inTangent); + vec3 finalNormal = EvaluateNormal(ctx.textureMetadataBufferAddr, mat, finalUV, inNormal, inTangent); // 4. Evaluate Metalness & Roughness - vec2 metalRough = EvaluateMetallicRoughness(mat, finalUV); + vec2 metalRough = EvaluateMetallicRoughness(ctx.textureMetadataBufferAddr, mat, finalUV); float finalMetalness = metalRough.x; float finalRoughness = clamp(metalRough.y, 0.04, 1.0); // 5. Evaluate Emissive - vec3 finalEmissive = EvaluateEmissive(mat, finalUV); + vec3 finalEmissive = EvaluateEmissive(ctx.textureMetadataBufferAddr, mat, finalUV); uint cameraDenseIndex = GET_SPARSE_INDEX(ctx.cameraSparseMapBufferAddr, ctx.activeCameraEntity); @@ -79,7 +79,7 @@ void main() { ssao = texture(ssaoTexture, screenUV).r; } - float finalAo = EvaluateAO(mat, finalUV); + float finalAo = EvaluateAO(ctx.textureMetadataBufferAddr, mat, finalUV); if (ctx.enableSsao == 1) { finalAo *= ssao; } diff --git a/SynapseEngine/Engine/Shaders/Passes/Shading/Wboit/TransparentForward.frag b/SynapseEngine/Engine/Shaders/Passes/Shading/Wboit/TransparentForward.frag index 0bdf5fd5..4aadb893 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Shading/Wboit/TransparentForward.frag +++ b/SynapseEngine/Engine/Shaders/Passes/Shading/Wboit/TransparentForward.frag @@ -44,24 +44,24 @@ void main() vec2 finalUV = inUV * mat.uvScale; // 2. Evaluate Albedo & Alpha - vec4 albedoAlpha = EvaluateAlbedoAlpha(mat, finalUV); + vec4 albedoAlpha = EvaluateAlbedoAlpha(ctx.textureMetadataBufferAddr, mat, finalUV); if (albedoAlpha.a < ctx.alphaLimitDiscard) { discard; } // 3. Evaluate Normals & TBN - vec3 finalNormal = EvaluateNormal(mat, finalUV, inNormal, inTangent); + vec3 finalNormal = EvaluateNormal(ctx.textureMetadataBufferAddr, mat, finalUV, inNormal, inTangent); // 4. Evaluate Metalness & Roughness - vec2 metalRough = EvaluateMetallicRoughness(mat, finalUV); + vec2 metalRough = EvaluateMetallicRoughness(ctx.textureMetadataBufferAddr, mat, finalUV); float finalMetalness = metalRough.x; float finalRoughness = clamp(metalRough.y, 0.04, 1.0); // 5. Evaluate Emissive - vec3 finalEmissive = EvaluateEmissive(mat, finalUV); + vec3 finalEmissive = EvaluateEmissive(ctx.textureMetadataBufferAddr, mat, finalUV); // 6. Evaluate Ambient Occlusion - float finalAo = EvaluateAO(mat, finalUV); + float finalAo = EvaluateAO(ctx.textureMetadataBufferAddr, mat, finalUV); uint cameraDenseIndex = GET_SPARSE_INDEX(ctx.cameraSparseMapBufferAddr, ctx.activeCameraEntity); CameraComponent camera = GET_CAMERA(ctx.cameraBufferAddr, cameraDenseIndex); diff --git a/SynapseEngine/Engine/Shaders/Passes/Shadow/DirectionLight/DirectionLightShadowMeshlet.task b/SynapseEngine/Engine/Shaders/Passes/Shadow/DirectionLight/DirectionLightShadowMeshlet.task index cf91845d..0b634460 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Shadow/DirectionLight/DirectionLightShadowMeshlet.task +++ b/SynapseEngine/Engine/Shaders/Passes/Shadow/DirectionLight/DirectionLightShadowMeshlet.task @@ -49,6 +49,7 @@ void main() { uint lightEntity = GET_DIRECTION_VISIBLE_SHADOW_LIGHT(ctx.directionLightVisibleShadowIndexBufferAddr, lightIdx); uint lightShadowDenseIdx = GET_SPARSE_INDEX(ctx.directionLightShadowSparseMapBufferAddr, lightEntity); uint lightDenseIdx = GET_SPARSE_INDEX(ctx.directionLightSparseMapBufferAddr, lightEntity); + uint modelDenseIndex = GET_SPARSE_INDEX(ctx.modelSparseMapBufferAddr, entityId); // 2. Initialize payload and shared memory if (threadIdx == 0) { @@ -58,6 +59,7 @@ void main() { payload.transformDenseIdx = transformDenseIndex; payload.lightShadowDenseIdx = lightShadowDenseIdx; payload.cascadeIdx = cascadeIdx; + payload.modelDenseIndex = modelDenseIndex; } barrier(); @@ -75,7 +77,7 @@ void main() { uint currentMeshletIdx = meshletGroupOffset + threadIdx; bool isVisible = (currentMeshletIdx < submeshData.meshletCount); - if (transformDenseIndex == INVALID_INDEX || lightShadowDenseIdx == INVALID_INDEX || lightDenseIdx == INVALID_INDEX) { + if (transformDenseIndex == INVALID_INDEX || lightShadowDenseIdx == INVALID_INDEX || lightDenseIdx == INVALID_INDEX || modelDenseIndex == INVALID_INDEX) { isVisible = false; } @@ -105,7 +107,7 @@ void main() { // 8. Backface Cone Culling for Directional Light if (pc.disableConeCulling == 0 && ctx.enableMeshletConeCulling == 1) { - if (TestConeCulling(worldCollider, lightComp.direction)) { + if (TestConeCullingLight(worldCollider, lightComp.direction)) { isVisible = false; } } @@ -117,19 +119,6 @@ void main() { } } - // 10. Occlusion Culling using Cascade Depth Pyramid (HZB) - float screenSizePixels = 0.0; - if (isVisible && ctx.enableMeshletOcclusionCulling == 1) { - mat4 shadowViewProj = GET_DIRECTION_LIGHT_SHADOW(ctx.directionLightShadowDataBufferAddr, lightShadowDenseIdx).cascadeViewProjsVulkan[cascadeIdx]; - vec4 shadowAtlasRect = GET_DIRECTION_LIGHT_SHADOW(ctx.directionLightShadowDataBufferAddr, lightShadowDenseIdx).cascadeAtlasRects[cascadeIdx]; - bool enableDepthOcclusion = (ctx.enableMeshletOcclusionCulling == 1); - - float shadowScreenSizePixels = 0.0; - if (false && IsSphereOccludedAtlasOrtho(worldCollider.center, worldCollider.radius, shadowViewProj, shadowAtlasRect, shadowDepthPyramid, float(ctx.directionLightShadowAtlasSize), ctx.directionLightShadowHizMipLevels, shadowScreenSizePixels)) { - isVisible = false; - } - } - // 11. Emit surviving meshlets if (isVisible) { uint slot = atomicAdd(survivingMeshletCount, 1); diff --git a/SynapseEngine/Engine/Shaders/Passes/Shadow/DirectionLight/DirectionLightShadowTraditional.vert b/SynapseEngine/Engine/Shaders/Passes/Shadow/DirectionLight/DirectionLightShadowTraditional.vert index 31576b6d..f2de60c1 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Shadow/DirectionLight/DirectionLightShadowTraditional.vert +++ b/SynapseEngine/Engine/Shaders/Passes/Shadow/DirectionLight/DirectionLightShadowTraditional.vert @@ -35,6 +35,13 @@ void main() { // 3. Fetch Model Component & Material Lookup uint modelDenseIndex = GET_SPARSE_INDEX(ctx.modelSparseMapBufferAddr, entityId); + uint transformDenseIndex = GET_SPARSE_INDEX(ctx.transformSparseMapBufferAddr, entityId); + + if (transformDenseIndex == INVALID_INDEX || modelDenseIndex == INVALID_INDEX) { + gl_Position = vec4(0.0, 0.0, 0.0, 0.0); + return; + } + ModelComponent comp = GET_MODEL_COMP(ctx.modelBufferAddr, modelDenseIndex); // 4. Fetch Model Addresses & Raw Vertex Data @@ -44,7 +51,6 @@ void main() { GpuVertexPosition v = GET_VERTEX_POS(addrs.vertexPositions, realVertexIndex); // 5. Fetch Transform and Camera - uint transformDenseIndex = GET_SPARSE_INDEX(ctx.transformSparseMapBufferAddr, entityId); TransformComponent transform = GET_TRANSFORM(ctx.transformBufferAddr, transformDenseIndex); uint cameraDenseIndex = GET_SPARSE_INDEX(ctx.cameraSparseMapBufferAddr, ctx.activeCameraEntity); diff --git a/SynapseEngine/Engine/Shaders/Passes/Shadow/PointLight/PointLightShadowMeshlet.task b/SynapseEngine/Engine/Shaders/Passes/Shadow/PointLight/PointLightShadowMeshlet.task index a8b559ab..3e933904 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Shadow/PointLight/PointLightShadowMeshlet.task +++ b/SynapseEngine/Engine/Shaders/Passes/Shadow/PointLight/PointLightShadowMeshlet.task @@ -49,6 +49,7 @@ void main() { uint lightEntity = GET_POINT_VISIBLE_SHADOW_LIGHT(ctx.pointLightVisibleShadowIndexBufferAddr, lightIdx); uint lightShadowDenseIdx = GET_SPARSE_INDEX(ctx.pointLightShadowSparseMapBufferAddr, lightEntity); uint lightDenseIdx = GET_SPARSE_INDEX(ctx.pointLightSparseMapBufferAddr, lightEntity); + uint modelDenseIndex = GET_SPARSE_INDEX(ctx.modelSparseMapBufferAddr, entityId); // 2. Initialize payload and shared memory if (threadIdx == 0) { @@ -58,6 +59,7 @@ void main() { payload.transformDenseIdx = transformDenseIndex; payload.lightShadowDenseIdx = lightShadowDenseIdx; payload.cascadeIdx = faceIndex; + payload.modelDenseIndex = modelDenseIndex; } barrier(); @@ -73,7 +75,7 @@ void main() { uint currentMeshletIdx = meshletGroupOffset + threadIdx; bool isVisible = (currentMeshletIdx < submeshData.meshletCount); - if (transformDenseIndex == INVALID_INDEX || lightShadowDenseIdx == INVALID_INDEX || lightDenseIdx == INVALID_INDEX) { + if (transformDenseIndex == INVALID_INDEX || lightShadowDenseIdx == INVALID_INDEX || lightDenseIdx == INVALID_INDEX || modelDenseIndex == INVALID_INDEX) { isVisible = false; } @@ -102,7 +104,9 @@ void main() { // 6. Backface Cone Culling if (pc.disableConeCulling == 0 && ctx.enableMeshletConeCulling == 1) { - //Todo: + if (TestConeCulling(worldCollider, pointCollider.center)) { + isVisible = false; + } } // 7. Point Sphere vs Meshlet Sphere Culling @@ -110,12 +114,6 @@ void main() { //Todo: } - - // 8. Occlusion Culling using Depth Pyramid (HZB) - if (isVisible && ctx.enableMeshletOcclusionCulling == 1) { - //Todo: - } - // 9. Emit surviving meshlets if (isVisible) { uint slot = atomicAdd(survivingMeshletCount, 1); diff --git a/SynapseEngine/Engine/Shaders/Passes/Shadow/PointLight/PointLightShadowTraditional.vert b/SynapseEngine/Engine/Shaders/Passes/Shadow/PointLight/PointLightShadowTraditional.vert index 6b9cb191..84ffe129 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Shadow/PointLight/PointLightShadowTraditional.vert +++ b/SynapseEngine/Engine/Shaders/Passes/Shadow/PointLight/PointLightShadowTraditional.vert @@ -36,6 +36,13 @@ void main() { // 3. Fetch Model Component & Material Lookup uint modelDenseIndex = GET_SPARSE_INDEX(ctx.modelSparseMapBufferAddr, entityId); + uint transformDenseIndex = GET_SPARSE_INDEX(ctx.transformSparseMapBufferAddr, entityId); + + if (transformDenseIndex == INVALID_INDEX || modelDenseIndex == INVALID_INDEX) { + gl_Position = vec4(0.0, 0.0, 0.0, 0.0); + return; + } + ModelComponent comp = GET_MODEL_COMP(ctx.modelBufferAddr, modelDenseIndex); // 4. Fetch Model Addresses & Raw Vertex Data @@ -44,7 +51,6 @@ void main() { GpuVertexPosition v = GET_VERTEX_POS(addrs.vertexPositions, realVertexIndex); // 5. Fetch Transform - uint transformDenseIndex = GET_SPARSE_INDEX(ctx.transformSparseMapBufferAddr, entityId); TransformComponent transform = GET_TRANSFORM(ctx.transformBufferAddr, transformDenseIndex); // 6. Evaluate Static Hierarchy (Default pose) diff --git a/SynapseEngine/Engine/Shaders/Passes/Shadow/SpotLight/SpotLightShadowMeshlet.task b/SynapseEngine/Engine/Shaders/Passes/Shadow/SpotLight/SpotLightShadowMeshlet.task index b8897ddc..69907664 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Shadow/SpotLight/SpotLightShadowMeshlet.task +++ b/SynapseEngine/Engine/Shaders/Passes/Shadow/SpotLight/SpotLightShadowMeshlet.task @@ -48,15 +48,18 @@ void main() { uint lightEntity = GET_SPOT_VISIBLE_SHADOW_LIGHT(ctx.spotLightVisibleShadowIndexBufferAddr, lightIdx); uint lightShadowDenseIdx = GET_SPARSE_INDEX(ctx.spotLightShadowSparseMapBufferAddr, lightEntity); uint lightDenseIdx = GET_SPARSE_INDEX(ctx.spotLightSparseMapBufferAddr, lightEntity); + uint modelDenseIndex = GET_SPARSE_INDEX(ctx.modelSparseMapBufferAddr, entityId); // 2. Initialize payload and shared memory if (threadIdx == 0) { + survivingMeshletCount = 0; payload.drawId = gl_DrawID; payload.entityId = entityId; payload.transformDenseIdx = transformDenseIndex; payload.lightShadowDenseIdx = lightShadowDenseIdx; payload.cascadeIdx = 0; + payload.modelDenseIndex = modelDenseIndex; } barrier(); @@ -72,7 +75,7 @@ void main() { uint currentMeshletIdx = meshletGroupOffset + threadIdx; bool isVisible = (currentMeshletIdx < submeshData.meshletCount); - if (transformDenseIndex == INVALID_INDEX || lightShadowDenseIdx == INVALID_INDEX || lightDenseIdx == INVALID_INDEX) { + if (transformDenseIndex == INVALID_INDEX || lightShadowDenseIdx == INVALID_INDEX || lightDenseIdx == INVALID_INDEX || modelDenseIndex == INVALID_INDEX) { isVisible = false; } @@ -101,7 +104,7 @@ void main() { // 6. Backface Cone Culling if (pc.disableConeCulling == 0 && ctx.enableMeshletConeCulling == 1) { - if (TestConeCulling(worldCollider, spotCollider.worldPos)) { + if (TestConeCullingLight(worldCollider, spotCollider.worldPos)) { isVisible = false; } } diff --git a/SynapseEngine/Engine/Shaders/Passes/Shadow/SpotLight/SpotLightShadowTraditional.vert b/SynapseEngine/Engine/Shaders/Passes/Shadow/SpotLight/SpotLightShadowTraditional.vert index 41ac59ac..817220a0 100644 --- a/SynapseEngine/Engine/Shaders/Passes/Shadow/SpotLight/SpotLightShadowTraditional.vert +++ b/SynapseEngine/Engine/Shaders/Passes/Shadow/SpotLight/SpotLightShadowTraditional.vert @@ -34,6 +34,13 @@ void main() { // 3. Fetch Model Component & Material Lookup uint modelDenseIndex = GET_SPARSE_INDEX(ctx.modelSparseMapBufferAddr, entityId); + uint transformDenseIndex = GET_SPARSE_INDEX(ctx.transformSparseMapBufferAddr, entityId); + + if (transformDenseIndex == INVALID_INDEX || modelDenseIndex == INVALID_INDEX) { + gl_Position = vec4(0.0, 0.0, 0.0, 0.0); + return; + } + ModelComponent comp = GET_MODEL_COMP(ctx.modelBufferAddr, modelDenseIndex); // 4. Fetch Model Addresses & Raw Vertex Data @@ -43,7 +50,6 @@ void main() { GpuVertexPosition v = GET_VERTEX_POS(addrs.vertexPositions, realVertexIndex); // 5. Fetch Transform and Camera - uint transformDenseIndex = GET_SPARSE_INDEX(ctx.transformSparseMapBufferAddr, entityId); TransformComponent transform = GET_TRANSFORM(ctx.transformBufferAddr, transformDenseIndex); uint cameraDenseIndex = GET_SPARSE_INDEX(ctx.cameraSparseMapBufferAddr, ctx.activeCameraEntity); diff --git a/SynapseEngine/Engine/Statistics/DefaultRenderStatCollector.cpp b/SynapseEngine/Engine/Statistics/DefaultRenderStatCollector.cpp new file mode 100644 index 00000000..86f1cd21 --- /dev/null +++ b/SynapseEngine/Engine/Statistics/DefaultRenderStatCollector.cpp @@ -0,0 +1,93 @@ +#include "DefaultRenderStatCollector.h" +#include + +namespace Syn { + + DefaultRenderStatCollector::DefaultRenderStatCollector(uint32_t framesInFlight) + : _framesInFlight(framesInFlight) + { + _pools.resize(framesInFlight); + _activeMeasurements.resize(framesInFlight); + _resolvedStats.resize(framesInFlight); + _queryCounters.resize(framesInFlight, 0); + + VkQueryPipelineStatisticFlags flags = + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT | + VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT | + VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT | + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT | + VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT | + VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT /* | + VK_QUERY_PIPELINE_STATISTIC_TASK_SHADER_INVOCATIONS_BIT_EXT | + VK_QUERY_PIPELINE_STATISTIC_MESH_SHADER_INVOCATIONS_BIT_EXT */; + + for (uint32_t i = 0; i < framesInFlight; ++i) { + _pools[i] = std::make_unique(MAX_QUERIES_PER_FRAME, flags); + } + } + + void DefaultRenderStatCollector::BeginFrame(VkCommandBuffer cmd, uint32_t frameIndex) { + _queryCounters[frameIndex] = 0; + _activeMeasurements[frameIndex].clear(); + _pools[frameIndex]->Reset(cmd, 0, MAX_QUERIES_PER_FRAME); + } + + uint32_t DefaultRenderStatCollector::StartPass(VkCommandBuffer cmd, uint32_t frameIndex, const std::string& groupName, const std::string& name) { + uint32_t queryIndex = _queryCounters[frameIndex]++; + + _pools[frameIndex]->BeginQuery(cmd, queryIndex); + _activeMeasurements[frameIndex].push_back({ groupName, name, queryIndex }); + + return queryIndex; + } + + void DefaultRenderStatCollector::EndPass(VkCommandBuffer cmd, uint32_t frameIndex, uint32_t queryIndex) { + _pools[frameIndex]->EndQuery(cmd, queryIndex); + } + + void DefaultRenderStatCollector::ResolveFrame(uint32_t frameIndex) { + auto& measurements = _activeMeasurements[frameIndex]; + if (measurements.empty()) return; + + uint32_t totalQueries = _queryCounters[frameIndex]; + auto activeFlags = _pools[frameIndex]->GetFlags(); + uint32_t activeStatCount = std::popcount(static_cast(activeFlags)); + std::vector results(totalQueries * activeStatCount); + + if (_pools[frameIndex]->GetResults(0, totalQueries, results, false)) { + auto& stats = _resolvedStats[frameIndex]; + stats.clear(); + stats.reserve(measurements.size()); + + for (size_t i = 0; i < measurements.size(); ++i) { + const auto& m = measurements[i]; + + RenderPassStats passStat; + passStat.groupName = m.groupName; + passStat.passName = m.passName; + + uint32_t localIndex = 0; + uint32_t offset = m.queryIndex * activeStatCount; + + auto extractStat = [&](VkQueryPipelineStatisticFlags flag) -> uint64_t { + return (activeFlags & flag) ? results[offset + localIndex++] : 0; + }; + + passStat.inputAssemblyVertices = extractStat(VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT); + passStat.inputAssemblyPrimitives = extractStat(VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT); + passStat.vertexShaderInvocations = extractStat(VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT); + passStat.clippingInvocations = extractStat(VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT); + passStat.clippingPrimitives = extractStat(VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT); + passStat.fragmentShaderInvocations = extractStat(VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT); + passStat.taskShaderInvocations = extractStat(VK_QUERY_PIPELINE_STATISTIC_TASK_SHADER_INVOCATIONS_BIT_EXT); + passStat.meshShaderInvocations = extractStat(VK_QUERY_PIPELINE_STATISTIC_MESH_SHADER_INVOCATIONS_BIT_EXT); + + stats.push_back(passStat); + } + } + } + + const std::vector& DefaultRenderStatCollector::GetStats(uint32_t frameIndex) const { + return _resolvedStats[frameIndex]; + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Statistics/DefaultRenderStatCollector.h b/SynapseEngine/Engine/Statistics/DefaultRenderStatCollector.h new file mode 100644 index 00000000..f8209582 --- /dev/null +++ b/SynapseEngine/Engine/Statistics/DefaultRenderStatCollector.h @@ -0,0 +1,42 @@ +#pragma once +#include "Engine/SynApi.h" +#include "IRenderStatCollector.h" +#include "Engine/Vk/Query/PipelineStatisticsQueryPool.h" + +#include +#include +#include + +namespace Syn { + + struct SYN_API StatMeasurement { + std::string groupName; + std::string passName; + uint32_t queryIndex; + }; + + class SYN_API DefaultRenderStatCollector : public IRenderStatCollector { + public: + explicit DefaultRenderStatCollector(uint32_t framesInFlight); + ~DefaultRenderStatCollector() override = default; + + DefaultRenderStatCollector(const DefaultRenderStatCollector&) = delete; + DefaultRenderStatCollector& operator=(const DefaultRenderStatCollector&) = delete; + + void BeginFrame(VkCommandBuffer cmd, uint32_t frameIndex) override; + uint32_t StartPass(VkCommandBuffer cmd, uint32_t frameIndex, const std::string& groupName, const std::string& name) override; + void EndPass(VkCommandBuffer cmd, uint32_t frameIndex, uint32_t queryIndex) override; + + void ResolveFrame(uint32_t frameIndex) override; + const std::vector& GetStats(uint32_t frameIndex) const override; + private: + static constexpr uint32_t MAX_QUERIES_PER_FRAME = 512; + + uint32_t _framesInFlight; + std::vector _queryCounters; + std::vector> _pools; + + std::vector> _activeMeasurements; + std::vector> _resolvedStats; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Statistics/FrameStatisticsManager.cpp b/SynapseEngine/Engine/Statistics/FrameStatisticsManager.cpp new file mode 100644 index 00000000..bad94788 --- /dev/null +++ b/SynapseEngine/Engine/Statistics/FrameStatisticsManager.cpp @@ -0,0 +1,27 @@ +#include "FrameStatisticsManager.h" + +namespace Syn { + + FrameStatisticsManager::FrameStatisticsManager(uint32_t framesInFlight) { + _gpuStatsPerFrame.resize(framesInFlight); + } + + void FrameStatisticsManager::UpdateCpuStats(const CpuRenderStats& newStats) { + _cpuStats = newStats; + } + + void FrameStatisticsManager::ResolveFrame(uint32_t frameIndex, IRenderStatCollector* gpuCollector) { + if (gpuCollector) { + gpuCollector->ResolveFrame(frameIndex); + _gpuStatsPerFrame[frameIndex] = gpuCollector->GetStats(frameIndex); + } + } + + const CpuRenderStats& FrameStatisticsManager::GetCpuStats() const { + return _cpuStats; + } + + const std::vector& FrameStatisticsManager::GetGpuStats(uint32_t frameIndex) const { + return _gpuStatsPerFrame[frameIndex]; + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Statistics/FrameStatisticsManager.h b/SynapseEngine/Engine/Statistics/FrameStatisticsManager.h new file mode 100644 index 00000000..059f3206 --- /dev/null +++ b/SynapseEngine/Engine/Statistics/FrameStatisticsManager.h @@ -0,0 +1,30 @@ +#pragma once +#include "Engine/SynApi.h" +#include "Engine/Statistics/IRenderStatCollector.h" +#include + +namespace Syn { + + struct SYN_API CpuRenderStats { + uint32_t totalModels = 0; + uint32_t totalDrawDescriptors = 0; + uint32_t traditionalDrawDescriptors = 0; + uint32_t meshletDrawDescriptors = 0; + uint32_t totalAllocatedInstances = 0; + uint32_t totalMaxMeshlets = 0; + }; + + class SYN_API FrameStatisticsManager { + public: + FrameStatisticsManager(uint32_t framesInFlight); + + void UpdateCpuStats(const CpuRenderStats& newStats); + void ResolveFrame(uint32_t frameIndex, IRenderStatCollector* gpuCollector); + + const CpuRenderStats& GetCpuStats() const; + const std::vector& GetGpuStats(uint32_t frameIndex) const; + private: + CpuRenderStats _cpuStats; + std::vector> _gpuStatsPerFrame; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Statistics/IRenderStatCollector.cpp b/SynapseEngine/Engine/Statistics/IRenderStatCollector.cpp new file mode 100644 index 00000000..3d9081eb --- /dev/null +++ b/SynapseEngine/Engine/Statistics/IRenderStatCollector.cpp @@ -0,0 +1 @@ +#include "IRenderStatCollector.h" \ No newline at end of file diff --git a/SynapseEngine/Engine/Statistics/IRenderStatCollector.h b/SynapseEngine/Engine/Statistics/IRenderStatCollector.h new file mode 100644 index 00000000..d8520946 --- /dev/null +++ b/SynapseEngine/Engine/Statistics/IRenderStatCollector.h @@ -0,0 +1,34 @@ +#pragma once +#include "Engine/SynApi.h" +#include +#include +#include + +namespace Syn +{ + struct SYN_API RenderPassStats { + std::string groupName; + std::string passName; + + uint64_t inputAssemblyVertices = 0; + uint64_t inputAssemblyPrimitives = 0; + uint64_t vertexShaderInvocations = 0; + uint64_t clippingInvocations = 0; + uint64_t clippingPrimitives = 0; + uint64_t fragmentShaderInvocations = 0; + uint64_t taskShaderInvocations = 0; + uint64_t meshShaderInvocations = 0; + }; + + class SYN_API IRenderStatCollector { + public: + virtual ~IRenderStatCollector() = default; + + virtual void BeginFrame(VkCommandBuffer cmd, uint32_t frameIndex) = 0; + virtual uint32_t StartPass(VkCommandBuffer cmd, uint32_t frameIndex, const std::string& groupName, const std::string& name) = 0; + virtual void EndPass(VkCommandBuffer cmd, uint32_t frameIndex, uint32_t queryIndex) = 0; + + virtual void ResolveFrame(uint32_t frameIndex) = 0; + virtual const std::vector& GetStats(uint32_t frameIndex) const = 0; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/System/ComponentSystem.h b/SynapseEngine/Engine/System/ComponentSystem.h index db7d4393..0641e938 100644 --- a/SynapseEngine/Engine/System/ComponentSystem.h +++ b/SynapseEngine/Engine/System/ComponentSystem.h @@ -122,12 +122,13 @@ namespace Syn bool hasUpdate = pool->template IsStateBitSet(); bool hasIndex = pool->template IsStateBitSet(); bool hasStaticUpload = pool->template IsStateBitSet(); + bool queued = pool->template IsStateBitSet(); bool hasCustom1 = pool->template IsStateBitSet(); bool hasCustom2 = pool->template IsStateBitSet(); bool hasCustom3 = pool->template IsStateBitSet(); bool hasDirtyStatics = !pool->GetStorage().GetDirtyStatics().empty(); - if (!hasChanged && !hasUpdate && !hasIndex && !hasCustom1 && !hasCustom2 && !hasCustom3 && !hasDirtyStatics && !hasStaticUpload) return; + if (!hasChanged && !hasUpdate && !hasIndex && !hasCustom1 && !hasCustom2 && !hasCustom3 && !hasDirtyStatics && !hasStaticUpload && !queued) return; //Info("{} -> OnFinish: Cleaning up frame. (Changed: {}, Update: {}, Index: {}, DirtyStatics: {})", GetName(), hasChanged, hasUpdate, hasIndex, hasDirtyStatics); @@ -136,6 +137,7 @@ namespace Syn if (pool->template IsBitSet(entity)) pool->template ResetBit(entity); if (pool->template IsBitSet(entity)) pool->template ResetBit(entity); + if (pool->template IsBitSet(entity)) pool->template ResetBit(entity); if (pool->template IsBitSet(entity)) pool->template ResetBit(entity); if (pool->template IsBitSet(entity)) pool->template ResetBit(entity); if (pool->template IsBitSet(entity)) pool->template ResetBit(entity); diff --git a/SynapseEngine/Engine/System/Core/CameraSystem.cpp b/SynapseEngine/Engine/System/Core/CameraSystem.cpp index c66f589a..0ef530cc 100644 --- a/SynapseEngine/Engine/System/Core/CameraSystem.cpp +++ b/SynapseEngine/Engine/System/Core/CameraSystem.cpp @@ -50,11 +50,6 @@ namespace Syn float forward = 0; float sideways = 0; - if (enableInput && inputManager->IsKeyHeld(KEY_W)) forward = 1; - if (enableInput && inputManager->IsKeyHeld(KEY_S)) forward = -1; - if (enableInput && inputManager->IsKeyHeld(KEY_D)) sideways = 1; - if (enableInput && inputManager->IsKeyHeld(KEY_A)) sideways = -1; - if (enableInput && inputManager->IsButtonHeld(BUTTON_RIGHT)) { auto deltaPos = inputManager->GetMouseDelta(); @@ -70,69 +65,100 @@ namespace Syn }; glm::vec3 worldUp = glm::vec3(0.0f, 1.0f, 0.0f); - cameraComponent.direction = glm::normalize(direction); cameraComponent.right = glm::normalize(glm::cross(cameraComponent.direction, worldUp)); cameraComponent.up = glm::normalize(glm::cross(cameraComponent.right, cameraComponent.direction)); - transformComponent.translation += (forward * cameraComponent.direction + sideways * cameraComponent.right) * cameraComponent.speed * deltaTime; + if (cameraComponent.useOrbit) + { + if (enableInput) + { + float sideways = 0; + if (inputManager->IsKeyHeld(KEY_D)) sideways = 1; + if (inputManager->IsKeyHeld(KEY_A)) sideways = -1; + + cameraComponent.target += (sideways * cameraComponent.right) * cameraComponent.speed * deltaTime; + + if (inputManager->IsKeyHeld(KEY_W)) cameraComponent.distance -= cameraComponent.speed * deltaTime; + if (inputManager->IsKeyHeld(KEY_S)) cameraComponent.distance += cameraComponent.speed * deltaTime; - cameraComponent.position = transformComponent.translation; - cameraComponent.target = cameraComponent.position + cameraComponent.direction; + cameraComponent.distance = glm::max(cameraComponent.distance, 0.1f); + } + + cameraComponent.position = cameraComponent.target - cameraComponent.direction * cameraComponent.distance; + transformComponent.translation = cameraComponent.position; + } + else + { + float forward = 0; + float sideways = 0; + + if (enableInput && inputManager->IsKeyHeld(KEY_W)) forward = 1; + if (enableInput && inputManager->IsKeyHeld(KEY_S)) forward = -1; + if (enableInput && inputManager->IsKeyHeld(KEY_D)) sideways = 1; + if (enableInput && inputManager->IsKeyHeld(KEY_A)) sideways = -1; + + transformComponent.translation += (forward * cameraComponent.direction + sideways * cameraComponent.right) * cameraComponent.speed * deltaTime; + + cameraComponent.position = transformComponent.translation; + cameraComponent.target = cameraComponent.position + cameraComponent.direction; + } cameraComponent.view = glm::lookAt(cameraComponent.position, cameraComponent.target, worldUp); cameraComponent.viewInv = glm::inverse(cameraComponent.view); - cameraComponent.proj = glm::perspective(glm::radians(cameraComponent.fov), cameraComponent.width / cameraComponent.height, cameraComponent.nearPlane, cameraComponent.farPlane); + if (cameraComponent.isOrthographic) + { + float aspectRatio = cameraComponent.width / cameraComponent.height; + float halfH = cameraComponent.orthoSize * 0.5f; + float halfW = halfH * aspectRatio; + cameraComponent.proj = glm::ortho(-halfW, halfW, -halfH, halfH, -cameraComponent.farPlane, cameraComponent.farPlane); + } + else + { + cameraComponent.proj = glm::perspective(glm::radians(cameraComponent.fov), cameraComponent.width / cameraComponent.height, cameraComponent.nearPlane, cameraComponent.farPlane); + } + cameraComponent.projInv = glm::inverse(cameraComponent.proj); cameraComponent.viewProj = cameraComponent.proj * cameraComponent.view; cameraComponent.viewProjInv = glm::inverse(cameraComponent.viewProj); - cameraComponent.frustum.Update(cameraComponent.viewProj); - - /* - float fovY = glm::radians(cameraComponent.fov); - float aspectRatio = cameraComponent.width / cameraComponent.height; - float halfV = cameraComponent.farPlane * tanf(fovY * 0.5f); - float halfH = halfV * aspectRatio; - - // Near - cameraComponent.frustum.planes[0] = FrustumCollider::CreatePlane( - cameraComponent.direction, - cameraComponent.position + cameraComponent.direction * cameraComponent.nearPlane - ); - - // Far - cameraComponent.frustum.planes[1] = FrustumCollider::CreatePlane( - -cameraComponent.direction, - cameraComponent.position + cameraComponent.direction * cameraComponent.farPlane - ); - - // Left - cameraComponent.frustum.planes[2] = FrustumCollider::CreatePlane( - -glm::cross(cameraComponent.up, glm::normalize(cameraComponent.direction * cameraComponent.farPlane - cameraComponent.right * halfH)), - cameraComponent.position - ); - - // Right - cameraComponent.frustum.planes[3] = FrustumCollider::CreatePlane( - -glm::cross(glm::normalize(cameraComponent.direction * cameraComponent.farPlane + cameraComponent.right * halfH), cameraComponent.up), - cameraComponent.position - ); - - // Top - cameraComponent.frustum.planes[4] = FrustumCollider::CreatePlane( - -glm::cross(cameraComponent.right, glm::normalize(cameraComponent.direction * cameraComponent.farPlane + cameraComponent.up * halfV)), - cameraComponent.position - ); - - // Bottom - cameraComponent.frustum.planes[5] = FrustumCollider::CreatePlane( - -glm::cross(glm::normalize(cameraComponent.direction * cameraComponent.farPlane - cameraComponent.up * halfV), cameraComponent.right), - cameraComponent.position - ); - */ + if (cameraComponent.isOrthographic) + { + float aspectRatio = cameraComponent.width / cameraComponent.height; + float halfH = cameraComponent.orthoSize * 0.5f; + float halfW = halfH * aspectRatio; + + cameraComponent.frustum.planes[0] = FrustumCollider::CreatePlane( + cameraComponent.direction, + cameraComponent.position + cameraComponent.direction * cameraComponent.nearPlane + ); + cameraComponent.frustum.planes[1] = FrustumCollider::CreatePlane( + -cameraComponent.right, + cameraComponent.position + cameraComponent.right * halfW + ); + cameraComponent.frustum.planes[2] = FrustumCollider::CreatePlane( + cameraComponent.right, + cameraComponent.position - cameraComponent.right * halfW + ); + cameraComponent.frustum.planes[3] = FrustumCollider::CreatePlane( + -cameraComponent.up, + cameraComponent.position + cameraComponent.up * halfH + ); + cameraComponent.frustum.planes[4] = FrustumCollider::CreatePlane( + cameraComponent.up, + cameraComponent.position - cameraComponent.up * halfH + ); + cameraComponent.frustum.planes[5] = FrustumCollider::CreatePlane( + -cameraComponent.direction, + cameraComponent.position + cameraComponent.direction * cameraComponent.farPlane + ); + } + else + { + cameraComponent.frustum.Update(cameraComponent.viewProj); + } cameraPool->SetBit(entity); transformPool->SetBit(entity); diff --git a/SynapseEngine/Engine/System/Core/StaticSpatialSahSystem.cpp b/SynapseEngine/Engine/System/Core/StaticSpatialSahSystem.cpp index 136c7f01..73fb27b9 100644 --- a/SynapseEngine/Engine/System/Core/StaticSpatialSahSystem.cpp +++ b/SynapseEngine/Engine/System/Core/StaticSpatialSahSystem.cpp @@ -5,8 +5,6 @@ #include "Engine/System/Core/TransformSystem.h" #include "Engine/System/Rendering/ModelSystem.h" #include "Engine/Mesh/Utils/MeshUtils.h" -#include "Engine/Mesh/ModelManager.h" -#include "Engine/Animation/AnimationManager.h" #include #include @@ -63,10 +61,8 @@ namespace Syn return; } - auto modelManager = ServiceLocator::GetModelManager(); - auto modelSnapshot = modelManager->GetResourceSnapshot(); - auto animationManager = ServiceLocator::GetAnimationManager(); - auto animSnapshot = animationManager->GetResourceSnapshot(); + auto& modelSnapshot = scene->GetSystemContext().modelSnapshots; + auto& animSnapshot = scene->GetSystemContext().animationSnapshots; _spatialItems.clear(); _spatialItems.resize(staticEntities.size()); diff --git a/SynapseEngine/Engine/System/Core/TagSetupSystem.cpp b/SynapseEngine/Engine/System/Core/TagSetupSystem.cpp new file mode 100644 index 00000000..ccf4f88b --- /dev/null +++ b/SynapseEngine/Engine/System/Core/TagSetupSystem.cpp @@ -0,0 +1,94 @@ +#include "TagSetupSystem.h" +#include "Engine/Scene/Scene.h" + +namespace Syn +{ + std::vector TagSetupSystem::GetWriteDependencies() const + { + return { TypeInfo::ID }; + } + + void TagSetupSystem::UpdateComponents(Scene* scene, uint32_t frameIndex, float deltaTime, tf::Subflow& subflow) + { + auto registry = scene->GetRegistry(); + auto tagPool = registry->GetPool(); + auto hierarchyPool = registry->GetPool(); + auto hierarchyManager = scene->GetHierarchyManager(); + + if (!tagPool || !hierarchyPool || !hierarchyManager) return; + + auto* workQueue = hierarchyManager->EnsureWorkQueue(); + + auto initTask = this->EmplaceTask(subflow, "InitTagQueue", [workQueue, hierarchyManager]() { + workQueue->Initialize(hierarchyManager->GetLevels()); + }); + + auto seedTasks = ParallelForEachIf(tagPool, subflow, "SeedTagQueue", [tagPool, hierarchyPool, workQueue](EntityID entity) { + + uint32_t level = 0; + if (hierarchyPool->Has(entity)) { + level = hierarchyPool->Get(entity).depthLevel; + } + + workQueue->Push(level, entity); + tagPool->SetBit(entity); + + }); + + for (auto& st : seedTasks) { + initTask.precede(st); + } + + uint32_t maxLevel = hierarchyManager->GetMaxActiveLevel(); + std::vector propagateTasks; + + for (uint32_t level = 0; level < maxLevel; ++level) + { + tf::Task propTask = this->EmplaceTask(subflow, "PropagateTagDirty_" + std::to_string(level), [=](tf::Subflow& nested_subflow) { + auto currentQueue = workQueue->GetQueue(level); + + if (currentQueue.empty()) return; + + nested_subflow.for_each(currentQueue.begin(), currentQueue.end(), [=](EntityID entity) { + + if (!hierarchyPool->Has(entity)) return; + + EntityID child = hierarchyPool->Get(entity).firstChild; + + while (child != NULL_ENTITY) + { + if (tagPool->Has(child)) + { + if (!tagPool->IsBitSet(child)) + { + tagPool->SetBit(child); + + uint32_t childLevel = hierarchyPool->Get(child).depthLevel; + workQueue->Push(childLevel, child); + + if (tagPool->IsStatic(child)) + tagPool->MarkStaticDirty(child); + else if (tagPool->IsDynamic(child)) + tagPool->SetBit(child); + } + } + + child = hierarchyPool->Get(child).nextSibling; + } + }); + }); + + if (!propagateTasks.empty()) { + propagateTasks.back().precede(propTask); + } + else { + for (auto& st : seedTasks) { + st.precede(propTask); + } + initTask.precede(propTask); + } + + propagateTasks.push_back(propTask); + } + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/System/Core/TagSetupSystem.h b/SynapseEngine/Engine/System/Core/TagSetupSystem.h new file mode 100644 index 00000000..c3e6f3b1 --- /dev/null +++ b/SynapseEngine/Engine/System/Core/TagSetupSystem.h @@ -0,0 +1,18 @@ +#pragma once +#include "Engine/System/ComponentSystem.h" +#include "Engine/Component/Core/TagComponent.h" +#include "Engine/Component/Core/HierarchyComponent.h" + +namespace Syn +{ + class SYN_API TagSetupSystem : public ComponentSystem + { + public: + std::string GetName() const override { return "TagSetupSystem"; } + std::string GetGroup() const override { return SystemGroupNames::CoreSystems; } + + std::vector GetWriteDependencies() const override; + protected: + void UpdateComponents(Scene* scene, uint32_t frameIndex, float deltaTime, tf::Subflow& subflow) override; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/System/Core/TagSystem.cpp b/SynapseEngine/Engine/System/Core/TagSystem.cpp new file mode 100644 index 00000000..cd094062 --- /dev/null +++ b/SynapseEngine/Engine/System/Core/TagSystem.cpp @@ -0,0 +1,107 @@ +#include "TagSystem.h" +#include "Engine/Scene/Scene.h" +#include "Engine/Component/Core/HierarchyComponent.h" +#include "TagSetupSystem.h" + +namespace Syn +{ + std::vector TagSystem::GetReadDependencies() const + { + return { TypeInfo::ID }; + } + + std::vector TagSystem::GetWriteDependencies() const + { + return { TypeInfo::ID }; + } + + void TagSystem::UpdateComponents(Scene* scene, uint32_t frameIndex, float deltaTime, tf::Subflow& subflow) + { + auto registry = scene->GetRegistry(); + auto tagPool = registry->GetPool(); + auto hierarchyPool = registry->GetPool(); + auto hierarchyManager = scene->GetHierarchyManager(); + + if (!tagPool || !hierarchyPool || !hierarchyManager) return; + + auto* workQueue = hierarchyManager->EnsureWorkQueue(); + uint32_t maxLevel = hierarchyManager->GetMaxActiveLevel(); + std::vector levelTasks; + + for (uint32_t level = 0; level < maxLevel; ++level) + { + tf::Task levelTask = this->EmplaceTask(subflow, "TagEnable_" + std::to_string(level), [=](tf::Subflow& nested_subflow) { + + auto currentQueue = workQueue->GetQueue(level); + + if (currentQueue.empty()) return; + + nested_subflow.for_each(currentQueue.begin(), currentQueue.end(), [=](EntityID entity) { + + auto& tag = tagPool->Get(entity); + + bool parentGlobalEnabled = true; + if (hierarchyPool->Has(entity)) + { + EntityID parent = hierarchyPool->Get(entity).parent; + + if (parent != NULL_ENTITY && tagPool->Has(parent)) { + parentGlobalEnabled = tagPool->Get(parent).globalEnabled; + } + } + + tag.globalEnabled = tag.localEnabled && parentGlobalEnabled; + + if (tagPool->IsDynamic(entity)) { + tagPool->SetBit(entity); + } + + tag.version++; + }); + }); + + if (!levelTasks.empty()) { + levelTasks.back().precede(levelTask); + } + + levelTasks.push_back(levelTask); + } + } + + void TagSystem::UploadComponents(Scene* scene, uint32_t frameIndex, tf::Subflow& subflow, bool uploadDynamic, bool uploadStatic) + { + auto registry = scene->GetRegistry(); + auto componentBufferManager = scene->GetComponentBufferManager(); + auto tagPool = registry->GetPool(); + if (!tagPool) return; + + auto tagDataBuffer = componentBufferManager->GetComponentBuffer(BufferNames::TagData, frameIndex); + if (!tagDataBuffer.buffer) return; + + auto tagDataBufferHandler = static_cast(tagDataBuffer.buffer->Map()); + bool forceUpload = this->ShouldForceUpload(); + + auto processUpload = [tagPool, tagDataBuffer, tagDataBufferHandler, forceUpload](EntityID entity) { + auto& tagComp = tagPool->Get(entity); + auto tagIndex = tagPool->GetMapping().Get(entity); + + if (forceUpload || tagDataBuffer.versions[tagIndex] != tagComp.version) + { + tagDataBuffer.versions[tagIndex] = tagComp.version; + + uint32_t flags = 0; + if (tagComp.globalEnabled) flags |= (1 << 0); + + tagDataBufferHandler[tagIndex] = flags; + } + }; + + ForEachStream(tagPool, subflow, SystemPhaseNames::UploadGPU, processUpload); + + if (uploadDynamic) + ForEachDynamic(tagPool, subflow, SystemPhaseNames::UploadGPU, processUpload); + + if (uploadStatic) + ForEachStatic(tagPool, subflow, SystemPhaseNames::UploadGPU, processUpload); + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/System/Core/TagSystem.h b/SynapseEngine/Engine/System/Core/TagSystem.h new file mode 100644 index 00000000..4dfb08cf --- /dev/null +++ b/SynapseEngine/Engine/System/Core/TagSystem.h @@ -0,0 +1,20 @@ +#pragma once +#include "Engine/System/ComponentSystem.h" +#include "Engine/Component/Core/TagComponent.h" + +namespace Syn +{ + class SYN_API TagSystem : public ComponentSystem + { + public: + std::string GetName() const override { return "TagSystem"; } + std::string GetGroup() const override { return SystemGroupNames::CoreSystems; } + std::vector GetWriteDependencies() const override; + std::vector GetReadDependencies() const override; + protected: + std::string GetSparseBufferName() const override { return BufferNames::TagSparseMap; } + + void UpdateComponents(Scene* scene, uint32_t frameIndex, float deltaTime, tf::Subflow& subflow) override; + void UploadComponents(Scene* scene, uint32_t frameIndex, tf::Subflow& subflow, bool uploadDynamic, bool uploadStatic) override; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/System/Core/TransformModelLinkSystem.cpp b/SynapseEngine/Engine/System/Core/TransformModelLinkSystem.cpp index ddb171f9..9949519c 100644 --- a/SynapseEngine/Engine/System/Core/TransformModelLinkSystem.cpp +++ b/SynapseEngine/Engine/System/Core/TransformModelLinkSystem.cpp @@ -3,6 +3,7 @@ #include "Engine/Scene/BufferNames.h" #include "Engine/System/Core/TransformSystem.h" #include "Engine/System/Rendering/ModelSystem.h" +#include "Engine/System/Core/TagSystem.h" #include namespace Syn diff --git a/SynapseEngine/Engine/System/Core/TransformSetupSystem.cpp b/SynapseEngine/Engine/System/Core/TransformSetupSystem.cpp new file mode 100644 index 00000000..a9d33c32 --- /dev/null +++ b/SynapseEngine/Engine/System/Core/TransformSetupSystem.cpp @@ -0,0 +1,94 @@ +#include "TransformSetupSystem.h" +#include "Engine/Scene/Scene.h" + +namespace Syn +{ + std::vector TransformSetupSystem::GetWriteDependencies() const + { + return { TypeInfo::ID }; + } + + void TransformSetupSystem::UpdateComponents(Scene* scene, uint32_t frameIndex, float deltaTime, tf::Subflow& subflow) + { + auto registry = scene->GetRegistry(); + auto transformPool = registry->GetPool(); + auto hierarchyPool = registry->GetPool(); + auto hierarchyManager = scene->GetHierarchyManager(); + + if (!transformPool || !hierarchyPool || !hierarchyManager) return; + + auto* workQueue = hierarchyManager->EnsureWorkQueue(); + + auto initTask = this->EmplaceTask(subflow, "InitTransformQueue", [workQueue, hierarchyManager]() { + workQueue->Initialize(hierarchyManager->GetLevels()); + }); + + auto seedTasks = ParallelForEachIf(transformPool, subflow, "SeedTransformQueue", [transformPool, hierarchyPool, workQueue](EntityID entity) { + + uint32_t level = 0; + if (hierarchyPool->Has(entity)) { + level = hierarchyPool->Get(entity).depthLevel; + } + + workQueue->Push(level, entity); + transformPool->SetBit(entity); + + }); + + for (auto& st : seedTasks) { + initTask.precede(st); + } + + uint32_t maxLevel = hierarchyManager->GetMaxActiveLevel(); + std::vector propagateTasks; + + for (uint32_t level = 0; level < maxLevel; ++level) + { + tf::Task propTask = this->EmplaceTask(subflow, "PropagateDirty_" + std::to_string(level), [=](tf::Subflow& nested_subflow) { + auto currentQueue = workQueue->GetQueue(level); + + if (currentQueue.empty()) return; + + nested_subflow.for_each(currentQueue.begin(), currentQueue.end(), [=](EntityID entity) { + + if (!hierarchyPool->Has(entity)) return; + + EntityID child = hierarchyPool->Get(entity).firstChild; + + while (child != NULL_ENTITY) + { + if (transformPool->Has(child)) + { + if (!transformPool->IsBitSet(child)) + { + transformPool->SetBit(child); + + uint32_t childLevel = hierarchyPool->Get(child).depthLevel; + workQueue->Push(childLevel, child); + + if (transformPool->IsStatic(child)) + transformPool->MarkStaticDirty(child); + else if (transformPool->IsDynamic(child)) + transformPool->SetBit(child); + } + } + + child = hierarchyPool->Get(child).nextSibling; + } + }); + }); + + if (!propagateTasks.empty()) { + propagateTasks.back().precede(propTask); + } + else { + for (auto& st : seedTasks) { + st.precede(propTask); + } + initTask.precede(propTask); + } + + propagateTasks.push_back(propTask); + } + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/System/Core/TransformSetupSystem.h b/SynapseEngine/Engine/System/Core/TransformSetupSystem.h new file mode 100644 index 00000000..bc0593af --- /dev/null +++ b/SynapseEngine/Engine/System/Core/TransformSetupSystem.h @@ -0,0 +1,18 @@ +#pragma once +#include "Engine/System/ComponentSystem.h" +#include "Engine/Component/Core/TransformComponent.h" +#include "Engine/Component/Core/HierarchyComponent.h" + +namespace Syn +{ + class SYN_API TransformSetupSystem : public ComponentSystem + { + public: + std::string GetName() const override { return "TransformSetupSystem"; } + std::string GetGroup() const override { return SystemGroupNames::CoreSystems; } + + std::vector GetWriteDependencies() const override; + protected: + void UpdateComponents(Scene* scene, uint32_t frameIndex, float deltaTime, tf::Subflow& subflow) override; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/System/Core/TransformSystem.cpp b/SynapseEngine/Engine/System/Core/TransformSystem.cpp index 78352748..cccc74a8 100644 --- a/SynapseEngine/Engine/System/Core/TransformSystem.cpp +++ b/SynapseEngine/Engine/System/Core/TransformSystem.cpp @@ -6,9 +6,15 @@ #include #include "Engine/Component/Rendering/ModelComponent.h" #include "Engine/System/Rendering/ModelSystem.h" +#include "TransformSetupSystem.h" namespace Syn { + std::vector TransformSystem::GetReadDependencies() const + { + return { TypeInfo::ID }; + } + std::vector TransformSystem::GetWriteDependencies() const { return { TypeInfo::ID }; @@ -18,24 +24,65 @@ namespace Syn { auto registry = scene->GetRegistry(); auto transformPool = registry->GetPool(); - if (!transformPool) return; + auto hierarchyPool = registry->GetPool(); + auto hierarchyManager = scene->GetHierarchyManager(); - ParallelForEachIf(transformPool, subflow, SystemPhaseNames::Update, [transformPool](EntityID entity) { - auto& transformComponent = transformPool->Get(entity); + if (!transformPool || !hierarchyPool || !hierarchyManager) return; + + auto* workQueue = hierarchyManager->EnsureWorkQueue(); + uint32_t maxLevel = hierarchyManager->GetMaxActiveLevel(); + std::vector levelTasks; + + for (uint32_t level = 0; level < maxLevel; ++level) + { + tf::Task levelTask = this->EmplaceTask(subflow, "TransformMath_" + std::to_string(level), [=](tf::Subflow& nested_subflow) { + + auto currentQueue = workQueue->GetQueue(level); - transformComponent.transform = glm::mat4(1.0f); - transformComponent.transform = glm::translate(transformComponent.transform, transformComponent.translation); - transformComponent.transform = glm::rotate(transformComponent.transform, glm::radians(transformComponent.rotation.z), glm::vec3(0, 0, 1)); - transformComponent.transform = glm::rotate(transformComponent.transform, glm::radians(transformComponent.rotation.y), glm::vec3(0, 1, 0)); - transformComponent.transform = glm::rotate(transformComponent.transform, glm::radians(transformComponent.rotation.x), glm::vec3(1, 0, 0)); - transformComponent.transform = glm::scale(transformComponent.transform, transformComponent.scale); - transformComponent.transformIT = glm::transpose(glm::inverse(transformComponent.transform)); + if (currentQueue.empty()) return; - if (transformPool->IsDynamic(entity)) - transformPool->SetBit(entity); + nested_subflow.for_each(currentQueue.begin(), currentQueue.end(), [=](EntityID entity) { - transformComponent.version++; - }); + auto& transformComponent = transformPool->Get(entity); + + glm::mat4 localMat = glm::translate(glm::mat4(1.0f), transformComponent.translation); + localMat = glm::rotate(localMat, glm::radians(transformComponent.rotation.z), glm::vec3(0, 0, 1)); + localMat = glm::rotate(localMat, glm::radians(transformComponent.rotation.y), glm::vec3(0, 1, 0)); + localMat = glm::rotate(localMat, glm::radians(transformComponent.rotation.x), glm::vec3(1, 0, 0)); + localMat = glm::scale(localMat, transformComponent.scale); + + if (hierarchyPool->Has(entity)) + { + EntityID parent = hierarchyPool->Get(entity).parent; + + if (parent != NULL_ENTITY && transformPool->Has(parent)) { + auto& parentTransform = transformPool->Get(parent); + transformComponent.transform = parentTransform.transform * localMat; + } + else { + transformComponent.transform = localMat; + } + } + else + { + transformComponent.transform = localMat; + } + + transformComponent.transformIT = glm::transpose(glm::inverse(transformComponent.transform)); + + if (transformPool->IsDynamic(entity)) { + transformPool->SetBit(entity); + } + + transformComponent.version++; + }); + }); + + if (!levelTasks.empty()) { + levelTasks.back().precede(levelTask); + } + levelTasks.push_back(levelTask); + } } void TransformSystem::UploadComponents(Scene* scene, uint32_t frameIndex, tf::Subflow& subflow, bool uploadDynamic, bool uploadStatic) diff --git a/SynapseEngine/Engine/System/Core/TransformSystem.h b/SynapseEngine/Engine/System/Core/TransformSystem.h index 54d44792..59cff60e 100644 --- a/SynapseEngine/Engine/System/Core/TransformSystem.h +++ b/SynapseEngine/Engine/System/Core/TransformSystem.h @@ -10,6 +10,7 @@ namespace Syn std::string GetName() const override { return "TransformSystem"; } std::string GetGroup() const override { return SystemGroupNames::CoreSystems; } + std::vector GetReadDependencies() const override; std::vector GetWriteDependencies() const override; protected: std::string GetSparseBufferName() const override { return BufferNames::TransformSparseMap; } diff --git a/SynapseEngine/Engine/System/Light/Direction/DirectionLightCullingSystem.cpp b/SynapseEngine/Engine/System/Light/Direction/DirectionLightCullingSystem.cpp index 73db86ba..b2548215 100644 --- a/SynapseEngine/Engine/System/Light/Direction/DirectionLightCullingSystem.cpp +++ b/SynapseEngine/Engine/System/Light/Direction/DirectionLightCullingSystem.cpp @@ -8,12 +8,16 @@ #include "Engine/Scene/BufferNames.h" #include +#include "Engine/Component/Core/TagComponent.h" +#include "Engine/System/Core/TagSystem.h" + namespace Syn { std::vector DirectionLightCullingSystem::GetReadDependencies() const { return { TypeInfo::ID, - TypeInfo::ID + TypeInfo::ID, + TypeInfo::ID }; } @@ -28,6 +32,7 @@ namespace Syn auto drawData = scene->GetSceneDrawData(); auto registry = scene->GetRegistry(); + auto tagPool = registry->GetPool(); auto pool = registry->GetPool(); auto shadowPool = registry->GetPool(); @@ -50,11 +55,15 @@ namespace Syn } }); - auto cullFunc = [pool, drawData, shadowPool](EntityID entity) { + auto cullFunc = [pool, drawData, shadowPool, tagPool](EntityID entity) { + if (tagPool && tagPool->Has(entity)) { + if (!tagPool->Get(entity).globalEnabled) { + return; + } + } + const auto& lightComp = pool->Get(entity); - // if (!lightComp.enabled) return; - std::atomic_ref countRef(drawData->DirectionLights.cmdTemplate.instanceCount); uint32_t slot = countRef.fetch_add(1, std::memory_order_relaxed); diff --git a/SynapseEngine/Engine/System/Light/Direction/DirectionLightShadowCullingSystem.cpp b/SynapseEngine/Engine/System/Light/Direction/DirectionLightShadowCullingSystem.cpp index ea93fa9b..008832e7 100644 --- a/SynapseEngine/Engine/System/Light/Direction/DirectionLightShadowCullingSystem.cpp +++ b/SynapseEngine/Engine/System/Light/Direction/DirectionLightShadowCullingSystem.cpp @@ -24,6 +24,9 @@ #include "DirectionLightShadowAtlasSystem.h" #include "DirectionLightShadowSystem.h" +#include "Engine/Component/Core/TagComponent.h" +#include "Engine/System/Core/TagSystem.h" + namespace Syn { constexpr bool ENABLE_DEBUG_LOGGING = false; @@ -60,6 +63,7 @@ namespace Syn TypeInfo::ID, TypeInfo::ID, TypeInfo::ID, + TypeInfo::ID }; } @@ -94,6 +98,7 @@ namespace Syn auto animPool = registry->GetPool(); auto overridePool = registry->GetPool(); auto shadowPool = registry->GetPool(); + auto tagPool = registry->GetPool(); EntityID cameraEntity = scene->GetSceneCameraEntity(); if (!modelPool || !transformPool || !cameraPool || cameraEntity == NULL_ENTITY || !shadowPool) @@ -110,20 +115,29 @@ namespace Syn auto animationManager = ServiceLocator::GetAnimationManager(); auto materialManager = ServiceLocator::GetMaterialManager(); - auto modelSnapshot = modelManager->GetResourceSnapshot(); - auto animSnapshot = animationManager->GetResourceSnapshot(); - auto matTypeSnapshot = materialManager->GetRenderTypeSnapshot(); + auto& modelSnapshot = scene->GetSystemContext().modelSnapshots; + auto& animSnapshot = scene->GetSystemContext().animationSnapshots; + auto& matTypeSnapshot = scene->GetSystemContext().materialRenderTypes; // Extract entity properties (runs exactly once per entity) - auto withEntityData = [modelPool, transformPool, animPool, overridePool, modelSnapshot, animSnapshot, drawData] + auto withEntityData = [modelPool, transformPool, animPool, overridePool, modelSnapshot, tagPool, animSnapshot, drawData] (EntityID entity, auto&& nextFunc) { if (!modelPool->Has(entity)) return; const auto& modelComp = modelPool->Get(entity); + if (modelComp.modelIndex == NULL_INDEX || modelComp.modelIndex >= drawData->Models.modelAllocations.Size()) return; + if (tagPool && tagPool->Has(entity)) { + const auto& tag = tagPool->Get(entity); + + if (!tag.globalEnabled || !modelComp.castShadow) { + return; + } + } + const auto& snapshotEntry = modelSnapshot[modelComp.modelIndex]; if (snapshotEntry.resource == nullptr || snapshotEntry.state != ResourceState::Ready) return; @@ -426,7 +440,7 @@ namespace Syn auto& mainGroup = drawData->Models; auto& shadowGroup = drawData->DirectionLightShadow; - if (settings->culling.directionLightShadowCullingDevice == CPU) + if (settings->culling.directionLightShadowCullingDevice == CPU ) { // Sync CPU counters to indirect commands for (uint32_t i = 0; i < mainGroup.activeTraditionalCount; ++i) { @@ -437,10 +451,14 @@ namespace Syn shadowGroup.meshletCmds[i].groupCountX = shadowGroup.paddedMeshletCounts[i * 16]; } - // Upload instances - size_t instanceSize = mainGroup.totalAllocatedInstances * SHADOW_MULTIPLIER * sizeof(uint32_t); - if (instanceSize > 0) { - shadowGroup.instanceBuffer.Write(frameIndex, shadowGroup.instances.Data(), instanceSize, 0); + uint32_t activeShadowLightCount = drawData->DirectionLightShadow.visibleLightCount; + if (activeShadowLightCount != 0) + { + // Upload instances + size_t instanceSize = mainGroup.totalAllocatedInstances * SHADOW_MULTIPLIER * sizeof(uint32_t); + if (instanceSize > 0) { + shadowGroup.instanceBuffer.Write(frameIndex, shadowGroup.instances.Data(), instanceSize, 0); + } } } diff --git a/SynapseEngine/Engine/System/Light/Point/PointLightCullingSystem.cpp b/SynapseEngine/Engine/System/Light/Point/PointLightCullingSystem.cpp index 2da2a525..66ec8745 100644 --- a/SynapseEngine/Engine/System/Light/Point/PointLightCullingSystem.cpp +++ b/SynapseEngine/Engine/System/Light/Point/PointLightCullingSystem.cpp @@ -10,12 +10,16 @@ #include "Engine/Mesh/MeshSourceNames.h" #include +#include "Engine/Component/Core/TagComponent.h" +#include "Engine/System/Core/TagSystem.h" + namespace Syn { std::vector PointLightCullingSystem::GetReadDependencies() const { return { TypeInfo::ID, - TypeInfo::ID + TypeInfo::ID, + TypeInfo::ID, }; } @@ -33,6 +37,7 @@ namespace Syn auto pool = registry->GetPool(); auto shadowPool = registry->GetPool(); auto cameraPool = registry->GetPool(); + auto tagPool = registry->GetPool(); EntityID cameraEntity = scene->GetSceneCameraEntity(); if (!pool || !cameraPool || cameraEntity == NULL_ENTITY) return; @@ -58,7 +63,13 @@ namespace Syn glm::vec2 screenRes = glm::vec2(cameraComp.width, cameraComp.height); - auto cullFunc = [this, settings, pool, shadowPool, cameraComp, drawData, screenRes](EntityID entity) { + auto cullFunc = [this, settings, pool, shadowPool, cameraComp, drawData, screenRes, tagPool](EntityID entity) { + if (tagPool && tagPool->Has(entity)) { + if (!tagPool->Get(entity).globalEnabled) { + return; + } + } + const auto& lightComp = pool->Get(entity); bool visibility = true; diff --git a/SynapseEngine/Engine/System/Light/Point/PointLightShadowCullingSystem.cpp b/SynapseEngine/Engine/System/Light/Point/PointLightShadowCullingSystem.cpp index 21e59e7c..6dd21af5 100644 --- a/SynapseEngine/Engine/System/Light/Point/PointLightShadowCullingSystem.cpp +++ b/SynapseEngine/Engine/System/Light/Point/PointLightShadowCullingSystem.cpp @@ -26,6 +26,9 @@ #include #include +#include "Engine/Component/Core/TagComponent.h" +#include "Engine/System/Core/TagSystem.h" + namespace Syn { constexpr bool ENABLE_DEBUG_LOGGING = false; @@ -57,6 +60,7 @@ namespace Syn TypeInfo::ID, TypeInfo::ID, TypeInfo::ID, + TypeInfo::ID }; } @@ -98,6 +102,7 @@ namespace Syn auto overridePool = registry->GetPool(); auto shadowPool = registry->GetPool(); auto lightPool = registry->GetPool(); + auto tagPool = registry->GetPool(); EntityID cameraEntity = scene->GetSceneCameraEntity(); if (!modelPool || !transformPool || !cameraPool || cameraEntity == NULL_ENTITY || !shadowPool || !lightPool) return; @@ -112,18 +117,25 @@ namespace Syn auto animationManager = ServiceLocator::GetAnimationManager(); auto materialManager = ServiceLocator::GetMaterialManager(); - auto modelSnapshot = modelManager->GetResourceSnapshot(); - auto animSnapshot = animationManager->GetResourceSnapshot(); - auto matTypeSnapshot = materialManager->GetRenderTypeSnapshot(); + auto& modelSnapshot = scene->GetSystemContext().modelSnapshots; + auto& animSnapshot = scene->GetSystemContext().animationSnapshots; + auto& matTypeSnapshot = scene->GetSystemContext().materialRenderTypes; // Extract Entity Data (Runs once per entity) - auto withEntityData = [modelPool, transformPool, animPool, overridePool, modelSnapshot, animSnapshot, drawData] + auto withEntityData = [modelPool, transformPool, animPool, overridePool, modelSnapshot, tagPool, animSnapshot, drawData] (EntityID entity, auto&& nextFunc) { if (!modelPool->Has(entity)) return; const auto& modelComp = modelPool->Get(entity); if (modelComp.modelIndex == NULL_INDEX || modelComp.modelIndex >= drawData->Models.modelAllocations.Size()) return; + if (tagPool && tagPool->Has(entity)) { + const auto& tag = tagPool->Get(entity); + if (!tag.globalEnabled || !modelComp.castShadow) { + return; + } + } + const auto& snapshotEntry = modelSnapshot[modelComp.modelIndex]; if (snapshotEntry.resource == nullptr || snapshotEntry.state != ResourceState::Ready) return; diff --git a/SynapseEngine/Engine/System/Light/Spot/SpotLightCullingSystem.cpp b/SynapseEngine/Engine/System/Light/Spot/SpotLightCullingSystem.cpp index 5ae563ed..4c01b2ed 100644 --- a/SynapseEngine/Engine/System/Light/Spot/SpotLightCullingSystem.cpp +++ b/SynapseEngine/Engine/System/Light/Spot/SpotLightCullingSystem.cpp @@ -8,12 +8,16 @@ #include "Engine/Collision/Tester/CollisionTester.h" #include +#include "Engine/Component/Core/TagComponent.h" +#include "Engine/System/Core/TagSystem.h" + namespace Syn { std::vector SpotLightCullingSystem::GetReadDependencies() const { return { TypeInfo::ID, - TypeInfo::ID + TypeInfo::ID, + TypeInfo::ID }; } @@ -31,6 +35,7 @@ namespace Syn auto pool = registry->GetPool(); auto shadowPool = registry->GetPool(); auto cameraPool = registry->GetPool(); + auto tagPool = registry->GetPool(); EntityID cameraEntity = scene->GetSceneCameraEntity(); if (!pool || !cameraPool || cameraEntity == NULL_ENTITY) return; @@ -56,7 +61,13 @@ namespace Syn glm::vec2 screenRes = glm::vec2(cameraComp.width, cameraComp.height); - auto cullFunc = [this, settings, pool, cameraComp, drawData, screenRes, shadowPool](EntityID entity) { + auto cullFunc = [this, settings, pool, cameraComp, drawData, screenRes, shadowPool, tagPool](EntityID entity) { + if (tagPool && tagPool->Has(entity)) { + if (!tagPool->Get(entity).globalEnabled) { + return; + } + } + const auto& lightComp = pool->Get(entity); bool visibility = true; diff --git a/SynapseEngine/Engine/System/Light/Spot/SpotLightShadowCullingSystem.cpp b/SynapseEngine/Engine/System/Light/Spot/SpotLightShadowCullingSystem.cpp index d4d3c16d..94da96ea 100644 --- a/SynapseEngine/Engine/System/Light/Spot/SpotLightShadowCullingSystem.cpp +++ b/SynapseEngine/Engine/System/Light/Spot/SpotLightShadowCullingSystem.cpp @@ -26,6 +26,9 @@ #include #include +#include "Engine/Component/Core/TagComponent.h" +#include "Engine/System/Core/TagSystem.h" + namespace Syn { constexpr bool ENABLE_DEBUG_LOGGING = false; @@ -65,6 +68,7 @@ namespace Syn TypeInfo::ID, TypeInfo::ID, TypeInfo::ID, + TypeInfo::ID }; } @@ -106,6 +110,7 @@ namespace Syn auto overridePool = registry->GetPool(); auto shadowPool = registry->GetPool(); auto spotLightPool = registry->GetPool(); + auto tagPool = registry->GetPool(); EntityID cameraEntity = scene->GetSceneCameraEntity(); if (!modelPool || !transformPool || !cameraPool || cameraEntity == NULL_ENTITY || !shadowPool || !spotLightPool) return; @@ -120,18 +125,25 @@ namespace Syn auto animationManager = ServiceLocator::GetAnimationManager(); auto materialManager = ServiceLocator::GetMaterialManager(); - auto modelSnapshot = modelManager->GetResourceSnapshot(); - auto animSnapshot = animationManager->GetResourceSnapshot(); - auto matTypeSnapshot = materialManager->GetRenderTypeSnapshot(); + auto& modelSnapshot = scene->GetSystemContext().modelSnapshots; + auto& animSnapshot = scene->GetSystemContext().animationSnapshots; + auto& matTypeSnapshot = scene->GetSystemContext().materialRenderTypes; // Extract Entity Data (Runs once per entity) - auto withEntityData = [modelPool, transformPool, animPool, overridePool, modelSnapshot, animSnapshot, drawData] + auto withEntityData = [modelPool, transformPool, animPool, overridePool, modelSnapshot, tagPool, animSnapshot, drawData] (EntityID entity, auto&& nextFunc) { if (!modelPool->Has(entity)) return; const auto& modelComp = modelPool->Get(entity); if (modelComp.modelIndex == NULL_INDEX || modelComp.modelIndex >= drawData->Models.modelAllocations.Size()) return; + if (tagPool && tagPool->Has(entity)) { + const auto& tag = tagPool->Get(entity); + if (!tag.globalEnabled || !modelComp.castShadow) { + return; + } + } + const auto& snapshotEntry = modelSnapshot[modelComp.modelIndex]; if (snapshotEntry.resource == nullptr || snapshotEntry.state != ResourceState::Ready) return; diff --git a/SynapseEngine/Engine/System/Physics/ConvexColliderSystem.cpp b/SynapseEngine/Engine/System/Physics/ConvexColliderSystem.cpp index 1d2e1e35..e7a785b0 100644 --- a/SynapseEngine/Engine/System/Physics/ConvexColliderSystem.cpp +++ b/SynapseEngine/Engine/System/Physics/ConvexColliderSystem.cpp @@ -4,7 +4,6 @@ #include "Engine/Component/Physics/RigidBodyComponent.h" #include "Engine/System/Physics/RigidBodySystem.h" #include "Engine/Component/Rendering/ModelComponent.h" -#include "Engine/Mesh/ModelManager.h" #include "Engine/ServiceLocator.h" #include "Engine/Physics/IPhysicsEngine.h" #include "PhysicsUtils.h" @@ -36,12 +35,11 @@ namespace Syn auto transformPool = registry->GetPool(); auto modelPool = registry->GetPool(); auto physicsEngine = scene->GetPhysicsEngine(); - auto modelManager = ServiceLocator::GetModelManager(); - if (!convexPool || !rbPool || !transformPool || !modelPool || !physicsEngine || !modelManager) + if (!convexPool || !rbPool || !transformPool || !modelPool || !physicsEngine) return; - auto modelSnapshots = modelManager->GetResourceSnapshot(); + auto& modelSnapshots = scene->GetSystemContext().modelSnapshots; ParallelForEach(convexPool, subflow, SystemPhaseNames::Update, [convexPool, rbPool, transformPool, modelPool, physicsEngine, modelSnapshots](EntityID entity) { diff --git a/SynapseEngine/Engine/System/Physics/MeshColliderSystem.cpp b/SynapseEngine/Engine/System/Physics/MeshColliderSystem.cpp index 5a518bf6..76917d87 100644 --- a/SynapseEngine/Engine/System/Physics/MeshColliderSystem.cpp +++ b/SynapseEngine/Engine/System/Physics/MeshColliderSystem.cpp @@ -5,7 +5,6 @@ #include "Engine/System/Physics/RigidBodySystem.h" #include "Engine/System/Rendering/ModelSystem.h" #include "Engine/Component/Rendering/ModelComponent.h" -#include "Engine/Mesh/ModelManager.h" #include "Engine/ServiceLocator.h" #include "Engine/Physics/IPhysicsEngine.h" #include "PhysicsUtils.h" @@ -33,11 +32,10 @@ namespace Syn auto transformPool = registry->GetPool(); auto modelPool = registry->GetPool(); auto physicsEngine = scene->GetPhysicsEngine(); - auto modelManager = ServiceLocator::GetModelManager(); - if (!meshColliderPool || !rbPool || !transformPool || !modelPool || !physicsEngine || !modelManager) return; + if (!meshColliderPool || !rbPool || !transformPool || !modelPool || !physicsEngine) return; - auto modelSnapshots = modelManager->GetResourceSnapshot(); + auto& modelSnapshots = scene->GetSystemContext().modelSnapshots; ParallelForEach(meshColliderPool, subflow, SystemPhaseNames::Update, [meshColliderPool, rbPool, transformPool, modelPool, physicsEngine, modelSnapshots](EntityID entity) { diff --git a/SynapseEngine/Engine/System/Physics/RigidBodySystem.cpp b/SynapseEngine/Engine/System/Physics/RigidBodySystem.cpp index d9b45646..4abe3fb2 100644 --- a/SynapseEngine/Engine/System/Physics/RigidBodySystem.cpp +++ b/SynapseEngine/Engine/System/Physics/RigidBodySystem.cpp @@ -19,8 +19,6 @@ #include "Engine/System/Rendering/ModelSystem.h" #include "Engine/System/Core/TransformSystem.h" -#include "Engine/Mesh/ModelManager.h" - namespace Syn { std::vector RigidBodySystem::GetReadDependencies() const @@ -55,10 +53,9 @@ namespace Syn auto modelPool = registry->GetPool(); auto physicsEngine = scene->GetPhysicsEngine(); - auto modelManager = ServiceLocator::GetModelManager(); - if (!rbPool || !physicsEngine || !modelManager) return; - auto modelSnapshots = modelManager->GetResourceSnapshot(); + if (!rbPool || !physicsEngine) return; + auto& modelSnapshots = scene->GetSystemContext().modelSnapshots; ParallelForEach(rbPool, subflow, SystemPhaseNames::Update, [rbPool, transformPool, boxPool, spherePool, capsulePool, physicsEngine, convexPool, meshPool, modelPool, modelSnapshots](EntityID entity) { auto& rb = rbPool->Get(entity); diff --git a/SynapseEngine/Engine/System/Rendering/AnimationSystem.cpp b/SynapseEngine/Engine/System/Rendering/AnimationSystem.cpp index 9f5cd439..7f22afe4 100644 --- a/SynapseEngine/Engine/System/Rendering/AnimationSystem.cpp +++ b/SynapseEngine/Engine/System/Rendering/AnimationSystem.cpp @@ -1,6 +1,5 @@ #include "AnimationSystem.h" #include "Engine/ServiceLocator.h" -#include "Engine/Animation/AnimationManager.h" namespace Syn { @@ -14,8 +13,8 @@ namespace Syn auto animPool = registry->GetPool(); if (!animPool) return; - auto animationManager = ServiceLocator::GetAnimationManager(); - auto animations = animationManager->GetResourceSnapshot(); + const auto& ctx = scene->GetSystemContext(); + auto& animations = ctx.animationSnapshots; ParallelForEachIf(animPool, subflow, SystemPhaseNames::Update, [animPool, deltaTime, animations](EntityID entity) { auto& animComponent = animPool->Get(entity); diff --git a/SynapseEngine/Engine/System/Rendering/MaterialOverrideSystem.cpp b/SynapseEngine/Engine/System/Rendering/MaterialOverrideSystem.cpp new file mode 100644 index 00000000..409ef66e --- /dev/null +++ b/SynapseEngine/Engine/System/Rendering/MaterialOverrideSystem.cpp @@ -0,0 +1,8 @@ +#include "MaterialOverrideSystem.h" + +namespace Syn +{ + std::vector MaterialOverrideSystem::GetWriteDependencies() const { + return { TypeInfo::ID }; + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/System/Rendering/MaterialOverrideSystem.h b/SynapseEngine/Engine/System/Rendering/MaterialOverrideSystem.h new file mode 100644 index 00000000..ed23dfb9 --- /dev/null +++ b/SynapseEngine/Engine/System/Rendering/MaterialOverrideSystem.h @@ -0,0 +1,15 @@ +#pragma once +#include "Engine/System/ComponentSystem.h" +#include "Engine/Component/Rendering/MaterialOverrideComponent.h" + +namespace Syn +{ + class SYN_API MaterialOverrideSystem : public ComponentSystem + { + public: + std::string GetName() const override { return "MaterialOverrideSystem"; } + std::string GetGroup() const override { return SystemGroupNames::RenderingSystems; } + + std::vector GetWriteDependencies() const override; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/System/Rendering/MaterialSystem.cpp b/SynapseEngine/Engine/System/Rendering/MaterialSystem.cpp index 0866a860..7d45c9a8 100644 --- a/SynapseEngine/Engine/System/Rendering/MaterialSystem.cpp +++ b/SynapseEngine/Engine/System/Rendering/MaterialSystem.cpp @@ -4,11 +4,18 @@ #include "Engine/FrameContext.h" #include "Engine/Mesh/ModelManager.h" #include "Engine/Component/Rendering/MaterialOverrideComponent.h" +#include "Engine/Component/Core/TagComponent.h" +#include "MaterialOverrideSystem.h" namespace Syn { + constexpr bool ENABLE_DEBUG_LOGGING = false; + std::vector MaterialSystem::GetWriteDependencies() const { - return { TypeInfo::ID }; + return { + TypeInfo::ID, + TypeInfo::ID + }; } void MaterialSystem::OnUpdate(Scene* scene, uint32_t frameIndex, float deltaTime, tf::Subflow& subflow) @@ -18,32 +25,54 @@ namespace Syn if (!pool) return; auto overridePool = registry->GetPool(); + auto tagPool = registry->GetPool(); auto drawData = scene->GetSceneDrawData(); - auto modelManager = ServiceLocator::GetModelManager(); - uint32_t currentModelManagerVersion = modelManager->GetVersion(); - - //Todo: Override component changed -> Update?? + uint32_t currentModelManagerVersion = scene->GetSystemContext().modelManagerVersion; - this->EmplaceTask(subflow, SystemPhaseNames::Update, [this, scene, pool, modelManager, currentModelManagerVersion, drawData, overridePool]() { + this->EmplaceTask(subflow, SystemPhaseNames::Update, [this, scene, pool, tagPool, currentModelManagerVersion, drawData, overridePool]() { bool needsRebuild = false; + bool needsUpload = false; + if (_lastModelManagerVersion != currentModelManagerVersion) { needsRebuild = true; _lastModelManagerVersion = currentModelManagerVersion; + + if constexpr (ENABLE_DEBUG_LOGGING) { + Info("[MaterialSystem UPDATE] Frame {}: ModelManager version changed to {}", scene->GetSystemContext().frameIndex, currentModelManagerVersion); + } + } - if (!pool->IsStateBitSet() && !pool->IsStateBitSet() && !needsRebuild) { + bool materialOverrideHasChanges = !overridePool->GetDirtyStatics().empty() + || overridePool->IsStateBitSet() + || overridePool->IsStateBitSet(); + + bool modelHasChanges = !pool->GetDirtyStatics().empty() || + pool->IsStateBitSet() || + pool->IsStateBitSet(); + + bool hasChanges = materialOverrideHasChanges || modelHasChanges || needsRebuild; + + if (!hasChanges) { return; } - auto modelSnapshots = modelManager->GetResourceSnapshot(); + needsUpload = true; + auto& modelSnapshots = scene->GetSystemContext().modelSnapshots; uint32_t totalExactMaterials = 0; auto countFunc = [&](EntityID entity) { + bool isShared = overridePool && overridePool->Has(entity) && overridePool->Get(entity).sharedMaterialEntity != NULL_ENTITY; + if (isShared) return; + auto& comp = pool->Get(entity); - if (comp.modelIndex < modelSnapshots.size() && modelSnapshots[comp.modelIndex].resource) { - totalExactMaterials += static_cast(modelSnapshots[comp.modelIndex].resource->cpuData.meshMaterialIndices.size()); + if (comp.modelIndex == UINT32_MAX) return; + + const auto& snapshot = modelSnapshots[comp.modelIndex]; + if (snapshot.state == ResourceState::Ready && snapshot.resource) { + totalExactMaterials += static_cast(snapshot.resource->cpuData.meshMaterialIndices.size()); } }; @@ -51,17 +80,23 @@ namespace Syn for (auto e : pool->GetStorage().GetDynamicEntities()) countFunc(e); for (auto e : pool->GetStorage().GetStreamEntities()) countFunc(e); - //Info("MaterialSystem: Rebuilding material indices. Total materials expected: {}", totalExactMaterials); - + if constexpr (ENABLE_DEBUG_LOGGING) { + Info("[MaterialSystem UPDATE] Frame {}: Rebuilding material indices. Total slots expected: {}", scene->GetSystemContext().frameIndex, totalExactMaterials); + } + _flatMaterialIndices.resize(totalExactMaterials); uint32_t currentOffset = 0; auto processEntity = [&](EntityID entity) { + bool isShared = overridePool && overridePool->Has(entity) && overridePool->Get(entity).sharedMaterialEntity != NULL_ENTITY; + if (isShared) return; + auto& comp = pool->Get(entity); if (comp.modelIndex >= modelSnapshots.size()) return; - auto model = modelSnapshots[comp.modelIndex].resource; - if (!model) return; + const auto& snapshot = modelSnapshots[comp.modelIndex]; + if (snapshot.state != ResourceState::Ready || !snapshot.resource) return; + auto model = snapshot.resource; const auto& defaultMaterials = model->cpuData.meshMaterialIndices; uint32_t materialCount = static_cast(defaultMaterials.size()); @@ -77,22 +112,36 @@ namespace Syn overrides = overrideComp.materials; } - if (comp.materialOffset != currentOffset) { - comp.materialOffset = currentOffset; - comp.version++; - pool->SetBit(entity); - pool->MarkStaticDirty(entity); + if constexpr (ENABLE_DEBUG_LOGGING) { + std::string entityName = "Unknown"; + if (tagPool && tagPool->Has(entity)) entityName = tagPool->Get(entity).name; + Info("[MaterialSystem UPDATE] Frame {}: Entity {} data changed! OldOffset: {}, NewOffset: {}", scene->GetSystemContext().frameIndex, entityName, comp.materialOffset, currentOffset); } - //Info("MaterialSystem: Entity {} assigned offset: {}, material count: {}", (uint32_t)entity, currentOffset, materialCount); + comp.materialOffset = currentOffset; + comp.version++; + pool->SetBit(entity); + pool->MarkStaticDirty(entity); + + needsUpload = true; + + if constexpr (ENABLE_DEBUG_LOGGING) { + std::string entityName = "Unknown"; + if (tagPool && tagPool->Has(entity)) entityName = tagPool->Get(entity).name; + Info("MaterialSystem: Entity {} assigned offset: {}, material count: {}", entityName, currentOffset, materialCount); + } for (uint32_t i = 0; i < materialCount; ++i) { - if (!overrides.empty() && overrides[i] != UINT32_MAX) { - _flatMaterialIndices[currentOffset + i] = overrides[i]; + uint32_t matIdx = defaultMaterials[i]; + if (!overrides.empty() && i < overrides.size() && overrides[i] != UINT32_MAX) { + matIdx = overrides[i]; } - else { - _flatMaterialIndices[currentOffset + i] = defaultMaterials[i]; + + if constexpr (ENABLE_DEBUG_LOGGING) { + Info(" -> Slot {}: MatID {}", currentOffset + i, matIdx); } + + _flatMaterialIndices[currentOffset + i] = matIdx; } currentOffset += materialCount; @@ -102,9 +151,36 @@ namespace Syn for (auto e : pool->GetStorage().GetDynamicEntities()) processEntity(e); for (auto e : pool->GetStorage().GetStreamEntities()) processEntity(e); - uint32_t framesInFlight = ServiceLocator::GetFrameContext()->framesInFlight; - this->SetFramesToUpload(framesInFlight); - scene->GetSceneDrawData()->RequestGlobalSync(framesInFlight); + auto processSharedEntity = [&](EntityID entity) { + if (!overridePool || !overridePool->Has(entity)) return; + + EntityID sharedEntity = overridePool->Get(entity).sharedMaterialEntity; + if (sharedEntity == NULL_ENTITY) return; + + if (pool->Has(sharedEntity)) { + auto& comp = pool->Get(entity); + uint32_t masterOffset = pool->Get(sharedEntity).materialOffset; + + comp.materialOffset = masterOffset; + comp.version++; + pool->SetBit(entity); + pool->MarkStaticDirty(entity); + } + }; + + for (auto e : pool->GetStorage().GetStaticEntities()) processSharedEntity(e); + for (auto e : pool->GetStorage().GetDynamicEntities()) processSharedEntity(e); + for (auto e : pool->GetStorage().GetStreamEntities()) processSharedEntity(e); + + if (needsRebuild || needsUpload) { + uint32_t framesInFlight = ServiceLocator::GetFrameContext()->framesInFlight; + this->SetFramesToUpload(framesInFlight); + scene->GetSceneDrawData()->RequestGlobalSync(framesInFlight); + + if constexpr (ENABLE_DEBUG_LOGGING) { + Info("[MaterialSystem UPDATE] Frame {}: Requested global sync and GPU upload for {} frames.", scene->GetSystemContext().frameIndex, framesInFlight); + } + } }); } @@ -117,16 +193,30 @@ namespace Syn this->DecrementFramesToUpload(); } + if constexpr (ENABLE_DEBUG_LOGGING) { + Info("[MaterialSystem UPLOAD] Frame {}: Upload check. Force: {}, FlatIndicesSize: {}", frameIndex, force, _flatMaterialIndices.size()); + } + if (!force || _flatMaterialIndices.empty()) return; auto drawData = scene->GetSceneDrawData(); + size_t reqFromModels = drawData->Models.requiredMaterialBufferSize; + size_t actualElements = _flatMaterialIndices.size(); + size_t requiredElements = std::max(actualElements, reqFromModels); + + if constexpr (ENABLE_DEBUG_LOGGING) { + Info("[MaterialSystem UPLOAD] Frame {}: Resizing GPU buffer. Actual CPU Elements: {}, Req from Models: {}, Final GPU Elements: {}", frameIndex, actualElements, reqFromModels, requiredElements); + } - size_t requiredElements = std::max(_flatMaterialIndices.size(), (size_t)(drawData->Models.requiredMaterialBufferSize / sizeof(uint32_t))); drawData->Models.materialIndexBuffer.UpdateCapacity(frameIndex, requiredElements); size_t actualDataSize = _flatMaterialIndices.size() * sizeof(uint32_t); drawData->Models.materialIndexBuffer.Write(frameIndex, _flatMaterialIndices.data(), actualDataSize, 0); + + if constexpr (ENABLE_DEBUG_LOGGING) { + Info("[MaterialSystem UPLOAD] Frame {}: GPU buffer written successfully ({} bytes).", frameIndex, actualDataSize); + } }); } } \ No newline at end of file diff --git a/SynapseEngine/Engine/System/Rendering/ModelFrustumCullingSystem.cpp b/SynapseEngine/Engine/System/Rendering/ModelFrustumCullingSystem.cpp index 5ad0452a..e3cc0b54 100644 --- a/SynapseEngine/Engine/System/Rendering/ModelFrustumCullingSystem.cpp +++ b/SynapseEngine/Engine/System/Rendering/ModelFrustumCullingSystem.cpp @@ -5,14 +5,12 @@ #include "Engine/System/Rendering/ModelSystem.h" #include "Engine/System/Core/TransformSystem.h" #include "Engine/System/Rendering/RenderSystem.h" -#include "Engine/Mesh/ModelManager.h" #include "Engine/System/Core/CameraSystem.h" -#include "Engine/Animation/AnimationManager.h" #include "Engine/System/Rendering/AnimationSystem.h" #include "Engine/System/Rendering/MaterialSystem.h" #include "Engine/System/Core/StaticSpatialSahSystem.h" +#include "Engine/System/Core/TagSystem.h" -#include "Engine/Material/MaterialManager.h" #include "Engine/Component/Rendering/MaterialOverrideComponent.h" #include "Engine/Mesh/Utils/MeshUtils.h" @@ -23,6 +21,8 @@ namespace Syn { + constexpr bool ENABLE_DEBUG_LOGGING = false; + std::vector ModelFrustumCullingSystem::GetReadDependencies() const { return { TypeInfo::ID, @@ -31,7 +31,8 @@ namespace Syn TypeInfo::ID, TypeInfo::ID, TypeInfo::ID, - TypeInfo::ID + TypeInfo::ID, + TypeInfo::ID }; } @@ -39,8 +40,7 @@ namespace Syn { auto settings = scene->GetSettings(); auto drawData = scene->GetSceneDrawData(); - auto materialManager = ServiceLocator::GetMaterialManager(); - auto matTypeSnapshot = materialManager->GetRenderTypeSnapshot(); + auto matTypeSnapshot = scene->GetSystemContext().materialRenderTypes; auto overridePool = scene->GetRegistry()->GetPool(); tf::Task initTask = this->EmplaceTask(subflow, "Update Init", [drawData]() { @@ -61,26 +61,30 @@ namespace Syn return; } - auto modelManager = ServiceLocator::GetModelManager(); - auto animationManager = ServiceLocator::GetAnimationManager(); - auto registry = scene->GetRegistry(); auto modelPool = registry->GetPool(); auto transformPool = registry->GetPool(); auto cameraPool = registry->GetPool(); auto animPool = registry->GetPool(); + auto tagPool = registry->GetPool(); EntityID cameraEntity = scene->GetSceneCameraEntity(); if (!modelPool || !transformPool || !cameraPool || cameraEntity == NULL_ENTITY) return; const auto& cameraComp = cameraPool->Get(cameraEntity); - auto modelSnapshot = modelManager->GetResourceSnapshot(); - auto animSnapshot = animationManager->GetResourceSnapshot(); + auto& modelSnapshot = scene->GetSystemContext().modelSnapshots; + auto& animSnapshot = scene->GetSystemContext().animationSnapshots; glm::vec2 screenRes = glm::vec2(cameraComp.width, cameraComp.height); - auto cullFunc = [settings, drawData, modelPool, transformPool, modelSnapshot, cameraComp, animPool, animSnapshot, matTypeSnapshot, overridePool, screenRes] + auto cullFunc = [settings, drawData, modelPool, transformPool, modelSnapshot, cameraComp, animPool, tagPool, animSnapshot, matTypeSnapshot, overridePool, screenRes] (EntityID entity, IntersectionType chunkVisibility) { + if (tagPool && tagPool->Has(entity)) { + if (!tagPool->Get(entity).globalEnabled) { + return; + } + } + const FrustumCollider& frustum = cameraComp.frustum; const auto& transformComp = transformPool->Get(entity); @@ -189,6 +193,12 @@ namespace Syn MaterialRenderType matType = (matIdx < matTypeSnapshot.size()) ? matTypeSnapshot[matIdx] : MaterialRenderType::Opaque1Sided; + if constexpr (ENABLE_DEBUG_LOGGING) { + std::string name = "Unknown"; + if (tagPool && tagPool->Has(entity)) name = tagPool->Get(entity).name; + Info("[FrustumCulling] Visible in camera: Entity {} ({}) | First visible sub-mesh MatType: {}", (uint32_t)entity, name, (uint32_t)matType); + } + if (meshAlloc.activeTypes[matType]) { uint32_t slotIndex = 0; diff --git a/SynapseEngine/Engine/System/Rendering/ModelSystem.cpp b/SynapseEngine/Engine/System/Rendering/ModelSystem.cpp index d1c0c952..9c1f17d6 100644 --- a/SynapseEngine/Engine/System/Rendering/ModelSystem.cpp +++ b/SynapseEngine/Engine/System/Rendering/ModelSystem.cpp @@ -1,11 +1,13 @@ #include "ModelSystem.h" #include "MaterialSystem.h" #include "Engine/ServiceLocator.h" -#include "Engine/Mesh/ModelManager.h" #include "Engine/FrameContext.h" +#include "Engine/Component/Core/TagComponent.h" namespace Syn { + constexpr bool ENABLE_DEBUG_LOGGING = false; + std::vector ModelSystem::GetReadDependencies() const { return { TypeInfo::ID @@ -22,8 +24,7 @@ namespace Syn auto modelPool = registry->GetPool(); if (!modelPool) return; - auto modelManager = ServiceLocator::GetModelManager(); - uint32_t currentVersion = modelManager->GetVersion(); + uint32_t currentVersion = scene->GetSystemContext().modelManagerVersion; this->EmplaceTask(subflow, SystemPhaseNames::Update, [this, scene, currentVersion]() { if (_lastModelManagerVersion != currentVersion) { @@ -45,6 +46,7 @@ namespace Syn auto registry = scene->GetRegistry(); auto componentBufferManager = scene->GetComponentBufferManager(); auto modelPool= registry->GetPool(); + auto tagPool = registry->GetPool(); if (!modelPool) return; auto modelDataBuffer = componentBufferManager->GetComponentBuffer(BufferNames::ModelData, frameIndex); @@ -53,12 +55,19 @@ namespace Syn bool forceUpload = this->ShouldForceUpload(); - auto processUpload = [modelPool, modelDataBuffer, modelDataBufferHandler, forceUpload](EntityID entity) { + auto processUpload = [modelPool, tagPool, modelDataBuffer, modelDataBufferHandler, forceUpload, scene](EntityID entity) { auto& modelComponent = modelPool->Get(entity); auto modelIndex = modelPool->GetMapping().Get(entity); if (forceUpload || modelDataBuffer.versions[modelIndex] != modelComponent.version) { + if constexpr (ENABLE_DEBUG_LOGGING) { + std::string name = "Unknown"; + if (tagPool && tagPool->Has(entity)) name = tagPool->Get(entity).name; + + Info("[ModelSystem UPLOAD] Entity: {} ({}) | Material offset: {}", (uint32_t)entity, name, modelComponent.materialOffset); + } + modelDataBuffer.versions[modelIndex] = modelComponent.version; modelDataBufferHandler[modelIndex] = ModelComponentGPU(entity, modelComponent); } @@ -66,7 +75,11 @@ namespace Syn }; ForEachStream(modelPool, subflow, SystemPhaseNames::UploadGPU, processUpload); - if (uploadDynamic) ForEachDynamic(modelPool, subflow, SystemPhaseNames::UploadGPU, processUpload); - if (uploadStatic) ForEachStatic(modelPool, subflow, SystemPhaseNames::UploadGPU, processUpload); + + if (uploadDynamic) + ForEachDynamic(modelPool, subflow, SystemPhaseNames::UploadGPU, processUpload); + + if (uploadStatic) + ForEachStatic(modelPool, subflow, SystemPhaseNames::UploadGPU, processUpload); } } \ No newline at end of file diff --git a/SynapseEngine/Engine/System/Rendering/RenderSystem.cpp b/SynapseEngine/Engine/System/Rendering/RenderSystem.cpp index e5aee327..431acc65 100644 --- a/SynapseEngine/Engine/System/Rendering/RenderSystem.cpp +++ b/SynapseEngine/Engine/System/Rendering/RenderSystem.cpp @@ -2,10 +2,7 @@ #include "Engine/Scene/Scene.h" #include "Engine/Component/Rendering/ModelComponent.h" #include "Engine/ServiceLocator.h" -#include "Engine/Mesh/ModelManager.h" -#include "Engine/Material/MaterialManager.h" #include "Engine/System/Rendering/ModelSystem.h" -#include "Engine/ServiceLocator.h" #include "Engine/FrameContext.h" #include "MaterialSystem.h" #include "Engine/Component/Rendering/MaterialOverrideComponent.h" @@ -32,16 +29,13 @@ namespace Syn auto overridePool = registry->GetPool(); if (!pool) return; - auto modelManager = ServiceLocator::GetModelManager(); - auto materialManager = ServiceLocator::GetMaterialManager(); - - uint32_t totalModels = static_cast(modelManager->GetResourceCount()); - uint32_t currentModelManagerVersion = modelManager->GetVersion(); - uint32_t currentMaterialManagerVersion = materialManager->GetVersion(); + uint32_t totalModels = static_cast(scene->GetSystemContext().modelSnapshots.size()); + uint32_t currentModelManagerVersion = scene->GetSystemContext().modelManagerVersion; + uint32_t currentMaterialManagerVersion = scene->GetSystemContext().materialManagerVersion; - this->EmplaceTask(subflow, SystemPhaseNames::Update, [this, scene, pool, overridePool, modelManager, materialManager, totalModels, currentModelManagerVersion, currentMaterialManagerVersion]() { - auto modelSnapshots = modelManager->GetResourceSnapshot(); - auto matTypeSnapshot = materialManager->GetRenderTypeSnapshot(); + this->EmplaceTask(subflow, SystemPhaseNames::Update, [this, scene, pool, overridePool, totalModels, currentModelManagerVersion, currentMaterialManagerVersion]() { + auto& modelSnapshots = scene->GetSystemContext().modelSnapshots; + auto& matTypeSnapshot = scene->GetSystemContext().materialRenderTypes; if (_lastModelManagerVersion != currentModelManagerVersion) { _needsRebuild = true; @@ -77,8 +71,9 @@ namespace Syn { if(_entitiesPerModel[modelId].empty() || modelId >= modelSnapshots.size()) continue; - auto model = modelSnapshots[modelId].resource; - if (!model) continue; + const auto& snapshot = modelSnapshots[modelId]; + if (snapshot.state != ResourceState::Ready || !snapshot.resource) continue; + auto model = snapshot.resource; uint32_t meshCount = model->cpuData.globalMeshCount; if (_meshMatCapacities[modelId].size() < meshCount) { @@ -147,10 +142,8 @@ namespace Syn void RenderSystem::RebuildGlobalBuffers(Scene* scene) { - auto modelManager = ServiceLocator::GetModelManager(); auto drawData = scene->GetSceneDrawData(); - auto modelSnapshots = modelManager->GetResourceSnapshot(); - + auto& modelSnapshots = scene->GetSystemContext().modelSnapshots; drawData->Models.activeDescriptorCount = 0; @@ -165,8 +158,10 @@ namespace Syn for (uint32_t modelId = 0; modelId < _modelCapacities.size(); ++modelId) { if (_modelCapacities[modelId] == 0 || modelId >= modelSnapshots.size()) continue; - auto model = modelSnapshots[modelId].resource; - if (!model) continue; + + const auto& snapshot = modelSnapshots[modelId]; + if (snapshot.state != ResourceState::Ready || !snapshot.resource) continue; + auto model = snapshot.resource; const auto& blueprints = model->cpuData.baseDrawCommands; for (size_t i = 0; i < blueprints.size(); ++i) { @@ -320,7 +315,7 @@ namespace Syn drawData->Models.totalAllocatedInstances = globalInstanceOffset; drawData->Debug.totalMaxMeshletInstances = totalMaxMeshletInstances; - drawData->Models.requiredMaterialBufferSize = totalMaterialIndicesCapacity * sizeof(uint32_t); + drawData->Models.requiredMaterialBufferSize = totalMaterialIndicesCapacity; if (drawData->Models.instances.Size() < globalInstanceOffset) { drawData->Models.instances.Resize(globalInstanceOffset); diff --git a/SynapseEngine/Engine/System/SystemContext.cpp b/SynapseEngine/Engine/System/SystemContext.cpp new file mode 100644 index 00000000..2321db1a --- /dev/null +++ b/SynapseEngine/Engine/System/SystemContext.cpp @@ -0,0 +1 @@ +#include "SystemContext.h" \ No newline at end of file diff --git a/SynapseEngine/Engine/System/SystemContext.h b/SynapseEngine/Engine/System/SystemContext.h new file mode 100644 index 00000000..0faaff76 --- /dev/null +++ b/SynapseEngine/Engine/System/SystemContext.h @@ -0,0 +1,22 @@ +#pragma once +#include "Engine/SynApi.h" +#include "Engine/Material/MaterialManager.h" +#include "Engine/Mesh/ModelManager.h" +#include "Engine/Animation/AnimationManager.h" +#include + +namespace Syn { + struct SYN_API SystemContext { + float deltaTime; + uint32_t frameIndex; + + uint32_t modelManagerVersion; + uint32_t materialManagerVersion; + uint32_t animationManagerVersion; + + std::vector materialRenderTypes; + std::vector::ResourceSnapshot> modelSnapshots; + std::vector::ResourceSnapshot> materialSnapshots; + std::vector::ResourceSnapshot> animationSnapshots; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Utils/RenderBuffer.cpp b/SynapseEngine/Engine/Utils/RenderBuffer.cpp index 0fe50d7f..163f7272 100644 --- a/SynapseEngine/Engine/Utils/RenderBuffer.cpp +++ b/SynapseEngine/Engine/Utils/RenderBuffer.cpp @@ -1,4 +1,5 @@ #include "RenderBuffer.h" +#include namespace Syn { @@ -25,6 +26,10 @@ namespace Syn gpuConfig.useDeviceAddress = (_config.usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT) != 0; for (uint32_t i = 0; i < _config.frames; ++i) { + if (!_config.debugName.empty()) { + mappedConfig.debugName = std::format("{}_Mapped_F{}", _config.debugName, i); + } + if (_config.strategy != BufferStrategy::GpuOnly) { _mapped.push_back(std::make_unique(mappedConfig, _config.elementSize, _config.upWindow, _config.downWindow)); } @@ -32,6 +37,10 @@ namespace Syn _mapped.push_back(nullptr); } + if (!_config.debugName.empty()) { + gpuConfig.debugName = std::format("{}_GPU_F{}", _config.debugName, i); + } + if (_config.strategy != BufferStrategy::MappedOnly) { _gpu.push_back(std::make_unique(gpuConfig, _config.elementSize, _config.upWindow, _config.downWindow)); } diff --git a/SynapseEngine/Engine/Utils/RenderBuffer.h b/SynapseEngine/Engine/Utils/RenderBuffer.h index bc71d3dd..7343c560 100644 --- a/SynapseEngine/Engine/Utils/RenderBuffer.h +++ b/SynapseEngine/Engine/Utils/RenderBuffer.h @@ -22,6 +22,7 @@ namespace Syn }; struct SYN_API RenderBufferConfig { + std::string debugName = ""; BufferStrategy strategy = BufferStrategy::Hybrid; uint32_t frames = 0; uint32_t elementSize = 0; diff --git a/SynapseEngine/Engine/Vk/Buffer/Buffer.h b/SynapseEngine/Engine/Vk/Buffer/Buffer.h index 75e5dc2e..52f380cf 100644 --- a/SynapseEngine/Engine/Vk/Buffer/Buffer.h +++ b/SynapseEngine/Engine/Vk/Buffer/Buffer.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include "../VkCommon.h" namespace Syn::Vk { @@ -7,6 +8,7 @@ namespace Syn::Vk { class BufferFactory; struct SYN_API BufferConfig { + std::string debugName = ""; VkDeviceSize size = 0; VkBufferUsageFlags usage = 0; VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO; diff --git a/SynapseEngine/Engine/Vk/Buffer/BufferFactory.cpp b/SynapseEngine/Engine/Vk/Buffer/BufferFactory.cpp index 1c379cf6..1d8c4104 100644 --- a/SynapseEngine/Engine/Vk/Buffer/BufferFactory.cpp +++ b/SynapseEngine/Engine/Vk/Buffer/BufferFactory.cpp @@ -43,6 +43,14 @@ namespace Syn::Vk { buffer->_persistentMappedData = allocResultInfo.pMappedData; buffer->_isMapped = true; } + + if (!buffer->GetConfig().debugName.empty()) { + device->SetDebugName( + VK_OBJECT_TYPE_BUFFER, + (uint64_t)buffer->Handle(), + buffer->GetConfig().debugName.c_str() + ); + } } std::unique_ptr BufferFactory::Create(const BufferConfig& config) { diff --git a/SynapseEngine/Engine/Vk/Core/Device.cpp b/SynapseEngine/Engine/Vk/Core/Device.cpp index 6de38a68..60e17c09 100644 --- a/SynapseEngine/Engine/Vk/Core/Device.cpp +++ b/SynapseEngine/Engine/Vk/Core/Device.cpp @@ -25,6 +25,7 @@ namespace Syn::Vk { VkPhysicalDeviceMeshShaderFeaturesEXT meshFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MESH_SHADER_FEATURES_EXT }; meshFeatures.meshShader = VK_TRUE; meshFeatures.taskShader = VK_TRUE; + meshFeatures.meshShaderQueries = VK_TRUE; VkPhysicalDeviceShaderObjectFeaturesEXT shaderObjectFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT }; shaderObjectFeatures.shaderObject = VK_TRUE; @@ -203,4 +204,17 @@ namespace Syn::Vk { void Device::WaitIdle() const { vkDeviceWaitIdle(_handle); } + + void Device::SetDebugName(VkObjectType objectType, uint64_t objectHandle, const char* name) const { + if constexpr (!Syn::EnableLogging) { + return; + } + + VkDebugUtilsObjectNameInfoEXT nameInfo{ VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT }; + nameInfo.objectType = objectType; + nameInfo.objectHandle = objectHandle; + nameInfo.pObjectName = name; + + vkSetDebugUtilsObjectNameEXT(_handle, &nameInfo); + } } \ No newline at end of file diff --git a/SynapseEngine/Engine/Vk/Core/Device.h b/SynapseEngine/Engine/Vk/Core/Device.h index fdfff13f..86bef913 100644 --- a/SynapseEngine/Engine/Vk/Core/Device.h +++ b/SynapseEngine/Engine/Vk/Core/Device.h @@ -15,6 +15,7 @@ namespace Syn::Vk { ThreadSafeQueue* GetComputeQueue() const { return _computeQueue.get(); } ThreadSafeQueue* GetTransferQueue() const { return _transferQueue.get(); } void WaitIdle() const; + void SetDebugName(VkObjectType objectType, uint64_t objectHandle, const char* name) const; private: void InitVMA(VkInstance instance, const PhysicalDevice& physicalDevice); private: diff --git a/SynapseEngine/Engine/Vk/Core/Instance.cpp b/SynapseEngine/Engine/Vk/Core/Instance.cpp index 01e207e2..793a26f8 100644 --- a/SynapseEngine/Engine/Vk/Core/Instance.cpp +++ b/SynapseEngine/Engine/Vk/Core/Instance.cpp @@ -70,7 +70,6 @@ namespace Syn::Vk { if (_validationEnabled) extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); - std::vector layers; if (_validationEnabled) layers.push_back("VK_LAYER_KHRONOS_validation"); diff --git a/SynapseEngine/Engine/Vk/Descriptor/DescriptorBuffer.cpp b/SynapseEngine/Engine/Vk/Descriptor/DescriptorBuffer.cpp index 8f74d3bb..1db57c61 100644 --- a/SynapseEngine/Engine/Vk/Descriptor/DescriptorBuffer.cpp +++ b/SynapseEngine/Engine/Vk/Descriptor/DescriptorBuffer.cpp @@ -3,6 +3,7 @@ #include "Engine/Vk/Context.h" #include "Engine/Vk/Core/Device.h" #include "Engine/Vk/Buffer/BufferFactory.h" +#include "Engine/Vk/Buffer/BufferUtils.h" namespace Syn::Vk { @@ -22,13 +23,32 @@ namespace Syn::Vk { VkDeviceSize layoutSizeInBytes = 0; vkGetDescriptorSetLayoutSizeEXT(device->Handle(), _layout, &layoutSizeInBytes); - - VkBufferUsageFlags usage = - VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT | - VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT | - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT; - - _buffer = BufferFactory::CreatePersistent(layoutSizeInBytes, usage); + _layoutSizeInBytes = layoutSizeInBytes; + + VkBufferUsageFlags gpuUsage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT | + VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT | + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT; + + BufferConfig mappedConfig; + mappedConfig.size = _layoutSizeInBytes; + mappedConfig.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + mappedConfig.memoryUsage = VMA_MEMORY_USAGE_AUTO; + mappedConfig.allocationFlags = VMA_ALLOCATION_CREATE_MAPPED_BIT | VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT; + mappedConfig.useDeviceAddress = false; + + BufferConfig gpuConfig{}; + gpuConfig.size = _layoutSizeInBytes; + gpuConfig.usage = gpuUsage | VK_BUFFER_USAGE_TRANSFER_DST_BIT; + gpuConfig.memoryUsage = VMA_MEMORY_USAGE_AUTO_PREFER_DEVICE; + gpuConfig.allocationFlags = 0; + gpuConfig.useDeviceAddress = true; + + _mapped = std::make_shared(mappedConfig); + _gpu = std::make_shared(gpuConfig); + _gpuConfig = gpuConfig; + _mappedConfig = mappedConfig; + _isDirty = true; } void DescriptorBuffer::FillSampledImages(uint32_t binding, uint32_t count, VkImageView view, VkImageLayout layout) @@ -44,7 +64,7 @@ namespace Syn::Vk { VkDeviceSize bindingOffset; vkGetDescriptorSetLayoutBindingOffsetEXT(device->Handle(), _layout, binding, &bindingOffset); - void* mappedData = _buffer->Map(); + void* mappedData = _mapped->Map(); char* targetBaseAddress = static_cast(mappedData) + bindingOffset; std::vector descriptorPayload(_sampledImageSize); @@ -53,19 +73,25 @@ namespace Syn::Vk { for (uint32_t i = 0; i < count; ++i) { std::memcpy(targetBaseAddress + (i * _sampledImageSize), descriptorPayload.data(), _sampledImageSize); } + + _isDirty = true; } void DescriptorBuffer::WriteDescriptor(uint32_t binding, uint32_t arrayElement, size_t descriptorSize, const VkDescriptorGetInfoEXT& getInfo) { + std::lock_guard lock(_bufferMutex); + auto device = ServiceLocator::GetVkContext()->GetDevice(); VkDeviceSize bindingOffset; vkGetDescriptorSetLayoutBindingOffsetEXT(device->Handle(), _layout, binding, &bindingOffset); - void* mappedData = _buffer->Map(); + void* mappedData = _mapped->Map(); char* targetAddress = static_cast(mappedData) + bindingOffset + (arrayElement * descriptorSize); vkGetDescriptorEXT(device->Handle(), &getInfo, descriptorSize, targetAddress); + + _isDirty = true; } void DescriptorBuffer::WriteCombinedImageSampler(uint32_t binding, uint32_t arrayElement, VkImageView view, VkSampler sampler, VkImageLayout layout) @@ -132,7 +158,7 @@ namespace Syn::Vk { void DescriptorBuffer::Bind(VkCommandBuffer cmd, VkPipelineLayout pipelineLayout, uint32_t setIndex, VkPipelineBindPoint bindPoint) { VkDescriptorBufferBindingInfoEXT bindingInfo{ VK_STRUCTURE_TYPE_DESCRIPTOR_BUFFER_BINDING_INFO_EXT }; - bindingInfo.address = _buffer->GetDeviceAddress(); + bindingInfo.address = _gpu->GetDeviceAddress(); bindingInfo.usage = VK_BUFFER_USAGE_RESOURCE_DESCRIPTOR_BUFFER_BIT_EXT | VK_BUFFER_USAGE_SAMPLER_DESCRIPTOR_BUFFER_BIT_EXT; vkCmdBindDescriptorBuffersEXT(cmd, 1, &bindingInfo); @@ -142,4 +168,33 @@ namespace Syn::Vk { vkCmdSetDescriptorBufferOffsetsEXT(cmd, bindPoint, pipelineLayout, setIndex, 1, &bufferIndex, &offset); } + + StaleDescriptorBuffers DescriptorBuffer::RecordSync(VkCommandBuffer cmd) + { + std::lock_guard lock(_bufferMutex); + + if (!_isDirty) return { nullptr, nullptr }; + + auto staleGpu = _gpu; + auto staleMapped = _mapped; + + _gpu = std::make_shared(_gpuConfig); + _mapped = std::make_shared(_mappedConfig); + + void* oldData = staleMapped->Map(); + void* newData = _mapped->Map(); + std::memcpy(newData, oldData, _layoutSizeInBytes); + + BufferCopyInfo copyInfo{}; + copyInfo.srcBuffer = _mapped->Handle(); + copyInfo.dstBuffer = _gpu->Handle(); + copyInfo.size = _layoutSizeInBytes; + copyInfo.srcOffset = 0; + copyInfo.dstOffset = 0; + + BufferUtils::CopyBuffer(cmd, copyInfo); + + _isDirty = false; + return { staleMapped, staleGpu }; + } } \ No newline at end of file diff --git a/SynapseEngine/Engine/Vk/Descriptor/DescriptorBuffer.h b/SynapseEngine/Engine/Vk/Descriptor/DescriptorBuffer.h index 84f07993..854fa4f7 100644 --- a/SynapseEngine/Engine/Vk/Descriptor/DescriptorBuffer.h +++ b/SynapseEngine/Engine/Vk/Descriptor/DescriptorBuffer.h @@ -2,9 +2,15 @@ #include "../VkCommon.h" #include "Engine/Vk/Buffer/Buffer.h" #include +#include namespace Syn::Vk { + struct SYN_API StaleDescriptorBuffers { + std::shared_ptr mapped; + std::shared_ptr gpu; + }; + class SYN_API DescriptorBuffer { public: DescriptorBuffer(VkDescriptorSetLayout layout); @@ -13,7 +19,7 @@ namespace Syn::Vk { DescriptorBuffer(const DescriptorBuffer&) = delete; DescriptorBuffer& operator=(const DescriptorBuffer&) = delete; - Buffer* GetBuffer() const { return _buffer.get(); } + Buffer* GetBuffer() const { return _gpu.get(); } void FillSampledImages(uint32_t binding, uint32_t count, VkImageView view, VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); void WriteCombinedImageSampler(uint32_t binding, uint32_t arrayElement, VkImageView view, VkSampler sampler, VkImageLayout layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); @@ -21,16 +27,25 @@ namespace Syn::Vk { void WriteSampler(uint32_t binding, uint32_t arrayElement, VkSampler sampler); void WriteBuffer(uint32_t binding, uint32_t arrayElement, VkBuffer buffer, VkDeviceSize offset, VkDeviceSize range, VkDescriptorType type); void Bind(VkCommandBuffer cmd, VkPipelineLayout pipelineLayout, uint32_t setIndex = 0, VkPipelineBindPoint bindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS); + StaleDescriptorBuffers RecordSync(VkCommandBuffer cmd); private: void WriteDescriptor(uint32_t binding, uint32_t arrayElement, size_t descriptorSize, const VkDescriptorGetInfoEXT& getInfo); private: - std::unique_ptr _buffer; VkDescriptorSetLayout _layout; + size_t _layoutSizeInBytes = 0; + + bool _isDirty = false; + std::shared_ptr _mapped; + std::shared_ptr _gpu; + Vk::BufferConfig _gpuConfig; + Vk::BufferConfig _mappedConfig; size_t _combinedImageSamplerSize = 0; size_t _sampledImageSize = 0; size_t _samplerSize = 0; size_t _storageBufferSize = 0; size_t _uniformBufferSize = 0; + + std::mutex _bufferMutex; }; } \ No newline at end of file diff --git a/SynapseEngine/Engine/Vk/Query/PipelineStatisticsQueryPool.cpp b/SynapseEngine/Engine/Vk/Query/PipelineStatisticsQueryPool.cpp new file mode 100644 index 00000000..f1e1b467 --- /dev/null +++ b/SynapseEngine/Engine/Vk/Query/PipelineStatisticsQueryPool.cpp @@ -0,0 +1,21 @@ +#include "PipelineStatisticsQueryPool.h" +#include + +namespace Syn::Vk +{ + PipelineStatisticsQueryPool::PipelineStatisticsQueryPool(uint32_t queryCount, VkQueryPipelineStatisticFlags flags) + : QueryPool(VK_QUERY_TYPE_PIPELINE_STATISTICS, queryCount, flags), _flags(flags) + {} + + void PipelineStatisticsQueryPool::BeginQuery(VkCommandBuffer cmd, uint32_t queryIndex) { + vkCmdBeginQuery(cmd, _handle, queryIndex, 0); + } + + void PipelineStatisticsQueryPool::EndQuery(VkCommandBuffer cmd, uint32_t queryIndex) { + vkCmdEndQuery(cmd, _handle, queryIndex); + } + + uint32_t PipelineStatisticsQueryPool::GetStride() const { + return std::popcount(static_cast(_flags)) * sizeof(uint64_t); + } +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Vk/Query/PipelineStatisticsQueryPool.h b/SynapseEngine/Engine/Vk/Query/PipelineStatisticsQueryPool.h new file mode 100644 index 00000000..5d2f1c29 --- /dev/null +++ b/SynapseEngine/Engine/Vk/Query/PipelineStatisticsQueryPool.h @@ -0,0 +1,19 @@ +#pragma once +#include "../VkCommon.h" +#include "QueryPool.h" + +namespace Syn::Vk +{ + class SYN_API PipelineStatisticsQueryPool : public QueryPool { + public: + PipelineStatisticsQueryPool(uint32_t queryCount, VkQueryPipelineStatisticFlags flags); + + void BeginQuery(VkCommandBuffer cmd, uint32_t queryIndex); + void EndQuery(VkCommandBuffer cmd, uint32_t queryIndex); + VkQueryPipelineStatisticFlags GetFlags() const { return _flags; } + protected: + uint32_t GetStride() const override; + private: + VkQueryPipelineStatisticFlags _flags; + }; +} \ No newline at end of file diff --git a/SynapseEngine/Engine/Vk/Query/QueryPool.cpp b/SynapseEngine/Engine/Vk/Query/QueryPool.cpp index 339dbb08..a6963058 100644 --- a/SynapseEngine/Engine/Vk/Query/QueryPool.cpp +++ b/SynapseEngine/Engine/Vk/Query/QueryPool.cpp @@ -32,6 +32,10 @@ namespace Syn::Vk bool QueryPool::GetResults(uint32_t firstQuery, uint32_t count, std::vector& outResults, bool wait) { auto device = ServiceLocator::GetVkContext()->GetDevice(); + uint32_t stride = GetStride(); + uint32_t statsPerQuery = stride / sizeof(uint64_t); + uint32_t requiredElements = count * statsPerQuery; + if (outResults.size() < count) { outResults.resize(count); } @@ -49,7 +53,7 @@ namespace Syn::Vk count, outResults.size() * sizeof(uint64_t), outResults.data(), - sizeof(uint64_t), + stride, flags ); diff --git a/SynapseEngine/Engine/Vk/Query/QueryPool.h b/SynapseEngine/Engine/Vk/Query/QueryPool.h index c146e670..79f923e7 100644 --- a/SynapseEngine/Engine/Vk/Query/QueryPool.h +++ b/SynapseEngine/Engine/Vk/Query/QueryPool.h @@ -19,6 +19,7 @@ namespace Syn::Vk VkQueryType GetType() const { return _type; } protected: QueryPool(VkQueryType type, uint32_t queryCount, VkQueryPipelineStatisticFlags pipelineStats = 0); + virtual uint32_t GetStride() const { return sizeof(uint64_t); } protected: VkQueryType _type; uint32_t _queryCount = 0; diff --git a/SynapseEngine/Engine/imgui.ini b/SynapseEngine/Engine/imgui.ini new file mode 100644 index 00000000..f87d64c5 --- /dev/null +++ b/SynapseEngine/Engine/imgui.ini @@ -0,0 +1,140 @@ +[Window][HostWindow_Scene] +Pos=0,23 +Size=2304,1273 +Collapsed=0 + +[Window][Debug##Default] +Pos=60,60 +Size=400,400 +Collapsed=0 + +[Window][ Inspector] +Pos=1883,23 +Size=421,633 +Collapsed=0 +DockId=0x00000005,0 + +[Window][ Graphics & Environment] +Pos=1883,658 +Size=421,638 +Collapsed=0 +DockId=0x00000006,0 + +[Window][ Scene Hierarchy] +Pos=0,23 +Size=470,278 +Collapsed=0 +DockId=0x00000009,0 + +[Window][ Performance Profiler] +Pos=0,303 +Size=470,993 +Collapsed=0 +DockId=0x0000000A,0 + +[Window][ Output Log] +Pos=472,787 +Size=1409,509 +Collapsed=0 +DockId=0x00000002,1 + +[Window][Content_Scene] +Pos=472,787 +Size=1409,509 +Collapsed=0 +DockId=0x00000002,0 + +[Window][ Viewport] +Pos=472,23 +Size=1409,762 +Collapsed=0 +DockId=0x00000001,0 + +[Table][0x3D1A1C69,2] +RefScale=13 +Column 0 Width=147 +Column 1 Weight=1.0000 + +[Table][0x6925898D,2] +RefScale=13 +Column 0 Width=217 +Column 1 Weight=1.0000 + +[Table][0xE847EDF4,2] +RefScale=13 +Column 0 Width=140 +Column 1 Weight=1.0000 + +[Table][0x182B970D,2] +RefScale=13 +Column 0 Width=0 +Column 1 Weight=-nan(ind) + +[Table][0x03404476,2] +RefScale=13 +Column 0 Width=0 +Column 1 Weight=-nan(ind) + +[Table][0x8556BC1A,2] +RefScale=13 +Column 0 Width=0 +Column 1 Weight=-nan(ind) + +[Table][0x51A78E48,2] +RefScale=13 +Column 0 Weight=1.0000 +Column 1 Width=32 + +[Table][0xB6D16E5C,3] +RefScale=13 + +[Table][0x05A9070B,4] +RefScale=13 +Column 0 Width=140 +Column 1 Width=60 +Column 2 Width=150 +Column 3 Weight=1.0000 + +[Table][0x94CE371A,2] +RefScale=13 +Column 0 Width=63 +Column 1 Weight=1.0000 + +[Table][0x5A9ED35A,2] +RefScale=13 +Column 0 Width=0 +Column 1 Weight=-nan(ind) + +[Table][0xF8524FE2,2] +RefScale=13 +Column 0 Width=0 +Column 1 Weight=-nan(ind) + +[Table][0xA047510E,2] +RefScale=13 +Column 0 Width=0 +Column 1 Weight=-nan(ind) + +[Table][0x32EB459A,2] +RefScale=13 +Column 0 Width=0 +Column 1 Weight=-nan(ind) + +[Table][0x243E03DF,2] +RefScale=13 +Column 0 Width=0 +Column 1 Weight=-nan(ind) + +[Docking][Data] +DockSpace ID=0x4713F8A8 Window=0xFBC4AE05 Pos=128,95 Size=2304,1273 Split=X Selected=0x1C1AF642 + DockNode ID=0x00000007 Parent=0x4713F8A8 SizeRef=470,1273 Split=Y Selected=0x02B8E2DB + DockNode ID=0x00000009 Parent=0x00000007 SizeRef=470,278 Selected=0xF995F4A5 + DockNode ID=0x0000000A Parent=0x00000007 SizeRef=470,993 Selected=0x02B8E2DB + DockNode ID=0x00000008 Parent=0x4713F8A8 SizeRef=1832,1273 Split=X + DockNode ID=0x00000003 Parent=0x00000008 SizeRef=1881,1273 Split=Y + DockNode ID=0x00000001 Parent=0x00000003 SizeRef=2304,762 CentralNode=1 Selected=0x1C1AF642 + DockNode ID=0x00000002 Parent=0x00000003 SizeRef=2304,509 Selected=0x81DECE6A + DockNode ID=0x00000004 Parent=0x00000008 SizeRef=421,1273 Split=Y Selected=0x57A55B3F + DockNode ID=0x00000005 Parent=0x00000004 SizeRef=421,633 Selected=0x70CE1A73 + DockNode ID=0x00000006 Parent=0x00000004 SizeRef=421,638 Selected=0x57A55B3F + diff --git a/SynapseEngine/Synapse_MaterialGraph.json b/SynapseEngine/Synapse_MaterialGraph.json index 314f09cc..853f7d31 100644 --- a/SynapseEngine/Synapse_MaterialGraph.json +++ b/SynapseEngine/Synapse_MaterialGraph.json @@ -1 +1 @@ -{"nodes":{"node:1":{"location":{"x":0,"y":0}},"node:10":{"location":{"x":0,"y":0}},"node:12":{"location":{"x":0,"y":0}},"node:14":{"location":{"x":0,"y":0}},"node:16":{"location":{"x":0,"y":0}},"node:18":{"location":{"x":0,"y":0}},"node:20":{"location":{"x":0,"y":0}},"node:22":{"location":{"x":0,"y":0}},"node:24":{"location":{"x":0,"y":0}},"node:26":{"location":{"x":0,"y":0}},"node:28":{"location":{"x":0,"y":0}},"node:8":{"location":{"x":0,"y":0}}},"selection":["node:28"],"view":{"scroll":{"x":-0.000213623046875,"y":0},"visible_rect":{"max":{"x":2303.999755859375,"y":1273},"min":{"x":-0.000213623046875,"y":0}},"zoom":1}} \ No newline at end of file +{"nodes":{"node:1":{"location":{"x":0,"y":0}},"node:4":{"location":{"x":0,"y":0}}},"selection":null,"view":{"scroll":{"x":-119.161598205566406,"y":0},"visible_rect":{"max":{"x":870.3157958984375,"y":1250},"min":{"x":-182.3157958984375,"y":0}},"zoom":0.653599977493286133}} \ No newline at end of file diff --git a/SynapseEngine/UnitTests/TestHierarchy.cpp b/SynapseEngine/UnitTests/TestHierarchy.cpp index c3ac8e94..6c5cd9ca 100644 --- a/SynapseEngine/UnitTests/TestHierarchy.cpp +++ b/SynapseEngine/UnitTests/TestHierarchy.cpp @@ -1,6 +1,6 @@ #include #include "Engine/Registry/Registry.h" -#include "Engine/Scene/HierarchyManager.h" +#include "Engine/Scene/Hierarchy/HierarchyManager.h" #include "Engine/Component/Core/HierarchyComponent.h" using namespace Syn; diff --git a/SynapseEngine/imgui.ini b/SynapseEngine/imgui.ini index dc6bf48b..b3eaf243 100644 --- a/SynapseEngine/imgui.ini +++ b/SynapseEngine/imgui.ini @@ -1,86 +1,159 @@ -[Window][WindowOverViewport_11111111] +[Window][HostWindow_Scene] Pos=0,23 Size=2304,1273 Collapsed=0 -[Window][Debug##Default] -Pos=60,60 -Size=400,400 -Collapsed=0 - [Window][ Inspector] -Pos=1468,23 -Size=452,490 +Pos=1811,23 +Size=493,630 Collapsed=0 -DockId=0x00000005,0 +DockId=0x00000007,0 [Window][ Viewport] -Pos=407,23 -Size=1059,680 +Pos=464,23 +Size=1345,842 Collapsed=0 -DockId=0x00000001,0 +DockId=0x00000003,0 -[Window][ Graphics & Environment] -Pos=1468,515 -Size=452,494 +[Window][Debug##Default] +Pos=60,60 +Size=400,400 +Collapsed=0 + +[Window][Content_Scene] +Pos=464,867 +Size=1345,429 Collapsed=0 -DockId=0x00000006,0 +DockId=0x00000004,0 -[Window][Material Graph] -Pos=440,23 -Size=1410,907 +[Window][ Graphics & Environment] +Pos=1811,655 +Size=493,641 Collapsed=0 -DockId=0x08BD597D,1 +DockId=0x00000008,0 [Window][ Scene Hierarchy] Pos=0,23 -Size=405,532 +Size=462,658 Collapsed=0 DockId=0x00000009,0 [Window][ Performance Profiler] -Pos=0,557 -Size=405,452 +Pos=0,683 +Size=462,613 Collapsed=0 DockId=0x0000000A,0 -[Window][ Content Browser] -Pos=440,932 -Size=1410,364 +[Window][ Output Log] +Pos=464,867 +Size=1345,429 Collapsed=0 -DockId=0x08BD597D,0 +DockId=0x00000004,1 -[Window][ Output Log] -Pos=407,705 -Size=1059,304 +[Window][HostWindow_Material] +Pos=0,23 +Size=2304,1273 Collapsed=0 -DockId=0x00000002,0 -[Window][HostWindow_Scene] +[Window][Content_Material] +Pos=494,865 +Size=1810,431 +Collapsed=0 +DockId=0x0000000E,0 + +[Window][ Materials] Pos=0,23 -Size=1920,986 +Size=492,655 Collapsed=0 +DockId=0x0000000B,0 -[Window][###Content_Scene] -Pos=407,705 -Size=1059,304 +[Window][ Material Graph] +Pos=1616,23 +Size=688,840 Collapsed=0 -DockId=0x00000002,1 +DockId=0x00000012,0 -[Table][0x51A78E48,2] -RefScale=13 -Column 0 Weight=1.0000 -Column 1 Width=48 +[Window][ Material Viewport] +Pos=494,23 +Size=1120,840 +Collapsed=0 +DockId=0x00000011,0 -[Table][0xB6D16E5C,3] -RefScale=13 -Column 0 Weight=0.7557 -Column 1 Width=91 -Column 2 Weight=0.2443 +[Window][ Material Properties] +Pos=0,680 +Size=492,616 +Collapsed=0 +DockId=0x0000000C,0 + +[Window][HostWindow_Model] +Pos=0,23 +Size=2304,1273 +Collapsed=0 + +[Window][Content_Model] +Pos=409,923 +Size=1496,373 +Collapsed=0 +DockId=0x00000014,0 + +[Window][ Model Hierarchy] +Pos=0,23 +Size=610,1273 +Collapsed=0 +DockId=0x00000017,0 + +[Window][ Model Properties##ModelPropsWindow] +Pos=1907,23 +Size=397,1273 +Collapsed=0 +DockId=0x00000016,0 + +[Window][HostWindow_Texture] +Pos=0,23 +Size=2304,1273 +Collapsed=0 + +[Window][Content_Texture] +Pos=60,60 +Size=276,222 +Collapsed=0 + +[Window][ Textures] +Pos=60,60 +Size=32,67 +Collapsed=0 + +[Window][ Texture Properties] +Pos=60,60 +Size=32,67 +Collapsed=0 + +[Window][ Texture Graph] +Pos=60,60 +Size=32,32 +Collapsed=0 + +[Window][ Model Viewport] +Pos=409,23 +Size=1496,898 +Collapsed=0 +DockId=0x00000013,0 + +[Window][ Models] +Pos=0,23 +Size=407,735 +Collapsed=0 +DockId=0x0000001B,0 + +[Window][ Internal Hierarchy] +Pos=0,760 +Size=407,536 +Collapsed=0 +DockId=0x0000001C,0 [Table][0x3D1A1C69,2] RefScale=13 -Column 0 Width=100 +Column 0 Width=147 Column 1 Weight=1.0000 [Table][0x6925898D,2] @@ -90,29 +163,40 @@ Column 1 Weight=1.0000 [Table][0xE847EDF4,2] RefScale=13 -Column 0 Width=100 +Column 0 Width=140 Column 1 Weight=1.0000 [Table][0x182B970D,2] RefScale=13 -Column 0 Width=100 -Column 1 Weight=-nan(ind) +Column 0 Width=168 +Column 1 Weight=1.0000 -[Table][0x8556BC1A,2] +[Table][0x03404476,2] RefScale=13 -Column 0 Width=100 -Column 1 Weight=-nan(ind) +Column 0 Width=126 +Column 1 Weight=1.0000 -[Table][0x94CE371A,2] +[Table][0x8556BC1A,2] RefScale=13 -Column 0 Width=100 +Column 0 Width=175 Column 1 Weight=1.0000 -[Table][0x5A9ED35A,2] +[Table][0xCC86EC87,2] RefScale=13 -Column 0 Width=100 +Column 0 Width=140 Column 1 Weight=1.0000 +[Table][0x51A78E48,2] +RefScale=13 +Column 0 Weight=1.0000 +Column 1 Width=48 + +[Table][0xB6D16E5C,3] +RefScale=13 +Column 0 Weight=0.5346 +Column 1 Width=58 +Column 2 Weight=0.4654 + [Table][0x05A9070B,4] RefScale=13 Column 0 Width=140 @@ -120,32 +204,127 @@ Column 1 Width=60 Column 2 Width=150 Column 3 Weight=1.0000 -[Table][0x5806762E,2] +[Table][0x94CE371A,2] RefScale=13 -Column 0 Width=100 +Column 0 Width=63 Column 1 Weight=1.0000 -[Table][0x50E67774,2] +[Table][0x5A9ED35A,2] +RefScale=13 +Column 0 Width=56 +Column 1 Weight=1.0000 + +[Table][0xF8524FE2,2] RefScale=13 -Column 0 Width=100 +Column 0 Width=98 Column 1 Weight=1.0000 +[Table][0xA047510E,2] +RefScale=13 +Column 0 Width=91 +Column 1 Weight=1.0000 + +[Table][0x32EB459A,2] +RefScale=13 +Column 0 Width=0 +Column 1 Weight=-nan(ind) + +[Table][0x243E03DF,2] +RefScale=13 +Column 0 Width=0 +Column 1 Weight=-nan(ind) + +[Table][0x9543A694,1] +Column 0 Weight=1.0000 + +[Table][0x8A428527,2] +RefScale=13 +Column 0 Width=126 +Column 1 Weight=1.0000 + +[Table][0xFFF52B67,2] +RefScale=13 +Column 0 Width=119 +Column 1 Weight=1.0000 + +[Table][0x748E37A9,2] +RefScale=13 +Column 0 Weight=1.0000 +Column 1 Width=45 + +[Table][0xF10D0EE1,2] +RefScale=13 +Column 0 Width=63 +Column 1 Weight=1.0000 + +[Table][0x22DE21CA,1] +Column 0 Weight=1.0000 + +[Table][0xD16AD86C,2] +RefScale=13 +Column 0 Width=63 +Column 1 Weight=1.0000 + +[Table][0xEA33DFC0,2] +RefScale=13 +Column 0 Width=70 +Column 1 Weight=1.0000 + +[Table][0xFFF76F10,2] +RefScale=13 +Column 0 Width=84 +Column 1 Weight=1.0000 + +[Table][0x5806762E,2] +RefScale=13 +Column 0 Width=84 +Column 1 Weight=1.0000 + +[Table][0x132E0EDB,2] +RefScale=13 +Column 0 Width=0 +Column 1 Weight=-nan(ind) + [Table][0x78D40C46,2] RefScale=13 -Column 0 Width=100 +Column 0 Width=135 +Column 1 Weight=1.0000 + +[Table][0x6EB26338,2] +RefScale=13 +Column 0 Width=84 Column 1 Weight=1.0000 [Docking][Data] -DockSpace ID=0x08BD597D Pos=128,95 Size=2304,1273 CentralNode=1 -DockSpace ID=0x4713F8A8 Window=0xFBC4AE05 Pos=-1920,237 Size=1920,986 Split=X Selected=0x1C1AF642 - DockNode ID=0x00000007 Parent=0x4713F8A8 SizeRef=405,1273 Split=Y Selected=0xF995F4A5 - DockNode ID=0x00000009 Parent=0x00000007 SizeRef=437,687 Selected=0xF995F4A5 - DockNode ID=0x0000000A Parent=0x00000007 SizeRef=437,584 Selected=0x02B8E2DB - DockNode ID=0x00000008 Parent=0x4713F8A8 SizeRef=1513,1273 Split=X - DockNode ID=0x00000003 Parent=0x00000008 SizeRef=1059,1273 Split=Y - DockNode ID=0x00000001 Parent=0x00000003 SizeRef=2304,680 CentralNode=1 Selected=0x1C1AF642 - DockNode ID=0x00000002 Parent=0x00000003 SizeRef=2304,304 Selected=0x81DECE6A - DockNode ID=0x00000004 Parent=0x00000008 SizeRef=452,1273 Split=Y Selected=0x57A55B3F - DockNode ID=0x00000005 Parent=0x00000004 SizeRef=452,633 Selected=0x70CE1A73 - DockNode ID=0x00000006 Parent=0x00000004 SizeRef=452,638 Selected=0x57A55B3F +DockSpace ID=0x1B7E3B2F Window=0xDCD75C92 Pos=128,95 Size=2304,1273 Split=X + DockNode ID=0x0000000F Parent=0x1B7E3B2F SizeRef=492,1273 Split=Y Selected=0xF8059156 + DockNode ID=0x0000000B Parent=0x0000000F SizeRef=542,655 Selected=0xF8059156 + DockNode ID=0x0000000C Parent=0x0000000F SizeRef=542,616 Selected=0x59113670 + DockNode ID=0x00000010 Parent=0x1B7E3B2F SizeRef=1810,1273 Split=Y + DockNode ID=0x0000000D Parent=0x00000010 SizeRef=1922,840 Split=X Selected=0x6F3619D2 + DockNode ID=0x00000011 Parent=0x0000000D SizeRef=1120,840 CentralNode=1 Selected=0x6F3619D2 + DockNode ID=0x00000012 Parent=0x0000000D SizeRef=688,840 Selected=0x814C861D + DockNode ID=0x0000000E Parent=0x00000010 SizeRef=1922,431 Selected=0x4B58EA58 +DockSpace ID=0x4713F8A8 Window=0xFBC4AE05 Pos=128,95 Size=2304,1273 Split=X Selected=0x1C1AF642 + DockNode ID=0x00000005 Parent=0x4713F8A8 SizeRef=462,1273 Split=Y Selected=0x02B8E2DB + DockNode ID=0x00000009 Parent=0x00000005 SizeRef=442,658 Selected=0xF995F4A5 + DockNode ID=0x0000000A Parent=0x00000005 SizeRef=442,613 Selected=0x02B8E2DB + DockNode ID=0x00000006 Parent=0x4713F8A8 SizeRef=1840,1273 Split=X + DockNode ID=0x00000001 Parent=0x00000006 SizeRef=1345,1273 Split=Y Selected=0x1C1AF642 + DockNode ID=0x00000003 Parent=0x00000001 SizeRef=1901,842 CentralNode=1 Selected=0x1C1AF642 + DockNode ID=0x00000004 Parent=0x00000001 SizeRef=1901,429 Selected=0x81DECE6A + DockNode ID=0x00000002 Parent=0x00000006 SizeRef=493,1273 Split=Y Selected=0x70CE1A73 + DockNode ID=0x00000007 Parent=0x00000002 SizeRef=401,630 Selected=0x70CE1A73 + DockNode ID=0x00000008 Parent=0x00000002 SizeRef=401,641 Selected=0x57A55B3F +DockSpace ID=0x64578384 Window=0xD880D529 Pos=128,95 Size=2304,1273 Split=X + DockNode ID=0x00000019 Parent=0x64578384 SizeRef=407,1273 Split=Y Selected=0x8F684317 + DockNode ID=0x0000001B Parent=0x00000019 SizeRef=407,735 Selected=0x8F684317 + DockNode ID=0x0000001C Parent=0x00000019 SizeRef=407,536 Selected=0x92BE6F94 + DockNode ID=0x0000001A Parent=0x64578384 SizeRef=1895,1273 Split=X + DockNode ID=0x00000017 Parent=0x0000001A SizeRef=610,1273 Selected=0x7B451746 + DockNode ID=0x00000018 Parent=0x0000001A SizeRef=1692,1273 Split=X + DockNode ID=0x00000015 Parent=0x00000018 SizeRef=1496,1273 Split=Y + DockNode ID=0x00000013 Parent=0x00000015 SizeRef=2304,898 CentralNode=1 Selected=0x8D543EF8 + DockNode ID=0x00000014 Parent=0x00000015 SizeRef=2304,373 Selected=0xB3A6D868 + DockNode ID=0x00000016 Parent=0x00000018 SizeRef=397,1273 Selected=0x54E69AFF diff --git a/SynapseEngine/synapse_stats.txt b/SynapseEngine/synapse_stats.txt index 6d164063..f11d4d47 100644 --- a/SynapseEngine/synapse_stats.txt +++ b/SynapseEngine/synapse_stats.txt @@ -1,10 +1,10 @@ -github.com/AlDanial/cloc v 2.08 T=7.97 s (187.4 files/s, 9899.4 lines/s) +github.com/AlDanial/cloc v 2.08 T=31.49 s (56.6 files/s, 2959.7 lines/s) ------------------------------------------------------------------------------- Language files blank comment code ------------------------------------------------------------------------------- -C++ 617 8277 702 36598 -C/C++ Header 706 3132 96 18645 -GLSL 170 2532 615 8277 +C++ 746 9977 732 44116 +C/C++ Header 851 3686 100 21819 +GLSL 186 2815 631 9324 ------------------------------------------------------------------------------- -SUM: 1493 13941 1413 63520 +SUM: 1783 16478 1463 75259 ------------------------------------------------------------------------------- diff --git a/SynapseEngine/xmake.lua b/SynapseEngine/xmake.lua index e541db7a..e6bf2d41 100644 --- a/SynapseEngine/xmake.lua +++ b/SynapseEngine/xmake.lua @@ -119,6 +119,7 @@ local vcpkg_packages = { "vcpkg::tinyxml2", "vcpkg::yaml-cpp", "vcpkg::tomlplusplus", + "vcpkg::nanosvg" } for _, pkg in ipairs(vcpkg_packages) do @@ -171,6 +172,30 @@ target("Editor") add_deps("Engine", "EditorCore") set_rundir("$(projectdir)") + on_load(function (target) + local asset_dir = path.join(os.projectdir(), "Assets") + + if not os.isdir(asset_dir) then + import("net.http") + import("utils.archive.extract") + + local zip_path = path.join(os.projectdir(), "Assets.zip") + local url = "https://github.com/TamasPetii/SynapseEngine/releases/latest/download/Assets.zip" + + http.download(url, zip_path) + + print(" Download complete! Extracting to: " .. os.projectdir()) + + extract(zip_path, os.projectdir()) + + os.rm(zip_path) + + print("=================================================") + print(" Assets successfully downloaded and installed!") + print("=================================================") + end + end) + target("UnitTests") set_kind("binary") add_files("UnitTests/**.cpp")