diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 49ea811c..979cf93d 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -90,6 +90,7 @@ add_executable(${PROJECT_NAME} WIN32 src/Viewport/SceneViewportOrientationGizmo.cpp src/Viewport/SceneViewportOverlayBuilder.cpp src/Viewport/SceneViewportOverlayFrameCache.cpp + src/Viewport/SceneViewportRenderPassBundle.cpp src/Viewport/SceneViewportOverlaySpriteResources.cpp src/Viewport/SceneViewportOverlayProviders.cpp src/Viewport/Passes/SceneViewportEditorOverlayPass.cpp diff --git a/editor/src/Viewport/SceneViewportRenderPassBundle.cpp b/editor/src/Viewport/SceneViewportRenderPassBundle.cpp new file mode 100644 index 00000000..3e96436e --- /dev/null +++ b/editor/src/Viewport/SceneViewportRenderPassBundle.cpp @@ -0,0 +1,43 @@ +#include "Viewport/SceneViewportRenderPassBundle.h" + +namespace XCEngine { +namespace Editor { + +void SceneViewportRenderPassBundle::Shutdown() { + m_overlayRenderer.Shutdown(); + m_selectionOutlineRenderer.Shutdown(); + m_gridRenderer.Shutdown(); +} + +SceneViewportRenderPlanBuildResult SceneViewportRenderPassBundle::BuildRenderPlan( + const ViewportRenderTargets& targets, + const SceneViewportOverlayData& overlay, + const std::vector& selectedObjectIds, + const SceneViewportOverlayFrameData& editorOverlayFrameData, + bool debugSelectionMask) { + return BuildSceneViewportRenderPlan( + targets, + overlay, + selectedObjectIds, + editorOverlayFrameData, + [this](const SceneViewportGridPassData& data) { + return CreateSceneViewportGridPass(m_gridRenderer, data); + }, + [this]( + RHI::RHIResourceView* objectIdTextureView, + const std::vector& selectionIds, + const SceneViewportSelectionOutlineStyle& style) { + return CreateSceneViewportSelectionOutlinePass( + m_selectionOutlineRenderer, + objectIdTextureView, + selectionIds, + style); + }, + [this](const SceneViewportOverlayFrameData& frameData) { + return CreateSceneViewportEditorOverlayPass(m_overlayRenderer, frameData); + }, + debugSelectionMask); +} + +} // namespace Editor +} // namespace XCEngine diff --git a/editor/src/Viewport/SceneViewportRenderPassBundle.h b/editor/src/Viewport/SceneViewportRenderPassBundle.h new file mode 100644 index 00000000..b04fbc7e --- /dev/null +++ b/editor/src/Viewport/SceneViewportRenderPassBundle.h @@ -0,0 +1,31 @@ +#pragma once + +#include "Passes/SceneViewportEditorOverlayPass.h" +#include "Passes/SceneViewportGridPass.h" +#include "Passes/SceneViewportSelectionOutlinePass.h" +#include "SceneViewportRenderPlan.h" + +namespace XCEngine { +namespace Editor { + +class SceneViewportRenderPassBundle { +public: + ~SceneViewportRenderPassBundle() = default; + + void Shutdown(); + + SceneViewportRenderPlanBuildResult BuildRenderPlan( + const ViewportRenderTargets& targets, + const SceneViewportOverlayData& overlay, + const std::vector& selectedObjectIds, + const SceneViewportOverlayFrameData& editorOverlayFrameData, + bool debugSelectionMask = false); + +private: + SceneViewportGridPassRenderer m_gridRenderer; + SceneViewportSelectionOutlinePassRenderer m_selectionOutlineRenderer; + SceneViewportEditorOverlayPassRenderer m_overlayRenderer; +}; + +} // namespace Editor +} // namespace XCEngine diff --git a/editor/src/Viewport/ViewportHostService.h b/editor/src/Viewport/ViewportHostService.h index d4971f13..b6a49fef 100644 --- a/editor/src/Viewport/ViewportHostService.h +++ b/editor/src/Viewport/ViewportHostService.h @@ -4,14 +4,12 @@ #include "Core/ISceneManager.h" #include "Core/ISelectionManager.h" #include "IViewportHostService.h" -#include "Passes/SceneViewportEditorOverlayPass.h" -#include "Passes/SceneViewportGridPass.h" -#include "Passes/SceneViewportSelectionOutlinePass.h" #include "SceneViewportCameraController.h" #include "SceneViewportEditorOverlayData.h" #include "SceneViewportOverlayFrameCache.h" #include "SceneViewportOverlayHandleBuilder.h" #include "SceneViewportOverlayBuilder.h" +#include "SceneViewportRenderPassBundle.h" #include "SceneViewportRenderPlan.h" #include "ViewportHostRenderFlowUtils.h" #include "ViewportHostRenderTargets.h" @@ -78,9 +76,7 @@ public: entry = {}; } - m_sceneViewportSelectionOutlineRenderer.Shutdown(); - m_sceneViewportGridRenderer.Shutdown(); - m_sceneViewportEditorOverlayRenderer.Shutdown(); + m_sceneViewportRenderPassBundle.Shutdown(); m_sceneViewCamera = {}; ResetSceneViewportOverlayFrameCacheState(m_sceneViewEditorOverlayFrameCache); m_sceneViewTransformGizmoOverlayState = {}; @@ -507,31 +503,11 @@ private: const SceneViewportOverlayFrameData& editorOverlayFrameData = GetSceneViewEditorOverlayFrameData(context); SceneViewportRenderPlanBuildResult renderPlan = - BuildSceneViewportRenderPlan( + m_sceneViewportRenderPassBundle.BuildRenderPlan( entry.renderTargets, outState.overlay, selectedObjectIds, editorOverlayFrameData, - [this](const SceneViewportGridPassData& data) { - return CreateSceneViewportGridPass( - m_sceneViewportGridRenderer, - data); - }, - [this]( - RHI::RHIResourceView* objectIdTextureView, - const std::vector& selectedObjectIds, - const SceneViewportSelectionOutlineStyle& style) { - return CreateSceneViewportSelectionOutlinePass( - m_sceneViewportSelectionOutlineRenderer, - objectIdTextureView, - selectedObjectIds, - style); - }, - [this](const SceneViewportOverlayFrameData& frameData) { - return CreateSceneViewportEditorOverlayPass( - m_sceneViewportEditorOverlayRenderer, - frameData); - }, kDebugSceneSelectionMask); outState.renderPlan = std::move(renderPlan.plan); if (renderPlan.warningStatusText != nullptr) { @@ -732,9 +708,7 @@ private: SceneViewportTransformGizmoOverlayState m_sceneViewTransformGizmoOverlayState = {}; SceneViewportOverlayFrameCacheState m_sceneViewEditorOverlayFrameCache = {}; bool m_sceneViewTransformGizmoOverlayDirty = false; - SceneViewportGridPassRenderer m_sceneViewportGridRenderer; - SceneViewportSelectionOutlinePassRenderer m_sceneViewportSelectionOutlineRenderer; - SceneViewportEditorOverlayPassRenderer m_sceneViewportEditorOverlayRenderer; + SceneViewportRenderPassBundle m_sceneViewportRenderPassBundle; }; } // namespace Editor diff --git a/tests/editor/CMakeLists.txt b/tests/editor/CMakeLists.txt index 10b8ce54..b0ae4707 100644 --- a/tests/editor/CMakeLists.txt +++ b/tests/editor/CMakeLists.txt @@ -19,6 +19,7 @@ set(EDITOR_TEST_SOURCES test_scene_viewport_transform_gizmo_coordinator.cpp test_scene_viewport_shader_paths.cpp test_scene_viewport_overlay_frame_cache.cpp + test_scene_viewport_render_pass_bundle.cpp test_scene_viewport_overlay_sprite_resources.cpp test_scene_viewport_overlay_renderer.cpp test_scene_viewport_overlay_providers.cpp @@ -52,8 +53,12 @@ set(EDITOR_TEST_SOURCES ${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportOrientationGizmo.cpp ${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportOverlayBuilder.cpp ${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportOverlayFrameCache.cpp + ${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportRenderPassBundle.cpp ${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportOverlaySpriteResources.cpp ${CMAKE_SOURCE_DIR}/editor/src/Viewport/SceneViewportOverlayProviders.cpp + ${CMAKE_SOURCE_DIR}/editor/src/Viewport/Passes/SceneViewportGridPass.cpp + ${CMAKE_SOURCE_DIR}/editor/src/Viewport/Passes/SceneViewportSelectionOutlinePass.cpp + ${CMAKE_SOURCE_DIR}/editor/src/Viewport/Passes/SceneViewportEditorOverlayPass.cpp ) if(XCENGINE_ENABLE_MONO_SCRIPTING AND TARGET xcengine_managed_assemblies) @@ -82,6 +87,7 @@ target_link_libraries(editor_tests PRIVATE target_include_directories(editor_tests PRIVATE ${CMAKE_SOURCE_DIR}/engine/include ${CMAKE_SOURCE_DIR}/editor/src + ${CMAKE_SOURCE_DIR}/editor/src/Viewport ${CMAKE_BINARY_DIR}/_deps/imgui-src ${CMAKE_BINARY_DIR}/_deps/imgui-src/backends ) diff --git a/tests/editor/test_scene_viewport_render_pass_bundle.cpp b/tests/editor/test_scene_viewport_render_pass_bundle.cpp new file mode 100644 index 00000000..00653c3b --- /dev/null +++ b/tests/editor/test_scene_viewport_render_pass_bundle.cpp @@ -0,0 +1,119 @@ +#include + +#include "Viewport/SceneViewportEditorOverlayData.h" +#include "Viewport/SceneViewportRenderPassBundle.h" + +namespace { + +using XCEngine::Editor::SceneViewportOverlayData; +using XCEngine::Editor::SceneViewportOverlayFrameData; +using XCEngine::Editor::SceneViewportOverlayLinePrimitive; +using XCEngine::Editor::SceneViewportRenderPassBundle; +using XCEngine::Editor::ViewportRenderTargets; +using XCEngine::RHI::Format; +using XCEngine::RHI::RHIResourceView; +using XCEngine::RHI::ResourceViewDimension; +using XCEngine::RHI::ResourceViewType; + +class DummyResourceView final : public RHIResourceView { +public: + explicit DummyResourceView( + ResourceViewType viewType = ResourceViewType::RenderTarget, + Format format = Format::R8G8B8A8_UNorm) + : m_viewType(viewType) + , m_format(format) { + } + + void Shutdown() override { + } + + void* GetNativeHandle() override { + return nullptr; + } + + bool IsValid() const override { + return true; + } + + ResourceViewType GetViewType() const override { + return m_viewType; + } + + ResourceViewDimension GetDimension() const override { + return ResourceViewDimension::Texture2D; + } + + Format GetFormat() const override { + return m_format; + } + +private: + ResourceViewType m_viewType = ResourceViewType::RenderTarget; + Format m_format = Format::R8G8B8A8_UNorm; +}; + +SceneViewportOverlayData CreateValidOverlay() { + SceneViewportOverlayData overlay = {}; + overlay.valid = true; + overlay.cameraPosition = XCEngine::Math::Vector3(1.0f, 2.0f, 3.0f); + overlay.cameraForward = XCEngine::Math::Vector3::Forward(); + overlay.cameraRight = XCEngine::Math::Vector3::Right(); + overlay.cameraUp = XCEngine::Math::Vector3::Up(); + overlay.verticalFovDegrees = 70.0f; + overlay.nearClipPlane = 0.1f; + overlay.farClipPlane = 500.0f; + overlay.orbitDistance = 9.0f; + return overlay; +} + +SceneViewportOverlayFrameData CreateOverlayFrameDataWithLine(const SceneViewportOverlayData& overlay) { + SceneViewportOverlayFrameData frameData = {}; + frameData.overlay = overlay; + + SceneViewportOverlayLinePrimitive& line = frameData.worldLines.emplace_back(); + line.startWorld = XCEngine::Math::Vector3::Zero(); + line.endWorld = XCEngine::Math::Vector3::Right(); + line.color = XCEngine::Math::Color::White(); + return frameData; +} + +TEST(SceneViewportRenderPassBundleTest, BuildRenderPlanCreatesGridOutlineAndOverlayPasses) { + DummyResourceView objectIdShaderView(ResourceViewType::ShaderResource); + + ViewportRenderTargets targets = {}; + targets.objectIdShaderView = &objectIdShaderView; + + const SceneViewportOverlayData overlay = CreateValidOverlay(); + const SceneViewportOverlayFrameData editorOverlayFrameData = + CreateOverlayFrameDataWithLine(overlay); + + SceneViewportRenderPassBundle bundle; + const auto result = bundle.BuildRenderPlan( + targets, + overlay, + { 7u, 11u }, + editorOverlayFrameData, + false); + + EXPECT_EQ(result.plan.postScenePasses.GetPassCount(), 2u); + EXPECT_EQ(result.plan.overlayPasses.GetPassCount(), 1u); + EXPECT_EQ(result.warningStatusText, nullptr); +} + +TEST(SceneViewportRenderPassBundleTest, BuildRenderPlanReportsMissingObjectIdShaderView) { + const SceneViewportOverlayData overlay = CreateValidOverlay(); + + SceneViewportRenderPassBundle bundle; + const auto result = bundle.BuildRenderPlan( + {}, + overlay, + { 42u }, + {}, + false); + + EXPECT_EQ(result.plan.postScenePasses.GetPassCount(), 1u); + EXPECT_EQ(result.plan.overlayPasses.GetPassCount(), 0u); + EXPECT_STREQ(result.warningStatusText, "Scene object id shader view is unavailable"); +} + +} // namespace