#include #include #include #include #include #include #include using namespace XCEngine::Components; using namespace XCEngine::Rendering; namespace { struct MockPipelineState { int initializeCalls = 0; int shutdownCalls = 0; int renderCalls = 0; uint32_t lastSurfaceWidth = 0; uint32_t lastSurfaceHeight = 0; CameraComponent* lastCamera = nullptr; size_t lastVisibleItemCount = 0; }; class MockPipeline final : public RenderPipeline { public: explicit MockPipeline(std::shared_ptr state) : m_state(std::move(state)) { } bool Initialize(const RenderContext&) override { ++m_state->initializeCalls; return true; } void Shutdown() override { ++m_state->shutdownCalls; } bool Render( const RenderContext&, const RenderSurface& surface, const RenderSceneData& sceneData) override { ++m_state->renderCalls; m_state->lastSurfaceWidth = surface.GetWidth(); m_state->lastSurfaceHeight = surface.GetHeight(); m_state->lastCamera = sceneData.camera; m_state->lastVisibleItemCount = sceneData.visibleItems.size(); return true; } private: std::shared_ptr m_state; }; RenderContext CreateValidContext() { RenderContext context; context.device = reinterpret_cast(1); context.commandList = reinterpret_cast(1); context.commandQueue = reinterpret_cast(1); return context; } } // namespace TEST(CameraRenderer_Test, UsesOverrideCameraAndSurfaceSizeWhenSubmittingScene) { Scene scene("CameraRendererScene"); GameObject* primaryCameraObject = scene.CreateGameObject("PrimaryCamera"); auto* primaryCamera = primaryCameraObject->AddComponent(); primaryCamera->SetPrimary(true); primaryCamera->SetDepth(10.0f); GameObject* overrideCameraObject = scene.CreateGameObject("OverrideCamera"); auto* overrideCamera = overrideCameraObject->AddComponent(); overrideCamera->SetPrimary(false); overrideCamera->SetDepth(-1.0f); auto state = std::make_shared(); CameraRenderer renderer(std::make_unique(state)); const RenderSurface surface(640, 480); ASSERT_TRUE(renderer.Render(scene, overrideCamera, CreateValidContext(), surface)); EXPECT_EQ(state->renderCalls, 1); EXPECT_EQ(state->lastSurfaceWidth, 640u); EXPECT_EQ(state->lastSurfaceHeight, 480u); EXPECT_EQ(state->lastCamera, overrideCamera); EXPECT_NE(state->lastCamera, primaryCamera); EXPECT_EQ(state->lastVisibleItemCount, 0u); } TEST(SceneRenderer_Test, ForwardsPipelineLifetimeAndRenderCallsToCameraRenderer) { Scene scene("SceneRendererScene"); GameObject* cameraObject = scene.CreateGameObject("Camera"); auto* camera = cameraObject->AddComponent(); camera->SetPrimary(true); camera->SetDepth(2.0f); auto initialState = std::make_shared(); auto replacementState = std::make_shared(); { auto initialPipeline = std::make_unique(initialState); MockPipeline* initialPipelineRaw = initialPipeline.get(); SceneRenderer renderer(std::move(initialPipeline)); EXPECT_EQ(renderer.GetPipeline(), initialPipelineRaw); auto replacementPipeline = std::make_unique(replacementState); MockPipeline* replacementPipelineRaw = replacementPipeline.get(); renderer.SetPipeline(std::move(replacementPipeline)); EXPECT_EQ(initialState->shutdownCalls, 1); EXPECT_EQ(renderer.GetPipeline(), replacementPipelineRaw); const RenderSurface surface(800, 600); ASSERT_TRUE(renderer.Render(scene, nullptr, CreateValidContext(), surface)); EXPECT_EQ(replacementState->renderCalls, 1); EXPECT_EQ(replacementState->lastSurfaceWidth, 800u); EXPECT_EQ(replacementState->lastSurfaceHeight, 600u); EXPECT_EQ(replacementState->lastCamera, camera); } EXPECT_EQ(initialState->shutdownCalls, 1); EXPECT_EQ(replacementState->shutdownCalls, 1); }