完美一版

This commit is contained in:
2026-08-22 00:57:37 +08:00
parent e3d3bfd767
commit a8f102bdb1
36 changed files with 1374 additions and 354 deletions
+18 -8
View File
@@ -1,4 +1,5 @@
#include <render_2D/axis/Axis.hpp>
#include <render_2D/base/Frame_2D.hpp>
#include <render_2D/event/Event.hpp>
#include <render_2D/event/Event_Routing_Rules.hpp>
#include <render_2D/scene/Render_Scene_2D.hpp>
@@ -12,6 +13,15 @@ std::unique_ptr<Object> build_axis() {
if (!result) std::terminate();
return std::move(result).value();
}
template <typename Scene>
std::unique_ptr<Frame_2D> render_frame(Scene* scene) {
static std::uint64_t sequence{1};
auto frame = std::make_unique<Frame_2D>(Frame_Identity{sequence++, 0});
EXPECT_EQ(scene->render(frame.get()), Render_Scene_2D::Render_Result::completed);
return frame;
}
template <typename Scene>
void render_once(Scene* scene) { static_cast<void>(render_frame(scene)); }
}
TEST(event_routing_rule, keeps_layered_targets_before_nearest_scored_targets) {
std::vector<int> targets{1, 2, 3, 4};
@@ -82,8 +92,8 @@ TEST(axis_render, scene_prepares_and_paints_uncached_axis_into_frame) {
prepare.add(axis.get());
paint.add(axis.get());
}).has_value()));
scene->render();
const Image_View view = scene->frame_view();
const auto frame = render_frame(scene.get());
const Image_View view = frame->image();
ASSERT_FALSE(view.empty());
bool contains_color{};
for (int y = 0; y < view.height && !contains_color; ++y) {
@@ -106,12 +116,12 @@ TEST(axis_event, numeric_axis_wheel_zoom_and_drag_update_authoritative_range) {
prepare.add(axis.get()); paint.add(axis.get());
}).has_value()));
scene->activate_view();
scene->render();
render_once(scene.get());
auto wheel = std::make_unique<Wheel_Event>();
wheel->position = {50.0, 0.0};
wheel->angle_delta_y = 120.0;
scene->dispatch_event(std::move(wheel));
scene->render();
render_once(scene.get());
EXPECT_EQ(axis->coordinate_range(), (Axis_Range{0.5, 9.5}));
auto press = std::make_unique<Pointer_Event>(Event_Type::pointer_press);
press->position = {50.0, 0.0};
@@ -120,7 +130,7 @@ TEST(axis_event, numeric_axis_wheel_zoom_and_drag_update_authoritative_range) {
auto move = std::make_unique<Pointer_Event>(Event_Type::pointer_move);
move->position = {60.0, 0.0};
scene->dispatch_event(std::move(move));
scene->render();
render_once(scene.get());
EXPECT_EQ(axis->coordinate_range(), (Axis_Range{-0.4, 8.6}));
}
TEST(axis_event, scene_routes_pointer_interaction_to_the_nearest_axis_segment) {
@@ -143,13 +153,13 @@ TEST(axis_event, scene_routes_pointer_interaction_to_the_nearest_axis_segment) {
paint.add(horizontal.get()); paint.add(vertical.get());
}).has_value()));
scene->activate_view();
scene->render();
render_once(scene.get());
auto near_vertical = std::make_unique<Wheel_Event>();
near_vertical->position = {22.0, 80.0};
near_vertical->angle_delta_y = 120.0;
scene->dispatch_event(std::move(near_vertical));
scene->render();
render_once(scene.get());
EXPECT_DOUBLE_EQ(horizontal->coordinate_range().size(), 10.0);
EXPECT_DOUBLE_EQ(vertical->coordinate_range().size(), 9.0);
@@ -157,7 +167,7 @@ TEST(axis_event, scene_routes_pointer_interaction_to_the_nearest_axis_segment) {
near_horizontal->position = {120.0, 178.0};
near_horizontal->angle_delta_y = 120.0;
scene->dispatch_event(std::move(near_horizontal));
scene->render();
render_once(scene.get());
EXPECT_DOUBLE_EQ(horizontal->coordinate_range().size(), 9.0);
EXPECT_DOUBLE_EQ(vertical->coordinate_range().size(), 9.0);
}
+31 -11
View File
@@ -1,4 +1,5 @@
#include <render_2D/plottable/Plottables.hpp>
#include <render_2D/base/Frame_2D.hpp>
#include <render_2D/scene/Render_Scene_2D.hpp>
#include <gtest/gtest.h>
#include <array>
@@ -30,6 +31,12 @@ void configure_axis(Axis* axis, Axis_Orientation orientation, Point_F position,
axis->template set<&Abs_Axis::Prop::position>(position);
axis->template set<&Abs_Axis::Prop::pixel_length>(length);
}
template <typename Scene>
void render_once(Scene* scene) {
static std::uint64_t sequence{1};
Frame_2D frame{Frame_Identity{sequence++, 0}};
EXPECT_EQ(scene->render(&frame), Render_Scene_2D::Render_Result::completed);
}
}
TEST(plottable_migration, curve_plots_share_partitioned_rendering) {
@@ -60,18 +67,31 @@ TEST(plottable_migration, curve_plots_share_partitioned_rendering) {
trace->append_sample(time->append_time({2'000}), 50.0);
trace->append_sample(time->append_time({3'000}), 90.0);
sweep->set<&Sweep_Spectrum::Prop::frequency_range>(Axis_Range{0.0, 100.0});
sweep->set<&Sweep_Spectrum::Prop::block_count>(2u);
sweep->set<&Sweep_Spectrum::Prop::partition_mode>(Plot_Partition_Mode::fixed);
sweep->set<&Sweep_Spectrum::Prop::partition_count>(2u);
const std::array<Plot_Value, 4> block{-90.0, -60.0, -30.0, -10.0};
sweep->append_block(block);
const std::array<Plot_Value, 4> first_block{-90.0, -60.0, -30.0, -10.0};
const std::array<Plot_Value, 4> second_block{-80.0, -50.0, -20.0, -5.0};
const std::array<Plot_Value, 4> replacement_block{-70.0, -40.0, -15.0, -2.0};
sweep->append_block(first_block);
sweep->append_block(second_block);
auto scene = build_scene<Scene>(trace.get(), sweep.get());
scene->set<&Render_Scene_2D::Prop::viewport>(canvas);
scene->activate_view();
scene->render();
render_once(scene.get());
EXPECT_EQ(trace->sample_count(), 3u);
EXPECT_GT(trace->rendered_point_count(), 0u);
EXPECT_EQ(sweep->stored_block_count(), 1u);
EXPECT_EQ(sweep->stored_block_count(), 2u);
EXPECT_GT(sweep->rendered_point_count(), 0u);
const auto completed_sweep_points = sweep->rendered_point_count();
sweep->append_block(replacement_block);
render_once(scene.get());
EXPECT_EQ(sweep->stored_block_count(), 2u);
EXPECT_EQ(sweep->rendered_point_count(), completed_sweep_points);
const auto& sweep_prop = sweep->read_prop<Sweep_Spectrum::Base_Tag>();
EXPECT_EQ(sweep_prop.blocks[0], std::vector<Plot_Value>(replacement_block.begin(), replacement_block.end()));
EXPECT_EQ(sweep_prop.blocks[1], std::vector<Plot_Value>(second_block.begin(), second_block.end()));
EXPECT_EQ(sweep_prop.next_block_index, 1u);
}
TEST(plottable_migration, raster_plots_share_partitioned_color_blocks) {
@@ -105,7 +125,7 @@ TEST(plottable_migration, raster_plots_share_partitioned_color_blocks) {
auto scene = build_scene<Scene>(glow.get(), waterfall.get());
scene->set<&Render_Scene_2D::Prop::viewport>(canvas);
scene->activate_view();
scene->render();
render_once(scene.get());
EXPECT_EQ(glow->history_count(), 1u);
EXPECT_GT(glow->rendered_cell_count(), 0u);
EXPECT_EQ(waterfall->row_count(), 2u);
@@ -133,7 +153,7 @@ TEST(plottable_migration, direct_overlay_and_constellation_build_and_render) {
auto scene = build_scene<Scene>(diagram.get(), overlay.get());
scene->set<&Render_Scene_2D::Prop::viewport>(canvas);
scene->activate_view();
scene->render();
render_once(scene.get());
EXPECT_EQ(diagram->point_count(), 1u);
EXPECT_EQ(overlay->read_state<Renderable::Base_Tag>().prepare_task_count, 0u);
EXPECT_EQ(overlay->read_state<Renderable::Base_Tag>().paint_task_count, 1u);
@@ -155,7 +175,7 @@ TEST(selection_overlay, control_extends_selection_and_plain_click_clears_it) {
auto scene = build_scene<Scene>(overlay.get());
scene->set<&Render_Scene_2D::Prop::viewport>(canvas);
scene->activate_view();
scene->render();
render_once(scene.get());
const auto drag = [&](Point_F first, Point_F second, Keyboard_Modifier modifiers) {
auto press = std::make_unique<Pointer_Event>(Event_Type::pointer_press);
@@ -172,7 +192,7 @@ TEST(selection_overlay, control_extends_selection_and_plain_click_clears_it) {
release->button = Mouse_Button::left;
release->modifiers = modifiers;
scene->dispatch_event(std::move(release));
scene->render();
render_once(scene.get());
};
drag({30.0, 90.0}, {60.0, 60.0}, Keyboard_Modifier::none);
EXPECT_EQ(overlay->selected_regions().size(), 1u);
@@ -202,7 +222,7 @@ TEST(selection_overlay, time_axis_selection_keeps_axis_coordinates_while_window_
auto scene = build_scene<Scene>(overlay.get());
scene->set<&Render_Scene_2D::Prop::viewport>(canvas);
scene->activate_view();
scene->render();
render_once(scene.get());
auto press = std::make_unique<Pointer_Event>(Event_Type::pointer_press);
press->position = {92.0, 88.0};
press->button = Mouse_Button::left;
@@ -214,12 +234,12 @@ TEST(selection_overlay, time_axis_selection_keeps_axis_coordinates_while_window_
release->position = {116.0, 56.0};
release->button = Mouse_Button::left;
scene->dispatch_event(std::move(release));
scene->render();
render_once(scene.get());
ASSERT_EQ(overlay->selected_regions().size(), 1u);
const Axis_Rectangle selected = overlay->selected_regions().front();
const auto pixel_before = time->coordinate_to_pixel(selected.horizontal.center());
time->append_time({4'000});
scene->render();
render_once(scene.get());
ASSERT_EQ(overlay->selected_regions().size(), 1u);
EXPECT_EQ(overlay->selected_regions().front(), selected);
EXPECT_NE(time->coordinate_to_pixel(selected.horizontal.center()), pixel_before);
+35 -20
View File
@@ -1,4 +1,5 @@
#include <render_2D/plottable/Spectrum.hpp>
#include <render_2D/base/Frame_2D.hpp>
#include <render_2D/scene/Render_Scene_2D.hpp>
#include <gtest/gtest.h>
namespace {
@@ -11,6 +12,14 @@ std::unique_ptr<Object> build_object(Args&&... args) {
if (!result) std::terminate();
return std::move(result).value();
}
template <typename Scene, typename... Renderables>
std::unique_ptr<Scene> build_scene(Renderables*... renderables) {
typename Scene::Builder builder;
(builder.add_renderable(renderables), ...);
auto result = builder.build();
if (!result) std::terminate();
return std::move(result).value();
}
bool contains_color(Image_View view) {
for (int y = 0; y < view.height; ++y) {
const auto* row = reinterpret_cast<const Pixel*>(view.data + static_cast<std::ptrdiff_t>(y) * view.stride);
@@ -19,16 +28,22 @@ bool contains_color(Image_View view) {
}
return false;
}
template <typename Scene>
std::unique_ptr<Frame_2D> render_frame(Scene* scene) {
static std::uint64_t sequence{1};
auto frame = std::make_unique<Frame_2D>(Frame_Identity{sequence++, 0});
EXPECT_EQ(scene->render(frame.get()), Render_Scene_2D::Render_Result::completed);
return frame;
}
}
TEST(spectrum_data, publishes_samples_and_interpolates_power) {
using Frequency = Impl<Frequency_Axis>;
using Power = Impl<Numeric_Axis>;
using Object = Impl<Spectrum>;
using Scene_Object = Impl<Render_Scene_2D>;
auto scene = build_object<Scene_Object>();
auto frequency = build_object<Frequency>();
auto power = build_object<Power>();
auto spectrum = build_object<Object>(scene.get(), frequency.get(), power.get());
auto spectrum = build_object<Object>(frequency.get(), power.get());
const auto missing = spectrum->power_at(25.0);
ASSERT_FALSE(missing.has_value());
EXPECT_EQ(missing.error(), Spectrum::Power_At_Result::no_samples);
@@ -49,10 +64,9 @@ TEST(spectrum_markers, supports_selection_frequency_changes_and_known_results) {
using Power = Impl<Numeric_Axis>;
using Object = Impl<Spectrum>;
using Scene_Object = Impl<Render_Scene_2D>;
auto scene = build_object<Scene_Object>();
auto frequency = build_object<Frequency>();
auto power = build_object<Power>();
auto spectrum = build_object<Object>(scene.get(), frequency.get(), power.get());
auto spectrum = build_object<Object>(frequency.get(), power.get());
spectrum->add_custom_marker(10.0);
spectrum->add_custom_line_marker(20.0);
spectrum->advance();
@@ -79,10 +93,10 @@ TEST(render_scene_2d, composites_axes_and_spectrum_into_final_frame) {
using Spectrum_Object = Impl<Spectrum>;
using Scene_Object = Impl<Render_Scene_2D>;
initialize_runtime(2);
auto scene = build_object<Scene_Object>();
auto frequency = build_object<Frequency>();
auto power = build_object<Power>();
auto spectrum = build_object<Spectrum_Object>(scene.get(), frequency.get(), power.get());
auto spectrum = build_object<Spectrum_Object>(frequency.get(), power.get());
auto scene = build_scene<Scene_Object>(spectrum.get());
const Size canvas{160, 120};
frequency->set<&Abs_Axis::Prop::position>(Point_F{20.0, 100.0});
frequency->set<&Abs_Axis::Prop::pixel_length>(120.0);
@@ -112,48 +126,49 @@ TEST(render_scene_2d, composites_axes_and_spectrum_into_final_frame) {
EXPECT_TRUE(cache_graph.depends_on(spectrum.get(), scene.get()));
EXPECT_TRUE(cache_graph.depends_on(spectrum.get(), frequency.get()));
EXPECT_TRUE(cache_graph.depends_on(spectrum.get(), power.get()));
scene->render();
auto output_frame = render_frame(scene.get());
EXPECT_GT(spectrum->rendered_point_count(), 0u);
const auto& render_state = spectrum->read_state<Renderable::Base_Tag>();
EXPECT_EQ(render_state.prepare_task_count, 4u);
EXPECT_EQ(render_state.paint_task_count, 1u);
const Image_View frame = scene->frame_view();
const Image_View frame = output_frame->image();
ASSERT_FALSE(frame.empty());
EXPECT_TRUE(contains_color(frame));
EXPECT_FALSE(spectrum->dirty<Paint_Cache_Tag>());
EXPECT_FALSE(spectrum->dirty<Paint_Tag>());
EXPECT_FALSE(frequency->dirty<Paint_Tag>());
EXPECT_FALSE(power->dirty<Paint_Tag>());
scene->render();
EXPECT_TRUE(contains_color(scene->frame_view()));
output_frame = render_frame(scene.get());
EXPECT_TRUE(contains_color(output_frame->image()));
frequency->set<&Numeric_Axis::Prop::precision>(3);
EXPECT_FALSE(spectrum->dirty<Paint_Cache_Tag>());
scene->render();
output_frame = render_frame(scene.get());
EXPECT_TRUE(spectrum->read_state<Renderable::Base_Tag>().paint_executed);
EXPECT_TRUE(frequency->read_state<Renderable::Base_Tag>().paint_executed);
EXPECT_TRUE(power->read_state<Renderable::Base_Tag>().paint_executed);
EXPECT_TRUE(contains_color(scene->frame_view()));
EXPECT_TRUE(contains_color(output_frame->image()));
frequency->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{0.0, 120.0});
EXPECT_TRUE(spectrum->dirty<Paint_Cache_Tag>());
scene->render();
output_frame = render_frame(scene.get());
EXPECT_FALSE(spectrum->dirty<Paint_Cache_Tag>());
EXPECT_TRUE(spectrum->read_state<Renderable::Base_Tag>().prepare_executed);
spectrum->set<&Spectrum::Prop::partition_count>(2u);
spectrum->update_samples(samples);
scene->render();
output_frame = render_frame(scene.get());
const auto& rebuilt_state = spectrum->read_state<Renderable::Base_Tag>();
EXPECT_TRUE(rebuilt_state.prepare_graph_rebuilt);
EXPECT_EQ(rebuilt_state.prepare_task_count, 3u);
EXPECT_TRUE(contains_color(scene->frame_view()));
EXPECT_TRUE(contains_color(output_frame->image()));
const Size resized_canvas{200, 140};
scene->set<&Render_Scene_2D::Prop::viewport>(resized_canvas);
EXPECT_TRUE(frequency->dirty<Prepare_Data_Tag>());
EXPECT_TRUE(power->dirty<Prepare_Data_Tag>());
scene->render();
EXPECT_TRUE(spectrum->dirty<Paint_Cache_Tag>());
EXPECT_FALSE(frequency->dirty<Prepare_Data_Tag>());
EXPECT_FALSE(power->dirty<Prepare_Data_Tag>());
output_frame = render_frame(scene.get());
EXPECT_EQ(scene->read_prop<Render_Scene_2D::Base_Tag>().viewport, resized_canvas);
EXPECT_TRUE(frequency->read_state<Renderable::Base_Tag>().prepare_executed);
EXPECT_FALSE(frequency->read_state<Renderable::Base_Tag>().prepare_executed);
EXPECT_TRUE(frequency->read_state<Renderable::Base_Tag>().paint_executed);
const Image_View resized_frame = scene->frame_view();
const Image_View resized_frame = output_frame->image();
EXPECT_EQ(resized_frame.width, resized_canvas.width);
EXPECT_EQ(resized_frame.height, resized_canvas.height);
EXPECT_TRUE(contains_color(resized_frame));