diff --git a/kernel/src/kernel/event.ipp b/kernel/src/kernel/event.ipp new file mode 100644 index 0000000..2651412 --- /dev/null +++ b/kernel/src/kernel/event.ipp @@ -0,0 +1,20 @@ +#pragma once +namespace aethera { +inline Event::Event(Event_Type value) : type(value) {} +inline Event::~Event() = default; +inline void Event::accept() const noexcept { accepted = true; } +inline bool Event::is_accepted() const noexcept { return accepted; } +constexpr Keyboard_Modifier operator|(Keyboard_Modifier left, Keyboard_Modifier right) noexcept { return static_cast(static_cast(left) | static_cast(right)); } +template Basic_Pointer_Event::Basic_Pointer_Event(Event_Type value) : Event(value) {} +template double Basic_Pointer_Event::position_x() const noexcept { return static_cast(position.x); } +template double Basic_Pointer_Event::position_y() const noexcept { return static_cast(position.y); } +template Mouse_Button Basic_Pointer_Event::pointer_button() const noexcept { return button; } +template Keyboard_Modifier Basic_Pointer_Event::keyboard_modifiers() const noexcept { return modifiers; } +template Basic_Wheel_Event::Basic_Wheel_Event() : Basic_Pointer_Event(Event_Type::wheel) {} +template double Basic_Wheel_Event::pixel_delta_x_value() const noexcept { return pixel_delta_x; } +template double Basic_Wheel_Event::pixel_delta_y_value() const noexcept { return pixel_delta_y; } +template double Basic_Wheel_Event::angle_delta_x_value() const noexcept { return angle_delta_x; } +template double Basic_Wheel_Event::angle_delta_y_value() const noexcept { return angle_delta_y; } +template Basic_Resize_Event::Basic_Resize_Event() : Event(Event_Type::resize) {} +inline Key_Event::Key_Event(Event_Type value) : Event(value) {} +} diff --git a/render_3D/tests/Visual_Tests.cpp b/render_3D/tests/Visual_Tests.cpp new file mode 100644 index 0000000..deca09d --- /dev/null +++ b/render_3D/tests/Visual_Tests.cpp @@ -0,0 +1,69 @@ +#include +#include +#include +#include +namespace aethera::render_3d { +namespace { +template +void verify_visual(Item valid, Item invalid) { + using Object = Impl; + auto built = typename Object::Builder{}.build(); + ASSERT_TRUE(built.has_value()); + auto object = std::move(built).value(); + EXPECT_EQ(object->update_items({valid}), Visual::Update_Items_Result::updated); + EXPECT_EQ(object->update_items({invalid}), Visual::Update_Items_Result::invalid_data); + object->advance(); + EXPECT_EQ(object->item_count(), 1U); + EXPECT_EQ(object->template read_state().item_count, 1U); +} +} +TEST(Render_3D_Visual, Migrated_Families_Build_And_Validate) { + verify_visual(Point{}, Point{.diameter_px = 0.0F}); + verify_visual(Splat{}, Splat{.sigma = {0.0F, 0.0F}}); + verify_visual(Pixel{}, Pixel{.size_px = 0.0F}); + verify_visual(Marker{}, Marker{.diameter_px = 0.0F}); + verify_visual(Sphere{}, Sphere{.radius = 0.0F}); + verify_visual(Segment{}, Segment{.width_px = 0.0F}); + verify_visual(Vector_Glyph{}, Vector_Glyph{.width_px = 0.0F}); + verify_visual(Primitive_Vertex{}, Primitive_Vertex{.position = {NAN, 0.0F, 0.0F}}); + verify_visual(Mesh_Vertex{}, Mesh_Vertex{.normal = {NAN, 0.0F, 0.0F}}); + verify_visual(Path_Vertex{}, Path_Vertex{.width_px = 0.0F}); + verify_visual(Image{}, Image{.extent = {0.0F, 0.0F}}); + verify_visual(Label{}, Label{.extent = {0.0F, 0.0F}}); + verify_visual(Glyph{}, Glyph{.angle = NAN}); + verify_visual(Text_Label{.text = "A"}, Text_Label{}); + verify_visual(Voxel{}, Voxel{.value = NAN}); +} +TEST(Render_3D_Scene, Builder_Instantiates_Async_Paint_Contract) { + using Visual_Object = Impl; + using Scene_Object = Impl; + auto visual_result = typename Visual_Object::Builder{}.build(); + ASSERT_TRUE(visual_result.has_value()); + auto visual = std::move(visual_result).value(); + typename Scene_Object::Builder scene_builder(visual.get()); + static_assert(std::same_as, Dependency_Graph_Error>>); +} +TEST(Render_3D_Scene, Paint_Submits_Without_Waiting_For_Gpu) { + using Visual_Object = Impl; + using Scene_Object = Impl; + auto visual_result = typename Visual_Object::Builder{}.build(); + ASSERT_TRUE(visual_result.has_value()); + auto visual = std::move(visual_result).value(); + ASSERT_EQ(visual->update_items({Point{.position = {0.0F, 0.0F, 0.0F}, .color = Color::red_color(), .diameter_px = 8.0F}}), Point_Visual::Update_Items_Result::updated); + visual->advance(); + try { + auto scene_result = typename Scene_Object::Builder(visual.get()).build(); + ASSERT_TRUE(scene_result.has_value()); + auto scene = std::move(scene_result).value(); + const auto started = std::chrono::steady_clock::now(); + EXPECT_EQ(scene->request_frame(), Render_Scene_3D::Request_Frame_Result::queued); + const auto submit_duration = std::chrono::steady_clock::now() - started; + EXPECT_LT(submit_duration, std::chrono::seconds(1)); + for (std::size_t attempt = 0; attempt != 500 && !scene->latest_frame(); ++attempt) std::this_thread::sleep_for(std::chrono::milliseconds(10)); + EXPECT_NE(scene->latest_frame(), nullptr); + } + catch (const std::exception& error) { + GTEST_SKIP() << "Vulkan/Datoviz unavailable: " << error.what(); + } +} +}