220 lines
8.4 KiB
C++
220 lines
8.4 KiB
C++
#include "Core2/export.h"
|
|
#include "Core2/plottable/Curve_Sampling.h"
|
|
#include "Core2/render/Blend2D_Cache.h"
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <array>
|
|
#include <cstddef>
|
|
#include <vector>
|
|
|
|
namespace renderive {
|
|
namespace {
|
|
|
|
TEST(Renderive_Core2, RootIdentityAndRefreshDiagnosticsComeFromKernelState) {
|
|
Plot_Core plot;
|
|
plot.init();
|
|
const auto root = plot.root_renderable();
|
|
ASSERT_TRUE(root);
|
|
root->set_object_name("renamed-root");
|
|
EXPECT_EQ(plot.root_renderable(), root);
|
|
|
|
plot.set_viewport_size({32, 24});
|
|
plot.activate_view();
|
|
plot.set_max_render_fps(144.0);
|
|
ASSERT_TRUE(plot.render_frame());
|
|
const auto diagnostics = plot.diagnostics();
|
|
EXPECT_DOUBLE_EQ(diagnostics.refresh.frequency_hz, 144.0);
|
|
EXPECT_EQ(diagnostics.refresh.frame_count, 1u);
|
|
}
|
|
|
|
TEST(Renderive_Core2, EveryCurveInterpolationModeHasDistinctSamplingSemantics) {
|
|
const std::array<double, 2> edge_values{0.0, 10.0};
|
|
const Range domain{0.0, 1.0};
|
|
const auto nearest = detail::curve_sampling::interpolate(
|
|
edge_values, domain, Line_Interpolation_Mode::Nearest_Sample);
|
|
const auto linear = detail::curve_sampling::interpolate(
|
|
edge_values, domain, Line_Interpolation_Mode::Linear_Value);
|
|
const auto power = detail::curve_sampling::interpolate(
|
|
edge_values, domain, Line_Interpolation_Mode::Linear_Power_Domain);
|
|
const auto step_left = detail::curve_sampling::interpolate(
|
|
edge_values, domain, Line_Interpolation_Mode::Step_Left);
|
|
const auto step_right = detail::curve_sampling::interpolate(
|
|
edge_values, domain, Line_Interpolation_Mode::Step_Right);
|
|
EXPECT_EQ(nearest.size(), 4u);
|
|
EXPECT_EQ(linear.size(), 2u);
|
|
ASSERT_EQ(power.size(), 5u);
|
|
EXPECT_NEAR(power[2].value, 7.4036269, 1e-6);
|
|
ASSERT_EQ(step_left.size(), 3u);
|
|
ASSERT_EQ(step_right.size(), 3u);
|
|
EXPECT_DOUBLE_EQ(step_left[1].coordinate, 1.0);
|
|
EXPECT_DOUBLE_EQ(step_left[1].value, 0.0);
|
|
EXPECT_DOUBLE_EQ(step_right[1].coordinate, 0.0);
|
|
EXPECT_DOUBLE_EQ(step_right[1].value, 10.0);
|
|
|
|
const std::array<double, 4> curved_values{0.0, 10.0, 0.0, 10.0};
|
|
const auto cubic = detail::curve_sampling::interpolate(
|
|
curved_values, {0.0, 3.0}, Line_Interpolation_Mode::Cubic_Value);
|
|
ASSERT_EQ(cubic.size(), 13u);
|
|
EXPECT_NEAR(cubic[2].value, 5.625, 1e-9);
|
|
|
|
const std::array<double, 11> visible_values{};
|
|
const Axis_Transform visible_x{{4.0, 6.0}, 0.0, 100.0};
|
|
const Axis_Transform visible_y{{0.0, 1.0}, 0.0, 100.0};
|
|
const auto clipped = detail::curve_points(
|
|
visible_values, {0.0, 10.0}, visible_x, visible_y, true,
|
|
Line_Interpolation_Mode::Linear_Value);
|
|
EXPECT_LT(clipped.size(), visible_values.size());
|
|
ASSERT_GE(clipped.size(), 2u);
|
|
EXPECT_LE(clipped.front().x, 0.0);
|
|
EXPECT_GE(clipped.back().x, 100.0);
|
|
}
|
|
|
|
TEST(Renderive_Core2, BicubicHeatmapUsesRealCubicResampling) {
|
|
const std::array<Pixel, 16> source{
|
|
pack_rgba(255, 0, 0), pack_rgba(0, 0, 0), pack_rgba(255, 255, 255), pack_rgba(0, 0, 255),
|
|
pack_rgba(0, 255, 0), pack_rgba(255, 255, 255), pack_rgba(0, 0, 0), pack_rgba(255, 0, 0),
|
|
pack_rgba(0, 0, 255), pack_rgba(0, 0, 0), pack_rgba(255, 255, 255), pack_rgba(0, 255, 0),
|
|
pack_rgba(255, 255, 255), pack_rgba(255, 0, 0), pack_rgba(0, 255, 0), pack_rgba(0, 0, 0)
|
|
};
|
|
const auto render = [&source](Image_Interpolation_Mode interpolation) {
|
|
detail::Blend2D_Color_Cache cache;
|
|
{
|
|
detail::Painter painter(cache, {11, 11});
|
|
painter.heatmap({0.0, 0.0, 11.0, 11.0}, 4, 4, source, interpolation);
|
|
}
|
|
const Image_View view = cache.view();
|
|
std::vector<Pixel> pixels;
|
|
pixels.reserve(static_cast<std::size_t>(view.width) * view.height);
|
|
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);
|
|
pixels.insert(pixels.end(), row, row + view.width);
|
|
}
|
|
return pixels;
|
|
};
|
|
const auto bilinear = render(Image_Interpolation_Mode::Bilinear);
|
|
const auto bicubic = render(Image_Interpolation_Mode::Bicubic);
|
|
EXPECT_EQ(bilinear.size(), bicubic.size());
|
|
EXPECT_NE(bilinear, bicubic);
|
|
}
|
|
|
|
TEST(Renderive_Core2, KernelSceneRendersBusinessObjectsIntoBlend2DFrame) {
|
|
Plot_Core plot;
|
|
plot.init();
|
|
plot.set_viewport_size({320, 180});
|
|
plot.activate_view();
|
|
|
|
const auto root = plot.root_renderable();
|
|
ASSERT_TRUE(root);
|
|
auto frequency_axis = Frequency_Axis::Builder(root, Orientation::Horizontal)
|
|
.set_x(32)
|
|
.set_y(150)
|
|
.set_pixel_length(270)
|
|
.set_coord_range({88.0, 108.0})
|
|
.build();
|
|
frequency_axis->set_locale({','});
|
|
frequency_axis->set_label_rotation_degrees(15);
|
|
EXPECT_EQ(frequency_axis->tick_label(88.5), "88,5 Hz");
|
|
frequency_axis->set_label_precision(4);
|
|
EXPECT_EQ(frequency_axis->tick_label(1'234'567.0), "1,2346 MHz");
|
|
auto power_axis = Axis::Builder(root, Orientation::Vertical)
|
|
.set_x(32)
|
|
.set_y(8)
|
|
.set_pixel_length(142)
|
|
.set_coord_range({-120.0, 0.0})
|
|
.build();
|
|
auto spectrum = Spectrum::Builder(root, frequency_axis, power_axis)
|
|
.set_frequency_range({88.0, 108.0})
|
|
.set_frequency_point_size(64)
|
|
.set_max_hold_visible(true)
|
|
.build();
|
|
|
|
std::vector<double> samples(64);
|
|
for (std::size_t index = 0; index < samples.size(); ++index)
|
|
samples[index] = -100.0 + static_cast<double>(index % 24) * 3.0;
|
|
spectrum->update_samples(samples);
|
|
|
|
ASSERT_TRUE(plot.render_frame());
|
|
bool saw_frame = false;
|
|
bool saw_drawn_pixel = false;
|
|
plot.with_frame([&](Image_View view) {
|
|
saw_frame = !view.empty() && view.width == 320 && view.height == 180;
|
|
if (!saw_frame)
|
|
return;
|
|
for (int y = 0; y < view.height && !saw_drawn_pixel; ++y) {
|
|
const auto* row = view.data + static_cast<std::ptrdiff_t>(y) * view.stride;
|
|
for (int x = 0; x < view.width * static_cast<int>(sizeof(Pixel)); ++x) {
|
|
if (row[x] != std::byte{}) {
|
|
saw_drawn_pixel = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
EXPECT_TRUE(saw_frame);
|
|
EXPECT_TRUE(saw_drawn_pixel);
|
|
EXPECT_EQ(plot.diagnostics().refresh.frame_count, 1u);
|
|
EXPECT_FALSE(plot.render_frame());
|
|
|
|
spectrum->update_samples(samples);
|
|
EXPECT_TRUE(plot.render_frame());
|
|
|
|
frequency_axis->set_use_wheel(true);
|
|
const Range before_zoom = frequency_axis->coord_range();
|
|
Wheel_Event wheel;
|
|
wheel.position = {160.0, 150.0};
|
|
wheel.angle_delta_y = 120.0;
|
|
plot.dispatch_event(wheel);
|
|
EXPECT_TRUE(wheel.is_accepted());
|
|
EXPECT_LT(frequency_axis->coord_range().size(), before_zoom.size());
|
|
EXPECT_TRUE(plot.render_frame());
|
|
|
|
plot.remove_renderable(spectrum);
|
|
EXPECT_TRUE(plot.render_frame(true));
|
|
EXPECT_FALSE(plot.render_frame());
|
|
}
|
|
|
|
TEST(Renderive_Core2, TimeAxisUsesOneFontStateAndFormatsConfiguredLabels) {
|
|
Plot_Core plot;
|
|
plot.init();
|
|
const auto root = plot.root_renderable();
|
|
auto axis = Time_Axis::Builder(root, Orientation::Horizontal)
|
|
.set_time_format("hh-mm-ss.zzz")
|
|
.set_font(Font{18.0, 700, true})
|
|
.set_tick_label_spacing_px(17)
|
|
.build();
|
|
ASSERT_TRUE(axis);
|
|
const int tick = axis->append_time(Time_Of_Day{3'723'045});
|
|
EXPECT_EQ(axis->tick_label(tick), "01-02-03.045");
|
|
EXPECT_EQ(axis->font(), (Font{18.0, 700, true}));
|
|
EXPECT_EQ(axis->unit_text_font(), axis->font());
|
|
EXPECT_EQ(axis->tick_label_spacing_px(), 17);
|
|
}
|
|
|
|
TEST(Renderive_Core2, PerformanceOverlayConsumesKernelFrameDiagnostics) {
|
|
Plot_Core plot;
|
|
plot.init();
|
|
plot.set_viewport_size({160, 90});
|
|
plot.activate_view();
|
|
plot.set_max_render_fps(120.0);
|
|
Performance_Overlay_Options options;
|
|
options.log.enabled = false;
|
|
const auto overlay = attach_performance_overlay(plot, options);
|
|
ASSERT_TRUE(overlay);
|
|
set_performance_plot_name(plot, "integration");
|
|
set_performance_overlay_enabled(plot, true);
|
|
|
|
ASSERT_TRUE(plot.render_frame(true));
|
|
const auto snapshot = overlay->display_snapshot();
|
|
ASSERT_TRUE(snapshot);
|
|
EXPECT_EQ(snapshot->plot_name, "integration");
|
|
EXPECT_EQ(snapshot->viewport_size, (Size{160, 90}));
|
|
EXPECT_FALSE(snapshot->lines.empty());
|
|
EXPECT_EQ(snapshot->frame_count, 1u);
|
|
EXPECT_DOUBLE_EQ(plot.max_render_fps(), 120.0);
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace renderive
|