#include "render_3D/Datoviz_Visuals.h" #include "render_3D/Scene_Context.hpp" #include #include #include #include #include namespace renderive::render_3d { namespace { template struct Visual_Frame_Test_Scene final : Scene3D_Context<>, Scene_Renderer { using Frame_Data = typename Visual::Frame_Data; explicit Visual_Frame_Test_Scene( const std::shared_ptr& visual) : owner(visual->renderable_id()) { auto builder = attach_builder(); builder.attach(renderive_Owner(visual)); } ~Visual_Frame_Test_Scene() override { shutdown(); } void render_frame() { publish_frame_state(); render(); wait_for_render(); } Node_Execution_Result render_scene( const Scene_Render_Context& context) override { prepared = context.template prepared(owner); if (!prepared) throw std::logic_error( "Datoviz visual did not publish frame-local data"); return Node_Execution_Result::completed(); } Renderable_Id owner{}; std::shared_ptr prepared; }; template void exercise(Item item) { static_assert(std::derived_from); auto visual = typename Visual::Builder{}.build(std::vector{item}); ASSERT_NE(visual, nullptr); EXPECT_EQ(visual->item_count(), 1U); EXPECT_EQ(visual->observation().event, Renderable_Observer_Event::Data_Updated); EXPECT_EQ(visual->observation().data_revision, visual->data_revision()); const auto initial_revision = visual->data_revision(); visual->edit_items([](auto& items) { items.push_back(items.front()); }); EXPECT_EQ(visual->item_count(), 2U); EXPECT_GT(visual->data_revision(), initial_revision); EXPECT_EQ(visual->observation().event, Renderable_Observer_Event::Data_Updated); EXPECT_EQ(visual->observation().item_count, 2U); EXPECT_EQ(visual->observation().data_revision, visual->data_revision()); Visual_Frame_Test_Scene scene(visual); scene.render_frame(); ASSERT_TRUE(scene.prepared); ASSERT_TRUE(scene.prepared->items); EXPECT_EQ(scene.prepared->items->size(), 2U); EXPECT_EQ(visual->observation().event, Renderable_Observer_Event::Published); const auto first_frame = scene.prepared; const auto first_published_revision = first_frame->data_revision; const auto revision = visual->data_revision(); visual->update_items(std::vector{item, item, item}); EXPECT_EQ(visual->item_count(), 3U); EXPECT_GT(visual->data_revision(), revision); EXPECT_EQ(visual->observation().event, Renderable_Observer_Event::Data_Updated); EXPECT_EQ(visual->observation().item_count, 3U); EXPECT_EQ(visual->observation().data_revision, visual->data_revision()); ASSERT_TRUE(first_frame->items); EXPECT_EQ(first_frame->items->size(), 2U); scene.render_frame(); ASSERT_TRUE(scene.prepared); ASSERT_TRUE(scene.prepared->items); EXPECT_EQ(scene.prepared->items->size(), 3U); EXPECT_GT(scene.prepared->data_revision, first_published_revision); EXPECT_EQ(visual->observation().event, Renderable_Observer_Event::Published); } TEST(DatovizVisualFamilies, EveryPublicFamilyUsesRenderableStorage) { exercise(Splat{}); exercise(Pixel{}); exercise(Marker{}); exercise(Sphere{}); exercise(Segment{.end = {1, 0, 0}}); exercise(Vector_Glyph{}); exercise(Primitive_Vertex{}); exercise(Mesh_Vertex{}); exercise(Path_Vertex{}); exercise(Image{}); exercise(Label{}); exercise(Glyph{}); exercise(Text_Label{.text = "Renderive"}); exercise(Voxel{}); } TEST(DatovizVisualFamilies, StateValidationAndBuilderPropertiesAreShared) { auto volume = Volume_Visual::Builder{} .set<&Volume_State::field_width>(4U) .set<&Volume_State::field_height>(4U) .set<&Volume_State::field_depth>(4U) .build(std::vector(64)); ASSERT_NE(volume, nullptr); EXPECT_EQ(volume->get<&Volume_State::field_depth>(), 4U); EXPECT_THROW((Volume_Visual::Builder{} .set<&Volume_State::field_width>(4U) .build()), std::invalid_argument); } } // namespace } // namespace renderive::render_3d