diff --git a/docs/plan/editor-core-refactor-plan.md b/docs/plan/editor-core-refactor-plan.md index 9b68e420..c6ab1760 100644 --- a/docs/plan/editor-core-refactor-plan.md +++ b/docs/plan/editor-core-refactor-plan.md @@ -47,6 +47,10 @@ incomplete: `XCEditorCore` no longer consumes `app/Bootstrap` or Win32 resource helper code to load built-in PNGs, title-bar branding, or executable-relative capture output paths. +- Scene viewport shader paths now flow through runtime initialization. The + scene viewport feature builds the paths from the runtime repo root and + injects them into the render service/pass bundle instead of letting render + passes infer source-tree paths from a compile-time repo-root macro. - Feature panels no longer use `Composition/EditorContext.h` directly. The app-core and app feature/viewport test targets now exercise `XCEditorCore` outside the executable host. @@ -109,6 +113,10 @@ Completed boundary cuts: instead of the executable-host switch. `XCENGINE_BUILD_XCUI_EDITOR_APP=OFF` can still build the product core and the app-facing test targets when renderer editor support is enabled. +- `XCEditorCore` and `XCEditor` no longer receive a compile-time + `XCUIEDITOR_REPO_ROOT` define. Product behavior that needs repo/resource + roots must receive runtime paths through startup wiring, shell/runtime + context, or host/resource services. - The old Win32 tab-drag-drop target test now covers the current reusable `XCEditor/Docking/UIEditorDockHostTransfer.h` API through `editor_windowing_phase1_tests`. @@ -438,6 +446,10 @@ Rendering/Viewport/SceneViewportRenderService.h not a rendering implementation detail. Keep future scene-to-viewport request values under `Core/Scene` so scene services can build requests without taking an `app/Rendering/**` include dependency. +- Scene viewport shader paths are runtime configuration now. Build them from + the runtime repo root in `SceneViewportFeature`, inject them into + `SceneViewportRenderService`, and keep grid/selection render passes from + inferring source-tree paths with compile-time macros or `__FILE__`. ### Utility Windows @@ -531,6 +543,14 @@ Completed cuts: scene viewport request contract without depending on `app/Rendering/**`, and `editor_app_core_tests` no longer needs the app rendering include root to validate scene runtime behavior. +- Scene viewport shader/resource paths are now injected from + `SceneViewportFeature` into `SceneViewportRenderService` and + `SceneViewportRenderPassBundle`. The concrete grid and selection-outline + passes no longer depend on `XCUIEDITOR_REPO_ROOT` or `__FILE__` source-tree + fallback logic to find editor shaders. +- `Application` now resolves the editor repo root at runtime by walking upward + from the executable directory and checking for editor/project markers, + rather than consuming a compile-time repo-root macro. ## Phase 6: Documentation Update @@ -588,6 +608,8 @@ The refactor is complete when: it depends on `Core/Windowing` composition interfaces instead. - `Services` no longer include `Features/**`. - Win32 and D3D12 communicate through neutral host/render contracts. +- Editor product behavior no longer depends on a compile-time repo-root macro; + runtime resource roots are injected through startup/runtime context. - app-core and app feature/viewport tests are wired into CMake and build without running the executable. - `editor/AGENTS.md` describes the new target shape and directory rules. diff --git a/editor/AGENTS.md b/editor/AGENTS.md index 13ad0b46..3ce10ec7 100644 --- a/editor/AGENTS.md +++ b/editor/AGENTS.md @@ -41,6 +41,10 @@ change. - `XCEditorCore` and `XCEditor` require `XCENGINE_ENABLE_RENDERING_EDITOR_SUPPORT=ON`; the root build defaults that support on when either the core library or app executable is enabled. +- `XCEditorCore` and `XCEditor` must not depend on a compile-time repo-root + define for product behavior. Runtime resource roots, executable directories, + and capture paths must enter through startup wiring, shell/runtime context, + or host/resource services. - `XCEditor` is built when `XCENGINE_BUILD_XCUI_EDITOR_APP=ON`; that mode also requires `XCENGINE_BUILD_XCUI_EDITOR_CORE=ON`. The executable target is named `XCEditor`, but its output name is `XCEngine`. @@ -291,6 +295,10 @@ inside pure shell/widget code. - `SceneViewportRenderService` renders scene content through the engine renderer and owns object-id picking state. Keep editor picking/render support behind `XCENGINE_ENABLE_RENDERING_EDITOR_SUPPORT`. +- Scene viewport shader/resource paths are runtime data. Build them from the + startup/runtime repo root in `SceneViewportFeature`, pass them into + `SceneViewportRenderService`, and keep render passes free of compile-time + source-tree path discovery. - D3D12 window rendering is behind the abstract `Rendering::Host::EditorWindowRenderRuntime`; native startup surface data is passed through the neutral @@ -512,6 +520,14 @@ ownership rule. `app/Host/Win32/Resources`, so `XCEditorCore` no longer consumes `app/Bootstrap` or Win32 resource helpers to initialize built-in icons, title-bar branding, or screenshot output roots. +- Scene viewport shader paths are now injected at runtime from + `SceneViewportFeature` into `SceneViewportRenderService` and its pass bundle. + Grid/selection passes no longer infer source-tree shader paths through + `XCUIEDITOR_REPO_ROOT` or `__FILE__`. +- `Application` no longer resolves the editor repo root from a compile-time + macro. It derives the runtime repo root by walking upward from the + executable directory and looking for editor/project markers before booting + `EditorContext`. - The private `editor/app` CMake include root was removed from `XCEditorCore` and `XCEditor`. App sources and editor app-facing unit files now include through explicit module roots, so app-wide include-root drift is caught by diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 4ae60c44..d33ec708 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -4,8 +4,6 @@ project(XCUIEditor VERSION 0.1 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) -file(TO_CMAKE_PATH "${CMAKE_SOURCE_DIR}" XCUIEDITOR_REPO_ROOT_PATH) - function(xcui_editor_apply_common_target_settings target visibility) target_compile_definitions(${target} ${visibility} UNICODE @@ -322,10 +320,6 @@ if(XCENGINE_BUILD_XCUI_EDITOR_CORE) ${CMAKE_CURRENT_SOURCE_DIR}/app/Windowing ) - target_compile_definitions(XCEditorCore PUBLIC - XCUIEDITOR_REPO_ROOT="${XCUIEDITOR_REPO_ROOT_PATH}" - ) - xcui_editor_apply_common_target_settings(XCEditorCore PUBLIC) target_link_libraries(XCEditorCore PUBLIC @@ -387,10 +381,6 @@ if(XCENGINE_BUILD_XCUI_EDITOR_APP) ${CMAKE_SOURCE_DIR}/engine/third_party/stb ) - target_compile_definitions(XCEditor PRIVATE - XCUIEDITOR_REPO_ROOT="${XCUIEDITOR_REPO_ROOT_PATH}" - ) - xcui_editor_apply_common_target_settings(XCEditor PRIVATE) target_link_libraries(XCEditor PRIVATE diff --git a/editor/app/Bootstrap/Application.cpp b/editor/app/Bootstrap/Application.cpp index 23044e12..a2395b52 100644 --- a/editor/app/Bootstrap/Application.cpp +++ b/editor/app/Bootstrap/Application.cpp @@ -33,6 +33,11 @@ constexpr const wchar_t* kWindowTitle = L"Main Scene * - Main.xx - XCEngine Edit constexpr DWORD kBorderlessWindowStyle = WS_POPUP | WS_THICKFRAME; constexpr int kDefaultSmokeTestDurationSeconds = 12; +bool HasEditorRepoMarkers(const std::filesystem::path& root) { + return std::filesystem::exists(root / "editor" / "AGENTS.md") && + std::filesystem::exists(root / "project"); +} + void EnableDpiAwareness() { const HMODULE user32 = GetModuleHandleW(L"user32.dll"); if (user32 != nullptr) { @@ -106,16 +111,12 @@ int RunXCEditor(HINSTANCE hInstance, int nCmdShow) { } // namespace XCEngine::UI::Editor -#ifndef XCUIEDITOR_REPO_ROOT -#define XCUIEDITOR_REPO_ROOT "." -#endif - namespace XCEngine::UI::Editor { bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) { m_hInstance = hInstance; - m_repoRoot = ResolveRepoRootPath(); m_resourceService = std::make_unique(m_hInstance); + m_repoRoot = ResolveRepoRootPath(m_resourceService->GetExecutableDirectory()); EnableDpiAwareness(); const std::filesystem::path logRoot = m_resourceService->GetExecutableDirectory() / "logs"; @@ -265,12 +266,28 @@ void Application::Shutdown() { ShutdownUIEditorRuntimeTrace(); } -std::filesystem::path Application::ResolveRepoRootPath() { - std::string root = XCUIEDITOR_REPO_ROOT; - if (root.size() >= 2u && root.front() == '"' && root.back() == '"') { - root = root.substr(1u, root.size() - 2u); +std::filesystem::path Application::ResolveRepoRootPath( + const std::filesystem::path& executableDirectory) { + std::error_code errorCode = {}; + std::filesystem::path current = + std::filesystem::weakly_canonical(executableDirectory, errorCode); + if (errorCode) { + current = executableDirectory.lexically_normal(); } - return std::filesystem::path(root).lexically_normal(); + + while (!current.empty()) { + if (HasEditorRepoMarkers(current)) { + return current.lexically_normal(); + } + + const std::filesystem::path parent = current.parent_path(); + if (parent == current) { + break; + } + current = parent; + } + + return executableDirectory.lexically_normal(); } LONG WINAPI Application::HandleUnhandledException(EXCEPTION_POINTERS* exceptionInfo) { diff --git a/editor/app/Bootstrap/Application.h b/editor/app/Bootstrap/Application.h index 30259e67..0ff5a025 100644 --- a/editor/app/Bootstrap/Application.h +++ b/editor/app/Bootstrap/Application.h @@ -49,7 +49,8 @@ private: bool Initialize(HINSTANCE hInstance, int nCmdShow); void Shutdown(); bool RegisterWindowClass(); - static std::filesystem::path ResolveRepoRootPath(); + static std::filesystem::path ResolveRepoRootPath( + const std::filesystem::path& executableDirectory); static LONG WINAPI HandleUnhandledException(EXCEPTION_POINTERS* exceptionInfo); HINSTANCE m_hInstance = nullptr; diff --git a/editor/app/Features/Scene/SceneViewportFeature.cpp b/editor/app/Features/Scene/SceneViewportFeature.cpp index 99606312..bc578457 100644 --- a/editor/app/Features/Scene/SceneViewportFeature.cpp +++ b/editor/app/Features/Scene/SceneViewportFeature.cpp @@ -2,6 +2,7 @@ #include "Panels/EditorPanelIds.h" #include "UiTextureHost.h" +#include "Viewport/SceneViewportResourcePaths.h" #include "Viewport/ViewportHostService.h" #include "EditorSceneRuntime.h" #include "EditorCommandFocusService.h" @@ -13,6 +14,7 @@ void SceneViewportFeature::Initialize( Rendering::Host::UiTextureHost& textureHost, const BuiltInIcons* builtInIcons, ViewportHostService& viewportHostService) { + m_renderService.Initialize(BuildSceneViewportShaderPaths(repoRoot)); viewportHostService.SetContentRenderer( kScenePanelId, &m_renderService, diff --git a/editor/app/Rendering/Viewport/Passes/SceneViewportGridPass.cpp b/editor/app/Rendering/Viewport/Passes/SceneViewportGridPass.cpp index d2b7eb2d..4dd31a8f 100644 --- a/editor/app/Rendering/Viewport/Passes/SceneViewportGridPass.cpp +++ b/editor/app/Rendering/Viewport/Passes/SceneViewportGridPass.cpp @@ -1,7 +1,5 @@ #include "Viewport/Passes/SceneViewportGridPass.h" -#include "Viewport/SceneViewportResourcePaths.h" - #include #include #include @@ -283,8 +281,12 @@ InfiniteGridParameters BuildInfiniteGridParameters( class SceneViewportGridPassRenderer::Impl { public: - Impl() - : m_shaderPath(GetSceneViewportInfiniteGridShaderPath()) { + Impl() = default; + + void SetShaderPath( + const ::XCEngine::Containers::String& shaderPath) { + m_shaderPath = shaderPath; + DestroyResources(); } void Shutdown() { @@ -626,6 +628,11 @@ void SceneViewportGridPassRenderer::Shutdown() { m_impl->Shutdown(); } +void SceneViewportGridPassRenderer::SetShaderPath( + const ::XCEngine::Containers::String& shaderPath) { + m_impl->SetShaderPath(shaderPath); +} + bool SceneViewportGridPassRenderer::Render( const ::XCEngine::Rendering::RenderContext& renderContext, const ::XCEngine::Rendering::RenderSurface& surface, diff --git a/editor/app/Rendering/Viewport/Passes/SceneViewportGridPass.h b/editor/app/Rendering/Viewport/Passes/SceneViewportGridPass.h index 24221da2..9365d59a 100644 --- a/editor/app/Rendering/Viewport/Passes/SceneViewportGridPass.h +++ b/editor/app/Rendering/Viewport/Passes/SceneViewportGridPass.h @@ -2,6 +2,7 @@ #include "Viewport/SceneViewportPassSpecs.h" +#include #include #include #include @@ -20,6 +21,8 @@ public: SceneViewportGridPassRenderer& operator=(SceneViewportGridPassRenderer&&) = delete; void Shutdown(); + void SetShaderPath( + const ::XCEngine::Containers::String& shaderPath); bool Render( const ::XCEngine::Rendering::RenderContext& renderContext, diff --git a/editor/app/Rendering/Viewport/Passes/SceneViewportSelectionOutlinePass.cpp b/editor/app/Rendering/Viewport/Passes/SceneViewportSelectionOutlinePass.cpp index 546483f3..8d335380 100644 --- a/editor/app/Rendering/Viewport/Passes/SceneViewportSelectionOutlinePass.cpp +++ b/editor/app/Rendering/Viewport/Passes/SceneViewportSelectionOutlinePass.cpp @@ -1,6 +1,5 @@ #include "Viewport/Passes/SceneViewportSelectionOutlinePass.h" -#include "Viewport/SceneViewportResourcePaths.h" #include "Viewport/ViewportRenderTargets.h" #include @@ -33,10 +32,11 @@ namespace { class SceneViewportSelectionMaskPass final : public ::XCEngine::Rendering::Passes::BuiltinDepthStylePassBase { public: - SceneViewportSelectionMaskPass() + explicit SceneViewportSelectionMaskPass( + const ::XCEngine::Containers::String& shaderPath) : BuiltinDepthStylePassBase( ::XCEngine::Rendering::BuiltinMaterialPass::SelectionMask, - GetSceneViewportSelectionMaskShaderPath()) { + shaderPath) { } const char* GetName() const override { @@ -270,9 +270,20 @@ public: ::XCEngine::Math::Vector4::Zero(); }; - Impl() - : m_selectionMaskPass(std::make_unique()) - , m_shaderPath(GetSceneViewportSelectionOutlineShaderPath()) { + Impl() = default; + + void SetShaderPaths( + const ::XCEngine::Containers::String& selectionMaskShaderPath, + const ::XCEngine::Containers::String& selectionOutlineShaderPath) { + m_selectionMaskShaderPath = selectionMaskShaderPath; + m_shaderPath = selectionOutlineShaderPath; + if (m_selectionMaskPass != nullptr) { + m_selectionMaskPass->Shutdown(); + } + m_selectionMaskPass = + std::make_unique( + m_selectionMaskShaderPath); + DestroyResources(); } void Shutdown() { @@ -289,6 +300,10 @@ public: ViewportRenderTargets& targets, const std::vector& selectedObjectIds, const SceneViewportSelectionOutlineStyle& style) { + if (m_selectionMaskPass == nullptr) { + return false; + } + ::XCEngine::Rendering::RenderSurface selectionMaskSurface = BuildViewportSelectionMaskSurface(targets); selectionMaskSurface.SetRenderArea(surface.GetRenderArea()); @@ -683,6 +698,7 @@ private: } std::unique_ptr m_selectionMaskPass = {}; + ::XCEngine::Containers::String m_selectionMaskShaderPath = {}; ::XCEngine::RHI::RHIDevice* m_device = nullptr; ::XCEngine::RHI::RHIType m_backendType = ::XCEngine::RHI::RHIType::D3D12; @@ -713,6 +729,14 @@ void SceneViewportSelectionOutlinePassRenderer::Shutdown() { m_impl->Shutdown(); } +void SceneViewportSelectionOutlinePassRenderer::SetShaderPaths( + const ::XCEngine::Containers::String& selectionMaskShaderPath, + const ::XCEngine::Containers::String& selectionOutlineShaderPath) { + m_impl->SetShaderPaths( + selectionMaskShaderPath, + selectionOutlineShaderPath); +} + bool SceneViewportSelectionOutlinePassRenderer::Render( const ::XCEngine::Rendering::RenderContext& renderContext, const ::XCEngine::Rendering::RenderSurface& surface, diff --git a/editor/app/Rendering/Viewport/Passes/SceneViewportSelectionOutlinePass.h b/editor/app/Rendering/Viewport/Passes/SceneViewportSelectionOutlinePass.h index 05bb782c..85f0da3a 100644 --- a/editor/app/Rendering/Viewport/Passes/SceneViewportSelectionOutlinePass.h +++ b/editor/app/Rendering/Viewport/Passes/SceneViewportSelectionOutlinePass.h @@ -2,6 +2,7 @@ #include "Viewport/SceneViewportPassSpecs.h" +#include #include #include #include @@ -28,6 +29,9 @@ public: SceneViewportSelectionOutlinePassRenderer&&) = delete; void Shutdown(); + void SetShaderPaths( + const ::XCEngine::Containers::String& selectionMaskShaderPath, + const ::XCEngine::Containers::String& selectionOutlineShaderPath); bool Render( const ::XCEngine::Rendering::RenderContext& renderContext, diff --git a/editor/app/Rendering/Viewport/SceneViewportRenderPassBundle.cpp b/editor/app/Rendering/Viewport/SceneViewportRenderPassBundle.cpp index a539db89..0424c2f1 100644 --- a/editor/app/Rendering/Viewport/SceneViewportRenderPassBundle.cpp +++ b/editor/app/Rendering/Viewport/SceneViewportRenderPassBundle.cpp @@ -8,6 +8,14 @@ void SceneViewportRenderPassBundle::Shutdown() { m_selectedHelpersRenderer.Shutdown(); } +void SceneViewportRenderPassBundle::Initialize( + const SceneViewportShaderPaths& shaderPaths) { + m_gridRenderer.SetShaderPath(shaderPaths.infiniteGridShaderPath); + m_selectionOutlineRenderer.SetShaderPaths( + shaderPaths.selectionMaskShaderPath, + shaderPaths.selectionOutlineShaderPath); +} + SceneViewportRenderPlanBuildResult SceneViewportRenderPassBundle::BuildRenderPlan( ViewportRenderTargets& targets, diff --git a/editor/app/Rendering/Viewport/SceneViewportRenderPassBundle.h b/editor/app/Rendering/Viewport/SceneViewportRenderPassBundle.h index 62e5c6a9..e82638f3 100644 --- a/editor/app/Rendering/Viewport/SceneViewportRenderPassBundle.h +++ b/editor/app/Rendering/Viewport/SceneViewportRenderPassBundle.h @@ -4,6 +4,7 @@ #include "Viewport/Passes/SceneViewportSelectionOutlinePass.h" #include "Viewport/Passes/SceneViewportSelectedHelpersPass.h" #include "Viewport/SceneViewportRenderPlan.h" +#include "Viewport/SceneViewportResourcePaths.h" namespace XCEngine::UI::Editor::App { @@ -12,6 +13,7 @@ public: ~SceneViewportRenderPassBundle() = default; void Shutdown(); + void Initialize(const SceneViewportShaderPaths& shaderPaths); SceneViewportRenderPlanBuildResult BuildRenderPlan( ViewportRenderTargets& targets, diff --git a/editor/app/Rendering/Viewport/SceneViewportRenderService.cpp b/editor/app/Rendering/Viewport/SceneViewportRenderService.cpp index d49431ab..d11f4f2a 100644 --- a/editor/app/Rendering/Viewport/SceneViewportRenderService.cpp +++ b/editor/app/Rendering/Viewport/SceneViewportRenderService.cpp @@ -50,6 +50,11 @@ SceneViewportRenderService::GetViewportResourceRequirements() { return requirements; } +void SceneViewportRenderService::Initialize( + const SceneViewportShaderPaths& shaderPaths) { + m_renderPassBundle.Initialize(shaderPaths); +} + void SceneViewportRenderService::Shutdown() { m_renderRequest = {}; m_renderPassBundle.Shutdown(); diff --git a/editor/app/Rendering/Viewport/SceneViewportRenderService.h b/editor/app/Rendering/Viewport/SceneViewportRenderService.h index 34ae2feb..6408fe29 100644 --- a/editor/app/Rendering/Viewport/SceneViewportRenderService.h +++ b/editor/app/Rendering/Viewport/SceneViewportRenderService.h @@ -35,6 +35,7 @@ public: static ViewportResourceRequirements GetViewportResourceRequirements(); + void Initialize(const SceneViewportShaderPaths& shaderPaths); void Shutdown(); void SetRenderRequest(SceneViewportRenderRequest request); diff --git a/editor/app/Rendering/Viewport/SceneViewportResourcePaths.h b/editor/app/Rendering/Viewport/SceneViewportResourcePaths.h index a12124d3..5c82bec9 100644 --- a/editor/app/Rendering/Viewport/SceneViewportResourcePaths.h +++ b/editor/app/Rendering/Viewport/SceneViewportResourcePaths.h @@ -6,56 +6,55 @@ namespace XCEngine::UI::Editor::App { +struct SceneViewportShaderPaths { + ::XCEngine::Containers::String infiniteGridShaderPath = {}; + ::XCEngine::Containers::String selectionMaskShaderPath = {}; + ::XCEngine::Containers::String selectionOutlineShaderPath = {}; + + bool IsComplete() const { + return !infiniteGridShaderPath.Empty() && + !selectionMaskShaderPath.Empty() && + !selectionOutlineShaderPath.Empty(); + } +}; + inline ::XCEngine::Containers::String NormalizeSceneViewportResourcePath( const std::filesystem::path& path) { return ::XCEngine::Containers::String( path.lexically_normal().generic_string().c_str()); } -inline std::filesystem::path GetSceneViewportResourceRepoRootPath() { -#ifdef XCUIEDITOR_REPO_ROOT - return std::filesystem::path(XCUIEDITOR_REPO_ROOT); -#else - return std::filesystem::path(__FILE__) - .parent_path() - .parent_path() - .parent_path() - .parent_path() - .parent_path(); -#endif +inline std::filesystem::path GetSceneViewportResourceRootPath( + const std::filesystem::path& repoRoot) { + return (repoRoot / "editor" / "resources").lexically_normal(); } inline ::XCEngine::Containers::String BuildSceneViewportResourcePath( + const std::filesystem::path& resourceRoot, const std::filesystem::path& relativePath) { return NormalizeSceneViewportResourcePath( - GetSceneViewportResourceRepoRootPath() / - "editor" / - "resources" / - relativePath); + resourceRoot / relativePath); } -inline ::XCEngine::Containers::String GetSceneViewportInfiniteGridShaderPath() { - return BuildSceneViewportResourcePath( - std::filesystem::path("shaders") / - "scene-viewport" / - "infinite-grid" / - "infinite-grid.shader"); -} +inline SceneViewportShaderPaths BuildSceneViewportShaderPaths( + const std::filesystem::path& repoRoot) { + const std::filesystem::path resourceRoot = + GetSceneViewportResourceRootPath(repoRoot); -inline ::XCEngine::Containers::String GetSceneViewportSelectionMaskShaderPath() { - return BuildSceneViewportResourcePath( - std::filesystem::path("shaders") / - "scene-viewport" / - "selection-mask" / - "selection-mask.shader"); -} - -inline ::XCEngine::Containers::String GetSceneViewportSelectionOutlineShaderPath() { - return BuildSceneViewportResourcePath( - std::filesystem::path("shaders") / - "scene-viewport" / - "selection-outline" / - "selection-outline.shader"); + SceneViewportShaderPaths paths = {}; + paths.infiniteGridShaderPath = BuildSceneViewportResourcePath( + resourceRoot, + std::filesystem::path("shaders") / "scene-viewport" / + "infinite-grid" / "infinite-grid.shader"); + paths.selectionMaskShaderPath = BuildSceneViewportResourcePath( + resourceRoot, + std::filesystem::path("shaders") / "scene-viewport" / + "selection-mask" / "selection-mask.shader"); + paths.selectionOutlineShaderPath = BuildSceneViewportResourcePath( + resourceRoot, + std::filesystem::path("shaders") / "scene-viewport" / + "selection-outline" / "selection-outline.shader"); + return paths; } } // namespace XCEngine::UI::Editor::App