#include "render_2D/scene/Render_Scene_2D.h" #include #include #include namespace renderive { namespace { std::unique_ptr make_scene( Render_Scene_2D::State state = {}) { auto strategy = std::make_shared(); return Render_Scene_2D::Builder(std::move(strategy)) .configure([&](Render_Scene_2D::Properties& properties) { properties = state; }) .build().value(); } TEST(RenderScene2DFramePipeline, BuilderOwnsConstructionAndState) { Render_Scene_2D::State state; state.viewport = {96, 54}; state.background = Color{8, 16, 24, 255}; auto scene = make_scene(state); ASSERT_TRUE(scene); EXPECT_EQ(scene->root_renderable()->object_name(), "root"); } TEST(RenderScene2DFramePipeline, SceneBuilderOwnsRenderableGroupAndObjectNames) { auto builder = Render_Scene_2D::Builder( std::make_shared()); const auto root = builder.root_renderable(); auto child = detail::make_renderable_group(false, "child"); Renderable_Build_Topology topology; topology.dependency.push_back( detail::build_relationship(child, root)); topology.display.push_back( detail::build_relationship(child, root)); detail::Renderable_Build_Access::set_topology(*child, std::move(topology)); builder.add_renderable(child); auto built_scene = builder.build(); ASSERT_TRUE(built_scene); ASSERT_TRUE(*built_scene); EXPECT_EQ(child->object_name(), "child"); EXPECT_EQ((*built_scene)->observer().renderable_count, 2U); } TEST(RenderScene2DFramePipeline, SceneBuilderRejectsMissingDependencyEndpoint) { auto builder = Render_Scene_2D::Builder( std::make_shared()); const auto root = builder.root_renderable(); auto external = detail::make_renderable_group(false, "external"); auto child = detail::make_renderable_group(false, "child"); Renderable_Build_Topology topology; topology.dependency.push_back( detail::build_relationship(child, external)); topology.display.push_back( detail::build_relationship(child, root)); detail::Renderable_Build_Access::set_topology(*child, std::move(topology)); builder.add_renderable(child); auto built_scene = builder.build(); ASSERT_FALSE(built_scene); EXPECT_EQ(built_scene.error(), Scene_Build_Result::dependency_endpoint_missing); } TEST(RenderScene2DFramePipeline, SceneBuilderRejectsDependencyCycle) { auto builder = Render_Scene_2D::Builder( std::make_shared()); auto first = detail::make_renderable_group(false, "first"); auto second = detail::make_renderable_group(false, "second"); Renderable_Build_Topology first_topology; first_topology.dependency.push_back( detail::build_relationship(first, second)); detail::Renderable_Build_Access::set_topology( *first, std::move(first_topology)); Renderable_Build_Topology second_topology; second_topology.dependency.push_back( detail::build_relationship(second, first)); detail::Renderable_Build_Access::set_topology( *second, std::move(second_topology)); builder.add_renderable(first); builder.add_renderable(second); auto built_scene = builder.build(); ASSERT_FALSE(built_scene); EXPECT_EQ(built_scene.error(), Scene_Build_Result::dependency_cycle); } TEST(RenderScene2DFramePipeline, SceneValidityDoesNotGateStrategyProgress) { Render_Scene_2D::State state; state.viewport = {80, 45}; auto scene = make_scene(state); scene->publish_frame_state(); EXPECT_EQ(scene->observer().state, state); EXPECT_EQ(scene->render_frame().value(), Plot_Render_Status::view_inactive); scene->activate_view(); EXPECT_EQ(scene->render_frame().value(), Plot_Render_Status::rendered); EXPECT_EQ(scene->render_frame().value(), Plot_Render_Status::rendered); EXPECT_EQ(scene->wait_for_render(), Scene_Render_Result::none); } TEST(RenderScene2DFramePipeline, ObserverReadsPublishedDoubleBufferedState) { Render_Scene_2D::State state; state.viewport = {32, 24}; auto scene = make_scene(state); scene->activate_view(); ASSERT_EQ(scene->render_frame().value(), Plot_Render_Status::rendered); ASSERT_EQ(scene->wait_for_render(), Scene_Render_Result::none); const auto observation = scene->observer(); EXPECT_EQ(observation.state, state); EXPECT_EQ(observation.renderable_count, 1U); EXPECT_TRUE(observation.view_active); EXPECT_GT(observation.frequency_hz, 0.0); } } // namespace } // namespace renderive