#include #include #include #include "renderive/renderable/Renderable.hpp" #include "renderive/scene/Scene.hpp" struct Scene3D_Context_Test_Renderable : Renderable_Base { explicit Scene3D_Context_Test_Renderable(Scene_Base& scene) : Renderable_Base(scene) {} void render(const Scene_Render_Context& context) override { scene_is_3d = dynamic_cast(context.scene) != nullptr; ++render_count; } std::atomic render_count{}; bool scene_is_3d{}; }; TEST(scene3d_context_test, uses_scene_3d_base_contract) { Scene3D_Context<> scene; auto renderable = std::make_shared(scene); scene.attach_renderable(renderable); scene.render(); scene.wait_for_render(); EXPECT_EQ(renderable->render_count.load(), 1); EXPECT_TRUE(renderable->scene_is_3d); } struct Scene3D_Dependency_Cache_Test_Renderable : Renderable_Base { explicit Scene3D_Dependency_Cache_Test_Renderable(Scene_Base& scene) : Renderable_Base(scene, {.cache_enabled = true}) {} void render(const Scene_Render_Context&) override { ++render_count; } int render_count{}; }; TEST(scene3d_context_test, propagates_cache_invalidation_through_unsorted_dependency_chain) { Scene3D_Context<> scene; auto leaf = std::make_shared(scene); auto middle = std::make_shared(scene); auto root = std::make_shared(scene); scene.attach_renderable(leaf); scene.attach_renderable(middle); scene.attach_renderable(root); scene.set_dependency_parent(*leaf, middle.get()); scene.set_dependency_parent(*middle, root.get()); scene.render(); scene.wait_for_render(); EXPECT_EQ(root->render_count, 1); EXPECT_EQ(middle->render_count, 1); EXPECT_EQ(leaf->render_count, 1); root->invalidate_cache(); scene.render(); scene.wait_for_render(); EXPECT_EQ(root->render_count, 2); EXPECT_EQ(middle->render_count, 2); EXPECT_EQ(leaf->render_count, 2); } TEST(scene3d_context_test, detach_parent_promotes_children_and_invalidates_dependency_cache) { Scene3D_Context<> scene; auto grandparent = std::make_shared(scene); auto parent = std::make_shared(scene); auto child = std::make_shared(scene); scene.attach_renderable(grandparent); scene.attach_renderable(parent); scene.attach_renderable(child); scene.set_display_parent(*parent, grandparent.get()); scene.set_display_parent(*child, parent.get()); scene.set_dependency_parent(*parent, grandparent.get()); scene.set_dependency_parent(*child, parent.get()); scene.render(); scene.wait_for_render(); EXPECT_EQ(child->render_count, 1); scene.detach_renderable(*parent); const auto topology = scene.topology_snapshot(); bool display_checked{}; bool dependency_checked{}; for (const auto& relation : topology.display) { if (relation.child.get() == child.get()) { EXPECT_EQ(relation.parent.get(), grandparent.get()); display_checked = true; } } for (const auto& relation : topology.dependency) { if (relation.child.get() == child.get()) { EXPECT_EQ(relation.parent.get(), grandparent.get()); dependency_checked = true; } } EXPECT_TRUE(display_checked); EXPECT_TRUE(dependency_checked); scene.render(); scene.wait_for_render(); EXPECT_EQ(parent->render_count, 1); EXPECT_EQ(child->render_count, 2); }