2D移植完成
This commit is contained in:
@@ -1,225 +1,59 @@
|
||||
#include <render_2D/plottable/Spectrum.hpp>
|
||||
#include <render_2D/base/Frame_2D.hpp>
|
||||
#include <render_2D/scene/Render_Scene_2D.hpp>
|
||||
#include <render_2D/module/plottable/Spectrum.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
namespace {
|
||||
using namespace aethera;
|
||||
using namespace aethera::render_2d;
|
||||
template <typename Object, typename... Args>
|
||||
std::unique_ptr<Object> build_object(Args&&... args) {
|
||||
typename Object::template Builder<Object> builder(std::forward<Args>(args)...);
|
||||
auto result = builder.build();
|
||||
if (!result) std::terminate();
|
||||
return std::move(result).value();
|
||||
}
|
||||
template <typename Scene, typename... Renderables>
|
||||
std::unique_ptr<Scene> build_scene(Renderables*... renderables) {
|
||||
typename Scene::template Builder<Scene> builder;
|
||||
(builder.add_renderable(not_null{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.data() + static_cast<std::ptrdiff_t>(y) * view.stride);
|
||||
for (int x = 0; x < view.width; ++x)
|
||||
if (row[x] != 0) return true;
|
||||
|
||||
struct Spectrum_Fixture {
|
||||
Spectrum_Fixture() {
|
||||
Frequency_Axis::Builder frequency_builder;
|
||||
frequency_builder
|
||||
.set<Prop_Tag>(&Abs_Axis::Prop::position, Point_F{10.0, 90.0})
|
||||
.set<Prop_Tag>(&Abs_Axis::Prop::pixel_length, 100.0)
|
||||
.set<Prop_Tag>(&Numeric_Axis::Prop::coordinate_range, Axis_Range{0.0, 100.0});
|
||||
Numeric_Axis::Builder power_builder;
|
||||
power_builder
|
||||
.set<Prop_Tag>(&Abs_Axis::Prop::position, Point_F{10.0, 90.0})
|
||||
.set<Prop_Tag>(&Abs_Axis::Prop::pixel_length, -80.0)
|
||||
.set<Prop_Tag>(&Abs_Axis::Prop::orientation, Axis_Orientation::vertical)
|
||||
.set<Prop_Tag>(&Numeric_Axis::Prop::coordinate_range, Axis_Range{-100.0, 0.0});
|
||||
frequency = frequency_builder.build();
|
||||
power = power_builder.build();
|
||||
aethera::detail::model_private(*frequency).advance();
|
||||
aethera::detail::model_private(*power).advance();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
std::uint64_t image_hash(Image_View view) {
|
||||
std::uint64_t value{1469598103934665603ULL};
|
||||
for (int y = 0; y < view.height; ++y) {
|
||||
const auto* row = view.data.data() +
|
||||
static_cast<std::ptrdiff_t>(y) * view.stride;
|
||||
for (std::ptrdiff_t index = 0;
|
||||
index < static_cast<std::ptrdiff_t>(view.width * sizeof(Pixel));
|
||||
++index) {
|
||||
value ^= static_cast<std::uint8_t>(row[index]);
|
||||
value *= 1099511628211ULL;
|
||||
}
|
||||
}
|
||||
return 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_TRUE(scene->render(
|
||||
frame.get(), [](not_null<Frame_2D*>) {}).has_value());
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
TEST(spectrum_data, publishes_samples_through_tagged_frame_buffer) {
|
||||
using Frequency = Frequency_Axis;
|
||||
using Power = Numeric_Axis;
|
||||
using Object = Spectrum;
|
||||
using Scene_Object = Render_Scene_2D;
|
||||
auto frequency = build_object<Frequency>();
|
||||
auto power = build_object<Power>();
|
||||
auto spectrum = build_object<Object>(not_null{frequency.get()},
|
||||
not_null{power.get()});
|
||||
spectrum->set<&Spectrum::Prop::frequency_range>(Axis_Range{0.0, 100.0});
|
||||
const double samples[]{-100.0, -50.0, 0.0};
|
||||
spectrum->pending_buffer<Spectrum_Frame_Tag>() =
|
||||
Spectrum_Frame{std::vector<Spectrum_Power>(std::begin(samples), std::end(samples))};
|
||||
spectrum->mark_dirty<Render_Graph_Tag>();
|
||||
spectrum->advance();
|
||||
EXPECT_EQ(spectrum->current_buffer<Spectrum_Frame_Tag>().samples,
|
||||
(std::vector<Spectrum_Power>{-100.0, -50.0, 0.0}));
|
||||
}
|
||||
TEST(spectrum_markers, uses_tagged_properties_as_the_only_marker_interface) {
|
||||
using Frequency = Frequency_Axis;
|
||||
using Power = Numeric_Axis;
|
||||
using Object = Spectrum;
|
||||
using Scene_Object = Render_Scene_2D;
|
||||
auto frequency = build_object<Frequency>();
|
||||
auto power = build_object<Power>();
|
||||
auto spectrum = build_object<Object>(not_null{frequency.get()},
|
||||
not_null{power.get()});
|
||||
spectrum->set<&Spectrum::Prop::custom_markers>(
|
||||
std::vector<Spectrum_Frequency>{10.0, 20.0});
|
||||
spectrum->advance();
|
||||
EXPECT_EQ(spectrum->read_prop<Spectrum::Base_Tag>().custom_markers.size(), 2u);
|
||||
spectrum->set<&Spectrum::Prop::selected_marker>(1);
|
||||
spectrum->advance();
|
||||
EXPECT_EQ(spectrum->read_prop<Spectrum::Base_Tag>().selected_marker, 1);
|
||||
spectrum->update_prop<&Spectrum::Prop::custom_markers>(
|
||||
[](Prop_Access<Object::Prop> props) {
|
||||
props.get<Spectrum::Base_Tag>().custom_markers[1] = 25.0;
|
||||
});
|
||||
spectrum->advance();
|
||||
EXPECT_DOUBLE_EQ(
|
||||
spectrum->read_prop<Spectrum::Base_Tag>().custom_markers[1], 25.0);
|
||||
spectrum->update_prop<&Spectrum::Prop::custom_markers,
|
||||
&Spectrum::Prop::selected_marker>(
|
||||
[](Prop_Access<Object::Prop> props) {
|
||||
auto& values = props.get<Spectrum::Base_Tag>();
|
||||
values.custom_markers.erase(values.custom_markers.begin() +
|
||||
values.selected_marker);
|
||||
values.selected_marker = -1;
|
||||
});
|
||||
spectrum->advance();
|
||||
EXPECT_EQ(spectrum->read_prop<Spectrum::Base_Tag>().custom_markers.size(), 1u);
|
||||
EXPECT_EQ(spectrum->read_prop<Spectrum::Base_Tag>().selected_marker, -1);
|
||||
}
|
||||
TEST(render_scene_2d, composites_axes_and_spectrum_into_final_frame) {
|
||||
using Frequency = Frequency_Axis;
|
||||
using Power = Numeric_Axis;
|
||||
using Spectrum_Object = Spectrum;
|
||||
using Scene_Object = Render_Scene_2D;
|
||||
initialize_runtime({.workers = 2});
|
||||
auto frequency = build_object<Frequency>();
|
||||
auto power = build_object<Power>();
|
||||
auto spectrum = build_object<Spectrum_Object>(not_null{frequency.get()},
|
||||
not_null{power.get()}, 3u);
|
||||
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);
|
||||
frequency->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{0.0, 100.0});
|
||||
power->set<&Abs_Axis::Prop::position>(Point_F{20.0, 100.0});
|
||||
power->set<&Abs_Axis::Prop::pixel_length>(-80.0);
|
||||
power->set<&Abs_Axis::Prop::orientation>(Axis_Orientation::vertical);
|
||||
power->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{-100.0, 0.0});
|
||||
spectrum->set<&Spectrum::Prop::frequency_range>(Axis_Range{0.0, 100.0});
|
||||
spectrum->set<&Spectrum::Prop::sweep_region_visible>(true);
|
||||
spectrum->set<&Spectrum::Prop::max_hold_visible>(true);
|
||||
const double samples[]{-90.0, -65.0, -20.0, -45.0, -75.0};
|
||||
spectrum->pending_buffer<Spectrum_Frame_Tag>() =
|
||||
Spectrum_Frame{std::vector<Spectrum_Power>(std::begin(samples), std::end(samples))};
|
||||
spectrum->mark_dirty<Render_Graph_Tag>();
|
||||
scene->set<&Render_Scene_2D::Prop::viewport>(canvas);
|
||||
scene->set<&Render_Scene_2D::Prop::background>(Color::transparent());
|
||||
scene->activate_view();
|
||||
const auto render_graph = scene->pending_dependency_graph<Render_Graph_Tag>();
|
||||
EXPECT_FALSE(render_graph.depends_on(spectrum.get(), scene.get()));
|
||||
EXPECT_FALSE(render_graph.depends_on(spectrum.get(), frequency.get()));
|
||||
EXPECT_FALSE(render_graph.depends_on(spectrum.get(), power.get()));
|
||||
EXPECT_TRUE(render_graph.depends_on(frequency.get(), spectrum.get()));
|
||||
EXPECT_TRUE(render_graph.depends_on(power.get(), spectrum.get()));
|
||||
const auto cache_graph = scene->pending_dependency_graph<Render_Cache_Tag>();
|
||||
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()));
|
||||
auto output_frame = render_frame(scene.get());
|
||||
EXPECT_GT(spectrum->read_state<Spectrum::Base_Tag>().rendered_point_count, 0u);
|
||||
const Image_View frame = output_frame->image();
|
||||
ASSERT_FALSE(frame.empty());
|
||||
EXPECT_TRUE(contains_color(frame));
|
||||
EXPECT_FALSE(spectrum->dirty<Render_Cache_Tag>());
|
||||
EXPECT_FALSE(spectrum->dirty<Render_Graph_Tag>());
|
||||
EXPECT_FALSE(frequency->dirty<Render_Graph_Tag>());
|
||||
EXPECT_FALSE(power->dirty<Render_Graph_Tag>());
|
||||
EXPECT_FALSE(spectrum->read_prop<Renderable_2D::Base_Tag>().cache_enabled);
|
||||
spectrum->set<&Renderable_2D::Prop::cache_enabled>(true);
|
||||
output_frame = render_frame(scene.get());
|
||||
EXPECT_TRUE(contains_color(output_frame->image()));
|
||||
frequency->set<&Numeric_Axis::Prop::precision>(3);
|
||||
EXPECT_FALSE(spectrum->dirty<Render_Cache_Tag>());
|
||||
output_frame = render_frame(scene.get());
|
||||
EXPECT_TRUE(contains_color(output_frame->image()));
|
||||
frequency->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{0.0, 120.0});
|
||||
EXPECT_TRUE(spectrum->dirty<Render_Cache_Tag>());
|
||||
output_frame = render_frame(scene.get());
|
||||
EXPECT_FALSE(spectrum->dirty<Render_Cache_Tag>());
|
||||
spectrum->set<&Spectrum::Prop::partition_count>(2u);
|
||||
spectrum->pending_buffer<Spectrum_Frame_Tag>() =
|
||||
Spectrum_Frame{std::vector<Spectrum_Power>(std::begin(samples), std::end(samples))};
|
||||
spectrum->mark_dirty<Render_Graph_Tag>();
|
||||
output_frame = render_frame(scene.get());
|
||||
EXPECT_TRUE(contains_color(output_frame->image()));
|
||||
const Size resized_canvas{200, 140};
|
||||
scene->set<&Render_Scene_2D::Prop::viewport>(resized_canvas);
|
||||
EXPECT_TRUE(spectrum->dirty<Render_Cache_Tag>());
|
||||
EXPECT_FALSE(frequency->dirty<Render_Graph_Tag>());
|
||||
EXPECT_FALSE(power->dirty<Render_Graph_Tag>());
|
||||
output_frame = render_frame(scene.get());
|
||||
EXPECT_EQ(scene->read_prop<Render_Scene_2D::Base_Tag>().viewport, resized_canvas);
|
||||
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));
|
||||
std::unique_ptr<Frequency_Axis> frequency;
|
||||
std::unique_ptr<Numeric_Axis> power;
|
||||
};
|
||||
|
||||
TEST(Spectrum, Imports_One_Frame_And_Publishes_Diagnostics) {
|
||||
Spectrum_Fixture fixture;
|
||||
Spectrum::Builder builder(*fixture.frequency, *fixture.power);
|
||||
builder
|
||||
.set<Prop_Tag>(&Spectrum::Prop::frequency_range, Axis_Range{0.0, 100.0})
|
||||
.set<Spectrum_Frame_Tag>([](Spectrum::Frame& frame) { frame.samples = {-100.0, -50.0, 0.0}; });
|
||||
auto spectrum = builder.build();
|
||||
auto& private_data = aethera::detail::model_private(*spectrum);
|
||||
private_data.advance();
|
||||
Blend2D_Cache cache;
|
||||
cache.ensure_size({120, 100});
|
||||
aethera::render_2d::detail::Painter painter(cache, {120, 100});
|
||||
private_data.paint(painter, {120, 100});
|
||||
Spectrum::State state;
|
||||
spectrum->get<State_Tag>([&](const Spectrum::State& value) { state = value; });
|
||||
EXPECT_EQ(state.sample_count, 3U);
|
||||
EXPECT_GT(state.rendered_point_count, 0U);
|
||||
}
|
||||
|
||||
TEST(spectrum_data, repeatedly_publishes_new_samples_during_long_running_render) {
|
||||
using Frequency = Frequency_Axis;
|
||||
using Power = Numeric_Axis;
|
||||
using Spectrum_Object = Spectrum;
|
||||
using Scene_Object = Render_Scene_2D;
|
||||
initialize_runtime({.workers = 4});
|
||||
auto frequency = build_object<Frequency>();
|
||||
auto power = build_object<Power>();
|
||||
auto spectrum = build_object<Spectrum_Object>(not_null{frequency.get()},
|
||||
not_null{power.get()});
|
||||
auto scene = build_scene<Scene_Object>(spectrum.get());
|
||||
frequency->set<&Abs_Axis::Prop::position>(Point_F{20.0, 100.0});
|
||||
frequency->set<&Abs_Axis::Prop::pixel_length>(120.0);
|
||||
frequency->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{0.0, 100.0});
|
||||
power->set<&Abs_Axis::Prop::position>(Point_F{20.0, 100.0});
|
||||
power->set<&Abs_Axis::Prop::pixel_length>(-80.0);
|
||||
power->set<&Abs_Axis::Prop::orientation>(Axis_Orientation::vertical);
|
||||
power->set<&Numeric_Axis::Prop::coordinate_range>(Axis_Range{-100.0, 0.0});
|
||||
spectrum->set<&Spectrum::Prop::frequency_range>(Axis_Range{0.0, 100.0});
|
||||
scene->set<&Render_Scene_2D::Prop::viewport>(Size{160, 120});
|
||||
scene->set<&Render_Scene_2D::Prop::background>(Color::transparent());
|
||||
scene->activate_view();
|
||||
|
||||
std::uint64_t previous_hash{};
|
||||
std::size_t changed_frames{};
|
||||
for (std::size_t frame_index = 0; frame_index < 720; ++frame_index) {
|
||||
std::vector<Spectrum_Power> samples(128, -95.0);
|
||||
const std::size_t peak = 8 + frame_index % 112;
|
||||
samples[peak] = -15.0;
|
||||
spectrum->pending_buffer<Spectrum_Frame_Tag>() =
|
||||
Spectrum_Frame{std::move(samples)};
|
||||
spectrum->mark_dirty<Render_Graph_Tag>();
|
||||
auto frame = render_frame(scene.get());
|
||||
const auto hash = image_hash(frame->image());
|
||||
if (frame_index != 0 && hash != previous_hash) ++changed_frames;
|
||||
previous_hash = hash;
|
||||
EXPECT_EQ(spectrum->read_state<Spectrum::Base_Tag>().sample_count, 128u);
|
||||
}
|
||||
EXPECT_GT(changed_frames, 700u);
|
||||
TEST(Spectrum, Marker_Collection_Remains_One_Property_Source) {
|
||||
Spectrum_Fixture fixture;
|
||||
Spectrum::Builder builder(*fixture.frequency, *fixture.power);
|
||||
builder
|
||||
.set<Prop_Tag>(&Spectrum::Prop::custom_markers, std::vector<Spectrum_Frequency>{10.0, 20.0})
|
||||
.set<Prop_Tag>(&Spectrum::Prop::selected_marker, 1);
|
||||
auto spectrum = builder.build();
|
||||
std::vector<Spectrum_Frequency> markers;
|
||||
spectrum->get<Prop_Tag>([&](const Spectrum::Prop& properties) { markers = properties.custom_markers; });
|
||||
EXPECT_EQ(markers, (std::vector<Spectrum_Frequency>{10.0, 20.0}));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user