From 290672159b4a71e1e49d0b3d2d7b8ff33cc96473 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Fri, 1 May 2026 19:02:25 +0800 Subject: [PATCH] refactor: advance runtime and pipeline architecture split --- .../AssetDatabase/Facade}/AssetDatabase.cpp | 1013 ++--------------- .../Core/AssetDatabase/Facade/AssetDatabase.h | 211 ++++ .../Import/AssetDatabaseImport.cpp | 393 +++++++ .../Import/AssetDatabaseImport.h | 33 + .../Maintenance/AssetDatabaseMaintenance.cpp | 215 ++++ .../Maintenance/AssetDatabaseMaintenance.h | 26 + .../Shared/AssetDatabaseShared.cpp | 287 +++++ .../Shared/AssetDatabaseShared.h | 56 + .../Stores/AssetDatabaseStores.cpp | 435 +++++++ .../Stores/AssetDatabaseStores.h | 55 + .../Contracts/IProjectAssetPipelineService.h | 29 + .../Core/Contracts/IProjectAssetResolver.h | 29 + Pipeline/Core/Contracts/ProjectAssetTypes.h | 66 ++ .../ImportService}/AssetImportService.cpp | 666 ++++++----- .../Core/ImportService/AssetImportService.h | 76 ++ .../ProjectAssetService.cpp | 153 +++ .../ProjectAssetService/ProjectAssetService.h | 51 + .../Core/SourceIndex}/ProjectAssetIndex.cpp | 32 +- Pipeline/Core/SourceIndex/ProjectAssetIndex.h | 33 + ...e-rendering-framedata-structure-subplan.md | 107 ++ docs/plan/target-architecture.md | 56 +- engine/CMakeLists.txt | 306 +++-- .../Asset/AssetManager}/ResourceManager.cpp | 162 ++- .../Asset/AssetManager/ResourceManager.h | 185 +++ .../Asset/AsyncLoad}/AsyncLoader.cpp | 6 +- engine/Runtime/Asset/AsyncLoad/AsyncLoader.h | 108 ++ .../Asset/ResourceStore}/ResourceCache.cpp | 5 +- .../Asset/ResourceStore/ResourceCache.h | 64 ++ .../Caches/DirectionalShadowSurfaceCache.cpp | 4 +- .../Caches/DirectionalShadowSurfaceCache.h | 51 + .../Rendering/Caches/RenderResourceCache.cpp | 2 +- .../Rendering/Caches/RenderResourceCache.h | 160 +++ .../Rendering/FrameData/CullingResults.h | 104 ++ .../Rendering/FrameData/RenderCameraData.h | 54 + .../FrameData/RenderEnvironmentData.h | 55 + .../Rendering/FrameData/RenderSceneData.h | 107 ++ .../Rendering/FrameData/RendererListUtils.h | 219 ++++ .../FrameData/VisibleGaussianSplatItem.h | 30 + .../Rendering/FrameData/VisibleRenderItem.h | 35 + .../Rendering/FrameData/VisibleVolumeItem.h | 30 + .../Materials/RenderMaterialResolve.h | 509 +++++++++ .../Materials/RenderMaterialStateUtils.h | 311 +++++ .../Runtime/Rendering/Picking/ObjectIdCodec.h | 56 + .../Picking/RenderObjectIdRegistry.cpp | 2 +- .../Picking/RenderObjectIdRegistry.h | 48 + .../Shadow/DirectionalShadowData.cpp | 2 +- .../Rendering/Shadow/DirectionalShadowData.h | 82 ++ .../Shadow/DirectionalShadowRuntime.cpp | 3 +- .../Shadow/DirectionalShadowRuntime.h | 30 + .../Resources/AudioClip/AudioClip.cpp | 2 +- .../Runtime/Resources/AudioClip/AudioClip.h | 105 ++ .../Resources/AudioClip/AudioLoader.cpp | 6 +- .../Runtime/Resources/AudioClip/AudioLoader.h | 26 + .../Resources/Material/Material.cpp | 5 +- engine/Runtime/Resources/Material/Material.h | 221 ++++ .../Resources/Material/MaterialLoader.cpp | 10 +- .../Resources/Material/MaterialLoader.h | 26 + .../Resources/Material/MaterialRenderState.h | 147 +++ .../{src => Runtime}/Resources/Mesh/Mesh.cpp | 6 +- engine/Runtime/Resources/Mesh/Mesh.h | 112 ++ .../Resources/Mesh/MeshImportSettings.cpp | 2 +- .../Resources/Mesh/MeshImportSettings.h | 85 ++ .../Resources/Mesh/MeshLoader.cpp | 18 +- engine/Runtime/Resources/Mesh/MeshLoader.h | 22 + .../Shader/Internal/ShaderArtifactLoader.cpp | 0 .../Shader/Internal/ShaderArtifactLoader.h | 0 .../ShaderAuthoringDirectiveUtils.cpp | 0 .../Shader/Internal/ShaderAuthoringInternal.h | 0 .../Shader/Internal/ShaderAuthoringLoader.cpp | 0 .../Shader/Internal/ShaderAuthoringLoader.h | 0 .../Internal/ShaderAuthoringParserCore.cpp | 0 .../Shader/Internal/ShaderAuthoringShared.cpp | 0 .../Internal/ShaderAuthoringTextUtils.cpp | 0 .../Shader/Internal/ShaderFileUtils.cpp | 4 +- .../Shader/Internal/ShaderFileUtils.h | 2 +- .../Internal/ShaderRuntimeBuildUtils.cpp | 4 +- .../Shader/Internal/ShaderRuntimeBuildUtils.h | 3 +- .../Resources/Shader/Shader.cpp | 2 +- engine/Runtime/Resources/Shader/Shader.h | 201 ++++ .../Shader/ShaderAuthoringParser.cpp | 0 .../Resources/Shader/ShaderAuthoringParser.h | 0 .../Shader/ShaderCompilationCache.cpp | 14 +- .../Resources/Shader/ShaderCompilationCache.h | 92 ++ .../Resources/Shader/ShaderIR.h | 3 +- .../Resources/Shader/ShaderLoader.cpp | 12 +- .../Runtime/Resources/Shader/ShaderLoader.h | 32 + .../Resources/Shader/ShaderSourceUtils.cpp | 2 +- .../Resources/Shader/ShaderSourceUtils.h | 3 +- .../Resources/Texture/Texture.cpp | 2 +- engine/Runtime/Resources/Texture/Texture.h | 73 ++ .../Texture/TextureImportSettings.cpp | 2 +- .../Resources/Texture/TextureImportSettings.h | 91 ++ .../Resources/Texture/TextureLoader.cpp | 8 +- .../Runtime/Resources/Texture/TextureLoader.h | 28 + .../Scene/ModelSceneInstantiation.cpp | 7 +- .../Runtime/Scene/ModelSceneInstantiation.h | 37 + engine/{src => Runtime}/Scene/RuntimeLoop.cpp | 2 +- engine/Runtime/Scene/RuntimeLoop.h | 47 + engine/{src => Runtime}/Scene/Scene.cpp | 66 +- engine/Runtime/Scene/Scene.h | 122 ++ .../{src => Runtime}/Scene/SceneManager.cpp | 18 +- engine/Runtime/Scene/SceneManager.h | 49 + .../{src => Runtime}/Scene/SceneRuntime.cpp | 6 +- engine/Runtime/Scene/SceneRuntime.h | 73 ++ .../ArtifactContainer}/ArtifactContainer.cpp | 2 +- .../ArtifactContainer/ArtifactContainer.h | 105 ++ .../Asset/AssetGUID}/AssetGUID.cpp | 2 +- engine/Shared/Asset/AssetGUID/AssetGUID.h | 54 + .../ResourceDependencyGraph.cpp | 2 +- .../DependencyGraph/ResourceDependencyGraph.h | 56 + .../Asset/ResourceType}/ResourceTypes.cpp | 2 +- .../Shared/Asset/ResourceType/ResourceTypes.h | 114 ++ .../XCEngine/Core/Asset/ArtifactContainer.h | 104 +- .../XCEngine/Core/Asset/AssetDatabase.h | 203 +--- .../include/XCEngine/Core/Asset/AssetGUID.h | 53 +- .../XCEngine/Core/Asset/AssetImportService.h | 106 +- .../include/XCEngine/Core/Asset/AsyncLoader.h | 107 +- .../Core/Asset/IProjectAssetPipelineService.h | 3 + .../Core/Asset/IProjectAssetResolver.h | 3 + .../XCEngine/Core/Asset/ProjectAssetIndex.h | 36 +- .../XCEngine/Core/Asset/ProjectAssetService.h | 3 + .../XCEngine/Core/Asset/ProjectAssetTypes.h | 3 + .../XCEngine/Core/Asset/ResourceCache.h | 63 +- .../Core/Asset/ResourceDependencyGraph.h | 55 +- .../XCEngine/Core/Asset/ResourceManager.h | 190 +--- .../XCEngine/Core/Asset/ResourceTypes.h | 113 +- .../Caches/DirectionalShadowSurfaceCache.h | 50 +- .../Rendering/Caches/RenderResourceCache.h | 159 +-- .../Rendering/FrameData/CullingResults.h | 103 +- .../Rendering/FrameData/RenderCameraData.h | 53 +- .../FrameData/RenderEnvironmentData.h | 54 +- .../Rendering/FrameData/RenderSceneData.h | 105 +- .../Rendering/FrameData/RendererListUtils.h | 217 +--- .../FrameData/VisibleGaussianSplatItem.h | 29 +- .../Rendering/FrameData/VisibleRenderItem.h | 33 +- .../Rendering/FrameData/VisibleVolumeItem.h | 29 +- .../Materials/RenderMaterialResolve.h | 508 +-------- .../Materials/RenderMaterialStateUtils.h | 310 +---- .../Rendering/Picking/ObjectIdCodec.h | 55 +- .../Picking/RenderObjectIdRegistry.h | 46 +- .../Rendering/Shadow/DirectionalShadowData.h | 81 +- .../Shadow/DirectionalShadowRuntime.h | 28 +- .../XCEngine/Resources/AudioClip/AudioClip.h | 104 +- .../Resources/AudioClip/AudioLoader.h | 25 +- .../XCEngine/Resources/Material/Material.h | 216 +--- .../Resources/Material/MaterialLoader.h | 24 +- .../Resources/Material/MaterialRenderState.h | 146 +-- engine/include/XCEngine/Resources/Mesh/Mesh.h | 111 +- .../Resources/Mesh/MeshImportSettings.h | 84 +- .../XCEngine/Resources/Mesh/MeshLoader.h | 21 +- .../XCEngine/Resources/Shader/Shader.h | 199 +--- .../Resources/Shader/ShaderCompilationCache.h | 90 +- .../XCEngine/Resources/Shader/ShaderLoader.h | 30 +- .../XCEngine/Resources/Texture/Texture.h | 72 +- .../Resources/Texture/TextureImportSettings.h | 90 +- .../Resources/Texture/TextureLoader.h | 27 +- .../XCEngine/Scene/ModelSceneInstantiation.h | 36 +- engine/include/XCEngine/Scene/RuntimeLoop.h | 46 +- engine/include/XCEngine/Scene/Scene.h | 120 +- engine/include/XCEngine/Scene/SceneManager.h | 47 +- engine/include/XCEngine/Scene/SceneRuntime.h | 71 +- .../src/Components/AudioSourceComponent.cpp | 2 +- engine/src/Components/CameraComponent.cpp | 2 +- engine/src/Components/GameObject.cpp | 2 +- .../GaussianSplatRendererComponent.cpp | 2 + engine/src/Components/TransformComponent.cpp | 2 +- engine/src/Core/IO/IResourceLoader.cpp | 4 +- .../src/Physics/PhysX/PhysXWorldBackend.cpp | 2 +- engine/src/Physics/PhysicsWorld.cpp | 2 +- .../Rendering/Execution/CameraRenderer.cpp | 6 +- .../Extraction/RenderSceneExtractor.cpp | 2 +- .../Extraction/RenderSceneUtility.cpp | 6 +- .../Features/BuiltinGaussianSplatPass.cpp | 4 +- .../Features/BuiltinVolumetricPass.cpp | 4 +- .../Rendering/Internal/ShaderVariantUtils.h | 2 +- .../BuiltinDepthStylePassBaseResources.cpp | 4 +- .../BuiltinForwardPipelineResources.cpp | 6 +- .../Internal/BuiltinForwardPipelineSkybox.cpp | 2 +- .../BuiltinForwardPipelineSurface.cpp | 8 +- .../Internal/DirectionalShadowPlanning.cpp | 2 +- .../Planning/SceneRenderRequestPlanner.cpp | 2 +- engine/src/Rendering/RenderPipeline.cpp | 4 +- engine/src/Resources/BuiltinResources.cpp | 8 +- .../GaussianSplat/GaussianSplatArtifactIO.cpp | 4 +- .../GaussianSplat/GaussianSplatLoader.cpp | 2 +- .../Internal/GaussianSplatPlyImporter.cpp | 2 +- .../Resources/Model/AssimpModelImporter.cpp | 6 +- .../src/Resources/Model/ModelArtifactIO.cpp | 4 +- engine/src/Resources/Model/ModelLoader.cpp | 2 +- .../src/Resources/UI/UIDocumentCompiler.cpp | 4 +- engine/src/Resources/UI/UIDocumentLoaders.cpp | 2 +- .../Resources/Volume/VolumeFieldLoader.cpp | 4 +- .../src/Scripting/Mono/MonoScriptRuntime.cpp | 4 +- engine/src/Scripting/ScriptEngine.cpp | 2 +- tests/Core/Asset/test_resource_manager.cpp | 148 ++- .../Material/test_material_loader.cpp | 3 - .../Resources/Texture/test_texture_loader.cpp | 15 +- 197 files changed, 7598 insertions(+), 6030 deletions(-) rename {engine/src/Core/Asset => Pipeline/Core/AssetDatabase/Facade}/AssetDatabase.cpp (73%) create mode 100644 Pipeline/Core/AssetDatabase/Facade/AssetDatabase.h create mode 100644 Pipeline/Core/AssetDatabase/Import/AssetDatabaseImport.cpp create mode 100644 Pipeline/Core/AssetDatabase/Import/AssetDatabaseImport.h create mode 100644 Pipeline/Core/AssetDatabase/Maintenance/AssetDatabaseMaintenance.cpp create mode 100644 Pipeline/Core/AssetDatabase/Maintenance/AssetDatabaseMaintenance.h create mode 100644 Pipeline/Core/AssetDatabase/Shared/AssetDatabaseShared.cpp create mode 100644 Pipeline/Core/AssetDatabase/Shared/AssetDatabaseShared.h create mode 100644 Pipeline/Core/AssetDatabase/Stores/AssetDatabaseStores.cpp create mode 100644 Pipeline/Core/AssetDatabase/Stores/AssetDatabaseStores.h create mode 100644 Pipeline/Core/Contracts/IProjectAssetPipelineService.h create mode 100644 Pipeline/Core/Contracts/IProjectAssetResolver.h create mode 100644 Pipeline/Core/Contracts/ProjectAssetTypes.h rename {engine/src/Core/Asset => Pipeline/Core/ImportService}/AssetImportService.cpp (72%) create mode 100644 Pipeline/Core/ImportService/AssetImportService.h create mode 100644 Pipeline/Core/ProjectAssetService/ProjectAssetService.cpp create mode 100644 Pipeline/Core/ProjectAssetService/ProjectAssetService.h rename {engine/src/Core/Asset => Pipeline/Core/SourceIndex}/ProjectAssetIndex.cpp (82%) create mode 100644 Pipeline/Core/SourceIndex/ProjectAssetIndex.h create mode 100644 docs/plan/runtime-rendering-framedata-structure-subplan.md rename engine/{src/Core/Asset => Runtime/Asset/AssetManager}/ResourceManager.cpp (84%) create mode 100644 engine/Runtime/Asset/AssetManager/ResourceManager.h rename engine/{src/Core/Asset => Runtime/Asset/AsyncLoad}/AsyncLoader.cpp (98%) create mode 100644 engine/Runtime/Asset/AsyncLoad/AsyncLoader.h rename engine/{src/Core/Asset => Runtime/Asset/ResourceStore}/ResourceCache.cpp (97%) create mode 100644 engine/Runtime/Asset/ResourceStore/ResourceCache.h rename engine/{src => Runtime}/Rendering/Caches/DirectionalShadowSurfaceCache.cpp (97%) create mode 100644 engine/Runtime/Rendering/Caches/DirectionalShadowSurfaceCache.h rename engine/{src => Runtime}/Rendering/Caches/RenderResourceCache.cpp (99%) create mode 100644 engine/Runtime/Rendering/Caches/RenderResourceCache.h create mode 100644 engine/Runtime/Rendering/FrameData/CullingResults.h create mode 100644 engine/Runtime/Rendering/FrameData/RenderCameraData.h create mode 100644 engine/Runtime/Rendering/FrameData/RenderEnvironmentData.h create mode 100644 engine/Runtime/Rendering/FrameData/RenderSceneData.h create mode 100644 engine/Runtime/Rendering/FrameData/RendererListUtils.h create mode 100644 engine/Runtime/Rendering/FrameData/VisibleGaussianSplatItem.h create mode 100644 engine/Runtime/Rendering/FrameData/VisibleRenderItem.h create mode 100644 engine/Runtime/Rendering/FrameData/VisibleVolumeItem.h create mode 100644 engine/Runtime/Rendering/Materials/RenderMaterialResolve.h create mode 100644 engine/Runtime/Rendering/Materials/RenderMaterialStateUtils.h create mode 100644 engine/Runtime/Rendering/Picking/ObjectIdCodec.h rename engine/{src => Runtime}/Rendering/Picking/RenderObjectIdRegistry.cpp (98%) create mode 100644 engine/Runtime/Rendering/Picking/RenderObjectIdRegistry.h rename engine/{src => Runtime}/Rendering/Shadow/DirectionalShadowData.cpp (95%) create mode 100644 engine/Runtime/Rendering/Shadow/DirectionalShadowData.h rename engine/{src => Runtime}/Rendering/Shadow/DirectionalShadowRuntime.cpp (95%) create mode 100644 engine/Runtime/Rendering/Shadow/DirectionalShadowRuntime.h rename engine/{src => Runtime}/Resources/AudioClip/AudioClip.cpp (98%) create mode 100644 engine/Runtime/Resources/AudioClip/AudioClip.h rename engine/{src => Runtime}/Resources/AudioClip/AudioLoader.cpp (97%) create mode 100644 engine/Runtime/Resources/AudioClip/AudioLoader.h rename engine/{src => Runtime}/Resources/Material/Material.cpp (99%) create mode 100644 engine/Runtime/Resources/Material/Material.h rename engine/{src => Runtime}/Resources/Material/MaterialLoader.cpp (99%) create mode 100644 engine/Runtime/Resources/Material/MaterialLoader.h create mode 100644 engine/Runtime/Resources/Material/MaterialRenderState.h rename engine/{src => Runtime}/Resources/Mesh/Mesh.cpp (95%) create mode 100644 engine/Runtime/Resources/Mesh/Mesh.h rename engine/{src => Runtime}/Resources/Mesh/MeshImportSettings.cpp (98%) create mode 100644 engine/Runtime/Resources/Mesh/MeshImportSettings.h rename engine/{src => Runtime}/Resources/Mesh/MeshLoader.cpp (98%) create mode 100644 engine/Runtime/Resources/Mesh/MeshLoader.h rename engine/{src => Runtime}/Resources/Shader/Internal/ShaderArtifactLoader.cpp (100%) rename engine/{src => Runtime}/Resources/Shader/Internal/ShaderArtifactLoader.h (100%) rename engine/{src => Runtime}/Resources/Shader/Internal/ShaderAuthoringDirectiveUtils.cpp (100%) rename engine/{src => Runtime}/Resources/Shader/Internal/ShaderAuthoringInternal.h (100%) rename engine/{src => Runtime}/Resources/Shader/Internal/ShaderAuthoringLoader.cpp (100%) rename engine/{src => Runtime}/Resources/Shader/Internal/ShaderAuthoringLoader.h (100%) rename engine/{src => Runtime}/Resources/Shader/Internal/ShaderAuthoringParserCore.cpp (100%) rename engine/{src => Runtime}/Resources/Shader/Internal/ShaderAuthoringShared.cpp (100%) rename engine/{src => Runtime}/Resources/Shader/Internal/ShaderAuthoringTextUtils.cpp (100%) rename engine/{src => Runtime}/Resources/Shader/Internal/ShaderFileUtils.cpp (95%) rename engine/{src => Runtime}/Resources/Shader/Internal/ShaderFileUtils.h (93%) rename engine/{src => Runtime}/Resources/Shader/Internal/ShaderRuntimeBuildUtils.cpp (99%) rename engine/{src => Runtime}/Resources/Shader/Internal/ShaderRuntimeBuildUtils.h (94%) rename engine/{src => Runtime}/Resources/Shader/Shader.cpp (99%) create mode 100644 engine/Runtime/Resources/Shader/Shader.h rename engine/{src => Runtime}/Resources/Shader/ShaderAuthoringParser.cpp (100%) rename engine/{src => Runtime}/Resources/Shader/ShaderAuthoringParser.h (100%) rename engine/{src => Runtime}/Resources/Shader/ShaderCompilationCache.cpp (96%) create mode 100644 engine/Runtime/Resources/Shader/ShaderCompilationCache.h rename engine/{src => Runtime}/Resources/Shader/ShaderIR.h (96%) rename engine/{src => Runtime}/Resources/Shader/ShaderLoader.cpp (92%) create mode 100644 engine/Runtime/Resources/Shader/ShaderLoader.h rename engine/{src => Runtime}/Resources/Shader/ShaderSourceUtils.cpp (99%) rename engine/{src => Runtime}/Resources/Shader/ShaderSourceUtils.h (96%) rename engine/{src => Runtime}/Resources/Texture/Texture.cpp (95%) create mode 100644 engine/Runtime/Resources/Texture/Texture.h rename engine/{src => Runtime}/Resources/Texture/TextureImportSettings.cpp (90%) create mode 100644 engine/Runtime/Resources/Texture/TextureImportSettings.h rename engine/{src => Runtime}/Resources/Texture/TextureLoader.cpp (98%) create mode 100644 engine/Runtime/Resources/Texture/TextureLoader.h rename engine/{src => Runtime}/Scene/ModelSceneInstantiation.cpp (98%) create mode 100644 engine/Runtime/Scene/ModelSceneInstantiation.h rename engine/{src => Runtime}/Scene/RuntimeLoop.cpp (98%) create mode 100644 engine/Runtime/Scene/RuntimeLoop.h rename engine/{src => Runtime}/Scene/Scene.cpp (92%) create mode 100644 engine/Runtime/Scene/Scene.h rename engine/{src => Runtime}/Scene/SceneManager.cpp (96%) create mode 100644 engine/Runtime/Scene/SceneManager.h rename engine/{src => Runtime}/Scene/SceneRuntime.cpp (97%) create mode 100644 engine/Runtime/Scene/SceneRuntime.h rename engine/{src/Core/Asset => Shared/Asset/ArtifactContainer}/ArtifactContainer.cpp (99%) create mode 100644 engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h rename engine/{src/Core/Asset => Shared/Asset/AssetGUID}/AssetGUID.cpp (98%) create mode 100644 engine/Shared/Asset/AssetGUID/AssetGUID.h rename engine/{src/Core/Asset => Shared/Asset/DependencyGraph}/ResourceDependencyGraph.cpp (99%) create mode 100644 engine/Shared/Asset/DependencyGraph/ResourceDependencyGraph.h rename engine/{src/Core/Asset => Shared/Asset/ResourceType}/ResourceTypes.cpp (93%) create mode 100644 engine/Shared/Asset/ResourceType/ResourceTypes.h create mode 100644 engine/include/XCEngine/Core/Asset/IProjectAssetPipelineService.h create mode 100644 engine/include/XCEngine/Core/Asset/IProjectAssetResolver.h create mode 100644 engine/include/XCEngine/Core/Asset/ProjectAssetService.h create mode 100644 engine/include/XCEngine/Core/Asset/ProjectAssetTypes.h diff --git a/engine/src/Core/Asset/AssetDatabase.cpp b/Pipeline/Core/AssetDatabase/Facade/AssetDatabase.cpp similarity index 73% rename from engine/src/Core/Asset/AssetDatabase.cpp rename to Pipeline/Core/AssetDatabase/Facade/AssetDatabase.cpp index f09ed874..0adbd308 100644 --- a/engine/src/Core/Asset/AssetDatabase.cpp +++ b/Pipeline/Core/AssetDatabase/Facade/AssetDatabase.cpp @@ -2,9 +2,13 @@ #define NOMINMAX #endif -#include +#include "AssetDatabase.h" -#include +#include "Pipeline/Core/AssetDatabase/Import/AssetDatabaseImport.h" +#include "Pipeline/Core/AssetDatabase/Maintenance/AssetDatabaseMaintenance.h" +#include "Pipeline/Core/AssetDatabase/Shared/AssetDatabaseShared.h" +#include "Pipeline/Core/AssetDatabase/Stores/AssetDatabaseStores.h" +#include "engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h" #include #include #include @@ -45,6 +49,14 @@ namespace XCEngine { namespace Resources { +using AssetDatabaseInternal::HasVirtualPathScheme; +using AssetDatabaseInternal::kModelSubAssetManifestFileName; +using AssetDatabaseInternal::ModelSubAssetManifestEntry; +using AssetDatabaseInternal::NormalizeArtifactPathString; +using AssetDatabaseInternal::ToContainersString; +using AssetDatabaseInternal::ToStdString; +using AssetDatabaseInternal::WriteModelSubAssetManifest; + namespace fs = std::filesystem; namespace { @@ -201,27 +213,6 @@ bool TryComputeFastFileHash(const fs::path& path, Containers::String& outHash) { } #endif -std::string ToStdString(const Containers::String& value) { - return std::string(value.CStr()); -} - -bool ShouldTraceAssetPath(const Containers::String& path) { - const std::string text = ToStdString(path); - return text.rfind("builtin://", 0) == 0 || - text.find("backpack") != std::string::npos || - text.find("New Material.mat") != std::string::npos; -} - -bool HasVirtualPathScheme(const Containers::String& value) { - return ToStdString(value).find("://") != std::string::npos; -} - -Containers::String ToContainersString(const std::string& value) { - return Containers::String(value.c_str()); -} - -Containers::String NormalizeArtifactPathString(const fs::path& path); -Containers::String NormalizeArtifactPathString(const Containers::String& path); bool SerializeTextureArtifactPayload(const Texture& texture, Containers::Array& outPayload); bool SerializeMaterialArtifactPayload( @@ -238,88 +229,10 @@ bool SerializeMeshArtifactPayload(const Mesh& mesh, bool WriteSingleEntryArtifactContainerFile(const fs::path& artifactPath, ResourceType resourceType, const Containers::Array& payload); -constexpr const char* kModelSubAssetManifestFileName = "subassets.tsv"; constexpr const char* kSourceAssetDbFileName = "assets.db"; constexpr const char* kArtifactDbFileName = "artifacts.db"; constexpr const char* kLegacySourceAssetDbDirectory = "SourceAssetDB"; constexpr const char* kLegacyArtifactDbDirectory = "ArtifactDB"; -constexpr Core::uint32 kArtifactDbSchemaVersion = 2; - -ArtifactStorageKind InferArtifactStorageKind(const Containers::String& projectRoot, - const AssetDatabase::ArtifactRecord& record) { - if (!record.mainArtifactPath.Empty()) { - const Containers::String absoluteMainArtifactPath = - NormalizeArtifactPathString(fs::path(projectRoot.CStr()) / record.mainArtifactPath.CStr()); - if (IsArtifactContainerFile(absoluteMainArtifactPath)) { - return ArtifactStorageKind::SingleFileContainer; - } - } - - return record.artifactDirectory.Empty() - ? ArtifactStorageKind::Unknown - : ArtifactStorageKind::LegacyDirectory; -} - -Containers::String BuildArtifactMainEntryLoadPath(const Containers::String& artifactMainPath, - ArtifactStorageKind storageKind, - const Containers::String& mainEntryName) { - if (storageKind == ArtifactStorageKind::SingleFileContainer && - !artifactMainPath.Empty() && - !mainEntryName.Empty()) { - return BuildArtifactContainerEntryPath(artifactMainPath, mainEntryName); - } - - return artifactMainPath; -} - -struct ModelSubAssetManifestEntry { - LocalID localID = kInvalidLocalID; - ResourceType resourceType = ResourceType::Unknown; - Containers::String artifactPath; -}; - -void PopulateResolvedAssetResult(const Containers::String& projectRoot, - const AssetDatabase::SourceAssetRecord& sourceRecord, - const AssetDatabase::ArtifactRecord& artifactRecord, - bool imported, - AssetDatabase::ResolvedAsset& outAsset) { - outAsset = AssetDatabase::ResolvedAsset(); - outAsset.exists = true; - outAsset.artifactReady = true; - outAsset.imported = imported; - outAsset.absolutePath = - ToContainersString((fs::path(projectRoot.CStr()) / sourceRecord.relativePath.CStr()).lexically_normal().generic_string()); - outAsset.relativePath = sourceRecord.relativePath; - outAsset.assetGuid = sourceRecord.guid; - outAsset.resourceType = artifactRecord.resourceType; - outAsset.artifactStorageKind = artifactRecord.storageKind; - outAsset.mainEntryName = artifactRecord.mainEntryName; - if (!artifactRecord.artifactDirectory.Empty()) { - outAsset.artifactDirectory = ToContainersString( - (fs::path(projectRoot.CStr()) / artifactRecord.artifactDirectory.CStr()).lexically_normal().generic_string()); - } - outAsset.artifactMainPath = ToContainersString( - (fs::path(projectRoot.CStr()) / artifactRecord.mainArtifactPath.CStr()).lexically_normal().generic_string()); - outAsset.artifactMainEntryPath = BuildArtifactMainEntryLoadPath( - outAsset.artifactMainPath, - artifactRecord.storageKind, - artifactRecord.mainEntryName); - outAsset.mainLocalID = artifactRecord.mainLocalID; -} - -Containers::String NormalizeArtifactPathString(const fs::path& path) { - if (path.empty()) { - return Containers::String(); - } - return ToContainersString(path.lexically_normal().generic_string()); -} - -Containers::String NormalizeArtifactPathString(const Containers::String& path) { - if (path.Empty()) { - return Containers::String(); - } - return NormalizeArtifactPathString(fs::path(path.CStr())); -} bool IsProjectRelativePath(const fs::path& path) { const std::string generic = path.generic_string(); @@ -809,173 +722,6 @@ std::vector CollectMtlDeclaredDependencyPaths(const fs::path& mtlPath) return dependencies; } -std::string EscapeField(const std::string& value) { - std::string escaped; - escaped.reserve(value.size()); - for (const char ch : value) { - if (ch == '\\' || ch == '\t' || ch == '\n' || ch == '\r') { - escaped.push_back('\\'); - switch (ch) { - case '\t': - escaped.push_back('t'); - break; - case '\n': - escaped.push_back('n'); - break; - case '\r': - escaped.push_back('r'); - break; - default: - escaped.push_back(ch); - break; - } - } else { - escaped.push_back(ch); - } - } - return escaped; -} - -std::string UnescapeField(const std::string& value) { - std::string result; - result.reserve(value.size()); - for (size_t index = 0; index < value.size(); ++index) { - if (value[index] == '\\' && index + 1 < value.size()) { - ++index; - switch (value[index]) { - case 't': - result.push_back('\t'); - break; - case 'n': - result.push_back('\n'); - break; - case 'r': - result.push_back('\r'); - break; - default: - result.push_back(value[index]); - break; - } - } else { - result.push_back(value[index]); - } - } - return result; -} - -std::vector SplitFields(const std::string& line) { - std::vector fields; - std::string current; - bool escaping = false; - - for (const char ch : line) { - if (escaping) { - current.push_back('\\'); - current.push_back(ch); - escaping = false; - continue; - } - - if (ch == '\\') { - escaping = true; - continue; - } - - if (ch == '\t') { - fields.push_back(UnescapeField(current)); - current.clear(); - continue; - } - - current.push_back(ch); - } - - if (escaping) { - current.push_back('\\'); - } - fields.push_back(UnescapeField(current)); - return fields; -} - -bool WriteModelSubAssetManifest(const fs::path& manifestPath, - const std::vector& entries) { - std::ofstream output(manifestPath, std::ios::out | std::ios::trunc); - if (!output.is_open()) { - return false; - } - - output << "# localID\tresourceType\tartifactPath\n"; - for (const ModelSubAssetManifestEntry& entry : entries) { - if (entry.localID == kInvalidLocalID || - entry.resourceType == ResourceType::Unknown || - entry.artifactPath.Empty()) { - continue; - } - - output << entry.localID << '\t' - << static_cast(entry.resourceType) << '\t' - << EscapeField(ToStdString(entry.artifactPath)) << '\n'; - } - - return static_cast(output); -} - -bool TryReadModelSubAssetManifest(const fs::path& manifestPath, - std::vector& outEntries) { - outEntries.clear(); - - std::ifstream input(manifestPath); - if (!input.is_open()) { - return false; - } - - std::string line; - while (std::getline(input, line)) { - if (line.empty() || line[0] == '#') { - continue; - } - - const std::vector fields = SplitFields(line); - if (fields.size() < 3) { - continue; - } - - ModelSubAssetManifestEntry entry; - entry.localID = static_cast(std::stoull(fields[0])); - entry.resourceType = static_cast(std::stoul(fields[1])); - entry.artifactPath = ToContainersString(fields[2]); - if (entry.localID == kInvalidLocalID || - entry.resourceType == ResourceType::Unknown || - entry.artifactPath.Empty()) { - continue; - } - - outEntries.push_back(entry); - } - - return true; -} - -bool TryResolveModelSubAssetArtifactPath(const fs::path& manifestPath, - const AssetRef& assetRef, - Containers::String& outArtifactPath) { - std::vector entries; - if (!TryReadModelSubAssetManifest(manifestPath, entries)) { - return false; - } - - for (const ModelSubAssetManifestEntry& entry : entries) { - if (entry.localID != assetRef.localID || entry.resourceType != assetRef.resourceType) { - continue; - } - - outArtifactPath = entry.artifactPath; - return true; - } - - return false; -} - void WriteString(std::ostream& stream, const Containers::String& value) { const Core::uint32 length = static_cast(value.Length()); stream.write(reinterpret_cast(&length), sizeof(length)); @@ -1498,6 +1244,29 @@ void AssetDatabase::SetLastErrorMessage(const Containers::String& message) { m_lastErrorMessage = message; } +AssetDatabase::AssetDatabase() + : m_sourceAssetDB(std::make_unique()) + , m_artifactDB(std::make_unique()) { +} + +AssetDatabase::~AssetDatabase() = default; + +AssetDatabaseInternal::SourceAssetDB& AssetDatabase::GetSourceAssetDB() { + return *m_sourceAssetDB; +} + +const AssetDatabaseInternal::SourceAssetDB& AssetDatabase::GetSourceAssetDB() const { + return *m_sourceAssetDB; +} + +AssetDatabaseInternal::ArtifactDB& AssetDatabase::GetArtifactDB() { + return *m_artifactDB; +} + +const AssetDatabaseInternal::ArtifactDB& AssetDatabase::GetArtifactDB() const { + return *m_artifactDB; +} + void AssetDatabase::Initialize(const Containers::String& projectRoot) { ClearLastErrorMessage(); m_projectRoot = NormalizePathString(projectRoot); @@ -1531,14 +1300,13 @@ void AssetDatabase::Shutdown() { m_libraryRoot.Clear(); m_sourceDbPath.Clear(); m_artifactDbPath.Clear(); - m_sourcesByPathKey.clear(); - m_sourcesByGuid.clear(); - m_artifactsByGuid.clear(); + GetSourceAssetDB().Clear(); + GetArtifactDB().Clear(); } AssetDatabase::MaintenanceStats AssetDatabase::Refresh() { ClearLastErrorMessage(); - return ScanAssets(); + return AssetDatabaseInternal::AssetDatabaseMaintenanceRunner(*this).Refresh(); } bool AssetDatabase::ResolvePath(const Containers::String& requestPath, @@ -1586,12 +1354,13 @@ bool AssetDatabase::TryGetAssetGuid(const Containers::String& requestPath, Asset return false; } - const auto sourceIt = m_sourcesByPathKey.find(ToStdString(MakeKey(relativePath))); - if (sourceIt == m_sourcesByPathKey.end()) { + const SourceAssetRecord* sourceRecord = + GetSourceAssetDB().FindByPathKey(ToStdString(MakeKey(relativePath))); + if (sourceRecord == nullptr) { return false; } - outGuid = sourceIt->second.guid; + outGuid = sourceRecord->guid; return outGuid.IsValid(); } @@ -1629,213 +1398,28 @@ bool AssetDatabase::TryGetAssetRef(const Containers::String& requestPath, } bool AssetDatabase::TryResolveAssetPath(const AssetRef& assetRef, Containers::String& outPath) { - outPath.Clear(); - ClearLastErrorMessage(); - - if (!assetRef.IsValid()) { - return false; - } - - if (assetRef.localID == kMainAssetLocalID) { - return TryGetPrimaryAssetPath(assetRef.assetGuid, outPath); - } - - const auto sourceIt = m_sourcesByGuid.find(assetRef.assetGuid); - if (sourceIt == m_sourcesByGuid.end()) { - SetLastErrorMessage(Containers::String("Unknown asset GUID for sub-asset path resolution: ") + - assetRef.assetGuid.ToString()); - return false; - } - - const SourceAssetRecord& sourceRecord = sourceIt->second; - const ResourceType primaryType = GetPrimaryResourceTypeForImporter(sourceRecord.importerName); - if (primaryType == ResourceType::Unknown) { - SetLastErrorMessage(Containers::String("Asset does not have an importable primary type: ") + - sourceRecord.relativePath); - return false; - } - - auto resolveFromArtifactRecord = [&](const ArtifactRecord& artifactRecord) -> bool { - const Containers::String absoluteMainArtifactPath = - NormalizePathString(fs::path(m_projectRoot.CStr()) / artifactRecord.mainArtifactPath.CStr()); - - ArtifactContainerReader reader; - Containers::String containerError; - if (reader.Open(absoluteMainArtifactPath, &containerError)) { - const ArtifactContainerEntryView* entry = - reader.FindEntry(assetRef.resourceType, assetRef.localID); - if (entry != nullptr) { - outPath = BuildArtifactContainerEntryPath(absoluteMainArtifactPath, entry->name); - return true; - } - } - - const fs::path manifestPath = - fs::path(m_projectRoot.CStr()) / - artifactRecord.artifactDirectory.CStr() / - kModelSubAssetManifestFileName; - - Containers::String artifactPath; - if (!TryResolveModelSubAssetArtifactPath(manifestPath, assetRef, artifactPath)) { - return false; - } - - outPath = NormalizePathString(fs::path(m_projectRoot.CStr()) / artifactPath.CStr()); - return true; - }; - - auto artifactIt = m_artifactsByGuid.find(assetRef.assetGuid); - if (artifactIt != m_artifactsByGuid.end() && - !ShouldReimport(sourceRecord, &artifactIt->second) && - resolveFromArtifactRecord(artifactIt->second)) { - return true; - } - - ResolvedAsset resolvedAsset; - if (!EnsureArtifact(sourceRecord.relativePath, primaryType, resolvedAsset)) { - if (m_lastErrorMessage.Empty()) { - SetLastErrorMessage(Containers::String("Failed to import asset while resolving sub-asset path: ") + - sourceRecord.relativePath); - } - return false; - } - - artifactIt = m_artifactsByGuid.find(assetRef.assetGuid); - if (artifactIt != m_artifactsByGuid.end() && resolveFromArtifactRecord(artifactIt->second)) { - return true; - } - - SetLastErrorMessage(Containers::String("Sub-asset localID was not found in artifact manifest: ") + - sourceRecord.relativePath); - return false; + return AssetDatabaseInternal::AssetDatabaseImportRunner(*this).TryResolveAssetPath( + assetRef, outPath); } bool AssetDatabase::ReimportAsset(const Containers::String& requestPath, ResolvedAsset& outAsset, MaintenanceStats* outStats) { - outAsset = ResolvedAsset(); - ClearLastErrorMessage(); - if (outStats != nullptr) { - *outStats = MaintenanceStats(); - } - - Containers::String absolutePath; - Containers::String relativePath; - if (!ResolvePath(requestPath, absolutePath, relativePath) || relativePath.Empty()) { - SetLastErrorMessage(Containers::String("Unable to resolve asset path: ") + requestPath); - return false; - } - - const fs::path absoluteFsPath(absolutePath.CStr()); - if (!fs::exists(absoluteFsPath) || fs::is_directory(absoluteFsPath)) { - SetLastErrorMessage(Containers::String("Asset source file does not exist: ") + absolutePath); - return false; - } - - SourceAssetRecord sourceRecord; - if (!EnsureMetaForPath(absoluteFsPath, false, sourceRecord)) { - SetLastErrorMessage(Containers::String("Failed to prepare asset metadata: ") + absolutePath); - return false; - } - - const ResourceType primaryType = GetPrimaryResourceTypeForImporter(sourceRecord.importerName); - if (primaryType == ResourceType::Unknown) { - SetLastErrorMessage(Containers::String("Asset type is not importable: ") + requestPath); - return false; - } - - ArtifactRecord rebuiltRecord; - if (!ImportAsset(sourceRecord, rebuiltRecord)) { - if (m_lastErrorMessage.Empty()) { - SetLastErrorMessage(Containers::String("Failed to import asset: ") + requestPath); - } - return false; - } - - m_artifactsByGuid[sourceRecord.guid] = rebuiltRecord; - m_sourcesByGuid[sourceRecord.guid].lastKnownArtifactKey = rebuiltRecord.artifactKey; - m_sourcesByPathKey[ToStdString(MakeKey(sourceRecord.relativePath))].lastKnownArtifactKey = rebuiltRecord.artifactKey; - SaveArtifactDB(); - SaveSourceAssetDB(); - - MaintenanceStats localStats; - localStats.importedAssetCount = 1; - localStats.removedArtifactCount = CleanupOrphanedArtifacts(); - if (outStats != nullptr) { - *outStats = localStats; - } - - PopulateResolvedAssetResult(m_projectRoot, sourceRecord, rebuiltRecord, true, outAsset); - ClearLastErrorMessage(); - return true; + return AssetDatabaseInternal::AssetDatabaseImportRunner(*this).ReimportAsset( + requestPath, outAsset, outStats); } bool AssetDatabase::ReimportAllAssets(MaintenanceStats* outStats) { - ClearLastErrorMessage(); - if (outStats != nullptr) { - *outStats = MaintenanceStats(); - } - - std::vector importableRecords; - importableRecords.reserve(m_sourcesByGuid.size()); - - for (const auto& [guid, record] : m_sourcesByGuid) { - (void)guid; - if (record.isFolder) { - continue; - } - - const ResourceType primaryType = GetPrimaryResourceTypeForImporter(record.importerName); - if (primaryType == ResourceType::Unknown) { - continue; - } - - const fs::path sourcePath = fs::path(m_projectRoot.CStr()) / record.relativePath.CStr(); - if (!fs::exists(sourcePath) || fs::is_directory(sourcePath)) { - continue; - } - - importableRecords.push_back(record); - } - - std::sort(importableRecords.begin(), importableRecords.end(), [](const SourceAssetRecord& lhs, const SourceAssetRecord& rhs) { - return ToStdString(lhs.relativePath) < ToStdString(rhs.relativePath); - }); - - bool allSucceeded = true; - MaintenanceStats localStats; - for (const SourceAssetRecord& record : importableRecords) { - ArtifactRecord rebuiltRecord; - if (!ImportAsset(record, rebuiltRecord)) { - Debug::Logger::Get().Error( - Debug::LogCategory::FileSystem, - Containers::String("[AssetDatabase] ReimportAllAssets failed path=") + record.relativePath); - allSucceeded = false; - continue; - } - - m_artifactsByGuid[record.guid] = rebuiltRecord; - m_sourcesByGuid[record.guid].lastKnownArtifactKey = rebuiltRecord.artifactKey; - m_sourcesByPathKey[ToStdString(MakeKey(record.relativePath))].lastKnownArtifactKey = rebuiltRecord.artifactKey; - ++localStats.importedAssetCount; - } - - SaveArtifactDB(); - SaveSourceAssetDB(); - localStats.removedArtifactCount = CleanupOrphanedArtifacts(); - if (outStats != nullptr) { - *outStats = localStats; - } - return allSucceeded; + return AssetDatabaseInternal::AssetDatabaseImportRunner(*this).ReimportAllAssets(outStats); } bool AssetDatabase::TryGetPrimaryAssetPath(const AssetGUID& guid, Containers::String& outRelativePath) const { - const auto sourceIt = m_sourcesByGuid.find(guid); - if (sourceIt == m_sourcesByGuid.end()) { + const SourceAssetRecord* sourceRecord = GetSourceAssetDB().FindByGuid(guid); + if (sourceRecord == nullptr) { return false; } - outRelativePath = sourceIt->second.relativePath; + outRelativePath = sourceRecord->relativePath; return true; } @@ -1843,17 +1427,19 @@ void AssetDatabase::BuildLookupSnapshot(std::unordered_map& outGuidToPath) const { outPathToGuid.clear(); outGuidToPath.clear(); - outPathToGuid.reserve(m_sourcesByPathKey.size()); - outGuidToPath.reserve(m_sourcesByGuid.size()); + const auto& sourceRecordsByPathKey = GetSourceAssetDB().GetRecordsByPathKey(); + const auto& sourceRecordsByGuid = GetSourceAssetDB().GetRecordsByGuid(); + outPathToGuid.reserve(sourceRecordsByPathKey.size()); + outGuidToPath.reserve(sourceRecordsByGuid.size()); - for (const auto& [pathKey, record] : m_sourcesByPathKey) { + for (const auto& [pathKey, record] : sourceRecordsByPathKey) { if (!record.guid.IsValid() || record.relativePath.Empty()) { continue; } outPathToGuid[pathKey] = record.guid; } - for (const auto& [guid, record] : m_sourcesByGuid) { + for (const auto& [guid, record] : sourceRecordsByGuid) { if (!guid.IsValid() || record.relativePath.Empty()) { continue; } @@ -1871,325 +1457,21 @@ void AssetDatabase::EnsureProjectLayout() { } void AssetDatabase::LoadSourceAssetDB() { - m_sourcesByPathKey.clear(); - m_sourcesByGuid.clear(); - - std::ifstream input(m_sourceDbPath.CStr()); - if (!input.is_open()) { - return; - } - - std::string line; - while (std::getline(input, line)) { - if (line.empty() || line[0] == '#') { - continue; - } - - const std::vector fields = SplitFields(line); - if (fields.size() < 10) { - continue; - } - - SourceAssetRecord record; - record.guid = AssetGUID::ParseOrDefault(ToContainersString(fields[0])); - record.relativePath = ToContainersString(fields[1]); - record.metaPath = ToContainersString(fields[2]); - record.isFolder = (fields[3] == "1"); - record.importerName = ToContainersString(fields[4]); - record.importerVersion = static_cast(std::stoul(fields[5])); - record.metaHash = ToContainersString(fields[6]); - record.sourceHash = ToContainersString(fields[7]); - record.sourceFileSize = static_cast(std::stoull(fields[8])); - record.sourceWriteTime = static_cast(std::stoull(fields[9])); - if (fields.size() > 10) { - record.lastKnownArtifactKey = ToContainersString(fields[10]); - } - - if (!record.guid.IsValid() || record.relativePath.Empty()) { - continue; - } - - m_sourcesByGuid[record.guid] = record; - m_sourcesByPathKey[ToStdString(MakeKey(record.relativePath))] = record; - } + GetSourceAssetDB().Load(m_sourceDbPath); } void AssetDatabase::SaveSourceAssetDB() const { - std::ofstream output(m_sourceDbPath.CStr(), std::ios::out | std::ios::trunc); - if (!output.is_open()) { - return; - } - - output << "# guid\trelativePath\tmetaPath\tisFolder\timporter\timporterVersion\tmetaHash\tsourceHash\tsize\twriteTime\tartifactKey\n"; - for (const auto& [guid, record] : m_sourcesByGuid) { - output << EscapeField(ToStdString(record.guid.ToString())) << '\t' - << EscapeField(ToStdString(record.relativePath)) << '\t' - << EscapeField(ToStdString(record.metaPath)) << '\t' - << (record.isFolder ? "1" : "0") << '\t' - << EscapeField(ToStdString(record.importerName)) << '\t' - << record.importerVersion << '\t' - << EscapeField(ToStdString(record.metaHash)) << '\t' - << EscapeField(ToStdString(record.sourceHash)) << '\t' - << record.sourceFileSize << '\t' - << record.sourceWriteTime << '\t' - << EscapeField(ToStdString(record.lastKnownArtifactKey)) << '\n'; - } + GetSourceAssetDB().Save(m_sourceDbPath); } void AssetDatabase::LoadArtifactDB() { - m_artifactsByGuid.clear(); - - std::ifstream input(m_artifactDbPath.CStr()); - if (!input.is_open()) { - return; - } - - std::string line; - Core::uint32 schemaVersion = 1; - while (std::getline(input, line)) { - if (line.empty()) { - continue; - } - - if (line[0] == '#') { - const std::string schemaToken = "schema="; - const size_t schemaTokenPosition = line.find(schemaToken); - if (schemaTokenPosition != std::string::npos) { - const size_t valueStart = schemaTokenPosition + schemaToken.length(); - const std::string valueText = line.substr(valueStart); - if (!valueText.empty()) { - schemaVersion = static_cast(std::stoul(valueText)); - } - } else if (line.find("storageKind") != std::string::npos && - line.find("mainEntryName") != std::string::npos) { - schemaVersion = std::max(schemaVersion, kArtifactDbSchemaVersion); - } - continue; - } - - const std::vector fields = SplitFields(line); - if (fields.size() < 10) { - continue; - } - - ArtifactRecord record; - record.artifactKey = ToContainersString(fields[0]); - record.assetGuid = AssetGUID::ParseOrDefault(ToContainersString(fields[1])); - record.importerName = ToContainersString(fields[2]); - record.importerVersion = static_cast(std::stoul(fields[3])); - record.resourceType = static_cast(std::stoul(fields[4])); - record.artifactDirectory = ToContainersString(fields[5]); - record.mainArtifactPath = ToContainersString(fields[6]); - record.sourceHash = ToContainersString(fields[7]); - record.metaHash = ToContainersString(fields[8]); - record.sourceFileSize = static_cast(std::stoull(fields[9])); - record.sourceWriteTime = fields.size() > 10 ? static_cast(std::stoull(fields[10])) : 0; - record.mainLocalID = fields.size() > 11 ? static_cast(std::stoull(fields[11])) : kMainAssetLocalID; - size_t dependencyFieldStart = 12; - if (schemaVersion >= kArtifactDbSchemaVersion && fields.size() > 13) { - record.storageKind = static_cast(std::stoul(fields[12])); - record.mainEntryName = ToContainersString(fields[13]); - dependencyFieldStart = 14; - } - - if (record.storageKind == ArtifactStorageKind::Unknown) { - record.storageKind = InferArtifactStorageKind(m_projectRoot, record); - } - if (record.mainEntryName.Empty() && - record.storageKind == ArtifactStorageKind::SingleFileContainer) { - record.mainEntryName = "main"; - } - if (record.artifactDirectory.Empty() && !record.mainArtifactPath.Empty()) { - record.artifactDirectory = - NormalizePathString(fs::path(record.mainArtifactPath.CStr()).parent_path()); - } - - for (size_t index = dependencyFieldStart; index + 3 < fields.size(); index += 4) { - ArtifactDependencyRecord dependency; - dependency.path = ToContainersString(fields[index + 0]); - dependency.hash = ToContainersString(fields[index + 1]); - dependency.fileSize = static_cast(std::stoull(fields[index + 2])); - dependency.writeTime = static_cast(std::stoull(fields[index + 3])); - if (!dependency.path.Empty()) { - record.dependencies.push_back(dependency); - } - } - - if (!record.assetGuid.IsValid() || record.artifactKey.Empty()) { - continue; - } - - m_artifactsByGuid[record.assetGuid] = record; - } + GetArtifactDB().Load(m_projectRoot, m_artifactDbPath); } void AssetDatabase::SaveArtifactDB() const { - std::ofstream output(m_artifactDbPath.CStr(), std::ios::out | std::ios::trunc); - if (!output.is_open()) { - return; - } - - output << "# schema=" << kArtifactDbSchemaVersion << "\n"; - output << "# artifactKey\tassetGuid\timporter\tversion\ttype\tartifactDir\tmainArtifact\tsourceHash\tmetaHash\tsize\twriteTime\tmainLocalID\tstorageKind\tmainEntryName\t(depPath\tdepHash\tdepSize\tdepWriteTime)...\n"; - for (const auto& [guid, record] : m_artifactsByGuid) { - output << EscapeField(ToStdString(record.artifactKey)) << '\t' - << EscapeField(ToStdString(record.assetGuid.ToString())) << '\t' - << EscapeField(ToStdString(record.importerName)) << '\t' - << record.importerVersion << '\t' - << static_cast(record.resourceType) << '\t' - << EscapeField(ToStdString(record.artifactDirectory)) << '\t' - << EscapeField(ToStdString(record.mainArtifactPath)) << '\t' - << EscapeField(ToStdString(record.sourceHash)) << '\t' - << EscapeField(ToStdString(record.metaHash)) << '\t' - << record.sourceFileSize << '\t' - << record.sourceWriteTime << '\t' - << record.mainLocalID << '\t' - << static_cast(record.storageKind) << '\t' - << EscapeField(ToStdString(record.mainEntryName)); - for (const ArtifactDependencyRecord& dependency : record.dependencies) { - output << '\t' << EscapeField(ToStdString(dependency.path)) - << '\t' << EscapeField(ToStdString(dependency.hash)) - << '\t' << dependency.fileSize - << '\t' << dependency.writeTime; - } - output << '\n'; - } + GetArtifactDB().Save(m_artifactDbPath); } -AssetDatabase::MaintenanceStats AssetDatabase::ScanAssets() { - MaintenanceStats stats; - std::unordered_map seenPaths; - const fs::path assetsRootPath(m_assetsRoot.CStr()); - if (fs::exists(assetsRootPath)) { - ScanAssetPath(assetsRootPath, seenPaths); - } - for (const fs::path& builtinShaderPath : CollectBuiltinShaderAssetPaths()) { - ScanAssetPath(builtinShaderPath, seenPaths); - } - RemoveMissingRecords(seenPaths); - stats.removedArtifactCount = CleanupOrphanedArtifacts(); - SaveSourceAssetDB(); - SaveArtifactDB(); - return stats; -} - -void AssetDatabase::ScanAssetPath(const fs::path& path, - std::unordered_map& seenPaths) { - if (!fs::exists(path)) { - return; - } - - if (path.has_extension() && ToLowerCopy(path.extension().string()) == ".meta") { - return; - } - - const bool isFolder = fs::is_directory(path); - SourceAssetRecord record; - if (EnsureMetaForPath(path, isFolder, record)) { - seenPaths[ToStdString(MakeKey(record.relativePath))] = true; - } - - if (!isFolder) { - return; - } - - for (const auto& entry : fs::directory_iterator(path)) { - ScanAssetPath(entry.path(), seenPaths); - } -} - -void AssetDatabase::RemoveMissingRecords(const std::unordered_map& seenPaths) { - std::vector missingPathKeys; - for (const auto& [pathKey, record] : m_sourcesByPathKey) { - if (seenPaths.find(pathKey) == seenPaths.end()) { - missingPathKeys.push_back(pathKey); - } - } - - for (const std::string& pathKey : missingPathKeys) { - auto recordIt = m_sourcesByPathKey.find(pathKey); - if (recordIt == m_sourcesByPathKey.end()) { - continue; - } - - m_artifactsByGuid.erase(recordIt->second.guid); - m_sourcesByGuid.erase(recordIt->second.guid); - m_sourcesByPathKey.erase(recordIt); - } - -} - -Core::uint32 AssetDatabase::CleanupOrphanedArtifacts() const { - std::error_code ec; - const fs::path artifactsRoot = fs::path(m_libraryRoot.CStr()) / "Artifacts"; - if (!fs::exists(artifactsRoot, ec) || !fs::is_directory(artifactsRoot, ec)) { - return 0; - } - - std::unordered_set retainedArtifactPathKeys; - retainedArtifactPathKeys.reserve(m_artifactsByGuid.size() * 2u); - for (const auto& [guid, record] : m_artifactsByGuid) { - (void)guid; - if (!record.artifactDirectory.Empty()) { - retainedArtifactPathKeys.insert(ToStdString(MakeKey(record.artifactDirectory))); - } - if (!record.mainArtifactPath.Empty()) { - retainedArtifactPathKeys.insert(ToStdString(MakeKey(record.mainArtifactPath))); - } - } - - Core::uint32 removedArtifactCount = 0; - for (const auto& shardEntry : fs::directory_iterator(artifactsRoot, ec)) { - if (ec) { - ec.clear(); - break; - } - - const fs::path shardPath = shardEntry.path(); - if (!shardEntry.is_directory()) { - fs::remove_all(shardPath, ec); - if (!ec) { - ++removedArtifactCount; - } - ec.clear(); - continue; - } - - for (const auto& artifactEntry : fs::directory_iterator(shardPath, ec)) { - if (ec) { - ec.clear(); - break; - } - - const Containers::String relativeArtifactPath = NormalizeRelativePath(artifactEntry.path()); - const std::string artifactPathKey = ToStdString(MakeKey(relativeArtifactPath)); - if (!relativeArtifactPath.Empty() && - retainedArtifactPathKeys.find(artifactPathKey) != retainedArtifactPathKeys.end()) { - continue; - } - - fs::remove_all(artifactEntry.path(), ec); - if (!ec) { - ++removedArtifactCount; - } - ec.clear(); - } - - std::error_code shardEc; - if (fs::is_empty(shardPath, shardEc)) { - fs::remove(shardPath, shardEc); - } - } - - if (removedArtifactCount > 0) { - Debug::Logger::Get().Info( - Debug::LogCategory::FileSystem, - Containers::String("[AssetDatabase] Removed orphan artifact entries count=") + - Containers::String(std::to_string(removedArtifactCount).c_str())); - } - - return removedArtifactCount; -} bool AssetDatabase::EnsureMetaForPath(const fs::path& sourcePath, bool isFolder, @@ -2200,9 +1482,9 @@ bool AssetDatabase::EnsureMetaForPath(const fs::path& sourcePath, } const std::string pathKey = ToStdString(MakeKey(relativePath)); - auto existingIt = m_sourcesByPathKey.find(pathKey); - if (existingIt != m_sourcesByPathKey.end()) { - outRecord = existingIt->second; + const SourceAssetRecord* existingRecord = GetSourceAssetDB().FindByPathKey(pathKey); + if (existingRecord != nullptr) { + outRecord = *existingRecord; } else { outRecord = SourceAssetRecord(); outRecord.relativePath = relativePath; @@ -2223,9 +1505,9 @@ bool AssetDatabase::EnsureMetaForPath(const fs::path& sourcePath, outRecord.metaHash = BuildSyntheticMetaHash(relativePath, outRecord.importerName, outRecord.importerVersion); - const auto duplicateGuidIt = m_sourcesByGuid.find(outRecord.guid); - if (duplicateGuidIt != m_sourcesByGuid.end() && - duplicateGuidIt->second.relativePath != relativePath) { + const SourceAssetRecord* duplicateGuidRecord = GetSourceAssetDB().FindByGuid(outRecord.guid); + if (duplicateGuidRecord != nullptr && + duplicateGuidRecord->relativePath != relativePath) { Containers::String duplicateSignature = NormalizePathString(sourcePath); duplicateSignature += ":"; duplicateSignature += relativePath; @@ -2239,11 +1521,11 @@ bool AssetDatabase::EnsureMetaForPath(const fs::path& sourcePath, } else { const Core::uint64 fileSize = GetFileSizeValue(sourcePath); const Core::uint64 writeTime = GetFileWriteTimeValue(sourcePath); - if (existingIt != m_sourcesByPathKey.end() && - existingIt->second.sourceFileSize == fileSize && - existingIt->second.sourceWriteTime == writeTime && - !existingIt->second.sourceHash.Empty()) { - outRecord.sourceHash = existingIt->second.sourceHash; + if (existingRecord != nullptr && + existingRecord->sourceFileSize == fileSize && + existingRecord->sourceWriteTime == writeTime && + !existingRecord->sourceHash.Empty()) { + outRecord.sourceHash = existingRecord->sourceHash; } else { outRecord.sourceHash = ComputeFileHash(sourcePath); } @@ -2251,8 +1533,7 @@ bool AssetDatabase::EnsureMetaForPath(const fs::path& sourcePath, outRecord.sourceWriteTime = writeTime; } - m_sourcesByPathKey[pathKey] = outRecord; - m_sourcesByGuid[outRecord.guid] = outRecord; + GetSourceAssetDB().Upsert(pathKey, outRecord); return true; } @@ -2277,9 +1558,9 @@ bool AssetDatabase::EnsureMetaForPath(const fs::path& sourcePath, shouldRewriteMeta = true; } - const auto duplicateGuidIt = m_sourcesByGuid.find(outRecord.guid); - if (duplicateGuidIt != m_sourcesByGuid.end() && - duplicateGuidIt->second.relativePath != relativePath) { + const SourceAssetRecord* duplicateGuidRecord = GetSourceAssetDB().FindByGuid(outRecord.guid); + if (duplicateGuidRecord != nullptr && + duplicateGuidRecord->relativePath != relativePath) { outRecord.guid = AssetGUID::Generate(); shouldRewriteMeta = true; } @@ -2296,11 +1577,11 @@ bool AssetDatabase::EnsureMetaForPath(const fs::path& sourcePath, } else { const Core::uint64 fileSize = GetFileSizeValue(sourcePath); const Core::uint64 writeTime = GetFileWriteTimeValue(sourcePath); - if (existingIt != m_sourcesByPathKey.end() && - existingIt->second.sourceFileSize == fileSize && - existingIt->second.sourceWriteTime == writeTime && - !existingIt->second.sourceHash.Empty()) { - outRecord.sourceHash = existingIt->second.sourceHash; + if (existingRecord != nullptr && + existingRecord->sourceFileSize == fileSize && + existingRecord->sourceWriteTime == writeTime && + !existingRecord->sourceHash.Empty()) { + outRecord.sourceHash = existingRecord->sourceHash; } else { outRecord.sourceHash = ComputeFileHash(sourcePath); } @@ -2308,8 +1589,7 @@ bool AssetDatabase::EnsureMetaForPath(const fs::path& sourcePath, outRecord.sourceWriteTime = writeTime; } - m_sourcesByPathKey[pathKey] = outRecord; - m_sourcesByGuid[outRecord.guid] = outRecord; + GetSourceAssetDB().Upsert(pathKey, outRecord); return true; } @@ -2550,131 +1830,8 @@ bool AssetDatabase::ImportAsset(const SourceAssetRecord& sourceRecord, bool AssetDatabase::EnsureArtifact(const Containers::String& requestPath, ResourceType requestedType, ResolvedAsset& outAsset) { - outAsset = ResolvedAsset(); - ClearLastErrorMessage(); - - Containers::String absolutePath; - Containers::String relativePath; - if (!ResolvePath(requestPath, absolutePath, relativePath) || relativePath.Empty()) { - SetLastErrorMessage(Containers::String("Unable to resolve asset path: ") + requestPath); - if (ShouldTraceAssetPath(requestPath)) { - Debug::Logger::Get().Info( - Debug::LogCategory::FileSystem, - Containers::String("[AssetDatabase] EnsureArtifact unresolved path=") + requestPath); - } - return false; - } - - const fs::path absoluteFsPath(absolutePath.CStr()); - if (!fs::exists(absoluteFsPath)) { - SetLastErrorMessage(Containers::String("Asset source file does not exist: ") + absolutePath); - if (ShouldTraceAssetPath(requestPath)) { - Debug::Logger::Get().Info( - Debug::LogCategory::FileSystem, - Containers::String("[AssetDatabase] EnsureArtifact missing source path=") + - requestPath + - " absolute=" + - absolutePath); - } - return false; - } - - SourceAssetRecord sourceRecord; - if (!EnsureMetaForPath(absoluteFsPath, fs::is_directory(absoluteFsPath), sourceRecord)) { - SetLastErrorMessage(Containers::String("Failed to prepare asset metadata: ") + absolutePath); - return false; - } - - if (ShouldTraceAssetPath(requestPath)) { - Debug::Logger::Get().Info( - Debug::LogCategory::FileSystem, - Containers::String("[AssetDatabase] EnsureArtifact source path=") + - requestPath + - " guid=" + - sourceRecord.guid.ToString() + - " importer=" + - sourceRecord.importerName + - " relative=" + - sourceRecord.relativePath); - } - - const ResourceType primaryType = GetPrimaryResourceTypeForImporter(sourceRecord.importerName); - if (primaryType == ResourceType::Unknown || primaryType != requestedType) { - SetLastErrorMessage( - Containers::String("Asset type mismatch for ") + - requestPath + - ": requested " + - GetResourceTypeName(requestedType) + - ", importer produces " + - GetResourceTypeName(primaryType)); - if (ShouldTraceAssetPath(requestPath)) { - Debug::Logger::Get().Info( - Debug::LogCategory::FileSystem, - Containers::String("[AssetDatabase] EnsureArtifact type-mismatch path=") + - requestPath + - " requested=" + - GetResourceTypeName(requestedType) + - " importerType=" + - GetResourceTypeName(primaryType)); - } - return false; - } - - ArtifactRecord* artifactRecord = nullptr; - auto artifactIt = m_artifactsByGuid.find(sourceRecord.guid); - if (artifactIt != m_artifactsByGuid.end()) { - artifactRecord = &artifactIt->second; - } - - if (ShouldReimport(sourceRecord, artifactRecord)) { - if (ShouldTraceAssetPath(requestPath)) { - Debug::Logger::Get().Info( - Debug::LogCategory::FileSystem, - Containers::String("[AssetDatabase] EnsureArtifact reimport path=") + requestPath); - } - ArtifactRecord rebuiltRecord; - if (!ImportAsset(sourceRecord, rebuiltRecord)) { - if (m_lastErrorMessage.Empty()) { - SetLastErrorMessage(Containers::String("Failed to import asset: ") + requestPath); - } - if (ShouldTraceAssetPath(requestPath)) { - Debug::Logger::Get().Error( - Debug::LogCategory::FileSystem, - Containers::String("[AssetDatabase] EnsureArtifact reimport failed path=") + requestPath); - } - return false; - } - - m_artifactsByGuid[sourceRecord.guid] = rebuiltRecord; - m_sourcesByGuid[sourceRecord.guid].lastKnownArtifactKey = rebuiltRecord.artifactKey; - m_sourcesByPathKey[ToStdString(MakeKey(sourceRecord.relativePath))].lastKnownArtifactKey = rebuiltRecord.artifactKey; - SaveArtifactDB(); - SaveSourceAssetDB(); - CleanupOrphanedArtifacts(); - artifactRecord = &m_artifactsByGuid[sourceRecord.guid]; - outAsset.imported = true; - } - - if (artifactRecord == nullptr) { - SetLastErrorMessage(Containers::String("Imported asset did not produce an artifact: ") + requestPath); - return false; - } - - outAsset.exists = true; - PopulateResolvedAssetResult(m_projectRoot, sourceRecord, *artifactRecord, outAsset.imported, outAsset); - ClearLastErrorMessage(); - - if (ShouldTraceAssetPath(requestPath)) { - Debug::Logger::Get().Info( - Debug::LogCategory::FileSystem, - Containers::String("[AssetDatabase] EnsureArtifact ready path=") + - requestPath + - " artifactKey=" + - artifactRecord->artifactKey + - " artifact=" + - outAsset.artifactMainPath); - } - return true; + return AssetDatabaseInternal::AssetDatabaseImportRunner(*this).EnsureArtifact( + requestPath, requestedType, outAsset); } bool AssetDatabase::ImportTextureAsset(const SourceAssetRecord& sourceRecord, diff --git a/Pipeline/Core/AssetDatabase/Facade/AssetDatabase.h b/Pipeline/Core/AssetDatabase/Facade/AssetDatabase.h new file mode 100644 index 00000000..19ea9356 --- /dev/null +++ b/Pipeline/Core/AssetDatabase/Facade/AssetDatabase.h @@ -0,0 +1,211 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace XCEngine { +namespace Resources { + +class Mesh; +class Material; +namespace AssetDatabaseInternal { +class AssetDatabaseImportRunner; +class AssetDatabaseMaintenanceRunner; +class SourceAssetDB; +class ArtifactDB; +} + +class AssetDatabase { +public: + AssetDatabase(); + ~AssetDatabase(); + + struct MaintenanceStats { + Core::uint32 importedAssetCount = 0; + Core::uint32 removedArtifactCount = 0; + }; + + struct ArtifactDependencyRecord { + Containers::String path; + Containers::String hash; + Core::uint64 fileSize = 0; + Core::uint64 writeTime = 0; + }; + + struct SourceAssetRecord { + AssetGUID guid; + Containers::String relativePath; + Containers::String metaPath; + bool isFolder = false; + Containers::String importerName; + Core::uint32 importerVersion = 0; + Containers::String metaHash; + Containers::String sourceHash; + Core::uint64 sourceFileSize = 0; + Core::uint64 sourceWriteTime = 0; + Containers::String lastKnownArtifactKey; + }; + + struct ArtifactRecord { + Containers::String artifactKey; + AssetGUID assetGuid; + Containers::String importerName; + Core::uint32 importerVersion = 0; + ResourceType resourceType = ResourceType::Unknown; + ArtifactStorageKind storageKind = ArtifactStorageKind::Unknown; + Containers::String artifactDirectory; + Containers::String mainArtifactPath; + Containers::String mainEntryName; + Containers::String sourceHash; + Containers::String metaHash; + Core::uint64 sourceFileSize = 0; + Core::uint64 sourceWriteTime = 0; + LocalID mainLocalID = kMainAssetLocalID; + std::vector dependencies; + }; + + struct ResolvedAsset { + bool exists = false; + bool artifactReady = false; + bool imported = false; + Containers::String absolutePath; + Containers::String relativePath; + AssetGUID assetGuid; + ResourceType resourceType = ResourceType::Unknown; + Containers::String artifactMainPath; + Containers::String artifactMainEntryPath; + Containers::String artifactDirectory; + ArtifactStorageKind artifactStorageKind = ArtifactStorageKind::Unknown; + Containers::String mainEntryName; + LocalID mainLocalID = kMainAssetLocalID; + }; + + void Initialize(const Containers::String& projectRoot); + void Shutdown(); + MaintenanceStats Refresh(); + + bool ResolvePath(const Containers::String& requestPath, + Containers::String& outAbsolutePath, + Containers::String& outRelativePath) const; + bool TryGetAssetGuid(const Containers::String& requestPath, AssetGUID& outGuid) const; + bool TryGetImportableResourceType(const Containers::String& requestPath, ResourceType& outType) const; + bool TryGetAssetRef(const Containers::String& requestPath, ResourceType resourceType, AssetRef& outRef) const; + bool TryResolveAssetPath(const AssetRef& assetRef, Containers::String& outPath); + bool ReimportAsset(const Containers::String& requestPath, + ResolvedAsset& outAsset, + MaintenanceStats* outStats = nullptr); + bool ReimportAllAssets(MaintenanceStats* outStats = nullptr); + bool EnsureArtifact(const Containers::String& requestPath, + ResourceType requestedType, + ResolvedAsset& outAsset); + bool TryGetPrimaryAssetPath(const AssetGUID& guid, Containers::String& outRelativePath) const; + void BuildLookupSnapshot(std::unordered_map& outPathToGuid, + std::unordered_map& outGuidToPath) const; + + const Containers::String& GetProjectRoot() const { return m_projectRoot; } + const Containers::String& GetAssetsRoot() const { return m_assetsRoot; } + const Containers::String& GetLibraryRoot() const { return m_libraryRoot; } + const Containers::String& GetLastErrorMessage() const { return m_lastErrorMessage; } + +private: + friend class AssetDatabaseInternal::AssetDatabaseImportRunner; + friend class AssetDatabaseInternal::AssetDatabaseMaintenanceRunner; + + static constexpr Core::uint32 kBaseImporterVersion = 7; + + void EnsureProjectLayout(); + void LoadSourceAssetDB(); + void SaveSourceAssetDB() const; + void LoadArtifactDB(); + void SaveArtifactDB() const; + + bool EnsureMetaForPath(const std::filesystem::path& sourcePath, + bool isFolder, + SourceAssetRecord& outRecord); + bool ReadMetaFile(const std::filesystem::path& metaPath, + SourceAssetRecord& inOutRecord) const; + void WriteMetaFile(const std::filesystem::path& metaPath, + const SourceAssetRecord& record) const; + + Containers::String NormalizeRelativePath(const std::filesystem::path& sourcePath) const; + static Containers::String NormalizePathString(const std::filesystem::path& path); + static Containers::String NormalizePathString(const Containers::String& path); + static Containers::String MakeKey(const Containers::String& path); + static Containers::String GetImporterNameForPath(const Containers::String& relativePath, bool isFolder); + static Core::uint32 GetCurrentImporterVersion(const Containers::String& importerName); + static ResourceType GetPrimaryResourceTypeForImporter(const Containers::String& importerName); + + bool ShouldReimport(const SourceAssetRecord& sourceRecord, + const ArtifactRecord* artifactRecord) const; + bool ImportAsset(const SourceAssetRecord& sourceRecord, + ArtifactRecord& outRecord); + bool ImportTextureAsset(const SourceAssetRecord& sourceRecord, + ArtifactRecord& outRecord); + bool ImportMaterialAsset(const SourceAssetRecord& sourceRecord, + ArtifactRecord& outRecord); + bool ImportModelAsset(const SourceAssetRecord& sourceRecord, + ArtifactRecord& outRecord); + bool ImportShaderAsset(const SourceAssetRecord& sourceRecord, + ArtifactRecord& outRecord); + bool ImportGaussianSplatAsset(const SourceAssetRecord& sourceRecord, + ArtifactRecord& outRecord); + bool ImportVolumeFieldAsset(const SourceAssetRecord& sourceRecord, + ArtifactRecord& outRecord); + bool ImportUIDocumentAsset(const SourceAssetRecord& sourceRecord, + UIDocumentKind kind, + const char* artifactFileName, + ResourceType resourceType, + ArtifactRecord& outRecord); + + Containers::String BuildArtifactKey( + const SourceAssetRecord& sourceRecord, + const std::vector& dependencies = {}) const; + Containers::String BuildArtifactDirectory(const Containers::String& artifactKey) const; + Containers::String BuildArtifactFilePath(const Containers::String& artifactKey, + const char* extension) const; + static Containers::String ReadWholeFileText(const std::filesystem::path& path); + static Containers::String ComputeFileHash(const std::filesystem::path& path); + static Core::uint64 GetFileSizeValue(const std::filesystem::path& path); + static Core::uint64 GetFileWriteTimeValue(const std::filesystem::path& path); + Containers::String NormalizeDependencyPath(const std::filesystem::path& path) const; + std::filesystem::path ResolveDependencyPath(const Containers::String& path) const; + bool CaptureDependencyRecord(const std::filesystem::path& path, + ArtifactDependencyRecord& outRecord) const; + bool AreDependenciesCurrent(const std::vector& dependencies) const; + bool CollectModelDependencies(const SourceAssetRecord& sourceRecord, + const std::vector& importedTexturePaths, + std::vector& outDependencies) const; + bool CollectMaterialDependencies(const Material& material, + std::vector& outDependencies) const; + bool CollectShaderDependencies(const SourceAssetRecord& sourceRecord, + std::vector& outDependencies, + Containers::String* outError = nullptr) const; + void ClearLastErrorMessage(); + void SetLastErrorMessage(const Containers::String& message); + + AssetDatabaseInternal::SourceAssetDB& GetSourceAssetDB(); + const AssetDatabaseInternal::SourceAssetDB& GetSourceAssetDB() const; + AssetDatabaseInternal::ArtifactDB& GetArtifactDB(); + const AssetDatabaseInternal::ArtifactDB& GetArtifactDB() const; + + Containers::String m_projectRoot; + Containers::String m_assetsRoot; + Containers::String m_libraryRoot; + Containers::String m_sourceDbPath; + Containers::String m_artifactDbPath; + Containers::String m_lastErrorMessage; + + std::unique_ptr m_sourceAssetDB; + std::unique_ptr m_artifactDB; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/Pipeline/Core/AssetDatabase/Import/AssetDatabaseImport.cpp b/Pipeline/Core/AssetDatabase/Import/AssetDatabaseImport.cpp new file mode 100644 index 00000000..eab26f9a --- /dev/null +++ b/Pipeline/Core/AssetDatabase/Import/AssetDatabaseImport.cpp @@ -0,0 +1,393 @@ +#include "Pipeline/Core/AssetDatabase/Import/AssetDatabaseImport.h" + +#include "Pipeline/Core/AssetDatabase/Maintenance/AssetDatabaseMaintenance.h" +#include "Pipeline/Core/AssetDatabase/Shared/AssetDatabaseShared.h" +#include "Pipeline/Core/AssetDatabase/Stores/AssetDatabaseStores.h" + +#include "engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h" +#include + +#include +#include +#include +#include + +namespace XCEngine { +namespace Resources { +namespace AssetDatabaseInternal { + +namespace fs = std::filesystem; + +AssetDatabaseImportRunner::AssetDatabaseImportRunner(AssetDatabase& assetDatabase) + : m_assetDatabase(assetDatabase) { +} + +bool AssetDatabaseImportRunner::ReimportAsset(const Containers::String& requestPath, + AssetDatabase::ResolvedAsset& outAsset, + AssetDatabase::MaintenanceStats* outStats) { + outAsset = AssetDatabase::ResolvedAsset(); + m_assetDatabase.ClearLastErrorMessage(); + if (outStats != nullptr) { + *outStats = AssetDatabase::MaintenanceStats(); + } + + Containers::String absolutePath; + Containers::String relativePath; + if (!m_assetDatabase.ResolvePath(requestPath, absolutePath, relativePath) || relativePath.Empty()) { + m_assetDatabase.SetLastErrorMessage(Containers::String("Unable to resolve asset path: ") + requestPath); + return false; + } + + const fs::path absoluteFsPath(absolutePath.CStr()); + if (!fs::exists(absoluteFsPath) || fs::is_directory(absoluteFsPath)) { + m_assetDatabase.SetLastErrorMessage(Containers::String("Asset source file does not exist: ") + absolutePath); + return false; + } + + AssetDatabase::SourceAssetRecord sourceRecord; + if (!m_assetDatabase.EnsureMetaForPath(absoluteFsPath, false, sourceRecord)) { + m_assetDatabase.SetLastErrorMessage(Containers::String("Failed to prepare asset metadata: ") + absolutePath); + return false; + } + + const ResourceType primaryType = + AssetDatabase::GetPrimaryResourceTypeForImporter(sourceRecord.importerName); + if (primaryType == ResourceType::Unknown) { + m_assetDatabase.SetLastErrorMessage(Containers::String("Asset type is not importable: ") + requestPath); + return false; + } + + AssetDatabase::ArtifactRecord rebuiltRecord; + if (!m_assetDatabase.ImportAsset(sourceRecord, rebuiltRecord)) { + if (m_assetDatabase.m_lastErrorMessage.Empty()) { + m_assetDatabase.SetLastErrorMessage(Containers::String("Failed to import asset: ") + requestPath); + } + return false; + } + + CommitArtifactRecord(sourceRecord, rebuiltRecord, true); + + AssetDatabase::MaintenanceStats localStats; + localStats.importedAssetCount = 1; + localStats.removedArtifactCount = + AssetDatabaseMaintenanceRunner(m_assetDatabase).CleanupOrphanedArtifacts(); + if (outStats != nullptr) { + *outStats = localStats; + } + + PopulateResolvedAssetResult(m_assetDatabase.m_projectRoot, sourceRecord, rebuiltRecord, true, outAsset); + m_assetDatabase.ClearLastErrorMessage(); + return true; +} + +std::vector AssetDatabaseImportRunner::CollectImportableRecords() const { + std::vector importableRecords; + const auto& sourceRecordsByGuid = m_assetDatabase.GetSourceAssetDB().GetRecordsByGuid(); + importableRecords.reserve(sourceRecordsByGuid.size()); + + for (const auto& [guid, record] : sourceRecordsByGuid) { + (void)guid; + if (record.isFolder) { + continue; + } + + const ResourceType primaryType = + AssetDatabase::GetPrimaryResourceTypeForImporter(record.importerName); + if (primaryType == ResourceType::Unknown) { + continue; + } + + const fs::path sourcePath = + fs::path(m_assetDatabase.m_projectRoot.CStr()) / record.relativePath.CStr(); + if (!fs::exists(sourcePath) || fs::is_directory(sourcePath)) { + continue; + } + + importableRecords.push_back(record); + } + + std::sort(importableRecords.begin(), importableRecords.end(), + [](const AssetDatabase::SourceAssetRecord& lhs, + const AssetDatabase::SourceAssetRecord& rhs) { + return ToStdString(lhs.relativePath) < ToStdString(rhs.relativePath); + }); + return importableRecords; +} + +bool AssetDatabaseImportRunner::ReimportAllAssets(AssetDatabase::MaintenanceStats* outStats) { + m_assetDatabase.ClearLastErrorMessage(); + if (outStats != nullptr) { + *outStats = AssetDatabase::MaintenanceStats(); + } + + const std::vector importableRecords = CollectImportableRecords(); + + bool allSucceeded = true; + AssetDatabase::MaintenanceStats localStats; + for (const AssetDatabase::SourceAssetRecord& record : importableRecords) { + AssetDatabase::ArtifactRecord rebuiltRecord; + if (!m_assetDatabase.ImportAsset(record, rebuiltRecord)) { + Debug::Logger::Get().Error( + Debug::LogCategory::FileSystem, + Containers::String("[AssetDatabase] ReimportAllAssets failed path=") + record.relativePath); + allSucceeded = false; + continue; + } + + CommitArtifactRecord(record, rebuiltRecord, false); + ++localStats.importedAssetCount; + } + + localStats.removedArtifactCount = + AssetDatabaseMaintenanceRunner(m_assetDatabase).CleanupOrphanedArtifacts(); + if (outStats != nullptr) { + *outStats = localStats; + } + return allSucceeded; +} + +bool AssetDatabaseImportRunner::EnsureArtifact(const Containers::String& requestPath, + ResourceType requestedType, + AssetDatabase::ResolvedAsset& outAsset) { + outAsset = AssetDatabase::ResolvedAsset(); + m_assetDatabase.ClearLastErrorMessage(); + + Containers::String absolutePath; + Containers::String relativePath; + if (!m_assetDatabase.ResolvePath(requestPath, absolutePath, relativePath) || relativePath.Empty()) { + m_assetDatabase.SetLastErrorMessage(Containers::String("Unable to resolve asset path: ") + requestPath); + if (ShouldTraceAssetPath(requestPath)) { + Debug::Logger::Get().Info( + Debug::LogCategory::FileSystem, + Containers::String("[AssetDatabase] EnsureArtifact unresolved path=") + requestPath); + } + return false; + } + + const fs::path absoluteFsPath(absolutePath.CStr()); + if (!fs::exists(absoluteFsPath)) { + m_assetDatabase.SetLastErrorMessage( + Containers::String("Asset source file does not exist: ") + absolutePath); + if (ShouldTraceAssetPath(requestPath)) { + Debug::Logger::Get().Info( + Debug::LogCategory::FileSystem, + Containers::String("[AssetDatabase] EnsureArtifact missing source path=") + + requestPath + + " absolute=" + + absolutePath); + } + return false; + } + + AssetDatabase::SourceAssetRecord sourceRecord; + if (!m_assetDatabase.EnsureMetaForPath( + absoluteFsPath, + fs::is_directory(absoluteFsPath), + sourceRecord)) { + m_assetDatabase.SetLastErrorMessage( + Containers::String("Failed to prepare asset metadata: ") + absolutePath); + return false; + } + + if (ShouldTraceAssetPath(requestPath)) { + Debug::Logger::Get().Info( + Debug::LogCategory::FileSystem, + Containers::String("[AssetDatabase] EnsureArtifact source path=") + + requestPath + + " guid=" + + sourceRecord.guid.ToString() + + " importer=" + + sourceRecord.importerName + + " relative=" + + sourceRecord.relativePath); + } + + const ResourceType primaryType = + AssetDatabase::GetPrimaryResourceTypeForImporter(sourceRecord.importerName); + if (primaryType == ResourceType::Unknown || primaryType != requestedType) { + m_assetDatabase.SetLastErrorMessage( + Containers::String("Asset type mismatch for ") + + requestPath + + ": requested " + + GetResourceTypeName(requestedType) + + ", importer produces " + + GetResourceTypeName(primaryType)); + if (ShouldTraceAssetPath(requestPath)) { + Debug::Logger::Get().Info( + Debug::LogCategory::FileSystem, + Containers::String("[AssetDatabase] EnsureArtifact type-mismatch path=") + + requestPath + + " requested=" + + GetResourceTypeName(requestedType) + + " importerType=" + + GetResourceTypeName(primaryType)); + } + return false; + } + + const AssetDatabase::ArtifactRecord* artifactRecord = + m_assetDatabase.GetArtifactDB().FindByGuid(sourceRecord.guid); + if (m_assetDatabase.ShouldReimport(sourceRecord, artifactRecord)) { + if (ShouldTraceAssetPath(requestPath)) { + Debug::Logger::Get().Info( + Debug::LogCategory::FileSystem, + Containers::String("[AssetDatabase] EnsureArtifact reimport path=") + requestPath); + } + + AssetDatabase::ArtifactRecord rebuiltRecord; + if (!m_assetDatabase.ImportAsset(sourceRecord, rebuiltRecord)) { + if (m_assetDatabase.m_lastErrorMessage.Empty()) { + m_assetDatabase.SetLastErrorMessage(Containers::String("Failed to import asset: ") + requestPath); + } + if (ShouldTraceAssetPath(requestPath)) { + Debug::Logger::Get().Error( + Debug::LogCategory::FileSystem, + Containers::String("[AssetDatabase] EnsureArtifact reimport failed path=") + requestPath); + } + return false; + } + + CommitArtifactRecord(sourceRecord, rebuiltRecord, true); + artifactRecord = m_assetDatabase.GetArtifactDB().FindByGuid(sourceRecord.guid); + outAsset.imported = true; + } + + if (artifactRecord == nullptr) { + m_assetDatabase.SetLastErrorMessage( + Containers::String("Imported asset did not produce an artifact: ") + requestPath); + return false; + } + + outAsset.exists = true; + PopulateResolvedAssetResult( + m_assetDatabase.m_projectRoot, + sourceRecord, + *artifactRecord, + outAsset.imported, + outAsset); + m_assetDatabase.ClearLastErrorMessage(); + + if (ShouldTraceAssetPath(requestPath)) { + Debug::Logger::Get().Info( + Debug::LogCategory::FileSystem, + Containers::String("[AssetDatabase] EnsureArtifact ready path=") + + requestPath + + " artifactKey=" + + artifactRecord->artifactKey + + " artifact=" + + outAsset.artifactMainPath); + } + return true; +} + +bool AssetDatabaseImportRunner::TryResolveAssetPath(const AssetRef& assetRef, + Containers::String& outPath) { + outPath.Clear(); + m_assetDatabase.ClearLastErrorMessage(); + + if (!assetRef.IsValid()) { + return false; + } + + if (assetRef.localID == kMainAssetLocalID) { + return m_assetDatabase.TryGetPrimaryAssetPath(assetRef.assetGuid, outPath); + } + + const AssetDatabase::SourceAssetRecord* sourceRecord = + m_assetDatabase.GetSourceAssetDB().FindByGuid(assetRef.assetGuid); + if (sourceRecord == nullptr) { + m_assetDatabase.SetLastErrorMessage( + Containers::String("Unknown asset GUID for sub-asset path resolution: ") + + assetRef.assetGuid.ToString()); + return false; + } + + const ResourceType primaryType = + AssetDatabase::GetPrimaryResourceTypeForImporter(sourceRecord->importerName); + if (primaryType == ResourceType::Unknown) { + m_assetDatabase.SetLastErrorMessage( + Containers::String("Asset does not have an importable primary type: ") + + sourceRecord->relativePath); + return false; + } + + auto resolveFromArtifactRecord = + [&](const AssetDatabase::ArtifactRecord& artifactRecord) -> bool { + const Containers::String absoluteMainArtifactPath = NormalizeArtifactPathString( + fs::path(m_assetDatabase.m_projectRoot.CStr()) / + artifactRecord.mainArtifactPath.CStr()); + + ArtifactContainerReader reader; + Containers::String containerError; + if (reader.Open(absoluteMainArtifactPath, &containerError)) { + const ArtifactContainerEntryView* entry = + reader.FindEntry(assetRef.resourceType, assetRef.localID); + if (entry != nullptr) { + outPath = BuildArtifactContainerEntryPath(absoluteMainArtifactPath, entry->name); + return true; + } + } + + const fs::path manifestPath = + fs::path(m_assetDatabase.m_projectRoot.CStr()) / + artifactRecord.artifactDirectory.CStr() / + kModelSubAssetManifestFileName; + + Containers::String artifactPath; + if (!TryResolveModelSubAssetArtifactPath(manifestPath, assetRef, artifactPath)) { + return false; + } + + outPath = NormalizeArtifactPathString( + fs::path(m_assetDatabase.m_projectRoot.CStr()) / artifactPath.CStr()); + return true; + }; + + const AssetDatabase::ArtifactRecord* artifactRecord = + m_assetDatabase.GetArtifactDB().FindByGuid(assetRef.assetGuid); + if (artifactRecord != nullptr && + !m_assetDatabase.ShouldReimport(*sourceRecord, artifactRecord) && + resolveFromArtifactRecord(*artifactRecord)) { + return true; + } + + AssetDatabase::ResolvedAsset resolvedAsset; + if (!m_assetDatabase.EnsureArtifact(sourceRecord->relativePath, primaryType, resolvedAsset)) { + if (m_assetDatabase.m_lastErrorMessage.Empty()) { + m_assetDatabase.SetLastErrorMessage( + Containers::String("Failed to import asset while resolving sub-asset path: ") + + sourceRecord->relativePath); + } + return false; + } + + artifactRecord = m_assetDatabase.GetArtifactDB().FindByGuid(assetRef.assetGuid); + if (artifactRecord != nullptr && resolveFromArtifactRecord(*artifactRecord)) { + return true; + } + + m_assetDatabase.SetLastErrorMessage( + Containers::String("Sub-asset localID was not found in artifact manifest: ") + + sourceRecord->relativePath); + return false; +} + +void AssetDatabaseImportRunner::CommitArtifactRecord( + const AssetDatabase::SourceAssetRecord& sourceRecord, + const AssetDatabase::ArtifactRecord& artifactRecord, + bool cleanupOrphans) { + m_assetDatabase.GetArtifactDB().Upsert(sourceRecord.guid, artifactRecord); + m_assetDatabase.GetSourceAssetDB().SetLastKnownArtifactKey( + ToStdString(AssetDatabase::MakeKey(sourceRecord.relativePath)), + sourceRecord.guid, + artifactRecord.artifactKey); + m_assetDatabase.SaveArtifactDB(); + m_assetDatabase.SaveSourceAssetDB(); + if (cleanupOrphans) { + AssetDatabaseMaintenanceRunner(m_assetDatabase).CleanupOrphanedArtifacts(); + } +} + +} // namespace AssetDatabaseInternal +} // namespace Resources +} // namespace XCEngine diff --git a/Pipeline/Core/AssetDatabase/Import/AssetDatabaseImport.h b/Pipeline/Core/AssetDatabase/Import/AssetDatabaseImport.h new file mode 100644 index 00000000..de34ab2b --- /dev/null +++ b/Pipeline/Core/AssetDatabase/Import/AssetDatabaseImport.h @@ -0,0 +1,33 @@ +#pragma once + +#include "Pipeline/Core/AssetDatabase/Facade/AssetDatabase.h" + +namespace XCEngine { +namespace Resources { +namespace AssetDatabaseInternal { + +class AssetDatabaseImportRunner { +public: + explicit AssetDatabaseImportRunner(AssetDatabase& assetDatabase); + + bool ReimportAsset(const Containers::String& requestPath, + AssetDatabase::ResolvedAsset& outAsset, + AssetDatabase::MaintenanceStats* outStats); + bool ReimportAllAssets(AssetDatabase::MaintenanceStats* outStats); + bool EnsureArtifact(const Containers::String& requestPath, + ResourceType requestedType, + AssetDatabase::ResolvedAsset& outAsset); + bool TryResolveAssetPath(const AssetRef& assetRef, Containers::String& outPath); + +private: + void CommitArtifactRecord(const AssetDatabase::SourceAssetRecord& sourceRecord, + const AssetDatabase::ArtifactRecord& artifactRecord, + bool cleanupOrphans); + std::vector CollectImportableRecords() const; + + AssetDatabase& m_assetDatabase; +}; + +} // namespace AssetDatabaseInternal +} // namespace Resources +} // namespace XCEngine diff --git a/Pipeline/Core/AssetDatabase/Maintenance/AssetDatabaseMaintenance.cpp b/Pipeline/Core/AssetDatabase/Maintenance/AssetDatabaseMaintenance.cpp new file mode 100644 index 00000000..17dbd1a0 --- /dev/null +++ b/Pipeline/Core/AssetDatabase/Maintenance/AssetDatabaseMaintenance.cpp @@ -0,0 +1,215 @@ +#include "Pipeline/Core/AssetDatabase/Maintenance/AssetDatabaseMaintenance.h" + +#include "Pipeline/Core/AssetDatabase/Stores/AssetDatabaseStores.h" + +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace XCEngine { +namespace Resources { +namespace AssetDatabaseInternal { + +namespace fs = std::filesystem; + +namespace { + +std::string ToStdString(const Containers::String& value) { + return std::string(value.CStr()); +} + +std::string ToLowerCopy(std::string text) { + std::transform(text.begin(), text.end(), text.begin(), [](unsigned char ch) { + return static_cast(std::tolower(ch)); + }); + return text; +} + +std::vector CollectBuiltinShaderAssetPaths() { + std::vector paths; + paths.reserve(14u); + + Containers::String resolvedPath; + const Containers::String builtinShaderPaths[] = { + GetBuiltinForwardLitShaderPath(), + GetBuiltinUnlitShaderPath(), + GetBuiltinDepthOnlyShaderPath(), + GetBuiltinShadowCasterShaderPath(), +#if XCENGINE_ENABLE_RENDERING_EDITOR_SUPPORT + GetBuiltinObjectIdShaderPath(), +#endif + GetBuiltinSkyboxShaderPath(), + GetBuiltinGaussianSplatShaderPath(), + GetBuiltinGaussianSplatUtilitiesShaderPath(), + GetBuiltinVolumetricShaderPath(), + GetBuiltinColorScalePostProcessShaderPath(), + GetBuiltinFinalColorShaderPath() + }; + + for (const Containers::String& builtinPath : builtinShaderPaths) { + if (TryResolveBuiltinShaderAssetPath(builtinPath, resolvedPath) && !resolvedPath.Empty()) { + paths.push_back(fs::path(resolvedPath.CStr())); + } + } + + return paths; +} + +} // namespace + +AssetDatabaseMaintenanceRunner::AssetDatabaseMaintenanceRunner(AssetDatabase& assetDatabase) + : m_assetDatabase(assetDatabase) { +} + +AssetDatabase::MaintenanceStats AssetDatabaseMaintenanceRunner::Refresh() { + AssetDatabase::MaintenanceStats stats; + std::unordered_map seenPaths; + const fs::path assetsRootPath(m_assetDatabase.m_assetsRoot.CStr()); + if (fs::exists(assetsRootPath)) { + ScanAssetPath(assetsRootPath, seenPaths); + } + for (const fs::path& builtinShaderPath : CollectBuiltinShaderAssetPaths()) { + ScanAssetPath(builtinShaderPath, seenPaths); + } + RemoveMissingRecords(seenPaths); + stats.removedArtifactCount = CleanupOrphanedArtifacts(); + m_assetDatabase.SaveSourceAssetDB(); + m_assetDatabase.SaveArtifactDB(); + return stats; +} + +void AssetDatabaseMaintenanceRunner::ScanAssetPath( + const fs::path& path, + std::unordered_map& seenPaths) { + if (!fs::exists(path)) { + return; + } + + if (path.has_extension() && + ToLowerCopy(path.extension().string()) == ".meta") { + return; + } + + const bool isFolder = fs::is_directory(path); + AssetDatabase::SourceAssetRecord record; + if (m_assetDatabase.EnsureMetaForPath(path, isFolder, record)) { + seenPaths[ToStdString(AssetDatabase::MakeKey(record.relativePath))] = true; + } + + if (!isFolder) { + return; + } + + for (const auto& entry : fs::directory_iterator(path)) { + ScanAssetPath(entry.path(), seenPaths); + } +} + +void AssetDatabaseMaintenanceRunner::RemoveMissingRecords( + const std::unordered_map& seenPaths) { + std::vector missingPathKeys; + for (const auto& [pathKey, record] : m_assetDatabase.GetSourceAssetDB().GetRecordsByPathKey()) { + (void)record; + if (seenPaths.find(pathKey) == seenPaths.end()) { + missingPathKeys.push_back(pathKey); + } + } + + for (const std::string& pathKey : missingPathKeys) { + const AssetDatabase::SourceAssetRecord* record = + m_assetDatabase.GetSourceAssetDB().FindByPathKey(pathKey); + if (record == nullptr) { + continue; + } + + m_assetDatabase.GetArtifactDB().EraseByGuid(record->guid); + m_assetDatabase.GetSourceAssetDB().EraseByPathKey(pathKey); + } +} + +Core::uint32 AssetDatabaseMaintenanceRunner::CleanupOrphanedArtifacts() const { + std::error_code ec; + const fs::path artifactsRoot = fs::path(m_assetDatabase.m_libraryRoot.CStr()) / "Artifacts"; + if (!fs::exists(artifactsRoot, ec) || !fs::is_directory(artifactsRoot, ec)) { + return 0; + } + + std::unordered_set retainedArtifactPathKeys; + const auto& artifactRecordsByGuid = m_assetDatabase.GetArtifactDB().GetRecordsByGuid(); + retainedArtifactPathKeys.reserve(artifactRecordsByGuid.size() * 2u); + for (const auto& [guid, record] : artifactRecordsByGuid) { + (void)guid; + if (!record.artifactDirectory.Empty()) { + retainedArtifactPathKeys.insert( + ToStdString(AssetDatabase::MakeKey(record.artifactDirectory))); + } + if (!record.mainArtifactPath.Empty()) { + retainedArtifactPathKeys.insert( + ToStdString(AssetDatabase::MakeKey(record.mainArtifactPath))); + } + } + + Core::uint32 removedArtifactCount = 0; + for (const auto& shardEntry : fs::directory_iterator(artifactsRoot, ec)) { + if (ec) { + ec.clear(); + break; + } + + const fs::path shardPath = shardEntry.path(); + if (!shardEntry.is_directory()) { + fs::remove_all(shardPath, ec); + if (!ec) { + ++removedArtifactCount; + } + ec.clear(); + continue; + } + + for (const auto& artifactEntry : fs::directory_iterator(shardPath, ec)) { + if (ec) { + ec.clear(); + break; + } + + const Containers::String relativeArtifactPath = + m_assetDatabase.NormalizeRelativePath(artifactEntry.path()); + const std::string artifactPathKey = + ToStdString(AssetDatabase::MakeKey(relativeArtifactPath)); + if (!relativeArtifactPath.Empty() && + retainedArtifactPathKeys.find(artifactPathKey) != retainedArtifactPathKeys.end()) { + continue; + } + + fs::remove_all(artifactEntry.path(), ec); + if (!ec) { + ++removedArtifactCount; + } + ec.clear(); + } + + std::error_code shardEc; + if (fs::is_empty(shardPath, shardEc)) { + fs::remove(shardPath, shardEc); + } + } + + if (removedArtifactCount > 0) { + Debug::Logger::Get().Info( + Debug::LogCategory::FileSystem, + Containers::String("[AssetDatabase] Removed orphan artifact entries count=") + + Containers::String(std::to_string(removedArtifactCount).c_str())); + } + + return removedArtifactCount; +} + +} // namespace AssetDatabaseInternal +} // namespace Resources +} // namespace XCEngine diff --git a/Pipeline/Core/AssetDatabase/Maintenance/AssetDatabaseMaintenance.h b/Pipeline/Core/AssetDatabase/Maintenance/AssetDatabaseMaintenance.h new file mode 100644 index 00000000..92180a2e --- /dev/null +++ b/Pipeline/Core/AssetDatabase/Maintenance/AssetDatabaseMaintenance.h @@ -0,0 +1,26 @@ +#pragma once + +#include "Pipeline/Core/AssetDatabase/Facade/AssetDatabase.h" + +namespace XCEngine { +namespace Resources { +namespace AssetDatabaseInternal { + +class AssetDatabaseMaintenanceRunner { +public: + explicit AssetDatabaseMaintenanceRunner(AssetDatabase& assetDatabase); + + AssetDatabase::MaintenanceStats Refresh(); + Core::uint32 CleanupOrphanedArtifacts() const; + +private: + void ScanAssetPath(const std::filesystem::path& path, + std::unordered_map& seenPaths); + void RemoveMissingRecords(const std::unordered_map& seenPaths); + + AssetDatabase& m_assetDatabase; +}; + +} // namespace AssetDatabaseInternal +} // namespace Resources +} // namespace XCEngine diff --git a/Pipeline/Core/AssetDatabase/Shared/AssetDatabaseShared.cpp b/Pipeline/Core/AssetDatabase/Shared/AssetDatabaseShared.cpp new file mode 100644 index 00000000..ca40081e --- /dev/null +++ b/Pipeline/Core/AssetDatabase/Shared/AssetDatabaseShared.cpp @@ -0,0 +1,287 @@ +#include "Pipeline/Core/AssetDatabase/Shared/AssetDatabaseShared.h" + +#include "engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h" + +#include +#include +#include +#include + +namespace XCEngine { +namespace Resources { +namespace AssetDatabaseInternal { + +namespace fs = std::filesystem; + +std::string ToStdString(const Containers::String& value) { + return std::string(value.CStr()); +} + +Containers::String ToContainersString(const std::string& value) { + return Containers::String(value.c_str()); +} + +bool HasVirtualPathScheme(const Containers::String& value) { + return ToStdString(value).find("://") != std::string::npos; +} + +bool ShouldTraceAssetPath(const Containers::String& path) { + const std::string text = ToStdString(path); + return text.rfind("builtin://", 0) == 0 || + text.find("backpack") != std::string::npos || + text.find("New Material.mat") != std::string::npos; +} + +Containers::String NormalizeArtifactPathString(const fs::path& path) { + if (path.empty()) { + return Containers::String(); + } + + return ToContainersString(path.lexically_normal().generic_string()); +} + +Containers::String NormalizeArtifactPathString(const Containers::String& path) { + if (path.Empty()) { + return Containers::String(); + } + + return NormalizeArtifactPathString(fs::path(path.CStr())); +} + +ArtifactStorageKind InferArtifactStorageKind( + const Containers::String& projectRoot, + const AssetDatabase::ArtifactRecord& record) { + if (!record.mainArtifactPath.Empty()) { + const Containers::String absoluteMainArtifactPath = + NormalizeArtifactPathString(fs::path(projectRoot.CStr()) / record.mainArtifactPath.CStr()); + if (IsArtifactContainerFile(absoluteMainArtifactPath)) { + return ArtifactStorageKind::SingleFileContainer; + } + } + + return record.artifactDirectory.Empty() + ? ArtifactStorageKind::Unknown + : ArtifactStorageKind::LegacyDirectory; +} + +Containers::String BuildArtifactMainEntryLoadPath( + const Containers::String& artifactMainPath, + ArtifactStorageKind storageKind, + const Containers::String& mainEntryName) { + if (storageKind == ArtifactStorageKind::SingleFileContainer && + !artifactMainPath.Empty() && + !mainEntryName.Empty()) { + return BuildArtifactContainerEntryPath(artifactMainPath, mainEntryName); + } + + return artifactMainPath; +} + +namespace { + +std::string EscapeField(const std::string& value) { + std::string escaped; + escaped.reserve(value.size()); + for (const char ch : value) { + if (ch == '\\' || ch == '\t' || ch == '\n' || ch == '\r') { + escaped.push_back('\\'); + switch (ch) { + case '\t': + escaped.push_back('t'); + break; + case '\n': + escaped.push_back('n'); + break; + case '\r': + escaped.push_back('r'); + break; + default: + escaped.push_back(ch); + break; + } + } else { + escaped.push_back(ch); + } + } + return escaped; +} + +std::string UnescapeField(const std::string& value) { + std::string result; + result.reserve(value.size()); + for (size_t index = 0; index < value.size(); ++index) { + if (value[index] == '\\' && index + 1 < value.size()) { + ++index; + switch (value[index]) { + case 't': + result.push_back('\t'); + break; + case 'n': + result.push_back('\n'); + break; + case 'r': + result.push_back('\r'); + break; + default: + result.push_back(value[index]); + break; + } + } else { + result.push_back(value[index]); + } + } + return result; +} + +std::vector SplitFields(const std::string& line) { + std::vector fields; + std::string current; + bool escaping = false; + + for (const char ch : line) { + if (escaping) { + current.push_back('\\'); + current.push_back(ch); + escaping = false; + continue; + } + + if (ch == '\\') { + escaping = true; + continue; + } + + if (ch == '\t') { + fields.push_back(UnescapeField(current)); + current.clear(); + continue; + } + + current.push_back(ch); + } + + if (escaping) { + current.push_back('\\'); + } + + fields.push_back(UnescapeField(current)); + return fields; +} + +} // namespace + +bool WriteModelSubAssetManifest( + const std::filesystem::path& manifestPath, + const std::vector& entries) { + std::ofstream output(manifestPath, std::ios::out | std::ios::trunc); + if (!output.is_open()) { + return false; + } + + output << "# localID\tresourceType\tartifactPath\n"; + for (const ModelSubAssetManifestEntry& entry : entries) { + if (entry.localID == kInvalidLocalID || + entry.resourceType == ResourceType::Unknown || + entry.artifactPath.Empty()) { + continue; + } + + output << entry.localID << '\t' + << static_cast(entry.resourceType) << '\t' + << EscapeField(ToStdString(entry.artifactPath)) << '\n'; + } + + return static_cast(output); +} + +bool TryReadModelSubAssetManifest( + const std::filesystem::path& manifestPath, + std::vector& outEntries) { + outEntries.clear(); + + std::ifstream input(manifestPath); + if (!input.is_open()) { + return false; + } + + std::string line; + while (std::getline(input, line)) { + if (line.empty() || line[0] == '#') { + continue; + } + + const std::vector fields = SplitFields(line); + if (fields.size() < 3) { + continue; + } + + ModelSubAssetManifestEntry entry; + entry.localID = static_cast(std::stoull(fields[0])); + entry.resourceType = static_cast(std::stoul(fields[1])); + entry.artifactPath = ToContainersString(fields[2]); + if (entry.localID == kInvalidLocalID || + entry.resourceType == ResourceType::Unknown || + entry.artifactPath.Empty()) { + continue; + } + + outEntries.push_back(entry); + } + + return true; +} + +bool TryResolveModelSubAssetArtifactPath( + const std::filesystem::path& manifestPath, + const AssetRef& assetRef, + Containers::String& outArtifactPath) { + std::vector entries; + if (!TryReadModelSubAssetManifest(manifestPath, entries)) { + return false; + } + + for (const ModelSubAssetManifestEntry& entry : entries) { + if (entry.localID != assetRef.localID || entry.resourceType != assetRef.resourceType) { + continue; + } + + outArtifactPath = entry.artifactPath; + return true; + } + + return false; +} + +void PopulateResolvedAssetResult( + const Containers::String& projectRoot, + const AssetDatabase::SourceAssetRecord& sourceRecord, + const AssetDatabase::ArtifactRecord& artifactRecord, + bool imported, + AssetDatabase::ResolvedAsset& outAsset) { + outAsset = AssetDatabase::ResolvedAsset(); + outAsset.exists = true; + outAsset.artifactReady = true; + outAsset.imported = imported; + outAsset.absolutePath = + NormalizeArtifactPathString(fs::path(projectRoot.CStr()) / sourceRecord.relativePath.CStr()); + outAsset.relativePath = sourceRecord.relativePath; + outAsset.assetGuid = sourceRecord.guid; + outAsset.resourceType = artifactRecord.resourceType; + outAsset.artifactStorageKind = artifactRecord.storageKind; + outAsset.mainEntryName = artifactRecord.mainEntryName; + if (!artifactRecord.artifactDirectory.Empty()) { + outAsset.artifactDirectory = NormalizeArtifactPathString( + fs::path(projectRoot.CStr()) / artifactRecord.artifactDirectory.CStr()); + } + outAsset.artifactMainPath = NormalizeArtifactPathString( + fs::path(projectRoot.CStr()) / artifactRecord.mainArtifactPath.CStr()); + outAsset.artifactMainEntryPath = BuildArtifactMainEntryLoadPath( + outAsset.artifactMainPath, + artifactRecord.storageKind, + artifactRecord.mainEntryName); + outAsset.mainLocalID = artifactRecord.mainLocalID; +} + +} // namespace AssetDatabaseInternal +} // namespace Resources +} // namespace XCEngine diff --git a/Pipeline/Core/AssetDatabase/Shared/AssetDatabaseShared.h b/Pipeline/Core/AssetDatabase/Shared/AssetDatabaseShared.h new file mode 100644 index 00000000..2fac1dfa --- /dev/null +++ b/Pipeline/Core/AssetDatabase/Shared/AssetDatabaseShared.h @@ -0,0 +1,56 @@ +#pragma once + +#include "Pipeline/Core/AssetDatabase/Facade/AssetDatabase.h" + +#include +#include +#include + +namespace XCEngine { +namespace Resources { +namespace AssetDatabaseInternal { + +std::string ToStdString(const Containers::String& value); +Containers::String ToContainersString(const std::string& value); +bool HasVirtualPathScheme(const Containers::String& value); +bool ShouldTraceAssetPath(const Containers::String& path); + +Containers::String NormalizeArtifactPathString(const std::filesystem::path& path); +Containers::String NormalizeArtifactPathString(const Containers::String& path); + +ArtifactStorageKind InferArtifactStorageKind( + const Containers::String& projectRoot, + const AssetDatabase::ArtifactRecord& record); +Containers::String BuildArtifactMainEntryLoadPath( + const Containers::String& artifactMainPath, + ArtifactStorageKind storageKind, + const Containers::String& mainEntryName); + +inline constexpr const char* kModelSubAssetManifestFileName = "subassets.tsv"; + +struct ModelSubAssetManifestEntry { + LocalID localID = kInvalidLocalID; + ResourceType resourceType = ResourceType::Unknown; + Containers::String artifactPath; +}; + +bool WriteModelSubAssetManifest( + const std::filesystem::path& manifestPath, + const std::vector& entries); +bool TryReadModelSubAssetManifest( + const std::filesystem::path& manifestPath, + std::vector& outEntries); +bool TryResolveModelSubAssetArtifactPath( + const std::filesystem::path& manifestPath, + const AssetRef& assetRef, + Containers::String& outArtifactPath); +void PopulateResolvedAssetResult( + const Containers::String& projectRoot, + const AssetDatabase::SourceAssetRecord& sourceRecord, + const AssetDatabase::ArtifactRecord& artifactRecord, + bool imported, + AssetDatabase::ResolvedAsset& outAsset); + +} // namespace AssetDatabaseInternal +} // namespace Resources +} // namespace XCEngine diff --git a/Pipeline/Core/AssetDatabase/Stores/AssetDatabaseStores.cpp b/Pipeline/Core/AssetDatabase/Stores/AssetDatabaseStores.cpp new file mode 100644 index 00000000..eca68bf4 --- /dev/null +++ b/Pipeline/Core/AssetDatabase/Stores/AssetDatabaseStores.cpp @@ -0,0 +1,435 @@ +#include "Pipeline/Core/AssetDatabase/Stores/AssetDatabaseStores.h" + +#include "Pipeline/Core/AssetDatabase/Shared/AssetDatabaseShared.h" +#include "engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h" + +#include +#include +#include +#include +#include +#include + +namespace XCEngine { +namespace Resources { + +using AssetDatabaseInternal::NormalizeArtifactPathString; +using AssetDatabaseInternal::ToContainersString; +using AssetDatabaseInternal::ToStdString; + +namespace { + +using SourceAssetRecord = AssetDatabase::SourceAssetRecord; +using ArtifactRecord = AssetDatabase::ArtifactRecord; +using ArtifactDependencyRecord = AssetDatabase::ArtifactDependencyRecord; +namespace fs = std::filesystem; + +Containers::String NormalizePathString(const fs::path& path) { + return ToContainersString(path.lexically_normal().generic_string()); +} + +Containers::String MakeKey(const Containers::String& path) { + std::string key = ToStdString(NormalizePathString(fs::path(path.CStr()))); + std::transform(key.begin(), key.end(), key.begin(), [](unsigned char ch) { + return static_cast(std::tolower(ch)); + }); + return ToContainersString(key); +} + +std::string EscapeField(const std::string& value) { + std::string escaped; + escaped.reserve(value.size()); + for (const char ch : value) { + if (ch == '\\' || ch == '\t' || ch == '\n' || ch == '\r') { + escaped.push_back('\\'); + switch (ch) { + case '\t': + escaped.push_back('t'); + break; + case '\n': + escaped.push_back('n'); + break; + case '\r': + escaped.push_back('r'); + break; + default: + escaped.push_back(ch); + break; + } + } else { + escaped.push_back(ch); + } + } + return escaped; +} + +std::string UnescapeField(const std::string& value) { + std::string result; + result.reserve(value.size()); + for (size_t index = 0; index < value.size(); ++index) { + if (value[index] == '\\' && index + 1 < value.size()) { + ++index; + switch (value[index]) { + case 't': + result.push_back('\t'); + break; + case 'n': + result.push_back('\n'); + break; + case 'r': + result.push_back('\r'); + break; + default: + result.push_back(value[index]); + break; + } + } else { + result.push_back(value[index]); + } + } + return result; +} + +std::vector SplitFields(const std::string& line) { + std::vector fields; + std::string current; + bool escaping = false; + + for (const char ch : line) { + if (escaping) { + current.push_back('\\'); + current.push_back(ch); + escaping = false; + continue; + } + + if (ch == '\\') { + escaping = true; + continue; + } + + if (ch == '\t') { + fields.push_back(UnescapeField(current)); + current.clear(); + continue; + } + + current.push_back(ch); + } + + if (escaping) { + current.push_back('\\'); + } + + fields.push_back(UnescapeField(current)); + return fields; +} + +constexpr Core::uint32 kArtifactDbSchemaVersion = 2; + +} // namespace + +namespace AssetDatabaseInternal { + +void SourceAssetDB::Clear() { + m_recordsByPathKey.clear(); + m_recordsByGuid.clear(); +} + +bool SourceAssetDB::Load(const Containers::String& sourceDbPath) { + Clear(); + + std::ifstream input(sourceDbPath.CStr()); + if (!input.is_open()) { + return false; + } + + std::string line; + while (std::getline(input, line)) { + if (line.empty() || line[0] == '#') { + continue; + } + + const std::vector fields = SplitFields(line); + if (fields.size() < 10) { + continue; + } + + SourceAssetRecord record; + record.guid = AssetGUID::ParseOrDefault(ToContainersString(fields[0])); + record.relativePath = ToContainersString(fields[1]); + record.metaPath = ToContainersString(fields[2]); + record.isFolder = (fields[3] == "1"); + record.importerName = ToContainersString(fields[4]); + record.importerVersion = static_cast(std::stoul(fields[5])); + record.metaHash = ToContainersString(fields[6]); + record.sourceHash = ToContainersString(fields[7]); + record.sourceFileSize = static_cast(std::stoull(fields[8])); + record.sourceWriteTime = static_cast(std::stoull(fields[9])); + if (fields.size() > 10) { + record.lastKnownArtifactKey = ToContainersString(fields[10]); + } + + if (!record.guid.IsValid() || record.relativePath.Empty()) { + continue; + } + + const std::string pathKey = ToStdString(MakeKey(record.relativePath)); + m_recordsByGuid[record.guid] = record; + m_recordsByPathKey[pathKey] = record; + } + + return true; +} + +bool SourceAssetDB::Save(const Containers::String& sourceDbPath) const { + std::ofstream output(sourceDbPath.CStr(), std::ios::out | std::ios::trunc); + if (!output.is_open()) { + return false; + } + + output << "# guid\trelativePath\tmetaPath\tisFolder\timporter\timporterVersion\tmetaHash\tsourceHash\tsize\twriteTime\tartifactKey\n"; + for (const auto& [guid, record] : m_recordsByGuid) { + (void)guid; + output << EscapeField(ToStdString(record.guid.ToString())) << '\t' + << EscapeField(ToStdString(record.relativePath)) << '\t' + << EscapeField(ToStdString(record.metaPath)) << '\t' + << (record.isFolder ? "1" : "0") << '\t' + << EscapeField(ToStdString(record.importerName)) << '\t' + << record.importerVersion << '\t' + << EscapeField(ToStdString(record.metaHash)) << '\t' + << EscapeField(ToStdString(record.sourceHash)) << '\t' + << record.sourceFileSize << '\t' + << record.sourceWriteTime << '\t' + << EscapeField(ToStdString(record.lastKnownArtifactKey)) << '\n'; + } + + return true; +} + +SourceAssetRecord* SourceAssetDB::FindByPathKey(const std::string& pathKey) { + auto it = m_recordsByPathKey.find(pathKey); + return it != m_recordsByPathKey.end() ? &it->second : nullptr; +} + +const SourceAssetRecord* SourceAssetDB::FindByPathKey(const std::string& pathKey) const { + auto it = m_recordsByPathKey.find(pathKey); + return it != m_recordsByPathKey.end() ? &it->second : nullptr; +} + +SourceAssetRecord* SourceAssetDB::FindByGuid(const AssetGUID& guid) { + auto it = m_recordsByGuid.find(guid); + return it != m_recordsByGuid.end() ? &it->second : nullptr; +} + +const SourceAssetRecord* SourceAssetDB::FindByGuid(const AssetGUID& guid) const { + auto it = m_recordsByGuid.find(guid); + return it != m_recordsByGuid.end() ? &it->second : nullptr; +} + +void SourceAssetDB::Upsert(const std::string& pathKey, const SourceAssetRecord& record) { + auto existingByPath = m_recordsByPathKey.find(pathKey); + if (existingByPath != m_recordsByPathKey.end() && existingByPath->second.guid != record.guid) { + m_recordsByGuid.erase(existingByPath->second.guid); + } + + auto existingByGuid = m_recordsByGuid.find(record.guid); + if (existingByGuid != m_recordsByGuid.end()) { + const std::string existingPathKey = ToStdString(MakeKey(existingByGuid->second.relativePath)); + if (existingPathKey != pathKey) { + m_recordsByPathKey.erase(existingPathKey); + } + } + + m_recordsByPathKey[pathKey] = record; + m_recordsByGuid[record.guid] = record; +} + +void SourceAssetDB::EraseByPathKey(const std::string& pathKey) { + auto it = m_recordsByPathKey.find(pathKey); + if (it == m_recordsByPathKey.end()) { + return; + } + + m_recordsByGuid.erase(it->second.guid); + m_recordsByPathKey.erase(it); +} + +void SourceAssetDB::SetLastKnownArtifactKey(const std::string& pathKey, + const AssetGUID& guid, + const Containers::String& artifactKey) { + auto pathIt = m_recordsByPathKey.find(pathKey); + if (pathIt != m_recordsByPathKey.end()) { + pathIt->second.lastKnownArtifactKey = artifactKey; + } + + auto guidIt = m_recordsByGuid.find(guid); + if (guidIt != m_recordsByGuid.end()) { + guidIt->second.lastKnownArtifactKey = artifactKey; + } +} + +const std::unordered_map& SourceAssetDB::GetRecordsByPathKey() const { + return m_recordsByPathKey; +} + +const std::unordered_map& SourceAssetDB::GetRecordsByGuid() const { + return m_recordsByGuid; +} + +void ArtifactDB::Clear() { + m_recordsByGuid.clear(); +} + +bool ArtifactDB::Load(const Containers::String& projectRoot, const Containers::String& artifactDbPath) { + Clear(); + + std::ifstream input(artifactDbPath.CStr()); + if (!input.is_open()) { + return false; + } + + std::string line; + Core::uint32 schemaVersion = 1; + while (std::getline(input, line)) { + if (line.empty()) { + continue; + } + + if (line[0] == '#') { + const std::string schemaToken = "schema="; + const size_t schemaTokenPosition = line.find(schemaToken); + if (schemaTokenPosition != std::string::npos) { + const size_t valueStart = schemaTokenPosition + schemaToken.length(); + const std::string valueText = line.substr(valueStart); + if (!valueText.empty()) { + schemaVersion = static_cast(std::stoul(valueText)); + } + } else if (line.find("storageKind") != std::string::npos && + line.find("mainEntryName") != std::string::npos) { + schemaVersion = std::max(schemaVersion, kArtifactDbSchemaVersion); + } + continue; + } + + const std::vector fields = SplitFields(line); + if (fields.size() < 10) { + continue; + } + + ArtifactRecord record; + record.artifactKey = ToContainersString(fields[0]); + record.assetGuid = AssetGUID::ParseOrDefault(ToContainersString(fields[1])); + record.importerName = ToContainersString(fields[2]); + record.importerVersion = static_cast(std::stoul(fields[3])); + record.resourceType = static_cast(std::stoul(fields[4])); + record.artifactDirectory = ToContainersString(fields[5]); + record.mainArtifactPath = ToContainersString(fields[6]); + record.sourceHash = ToContainersString(fields[7]); + record.metaHash = ToContainersString(fields[8]); + record.sourceFileSize = static_cast(std::stoull(fields[9])); + record.sourceWriteTime = + fields.size() > 10 ? static_cast(std::stoull(fields[10])) : 0; + record.mainLocalID = + fields.size() > 11 ? static_cast(std::stoull(fields[11])) : kMainAssetLocalID; + size_t dependencyFieldStart = 12; + if (schemaVersion >= kArtifactDbSchemaVersion && fields.size() > 13) { + record.storageKind = static_cast(std::stoul(fields[12])); + record.mainEntryName = ToContainersString(fields[13]); + dependencyFieldStart = 14; + } + + if (record.storageKind == ArtifactStorageKind::Unknown) { + record.storageKind = InferArtifactStorageKind(projectRoot, record); + } + if (record.mainEntryName.Empty() && + record.storageKind == ArtifactStorageKind::SingleFileContainer) { + record.mainEntryName = "main"; + } + if (record.artifactDirectory.Empty() && !record.mainArtifactPath.Empty()) { + record.artifactDirectory = NormalizeArtifactPathString( + fs::path(record.mainArtifactPath.CStr()).parent_path()); + } + + for (size_t index = dependencyFieldStart; index + 3 < fields.size(); index += 4) { + ArtifactDependencyRecord dependency; + dependency.path = ToContainersString(fields[index + 0]); + dependency.hash = ToContainersString(fields[index + 1]); + dependency.fileSize = static_cast(std::stoull(fields[index + 2])); + dependency.writeTime = static_cast(std::stoull(fields[index + 3])); + if (!dependency.path.Empty()) { + record.dependencies.push_back(dependency); + } + } + + if (!record.assetGuid.IsValid() || record.artifactKey.Empty()) { + continue; + } + + m_recordsByGuid[record.assetGuid] = record; + } + + return true; +} + +bool ArtifactDB::Save(const Containers::String& artifactDbPath) const { + std::ofstream output(artifactDbPath.CStr(), std::ios::out | std::ios::trunc); + if (!output.is_open()) { + return false; + } + + output << "# schema=" << kArtifactDbSchemaVersion << "\n"; + output << "# artifactKey\tassetGuid\timporter\tversion\ttype\tartifactDir\tmainArtifact\tsourceHash\tmetaHash\tsize\twriteTime\tmainLocalID\tstorageKind\tmainEntryName\t(depPath\tdepHash\tdepSize\tdepWriteTime)...\n"; + for (const auto& [guid, record] : m_recordsByGuid) { + (void)guid; + output << EscapeField(ToStdString(record.artifactKey)) << '\t' + << EscapeField(ToStdString(record.assetGuid.ToString())) << '\t' + << EscapeField(ToStdString(record.importerName)) << '\t' + << record.importerVersion << '\t' + << static_cast(record.resourceType) << '\t' + << EscapeField(ToStdString(record.artifactDirectory)) << '\t' + << EscapeField(ToStdString(record.mainArtifactPath)) << '\t' + << EscapeField(ToStdString(record.sourceHash)) << '\t' + << EscapeField(ToStdString(record.metaHash)) << '\t' + << record.sourceFileSize << '\t' + << record.sourceWriteTime << '\t' + << record.mainLocalID << '\t' + << static_cast(record.storageKind) << '\t' + << EscapeField(ToStdString(record.mainEntryName)); + for (const ArtifactDependencyRecord& dependency : record.dependencies) { + output << '\t' << EscapeField(ToStdString(dependency.path)) + << '\t' << EscapeField(ToStdString(dependency.hash)) + << '\t' << dependency.fileSize + << '\t' << dependency.writeTime; + } + output << '\n'; + } + + return true; +} + +ArtifactRecord* ArtifactDB::FindByGuid(const AssetGUID& guid) { + auto it = m_recordsByGuid.find(guid); + return it != m_recordsByGuid.end() ? &it->second : nullptr; +} + +const ArtifactRecord* ArtifactDB::FindByGuid(const AssetGUID& guid) const { + auto it = m_recordsByGuid.find(guid); + return it != m_recordsByGuid.end() ? &it->second : nullptr; +} + +void ArtifactDB::Upsert(const AssetGUID& guid, const ArtifactRecord& record) { + m_recordsByGuid[guid] = record; +} + +void ArtifactDB::EraseByGuid(const AssetGUID& guid) { + m_recordsByGuid.erase(guid); +} + +const std::unordered_map& ArtifactDB::GetRecordsByGuid() const { + return m_recordsByGuid; +} + +} // namespace AssetDatabaseInternal +} // namespace Resources +} // namespace XCEngine diff --git a/Pipeline/Core/AssetDatabase/Stores/AssetDatabaseStores.h b/Pipeline/Core/AssetDatabase/Stores/AssetDatabaseStores.h new file mode 100644 index 00000000..dd561197 --- /dev/null +++ b/Pipeline/Core/AssetDatabase/Stores/AssetDatabaseStores.h @@ -0,0 +1,55 @@ +#pragma once + +#include "Pipeline/Core/AssetDatabase/Facade/AssetDatabase.h" + +#include + +namespace XCEngine { +namespace Resources { +namespace AssetDatabaseInternal { + +class SourceAssetDB { +public: + void Clear(); + bool Load(const Containers::String& sourceDbPath); + bool Save(const Containers::String& sourceDbPath) const; + + AssetDatabase::SourceAssetRecord* FindByPathKey(const std::string& pathKey); + const AssetDatabase::SourceAssetRecord* FindByPathKey(const std::string& pathKey) const; + AssetDatabase::SourceAssetRecord* FindByGuid(const AssetGUID& guid); + const AssetDatabase::SourceAssetRecord* FindByGuid(const AssetGUID& guid) const; + + void Upsert(const std::string& pathKey, const AssetDatabase::SourceAssetRecord& record); + void EraseByPathKey(const std::string& pathKey); + void SetLastKnownArtifactKey(const std::string& pathKey, + const AssetGUID& guid, + const Containers::String& artifactKey); + + const std::unordered_map& GetRecordsByPathKey() const; + const std::unordered_map& GetRecordsByGuid() const; + +private: + std::unordered_map m_recordsByPathKey; + std::unordered_map m_recordsByGuid; +}; + +class ArtifactDB { +public: + void Clear(); + bool Load(const Containers::String& projectRoot, const Containers::String& artifactDbPath); + bool Save(const Containers::String& artifactDbPath) const; + + AssetDatabase::ArtifactRecord* FindByGuid(const AssetGUID& guid); + const AssetDatabase::ArtifactRecord* FindByGuid(const AssetGUID& guid) const; + void Upsert(const AssetGUID& guid, const AssetDatabase::ArtifactRecord& record); + void EraseByGuid(const AssetGUID& guid); + + const std::unordered_map& GetRecordsByGuid() const; + +private: + std::unordered_map m_recordsByGuid; +}; + +} // namespace AssetDatabaseInternal +} // namespace Resources +} // namespace XCEngine diff --git a/Pipeline/Core/Contracts/IProjectAssetPipelineService.h b/Pipeline/Core/Contracts/IProjectAssetPipelineService.h new file mode 100644 index 00000000..dd9d751c --- /dev/null +++ b/Pipeline/Core/Contracts/IProjectAssetPipelineService.h @@ -0,0 +1,29 @@ +#pragma once + +#include "IProjectAssetResolver.h" + +namespace XCEngine { +namespace Resources { + +class IProjectAssetPipelineService : public IProjectAssetResolver { +public: + ~IProjectAssetPipelineService() override = default; + + virtual void Initialize() = 0; + virtual void Shutdown() = 0; + + virtual void SetProjectRoot(const Containers::String& projectRoot) = 0; + virtual Containers::String GetLibraryRoot() const = 0; + + virtual bool BootstrapProject() = 0; + virtual void Refresh() = 0; + virtual bool ClearLibraryCache() = 0; + virtual bool RebuildLibraryCache() = 0; + virtual bool ReimportAllAssets() = 0; + virtual bool ReimportAsset(const Containers::String& requestPath, + ProjectAssetImportedAsset& outAsset) = 0; + virtual ProjectAssetImportStatusSnapshot GetLastImportStatus() const = 0; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/Pipeline/Core/Contracts/IProjectAssetResolver.h b/Pipeline/Core/Contracts/IProjectAssetResolver.h new file mode 100644 index 00000000..e6d93514 --- /dev/null +++ b/Pipeline/Core/Contracts/IProjectAssetResolver.h @@ -0,0 +1,29 @@ +#pragma once + +#include "ProjectAssetTypes.h" + +namespace XCEngine { +namespace Resources { + +class IProjectAssetResolver { +public: + virtual ~IProjectAssetResolver() = default; + + virtual Containers::String GetProjectRoot() const = 0; + virtual bool TryGetImportableResourceType(const Containers::String& requestPath, + ResourceType& outType) const = 0; + virtual bool EnsureArtifact(const Containers::String& requestPath, + ResourceType requestedType, + ProjectAssetImportedAsset& outAsset) = 0; + virtual bool TryGetAssetRef(const Containers::String& requestPath, + ResourceType resourceType, + AssetRef& outRef) const = 0; + virtual bool TryGetPrimaryAssetPath(const AssetGUID& guid, + Containers::String& outRelativePath) const = 0; + virtual bool TryResolveAssetPath(const AssetRef& assetRef, + Containers::String& outPath) const = 0; + virtual void BuildLookupSnapshot(ProjectAssetLookupSnapshot& outSnapshot) const = 0; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/Pipeline/Core/Contracts/ProjectAssetTypes.h b/Pipeline/Core/Contracts/ProjectAssetTypes.h new file mode 100644 index 00000000..6c59e276 --- /dev/null +++ b/Pipeline/Core/Contracts/ProjectAssetTypes.h @@ -0,0 +1,66 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include + +namespace XCEngine { +namespace Resources { + +enum class ArtifactStorageKind : Core::uint8 { + Unknown = 0, + LegacyDirectory = 1, + SingleFileContainer = 2 +}; + +struct ProjectAssetImportStatusSnapshot { + Core::uint64 revision = 0; + bool inProgress = false; + bool success = false; + Containers::String operation; + Containers::String targetPath; + Containers::String message; + Core::uint64 startedAtMs = 0; + Core::uint64 completedAtMs = 0; + Core::uint64 durationMs = 0; + Core::uint32 importedAssetCount = 0; + Core::uint32 removedArtifactCount = 0; + + bool HasValue() const { + return revision != 0; + } +}; + +struct ProjectAssetLookupSnapshot { + std::unordered_map assetGuidByPathKey; + std::unordered_map assetPathByGuid; + + void Clear() { + assetGuidByPathKey.clear(); + assetPathByGuid.clear(); + } +}; + +struct ProjectAssetImportedAsset { + bool exists = false; + bool artifactReady = false; + bool imported = false; + Containers::String absolutePath; + Containers::String relativePath; + AssetGUID assetGuid; + ResourceType resourceType = ResourceType::Unknown; + Containers::String runtimeLoadPath; + Containers::String artifactMainPath; + Containers::String artifactMainEntryPath; + Containers::String artifactDirectory; + ArtifactStorageKind artifactStorageKind = ArtifactStorageKind::Unknown; + Containers::String mainEntryName; + LocalID mainLocalID = kMainAssetLocalID; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Core/Asset/AssetImportService.cpp b/Pipeline/Core/ImportService/AssetImportService.cpp similarity index 72% rename from engine/src/Core/Asset/AssetImportService.cpp rename to Pipeline/Core/ImportService/AssetImportService.cpp index 283e319d..5569f56e 100644 --- a/engine/src/Core/Asset/AssetImportService.cpp +++ b/Pipeline/Core/ImportService/AssetImportService.cpp @@ -1,4 +1,5 @@ -#include +#include "AssetImportService.h" +#include "Pipeline/Core/AssetDatabase/Facade/AssetDatabase.h" #include #include @@ -15,325 +16,24 @@ Containers::String ToContainersString(const std::string& value) { return Containers::String(value.c_str()); } -Containers::String BuildStatsSuffix(const AssetDatabase::MaintenanceStats& stats) { +Containers::String BuildStatsSuffix(Core::uint32 importedAssetCount, + Core::uint32 removedArtifactCount) { std::string suffix; - if (stats.importedAssetCount > 0) { + if (importedAssetCount > 0) { suffix += " imported="; - suffix += std::to_string(stats.importedAssetCount); + suffix += std::to_string(importedAssetCount); } - if (stats.removedArtifactCount > 0) { + if (removedArtifactCount > 0) { suffix += " removedOrphans="; - suffix += std::to_string(stats.removedArtifactCount); + suffix += std::to_string(removedArtifactCount); } return ToContainersString(suffix); } -Core::uint64 GetCurrentSteadyTimeMs() { - return static_cast( - std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()).count()); -} - -} // namespace - -void AssetImportService::Initialize() { -} - -void AssetImportService::Shutdown() { - std::lock_guard lock(m_mutex); - m_assetDatabase.Shutdown(); - m_projectRoot.Clear(); - ResetImportStatusLocked(); -} - -void AssetImportService::SetProjectRoot(const Containers::String& projectRoot) { - std::lock_guard lock(m_mutex); - - if (m_projectRoot == projectRoot) { - return; - } - - if (!m_projectRoot.Empty()) { - m_assetDatabase.Shutdown(); - } - - m_projectRoot = projectRoot; - ResetImportStatusLocked(); - if (!m_projectRoot.Empty()) { - m_assetDatabase.Initialize(m_projectRoot); - } -} - -Containers::String AssetImportService::GetProjectRoot() const { - std::lock_guard lock(m_mutex); - return m_projectRoot; -} - -Containers::String AssetImportService::GetLibraryRoot() const { - std::lock_guard lock(m_mutex); - return m_assetDatabase.GetLibraryRoot(); -} - -bool AssetImportService::BootstrapProject() { - std::lock_guard lock(m_mutex); - if (m_projectRoot.Empty()) { - FinishImportStatusLocked( - "Bootstrap Project", - Containers::String(), - false, - "Cannot bootstrap project assets without an active project.", - AssetDatabase::MaintenanceStats()); - return false; - } - - BeginImportStatusLocked( - "Bootstrap Project", - m_projectRoot, - "Bootstrapping project Library state..."); - - const AssetDatabase::MaintenanceStats stats = m_assetDatabase.Refresh(); - FinishImportStatusLocked( - "Bootstrap Project", - m_projectRoot, - true, - Containers::String("Bootstrapped project Library state.") + BuildStatsSuffix(stats), - stats); - return true; -} - -void AssetImportService::Refresh() { - std::lock_guard lock(m_mutex); - if (!m_projectRoot.Empty()) { - const AssetDatabase::MaintenanceStats stats = m_assetDatabase.Refresh(); - if (stats.removedArtifactCount > 0) { - FinishImportStatusLocked( - "Refresh", - m_projectRoot, - true, - Containers::String("Refresh removed orphan artifact entries.") + BuildStatsSuffix(stats), - stats); - } - } -} - -bool AssetImportService::ClearLibraryCache() { - std::lock_guard lock(m_mutex); - if (m_projectRoot.Empty()) { - FinishImportStatusLocked( - "Clear Library", - Containers::String(), - false, - "Cannot clear Library cache without an active project.", - AssetDatabase::MaintenanceStats()); - return false; - } - - BeginImportStatusLocked( - "Clear Library", - m_assetDatabase.GetLibraryRoot(), - "Clearing Library cache..."); - - const Containers::String projectRoot = m_projectRoot; - const Containers::String libraryRoot = m_assetDatabase.GetLibraryRoot(); - - m_assetDatabase.Shutdown(); - - std::error_code ec; - fs::remove_all(fs::path(libraryRoot.CStr()), ec); - - m_assetDatabase.Initialize(projectRoot); - const AssetDatabase::MaintenanceStats stats = m_assetDatabase.Refresh(); - const bool succeeded = !ec; - FinishImportStatusLocked( - "Clear Library", - libraryRoot, - succeeded, - succeeded - ? Containers::String("Cleared Library cache and rebuilt source asset lookup.") + BuildStatsSuffix(stats) - : Containers::String("Failed to clear Library cache."), - stats); - return succeeded; -} - -bool AssetImportService::RebuildLibraryCache() { - if (!ClearLibraryCache()) { - return false; - } - - return ReimportAllAssets(); -} - -bool AssetImportService::ReimportAllAssets() { - std::lock_guard lock(m_mutex); - if (m_projectRoot.Empty()) { - FinishImportStatusLocked( - "Reimport All Assets", - Containers::String(), - false, - "Cannot reimport assets without an active project.", - AssetDatabase::MaintenanceStats()); - return false; - } - - BeginImportStatusLocked( - "Reimport All Assets", - m_projectRoot, - "Reimporting all project assets..."); - m_assetDatabase.Refresh(); - - AssetDatabase::MaintenanceStats stats; - const bool succeeded = m_assetDatabase.ReimportAllAssets(&stats); - FinishImportStatusLocked( - "Reimport All Assets", - m_projectRoot, - succeeded, - succeeded - ? Containers::String("Reimported all project assets.") + BuildStatsSuffix(stats) - : Containers::String("Reimport all assets completed with failures.") + BuildStatsSuffix(stats), - stats); - return succeeded; -} - -bool AssetImportService::ReimportAsset(const Containers::String& requestPath, - ImportedAsset& outAsset) { - std::lock_guard lock(m_mutex); - if (m_projectRoot.Empty()) { - FinishImportStatusLocked( - "Reimport Asset", - requestPath, - false, - "Cannot reimport an asset without an active project.", - AssetDatabase::MaintenanceStats()); - return false; - } - - BeginImportStatusLocked( - "Reimport Asset", - requestPath, - Containers::String("Reimporting asset: ") + requestPath); - m_assetDatabase.Refresh(); - - AssetDatabase::ResolvedAsset resolvedAsset; - AssetDatabase::MaintenanceStats stats; - if (!m_assetDatabase.ReimportAsset(requestPath, resolvedAsset, &stats)) { - const Containers::String databaseError = m_assetDatabase.GetLastErrorMessage(); - FinishImportStatusLocked( - "Reimport Asset", - requestPath, - false, - !databaseError.Empty() - ? Containers::String("Failed to reimport asset: ") + requestPath + " - " + databaseError - : Containers::String("Failed to reimport asset: ") + requestPath, - stats); - return false; - } - - outAsset = ConvertResolvedAsset(resolvedAsset); - FinishImportStatusLocked( - "Reimport Asset", - requestPath, - true, - Containers::String("Reimported asset: ") + requestPath + BuildStatsSuffix(stats), - stats); - return true; -} - -AssetImportService::ImportStatusSnapshot AssetImportService::GetLastImportStatus() const { - std::lock_guard lock(m_mutex); - return m_lastImportStatus; -} - -bool AssetImportService::TryGetImportableResourceType(const Containers::String& requestPath, - ResourceType& outType) const { - std::lock_guard lock(m_mutex); - if (m_projectRoot.Empty()) { - outType = ResourceType::Unknown; - return false; - } - - return m_assetDatabase.TryGetImportableResourceType(requestPath, outType); -} - -bool AssetImportService::EnsureArtifact(const Containers::String& requestPath, - ResourceType requestedType, - ImportedAsset& outAsset) { - std::lock_guard lock(m_mutex); - if (m_projectRoot.Empty()) { - return false; - } - - AssetDatabase::ResolvedAsset resolvedAsset; - if (!m_assetDatabase.EnsureArtifact(requestPath, requestedType, resolvedAsset)) { - const Containers::String databaseError = m_assetDatabase.GetLastErrorMessage(); - FinishImportStatusLocked( - "Import Asset", - requestPath, - false, - !databaseError.Empty() - ? Containers::String("Failed to build asset artifact: ") + requestPath + " - " + databaseError - : Containers::String("Failed to build asset artifact: ") + requestPath, - AssetDatabase::MaintenanceStats()); - return false; - } - - outAsset = ConvertResolvedAsset(resolvedAsset); - if (resolvedAsset.imported) { - AssetDatabase::MaintenanceStats stats; - stats.importedAssetCount = 1; - FinishImportStatusLocked( - "Import Asset", - requestPath, - true, - Containers::String("Imported asset artifact: ") + requestPath, - stats); - } - return true; -} - -bool AssetImportService::TryGetAssetRef(const Containers::String& requestPath, - ResourceType resourceType, - AssetRef& outRef) const { - std::lock_guard lock(m_mutex); - if (m_projectRoot.Empty()) { - return false; - } - - return m_assetDatabase.TryGetAssetRef(requestPath, resourceType, outRef); -} - -bool AssetImportService::TryResolveAssetPath(const AssetRef& assetRef, - Containers::String& outPath) { - std::lock_guard lock(m_mutex); - if (m_projectRoot.Empty()) { - return false; - } - - return m_assetDatabase.TryResolveAssetPath(assetRef, outPath); -} - -bool AssetImportService::TryGetPrimaryAssetPath(const AssetGUID& guid, Containers::String& outRelativePath) const { - std::lock_guard lock(m_mutex); - if (m_projectRoot.Empty()) { - return false; - } - - return m_assetDatabase.TryGetPrimaryAssetPath(guid, outRelativePath); -} - -void AssetImportService::BuildLookupSnapshot(LookupSnapshot& outSnapshot) const { - std::lock_guard lock(m_mutex); - outSnapshot.Clear(); - if (m_projectRoot.Empty()) { - return; - } - - m_assetDatabase.BuildLookupSnapshot(outSnapshot.assetGuidByPathKey, outSnapshot.assetPathByGuid); -} - -AssetImportService::ImportedAsset AssetImportService::ConvertResolvedAsset( +AssetImportService::ImportedAsset ConvertResolvedAsset( const AssetDatabase::ResolvedAsset& resolvedAsset) { - ImportedAsset importedAsset; + AssetImportService::ImportedAsset importedAsset; importedAsset.exists = resolvedAsset.exists; importedAsset.artifactReady = resolvedAsset.artifactReady; importedAsset.imported = resolvedAsset.imported; @@ -356,6 +56,350 @@ AssetImportService::ImportedAsset AssetImportService::ConvertResolvedAsset( return importedAsset; } +Core::uint64 GetCurrentSteadyTimeMs() { + return static_cast( + std::chrono::duration_cast( + std::chrono::steady_clock::now().time_since_epoch()).count()); +} + +} // namespace + +AssetImportService::AssetImportService() = default; + +AssetImportService::~AssetImportService() = default; + +void AssetImportService::Initialize() { + if (!m_assetDatabase) { + m_assetDatabase = std::make_unique(); + } +} + +void AssetImportService::Shutdown() { + std::lock_guard lock(m_mutex); + if (m_assetDatabase) { + m_assetDatabase->Shutdown(); + } + m_projectRoot.Clear(); + ResetImportStatusLocked(); +} + +void AssetImportService::SetProjectRoot(const Containers::String& projectRoot) { + std::lock_guard lock(m_mutex); + + if (m_projectRoot == projectRoot) { + return; + } + + if (!m_projectRoot.Empty()) { + if (m_assetDatabase) { + m_assetDatabase->Shutdown(); + } + } + + Initialize(); + m_projectRoot = projectRoot; + ResetImportStatusLocked(); + if (!m_projectRoot.Empty()) { + m_assetDatabase->Initialize(m_projectRoot); + } +} + +Containers::String AssetImportService::GetProjectRoot() const { + std::lock_guard lock(m_mutex); + return m_projectRoot; +} + +Containers::String AssetImportService::GetLibraryRoot() const { + std::lock_guard lock(m_mutex); + return m_assetDatabase ? m_assetDatabase->GetLibraryRoot() : Containers::String(); +} + +bool AssetImportService::BootstrapProject() { + std::lock_guard lock(m_mutex); + if (m_projectRoot.Empty()) { + FinishImportStatusLocked( + "Bootstrap Project", + Containers::String(), + false, + "Cannot bootstrap project assets without an active project.", + ImportOperationStats()); + return false; + } + + BeginImportStatusLocked( + "Bootstrap Project", + m_projectRoot, + "Bootstrapping project Library state..."); + + const AssetDatabase::MaintenanceStats stats = m_assetDatabase->Refresh(); + ImportOperationStats serviceStats; + serviceStats.importedAssetCount = stats.importedAssetCount; + serviceStats.removedArtifactCount = stats.removedArtifactCount; + FinishImportStatusLocked( + "Bootstrap Project", + m_projectRoot, + true, + Containers::String("Bootstrapped project Library state.") + + BuildStatsSuffix(serviceStats.importedAssetCount, serviceStats.removedArtifactCount), + serviceStats); + return true; +} + +void AssetImportService::Refresh() { + std::lock_guard lock(m_mutex); + if (!m_projectRoot.Empty()) { + const AssetDatabase::MaintenanceStats stats = m_assetDatabase->Refresh(); + if (stats.removedArtifactCount > 0) { + ImportOperationStats serviceStats; + serviceStats.importedAssetCount = stats.importedAssetCount; + serviceStats.removedArtifactCount = stats.removedArtifactCount; + FinishImportStatusLocked( + "Refresh", + m_projectRoot, + true, + Containers::String("Refresh removed orphan artifact entries.") + + BuildStatsSuffix(serviceStats.importedAssetCount, serviceStats.removedArtifactCount), + serviceStats); + } + } +} + +bool AssetImportService::ClearLibraryCache() { + std::lock_guard lock(m_mutex); + if (m_projectRoot.Empty()) { + FinishImportStatusLocked( + "Clear Library", + Containers::String(), + false, + "Cannot clear Library cache without an active project.", + ImportOperationStats()); + return false; + } + + BeginImportStatusLocked( + "Clear Library", + m_assetDatabase->GetLibraryRoot(), + "Clearing Library cache..."); + + const Containers::String projectRoot = m_projectRoot; + const Containers::String libraryRoot = m_assetDatabase->GetLibraryRoot(); + + m_assetDatabase->Shutdown(); + + std::error_code ec; + fs::remove_all(fs::path(libraryRoot.CStr()), ec); + + m_assetDatabase->Initialize(projectRoot); + const AssetDatabase::MaintenanceStats stats = m_assetDatabase->Refresh(); + const bool succeeded = !ec; + ImportOperationStats serviceStats; + serviceStats.importedAssetCount = stats.importedAssetCount; + serviceStats.removedArtifactCount = stats.removedArtifactCount; + FinishImportStatusLocked( + "Clear Library", + libraryRoot, + succeeded, + succeeded + ? Containers::String("Cleared Library cache and rebuilt source asset lookup.") + + BuildStatsSuffix(serviceStats.importedAssetCount, serviceStats.removedArtifactCount) + : Containers::String("Failed to clear Library cache."), + serviceStats); + return succeeded; +} + +bool AssetImportService::RebuildLibraryCache() { + if (!ClearLibraryCache()) { + return false; + } + + return ReimportAllAssets(); +} + +bool AssetImportService::ReimportAllAssets() { + std::lock_guard lock(m_mutex); + if (m_projectRoot.Empty()) { + FinishImportStatusLocked( + "Reimport All Assets", + Containers::String(), + false, + "Cannot reimport assets without an active project.", + ImportOperationStats()); + return false; + } + + BeginImportStatusLocked( + "Reimport All Assets", + m_projectRoot, + "Reimporting all project assets..."); + m_assetDatabase->Refresh(); + + AssetDatabase::MaintenanceStats stats; + const bool succeeded = m_assetDatabase->ReimportAllAssets(&stats); + ImportOperationStats serviceStats; + serviceStats.importedAssetCount = stats.importedAssetCount; + serviceStats.removedArtifactCount = stats.removedArtifactCount; + FinishImportStatusLocked( + "Reimport All Assets", + m_projectRoot, + succeeded, + succeeded + ? Containers::String("Reimported all project assets.") + + BuildStatsSuffix(serviceStats.importedAssetCount, serviceStats.removedArtifactCount) + : Containers::String("Reimport all assets completed with failures.") + + BuildStatsSuffix(serviceStats.importedAssetCount, serviceStats.removedArtifactCount), + serviceStats); + return succeeded; +} + +bool AssetImportService::ReimportAsset(const Containers::String& requestPath, + ImportedAsset& outAsset) { + std::lock_guard lock(m_mutex); + if (m_projectRoot.Empty()) { + FinishImportStatusLocked( + "Reimport Asset", + requestPath, + false, + "Cannot reimport an asset without an active project.", + ImportOperationStats()); + return false; + } + + BeginImportStatusLocked( + "Reimport Asset", + requestPath, + Containers::String("Reimporting asset: ") + requestPath); + m_assetDatabase->Refresh(); + + AssetDatabase::ResolvedAsset resolvedAsset; + AssetDatabase::MaintenanceStats stats; + if (!m_assetDatabase->ReimportAsset(requestPath, resolvedAsset, &stats)) { + const Containers::String databaseError = m_assetDatabase->GetLastErrorMessage(); + ImportOperationStats serviceStats; + serviceStats.importedAssetCount = stats.importedAssetCount; + serviceStats.removedArtifactCount = stats.removedArtifactCount; + FinishImportStatusLocked( + "Reimport Asset", + requestPath, + false, + !databaseError.Empty() + ? Containers::String("Failed to reimport asset: ") + requestPath + " - " + databaseError + : Containers::String("Failed to reimport asset: ") + requestPath, + serviceStats); + return false; + } + + outAsset = ConvertResolvedAsset(resolvedAsset); + ImportOperationStats serviceStats; + serviceStats.importedAssetCount = stats.importedAssetCount; + serviceStats.removedArtifactCount = stats.removedArtifactCount; + FinishImportStatusLocked( + "Reimport Asset", + requestPath, + true, + Containers::String("Reimported asset: ") + + requestPath + + BuildStatsSuffix(serviceStats.importedAssetCount, serviceStats.removedArtifactCount), + serviceStats); + return true; +} + +AssetImportService::ImportStatusSnapshot AssetImportService::GetLastImportStatus() const { + std::lock_guard lock(m_mutex); + return m_lastImportStatus; +} + +bool AssetImportService::TryGetImportableResourceType(const Containers::String& requestPath, + ResourceType& outType) const { + std::lock_guard lock(m_mutex); + if (m_projectRoot.Empty()) { + outType = ResourceType::Unknown; + return false; + } + + return m_assetDatabase && m_assetDatabase->TryGetImportableResourceType(requestPath, outType); +} + +bool AssetImportService::EnsureArtifact(const Containers::String& requestPath, + ResourceType requestedType, + ImportedAsset& outAsset) { + std::lock_guard lock(m_mutex); + if (m_projectRoot.Empty()) { + return false; + } + + AssetDatabase::ResolvedAsset resolvedAsset; + if (!m_assetDatabase->EnsureArtifact(requestPath, requestedType, resolvedAsset)) { + const Containers::String databaseError = m_assetDatabase->GetLastErrorMessage(); + FinishImportStatusLocked( + "Import Asset", + requestPath, + false, + !databaseError.Empty() + ? Containers::String("Failed to build asset artifact: ") + requestPath + " - " + databaseError + : Containers::String("Failed to build asset artifact: ") + requestPath, + ImportOperationStats()); + return false; + } + + outAsset = ConvertResolvedAsset(resolvedAsset); + if (resolvedAsset.imported) { + AssetDatabase::MaintenanceStats stats; + stats.importedAssetCount = 1; + ImportOperationStats serviceStats; + serviceStats.importedAssetCount = stats.importedAssetCount; + serviceStats.removedArtifactCount = stats.removedArtifactCount; + FinishImportStatusLocked( + "Import Asset", + requestPath, + true, + Containers::String("Imported asset artifact: ") + requestPath, + serviceStats); + } + return true; +} + +bool AssetImportService::TryGetAssetRef(const Containers::String& requestPath, + ResourceType resourceType, + AssetRef& outRef) const { + std::lock_guard lock(m_mutex); + if (m_projectRoot.Empty()) { + return false; + } + + return m_assetDatabase && m_assetDatabase->TryGetAssetRef(requestPath, resourceType, outRef); +} + +bool AssetImportService::TryResolveAssetPath(const AssetRef& assetRef, + Containers::String& outPath) const { + std::lock_guard lock(m_mutex); + if (m_projectRoot.Empty()) { + return false; + } + + return m_assetDatabase && m_assetDatabase->TryResolveAssetPath(assetRef, outPath); +} + +bool AssetImportService::TryGetPrimaryAssetPath(const AssetGUID& guid, Containers::String& outRelativePath) const { + std::lock_guard lock(m_mutex); + if (m_projectRoot.Empty()) { + return false; + } + + return m_assetDatabase && m_assetDatabase->TryGetPrimaryAssetPath(guid, outRelativePath); +} + +void AssetImportService::BuildLookupSnapshot(LookupSnapshot& outSnapshot) const { + std::lock_guard lock(m_mutex); + outSnapshot.Clear(); + if (m_projectRoot.Empty()) { + return; + } + + if (m_assetDatabase) { + m_assetDatabase->BuildLookupSnapshot(outSnapshot.assetGuidByPathKey, outSnapshot.assetPathByGuid); + } +} + void AssetImportService::ResetImportStatusLocked() { m_lastImportStatus = ImportStatusSnapshot(); m_nextImportStatusRevision = 1; @@ -382,7 +426,7 @@ void AssetImportService::FinishImportStatusLocked(const Containers::String& oper const Containers::String& targetPath, bool success, const Containers::String& message, - const AssetDatabase::MaintenanceStats& stats) { + const ImportOperationStats& stats) { const Core::uint64 completedAtMs = GetCurrentSteadyTimeMs(); const Core::uint64 startedAtMs = m_lastImportStatus.startedAtMs != 0 ? m_lastImportStatus.startedAtMs diff --git a/Pipeline/Core/ImportService/AssetImportService.h b/Pipeline/Core/ImportService/AssetImportService.h new file mode 100644 index 00000000..0545cf83 --- /dev/null +++ b/Pipeline/Core/ImportService/AssetImportService.h @@ -0,0 +1,76 @@ +#pragma once + +#include + +#include +#include + +namespace XCEngine { +namespace Resources { + +class AssetDatabase; + +class AssetImportService : public IProjectAssetPipelineService { +public: + using ImportStatusSnapshot = ProjectAssetImportStatusSnapshot; + using LookupSnapshot = ProjectAssetLookupSnapshot; + using ImportedAsset = ProjectAssetImportedAsset; + + AssetImportService(); + ~AssetImportService() override; + + void Initialize() override; + void Shutdown() override; + + void SetProjectRoot(const Containers::String& projectRoot) override; + Containers::String GetProjectRoot() const override; + Containers::String GetLibraryRoot() const override; + + bool BootstrapProject() override; + void Refresh() override; + bool ClearLibraryCache() override; + bool RebuildLibraryCache() override; + bool ReimportAllAssets() override; + bool ReimportAsset(const Containers::String& requestPath, + ImportedAsset& outAsset) override; + ImportStatusSnapshot GetLastImportStatus() const override; + bool TryGetImportableResourceType(const Containers::String& requestPath, + ResourceType& outType) const override; + + bool EnsureArtifact(const Containers::String& requestPath, + ResourceType requestedType, + ImportedAsset& outAsset) override; + bool TryGetAssetRef(const Containers::String& requestPath, + ResourceType resourceType, + AssetRef& outRef) const override; + bool TryResolveAssetPath(const AssetRef& assetRef, + Containers::String& outPath) const override; + bool TryGetPrimaryAssetPath(const AssetGUID& guid, + Containers::String& outRelativePath) const override; + void BuildLookupSnapshot(LookupSnapshot& outSnapshot) const override; + +private: + struct ImportOperationStats { + Core::uint32 importedAssetCount = 0; + Core::uint32 removedArtifactCount = 0; + }; + + void ResetImportStatusLocked(); + void BeginImportStatusLocked(const Containers::String& operation, + const Containers::String& targetPath, + const Containers::String& message); + void FinishImportStatusLocked(const Containers::String& operation, + const Containers::String& targetPath, + bool success, + const Containers::String& message, + const ImportOperationStats& stats); + + mutable std::recursive_mutex m_mutex; + Containers::String m_projectRoot; + std::unique_ptr m_assetDatabase; + ImportStatusSnapshot m_lastImportStatus; + Core::uint64 m_nextImportStatusRevision = 1; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/Pipeline/Core/ProjectAssetService/ProjectAssetService.cpp b/Pipeline/Core/ProjectAssetService/ProjectAssetService.cpp new file mode 100644 index 00000000..6983ede9 --- /dev/null +++ b/Pipeline/Core/ProjectAssetService/ProjectAssetService.cpp @@ -0,0 +1,153 @@ +#include "ProjectAssetService.h" + +#include "Pipeline/Core/ImportService/AssetImportService.h" +#include "Pipeline/Core/SourceIndex/ProjectAssetIndex.h" + +namespace XCEngine { +namespace Resources { + +struct ProjectAssetService::Impl { + mutable AssetImportService assetImportService; + mutable ProjectAssetIndex projectAssetIndex; +}; + +ProjectAssetService::ProjectAssetService() + : m_impl(std::make_unique()) { +} + +ProjectAssetService::~ProjectAssetService() = default; + +void ProjectAssetService::Initialize() { + m_impl->assetImportService.Initialize(); +} + +void ProjectAssetService::Shutdown() { + m_impl->assetImportService.Shutdown(); + m_impl->projectAssetIndex.ResetProjectRoot(); +} + +void ProjectAssetService::SetProjectRoot(const Containers::String& projectRoot) { + m_impl->assetImportService.SetProjectRoot(projectRoot); + if (projectRoot.Empty()) { + m_impl->projectAssetIndex.ResetProjectRoot(); + } +} + +Containers::String ProjectAssetService::GetProjectRoot() const { + return m_impl->assetImportService.GetProjectRoot(); +} + +Containers::String ProjectAssetService::GetLibraryRoot() const { + return m_impl->assetImportService.GetLibraryRoot(); +} + +bool ProjectAssetService::BootstrapProject() { + const bool bootstrapped = m_impl->assetImportService.BootstrapProject(); + m_impl->projectAssetIndex.RefreshFrom(m_impl->assetImportService); + return bootstrapped; +} + +void ProjectAssetService::Refresh() { + if (m_impl->assetImportService.GetProjectRoot().Empty()) { + return; + } + + m_impl->assetImportService.Refresh(); + m_impl->projectAssetIndex.RefreshFrom(m_impl->assetImportService); +} + +bool ProjectAssetService::ClearLibraryCache() { + if (m_impl->assetImportService.GetProjectRoot().Empty()) { + return false; + } + + const bool cleared = m_impl->assetImportService.ClearLibraryCache(); + m_impl->projectAssetIndex.RefreshFrom(m_impl->assetImportService); + return cleared; +} + +bool ProjectAssetService::RebuildLibraryCache() { + if (m_impl->assetImportService.GetProjectRoot().Empty()) { + return false; + } + + const bool rebuilt = m_impl->assetImportService.RebuildLibraryCache(); + m_impl->projectAssetIndex.RefreshFrom(m_impl->assetImportService); + return rebuilt; +} + +bool ProjectAssetService::ReimportAllAssets() { + if (m_impl->assetImportService.GetProjectRoot().Empty()) { + return false; + } + + const bool reimported = m_impl->assetImportService.ReimportAllAssets(); + m_impl->projectAssetIndex.RefreshFrom(m_impl->assetImportService); + return reimported; +} + +bool ProjectAssetService::ReimportAsset(const Containers::String& requestPath, + ProjectAssetImportedAsset& outAsset) { + if (m_impl->assetImportService.GetProjectRoot().Empty() || requestPath.Empty()) { + return false; + } + + const bool reimported = m_impl->assetImportService.ReimportAsset(requestPath, outAsset); + m_impl->projectAssetIndex.RefreshFrom(m_impl->assetImportService); + if (reimported && outAsset.assetGuid.IsValid() && !outAsset.relativePath.Empty()) { + m_impl->projectAssetIndex.RememberResolvedPath(outAsset.assetGuid, outAsset.relativePath); + } + + return reimported; +} + +ProjectAssetImportStatusSnapshot ProjectAssetService::GetLastImportStatus() const { + return m_impl->assetImportService.GetLastImportStatus(); +} + +bool ProjectAssetService::TryGetImportableResourceType(const Containers::String& requestPath, + ResourceType& outType) const { + return m_impl->assetImportService.TryGetImportableResourceType(requestPath, outType); +} + +bool ProjectAssetService::EnsureArtifact(const Containers::String& requestPath, + ResourceType requestedType, + ProjectAssetImportedAsset& outAsset) { + const bool resolved = + m_impl->assetImportService.EnsureArtifact(requestPath, requestedType, outAsset); + if (resolved && outAsset.assetGuid.IsValid() && !outAsset.relativePath.Empty()) { + m_impl->projectAssetIndex.RememberResolvedPath(outAsset.assetGuid, outAsset.relativePath); + } + + return resolved; +} + +bool ProjectAssetService::TryGetAssetRef(const Containers::String& requestPath, + ResourceType resourceType, + AssetRef& outRef) const { + return m_impl->projectAssetIndex.TryGetAssetRef( + m_impl->assetImportService, + requestPath, + resourceType, + outRef); +} + +bool ProjectAssetService::TryGetPrimaryAssetPath(const AssetGUID& guid, + Containers::String& outRelativePath) const { + return m_impl->assetImportService.TryGetPrimaryAssetPath(guid, outRelativePath); +} + +bool ProjectAssetService::TryResolveAssetPath(const AssetRef& assetRef, + Containers::String& outPath) const { + return m_impl->projectAssetIndex.TryResolveAssetPath( + m_impl->assetImportService, + assetRef, + outPath); +} + +void ProjectAssetService::BuildLookupSnapshot(ProjectAssetLookupSnapshot& outSnapshot) const { + m_impl->assetImportService.BuildLookupSnapshot(outSnapshot); +} + +} // namespace Resources +} // namespace XCEngine diff --git a/Pipeline/Core/ProjectAssetService/ProjectAssetService.h b/Pipeline/Core/ProjectAssetService/ProjectAssetService.h new file mode 100644 index 00000000..4e28e947 --- /dev/null +++ b/Pipeline/Core/ProjectAssetService/ProjectAssetService.h @@ -0,0 +1,51 @@ +#pragma once + +#include + +#include + +namespace XCEngine { +namespace Resources { + +class ProjectAssetService final : public IProjectAssetPipelineService { +public: + ProjectAssetService(); + ~ProjectAssetService() override; + + void Initialize() override; + void Shutdown() override; + + void SetProjectRoot(const Containers::String& projectRoot) override; + Containers::String GetProjectRoot() const override; + Containers::String GetLibraryRoot() const override; + + bool BootstrapProject() override; + void Refresh() override; + bool ClearLibraryCache() override; + bool RebuildLibraryCache() override; + bool ReimportAllAssets() override; + bool ReimportAsset(const Containers::String& requestPath, + ProjectAssetImportedAsset& outAsset) override; + ProjectAssetImportStatusSnapshot GetLastImportStatus() const override; + + bool TryGetImportableResourceType(const Containers::String& requestPath, + ResourceType& outType) const override; + bool EnsureArtifact(const Containers::String& requestPath, + ResourceType requestedType, + ProjectAssetImportedAsset& outAsset) override; + bool TryGetAssetRef(const Containers::String& requestPath, + ResourceType resourceType, + AssetRef& outRef) const override; + bool TryGetPrimaryAssetPath(const AssetGUID& guid, + Containers::String& outRelativePath) const override; + bool TryResolveAssetPath(const AssetRef& assetRef, + Containers::String& outPath) const override; + void BuildLookupSnapshot(ProjectAssetLookupSnapshot& outSnapshot) const override; + +private: + struct Impl; + std::unique_ptr m_impl; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Core/Asset/ProjectAssetIndex.cpp b/Pipeline/Core/SourceIndex/ProjectAssetIndex.cpp similarity index 82% rename from engine/src/Core/Asset/ProjectAssetIndex.cpp rename to Pipeline/Core/SourceIndex/ProjectAssetIndex.cpp index f40db15e..3bdd3072 100644 --- a/engine/src/Core/Asset/ProjectAssetIndex.cpp +++ b/Pipeline/Core/SourceIndex/ProjectAssetIndex.cpp @@ -1,6 +1,4 @@ -#include - -#include +#include "ProjectAssetIndex.h" #include #include @@ -75,11 +73,11 @@ void ProjectAssetIndex::ResetProjectRoot(const Containers::String& projectRoot) m_assetPathByGuid.clear(); } -void ProjectAssetIndex::RefreshFrom(const AssetImportService& importService) { - AssetImportService::LookupSnapshot snapshot; - const Containers::String projectRoot = importService.GetProjectRoot(); +void ProjectAssetIndex::RefreshFrom(const IProjectAssetResolver& resolver) { + ProjectAssetLookupSnapshot snapshot; + const Containers::String projectRoot = resolver.GetProjectRoot(); if (!projectRoot.Empty()) { - importService.BuildLookupSnapshot(snapshot); + resolver.BuildLookupSnapshot(snapshot); } std::unique_lock lock(m_mutex); @@ -88,7 +86,7 @@ void ProjectAssetIndex::RefreshFrom(const AssetImportService& importService) { m_assetPathByGuid = std::move(snapshot.assetPathByGuid); } -bool ProjectAssetIndex::TryGetAssetRef(AssetImportService& importService, +bool ProjectAssetIndex::TryGetAssetRef(IProjectAssetPipelineService& pipelineService, const Containers::String& path, ResourceType resourceType, AssetRef& outRef) const { @@ -108,21 +106,21 @@ bool ProjectAssetIndex::TryGetAssetRef(AssetImportService& importService, } if (!resolved) { - resolved = importService.TryGetAssetRef(path, resourceType, outRef); + resolved = pipelineService.TryGetAssetRef(path, resourceType, outRef); if (!resolved) { - const Containers::String projectRoot = importService.GetProjectRoot(); + const Containers::String projectRoot = pipelineService.GetProjectRoot(); const Containers::String relativePath = MakeAssetLookupRelativePath(projectRoot, path); if (!relativePath.Empty() && !projectRoot.Empty()) { auto* index = const_cast(this); - importService.Refresh(); - index->RefreshFrom(importService); - resolved = importService.TryGetAssetRef(path, resourceType, outRef); + pipelineService.Refresh(); + index->RefreshFrom(pipelineService); + resolved = pipelineService.TryGetAssetRef(path, resourceType, outRef); } } if (resolved) { Containers::String relativePath; - if (importService.TryGetPrimaryAssetPath(outRef.assetGuid, relativePath)) { + if (pipelineService.TryGetPrimaryAssetPath(outRef.assetGuid, relativePath)) { const_cast(this)->RememberResolvedPath(outRef.assetGuid, relativePath); } } @@ -131,7 +129,7 @@ bool ProjectAssetIndex::TryGetAssetRef(AssetImportService& importService, return resolved; } -bool ProjectAssetIndex::TryResolveAssetPath(AssetImportService& importService, +bool ProjectAssetIndex::TryResolveAssetPath(const IProjectAssetResolver& resolver, const AssetRef& assetRef, Containers::String& outPath) const { if (!assetRef.IsValid()) { @@ -139,7 +137,7 @@ bool ProjectAssetIndex::TryResolveAssetPath(AssetImportService& importService, } if (assetRef.localID != kMainAssetLocalID) { - return importService.TryResolveAssetPath(assetRef, outPath); + return resolver.TryResolveAssetPath(assetRef, outPath); } bool resolved = false; @@ -153,7 +151,7 @@ bool ProjectAssetIndex::TryResolveAssetPath(AssetImportService& importService, } if (!resolved) { - resolved = importService.TryResolveAssetPath(assetRef, outPath); + resolved = resolver.TryResolveAssetPath(assetRef, outPath); if (resolved) { const_cast(this)->RememberResolvedPath(assetRef.assetGuid, outPath); } diff --git a/Pipeline/Core/SourceIndex/ProjectAssetIndex.h b/Pipeline/Core/SourceIndex/ProjectAssetIndex.h new file mode 100644 index 00000000..7ad44b1f --- /dev/null +++ b/Pipeline/Core/SourceIndex/ProjectAssetIndex.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include +#include + +namespace XCEngine { +namespace Resources { + +class ProjectAssetIndex { +public: + void ResetProjectRoot(const Containers::String& projectRoot = Containers::String()); + void RefreshFrom(const IProjectAssetResolver& resolver); + + bool TryGetAssetRef(IProjectAssetPipelineService& pipelineService, + const Containers::String& path, + ResourceType resourceType, + AssetRef& outRef) const; + bool TryResolveAssetPath(const IProjectAssetResolver& resolver, + const AssetRef& assetRef, + Containers::String& outPath) const; + void RememberResolvedPath(const AssetGUID& assetGuid, const Containers::String& relativePath); + +private: + mutable std::shared_mutex m_mutex; + Containers::String m_projectRoot; + std::unordered_map m_assetGuidByPathKey; + std::unordered_map m_assetPathByGuid; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/docs/plan/runtime-rendering-framedata-structure-subplan.md b/docs/plan/runtime-rendering-framedata-structure-subplan.md new file mode 100644 index 00000000..789d5afd --- /dev/null +++ b/docs/plan/runtime-rendering-framedata-structure-subplan.md @@ -0,0 +1,107 @@ +# XCEngine 子计划:Runtime Rendering FrameData 第一刀 + +## 1. 为什么现在切这个 + +截至 `2026-05-01`: + +- `Runtime/Asset` +- `Runtime/Resources` +- `Runtime/Scene` +- `Runtime/Rendering/Caches` +- `Runtime/Rendering/Shadow` +- `Runtime/Rendering/Materials` +- `Runtime/Rendering/Picking` + +`Picking` 已完成后,下一步优先选择 `Runtime/Rendering/FrameData`,原因是: + +- `FrameData` 主要由稳定数据头和少量 header-only 工具组成 +- 依赖虽然广,但大多是只读消费,不牵涉主流程重构 +- 可以继续按低风险方式把 rendering 运行时数据契约落到真实树 +- 能为后续 `Extraction` 收口提前建立稳定内部路径 + +## 2. 本子计划切什么 + +这一轮聚焦: + +- `RenderCameraData.h` +- `RenderEnvironmentData.h` +- `CullingResults.h` +- `VisibleRenderItem.h` +- `VisibleGaussianSplatItem.h` +- `VisibleVolumeItem.h` +- `RenderSceneData.h` +- `RendererListUtils.h` + +如果这些文件继续保持 header-only,就只迁真实头文件位置并收口 include。 + +这一轮明确不碰: + +- `RenderSceneExtractor.cpp` +- `RenderSceneUtility.cpp` +- `Builtin*Pass` 行为逻辑 +- `RenderGraph` +- `RenderPipeline` + +除非只是机械性的 include / CMake 路径调整。 + +## 3. 目标 + +这一刀至少达到: + +- frame data 真实定义迁到 `engine/Runtime/Rendering/FrameData/*` +- 旧 `engine/include/XCEngine/Rendering/FrameData/*` public 头收窄成兼容 forwarding 层 +- 内部实现侧 include 改用稳定内部路径 +- `XCEditor` 编译和 12 秒 editor smoke 继续稳定 + +## 4. 建议切法 + +### Step 1:先切基础数据头 + +优先处理: + +- `RenderCameraData.h` +- `RenderEnvironmentData.h` +- `CullingResults.h` + +原因: + +- 是更上层 `RenderSceneData` 的直接基础 +- 结构独立、风险最低 + +### Step 2:再切 visible item 与 scene data + +随后处理: + +- `VisibleRenderItem.h` +- `VisibleGaussianSplatItem.h` +- `VisibleVolumeItem.h` +- `RenderSceneData.h` + +原因: + +- 构成 render scene 抽取结果的主体数据契约 +- 对后续 `Extraction` 收口是前置条件 + +### Step 3:最后切 `RendererListUtils` + +统一收口: + +- `RendererListUtils.h` +- `engine/CMakeLists.txt` +- 旧 public 头 forwarding +- 内部真实路径 include +- 阶段验证 + +## 5. 验证要求 + +本阶段完成后继续保持: + +1. 编译 `XCEditor` +2. 执行 12 秒 `editor_ui_smoke_runner` + +## 6. 当前状态 + +截至 `2026-05-01`: + +- `Runtime/Rendering/Picking` 第一刀已完成 +- 下一刀从 `RenderCameraData` 开始 diff --git a/docs/plan/target-architecture.md b/docs/plan/target-architecture.md index ca04c0c3..ec064545 100644 --- a/docs/plan/target-architecture.md +++ b/docs/plan/target-architecture.md @@ -37,8 +37,8 @@ 代码库按执行阶段拆分为: - `engine/foundation`:基础设施层 -- `engine/shared`:跨阶段稳定契约层 -- `engine/runtime`:运行时系统 +- `engine/Shared`:跨阶段稳定契约层 +- `engine/Runtime`:运行时系统 - `pipeline`:导入、构建、烘焙系统 - `editor`:当前编辑器应用树 - `programs`:各类可执行入口 @@ -135,11 +135,11 @@ XCEngine/ passes/ pipelines/ frame_graph/ - gpu_cache/ + Caches/ audio/ physics/ scripting/ - pipeline/ + Pipeline/ core/ SourceAssetDB/ ArtifactDB/ @@ -187,7 +187,7 @@ XCEngine/ foundation/ shared/ runtime/ - pipeline/ + Pipeline/ editor/ e2e/ docs/ @@ -210,7 +210,7 @@ XCEngine/ - 序列化 - 文件系统封装 -### 5.2 `engine/shared` +### 5.2 `engine/Shared` 共享契约层承载跨阶段稳定数据结构: @@ -223,7 +223,7 @@ XCEngine/ 这一层只放数据契约,不放 manager、loader、cache、importer、orchestrator。 -### 5.3 `engine/runtime` +### 5.3 `engine/Runtime` 运行时层负责: @@ -282,13 +282,13 @@ editor 内部目录重组不属于第一阶段工作。 当前主要系统映射如下: -- `ResourceManager` -> `engine/runtime/asset/AssetManager` -- `ResourceCache` -> `engine/runtime/asset/ResourceStore` -- `AsyncLoader` -> `engine/runtime/asset/AsyncLoad` -- `ProjectAssetIndex` -> `pipeline/core/SourceIndex` -- `AssetImportService` -> `pipeline/core/ImportService` -- `AssetDatabase` -> `pipeline/core/SourceAssetDB` + `pipeline/core/ArtifactDB` -- `RenderResourceCache` -> `engine/runtime/rendering/gpu_cache` +- `ResourceManager` -> `engine/Runtime/Asset/AssetManager` +- `ResourceCache` -> `engine/Runtime/Asset/ResourceStore` +- `AsyncLoader` -> `engine/Runtime/Asset/AsyncLoad` +- `ProjectAssetIndex` -> `Pipeline/Core/SourceIndex` +- `AssetImportService` -> `Pipeline/Core/ImportService` +- `AssetDatabase` -> `Pipeline/Core/SourceAssetDB` + `Pipeline/Core/ArtifactDB` +- `RenderResourceCache` -> `engine/Runtime/Rendering/Caches` 重构过程中,editor 迭代路径先保持在现有项目工作流上,再逐步完成职责分拆。 @@ -375,7 +375,7 @@ xcshadercook 工作项: -- 把文件迁移到 `engine/foundation`、`engine/shared`、`engine/runtime`、`pipeline` +- 把文件迁移到 `engine/foundation`、`engine/Shared`、`engine/Runtime`、`pipeline` - 更新 include、CMake 和测试 - 除非前置拆分强依赖,否则不在这一阶段重组 editor 内部树 @@ -411,3 +411,29 @@ xcshadercook 4. shared 层只保留稳定数据契约。 5. phases 1 到 3 期间,editor 日常迭代路径保持连续可用。 6. 每个阶段完成后都要先编译 `XCEditor`,再执行 12 秒冒烟测试。 + +## 10. 当前推进状态 + +截至 `2026-05-01`: + +- `engine/Shared/Asset` 已承接 `ArtifactContainer`、`AssetGUID`、`ResourceTypes`、`ResourceDependencyGraph` 的真实定义与实现 +- `Pipeline/Core` 已承接 `AssetDatabase`、`AssetImportService`、`ProjectAssetIndex`、`ProjectAssetService` 与相关 contracts +- `engine/Runtime/Asset` 已承接 `ResourceManager`、`ResourceCache`、`AsyncLoader` +- `engine/Runtime/Resources` 已承接 `Texture`、`Mesh`、`AudioClip`、`Shader`、`Material` +- 对应旧 `engine/include/XCEngine/Core/Asset/*` 与 `engine/include/XCEngine/Resources/*` 的迁移对象已逐步收窄为兼容 forwarding 层 +- `engine/Runtime/Scene` 已承接 `Scene`、`SceneRuntime`、`SceneManager`、`RuntimeLoop`、`ModelSceneInstantiation` +- `Scene` 这一刀已完成 `XCEditor` 编译与 12 秒 editor smoke 验证 + +当前活跃子计划: + +- `Runtime/Rendering/FrameData` 第一刀 + +下一步优先项: + +- `Runtime/Rendering/Caches` 第一刀已完成,真实定义已迁到 `engine/Runtime/Rendering/Caches` +- `Runtime/Rendering/Shadow` 第一刀已完成,真实定义已迁到 `engine/Runtime/Rendering/Shadow` +- `Runtime/Rendering/Materials` 第一刀已完成,真实定义已迁到 `engine/Runtime/Rendering/Materials` +- `Runtime/Rendering/Picking` 第一刀已完成,真实定义已迁到 `engine/Runtime/Rendering/Picking` +- 继续收窄旧 `engine/include/XCEngine/Rendering/FrameData/*` public 头 +- 将 `RenderCameraData`、`RenderEnvironmentData`、`CullingResults`、`Visible*`、`RenderSceneData`、`RendererListUtils` 的真实定义迁到 `engine/Runtime/Rendering/FrameData` +- 在不重组渲染主流程的前提下,继续把低耦合 rendering 支撑块从旧 `include/src` 物理布局中抽离出来 diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 00517cf7..88e2ad0e 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.15) +cmake_minimum_required(VERSION 3.15) if(MSVC AND POLICY CMP0141) cmake_policy(SET CMP0141 NEW) @@ -101,20 +101,24 @@ endif() set(XCENGINE_RENDERING_EDITOR_SUPPORT_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Picking/ObjectIdCodec.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Picking/RenderObjectIdRegistry.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/Picking/ObjectIdCodec.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/Picking/RenderObjectIdRegistry.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinObjectIdPass.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Picking/RenderObjectIdRegistry.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/Picking/RenderObjectIdRegistry.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinObjectIdPass.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinObjectIdPassResources.cpp ) add_library(XCEngineCore INTERFACE) target_include_directories(XCEngineCore INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine ) add_library(XCEngineInput INTERFACE) target_include_directories(XCEngineInput INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine ) @@ -157,6 +161,7 @@ add_library(XCEngineUI STATIC ) target_include_directories(XCEngineUI PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine ) @@ -183,6 +188,151 @@ else() target_compile_options(XCEngineUI PRIVATE -Wall) endif() +set(XCENGINE_SHARED_ASSET_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/IResource.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/AssetGUID.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/AssetRef.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ArtifactFormats.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ArtifactContainer.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ProjectAssetTypes.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ResourceTypes.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ResourceDependencyGraph.h + ${CMAKE_CURRENT_SOURCE_DIR}/Shared/Asset/AssetGUID/AssetGUID.h + ${CMAKE_CURRENT_SOURCE_DIR}/Shared/Asset/AssetGUID/AssetGUID.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Shared/Asset/ArtifactContainer/ArtifactContainer.h + ${CMAKE_CURRENT_SOURCE_DIR}/Shared/Asset/ArtifactContainer/ArtifactContainer.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Shared/Asset/ResourceType/ResourceTypes.h + ${CMAKE_CURRENT_SOURCE_DIR}/Shared/Asset/ResourceType/ResourceTypes.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Shared/Asset/DependencyGraph/ResourceDependencyGraph.h + ${CMAKE_CURRENT_SOURCE_DIR}/Shared/Asset/DependencyGraph/ResourceDependencyGraph.cpp +) + +set(XCENGINE_PIPELINE_CORE_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/IProjectAssetResolver.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/IProjectAssetPipelineService.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/AssetDatabase.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/AssetImportService.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ProjectAssetIndex.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ProjectAssetService.h + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/Contracts/ProjectAssetTypes.h + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/Contracts/IProjectAssetResolver.h + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/Contracts/IProjectAssetPipelineService.h + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/AssetDatabase/Facade/AssetDatabase.h + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/ImportService/AssetImportService.h + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/ProjectAssetService/ProjectAssetService.h + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/SourceIndex/ProjectAssetIndex.h + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/AssetDatabase/Facade/AssetDatabase.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/AssetDatabase/Import/AssetDatabaseImport.h + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/AssetDatabase/Import/AssetDatabaseImport.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/AssetDatabase/Maintenance/AssetDatabaseMaintenance.h + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/AssetDatabase/Maintenance/AssetDatabaseMaintenance.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/AssetDatabase/Shared/AssetDatabaseShared.h + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/AssetDatabase/Shared/AssetDatabaseShared.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/AssetDatabase/Stores/AssetDatabaseStores.h + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/AssetDatabase/Stores/AssetDatabaseStores.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/ImportService/AssetImportService.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/ProjectAssetService/ProjectAssetService.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/../Pipeline/Core/SourceIndex/ProjectAssetIndex.cpp +) + +set(XCENGINE_RUNTIME_ASSET_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ImportSettings.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ResourceHandle.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ResourceManager.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ResourceCache.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/AsyncLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Asset/AssetManager/ResourceManager.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Asset/AssetManager/ResourceManager.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Asset/ResourceStore/ResourceCache.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Asset/ResourceStore/ResourceCache.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Asset/AsyncLoad/AsyncLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Asset/AsyncLoad/AsyncLoader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Core/IO/IResourceLoader.cpp +) + +function(xcengine_configure_internal_asset_target target_name) + target_include_directories(${target_name} PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine + ${CMAKE_CURRENT_SOURCE_DIR}/third_party + ${CMAKE_CURRENT_SOURCE_DIR}/third_party/GLAD/include + ${CMAKE_CURRENT_SOURCE_DIR}/third_party/stb + ${CMAKE_CURRENT_SOURCE_DIR}/third_party/assimp/include + ) + + target_include_directories(${target_name} PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR}/.. + ) + + if(XCENGINE_HAS_NANOVDB) + target_include_directories(${target_name} PRIVATE + ${XCENGINE_NANOVDB_INCLUDE_DIR} + ) + target_compile_definitions(${target_name} PRIVATE + XCENGINE_HAS_NANOVDB=1 + ) + endif() + + if(XCENGINE_ENABLE_PHYSX) + target_include_directories(${target_name} PRIVATE + ${XCENGINE_PHYSX_INCLUDE_DIR} + ) + target_compile_definitions(${target_name} PRIVATE + XCENGINE_ENABLE_PHYSX=1 + ) + else() + target_compile_definitions(${target_name} PRIVATE + XCENGINE_ENABLE_PHYSX=0 + ) + endif() + + target_compile_definitions(${target_name} PRIVATE + XCENGINE_SUPPORT_OPENGL + XCENGINE_SUPPORT_VULKAN + ) + + if(MSVC) + target_compile_options(${target_name} PRIVATE + /FS + /W3 + $<$:/Z7>) + set_target_properties(${target_name} PROPERTIES + MSVC_DEBUG_INFORMATION_FORMAT "$<$:Embedded>" + COMPILE_PDB_NAME "${target_name}-compile" + COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb" + COMPILE_PDB_OUTPUT_DIRECTORY_DEBUG "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb/Debug" + COMPILE_PDB_OUTPUT_DIRECTORY_RELEASE "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb/Release" + COMPILE_PDB_OUTPUT_DIRECTORY_MINSIZEREL "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb/MinSizeRel" + COMPILE_PDB_OUTPUT_DIRECTORY_RELWITHDEBINFO "${CMAKE_CURRENT_BINARY_DIR}/compile-pdb/RelWithDebInfo" + ) + else() + target_compile_options(${target_name} PRIVATE -Wall) + endif() +endfunction() + +add_library(xc_shared_asset STATIC + ${XCENGINE_SHARED_ASSET_SOURCES} +) +xcengine_configure_internal_asset_target(xc_shared_asset) + +add_library(xc_pipeline_core STATIC + ${XCENGINE_PIPELINE_CORE_SOURCES} +) +xcengine_configure_internal_asset_target(xc_pipeline_core) +target_link_libraries(xc_pipeline_core PUBLIC + xc_shared_asset +) + +add_library(xc_runtime_asset STATIC + ${XCENGINE_RUNTIME_ASSET_SOURCES} +) +xcengine_configure_internal_asset_target(xc_runtime_asset) +target_link_libraries(xc_runtime_asset PUBLIC + xc_shared_asset +) + add_library(XCEngine STATIC # Core (Types, RefCounted, SmartPtr, Event) ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Types.h @@ -414,40 +564,12 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/RHIFactory.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/RHI/RHIScreenshot.cpp - # Core/Asset (Resource System Core) - ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/IResource.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/AssetGUID.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/AssetRef.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ArtifactFormats.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ArtifactContainer.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/AssetDatabase.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/AssetImportService.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ProjectAssetIndex.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ResourceTypes.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ImportSettings.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ResourceHandle.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ResourceManager.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ResourceCache.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/AsyncLoader.h - ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/Asset/ResourceDependencyGraph.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/Core/Asset/AssetGUID.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Core/Asset/ArtifactContainer.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Core/Asset/AssetDatabase.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Core/Asset/AssetImportService.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Core/Asset/ProjectAssetIndex.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Core/Asset/ResourceManager.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Core/Asset/ResourceCache.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Core/Asset/AsyncLoader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Core/Asset/ResourceTypes.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Core/Asset/ResourceDependencyGraph.cpp - # Core/IO (File System Abstraction) ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/IO/IResourceLoader.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/IO/ResourcePath.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/IO/ResourceFileSystem.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/IO/FileArchive.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Core/IO/ResourcePackage.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/Core/IO/IResourceLoader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Core/IO/ResourcePath.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Core/IO/ResourceFileSystem.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Core/IO/FileArchive.cpp @@ -458,6 +580,9 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Texture/Texture.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Texture/TextureLoader.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Texture/TextureImportSettings.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Texture/Texture.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Texture/TextureLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Texture/TextureImportSettings.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/BuiltinResources.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Model/AssimpModelImporter.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Model/Model.h @@ -469,22 +594,43 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Mesh/Mesh.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Mesh/MeshLoader.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Mesh/MeshImportSettings.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Mesh/Mesh.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Mesh/MeshLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Mesh/MeshImportSettings.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Material/Material.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Material/MaterialLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Material/MaterialRenderState.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Material/Material.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Material/MaterialLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Material/MaterialRenderState.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Shader/Shader.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Shader/ShaderCompilationCache.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Shader/ShaderKeywordTypes.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Shader/ShaderLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/Shader.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/ShaderCompilationCache.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/ShaderLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/ShaderIR.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/ShaderSourceUtils.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/ShaderAuthoringParser.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/Internal/ShaderFileUtils.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/Internal/ShaderRuntimeBuildUtils.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/Internal/ShaderAuthoringLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/Internal/ShaderArtifactLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/Internal/ShaderAuthoringInternal.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Volume/VolumeField.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/Volume/VolumeFieldLoader.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/AudioClip/AudioClip.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/AudioClip/AudioLoader.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/AudioClip/AudioClip.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/AudioClip/AudioLoader.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/UI/UIDocumentTypes.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/UI/UIDocumentCompiler.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/UI/UIDocuments.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Resources/UI/UIDocumentLoaders.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Texture/Texture.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Texture/TextureLoader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Texture/TextureImportSettings.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Texture/Texture.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Texture/TextureLoader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Texture/TextureImportSettings.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/BuiltinResources.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Model/AssimpModelImporter.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Model/Model.cpp @@ -494,36 +640,28 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/GaussianSplat/GaussianSplatArtifactIO.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/GaussianSplat/GaussianSplatLoader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/GaussianSplat/Internal/GaussianSplatPlyImporter.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Mesh/Mesh.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Mesh/MeshLoader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Mesh/MeshImportSettings.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Material/Material.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Material/MaterialLoader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Shader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/ShaderCompilationCache.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/ShaderLoader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/ShaderIR.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderFileUtils.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderFileUtils.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderRuntimeBuildUtils.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderRuntimeBuildUtils.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderAuthoringLoader.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderAuthoringLoader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderArtifactLoader.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderArtifactLoader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderAuthoringInternal.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderAuthoringTextUtils.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderAuthoringDirectiveUtils.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderAuthoringShared.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/Internal/ShaderAuthoringParserCore.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/ShaderSourceUtils.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/ShaderSourceUtils.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/ShaderAuthoringParser.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Shader/ShaderAuthoringParser.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Mesh/Mesh.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Mesh/MeshLoader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Mesh/MeshImportSettings.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Material/Material.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Material/MaterialLoader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/Shader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/ShaderCompilationCache.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/ShaderLoader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/Internal/ShaderFileUtils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/Internal/ShaderRuntimeBuildUtils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/Internal/ShaderAuthoringLoader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/Internal/ShaderArtifactLoader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/Internal/ShaderAuthoringTextUtils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/Internal/ShaderAuthoringDirectiveUtils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/Internal/ShaderAuthoringShared.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/Internal/ShaderAuthoringParserCore.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/ShaderSourceUtils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/Shader/ShaderAuthoringParser.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Volume/VolumeField.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/Volume/VolumeFieldLoader.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/AudioClip/AudioClip.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/AudioClip/AudioLoader.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/AudioClip/AudioClip.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Resources/AudioClip/AudioLoader.cpp ${XCENGINE_OPTIONAL_UI_RESOURCE_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/UI/UIDocuments.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Resources/UI/UIDocumentLoaders.cpp @@ -595,11 +733,20 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/SceneRenderer.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/CullingResults.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/RenderCameraData.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/RenderEnvironmentData.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/RenderSceneData.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/RendererListUtils.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/VisibleGaussianSplatItem.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/VisibleRenderItem.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/FrameData/VisibleVolumeItem.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/FrameData/CullingResults.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/FrameData/RenderCameraData.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/FrameData/RenderEnvironmentData.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/FrameData/RenderSceneData.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/FrameData/RendererListUtils.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/FrameData/VisibleGaussianSplatItem.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/FrameData/VisibleRenderItem.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/FrameData/VisibleVolumeItem.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Planning/CameraRenderRequest.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Planning/FinalColorPassFactory.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Planning/FinalColorSettings.h @@ -607,6 +754,8 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Planning/SceneRenderRequestUtils.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Picking/ObjectIdCodec.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Picking/RenderObjectIdRegistry.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/Picking/ObjectIdCodec.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/Picking/RenderObjectIdRegistry.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Extraction/RenderSceneExtractor.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Extraction/RenderSceneUtility.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Graph/RenderGraphTypes.h @@ -619,6 +768,8 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Graph/RenderGraphExecutor.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Materials/RenderMaterialResolve.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Materials/RenderMaterialStateUtils.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/Materials/RenderMaterialResolve.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/Materials/RenderMaterialStateUtils.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/RenderPass.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/RenderPassGraphContract.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/RenderPipeline.h @@ -633,8 +784,12 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/SceneRenderSequence.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Caches/RenderResourceCache.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Caches/DirectionalShadowSurfaceCache.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/Caches/RenderResourceCache.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/Caches/DirectionalShadowSurfaceCache.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Shadow/DirectionalShadowData.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Shadow/DirectionalShadowRuntime.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/Shadow/DirectionalShadowData.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/Shadow/DirectionalShadowRuntime.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinDepthStylePassBase.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinDepthOnlyPass.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Passes/BuiltinShadowCasterPass.h @@ -676,7 +831,7 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameGraph/SurfaceUtils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Internal/RenderPipelineFactory.h ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Internal/RenderPipelineFactory.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Caches/DirectionalShadowSurfaceCache.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/Caches/DirectionalShadowSurfaceCache.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/RenderPassGraphContract.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/RenderPipelineStageGraphContract.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinDepthStylePassBase.cpp @@ -699,7 +854,7 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Graph/RenderGraph.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Graph/RenderGraphCompiler.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Graph/RenderGraphExecutor.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Caches/RenderResourceCache.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/Caches/RenderResourceCache.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Planning/CameraFramePlanBuilder.h ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Planning/CameraFramePlanBuilder.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Planning/SceneRenderRequestPlanner.cpp @@ -707,8 +862,8 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Planning/Internal/CameraFrameFullscreenStagePlanner.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Planning/Internal/DirectionalShadowPlanning.h ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Planning/Internal/DirectionalShadowPlanning.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Shadow/DirectionalShadowData.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Shadow/DirectionalShadowRuntime.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/Shadow/DirectionalShadowData.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Rendering/Shadow/DirectionalShadowRuntime.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/SceneRenderer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Pipelines/BuiltinForwardPipeline.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Pipelines/NativeSceneRecorder.cpp @@ -728,11 +883,16 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Scene/SceneRuntime.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Scene/RuntimeLoop.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Scene/SceneManager.h - ${CMAKE_CURRENT_SOURCE_DIR}/src/Scene/Scene.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Scene/ModelSceneInstantiation.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Scene/SceneRuntime.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Scene/RuntimeLoop.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Scene/SceneManager.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Scene/Scene.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Scene/ModelSceneInstantiation.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Scene/SceneRuntime.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Scene/RuntimeLoop.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Scene/SceneManager.h + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Scene/Scene.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Scene/ModelSceneInstantiation.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Scene/SceneRuntime.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Scene/RuntimeLoop.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Runtime/Scene/SceneManager.cpp # Platform ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Platform/PlatformTypes.h @@ -836,6 +996,7 @@ add_library(XCEngine STATIC ) target_include_directories(XCEngine PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine ${CMAKE_CURRENT_SOURCE_DIR}/third_party @@ -846,6 +1007,7 @@ target_include_directories(XCEngine PUBLIC target_include_directories(XCEngine PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR}/.. ) if(XCENGINE_HAS_NANOVDB) @@ -866,6 +1028,9 @@ endif() target_link_libraries(XCEngine PUBLIC XCEngineUI + xc_shared_asset + xc_pipeline_core + xc_runtime_asset ${CMAKE_CURRENT_SOURCE_DIR}/third_party/assimp/lib/assimp-vc143-mt.lib opengl32 Vulkan::Vulkan @@ -971,6 +1136,7 @@ if(XCENGINE_ENABLE_RENDERING_EDITOR_SUPPORT) ) target_include_directories(XCEngineRenderingEditorSupport PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/include ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine ${CMAKE_CURRENT_SOURCE_DIR}/src diff --git a/engine/src/Core/Asset/ResourceManager.cpp b/engine/Runtime/Asset/AssetManager/ResourceManager.cpp similarity index 84% rename from engine/src/Core/Asset/ResourceManager.cpp rename to engine/Runtime/Asset/AssetManager/ResourceManager.cpp index 225fe16a..8804d9d0 100644 --- a/engine/src/Core/Asset/ResourceManager.cpp +++ b/engine/Runtime/Asset/AssetManager/ResourceManager.cpp @@ -1,15 +1,16 @@ -#include +#include "ResourceManager.h" +#include "Pipeline/Core/ProjectAssetService/ProjectAssetService.h" #include -#include +#include "engine/Shared/Asset/ResourceType/ResourceTypes.h" #include #include -#include +#include "engine/Runtime/Resources/AudioClip/AudioLoader.h" #include -#include +#include "engine/Runtime/Resources/Material/MaterialLoader.h" #include -#include -#include -#include +#include "engine/Runtime/Resources/Mesh/MeshLoader.h" +#include "engine/Runtime/Resources/Shader/ShaderLoader.h" +#include "engine/Runtime/Resources/Texture/TextureLoader.h" #include #include #include @@ -81,6 +82,20 @@ void ResourceManager::Initialize() { EnsureInitialized(); } +void ResourceManager::SetProjectAssetPipelineService( + IProjectAssetPipelineService* projectAssetPipelineService) { + if (m_ownedProjectAssetPipelineService) { + m_ownedProjectAssetPipelineService->Shutdown(); + m_ownedProjectAssetPipelineService.reset(); + } + + m_projectAssetPipelineService = projectAssetPipelineService; + m_projectAssetResolver = projectAssetPipelineService; + if (m_projectAssetPipelineService != nullptr) { + m_projectAssetPipelineService->SetProjectRoot(m_resourceRoot); + } +} + void ResourceManager::EnsureInitialized() { if (m_asyncLoader) { return; @@ -105,7 +120,7 @@ void ResourceManager::EnsureInitialized() { RegisterBuiltinLoader(*this, g_uiThemeLoader); RegisterBuiltinLoader(*this, g_uiSchemaLoader); RegisterBuiltinLoader(*this, g_volumeFieldLoader); - m_assetImportService.Initialize(); + EnsureProjectAssetPipelineService(); m_asyncLoader = std::move(asyncLoader); } @@ -117,9 +132,14 @@ void ResourceManager::Shutdown() { m_asyncLoader.reset(); } - m_assetImportService.Shutdown(); + if (m_ownedProjectAssetPipelineService) { + m_ownedProjectAssetPipelineService->Shutdown(); + m_ownedProjectAssetPipelineService.reset(); + } + m_projectAssetPipelineService = nullptr; + m_projectAssetResolver = nullptr; ResourceFileSystem::Get().Shutdown(); - m_projectAssetIndex.ResetProjectRoot(); + m_resourceRoot.Clear(); std::lock_guard inFlightLock(m_inFlightLoadsMutex); m_inFlightLoads.clear(); @@ -127,15 +147,18 @@ void ResourceManager::Shutdown() { void ResourceManager::SetResourceRoot(const Containers::String& rootPath) { EnsureInitialized(); + IProjectAssetPipelineService& projectAssetPipelineService = + EnsureProjectAssetPipelineService(); m_resourceRoot = rootPath; if (!m_resourceRoot.Empty()) { ResourceFileSystem::Get().Initialize(rootPath); - m_assetImportService.SetProjectRoot(rootPath); - BootstrapProjectAssets(); + projectAssetPipelineService.SetProjectRoot(rootPath); + if (m_ownedProjectAssetPipelineService) { + projectAssetPipelineService.BootstrapProject(); + } } else { - m_assetImportService.SetProjectRoot(Containers::String()); + projectAssetPipelineService.SetProjectRoot(Containers::String()); ResourceFileSystem::Get().Shutdown(); - m_projectAssetIndex.ResetProjectRoot(); } } @@ -143,16 +166,6 @@ const Containers::String& ResourceManager::GetResourceRoot() const { return m_resourceRoot; } -bool ResourceManager::BootstrapProjectAssets() { - if (m_resourceRoot.Empty()) { - return false; - } - - const bool bootstrapped = m_assetImportService.BootstrapProject(); - m_projectAssetIndex.RefreshFrom(m_assetImportService); - return bootstrapped; -} - void ResourceManager::AddRef(ResourceGUID guid) { std::lock_guard lock(m_mutex); @@ -415,71 +428,11 @@ void ResourceManager::UnloadGroup(const Containers::Array& guids) } } -void ResourceManager::RefreshProjectAssets() { - if (!m_resourceRoot.Empty()) { - m_assetImportService.Refresh(); - m_projectAssetIndex.RefreshFrom(m_assetImportService); - } -} - -bool ResourceManager::CanReimportProjectAsset(const Containers::String& path) const { - if (m_resourceRoot.Empty() || path.Empty()) { - return false; - } - - ResourceType importType = ResourceType::Unknown; - return m_assetImportService.TryGetImportableResourceType(path, importType); -} - -bool ResourceManager::ReimportProjectAsset(const Containers::String& path) { - if (m_resourceRoot.Empty() || path.Empty()) { - return false; - } - - UnloadAll(); - - AssetImportService::ImportedAsset importedAsset; - const bool reimported = m_assetImportService.ReimportAsset(path, importedAsset); - m_projectAssetIndex.RefreshFrom(m_assetImportService); - if (reimported && importedAsset.assetGuid.IsValid() && !importedAsset.relativePath.Empty()) { - m_projectAssetIndex.RememberResolvedPath(importedAsset.assetGuid, importedAsset.relativePath); - } - - return reimported; -} - -bool ResourceManager::ClearProjectLibraryCache() { - if (m_resourceRoot.Empty()) { - return false; - } - - UnloadAll(); - const bool cleared = m_assetImportService.ClearLibraryCache(); - m_projectAssetIndex.RefreshFrom(m_assetImportService); - return cleared; -} - -bool ResourceManager::RebuildProjectAssetCache() { - if (m_resourceRoot.Empty()) { - return false; - } - - UnloadAll(); - const bool rebuilt = m_assetImportService.RebuildLibraryCache(); - m_projectAssetIndex.RefreshFrom(m_assetImportService); - return rebuilt; -} - -Containers::String ResourceManager::GetProjectLibraryRoot() const { - return m_assetImportService.GetLibraryRoot(); -} - -AssetImportService::ImportStatusSnapshot ResourceManager::GetProjectAssetImportStatus() const { - return m_assetImportService.GetLastImportStatus(); -} - bool ResourceManager::TryGetAssetRef(const Containers::String& path, ResourceType resourceType, AssetRef& outRef) const { - const bool resolved = m_projectAssetIndex.TryGetAssetRef(m_assetImportService, path, resourceType, outRef); + const IProjectAssetResolver* projectAssetResolver = m_projectAssetResolver; + const bool resolved = + projectAssetResolver != nullptr && + projectAssetResolver->TryGetAssetRef(path, resourceType, outRef); if (ShouldTraceResourcePath(path)) { Debug::Logger::Get().Info( @@ -497,7 +450,10 @@ bool ResourceManager::TryGetAssetRef(const Containers::String& path, ResourceTyp } bool ResourceManager::TryResolveAssetPath(const AssetRef& assetRef, Containers::String& outPath) const { - const bool resolved = m_projectAssetIndex.TryResolveAssetPath(m_assetImportService, assetRef, outPath); + const IProjectAssetResolver* projectAssetResolver = m_projectAssetResolver; + const bool resolved = + projectAssetResolver != nullptr && + projectAssetResolver->TryResolveAssetPath(assetRef, outPath); if (resolved && ShouldTraceResourcePath(outPath)) { Debug::Logger::Get().Info( @@ -527,6 +483,18 @@ bool ResourceManager::IsDeferredSceneLoadEnabled() const { return m_deferredSceneLoadDepth.load() > 0; } +IProjectAssetPipelineService& ResourceManager::EnsureProjectAssetPipelineService() const { + if (m_projectAssetPipelineService == nullptr) { + auto projectAssetPipelineService = Core::MakeUnique(); + projectAssetPipelineService->Initialize(); + m_projectAssetPipelineService = projectAssetPipelineService.get(); + m_projectAssetResolver = projectAssetPipelineService.get(); + m_ownedProjectAssetPipelineService = std::move(projectAssetPipelineService); + } + + return *m_projectAssetPipelineService; +} + LoadResult ResourceManager::LoadResource(const Containers::String& path, ResourceType type, ImportSettings* settings) { @@ -553,17 +521,18 @@ LoadResult ResourceManager::LoadResource(const Containers::String& path, Containers::String loadPath = path; Containers::String cachePath = path; - AssetImportService::ImportedAsset resolvedAsset; + ProjectAssetImportedAsset resolvedAsset; ResourceType importableType = ResourceType::Unknown; + IProjectAssetResolver* projectAssetResolver = m_projectAssetResolver; const bool shouldUseProjectArtifact = !m_resourceRoot.Empty() && - m_assetImportService.TryGetImportableResourceType(path, importableType) && + projectAssetResolver != nullptr && + projectAssetResolver->TryGetImportableResourceType(path, importableType) && importableType == type; if (shouldUseProjectArtifact && - m_assetImportService.EnsureArtifact(path, type, resolvedAsset) && + projectAssetResolver->EnsureArtifact(path, type, resolvedAsset) && resolvedAsset.artifactReady) { - m_projectAssetIndex.RememberResolvedPath(resolvedAsset.assetGuid, resolvedAsset.relativePath); loadPath = resolvedAsset.runtimeLoadPath; cachePath = loadPath; if (ShouldTraceResourcePath(path)) { @@ -578,13 +547,14 @@ LoadResult ResourceManager::LoadResource(const Containers::String& path, Containers::String builtinShaderAssetPath; if (TryResolveBuiltinShaderAssetPath(path, builtinShaderAssetPath)) { ResourceType builtinImportableType = ResourceType::Unknown; - AssetImportService::ImportedAsset builtinResolvedAsset; + ProjectAssetImportedAsset builtinResolvedAsset; if (!m_resourceRoot.Empty() && - m_assetImportService.TryGetImportableResourceType( + projectAssetResolver != nullptr && + projectAssetResolver->TryGetImportableResourceType( builtinShaderAssetPath, builtinImportableType) && builtinImportableType == type && - m_assetImportService.EnsureArtifact( + projectAssetResolver->EnsureArtifact( builtinShaderAssetPath, type, builtinResolvedAsset) && diff --git a/engine/Runtime/Asset/AssetManager/ResourceManager.h b/engine/Runtime/Asset/AssetManager/ResourceManager.h new file mode 100644 index 00000000..b3f496b0 --- /dev/null +++ b/engine/Runtime/Asset/AssetManager/ResourceManager.h @@ -0,0 +1,185 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace XCEngine { +namespace Resources { + +class ResourceManager { +public: + class ScopedDeferredSceneLoad { + public: + explicit ScopedDeferredSceneLoad(ResourceManager& manager = ResourceManager::Get()); + ScopedDeferredSceneLoad(const ScopedDeferredSceneLoad&) = delete; + ScopedDeferredSceneLoad& operator=(const ScopedDeferredSceneLoad&) = delete; + ~ScopedDeferredSceneLoad(); + + private: + ResourceManager* m_manager = nullptr; + }; + + static ResourceManager& Get(); + + void Initialize(); + void Shutdown(); + void SetProjectAssetPipelineService(IProjectAssetPipelineService* projectAssetPipelineService); + + void SetResourceRoot(const Containers::String& rootPath); + const Containers::String& GetResourceRoot() const; + + template + ResourceHandle Load(const Containers::String& path, ImportSettings* settings = nullptr) { + static_assert(std::is_base_of_v, "T must derive from IResource"); + + LoadResult result = LoadResource(path, GetResourceType(), settings); + if (!result || result.resource == nullptr) { + return ResourceHandle(); + } + + return ResourceHandle(static_cast(result.resource)); + } + + template + ResourceHandle Load(const AssetRef& assetRef, ImportSettings* settings = nullptr) { + static_assert(std::is_base_of_v, "T must derive from IResource"); + + Containers::String path; + if (!TryResolveAssetPath(assetRef, path)) { + return ResourceHandle(); + } + + return Load(path, settings); + } + + void LoadAsync(const Containers::String& path, ResourceType type, + std::function callback); + void LoadAsync(const Containers::String& path, ResourceType type, ImportSettings* settings, + std::function callback); + void UpdateAsyncLoads(); + bool IsAsyncLoading() const; + Core::uint32 GetAsyncPendingCount() const; + + void Unload(const Containers::String& path); + void Unload(ResourceGUID guid); + void UnloadUnused(); + void UnloadAll(); + + void AddRef(ResourceGUID guid); + void Release(ResourceGUID guid); + Core::uint32 GetRefCount(ResourceGUID guid) const; + + void RegisterLoader(IResourceLoader* loader); + void UnregisterLoader(ResourceType type); + IResourceLoader* GetLoader(ResourceType type) const; + + void SetMemoryBudget(size_t bytes); + size_t GetMemoryUsage() const; + size_t GetMemoryBudget() const; + void FlushCache(); + + IResource* Find(const Containers::String& path); + IResource* Find(ResourceGUID guid); + bool Exists(const Containers::String& path) const; + bool Exists(ResourceGUID guid) const; + + Containers::String ResolvePath(const Containers::String& relativePath) const; + + template + void LoadGroup(const Containers::Array& paths, + std::function)> callback) { + for (const auto& path : paths) { + LoadAsync(path, GetResourceType(), [callback](LoadResult result) { + if (result && result.resource) { + callback(ResourceHandle(static_cast(result.resource))); + } else { + callback(ResourceHandle()); + } + }); + } + } + + Containers::Array GetResourcePaths() const; + void UnloadGroup(const Containers::Array& guids); + bool TryGetAssetRef(const Containers::String& path, ResourceType resourceType, AssetRef& outRef) const; + bool TryResolveAssetPath(const AssetRef& assetRef, Containers::String& outPath) const; + void BeginDeferredSceneLoad(); + void EndDeferredSceneLoad(); + bool IsDeferredSceneLoadEnabled() const; + +private: + struct InFlightLoadKey { + ResourceGUID guid; + ResourceType type = ResourceType::Unknown; + + bool operator==(const InFlightLoadKey& other) const { + return guid == other.guid && type == other.type; + } + }; + + struct InFlightLoadKeyHasher { + size_t operator()(const InFlightLoadKey& key) const noexcept { + return std::hash{}(key.guid) ^ + (static_cast(key.type) << 1); + } + }; + + struct InFlightLoadState { + bool completed = false; + bool success = false; + Containers::String errorMessage; + std::condition_variable condition; + }; + + ResourceManager() = default; + ~ResourceManager() = default; + + void EnsureInitialized(); + IResource* FindInCache(ResourceGUID guid); + void AddToCache(ResourceGUID guid, IResource* resource); + IResourceLoader* FindLoader(ResourceType type); + void ReloadResource(ResourceGUID guid); + LoadResult LoadResource(const Containers::String& path, ResourceType type, ImportSettings* settings); + IProjectAssetPipelineService& EnsureProjectAssetPipelineService() const; + + Containers::String m_resourceRoot; + Containers::HashMap m_resourceCache; + Containers::HashMap m_refCounts; + Containers::HashMap m_guidToPath; + Containers::HashMap m_loaders; + + size_t m_memoryUsage = 0; + size_t m_memoryBudget = 512 * 1024 * 1024; + + mutable Core::UniqueRef m_ownedProjectAssetPipelineService; + mutable IProjectAssetPipelineService* m_projectAssetPipelineService = nullptr; + mutable IProjectAssetResolver* m_projectAssetResolver = nullptr; + ResourceCache m_cache; + Core::UniqueRef m_asyncLoader; + Threading::Mutex m_mutex; + std::mutex m_initializeMutex; + std::mutex m_inFlightLoadsMutex; + std::unordered_map, InFlightLoadKeyHasher> m_inFlightLoads; + std::atomic m_deferredSceneLoadDepth{0}; + + friend class ResourceHandleBase; + friend class AsyncLoader; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Core/Asset/AsyncLoader.cpp b/engine/Runtime/Asset/AsyncLoad/AsyncLoader.cpp similarity index 98% rename from engine/src/Core/Asset/AsyncLoader.cpp rename to engine/Runtime/Asset/AsyncLoad/AsyncLoader.cpp index c818054c..cf3657f2 100644 --- a/engine/src/Core/Asset/AsyncLoader.cpp +++ b/engine/Runtime/Asset/AsyncLoad/AsyncLoader.cpp @@ -1,6 +1,6 @@ -#include -#include -#include +#include "AsyncLoader.h" +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" +#include "engine/Shared/Asset/ResourceType/ResourceTypes.h" #include namespace XCEngine { diff --git a/engine/Runtime/Asset/AsyncLoad/AsyncLoader.h b/engine/Runtime/Asset/AsyncLoad/AsyncLoader.h new file mode 100644 index 00000000..7a18583d --- /dev/null +++ b/engine/Runtime/Asset/AsyncLoad/AsyncLoader.h @@ -0,0 +1,108 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace XCEngine { +namespace Resources { + +struct LoadRequest { + Containers::String path; + ResourceType type; + std::function callback; + ImportSettings* settings; + Core::uint64 requestId; + + LoadRequest() : requestId(0), settings(nullptr) {} + + LoadRequest(const Containers::String& p, ResourceType t, + std::function cb, ImportSettings* s = nullptr) + : path(p), type(t), callback(std::move(cb)), + settings(s), requestId(GenerateRequestId()) {} + + LoadRequest(LoadRequest&& other) noexcept + : path(std::move(other.path)), type(other.type), + callback(std::move(other.callback)), settings(other.settings), + requestId(other.requestId) { + other.settings = nullptr; + } + + LoadRequest& operator=(LoadRequest&& other) noexcept { + if (this != &other) { + path = std::move(other.path); + type = other.type; + callback = std::move(other.callback); + settings = other.settings; + requestId = other.requestId; + other.settings = nullptr; + } + return *this; + } + + LoadRequest(const LoadRequest&) = default; + LoadRequest& operator=(const LoadRequest&) = default; + +private: + static Core::uint64 GenerateRequestId(); +}; + +struct CompletedLoadRequest { + LoadRequest request; + LoadResult result; + + CompletedLoadRequest(LoadRequest inRequest, LoadResult inResult) + : request(std::move(inRequest)), result(std::move(inResult)) {} +}; + +class AsyncLoader { +public: + static AsyncLoader& Get(); + + void Initialize(Core::uint32 workerThreadCount = 2); + void Shutdown(); + + void Submit(const Containers::String& path, ResourceType type, + std::function callback); + void Submit(const Containers::String& path, ResourceType type, ImportSettings* settings, + std::function callback); + + void Update(); + bool IsLoading() const { return m_pendingCount > 0; } + Core::uint32 GetPendingCount() const { return m_pendingCount; } + float GetProgress() const; + void CancelAll(); + void Cancel(Core::uint64 requestId); + + ~AsyncLoader() = default; + + AsyncLoader() = default; + +private: + void SubmitInternal(LoadRequest request); + IResourceLoader* FindLoader(ResourceType type) const; + void WorkerThread(); + void QueueCompleted(LoadRequest request, LoadResult result); + + std::mutex m_queueMutex; + std::condition_variable m_pendingCondition; + std::deque m_pendingQueue; + + std::mutex m_completedMutex; + std::deque m_completedQueue; + std::vector m_workerThreads; + + std::atomic m_running{false}; + std::atomic m_pendingCount{0}; + std::atomic m_completedCount{0}; + std::atomic m_totalRequested{0}; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Core/Asset/ResourceCache.cpp b/engine/Runtime/Asset/ResourceStore/ResourceCache.cpp similarity index 97% rename from engine/src/Core/Asset/ResourceCache.cpp rename to engine/Runtime/Asset/ResourceStore/ResourceCache.cpp index d39e11ad..56fbeee2 100644 --- a/engine/src/Core/Asset/ResourceCache.cpp +++ b/engine/Runtime/Asset/ResourceStore/ResourceCache.cpp @@ -1,5 +1,6 @@ -#include -#include +#include "ResourceCache.h" + +#include namespace XCEngine { namespace Resources { diff --git a/engine/Runtime/Asset/ResourceStore/ResourceCache.h b/engine/Runtime/Asset/ResourceStore/ResourceCache.h new file mode 100644 index 00000000..b13dd62c --- /dev/null +++ b/engine/Runtime/Asset/ResourceStore/ResourceCache.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace XCEngine { +namespace Resources { + +class IResource; + +struct CacheEntry { + IResource* resource; + ResourceGUID guid; + size_t memorySize; + Core::uint64 lastAccessTime; + Core::uint32 accessCount; + + CacheEntry() : resource(nullptr), memorySize(0), lastAccessTime(0), accessCount(0) {} + CacheEntry(IResource* res, size_t size); + + static Core::uint64 GetCurrentTick(); +}; + +class ResourceCache { +public: + ResourceCache(); + ~ResourceCache(); + + void Add(ResourceGUID guid, IResource* resource); + void Remove(ResourceGUID guid); + IResource* Find(ResourceGUID guid) const; + void Touch(ResourceGUID guid); + + size_t GetSize() const { return m_cache.Size(); } + size_t GetMemoryUsage() const { return m_memoryUsage; } + + void SetMemoryBudget(size_t bytes); + size_t GetMemoryBudget() const { return m_memoryBudget; } + + void OnMemoryPressure(size_t requiredBytes); + void OnZeroRefCount(ResourceGUID guid); + void Flush(); + void Clear(); + + Containers::Array GetLRUList(size_t count) const; + +private: + void Evict(size_t requiredBytes); + void UpdateMemoryStats(); + + Containers::HashMap m_cache; + Containers::Array m_lruOrder; + size_t m_memoryUsage = 0; + size_t m_memoryBudget = 512 * 1024 * 1024; + + Threading::Mutex m_mutex; + mutable Threading::Mutex m_cacheMutex; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Rendering/Caches/DirectionalShadowSurfaceCache.cpp b/engine/Runtime/Rendering/Caches/DirectionalShadowSurfaceCache.cpp similarity index 97% rename from engine/src/Rendering/Caches/DirectionalShadowSurfaceCache.cpp rename to engine/Runtime/Rendering/Caches/DirectionalShadowSurfaceCache.cpp index f5bb8815..4cce075f 100644 --- a/engine/src/Rendering/Caches/DirectionalShadowSurfaceCache.cpp +++ b/engine/Runtime/Rendering/Caches/DirectionalShadowSurfaceCache.cpp @@ -1,7 +1,7 @@ -#include "Rendering/Caches/DirectionalShadowSurfaceCache.h" +#include "DirectionalShadowSurfaceCache.h" #include "Rendering/RenderContext.h" -#include "Rendering/Shadow/DirectionalShadowData.h" +#include "engine/Runtime/Rendering/Shadow/DirectionalShadowData.h" #include "RHI/RHIDevice.h" #include "RHI/RHIResourceView.h" #include "RHI/RHITexture.h" diff --git a/engine/Runtime/Rendering/Caches/DirectionalShadowSurfaceCache.h b/engine/Runtime/Rendering/Caches/DirectionalShadowSurfaceCache.h new file mode 100644 index 00000000..46f4b1c8 --- /dev/null +++ b/engine/Runtime/Rendering/Caches/DirectionalShadowSurfaceCache.h @@ -0,0 +1,51 @@ +#pragma once + +#include + +namespace XCEngine { +namespace RHI { +class RHIDevice; +class RHIResourceView; +class RHITexture; +} // namespace RHI + +namespace Rendering { + +struct DirectionalShadowRenderPlan; +struct RenderContext; + +struct DirectionalShadowSurfaceAllocation { + RenderSurface surface = {}; + RHI::RHIResourceView* depthShaderView = nullptr; + + bool IsValid() const { + return surface.GetDepthAttachment() != nullptr && + depthShaderView != nullptr; + } +}; + +class DirectionalShadowSurfaceCache { +public: + DirectionalShadowSurfaceCache() = default; + DirectionalShadowSurfaceCache(const DirectionalShadowSurfaceCache&) = delete; + DirectionalShadowSurfaceCache& operator=(const DirectionalShadowSurfaceCache&) = delete; + ~DirectionalShadowSurfaceCache(); + + const DirectionalShadowSurfaceAllocation* Resolve( + const RenderContext& context, + const DirectionalShadowRenderPlan& plan); + +private: + bool Matches(const RenderContext& context, const DirectionalShadowRenderPlan& plan) const; + void Reset(); + + RHI::RHIDevice* m_device = nullptr; + uint32_t m_width = 0; + uint32_t m_height = 0; + RHI::RHITexture* m_depthTexture = nullptr; + RHI::RHIResourceView* m_depthView = nullptr; + DirectionalShadowSurfaceAllocation m_allocation = {}; +}; + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/src/Rendering/Caches/RenderResourceCache.cpp b/engine/Runtime/Rendering/Caches/RenderResourceCache.cpp similarity index 99% rename from engine/src/Rendering/Caches/RenderResourceCache.cpp rename to engine/Runtime/Rendering/Caches/RenderResourceCache.cpp index 8214d700..0a9e628b 100644 --- a/engine/src/Rendering/Caches/RenderResourceCache.cpp +++ b/engine/Runtime/Rendering/Caches/RenderResourceCache.cpp @@ -1,4 +1,4 @@ -#include "Rendering/Caches/RenderResourceCache.h" +#include "RenderResourceCache.h" #include "Debug/Logger.h" diff --git a/engine/Runtime/Rendering/Caches/RenderResourceCache.h b/engine/Runtime/Rendering/Caches/RenderResourceCache.h new file mode 100644 index 00000000..46541a94 --- /dev/null +++ b/engine/Runtime/Rendering/Caches/RenderResourceCache.h @@ -0,0 +1,160 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace XCEngine { +namespace Rendering { + +class RenderResourceCache { +public: + enum class GaussianSplatResidencyState { + Uninitialized = 0, + CpuReady, + GpuUploading, + GpuReady, + Failed + }; + + struct CachedMesh { + RHI::RHIBuffer* vertexBuffer = nullptr; + RHI::RHIResourceView* vertexBufferView = nullptr; + RHI::RHIBuffer* indexBuffer = nullptr; + RHI::RHIResourceView* indexBufferView = nullptr; + uint32_t vertexCount = 0; + uint32_t indexCount = 0; + uint32_t vertexStride = 0; + bool uses32BitIndices = false; + }; + + struct CachedTexture { + RHI::RHITexture* texture = nullptr; + RHI::RHIResourceView* shaderResourceView = nullptr; + uint32_t width = 0; + uint32_t height = 0; + }; + + struct CachedBufferView { + RHI::RHIResourceView* resourceView = nullptr; + }; + + struct CachedVolumeField { + RHI::RHIBuffer* payloadBuffer = nullptr; + RHI::RHIResourceView* shaderResourceView = nullptr; + uint32_t elementStride = 0; + uint32_t elementCount = 0; + uint64_t payloadSize = 0; + Resources::VolumeStorageKind storageKind = Resources::VolumeStorageKind::Unknown; + }; + + struct CachedGaussianSplatSection { + RHI::RHIBuffer* buffer = nullptr; + RHI::RHIResourceView* shaderResourceView = nullptr; + Resources::GaussianSplatSectionType type = Resources::GaussianSplatSectionType::Unknown; + Resources::GaussianSplatSectionFormat format = Resources::GaussianSplatSectionFormat::Unknown; + uint32_t elementStride = 0; + uint32_t elementCount = 0; + uint64_t payloadSize = 0; + }; + + struct CachedGaussianSplat { + GaussianSplatResidencyState residencyState = GaussianSplatResidencyState::Uninitialized; + uint32_t contentVersion = 0; + uint32_t splatCount = 0; + uint32_t chunkCount = 0; + uint32_t cameraCount = 0; + Math::Bounds bounds; + CachedGaussianSplatSection positions; + CachedGaussianSplatSection other; + CachedGaussianSplatSection color; + CachedGaussianSplatSection sh; + CachedGaussianSplatSection chunks; + }; + + ~RenderResourceCache(); + + void Shutdown(); + + const CachedMesh* GetOrCreateMesh(RHI::RHIDevice* device, const Resources::Mesh* mesh); + const CachedTexture* GetOrCreateTexture(RHI::RHIDevice* device, const Resources::Texture* texture); + const CachedVolumeField* GetOrCreateVolumeField( + RHI::RHIDevice* device, + const Resources::VolumeField* volumeField); + const CachedGaussianSplat* GetOrCreateGaussianSplat( + RHI::RHIDevice* device, + const Resources::GaussianSplat* gaussianSplat); + const CachedBufferView* GetOrCreateBufferView( + RHI::RHIDevice* device, + RHI::RHIBuffer* buffer, + RHI::ResourceViewType viewType, + const RHI::ResourceViewDesc& viewDesc); + +private: + struct BufferViewCacheKey { + const RHI::RHIBuffer* buffer = nullptr; + RHI::ResourceViewType viewType = RHI::ResourceViewType::ShaderResource; + uint32_t format = 0; + RHI::ResourceViewDimension dimension = RHI::ResourceViewDimension::Unknown; + uint64_t bufferLocation = 0; + uint32_t firstElement = 0; + uint32_t elementCount = 0; + uint32_t structureByteStride = 0; + + bool operator==(const BufferViewCacheKey& other) const { + return buffer == other.buffer && + viewType == other.viewType && + format == other.format && + dimension == other.dimension && + bufferLocation == other.bufferLocation && + firstElement == other.firstElement && + elementCount == other.elementCount && + structureByteStride == other.structureByteStride; + } + }; + + struct BufferViewCacheKeyHash { + size_t operator()(const BufferViewCacheKey& key) const noexcept; + }; + + bool UploadMesh(RHI::RHIDevice* device, const Resources::Mesh* mesh, CachedMesh& cachedMesh); + bool UploadTexture(RHI::RHIDevice* device, const Resources::Texture* texture, CachedTexture& cachedTexture); + bool UploadVolumeField( + RHI::RHIDevice* device, + const Resources::VolumeField* volumeField, + CachedVolumeField& cachedVolumeField); + bool UploadGaussianSplat( + RHI::RHIDevice* device, + const Resources::GaussianSplat* gaussianSplat, + CachedGaussianSplat& cachedGaussianSplat); + bool UploadGaussianSplatSection( + RHI::RHIDevice* device, + const Resources::GaussianSplat* gaussianSplat, + Resources::GaussianSplatSectionType sectionType, + Resources::GaussianSplatSectionFormat requiredFormat, + uint32_t requiredStride, + bool requiredSection, + CachedGaussianSplatSection& cachedSection); + bool CreateBufferView( + RHI::RHIDevice* device, + RHI::RHIBuffer* buffer, + RHI::ResourceViewType viewType, + const RHI::ResourceViewDesc& viewDesc, + CachedBufferView& cachedBufferView); + + std::unordered_map m_meshCache; + std::unordered_map m_textureCache; + std::unordered_map m_volumeFieldCache; + std::unordered_map m_gaussianSplatCache; + std::unordered_map m_bufferViewCache; +}; + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/Runtime/Rendering/FrameData/CullingResults.h b/engine/Runtime/Rendering/FrameData/CullingResults.h new file mode 100644 index 00000000..9d3fbf1d --- /dev/null +++ b/engine/Runtime/Rendering/FrameData/CullingResults.h @@ -0,0 +1,104 @@ +#pragma once + +#include + +#include +#include +#include + +namespace XCEngine { +namespace Rendering { + +enum class RendererListType : Core::uint32 { + AllVisible = 0, + Opaque = 1, + Transparent = 2, + ShadowCaster = 3, + ObjectId = 4 +}; + +enum class RendererSortMode : Core::uint32 { + None = 0, + FrontToBack = 1, + BackToFront = 2 +}; + +struct FilteringSettings { + Core::int32 renderQueueMin = std::numeric_limits::lowest(); + Core::int32 renderQueueMax = std::numeric_limits::max(); + Core::uint32 renderLayerMask = std::numeric_limits::max(); + bool requireShadowCasting = false; + bool requireRenderObjectId = false; + + bool operator==(const FilteringSettings& other) const { + return renderQueueMin == other.renderQueueMin && + renderQueueMax == other.renderQueueMax && + renderLayerMask == other.renderLayerMask && + requireShadowCasting == other.requireShadowCasting && + requireRenderObjectId == other.requireRenderObjectId; + } +}; + +struct SortingSettings { + RendererSortMode sortMode = RendererSortMode::None; + + bool operator==(const SortingSettings& other) const { + return sortMode == other.sortMode; + } +}; + +struct RendererListDesc { + RendererListType type = RendererListType::AllVisible; + FilteringSettings filtering = {}; + SortingSettings sorting = {}; + + bool operator==(const RendererListDesc& other) const { + return type == other.type && + filtering == other.filtering && + sorting == other.sorting; + } +}; + +struct RendererList { + RendererListDesc desc = {}; + std::vector visibleRenderItemIndices; + + bool Empty() const { + return visibleRenderItemIndices.empty(); + } + + size_t Size() const { + return visibleRenderItemIndices.size(); + } +}; + +struct CullingResults { + std::vector rendererLists; + + void Clear() { + rendererLists.clear(); + } + + RendererList* FindRendererList(RendererListType type) { + for (RendererList& rendererList : rendererLists) { + if (rendererList.desc.type == type) { + return &rendererList; + } + } + + return nullptr; + } + + const RendererList* FindRendererList(RendererListType type) const { + for (const RendererList& rendererList : rendererLists) { + if (rendererList.desc.type == type) { + return &rendererList; + } + } + + return nullptr; + } +}; + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/Runtime/Rendering/FrameData/RenderCameraData.h b/engine/Runtime/Rendering/FrameData/RenderCameraData.h new file mode 100644 index 00000000..be29a1b8 --- /dev/null +++ b/engine/Runtime/Rendering/FrameData/RenderCameraData.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include +#include + +#include + +namespace XCEngine { +namespace Rendering { + +enum class RenderClearFlags : uint8_t { + None = 0, + Color = 1 << 0, + Depth = 1 << 1, + All = (1 << 0) | (1 << 1) +}; + +constexpr RenderClearFlags operator|(RenderClearFlags lhs, RenderClearFlags rhs) { + return static_cast( + static_cast(lhs) | static_cast(rhs)); +} + +constexpr RenderClearFlags operator&(RenderClearFlags lhs, RenderClearFlags rhs) { + return static_cast( + static_cast(lhs) & static_cast(rhs)); +} + +constexpr bool HasRenderClearFlag(RenderClearFlags flags, RenderClearFlags flag) { + return static_cast(flags & flag) != 0; +} + +struct RenderCameraData { + Math::Matrix4x4 view = Math::Matrix4x4::Identity(); + Math::Matrix4x4 projection = Math::Matrix4x4::Identity(); + Math::Matrix4x4 viewProjection = Math::Matrix4x4::Identity(); + Math::Vector3 worldPosition = Math::Vector3::Zero(); + Math::Vector3 worldRight = Math::Vector3::Right(); + Math::Vector3 worldUp = Math::Vector3::Up(); + Math::Vector3 worldForward = Math::Vector3::Forward(); + Math::Color clearColor = Math::Color::Black(); + RenderClearFlags clearFlags = RenderClearFlags::All; + bool perspectiveProjection = true; + float verticalFovRadians = 60.0f * Math::DEG_TO_RAD; + float orthographicSize = 5.0f; + float aspectRatio = 1.0f; + float nearClipPlane = 0.1f; + float farClipPlane = 1000.0f; + uint32_t viewportWidth = 0; + uint32_t viewportHeight = 0; +}; + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/Runtime/Rendering/FrameData/RenderEnvironmentData.h b/engine/Runtime/Rendering/FrameData/RenderEnvironmentData.h new file mode 100644 index 00000000..add5274e --- /dev/null +++ b/engine/Runtime/Rendering/FrameData/RenderEnvironmentData.h @@ -0,0 +1,55 @@ +#pragma once + +#include + +#include + +namespace XCEngine { +namespace Resources { +class Material; +} // namespace Resources +} // namespace XCEngine + +namespace XCEngine { +namespace Rendering { + +enum class RenderEnvironmentMode : uint32_t { + None = 0, + ProceduralSkybox, + MaterialSkybox +}; + +struct ProceduralSkyboxData { + Math::Color topColor = Math::Color(0.18f, 0.36f, 0.74f, 1.0f); + Math::Color horizonColor = Math::Color(0.78f, 0.84f, 0.92f, 1.0f); + Math::Color bottomColor = Math::Color(0.92f, 0.93f, 0.95f, 1.0f); +}; + +struct MaterialSkyboxData { + const Resources::Material* material = nullptr; + + bool IsValid() const { + return material != nullptr; + } +}; + +struct RenderEnvironmentData { + RenderEnvironmentMode mode = RenderEnvironmentMode::None; + ProceduralSkyboxData skybox = {}; + MaterialSkyboxData materialSkybox = {}; + + bool HasProceduralSkybox() const { + return mode == RenderEnvironmentMode::ProceduralSkybox; + } + + bool HasMaterialSkybox() const { + return mode == RenderEnvironmentMode::MaterialSkybox && materialSkybox.IsValid(); + } + + bool HasSkybox() const { + return HasProceduralSkybox() || HasMaterialSkybox(); + } +}; + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/Runtime/Rendering/FrameData/RenderSceneData.h b/engine/Runtime/Rendering/FrameData/RenderSceneData.h new file mode 100644 index 00000000..45663954 --- /dev/null +++ b/engine/Runtime/Rendering/FrameData/RenderSceneData.h @@ -0,0 +1,107 @@ +#pragma once + +#include +#include +#include +#include + +#include "engine/Runtime/Rendering/FrameData/CullingResults.h" +#include "engine/Runtime/Rendering/FrameData/RenderCameraData.h" +#include "engine/Runtime/Rendering/FrameData/RenderEnvironmentData.h" +#include "engine/Runtime/Rendering/FrameData/VisibleGaussianSplatItem.h" +#include "engine/Runtime/Rendering/FrameData/VisibleRenderItem.h" +#include "engine/Runtime/Rendering/FrameData/VisibleVolumeItem.h" +#include "engine/Runtime/Rendering/Shadow/DirectionalShadowData.h" + +#include +#include +#include + +namespace XCEngine { +namespace Components { +class CameraComponent; +} // namespace Components + +namespace Rendering { + +struct RenderDirectionalLightData { + bool enabled = false; + bool castsShadows = false; + Math::Vector3 direction = Math::Vector3::Back(); + float intensity = 1.0f; + Math::Color color = Math::Color::White(); +}; + +enum class RenderLightType : uint32_t { + Directional = 0, + Point = 1, + Spot = 2 +}; + +struct RenderAdditionalLightData { + RenderLightType type = RenderLightType::Point; + bool enabled = false; + bool castsShadows = false; + Math::Color color = Math::Color::White(); + float intensity = 1.0f; + Math::Vector3 position = Math::Vector3::Zero(); + Math::Vector3 direction = Math::Vector3::Back(); + float range = 0.0f; + float spotAngle = 0.0f; +}; + +struct RenderLightingData { + static constexpr uint32_t kMaxAdditionalLightCount = 8u; + + RenderDirectionalLightData mainDirectionalLight; + RenderDirectionalShadowData mainDirectionalShadow; + std::array additionalLights = {}; + uint32_t additionalLightCount = 0u; + + bool HasMainDirectionalLight() const { + return mainDirectionalLight.enabled; + } + + bool HasMainDirectionalShadow() const { + return mainDirectionalShadow.IsValid(); + } + + bool HasAdditionalLights() const { + return additionalLightCount > 0u; + } +}; + +struct RenderSceneData { + Components::CameraComponent* camera = nullptr; + RenderCameraData cameraData; + RenderEnvironmentData environment; + RenderLightingData lighting; + Resources::ShaderKeywordSet globalShaderKeywords; + CullingResults cullingResults; + std::vector visibleItems; + std::vector visibleGaussianSplats; + std::vector visibleVolumes; + + bool HasCamera() const { + return camera != nullptr; + } + + RendererList* FindRendererList(RendererListType type) { + return cullingResults.FindRendererList(type); + } + + const RendererList* FindRendererList(RendererListType type) const { + return cullingResults.FindRendererList(type); + } + + const VisibleRenderItem* TryGetVisibleRenderItem(Core::uint32 index) const { + if (index >= visibleItems.size()) { + return nullptr; + } + + return &visibleItems[index]; + } +}; + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/Runtime/Rendering/FrameData/RendererListUtils.h b/engine/Runtime/Rendering/FrameData/RendererListUtils.h new file mode 100644 index 00000000..d5690522 --- /dev/null +++ b/engine/Runtime/Rendering/FrameData/RendererListUtils.h @@ -0,0 +1,219 @@ +#pragma once + +#include +#include + +#include "engine/Runtime/Rendering/FrameData/RenderSceneData.h" + +#include +#include +#include + +namespace XCEngine { +namespace Rendering { + +inline FilteringSettings BuildDefaultFilteringSettings(RendererListType type) { + FilteringSettings filtering = {}; + + switch (type) { + case RendererListType::AllVisible: + break; + case RendererListType::Opaque: + filtering.renderQueueMax = + static_cast(Resources::MaterialRenderQueue::Transparent) - 1; + break; + case RendererListType::Transparent: + filtering.renderQueueMin = + static_cast(Resources::MaterialRenderQueue::Transparent); + break; + case RendererListType::ShadowCaster: + filtering.requireShadowCasting = true; + break; + case RendererListType::ObjectId: + filtering.requireRenderObjectId = true; + break; + } + + return filtering; +} + +inline SortingSettings BuildDefaultSortingSettings(RendererListType type) { + SortingSettings sorting = {}; + + switch (type) { + case RendererListType::Opaque: + case RendererListType::ShadowCaster: + case RendererListType::ObjectId: + sorting.sortMode = RendererSortMode::FrontToBack; + break; + case RendererListType::Transparent: + sorting.sortMode = RendererSortMode::BackToFront; + break; + case RendererListType::AllVisible: + sorting.sortMode = RendererSortMode::None; + break; + } + + return sorting; +} + +inline RendererListDesc BuildDefaultRendererListDesc(RendererListType type) { + RendererListDesc desc = {}; + desc.type = type; + desc.filtering = BuildDefaultFilteringSettings(type); + desc.sorting = BuildDefaultSortingSettings(type); + return desc; +} + +inline bool MatchesFilteringSettings( + const VisibleRenderItem& visibleItem, + const FilteringSettings& filtering) { + if (visibleItem.renderQueue < filtering.renderQueueMin || + visibleItem.renderQueue > filtering.renderQueueMax) { + return false; + } + + if (visibleItem.renderLayer >= 32u || + ((filtering.renderLayerMask & + (1u << visibleItem.renderLayer)) == 0u)) { + return false; + } + + if (filtering.requireShadowCasting && + visibleItem.meshRenderer != nullptr && + !visibleItem.meshRenderer->GetCastShadows()) { + return false; + } + + if (filtering.requireRenderObjectId && + !IsValidRenderObjectId(visibleItem.renderObjectId)) { + return false; + } + + return true; +} + +inline bool MatchesRendererListDesc( + const VisibleRenderItem& visibleItem, + const RendererListDesc& desc) { + return MatchesFilteringSettings(visibleItem, desc.filtering); +} + +inline RendererList BuildRendererList( + RendererListType type, + const std::vector& visibleItems) { + RendererList rendererList = {}; + rendererList.desc = BuildDefaultRendererListDesc(type); + rendererList.visibleRenderItemIndices.reserve(visibleItems.size()); + + for (Core::uint32 visibleItemIndex = 0; + visibleItemIndex < static_cast(visibleItems.size()); + ++visibleItemIndex) { + if (!MatchesRendererListDesc( + visibleItems[visibleItemIndex], + rendererList.desc)) { + continue; + } + + rendererList.visibleRenderItemIndices.push_back(visibleItemIndex); + } + + return rendererList; +} + +template +inline void VisitRendererListVisibleItems( + const RenderSceneData& sceneData, + RendererListType rendererListType, + Visitor&& visitor) { + const RendererList* rendererList = sceneData.FindRendererList(rendererListType); + if (rendererList != nullptr) { + for (Core::uint32 visibleItemIndex : rendererList->visibleRenderItemIndices) { + const VisibleRenderItem* visibleItem = + sceneData.TryGetVisibleRenderItem(visibleItemIndex); + if (visibleItem == nullptr) { + continue; + } + + visitor(*visibleItem); + } + return; + } + + const RendererListDesc fallbackDesc = BuildDefaultRendererListDesc(rendererListType); + for (const VisibleRenderItem& visibleItem : sceneData.visibleItems) { + if (!MatchesRendererListDesc(visibleItem, fallbackDesc)) { + continue; + } + + visitor(visibleItem); + } +} + +template +inline void VisitRendererListVisibleItems( + const RenderSceneData& sceneData, + const RendererListDesc& rendererListDesc, + Visitor&& visitor) { + const RendererListDesc defaultDesc = + BuildDefaultRendererListDesc( + rendererListDesc.type); + if (rendererListDesc == defaultDesc) { + VisitRendererListVisibleItems( + sceneData, + rendererListDesc.type, + std::forward(visitor)); + return; + } + + std::vector matchedItems; + matchedItems.reserve(sceneData.visibleItems.size()); + for (const VisibleRenderItem& visibleItem : sceneData.visibleItems) { + if (!MatchesRendererListDesc( + visibleItem, + rendererListDesc)) { + continue; + } + + matchedItems.push_back(&visibleItem); + } + + switch (rendererListDesc.sorting.sortMode) { + case RendererSortMode::FrontToBack: + std::stable_sort( + matchedItems.begin(), + matchedItems.end(), + [](const VisibleRenderItem* lhs, const VisibleRenderItem* rhs) { + return lhs != nullptr && + rhs != nullptr && + lhs->cameraDistanceSq < + rhs->cameraDistanceSq; + }); + break; + case RendererSortMode::BackToFront: + std::stable_sort( + matchedItems.begin(), + matchedItems.end(), + [](const VisibleRenderItem* lhs, const VisibleRenderItem* rhs) { + return lhs != nullptr && + rhs != nullptr && + lhs->cameraDistanceSq > + rhs->cameraDistanceSq; + }); + break; + case RendererSortMode::None: + default: + break; + } + + for (const VisibleRenderItem* visibleItem : matchedItems) { + if (visibleItem == nullptr) { + continue; + } + + visitor(*visibleItem); + } +} + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/Runtime/Rendering/FrameData/VisibleGaussianSplatItem.h b/engine/Runtime/Rendering/FrameData/VisibleGaussianSplatItem.h new file mode 100644 index 00000000..7f36e62d --- /dev/null +++ b/engine/Runtime/Rendering/FrameData/VisibleGaussianSplatItem.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +namespace XCEngine { +namespace Components { +class GameObject; +class GaussianSplatRendererComponent; +} // namespace Components + +namespace Resources { +class GaussianSplat; +class Material; +} // namespace Resources + +namespace Rendering { + +struct VisibleGaussianSplatItem { + Components::GameObject* gameObject = nullptr; + Components::GaussianSplatRendererComponent* gaussianSplatRenderer = nullptr; + Resources::GaussianSplat* gaussianSplat = nullptr; + const Resources::Material* material = nullptr; + Core::int32 renderQueue = 0; + float cameraDistanceSq = 0.0f; + Math::Matrix4x4 localToWorld = Math::Matrix4x4::Identity(); +}; + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/Runtime/Rendering/FrameData/VisibleRenderItem.h b/engine/Runtime/Rendering/FrameData/VisibleRenderItem.h new file mode 100644 index 00000000..b2acd54d --- /dev/null +++ b/engine/Runtime/Rendering/FrameData/VisibleRenderItem.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include + +#include "engine/Runtime/Rendering/Picking/ObjectIdCodec.h" + +namespace XCEngine { +namespace Components { +class GameObject; +class MeshFilterComponent; +class MeshRendererComponent; +} // namespace Components + +namespace Rendering { + +struct VisibleRenderItem { + Components::GameObject* gameObject = nullptr; + Components::MeshFilterComponent* meshFilter = nullptr; + Components::MeshRendererComponent* meshRenderer = nullptr; + Resources::Mesh* mesh = nullptr; + const Resources::Material* material = nullptr; + RenderObjectId renderObjectId = kInvalidRenderObjectId; + Core::uint32 materialIndex = 0; + Core::uint32 sectionIndex = 0; + bool hasSection = false; + Core::uint32 renderLayer = 0; + Core::int32 renderQueue = 0; + float cameraDistanceSq = 0.0f; + Math::Matrix4x4 localToWorld = Math::Matrix4x4::Identity(); +}; + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/Runtime/Rendering/FrameData/VisibleVolumeItem.h b/engine/Runtime/Rendering/FrameData/VisibleVolumeItem.h new file mode 100644 index 00000000..4337419d --- /dev/null +++ b/engine/Runtime/Rendering/FrameData/VisibleVolumeItem.h @@ -0,0 +1,30 @@ +#pragma once + +#include +#include + +namespace XCEngine { +namespace Components { +class GameObject; +class VolumeRendererComponent; +} // namespace Components + +namespace Resources { +class Material; +class VolumeField; +} // namespace Resources + +namespace Rendering { + +struct VisibleVolumeItem { + Components::GameObject* gameObject = nullptr; + Components::VolumeRendererComponent* volumeRenderer = nullptr; + Resources::VolumeField* volumeField = nullptr; + const Resources::Material* material = nullptr; + Core::int32 renderQueue = 0; + float cameraDistanceSq = 0.0f; + Math::Matrix4x4 localToWorld = Math::Matrix4x4::Identity(); +}; + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/Runtime/Rendering/Materials/RenderMaterialResolve.h b/engine/Runtime/Rendering/Materials/RenderMaterialResolve.h new file mode 100644 index 00000000..a45e5e12 --- /dev/null +++ b/engine/Runtime/Rendering/Materials/RenderMaterialResolve.h @@ -0,0 +1,509 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +namespace XCEngine { +namespace Rendering { + +enum class BuiltinSkyboxTextureMode : Core::uint8 { + None = 0, + Panoramic = 1, + Cubemap = 2 +}; + +struct BuiltinSkyboxMaterialData { + Math::Vector4 tint = Math::Vector4::One(); + float exposure = 1.0f; + float rotationDegrees = 0.0f; + BuiltinSkyboxTextureMode textureMode = BuiltinSkyboxTextureMode::None; +}; + +struct BuiltinDepthStyleMaterialConstants { + Math::Vector4 baseColorFactor = Math::Vector4::One(); + Math::Vector4 alphaCutoffParams = Math::Vector4(0.5f, 0.0f, 0.0f, 0.0f); +}; + +struct MaterialConstantLayoutView { + const Resources::MaterialConstantFieldDesc* fields = nullptr; + size_t count = 0; + size_t size = 0; + + bool IsValid() const { + return fields != nullptr && count > 0 && size > 0; + } +}; + +struct MaterialConstantPayloadView { + const void* data = nullptr; + size_t size = 0; + MaterialConstantLayoutView layout = {}; + + bool IsValid() const { + return data != nullptr && size > 0 && layout.IsValid() && layout.size == size; + } +}; + +struct MaterialBufferResourceView { + RHI::RHIBuffer* buffer = nullptr; + RHI::ResourceViewType viewType = RHI::ResourceViewType::ShaderResource; + RHI::ResourceViewDesc viewDesc = {}; + + bool IsValid() const { + return buffer != nullptr && + (viewType == RHI::ResourceViewType::ShaderResource || + viewType == RHI::ResourceViewType::UnorderedAccess) && + viewDesc.dimension != RHI::ResourceViewDimension::Unknown; + } +}; + +inline bool IsMaterialBufferResourceType(Resources::ShaderResourceType type) { + switch (type) { + case Resources::ShaderResourceType::StructuredBuffer: + case Resources::ShaderResourceType::RawBuffer: + case Resources::ShaderResourceType::RWStructuredBuffer: + case Resources::ShaderResourceType::RWRawBuffer: + return true; + default: + return false; + } +} + +inline const Resources::ShaderPropertyDesc* FindShaderPropertyBySemantic( + const Resources::Material* material, + const Containers::String& semantic) { + if (material == nullptr || material->GetShader() == nullptr) { + return nullptr; + } + + const Containers::String normalizedSemantic = NormalizeBuiltinPassMetadataValue(semantic); + for (const Resources::ShaderPropertyDesc& property : material->GetShader()->GetProperties()) { + if (NormalizeBuiltinPassMetadataValue(property.semantic) == normalizedSemantic) { + return &property; + } + } + + return nullptr; +} + +inline Math::Vector4 ResolveBuiltinBaseColorFactor(const Resources::Material* material) { + if (material == nullptr) { + return Math::Vector4::One(); + } + + if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "BaseColor")) { + if (material->HasProperty(property->name) && + (property->type == Resources::ShaderPropertyType::Color || + property->type == Resources::ShaderPropertyType::Vector)) { + return material->GetFloat4(property->name); + } + } + + return Math::Vector4::One(); +} + +inline const Resources::Texture* ResolveBuiltinBaseColorTexture(const Resources::Material* material) { + if (material == nullptr) { + return nullptr; + } + + if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "BaseColorTexture")) { + const Resources::ResourceHandle textureHandle = material->GetTexture(property->name); + if (textureHandle.Get() != nullptr && textureHandle->IsValid()) { + return textureHandle.Get(); + } + } + + return nullptr; +} + +inline float ResolveBuiltinAlphaCutoff(const Resources::Material* material) { + if (material == nullptr) { + return 0.5f; + } + + if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "AlphaCutoff")) { + if (material->HasProperty(property->name) && + (property->type == Resources::ShaderPropertyType::Float || + property->type == Resources::ShaderPropertyType::Range)) { + return material->GetFloat(property->name); + } + } + + return 0.5f; +} + +inline bool IsCubemapSkyboxTextureType(Resources::TextureType type) { + return type == Resources::TextureType::TextureCube || + type == Resources::TextureType::TextureCubeArray; +} + +inline bool IsPanoramicSkyboxTextureType(Resources::TextureType type) { + return type == Resources::TextureType::Texture2D || + type == Resources::TextureType::Texture2DArray; +} + +inline const Resources::Texture* ResolveSkyboxPanoramicTexture(const Resources::Material* material) { + if (material == nullptr) { + return nullptr; + } + + if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "SkyboxPanoramicTexture")) { + const Resources::ResourceHandle textureHandle = material->GetTexture(property->name); + if (textureHandle.Get() != nullptr && + textureHandle->IsValid() && + IsPanoramicSkyboxTextureType(textureHandle->GetTextureType())) { + return textureHandle.Get(); + } + } + + if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "SkyboxTexture")) { + const Resources::ResourceHandle textureHandle = material->GetTexture(property->name); + if (textureHandle.Get() != nullptr && + textureHandle->IsValid() && + IsPanoramicSkyboxTextureType(textureHandle->GetTextureType())) { + return textureHandle.Get(); + } + } + + return nullptr; +} + +inline const Resources::Texture* ResolveSkyboxCubemapTexture(const Resources::Material* material) { + if (material == nullptr) { + return nullptr; + } + + if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "SkyboxTexture")) { + const Resources::ResourceHandle textureHandle = material->GetTexture(property->name); + if (textureHandle.Get() != nullptr && + textureHandle->IsValid() && + IsCubemapSkyboxTextureType(textureHandle->GetTextureType())) { + return textureHandle.Get(); + } + } + + return nullptr; +} + +inline BuiltinSkyboxTextureMode ResolveSkyboxTextureMode(const Resources::Material* material) { + if (ResolveSkyboxPanoramicTexture(material) != nullptr) { + return BuiltinSkyboxTextureMode::Panoramic; + } + if (ResolveSkyboxCubemapTexture(material) != nullptr) { + return BuiltinSkyboxTextureMode::Cubemap; + } + return BuiltinSkyboxTextureMode::None; +} + +inline Math::Vector4 ResolveSkyboxTint(const Resources::Material* material) { + if (material == nullptr) { + return Math::Vector4::One(); + } + + if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "Tint")) { + if (material->HasProperty(property->name) && + (property->type == Resources::ShaderPropertyType::Color || + property->type == Resources::ShaderPropertyType::Vector)) { + return material->GetFloat4(property->name); + } + } + + return Math::Vector4::One(); +} + +inline float ResolveSkyboxExposure(const Resources::Material* material) { + if (material == nullptr) { + return 1.0f; + } + + if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "Exposure")) { + if (material->HasProperty(property->name) && + (property->type == Resources::ShaderPropertyType::Float || + property->type == Resources::ShaderPropertyType::Range)) { + return material->GetFloat(property->name); + } + } + + return 1.0f; +} + +inline float ResolveSkyboxRotationDegrees(const Resources::Material* material) { + if (material == nullptr) { + return 0.0f; + } + + if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "Rotation")) { + if (material->HasProperty(property->name) && + (property->type == Resources::ShaderPropertyType::Float || + property->type == Resources::ShaderPropertyType::Range)) { + return material->GetFloat(property->name); + } + } + + return 0.0f; +} + +inline BuiltinSkyboxMaterialData BuildBuiltinSkyboxMaterialData(const Resources::Material* material) { + BuiltinSkyboxMaterialData data = {}; + data.tint = ResolveSkyboxTint(material); + data.exposure = ResolveSkyboxExposure(material); + data.rotationDegrees = ResolveSkyboxRotationDegrees(material); + data.textureMode = ResolveSkyboxTextureMode(material); + return data; +} + +inline MaterialConstantPayloadView ResolveSchemaMaterialConstantPayload(const Resources::Material* material) { + if (material == nullptr || material->GetShader() == nullptr) { + return {}; + } + + const Containers::Array& constantLayout = material->GetConstantLayout(); + const Containers::Array& constantBufferData = material->GetConstantBufferData(); + if (constantLayout.Empty() || constantBufferData.Empty()) { + return {}; + } + + MaterialConstantLayoutView layoutView = {}; + layoutView.fields = constantLayout.Data(); + layoutView.count = constantLayout.Size(); + layoutView.size = constantBufferData.Size(); + + return { constantBufferData.Data(), constantBufferData.Size(), layoutView }; +} + +inline BuiltinDepthStyleMaterialConstants BuildBuiltinDepthStyleMaterialConstants( + const Resources::Material* material) { + BuiltinDepthStyleMaterialConstants constants = {}; + constants.baseColorFactor = ResolveBuiltinBaseColorFactor(material); + constants.alphaCutoffParams = Math::Vector4(ResolveBuiltinAlphaCutoff(material), 0.0f, 0.0f, 0.0f); + return constants; +} + +inline MaterialConstantPayloadView ResolveBuiltinDepthStyleMaterialConstantPayload( + const Resources::Material* material, + BuiltinDepthStyleMaterialConstants& outConstants, + Resources::MaterialConstantFieldDesc (&outLayout)[2]) { + outConstants = BuildBuiltinDepthStyleMaterialConstants(material); + + outLayout[0].name = "gBaseColorFactor"; + outLayout[0].type = Resources::MaterialPropertyType::Float4; + outLayout[0].offset = 0u; + outLayout[0].size = static_cast(sizeof(Math::Vector4)); + outLayout[0].alignedSize = static_cast(sizeof(Math::Vector4)); + + outLayout[1].name = "gAlphaCutoffParams"; + outLayout[1].type = Resources::MaterialPropertyType::Float4; + outLayout[1].offset = static_cast(sizeof(Math::Vector4)); + outLayout[1].size = static_cast(sizeof(Math::Vector4)); + outLayout[1].alignedSize = static_cast(sizeof(Math::Vector4)); + + MaterialConstantLayoutView layoutView = {}; + layoutView.fields = outLayout; + layoutView.count = 2u; + layoutView.size = sizeof(BuiltinDepthStyleMaterialConstants); + + return { &outConstants, sizeof(BuiltinDepthStyleMaterialConstants), layoutView }; +} + +inline bool TryResolveMaterialBufferResourceView( + const Resources::Material* material, + const BuiltinPassResourceBindingDesc& binding, + MaterialBufferResourceView& outView) { + outView = {}; + if (material == nullptr || !IsMaterialBufferResourceType(binding.resourceType)) { + return false; + } + + const Resources::MaterialBufferBinding* materialBinding = material->FindBufferBinding(binding.name); + if (materialBinding == nullptr || materialBinding->buffer == nullptr) { + return false; + } + + outView.buffer = materialBinding->buffer; + outView.viewDesc.firstElement = materialBinding->viewDesc.firstElement; + outView.viewDesc.elementCount = materialBinding->viewDesc.elementCount; + + switch (binding.resourceType) { + case Resources::ShaderResourceType::StructuredBuffer: + outView.viewType = RHI::ResourceViewType::ShaderResource; + outView.viewDesc.dimension = RHI::ResourceViewDimension::StructuredBuffer; + outView.viewDesc.structureByteStride = + materialBinding->viewDesc.structureByteStride > 0 + ? materialBinding->viewDesc.structureByteStride + : materialBinding->buffer->GetStride(); + break; + case Resources::ShaderResourceType::RawBuffer: + outView.viewType = RHI::ResourceViewType::ShaderResource; + outView.viewDesc.dimension = RHI::ResourceViewDimension::RawBuffer; + break; + case Resources::ShaderResourceType::RWStructuredBuffer: + outView.viewType = RHI::ResourceViewType::UnorderedAccess; + outView.viewDesc.dimension = RHI::ResourceViewDimension::StructuredBuffer; + outView.viewDesc.structureByteStride = + materialBinding->viewDesc.structureByteStride > 0 + ? materialBinding->viewDesc.structureByteStride + : materialBinding->buffer->GetStride(); + break; + case Resources::ShaderResourceType::RWRawBuffer: + outView.viewType = RHI::ResourceViewType::UnorderedAccess; + outView.viewDesc.dimension = RHI::ResourceViewDimension::RawBuffer; + break; + default: + return false; + } + + if (outView.viewDesc.dimension == RHI::ResourceViewDimension::StructuredBuffer && + outView.viewDesc.structureByteStride == 0) { + outView = {}; + return false; + } + + return outView.IsValid(); +} + +inline const Resources::Material* ResolveMaterial( + const Components::MeshRendererComponent* meshRenderer, + const Resources::Mesh* mesh, + Core::uint32 materialIndex) { + if (meshRenderer != nullptr && materialIndex < meshRenderer->GetMaterialCount()) { + if (const Resources::Material* material = meshRenderer->GetMaterial(materialIndex)) { + return material; + } + } + + if (mesh != nullptr && materialIndex < mesh->GetMaterials().Size()) { + if (const Resources::Material* material = mesh->GetMaterials()[materialIndex]) { + return material; + } + } + + if (meshRenderer != nullptr && meshRenderer->GetMaterialCount() > 0) { + if (const Resources::Material* material = meshRenderer->GetMaterial(0)) { + return material; + } + } + + if (mesh != nullptr && mesh->GetMaterials().Size() > 0) { + return mesh->GetMaterials()[0]; + } + + return nullptr; +} + +inline const Resources::Material* ResolveMaterial(const VisibleRenderItem& visibleItem) { + if (visibleItem.material != nullptr) { + return visibleItem.material; + } + + return ResolveMaterial(visibleItem.meshRenderer, visibleItem.mesh, visibleItem.materialIndex); +} + +inline bool TryResolveRenderQueueTagValue( + const Containers::String& queueValue, + Core::int32& outRenderQueue) { + const Containers::String normalized = NormalizeBuiltinPassMetadataValue(queueValue); + if (normalized.Empty()) { + return false; + } + + if (normalized == Containers::String("background")) { + outRenderQueue = static_cast(Resources::MaterialRenderQueue::Background); + return true; + } + if (normalized == Containers::String("geometry")) { + outRenderQueue = static_cast(Resources::MaterialRenderQueue::Geometry); + return true; + } + if (normalized == Containers::String("alphatest")) { + outRenderQueue = static_cast(Resources::MaterialRenderQueue::AlphaTest); + return true; + } + if (normalized == Containers::String("transparent")) { + outRenderQueue = static_cast(Resources::MaterialRenderQueue::Transparent); + return true; + } + if (normalized == Containers::String("overlay")) { + outRenderQueue = static_cast(Resources::MaterialRenderQueue::Overlay); + return true; + } + + char* end = nullptr; + const long parsedValue = std::strtol(normalized.CStr(), &end, 10); + if (end != nullptr && *end == '\0') { + outRenderQueue = static_cast(parsedValue); + return true; + } + + return false; +} + +inline bool TryResolveShaderPassRenderQueue(const Resources::ShaderPass& shaderPass, Core::int32& outRenderQueue) { + for (const Resources::ShaderPassTagEntry& tag : shaderPass.tags) { + if (NormalizeBuiltinPassMetadataValue(tag.name) == Containers::String("queue") && + TryResolveRenderQueueTagValue(tag.value, outRenderQueue)) { + return true; + } + } + + return false; +} + +inline Core::int32 ResolveMaterialRenderQueue(const Resources::Material* material) { + const Core::int32 defaultQueue = static_cast(Resources::MaterialRenderQueue::Geometry); + if (material == nullptr) { + return defaultQueue; + } + + const Core::int32 materialQueue = material->GetRenderQueue(); + if (materialQueue != defaultQueue) { + return materialQueue; + } + + if (const Resources::Shader* shader = material->GetShader()) { + for (const Resources::ShaderPass& pass : shader->GetPasses()) { + Core::int32 shaderQueue = defaultQueue; + if (TryResolveShaderPassRenderQueue(pass, shaderQueue)) { + return shaderQueue; + } + } + } + + return materialQueue; +} + +inline bool IsTransparentRenderQueue(Core::int32 renderQueue) { + return renderQueue >= static_cast(Resources::MaterialRenderQueue::Transparent); +} + +inline bool MatchesBuiltinPass(const Resources::Material* material, BuiltinMaterialPass pass) { + if (material == nullptr) { + return false; + } + + const Resources::Shader* shader = material->GetShader(); + if (shader == nullptr) { + return false; + } + + for (const Resources::ShaderPass& shaderPassEntry : shader->GetPasses()) { + if (ShaderPassMatchesBuiltinPass(shaderPassEntry, pass)) { + return true; + } + } + + return false; +} + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/Runtime/Rendering/Materials/RenderMaterialStateUtils.h b/engine/Runtime/Rendering/Materials/RenderMaterialStateUtils.h new file mode 100644 index 00000000..c838b497 --- /dev/null +++ b/engine/Runtime/Rendering/Materials/RenderMaterialStateUtils.h @@ -0,0 +1,311 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include + +namespace XCEngine { +namespace Rendering { + +inline RHI::CullMode ToRHICullMode(Resources::MaterialCullMode mode) { + switch (mode) { + case Resources::MaterialCullMode::Front: + return RHI::CullMode::Front; + case Resources::MaterialCullMode::Back: + return RHI::CullMode::Back; + case Resources::MaterialCullMode::None: + default: + return RHI::CullMode::None; + } +} + +inline RHI::ComparisonFunc ToRHIComparisonFunc(Resources::MaterialComparisonFunc func) { + switch (func) { + case Resources::MaterialComparisonFunc::Never: + return RHI::ComparisonFunc::Never; + case Resources::MaterialComparisonFunc::Equal: + return RHI::ComparisonFunc::Equal; + case Resources::MaterialComparisonFunc::LessEqual: + return RHI::ComparisonFunc::LessEqual; + case Resources::MaterialComparisonFunc::Greater: + return RHI::ComparisonFunc::Greater; + case Resources::MaterialComparisonFunc::NotEqual: + return RHI::ComparisonFunc::NotEqual; + case Resources::MaterialComparisonFunc::GreaterEqual: + return RHI::ComparisonFunc::GreaterEqual; + case Resources::MaterialComparisonFunc::Always: + return RHI::ComparisonFunc::Always; + case Resources::MaterialComparisonFunc::Less: + default: + return RHI::ComparisonFunc::Less; + } +} + +inline RHI::BlendFactor ToRHIBlendFactor(Resources::MaterialBlendFactor factor) { + switch (factor) { + case Resources::MaterialBlendFactor::Zero: + return RHI::BlendFactor::Zero; + case Resources::MaterialBlendFactor::SrcColor: + return RHI::BlendFactor::SrcColor; + case Resources::MaterialBlendFactor::InvSrcColor: + return RHI::BlendFactor::InvSrcColor; + case Resources::MaterialBlendFactor::SrcAlpha: + return RHI::BlendFactor::SrcAlpha; + case Resources::MaterialBlendFactor::InvSrcAlpha: + return RHI::BlendFactor::InvSrcAlpha; + case Resources::MaterialBlendFactor::DstAlpha: + return RHI::BlendFactor::DstAlpha; + case Resources::MaterialBlendFactor::InvDstAlpha: + return RHI::BlendFactor::InvDstAlpha; + case Resources::MaterialBlendFactor::DstColor: + return RHI::BlendFactor::DstColor; + case Resources::MaterialBlendFactor::InvDstColor: + return RHI::BlendFactor::InvDstColor; + case Resources::MaterialBlendFactor::SrcAlphaSat: + return RHI::BlendFactor::SrcAlphaSat; + case Resources::MaterialBlendFactor::BlendFactor: + return RHI::BlendFactor::BlendFactor; + case Resources::MaterialBlendFactor::InvBlendFactor: + return RHI::BlendFactor::InvBlendFactor; + case Resources::MaterialBlendFactor::Src1Color: + return RHI::BlendFactor::Src1Color; + case Resources::MaterialBlendFactor::InvSrc1Color: + return RHI::BlendFactor::InvSrc1Color; + case Resources::MaterialBlendFactor::Src1Alpha: + return RHI::BlendFactor::Src1Alpha; + case Resources::MaterialBlendFactor::InvSrc1Alpha: + return RHI::BlendFactor::InvSrc1Alpha; + case Resources::MaterialBlendFactor::One: + default: + return RHI::BlendFactor::One; + } +} + +inline RHI::BlendOp ToRHIBlendOp(Resources::MaterialBlendOp op) { + switch (op) { + case Resources::MaterialBlendOp::Subtract: + return RHI::BlendOp::Subtract; + case Resources::MaterialBlendOp::ReverseSubtract: + return RHI::BlendOp::ReverseSubtract; + case Resources::MaterialBlendOp::Min: + return RHI::BlendOp::Min; + case Resources::MaterialBlendOp::Max: + return RHI::BlendOp::Max; + case Resources::MaterialBlendOp::Add: + default: + return RHI::BlendOp::Add; + } +} + +inline RHI::StencilOp ToRHIStencilOp(Resources::MaterialStencilOp op) { + switch (op) { + case Resources::MaterialStencilOp::Zero: + return RHI::StencilOp::Zero; + case Resources::MaterialStencilOp::Replace: + return RHI::StencilOp::Replace; + case Resources::MaterialStencilOp::IncrSat: + return RHI::StencilOp::IncrSat; + case Resources::MaterialStencilOp::DecrSat: + return RHI::StencilOp::DecrSat; + case Resources::MaterialStencilOp::Invert: + return RHI::StencilOp::Invert; + case Resources::MaterialStencilOp::IncrWrap: + return RHI::StencilOp::Incr; + case Resources::MaterialStencilOp::DecrWrap: + return RHI::StencilOp::Decr; + case Resources::MaterialStencilOp::Keep: + default: + return RHI::StencilOp::Keep; + } +} + +inline Resources::MaterialRenderState ResolveEffectiveRenderState( + const Resources::ShaderPass* shaderPass, + const Resources::Material* material) { + Resources::MaterialRenderState renderState = {}; + + if (shaderPass != nullptr && shaderPass->hasFixedFunctionState) { + renderState = shaderPass->fixedFunctionState; + } else if (material != nullptr) { + renderState = material->GetRenderState(); + } + + if (material != nullptr && material->HasRenderStateOverride()) { + renderState = material->GetRenderState(); + } + + return renderState; +} + +inline Resources::MaterialRenderState ApplyRenderStateBlock( + Resources::MaterialRenderState renderState, + const RenderStateBlock* renderStateBlock) { + if (renderStateBlock == nullptr || + !renderStateBlock->HasOverrides()) { + return renderState; + } + + if (renderStateBlock->HasDepthOverride()) { + renderState.depthWriteEnable = + renderStateBlock->depthState.writeEnabled; + renderState.depthFunc = + renderStateBlock->depthState.compareFunction; + } + + if (renderStateBlock->HasStencilOverride()) { + renderState.stencil.enabled = + renderStateBlock->stencilState.enabled; + renderState.stencil.readMask = + renderStateBlock->stencilState.readMask; + renderState.stencil.writeMask = + renderStateBlock->stencilState.writeMask; + renderState.stencil.reference = + renderStateBlock->stencilReference; + renderState.stencil.front.failOp = + renderStateBlock->stencilState.frontFace.failOp; + renderState.stencil.front.passOp = + renderStateBlock->stencilState.frontFace.passOp; + renderState.stencil.front.depthFailOp = + renderStateBlock->stencilState.frontFace.depthFailOp; + renderState.stencil.front.func = + renderStateBlock->stencilState.frontFace.compareFunction; + renderState.stencil.back.failOp = + renderStateBlock->stencilState.backFace.failOp; + renderState.stencil.back.passOp = + renderStateBlock->stencilState.backFace.passOp; + renderState.stencil.back.depthFailOp = + renderStateBlock->stencilState.backFace.depthFailOp; + renderState.stencil.back.func = + renderStateBlock->stencilState.backFace.compareFunction; + } + + return renderState; +} + +inline RHI::RasterizerDesc BuildRasterizerState(const Resources::MaterialRenderState& renderState) { + RHI::RasterizerDesc desc = {}; + desc.fillMode = static_cast(RHI::FillMode::Solid); + desc.cullMode = static_cast(RHI::CullMode::None); + desc.frontFace = static_cast(RHI::FrontFace::CounterClockwise); + desc.depthClipEnable = true; + desc.cullMode = static_cast(ToRHICullMode(renderState.cullMode)); + desc.depthBias = renderState.depthBiasUnits; + desc.slopeScaledDepthBias = renderState.depthBiasFactor; + + return desc; +} + +inline RHI::BlendDesc BuildBlendState(const Resources::MaterialRenderState& renderState) { + RHI::BlendDesc desc = {}; + desc.blendEnable = renderState.blendEnable; + desc.srcBlend = static_cast(ToRHIBlendFactor(renderState.srcBlend)); + desc.dstBlend = static_cast(ToRHIBlendFactor(renderState.dstBlend)); + desc.srcBlendAlpha = static_cast(ToRHIBlendFactor(renderState.srcBlendAlpha)); + desc.dstBlendAlpha = static_cast(ToRHIBlendFactor(renderState.dstBlendAlpha)); + desc.blendOp = static_cast(ToRHIBlendOp(renderState.blendOp)); + desc.blendOpAlpha = static_cast(ToRHIBlendOp(renderState.blendOpAlpha)); + desc.colorWriteMask = renderState.colorWriteMask; + + return desc; +} + +inline RHI::DepthStencilStateDesc BuildDepthStencilState(const Resources::MaterialRenderState& renderState) { + RHI::DepthStencilStateDesc desc = {}; + desc.depthTestEnable = renderState.depthTestEnable; + desc.depthWriteEnable = renderState.depthWriteEnable; + desc.depthFunc = static_cast(ToRHIComparisonFunc(renderState.depthFunc)); + desc.stencilEnable = renderState.stencil.enabled; + desc.stencilReadMask = renderState.stencil.readMask; + desc.stencilWriteMask = renderState.stencil.writeMask; + desc.front.failOp = static_cast(ToRHIStencilOp(renderState.stencil.front.failOp)); + desc.front.passOp = static_cast(ToRHIStencilOp(renderState.stencil.front.passOp)); + desc.front.depthFailOp = static_cast(ToRHIStencilOp(renderState.stencil.front.depthFailOp)); + desc.front.func = static_cast(ToRHIComparisonFunc(renderState.stencil.front.func)); + desc.back.failOp = static_cast(ToRHIStencilOp(renderState.stencil.back.failOp)); + desc.back.passOp = static_cast(ToRHIStencilOp(renderState.stencil.back.passOp)); + desc.back.depthFailOp = static_cast(ToRHIStencilOp(renderState.stencil.back.depthFailOp)); + desc.back.func = static_cast(ToRHIComparisonFunc(renderState.stencil.back.func)); + + return desc; +} + +inline void ApplyRenderState(const Resources::MaterialRenderState& renderState, RHI::GraphicsPipelineDesc& pipelineDesc) { + pipelineDesc.rasterizerState = BuildRasterizerState(renderState); + pipelineDesc.blendState = BuildBlendState(renderState); + pipelineDesc.depthStencilState = BuildDepthStencilState(renderState); +} + +inline void ApplyMaterialRenderState(const Resources::Material* material, RHI::GraphicsPipelineDesc& pipelineDesc) { + ApplyRenderState(ResolveEffectiveRenderState(nullptr, material), pipelineDesc); +} + +inline void ApplyResolvedRenderState( + const Resources::ShaderPass* shaderPass, + const Resources::Material* material, + RHI::GraphicsPipelineDesc& pipelineDesc) { + ApplyRenderState(ResolveEffectiveRenderState(shaderPass, material), pipelineDesc); +} + +inline void ApplyDynamicRenderState( + const Resources::MaterialRenderState& renderState, + RHI::RHICommandList& commandList) { + if (renderState.stencil.enabled) { + commandList.SetStencilRef(renderState.stencil.reference); + } +} + +inline Resources::MaterialRenderState BuildStaticPipelineRenderStateKey( + const Resources::MaterialRenderState& renderState) { + Resources::MaterialRenderState keyState = renderState; + keyState.stencil.reference = 0; + return keyState; +} + +struct MaterialRenderStateHash { + size_t operator()(const Resources::MaterialRenderState& state) const noexcept { + size_t hash = 2166136261u; + auto combine = [&hash](size_t value) { + hash ^= value + 0x9e3779b9u + (hash << 6) + (hash >> 2); + }; + auto combineFloat = [&combine](float value) { + Core::uint32 bits = 0; + std::memcpy(&bits, &value, sizeof(bits)); + combine(static_cast(bits)); + }; + + combine(static_cast(state.blendEnable)); + combine(static_cast(state.srcBlend)); + combine(static_cast(state.dstBlend)); + combine(static_cast(state.srcBlendAlpha)); + combine(static_cast(state.dstBlendAlpha)); + combine(static_cast(state.blendOp)); + combine(static_cast(state.blendOpAlpha)); + combine(static_cast(state.colorWriteMask)); + combine(static_cast(state.depthTestEnable)); + combine(static_cast(state.depthWriteEnable)); + combine(static_cast(state.depthFunc)); + combine(static_cast(state.cullMode)); + combineFloat(state.depthBiasFactor); + combine(static_cast(state.depthBiasUnits)); + combine(static_cast(state.stencil.enabled)); + combine(static_cast(state.stencil.readMask)); + combine(static_cast(state.stencil.writeMask)); + combine(static_cast(state.stencil.reference)); + combine(static_cast(state.stencil.front.failOp)); + combine(static_cast(state.stencil.front.passOp)); + combine(static_cast(state.stencil.front.depthFailOp)); + combine(static_cast(state.stencil.front.func)); + combine(static_cast(state.stencil.back.failOp)); + combine(static_cast(state.stencil.back.passOp)); + combine(static_cast(state.stencil.back.depthFailOp)); + combine(static_cast(state.stencil.back.func)); + return hash; + } +}; + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/Runtime/Rendering/Picking/ObjectIdCodec.h b/engine/Runtime/Rendering/Picking/ObjectIdCodec.h new file mode 100644 index 00000000..105c7d9f --- /dev/null +++ b/engine/Runtime/Rendering/Picking/ObjectIdCodec.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include + +namespace XCEngine { +namespace Rendering { + +using RenderObjectId = Core::uint32; +using EncodedObjectId = RenderObjectId; + +static constexpr RenderObjectId kInvalidRenderObjectId = 0u; + +inline bool IsValidRenderObjectId(RenderObjectId renderObjectId) { + return renderObjectId != kInvalidRenderObjectId; +} + +inline EncodedObjectId EncodeRenderObjectIdToEncodedId(RenderObjectId renderObjectId) { + return renderObjectId; +} + +inline EncodedObjectId EncodeRenderObjectIdToUInt32(RenderObjectId renderObjectId) { + return EncodeRenderObjectIdToEncodedId(renderObjectId); +} + +inline Math::Vector4 EncodeRenderObjectIdToColor(RenderObjectId renderObjectId) { + const EncodedObjectId encodedId = EncodeRenderObjectIdToEncodedId(renderObjectId); + constexpr float kInv255 = 1.0f / 255.0f; + return Math::Vector4( + static_cast((encodedId >> 0) & 0xFFu) * kInv255, + static_cast((encodedId >> 8) & 0xFFu) * kInv255, + static_cast((encodedId >> 16) & 0xFFu) * kInv255, + static_cast((encodedId >> 24) & 0xFFu) * kInv255); +} + +inline EncodedObjectId DecodeEncodedObjectIdFromColor( + Core::uint8 r, + Core::uint8 g, + Core::uint8 b, + Core::uint8 a) { + return static_cast(r) | + (static_cast(g) << 8u) | + (static_cast(b) << 16u) | + (static_cast(a) << 24u); +} + +inline RenderObjectId DecodeRenderObjectIdFromColor( + Core::uint8 r, + Core::uint8 g, + Core::uint8 b, + Core::uint8 a) { + return DecodeEncodedObjectIdFromColor(r, g, b, a); +} + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/src/Rendering/Picking/RenderObjectIdRegistry.cpp b/engine/Runtime/Rendering/Picking/RenderObjectIdRegistry.cpp similarity index 98% rename from engine/src/Rendering/Picking/RenderObjectIdRegistry.cpp rename to engine/Runtime/Rendering/Picking/RenderObjectIdRegistry.cpp index 3563a85a..70c1c6cb 100644 --- a/engine/src/Rendering/Picking/RenderObjectIdRegistry.cpp +++ b/engine/Runtime/Rendering/Picking/RenderObjectIdRegistry.cpp @@ -1,4 +1,4 @@ -#include +#include "engine/Runtime/Rendering/Picking/RenderObjectIdRegistry.h" #include diff --git a/engine/Runtime/Rendering/Picking/RenderObjectIdRegistry.h b/engine/Runtime/Rendering/Picking/RenderObjectIdRegistry.h new file mode 100644 index 00000000..7dde9ac1 --- /dev/null +++ b/engine/Runtime/Rendering/Picking/RenderObjectIdRegistry.h @@ -0,0 +1,48 @@ +#pragma once + +#include + +#include "engine/Runtime/Rendering/Picking/ObjectIdCodec.h" + +#include +#include + +namespace XCEngine { +namespace Rendering { + +class RenderObjectIdRegistry { +public: + static RenderObjectIdRegistry& Get(); + + RenderObjectIdRegistry(const RenderObjectIdRegistry&) = delete; + RenderObjectIdRegistry& operator=(const RenderObjectIdRegistry&) = delete; + + RenderObjectId GetOrAllocateRenderObjectId(Core::uint64 runtimeObjectId); + bool TryGetRenderObjectId( + Core::uint64 runtimeObjectId, + RenderObjectId& outRenderObjectId) const; + bool TryResolveRuntimeObjectId( + RenderObjectId renderObjectId, + Core::uint64& outRuntimeObjectId) const; + Core::uint64 ResolveRuntimeObjectId(RenderObjectId renderObjectId) const; + + void Reset(); + Core::uint64 GetGeneration() const; + +private: + RenderObjectIdRegistry() = default; + + RenderObjectId AllocateRenderObjectIdLocked(); + void BumpGenerationLocked(); + + mutable std::mutex m_mutex = {}; + RenderObjectId m_nextRenderObjectId = 1u; + Core::uint64 m_generation = 1u; + std::unordered_map + m_renderObjectIdByRuntimeObjectId = {}; + std::unordered_map + m_runtimeObjectIdByRenderObjectId = {}; +}; + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/src/Rendering/Shadow/DirectionalShadowData.cpp b/engine/Runtime/Rendering/Shadow/DirectionalShadowData.cpp similarity index 95% rename from engine/src/Rendering/Shadow/DirectionalShadowData.cpp rename to engine/Runtime/Rendering/Shadow/DirectionalShadowData.cpp index 0430cd1a..bd81a7ab 100644 --- a/engine/src/Rendering/Shadow/DirectionalShadowData.cpp +++ b/engine/Runtime/Rendering/Shadow/DirectionalShadowData.cpp @@ -1,4 +1,4 @@ -#include "Rendering/Shadow/DirectionalShadowData.h" +#include "DirectionalShadowData.h" namespace XCEngine { namespace Rendering { diff --git a/engine/Runtime/Rendering/Shadow/DirectionalShadowData.h b/engine/Runtime/Rendering/Shadow/DirectionalShadowData.h new file mode 100644 index 00000000..8a722204 --- /dev/null +++ b/engine/Runtime/Rendering/Shadow/DirectionalShadowData.h @@ -0,0 +1,82 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace XCEngine { +namespace RHI { +class RHIResourceView; +} // namespace RHI + +namespace Rendering { + +struct DirectionalShadowRenderPlan { + bool enabled = false; + Math::Vector3 lightDirection = Math::Vector3::Back(); + Math::Vector3 focusPoint = Math::Vector3::Zero(); + float orthographicHalfExtent = 0.0f; + float texelWorldSize = 0.0f; + float nearClipPlane = 0.1f; + float farClipPlane = 0.0f; + DirectionalShadowSamplingSettings sampling = {}; + DirectionalShadowCasterBiasSettings casterBias = {}; + uint32_t mapWidth = 0; + uint32_t mapHeight = 0; + RenderCameraData cameraData = {}; + + bool IsValid() const { + return enabled && + mapWidth > 0 && + mapHeight > 0 && + cameraData.viewportWidth == mapWidth && + cameraData.viewportHeight == mapHeight; + } +}; + +struct RenderDirectionalShadowMapMetrics { + Math::Vector2 inverseMapSize = Math::Vector2::Zero(); + float worldTexelSize = 0.0f; + float padding = 0.0f; +}; + +static_assert( + sizeof(RenderDirectionalShadowMapMetrics) == sizeof(float) * 4u, + "RenderDirectionalShadowMapMetrics must stay float4-sized for GPU constant layout"); + +struct RenderDirectionalShadowSamplingData { + float enabled = 0.0f; + DirectionalShadowSamplingSettings settings = {}; +}; + +static_assert( + sizeof(RenderDirectionalShadowSamplingData) == sizeof(float) * 4u, + "RenderDirectionalShadowSamplingData must stay float4-sized for GPU constant layout"); + +struct RenderDirectionalShadowCasterBiasData { + DirectionalShadowCasterBiasSettings settings = {}; +}; + +struct RenderDirectionalShadowData { + bool enabled = false; + Math::Matrix4x4 viewProjection = Math::Matrix4x4::Identity(); + RenderDirectionalShadowMapMetrics mapMetrics = {}; + RenderDirectionalShadowSamplingData sampling = {}; + RenderDirectionalShadowCasterBiasData casterBias = {}; + RHI::RHIResourceView* shadowMap = nullptr; + + bool IsValid() const { + return enabled && shadowMap != nullptr; + } +}; + +RenderDirectionalShadowData BuildRenderDirectionalShadowData( + const DirectionalShadowRenderPlan& plan, + RHI::RHIResourceView* shadowMapView); + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/src/Rendering/Shadow/DirectionalShadowRuntime.cpp b/engine/Runtime/Rendering/Shadow/DirectionalShadowRuntime.cpp similarity index 95% rename from engine/src/Rendering/Shadow/DirectionalShadowRuntime.cpp rename to engine/Runtime/Rendering/Shadow/DirectionalShadowRuntime.cpp index 9fedf407..da48ec74 100644 --- a/engine/src/Rendering/Shadow/DirectionalShadowRuntime.cpp +++ b/engine/Runtime/Rendering/Shadow/DirectionalShadowRuntime.cpp @@ -1,6 +1,7 @@ -#include "Rendering/Shadow/DirectionalShadowRuntime.h" +#include "DirectionalShadowRuntime.h" #include "Rendering/Execution/CameraFramePlan.h" + #include namespace XCEngine { diff --git a/engine/Runtime/Rendering/Shadow/DirectionalShadowRuntime.h b/engine/Runtime/Rendering/Shadow/DirectionalShadowRuntime.h new file mode 100644 index 00000000..db69cdf9 --- /dev/null +++ b/engine/Runtime/Rendering/Shadow/DirectionalShadowRuntime.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#include "engine/Runtime/Rendering/Caches/DirectionalShadowSurfaceCache.h" + +namespace XCEngine { +namespace Rendering { + +struct CameraFramePlan; +class RenderPipeline; + +class DirectionalShadowRuntime { +public: + DirectionalShadowRuntime() = default; + DirectionalShadowRuntime(const DirectionalShadowRuntime&) = delete; + DirectionalShadowRuntime& operator=(const DirectionalShadowRuntime&) = delete; + ~DirectionalShadowRuntime() = default; + + bool ResolveExecutionState( + const CameraFramePlan& plan, + const RenderPipeline& pipeline, + DirectionalShadowExecutionState& outShadowState); + +private: + DirectionalShadowSurfaceCache m_surfaceCache; +}; + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/src/Resources/AudioClip/AudioClip.cpp b/engine/Runtime/Resources/AudioClip/AudioClip.cpp similarity index 98% rename from engine/src/Resources/AudioClip/AudioClip.cpp rename to engine/Runtime/Resources/AudioClip/AudioClip.cpp index fce38c2e..7a4bb91c 100644 --- a/engine/src/Resources/AudioClip/AudioClip.cpp +++ b/engine/Runtime/Resources/AudioClip/AudioClip.cpp @@ -1,4 +1,4 @@ -#include +#include "AudioClip.h" namespace XCEngine { namespace Resources { diff --git a/engine/Runtime/Resources/AudioClip/AudioClip.h b/engine/Runtime/Resources/AudioClip/AudioClip.h new file mode 100644 index 00000000..07e3acef --- /dev/null +++ b/engine/Runtime/Resources/AudioClip/AudioClip.h @@ -0,0 +1,105 @@ +#pragma once + +#include +#include +#include +#include + +namespace XCEngine { +namespace Resources { + +enum class AudioFormat : Core::uint8 { + Unknown, + WAV, + OGG, + MP3, + FLAC +}; + +enum class AudioType : Core::uint8 { + SoundEffect, + Music, + Voice, + Ambient +}; + +class AudioClip : public IResource { +public: + AudioClip(); + virtual ~AudioClip() override; + + ResourceType GetType() const override { return ResourceType::AudioClip; } + const Containers::String& GetName() const override { return m_name; } + const Containers::String& GetPath() const override { return m_path; } + ResourceGUID GetGUID() const override { return m_guid; } + bool IsValid() const override { return m_isValid; } + size_t GetMemorySize() const override { return m_memorySize; } + void Release() override; + + void SetPCMData(const Containers::Array& data); + const Containers::Array& GetPCMData() const { return m_pcmData; } + size_t GetPCMDataSize() const { return m_pcmData.Size(); } + + // Legacy compatibility: audio data now means decoded/interpretable PCM bytes. + void SetAudioData(const Containers::Array& data) { SetPCMData(data); } + const Containers::Array& GetAudioData() const { return GetPCMData(); } + + void SetSampleRate(Core::uint32 rate); + Core::uint32 GetSampleRate() const { return m_sampleRate; } + + void SetChannels(Core::uint32 channels); + Core::uint32 GetChannels() const { return m_channels; } + + void SetBitsPerSample(Core::uint32 bits); + Core::uint32 GetBitsPerSample() const { return m_bitsPerSample; } + + void SetDuration(float seconds) { m_duration = seconds; } + float GetDuration() const { return m_duration; } + + const std::vector& GetDecodedPCMData() const; + bool HasDecodedPCMData() const { return m_decodedPCMValid; } + + Core::uint64 GetFrameCount() const; + Core::uint64 GetSampleCount() const; + + void SetAudioFormat(AudioFormat format) { m_format = format; } + AudioFormat GetAudioFormat() const { return m_format; } + + void SetAudioType(AudioType type) { m_audioType = type; } + AudioType GetAudioType() const { return m_audioType; } + + void SetIs3D(bool is3D) { m_is3D = is3D; } + bool Is3D() const { return m_is3D; } + + void SetLoop(bool loop) { m_loop = loop; } + bool IsLoop() const { return m_loop; } + + class IRHIAudioBuffer* GetRHIResource() const { return m_rhiResource; } + void SetRHIResource(class IRHIAudioBuffer* resource); + +private: + void RefreshDerivedData(); + void RefreshMemorySize(); + void InvalidateDecodedPCMData(); + void BuildDecodedPCMData() const; + + Containers::Array m_pcmData; + mutable std::vector m_decodedPCMData; + mutable bool m_decodedPCMValid = false; + + Core::uint32 m_sampleRate = 44100; + Core::uint32 m_channels = 2; + Core::uint32 m_bitsPerSample = 16; + float m_duration = 0.0f; + + AudioFormat m_format = AudioFormat::WAV; + AudioType m_audioType = AudioType::SoundEffect; + + bool m_is3D = false; + bool m_loop = false; + + class IRHIAudioBuffer* m_rhiResource = nullptr; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/AudioClip/AudioLoader.cpp b/engine/Runtime/Resources/AudioClip/AudioLoader.cpp similarity index 97% rename from engine/src/Resources/AudioClip/AudioLoader.cpp rename to engine/Runtime/Resources/AudioClip/AudioLoader.cpp index 86160328..16e9d400 100644 --- a/engine/src/Resources/AudioClip/AudioLoader.cpp +++ b/engine/Runtime/Resources/AudioClip/AudioLoader.cpp @@ -1,6 +1,6 @@ -#include -#include -#include +#include "AudioLoader.h" +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" +#include "engine/Shared/Asset/ResourceType/ResourceTypes.h" #include namespace XCEngine { diff --git a/engine/Runtime/Resources/AudioClip/AudioLoader.h b/engine/Runtime/Resources/AudioClip/AudioLoader.h new file mode 100644 index 00000000..0b08b609 --- /dev/null +++ b/engine/Runtime/Resources/AudioClip/AudioLoader.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include "AudioClip.h" + +namespace XCEngine { +namespace Resources { + +class AudioLoader : public IResourceLoader { +public: + AudioLoader(); + virtual ~AudioLoader() override; + + ResourceType GetResourceType() const override { return ResourceType::AudioClip; } + Containers::Array GetSupportedExtensions() const override; + bool CanLoad(const Containers::String& path) const override; + LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override; + ImportSettings* GetDefaultSettings() const override; + +private: + bool ParseWAVData(const Containers::Array& data, AudioClip* audioClip); + AudioFormat DetectAudioFormat(const Containers::String& path, const Containers::Array& data); +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/Material/Material.cpp b/engine/Runtime/Resources/Material/Material.cpp similarity index 99% rename from engine/src/Resources/Material/Material.cpp rename to engine/Runtime/Resources/Material/Material.cpp index 7b3414de..3cd8ccf3 100644 --- a/engine/src/Resources/Material/Material.cpp +++ b/engine/Runtime/Resources/Material/Material.cpp @@ -1,6 +1,5 @@ -#include -#include -#include +#include "Material.h" +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" #include #include diff --git a/engine/Runtime/Resources/Material/Material.h b/engine/Runtime/Resources/Material/Material.h new file mode 100644 index 00000000..ff7a07b5 --- /dev/null +++ b/engine/Runtime/Resources/Material/Material.h @@ -0,0 +1,221 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "MaterialRenderState.h" +#include "engine/Runtime/Resources/Shader/Shader.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace XCEngine { +namespace RHI { +class RHIBuffer; +} +namespace Resources { + +enum class MaterialRenderQueue : Core::int32 { + Background = 1000, + Geometry = 2000, + AlphaTest = 2450, + Transparent = 3000, + Overlay = 4000 +}; + +enum class MaterialPropertyType { + Float, Float2, Float3, Float4, + Int, Int2, Int3, Int4, + Bool, Texture, Cubemap +}; + +struct MaterialProperty { + Containers::String name; + MaterialPropertyType type; + + union Value { + float floatValue[4]; + Core::int32 intValue[4]; + bool boolValue; + + Value() { memset(this, 0, sizeof(Value)); } + } value; + + Core::uint32 refCount = 0; + + MaterialProperty() : type(MaterialPropertyType::Float), refCount(0) {} +}; + +struct MaterialConstantFieldDesc { + Containers::String name; + MaterialPropertyType type = MaterialPropertyType::Float; + Core::uint32 offset = 0; + Core::uint32 size = 0; + Core::uint32 alignedSize = 0; +}; + +struct MaterialTagEntry { + Containers::String name; + Containers::String value; +}; + +struct PendingTextureLoadState { + IResource* resource = nullptr; + Containers::String errorMessage; + bool completed = false; +}; + +struct MaterialTextureBinding { + Containers::String name; + Core::uint32 slot = 0; + ResourceHandle texture; + AssetRef textureRef; + Containers::String texturePath; + std::shared_ptr pendingLoad; +}; + +struct MaterialBufferBindingViewDesc { + Core::uint32 firstElement = 0; + Core::uint32 elementCount = 0; + Core::uint32 structureByteStride = 0; +}; + +struct MaterialBufferBinding { + Containers::String name; + RHI::RHIBuffer* buffer = nullptr; + MaterialBufferBindingViewDesc viewDesc = {}; +}; + +class Material : public IResource { +public: + Material(); + virtual ~Material() override; + + ResourceType GetType() const override { return ResourceType::Material; } + const Containers::String& GetName() const override { return m_name; } + const Containers::String& GetPath() const override { return m_path; } + ResourceGUID GetGUID() const override { return m_guid; } + bool IsValid() const override { return m_isValid; } + size_t GetMemorySize() const override { return m_memorySize; } + void Release() override; + + void SetShader(const ResourceHandle& shader); + class Shader* GetShader() const { return m_shader.Get(); } + + void SetRenderQueue(Core::int32 renderQueue); + void SetRenderQueue(MaterialRenderQueue renderQueue); + Core::int32 GetRenderQueue() const { return m_renderQueue; } + + void SetRenderState(const MaterialRenderState& renderState); + const MaterialRenderState& GetRenderState() const { return m_renderState; } + bool HasRenderStateOverride() const { return m_hasRenderStateOverride; } + void SetRenderStateOverrideEnabled(bool enabled); + + void SetTag(const Containers::String& name, const Containers::String& value); + Containers::String GetTag(const Containers::String& name) const; + bool HasTag(const Containers::String& name) const; + void RemoveTag(const Containers::String& name); + void ClearTags(); + Core::uint32 GetTagCount() const { return static_cast(m_tags.Size()); } + Containers::String GetTagName(Core::uint32 index) const; + Containers::String GetTagValue(Core::uint32 index) const; + const Containers::Array& GetTags() const { return m_tags; } + + void EnableKeyword(const Containers::String& keyword); + void DisableKeyword(const Containers::String& keyword); + void SetKeywordEnabled(const Containers::String& keyword, bool enabled); + bool IsKeywordEnabled(const Containers::String& keyword) const; + void ClearKeywords(); + Core::uint32 GetKeywordCount() const { return static_cast(m_keywordSet.enabledKeywords.Size()); } + Containers::String GetKeyword(Core::uint32 index) const; + const ShaderKeywordSet& GetKeywordSet() const { return m_keywordSet; } + + void SetFloat(const Containers::String& name, float value); + void SetFloat2(const Containers::String& name, const Math::Vector2& value); + void SetFloat3(const Containers::String& name, const Math::Vector3& value); + void SetFloat4(const Containers::String& name, const Math::Vector4& value); + void SetInt(const Containers::String& name, Core::int32 value); + void SetBool(const Containers::String& name, bool value); + void SetTexture(const Containers::String& name, const ResourceHandle& texture); + void SetBuffer(const Containers::String& name, RHI::RHIBuffer* buffer); + void SetBuffer( + const Containers::String& name, + RHI::RHIBuffer* buffer, + const MaterialBufferBindingViewDesc& viewDesc); + void SetTextureAssetRef(const Containers::String& name, + const AssetRef& textureRef, + const Containers::String& texturePath = Containers::String()); + void SetTexturePath(const Containers::String& name, const Containers::String& texturePath); + + float GetFloat(const Containers::String& name) const; + Math::Vector2 GetFloat2(const Containers::String& name) const; + Math::Vector3 GetFloat3(const Containers::String& name) const; + Math::Vector4 GetFloat4(const Containers::String& name) const; + Core::int32 GetInt(const Containers::String& name) const; + bool GetBool(const Containers::String& name) const; + ResourceHandle GetTexture(const Containers::String& name) const; + RHI::RHIBuffer* GetBuffer(const Containers::String& name) const; + const MaterialBufferBinding* FindBufferBinding(const Containers::String& name) const; + Core::uint32 GetTextureBindingCount() const { return static_cast(m_textureBindings.Size()); } + Core::uint32 GetBufferBindingCount() const { return static_cast(m_bufferBindings.Size()); } + Containers::String GetTextureBindingName(Core::uint32 index) const; + AssetRef GetTextureBindingAssetRef(Core::uint32 index) const; + Containers::String GetTextureBindingPath(Core::uint32 index) const; + ResourceHandle GetTextureBindingLoadedTexture(Core::uint32 index) const; + ResourceHandle GetTextureBindingTexture(Core::uint32 index) const; + const Containers::Array& GetTextureBindings() const { return m_textureBindings; } + const Containers::Array& GetBufferBindings() const { return m_bufferBindings; } + std::vector GetProperties() const; + + const Containers::Array& GetConstantBufferData() const { return m_constantBufferData; } + const Containers::Array& GetConstantLayout() const { return m_constantLayout; } + const MaterialConstantFieldDesc* FindConstantField(const Containers::String& name) const; + void UpdateConstantBuffer(); + Core::uint64 GetChangeVersion() const { return m_changeVersion; } + void RecalculateMemorySize(); + + bool HasProperty(const Containers::String& name) const; + void RemoveProperty(const Containers::String& name); + void ClearAllProperties(); + void RemoveBufferBinding(const Containers::String& name); + void ClearBufferBindings(); + +private: + const ShaderPropertyDesc* FindShaderPropertyDesc(const Containers::String& name) const; + bool CanAssignPropertyType(const Containers::String& name, MaterialPropertyType type) const; + bool ResetPropertyToShaderDefault(const Containers::String& name); + void SyncShaderSchemaProperties(bool removeUnknownProperties); + void SyncShaderRuntimeBufferBindings(bool removeUnknownBindings); + void BeginAsyncTextureLoad(Core::uint32 index); + void ResolvePendingTextureBinding(Core::uint32 index); + void ResolvePendingTextureBindings(); + void MarkChanged(bool updateConstantBuffer); + void UpdateMemorySize(); + void SyncShaderSchemaKeywords(bool removeUnknownKeywords); + + ResourceHandle m_shader; + Core::int32 m_renderQueue = static_cast(MaterialRenderQueue::Geometry); + MaterialRenderState m_renderState; + bool m_hasRenderStateOverride = false; + Containers::Array m_tags; + ShaderKeywordSet m_keywordSet; + Containers::HashMap m_properties; + Containers::Array m_constantLayout; + Containers::Array m_constantBufferData; + Containers::Array m_textureBindings; + Containers::Array m_bufferBindings; + Core::uint64 m_changeVersion = 1; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/Material/MaterialLoader.cpp b/engine/Runtime/Resources/Material/MaterialLoader.cpp similarity index 99% rename from engine/src/Resources/Material/MaterialLoader.cpp rename to engine/Runtime/Resources/Material/MaterialLoader.cpp index 71eca38c..b0176e26 100644 --- a/engine/src/Resources/Material/MaterialLoader.cpp +++ b/engine/Runtime/Resources/Material/MaterialLoader.cpp @@ -1,10 +1,10 @@ -#include -#include +#include "MaterialLoader.h" +#include "engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h" #include #include -#include -#include -#include +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" +#include "engine/Shared/Asset/ResourceType/ResourceTypes.h" +#include "engine/Runtime/Resources/Shader/ShaderLoader.h" #include #include diff --git a/engine/Runtime/Resources/Material/MaterialLoader.h b/engine/Runtime/Resources/Material/MaterialLoader.h new file mode 100644 index 00000000..12b450d0 --- /dev/null +++ b/engine/Runtime/Resources/Material/MaterialLoader.h @@ -0,0 +1,26 @@ +#pragma once + +#include + +#include "Material.h" + +namespace XCEngine { +namespace Resources { + +class MaterialLoader : public IResourceLoader { +public: + MaterialLoader(); + virtual ~MaterialLoader() override; + + ResourceType GetResourceType() const override { return ResourceType::Material; } + Containers::Array GetSupportedExtensions() const override; + bool CanLoad(const Containers::String& path) const override; + LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override; + ImportSettings* GetDefaultSettings() const override; + +private: + bool ParseMaterialData(const Containers::Array& data, Material* material); +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/Runtime/Resources/Material/MaterialRenderState.h b/engine/Runtime/Resources/Material/MaterialRenderState.h new file mode 100644 index 00000000..383c4172 --- /dev/null +++ b/engine/Runtime/Resources/Material/MaterialRenderState.h @@ -0,0 +1,147 @@ +#pragma once + +#include + +namespace XCEngine { +namespace Resources { + +enum class MaterialCullMode : Core::uint8 { + None = 0, + Front = 1, + Back = 2 +}; + +enum class MaterialComparisonFunc : Core::uint8 { + Never = 0, + Less = 1, + Equal = 2, + LessEqual = 3, + Greater = 4, + NotEqual = 5, + GreaterEqual = 6, + Always = 7 +}; + +enum class MaterialBlendOp : Core::uint8 { + Add = 0, + Subtract = 1, + ReverseSubtract = 2, + Min = 3, + Max = 4 +}; + +enum class MaterialBlendFactor : Core::uint8 { + Zero = 0, + One = 1, + SrcColor = 2, + InvSrcColor = 3, + SrcAlpha = 4, + InvSrcAlpha = 5, + DstAlpha = 6, + InvDstAlpha = 7, + DstColor = 8, + InvDstColor = 9, + SrcAlphaSat = 10, + BlendFactor = 11, + InvBlendFactor = 12, + Src1Color = 13, + InvSrc1Color = 14, + Src1Alpha = 15, + InvSrc1Alpha = 16 +}; + +enum class MaterialStencilOp : Core::uint8 { + Keep = 0, + Zero = 1, + Replace = 2, + IncrSat = 3, + DecrSat = 4, + Invert = 5, + IncrWrap = 6, + DecrWrap = 7 +}; + +struct MaterialStencilFaceState { + MaterialStencilOp failOp = MaterialStencilOp::Keep; + MaterialStencilOp passOp = MaterialStencilOp::Keep; + MaterialStencilOp depthFailOp = MaterialStencilOp::Keep; + MaterialComparisonFunc func = MaterialComparisonFunc::Always; + + bool operator==(const MaterialStencilFaceState& other) const { + return failOp == other.failOp && + passOp == other.passOp && + depthFailOp == other.depthFailOp && + func == other.func; + } + + bool operator!=(const MaterialStencilFaceState& other) const { + return !(*this == other); + } +}; + +struct MaterialStencilState { + bool enabled = false; + Core::uint8 readMask = 0xFF; + Core::uint8 writeMask = 0xFF; + Core::uint8 reference = 0; + MaterialStencilFaceState front = {}; + MaterialStencilFaceState back = {}; + + bool operator==(const MaterialStencilState& other) const { + return enabled == other.enabled && + readMask == other.readMask && + writeMask == other.writeMask && + reference == other.reference && + front == other.front && + back == other.back; + } + + bool operator!=(const MaterialStencilState& other) const { + return !(*this == other); + } +}; + +struct MaterialRenderState { + bool blendEnable = false; + MaterialBlendFactor srcBlend = MaterialBlendFactor::One; + MaterialBlendFactor dstBlend = MaterialBlendFactor::Zero; + MaterialBlendFactor srcBlendAlpha = MaterialBlendFactor::One; + MaterialBlendFactor dstBlendAlpha = MaterialBlendFactor::Zero; + MaterialBlendOp blendOp = MaterialBlendOp::Add; + MaterialBlendOp blendOpAlpha = MaterialBlendOp::Add; + Core::uint8 colorWriteMask = 0xF; + + bool depthTestEnable = true; + bool depthWriteEnable = true; + MaterialComparisonFunc depthFunc = MaterialComparisonFunc::Less; + + MaterialCullMode cullMode = MaterialCullMode::None; + float depthBiasFactor = 0.0f; + Core::int32 depthBiasUnits = 0; + MaterialStencilState stencil = {}; + + bool operator==(const MaterialRenderState& other) const { + return blendEnable == other.blendEnable && + srcBlend == other.srcBlend && + dstBlend == other.dstBlend && + srcBlendAlpha == other.srcBlendAlpha && + dstBlendAlpha == other.dstBlendAlpha && + blendOp == other.blendOp && + blendOpAlpha == other.blendOpAlpha && + colorWriteMask == other.colorWriteMask && + depthTestEnable == other.depthTestEnable && + depthWriteEnable == other.depthWriteEnable && + depthFunc == other.depthFunc && + cullMode == other.cullMode && + depthBiasFactor == other.depthBiasFactor && + depthBiasUnits == other.depthBiasUnits && + stencil == other.stencil; + } + + bool operator!=(const MaterialRenderState& other) const { + return !(*this == other); + } +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/Mesh/Mesh.cpp b/engine/Runtime/Resources/Mesh/Mesh.cpp similarity index 95% rename from engine/src/Resources/Mesh/Mesh.cpp rename to engine/Runtime/Resources/Mesh/Mesh.cpp index 0896282b..ff9c5c3b 100644 --- a/engine/src/Resources/Mesh/Mesh.cpp +++ b/engine/Runtime/Resources/Mesh/Mesh.cpp @@ -1,6 +1,6 @@ -#include -#include -#include +#include "Mesh.h" +#include "engine/Runtime/Resources/Material/Material.h" +#include "engine/Runtime/Resources/Texture/Texture.h" #include #include diff --git a/engine/Runtime/Resources/Mesh/Mesh.h b/engine/Runtime/Resources/Mesh/Mesh.h new file mode 100644 index 00000000..4e1dcb48 --- /dev/null +++ b/engine/Runtime/Resources/Mesh/Mesh.h @@ -0,0 +1,112 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace XCEngine { +namespace Resources { + +class Material; +class Texture; + +enum class VertexAttribute : Core::uint32 { + Position = 1 << 0, Normal = 1 << 1, Tangent = 1 << 2, + Color = 1 << 3, UV0 = 1 << 4, UV1 = 1 << 5, + UV2 = 1 << 6, UV3 = 1 << 7, BoneWeights = 1 << 8, BoneIndices = 1 << 9, + Bitangent = 1 << 10 +}; + +inline VertexAttribute operator|(VertexAttribute a, VertexAttribute b) { + return static_cast(static_cast(a) | static_cast(b)); +} + +inline VertexAttribute operator&(VertexAttribute a, VertexAttribute b) { + return static_cast(static_cast(a) & static_cast(b)); +} + +inline bool HasVertexAttribute(VertexAttribute attributes, VertexAttribute flag) { + return (static_cast(attributes) & static_cast(flag)) != 0; +} + +struct StaticMeshVertex { + Math::Vector3 position = Math::Vector3::Zero(); + Math::Vector3 normal = Math::Vector3::Zero(); + Math::Vector3 tangent = Math::Vector3::Zero(); + Math::Vector3 bitangent = Math::Vector3::Zero(); + Math::Vector2 uv0 = Math::Vector2::Zero(); + Math::Vector2 uv1 = Math::Vector2::Zero(); + Math::Vector4 color = Math::Vector4::One(); +}; + +struct MeshSection { + Core::uint32 baseVertex; + Core::uint32 vertexCount; + Core::uint32 startIndex; + Core::uint32 indexCount; + Core::uint32 materialID; + Math::Bounds bounds; +}; + +class Mesh : public IResource { +public: + Mesh(); + virtual ~Mesh() override; + + ResourceType GetType() const override { return ResourceType::Mesh; } + const Containers::String& GetName() const override { return m_name; } + const Containers::String& GetPath() const override { return m_path; } + ResourceGUID GetGUID() const override { return m_guid; } + bool IsValid() const override { return m_isValid; } + size_t GetMemorySize() const override { return m_memorySize; } + void Release() override; + + void SetVertexData(const void* data, size_t size, Core::uint32 vertexCount, + Core::uint32 vertexStride, VertexAttribute attributes); + const void* GetVertexData() const { return m_vertexData.Data(); } + size_t GetVertexDataSize() const { return m_vertexData.Size(); } + Core::uint32 GetVertexCount() const { return m_vertexCount; } + Core::uint32 GetVertexStride() const { return m_vertexStride; } + VertexAttribute GetVertexAttributes() const { return m_attributes; } + + void SetIndexData(const void* data, size_t size, Core::uint32 indexCount, bool use32Bit); + const void* GetIndexData() const { return m_indexData.Data(); } + size_t GetIndexDataSize() const { return m_indexData.Size(); } + Core::uint32 GetIndexCount() const { return m_indexCount; } + bool IsUse32BitIndex() const { return m_use32BitIndex; } + + void SetBounds(const Math::Bounds& bounds) { m_bounds = bounds; } + const Math::Bounds& GetBounds() const { return m_bounds; } + + void AddSection(const MeshSection& section); + void AddMaterial(Material* material); + void AddTexture(Texture* texture); + const Containers::Array& GetSections() const { return m_sections; } + const Containers::Array& GetMaterials() const { return m_materials; } + const Containers::Array& GetTextures() const { return m_textures; } + Material* GetMaterial(Core::uint32 index) const; + +private: + void UpdateMemorySize(); + + Core::uint32 m_vertexCount = 0; + Core::uint32 m_vertexStride = 0; + VertexAttribute m_attributes = VertexAttribute::Position; + + Core::uint32 m_indexCount = 0; + bool m_use32BitIndex = false; + + Containers::Array m_vertexData; + Containers::Array m_indexData; + Containers::Array m_sections; + Containers::Array m_materials; + Containers::Array m_textures; + Math::Bounds m_bounds; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/Mesh/MeshImportSettings.cpp b/engine/Runtime/Resources/Mesh/MeshImportSettings.cpp similarity index 98% rename from engine/src/Resources/Mesh/MeshImportSettings.cpp rename to engine/Runtime/Resources/Mesh/MeshImportSettings.cpp index 97426dd1..856d5900 100644 --- a/engine/src/Resources/Mesh/MeshImportSettings.cpp +++ b/engine/Runtime/Resources/Mesh/MeshImportSettings.cpp @@ -1,4 +1,4 @@ -#include +#include "MeshImportSettings.h" #include #include #include diff --git a/engine/Runtime/Resources/Mesh/MeshImportSettings.h b/engine/Runtime/Resources/Mesh/MeshImportSettings.h new file mode 100644 index 00000000..39d4d7ef --- /dev/null +++ b/engine/Runtime/Resources/Mesh/MeshImportSettings.h @@ -0,0 +1,85 @@ +#pragma once + +#include +#include "Mesh.h" +#include + +namespace XCEngine { +namespace Resources { + +enum class MeshImportFlags : Core::uint32 { + None = 0, + FlipUVs = 1 << 0, + FlipWindingOrder = 1 << 1, + GenerateNormals = 1 << 2, + GenerateTangents = 1 << 3, + OptimizeMesh = 1 << 4, + ImportSkinning = 1 << 5, + ImportAnimations = 1 << 6, + ImportMaterials = 1 << 7, + ImportCameras = 1 << 8, + ImportLights = 1 << 9 +}; + +inline MeshImportFlags operator|(MeshImportFlags a, MeshImportFlags b) { + return static_cast(static_cast(a) | static_cast(b)); +} + +inline MeshImportFlags operator&(MeshImportFlags a, MeshImportFlags b) { + return static_cast(static_cast(a) & static_cast(b)); +} + +inline MeshImportFlags operator~(MeshImportFlags a) { + return static_cast(~static_cast(a)); +} + +class MeshImportSettings : public ImportSettings { +public: + MeshImportSettings(); + virtual ~MeshImportSettings() override; + + Core::UniqueRef Clone() const override; + bool LoadFromJSON(const Containers::String& json) override; + Containers::String SaveToJSON() const override; + + void SetImportFlags(MeshImportFlags flags) { m_importFlags = flags; } + MeshImportFlags GetImportFlags() const { return m_importFlags; } + + void AddImportFlag(MeshImportFlags flag) { m_importFlags = static_cast(static_cast(m_importFlags) | static_cast(flag)); } + void RemoveImportFlag(MeshImportFlags flag) { m_importFlags = static_cast(static_cast(m_importFlags) & ~static_cast(flag)); } + bool HasImportFlag(MeshImportFlags flag) const { return (static_cast(m_importFlags) & static_cast(flag)) != 0; } + + void SetScale(float scale) { m_scale = scale; } + float GetScale() const { return m_scale; } + + void SetOffset(const Math::Vector3& offset) { m_offset = offset; } + const Math::Vector3& GetOffset() const { return m_offset; } + + void SetAxisConversion(bool convert) { m_axisConversion = convert; } + bool GetAxisConversion() const { return m_axisConversion; } + + void SetMergeMeshes(bool merge) { m_mergeMeshes = merge; } + bool GetMergeMeshes() const { return m_mergeMeshes; } + + void SetOptimizeThreshold(float threshold) { m_optimizeThreshold = threshold; } + float GetOptimizeThreshold() const { return m_optimizeThreshold; } + + void SetImportScale(float scale) { m_importScale = scale; } + float GetImportScale() const { return m_importScale; } + + void SetThreshold(float threshold) { m_threshold = threshold; } + float GetThreshold() const { return m_threshold; } + +private: + MeshImportFlags m_importFlags = MeshImportFlags::ImportMaterials; + float m_scale = 1.0f; + Math::Vector3 m_offset = Math::Vector3::Zero(); + bool m_axisConversion = true; + bool m_mergeMeshes = false; + float m_optimizeThreshold = 0.3f; + float m_importScale = 1.0f; + float m_threshold = 0.0f; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/Mesh/MeshLoader.cpp b/engine/Runtime/Resources/Mesh/MeshLoader.cpp similarity index 98% rename from engine/src/Resources/Mesh/MeshLoader.cpp rename to engine/Runtime/Resources/Mesh/MeshLoader.cpp index 5401f103..b331e67b 100644 --- a/engine/src/Resources/Mesh/MeshLoader.cpp +++ b/engine/Runtime/Resources/Mesh/MeshLoader.cpp @@ -1,15 +1,15 @@ -#include -#include +#include "MeshLoader.h" +#include "engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h" #include #include -#include -#include -#include -#include +#include "engine/Runtime/Resources/Material/MaterialLoader.h" +#include "MeshImportSettings.h" +#include "engine/Runtime/Resources/Material/Material.h" +#include "engine/Runtime/Resources/Texture/Texture.h" #include -#include -#include -#include +#include "engine/Runtime/Resources/Texture/TextureLoader.h" +#include "engine/Runtime/Resources/Texture/TextureImportSettings.h" +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" #include #include #include diff --git a/engine/Runtime/Resources/Mesh/MeshLoader.h b/engine/Runtime/Resources/Mesh/MeshLoader.h new file mode 100644 index 00000000..566ba492 --- /dev/null +++ b/engine/Runtime/Resources/Mesh/MeshLoader.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include "Mesh.h" + +namespace XCEngine { +namespace Resources { + +class MeshLoader : public IResourceLoader { +public: + MeshLoader(); + virtual ~MeshLoader() override; + + ResourceType GetResourceType() const override { return ResourceType::Mesh; } + Containers::Array GetSupportedExtensions() const override; + bool CanLoad(const Containers::String& path) const override; + LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override; + ImportSettings* GetDefaultSettings() const override; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/Shader/Internal/ShaderArtifactLoader.cpp b/engine/Runtime/Resources/Shader/Internal/ShaderArtifactLoader.cpp similarity index 100% rename from engine/src/Resources/Shader/Internal/ShaderArtifactLoader.cpp rename to engine/Runtime/Resources/Shader/Internal/ShaderArtifactLoader.cpp diff --git a/engine/src/Resources/Shader/Internal/ShaderArtifactLoader.h b/engine/Runtime/Resources/Shader/Internal/ShaderArtifactLoader.h similarity index 100% rename from engine/src/Resources/Shader/Internal/ShaderArtifactLoader.h rename to engine/Runtime/Resources/Shader/Internal/ShaderArtifactLoader.h diff --git a/engine/src/Resources/Shader/Internal/ShaderAuthoringDirectiveUtils.cpp b/engine/Runtime/Resources/Shader/Internal/ShaderAuthoringDirectiveUtils.cpp similarity index 100% rename from engine/src/Resources/Shader/Internal/ShaderAuthoringDirectiveUtils.cpp rename to engine/Runtime/Resources/Shader/Internal/ShaderAuthoringDirectiveUtils.cpp diff --git a/engine/src/Resources/Shader/Internal/ShaderAuthoringInternal.h b/engine/Runtime/Resources/Shader/Internal/ShaderAuthoringInternal.h similarity index 100% rename from engine/src/Resources/Shader/Internal/ShaderAuthoringInternal.h rename to engine/Runtime/Resources/Shader/Internal/ShaderAuthoringInternal.h diff --git a/engine/src/Resources/Shader/Internal/ShaderAuthoringLoader.cpp b/engine/Runtime/Resources/Shader/Internal/ShaderAuthoringLoader.cpp similarity index 100% rename from engine/src/Resources/Shader/Internal/ShaderAuthoringLoader.cpp rename to engine/Runtime/Resources/Shader/Internal/ShaderAuthoringLoader.cpp diff --git a/engine/src/Resources/Shader/Internal/ShaderAuthoringLoader.h b/engine/Runtime/Resources/Shader/Internal/ShaderAuthoringLoader.h similarity index 100% rename from engine/src/Resources/Shader/Internal/ShaderAuthoringLoader.h rename to engine/Runtime/Resources/Shader/Internal/ShaderAuthoringLoader.h diff --git a/engine/src/Resources/Shader/Internal/ShaderAuthoringParserCore.cpp b/engine/Runtime/Resources/Shader/Internal/ShaderAuthoringParserCore.cpp similarity index 100% rename from engine/src/Resources/Shader/Internal/ShaderAuthoringParserCore.cpp rename to engine/Runtime/Resources/Shader/Internal/ShaderAuthoringParserCore.cpp diff --git a/engine/src/Resources/Shader/Internal/ShaderAuthoringShared.cpp b/engine/Runtime/Resources/Shader/Internal/ShaderAuthoringShared.cpp similarity index 100% rename from engine/src/Resources/Shader/Internal/ShaderAuthoringShared.cpp rename to engine/Runtime/Resources/Shader/Internal/ShaderAuthoringShared.cpp diff --git a/engine/src/Resources/Shader/Internal/ShaderAuthoringTextUtils.cpp b/engine/Runtime/Resources/Shader/Internal/ShaderAuthoringTextUtils.cpp similarity index 100% rename from engine/src/Resources/Shader/Internal/ShaderAuthoringTextUtils.cpp rename to engine/Runtime/Resources/Shader/Internal/ShaderAuthoringTextUtils.cpp diff --git a/engine/src/Resources/Shader/Internal/ShaderFileUtils.cpp b/engine/Runtime/Resources/Shader/Internal/ShaderFileUtils.cpp similarity index 95% rename from engine/src/Resources/Shader/Internal/ShaderFileUtils.cpp rename to engine/Runtime/Resources/Shader/Internal/ShaderFileUtils.cpp index 05d4b5e5..05263d0c 100644 --- a/engine/src/Resources/Shader/Internal/ShaderFileUtils.cpp +++ b/engine/Runtime/Resources/Shader/Internal/ShaderFileUtils.cpp @@ -1,7 +1,7 @@ #include "ShaderFileUtils.h" -#include -#include +#include "engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h" +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" #include #include diff --git a/engine/src/Resources/Shader/Internal/ShaderFileUtils.h b/engine/Runtime/Resources/Shader/Internal/ShaderFileUtils.h similarity index 93% rename from engine/src/Resources/Shader/Internal/ShaderFileUtils.h rename to engine/Runtime/Resources/Shader/Internal/ShaderFileUtils.h index fc078bc3..f3228b8f 100644 --- a/engine/src/Resources/Shader/Internal/ShaderFileUtils.h +++ b/engine/Runtime/Resources/Shader/Internal/ShaderFileUtils.h @@ -3,7 +3,7 @@ #include #include #include -#include +#include "../Shader.h" #include diff --git a/engine/src/Resources/Shader/Internal/ShaderRuntimeBuildUtils.cpp b/engine/Runtime/Resources/Shader/Internal/ShaderRuntimeBuildUtils.cpp similarity index 99% rename from engine/src/Resources/Shader/Internal/ShaderRuntimeBuildUtils.cpp rename to engine/Runtime/Resources/Shader/Internal/ShaderRuntimeBuildUtils.cpp index 4ad70347..5ac392fe 100644 --- a/engine/src/Resources/Shader/Internal/ShaderRuntimeBuildUtils.cpp +++ b/engine/Runtime/Resources/Shader/Internal/ShaderRuntimeBuildUtils.cpp @@ -5,10 +5,10 @@ #include "ShaderAuthoringInternal.h" #include "ShaderFileUtils.h" -#include +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" #include #include -#include +#include "../ShaderLoader.h" #include #include diff --git a/engine/src/Resources/Shader/Internal/ShaderRuntimeBuildUtils.h b/engine/Runtime/Resources/Shader/Internal/ShaderRuntimeBuildUtils.h similarity index 94% rename from engine/src/Resources/Shader/Internal/ShaderRuntimeBuildUtils.h rename to engine/Runtime/Resources/Shader/Internal/ShaderRuntimeBuildUtils.h index a37b346c..8d9a11db 100644 --- a/engine/src/Resources/Shader/Internal/ShaderRuntimeBuildUtils.h +++ b/engine/Runtime/Resources/Shader/Internal/ShaderRuntimeBuildUtils.h @@ -3,7 +3,8 @@ #include "../ShaderIR.h" #include -#include + +#include "../Shader.h" #include diff --git a/engine/src/Resources/Shader/Shader.cpp b/engine/Runtime/Resources/Shader/Shader.cpp similarity index 99% rename from engine/src/Resources/Shader/Shader.cpp rename to engine/Runtime/Resources/Shader/Shader.cpp index c41c8864..5a002ab4 100644 --- a/engine/src/Resources/Shader/Shader.cpp +++ b/engine/Runtime/Resources/Shader/Shader.cpp @@ -1,4 +1,4 @@ -#include +#include "Shader.h" #include diff --git a/engine/Runtime/Resources/Shader/Shader.h b/engine/Runtime/Resources/Shader/Shader.h new file mode 100644 index 00000000..e75ddca8 --- /dev/null +++ b/engine/Runtime/Resources/Shader/Shader.h @@ -0,0 +1,201 @@ +#pragma once + +#include +#include +#include +#include + +#include "engine/Runtime/Resources/Material/MaterialRenderState.h" + +namespace XCEngine { +namespace Resources { + +enum class ShaderType : Core::uint8 { + Vertex, + Fragment, + Geometry, + Compute, + Hull, + Domain +}; + +enum class ShaderLanguage : Core::uint8 { + GLSL, + HLSL, + SPIRV +}; + +enum class ShaderBackend : Core::uint8 { + Generic = 0, + D3D12, + OpenGL, + Vulkan +}; + +enum class ShaderPropertyType : Core::uint8 { + Float = 0, + Range, + Int, + Vector, + Color, + Texture2D, + TextureCube +}; + +enum class ShaderResourceType : Core::uint8 { + ConstantBuffer = 0, + Texture2D, + TextureCube, + Sampler, + StructuredBuffer, + RawBuffer, + RWStructuredBuffer, + RWRawBuffer +}; + +struct ShaderUniform { + Containers::String name; + Core::uint32 location; + Core::uint32 size; + Core::uint32 type; +}; + +struct ShaderAttribute { + Containers::String name; + Core::uint32 location; + Core::uint32 size; + Core::uint32 type; +}; + +struct ShaderPassTagEntry { + Containers::String name; + Containers::String value; +}; + +struct ShaderPropertyDesc { + Containers::String name; + Containers::String displayName; + ShaderPropertyType type = ShaderPropertyType::Float; + Containers::String defaultValue; + Containers::String semantic; +}; + +struct ShaderResourceBindingDesc { + Containers::String name; + ShaderResourceType type = ShaderResourceType::ConstantBuffer; + Core::uint32 set = 0; + Core::uint32 binding = 0; + Containers::String semantic; +}; + +struct ShaderBackendCompiledBinary { + ShaderBackend backend = ShaderBackend::Generic; + Containers::Array payload; +}; + +struct ShaderStageVariant { + ShaderType stage = ShaderType::Fragment; + ShaderLanguage language = ShaderLanguage::GLSL; + ShaderBackend backend = ShaderBackend::Generic; + ShaderKeywordSet requiredKeywords; + Containers::String entryPoint; + Containers::String profile; + Containers::String sourceCode; + Containers::Array compiledBinary; + Containers::Array backendCompiledBinaries; + + const Containers::Array* GetCompiledBinaryForBackend( + ShaderBackend targetBackend) const; + void SetCompiledBinaryForBackend( + ShaderBackend targetBackend, + const Containers::Array& binary); + void SetCompiledBinaryForBackend( + ShaderBackend targetBackend, + Containers::Array&& binary); +}; + +struct ShaderPass { + Containers::String name; + bool hasFixedFunctionState = false; + MaterialRenderState fixedFunctionState; + Containers::Array tags; + Containers::Array resources; + Containers::Array keywordDeclarations; + Containers::Array variants; +}; + +class Shader : public IResource { +public: + Shader(); + virtual ~Shader() override; + + ResourceType GetType() const override { return ResourceType::Shader; } + const Containers::String& GetName() const override { return m_name; } + const Containers::String& GetPath() const override { return m_path; } + ResourceGUID GetGUID() const override { return m_guid; } + bool IsValid() const override { return m_isValid; } + size_t GetMemorySize() const override { return m_memorySize; } + void Release() override; + + void AddUniform(const ShaderUniform& uniform); + const Containers::Array& GetUniforms() const { return m_uniforms; } + + void AddAttribute(const ShaderAttribute& attribute); + const Containers::Array& GetAttributes() const { return m_attributes; } + + void AddProperty(const ShaderPropertyDesc& property); + void ClearProperties(); + const Containers::Array& GetProperties() const { return m_properties; } + const ShaderPropertyDesc* FindProperty(const Containers::String& propertyName) const; + void SetFallback(const Containers::String& fallback); + const Containers::String& GetFallback() const { return m_fallback; } + + void AddPass(const ShaderPass& pass); + void ClearPasses(); + Core::uint32 GetPassCount() const { return static_cast(m_passes.Size()); } + const Containers::Array& GetPasses() const { return m_passes; } + + void AddPassVariant(const Containers::String& passName, const ShaderStageVariant& variant); + void SetPassTag( + const Containers::String& passName, + const Containers::String& tagName, + const Containers::String& tagValue); + void AddPassResourceBinding( + const Containers::String& passName, + const ShaderResourceBindingDesc& binding); + void AddPassKeywordDeclaration( + const Containers::String& passName, + const ShaderKeywordDeclaration& declaration); + bool HasPass(const Containers::String& passName) const; + const ShaderPass* FindPass(const Containers::String& passName) const; + ShaderPass* FindPass(const Containers::String& passName); + bool PassDeclaresKeyword( + const Containers::String& passName, + const Containers::String& keyword) const; + bool DeclaresKeyword(const Containers::String& keyword) const; + const ShaderResourceBindingDesc* FindPassResourceBinding( + const Containers::String& passName, + const Containers::String& resourceName) const; + const ShaderStageVariant* FindVariant( + const Containers::String& passName, + ShaderType stage, + ShaderBackend backend = ShaderBackend::Generic, + const ShaderKeywordSet& enabledKeywords = ShaderKeywordSet()) const; + + class IRHIShader* GetRHIResource() const { return m_rhiResource; } + void SetRHIResource(class IRHIShader* resource); + +private: + ShaderPass& GetOrCreatePass(const Containers::String& passName); + + Containers::Array m_uniforms; + Containers::Array m_attributes; + Containers::Array m_properties; + Containers::Array m_passes; + Containers::String m_fallback; + + class IRHIShader* m_rhiResource = nullptr; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/Shader/ShaderAuthoringParser.cpp b/engine/Runtime/Resources/Shader/ShaderAuthoringParser.cpp similarity index 100% rename from engine/src/Resources/Shader/ShaderAuthoringParser.cpp rename to engine/Runtime/Resources/Shader/ShaderAuthoringParser.cpp diff --git a/engine/src/Resources/Shader/ShaderAuthoringParser.h b/engine/Runtime/Resources/Shader/ShaderAuthoringParser.h similarity index 100% rename from engine/src/Resources/Shader/ShaderAuthoringParser.h rename to engine/Runtime/Resources/Shader/ShaderAuthoringParser.h diff --git a/engine/src/Resources/Shader/ShaderCompilationCache.cpp b/engine/Runtime/Resources/Shader/ShaderCompilationCache.cpp similarity index 96% rename from engine/src/Resources/Shader/ShaderCompilationCache.cpp rename to engine/Runtime/Resources/Shader/ShaderCompilationCache.cpp index 21a5da15..c7c4a7df 100644 --- a/engine/src/Resources/Shader/ShaderCompilationCache.cpp +++ b/engine/Runtime/Resources/Shader/ShaderCompilationCache.cpp @@ -1,4 +1,4 @@ -#include +#include "ShaderCompilationCache.h" #include #include @@ -246,8 +246,9 @@ void ShaderCompilationCache::SaveDatabase() const { } } -bool ShaderCompilationCache::Store(const ShaderCacheEntry& entry, - Containers::String* outErrorMessage) { +bool ShaderCompilationCache::Store( + const ShaderCacheEntry& entry, + Containers::String* outErrorMessage) { if (!IsInitialized()) { if (outErrorMessage != nullptr) { *outErrorMessage = MakeError("ShaderCompilationCache is not initialized."); @@ -319,9 +320,10 @@ bool ShaderCompilationCache::Store(const ShaderCacheEntry& entry, return true; } -bool ShaderCompilationCache::TryLoad(const ShaderCompileKey& key, - ShaderCacheEntry& outEntry, - Containers::String* outErrorMessage) const { +bool ShaderCompilationCache::TryLoad( + const ShaderCompileKey& key, + ShaderCacheEntry& outEntry, + Containers::String* outErrorMessage) const { outEntry = {}; if (!IsInitialized()) { if (outErrorMessage != nullptr) { diff --git a/engine/Runtime/Resources/Shader/ShaderCompilationCache.h b/engine/Runtime/Resources/Shader/ShaderCompilationCache.h new file mode 100644 index 00000000..e4630fe0 --- /dev/null +++ b/engine/Runtime/Resources/Shader/ShaderCompilationCache.h @@ -0,0 +1,92 @@ +#pragma once + +#include +#include +#include +#include + +#include "Shader.h" + +#include + +namespace XCEngine { +namespace Resources { + +constexpr Core::uint32 kShaderCompilationCacheSchemaVersion = 1; + +enum class ShaderBytecodeFormat : Core::uint32 { + Unknown = 0, + DXIL, + DXBC, + SPIRV, + GLSLSource, + OpenGLProgramBinary +}; + +struct ShaderCompileKey { + Containers::String shaderPath; + Containers::String sourceHash; + Containers::String dependencyHash; + Containers::String passName; + Containers::String entryPoint; + Containers::String profile; + Containers::String compilerName; + Containers::String compilerVersion; + Containers::String optionsSignature; + ShaderType stage = ShaderType::Fragment; + ShaderLanguage sourceLanguage = ShaderLanguage::HLSL; + ShaderBackend backend = ShaderBackend::Generic; + Containers::Array keywords; + + void Normalize(); + Containers::String BuildSignature() const; + Containers::String BuildCacheKey() const; +}; + +struct ShaderCacheEntry { + ShaderCompileKey key; + ShaderBytecodeFormat format = ShaderBytecodeFormat::Unknown; + Containers::Array payload; +}; + +class ShaderCompilationCache { +public: + void Initialize(const Containers::String& libraryRoot); + void Shutdown(); + + bool IsInitialized() const { return !m_libraryRoot.Empty(); } + const Containers::String& GetLibraryRoot() const { return m_libraryRoot; } + const Containers::String& GetDatabasePath() const { return m_databasePath; } + Core::uint32 GetRecordCount() const { return static_cast(m_records.size()); } + + Containers::String BuildCacheKey(const ShaderCompileKey& key) const; + Containers::String BuildCacheRelativePath(const ShaderCompileKey& key) const; + Containers::String BuildCacheAbsolutePath(const ShaderCompileKey& key) const; + + bool Store(const ShaderCacheEntry& entry, + Containers::String* outErrorMessage = nullptr); + bool TryLoad(const ShaderCompileKey& key, + ShaderCacheEntry& outEntry, + Containers::String* outErrorMessage = nullptr) const; + +private: + struct ShaderCacheRecord { + ShaderBackend backend = ShaderBackend::Generic; + ShaderBytecodeFormat format = ShaderBytecodeFormat::Unknown; + Containers::String relativePath; + Core::uint64 payloadSize = 0; + }; + + void LoadDatabase(); + void SaveDatabase() const; + + static Containers::String BuildBackendDirectoryName(ShaderBackend backend); + static AssetGUID ComputeKeyGuid(const Containers::String& cacheKey); + + Containers::String m_libraryRoot; + Containers::String m_databasePath; + std::unordered_map m_records; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/Shader/ShaderIR.h b/engine/Runtime/Resources/Shader/ShaderIR.h similarity index 96% rename from engine/src/Resources/Shader/ShaderIR.h rename to engine/Runtime/Resources/Shader/ShaderIR.h index 7b9a9746..2594572f 100644 --- a/engine/src/Resources/Shader/ShaderIR.h +++ b/engine/Runtime/Resources/Shader/ShaderIR.h @@ -2,7 +2,8 @@ #include #include -#include + +#include "Shader.h" #include diff --git a/engine/src/Resources/Shader/ShaderLoader.cpp b/engine/Runtime/Resources/Shader/ShaderLoader.cpp similarity index 92% rename from engine/src/Resources/Shader/ShaderLoader.cpp rename to engine/Runtime/Resources/Shader/ShaderLoader.cpp index 61d6e2ef..0894b4c8 100644 --- a/engine/src/Resources/Shader/ShaderLoader.cpp +++ b/engine/Runtime/Resources/Shader/ShaderLoader.cpp @@ -1,12 +1,12 @@ -#include +#include "ShaderLoader.h" #include "Internal/ShaderArtifactLoader.h" #include "Internal/ShaderAuthoringLoader.h" -#include "ShaderAuthoringParser.h" #include "Internal/ShaderFileUtils.h" #include "Internal/ShaderRuntimeBuildUtils.h" +#include "ShaderAuthoringParser.h" -#include +#include "engine/Shared/Asset/ResourceType/ResourceTypes.h" #include #include @@ -30,7 +30,7 @@ bool ShaderLoader::CanLoad(const Containers::String& path) const { return true; } - const Containers::String ext = GetExtension(path).ToLower(); + const Containers::String ext = GetShaderPathExtension(path).ToLower(); return ext == "shader" || ext == "xcshader"; } @@ -112,7 +112,9 @@ bool ShaderLoader::CollectSourceDependencies( return CollectShaderAuthoringDependencyPaths(path, sourceText, outDependencies, outError); } -ShaderType ShaderLoader::DetectShaderType(const Containers::String& path, const Containers::String& source) { +ShaderType ShaderLoader::DetectShaderType( + const Containers::String& path, + const Containers::String& source) { (void)source; return DetectShaderTypeFromPath(path); } diff --git a/engine/Runtime/Resources/Shader/ShaderLoader.h b/engine/Runtime/Resources/Shader/ShaderLoader.h new file mode 100644 index 00000000..a45f7929 --- /dev/null +++ b/engine/Runtime/Resources/Shader/ShaderLoader.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +#include "Shader.h" + +namespace XCEngine { +namespace Resources { + +class ShaderLoader : public IResourceLoader { +public: + ShaderLoader(); + virtual ~ShaderLoader() override; + + ResourceType GetResourceType() const override { return ResourceType::Shader; } + Containers::Array GetSupportedExtensions() const override; + bool CanLoad(const Containers::String& path) const override; + LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override; + ImportSettings* GetDefaultSettings() const override; + bool CollectSourceDependencies(const Containers::String& path, + Containers::Array& outDependencies) const; + bool CollectSourceDependencies(const Containers::String& path, + Containers::Array& outDependencies, + Containers::String* outError) const; + +private: + ShaderType DetectShaderType(const Containers::String& path, const Containers::String& source); + bool ParseShaderSource(const Containers::String& source, Shader* shader); +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/Shader/ShaderSourceUtils.cpp b/engine/Runtime/Resources/Shader/ShaderSourceUtils.cpp similarity index 99% rename from engine/src/Resources/Shader/ShaderSourceUtils.cpp rename to engine/Runtime/Resources/Shader/ShaderSourceUtils.cpp index 1f2d30b0..c1b9a73b 100644 --- a/engine/src/Resources/Shader/ShaderSourceUtils.cpp +++ b/engine/Runtime/Resources/Shader/ShaderSourceUtils.cpp @@ -1,6 +1,6 @@ #include "ShaderSourceUtils.h" -#include +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" #include #include diff --git a/engine/src/Resources/Shader/ShaderSourceUtils.h b/engine/Runtime/Resources/Shader/ShaderSourceUtils.h similarity index 96% rename from engine/src/Resources/Shader/ShaderSourceUtils.h rename to engine/Runtime/Resources/Shader/ShaderSourceUtils.h index a230fefa..d329e52d 100644 --- a/engine/src/Resources/Shader/ShaderSourceUtils.h +++ b/engine/Runtime/Resources/Shader/ShaderSourceUtils.h @@ -1,7 +1,8 @@ #pragma once #include -#include + +#include "Shader.h" #include diff --git a/engine/src/Resources/Texture/Texture.cpp b/engine/Runtime/Resources/Texture/Texture.cpp similarity index 95% rename from engine/src/Resources/Texture/Texture.cpp rename to engine/Runtime/Resources/Texture/Texture.cpp index b07b3db2..e4103656 100644 --- a/engine/src/Resources/Texture/Texture.cpp +++ b/engine/Runtime/Resources/Texture/Texture.cpp @@ -1,4 +1,4 @@ -#include +#include "Texture.h" #include namespace XCEngine { diff --git a/engine/Runtime/Resources/Texture/Texture.h b/engine/Runtime/Resources/Texture/Texture.h new file mode 100644 index 00000000..18959ab4 --- /dev/null +++ b/engine/Runtime/Resources/Texture/Texture.h @@ -0,0 +1,73 @@ +#pragma once + +#include +#include + +namespace XCEngine { +namespace Resources { + +enum class TextureType { + Texture2D, Texture3D, TextureCube, Texture2DArray, TextureCubeArray +}; + +enum class TextureFormat { + Unknown, R8_UNORM, RG8_UNORM, RGBA8_UNORM, RGBA8_SRGB, + R16_FLOAT, RG16_FLOAT, RGBA16_FLOAT, + R32_FLOAT, RG32_FLOAT, RGBA32_FLOAT, + D16_UNORM, D24_UNORM_S8_UINT, D32_FLOAT, D32_FLOAT_S8_X24_UINT, + BC1_UNORM, BC1_UNORM_SRGB, BC2_UNORM, BC2_UNORM_SRGB, + BC3_UNORM, BC3_UNORM_SRGB, BC4_UNORM, BC5_UNORM, BC6H_UF16, + BC7_UNORM, BC7_UNORM_SRGB +}; + +enum class TextureUsage : Core::uint8 { + None = 0, ShaderResource = 1 << 0, RenderTarget = 1 << 1, + DepthStencil = 1 << 2, UnorderedAccess = 1 << 3, + TransferSrc = 1 << 4, TransferDst = 1 << 5 +}; + +class Texture : public IResource { +public: + Texture(); + virtual ~Texture() override; + + ResourceType GetType() const override { return ResourceType::Texture; } + const Containers::String& GetName() const override { return m_name; } + const Containers::String& GetPath() const override { return m_path; } + ResourceGUID GetGUID() const override { return m_guid; } + bool IsValid() const override { return m_isValid; } + size_t GetMemorySize() const override { return m_memorySize; } + void Release() override; + + Core::uint32 GetWidth() const { return m_width; } + Core::uint32 GetHeight() const { return m_height; } + Core::uint32 GetDepth() const { return m_depth; } + Core::uint32 GetMipLevels() const { return m_mipLevels; } + Core::uint32 GetArraySize() const { return m_arraySize; } + TextureType GetTextureType() const { return m_textureType; } + TextureFormat GetFormat() const { return m_format; } + TextureUsage GetUsage() const { return m_usage; } + + const void* GetPixelData() const { return m_pixelData.Data(); } + size_t GetPixelDataSize() const { return m_pixelData.Size(); } + + bool Create(Core::uint32 width, Core::uint32 height, Core::uint32 depth, + Core::uint32 mipLevels, TextureType type, TextureFormat format, + const void* data, size_t dataSize, Core::uint32 arraySize = 1); + bool GenerateMipmaps(); + +private: + Core::uint32 m_width = 0; + Core::uint32 m_height = 0; + Core::uint32 m_depth = 1; + Core::uint32 m_mipLevels = 1; + Core::uint32 m_arraySize = 1; + TextureType m_textureType = TextureType::Texture2D; + TextureFormat m_format = TextureFormat::RGBA8_UNORM; + TextureUsage m_usage = TextureUsage::ShaderResource; + + Containers::Array m_pixelData; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/Texture/TextureImportSettings.cpp b/engine/Runtime/Resources/Texture/TextureImportSettings.cpp similarity index 90% rename from engine/src/Resources/Texture/TextureImportSettings.cpp rename to engine/Runtime/Resources/Texture/TextureImportSettings.cpp index a6ac317b..9a710df7 100644 --- a/engine/src/Resources/Texture/TextureImportSettings.cpp +++ b/engine/Runtime/Resources/Texture/TextureImportSettings.cpp @@ -1,4 +1,4 @@ -#include +#include "TextureImportSettings.h" namespace XCEngine { namespace Resources { diff --git a/engine/Runtime/Resources/Texture/TextureImportSettings.h b/engine/Runtime/Resources/Texture/TextureImportSettings.h new file mode 100644 index 00000000..bbd28e47 --- /dev/null +++ b/engine/Runtime/Resources/Texture/TextureImportSettings.h @@ -0,0 +1,91 @@ +#pragma once + +#include +#include "Texture.h" +#include + +namespace XCEngine { +namespace Resources { + +enum class MipmapFilter { + Box, + Kaiser +}; + +enum class CompressionQuality { + Low, + Medium, + High, + Ultra +}; + +class TextureImportSettings : public ImportSettings { +public: + TextureImportSettings(); + virtual ~TextureImportSettings() override; + + Core::UniqueRef Clone() const override; + bool LoadFromJSON(const Containers::String& json) override; + Containers::String SaveToJSON() const override; + + void SetTextureType(TextureType type) { m_textureType = type; } + TextureType GetTextureType() const { return m_textureType; } + + void SetTargetFormat(TextureFormat format) { m_targetFormat = format; } + TextureFormat GetTargetFormat() const { return m_targetFormat; } + + void SetGenerateMipmaps(bool generate) { m_generateMipmaps = generate; } + bool GetGenerateMipmaps() const { return m_generateMipmaps; } + + void SetMipmapFilter(MipmapFilter filter) { m_mipmapFilter = filter; } + MipmapFilter GetMipmapFilter() const { return m_mipmapFilter; } + + void SetMaxAnisotropy(Core::uint32 anisotropy) { m_maxAnisotropy = anisotropy; } + Core::uint32 GetMaxAnisotropy() const { return m_maxAnisotropy; } + + void SetSRGB(bool srgb) { m_sRGB = srgb; } + bool GetSRGB() const { return m_sRGB; } + + void SetFlipVertical(bool flip) { m_flipVertical = flip; } + bool GetFlipVertical() const { return m_flipVertical; } + + void SetFlipHorizontal(bool flip) { m_flipHorizontal = flip; } + bool GetFlipHorizontal() const { return m_flipHorizontal; } + + void SetBorderColor(const Math::Vector3& color) { m_borderColor = color; } + const Math::Vector3& GetBorderColor() const { return m_borderColor; } + + void SetCompressionQuality(CompressionQuality quality) { m_compressionQuality = quality; } + CompressionQuality GetCompressionQuality() const { return m_compressionQuality; } + + void SetUseHardwareCompression(bool use) { m_useHardwareCompression = use; } + bool GetUseHardwareCompression() const { return m_useHardwareCompression; } + + void SetMaxSize(Core::uint32 size) { m_maxSize = size; } + Core::uint32 GetMaxSize() const { return m_maxSize; } + + void SetGenerateNormalMap(bool generate) { m_generateNormalMap = generate; } + bool GetGenerateNormalMap() const { return m_generateNormalMap; } + + void SetNormalMapStrength(float strength) { m_normalMapStrength = strength; } + float GetNormalMapStrength() const { return m_normalMapStrength; } + +private: + TextureType m_textureType = TextureType::Texture2D; + TextureFormat m_targetFormat = TextureFormat::Unknown; + bool m_generateMipmaps = true; + MipmapFilter m_mipmapFilter = MipmapFilter::Box; + Core::uint32 m_maxAnisotropy = 16; + bool m_sRGB = false; + bool m_flipVertical = false; + bool m_flipHorizontal = false; + Math::Vector3 m_borderColor = Math::Vector3::Zero(); + CompressionQuality m_compressionQuality = CompressionQuality::High; + bool m_useHardwareCompression = true; + Core::uint32 m_maxSize = 0; + bool m_generateNormalMap = false; + float m_normalMapStrength = 1.0f; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Resources/Texture/TextureLoader.cpp b/engine/Runtime/Resources/Texture/TextureLoader.cpp similarity index 98% rename from engine/src/Resources/Texture/TextureLoader.cpp rename to engine/Runtime/Resources/Texture/TextureLoader.cpp index 97971170..acc10631 100644 --- a/engine/src/Resources/Texture/TextureLoader.cpp +++ b/engine/Runtime/Resources/Texture/TextureLoader.cpp @@ -1,9 +1,9 @@ -#include -#include +#include "TextureLoader.h" +#include "engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h" #include #include -#include -#include +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" +#include "TextureImportSettings.h" #include #include #include diff --git a/engine/Runtime/Resources/Texture/TextureLoader.h b/engine/Runtime/Resources/Texture/TextureLoader.h new file mode 100644 index 00000000..79bb5577 --- /dev/null +++ b/engine/Runtime/Resources/Texture/TextureLoader.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include "Texture.h" + +namespace XCEngine { +namespace Resources { + +class TextureLoader : public IResourceLoader { +public: + TextureLoader(); + virtual ~TextureLoader() override; + + ResourceType GetResourceType() const override { return ResourceType::Texture; } + Containers::Array GetSupportedExtensions() const override; + bool CanLoad(const Containers::String& path) const override; + LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override; + LoadResult LoadFromMemory( + const Containers::String& path, + const void* data, + size_t dataSize, + const ImportSettings* settings = nullptr) const; + ImportSettings* GetDefaultSettings() const override; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Scene/ModelSceneInstantiation.cpp b/engine/Runtime/Scene/ModelSceneInstantiation.cpp similarity index 98% rename from engine/src/Scene/ModelSceneInstantiation.cpp rename to engine/Runtime/Scene/ModelSceneInstantiation.cpp index d74b5769..db573c88 100644 --- a/engine/src/Scene/ModelSceneInstantiation.cpp +++ b/engine/Runtime/Scene/ModelSceneInstantiation.cpp @@ -1,10 +1,11 @@ -#include +#include "ModelSceneInstantiation.h" #include #include #include -#include -#include + +#include "Scene.h" +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" namespace XCEngine { diff --git a/engine/Runtime/Scene/ModelSceneInstantiation.h b/engine/Runtime/Scene/ModelSceneInstantiation.h new file mode 100644 index 00000000..f36dfa4b --- /dev/null +++ b/engine/Runtime/Scene/ModelSceneInstantiation.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include + +#include + +namespace XCEngine { + +namespace Components { +class GameObject; +class Scene; +} + +struct ModelSceneInstantiationResult { + Components::GameObject* rootObject = nullptr; + std::vector nodeObjects; + std::vector meshObjects; +}; + +bool InstantiateModelHierarchy( + Components::Scene& scene, + const Resources::Model& model, + const Resources::AssetRef& modelAssetRef, + Components::GameObject* parent = nullptr, + ModelSceneInstantiationResult* outResult = nullptr, + Containers::String* outErrorMessage = nullptr); + +bool InstantiateModelHierarchy( + Components::Scene& scene, + const Containers::String& modelPath, + Components::GameObject* parent = nullptr, + ModelSceneInstantiationResult* outResult = nullptr, + Containers::String* outErrorMessage = nullptr); + +} // namespace XCEngine diff --git a/engine/src/Scene/RuntimeLoop.cpp b/engine/Runtime/Scene/RuntimeLoop.cpp similarity index 98% rename from engine/src/Scene/RuntimeLoop.cpp rename to engine/Runtime/Scene/RuntimeLoop.cpp index 81a9b5b4..7f12d73f 100644 --- a/engine/src/Scene/RuntimeLoop.cpp +++ b/engine/Runtime/Scene/RuntimeLoop.cpp @@ -1,4 +1,4 @@ -#include "Scene/RuntimeLoop.h" +#include "RuntimeLoop.h" #include diff --git a/engine/Runtime/Scene/RuntimeLoop.h b/engine/Runtime/Scene/RuntimeLoop.h new file mode 100644 index 00000000..1ce074a8 --- /dev/null +++ b/engine/Runtime/Scene/RuntimeLoop.h @@ -0,0 +1,47 @@ +#pragma once + +#include "SceneRuntime.h" + +#include + +namespace XCEngine { +namespace Components { + +class RuntimeLoop { +public: + struct Settings { + float fixedDeltaTime = 1.0f / 50.0f; + float maxFrameDeltaTime = 0.1f; + uint32_t maxFixedStepsPerFrame = 4; + }; + + explicit RuntimeLoop(Settings settings = {}); + + void SetSettings(const Settings& settings); + const Settings& GetSettings() const { return m_settings; } + + void Start(Scene* scene); + void Stop(); + void ReplaceScene(Scene* scene); + + void Tick(float deltaTime); + void Pause(); + void Resume(); + void StepFrame(); + + bool IsRunning() const { return m_sceneRuntime.IsRunning(); } + bool IsPaused() const { return m_paused; } + Scene* GetScene() const { return m_sceneRuntime.GetScene(); } + Physics::PhysicsWorld* GetPhysicsWorld() const { return m_sceneRuntime.GetPhysicsWorld(); } + float GetFixedAccumulator() const { return m_fixedAccumulator; } + +private: + SceneRuntime m_sceneRuntime; + Settings m_settings = {}; + float m_fixedAccumulator = 0.0f; + bool m_paused = false; + bool m_stepRequested = false; +}; + +} // namespace Components +} // namespace XCEngine diff --git a/engine/src/Scene/Scene.cpp b/engine/Runtime/Scene/Scene.cpp similarity index 92% rename from engine/src/Scene/Scene.cpp rename to engine/Runtime/Scene/Scene.cpp index f9fe1c80..0a40b98b 100644 --- a/engine/src/Scene/Scene.cpp +++ b/engine/Runtime/Scene/Scene.cpp @@ -1,10 +1,12 @@ -#include "Scene/Scene.h" +#include "Scene.h" + #include "Components/ComponentFactoryRegistry.h" -#include "Debug/Logger.h" #include "Components/GameObject.h" #include "Components/TransformComponent.h" -#include +#include "Debug/Logger.h" + #include +#include #include namespace XCEngine { @@ -18,10 +20,6 @@ bool ShouldTraceSceneComponentPayload(const std::string& payload) { payload.find("New Material.mat") != std::string::npos; } -} // namespace - -namespace { - struct PendingComponentData { std::string type; std::string payload; @@ -66,9 +64,15 @@ std::string UnescapeString(const std::string& value) { if (value[i] == '\\' && i + 1 < value.size()) { ++i; switch (value[i]) { - case 'n': unescaped.push_back('\n'); break; - case 'r': unescaped.push_back('\r'); break; - default: unescaped.push_back(value[i]); break; + case 'n': + unescaped.push_back('\n'); + break; + case 'r': + unescaped.push_back('\r'); + break; + default: + unescaped.push_back(value[i]); + break; } } else { unescaped.push_back(value[i]); @@ -155,21 +159,21 @@ Scene::~Scene() { GameObject* Scene::CreateGameObject(const std::string& name, GameObject* parent) { auto gameObject = std::make_unique(name); GameObject* ptr = gameObject.get(); - + GameObject::GetGlobalRegistry()[ptr->m_id] = ptr; m_gameObjectIDs.insert(ptr->m_id); m_gameObjects.emplace(ptr->m_id, std::move(gameObject)); ptr->m_scene = this; - + if (parent) { ptr->SetParent(parent); } else { m_rootGameObjects.push_back(ptr->m_id); } ptr->Awake(); - + m_onGameObjectCreated.Invoke(ptr); - + return ptr; } @@ -188,14 +192,13 @@ void Scene::DestroyGameObject(GameObject* gameObject) { } else { m_rootGameObjects.erase( std::remove(m_rootGameObjects.begin(), m_rootGameObjects.end(), gameObject->m_id), - m_rootGameObjects.end() - ); + m_rootGameObjects.end()); } m_onGameObjectDestroyed.Invoke(gameObject); - + gameObject->OnDestroy(); - + m_gameObjectIDs.erase(gameObject->m_id); GameObject::GetGlobalRegistry().erase(gameObject->m_id); m_gameObjects.erase(gameObject->m_id); @@ -301,7 +304,9 @@ void Scene::DeserializeFromString(const std::string& data) { GameObject::ID maxId = 0; while (std::getline(input, line)) { - if (line.empty() || line[0] == '#') continue; + if (line.empty() || line[0] == '#') { + continue; + } if (line == "gameobject_begin") { pendingObjects.emplace_back(); @@ -385,16 +390,17 @@ void Scene::DeserializeFromString(const std::string& data) { Debug::Logger::Get().Info( Debug::LogCategory::FileSystem, Containers::String("[Scene] Deserialize component objectId=") + - Containers::String(std::to_string(pending.id).c_str()) + - " name=" + - Containers::String(pending.name.c_str()) + - " type=" + - Containers::String(componentData.type.c_str()) + - " payload=" + - Containers::String(componentData.payload.c_str())); + Containers::String(std::to_string(pending.id).c_str()) + + " name=" + + Containers::String(pending.name.c_str()) + + " type=" + + Containers::String(componentData.type.c_str()) + + " payload=" + + Containers::String(componentData.payload.c_str())); } - if (Component* component = ComponentFactoryRegistry::Get().CreateComponent(go.get(), componentData.type)) { + if (Component* component = + ComponentFactoryRegistry::Get().CreateComponent(go.get(), componentData.type)) { if (!componentData.payload.empty()) { std::istringstream componentStream(componentData.payload); component->Deserialize(componentStream); @@ -467,9 +473,9 @@ void Scene::Load(const std::string& filePath) { Debug::Logger::Get().Info( Debug::LogCategory::FileSystem, Containers::String("[Scene] Load bytes=") + - Containers::String(std::to_string(buffer.str().size()).c_str()) + - " file=" + - Containers::String(filePath.c_str())); + Containers::String(std::to_string(buffer.str().size()).c_str()) + + " file=" + + Containers::String(filePath.c_str())); DeserializeFromString(buffer.str()); } diff --git a/engine/Runtime/Scene/Scene.h b/engine/Runtime/Scene/Scene.h new file mode 100644 index 00000000..650b13a1 --- /dev/null +++ b/engine/Runtime/Scene/Scene.h @@ -0,0 +1,122 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +namespace XCEngine { +namespace Components { + +class Scene { +public: + using GameObjectID = uint64_t; + static constexpr GameObjectID INVALID_GAMEOBJECT_ID = 0; + + Scene(); + explicit Scene(const std::string& name); + ~Scene(); + + const std::string& GetName() const { return m_name; } + void SetName(const std::string& name) { m_name = name; } + + bool IsActive() const { return m_active; } + void SetActive(bool active) { m_active = active; } + + GameObject* CreateGameObject(const std::string& name, GameObject* parent = nullptr); + void DestroyGameObject(GameObject* gameObject); + + GameObject* Find(const std::string& name) const; + GameObject* FindByID(GameObjectID id) const; + GameObject* FindGameObjectWithTag(const std::string& tag) const; + + template + T* FindObjectOfType() const { + for (auto* go : GetRootGameObjects()) { + if (T* comp = go->GetComponent()) { + return comp; + } + if (T* comp = FindInChildren(go)) { + return comp; + } + } + return nullptr; + } + + template + std::vector FindObjectsOfType() const { + std::vector results; + for (auto* go : GetRootGameObjects()) { + if (T* comp = go->GetComponent()) { + results.push_back(comp); + } + FindInChildren(go, results); + } + return results; + } + + std::vector GetRootGameObjects() const; + + void Update(float deltaTime); + void FixedUpdate(float fixedDeltaTime); + void LateUpdate(float deltaTime); + + void Save(const std::string& filePath); + void Load(const std::string& filePath); + std::string SerializeToString() const; + void DeserializeFromString(const std::string& data); + + Core::Event& OnGameObjectCreated() { return m_onGameObjectCreated; } + Core::Event& OnGameObjectDestroyed() { return m_onGameObjectDestroyed; } + Core::Event& OnComponentAdded() { return m_onComponentAdded; } + Core::Event& OnComponentRemoved() { return m_onComponentRemoved; } + +private: + GameObject* FindInChildren(GameObject* parent, const std::string& name) const; + + template + T* FindInChildren(GameObject* parent) const { + for (size_t i = 0; i < parent->GetChildCount(); ++i) { + GameObject* child = parent->GetChild(i); + if (T* comp = child->GetComponent()) { + return comp; + } + if (T* comp = FindInChildren(child)) { + return comp; + } + } + return nullptr; + } + + template + void FindInChildren(GameObject* parent, std::vector& results) const { + for (size_t i = 0; i < parent->GetChildCount(); ++i) { + GameObject* child = parent->GetChild(i); + if (T* comp = child->GetComponent()) { + results.push_back(comp); + } + FindInChildren(child, results); + } + } + + std::string m_name; + bool m_active = true; + std::unordered_map> m_gameObjects; + std::vector m_rootGameObjects; + std::unordered_set m_gameObjectIDs; + + Core::Event m_onGameObjectCreated; + Core::Event m_onGameObjectDestroyed; + Core::Event m_onComponentAdded; + Core::Event m_onComponentRemoved; + + friend class GameObject; + friend class SceneManager; +}; + +} // namespace Components +} // namespace XCEngine diff --git a/engine/src/Scene/SceneManager.cpp b/engine/Runtime/Scene/SceneManager.cpp similarity index 96% rename from engine/src/Scene/SceneManager.cpp rename to engine/Runtime/Scene/SceneManager.cpp index bd4b6da1..2dedeb8d 100644 --- a/engine/src/Scene/SceneManager.cpp +++ b/engine/Runtime/Scene/SceneManager.cpp @@ -1,4 +1,4 @@ -#include "Scene/SceneManager.h" +#include "SceneManager.h" namespace XCEngine { namespace Components { @@ -12,11 +12,11 @@ Scene* SceneManager::CreateScene(const std::string& name) { auto scene = std::make_unique(name); Scene* ptr = scene.get(); m_scenes[name] = std::move(scene); - + if (!m_activeScene) { m_activeScene = ptr; } - + m_onSceneLoaded.Invoke(ptr); return ptr; } @@ -25,7 +25,7 @@ void SceneManager::LoadScene(const std::string& filePath) { auto scene = std::make_unique(); scene->Load(filePath); Scene* ptr = scene.get(); - + std::string name = filePath; size_t pos = name.find_last_of("/\\"); if (pos != std::string::npos) { @@ -35,7 +35,7 @@ void SceneManager::LoadScene(const std::string& filePath) { if (pos != std::string::npos) { name = name.substr(0, pos); } - + m_scenes[name] = std::move(scene); m_onSceneLoaded.Invoke(ptr); } @@ -52,11 +52,11 @@ void SceneManager::UnloadScene(Scene* scene) { if (!scene) { return; } - + if (m_activeScene == scene) { m_activeScene = nullptr; } - + auto it = m_scenes.begin(); while (it != m_scenes.end()) { if (it->second.get() == scene) { @@ -67,7 +67,7 @@ void SceneManager::UnloadScene(Scene* scene) { ++it; } } - + if (m_activeScene == nullptr && !m_scenes.empty()) { m_activeScene = m_scenes.begin()->second.get(); m_onActiveSceneChanged.Invoke(m_activeScene); @@ -113,4 +113,4 @@ std::vector SceneManager::GetAllScenes() const { } } // namespace Components -} // namespace XCEngine \ No newline at end of file +} // namespace XCEngine diff --git a/engine/Runtime/Scene/SceneManager.h b/engine/Runtime/Scene/SceneManager.h new file mode 100644 index 00000000..ae6d42c9 --- /dev/null +++ b/engine/Runtime/Scene/SceneManager.h @@ -0,0 +1,49 @@ +#pragma once + +#include "Scene.h" + +#include +#include +#include +#include + +namespace XCEngine { +namespace Components { + +class SceneManager { +public: + static SceneManager& Get(); + + Scene* CreateScene(const std::string& name); + void LoadScene(const std::string& filePath); + void LoadSceneAsync(const std::string& filePath, std::function callback); + void UnloadScene(Scene* scene); + void UnloadScene(const std::string& sceneName); + + void SetActiveScene(Scene* scene); + void SetActiveScene(const std::string& sceneName); + Scene* GetActiveScene() const { return m_activeScene; } + + Scene* GetScene(const std::string& name) const; + std::vector GetAllScenes() const; + + Core::Event& OnSceneLoaded() { return m_onSceneLoaded; } + Core::Event& OnSceneUnloaded() { return m_onSceneUnloaded; } + Core::Event& OnActiveSceneChanged() { return m_onActiveSceneChanged; } + +private: + SceneManager() = default; + ~SceneManager() = default; + SceneManager(const SceneManager&) = delete; + SceneManager& operator=(const SceneManager&) = delete; + + Scene* m_activeScene = nullptr; + std::unordered_map> m_scenes; + + Core::Event m_onSceneLoaded; + Core::Event m_onSceneUnloaded; + Core::Event m_onActiveSceneChanged; +}; + +} // namespace Components +} // namespace XCEngine diff --git a/engine/src/Scene/SceneRuntime.cpp b/engine/Runtime/Scene/SceneRuntime.cpp similarity index 97% rename from engine/src/Scene/SceneRuntime.cpp rename to engine/Runtime/Scene/SceneRuntime.cpp index da93b47c..3bbd7e9f 100644 --- a/engine/src/Scene/SceneRuntime.cpp +++ b/engine/Runtime/Scene/SceneRuntime.cpp @@ -1,9 +1,10 @@ -#include "Scene/SceneRuntime.h" +#include "SceneRuntime.h" #include -#include "Scripting/ScriptEngine.h" #include +#include "Scripting/ScriptEngine.h" + namespace XCEngine { namespace Components { @@ -114,7 +115,6 @@ void SceneRuntime::FixedUpdate(float fixedDeltaTime) { return; } - // Scripts run first so their state changes are visible to native components in the same frame. Scripting::ScriptEngine::Get().OnFixedUpdate(fixedDeltaTime); m_scene->FixedUpdate(fixedDeltaTime); if (m_physicsWorld) { diff --git a/engine/Runtime/Scene/SceneRuntime.h b/engine/Runtime/Scene/SceneRuntime.h new file mode 100644 index 00000000..bebf645f --- /dev/null +++ b/engine/Runtime/Scene/SceneRuntime.h @@ -0,0 +1,73 @@ +#pragma once + +#include "Scene.h" + +#include + +#include + +namespace XCEngine { +namespace UI { +namespace Runtime { + +class UISceneRuntimeContext; +class UISystem; +class UIScreenStackController; +struct UISystemFrameResult; + +} // namespace Runtime +} // namespace UI + +namespace Physics { + +class PhysicsWorld; + +} // namespace Physics +} // namespace XCEngine + +namespace XCEngine { +namespace Components { + +class SceneRuntime { +public: + SceneRuntime(); + ~SceneRuntime(); + + SceneRuntime(SceneRuntime&& other) noexcept; + SceneRuntime& operator=(SceneRuntime&& other) noexcept; + + SceneRuntime(const SceneRuntime&) = delete; + SceneRuntime& operator=(const SceneRuntime&) = delete; + + void Start(Scene* scene); + void Stop(); + void ReplaceScene(Scene* scene); + + void FixedUpdate(float fixedDeltaTime); + void Update(float deltaTime); + void LateUpdate(float deltaTime); + + UI::Runtime::UISystem& GetUISystem(); + UI::Runtime::UIScreenStackController& GetUIScreenStackController(); + const UI::Runtime::UISystemFrameResult& GetLastUIFrame() const; + void SetUIViewportRect(const UI::UIRect& viewportRect); + void SetUIFocused(bool focused); + void QueueUIInputEvent(const UI::UIInputEvent& event); + void ClearQueuedUIInputEvents(); + + bool IsRunning() const { return m_running; } + Scene* GetScene() const { return m_scene; } + Physics::PhysicsWorld* GetPhysicsWorld() const { return m_physicsWorld.get(); } + +private: + void CreatePhysicsWorldForScene(Scene* scene); + void DestroyPhysicsWorld(); + + std::unique_ptr m_uiRuntime; + std::unique_ptr m_physicsWorld; + Scene* m_scene = nullptr; + bool m_running = false; +}; + +} // namespace Components +} // namespace XCEngine diff --git a/engine/src/Core/Asset/ArtifactContainer.cpp b/engine/Shared/Asset/ArtifactContainer/ArtifactContainer.cpp similarity index 99% rename from engine/src/Core/Asset/ArtifactContainer.cpp rename to engine/Shared/Asset/ArtifactContainer/ArtifactContainer.cpp index 0a1c2a55..33231ede 100644 --- a/engine/src/Core/Asset/ArtifactContainer.cpp +++ b/engine/Shared/Asset/ArtifactContainer/ArtifactContainer.cpp @@ -1,4 +1,4 @@ -#include +#include "ArtifactContainer.h" #include #include diff --git a/engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h b/engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h new file mode 100644 index 00000000..15c06c05 --- /dev/null +++ b/engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h @@ -0,0 +1,105 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace XCEngine { +namespace Resources { + +constexpr Core::uint32 kArtifactContainerSchemaVersion = 1; + +enum class ArtifactContainerCompression : Core::uint32 { + None = 0 +}; + +struct ArtifactContainerEntry { + Containers::String name; + ResourceType resourceType = ResourceType::Unknown; + LocalID localID = kInvalidLocalID; + Core::uint32 flags = 0; + ArtifactContainerCompression compression = ArtifactContainerCompression::None; + Containers::Array payload; +}; + +struct ArtifactContainerEntryView { + Containers::String name; + ResourceType resourceType = ResourceType::Unknown; + LocalID localID = kInvalidLocalID; + Core::uint32 flags = 0; + ArtifactContainerCompression compression = ArtifactContainerCompression::None; + Core::uint64 payloadOffset = 0; + Core::uint64 payloadSize = 0; +}; + +class ArtifactContainerWriter { +public: + void Clear(); + void AddEntry(const ArtifactContainerEntry& entry); + void AddEntry(ArtifactContainerEntry&& entry); + + const Containers::Array& GetEntries() const { return m_entries; } + + bool WriteToFile(const Containers::String& path, + Containers::String* outErrorMessage = nullptr) const; + +private: + Containers::Array m_entries; +}; + +class ArtifactContainerReader { +public: + bool Open(const Containers::String& path, + Containers::String* outErrorMessage = nullptr); + void Close(); + + bool IsOpen() const { return !m_path.Empty(); } + const Containers::String& GetPath() const { return m_path; } + const Containers::Array& GetEntries() const { return m_entries; } + Core::uint32 GetEntryCount() const { return static_cast(m_entries.Size()); } + + const ArtifactContainerEntryView* FindEntryByName(const Containers::String& name) const; + const ArtifactContainerEntryView* FindEntry(ResourceType resourceType, + LocalID localID) const; + + bool ReadEntryPayload(const ArtifactContainerEntryView& entry, + Containers::Array& outPayload, + Containers::String* outErrorMessage = nullptr) const; + bool ReadEntryPayload(const Containers::String& name, + Containers::Array& outPayload, + Containers::String* outErrorMessage = nullptr) const; + +private: + Containers::String m_path; + Containers::Array m_entries; + Core::uint64 m_payloadStart = 0; + Core::uint64 m_payloadSize = 0; +}; + +bool WriteArtifactContainer(const Containers::String& path, + const Containers::Array& entries, + Containers::String* outErrorMessage = nullptr); +bool IsArtifactContainerFile(const Containers::String& path); +Containers::String BuildArtifactContainerEntryPath(const Containers::String& containerPath, + const Containers::String& entryName); +bool TryParseArtifactContainerEntryPath(const Containers::String& path, + Containers::String& outContainerPath, + Containers::String& outEntryName); +bool ReadArtifactContainerEntryPayload(const Containers::String& containerPath, + const Containers::String& entryName, + ResourceType expectedType, + Containers::Array& outPayload, + Containers::String* outErrorMessage = nullptr); +bool ReadArtifactContainerPayloadByPath(const Containers::String& path, + ResourceType expectedType, + Containers::Array& outPayload, + Containers::String* outErrorMessage = nullptr); +bool ReadArtifactContainerMainEntryPayload(const Containers::String& path, + ResourceType expectedType, + Containers::Array& outPayload, + Containers::String* outErrorMessage = nullptr); + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Core/Asset/AssetGUID.cpp b/engine/Shared/Asset/AssetGUID/AssetGUID.cpp similarity index 98% rename from engine/src/Core/Asset/AssetGUID.cpp rename to engine/Shared/Asset/AssetGUID/AssetGUID.cpp index e4d3f169..68ea75f0 100644 --- a/engine/src/Core/Asset/AssetGUID.cpp +++ b/engine/Shared/Asset/AssetGUID/AssetGUID.cpp @@ -1,4 +1,4 @@ -#include +#include "AssetGUID.h" #include #include diff --git a/engine/Shared/Asset/AssetGUID/AssetGUID.h b/engine/Shared/Asset/AssetGUID/AssetGUID.h new file mode 100644 index 00000000..92385b05 --- /dev/null +++ b/engine/Shared/Asset/AssetGUID/AssetGUID.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include + +namespace XCEngine { +namespace Resources { + +struct AssetGUID { + Core::uint64 high = 0; + Core::uint64 low = 0; + + AssetGUID() = default; + AssetGUID(Core::uint64 inHigh, Core::uint64 inLow) + : high(inHigh), low(inLow) {} + + bool IsValid() const { + return high != 0 || low != 0; + } + + bool operator==(const AssetGUID& other) const { + return high == other.high && low == other.low; + } + + bool operator!=(const AssetGUID& other) const { + return !(*this == other); + } + + static AssetGUID Generate(); + static bool TryParse(const Containers::String& text, AssetGUID& outGuid); + static AssetGUID ParseOrDefault(const Containers::String& text); + + Containers::String ToString() const; +}; + +using LocalID = Core::uint64; + +constexpr LocalID kInvalidLocalID = 0; +constexpr LocalID kMainAssetLocalID = 1; + +AssetGUID HashBytesToAssetGUID(const void* data, size_t size); +AssetGUID HashStringToAssetGUID(const Containers::String& text); + +} // namespace Resources +} // namespace XCEngine + +namespace std { +template<> +struct hash { + size_t operator()(const XCEngine::Resources::AssetGUID& guid) const noexcept { + return static_cast(guid.high ^ (guid.low * 0x9e3779b97f4a7c15ULL)); + } +}; +} diff --git a/engine/src/Core/Asset/ResourceDependencyGraph.cpp b/engine/Shared/Asset/DependencyGraph/ResourceDependencyGraph.cpp similarity index 99% rename from engine/src/Core/Asset/ResourceDependencyGraph.cpp rename to engine/Shared/Asset/DependencyGraph/ResourceDependencyGraph.cpp index c42c2adf..5be83fd8 100644 --- a/engine/src/Core/Asset/ResourceDependencyGraph.cpp +++ b/engine/Shared/Asset/DependencyGraph/ResourceDependencyGraph.cpp @@ -1,4 +1,4 @@ -#include +#include "ResourceDependencyGraph.h" namespace XCEngine { namespace Resources { diff --git a/engine/Shared/Asset/DependencyGraph/ResourceDependencyGraph.h b/engine/Shared/Asset/DependencyGraph/ResourceDependencyGraph.h new file mode 100644 index 00000000..ba14e67b --- /dev/null +++ b/engine/Shared/Asset/DependencyGraph/ResourceDependencyGraph.h @@ -0,0 +1,56 @@ +#pragma once + +#include +#include +#include +#include + +namespace XCEngine { +namespace Resources { + +struct DependencyNode { + ResourceGUID guid; + ResourceType type; + Containers::Array dependencies; + Containers::Array dependents; + Core::uint32 refCount = 0; +}; + +class ResourceDependencyGraph { +public: + ResourceDependencyGraph(); + ~ResourceDependencyGraph(); + + void AddNode(ResourceGUID guid, ResourceType type); + void RemoveNode(ResourceGUID guid); + + void AddDependency(ResourceGUID owner, ResourceGUID dependency); + void RemoveDependency(ResourceGUID owner, ResourceGUID dependency); + + Containers::Array GetDependencies(ResourceGUID guid) const; + Containers::Array GetDependents(ResourceGUID guid) const; + Containers::Array GetAllDependencies(ResourceGUID guid) const; + + void IncrementRefCount(ResourceGUID guid); + void DecrementRefCount(ResourceGUID guid); + Core::uint32 GetRefCount(ResourceGUID guid) const; + + bool HasCircularDependency(ResourceGUID guid, Containers::Array& outCycle) const; + + Containers::Array TopologicalSort() const; + + bool Unload(ResourceGUID guid); + + void Clear(); + + bool HasNode(ResourceGUID guid) const; + +private: + bool HasCircularDependencyInternal(ResourceGUID guid, Containers::HashMap& visited, + Containers::Array& path, Containers::Array& outCycle) const; + + Containers::HashMap m_nodes; +}; + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/src/Core/Asset/ResourceTypes.cpp b/engine/Shared/Asset/ResourceType/ResourceTypes.cpp similarity index 93% rename from engine/src/Core/Asset/ResourceTypes.cpp rename to engine/Shared/Asset/ResourceType/ResourceTypes.cpp index 47f98bbd..0ca8e619 100644 --- a/engine/src/Core/Asset/ResourceTypes.cpp +++ b/engine/Shared/Asset/ResourceType/ResourceTypes.cpp @@ -1,4 +1,4 @@ -#include +#include "ResourceTypes.h" namespace XCEngine { namespace Resources { diff --git a/engine/Shared/Asset/ResourceType/ResourceTypes.h b/engine/Shared/Asset/ResourceType/ResourceTypes.h new file mode 100644 index 00000000..fe33cfb1 --- /dev/null +++ b/engine/Shared/Asset/ResourceType/ResourceTypes.h @@ -0,0 +1,114 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace XCEngine { +namespace Resources { + +enum class ResourceType : Core::uint8 { + Unknown = 0, + Texture, + Mesh, + Material, + Shader, + AudioClip, + Binary, + AnimationClip, + Skeleton, + Font, + ParticleSystem, + Scene, + Prefab, + UIView, + UITheme, + UISchema, + VolumeField, + Model, + GaussianSplat, + RenderPipelineAsset +}; + +constexpr const char* GetResourceTypeName(ResourceType type) { + switch (type) { + case ResourceType::Texture: return "Texture"; + case ResourceType::Mesh: return "Mesh"; + case ResourceType::Material: return "Material"; + case ResourceType::Shader: return "Shader"; + case ResourceType::AudioClip: return "AudioClip"; + case ResourceType::Binary: return "Binary"; + case ResourceType::AnimationClip: return "AnimationClip"; + case ResourceType::Skeleton: return "Skeleton"; + case ResourceType::Font: return "Font"; + case ResourceType::ParticleSystem: return "ParticleSystem"; + case ResourceType::Scene: return "Scene"; + case ResourceType::Prefab: return "Prefab"; + case ResourceType::UIView: return "UIView"; + case ResourceType::UITheme: return "UITheme"; + case ResourceType::UISchema: return "UISchema"; + case ResourceType::VolumeField: return "VolumeField"; + case ResourceType::Model: return "Model"; + case ResourceType::GaussianSplat: return "GaussianSplat"; + case ResourceType::RenderPipelineAsset: return "RenderPipelineAsset"; + default: return "Unknown"; + } +} + +struct ResourceGUID { + Core::uint64 value; + + ResourceGUID() : value(0) {} + explicit ResourceGUID(Core::uint64 v) : value(v) {} + + bool IsValid() const { return value != 0; } + + bool operator==(const ResourceGUID& other) const { return value == other.value; } + bool operator!=(const ResourceGUID& other) const { return value != other.value; } + + static ResourceGUID Generate(const char* path); + static ResourceGUID Generate(const Containers::String& path); + + Containers::String ToString() const; +}; + +inline ResourceGUID MakeResourceGUID(const char* path) { + return ResourceGUID::Generate(path); +} + +} // namespace Resources + +} // namespace XCEngine + +namespace std { +template<> +struct hash { + size_t operator()(const XCEngine::Resources::ResourceGUID& guid) const noexcept { + return static_cast(guid.value); + } +}; +} + +namespace XCEngine { +namespace Resources { + +template +ResourceType GetResourceType(); + +template<> inline ResourceType GetResourceType() { return ResourceType::Texture; } +template<> inline ResourceType GetResourceType() { return ResourceType::Mesh; } +template<> inline ResourceType GetResourceType() { return ResourceType::Material; } +template<> inline ResourceType GetResourceType() { return ResourceType::Shader; } +template<> inline ResourceType GetResourceType() { return ResourceType::AudioClip; } +template<> inline ResourceType GetResourceType() { return ResourceType::Binary; } +template<> inline ResourceType GetResourceType() { return ResourceType::UIView; } +template<> inline ResourceType GetResourceType() { return ResourceType::UITheme; } +template<> inline ResourceType GetResourceType() { return ResourceType::UISchema; } +template<> inline ResourceType GetResourceType() { return ResourceType::VolumeField; } +template<> inline ResourceType GetResourceType() { return ResourceType::Model; } +template<> inline ResourceType GetResourceType() { return ResourceType::GaussianSplat; } + +} // namespace Resources +} // namespace XCEngine diff --git a/engine/include/XCEngine/Core/Asset/ArtifactContainer.h b/engine/include/XCEngine/Core/Asset/ArtifactContainer.h index 15c06c05..aebc7198 100644 --- a/engine/include/XCEngine/Core/Asset/ArtifactContainer.h +++ b/engine/include/XCEngine/Core/Asset/ArtifactContainer.h @@ -1,105 +1,3 @@ #pragma once -#include -#include -#include -#include -#include - -namespace XCEngine { -namespace Resources { - -constexpr Core::uint32 kArtifactContainerSchemaVersion = 1; - -enum class ArtifactContainerCompression : Core::uint32 { - None = 0 -}; - -struct ArtifactContainerEntry { - Containers::String name; - ResourceType resourceType = ResourceType::Unknown; - LocalID localID = kInvalidLocalID; - Core::uint32 flags = 0; - ArtifactContainerCompression compression = ArtifactContainerCompression::None; - Containers::Array payload; -}; - -struct ArtifactContainerEntryView { - Containers::String name; - ResourceType resourceType = ResourceType::Unknown; - LocalID localID = kInvalidLocalID; - Core::uint32 flags = 0; - ArtifactContainerCompression compression = ArtifactContainerCompression::None; - Core::uint64 payloadOffset = 0; - Core::uint64 payloadSize = 0; -}; - -class ArtifactContainerWriter { -public: - void Clear(); - void AddEntry(const ArtifactContainerEntry& entry); - void AddEntry(ArtifactContainerEntry&& entry); - - const Containers::Array& GetEntries() const { return m_entries; } - - bool WriteToFile(const Containers::String& path, - Containers::String* outErrorMessage = nullptr) const; - -private: - Containers::Array m_entries; -}; - -class ArtifactContainerReader { -public: - bool Open(const Containers::String& path, - Containers::String* outErrorMessage = nullptr); - void Close(); - - bool IsOpen() const { return !m_path.Empty(); } - const Containers::String& GetPath() const { return m_path; } - const Containers::Array& GetEntries() const { return m_entries; } - Core::uint32 GetEntryCount() const { return static_cast(m_entries.Size()); } - - const ArtifactContainerEntryView* FindEntryByName(const Containers::String& name) const; - const ArtifactContainerEntryView* FindEntry(ResourceType resourceType, - LocalID localID) const; - - bool ReadEntryPayload(const ArtifactContainerEntryView& entry, - Containers::Array& outPayload, - Containers::String* outErrorMessage = nullptr) const; - bool ReadEntryPayload(const Containers::String& name, - Containers::Array& outPayload, - Containers::String* outErrorMessage = nullptr) const; - -private: - Containers::String m_path; - Containers::Array m_entries; - Core::uint64 m_payloadStart = 0; - Core::uint64 m_payloadSize = 0; -}; - -bool WriteArtifactContainer(const Containers::String& path, - const Containers::Array& entries, - Containers::String* outErrorMessage = nullptr); -bool IsArtifactContainerFile(const Containers::String& path); -Containers::String BuildArtifactContainerEntryPath(const Containers::String& containerPath, - const Containers::String& entryName); -bool TryParseArtifactContainerEntryPath(const Containers::String& path, - Containers::String& outContainerPath, - Containers::String& outEntryName); -bool ReadArtifactContainerEntryPayload(const Containers::String& containerPath, - const Containers::String& entryName, - ResourceType expectedType, - Containers::Array& outPayload, - Containers::String* outErrorMessage = nullptr); -bool ReadArtifactContainerPayloadByPath(const Containers::String& path, - ResourceType expectedType, - Containers::Array& outPayload, - Containers::String* outErrorMessage = nullptr); -bool ReadArtifactContainerMainEntryPayload(const Containers::String& path, - ResourceType expectedType, - Containers::Array& outPayload, - Containers::String* outErrorMessage = nullptr); - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Core/Asset/AssetDatabase.h b/engine/include/XCEngine/Core/Asset/AssetDatabase.h index 19adcd79..989be50f 100644 --- a/engine/include/XCEngine/Core/Asset/AssetDatabase.h +++ b/engine/include/XCEngine/Core/Asset/AssetDatabase.h @@ -1,204 +1,3 @@ #pragma once -#include -#include -#include -#include - -#include -#include -#include - -namespace XCEngine { -namespace Resources { - -enum class ArtifactStorageKind : Core::uint8 { - Unknown = 0, - LegacyDirectory = 1, - SingleFileContainer = 2 -}; - -class Mesh; -class Material; - -class AssetDatabase { -public: - struct MaintenanceStats { - Core::uint32 importedAssetCount = 0; - Core::uint32 removedArtifactCount = 0; - }; - - struct ArtifactDependencyRecord { - Containers::String path; - Containers::String hash; - Core::uint64 fileSize = 0; - Core::uint64 writeTime = 0; - }; - - struct SourceAssetRecord { - AssetGUID guid; - Containers::String relativePath; - Containers::String metaPath; - bool isFolder = false; - Containers::String importerName; - Core::uint32 importerVersion = 0; - Containers::String metaHash; - Containers::String sourceHash; - Core::uint64 sourceFileSize = 0; - Core::uint64 sourceWriteTime = 0; - Containers::String lastKnownArtifactKey; - }; - - struct ArtifactRecord { - Containers::String artifactKey; - AssetGUID assetGuid; - Containers::String importerName; - Core::uint32 importerVersion = 0; - ResourceType resourceType = ResourceType::Unknown; - ArtifactStorageKind storageKind = ArtifactStorageKind::Unknown; - Containers::String artifactDirectory; - Containers::String mainArtifactPath; - Containers::String mainEntryName; - Containers::String sourceHash; - Containers::String metaHash; - Core::uint64 sourceFileSize = 0; - Core::uint64 sourceWriteTime = 0; - LocalID mainLocalID = kMainAssetLocalID; - std::vector dependencies; - }; - - struct ResolvedAsset { - bool exists = false; - bool artifactReady = false; - bool imported = false; - Containers::String absolutePath; - Containers::String relativePath; - AssetGUID assetGuid; - ResourceType resourceType = ResourceType::Unknown; - Containers::String artifactMainPath; - Containers::String artifactMainEntryPath; - Containers::String artifactDirectory; - ArtifactStorageKind artifactStorageKind = ArtifactStorageKind::Unknown; - Containers::String mainEntryName; - LocalID mainLocalID = kMainAssetLocalID; - }; - - void Initialize(const Containers::String& projectRoot); - void Shutdown(); - MaintenanceStats Refresh(); - - bool ResolvePath(const Containers::String& requestPath, - Containers::String& outAbsolutePath, - Containers::String& outRelativePath) const; - bool TryGetAssetGuid(const Containers::String& requestPath, AssetGUID& outGuid) const; - bool TryGetImportableResourceType(const Containers::String& requestPath, ResourceType& outType) const; - bool TryGetAssetRef(const Containers::String& requestPath, ResourceType resourceType, AssetRef& outRef) const; - bool TryResolveAssetPath(const AssetRef& assetRef, Containers::String& outPath); - bool ReimportAsset(const Containers::String& requestPath, - ResolvedAsset& outAsset, - MaintenanceStats* outStats = nullptr); - bool ReimportAllAssets(MaintenanceStats* outStats = nullptr); - bool EnsureArtifact(const Containers::String& requestPath, - ResourceType requestedType, - ResolvedAsset& outAsset); - bool TryGetPrimaryAssetPath(const AssetGUID& guid, Containers::String& outRelativePath) const; - void BuildLookupSnapshot(std::unordered_map& outPathToGuid, - std::unordered_map& outGuidToPath) const; - - const Containers::String& GetProjectRoot() const { return m_projectRoot; } - const Containers::String& GetAssetsRoot() const { return m_assetsRoot; } - const Containers::String& GetLibraryRoot() const { return m_libraryRoot; } - const Containers::String& GetLastErrorMessage() const { return m_lastErrorMessage; } - -private: - static constexpr Core::uint32 kBaseImporterVersion = 7; - - void EnsureProjectLayout(); - void LoadSourceAssetDB(); - void SaveSourceAssetDB() const; - void LoadArtifactDB(); - void SaveArtifactDB() const; - MaintenanceStats ScanAssets(); - void ScanAssetPath(const std::filesystem::path& path, - std::unordered_map& seenPaths); - void RemoveMissingRecords(const std::unordered_map& seenPaths); - Core::uint32 CleanupOrphanedArtifacts() const; - - bool EnsureMetaForPath(const std::filesystem::path& sourcePath, - bool isFolder, - SourceAssetRecord& outRecord); - bool ReadMetaFile(const std::filesystem::path& metaPath, - SourceAssetRecord& inOutRecord) const; - void WriteMetaFile(const std::filesystem::path& metaPath, - const SourceAssetRecord& record) const; - - Containers::String NormalizeRelativePath(const std::filesystem::path& sourcePath) const; - static Containers::String NormalizePathString(const std::filesystem::path& path); - static Containers::String NormalizePathString(const Containers::String& path); - static Containers::String MakeKey(const Containers::String& path); - static Containers::String GetImporterNameForPath(const Containers::String& relativePath, bool isFolder); - static Core::uint32 GetCurrentImporterVersion(const Containers::String& importerName); - static ResourceType GetPrimaryResourceTypeForImporter(const Containers::String& importerName); - - bool ShouldReimport(const SourceAssetRecord& sourceRecord, - const ArtifactRecord* artifactRecord) const; - bool ImportAsset(const SourceAssetRecord& sourceRecord, - ArtifactRecord& outRecord); - bool ImportTextureAsset(const SourceAssetRecord& sourceRecord, - ArtifactRecord& outRecord); - bool ImportMaterialAsset(const SourceAssetRecord& sourceRecord, - ArtifactRecord& outRecord); - bool ImportModelAsset(const SourceAssetRecord& sourceRecord, - ArtifactRecord& outRecord); - bool ImportShaderAsset(const SourceAssetRecord& sourceRecord, - ArtifactRecord& outRecord); - bool ImportGaussianSplatAsset(const SourceAssetRecord& sourceRecord, - ArtifactRecord& outRecord); - bool ImportVolumeFieldAsset(const SourceAssetRecord& sourceRecord, - ArtifactRecord& outRecord); - bool ImportUIDocumentAsset(const SourceAssetRecord& sourceRecord, - UIDocumentKind kind, - const char* artifactFileName, - ResourceType resourceType, - ArtifactRecord& outRecord); - - Containers::String BuildArtifactKey( - const SourceAssetRecord& sourceRecord, - const std::vector& dependencies = {}) const; - Containers::String BuildArtifactDirectory(const Containers::String& artifactKey) const; - Containers::String BuildArtifactFilePath(const Containers::String& artifactKey, - const char* extension) const; - static Containers::String ReadWholeFileText(const std::filesystem::path& path); - static Containers::String ComputeFileHash(const std::filesystem::path& path); - static Core::uint64 GetFileSizeValue(const std::filesystem::path& path); - static Core::uint64 GetFileWriteTimeValue(const std::filesystem::path& path); - Containers::String NormalizeDependencyPath(const std::filesystem::path& path) const; - std::filesystem::path ResolveDependencyPath(const Containers::String& path) const; - bool CaptureDependencyRecord(const std::filesystem::path& path, - ArtifactDependencyRecord& outRecord) const; - bool AreDependenciesCurrent(const std::vector& dependencies) const; - bool CollectModelDependencies(const SourceAssetRecord& sourceRecord, - const std::vector& importedTexturePaths, - std::vector& outDependencies) const; - bool CollectMaterialDependencies(const Material& material, - std::vector& outDependencies) const; - bool CollectShaderDependencies(const SourceAssetRecord& sourceRecord, - std::vector& outDependencies, - Containers::String* outError = nullptr) const; - void ClearLastErrorMessage(); - void SetLastErrorMessage(const Containers::String& message); - - Containers::String m_projectRoot; - Containers::String m_assetsRoot; - Containers::String m_libraryRoot; - Containers::String m_sourceDbPath; - Containers::String m_artifactDbPath; - Containers::String m_lastErrorMessage; - - std::unordered_map m_sourcesByPathKey; - std::unordered_map m_sourcesByGuid; - std::unordered_map m_artifactsByGuid; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Core/Asset/AssetGUID.h b/engine/include/XCEngine/Core/Asset/AssetGUID.h index 92385b05..bda0e9a8 100644 --- a/engine/include/XCEngine/Core/Asset/AssetGUID.h +++ b/engine/include/XCEngine/Core/Asset/AssetGUID.h @@ -1,54 +1,3 @@ #pragma once -#include -#include - -namespace XCEngine { -namespace Resources { - -struct AssetGUID { - Core::uint64 high = 0; - Core::uint64 low = 0; - - AssetGUID() = default; - AssetGUID(Core::uint64 inHigh, Core::uint64 inLow) - : high(inHigh), low(inLow) {} - - bool IsValid() const { - return high != 0 || low != 0; - } - - bool operator==(const AssetGUID& other) const { - return high == other.high && low == other.low; - } - - bool operator!=(const AssetGUID& other) const { - return !(*this == other); - } - - static AssetGUID Generate(); - static bool TryParse(const Containers::String& text, AssetGUID& outGuid); - static AssetGUID ParseOrDefault(const Containers::String& text); - - Containers::String ToString() const; -}; - -using LocalID = Core::uint64; - -constexpr LocalID kInvalidLocalID = 0; -constexpr LocalID kMainAssetLocalID = 1; - -AssetGUID HashBytesToAssetGUID(const void* data, size_t size); -AssetGUID HashStringToAssetGUID(const Containers::String& text); - -} // namespace Resources -} // namespace XCEngine - -namespace std { -template<> -struct hash { - size_t operator()(const XCEngine::Resources::AssetGUID& guid) const noexcept { - return static_cast(guid.high ^ (guid.low * 0x9e3779b97f4a7c15ULL)); - } -}; -} +#include diff --git a/engine/include/XCEngine/Core/Asset/AssetImportService.h b/engine/include/XCEngine/Core/Asset/AssetImportService.h index 5d0d6483..e8fbbfb6 100644 --- a/engine/include/XCEngine/Core/Asset/AssetImportService.h +++ b/engine/include/XCEngine/Core/Asset/AssetImportService.h @@ -1,107 +1,3 @@ #pragma once -#include "AssetDatabase.h" - -#include -#include - -namespace XCEngine { -namespace Resources { - -class AssetImportService { -public: - struct ImportStatusSnapshot { - Core::uint64 revision = 0; - bool inProgress = false; - bool success = false; - Containers::String operation; - Containers::String targetPath; - Containers::String message; - Core::uint64 startedAtMs = 0; - Core::uint64 completedAtMs = 0; - Core::uint64 durationMs = 0; - Core::uint32 importedAssetCount = 0; - Core::uint32 removedArtifactCount = 0; - - bool HasValue() const { - return revision != 0; - } - }; - - struct LookupSnapshot { - std::unordered_map assetGuidByPathKey; - std::unordered_map assetPathByGuid; - - void Clear() { - assetGuidByPathKey.clear(); - assetPathByGuid.clear(); - } - }; - - struct ImportedAsset { - bool exists = false; - bool artifactReady = false; - bool imported = false; - Containers::String absolutePath; - Containers::String relativePath; - AssetGUID assetGuid; - ResourceType resourceType = ResourceType::Unknown; - Containers::String runtimeLoadPath; - Containers::String artifactMainPath; - Containers::String artifactMainEntryPath; - Containers::String artifactDirectory; - ArtifactStorageKind artifactStorageKind = ArtifactStorageKind::Unknown; - Containers::String mainEntryName; - LocalID mainLocalID = kMainAssetLocalID; - }; - - void Initialize(); - void Shutdown(); - - void SetProjectRoot(const Containers::String& projectRoot); - Containers::String GetProjectRoot() const; - Containers::String GetLibraryRoot() const; - - bool BootstrapProject(); - void Refresh(); - bool ClearLibraryCache(); - bool RebuildLibraryCache(); - bool ReimportAllAssets(); - bool ReimportAsset(const Containers::String& requestPath, - ImportedAsset& outAsset); - ImportStatusSnapshot GetLastImportStatus() const; - bool TryGetImportableResourceType(const Containers::String& requestPath, - ResourceType& outType) const; - - bool EnsureArtifact(const Containers::String& requestPath, - ResourceType requestedType, - ImportedAsset& outAsset); - bool TryGetAssetRef(const Containers::String& requestPath, - ResourceType resourceType, - AssetRef& outRef) const; - bool TryResolveAssetPath(const AssetRef& assetRef, - Containers::String& outPath); - bool TryGetPrimaryAssetPath(const AssetGUID& guid, Containers::String& outRelativePath) const; - void BuildLookupSnapshot(LookupSnapshot& outSnapshot) const; - -private: - static ImportedAsset ConvertResolvedAsset(const AssetDatabase::ResolvedAsset& resolvedAsset); - void ResetImportStatusLocked(); - void BeginImportStatusLocked(const Containers::String& operation, - const Containers::String& targetPath, - const Containers::String& message); - void FinishImportStatusLocked(const Containers::String& operation, - const Containers::String& targetPath, - bool success, - const Containers::String& message, - const AssetDatabase::MaintenanceStats& stats); - - mutable std::recursive_mutex m_mutex; - Containers::String m_projectRoot; - AssetDatabase m_assetDatabase; - ImportStatusSnapshot m_lastImportStatus; - Core::uint64 m_nextImportStatusRevision = 1; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Core/Asset/AsyncLoader.h b/engine/include/XCEngine/Core/Asset/AsyncLoader.h index 7a18583d..2714d0d8 100644 --- a/engine/include/XCEngine/Core/Asset/AsyncLoader.h +++ b/engine/include/XCEngine/Core/Asset/AsyncLoader.h @@ -1,108 +1,3 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace XCEngine { -namespace Resources { - -struct LoadRequest { - Containers::String path; - ResourceType type; - std::function callback; - ImportSettings* settings; - Core::uint64 requestId; - - LoadRequest() : requestId(0), settings(nullptr) {} - - LoadRequest(const Containers::String& p, ResourceType t, - std::function cb, ImportSettings* s = nullptr) - : path(p), type(t), callback(std::move(cb)), - settings(s), requestId(GenerateRequestId()) {} - - LoadRequest(LoadRequest&& other) noexcept - : path(std::move(other.path)), type(other.type), - callback(std::move(other.callback)), settings(other.settings), - requestId(other.requestId) { - other.settings = nullptr; - } - - LoadRequest& operator=(LoadRequest&& other) noexcept { - if (this != &other) { - path = std::move(other.path); - type = other.type; - callback = std::move(other.callback); - settings = other.settings; - requestId = other.requestId; - other.settings = nullptr; - } - return *this; - } - - LoadRequest(const LoadRequest&) = default; - LoadRequest& operator=(const LoadRequest&) = default; - -private: - static Core::uint64 GenerateRequestId(); -}; - -struct CompletedLoadRequest { - LoadRequest request; - LoadResult result; - - CompletedLoadRequest(LoadRequest inRequest, LoadResult inResult) - : request(std::move(inRequest)), result(std::move(inResult)) {} -}; - -class AsyncLoader { -public: - static AsyncLoader& Get(); - - void Initialize(Core::uint32 workerThreadCount = 2); - void Shutdown(); - - void Submit(const Containers::String& path, ResourceType type, - std::function callback); - void Submit(const Containers::String& path, ResourceType type, ImportSettings* settings, - std::function callback); - - void Update(); - bool IsLoading() const { return m_pendingCount > 0; } - Core::uint32 GetPendingCount() const { return m_pendingCount; } - float GetProgress() const; - void CancelAll(); - void Cancel(Core::uint64 requestId); - - ~AsyncLoader() = default; - - AsyncLoader() = default; - -private: - void SubmitInternal(LoadRequest request); - IResourceLoader* FindLoader(ResourceType type) const; - void WorkerThread(); - void QueueCompleted(LoadRequest request, LoadResult result); - - std::mutex m_queueMutex; - std::condition_variable m_pendingCondition; - std::deque m_pendingQueue; - - std::mutex m_completedMutex; - std::deque m_completedQueue; - std::vector m_workerThreads; - - std::atomic m_running{false}; - std::atomic m_pendingCount{0}; - std::atomic m_completedCount{0}; - std::atomic m_totalRequested{0}; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Core/Asset/IProjectAssetPipelineService.h b/engine/include/XCEngine/Core/Asset/IProjectAssetPipelineService.h new file mode 100644 index 00000000..72995269 --- /dev/null +++ b/engine/include/XCEngine/Core/Asset/IProjectAssetPipelineService.h @@ -0,0 +1,3 @@ +#pragma once + +#include diff --git a/engine/include/XCEngine/Core/Asset/IProjectAssetResolver.h b/engine/include/XCEngine/Core/Asset/IProjectAssetResolver.h new file mode 100644 index 00000000..c62fb8ee --- /dev/null +++ b/engine/include/XCEngine/Core/Asset/IProjectAssetResolver.h @@ -0,0 +1,3 @@ +#pragma once + +#include diff --git a/engine/include/XCEngine/Core/Asset/ProjectAssetIndex.h b/engine/include/XCEngine/Core/Asset/ProjectAssetIndex.h index 2e58f170..30a572b0 100644 --- a/engine/include/XCEngine/Core/Asset/ProjectAssetIndex.h +++ b/engine/include/XCEngine/Core/Asset/ProjectAssetIndex.h @@ -1,37 +1,3 @@ #pragma once -#include -#include -#include - -#include -#include - -namespace XCEngine { -namespace Resources { - -class AssetImportService; - -class ProjectAssetIndex { -public: - void ResetProjectRoot(const Containers::String& projectRoot = Containers::String()); - void RefreshFrom(const AssetImportService& importService); - - bool TryGetAssetRef(AssetImportService& importService, - const Containers::String& path, - ResourceType resourceType, - AssetRef& outRef) const; - bool TryResolveAssetPath(AssetImportService& importService, - const AssetRef& assetRef, - Containers::String& outPath) const; - void RememberResolvedPath(const AssetGUID& assetGuid, const Containers::String& relativePath); - -private: - mutable std::shared_mutex m_mutex; - Containers::String m_projectRoot; - std::unordered_map m_assetGuidByPathKey; - std::unordered_map m_assetPathByGuid; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Core/Asset/ProjectAssetService.h b/engine/include/XCEngine/Core/Asset/ProjectAssetService.h new file mode 100644 index 00000000..0fd93829 --- /dev/null +++ b/engine/include/XCEngine/Core/Asset/ProjectAssetService.h @@ -0,0 +1,3 @@ +#pragma once + +#include diff --git a/engine/include/XCEngine/Core/Asset/ProjectAssetTypes.h b/engine/include/XCEngine/Core/Asset/ProjectAssetTypes.h new file mode 100644 index 00000000..63e10e7e --- /dev/null +++ b/engine/include/XCEngine/Core/Asset/ProjectAssetTypes.h @@ -0,0 +1,3 @@ +#pragma once + +#include diff --git a/engine/include/XCEngine/Core/Asset/ResourceCache.h b/engine/include/XCEngine/Core/Asset/ResourceCache.h index 3e878814..650f1e8d 100644 --- a/engine/include/XCEngine/Core/Asset/ResourceCache.h +++ b/engine/include/XCEngine/Core/Asset/ResourceCache.h @@ -1,64 +1,3 @@ #pragma once -#include "ResourceTypes.h" -#include -#include -#include -#include - -namespace XCEngine { -namespace Resources { - -class IResource; - -struct CacheEntry { - IResource* resource; - ResourceGUID guid; - size_t memorySize; - Core::uint64 lastAccessTime; - Core::uint32 accessCount; - - CacheEntry() : resource(nullptr), memorySize(0), lastAccessTime(0), accessCount(0) {} - CacheEntry(IResource* res, size_t size); - - static Core::uint64 GetCurrentTick(); -}; - -class ResourceCache { -public: - ResourceCache(); - ~ResourceCache(); - - void Add(ResourceGUID guid, IResource* resource); - void Remove(ResourceGUID guid); - IResource* Find(ResourceGUID guid) const; - void Touch(ResourceGUID guid); - - size_t GetSize() const { return m_cache.Size(); } - size_t GetMemoryUsage() const { return m_memoryUsage; } - - void SetMemoryBudget(size_t bytes); - size_t GetMemoryBudget() const { return m_memoryBudget; } - - void OnMemoryPressure(size_t requiredBytes); - void OnZeroRefCount(ResourceGUID guid); - void Flush(); - void Clear(); - - Containers::Array GetLRUList(size_t count) const; - -private: - void Evict(size_t requiredBytes); - void UpdateMemoryStats(); - - Containers::HashMap m_cache; - Containers::Array m_lruOrder; - size_t m_memoryUsage = 0; - size_t m_memoryBudget = 512 * 1024 * 1024; - - Threading::Mutex m_mutex; - mutable Threading::Mutex m_cacheMutex; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Core/Asset/ResourceDependencyGraph.h b/engine/include/XCEngine/Core/Asset/ResourceDependencyGraph.h index e28ce0eb..5ab99fdd 100644 --- a/engine/include/XCEngine/Core/Asset/ResourceDependencyGraph.h +++ b/engine/include/XCEngine/Core/Asset/ResourceDependencyGraph.h @@ -1,56 +1,3 @@ #pragma once -#include "ResourceTypes.h" -#include -#include -#include - -namespace XCEngine { -namespace Resources { - -struct DependencyNode { - ResourceGUID guid; - ResourceType type; - Containers::Array dependencies; - Containers::Array dependents; - Core::uint32 refCount = 0; -}; - -class ResourceDependencyGraph { -public: - ResourceDependencyGraph(); - ~ResourceDependencyGraph(); - - void AddNode(ResourceGUID guid, ResourceType type); - void RemoveNode(ResourceGUID guid); - - void AddDependency(ResourceGUID owner, ResourceGUID dependency); - void RemoveDependency(ResourceGUID owner, ResourceGUID dependency); - - Containers::Array GetDependencies(ResourceGUID guid) const; - Containers::Array GetDependents(ResourceGUID guid) const; - Containers::Array GetAllDependencies(ResourceGUID guid) const; - - void IncrementRefCount(ResourceGUID guid); - void DecrementRefCount(ResourceGUID guid); - Core::uint32 GetRefCount(ResourceGUID guid) const; - - bool HasCircularDependency(ResourceGUID guid, Containers::Array& outCycle) const; - - Containers::Array TopologicalSort() const; - - bool Unload(ResourceGUID guid); - - void Clear(); - - bool HasNode(ResourceGUID guid) const; - -private: - bool HasCircularDependencyInternal(ResourceGUID guid, Containers::HashMap& visited, - Containers::Array& path, Containers::Array& outCycle) const; - - Containers::HashMap m_nodes; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Core/Asset/ResourceManager.h b/engine/include/XCEngine/Core/Asset/ResourceManager.h index 1c737d6b..e7b37d66 100644 --- a/engine/include/XCEngine/Core/Asset/ResourceManager.h +++ b/engine/include/XCEngine/Core/Asset/ResourceManager.h @@ -1,191 +1,3 @@ #pragma once -#include -#include "AssetImportService.h" -#include "ProjectAssetIndex.h" -#include "ResourceCache.h" -#include "AsyncLoader.h" -#include "ResourceHandle.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace XCEngine { -namespace Resources { - -class ResourceManager { -public: - class ScopedDeferredSceneLoad { - public: - explicit ScopedDeferredSceneLoad(ResourceManager& manager = ResourceManager::Get()); - ScopedDeferredSceneLoad(const ScopedDeferredSceneLoad&) = delete; - ScopedDeferredSceneLoad& operator=(const ScopedDeferredSceneLoad&) = delete; - ~ScopedDeferredSceneLoad(); - - private: - ResourceManager* m_manager = nullptr; - }; - - static ResourceManager& Get(); - - void Initialize(); - void Shutdown(); - - void SetResourceRoot(const Containers::String& rootPath); - const Containers::String& GetResourceRoot() const; - bool BootstrapProjectAssets(); - - template - ResourceHandle Load(const Containers::String& path, ImportSettings* settings = nullptr) { - static_assert(std::is_base_of_v, "T must derive from IResource"); - - LoadResult result = LoadResource(path, GetResourceType(), settings); - if (!result || result.resource == nullptr) { - return ResourceHandle(); - } - - return ResourceHandle(static_cast(result.resource)); - } - - template - ResourceHandle Load(const AssetRef& assetRef, ImportSettings* settings = nullptr) { - static_assert(std::is_base_of_v, "T must derive from IResource"); - - Containers::String path; - if (!TryResolveAssetPath(assetRef, path)) { - return ResourceHandle(); - } - - return Load(path, settings); - } - - void LoadAsync(const Containers::String& path, ResourceType type, - std::function callback); - void LoadAsync(const Containers::String& path, ResourceType type, ImportSettings* settings, - std::function callback); - void UpdateAsyncLoads(); - bool IsAsyncLoading() const; - Core::uint32 GetAsyncPendingCount() const; - - void Unload(const Containers::String& path); - void Unload(ResourceGUID guid); - void UnloadUnused(); - void UnloadAll(); - - void AddRef(ResourceGUID guid); - void Release(ResourceGUID guid); - Core::uint32 GetRefCount(ResourceGUID guid) const; - - void RegisterLoader(IResourceLoader* loader); - void UnregisterLoader(ResourceType type); - IResourceLoader* GetLoader(ResourceType type) const; - - void SetMemoryBudget(size_t bytes); - size_t GetMemoryUsage() const; - size_t GetMemoryBudget() const; - void FlushCache(); - - IResource* Find(const Containers::String& path); - IResource* Find(ResourceGUID guid); - bool Exists(const Containers::String& path) const; - bool Exists(ResourceGUID guid) const; - - Containers::String ResolvePath(const Containers::String& relativePath) const; - - template - void LoadGroup(const Containers::Array& paths, - std::function)> callback) { - for (const auto& path : paths) { - LoadAsync(path, GetResourceType(), [callback](LoadResult result) { - if (result && result.resource) { - callback(ResourceHandle(static_cast(result.resource))); - } else { - callback(ResourceHandle()); - } - }); - } - } - - Containers::Array GetResourcePaths() const; - void UnloadGroup(const Containers::Array& guids); - void RefreshProjectAssets(); - bool CanReimportProjectAsset(const Containers::String& path) const; - bool ReimportProjectAsset(const Containers::String& path); - bool ClearProjectLibraryCache(); - bool RebuildProjectAssetCache(); - Containers::String GetProjectLibraryRoot() const; - AssetImportService::ImportStatusSnapshot GetProjectAssetImportStatus() const; - bool TryGetAssetRef(const Containers::String& path, ResourceType resourceType, AssetRef& outRef) const; - bool TryResolveAssetPath(const AssetRef& assetRef, Containers::String& outPath) const; - void BeginDeferredSceneLoad(); - void EndDeferredSceneLoad(); - bool IsDeferredSceneLoadEnabled() const; - -private: - struct InFlightLoadKey { - ResourceGUID guid; - ResourceType type = ResourceType::Unknown; - - bool operator==(const InFlightLoadKey& other) const { - return guid == other.guid && type == other.type; - } - }; - - struct InFlightLoadKeyHasher { - size_t operator()(const InFlightLoadKey& key) const noexcept { - return std::hash{}(key.guid) ^ - (static_cast(key.type) << 1); - } - }; - - struct InFlightLoadState { - bool completed = false; - bool success = false; - Containers::String errorMessage; - std::condition_variable condition; - }; - - ResourceManager() = default; - ~ResourceManager() = default; - - void EnsureInitialized(); - IResource* FindInCache(ResourceGUID guid); - void AddToCache(ResourceGUID guid, IResource* resource); - IResourceLoader* FindLoader(ResourceType type); - void ReloadResource(ResourceGUID guid); - LoadResult LoadResource(const Containers::String& path, ResourceType type, ImportSettings* settings); - - Containers::String m_resourceRoot; - Containers::HashMap m_resourceCache; - Containers::HashMap m_refCounts; - Containers::HashMap m_guidToPath; - Containers::HashMap m_loaders; - - size_t m_memoryUsage = 0; - size_t m_memoryBudget = 512 * 1024 * 1024; - - mutable AssetImportService m_assetImportService; - mutable ProjectAssetIndex m_projectAssetIndex; - ResourceCache m_cache; - Core::UniqueRef m_asyncLoader; - Threading::Mutex m_mutex; - std::mutex m_initializeMutex; - std::mutex m_inFlightLoadsMutex; - std::unordered_map, InFlightLoadKeyHasher> m_inFlightLoads; - std::atomic m_deferredSceneLoadDepth{0}; - - friend class ResourceHandleBase; - friend class AsyncLoader; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Core/Asset/ResourceTypes.h b/engine/include/XCEngine/Core/Asset/ResourceTypes.h index fe33cfb1..0089b3bf 100644 --- a/engine/include/XCEngine/Core/Asset/ResourceTypes.h +++ b/engine/include/XCEngine/Core/Asset/ResourceTypes.h @@ -1,114 +1,3 @@ #pragma once -#include -#include -#include -#include -#include - -namespace XCEngine { -namespace Resources { - -enum class ResourceType : Core::uint8 { - Unknown = 0, - Texture, - Mesh, - Material, - Shader, - AudioClip, - Binary, - AnimationClip, - Skeleton, - Font, - ParticleSystem, - Scene, - Prefab, - UIView, - UITheme, - UISchema, - VolumeField, - Model, - GaussianSplat, - RenderPipelineAsset -}; - -constexpr const char* GetResourceTypeName(ResourceType type) { - switch (type) { - case ResourceType::Texture: return "Texture"; - case ResourceType::Mesh: return "Mesh"; - case ResourceType::Material: return "Material"; - case ResourceType::Shader: return "Shader"; - case ResourceType::AudioClip: return "AudioClip"; - case ResourceType::Binary: return "Binary"; - case ResourceType::AnimationClip: return "AnimationClip"; - case ResourceType::Skeleton: return "Skeleton"; - case ResourceType::Font: return "Font"; - case ResourceType::ParticleSystem: return "ParticleSystem"; - case ResourceType::Scene: return "Scene"; - case ResourceType::Prefab: return "Prefab"; - case ResourceType::UIView: return "UIView"; - case ResourceType::UITheme: return "UITheme"; - case ResourceType::UISchema: return "UISchema"; - case ResourceType::VolumeField: return "VolumeField"; - case ResourceType::Model: return "Model"; - case ResourceType::GaussianSplat: return "GaussianSplat"; - case ResourceType::RenderPipelineAsset: return "RenderPipelineAsset"; - default: return "Unknown"; - } -} - -struct ResourceGUID { - Core::uint64 value; - - ResourceGUID() : value(0) {} - explicit ResourceGUID(Core::uint64 v) : value(v) {} - - bool IsValid() const { return value != 0; } - - bool operator==(const ResourceGUID& other) const { return value == other.value; } - bool operator!=(const ResourceGUID& other) const { return value != other.value; } - - static ResourceGUID Generate(const char* path); - static ResourceGUID Generate(const Containers::String& path); - - Containers::String ToString() const; -}; - -inline ResourceGUID MakeResourceGUID(const char* path) { - return ResourceGUID::Generate(path); -} - -} // namespace Resources - -} // namespace XCEngine - -namespace std { -template<> -struct hash { - size_t operator()(const XCEngine::Resources::ResourceGUID& guid) const noexcept { - return static_cast(guid.value); - } -}; -} - -namespace XCEngine { -namespace Resources { - -template -ResourceType GetResourceType(); - -template<> inline ResourceType GetResourceType() { return ResourceType::Texture; } -template<> inline ResourceType GetResourceType() { return ResourceType::Mesh; } -template<> inline ResourceType GetResourceType() { return ResourceType::Material; } -template<> inline ResourceType GetResourceType() { return ResourceType::Shader; } -template<> inline ResourceType GetResourceType() { return ResourceType::AudioClip; } -template<> inline ResourceType GetResourceType() { return ResourceType::Binary; } -template<> inline ResourceType GetResourceType() { return ResourceType::UIView; } -template<> inline ResourceType GetResourceType() { return ResourceType::UITheme; } -template<> inline ResourceType GetResourceType() { return ResourceType::UISchema; } -template<> inline ResourceType GetResourceType() { return ResourceType::VolumeField; } -template<> inline ResourceType GetResourceType() { return ResourceType::Model; } -template<> inline ResourceType GetResourceType() { return ResourceType::GaussianSplat; } - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Rendering/Caches/DirectionalShadowSurfaceCache.h b/engine/include/XCEngine/Rendering/Caches/DirectionalShadowSurfaceCache.h index 46f4b1c8..94fedfb8 100644 --- a/engine/include/XCEngine/Rendering/Caches/DirectionalShadowSurfaceCache.h +++ b/engine/include/XCEngine/Rendering/Caches/DirectionalShadowSurfaceCache.h @@ -1,51 +1,3 @@ #pragma once -#include - -namespace XCEngine { -namespace RHI { -class RHIDevice; -class RHIResourceView; -class RHITexture; -} // namespace RHI - -namespace Rendering { - -struct DirectionalShadowRenderPlan; -struct RenderContext; - -struct DirectionalShadowSurfaceAllocation { - RenderSurface surface = {}; - RHI::RHIResourceView* depthShaderView = nullptr; - - bool IsValid() const { - return surface.GetDepthAttachment() != nullptr && - depthShaderView != nullptr; - } -}; - -class DirectionalShadowSurfaceCache { -public: - DirectionalShadowSurfaceCache() = default; - DirectionalShadowSurfaceCache(const DirectionalShadowSurfaceCache&) = delete; - DirectionalShadowSurfaceCache& operator=(const DirectionalShadowSurfaceCache&) = delete; - ~DirectionalShadowSurfaceCache(); - - const DirectionalShadowSurfaceAllocation* Resolve( - const RenderContext& context, - const DirectionalShadowRenderPlan& plan); - -private: - bool Matches(const RenderContext& context, const DirectionalShadowRenderPlan& plan) const; - void Reset(); - - RHI::RHIDevice* m_device = nullptr; - uint32_t m_width = 0; - uint32_t m_height = 0; - RHI::RHITexture* m_depthTexture = nullptr; - RHI::RHIResourceView* m_depthView = nullptr; - DirectionalShadowSurfaceAllocation m_allocation = {}; -}; - -} // namespace Rendering -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Rendering/Caches/RenderResourceCache.h b/engine/include/XCEngine/Rendering/Caches/RenderResourceCache.h index 46541a94..4eb9c504 100644 --- a/engine/include/XCEngine/Rendering/Caches/RenderResourceCache.h +++ b/engine/include/XCEngine/Rendering/Caches/RenderResourceCache.h @@ -1,160 +1,3 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace XCEngine { -namespace Rendering { - -class RenderResourceCache { -public: - enum class GaussianSplatResidencyState { - Uninitialized = 0, - CpuReady, - GpuUploading, - GpuReady, - Failed - }; - - struct CachedMesh { - RHI::RHIBuffer* vertexBuffer = nullptr; - RHI::RHIResourceView* vertexBufferView = nullptr; - RHI::RHIBuffer* indexBuffer = nullptr; - RHI::RHIResourceView* indexBufferView = nullptr; - uint32_t vertexCount = 0; - uint32_t indexCount = 0; - uint32_t vertexStride = 0; - bool uses32BitIndices = false; - }; - - struct CachedTexture { - RHI::RHITexture* texture = nullptr; - RHI::RHIResourceView* shaderResourceView = nullptr; - uint32_t width = 0; - uint32_t height = 0; - }; - - struct CachedBufferView { - RHI::RHIResourceView* resourceView = nullptr; - }; - - struct CachedVolumeField { - RHI::RHIBuffer* payloadBuffer = nullptr; - RHI::RHIResourceView* shaderResourceView = nullptr; - uint32_t elementStride = 0; - uint32_t elementCount = 0; - uint64_t payloadSize = 0; - Resources::VolumeStorageKind storageKind = Resources::VolumeStorageKind::Unknown; - }; - - struct CachedGaussianSplatSection { - RHI::RHIBuffer* buffer = nullptr; - RHI::RHIResourceView* shaderResourceView = nullptr; - Resources::GaussianSplatSectionType type = Resources::GaussianSplatSectionType::Unknown; - Resources::GaussianSplatSectionFormat format = Resources::GaussianSplatSectionFormat::Unknown; - uint32_t elementStride = 0; - uint32_t elementCount = 0; - uint64_t payloadSize = 0; - }; - - struct CachedGaussianSplat { - GaussianSplatResidencyState residencyState = GaussianSplatResidencyState::Uninitialized; - uint32_t contentVersion = 0; - uint32_t splatCount = 0; - uint32_t chunkCount = 0; - uint32_t cameraCount = 0; - Math::Bounds bounds; - CachedGaussianSplatSection positions; - CachedGaussianSplatSection other; - CachedGaussianSplatSection color; - CachedGaussianSplatSection sh; - CachedGaussianSplatSection chunks; - }; - - ~RenderResourceCache(); - - void Shutdown(); - - const CachedMesh* GetOrCreateMesh(RHI::RHIDevice* device, const Resources::Mesh* mesh); - const CachedTexture* GetOrCreateTexture(RHI::RHIDevice* device, const Resources::Texture* texture); - const CachedVolumeField* GetOrCreateVolumeField( - RHI::RHIDevice* device, - const Resources::VolumeField* volumeField); - const CachedGaussianSplat* GetOrCreateGaussianSplat( - RHI::RHIDevice* device, - const Resources::GaussianSplat* gaussianSplat); - const CachedBufferView* GetOrCreateBufferView( - RHI::RHIDevice* device, - RHI::RHIBuffer* buffer, - RHI::ResourceViewType viewType, - const RHI::ResourceViewDesc& viewDesc); - -private: - struct BufferViewCacheKey { - const RHI::RHIBuffer* buffer = nullptr; - RHI::ResourceViewType viewType = RHI::ResourceViewType::ShaderResource; - uint32_t format = 0; - RHI::ResourceViewDimension dimension = RHI::ResourceViewDimension::Unknown; - uint64_t bufferLocation = 0; - uint32_t firstElement = 0; - uint32_t elementCount = 0; - uint32_t structureByteStride = 0; - - bool operator==(const BufferViewCacheKey& other) const { - return buffer == other.buffer && - viewType == other.viewType && - format == other.format && - dimension == other.dimension && - bufferLocation == other.bufferLocation && - firstElement == other.firstElement && - elementCount == other.elementCount && - structureByteStride == other.structureByteStride; - } - }; - - struct BufferViewCacheKeyHash { - size_t operator()(const BufferViewCacheKey& key) const noexcept; - }; - - bool UploadMesh(RHI::RHIDevice* device, const Resources::Mesh* mesh, CachedMesh& cachedMesh); - bool UploadTexture(RHI::RHIDevice* device, const Resources::Texture* texture, CachedTexture& cachedTexture); - bool UploadVolumeField( - RHI::RHIDevice* device, - const Resources::VolumeField* volumeField, - CachedVolumeField& cachedVolumeField); - bool UploadGaussianSplat( - RHI::RHIDevice* device, - const Resources::GaussianSplat* gaussianSplat, - CachedGaussianSplat& cachedGaussianSplat); - bool UploadGaussianSplatSection( - RHI::RHIDevice* device, - const Resources::GaussianSplat* gaussianSplat, - Resources::GaussianSplatSectionType sectionType, - Resources::GaussianSplatSectionFormat requiredFormat, - uint32_t requiredStride, - bool requiredSection, - CachedGaussianSplatSection& cachedSection); - bool CreateBufferView( - RHI::RHIDevice* device, - RHI::RHIBuffer* buffer, - RHI::ResourceViewType viewType, - const RHI::ResourceViewDesc& viewDesc, - CachedBufferView& cachedBufferView); - - std::unordered_map m_meshCache; - std::unordered_map m_textureCache; - std::unordered_map m_volumeFieldCache; - std::unordered_map m_gaussianSplatCache; - std::unordered_map m_bufferViewCache; -}; - -} // namespace Rendering -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Rendering/FrameData/CullingResults.h b/engine/include/XCEngine/Rendering/FrameData/CullingResults.h index 9d3fbf1d..e8c1edfb 100644 --- a/engine/include/XCEngine/Rendering/FrameData/CullingResults.h +++ b/engine/include/XCEngine/Rendering/FrameData/CullingResults.h @@ -1,104 +1,3 @@ #pragma once -#include - -#include -#include -#include - -namespace XCEngine { -namespace Rendering { - -enum class RendererListType : Core::uint32 { - AllVisible = 0, - Opaque = 1, - Transparent = 2, - ShadowCaster = 3, - ObjectId = 4 -}; - -enum class RendererSortMode : Core::uint32 { - None = 0, - FrontToBack = 1, - BackToFront = 2 -}; - -struct FilteringSettings { - Core::int32 renderQueueMin = std::numeric_limits::lowest(); - Core::int32 renderQueueMax = std::numeric_limits::max(); - Core::uint32 renderLayerMask = std::numeric_limits::max(); - bool requireShadowCasting = false; - bool requireRenderObjectId = false; - - bool operator==(const FilteringSettings& other) const { - return renderQueueMin == other.renderQueueMin && - renderQueueMax == other.renderQueueMax && - renderLayerMask == other.renderLayerMask && - requireShadowCasting == other.requireShadowCasting && - requireRenderObjectId == other.requireRenderObjectId; - } -}; - -struct SortingSettings { - RendererSortMode sortMode = RendererSortMode::None; - - bool operator==(const SortingSettings& other) const { - return sortMode == other.sortMode; - } -}; - -struct RendererListDesc { - RendererListType type = RendererListType::AllVisible; - FilteringSettings filtering = {}; - SortingSettings sorting = {}; - - bool operator==(const RendererListDesc& other) const { - return type == other.type && - filtering == other.filtering && - sorting == other.sorting; - } -}; - -struct RendererList { - RendererListDesc desc = {}; - std::vector visibleRenderItemIndices; - - bool Empty() const { - return visibleRenderItemIndices.empty(); - } - - size_t Size() const { - return visibleRenderItemIndices.size(); - } -}; - -struct CullingResults { - std::vector rendererLists; - - void Clear() { - rendererLists.clear(); - } - - RendererList* FindRendererList(RendererListType type) { - for (RendererList& rendererList : rendererLists) { - if (rendererList.desc.type == type) { - return &rendererList; - } - } - - return nullptr; - } - - const RendererList* FindRendererList(RendererListType type) const { - for (const RendererList& rendererList : rendererLists) { - if (rendererList.desc.type == type) { - return &rendererList; - } - } - - return nullptr; - } -}; - -} // namespace Rendering -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Rendering/FrameData/RenderCameraData.h b/engine/include/XCEngine/Rendering/FrameData/RenderCameraData.h index be29a1b8..df76bc59 100644 --- a/engine/include/XCEngine/Rendering/FrameData/RenderCameraData.h +++ b/engine/include/XCEngine/Rendering/FrameData/RenderCameraData.h @@ -1,54 +1,3 @@ #pragma once -#include -#include -#include - -#include - -namespace XCEngine { -namespace Rendering { - -enum class RenderClearFlags : uint8_t { - None = 0, - Color = 1 << 0, - Depth = 1 << 1, - All = (1 << 0) | (1 << 1) -}; - -constexpr RenderClearFlags operator|(RenderClearFlags lhs, RenderClearFlags rhs) { - return static_cast( - static_cast(lhs) | static_cast(rhs)); -} - -constexpr RenderClearFlags operator&(RenderClearFlags lhs, RenderClearFlags rhs) { - return static_cast( - static_cast(lhs) & static_cast(rhs)); -} - -constexpr bool HasRenderClearFlag(RenderClearFlags flags, RenderClearFlags flag) { - return static_cast(flags & flag) != 0; -} - -struct RenderCameraData { - Math::Matrix4x4 view = Math::Matrix4x4::Identity(); - Math::Matrix4x4 projection = Math::Matrix4x4::Identity(); - Math::Matrix4x4 viewProjection = Math::Matrix4x4::Identity(); - Math::Vector3 worldPosition = Math::Vector3::Zero(); - Math::Vector3 worldRight = Math::Vector3::Right(); - Math::Vector3 worldUp = Math::Vector3::Up(); - Math::Vector3 worldForward = Math::Vector3::Forward(); - Math::Color clearColor = Math::Color::Black(); - RenderClearFlags clearFlags = RenderClearFlags::All; - bool perspectiveProjection = true; - float verticalFovRadians = 60.0f * Math::DEG_TO_RAD; - float orthographicSize = 5.0f; - float aspectRatio = 1.0f; - float nearClipPlane = 0.1f; - float farClipPlane = 1000.0f; - uint32_t viewportWidth = 0; - uint32_t viewportHeight = 0; -}; - -} // namespace Rendering -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Rendering/FrameData/RenderEnvironmentData.h b/engine/include/XCEngine/Rendering/FrameData/RenderEnvironmentData.h index add5274e..0a503f6b 100644 --- a/engine/include/XCEngine/Rendering/FrameData/RenderEnvironmentData.h +++ b/engine/include/XCEngine/Rendering/FrameData/RenderEnvironmentData.h @@ -1,55 +1,3 @@ #pragma once -#include - -#include - -namespace XCEngine { -namespace Resources { -class Material; -} // namespace Resources -} // namespace XCEngine - -namespace XCEngine { -namespace Rendering { - -enum class RenderEnvironmentMode : uint32_t { - None = 0, - ProceduralSkybox, - MaterialSkybox -}; - -struct ProceduralSkyboxData { - Math::Color topColor = Math::Color(0.18f, 0.36f, 0.74f, 1.0f); - Math::Color horizonColor = Math::Color(0.78f, 0.84f, 0.92f, 1.0f); - Math::Color bottomColor = Math::Color(0.92f, 0.93f, 0.95f, 1.0f); -}; - -struct MaterialSkyboxData { - const Resources::Material* material = nullptr; - - bool IsValid() const { - return material != nullptr; - } -}; - -struct RenderEnvironmentData { - RenderEnvironmentMode mode = RenderEnvironmentMode::None; - ProceduralSkyboxData skybox = {}; - MaterialSkyboxData materialSkybox = {}; - - bool HasProceduralSkybox() const { - return mode == RenderEnvironmentMode::ProceduralSkybox; - } - - bool HasMaterialSkybox() const { - return mode == RenderEnvironmentMode::MaterialSkybox && materialSkybox.IsValid(); - } - - bool HasSkybox() const { - return HasProceduralSkybox() || HasMaterialSkybox(); - } -}; - -} // namespace Rendering -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Rendering/FrameData/RenderSceneData.h b/engine/include/XCEngine/Rendering/FrameData/RenderSceneData.h index a348fbed..ff8c45c1 100644 --- a/engine/include/XCEngine/Rendering/FrameData/RenderSceneData.h +++ b/engine/include/XCEngine/Rendering/FrameData/RenderSceneData.h @@ -1,106 +1,3 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -namespace XCEngine { -namespace Components { -class CameraComponent; -} // namespace Components - -namespace Rendering { - -struct RenderDirectionalLightData { - bool enabled = false; - bool castsShadows = false; - Math::Vector3 direction = Math::Vector3::Back(); - float intensity = 1.0f; - Math::Color color = Math::Color::White(); -}; - -enum class RenderLightType : uint32_t { - Directional = 0, - Point = 1, - Spot = 2 -}; - -struct RenderAdditionalLightData { - RenderLightType type = RenderLightType::Point; - bool enabled = false; - bool castsShadows = false; - Math::Color color = Math::Color::White(); - float intensity = 1.0f; - Math::Vector3 position = Math::Vector3::Zero(); - Math::Vector3 direction = Math::Vector3::Back(); - float range = 0.0f; - float spotAngle = 0.0f; -}; - -struct RenderLightingData { - static constexpr uint32_t kMaxAdditionalLightCount = 8u; - - RenderDirectionalLightData mainDirectionalLight; - RenderDirectionalShadowData mainDirectionalShadow; - std::array additionalLights = {}; - uint32_t additionalLightCount = 0u; - - bool HasMainDirectionalLight() const { - return mainDirectionalLight.enabled; - } - - bool HasMainDirectionalShadow() const { - return mainDirectionalShadow.IsValid(); - } - - bool HasAdditionalLights() const { - return additionalLightCount > 0u; - } -}; - -struct RenderSceneData { - Components::CameraComponent* camera = nullptr; - RenderCameraData cameraData; - RenderEnvironmentData environment; - RenderLightingData lighting; - Resources::ShaderKeywordSet globalShaderKeywords; - CullingResults cullingResults; - std::vector visibleItems; - std::vector visibleGaussianSplats; - std::vector visibleVolumes; - - bool HasCamera() const { - return camera != nullptr; - } - - RendererList* FindRendererList(RendererListType type) { - return cullingResults.FindRendererList(type); - } - - const RendererList* FindRendererList(RendererListType type) const { - return cullingResults.FindRendererList(type); - } - - const VisibleRenderItem* TryGetVisibleRenderItem(Core::uint32 index) const { - if (index >= visibleItems.size()) { - return nullptr; - } - - return &visibleItems[index]; - } -}; - -} // namespace Rendering -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Rendering/FrameData/RendererListUtils.h b/engine/include/XCEngine/Rendering/FrameData/RendererListUtils.h index 464aab28..00996b5b 100644 --- a/engine/include/XCEngine/Rendering/FrameData/RendererListUtils.h +++ b/engine/include/XCEngine/Rendering/FrameData/RendererListUtils.h @@ -1,218 +1,3 @@ #pragma once -#include -#include -#include - -#include -#include -#include - -namespace XCEngine { -namespace Rendering { - -inline FilteringSettings BuildDefaultFilteringSettings(RendererListType type) { - FilteringSettings filtering = {}; - - switch (type) { - case RendererListType::AllVisible: - break; - case RendererListType::Opaque: - filtering.renderQueueMax = - static_cast(Resources::MaterialRenderQueue::Transparent) - 1; - break; - case RendererListType::Transparent: - filtering.renderQueueMin = - static_cast(Resources::MaterialRenderQueue::Transparent); - break; - case RendererListType::ShadowCaster: - filtering.requireShadowCasting = true; - break; - case RendererListType::ObjectId: - filtering.requireRenderObjectId = true; - break; - } - - return filtering; -} - -inline SortingSettings BuildDefaultSortingSettings(RendererListType type) { - SortingSettings sorting = {}; - - switch (type) { - case RendererListType::Opaque: - case RendererListType::ShadowCaster: - case RendererListType::ObjectId: - sorting.sortMode = RendererSortMode::FrontToBack; - break; - case RendererListType::Transparent: - sorting.sortMode = RendererSortMode::BackToFront; - break; - case RendererListType::AllVisible: - sorting.sortMode = RendererSortMode::None; - break; - } - - return sorting; -} - -inline RendererListDesc BuildDefaultRendererListDesc(RendererListType type) { - RendererListDesc desc = {}; - desc.type = type; - desc.filtering = BuildDefaultFilteringSettings(type); - desc.sorting = BuildDefaultSortingSettings(type); - return desc; -} - -inline bool MatchesFilteringSettings( - const VisibleRenderItem& visibleItem, - const FilteringSettings& filtering) { - if (visibleItem.renderQueue < filtering.renderQueueMin || - visibleItem.renderQueue > filtering.renderQueueMax) { - return false; - } - - if (visibleItem.renderLayer >= 32u || - ((filtering.renderLayerMask & - (1u << visibleItem.renderLayer)) == 0u)) { - return false; - } - - if (filtering.requireShadowCasting && - visibleItem.meshRenderer != nullptr && - !visibleItem.meshRenderer->GetCastShadows()) { - return false; - } - - if (filtering.requireRenderObjectId && - !IsValidRenderObjectId(visibleItem.renderObjectId)) { - return false; - } - - return true; -} - -inline bool MatchesRendererListDesc( - const VisibleRenderItem& visibleItem, - const RendererListDesc& desc) { - return MatchesFilteringSettings(visibleItem, desc.filtering); -} - -inline RendererList BuildRendererList( - RendererListType type, - const std::vector& visibleItems) { - RendererList rendererList = {}; - rendererList.desc = BuildDefaultRendererListDesc(type); - rendererList.visibleRenderItemIndices.reserve(visibleItems.size()); - - for (Core::uint32 visibleItemIndex = 0; - visibleItemIndex < static_cast(visibleItems.size()); - ++visibleItemIndex) { - if (!MatchesRendererListDesc( - visibleItems[visibleItemIndex], - rendererList.desc)) { - continue; - } - - rendererList.visibleRenderItemIndices.push_back(visibleItemIndex); - } - - return rendererList; -} - -template -inline void VisitRendererListVisibleItems( - const RenderSceneData& sceneData, - RendererListType rendererListType, - Visitor&& visitor) { - const RendererList* rendererList = sceneData.FindRendererList(rendererListType); - if (rendererList != nullptr) { - for (Core::uint32 visibleItemIndex : rendererList->visibleRenderItemIndices) { - const VisibleRenderItem* visibleItem = - sceneData.TryGetVisibleRenderItem(visibleItemIndex); - if (visibleItem == nullptr) { - continue; - } - - visitor(*visibleItem); - } - return; - } - - const RendererListDesc fallbackDesc = BuildDefaultRendererListDesc(rendererListType); - for (const VisibleRenderItem& visibleItem : sceneData.visibleItems) { - if (!MatchesRendererListDesc(visibleItem, fallbackDesc)) { - continue; - } - - visitor(visibleItem); - } -} - -template -inline void VisitRendererListVisibleItems( - const RenderSceneData& sceneData, - const RendererListDesc& rendererListDesc, - Visitor&& visitor) { - const RendererListDesc defaultDesc = - BuildDefaultRendererListDesc( - rendererListDesc.type); - if (rendererListDesc == defaultDesc) { - VisitRendererListVisibleItems( - sceneData, - rendererListDesc.type, - std::forward(visitor)); - return; - } - - std::vector matchedItems; - matchedItems.reserve(sceneData.visibleItems.size()); - for (const VisibleRenderItem& visibleItem : sceneData.visibleItems) { - if (!MatchesRendererListDesc( - visibleItem, - rendererListDesc)) { - continue; - } - - matchedItems.push_back(&visibleItem); - } - - switch (rendererListDesc.sorting.sortMode) { - case RendererSortMode::FrontToBack: - std::stable_sort( - matchedItems.begin(), - matchedItems.end(), - [](const VisibleRenderItem* lhs, const VisibleRenderItem* rhs) { - return lhs != nullptr && - rhs != nullptr && - lhs->cameraDistanceSq < - rhs->cameraDistanceSq; - }); - break; - case RendererSortMode::BackToFront: - std::stable_sort( - matchedItems.begin(), - matchedItems.end(), - [](const VisibleRenderItem* lhs, const VisibleRenderItem* rhs) { - return lhs != nullptr && - rhs != nullptr && - lhs->cameraDistanceSq > - rhs->cameraDistanceSq; - }); - break; - case RendererSortMode::None: - default: - break; - } - - for (const VisibleRenderItem* visibleItem : matchedItems) { - if (visibleItem == nullptr) { - continue; - } - - visitor(*visibleItem); - } -} - -} // namespace Rendering -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Rendering/FrameData/VisibleGaussianSplatItem.h b/engine/include/XCEngine/Rendering/FrameData/VisibleGaussianSplatItem.h index 7f36e62d..3b7379db 100644 --- a/engine/include/XCEngine/Rendering/FrameData/VisibleGaussianSplatItem.h +++ b/engine/include/XCEngine/Rendering/FrameData/VisibleGaussianSplatItem.h @@ -1,30 +1,3 @@ #pragma once -#include -#include - -namespace XCEngine { -namespace Components { -class GameObject; -class GaussianSplatRendererComponent; -} // namespace Components - -namespace Resources { -class GaussianSplat; -class Material; -} // namespace Resources - -namespace Rendering { - -struct VisibleGaussianSplatItem { - Components::GameObject* gameObject = nullptr; - Components::GaussianSplatRendererComponent* gaussianSplatRenderer = nullptr; - Resources::GaussianSplat* gaussianSplat = nullptr; - const Resources::Material* material = nullptr; - Core::int32 renderQueue = 0; - float cameraDistanceSq = 0.0f; - Math::Matrix4x4 localToWorld = Math::Matrix4x4::Identity(); -}; - -} // namespace Rendering -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Rendering/FrameData/VisibleRenderItem.h b/engine/include/XCEngine/Rendering/FrameData/VisibleRenderItem.h index 7174443d..550efbc6 100644 --- a/engine/include/XCEngine/Rendering/FrameData/VisibleRenderItem.h +++ b/engine/include/XCEngine/Rendering/FrameData/VisibleRenderItem.h @@ -1,34 +1,3 @@ #pragma once -#include -#include -#include -#include - -namespace XCEngine { -namespace Components { -class GameObject; -class MeshFilterComponent; -class MeshRendererComponent; -} // namespace Components - -namespace Rendering { - -struct VisibleRenderItem { - Components::GameObject* gameObject = nullptr; - Components::MeshFilterComponent* meshFilter = nullptr; - Components::MeshRendererComponent* meshRenderer = nullptr; - Resources::Mesh* mesh = nullptr; - const Resources::Material* material = nullptr; - RenderObjectId renderObjectId = kInvalidRenderObjectId; - Core::uint32 materialIndex = 0; - Core::uint32 sectionIndex = 0; - bool hasSection = false; - Core::uint32 renderLayer = 0; - Core::int32 renderQueue = 0; - float cameraDistanceSq = 0.0f; - Math::Matrix4x4 localToWorld = Math::Matrix4x4::Identity(); -}; - -} // namespace Rendering -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Rendering/FrameData/VisibleVolumeItem.h b/engine/include/XCEngine/Rendering/FrameData/VisibleVolumeItem.h index 4337419d..2eeae6e4 100644 --- a/engine/include/XCEngine/Rendering/FrameData/VisibleVolumeItem.h +++ b/engine/include/XCEngine/Rendering/FrameData/VisibleVolumeItem.h @@ -1,30 +1,3 @@ #pragma once -#include -#include - -namespace XCEngine { -namespace Components { -class GameObject; -class VolumeRendererComponent; -} // namespace Components - -namespace Resources { -class Material; -class VolumeField; -} // namespace Resources - -namespace Rendering { - -struct VisibleVolumeItem { - Components::GameObject* gameObject = nullptr; - Components::VolumeRendererComponent* volumeRenderer = nullptr; - Resources::VolumeField* volumeField = nullptr; - const Resources::Material* material = nullptr; - Core::int32 renderQueue = 0; - float cameraDistanceSq = 0.0f; - Math::Matrix4x4 localToWorld = Math::Matrix4x4::Identity(); -}; - -} // namespace Rendering -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Rendering/Materials/RenderMaterialResolve.h b/engine/include/XCEngine/Rendering/Materials/RenderMaterialResolve.h index a45e5e12..3b0d8e0c 100644 --- a/engine/include/XCEngine/Rendering/Materials/RenderMaterialResolve.h +++ b/engine/include/XCEngine/Rendering/Materials/RenderMaterialResolve.h @@ -1,509 +1,3 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -namespace XCEngine { -namespace Rendering { - -enum class BuiltinSkyboxTextureMode : Core::uint8 { - None = 0, - Panoramic = 1, - Cubemap = 2 -}; - -struct BuiltinSkyboxMaterialData { - Math::Vector4 tint = Math::Vector4::One(); - float exposure = 1.0f; - float rotationDegrees = 0.0f; - BuiltinSkyboxTextureMode textureMode = BuiltinSkyboxTextureMode::None; -}; - -struct BuiltinDepthStyleMaterialConstants { - Math::Vector4 baseColorFactor = Math::Vector4::One(); - Math::Vector4 alphaCutoffParams = Math::Vector4(0.5f, 0.0f, 0.0f, 0.0f); -}; - -struct MaterialConstantLayoutView { - const Resources::MaterialConstantFieldDesc* fields = nullptr; - size_t count = 0; - size_t size = 0; - - bool IsValid() const { - return fields != nullptr && count > 0 && size > 0; - } -}; - -struct MaterialConstantPayloadView { - const void* data = nullptr; - size_t size = 0; - MaterialConstantLayoutView layout = {}; - - bool IsValid() const { - return data != nullptr && size > 0 && layout.IsValid() && layout.size == size; - } -}; - -struct MaterialBufferResourceView { - RHI::RHIBuffer* buffer = nullptr; - RHI::ResourceViewType viewType = RHI::ResourceViewType::ShaderResource; - RHI::ResourceViewDesc viewDesc = {}; - - bool IsValid() const { - return buffer != nullptr && - (viewType == RHI::ResourceViewType::ShaderResource || - viewType == RHI::ResourceViewType::UnorderedAccess) && - viewDesc.dimension != RHI::ResourceViewDimension::Unknown; - } -}; - -inline bool IsMaterialBufferResourceType(Resources::ShaderResourceType type) { - switch (type) { - case Resources::ShaderResourceType::StructuredBuffer: - case Resources::ShaderResourceType::RawBuffer: - case Resources::ShaderResourceType::RWStructuredBuffer: - case Resources::ShaderResourceType::RWRawBuffer: - return true; - default: - return false; - } -} - -inline const Resources::ShaderPropertyDesc* FindShaderPropertyBySemantic( - const Resources::Material* material, - const Containers::String& semantic) { - if (material == nullptr || material->GetShader() == nullptr) { - return nullptr; - } - - const Containers::String normalizedSemantic = NormalizeBuiltinPassMetadataValue(semantic); - for (const Resources::ShaderPropertyDesc& property : material->GetShader()->GetProperties()) { - if (NormalizeBuiltinPassMetadataValue(property.semantic) == normalizedSemantic) { - return &property; - } - } - - return nullptr; -} - -inline Math::Vector4 ResolveBuiltinBaseColorFactor(const Resources::Material* material) { - if (material == nullptr) { - return Math::Vector4::One(); - } - - if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "BaseColor")) { - if (material->HasProperty(property->name) && - (property->type == Resources::ShaderPropertyType::Color || - property->type == Resources::ShaderPropertyType::Vector)) { - return material->GetFloat4(property->name); - } - } - - return Math::Vector4::One(); -} - -inline const Resources::Texture* ResolveBuiltinBaseColorTexture(const Resources::Material* material) { - if (material == nullptr) { - return nullptr; - } - - if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "BaseColorTexture")) { - const Resources::ResourceHandle textureHandle = material->GetTexture(property->name); - if (textureHandle.Get() != nullptr && textureHandle->IsValid()) { - return textureHandle.Get(); - } - } - - return nullptr; -} - -inline float ResolveBuiltinAlphaCutoff(const Resources::Material* material) { - if (material == nullptr) { - return 0.5f; - } - - if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "AlphaCutoff")) { - if (material->HasProperty(property->name) && - (property->type == Resources::ShaderPropertyType::Float || - property->type == Resources::ShaderPropertyType::Range)) { - return material->GetFloat(property->name); - } - } - - return 0.5f; -} - -inline bool IsCubemapSkyboxTextureType(Resources::TextureType type) { - return type == Resources::TextureType::TextureCube || - type == Resources::TextureType::TextureCubeArray; -} - -inline bool IsPanoramicSkyboxTextureType(Resources::TextureType type) { - return type == Resources::TextureType::Texture2D || - type == Resources::TextureType::Texture2DArray; -} - -inline const Resources::Texture* ResolveSkyboxPanoramicTexture(const Resources::Material* material) { - if (material == nullptr) { - return nullptr; - } - - if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "SkyboxPanoramicTexture")) { - const Resources::ResourceHandle textureHandle = material->GetTexture(property->name); - if (textureHandle.Get() != nullptr && - textureHandle->IsValid() && - IsPanoramicSkyboxTextureType(textureHandle->GetTextureType())) { - return textureHandle.Get(); - } - } - - if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "SkyboxTexture")) { - const Resources::ResourceHandle textureHandle = material->GetTexture(property->name); - if (textureHandle.Get() != nullptr && - textureHandle->IsValid() && - IsPanoramicSkyboxTextureType(textureHandle->GetTextureType())) { - return textureHandle.Get(); - } - } - - return nullptr; -} - -inline const Resources::Texture* ResolveSkyboxCubemapTexture(const Resources::Material* material) { - if (material == nullptr) { - return nullptr; - } - - if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "SkyboxTexture")) { - const Resources::ResourceHandle textureHandle = material->GetTexture(property->name); - if (textureHandle.Get() != nullptr && - textureHandle->IsValid() && - IsCubemapSkyboxTextureType(textureHandle->GetTextureType())) { - return textureHandle.Get(); - } - } - - return nullptr; -} - -inline BuiltinSkyboxTextureMode ResolveSkyboxTextureMode(const Resources::Material* material) { - if (ResolveSkyboxPanoramicTexture(material) != nullptr) { - return BuiltinSkyboxTextureMode::Panoramic; - } - if (ResolveSkyboxCubemapTexture(material) != nullptr) { - return BuiltinSkyboxTextureMode::Cubemap; - } - return BuiltinSkyboxTextureMode::None; -} - -inline Math::Vector4 ResolveSkyboxTint(const Resources::Material* material) { - if (material == nullptr) { - return Math::Vector4::One(); - } - - if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "Tint")) { - if (material->HasProperty(property->name) && - (property->type == Resources::ShaderPropertyType::Color || - property->type == Resources::ShaderPropertyType::Vector)) { - return material->GetFloat4(property->name); - } - } - - return Math::Vector4::One(); -} - -inline float ResolveSkyboxExposure(const Resources::Material* material) { - if (material == nullptr) { - return 1.0f; - } - - if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "Exposure")) { - if (material->HasProperty(property->name) && - (property->type == Resources::ShaderPropertyType::Float || - property->type == Resources::ShaderPropertyType::Range)) { - return material->GetFloat(property->name); - } - } - - return 1.0f; -} - -inline float ResolveSkyboxRotationDegrees(const Resources::Material* material) { - if (material == nullptr) { - return 0.0f; - } - - if (const Resources::ShaderPropertyDesc* property = FindShaderPropertyBySemantic(material, "Rotation")) { - if (material->HasProperty(property->name) && - (property->type == Resources::ShaderPropertyType::Float || - property->type == Resources::ShaderPropertyType::Range)) { - return material->GetFloat(property->name); - } - } - - return 0.0f; -} - -inline BuiltinSkyboxMaterialData BuildBuiltinSkyboxMaterialData(const Resources::Material* material) { - BuiltinSkyboxMaterialData data = {}; - data.tint = ResolveSkyboxTint(material); - data.exposure = ResolveSkyboxExposure(material); - data.rotationDegrees = ResolveSkyboxRotationDegrees(material); - data.textureMode = ResolveSkyboxTextureMode(material); - return data; -} - -inline MaterialConstantPayloadView ResolveSchemaMaterialConstantPayload(const Resources::Material* material) { - if (material == nullptr || material->GetShader() == nullptr) { - return {}; - } - - const Containers::Array& constantLayout = material->GetConstantLayout(); - const Containers::Array& constantBufferData = material->GetConstantBufferData(); - if (constantLayout.Empty() || constantBufferData.Empty()) { - return {}; - } - - MaterialConstantLayoutView layoutView = {}; - layoutView.fields = constantLayout.Data(); - layoutView.count = constantLayout.Size(); - layoutView.size = constantBufferData.Size(); - - return { constantBufferData.Data(), constantBufferData.Size(), layoutView }; -} - -inline BuiltinDepthStyleMaterialConstants BuildBuiltinDepthStyleMaterialConstants( - const Resources::Material* material) { - BuiltinDepthStyleMaterialConstants constants = {}; - constants.baseColorFactor = ResolveBuiltinBaseColorFactor(material); - constants.alphaCutoffParams = Math::Vector4(ResolveBuiltinAlphaCutoff(material), 0.0f, 0.0f, 0.0f); - return constants; -} - -inline MaterialConstantPayloadView ResolveBuiltinDepthStyleMaterialConstantPayload( - const Resources::Material* material, - BuiltinDepthStyleMaterialConstants& outConstants, - Resources::MaterialConstantFieldDesc (&outLayout)[2]) { - outConstants = BuildBuiltinDepthStyleMaterialConstants(material); - - outLayout[0].name = "gBaseColorFactor"; - outLayout[0].type = Resources::MaterialPropertyType::Float4; - outLayout[0].offset = 0u; - outLayout[0].size = static_cast(sizeof(Math::Vector4)); - outLayout[0].alignedSize = static_cast(sizeof(Math::Vector4)); - - outLayout[1].name = "gAlphaCutoffParams"; - outLayout[1].type = Resources::MaterialPropertyType::Float4; - outLayout[1].offset = static_cast(sizeof(Math::Vector4)); - outLayout[1].size = static_cast(sizeof(Math::Vector4)); - outLayout[1].alignedSize = static_cast(sizeof(Math::Vector4)); - - MaterialConstantLayoutView layoutView = {}; - layoutView.fields = outLayout; - layoutView.count = 2u; - layoutView.size = sizeof(BuiltinDepthStyleMaterialConstants); - - return { &outConstants, sizeof(BuiltinDepthStyleMaterialConstants), layoutView }; -} - -inline bool TryResolveMaterialBufferResourceView( - const Resources::Material* material, - const BuiltinPassResourceBindingDesc& binding, - MaterialBufferResourceView& outView) { - outView = {}; - if (material == nullptr || !IsMaterialBufferResourceType(binding.resourceType)) { - return false; - } - - const Resources::MaterialBufferBinding* materialBinding = material->FindBufferBinding(binding.name); - if (materialBinding == nullptr || materialBinding->buffer == nullptr) { - return false; - } - - outView.buffer = materialBinding->buffer; - outView.viewDesc.firstElement = materialBinding->viewDesc.firstElement; - outView.viewDesc.elementCount = materialBinding->viewDesc.elementCount; - - switch (binding.resourceType) { - case Resources::ShaderResourceType::StructuredBuffer: - outView.viewType = RHI::ResourceViewType::ShaderResource; - outView.viewDesc.dimension = RHI::ResourceViewDimension::StructuredBuffer; - outView.viewDesc.structureByteStride = - materialBinding->viewDesc.structureByteStride > 0 - ? materialBinding->viewDesc.structureByteStride - : materialBinding->buffer->GetStride(); - break; - case Resources::ShaderResourceType::RawBuffer: - outView.viewType = RHI::ResourceViewType::ShaderResource; - outView.viewDesc.dimension = RHI::ResourceViewDimension::RawBuffer; - break; - case Resources::ShaderResourceType::RWStructuredBuffer: - outView.viewType = RHI::ResourceViewType::UnorderedAccess; - outView.viewDesc.dimension = RHI::ResourceViewDimension::StructuredBuffer; - outView.viewDesc.structureByteStride = - materialBinding->viewDesc.structureByteStride > 0 - ? materialBinding->viewDesc.structureByteStride - : materialBinding->buffer->GetStride(); - break; - case Resources::ShaderResourceType::RWRawBuffer: - outView.viewType = RHI::ResourceViewType::UnorderedAccess; - outView.viewDesc.dimension = RHI::ResourceViewDimension::RawBuffer; - break; - default: - return false; - } - - if (outView.viewDesc.dimension == RHI::ResourceViewDimension::StructuredBuffer && - outView.viewDesc.structureByteStride == 0) { - outView = {}; - return false; - } - - return outView.IsValid(); -} - -inline const Resources::Material* ResolveMaterial( - const Components::MeshRendererComponent* meshRenderer, - const Resources::Mesh* mesh, - Core::uint32 materialIndex) { - if (meshRenderer != nullptr && materialIndex < meshRenderer->GetMaterialCount()) { - if (const Resources::Material* material = meshRenderer->GetMaterial(materialIndex)) { - return material; - } - } - - if (mesh != nullptr && materialIndex < mesh->GetMaterials().Size()) { - if (const Resources::Material* material = mesh->GetMaterials()[materialIndex]) { - return material; - } - } - - if (meshRenderer != nullptr && meshRenderer->GetMaterialCount() > 0) { - if (const Resources::Material* material = meshRenderer->GetMaterial(0)) { - return material; - } - } - - if (mesh != nullptr && mesh->GetMaterials().Size() > 0) { - return mesh->GetMaterials()[0]; - } - - return nullptr; -} - -inline const Resources::Material* ResolveMaterial(const VisibleRenderItem& visibleItem) { - if (visibleItem.material != nullptr) { - return visibleItem.material; - } - - return ResolveMaterial(visibleItem.meshRenderer, visibleItem.mesh, visibleItem.materialIndex); -} - -inline bool TryResolveRenderQueueTagValue( - const Containers::String& queueValue, - Core::int32& outRenderQueue) { - const Containers::String normalized = NormalizeBuiltinPassMetadataValue(queueValue); - if (normalized.Empty()) { - return false; - } - - if (normalized == Containers::String("background")) { - outRenderQueue = static_cast(Resources::MaterialRenderQueue::Background); - return true; - } - if (normalized == Containers::String("geometry")) { - outRenderQueue = static_cast(Resources::MaterialRenderQueue::Geometry); - return true; - } - if (normalized == Containers::String("alphatest")) { - outRenderQueue = static_cast(Resources::MaterialRenderQueue::AlphaTest); - return true; - } - if (normalized == Containers::String("transparent")) { - outRenderQueue = static_cast(Resources::MaterialRenderQueue::Transparent); - return true; - } - if (normalized == Containers::String("overlay")) { - outRenderQueue = static_cast(Resources::MaterialRenderQueue::Overlay); - return true; - } - - char* end = nullptr; - const long parsedValue = std::strtol(normalized.CStr(), &end, 10); - if (end != nullptr && *end == '\0') { - outRenderQueue = static_cast(parsedValue); - return true; - } - - return false; -} - -inline bool TryResolveShaderPassRenderQueue(const Resources::ShaderPass& shaderPass, Core::int32& outRenderQueue) { - for (const Resources::ShaderPassTagEntry& tag : shaderPass.tags) { - if (NormalizeBuiltinPassMetadataValue(tag.name) == Containers::String("queue") && - TryResolveRenderQueueTagValue(tag.value, outRenderQueue)) { - return true; - } - } - - return false; -} - -inline Core::int32 ResolveMaterialRenderQueue(const Resources::Material* material) { - const Core::int32 defaultQueue = static_cast(Resources::MaterialRenderQueue::Geometry); - if (material == nullptr) { - return defaultQueue; - } - - const Core::int32 materialQueue = material->GetRenderQueue(); - if (materialQueue != defaultQueue) { - return materialQueue; - } - - if (const Resources::Shader* shader = material->GetShader()) { - for (const Resources::ShaderPass& pass : shader->GetPasses()) { - Core::int32 shaderQueue = defaultQueue; - if (TryResolveShaderPassRenderQueue(pass, shaderQueue)) { - return shaderQueue; - } - } - } - - return materialQueue; -} - -inline bool IsTransparentRenderQueue(Core::int32 renderQueue) { - return renderQueue >= static_cast(Resources::MaterialRenderQueue::Transparent); -} - -inline bool MatchesBuiltinPass(const Resources::Material* material, BuiltinMaterialPass pass) { - if (material == nullptr) { - return false; - } - - const Resources::Shader* shader = material->GetShader(); - if (shader == nullptr) { - return false; - } - - for (const Resources::ShaderPass& shaderPassEntry : shader->GetPasses()) { - if (ShaderPassMatchesBuiltinPass(shaderPassEntry, pass)) { - return true; - } - } - - return false; -} - -} // namespace Rendering -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Rendering/Materials/RenderMaterialStateUtils.h b/engine/include/XCEngine/Rendering/Materials/RenderMaterialStateUtils.h index c838b497..72b45fbf 100644 --- a/engine/include/XCEngine/Rendering/Materials/RenderMaterialStateUtils.h +++ b/engine/include/XCEngine/Rendering/Materials/RenderMaterialStateUtils.h @@ -1,311 +1,3 @@ #pragma once -#include - -#include -#include -#include -#include -#include - -namespace XCEngine { -namespace Rendering { - -inline RHI::CullMode ToRHICullMode(Resources::MaterialCullMode mode) { - switch (mode) { - case Resources::MaterialCullMode::Front: - return RHI::CullMode::Front; - case Resources::MaterialCullMode::Back: - return RHI::CullMode::Back; - case Resources::MaterialCullMode::None: - default: - return RHI::CullMode::None; - } -} - -inline RHI::ComparisonFunc ToRHIComparisonFunc(Resources::MaterialComparisonFunc func) { - switch (func) { - case Resources::MaterialComparisonFunc::Never: - return RHI::ComparisonFunc::Never; - case Resources::MaterialComparisonFunc::Equal: - return RHI::ComparisonFunc::Equal; - case Resources::MaterialComparisonFunc::LessEqual: - return RHI::ComparisonFunc::LessEqual; - case Resources::MaterialComparisonFunc::Greater: - return RHI::ComparisonFunc::Greater; - case Resources::MaterialComparisonFunc::NotEqual: - return RHI::ComparisonFunc::NotEqual; - case Resources::MaterialComparisonFunc::GreaterEqual: - return RHI::ComparisonFunc::GreaterEqual; - case Resources::MaterialComparisonFunc::Always: - return RHI::ComparisonFunc::Always; - case Resources::MaterialComparisonFunc::Less: - default: - return RHI::ComparisonFunc::Less; - } -} - -inline RHI::BlendFactor ToRHIBlendFactor(Resources::MaterialBlendFactor factor) { - switch (factor) { - case Resources::MaterialBlendFactor::Zero: - return RHI::BlendFactor::Zero; - case Resources::MaterialBlendFactor::SrcColor: - return RHI::BlendFactor::SrcColor; - case Resources::MaterialBlendFactor::InvSrcColor: - return RHI::BlendFactor::InvSrcColor; - case Resources::MaterialBlendFactor::SrcAlpha: - return RHI::BlendFactor::SrcAlpha; - case Resources::MaterialBlendFactor::InvSrcAlpha: - return RHI::BlendFactor::InvSrcAlpha; - case Resources::MaterialBlendFactor::DstAlpha: - return RHI::BlendFactor::DstAlpha; - case Resources::MaterialBlendFactor::InvDstAlpha: - return RHI::BlendFactor::InvDstAlpha; - case Resources::MaterialBlendFactor::DstColor: - return RHI::BlendFactor::DstColor; - case Resources::MaterialBlendFactor::InvDstColor: - return RHI::BlendFactor::InvDstColor; - case Resources::MaterialBlendFactor::SrcAlphaSat: - return RHI::BlendFactor::SrcAlphaSat; - case Resources::MaterialBlendFactor::BlendFactor: - return RHI::BlendFactor::BlendFactor; - case Resources::MaterialBlendFactor::InvBlendFactor: - return RHI::BlendFactor::InvBlendFactor; - case Resources::MaterialBlendFactor::Src1Color: - return RHI::BlendFactor::Src1Color; - case Resources::MaterialBlendFactor::InvSrc1Color: - return RHI::BlendFactor::InvSrc1Color; - case Resources::MaterialBlendFactor::Src1Alpha: - return RHI::BlendFactor::Src1Alpha; - case Resources::MaterialBlendFactor::InvSrc1Alpha: - return RHI::BlendFactor::InvSrc1Alpha; - case Resources::MaterialBlendFactor::One: - default: - return RHI::BlendFactor::One; - } -} - -inline RHI::BlendOp ToRHIBlendOp(Resources::MaterialBlendOp op) { - switch (op) { - case Resources::MaterialBlendOp::Subtract: - return RHI::BlendOp::Subtract; - case Resources::MaterialBlendOp::ReverseSubtract: - return RHI::BlendOp::ReverseSubtract; - case Resources::MaterialBlendOp::Min: - return RHI::BlendOp::Min; - case Resources::MaterialBlendOp::Max: - return RHI::BlendOp::Max; - case Resources::MaterialBlendOp::Add: - default: - return RHI::BlendOp::Add; - } -} - -inline RHI::StencilOp ToRHIStencilOp(Resources::MaterialStencilOp op) { - switch (op) { - case Resources::MaterialStencilOp::Zero: - return RHI::StencilOp::Zero; - case Resources::MaterialStencilOp::Replace: - return RHI::StencilOp::Replace; - case Resources::MaterialStencilOp::IncrSat: - return RHI::StencilOp::IncrSat; - case Resources::MaterialStencilOp::DecrSat: - return RHI::StencilOp::DecrSat; - case Resources::MaterialStencilOp::Invert: - return RHI::StencilOp::Invert; - case Resources::MaterialStencilOp::IncrWrap: - return RHI::StencilOp::Incr; - case Resources::MaterialStencilOp::DecrWrap: - return RHI::StencilOp::Decr; - case Resources::MaterialStencilOp::Keep: - default: - return RHI::StencilOp::Keep; - } -} - -inline Resources::MaterialRenderState ResolveEffectiveRenderState( - const Resources::ShaderPass* shaderPass, - const Resources::Material* material) { - Resources::MaterialRenderState renderState = {}; - - if (shaderPass != nullptr && shaderPass->hasFixedFunctionState) { - renderState = shaderPass->fixedFunctionState; - } else if (material != nullptr) { - renderState = material->GetRenderState(); - } - - if (material != nullptr && material->HasRenderStateOverride()) { - renderState = material->GetRenderState(); - } - - return renderState; -} - -inline Resources::MaterialRenderState ApplyRenderStateBlock( - Resources::MaterialRenderState renderState, - const RenderStateBlock* renderStateBlock) { - if (renderStateBlock == nullptr || - !renderStateBlock->HasOverrides()) { - return renderState; - } - - if (renderStateBlock->HasDepthOverride()) { - renderState.depthWriteEnable = - renderStateBlock->depthState.writeEnabled; - renderState.depthFunc = - renderStateBlock->depthState.compareFunction; - } - - if (renderStateBlock->HasStencilOverride()) { - renderState.stencil.enabled = - renderStateBlock->stencilState.enabled; - renderState.stencil.readMask = - renderStateBlock->stencilState.readMask; - renderState.stencil.writeMask = - renderStateBlock->stencilState.writeMask; - renderState.stencil.reference = - renderStateBlock->stencilReference; - renderState.stencil.front.failOp = - renderStateBlock->stencilState.frontFace.failOp; - renderState.stencil.front.passOp = - renderStateBlock->stencilState.frontFace.passOp; - renderState.stencil.front.depthFailOp = - renderStateBlock->stencilState.frontFace.depthFailOp; - renderState.stencil.front.func = - renderStateBlock->stencilState.frontFace.compareFunction; - renderState.stencil.back.failOp = - renderStateBlock->stencilState.backFace.failOp; - renderState.stencil.back.passOp = - renderStateBlock->stencilState.backFace.passOp; - renderState.stencil.back.depthFailOp = - renderStateBlock->stencilState.backFace.depthFailOp; - renderState.stencil.back.func = - renderStateBlock->stencilState.backFace.compareFunction; - } - - return renderState; -} - -inline RHI::RasterizerDesc BuildRasterizerState(const Resources::MaterialRenderState& renderState) { - RHI::RasterizerDesc desc = {}; - desc.fillMode = static_cast(RHI::FillMode::Solid); - desc.cullMode = static_cast(RHI::CullMode::None); - desc.frontFace = static_cast(RHI::FrontFace::CounterClockwise); - desc.depthClipEnable = true; - desc.cullMode = static_cast(ToRHICullMode(renderState.cullMode)); - desc.depthBias = renderState.depthBiasUnits; - desc.slopeScaledDepthBias = renderState.depthBiasFactor; - - return desc; -} - -inline RHI::BlendDesc BuildBlendState(const Resources::MaterialRenderState& renderState) { - RHI::BlendDesc desc = {}; - desc.blendEnable = renderState.blendEnable; - desc.srcBlend = static_cast(ToRHIBlendFactor(renderState.srcBlend)); - desc.dstBlend = static_cast(ToRHIBlendFactor(renderState.dstBlend)); - desc.srcBlendAlpha = static_cast(ToRHIBlendFactor(renderState.srcBlendAlpha)); - desc.dstBlendAlpha = static_cast(ToRHIBlendFactor(renderState.dstBlendAlpha)); - desc.blendOp = static_cast(ToRHIBlendOp(renderState.blendOp)); - desc.blendOpAlpha = static_cast(ToRHIBlendOp(renderState.blendOpAlpha)); - desc.colorWriteMask = renderState.colorWriteMask; - - return desc; -} - -inline RHI::DepthStencilStateDesc BuildDepthStencilState(const Resources::MaterialRenderState& renderState) { - RHI::DepthStencilStateDesc desc = {}; - desc.depthTestEnable = renderState.depthTestEnable; - desc.depthWriteEnable = renderState.depthWriteEnable; - desc.depthFunc = static_cast(ToRHIComparisonFunc(renderState.depthFunc)); - desc.stencilEnable = renderState.stencil.enabled; - desc.stencilReadMask = renderState.stencil.readMask; - desc.stencilWriteMask = renderState.stencil.writeMask; - desc.front.failOp = static_cast(ToRHIStencilOp(renderState.stencil.front.failOp)); - desc.front.passOp = static_cast(ToRHIStencilOp(renderState.stencil.front.passOp)); - desc.front.depthFailOp = static_cast(ToRHIStencilOp(renderState.stencil.front.depthFailOp)); - desc.front.func = static_cast(ToRHIComparisonFunc(renderState.stencil.front.func)); - desc.back.failOp = static_cast(ToRHIStencilOp(renderState.stencil.back.failOp)); - desc.back.passOp = static_cast(ToRHIStencilOp(renderState.stencil.back.passOp)); - desc.back.depthFailOp = static_cast(ToRHIStencilOp(renderState.stencil.back.depthFailOp)); - desc.back.func = static_cast(ToRHIComparisonFunc(renderState.stencil.back.func)); - - return desc; -} - -inline void ApplyRenderState(const Resources::MaterialRenderState& renderState, RHI::GraphicsPipelineDesc& pipelineDesc) { - pipelineDesc.rasterizerState = BuildRasterizerState(renderState); - pipelineDesc.blendState = BuildBlendState(renderState); - pipelineDesc.depthStencilState = BuildDepthStencilState(renderState); -} - -inline void ApplyMaterialRenderState(const Resources::Material* material, RHI::GraphicsPipelineDesc& pipelineDesc) { - ApplyRenderState(ResolveEffectiveRenderState(nullptr, material), pipelineDesc); -} - -inline void ApplyResolvedRenderState( - const Resources::ShaderPass* shaderPass, - const Resources::Material* material, - RHI::GraphicsPipelineDesc& pipelineDesc) { - ApplyRenderState(ResolveEffectiveRenderState(shaderPass, material), pipelineDesc); -} - -inline void ApplyDynamicRenderState( - const Resources::MaterialRenderState& renderState, - RHI::RHICommandList& commandList) { - if (renderState.stencil.enabled) { - commandList.SetStencilRef(renderState.stencil.reference); - } -} - -inline Resources::MaterialRenderState BuildStaticPipelineRenderStateKey( - const Resources::MaterialRenderState& renderState) { - Resources::MaterialRenderState keyState = renderState; - keyState.stencil.reference = 0; - return keyState; -} - -struct MaterialRenderStateHash { - size_t operator()(const Resources::MaterialRenderState& state) const noexcept { - size_t hash = 2166136261u; - auto combine = [&hash](size_t value) { - hash ^= value + 0x9e3779b9u + (hash << 6) + (hash >> 2); - }; - auto combineFloat = [&combine](float value) { - Core::uint32 bits = 0; - std::memcpy(&bits, &value, sizeof(bits)); - combine(static_cast(bits)); - }; - - combine(static_cast(state.blendEnable)); - combine(static_cast(state.srcBlend)); - combine(static_cast(state.dstBlend)); - combine(static_cast(state.srcBlendAlpha)); - combine(static_cast(state.dstBlendAlpha)); - combine(static_cast(state.blendOp)); - combine(static_cast(state.blendOpAlpha)); - combine(static_cast(state.colorWriteMask)); - combine(static_cast(state.depthTestEnable)); - combine(static_cast(state.depthWriteEnable)); - combine(static_cast(state.depthFunc)); - combine(static_cast(state.cullMode)); - combineFloat(state.depthBiasFactor); - combine(static_cast(state.depthBiasUnits)); - combine(static_cast(state.stencil.enabled)); - combine(static_cast(state.stencil.readMask)); - combine(static_cast(state.stencil.writeMask)); - combine(static_cast(state.stencil.reference)); - combine(static_cast(state.stencil.front.failOp)); - combine(static_cast(state.stencil.front.passOp)); - combine(static_cast(state.stencil.front.depthFailOp)); - combine(static_cast(state.stencil.front.func)); - combine(static_cast(state.stencil.back.failOp)); - combine(static_cast(state.stencil.back.passOp)); - combine(static_cast(state.stencil.back.depthFailOp)); - combine(static_cast(state.stencil.back.func)); - return hash; - } -}; - -} // namespace Rendering -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Rendering/Picking/ObjectIdCodec.h b/engine/include/XCEngine/Rendering/Picking/ObjectIdCodec.h index 105c7d9f..4d457c9f 100644 --- a/engine/include/XCEngine/Rendering/Picking/ObjectIdCodec.h +++ b/engine/include/XCEngine/Rendering/Picking/ObjectIdCodec.h @@ -1,56 +1,3 @@ #pragma once -#include -#include - -namespace XCEngine { -namespace Rendering { - -using RenderObjectId = Core::uint32; -using EncodedObjectId = RenderObjectId; - -static constexpr RenderObjectId kInvalidRenderObjectId = 0u; - -inline bool IsValidRenderObjectId(RenderObjectId renderObjectId) { - return renderObjectId != kInvalidRenderObjectId; -} - -inline EncodedObjectId EncodeRenderObjectIdToEncodedId(RenderObjectId renderObjectId) { - return renderObjectId; -} - -inline EncodedObjectId EncodeRenderObjectIdToUInt32(RenderObjectId renderObjectId) { - return EncodeRenderObjectIdToEncodedId(renderObjectId); -} - -inline Math::Vector4 EncodeRenderObjectIdToColor(RenderObjectId renderObjectId) { - const EncodedObjectId encodedId = EncodeRenderObjectIdToEncodedId(renderObjectId); - constexpr float kInv255 = 1.0f / 255.0f; - return Math::Vector4( - static_cast((encodedId >> 0) & 0xFFu) * kInv255, - static_cast((encodedId >> 8) & 0xFFu) * kInv255, - static_cast((encodedId >> 16) & 0xFFu) * kInv255, - static_cast((encodedId >> 24) & 0xFFu) * kInv255); -} - -inline EncodedObjectId DecodeEncodedObjectIdFromColor( - Core::uint8 r, - Core::uint8 g, - Core::uint8 b, - Core::uint8 a) { - return static_cast(r) | - (static_cast(g) << 8u) | - (static_cast(b) << 16u) | - (static_cast(a) << 24u); -} - -inline RenderObjectId DecodeRenderObjectIdFromColor( - Core::uint8 r, - Core::uint8 g, - Core::uint8 b, - Core::uint8 a) { - return DecodeEncodedObjectIdFromColor(r, g, b, a); -} - -} // namespace Rendering -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Rendering/Picking/RenderObjectIdRegistry.h b/engine/include/XCEngine/Rendering/Picking/RenderObjectIdRegistry.h index 2eb2dfcc..3ee56ad4 100644 --- a/engine/include/XCEngine/Rendering/Picking/RenderObjectIdRegistry.h +++ b/engine/include/XCEngine/Rendering/Picking/RenderObjectIdRegistry.h @@ -1,47 +1,3 @@ #pragma once -#include -#include - -#include -#include - -namespace XCEngine { -namespace Rendering { - -class RenderObjectIdRegistry { -public: - static RenderObjectIdRegistry& Get(); - - RenderObjectIdRegistry(const RenderObjectIdRegistry&) = delete; - RenderObjectIdRegistry& operator=(const RenderObjectIdRegistry&) = delete; - - RenderObjectId GetOrAllocateRenderObjectId(Core::uint64 runtimeObjectId); - bool TryGetRenderObjectId( - Core::uint64 runtimeObjectId, - RenderObjectId& outRenderObjectId) const; - bool TryResolveRuntimeObjectId( - RenderObjectId renderObjectId, - Core::uint64& outRuntimeObjectId) const; - Core::uint64 ResolveRuntimeObjectId(RenderObjectId renderObjectId) const; - - void Reset(); - Core::uint64 GetGeneration() const; - -private: - RenderObjectIdRegistry() = default; - - RenderObjectId AllocateRenderObjectIdLocked(); - void BumpGenerationLocked(); - - mutable std::mutex m_mutex = {}; - RenderObjectId m_nextRenderObjectId = 1u; - Core::uint64 m_generation = 1u; - std::unordered_map - m_renderObjectIdByRuntimeObjectId = {}; - std::unordered_map - m_runtimeObjectIdByRenderObjectId = {}; -}; - -} // namespace Rendering -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Rendering/Shadow/DirectionalShadowData.h b/engine/include/XCEngine/Rendering/Shadow/DirectionalShadowData.h index 8a722204..0ad8a3d1 100644 --- a/engine/include/XCEngine/Rendering/Shadow/DirectionalShadowData.h +++ b/engine/include/XCEngine/Rendering/Shadow/DirectionalShadowData.h @@ -1,82 +1,3 @@ #pragma once -#include -#include -#include -#include -#include - -#include - -namespace XCEngine { -namespace RHI { -class RHIResourceView; -} // namespace RHI - -namespace Rendering { - -struct DirectionalShadowRenderPlan { - bool enabled = false; - Math::Vector3 lightDirection = Math::Vector3::Back(); - Math::Vector3 focusPoint = Math::Vector3::Zero(); - float orthographicHalfExtent = 0.0f; - float texelWorldSize = 0.0f; - float nearClipPlane = 0.1f; - float farClipPlane = 0.0f; - DirectionalShadowSamplingSettings sampling = {}; - DirectionalShadowCasterBiasSettings casterBias = {}; - uint32_t mapWidth = 0; - uint32_t mapHeight = 0; - RenderCameraData cameraData = {}; - - bool IsValid() const { - return enabled && - mapWidth > 0 && - mapHeight > 0 && - cameraData.viewportWidth == mapWidth && - cameraData.viewportHeight == mapHeight; - } -}; - -struct RenderDirectionalShadowMapMetrics { - Math::Vector2 inverseMapSize = Math::Vector2::Zero(); - float worldTexelSize = 0.0f; - float padding = 0.0f; -}; - -static_assert( - sizeof(RenderDirectionalShadowMapMetrics) == sizeof(float) * 4u, - "RenderDirectionalShadowMapMetrics must stay float4-sized for GPU constant layout"); - -struct RenderDirectionalShadowSamplingData { - float enabled = 0.0f; - DirectionalShadowSamplingSettings settings = {}; -}; - -static_assert( - sizeof(RenderDirectionalShadowSamplingData) == sizeof(float) * 4u, - "RenderDirectionalShadowSamplingData must stay float4-sized for GPU constant layout"); - -struct RenderDirectionalShadowCasterBiasData { - DirectionalShadowCasterBiasSettings settings = {}; -}; - -struct RenderDirectionalShadowData { - bool enabled = false; - Math::Matrix4x4 viewProjection = Math::Matrix4x4::Identity(); - RenderDirectionalShadowMapMetrics mapMetrics = {}; - RenderDirectionalShadowSamplingData sampling = {}; - RenderDirectionalShadowCasterBiasData casterBias = {}; - RHI::RHIResourceView* shadowMap = nullptr; - - bool IsValid() const { - return enabled && shadowMap != nullptr; - } -}; - -RenderDirectionalShadowData BuildRenderDirectionalShadowData( - const DirectionalShadowRenderPlan& plan, - RHI::RHIResourceView* shadowMapView); - -} // namespace Rendering -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Rendering/Shadow/DirectionalShadowRuntime.h b/engine/include/XCEngine/Rendering/Shadow/DirectionalShadowRuntime.h index 3d618f12..b43b5a41 100644 --- a/engine/include/XCEngine/Rendering/Shadow/DirectionalShadowRuntime.h +++ b/engine/include/XCEngine/Rendering/Shadow/DirectionalShadowRuntime.h @@ -1,29 +1,3 @@ #pragma once -#include -#include - -namespace XCEngine { -namespace Rendering { - -struct CameraFramePlan; -class RenderPipeline; - -class DirectionalShadowRuntime { -public: - DirectionalShadowRuntime() = default; - DirectionalShadowRuntime(const DirectionalShadowRuntime&) = delete; - DirectionalShadowRuntime& operator=(const DirectionalShadowRuntime&) = delete; - ~DirectionalShadowRuntime() = default; - - bool ResolveExecutionState( - const CameraFramePlan& plan, - const RenderPipeline& pipeline, - DirectionalShadowExecutionState& outShadowState); - -private: - DirectionalShadowSurfaceCache m_surfaceCache; -}; - -} // namespace Rendering -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Resources/AudioClip/AudioClip.h b/engine/include/XCEngine/Resources/AudioClip/AudioClip.h index 07e3acef..5e1582b2 100644 --- a/engine/include/XCEngine/Resources/AudioClip/AudioClip.h +++ b/engine/include/XCEngine/Resources/AudioClip/AudioClip.h @@ -1,105 +1,3 @@ #pragma once -#include -#include -#include -#include - -namespace XCEngine { -namespace Resources { - -enum class AudioFormat : Core::uint8 { - Unknown, - WAV, - OGG, - MP3, - FLAC -}; - -enum class AudioType : Core::uint8 { - SoundEffect, - Music, - Voice, - Ambient -}; - -class AudioClip : public IResource { -public: - AudioClip(); - virtual ~AudioClip() override; - - ResourceType GetType() const override { return ResourceType::AudioClip; } - const Containers::String& GetName() const override { return m_name; } - const Containers::String& GetPath() const override { return m_path; } - ResourceGUID GetGUID() const override { return m_guid; } - bool IsValid() const override { return m_isValid; } - size_t GetMemorySize() const override { return m_memorySize; } - void Release() override; - - void SetPCMData(const Containers::Array& data); - const Containers::Array& GetPCMData() const { return m_pcmData; } - size_t GetPCMDataSize() const { return m_pcmData.Size(); } - - // Legacy compatibility: audio data now means decoded/interpretable PCM bytes. - void SetAudioData(const Containers::Array& data) { SetPCMData(data); } - const Containers::Array& GetAudioData() const { return GetPCMData(); } - - void SetSampleRate(Core::uint32 rate); - Core::uint32 GetSampleRate() const { return m_sampleRate; } - - void SetChannels(Core::uint32 channels); - Core::uint32 GetChannels() const { return m_channels; } - - void SetBitsPerSample(Core::uint32 bits); - Core::uint32 GetBitsPerSample() const { return m_bitsPerSample; } - - void SetDuration(float seconds) { m_duration = seconds; } - float GetDuration() const { return m_duration; } - - const std::vector& GetDecodedPCMData() const; - bool HasDecodedPCMData() const { return m_decodedPCMValid; } - - Core::uint64 GetFrameCount() const; - Core::uint64 GetSampleCount() const; - - void SetAudioFormat(AudioFormat format) { m_format = format; } - AudioFormat GetAudioFormat() const { return m_format; } - - void SetAudioType(AudioType type) { m_audioType = type; } - AudioType GetAudioType() const { return m_audioType; } - - void SetIs3D(bool is3D) { m_is3D = is3D; } - bool Is3D() const { return m_is3D; } - - void SetLoop(bool loop) { m_loop = loop; } - bool IsLoop() const { return m_loop; } - - class IRHIAudioBuffer* GetRHIResource() const { return m_rhiResource; } - void SetRHIResource(class IRHIAudioBuffer* resource); - -private: - void RefreshDerivedData(); - void RefreshMemorySize(); - void InvalidateDecodedPCMData(); - void BuildDecodedPCMData() const; - - Containers::Array m_pcmData; - mutable std::vector m_decodedPCMData; - mutable bool m_decodedPCMValid = false; - - Core::uint32 m_sampleRate = 44100; - Core::uint32 m_channels = 2; - Core::uint32 m_bitsPerSample = 16; - float m_duration = 0.0f; - - AudioFormat m_format = AudioFormat::WAV; - AudioType m_audioType = AudioType::SoundEffect; - - bool m_is3D = false; - bool m_loop = false; - - class IRHIAudioBuffer* m_rhiResource = nullptr; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Resources/AudioClip/AudioLoader.h b/engine/include/XCEngine/Resources/AudioClip/AudioLoader.h index 0b08b609..2b00b706 100644 --- a/engine/include/XCEngine/Resources/AudioClip/AudioLoader.h +++ b/engine/include/XCEngine/Resources/AudioClip/AudioLoader.h @@ -1,26 +1,3 @@ #pragma once -#include -#include "AudioClip.h" - -namespace XCEngine { -namespace Resources { - -class AudioLoader : public IResourceLoader { -public: - AudioLoader(); - virtual ~AudioLoader() override; - - ResourceType GetResourceType() const override { return ResourceType::AudioClip; } - Containers::Array GetSupportedExtensions() const override; - bool CanLoad(const Containers::String& path) const override; - LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override; - ImportSettings* GetDefaultSettings() const override; - -private: - bool ParseWAVData(const Containers::Array& data, AudioClip* audioClip); - AudioFormat DetectAudioFormat(const Containers::String& path, const Containers::Array& data); -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Resources/Material/Material.h b/engine/include/XCEngine/Resources/Material/Material.h index 67ca7f58..90981dac 100644 --- a/engine/include/XCEngine/Resources/Material/Material.h +++ b/engine/include/XCEngine/Resources/Material/Material.h @@ -1,217 +1,3 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -namespace XCEngine { -namespace RHI { -class RHIBuffer; -} -namespace Resources { - -enum class MaterialRenderQueue : Core::int32 { - Background = 1000, - Geometry = 2000, - AlphaTest = 2450, - Transparent = 3000, - Overlay = 4000 -}; - -enum class MaterialPropertyType { - Float, Float2, Float3, Float4, - Int, Int2, Int3, Int4, - Bool, Texture, Cubemap -}; - -struct MaterialProperty { - Containers::String name; - MaterialPropertyType type; - - union Value { - float floatValue[4]; - Core::int32 intValue[4]; - bool boolValue; - - Value() { memset(this, 0, sizeof(Value)); } - } value; - - Core::uint32 refCount = 0; - - MaterialProperty() : type(MaterialPropertyType::Float), refCount(0) {} -}; - -struct MaterialConstantFieldDesc { - Containers::String name; - MaterialPropertyType type = MaterialPropertyType::Float; - Core::uint32 offset = 0; - Core::uint32 size = 0; - Core::uint32 alignedSize = 0; -}; - -struct MaterialTagEntry { - Containers::String name; - Containers::String value; -}; - -struct PendingTextureLoadState { - IResource* resource = nullptr; - Containers::String errorMessage; - bool completed = false; -}; - -struct MaterialTextureBinding { - Containers::String name; - Core::uint32 slot = 0; - ResourceHandle texture; - AssetRef textureRef; - Containers::String texturePath; - std::shared_ptr pendingLoad; -}; - -struct MaterialBufferBindingViewDesc { - Core::uint32 firstElement = 0; - Core::uint32 elementCount = 0; - Core::uint32 structureByteStride = 0; -}; - -struct MaterialBufferBinding { - Containers::String name; - RHI::RHIBuffer* buffer = nullptr; - MaterialBufferBindingViewDesc viewDesc = {}; -}; - -class Material : public IResource { -public: - Material(); - virtual ~Material() override; - - ResourceType GetType() const override { return ResourceType::Material; } - const Containers::String& GetName() const override { return m_name; } - const Containers::String& GetPath() const override { return m_path; } - ResourceGUID GetGUID() const override { return m_guid; } - bool IsValid() const override { return m_isValid; } - size_t GetMemorySize() const override { return m_memorySize; } - void Release() override; - - void SetShader(const ResourceHandle& shader); - class Shader* GetShader() const { return m_shader.Get(); } - - void SetRenderQueue(Core::int32 renderQueue); - void SetRenderQueue(MaterialRenderQueue renderQueue); - Core::int32 GetRenderQueue() const { return m_renderQueue; } - - void SetRenderState(const MaterialRenderState& renderState); - const MaterialRenderState& GetRenderState() const { return m_renderState; } - bool HasRenderStateOverride() const { return m_hasRenderStateOverride; } - void SetRenderStateOverrideEnabled(bool enabled); - - void SetTag(const Containers::String& name, const Containers::String& value); - Containers::String GetTag(const Containers::String& name) const; - bool HasTag(const Containers::String& name) const; - void RemoveTag(const Containers::String& name); - void ClearTags(); - Core::uint32 GetTagCount() const { return static_cast(m_tags.Size()); } - Containers::String GetTagName(Core::uint32 index) const; - Containers::String GetTagValue(Core::uint32 index) const; - const Containers::Array& GetTags() const { return m_tags; } - - void EnableKeyword(const Containers::String& keyword); - void DisableKeyword(const Containers::String& keyword); - void SetKeywordEnabled(const Containers::String& keyword, bool enabled); - bool IsKeywordEnabled(const Containers::String& keyword) const; - void ClearKeywords(); - Core::uint32 GetKeywordCount() const { return static_cast(m_keywordSet.enabledKeywords.Size()); } - Containers::String GetKeyword(Core::uint32 index) const; - const ShaderKeywordSet& GetKeywordSet() const { return m_keywordSet; } - - void SetFloat(const Containers::String& name, float value); - void SetFloat2(const Containers::String& name, const Math::Vector2& value); - void SetFloat3(const Containers::String& name, const Math::Vector3& value); - void SetFloat4(const Containers::String& name, const Math::Vector4& value); - void SetInt(const Containers::String& name, Core::int32 value); - void SetBool(const Containers::String& name, bool value); - void SetTexture(const Containers::String& name, const ResourceHandle& texture); - void SetBuffer(const Containers::String& name, RHI::RHIBuffer* buffer); - void SetBuffer( - const Containers::String& name, - RHI::RHIBuffer* buffer, - const MaterialBufferBindingViewDesc& viewDesc); - void SetTextureAssetRef(const Containers::String& name, - const AssetRef& textureRef, - const Containers::String& texturePath = Containers::String()); - void SetTexturePath(const Containers::String& name, const Containers::String& texturePath); - - float GetFloat(const Containers::String& name) const; - Math::Vector2 GetFloat2(const Containers::String& name) const; - Math::Vector3 GetFloat3(const Containers::String& name) const; - Math::Vector4 GetFloat4(const Containers::String& name) const; - Core::int32 GetInt(const Containers::String& name) const; - bool GetBool(const Containers::String& name) const; - ResourceHandle GetTexture(const Containers::String& name) const; - RHI::RHIBuffer* GetBuffer(const Containers::String& name) const; - const MaterialBufferBinding* FindBufferBinding(const Containers::String& name) const; - Core::uint32 GetTextureBindingCount() const { return static_cast(m_textureBindings.Size()); } - Core::uint32 GetBufferBindingCount() const { return static_cast(m_bufferBindings.Size()); } - Containers::String GetTextureBindingName(Core::uint32 index) const; - AssetRef GetTextureBindingAssetRef(Core::uint32 index) const; - Containers::String GetTextureBindingPath(Core::uint32 index) const; - ResourceHandle GetTextureBindingLoadedTexture(Core::uint32 index) const; - ResourceHandle GetTextureBindingTexture(Core::uint32 index) const; - const Containers::Array& GetTextureBindings() const { return m_textureBindings; } - const Containers::Array& GetBufferBindings() const { return m_bufferBindings; } - std::vector GetProperties() const; - - const Containers::Array& GetConstantBufferData() const { return m_constantBufferData; } - const Containers::Array& GetConstantLayout() const { return m_constantLayout; } - const MaterialConstantFieldDesc* FindConstantField(const Containers::String& name) const; - void UpdateConstantBuffer(); - Core::uint64 GetChangeVersion() const { return m_changeVersion; } - void RecalculateMemorySize(); - - bool HasProperty(const Containers::String& name) const; - void RemoveProperty(const Containers::String& name); - void ClearAllProperties(); - void RemoveBufferBinding(const Containers::String& name); - void ClearBufferBindings(); - -private: - const ShaderPropertyDesc* FindShaderPropertyDesc(const Containers::String& name) const; - bool CanAssignPropertyType(const Containers::String& name, MaterialPropertyType type) const; - bool ResetPropertyToShaderDefault(const Containers::String& name); - void SyncShaderSchemaProperties(bool removeUnknownProperties); - void SyncShaderRuntimeBufferBindings(bool removeUnknownBindings); - void BeginAsyncTextureLoad(Core::uint32 index); - void ResolvePendingTextureBinding(Core::uint32 index); - void ResolvePendingTextureBindings(); - void MarkChanged(bool updateConstantBuffer); - void UpdateMemorySize(); - void SyncShaderSchemaKeywords(bool removeUnknownKeywords); - - ResourceHandle m_shader; - Core::int32 m_renderQueue = static_cast(MaterialRenderQueue::Geometry); - MaterialRenderState m_renderState; - bool m_hasRenderStateOverride = false; - Containers::Array m_tags; - ShaderKeywordSet m_keywordSet; - Containers::HashMap m_properties; - Containers::Array m_constantLayout; - Containers::Array m_constantBufferData; - Containers::Array m_textureBindings; - Containers::Array m_bufferBindings; - Core::uint64 m_changeVersion = 1; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Resources/Material/MaterialLoader.h b/engine/include/XCEngine/Resources/Material/MaterialLoader.h index ec5acc81..6a46ba82 100644 --- a/engine/include/XCEngine/Resources/Material/MaterialLoader.h +++ b/engine/include/XCEngine/Resources/Material/MaterialLoader.h @@ -1,25 +1,3 @@ #pragma once -#include -#include "Material.h" - -namespace XCEngine { -namespace Resources { - -class MaterialLoader : public IResourceLoader { -public: - MaterialLoader(); - virtual ~MaterialLoader() override; - - ResourceType GetResourceType() const override { return ResourceType::Material; } - Containers::Array GetSupportedExtensions() const override; - bool CanLoad(const Containers::String& path) const override; - LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override; - ImportSettings* GetDefaultSettings() const override; - -private: - bool ParseMaterialData(const Containers::Array& data, Material* material); -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Resources/Material/MaterialRenderState.h b/engine/include/XCEngine/Resources/Material/MaterialRenderState.h index 383c4172..831f5372 100644 --- a/engine/include/XCEngine/Resources/Material/MaterialRenderState.h +++ b/engine/include/XCEngine/Resources/Material/MaterialRenderState.h @@ -1,147 +1,3 @@ #pragma once -#include - -namespace XCEngine { -namespace Resources { - -enum class MaterialCullMode : Core::uint8 { - None = 0, - Front = 1, - Back = 2 -}; - -enum class MaterialComparisonFunc : Core::uint8 { - Never = 0, - Less = 1, - Equal = 2, - LessEqual = 3, - Greater = 4, - NotEqual = 5, - GreaterEqual = 6, - Always = 7 -}; - -enum class MaterialBlendOp : Core::uint8 { - Add = 0, - Subtract = 1, - ReverseSubtract = 2, - Min = 3, - Max = 4 -}; - -enum class MaterialBlendFactor : Core::uint8 { - Zero = 0, - One = 1, - SrcColor = 2, - InvSrcColor = 3, - SrcAlpha = 4, - InvSrcAlpha = 5, - DstAlpha = 6, - InvDstAlpha = 7, - DstColor = 8, - InvDstColor = 9, - SrcAlphaSat = 10, - BlendFactor = 11, - InvBlendFactor = 12, - Src1Color = 13, - InvSrc1Color = 14, - Src1Alpha = 15, - InvSrc1Alpha = 16 -}; - -enum class MaterialStencilOp : Core::uint8 { - Keep = 0, - Zero = 1, - Replace = 2, - IncrSat = 3, - DecrSat = 4, - Invert = 5, - IncrWrap = 6, - DecrWrap = 7 -}; - -struct MaterialStencilFaceState { - MaterialStencilOp failOp = MaterialStencilOp::Keep; - MaterialStencilOp passOp = MaterialStencilOp::Keep; - MaterialStencilOp depthFailOp = MaterialStencilOp::Keep; - MaterialComparisonFunc func = MaterialComparisonFunc::Always; - - bool operator==(const MaterialStencilFaceState& other) const { - return failOp == other.failOp && - passOp == other.passOp && - depthFailOp == other.depthFailOp && - func == other.func; - } - - bool operator!=(const MaterialStencilFaceState& other) const { - return !(*this == other); - } -}; - -struct MaterialStencilState { - bool enabled = false; - Core::uint8 readMask = 0xFF; - Core::uint8 writeMask = 0xFF; - Core::uint8 reference = 0; - MaterialStencilFaceState front = {}; - MaterialStencilFaceState back = {}; - - bool operator==(const MaterialStencilState& other) const { - return enabled == other.enabled && - readMask == other.readMask && - writeMask == other.writeMask && - reference == other.reference && - front == other.front && - back == other.back; - } - - bool operator!=(const MaterialStencilState& other) const { - return !(*this == other); - } -}; - -struct MaterialRenderState { - bool blendEnable = false; - MaterialBlendFactor srcBlend = MaterialBlendFactor::One; - MaterialBlendFactor dstBlend = MaterialBlendFactor::Zero; - MaterialBlendFactor srcBlendAlpha = MaterialBlendFactor::One; - MaterialBlendFactor dstBlendAlpha = MaterialBlendFactor::Zero; - MaterialBlendOp blendOp = MaterialBlendOp::Add; - MaterialBlendOp blendOpAlpha = MaterialBlendOp::Add; - Core::uint8 colorWriteMask = 0xF; - - bool depthTestEnable = true; - bool depthWriteEnable = true; - MaterialComparisonFunc depthFunc = MaterialComparisonFunc::Less; - - MaterialCullMode cullMode = MaterialCullMode::None; - float depthBiasFactor = 0.0f; - Core::int32 depthBiasUnits = 0; - MaterialStencilState stencil = {}; - - bool operator==(const MaterialRenderState& other) const { - return blendEnable == other.blendEnable && - srcBlend == other.srcBlend && - dstBlend == other.dstBlend && - srcBlendAlpha == other.srcBlendAlpha && - dstBlendAlpha == other.dstBlendAlpha && - blendOp == other.blendOp && - blendOpAlpha == other.blendOpAlpha && - colorWriteMask == other.colorWriteMask && - depthTestEnable == other.depthTestEnable && - depthWriteEnable == other.depthWriteEnable && - depthFunc == other.depthFunc && - cullMode == other.cullMode && - depthBiasFactor == other.depthBiasFactor && - depthBiasUnits == other.depthBiasUnits && - stencil == other.stencil; - } - - bool operator!=(const MaterialRenderState& other) const { - return !(*this == other); - } -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Resources/Mesh/Mesh.h b/engine/include/XCEngine/Resources/Mesh/Mesh.h index 4e1dcb48..b6887270 100644 --- a/engine/include/XCEngine/Resources/Mesh/Mesh.h +++ b/engine/include/XCEngine/Resources/Mesh/Mesh.h @@ -1,112 +1,3 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include - -namespace XCEngine { -namespace Resources { - -class Material; -class Texture; - -enum class VertexAttribute : Core::uint32 { - Position = 1 << 0, Normal = 1 << 1, Tangent = 1 << 2, - Color = 1 << 3, UV0 = 1 << 4, UV1 = 1 << 5, - UV2 = 1 << 6, UV3 = 1 << 7, BoneWeights = 1 << 8, BoneIndices = 1 << 9, - Bitangent = 1 << 10 -}; - -inline VertexAttribute operator|(VertexAttribute a, VertexAttribute b) { - return static_cast(static_cast(a) | static_cast(b)); -} - -inline VertexAttribute operator&(VertexAttribute a, VertexAttribute b) { - return static_cast(static_cast(a) & static_cast(b)); -} - -inline bool HasVertexAttribute(VertexAttribute attributes, VertexAttribute flag) { - return (static_cast(attributes) & static_cast(flag)) != 0; -} - -struct StaticMeshVertex { - Math::Vector3 position = Math::Vector3::Zero(); - Math::Vector3 normal = Math::Vector3::Zero(); - Math::Vector3 tangent = Math::Vector3::Zero(); - Math::Vector3 bitangent = Math::Vector3::Zero(); - Math::Vector2 uv0 = Math::Vector2::Zero(); - Math::Vector2 uv1 = Math::Vector2::Zero(); - Math::Vector4 color = Math::Vector4::One(); -}; - -struct MeshSection { - Core::uint32 baseVertex; - Core::uint32 vertexCount; - Core::uint32 startIndex; - Core::uint32 indexCount; - Core::uint32 materialID; - Math::Bounds bounds; -}; - -class Mesh : public IResource { -public: - Mesh(); - virtual ~Mesh() override; - - ResourceType GetType() const override { return ResourceType::Mesh; } - const Containers::String& GetName() const override { return m_name; } - const Containers::String& GetPath() const override { return m_path; } - ResourceGUID GetGUID() const override { return m_guid; } - bool IsValid() const override { return m_isValid; } - size_t GetMemorySize() const override { return m_memorySize; } - void Release() override; - - void SetVertexData(const void* data, size_t size, Core::uint32 vertexCount, - Core::uint32 vertexStride, VertexAttribute attributes); - const void* GetVertexData() const { return m_vertexData.Data(); } - size_t GetVertexDataSize() const { return m_vertexData.Size(); } - Core::uint32 GetVertexCount() const { return m_vertexCount; } - Core::uint32 GetVertexStride() const { return m_vertexStride; } - VertexAttribute GetVertexAttributes() const { return m_attributes; } - - void SetIndexData(const void* data, size_t size, Core::uint32 indexCount, bool use32Bit); - const void* GetIndexData() const { return m_indexData.Data(); } - size_t GetIndexDataSize() const { return m_indexData.Size(); } - Core::uint32 GetIndexCount() const { return m_indexCount; } - bool IsUse32BitIndex() const { return m_use32BitIndex; } - - void SetBounds(const Math::Bounds& bounds) { m_bounds = bounds; } - const Math::Bounds& GetBounds() const { return m_bounds; } - - void AddSection(const MeshSection& section); - void AddMaterial(Material* material); - void AddTexture(Texture* texture); - const Containers::Array& GetSections() const { return m_sections; } - const Containers::Array& GetMaterials() const { return m_materials; } - const Containers::Array& GetTextures() const { return m_textures; } - Material* GetMaterial(Core::uint32 index) const; - -private: - void UpdateMemorySize(); - - Core::uint32 m_vertexCount = 0; - Core::uint32 m_vertexStride = 0; - VertexAttribute m_attributes = VertexAttribute::Position; - - Core::uint32 m_indexCount = 0; - bool m_use32BitIndex = false; - - Containers::Array m_vertexData; - Containers::Array m_indexData; - Containers::Array m_sections; - Containers::Array m_materials; - Containers::Array m_textures; - Math::Bounds m_bounds; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Resources/Mesh/MeshImportSettings.h b/engine/include/XCEngine/Resources/Mesh/MeshImportSettings.h index d091719f..b79b9f2f 100644 --- a/engine/include/XCEngine/Resources/Mesh/MeshImportSettings.h +++ b/engine/include/XCEngine/Resources/Mesh/MeshImportSettings.h @@ -1,85 +1,3 @@ #pragma once -#include -#include -#include - -namespace XCEngine { -namespace Resources { - -enum class MeshImportFlags : Core::uint32 { - None = 0, - FlipUVs = 1 << 0, - FlipWindingOrder = 1 << 1, - GenerateNormals = 1 << 2, - GenerateTangents = 1 << 3, - OptimizeMesh = 1 << 4, - ImportSkinning = 1 << 5, - ImportAnimations = 1 << 6, - ImportMaterials = 1 << 7, - ImportCameras = 1 << 8, - ImportLights = 1 << 9 -}; - -inline MeshImportFlags operator|(MeshImportFlags a, MeshImportFlags b) { - return static_cast(static_cast(a) | static_cast(b)); -} - -inline MeshImportFlags operator&(MeshImportFlags a, MeshImportFlags b) { - return static_cast(static_cast(a) & static_cast(b)); -} - -inline MeshImportFlags operator~(MeshImportFlags a) { - return static_cast(~static_cast(a)); -} - -class MeshImportSettings : public ImportSettings { -public: - MeshImportSettings(); - virtual ~MeshImportSettings() override; - - Core::UniqueRef Clone() const override; - bool LoadFromJSON(const Containers::String& json) override; - Containers::String SaveToJSON() const override; - - void SetImportFlags(MeshImportFlags flags) { m_importFlags = flags; } - MeshImportFlags GetImportFlags() const { return m_importFlags; } - - void AddImportFlag(MeshImportFlags flag) { m_importFlags = static_cast(static_cast(m_importFlags) | static_cast(flag)); } - void RemoveImportFlag(MeshImportFlags flag) { m_importFlags = static_cast(static_cast(m_importFlags) & ~static_cast(flag)); } - bool HasImportFlag(MeshImportFlags flag) const { return (static_cast(m_importFlags) & static_cast(flag)) != 0; } - - void SetScale(float scale) { m_scale = scale; } - float GetScale() const { return m_scale; } - - void SetOffset(const Math::Vector3& offset) { m_offset = offset; } - const Math::Vector3& GetOffset() const { return m_offset; } - - void SetAxisConversion(bool convert) { m_axisConversion = convert; } - bool GetAxisConversion() const { return m_axisConversion; } - - void SetMergeMeshes(bool merge) { m_mergeMeshes = merge; } - bool GetMergeMeshes() const { return m_mergeMeshes; } - - void SetOptimizeThreshold(float threshold) { m_optimizeThreshold = threshold; } - float GetOptimizeThreshold() const { return m_optimizeThreshold; } - - void SetImportScale(float scale) { m_importScale = scale; } - float GetImportScale() const { return m_importScale; } - - void SetThreshold(float threshold) { m_threshold = threshold; } - float GetThreshold() const { return m_threshold; } - -private: - MeshImportFlags m_importFlags = MeshImportFlags::ImportMaterials; - float m_scale = 1.0f; - Math::Vector3 m_offset = Math::Vector3::Zero(); - bool m_axisConversion = true; - bool m_mergeMeshes = false; - float m_optimizeThreshold = 0.3f; - float m_importScale = 1.0f; - float m_threshold = 0.0f; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Resources/Mesh/MeshLoader.h b/engine/include/XCEngine/Resources/Mesh/MeshLoader.h index 566ba492..31aca511 100644 --- a/engine/include/XCEngine/Resources/Mesh/MeshLoader.h +++ b/engine/include/XCEngine/Resources/Mesh/MeshLoader.h @@ -1,22 +1,3 @@ #pragma once -#include -#include "Mesh.h" - -namespace XCEngine { -namespace Resources { - -class MeshLoader : public IResourceLoader { -public: - MeshLoader(); - virtual ~MeshLoader() override; - - ResourceType GetResourceType() const override { return ResourceType::Mesh; } - Containers::Array GetSupportedExtensions() const override; - bool CanLoad(const Containers::String& path) const override; - LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override; - ImportSettings* GetDefaultSettings() const override; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Resources/Shader/Shader.h b/engine/include/XCEngine/Resources/Shader/Shader.h index a6820868..a5ce236f 100644 --- a/engine/include/XCEngine/Resources/Shader/Shader.h +++ b/engine/include/XCEngine/Resources/Shader/Shader.h @@ -1,200 +1,3 @@ #pragma once -#include -#include -#include -#include -#include - -namespace XCEngine { -namespace Resources { - -enum class ShaderType : Core::uint8 { - Vertex, - Fragment, - Geometry, - Compute, - Hull, - Domain -}; - -enum class ShaderLanguage : Core::uint8 { - GLSL, - HLSL, - SPIRV -}; - -enum class ShaderBackend : Core::uint8 { - Generic = 0, - D3D12, - OpenGL, - Vulkan -}; - -enum class ShaderPropertyType : Core::uint8 { - Float = 0, - Range, - Int, - Vector, - Color, - Texture2D, - TextureCube -}; - -enum class ShaderResourceType : Core::uint8 { - ConstantBuffer = 0, - Texture2D, - TextureCube, - Sampler, - StructuredBuffer, - RawBuffer, - RWStructuredBuffer, - RWRawBuffer -}; - -struct ShaderUniform { - Containers::String name; - Core::uint32 location; - Core::uint32 size; - Core::uint32 type; -}; - -struct ShaderAttribute { - Containers::String name; - Core::uint32 location; - Core::uint32 size; - Core::uint32 type; -}; - -struct ShaderPassTagEntry { - Containers::String name; - Containers::String value; -}; - -struct ShaderPropertyDesc { - Containers::String name; - Containers::String displayName; - ShaderPropertyType type = ShaderPropertyType::Float; - Containers::String defaultValue; - Containers::String semantic; -}; - -struct ShaderResourceBindingDesc { - Containers::String name; - ShaderResourceType type = ShaderResourceType::ConstantBuffer; - Core::uint32 set = 0; - Core::uint32 binding = 0; - Containers::String semantic; -}; - -struct ShaderBackendCompiledBinary { - ShaderBackend backend = ShaderBackend::Generic; - Containers::Array payload; -}; - -struct ShaderStageVariant { - ShaderType stage = ShaderType::Fragment; - ShaderLanguage language = ShaderLanguage::GLSL; - ShaderBackend backend = ShaderBackend::Generic; - ShaderKeywordSet requiredKeywords; - Containers::String entryPoint; - Containers::String profile; - Containers::String sourceCode; - Containers::Array compiledBinary; - Containers::Array backendCompiledBinaries; - - const Containers::Array* GetCompiledBinaryForBackend( - ShaderBackend targetBackend) const; - void SetCompiledBinaryForBackend( - ShaderBackend targetBackend, - const Containers::Array& binary); - void SetCompiledBinaryForBackend( - ShaderBackend targetBackend, - Containers::Array&& binary); -}; - -struct ShaderPass { - Containers::String name; - bool hasFixedFunctionState = false; - MaterialRenderState fixedFunctionState; - Containers::Array tags; - Containers::Array resources; - Containers::Array keywordDeclarations; - Containers::Array variants; -}; - -class Shader : public IResource { -public: - Shader(); - virtual ~Shader() override; - - ResourceType GetType() const override { return ResourceType::Shader; } - const Containers::String& GetName() const override { return m_name; } - const Containers::String& GetPath() const override { return m_path; } - ResourceGUID GetGUID() const override { return m_guid; } - bool IsValid() const override { return m_isValid; } - size_t GetMemorySize() const override { return m_memorySize; } - void Release() override; - - void AddUniform(const ShaderUniform& uniform); - const Containers::Array& GetUniforms() const { return m_uniforms; } - - void AddAttribute(const ShaderAttribute& attribute); - const Containers::Array& GetAttributes() const { return m_attributes; } - - void AddProperty(const ShaderPropertyDesc& property); - void ClearProperties(); - const Containers::Array& GetProperties() const { return m_properties; } - const ShaderPropertyDesc* FindProperty(const Containers::String& propertyName) const; - void SetFallback(const Containers::String& fallback); - const Containers::String& GetFallback() const { return m_fallback; } - - void AddPass(const ShaderPass& pass); - void ClearPasses(); - Core::uint32 GetPassCount() const { return static_cast(m_passes.Size()); } - const Containers::Array& GetPasses() const { return m_passes; } - - void AddPassVariant(const Containers::String& passName, const ShaderStageVariant& variant); - void SetPassTag( - const Containers::String& passName, - const Containers::String& tagName, - const Containers::String& tagValue); - void AddPassResourceBinding( - const Containers::String& passName, - const ShaderResourceBindingDesc& binding); - void AddPassKeywordDeclaration( - const Containers::String& passName, - const ShaderKeywordDeclaration& declaration); - bool HasPass(const Containers::String& passName) const; - const ShaderPass* FindPass(const Containers::String& passName) const; - ShaderPass* FindPass(const Containers::String& passName); - bool PassDeclaresKeyword( - const Containers::String& passName, - const Containers::String& keyword) const; - bool DeclaresKeyword(const Containers::String& keyword) const; - const ShaderResourceBindingDesc* FindPassResourceBinding( - const Containers::String& passName, - const Containers::String& resourceName) const; - const ShaderStageVariant* FindVariant( - const Containers::String& passName, - ShaderType stage, - ShaderBackend backend = ShaderBackend::Generic, - const ShaderKeywordSet& enabledKeywords = ShaderKeywordSet()) const; - - class IRHIShader* GetRHIResource() const { return m_rhiResource; } - void SetRHIResource(class IRHIShader* resource); - -private: - ShaderPass& GetOrCreatePass(const Containers::String& passName); - - Containers::Array m_uniforms; - Containers::Array m_attributes; - Containers::Array m_properties; - Containers::Array m_passes; - Containers::String m_fallback; - - class IRHIShader* m_rhiResource = nullptr; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Resources/Shader/ShaderCompilationCache.h b/engine/include/XCEngine/Resources/Shader/ShaderCompilationCache.h index 7fb89555..9bf2f24b 100644 --- a/engine/include/XCEngine/Resources/Shader/ShaderCompilationCache.h +++ b/engine/include/XCEngine/Resources/Shader/ShaderCompilationCache.h @@ -1,91 +1,3 @@ #pragma once -#include -#include -#include -#include -#include - -#include - -namespace XCEngine { -namespace Resources { - -constexpr Core::uint32 kShaderCompilationCacheSchemaVersion = 1; - -enum class ShaderBytecodeFormat : Core::uint32 { - Unknown = 0, - DXIL, - DXBC, - SPIRV, - GLSLSource, - OpenGLProgramBinary -}; - -struct ShaderCompileKey { - Containers::String shaderPath; - Containers::String sourceHash; - Containers::String dependencyHash; - Containers::String passName; - Containers::String entryPoint; - Containers::String profile; - Containers::String compilerName; - Containers::String compilerVersion; - Containers::String optionsSignature; - ShaderType stage = ShaderType::Fragment; - ShaderLanguage sourceLanguage = ShaderLanguage::HLSL; - ShaderBackend backend = ShaderBackend::Generic; - Containers::Array keywords; - - void Normalize(); - Containers::String BuildSignature() const; - Containers::String BuildCacheKey() const; -}; - -struct ShaderCacheEntry { - ShaderCompileKey key; - ShaderBytecodeFormat format = ShaderBytecodeFormat::Unknown; - Containers::Array payload; -}; - -class ShaderCompilationCache { -public: - void Initialize(const Containers::String& libraryRoot); - void Shutdown(); - - bool IsInitialized() const { return !m_libraryRoot.Empty(); } - const Containers::String& GetLibraryRoot() const { return m_libraryRoot; } - const Containers::String& GetDatabasePath() const { return m_databasePath; } - Core::uint32 GetRecordCount() const { return static_cast(m_records.size()); } - - Containers::String BuildCacheKey(const ShaderCompileKey& key) const; - Containers::String BuildCacheRelativePath(const ShaderCompileKey& key) const; - Containers::String BuildCacheAbsolutePath(const ShaderCompileKey& key) const; - - bool Store(const ShaderCacheEntry& entry, - Containers::String* outErrorMessage = nullptr); - bool TryLoad(const ShaderCompileKey& key, - ShaderCacheEntry& outEntry, - Containers::String* outErrorMessage = nullptr) const; - -private: - struct ShaderCacheRecord { - ShaderBackend backend = ShaderBackend::Generic; - ShaderBytecodeFormat format = ShaderBytecodeFormat::Unknown; - Containers::String relativePath; - Core::uint64 payloadSize = 0; - }; - - void LoadDatabase(); - void SaveDatabase() const; - - static Containers::String BuildBackendDirectoryName(ShaderBackend backend); - static AssetGUID ComputeKeyGuid(const Containers::String& cacheKey); - - Containers::String m_libraryRoot; - Containers::String m_databasePath; - std::unordered_map m_records; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Resources/Shader/ShaderLoader.h b/engine/include/XCEngine/Resources/Shader/ShaderLoader.h index f47e704c..b96172f5 100644 --- a/engine/include/XCEngine/Resources/Shader/ShaderLoader.h +++ b/engine/include/XCEngine/Resources/Shader/ShaderLoader.h @@ -1,31 +1,3 @@ #pragma once -#include -#include "Shader.h" - -namespace XCEngine { -namespace Resources { - -class ShaderLoader : public IResourceLoader { -public: - ShaderLoader(); - virtual ~ShaderLoader() override; - - ResourceType GetResourceType() const override { return ResourceType::Shader; } - Containers::Array GetSupportedExtensions() const override; - bool CanLoad(const Containers::String& path) const override; - LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override; - ImportSettings* GetDefaultSettings() const override; - bool CollectSourceDependencies(const Containers::String& path, - Containers::Array& outDependencies) const; - bool CollectSourceDependencies(const Containers::String& path, - Containers::Array& outDependencies, - Containers::String* outError) const; - -private: - ShaderType DetectShaderType(const Containers::String& path, const Containers::String& source); - bool ParseShaderSource(const Containers::String& source, Shader* shader); -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Resources/Texture/Texture.h b/engine/include/XCEngine/Resources/Texture/Texture.h index 18959ab4..4d4c88ba 100644 --- a/engine/include/XCEngine/Resources/Texture/Texture.h +++ b/engine/include/XCEngine/Resources/Texture/Texture.h @@ -1,73 +1,3 @@ #pragma once -#include -#include - -namespace XCEngine { -namespace Resources { - -enum class TextureType { - Texture2D, Texture3D, TextureCube, Texture2DArray, TextureCubeArray -}; - -enum class TextureFormat { - Unknown, R8_UNORM, RG8_UNORM, RGBA8_UNORM, RGBA8_SRGB, - R16_FLOAT, RG16_FLOAT, RGBA16_FLOAT, - R32_FLOAT, RG32_FLOAT, RGBA32_FLOAT, - D16_UNORM, D24_UNORM_S8_UINT, D32_FLOAT, D32_FLOAT_S8_X24_UINT, - BC1_UNORM, BC1_UNORM_SRGB, BC2_UNORM, BC2_UNORM_SRGB, - BC3_UNORM, BC3_UNORM_SRGB, BC4_UNORM, BC5_UNORM, BC6H_UF16, - BC7_UNORM, BC7_UNORM_SRGB -}; - -enum class TextureUsage : Core::uint8 { - None = 0, ShaderResource = 1 << 0, RenderTarget = 1 << 1, - DepthStencil = 1 << 2, UnorderedAccess = 1 << 3, - TransferSrc = 1 << 4, TransferDst = 1 << 5 -}; - -class Texture : public IResource { -public: - Texture(); - virtual ~Texture() override; - - ResourceType GetType() const override { return ResourceType::Texture; } - const Containers::String& GetName() const override { return m_name; } - const Containers::String& GetPath() const override { return m_path; } - ResourceGUID GetGUID() const override { return m_guid; } - bool IsValid() const override { return m_isValid; } - size_t GetMemorySize() const override { return m_memorySize; } - void Release() override; - - Core::uint32 GetWidth() const { return m_width; } - Core::uint32 GetHeight() const { return m_height; } - Core::uint32 GetDepth() const { return m_depth; } - Core::uint32 GetMipLevels() const { return m_mipLevels; } - Core::uint32 GetArraySize() const { return m_arraySize; } - TextureType GetTextureType() const { return m_textureType; } - TextureFormat GetFormat() const { return m_format; } - TextureUsage GetUsage() const { return m_usage; } - - const void* GetPixelData() const { return m_pixelData.Data(); } - size_t GetPixelDataSize() const { return m_pixelData.Size(); } - - bool Create(Core::uint32 width, Core::uint32 height, Core::uint32 depth, - Core::uint32 mipLevels, TextureType type, TextureFormat format, - const void* data, size_t dataSize, Core::uint32 arraySize = 1); - bool GenerateMipmaps(); - -private: - Core::uint32 m_width = 0; - Core::uint32 m_height = 0; - Core::uint32 m_depth = 1; - Core::uint32 m_mipLevels = 1; - Core::uint32 m_arraySize = 1; - TextureType m_textureType = TextureType::Texture2D; - TextureFormat m_format = TextureFormat::RGBA8_UNORM; - TextureUsage m_usage = TextureUsage::ShaderResource; - - Containers::Array m_pixelData; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Resources/Texture/TextureImportSettings.h b/engine/include/XCEngine/Resources/Texture/TextureImportSettings.h index 1138acdb..64f9f5fd 100644 --- a/engine/include/XCEngine/Resources/Texture/TextureImportSettings.h +++ b/engine/include/XCEngine/Resources/Texture/TextureImportSettings.h @@ -1,91 +1,3 @@ #pragma once -#include -#include -#include - -namespace XCEngine { -namespace Resources { - -enum class MipmapFilter { - Box, - Kaiser -}; - -enum class CompressionQuality { - Low, - Medium, - High, - Ultra -}; - -class TextureImportSettings : public ImportSettings { -public: - TextureImportSettings(); - virtual ~TextureImportSettings() override; - - Core::UniqueRef Clone() const override; - bool LoadFromJSON(const Containers::String& json) override; - Containers::String SaveToJSON() const override; - - void SetTextureType(TextureType type) { m_textureType = type; } - TextureType GetTextureType() const { return m_textureType; } - - void SetTargetFormat(TextureFormat format) { m_targetFormat = format; } - TextureFormat GetTargetFormat() const { return m_targetFormat; } - - void SetGenerateMipmaps(bool generate) { m_generateMipmaps = generate; } - bool GetGenerateMipmaps() const { return m_generateMipmaps; } - - void SetMipmapFilter(MipmapFilter filter) { m_mipmapFilter = filter; } - MipmapFilter GetMipmapFilter() const { return m_mipmapFilter; } - - void SetMaxAnisotropy(Core::uint32 anisotropy) { m_maxAnisotropy = anisotropy; } - Core::uint32 GetMaxAnisotropy() const { return m_maxAnisotropy; } - - void SetSRGB(bool srgb) { m_sRGB = srgb; } - bool GetSRGB() const { return m_sRGB; } - - void SetFlipVertical(bool flip) { m_flipVertical = flip; } - bool GetFlipVertical() const { return m_flipVertical; } - - void SetFlipHorizontal(bool flip) { m_flipHorizontal = flip; } - bool GetFlipHorizontal() const { return m_flipHorizontal; } - - void SetBorderColor(const Math::Vector3& color) { m_borderColor = color; } - const Math::Vector3& GetBorderColor() const { return m_borderColor; } - - void SetCompressionQuality(CompressionQuality quality) { m_compressionQuality = quality; } - CompressionQuality GetCompressionQuality() const { return m_compressionQuality; } - - void SetUseHardwareCompression(bool use) { m_useHardwareCompression = use; } - bool GetUseHardwareCompression() const { return m_useHardwareCompression; } - - void SetMaxSize(Core::uint32 size) { m_maxSize = size; } - Core::uint32 GetMaxSize() const { return m_maxSize; } - - void SetGenerateNormalMap(bool generate) { m_generateNormalMap = generate; } - bool GetGenerateNormalMap() const { return m_generateNormalMap; } - - void SetNormalMapStrength(float strength) { m_normalMapStrength = strength; } - float GetNormalMapStrength() const { return m_normalMapStrength; } - -private: - TextureType m_textureType = TextureType::Texture2D; - TextureFormat m_targetFormat = TextureFormat::Unknown; - bool m_generateMipmaps = true; - MipmapFilter m_mipmapFilter = MipmapFilter::Box; - Core::uint32 m_maxAnisotropy = 16; - bool m_sRGB = false; - bool m_flipVertical = false; - bool m_flipHorizontal = false; - Math::Vector3 m_borderColor = Math::Vector3::Zero(); - CompressionQuality m_compressionQuality = CompressionQuality::High; - bool m_useHardwareCompression = true; - Core::uint32 m_maxSize = 0; - bool m_generateNormalMap = false; - float m_normalMapStrength = 1.0f; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Resources/Texture/TextureLoader.h b/engine/include/XCEngine/Resources/Texture/TextureLoader.h index 79bb5577..bf77f0aa 100644 --- a/engine/include/XCEngine/Resources/Texture/TextureLoader.h +++ b/engine/include/XCEngine/Resources/Texture/TextureLoader.h @@ -1,28 +1,3 @@ #pragma once -#include -#include -#include "Texture.h" - -namespace XCEngine { -namespace Resources { - -class TextureLoader : public IResourceLoader { -public: - TextureLoader(); - virtual ~TextureLoader() override; - - ResourceType GetResourceType() const override { return ResourceType::Texture; } - Containers::Array GetSupportedExtensions() const override; - bool CanLoad(const Containers::String& path) const override; - LoadResult Load(const Containers::String& path, const ImportSettings* settings = nullptr) override; - LoadResult LoadFromMemory( - const Containers::String& path, - const void* data, - size_t dataSize, - const ImportSettings* settings = nullptr) const; - ImportSettings* GetDefaultSettings() const override; -}; - -} // namespace Resources -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Scene/ModelSceneInstantiation.h b/engine/include/XCEngine/Scene/ModelSceneInstantiation.h index f36dfa4b..f86372ec 100644 --- a/engine/include/XCEngine/Scene/ModelSceneInstantiation.h +++ b/engine/include/XCEngine/Scene/ModelSceneInstantiation.h @@ -1,37 +1,3 @@ #pragma once -#include -#include -#include - -#include - -namespace XCEngine { - -namespace Components { -class GameObject; -class Scene; -} - -struct ModelSceneInstantiationResult { - Components::GameObject* rootObject = nullptr; - std::vector nodeObjects; - std::vector meshObjects; -}; - -bool InstantiateModelHierarchy( - Components::Scene& scene, - const Resources::Model& model, - const Resources::AssetRef& modelAssetRef, - Components::GameObject* parent = nullptr, - ModelSceneInstantiationResult* outResult = nullptr, - Containers::String* outErrorMessage = nullptr); - -bool InstantiateModelHierarchy( - Components::Scene& scene, - const Containers::String& modelPath, - Components::GameObject* parent = nullptr, - ModelSceneInstantiationResult* outResult = nullptr, - Containers::String* outErrorMessage = nullptr); - -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Scene/RuntimeLoop.h b/engine/include/XCEngine/Scene/RuntimeLoop.h index 18e13758..14ad730c 100644 --- a/engine/include/XCEngine/Scene/RuntimeLoop.h +++ b/engine/include/XCEngine/Scene/RuntimeLoop.h @@ -1,47 +1,3 @@ #pragma once -#include - -#include - -namespace XCEngine { -namespace Components { - -class RuntimeLoop { -public: - struct Settings { - float fixedDeltaTime = 1.0f / 50.0f; - float maxFrameDeltaTime = 0.1f; - uint32_t maxFixedStepsPerFrame = 4; - }; - - explicit RuntimeLoop(Settings settings = {}); - - void SetSettings(const Settings& settings); - const Settings& GetSettings() const { return m_settings; } - - void Start(Scene* scene); - void Stop(); - void ReplaceScene(Scene* scene); - - void Tick(float deltaTime); - void Pause(); - void Resume(); - void StepFrame(); - - bool IsRunning() const { return m_sceneRuntime.IsRunning(); } - bool IsPaused() const { return m_paused; } - Scene* GetScene() const { return m_sceneRuntime.GetScene(); } - Physics::PhysicsWorld* GetPhysicsWorld() const { return m_sceneRuntime.GetPhysicsWorld(); } - float GetFixedAccumulator() const { return m_fixedAccumulator; } - -private: - SceneRuntime m_sceneRuntime; - Settings m_settings = {}; - float m_fixedAccumulator = 0.0f; - bool m_paused = false; - bool m_stepRequested = false; -}; - -} // namespace Components -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Scene/Scene.h b/engine/include/XCEngine/Scene/Scene.h index 381a59f4..0ea04fab 100644 --- a/engine/include/XCEngine/Scene/Scene.h +++ b/engine/include/XCEngine/Scene/Scene.h @@ -1,121 +1,3 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include - -namespace XCEngine { -namespace Components { - -class Scene { -public: - using GameObjectID = uint64_t; - static constexpr GameObjectID INVALID_GAMEOBJECT_ID = 0; - - Scene(); - explicit Scene(const std::string& name); - ~Scene(); - - const std::string& GetName() const { return m_name; } - void SetName(const std::string& name) { m_name = name; } - - bool IsActive() const { return m_active; } - void SetActive(bool active) { m_active = active; } - - GameObject* CreateGameObject(const std::string& name, GameObject* parent = nullptr); - void DestroyGameObject(GameObject* gameObject); - - GameObject* Find(const std::string& name) const; - GameObject* FindByID(GameObjectID id) const; - GameObject* FindGameObjectWithTag(const std::string& tag) const; - - template - T* FindObjectOfType() const { - for (auto* go : GetRootGameObjects()) { - if (T* comp = go->GetComponent()) { - return comp; - } - if (T* comp = FindInChildren(go)) { - return comp; - } - } - return nullptr; - } - - template - std::vector FindObjectsOfType() const { - std::vector results; - for (auto* go : GetRootGameObjects()) { - if (T* comp = go->GetComponent()) { - results.push_back(comp); - } - FindInChildren(go, results); - } - return results; - } - - std::vector GetRootGameObjects() const; - - void Update(float deltaTime); - void FixedUpdate(float fixedDeltaTime); - void LateUpdate(float deltaTime); - - void Save(const std::string& filePath); - void Load(const std::string& filePath); - std::string SerializeToString() const; - void DeserializeFromString(const std::string& data); - - Core::Event& OnGameObjectCreated() { return m_onGameObjectCreated; } - Core::Event& OnGameObjectDestroyed() { return m_onGameObjectDestroyed; } - Core::Event& OnComponentAdded() { return m_onComponentAdded; } - Core::Event& OnComponentRemoved() { return m_onComponentRemoved; } - -private: - GameObject* FindInChildren(GameObject* parent, const std::string& name) const; - - template - T* FindInChildren(GameObject* parent) const { - for (size_t i = 0; i < parent->GetChildCount(); ++i) { - GameObject* child = parent->GetChild(i); - if (T* comp = child->GetComponent()) { - return comp; - } - if (T* comp = FindInChildren(child)) { - return comp; - } - } - return nullptr; - } - - template - void FindInChildren(GameObject* parent, std::vector& results) const { - for (size_t i = 0; i < parent->GetChildCount(); ++i) { - GameObject* child = parent->GetChild(i); - if (T* comp = child->GetComponent()) { - results.push_back(comp); - } - FindInChildren(child, results); - } - } - - std::string m_name; - bool m_active = true; - std::unordered_map> m_gameObjects; - std::vector m_rootGameObjects; - std::unordered_set m_gameObjectIDs; - - Core::Event m_onGameObjectCreated; - Core::Event m_onGameObjectDestroyed; - Core::Event m_onComponentAdded; - Core::Event m_onComponentRemoved; - - friend class GameObject; - friend class SceneManager; -}; - -} // namespace Components -} // namespace XCEngine +#include diff --git a/engine/include/XCEngine/Scene/SceneManager.h b/engine/include/XCEngine/Scene/SceneManager.h index 95596f14..b3fec38d 100644 --- a/engine/include/XCEngine/Scene/SceneManager.h +++ b/engine/include/XCEngine/Scene/SceneManager.h @@ -1,48 +1,3 @@ #pragma once -#include "Scene.h" -#include -#include -#include -#include - -namespace XCEngine { -namespace Components { - -class SceneManager { -public: - static SceneManager& Get(); - - Scene* CreateScene(const std::string& name); - void LoadScene(const std::string& filePath); - void LoadSceneAsync(const std::string& filePath, std::function callback); - void UnloadScene(Scene* scene); - void UnloadScene(const std::string& sceneName); - - void SetActiveScene(Scene* scene); - void SetActiveScene(const std::string& sceneName); - Scene* GetActiveScene() const { return m_activeScene; } - - Scene* GetScene(const std::string& name) const; - std::vector GetAllScenes() const; - - Core::Event& OnSceneLoaded() { return m_onSceneLoaded; } - Core::Event& OnSceneUnloaded() { return m_onSceneUnloaded; } - Core::Event& OnActiveSceneChanged() { return m_onActiveSceneChanged; } - -private: - SceneManager() = default; - ~SceneManager() = default; - SceneManager(const SceneManager&) = delete; - SceneManager& operator=(const SceneManager&) = delete; - - Scene* m_activeScene = nullptr; - std::unordered_map> m_scenes; - - Core::Event m_onSceneLoaded; - Core::Event m_onSceneUnloaded; - Core::Event m_onActiveSceneChanged; -}; - -} // namespace Components -} // namespace XCEngine \ No newline at end of file +#include diff --git a/engine/include/XCEngine/Scene/SceneRuntime.h b/engine/include/XCEngine/Scene/SceneRuntime.h index e0e7fda5..4aaf5471 100644 --- a/engine/include/XCEngine/Scene/SceneRuntime.h +++ b/engine/include/XCEngine/Scene/SceneRuntime.h @@ -1,72 +1,3 @@ #pragma once -#include -#include - -#include - -namespace XCEngine { -namespace UI { -namespace Runtime { - -class UISceneRuntimeContext; -class UISystem; -class UIScreenStackController; -struct UISystemFrameResult; - -} // namespace Runtime -} // namespace UI - -namespace Physics { - -class PhysicsWorld; - -} // namespace Physics -} // namespace XCEngine - -namespace XCEngine { -namespace Components { - -class SceneRuntime { -public: - SceneRuntime(); - ~SceneRuntime(); - - SceneRuntime(SceneRuntime&& other) noexcept; - SceneRuntime& operator=(SceneRuntime&& other) noexcept; - - SceneRuntime(const SceneRuntime&) = delete; - SceneRuntime& operator=(const SceneRuntime&) = delete; - - void Start(Scene* scene); - void Stop(); - void ReplaceScene(Scene* scene); - - void FixedUpdate(float fixedDeltaTime); - void Update(float deltaTime); - void LateUpdate(float deltaTime); - - UI::Runtime::UISystem& GetUISystem(); - UI::Runtime::UIScreenStackController& GetUIScreenStackController(); - const UI::Runtime::UISystemFrameResult& GetLastUIFrame() const; - void SetUIViewportRect(const UI::UIRect& viewportRect); - void SetUIFocused(bool focused); - void QueueUIInputEvent(const UI::UIInputEvent& event); - void ClearQueuedUIInputEvents(); - - bool IsRunning() const { return m_running; } - Scene* GetScene() const { return m_scene; } - Physics::PhysicsWorld* GetPhysicsWorld() const { return m_physicsWorld.get(); } - -private: - void CreatePhysicsWorldForScene(Scene* scene); - void DestroyPhysicsWorld(); - - std::unique_ptr m_uiRuntime; - std::unique_ptr m_physicsWorld; - Scene* m_scene = nullptr; - bool m_running = false; -}; - -} // namespace Components -} // namespace XCEngine +#include diff --git a/engine/src/Components/AudioSourceComponent.cpp b/engine/src/Components/AudioSourceComponent.cpp index 9495337c..ddeed898 100644 --- a/engine/src/Components/AudioSourceComponent.cpp +++ b/engine/src/Components/AudioSourceComponent.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" #include #include #include diff --git a/engine/src/Components/CameraComponent.cpp b/engine/src/Components/CameraComponent.cpp index 04cd3423..b7a021ce 100644 --- a/engine/src/Components/CameraComponent.cpp +++ b/engine/src/Components/CameraComponent.cpp @@ -1,7 +1,7 @@ #include "Components/CameraComponent.h" #include "Core/Asset/ResourceManager.h" -#include "Resources/Material/Material.h" +#include "engine/Runtime/Resources/Material/Material.h" #include #include diff --git a/engine/src/Components/GameObject.cpp b/engine/src/Components/GameObject.cpp index 64efd24f..a00df147 100644 --- a/engine/src/Components/GameObject.cpp +++ b/engine/src/Components/GameObject.cpp @@ -1,6 +1,6 @@ #include "Components/GameObject.h" #include "Components/TransformComponent.h" -#include "Scene/Scene.h" +#include "engine/Runtime/Scene/Scene.h" namespace XCEngine { namespace Components { diff --git a/engine/src/Components/GaussianSplatRendererComponent.cpp b/engine/src/Components/GaussianSplatRendererComponent.cpp index 1f3bc0d2..b700d334 100644 --- a/engine/src/Components/GaussianSplatRendererComponent.cpp +++ b/engine/src/Components/GaussianSplatRendererComponent.cpp @@ -2,6 +2,8 @@ #include "Core/Asset/ResourceManager.h" +#include + namespace XCEngine { namespace Components { diff --git a/engine/src/Components/TransformComponent.cpp b/engine/src/Components/TransformComponent.cpp index cf4c3467..8700e4ea 100644 --- a/engine/src/Components/TransformComponent.cpp +++ b/engine/src/Components/TransformComponent.cpp @@ -1,6 +1,6 @@ #include "Components/TransformComponent.h" #include "Components/GameObject.h" -#include "Scene/Scene.h" +#include "engine/Runtime/Scene/Scene.h" #include #include diff --git a/engine/src/Core/IO/IResourceLoader.cpp b/engine/src/Core/IO/IResourceLoader.cpp index 223d0754..09b38a3e 100644 --- a/engine/src/Core/IO/IResourceLoader.cpp +++ b/engine/src/Core/IO/IResourceLoader.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include "engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h" +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" #include #include diff --git a/engine/src/Physics/PhysX/PhysXWorldBackend.cpp b/engine/src/Physics/PhysX/PhysXWorldBackend.cpp index c84e2f97..e41c37d9 100644 --- a/engine/src/Physics/PhysX/PhysXWorldBackend.cpp +++ b/engine/src/Physics/PhysX/PhysXWorldBackend.cpp @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/engine/src/Physics/PhysicsWorld.cpp b/engine/src/Physics/PhysicsWorld.cpp index 17985be5..5a1a636c 100644 --- a/engine/src/Physics/PhysicsWorld.cpp +++ b/engine/src/Physics/PhysicsWorld.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include diff --git a/engine/src/Rendering/Execution/CameraRenderer.cpp b/engine/src/Rendering/Execution/CameraRenderer.cpp index e748b999..15a1c832 100644 --- a/engine/src/Rendering/Execution/CameraRenderer.cpp +++ b/engine/src/Rendering/Execution/CameraRenderer.cpp @@ -1,4 +1,4 @@ -#include "Rendering/Execution/CameraRenderer.h" +#include "Rendering/Execution/CameraRenderer.h" #include "Components/CameraComponent.h" #include "Rendering/Execution/DirectionalShadowExecutionState.h" @@ -11,8 +11,8 @@ #include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h" #include "Rendering/RenderPipelineAsset.h" #include "Rendering/RenderSurface.h" -#include "Rendering/Shadow/DirectionalShadowRuntime.h" -#include "Scene/Scene.h" +#include "engine/Runtime/Rendering/Shadow/DirectionalShadowRuntime.h" +#include "engine/Runtime/Scene/Scene.h" namespace XCEngine { namespace Rendering { diff --git a/engine/src/Rendering/Extraction/RenderSceneExtractor.cpp b/engine/src/Rendering/Extraction/RenderSceneExtractor.cpp index 0735f5f2..e4491ca4 100644 --- a/engine/src/Rendering/Extraction/RenderSceneExtractor.cpp +++ b/engine/src/Rendering/Extraction/RenderSceneExtractor.cpp @@ -5,7 +5,7 @@ #include "Components/LightComponent.h" #include "Rendering/FrameData/RendererListUtils.h" #include "Rendering/Extraction/RenderSceneUtility.h" -#include "Scene/Scene.h" +#include "engine/Runtime/Scene/Scene.h" #include diff --git a/engine/src/Rendering/Extraction/RenderSceneUtility.cpp b/engine/src/Rendering/Extraction/RenderSceneUtility.cpp index 58963f4e..50cc1140 100644 --- a/engine/src/Rendering/Extraction/RenderSceneUtility.cpp +++ b/engine/src/Rendering/Extraction/RenderSceneUtility.cpp @@ -8,11 +8,11 @@ #include "Components/MeshRendererComponent.h" #include "Components/TransformComponent.h" #include "Components/VolumeRendererComponent.h" -#include "Rendering/Materials/RenderMaterialResolve.h" +#include "engine/Runtime/Rendering/Materials/RenderMaterialResolve.h" #if XCENGINE_ENABLE_RENDERING_EDITOR_SUPPORT -#include "Rendering/Picking/RenderObjectIdRegistry.h" +#include "engine/Runtime/Rendering/Picking/RenderObjectIdRegistry.h" #endif -#include "Scene/Scene.h" +#include "engine/Runtime/Scene/Scene.h" #include diff --git a/engine/src/Rendering/Features/BuiltinGaussianSplatPass.cpp b/engine/src/Rendering/Features/BuiltinGaussianSplatPass.cpp index 347dc8c2..a02f6cf6 100644 --- a/engine/src/Rendering/Features/BuiltinGaussianSplatPass.cpp +++ b/engine/src/Rendering/Features/BuiltinGaussianSplatPass.cpp @@ -13,8 +13,8 @@ #include "Rendering/RenderSurface.h" #include "Resources/BuiltinResources.h" #include "Resources/GaussianSplat/GaussianSplat.h" -#include "Resources/Material/Material.h" -#include "Resources/Shader/Shader.h" +#include "engine/Runtime/Resources/Material/Material.h" +#include "engine/Runtime/Resources/Shader/Shader.h" namespace XCEngine { namespace Rendering { diff --git a/engine/src/Rendering/Features/BuiltinVolumetricPass.cpp b/engine/src/Rendering/Features/BuiltinVolumetricPass.cpp index 21c15476..d0c3a875 100644 --- a/engine/src/Rendering/Features/BuiltinVolumetricPass.cpp +++ b/engine/src/Rendering/Features/BuiltinVolumetricPass.cpp @@ -12,8 +12,8 @@ #include "Rendering/FrameData/VisibleVolumeItem.h" #include "Rendering/RenderSurface.h" #include "Resources/BuiltinResources.h" -#include "Resources/Material/Material.h" -#include "Resources/Shader/Shader.h" +#include "engine/Runtime/Resources/Material/Material.h" +#include "engine/Runtime/Resources/Shader/Shader.h" #include "Resources/Volume/VolumeField.h" #include diff --git a/engine/src/Rendering/Internal/ShaderVariantUtils.h b/engine/src/Rendering/Internal/ShaderVariantUtils.h index d4defc63..662a5e45 100644 --- a/engine/src/Rendering/Internal/ShaderVariantUtils.h +++ b/engine/src/Rendering/Internal/ShaderVariantUtils.h @@ -5,7 +5,7 @@ #include #include #include -#include +#include "engine/Runtime/Resources/Shader/Shader.h" #include #include diff --git a/engine/src/Rendering/Passes/BuiltinDepthStylePassBaseResources.cpp b/engine/src/Rendering/Passes/BuiltinDepthStylePassBaseResources.cpp index 4373c046..6d5b043c 100644 --- a/engine/src/Rendering/Passes/BuiltinDepthStylePassBaseResources.cpp +++ b/engine/src/Rendering/Passes/BuiltinDepthStylePassBaseResources.cpp @@ -7,10 +7,10 @@ #include "Rendering/Builtin/BuiltinPassLayoutUtils.h" #include "Rendering/Internal/RenderSurfacePipelineUtils.h" #include "Rendering/Internal/ShaderVariantUtils.h" -#include "Rendering/Materials/RenderMaterialResolve.h" +#include "engine/Runtime/Rendering/Materials/RenderMaterialResolve.h" #include "Rendering/Extraction/RenderSceneExtractor.h" #include "Rendering/RenderSurface.h" -#include "Resources/Material/Material.h" +#include "engine/Runtime/Resources/Material/Material.h" #include "Resources/Mesh/Mesh.h" #include "Resources/Texture/Texture.h" diff --git a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineResources.cpp b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineResources.cpp index 851c572e..978d3bfd 100644 --- a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineResources.cpp +++ b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineResources.cpp @@ -3,9 +3,9 @@ #include "Debug/Logger.h" #include "RHI/RHIDevice.h" #include "Rendering/Builtin/BuiltinPassLayoutUtils.h" -#include "Rendering/Materials/RenderMaterialResolve.h" -#include "Resources/Material/Material.h" -#include "Resources/Shader/Shader.h" +#include "engine/Runtime/Rendering/Materials/RenderMaterialResolve.h" +#include "engine/Runtime/Resources/Material/Material.h" +#include "engine/Runtime/Resources/Shader/Shader.h" #include "Resources/Texture/Texture.h" namespace XCEngine { diff --git a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSkybox.cpp b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSkybox.cpp index 6ce6a867..6338c127 100644 --- a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSkybox.cpp +++ b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSkybox.cpp @@ -6,7 +6,7 @@ #include "Rendering/Internal/RenderSurfacePipelineUtils.h" #include "Rendering/Internal/ShaderVariantUtils.h" #include "Rendering/RenderSurface.h" -#include "Resources/Shader/Shader.h" +#include "engine/Runtime/Resources/Shader/Shader.h" #include #include diff --git a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSurface.cpp b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSurface.cpp index 93fda92c..c72b8e0e 100644 --- a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSurface.cpp +++ b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineSurface.cpp @@ -7,10 +7,10 @@ #include "Rendering/FrameData/RendererListUtils.h" #include "Rendering/Internal/RenderSurfacePipelineUtils.h" #include "Rendering/Internal/ShaderVariantUtils.h" -#include "Rendering/Materials/RenderMaterialResolve.h" -#include "Rendering/Materials/RenderMaterialStateUtils.h" -#include "Resources/Material/Material.h" -#include "Resources/Shader/Shader.h" +#include "engine/Runtime/Rendering/Materials/RenderMaterialResolve.h" +#include "engine/Runtime/Rendering/Materials/RenderMaterialStateUtils.h" +#include "engine/Runtime/Resources/Material/Material.h" +#include "engine/Runtime/Resources/Shader/Shader.h" #include "Resources/Texture/Texture.h" #include diff --git a/engine/src/Rendering/Planning/Internal/DirectionalShadowPlanning.cpp b/engine/src/Rendering/Planning/Internal/DirectionalShadowPlanning.cpp index e357c90b..4f409c79 100644 --- a/engine/src/Rendering/Planning/Internal/DirectionalShadowPlanning.cpp +++ b/engine/src/Rendering/Planning/Internal/DirectionalShadowPlanning.cpp @@ -7,7 +7,7 @@ #include "Components/MeshRendererComponent.h" #include "Core/Math/Matrix4.h" #include "Core/Math/Quaternion.h" -#include "Scene/Scene.h" +#include "engine/Runtime/Scene/Scene.h" #include #include diff --git a/engine/src/Rendering/Planning/SceneRenderRequestPlanner.cpp b/engine/src/Rendering/Planning/SceneRenderRequestPlanner.cpp index ce0371d2..91503e25 100644 --- a/engine/src/Rendering/Planning/SceneRenderRequestPlanner.cpp +++ b/engine/src/Rendering/Planning/SceneRenderRequestPlanner.cpp @@ -4,7 +4,7 @@ #include "Rendering/Planning/Internal/DirectionalShadowPlanning.h" #include "Rendering/Planning/SceneRenderRequestUtils.h" #include "Rendering/RenderPipelineAsset.h" -#include "Scene/Scene.h" +#include "engine/Runtime/Scene/Scene.h" #include diff --git a/engine/src/Rendering/RenderPipeline.cpp b/engine/src/Rendering/RenderPipeline.cpp index c83835e8..d582403b 100644 --- a/engine/src/Rendering/RenderPipeline.cpp +++ b/engine/src/Rendering/RenderPipeline.cpp @@ -1,11 +1,11 @@ #include -#include #include #include "Components/CameraComponent.h" +#include "engine/Runtime/Rendering/Caches/DirectionalShadowSurfaceCache.h" #include "Rendering/Execution/CameraFramePlan.h" -#include "Rendering/Shadow/DirectionalShadowData.h" +#include "engine/Runtime/Rendering/Shadow/DirectionalShadowData.h" namespace XCEngine { namespace Rendering { diff --git a/engine/src/Resources/BuiltinResources.cpp b/engine/src/Resources/BuiltinResources.cpp index d73decb7..396768e8 100644 --- a/engine/src/Resources/BuiltinResources.cpp +++ b/engine/src/Resources/BuiltinResources.cpp @@ -3,11 +3,11 @@ #include #include #include -#include -#include +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" +#include "engine/Runtime/Resources/Material/Material.h" #include -#include -#include +#include "engine/Runtime/Resources/Shader/Shader.h" +#include "engine/Runtime/Resources/Shader/ShaderLoader.h" #include #include diff --git a/engine/src/Resources/GaussianSplat/GaussianSplatArtifactIO.cpp b/engine/src/Resources/GaussianSplat/GaussianSplatArtifactIO.cpp index d200e502..c3ba41a5 100644 --- a/engine/src/Resources/GaussianSplat/GaussianSplatArtifactIO.cpp +++ b/engine/src/Resources/GaussianSplat/GaussianSplatArtifactIO.cpp @@ -1,8 +1,8 @@ #include -#include +#include "engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h" #include -#include +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" #include #include diff --git a/engine/src/Resources/GaussianSplat/GaussianSplatLoader.cpp b/engine/src/Resources/GaussianSplat/GaussianSplatLoader.cpp index e137ec49..03702bfd 100644 --- a/engine/src/Resources/GaussianSplat/GaussianSplatLoader.cpp +++ b/engine/src/Resources/GaussianSplat/GaussianSplatLoader.cpp @@ -1,6 +1,6 @@ #include -#include +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" #include namespace XCEngine { diff --git a/engine/src/Resources/GaussianSplat/Internal/GaussianSplatPlyImporter.cpp b/engine/src/Resources/GaussianSplat/Internal/GaussianSplatPlyImporter.cpp index 3ffb0705..f855aef1 100644 --- a/engine/src/Resources/GaussianSplat/Internal/GaussianSplatPlyImporter.cpp +++ b/engine/src/Resources/GaussianSplat/Internal/GaussianSplatPlyImporter.cpp @@ -1,6 +1,6 @@ #include "Resources/GaussianSplat/Internal/GaussianSplatPlyImporter.h" -#include +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" #include #include diff --git a/engine/src/Resources/Model/AssimpModelImporter.cpp b/engine/src/Resources/Model/AssimpModelImporter.cpp index 0eda61d4..3e645114 100644 --- a/engine/src/Resources/Model/AssimpModelImporter.cpp +++ b/engine/src/Resources/Model/AssimpModelImporter.cpp @@ -1,12 +1,12 @@ #include -#include +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" #include #include -#include +#include "engine/Runtime/Resources/Material/Material.h" #include #include -#include +#include "engine/Runtime/Resources/Shader/Shader.h" #include #include #include diff --git a/engine/src/Resources/Model/ModelArtifactIO.cpp b/engine/src/Resources/Model/ModelArtifactIO.cpp index 480d8b26..a19d210e 100644 --- a/engine/src/Resources/Model/ModelArtifactIO.cpp +++ b/engine/src/Resources/Model/ModelArtifactIO.cpp @@ -1,8 +1,8 @@ #include -#include +#include "engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h" #include -#include +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" #include #include diff --git a/engine/src/Resources/Model/ModelLoader.cpp b/engine/src/Resources/Model/ModelLoader.cpp index a274f5a1..0600b8c0 100644 --- a/engine/src/Resources/Model/ModelLoader.cpp +++ b/engine/src/Resources/Model/ModelLoader.cpp @@ -1,6 +1,6 @@ #include -#include +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" #include namespace XCEngine { diff --git a/engine/src/Resources/UI/UIDocumentCompiler.cpp b/engine/src/Resources/UI/UIDocumentCompiler.cpp index 875811c1..cb7c0733 100644 --- a/engine/src/Resources/UI/UIDocumentCompiler.cpp +++ b/engine/src/Resources/UI/UIDocumentCompiler.cpp @@ -1,8 +1,8 @@ #include -#include +#include "engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h" #include -#include +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" #include #include diff --git a/engine/src/Resources/UI/UIDocumentLoaders.cpp b/engine/src/Resources/UI/UIDocumentLoaders.cpp index 5f2df164..365743d3 100644 --- a/engine/src/Resources/UI/UIDocumentLoaders.cpp +++ b/engine/src/Resources/UI/UIDocumentLoaders.cpp @@ -1,5 +1,5 @@ #include -#include +#include "engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h" #include diff --git a/engine/src/Resources/Volume/VolumeFieldLoader.cpp b/engine/src/Resources/Volume/VolumeFieldLoader.cpp index 24672d87..d42b973e 100644 --- a/engine/src/Resources/Volume/VolumeFieldLoader.cpp +++ b/engine/src/Resources/Volume/VolumeFieldLoader.cpp @@ -1,8 +1,8 @@ #include -#include +#include "engine/Shared/Asset/ArtifactContainer/ArtifactContainer.h" #include -#include +#include "engine/Runtime/Asset/AssetManager/ResourceManager.h" #include #include diff --git a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp index ef83f568..aec40bac 100644 --- a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp +++ b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp @@ -10,7 +10,7 @@ #include "Debug/Logger.h" #include "Input/InputManager.h" #include "Physics/PhysicsWorld.h" -#include "Rendering/Caches/DirectionalShadowSurfaceCache.h" +#include "engine/Runtime/Rendering/Caches/DirectionalShadowSurfaceCache.h" #include "Rendering/Execution/CameraFramePlan.h" #include "Rendering/Execution/CameraStackFramePlan.h" #include "Rendering/Execution/DirectionalShadowExecutionState.h" @@ -35,7 +35,7 @@ #include "Resources/BuiltinResources.h" #include "Core/Asset/ResourceManager.h" #include "RHI/RHICommandList.h" -#include "Scene/Scene.h" +#include "engine/Runtime/Scene/Scene.h" #include "Scripting/ScriptComponent.h" #include "Scripting/ScriptEngine.h" diff --git a/engine/src/Scripting/ScriptEngine.cpp b/engine/src/Scripting/ScriptEngine.cpp index 2d55211d..46f45e18 100644 --- a/engine/src/Scripting/ScriptEngine.cpp +++ b/engine/src/Scripting/ScriptEngine.cpp @@ -1,7 +1,7 @@ #include "Scripting/ScriptEngine.h" #include "Components/GameObject.h" -#include "Scene/Scene.h" +#include "engine/Runtime/Scene/Scene.h" #include "Scripting/ScriptComponent.h" #include diff --git a/tests/Core/Asset/test_resource_manager.cpp b/tests/Core/Asset/test_resource_manager.cpp index 8e5b7287..c975e90d 100644 --- a/tests/Core/Asset/test_resource_manager.cpp +++ b/tests/Core/Asset/test_resource_manager.cpp @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -323,6 +324,61 @@ TEST(AssetImportService_Test, BootstrapProjectBuildsLookupSnapshotAndReportsStat fs::remove_all(projectRoot); } +TEST(ProjectAssetService_Test, BootstrapProjectBuildsLookupSnapshotAndReportsStatus) { + namespace fs = std::filesystem; + + ProjectAssetService projectAssetService; + projectAssetService.Initialize(); + + const fs::path projectRoot = fs::temp_directory_path() / "xc_project_asset_service_bootstrap_test"; + const fs::path assetsDir = projectRoot / "Assets"; + const fs::path materialPath = assetsDir / "runtime.material"; + + fs::remove_all(projectRoot); + fs::create_directories(assetsDir); + { + std::ofstream materialFile(materialPath); + ASSERT_TRUE(materialFile.is_open()); + materialFile << "{\n"; + materialFile << " \"renderQueue\": \"geometry\"\n"; + materialFile << "}\n"; + } + + projectAssetService.SetProjectRoot(projectRoot.string().c_str()); + EXPECT_TRUE(projectAssetService.BootstrapProject()); + + const ProjectAssetImportStatusSnapshot status = + projectAssetService.GetLastImportStatus(); + EXPECT_TRUE(status.HasValue()); + EXPECT_FALSE(status.inProgress); + EXPECT_TRUE(status.success); + EXPECT_EQ(std::string(status.operation.CStr()), "Bootstrap Project"); + EXPECT_EQ(std::string(status.targetPath.CStr()), projectRoot.string()); + + AssetRef assetRef; + EXPECT_TRUE(projectAssetService.TryGetAssetRef( + "Assets/runtime.material", + ResourceType::Material, + assetRef)); + EXPECT_TRUE(assetRef.IsValid()); + + XCEngine::Containers::String resolvedPath; + EXPECT_TRUE(projectAssetService.TryResolveAssetPath(assetRef, resolvedPath)); + EXPECT_EQ(std::string(resolvedPath.CStr()), "Assets/runtime.material"); + + ProjectAssetImportedAsset importedAsset; + EXPECT_TRUE(projectAssetService.EnsureArtifact( + "Assets/runtime.material", + ResourceType::Material, + importedAsset)); + EXPECT_TRUE(importedAsset.exists); + EXPECT_TRUE(importedAsset.artifactReady); + EXPECT_FALSE(importedAsset.runtimeLoadPath.Empty()); + + projectAssetService.Shutdown(); + fs::remove_all(projectRoot); +} + TEST(AssetImportService_Test, RebuildLibraryCacheKeepsStableAssetRefs) { namespace fs = std::filesystem; @@ -424,10 +480,14 @@ TEST(AssetImportService_Test, EnsureArtifactExposesContainerEntryRuntimeLoadPath fs::remove_all(projectRoot); } -TEST(ResourceManager_Test, RebuildProjectAssetCacheRefreshesLookupState) { +TEST(ProjectAssetService_Test, RebuildLibraryCacheRefreshesLookupStateThroughInjectedResolver) { namespace fs = std::filesystem; + ProjectAssetService projectAssetService; + projectAssetService.Initialize(); + ResourceManager& manager = ResourceManager::Get(); + manager.SetProjectAssetPipelineService(&projectAssetService); manager.Initialize(); const fs::path projectRoot = fs::temp_directory_path() / "xc_resource_manager_rebuild_cache_test"; @@ -445,15 +505,16 @@ TEST(ResourceManager_Test, RebuildProjectAssetCacheRefreshesLookupState) { } manager.SetResourceRoot(projectRoot.string().c_str()); + ASSERT_TRUE(projectAssetService.BootstrapProject()); AssetRef firstAssetRef; ASSERT_TRUE(manager.TryGetAssetRef("Assets/runtime.material", ResourceType::Material, firstAssetRef)); ASSERT_TRUE(firstAssetRef.IsValid()); - const fs::path libraryRoot(manager.GetProjectLibraryRoot().CStr()); + const fs::path libraryRoot(projectAssetService.GetLibraryRoot().CStr()); EXPECT_TRUE(fs::exists(libraryRoot / "assets.db")); - EXPECT_TRUE(manager.RebuildProjectAssetCache()); + EXPECT_TRUE(projectAssetService.RebuildLibraryCache()); EXPECT_TRUE(fs::exists(libraryRoot / "assets.db")); AssetRef secondAssetRef; @@ -463,6 +524,8 @@ TEST(ResourceManager_Test, RebuildProjectAssetCacheRefreshesLookupState) { manager.SetResourceRoot(""); manager.Shutdown(); + manager.SetProjectAssetPipelineService(nullptr); + projectAssetService.Shutdown(); fs::remove_all(projectRoot); } @@ -531,20 +594,59 @@ TEST(ResourceManager_Test, SetResourceRootBootstrapsProjectAssetCache) { EXPECT_TRUE(manager.TryGetAssetRef("Assets/runtime.material", ResourceType::Material, assetRef)); EXPECT_TRUE(assetRef.IsValid()); - const AssetImportService::ImportStatusSnapshot status = manager.GetProjectAssetImportStatus(); - EXPECT_TRUE(status.HasValue()); - EXPECT_FALSE(status.inProgress); - EXPECT_TRUE(status.success); - EXPECT_EQ(std::string(status.operation.CStr()), "Bootstrap Project"); - EXPECT_GT(status.startedAtMs, 0u); - EXPECT_GE(status.completedAtMs, status.startedAtMs); - EXPECT_EQ(status.durationMs, status.completedAtMs - status.startedAtMs); + EXPECT_TRUE(fs::exists(projectRoot / "Library" / "assets.db")); + EXPECT_TRUE(fs::exists(projectRoot / "Library" / "artifacts.db")); manager.SetResourceRoot(""); manager.Shutdown(); fs::remove_all(projectRoot); } +TEST(ResourceManager_Test, ExternalProjectAssetPipelineBootstrapIsExplicit) { + namespace fs = std::filesystem; + + ProjectAssetService projectAssetService; + projectAssetService.Initialize(); + + ResourceManager& manager = ResourceManager::Get(); + manager.SetProjectAssetPipelineService(&projectAssetService); + manager.Initialize(); + + const fs::path projectRoot = fs::temp_directory_path() / "xc_resource_manager_external_pipeline_bootstrap_test"; + const fs::path assetsDir = projectRoot / "Assets"; + const fs::path materialPath = assetsDir / "runtime.material"; + + fs::remove_all(projectRoot); + fs::create_directories(assetsDir); + { + std::ofstream materialFile(materialPath); + ASSERT_TRUE(materialFile.is_open()); + materialFile << "{\n"; + materialFile << " \"renderQueue\": \"geometry\"\n"; + materialFile << "}\n"; + } + + manager.SetResourceRoot(projectRoot.string().c_str()); + EXPECT_FALSE(projectAssetService.GetLastImportStatus().HasValue()); + + EXPECT_TRUE(projectAssetService.BootstrapProject()); + const ProjectAssetImportStatusSnapshot status = + projectAssetService.GetLastImportStatus(); + EXPECT_TRUE(status.HasValue()); + EXPECT_EQ(std::string(status.operation.CStr()), "Bootstrap Project"); + + AssetRef assetRef; + EXPECT_TRUE(manager.TryGetAssetRef( + "Assets/runtime.material", + ResourceType::Material, + assetRef)); + EXPECT_TRUE(assetRef.IsValid()); + + manager.Shutdown(); + projectAssetService.Shutdown(); + fs::remove_all(projectRoot); +} + TEST(AssetImportService_Test, ClearLibraryAndReimportAllAssetsManageArtifactsExplicitly) { namespace fs = std::filesystem; @@ -682,10 +784,14 @@ TEST(AssetImportService_Test, ImportStatusTracksExplicitOperationsAndRefreshClea fs::remove_all(projectRoot); } -TEST(ResourceManager_Test, ReimportProjectAssetBuildsArtifactForSelectedPath) { +TEST(ProjectAssetService_Test, ReimportAssetBuildsArtifactForSelectedPathThroughInjectedResolver) { namespace fs = std::filesystem; + ProjectAssetService projectAssetService; + projectAssetService.Initialize(); + ResourceManager& manager = ResourceManager::Get(); + manager.SetProjectAssetPipelineService(&projectAssetService); manager.Initialize(); const fs::path projectRoot = fs::temp_directory_path() / "xc_resource_manager_reimport_asset_test"; @@ -703,14 +809,26 @@ TEST(ResourceManager_Test, ReimportProjectAssetBuildsArtifactForSelectedPath) { } manager.SetResourceRoot(projectRoot.string().c_str()); - EXPECT_TRUE(manager.CanReimportProjectAsset("Assets/runtime.material")); + ASSERT_TRUE(projectAssetService.BootstrapProject()); - const fs::path libraryRoot(manager.GetProjectLibraryRoot().CStr()); - EXPECT_TRUE(manager.ReimportProjectAsset("Assets/runtime.material")); + ResourceType importType = ResourceType::Unknown; + EXPECT_TRUE(projectAssetService.TryGetImportableResourceType( + "Assets/runtime.material", + importType)); + EXPECT_EQ(importType, ResourceType::Material); + + const fs::path libraryRoot(projectAssetService.GetLibraryRoot().CStr()); + ProjectAssetImportedAsset importedAsset; + EXPECT_TRUE(projectAssetService.ReimportAsset( + "Assets/runtime.material", + importedAsset)); + EXPECT_TRUE(importedAsset.artifactReady); EXPECT_TRUE(DirectoryHasEntries(libraryRoot / "Artifacts")); manager.SetResourceRoot(""); manager.Shutdown(); + manager.SetProjectAssetPipelineService(nullptr); + projectAssetService.Shutdown(); fs::remove_all(projectRoot); } diff --git a/tests/Resources/Material/test_material_loader.cpp b/tests/Resources/Material/test_material_loader.cpp index 5c6ff243..b7a87ce7 100644 --- a/tests/Resources/Material/test_material_loader.cpp +++ b/tests/Resources/Material/test_material_loader.cpp @@ -854,7 +854,6 @@ TEST(MaterialLoader, AssetDatabaseMaterialArtifactRoundTripsKeywords) { "}\n"); manager.SetResourceRoot(projectRoot.string().c_str()); - manager.RefreshProjectAssets(); AssetDatabase database; database.Initialize(projectRoot.string().c_str()); @@ -906,7 +905,6 @@ TEST(MaterialLoader, AssetDatabaseMaterialArtifactRoundTripsBuiltinShaderWithout "}\n"); manager.SetResourceRoot(projectRoot.string().c_str()); - manager.RefreshProjectAssets(); AssetDatabase database; database.Initialize(projectRoot.string().c_str()); @@ -1188,7 +1186,6 @@ TEST(MaterialLoader, LoadMaterialArtifactDefersTexturePayloadUntilRequested) { fs::copy_options::overwrite_existing); manager.SetResourceRoot(projectRoot.string().c_str()); - manager.RefreshProjectAssets(); { std::ofstream output(materialArtifactPath, std::ios::binary | std::ios::trunc); diff --git a/tests/Resources/Texture/test_texture_loader.cpp b/tests/Resources/Texture/test_texture_loader.cpp index 36f13737..9a54a842 100644 --- a/tests/Resources/Texture/test_texture_loader.cpp +++ b/tests/Resources/Texture/test_texture_loader.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -181,7 +182,11 @@ TEST(TextureLoader, ResourceManagerLoadsTextureByAssetRefFromProjectAssets) { TEST(TextureLoader, ResourceManagerLoadsLibraryArtifactTextureWithoutReimportingIt) { namespace fs = std::filesystem; + ProjectAssetService projectAssetService; + projectAssetService.Initialize(); + ResourceManager& manager = ResourceManager::Get(); + manager.SetProjectAssetPipelineService(&projectAssetService); manager.Initialize(); const fs::path projectRoot = fs::temp_directory_path() / "xc_texture_library_artifact_direct_load_test"; @@ -193,7 +198,10 @@ TEST(TextureLoader, ResourceManagerLoadsLibraryArtifactTextureWithoutReimporting fs::copy_file(GetTextureFixturePath("checker.bmp"), texturePath, fs::copy_options::overwrite_existing); manager.SetResourceRoot(projectRoot.string().c_str()); - const AssetImportService::ImportStatusSnapshot bootstrapStatus = manager.GetProjectAssetImportStatus(); + EXPECT_FALSE(projectAssetService.GetLastImportStatus().HasValue()); + EXPECT_TRUE(projectAssetService.BootstrapProject()); + const ProjectAssetImportStatusSnapshot bootstrapStatus = + projectAssetService.GetLastImportStatus(); EXPECT_TRUE(bootstrapStatus.HasValue()); EXPECT_TRUE(bootstrapStatus.success); EXPECT_EQ(std::string(bootstrapStatus.operation.CStr()), "Bootstrap Project"); @@ -219,7 +227,8 @@ TEST(TextureLoader, ResourceManagerLoadsLibraryArtifactTextureWithoutReimporting EXPECT_EQ(textureHandle->GetWidth(), 2u); EXPECT_EQ(textureHandle->GetHeight(), 2u); EXPECT_EQ(textureHandle->GetPath(), relativeArtifactPath.generic_string().c_str()); - const AssetImportService::ImportStatusSnapshot postLoadStatus = manager.GetProjectAssetImportStatus(); + const ProjectAssetImportStatusSnapshot postLoadStatus = + projectAssetService.GetLastImportStatus(); EXPECT_TRUE(postLoadStatus.HasValue()); EXPECT_EQ(std::string(postLoadStatus.operation.CStr()), "Bootstrap Project"); EXPECT_GT(postLoadStatus.startedAtMs, 0u); @@ -229,6 +238,8 @@ TEST(TextureLoader, ResourceManagerLoadsLibraryArtifactTextureWithoutReimporting database.Shutdown(); manager.SetResourceRoot(""); manager.Shutdown(); + manager.SetProjectAssetPipelineService(nullptr); + projectAssetService.Shutdown(); fs::remove_all(projectRoot); }