From 3d027967b9199d4e186b84b7999fe079292ed3ad Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Sun, 2 Aug 2026 03:43:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8D=E7=A7=B0=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/Axis/Abs_Axis.cpp | 34 +- Core/Axis/Abs_Axis.h | 21 +- Core/Axis/Abs_Axis_p.h | 81 +- Core/Axis/Axis.cpp | 2 +- Core/Axis/Axis.h | 10 +- Core/Axis/Axis_p.h | 6 +- Core/Axis/Frequency_Axis_p.h | 4 +- Core/Axis/Time_Axis.cpp | 26 +- Core/Axis/Time_Axis.h | 17 +- Core/Axis/Time_Axis_p.h | 18 +- Core/architecture/Buffer_Role.h | 8 - Core/architecture/Frame_Scheduler.cpp | 8 +- Core/architecture/Frame_Scheduler.h | 25 +- Core/architecture/Render_Config.h | 19 +- Core/architecture/Render_Data.h | 23 +- Core/architecture/Render_Lease.h | 10 +- Core/architecture/Render_Utils.cpp | 2 +- Core/architecture/Renderable.cpp | 12 +- Core/architecture/Timeline_Stream.cpp | 42 +- Core/architecture/Timeline_Stream.h | 22 +- Core/base/Color.h | 30 +- Core/base/Geometry.h | 28 +- Core/base/Style.h | 4 +- Core/base/Text.h | 23 +- Core/execution/Render_Executor.cpp | 2 +- Core/execution/Render_Executor.h | 11 +- Core/plot/Plot_Core.cpp | 130 +-- Core/plot/Plot_Core.h | 6 +- Core/plot/Plot_Frame_Pipeline.cpp | 62 +- Core/plot/Plot_Frame_Pipeline.h | 55 +- Core/plot/Present_Frame.cpp | 28 - Core/plot/Present_Frame_Lease.cpp | 21 + ...{Present_Frame.h => Present_Frame_Lease.h} | 15 +- Core/plottable/Afterglow.cpp | 92 +-- Core/plottable/Afterglow.h | 26 +- Core/plottable/Afterglow_p.h | 86 +- ...nisphere.cpp => Constellation_Diagram.cpp} | 66 +- ...{Planisphere.h => Constellation_Diagram.h} | 32 +- ...nisphere_p.h => Constellation_Diagram_p.h} | 14 +- ...udio_Frequency.cpp => Frequency_Trace.cpp} | 30 +- .../{Audio_Frequency.h => Frequency_Trace.h} | 18 +- ...udio_Frequency_p.h => Frequency_Trace_p.h} | 6 +- Core/plottable/Hover_Info.h | 166 ---- .../{Hover_Info.cpp => Hover_Tooltip.cpp} | 20 +- Core/plottable/Hover_Tooltip.h | 166 ++++ Core/plottable/Interpolation.h | 13 +- Core/plottable/Interpolation_p.h | 40 +- Core/plottable/Multi_Select_Rect.cpp | 73 -- ...nce_Shower.cpp => Performance_Overlay.cpp} | 163 ++-- ...ormance_Shower.h => Performance_Overlay.h} | 20 +- ...nce_Shower_p.h => Performance_Overlay_p.h} | 301 ++++--- .../plottable/Selection_Rectangle_Overlay.cpp | 73 ++ ...t_Rect.h => Selection_Rectangle_Overlay.h} | 42 +- ...ct_p.h => Selection_Rectangle_Overlay_p.h} | 55 +- Core/plottable/Spectrum.cpp | 186 ++--- Core/plottable/Spectrum.h | 108 +-- Core/plottable/Spectrum_p.h | 17 +- Core/plottable/Sweep_Frequency.cpp | 122 --- Core/plottable/Sweep_Frequency_p.h | 103 --- Core/plottable/Sweep_Spectrum.cpp | 122 +++ .../{Sweep_Frequency.h => Sweep_Spectrum.h} | 40 +- Core/plottable/Sweep_Spectrum_p.h | 103 +++ Core/plottable/Waterfall.cpp | 24 +- Core/plottable/Waterfall.h | 18 +- Core/plottable/Waterfall_p.h | 20 +- Core/plottable/export.h | 39 +- Core/primitive/Curve.cpp | 73 +- Core/primitive/Curve.h | 32 +- Core/primitive/Curve_Utils_p.h | 91 +-- Core/primitive/Fill_Area.cpp | 4 +- Core/primitive/Fill_Area.h | 10 +- Core/primitive/Grid.cpp | 4 +- Core/primitive/Label.cpp | 10 +- Core/primitive/Label.h | 8 +- Core/primitive/Marker.cpp | 4 +- Core/primitive/Marker.h | 8 +- Core/primitive/Point_Set.cpp | 8 +- Core/primitive/Point_Set.h | 18 +- Core/primitive/Raster_Image.cpp | 4 +- Core/primitive/Raster_Image.h | 20 +- Core/render/Blend2D_Convert.cpp | 6 +- Core/render/Canvas.cpp | 4 +- Core/render/Image.cpp | 2 +- Core/render/Image.h | 2 +- Demo_Gallery/Afterglow_Plot.h | 51 -- Demo_Gallery/Audio_Plot.h | 50 -- Demo_Gallery/Demo_Gallery.cpp | 164 ---- Demo_Gallery/Demo_Gallery.h | 41 - Demo_Gallery/Normal_test.h | 296 ------- Demo_Gallery/Planisphere_Plot.h | 52 -- Demo_Gallery/Spectrum_Plot.h | 62 -- Demo_Gallery/Sweep_Frequent_Plot.h | 55 -- Demo_Gallery/Waterfall_Plot.h | 56 -- Demo_Gallery/base/Axis_Test.h | 38 - Demo_Gallery/base/Frequency_Axis.h | 36 - Demo_Gallery/base/Frequency_Axis_Test.h | 36 - Demo_Gallery/base/Multi_Select_Test.h | 43 - Demo_Gallery/base/Time_Axis_Test.h | 35 - Demo_Gallery/base/Tool.h | 761 ------------------ Demo_Gallery/base/export.h | 2 - Demo_Gallery/demo_gallery_main.cpp | 203 ----- Demo_Gallery/export.h | 14 - Qt/plot/Latency_Eager_Plot.cpp | 12 +- Qt/plot/Latency_Eager_Plot.h | 4 +- Qt/plot/Plot.cpp | 20 +- Qt/plot/Plot.h | 10 +- export.h | 2 +- main.cmake | 6 +- test/Renderive_Core_Tests.cpp | 112 +-- 109 files changed, 1699 insertions(+), 3979 deletions(-) delete mode 100644 Core/plot/Present_Frame.cpp create mode 100644 Core/plot/Present_Frame_Lease.cpp rename Core/plot/{Present_Frame.h => Present_Frame_Lease.h} (70%) rename Core/plottable/{Planisphere.cpp => Constellation_Diagram.cpp} (60%) rename Core/plottable/{Planisphere.h => Constellation_Diagram.h} (75%) rename Core/plottable/{Planisphere_p.h => Constellation_Diagram_p.h} (93%) rename Core/plottable/{Audio_Frequency.cpp => Frequency_Trace.cpp} (67%) rename Core/plottable/{Audio_Frequency.h => Frequency_Trace.h} (78%) rename Core/plottable/{Audio_Frequency_p.h => Frequency_Trace_p.h} (94%) delete mode 100644 Core/plottable/Hover_Info.h rename Core/plottable/{Hover_Info.cpp => Hover_Tooltip.cpp} (68%) create mode 100644 Core/plottable/Hover_Tooltip.h delete mode 100644 Core/plottable/Multi_Select_Rect.cpp rename Core/plottable/{Performance_Shower.cpp => Performance_Overlay.cpp} (77%) rename Core/plottable/{Performance_Shower.h => Performance_Overlay.h} (74%) rename Core/plottable/{Performance_Shower_p.h => Performance_Overlay_p.h} (86%) create mode 100644 Core/plottable/Selection_Rectangle_Overlay.cpp rename Core/plottable/{Multi_Select_Rect.h => Selection_Rectangle_Overlay.h} (61%) rename Core/plottable/{Multi_Select_Rect_p.h => Selection_Rectangle_Overlay_p.h} (81%) delete mode 100644 Core/plottable/Sweep_Frequency.cpp delete mode 100644 Core/plottable/Sweep_Frequency_p.h create mode 100644 Core/plottable/Sweep_Spectrum.cpp rename Core/plottable/{Sweep_Frequency.h => Sweep_Spectrum.h} (75%) create mode 100644 Core/plottable/Sweep_Spectrum_p.h delete mode 100644 Demo_Gallery/Afterglow_Plot.h delete mode 100644 Demo_Gallery/Audio_Plot.h delete mode 100644 Demo_Gallery/Demo_Gallery.cpp delete mode 100644 Demo_Gallery/Demo_Gallery.h delete mode 100644 Demo_Gallery/Normal_test.h delete mode 100644 Demo_Gallery/Planisphere_Plot.h delete mode 100644 Demo_Gallery/Spectrum_Plot.h delete mode 100644 Demo_Gallery/Sweep_Frequent_Plot.h delete mode 100644 Demo_Gallery/Waterfall_Plot.h delete mode 100644 Demo_Gallery/base/Axis_Test.h delete mode 100644 Demo_Gallery/base/Frequency_Axis.h delete mode 100644 Demo_Gallery/base/Frequency_Axis_Test.h delete mode 100644 Demo_Gallery/base/Multi_Select_Test.h delete mode 100644 Demo_Gallery/base/Time_Axis_Test.h delete mode 100644 Demo_Gallery/base/Tool.h delete mode 100644 Demo_Gallery/base/export.h delete mode 100644 Demo_Gallery/demo_gallery_main.cpp delete mode 100644 Demo_Gallery/export.h diff --git a/Core/Axis/Abs_Axis.cpp b/Core/Axis/Abs_Axis.cpp index 2f575af..9683ed5 100644 --- a/Core/Axis/Abs_Axis.cpp +++ b/Core/Axis/Abs_Axis.cpp @@ -6,11 +6,11 @@ RENDERIVE_DEFINE_RENDERABLE_BINDING(Abs_Axis, Abs_Axis_Private, Abs_Axis_Render_ RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, int, x) RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, int, y) RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, Orientation, orientation) -size_t Abs_Axis::pixel_size() { - return d()->edit_state_value(&Abs_Axis_Render_State::pixel_size); +size_t Abs_Axis::pixel_length() { + return d()->edit_state_value(&Abs_Axis_Render_State::pixel_length); } -void Abs_Axis::set_pixel_size(size_t value) { - d()->set_state_value(&Abs_Axis_Render_State::pixel_size, std::max(1, value)); +void Abs_Axis::set_pixel_length(size_t value) { + d()->set_state_value(&Abs_Axis_Render_State::pixel_length, std::max(1, value)); } RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, int, tick_length) RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, int, sub_tick_length) @@ -20,7 +20,7 @@ RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, std::string, unit_t RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, Font, unit_text_font) RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, Pen, unit_text_pen) RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, Brush, unit_text_background_brush) -RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, int, rotate) +RENDERIVE_DEFINE_STATE_PROP(Abs_Axis, Abs_Axis_Render_State, int, label_rotation_degrees) double Abs_Axis::pixel_to_coord(double pixel) { return d()->edit_pixel_to_coord(pixel); } @@ -43,11 +43,11 @@ std::vector Abs_Axis_Private::create_tick_vector(double tick_step, const } return result; } -std::vector Abs_Axis_Private::create_label_vector(const std::vector& ticks, SRC src) { +std::vector Abs_Axis_Private::create_label_vector(const std::vector& ticks, State_Role State_Role) { std::vector result; result.reserve(ticks.size()); for (double tick_coord : ticks) - result.push_back(get_tick_label(tick_coord, src)); + result.push_back(get_tick_label(tick_coord, State_Role)); return result; } std::vector Abs_Axis_Private::create_sub_tick_vector(int sub_tick_count, const std::vector& ticks, const Range& range) { @@ -164,9 +164,9 @@ double Abs_Axis_Private::pick_closest(double target, const std::vector& else return target - *(it - 1) < *it - target ? *(it - 1) : *it; } -std::string Abs_Axis_Private::get_tick_label(double tick, SRC src) { - auto render_state = reinterpret_cast(state(src)); - return format_number(tick, Number_Format{.precision = render_state->number_precision}); +std::string Abs_Axis_Private::get_tick_label(double tick, State_Role State_Role) { + auto render_state = reinterpret_cast(state(State_Role)); + return format_number(tick, Number_Format{.precision = render_state->label_precision}); } double Abs_Axis::start_coord() { return d()->edit_axis_state()->coord_start; @@ -179,24 +179,24 @@ Range Abs_Axis::coord_range() { auto render_state = d()->edit_axis_state(); return {render_state->coord_start, render_state->coord_start + render_state->coord_length}; } -int Abs_Axis::get_pixel_point_size(Range range) { +int Abs_Axis::pixel_sample_count(Range range) { auto render_state = d()->edit_axis_state(); double length = coord_range().length(); if (length == 0.0) return 0; - return static_cast(std::abs(range.length() / length) * render_state->pixel_size); + return static_cast(std::abs(range.length() / length) * render_state->pixel_length); } -int Abs_Axis::get_pixel_point_size() { +int Abs_Axis::pixel_sample_count() { auto render_state = d()->edit_axis_state(); - return static_cast(render_state->pixel_size); + return static_cast(render_state->pixel_length); } -double Abs_Axis::get_tick_step(const Range& range) { +double Abs_Axis::tick_step(const Range& range) { return d()->get_tick_step(range); } -int Abs_Axis::get_sub_tick_count(double tick_step) { +int Abs_Axis::sub_tick_count(double tick_step) { return d()->get_sub_tick_count(tick_step); } -std::string Abs_Axis::get_tick_label(double tick) { +std::string Abs_Axis::tick_label(double tick) { return d()->edit_tick_label(tick); } std::vector Abs_Axis::create_label_vector(const std::vector& ticks) { diff --git a/Core/Axis/Abs_Axis.h b/Core/Axis/Abs_Axis.h index 5e78f54..ad7f52a 100644 --- a/Core/Axis/Abs_Axis.h +++ b/Core/Axis/Abs_Axis.h @@ -22,7 +22,7 @@ struct Abs_Axis_Prop { Font unit_text_font; Pen unit_text_pen = Pen{.color = Color::white()}; Brush unit_text_background_brush = Brush{.color = Color::black()}; - int rotate = 0; + int label_rotation_degrees = 0; }; struct Abs_Axis_Private; class LIB_DECL Abs_Axis : public Renderable { @@ -34,7 +34,7 @@ public: PROP(int, x) PROP(int, y) PROP(Orientation, orientation) - PROP(size_t, pixel_size) + PROP(size_t, pixel_length) PROP(int, tick_length) PROP(int, sub_tick_length) PROP(Color, color) @@ -43,23 +43,22 @@ public: PROP(Font, unit_text_font) PROP(Pen, unit_text_pen) PROP(Brush, unit_text_background_brush) - PROP(int, rotate) + PROP(int, label_rotation_degrees) [[nodiscard]] virtual double pixel_to_coord(double pixel); [[nodiscard]] virtual double coord_to_pixel(double coord); - [[nodiscard]] virtual double get_tick_step(const Range& range); - [[nodiscard]] virtual int get_sub_tick_count(double tick_step); - virtual std::string get_tick_label(double tick); + [[nodiscard]] virtual double tick_step(const Range& range); + [[nodiscard]] virtual int sub_tick_count(double tick_step); + virtual std::string tick_label(double tick); virtual std::vector create_tick_vector(double tick_step, const Range& range); virtual std::vector create_sub_tick_vector(int sub_tick_count, const std::vector& ticks, const Range& range); virtual std::vector create_label_vector(const std::vector& ticks); double start_coord(); double end_coord(); Range coord_range(); - int get_pixel_point_size(Range range); - int get_pixel_point_size(); + int pixel_sample_count(Range range); + int pixel_sample_count(); template struct Builder_T; - private: friend struct Axis_Render_Access; Abs_Axis_Private* d(); @@ -69,7 +68,7 @@ struct Abs_Axis::Builder_T : protected Abs_Axis_Prop { PROP_BT(int, x) PROP_BT(int, y) PROP_BT(Orientation, orientation) - PROP_BT(size_t, pixel_size) + PROP_BT(size_t, pixel_length) PROP_BT(int, tick_length) PROP_BT(int, sub_tick_length) PROP_BT(Color, color) @@ -78,7 +77,7 @@ struct Abs_Axis::Builder_T : protected Abs_Axis_Prop { PROP_BT(Font, unit_text_font) PROP_BT(Pen, unit_text_pen) PROP_BT(Brush, unit_text_background_brush) - PROP_BT(int, rotate) + PROP_BT(int, label_rotation_degrees) std::shared_ptr parent{}; size_t pixel_size{}; void set(Abs_Axis* ret); diff --git a/Core/Axis/Abs_Axis_p.h b/Core/Axis/Abs_Axis_p.h index 4358da3..4f18fc1 100644 --- a/Core/Axis/Abs_Axis_p.h +++ b/Core/Axis/Abs_Axis_p.h @@ -8,8 +8,8 @@ #include "blend2d/blend2d.h" namespace renderive { struct Abs_Axis_Render_State : Render_State, Abs_Axis_Prop { - size_t pixel_size{}; - int number_precision = 2; + size_t pixel_length{}; + int label_precision = 2; void scale_range(double factor, double center) { coord_start = (coord_start - center) * factor + center; coord_length *= factor; @@ -19,7 +19,7 @@ struct Abs_Axis_Input_Data : Input_Data {}; struct Abs_Axis_Private : Typed_Render_Data { int tick_count = 2; [[nodiscard]] Abs_Axis_Render_State* edit_axis_state() { - return state_data(SRC::Edit); + return state_data(State_Role::State_Edit); } [[nodiscard]] Abs_Axis_Render_State* render_axis_state() { return render_state(); @@ -47,47 +47,47 @@ struct Abs_Axis_Private : Typed_Render_Data labels = create_label_vector(ticks, SRC::Render); + std::vector labels = create_label_vector(ticks, State_Render); Text_Metrics tm = canvas.measure_text(!s->unit_text_font.valid() ? "0" : " "); double h = tm.line_height(); canvas.set_pen(Pen{.color = s->color}); if (s->orientation == Orientation::Horizontal) { - canvas.draw_line({(double)s->x, (double)s->y}, {(double)(s->x + s->pixel_size), (double)s->y}); + canvas.draw_line({(double)s->x, (double)s->y}, {(double)(s->x + s->pixel_length), (double)s->y}); int n = (int)ticks.size(); for (int i = 0; i < n; ++i) { double tick = ticks[i]; - double x = coord_to_pixel(tick, SRC::Render); + double x = coord_to_pixel(tick, State_Render); canvas.draw_line({x, (double)s->y}, {x, (double)(s->y + s->tick_length)}); const std::string& label = labels[i]; PointF start{x, (double)(s->y + s->tick_length)}; canvas.save(); canvas.translate(start.x, start.y); - canvas.rotate((double)s->rotate * 3.14159265358979 / 180.0); + canvas.rotate((double)s->label_rotation_degrees * 3.14159265358979 / 180.0); canvas.draw_text({0.0, 0.0}, label); canvas.restore(); } for (double tick : sub_ticks) { - double x = coord_to_pixel(tick, SRC::Render); + double x = coord_to_pixel(tick, State_Render); canvas.draw_line({x, (double)s->y}, {x, (double)(s->y + s->sub_tick_length)}); } } else if (s->orientation == Orientation::Vertical) { - canvas.draw_line({(double)s->x, (double)s->y}, {(double)s->x, (double)(s->y + s->pixel_size)}); + canvas.draw_line({(double)s->x, (double)s->y}, {(double)s->x, (double)(s->y + s->pixel_length)}); int n = (int)ticks.size(); for (int i = 0; i < n; ++i) { double tick = ticks[i]; - double y = coord_to_pixel(tick, SRC::Render); + double y = coord_to_pixel(tick, State_Render); const std::string& label = labels[i]; canvas.draw_line({(double)s->x, y}, {(double)(s->x + s->tick_length), y}); PointF start{(double)(s->x + s->tick_length * 2), y + h / 2.0}; canvas.save(); canvas.translate(start.x, start.y); - canvas.rotate((double)s->rotate * 3.14159265358979 / 180.0); + canvas.rotate((double)s->label_rotation_degrees * 3.14159265358979 / 180.0); canvas.draw_text({0.0, 0.0}, label); canvas.restore(); } for (double tick : sub_ticks) { - double y = coord_to_pixel(tick, SRC::Render); + double y = coord_to_pixel(tick, State_Render); canvas.draw_line({(double)s->x, y}, {(double)(s->x + s->sub_tick_length), y}); } } @@ -96,7 +96,7 @@ struct Abs_Axis_Private : Typed_Render_Dataunit_text_font, s->unit_text); double w = um.width; if (s->orientation == Orientation::Horizontal) { - double x = pixel_start + (double)s->pixel_size - w; + double x = pixel_start + (double)s->pixel_length - w; double y = (double)s->y - h; RectF area(x, y, w, h); canvas.set_brush(s->unit_text_background_brush); @@ -116,13 +116,13 @@ struct Abs_Axis_Private : Typed_Render_Dataunit_text); } } - [[nodiscard]] virtual double pixel_to_coord(double pixel, SRC src) { - auto s = static_cast(state(src)); - return s->coord_start + s->coord_length * (pixel - (double)pixel_start_of(s)) / (double)s->pixel_size; + [[nodiscard]] virtual double pixel_to_coord(double pixel, State_Role State_Role) { + auto s = static_cast(state(State_Role)); + return s->coord_start + s->coord_length * (pixel - (double)pixel_start_of(s)) / (double)s->pixel_length; } - [[nodiscard]] virtual double coord_to_pixel(double coord, SRC src) { - auto s = static_cast(state(src)); - return pixel_start_of(s) + (double)s->pixel_size * (coord - s->coord_start) / s->coord_length; + [[nodiscard]] virtual double coord_to_pixel(double coord, State_Role State_Role) { + auto s = static_cast(state(State_Role)); + return pixel_start_of(s) + (double)s->pixel_length * (coord - s->coord_start) / s->coord_length; } virtual double get_tick_step(const Range& range) { double exact_step = range.size() / double(tick_count + 1e-10); @@ -131,19 +131,19 @@ struct Abs_Axis_Private : Typed_Render_Data create_tick_vector(double tick_step, const Range& range); virtual std::vector create_sub_tick_vector(int sub_tick_count, const std::vector& ticks, const Range& range); - virtual std::string get_tick_label(double tick, SRC); - virtual std::vector create_label_vector(const std::vector& ticks, SRC); + virtual std::string get_tick_label(double tick, State_Role); + virtual std::vector create_label_vector(const std::vector& ticks, State_Role); [[nodiscard]] double edit_pixel_to_coord(double pixel) { - return pixel_to_coord(pixel, SRC::Edit); + return pixel_to_coord(pixel, State_Role::State_Edit); } [[nodiscard]] double render_pixel_to_coord(double pixel) { - return pixel_to_coord(pixel, SRC::Render); + return pixel_to_coord(pixel, State_Render); } [[nodiscard]] double edit_coord_to_pixel(double coord) { - return coord_to_pixel(coord, SRC::Edit); + return coord_to_pixel(coord, State_Role::State_Edit); } [[nodiscard]] double render_coord_to_pixel(double coord) { - return coord_to_pixel(coord, SRC::Render); + return coord_to_pixel(coord, State_Render); } [[nodiscard]] Range edit_coord_range() { const auto* s = edit_axis_state(); @@ -154,47 +154,42 @@ struct Abs_Axis_Private : Typed_Render_Datacoord_start, s->coord_start + s->coord_length}; } [[nodiscard]] int render_pixel_size() { - return std::abs(static_cast(render_axis_state()->pixel_size)); + return std::abs(static_cast(render_axis_state()->pixel_length)); } [[nodiscard]] std::string edit_tick_label(double tick) { - return get_tick_label(tick, SRC::Edit); + return get_tick_label(tick, State_Role::State_Edit); } [[nodiscard]] std::string render_tick_label(double tick) { - return get_tick_label(tick, SRC::Render); + return get_tick_label(tick, State_Render); } [[nodiscard]] std::vector edit_label_vector(const std::vector& ticks) { - return create_label_vector(ticks, SRC::Edit); + return create_label_vector(ticks, State_Role::State_Edit); } [[nodiscard]] std::vector render_label_vector(const std::vector& ticks) { - return create_label_vector(ticks, SRC::Render); + return create_label_vector(ticks, State_Render); } }; struct Axis_Frame_Snapshot { Orientation orientation = Orientation::Horizontal; Range coord_range{0.0, 1.0}; Range pixel_range{0.0, 1.0}; - [[nodiscard]] double coord_to_pixel(double coord) const { if (coord_range.length() == 0.0) return pixel_range.origin; return pixel_range.origin + pixel_range.length() * (coord - coord_range.origin) / coord_range.length(); } - [[nodiscard]] double pixel_to_coord(double pixel) const { if (pixel_range.length() == 0.0) return coord_range.origin; return coord_range.origin + coord_range.length() * (pixel - pixel_range.origin) / pixel_range.length(); } - [[nodiscard]] int pixel_size() const { return static_cast(std::max(1.0, pixel_range.size())); } }; - struct Axis_Mapping_2D { Axis_Frame_Snapshot domain; Axis_Frame_Snapshot value; - [[nodiscard]] PointF map(double domain_coord, double value_coord) const { PointF ret{}; double domain_pixel = domain.coord_to_pixel(domain_coord); @@ -209,25 +204,20 @@ struct Axis_Mapping_2D { } return ret; } - [[nodiscard]] PointF map(PointF data_point) const { return map(data_point.x, data_point.y); } - [[nodiscard]] double domain_pixel(PointF screen_point) const { return domain.orientation == Orientation::Horizontal ? screen_point.x : screen_point.y; } - [[nodiscard]] double value_pixel(PointF screen_point) const { return value.orientation == Orientation::Horizontal ? screen_point.x : screen_point.y; } }; - struct Axis_Basis_2D { PointF origin{}; PointF domain_vector{}; PointF value_vector{}; - [[nodiscard]] static Axis_Basis_2D from_ranges(const Axis_Mapping_2D& mapping, const Range& domain_range, const Range& value_range) { PointF origin = mapping.map(domain_range.origin, value_range.origin); PointF domain_target = mapping.map(domain_range.target, value_range.origin); @@ -235,10 +225,10 @@ struct Axis_Basis_2D { return Axis_Basis_2D{ origin, PointF{domain_target.x - origin.x, domain_target.y - origin.y}, - PointF{value_target.x - origin.x, value_target.y - origin.y}}; + PointF{value_target.x - origin.x, value_target.y - origin.y} + }; } }; - struct Axis_Render_Access final { static Axis_Frame_Snapshot snapshot(Abs_Axis* axis) { const auto* s = axis->d()->render_axis_state(); @@ -246,7 +236,8 @@ struct Axis_Render_Access final { return Axis_Frame_Snapshot{ s->orientation, Range{s->coord_start, s->coord_start + s->coord_length}, - Range{pixel_start, pixel_start + static_cast(s->pixel_size)}}; + Range{pixel_start, pixel_start + static_cast(s->pixel_length)} + }; } static Axis_Mapping_2D mapping(Abs_Axis* domain_axis, Abs_Axis* value_axis) { return Axis_Mapping_2D{snapshot(domain_axis), snapshot(value_axis)}; @@ -281,7 +272,7 @@ void Abs_Axis::Builder_T::set(Abs_Axis* ret) { sc->x = this->x; sc->y = this->y; sc->orientation = this->orientation; - sc->pixel_size = std::max(1, this->pixel_size); + sc->pixel_length = std::max(1, this->pixel_size); sc->tick_length = this->tick_length; sc->sub_tick_length = this->sub_tick_length; sc->color = this->color; @@ -290,6 +281,6 @@ void Abs_Axis::Builder_T::set(Abs_Axis* ret) { sc->unit_text_font = this->unit_text_font; sc->unit_text_pen = this->unit_text_pen; sc->unit_text_background_brush = this->unit_text_background_brush; - sc->rotate = this->rotate; + sc->label_rotation_degrees = this->label_rotation_degrees; } } // namespace renderive diff --git a/Core/Axis/Axis.cpp b/Core/Axis/Axis.cpp index 816c3f5..2a9155a 100644 --- a/Core/Axis/Axis.cpp +++ b/Core/Axis/Axis.cpp @@ -2,7 +2,7 @@ #include "../base/Memory.h" namespace renderive { RENDERIVE_DEFINE_RENDERABLE_BINDING(Axis, Axis_Private, Axis_Render_State, Axis_Input_Data, "Axis") -RENDERIVE_DEFINE_STATE_PROP(Axis, Axis_Render_State, int, number_precision) +RENDERIVE_DEFINE_STATE_PROP(Axis, Axis_Render_State, int, label_precision) RENDERIVE_DEFINE_STATE_PROP(Axis, Axis_Render_State, double, coord_start) double Axis::coord_length() { return d()->edit_state_value(&Axis_Render_State::coord_length); diff --git a/Core/Axis/Axis.h b/Core/Axis/Axis.h index 44adbbc..911c84a 100644 --- a/Core/Axis/Axis.h +++ b/Core/Axis/Axis.h @@ -13,7 +13,7 @@ public: Render_Object_Owner create_render_state() override; Render_Object_Owner create_input_data() override; Axis(); - PROP(int, number_precision) + PROP(int, label_precision) PROP(double, coord_start) PROP(double, coord_length) /// 设置轴坐标范围。 @@ -21,13 +21,12 @@ public: template struct Builder_T; struct Builder; - private: Axis_Private* d(); }; template struct Axis::Builder_T : Abs_Axis::Builder_T { - PROP_BT(int, number_precision) + PROP_BT(int, label_precision) // PROP_BT(double, coord_start) // PROP_BT(double, coord_length) That& set_coord_range(Range r) { @@ -49,15 +48,14 @@ struct Axis::Builder_T : Abs_Axis::Builder_T { return t; } void set(Axis* ret); - int number_precision = 2; + int label_precision = 2; bool use_wheel = false; bool use_drag = false; }; -struct LIB_DECL Axis::Builder : Builder_T{ +struct LIB_DECL Axis::Builder : Builder_T { /// 创建数值轴构造器。 Builder(std::shared_ptr parent, Orientation orientation); /// 构建并返回数值轴对象。 std::shared_ptr build(); - }; } // namespace renderive diff --git a/Core/Axis/Axis_p.h b/Core/Axis/Axis_p.h index 86676a5..aac561a 100644 --- a/Core/Axis/Axis_p.h +++ b/Core/Axis/Axis_p.h @@ -20,7 +20,7 @@ struct Axis_Private : Typed_Render_Data_Baseorientation == Orientation::Horizontal ? event.position.x : event.position.y; - double cursor_coord = pixel_to_coord(cursor_pixel, SRC::Edit); + double cursor_coord = pixel_to_coord(cursor_pixel, State_Edit); double new_coord_length = edit->coord_length * factor; double new_coord_start = cursor_coord - new_coord_length * (cursor_coord - edit->coord_start) / edit->coord_length; edit->coord_start = new_coord_start; @@ -43,7 +43,7 @@ struct Axis_Private : Typed_Render_Data_Base state(this); start_coord_value = state->coord_start; - pixel_pre_coord = state->coord_length / static_cast(state->pixel_size); + pixel_pre_coord = state->coord_length / static_cast(state->pixel_length); event.accept(); } void mouse_move_event(const Pointer_Event& event) override { @@ -75,7 +75,7 @@ void Axis::Builder_T::set(Axis* ret) { Abs_Axis::Builder_T::set(ret); Axis_Private* pd = ret->d(); Axis_Render_State* sc = reinterpret_cast(pd->state(State_Edit)); - PROP_RT(int, number_precision) + PROP_RT(int, label_precision) PROP_RT(double, coord_start) PROP_RT(double, coord_length) if (sc->coord_length == 0.0) diff --git a/Core/Axis/Frequency_Axis_p.h b/Core/Axis/Frequency_Axis_p.h index d61152e..7824664 100644 --- a/Core/Axis/Frequency_Axis_p.h +++ b/Core/Axis/Frequency_Axis_p.h @@ -9,7 +9,7 @@ namespace renderive { struct Frequency_Axis_Input_Data : Axis_Input_Data {}; struct Frequency_Axis_Render_State : Axis_Render_State {}; struct Frequency_Axis_Private : Typed_Render_Data_Base { - std::vector create_label_vector(const std::vector& ticks, SRC src) override { + std::vector create_label_vector(const std::vector& ticks, State_Role src) override { const int exponent = unit_exponent(ticks); if (!ticks.empty()) render_state()->unit_text = "Frequency/" + unit_text(exponent); @@ -46,7 +46,7 @@ struct Frequency_Axis_Private : Typed_Render_Data_Basenumber_precision; + int precision = s->label_precision; auto dot_pos = value.find('.'); if (dot_pos == std::string::npos) dot_pos = value.size(); diff --git a/Core/Axis/Time_Axis.cpp b/Core/Axis/Time_Axis.cpp index fbf4063..3e59e32 100644 --- a/Core/Axis/Time_Axis.cpp +++ b/Core/Axis/Time_Axis.cpp @@ -3,17 +3,17 @@ namespace renderive { RENDERIVE_DEFINE_RENDERABLE_BINDING(Time_Axis, Time_Axis_Private, Time_Axis_Render_State, Time_Axis_Input_Data, "time_axis") int Time_Axis::time_point_size() { - return d()->edit_state_value(&Time_Axis_Render_State::time_point_size); + return d()->edit_state_value(&Time_Axis_Render_State::visible_time_point_count); } void Time_Axis::set_time_point_size(int value) { value = std::max(1, value); - d()->set_state_value(&Time_Axis_Render_State::time_point_size, value); + d()->set_state_value(&Time_Axis_Render_State::visible_time_point_count, value); } -int Time_Axis::tick_pixel_space() { - return d()->edit_state_value(&Time_Axis_Render_State::tick_pixel_space); +int Time_Axis::tick_label_spacing_px() { + return d()->edit_state_value(&Time_Axis_Render_State::tick_label_spacing_px); } -void Time_Axis::set_tick_pixel_space(int value) { - d()->set_state_value(&Time_Axis_Render_State::tick_pixel_space, std::max(1, value)); +void Time_Axis::set_tick_label_spacing_px(int value) { + d()->set_state_value(&Time_Axis_Render_State::tick_label_spacing_px, std::max(1, value)); } RENDERIVE_DEFINE_STATE_PROP(Time_Axis, Time_Axis_Render_State, std::string, time_format) RENDERIVE_DEFINE_STATE_PROP(Time_Axis, Time_Axis_Render_State, Font, font) @@ -29,20 +29,20 @@ bool Time_Axis::start_coord_to_end_coord() { void Time_Axis::set_start_coord_to_end_coord(bool value) { d()->set_state_value(&Time_Axis_Render_State::start_coord_to_end_coord, value); } -int Time_Axis::give_data(Time_Of_Day time) { +int Time_Axis::append_time(Time_Of_Day time) { if (!ok()) return -1; auto stream = timeline_stream(); if (!stream) return -1; - int tick = stream->push_time(time); + int tick = stream->append_time(time); mark_render_dirty(); return tick; } Time_Of_Day Time_Axis::tick_to_time(int tick) { auto stream = timeline_stream(); if (stream) - return stream->capture(time_point_size(), d()->state_data(SRC::Edit)->get_tick_space_hint(), start_coord_to_end_coord()).time_by_tick(tick); + return stream->capture(time_point_size(), d()->state_data(State_Edit)->label_tick_interval_hint(), start_coord_to_end_coord()).time_by_tick(tick); return d()->time_by_tick(tick); } Time_Axis::Builder::Builder(std::shared_ptr parent, Orientation orientation) { @@ -55,14 +55,14 @@ std::shared_ptr Time_Axis::Builder::build() { set(ret.get()); Time_Axis_Private* pd = ret->d(); Time_Axis_Render_State* sc = reinterpret_cast(pd->state(State_Edit)); - PROP_R(int, time_point_size) - PROP_R(int, tick_pixel_space) + PROP_R(int, visible_time_point_count) + PROP_R(int, tick_label_spacing_px) PROP_R(std::string, time_format) PROP_R(Font, font) PROP_R(std::shared_ptr, timeline_stream) PROP_R(bool, start_coord_to_end_coord) - sc->time_point_size = std::max(1, sc->time_point_size); - sc->tick_pixel_space = std::max(1, sc->tick_pixel_space); + sc->visible_time_point_count = std::max(1, sc->visible_time_point_count); + sc->tick_label_spacing_px = std::max(1, sc->tick_label_spacing_px); if (!sc->timeline_stream) sc->timeline_stream = renderive::make_shared(); return ret; diff --git a/Core/Axis/Time_Axis.h b/Core/Axis/Time_Axis.h index b52f940..21036ab 100644 --- a/Core/Axis/Time_Axis.h +++ b/Core/Axis/Time_Axis.h @@ -16,34 +16,33 @@ public: Render_Object_Owner create_input_data() override; Time_Axis(); PROP(int, time_point_size) - PROP(int, tick_pixel_space) + PROP(int, tick_label_spacing_px) PROP(std::string, time_format) PROP(Font, font) PROP(std::shared_ptr, timeline_stream) PROP(bool, start_coord_to_end_coord) /// 推入一个新的时间点并返回对应 tick。 - int give_data(Time_Of_Day time); + int append_time(Time_Of_Day time); /// 将 tick 转换成时间。 Time_Of_Day tick_to_time(int tick); struct Builder; - private: friend struct Time_Axis_Render_Access; Time_Axis_Private* d(); }; struct Time_Axis_Prop { - int time_point_size = 100; - int tick_pixel_space = 8; + int visible_time_point_count = 100; + int tick_label_spacing_px = 8; std::string time_format = "mm:ss.zzz"; Font font; std::shared_ptr timeline_stream; bool start_coord_to_end_coord = false; }; struct LIB_DECL Time_Axis::Builder : Abs_Axis::Builder_T, -public -Time_Axis_Prop { - PROP_B(int, time_point_size) - PROP_B(int, tick_pixel_space) + public + Time_Axis_Prop { + PROP_B(int, visible_time_point_count) + PROP_B(int, tick_label_spacing_px) PROP_B(std::string, time_format) PROP_B(Font, font) PROP_B(std::shared_ptr, timeline_stream) diff --git a/Core/Axis/Time_Axis_p.h b/Core/Axis/Time_Axis_p.h index ae802c1..e0669fd 100644 --- a/Core/Axis/Time_Axis_p.h +++ b/Core/Axis/Time_Axis_p.h @@ -14,9 +14,9 @@ namespace renderive { struct Time_Axis_Input_Data : Abs_Axis_Input_Data {}; struct Time_Axis_Render_State : Abs_Axis_Render_State, Time_Axis_Prop { - int get_tick_space_hint() const { - double rate = (double)time_point_size / (double)pixel_size; - double ret = rate * (tick_pixel_space + (double)(orientation == Orientation::Horizontal ? 80 : 20)); + int label_tick_interval_hint() const { + double rate = (double)visible_time_point_count / (double)pixel_length; + double ret = rate * (tick_label_spacing_px + (double)(orientation == Orientation::Horizontal ? 80 : 20)); return std::max(1, (int)ret); } }; @@ -29,7 +29,7 @@ struct Time_Axis_Private : Typed_Render_Data_Base capture_timeline(const Plot_Render_Snapshot& snapshot, const Time_Axis_Render_State* state) const { if (!state || !state->timeline_stream) return {}; - return snapshot.timeline_snapshot(state->timeline_stream, state->time_point_size, state->get_tick_space_hint(), state->start_coord_to_end_coord); + return snapshot.timeline_snapshot(state->timeline_stream, state->visible_time_point_count, state->label_tick_interval_hint(), state->start_coord_to_end_coord); } std::shared_ptr capture_timeline(const Plot_Render_Snapshot& snapshot) { sync_state_pipeline(); @@ -43,14 +43,14 @@ struct Time_Axis_Private : Typed_Render_Data_Basecoord_start = timeline_snapshot->lower; + s->coord_start = timeline_snapshot->coordinate_begin; s->coord_length = timeline_snapshot->time_point_size; ticks.clear(); - for (const Timeline_Tick& tick : timeline_snapshot->ticks) { - ticks.push_back(tick.tick); + for (const Timeline_Label_Tick& tick : timeline_snapshot->ticks) { + ticks.push_back(tick.coordinate); } } - std::vector create_label_vector(const std::vector& ticks, SRC src) override { + std::vector create_label_vector(const std::vector& ticks, State_Role src) override { auto s = reinterpret_cast(state(src)); std::vector result; result.reserve(ticks.size()); @@ -67,7 +67,7 @@ struct Time_Axis_Private : Typed_Render_Data_Base(state(src)); return format_time(time_by_tick((int)tick), render_state->time_format); } diff --git a/Core/architecture/Buffer_Role.h b/Core/architecture/Buffer_Role.h index 1da520a..8b14fbe 100644 --- a/Core/architecture/Buffer_Role.h +++ b/Core/architecture/Buffer_Role.h @@ -1,10 +1,2 @@ #pragma once #include - -namespace renderive { -enum class SRC : std::uint8_t { - Edit, - Ready, - Render -}; -} // namespace renderive diff --git a/Core/architecture/Frame_Scheduler.cpp b/Core/architecture/Frame_Scheduler.cpp index 675d0dc..b459b12 100644 --- a/Core/architecture/Frame_Scheduler.cpp +++ b/Core/architecture/Frame_Scheduler.cpp @@ -60,7 +60,7 @@ void Frame_Lifecycle_Record::record_renderable_cache_miss(const std::string& obj void Frame_Lifecycle_Record::record_renderable_cache_rebuild(const std::string& object_name, const std::string& parent_object_name, int tree_depth, std::uint64_t rebuild_time_ns, std::uint64_t image_bytes, std::uint64_t image_area, std::uint64_t edit_version, std::uint64_t ready_version) { ++renderable_cache_rebuild_count; - Renderable_Cache_Frame_Stat& stat = cache_stat(object_name, parent_object_name, tree_depth); + Renderable_Cache_Frame_Stats& stat = cache_stat(object_name, parent_object_name, tree_depth); renderable_cache_rebuild_time_ns += rebuild_time_ns; renderable_cache_image_bytes += image_bytes; renderable_cache_image_area += image_area; @@ -75,7 +75,7 @@ void Frame_Lifecycle_Record::record_renderable_cache_rebuild(const std::string& void Frame_Lifecycle_Record::record_renderable_cache_compose(const std::string& object_name, const std::string& parent_object_name, int tree_depth, std::uint64_t compose_time_ns, std::uint64_t image_bytes, std::uint64_t image_area, std::uint64_t edit_version, std::uint64_t ready_version) { renderable_cache_compose_time_ns += compose_time_ns; - Renderable_Cache_Frame_Stat& stat = cache_stat(object_name, parent_object_name, tree_depth); + Renderable_Cache_Frame_Stats& stat = cache_stat(object_name, parent_object_name, tree_depth); stat.compose_time_ns += compose_time_ns; stat.last_compose_time_ns = compose_time_ns; stat.last_image_bytes = image_bytes; @@ -97,12 +97,12 @@ Renderable_Frame_Stat& Frame_Lifecycle_Record::renderable_stat(const std::string return renderable_stats.back(); } -Renderable_Cache_Frame_Stat& Frame_Lifecycle_Record::cache_stat(const std::string& object_name, const std::string& parent_object_name, int tree_depth) { +Renderable_Cache_Frame_Stats& Frame_Lifecycle_Record::cache_stat(const std::string& object_name, const std::string& parent_object_name, int tree_depth) { for (auto& stat : renderable_cache_stats) { if (stat.object_name == object_name && stat.parent_object_name == parent_object_name && stat.tree_depth == tree_depth) return stat; } - Renderable_Cache_Frame_Stat stat; + Renderable_Cache_Frame_Stats stat; stat.object_name = object_name; stat.parent_object_name = parent_object_name; stat.tree_depth = tree_depth; diff --git a/Core/architecture/Frame_Scheduler.h b/Core/architecture/Frame_Scheduler.h index 955332a..4dca874 100644 --- a/Core/architecture/Frame_Scheduler.h +++ b/Core/architecture/Frame_Scheduler.h @@ -3,19 +3,15 @@ #include #include #include - namespace renderive { - struct Smoothed_Interval { double srtt_ms{}; double jitter_ms{}; std::uint64_t sample_count{}; - void update(double sample_ms); [[nodiscard]] double safe_ms(double jitter_factor = 2.0) const; [[nodiscard]] bool valid() const; }; - struct Refresh_Control_Snapshot { Refresh_Limit_Source source = Refresh_Limit_Source::Unknown; std::uint64_t render_period_ns{}; @@ -23,8 +19,7 @@ struct Refresh_Control_Snapshot { std::uint64_t user_period_ns{}; std::uint64_t target_period_ns{}; }; - -struct Renderable_Cache_Frame_Stat { +struct Renderable_Cache_Frame_Stats { std::string object_name; std::string parent_object_name; int tree_depth{}; @@ -40,7 +35,6 @@ struct Renderable_Cache_Frame_Stat { std::uint64_t last_edit_version{}; std::uint64_t last_ready_version{}; }; - struct Renderable_Frame_Stat { std::string object_name; std::string parent_object_name; @@ -53,7 +47,6 @@ struct Renderable_Frame_Stat { std::uint64_t last_total_render_time_ns{}; std::uint64_t last_self_draw_time_ns{}; }; - struct Frame_Lifecycle_Record { std::uint64_t frame_id{}; std::uint64_t input_version{}; @@ -80,7 +73,7 @@ struct Frame_Lifecycle_Record { std::uint64_t superseded_time_ns{}; Frame_Outcome outcome = Frame_Outcome::Render_Acquire_Dropped; Refresh_Control_Snapshot refresh; - Frame_Worker_Stat worker; + Frame_Worker_Stats worker; std::uint64_t raw_input_count{}; std::uint64_t prepared_output_count{}; std::uint64_t renderable_cache_hit_count{}; @@ -94,21 +87,18 @@ struct Frame_Lifecycle_Record { std::uint64_t pixel_height{}; std::uint64_t viewport_version{}; std::vector renderable_stats; - std::vector renderable_cache_stats; - + std::vector renderable_cache_stats; void record_renderable_render(const std::string& object_name, const std::string& parent_object_name, int tree_depth, Renderable_Cache_Mode cache_mode, std::uint64_t render_time_ns); void record_renderable_self_draw(const std::string& object_name, const std::string& parent_object_name, int tree_depth, Renderable_Cache_Mode cache_mode, std::uint64_t draw_time_ns); void record_renderable_cache_hit(const std::string& object_name, const std::string& parent_object_name, int tree_depth); void record_renderable_cache_miss(const std::string& object_name, const std::string& parent_object_name, int tree_depth); void record_renderable_cache_rebuild(const std::string& object_name, const std::string& parent_object_name, int tree_depth, std::uint64_t rebuild_time_ns, std::uint64_t image_bytes, std::uint64_t image_area, std::uint64_t edit_version, std::uint64_t ready_version); void record_renderable_cache_compose(const std::string& object_name, const std::string& parent_object_name, int tree_depth, std::uint64_t compose_time_ns, std::uint64_t image_bytes, std::uint64_t image_area, std::uint64_t edit_version, std::uint64_t ready_version); - private: Renderable_Frame_Stat& renderable_stat(const std::string& object_name, const std::string& parent_object_name, int tree_depth); - Renderable_Cache_Frame_Stat& cache_stat(const std::string& object_name, const std::string& parent_object_name, int tree_depth); + Renderable_Cache_Frame_Stats& cache_stat(const std::string& object_name, const std::string& parent_object_name, int tree_depth); }; - -inline std::uint64_t renderable_cache_subtree_compose_time(const std::vector& stats, const Renderable_Cache_Frame_Stat& node) { +inline std::uint64_t renderable_cache_subtree_compose_time(const std::vector& stats, const Renderable_Cache_Frame_Stats& node) { std::uint64_t compose_time_ns = node.compose_time_ns; for (const auto& stat : stats) { if (stat.parent_object_name == node.object_name && stat.tree_depth == node.tree_depth + 1) @@ -116,13 +106,11 @@ inline std::uint64_t renderable_cache_subtree_compose_time(const std::vector namespace renderive { using Plot_Execution_Id = std::uint64_t; - enum class Render_Task_Kind : std::uint8_t { Frame, Curve, @@ -12,35 +11,32 @@ enum class Render_Task_Kind : std::uint8_t { Compose, Performance }; - struct Render_Runtime_Config { std::size_t worker_count{}; }; - struct Render_Executor_Snapshot { std::size_t worker_count{}; std::size_t active_workers{}; std::size_t idle_workers{}; std::size_t active_frame_jobs{}; std::size_t queued_frame_jobs{}; - std::uint64_t submitted_tasks{}; - std::uint64_t started_tasks{}; - std::uint64_t completed_tasks{}; + std::uint64_t submitted_jobs{}; + std::uint64_t started_task_nodes{}; + std::uint64_t completed_task_nodes{}; std::uint64_t rejected_frame_jobs{}; std::uint64_t dropped_frame_attempts{}; std::uint64_t peak_concurrency{}; std::uint64_t average_queue_wait_ns{}; - std::uint64_t p95_queue_wait_ns{}; + std::uint64_t max_queue_wait_ns{}; std::uint64_t average_task_duration_ns{}; - std::uint64_t p95_task_duration_ns{}; + std::uint64_t max_task_duration_ns{}; std::uint64_t curve_tasks{}; std::uint64_t waterfall_tasks{}; std::uint64_t primitive_tasks{}; std::uint64_t compose_tasks{}; std::uint64_t performance_tasks{}; }; - -struct Frame_Worker_Stat { +struct Frame_Worker_Stats { Render_Executor_Snapshot executor_at_submit; Render_Executor_Snapshot executor_at_finish; std::uint32_t task_count{}; @@ -51,20 +47,17 @@ struct Frame_Worker_Stat { std::uint64_t parallel_stage_wall_ns{}; std::uint64_t rejected_task_count{}; }; - enum class Refresh_Limit_Source : std::uint8_t { Unknown, Render, Paint, User }; - enum Frame_Role : std::uint8_t { Frame_Rendering, Frame_Middle, Frame_Painting }; - enum class Frame_Outcome : std::uint8_t { Presented, Superseded, diff --git a/Core/architecture/Render_Data.h b/Core/architecture/Render_Data.h index e135942..dcea40b 100644 --- a/Core/architecture/Render_Data.h +++ b/Core/architecture/Render_Data.h @@ -19,17 +19,13 @@ #include #include #include - namespace renderive { - struct Render_Data; struct Renderable; - struct Input_Data { virtual ~Input_Data() = default; virtual void clear() {} }; - struct Latest_Input_Data : Input_Data { bool pending = false; void mark_latest_pushed() { @@ -39,44 +35,36 @@ struct Latest_Input_Data : Input_Data { pending = false; } }; - struct Render_State { virtual ~Render_State() = default; std::uint64_t version = 0; }; - struct Hit_Testable { virtual ~Hit_Testable() = default; virtual bool select_test(const PointF& pos) = 0; }; - struct Pointer_Interactive { virtual ~Pointer_Interactive() = default; virtual void mouse_press_event(const Pointer_Event& event) = 0; virtual void mouse_move_event(const Pointer_Event& event) = 0; virtual void mouse_release_event(const Pointer_Event& event) = 0; }; - struct Wheel_Interactive { virtual ~Wheel_Interactive() = default; virtual void wheel_event(const Wheel_Event& event) = 0; }; - struct Key_Press_Interactive { virtual ~Key_Press_Interactive() = default; virtual void key_press_event(const Key_Event& event) = 0; }; - struct Key_Release_Interactive { virtual ~Key_Release_Interactive() = default; virtual void key_release_event(const Key_Event& event) = 0; }; - struct Hover_Interactive { virtual ~Hover_Interactive() = default; virtual void set_hover_state(Point pos, bool active) = 0; }; - struct Render_Object_Owner : Move_Only { Render_Object_Owner() noexcept = default; Render_Object_Owner(void* pointer, std::pmr::memory_resource* resource, void (*destroy)(void*, std::pmr::memory_resource*)) noexcept : pointer(pointer), resource(resource), destroy(destroy) {} @@ -112,7 +100,6 @@ struct Render_Object_Owner : Move_Only { std::pmr::memory_resource* resource{}; void (*destroy)(void*, std::pmr::memory_resource*){}; }; - template Render_Object_Owner make_render_object(Args&&... args) { std::pmr::memory_resource* resource = memory_resource(Memory_Domain::Renderable); @@ -131,14 +118,12 @@ Render_Object_Owner make_render_object(Args&&... args) { allocator.deallocate(static_cast(object), 1); }); } - struct Input_Buffer_Slot { Input_Data* data{}; std::uint64_t version = 0; bool pending = false; std::shared_ptr completion_state; }; - struct Render_Data { Renderable* q_ptr{}; Triple_Role_Buffer_Control state_control; @@ -149,11 +134,10 @@ struct Render_Data { std::array input_buffer_owners{}; std::pmr::vector> committed_update_states{memory_resource(Memory_Domain::Update_Completion)}; std::uint64_t input_version = 0; - Render_State* state(std::uint8_t role) const { return state_by_index(state_control.read_view()[role]); } - Render_State* state(SRC src) const { + Render_State* state(State_Role src) const { return state(static_cast(src)); } Render_State* state_by_index(std::uint8_t index) const { @@ -213,7 +197,6 @@ struct Render_Data { input_control.reset(); } void cancel_pending_completions(); - public: virtual void sync_state_pipeline() = 0; virtual Render_State* render_state() = 0; @@ -225,7 +208,6 @@ public: clear_state_buffers(); clear_input_buffers(); } - virtual void draw(Canvas& canvas, const Plot_Render_Snapshot& snapshot) {} virtual void prepare_data(const Plot_Render_Snapshot& snapshot) { sync_state_pipeline(); @@ -234,7 +216,6 @@ public: return {0, 0, plot_size.width, plot_size.height}; } }; - struct Base_Render_Data : Render_Data { Render_State* render_state() override { return nullptr; @@ -253,7 +234,6 @@ struct Base_Render_Data : Render_Data { } void sync_state_pipeline() override {} }; - class Plot_Core; struct LIB_DECL Render_Edit_Guard { Render_Edit_Guard(Render_Data* data, Triple_Buffer_Lease lease); @@ -261,5 +241,4 @@ struct LIB_DECL Render_Edit_Guard { Render_Data* data{}; Triple_Buffer_Lease lease{}; }; - } // namespace renderive diff --git a/Core/architecture/Render_Lease.h b/Core/architecture/Render_Lease.h index 08c8bf6..9219484 100644 --- a/Core/architecture/Render_Lease.h +++ b/Core/architecture/Render_Lease.h @@ -23,7 +23,7 @@ struct Typed_Render_Data_Base : Base { Input* edit_input_data() override { return reinterpret_cast(this->input_data(Input_Edit)); } - State* state_data(SRC src) { + State* state_data(State_Role src) { return reinterpret_cast(this->state(src)); } State* state_data_by_index(std::uint8_t index) { @@ -34,23 +34,23 @@ struct Typed_Render_Data_Base : Base { } template requires std::derived_from - Field state_value(Field Source_State::* field, SRC src) { + Field state_value(Field Source_State::* field, State_Role src) { return state_data(src)->*field; } template requires std::derived_from Field edit_state_value(Field Source_State::* field) { - return state_value(field, SRC::Edit); + return state_value(field, State_Edit); } template requires std::derived_from Field ready_state_value(Field Source_State::* field) { - return state_value(field, SRC::Ready); + return state_value(field, State_Ready); } template requires std::derived_from Field render_state_value(Field Source_State::* field) { - return state_value(field, SRC::Render); + return state_value(field, State_Render); } template requires std::derived_from diff --git a/Core/architecture/Render_Utils.cpp b/Core/architecture/Render_Utils.cpp index 15f08f6..7d7f3bb 100644 --- a/Core/architecture/Render_Utils.cpp +++ b/Core/architecture/Render_Utils.cpp @@ -7,7 +7,7 @@ std::vector get_turbo_color_gradient() { std::vector colors; colors.reserve(Turbo_Color_Map.size()); for (const auto& c : Turbo_Color_Map) - colors.push_back(pack_rgba(c.red, c.green, c.blue, c.alpha)); + colors.push_back(pack_rgba(c.r, c.g, c.b, c.a)); return colors; } diff --git a/Core/architecture/Renderable.cpp b/Core/architecture/Renderable.cpp index 4cc03b7..5b145b7 100644 --- a/Core/architecture/Renderable.cpp +++ b/Core/architecture/Renderable.cpp @@ -244,7 +244,7 @@ void Renderable::render_cached(Canvas& canvas, const Plot_Render_Snapshot& snaps std::uint64_t begin_time = steady_now_ns(); canvas.draw_image(RectF{static_cast(bounds.x), static_cast(bounds.y), static_cast(cache_image.width()), static_cast(cache_image.height())}, cache_image); if (snapshot.frame_metadata) - snapshot.frame_metadata->record_renderable_cache_compose(object_name_, parent_object_name, tree_depth, steady_now_ns() - begin_time, static_cast(cache_image.size_bytes()), static_cast(bounds.width) * static_cast(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire)); + snapshot.frame_metadata->record_renderable_cache_compose(object_name_, parent_object_name, tree_depth, steady_now_ns() - begin_time, static_cast(cache_image.byte_size()), static_cast(bounds.width) * static_cast(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire)); return; } if (snapshot.frame_metadata) @@ -252,12 +252,12 @@ void Renderable::render_cached(Canvas& canvas, const Plot_Render_Snapshot& snaps std::uint64_t rebuild_begin_time = steady_now_ns(); render_cache_image(bounds, snapshot, edit_version); if (snapshot.frame_metadata) - snapshot.frame_metadata->record_renderable_cache_rebuild(object_name_, parent_object_name, tree_depth, steady_now_ns() - rebuild_begin_time, cache_image.empty() ? 0 : static_cast(cache_image.size_bytes()), static_cast(bounds.width) * static_cast(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire)); + snapshot.frame_metadata->record_renderable_cache_rebuild(object_name_, parent_object_name, tree_depth, steady_now_ns() - rebuild_begin_time, cache_image.empty() ? 0 : static_cast(cache_image.byte_size()), static_cast(bounds.width) * static_cast(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire)); if (!cache_image.empty()) { std::uint64_t begin_time = steady_now_ns(); canvas.draw_image(RectF{static_cast(bounds.x), static_cast(bounds.y), static_cast(cache_image.width()), static_cast(cache_image.height())}, cache_image); if (snapshot.frame_metadata) - snapshot.frame_metadata->record_renderable_cache_compose(object_name_, parent_object_name, tree_depth, steady_now_ns() - begin_time, static_cast(cache_image.size_bytes()), static_cast(bounds.width) * static_cast(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire)); + snapshot.frame_metadata->record_renderable_cache_compose(object_name_, parent_object_name, tree_depth, steady_now_ns() - begin_time, static_cast(cache_image.byte_size()), static_cast(bounds.width) * static_cast(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire)); } } std::size_t Renderable::render_tree_node(Canvas& canvas, const Plot_Render_Snapshot& snapshot, const Renderable_Tree_Snapshot& tree, std::size_t index) { @@ -307,7 +307,7 @@ void Renderable::render_cached_tree_node(Canvas& canvas, const Plot_Render_Snaps std::uint64_t begin_time = steady_now_ns(); canvas.draw_image(RectF{static_cast(bounds.x), static_cast(bounds.y), static_cast(cache_image.width()), static_cast(cache_image.height())}, cache_image); if (snapshot.frame_metadata) - snapshot.frame_metadata->record_renderable_cache_compose(object_name_, node.cache_parent_object_name, node.cache_tree_depth, steady_now_ns() - begin_time, static_cast(cache_image.size_bytes()), static_cast(bounds.width) * static_cast(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire)); + snapshot.frame_metadata->record_renderable_cache_compose(object_name_, node.cache_parent_object_name, node.cache_tree_depth, steady_now_ns() - begin_time, static_cast(cache_image.byte_size()), static_cast(bounds.width) * static_cast(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire)); return; } if (snapshot.frame_metadata) @@ -315,12 +315,12 @@ void Renderable::render_cached_tree_node(Canvas& canvas, const Plot_Render_Snaps std::uint64_t rebuild_begin_time = steady_now_ns(); render_cache_image_tree_node(bounds, snapshot, tree, index, edit_version); if (snapshot.frame_metadata) - snapshot.frame_metadata->record_renderable_cache_rebuild(object_name_, node.cache_parent_object_name, node.cache_tree_depth, steady_now_ns() - rebuild_begin_time, cache_image.empty() ? 0 : static_cast(cache_image.size_bytes()), static_cast(bounds.width) * static_cast(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire)); + snapshot.frame_metadata->record_renderable_cache_rebuild(object_name_, node.cache_parent_object_name, node.cache_tree_depth, steady_now_ns() - rebuild_begin_time, cache_image.empty() ? 0 : static_cast(cache_image.byte_size()), static_cast(bounds.width) * static_cast(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire)); if (!cache_image.empty()) { std::uint64_t begin_time = steady_now_ns(); canvas.draw_image(RectF{static_cast(bounds.x), static_cast(bounds.y), static_cast(cache_image.width()), static_cast(cache_image.height())}, cache_image); if (snapshot.frame_metadata) - snapshot.frame_metadata->record_renderable_cache_compose(object_name_, node.cache_parent_object_name, node.cache_tree_depth, steady_now_ns() - begin_time, static_cast(cache_image.size_bytes()), static_cast(bounds.width) * static_cast(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire)); + snapshot.frame_metadata->record_renderable_cache_compose(object_name_, node.cache_parent_object_name, node.cache_tree_depth, steady_now_ns() - begin_time, static_cast(cache_image.byte_size()), static_cast(bounds.width) * static_cast(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire)); } } void Renderable::render_cache_image_tree_node(const Rect& bounds, const Plot_Render_Snapshot& snapshot, const Renderable_Tree_Snapshot& tree, std::size_t index, std::uint64_t version) { diff --git a/Core/architecture/Timeline_Stream.cpp b/Core/architecture/Timeline_Stream.cpp index 0fe227f..87a50da 100644 --- a/Core/architecture/Timeline_Stream.cpp +++ b/Core/architecture/Timeline_Stream.cpp @@ -3,31 +3,31 @@ #include #include namespace renderive { -int Timeline_Stream_Snapshot::upper() const { - return lower + time_point_size - 1; +int Timeline_Stream_Snapshot::coordinate_end() const { + return coordinate_begin + time_point_size - 1; } bool Timeline_Stream_Snapshot::coord_by_stream_tick(int stream_tick, int& coord) const { if (times.empty()) return false; - if (stream_tick < lower_stream_tick || stream_tick > upper_stream_tick) + if (stream_tick < first_stream_tick || stream_tick > last_stream_tick) return false; int count = static_cast(times.size()); - if (start_coord_to_end_coord) - coord = lower + (upper_stream_tick - stream_tick); + if (newest_at_axis_start) + coord = coordinate_begin + (last_stream_tick - stream_tick); else - coord = lower + (time_point_size - count) + (stream_tick - lower_stream_tick); - return coord >= lower && coord <= upper(); + coord = coordinate_begin + (time_point_size - count) + (stream_tick - first_stream_tick); + return coord >= coordinate_begin && coord <= coordinate_end(); } Time_Of_Day Timeline_Stream_Snapshot::time_by_tick(int tick) const { - int offset = tick - lower; + int offset = tick - coordinate_begin; int count = static_cast(times.size()); - int index = start_coord_to_end_coord ? count - 1 - offset : offset - (time_point_size - count); + int index = newest_at_axis_start ? count - 1 - offset : offset - (time_point_size - count); if (index < 0 || index >= count) return {}; return times[static_cast(index)]; } Timeline_Stream::Timeline_Stream() = default; -int Timeline_Stream::push_time(Time_Of_Day time) { +int Timeline_Stream::append_time(Time_Of_Day time) { int tick = next_tick_value.fetch_add(1, std::memory_order_acq_rel); if (tick == std::numeric_limits::max()) { int expected = std::numeric_limits::min(); @@ -43,9 +43,9 @@ int Timeline_Stream::push_time(Time_Of_Day time) { } return tick; } -Timeline_Stream_Snapshot Timeline_Stream::capture(int time_point_size, int tick_space, bool start_coord_to_end_coord) const { +Timeline_Stream_Snapshot Timeline_Stream::capture(int time_point_size, int label_tick_interval, bool start_coord_to_end_coord) const { time_point_size = std::max(1, time_point_size); - tick_space = std::max(1, tick_space); + label_tick_interval = std::max(1, label_tick_interval); Timeline_Stream_Snapshot snapshot; std::pmr::vector captured; { @@ -58,26 +58,26 @@ Timeline_Stream_Snapshot Timeline_Stream::capture(int time_point_size, int tick_ for (auto it = first; it != samples.end(); ++it) captured.push_back(*it); } - snapshot.start_coord_to_end_coord = start_coord_to_end_coord; + snapshot.newest_at_axis_start = start_coord_to_end_coord; snapshot.time_point_size = time_point_size; if (captured.empty()) { - snapshot.lower = 0; + snapshot.coordinate_begin = 0; return snapshot; } - snapshot.lower_stream_tick = captured.front().tick; - snapshot.upper_stream_tick = captured.back().tick; - snapshot.lower = snapshot.upper_stream_tick - time_point_size + 1; + snapshot.first_stream_tick = captured.front().stream_tick; + snapshot.last_stream_tick = captured.back().stream_tick; + snapshot.coordinate_begin = snapshot.last_stream_tick - time_point_size + 1; snapshot.times.reserve(captured.size()); for (const auto& sample : captured) snapshot.times.push_back(sample.time); - snapshot.ticks.reserve(captured.size() / static_cast(tick_space) + 1); + snapshot.ticks.reserve(captured.size() / static_cast(label_tick_interval) + 1); for (const auto& sample : captured) { int coord{}; - if ((tick_space == 1 || sample.tick % tick_space == 0) && snapshot.coord_by_stream_tick(sample.tick, coord)) + if ((label_tick_interval == 1 || sample.stream_tick % label_tick_interval == 0) && snapshot.coord_by_stream_tick(sample.stream_tick, coord)) snapshot.ticks.push_back({sample.time, coord}); } - std::sort(snapshot.ticks.begin(), snapshot.ticks.end(), [](const Timeline_Tick& left, const Timeline_Tick& right) { - return left.tick < right.tick; + std::sort(snapshot.ticks.begin(), snapshot.ticks.end(), [](const Timeline_Label_Tick& left, const Timeline_Label_Tick& right) { + return left.coordinate < right.coordinate; }); return snapshot; } diff --git a/Core/architecture/Timeline_Stream.h b/Core/architecture/Timeline_Stream.h index 9e2f84d..13a9429 100644 --- a/Core/architecture/Timeline_Stream.h +++ b/Core/architecture/Timeline_Stream.h @@ -8,31 +8,31 @@ #include "../base/Time_Of_Day.h" #include "global.h" namespace renderive { -struct Timeline_Tick { +struct Timeline_Label_Tick { Time_Of_Day time; - int tick{}; + int coordinate{}; }; struct LIB_DECL Timeline_Stream_Snapshot { std::uint64_t version{}; - bool start_coord_to_end_coord = false; - int lower{}; + bool newest_at_axis_start = false; // 当前 true 时 代表最新时间映射到起始坐标 + int coordinate_begin{}; int time_point_size = 1; - int lower_stream_tick{}; - int upper_stream_tick = -1; + int first_stream_tick{}; + int last_stream_tick = -1; std::vector times; - std::vector ticks; - [[nodiscard]] int upper() const; + std::vector ticks; + [[nodiscard]] int coordinate_end() const; [[nodiscard]] bool coord_by_stream_tick(int stream_tick, int& coord) const; [[nodiscard]] Time_Of_Day time_by_tick(int tick) const; }; class LIB_DECL Timeline_Stream { public: Timeline_Stream(); - int push_time(Time_Of_Day time); - [[nodiscard]] Timeline_Stream_Snapshot capture(int time_point_size, int tick_space, bool start_coord_to_end_coord) const; + int append_time(Time_Of_Day time); + [[nodiscard]] Timeline_Stream_Snapshot capture(int time_point_size, int label_tick_interval, bool start_coord_to_end_coord) const; private: struct Sample { - int tick{}; + int stream_tick{}; Time_Of_Day time; }; static constexpr std::size_t Max_Buffered_Time_Count = 65536; diff --git a/Core/base/Color.h b/Core/base/Color.h index acf645c..b840d53 100644 --- a/Core/base/Color.h +++ b/Core/base/Color.h @@ -1,14 +1,11 @@ #pragma once #include - namespace renderive { - struct Color { - std::uint8_t red{}; - std::uint8_t green{}; - std::uint8_t blue{}; - std::uint8_t alpha{255}; - + std::uint8_t r{}; + std::uint8_t g{}; + std::uint8_t b{}; + std::uint8_t a{255}; static constexpr Color transparent() { return {0, 0, 0, 0}; } @@ -18,36 +15,32 @@ struct Color { static constexpr Color white() { return {255, 255, 255, 255}; } - static constexpr Color red_color() { + static constexpr Color red() { return {255, 0, 0, 255}; } - static constexpr Color green_color() { + static constexpr Color green() { return {0, 255, 0, 255}; } static constexpr Color yellow() { return {255, 255, 0, 255}; } bool operator==(const Color& other) const { - return red == other.red && green == other.green && blue == other.blue && alpha == other.alpha; + return r == other.r && g == other.g && b == other.b && a == other.a; } bool operator!=(const Color& other) const { return !(*this == other); } }; - using Pixel = std::uint32_t; - constexpr Pixel premultiply(Color color) { - auto r = static_cast((color.red * color.alpha + 127) / 255); - auto g = static_cast((color.green * color.alpha + 127) / 255); - auto b = static_cast((color.blue * color.alpha + 127) / 255); - return (static_cast(color.alpha) << 24) | (r << 16) | (g << 8) | b; + auto r = static_cast((color.r * color.a + 127) / 255); + auto g = static_cast((color.g * color.a + 127) / 255); + auto b = static_cast((color.b * color.a + 127) / 255); + return (static_cast(color.a) << 24) | (r << 16) | (g << 8) | b; } - constexpr Pixel pack_rgba(std::uint8_t r, std::uint8_t g, std::uint8_t b, std::uint8_t a = 255) { return (static_cast(a) << 24) | (static_cast(r) << 16) | (static_cast(g) << 8) | static_cast(b); } - constexpr Color premultiplied_to_color(Pixel pixel) { auto a = static_cast(pixel >> 24); if (a == 0) @@ -62,5 +55,4 @@ constexpr Color premultiplied_to_color(Pixel pixel) { a }; } - } // namespace renderive diff --git a/Core/base/Geometry.h b/Core/base/Geometry.h index cb8c9f0..71b8318 100644 --- a/Core/base/Geometry.h +++ b/Core/base/Geometry.h @@ -2,19 +2,15 @@ #include #include #include - namespace renderive { - struct Point { int x{}; int y{}; }; - struct PointF { double x{}; double y{}; }; - struct Size { int width{}; int height{}; @@ -28,7 +24,6 @@ struct Size { return !(*this == other); } }; - struct Rect { int x{}; int y{}; @@ -50,18 +45,17 @@ struct Rect { return point.x >= x && point.x <= right() && point.y >= y && point.y <= bottom(); } [[nodiscard]] Rect intersected(const Rect& other) const { - int r = std::min(right(), other.right()); - int b = std::min(bottom(), other.bottom()); + int r = std::min(right(), other.right()); + int b = std::min(bottom(), other.bottom()); int nx = std::max(x, other.x); int ny = std::max(y, other.y); - int w = r - nx; - int h = b - ny; + int w = r - nx; + int h = b - ny; if (w <= 0 || h <= 0) return {}; return {nx, ny, w, h}; } }; - struct RectF { double x{}; double y{}; @@ -98,23 +92,21 @@ struct RectF { return {nx, ny, nw, nh}; } [[nodiscard]] RectF intersected(const RectF& other) const { - double r = std::min(right(), other.right()); - double b = std::min(bottom(), other.bottom()); + double r = std::min(right(), other.right()); + double b = std::min(bottom(), other.bottom()); double nx = std::max(x, other.x); double ny = std::max(y, other.y); - double w = r - nx; - double h = b - ny; + double w = r - nx; + double h = b - ny; if (w <= 0.0 || h <= 0.0) return {}; return {nx, ny, w, h}; } }; - enum class Orientation : std::uint8_t { Horizontal, Vertical }; - struct Range { double origin; double target; @@ -124,7 +116,7 @@ struct Range { [[nodiscard]] double length() const { return target - origin; } - [[nodiscard]] double middle() const { + [[nodiscard]] double center() const { return origin + (target - origin) / 2.0; } bool operator==(const Range& other) const { @@ -139,7 +131,5 @@ struct Range { return value > target - 0.0001 && value < origin + 0.0001; } }; - std::ostream& operator<<(std::ostream& stream, const Range& range); - } // namespace renderive diff --git a/Core/base/Style.h b/Core/base/Style.h index 0573782..ba92d22 100644 --- a/Core/base/Style.h +++ b/Core/base/Style.h @@ -30,7 +30,7 @@ struct Pen { Line_Cap cap = Line_Cap::Butt; Line_Join join = Line_Join::Miter; [[nodiscard]] bool enabled() const { - return style != Line_Style::None && width > 0.0 && color.alpha != 0; + return style != Line_Style::None && width > 0.0 && color.a != 0; } }; @@ -43,7 +43,7 @@ struct Brush { Color color = Color::transparent(); Brush_Style style = Brush_Style::None; [[nodiscard]] bool enabled() const { - return style != Brush_Style::None && color.alpha != 0; + return style != Brush_Style::None && color.a != 0; } }; diff --git a/Core/base/Text.h b/Core/base/Text.h index c54409f..84d99ad 100644 --- a/Core/base/Text.h +++ b/Core/base/Text.h @@ -2,22 +2,18 @@ #include #include #include "Bitmask.h" - namespace renderive { - enum class Text_Align : std::uint16_t { - None = 0, - Left = 1 << 0, - Right = 1 << 1, - HCenter = 1 << 2, - Top = 1 << 3, - Bottom = 1 << 4, - VCenter = 1 << 5, - Center = HCenter | VCenter + None = 0, + Left = 1 << 0, + Right = 1 << 1, + Horizontal_Center = 1 << 2, + Top = 1 << 3, + Bottom = 1 << 4, + Vertical_Center = 1 << 5, + Center = Horizontal_Center | Vertical_Center }; - struct Font_Face; - struct Font { std::shared_ptr face; double size = 12.0; @@ -27,7 +23,6 @@ struct Font { return face != nullptr && size > 0.0; } }; - struct Text_Metrics { double width{}; double height{}; @@ -38,7 +33,5 @@ struct Text_Metrics { return ascent + descent + line_gap; } }; - } // namespace renderive - RENDERIVE_ENABLE_BITMASK(renderive::Text_Align) diff --git a/Core/execution/Render_Executor.cpp b/Core/execution/Render_Executor.cpp index 0baff20..099b33b 100644 --- a/Core/execution/Render_Executor.cpp +++ b/Core/execution/Render_Executor.cpp @@ -262,7 +262,7 @@ private: std::uint64_t queue_wait_ns = run_record->queue_wait_ns; std::uint64_t run_ns = end_ns > begin_ns ? end_ns - begin_ns : 0; if (task.frame_stat) { - Frame_Worker_Stat& stat = *task.frame_stat; + Frame_Worker_Stats& stat = *task.frame_stat; stat.task_count += std::max(1, task.logical_task_count); stat.peak_parallelism = static_cast(std::max(stat.peak_parallelism, metrics->peak_concurrency.load(std::memory_order_acquire))); stat.queue_wait_total_ns += queue_wait_ns; diff --git a/Core/execution/Render_Executor.h b/Core/execution/Render_Executor.h index 93540bd..d4e172c 100644 --- a/Core/execution/Render_Executor.h +++ b/Core/execution/Render_Executor.h @@ -5,41 +5,32 @@ #include #include #include - namespace renderive { - struct Render_Executor_Task { using Taskflow_Builder = std::function; - Plot_Execution_Id plot_id{}; std::uint64_t frame_id{}; Render_Task_Kind kind = Render_Task_Kind::Primitive; Task work; Taskflow_Builder build_taskflow; Task completion; - std::shared_ptr frame_stat; + std::shared_ptr frame_stat; std::uint32_t logical_task_count{1}; bool frame_job{}; }; - class Render_Executor_Private; - class LIB_DECL Render_Executor { public: explicit Render_Executor(Render_Runtime_Config config = {}); Render_Executor(const Render_Executor&) = delete; Render_Executor& operator=(const Render_Executor&) = delete; ~Render_Executor(); - bool try_submit(Render_Executor_Task task); void shutdown(); [[nodiscard]] Render_Executor_Snapshot snapshot() const; [[nodiscard]] std::size_t worker_count() const; - private: std::unique_ptr d; }; - std::size_t resolve_render_worker_count(std::size_t configured_count); - } // namespace renderive diff --git a/Core/plot/Plot_Core.cpp b/Core/plot/Plot_Core.cpp index 5fa432a..1e0c1c8 100644 --- a/Core/plot/Plot_Core.cpp +++ b/Core/plot/Plot_Core.cpp @@ -8,11 +8,8 @@ #include #include #include - namespace renderive { - class Plot_Core_Private; - struct Frame_Render_Job { std::shared_ptr owner; std::uint64_t generation{}; @@ -21,53 +18,44 @@ struct Frame_Render_Job { std::shared_ptr lifecycle; Plot_Render_Snapshot render_snapshot; Renderable_Tree_Snapshot renderables; - std::shared_ptr worker_stat; + std::shared_ptr worker_stat; }; - class Plot_Core_Private final : public std::enable_shared_from_this { public: explicit Plot_Core_Private(std::unique_ptr s) : strategy(std::move(s)) {} - ~Plot_Core_Private() = default; - bool render_enabled() const { return rendering.load(std::memory_order_acquire); } - bool destroying() const { return destroying_flag.load(std::memory_order_acquire); } - Refresh_Runtime_Snapshot refresh_runtime_snapshot(std::uint64_t now_ns = steady_now_ns()) const { return { render_enabled(), destroying(), - pipeline.has_new_state(), - pipeline.job_state != Plot_Render_Job_State::Idle, - pipeline.middle_has_new_frame(), - pipeline.paint_active(), + pipeline.has_unrendered_edit(), + pipeline.render_job_state != Frame_Job_State::Idle, + pipeline.middle_frame_ready(), + pipeline.painting_frame_in_use(), now_ns }; } - bool submit_render_once() { if (!rendering.load(std::memory_order_acquire) || destroying_flag.load(std::memory_order_acquire)) return false; if (!root) return false; - Size size{ context->render_width.load(std::memory_order_acquire), context->render_height.load(std::memory_order_acquire) }; if (size.empty()) return false; - - auto frame_lease = pipeline.try_begin_render(); + auto frame_lease = pipeline.try_acquire_render_frame(); if (!frame_lease) return false; - Plot_Frame* buffer = frame_lease.frame; cancel_update_states(buffer->presented_update_states); std::uint64_t render_role_enter_ns = buffer->metadata ? buffer->metadata->render_role_enter_ns : 0; @@ -76,7 +64,7 @@ public: Frame_Lifecycle_Record& frame = *frame_record; std::uint64_t submit_time = steady_now_ns(); frame.frame_id = ++next_frame_id; - frame.input_version = pipeline.edit_state_version.load(std::memory_order_acquire); + frame.input_version = pipeline.edit_version.load(std::memory_order_acquire); frame.render_request_ns = submit_time; frame.render_role_enter_ns = render_role_enter_ns ? render_role_enter_ns : submit_time; frame.core_data_time_ns = latest_input_time_ns.load(std::memory_order_acquire); @@ -86,18 +74,16 @@ public: frame.viewport_version = context->viewport_version.load(std::memory_order_acquire); frame.wait_21_ns = submit_time > frame.render_role_enter_ns ? submit_time - frame.render_role_enter_ns : 0; frame.render_begin_ns = submit_time; - - std::uint64_t previous_render_state_version = pipeline.render_state_version; - pipeline.job_state = Plot_Render_Job_State::Running; - pipeline.render_state_version = frame.input_version; - + std::uint64_t previous_render_state_version = pipeline.rendered_edit_version; + pipeline.render_job_state = Frame_Job_State::Running; + pipeline.rendered_edit_version = frame.input_version; auto job = std::make_shared(); job->owner = shared_from_this(); job->generation = generation.load(std::memory_order_acquire); job->frame_lease = std::move(frame_lease); job->buffer = buffer; job->lifecycle = frame_record; - job->worker_stat = std::make_shared(); + job->worker_stat = std::make_shared(); job->render_snapshot.context = context; job->render_snapshot.size = size; job->render_snapshot.background_color = background_color(); @@ -106,7 +92,6 @@ public: job->render_snapshot.frame_metadata = frame_record.get(); job->render_snapshot.frame_update_states = &buffer->presented_update_states; previous_frame_time_ns = submit_time; - job->renderables = renderable_tree_snapshot(); auto& scheduler = Global::instance()->render_scheduler(); bool submitted = scheduler.try_submit_render_task(Render_Executor_Task{ @@ -140,21 +125,18 @@ public: }); if (submitted) return true; - frame.outcome = Frame_Outcome::Worker_Budget_Dropped; frame.worker.rejected_task_count++; job->frame_lease.reset(); - pipeline.render_state_version = previous_render_state_version; - pipeline.job_state = Plot_Render_Job_State::Idle; + pipeline.rendered_edit_version = previous_render_state_version; + pipeline.render_job_state = Frame_Job_State::Idle; collect_frame(frame_record); trigger_refresh_strategy(Refresh_Trigger::Render_Finished, &frame); return false; } - static bool frame_job_valid(const std::shared_ptr& job) { return job && job->buffer && job->lifecycle && job->render_snapshot.context && !job->render_snapshot.destroying(); } - void prepare_frame_job(const std::shared_ptr& job) { if (!frame_job_valid(job)) return; @@ -170,7 +152,6 @@ public: frame.prepare_end_ns = steady_now_ns(); job->render_snapshot.context->first_prepare_data.store(false, std::memory_order_release); } - void draw_frame_job(const std::shared_ptr& job) { if (!frame_job_valid(job) || !job->lifecycle->prepare_end_ns) return; @@ -178,14 +159,12 @@ public: job->buffer->image.resize(job->render_snapshot.size.width, job->render_snapshot.size.height); job->buffer->image.fill(job->render_snapshot.background_color); Canvas canvas(job->buffer->image); - frame.draw_begin_ns = steady_now_ns(); if (!job->renderables.empty() && job->renderables.front().renderable) job->renderables.front().renderable->render_tree_snapshot(canvas, job->render_snapshot, job->renderables, 0); frame.draw_end_ns = steady_now_ns(); frame.render_end_ns = steady_now_ns(); } - void finalize_frame_job(const std::shared_ptr& job) { if (!frame_job_valid(job) || !job->lifecycle->render_end_ns) return; @@ -196,7 +175,6 @@ public: update_state->complete_until(Update_Stage::Rendered); } } - void execute_frame_job(const std::shared_ptr& job) { if (!job || !job->buffer || !job->lifecycle || !job->render_snapshot.context || job->render_snapshot.destroying()) return; @@ -204,7 +182,6 @@ public: draw_frame_job(job); finalize_frame_job(job); } - void complete_frame_job(const std::shared_ptr& job) { if (!job || !job->buffer || !job->lifecycle) return; @@ -216,27 +193,24 @@ public: job->frame_lease.reset(); if (!valid_generation || !valid_context || !frame.render_end_ns) { frame.outcome = Frame_Outcome::Cancelled; - pipeline.job_state = Plot_Render_Job_State::Idle; + pipeline.render_job_state = Frame_Job_State::Idle; supersede_update_states(job->buffer->presented_update_states); trigger_refresh_strategy(Refresh_Trigger::Render_Finished, &frame); return; } - - auto publish_result = pipeline.try_publish_rendered(steady_now_ns()); - if (publish_result.superseded_middle) { - trigger_refresh_strategy(Refresh_Trigger::Frame_Returned, publish_result.superseded_middle.get()); - collect_frame(publish_result.superseded_middle); + auto publish_result = pipeline.try_publish_rendered_frame(steady_now_ns()); + if (publish_result.superseded_frame_record) { + trigger_refresh_strategy(Refresh_Trigger::Frame_Returned, publish_result.superseded_frame_record.get()); + collect_frame(publish_result.superseded_frame_record); } - if (publish_result.dropped_frame) { - collect_frame(publish_result.dropped_frame); + if (publish_result.dropped_frame_record) { + collect_frame(publish_result.dropped_frame_record); } - - pipeline.job_state = Plot_Render_Job_State::Idle; + pipeline.render_job_state = Frame_Job_State::Idle; if (publish_result.request_present) request_present(publish_result.dirty_rect); trigger_refresh_strategy(Refresh_Trigger::Render_Finished, &frame); } - void post_scheduler_action(Task task) { if (!task) return; @@ -253,7 +227,6 @@ public: } scheduler.post(std::move(action)); } - void trigger_refresh_strategy(Refresh_Trigger trigger, Frame_Lifecycle_Record* frame = nullptr) { if (!strategy) return; @@ -262,7 +235,6 @@ public: Refresh_Action action = strategy->on_trigger(trigger, runtime, frame); apply_refresh_action(action, runtime); } - void notify_input_changed(std::uint64_t now_ns) { if (!strategy) return; @@ -270,7 +242,6 @@ public: Refresh_Action action = strategy->on_trigger(Refresh_Trigger::Input_Dirty, runtime, nullptr); apply_refresh_action(action, runtime); } - void notify_started() { if (!strategy_started) { strategy_started = true; @@ -280,7 +251,6 @@ public: trigger_refresh_strategy(Refresh_Trigger::Input_Dirty); } } - void notify_paused() { invalidate_refresh_deadline(); if (!strategy_started) @@ -288,17 +258,15 @@ public: strategy_started = false; trigger_refresh_strategy(Refresh_Trigger::Paused); } - void notify_frame_returned(std::shared_ptr frame) { if (!frame) return; trigger_refresh_strategy(Refresh_Trigger::Frame_Returned, frame.get()); collect_frame(frame); } - void apply_refresh_action(Refresh_Action action, const Refresh_Runtime_Snapshot& runtime) { if (action.request_paint) { - auto update_result = pipeline.request_paint_update(steady_now_ns()); + auto update_result = pipeline.request_present(steady_now_ns()); if (update_result.request_present) request_present(update_result.dirty_rect); } @@ -314,7 +282,6 @@ public: if (!runtime.enabled || runtime.destroying || !runtime.dirty) invalidate_refresh_deadline(); } - void schedule_refresh_deadline(std::uint64_t deadline_ns) { if (deadline_ns <= steady_now_ns()) { invalidate_refresh_deadline(); @@ -336,12 +303,10 @@ public: self->trigger_refresh_strategy(Refresh_Trigger::Timer_Fired); }); } - void invalidate_refresh_deadline() { scheduled_refresh_deadline_ns = 0; ++refresh_deadline_generation; } - void dispatch_event(const Event& event) { if (!root) return; @@ -376,26 +341,22 @@ public: break; } } - std::vector> renderable_snapshot() const { std::vector> result; append_renderable_snapshot(result, root); return result; } - Renderable_Tree_Snapshot renderable_tree_snapshot() const { Renderable_Tree_Snapshot result; if (root) root->append_tree_snapshot(result); return result; } - std::vector> reverse_renderable_snapshot() const { std::vector> result = renderable_snapshot(); std::reverse(result.begin(), result.end()); return result; } - void append_renderable_snapshot(std::vector>& result, const std::shared_ptr& renderable) const { if (!renderable) return; @@ -403,7 +364,6 @@ public: for (const auto& child : renderable->children_snapshot()) append_renderable_snapshot(result, child); } - void dispatch_to_renderables(const std::vector>& renderables, const Event& event) { for (const auto& renderable : renderables) { if (!renderable || event.is_accepted()) @@ -411,7 +371,6 @@ public: renderable->plot_event(event); } } - void update_hover_targets(const Pointer_Event& event) { Point pos{static_cast(event.position.x), static_cast(event.position.y)}; std::vector> hits = root->hit_renderables(event.position); @@ -431,7 +390,6 @@ public: hover_targets.push_back(target); } } - void clear_hover_targets() { Point pos{}; for (const auto& old_target : hover_targets) { @@ -440,12 +398,10 @@ public: } hover_targets.clear(); } - void request_present(Rect dirty_rect) { if (auto target = sink.lock()) target->request_present(dirty_rect); } - void collect_frame(std::shared_ptr frame) { if (!frame) return; @@ -453,12 +409,10 @@ public: if (observer && observer->enabled()) observer->collect_frame(frame); } - Color background_color() const { Pixel p = context->background_rgba.load(std::memory_order_acquire); return premultiplied_to_color(p); } - std::unique_ptr strategy; std::shared_ptr context = std::make_shared(); std::shared_ptr root; @@ -477,21 +431,18 @@ public: Plot_Execution_Id plot_execution_id{}; std::atomic generation{1}; }; - namespace { Plot_Execution_Id next_plot_execution_id() { static std::atomic next_id{1}; return next_id.fetch_add(1, std::memory_order_acq_rel); } } // namespace - Plot_Core::Plot_Core(std::unique_ptr strategy) : d(std::make_shared(std::move(strategy))) { d->plot_execution_id = next_plot_execution_id(); d->context->owner.store(this, std::memory_order_release); Global::instance()->render_scheduler().register_plot(this); } - Plot_Core::~Plot_Core() { d->destroying_flag.store(true, std::memory_order_release); d->context->destroying.store(true, std::memory_order_release); @@ -500,7 +451,6 @@ Plot_Core::~Plot_Core() { d->pipeline.cancel_all_update_states(); d->context->owner.store(nullptr, std::memory_order_release); } - void Plot_Core::init() { if (!d->root) { d->root = std::make_shared(); @@ -509,15 +459,12 @@ void Plot_Core::init() { } d->context->first_resize.store(true, std::memory_order_release); } - std::shared_ptr Plot_Core::render_context() const { return d->context; } - std::shared_ptr Plot_Core::root_renderable() const { return d->root; } - std::shared_ptr Plot_Core::create_renderable_node( const std::shared_ptr& parent, std::string object_name) { if (!parent) @@ -527,7 +474,6 @@ std::shared_ptr Plot_Core::create_renderable_node( node->init(parent); return node; } - void Plot_Core::remove_renderable(const std::shared_ptr& renderable) { if (!renderable) return; @@ -537,16 +483,13 @@ void Plot_Core::remove_renderable(const std::shared_ptr& renderable) renderable->detach_from_parent(); mark_render_state_dirty(); } - void Plot_Core::set_background_color(Color color) { d->context->background_rgba.store(premultiply(color), std::memory_order_release); mark_render_state_dirty(); } - Color Plot_Core::background_color() const { return d->background_color(); } - void Plot_Core::set_viewport_size(Size size) { Size previous{ d->context->render_width.load(std::memory_order_acquire), @@ -559,30 +502,26 @@ void Plot_Core::set_viewport_size(Size size) { if (!size.empty()) d->context->first_resize.store(false, std::memory_order_release); } - Size Plot_Core::viewport_size() const { return { d->context->render_width.load(std::memory_order_acquire), d->context->render_height.load(std::memory_order_acquire) }; } - void Plot_Core::dispatch_event(const Event& event) { d->dispatch_event(event); } - void Plot_Core::mark_render_state_dirty() { if (d->destroying_flag.load(std::memory_order_acquire)) return; std::uint64_t now_ns = steady_now_ns(); - d->pipeline.mark_edit_state(); + d->pipeline.advance_edit_version(); d->latest_input_time_ns.store(now_ns, std::memory_order_release); d->pending_input_count.fetch_add(1, std::memory_order_relaxed); d->post_scheduler_action([data = d, now_ns]() { data->notify_input_changed(now_ns); }); } - void Plot_Core::request_manual_refresh() { if (d->destroying_flag.load(std::memory_order_acquire)) return; @@ -590,7 +529,6 @@ void Plot_Core::request_manual_refresh() { data->trigger_refresh_strategy(Refresh_Trigger::Manual_Request); }); } - void Plot_Core::start_render() { if (d->destroying_flag.load(std::memory_order_acquire)) return; @@ -599,34 +537,30 @@ void Plot_Core::start_render() { data->notify_started(); }); } - void Plot_Core::pause_render() { d->rendering.store(false, std::memory_order_release); d->post_scheduler_action([data = d]() { data->notify_paused(); }); } - bool Plot_Core::is_rendering() const { return d->rendering.load(std::memory_order_acquire); } - void Plot_Core::set_presentation_sink(std::weak_ptr sink) { d->sink = std::move(sink); } - -Present_Frame Plot_Core::begin_present() { - Present_Frame result; +Present_Frame_Lease Plot_Core::begin_present() { + Present_Frame_Lease result; if (!d->root) return result; - auto consumed = d->pipeline.try_begin_paint(steady_now_ns()); - if (consumed.returned_frame) { - d->post_scheduler_action([data = d, frame = consumed.returned_frame]() mutable { + auto consumed = d->pipeline.try_acquire_paint_frame(steady_now_ns()); + if (consumed.returned_frame_record) { + d->post_scheduler_action([data = d, frame = consumed.returned_frame_record]() mutable { data->notify_frame_returned(frame); }); } - result.is_new_frame = consumed.new_frame; - result.update_was_pending = consumed.update_was_pending; + result.is_new_frame = consumed.has_new_frame; + result.update_was_pending = consumed.present_request_was_pending; if (consumed.lease) result.lease_ = std::make_unique(std::move(consumed.lease)); if (!result.new_frame() && result.request_was_pending()) { @@ -636,8 +570,7 @@ Present_Frame Plot_Core::begin_present() { } return result; } - -void Plot_Core::end_present(Present_Frame&& frame, std::uint64_t paint_begin_ns, std::uint64_t paint_end_ns) { +void Plot_Core::end_present(Present_Frame_Lease&& frame, std::uint64_t paint_begin_ns, std::uint64_t paint_end_ns) { if (frame.lease_ && frame.lease_->frame) { auto* rendered_frame = frame.lease_->frame; if (rendered_frame->metadata) { @@ -652,5 +585,4 @@ void Plot_Core::end_present(Present_Frame&& frame, std::uint64_t paint_begin_ns, data->trigger_refresh_strategy(Refresh_Trigger::Paint_Finished); }); } - } // namespace renderive diff --git a/Core/plot/Plot_Core.h b/Core/plot/Plot_Core.h index b0195e7..01352c7 100644 --- a/Core/plot/Plot_Core.h +++ b/Core/plot/Plot_Core.h @@ -4,7 +4,7 @@ #include "../base/Color.h" #include "../base/Geometry.h" #include "../event/Event.h" -#include "Present_Frame.h" +#include "Present_Frame_Lease.h" #include "Presentation_Sink.h" #include "Refresh_Strategy.h" #include @@ -44,8 +44,8 @@ public: void set_presentation_sink(std::weak_ptr sink); - Present_Frame begin_present(); - void end_present(Present_Frame&& frame, std::uint64_t paint_begin_ns, std::uint64_t paint_end_ns); + Present_Frame_Lease begin_present(); + void end_present(Present_Frame_Lease&& frame, std::uint64_t paint_begin_ns, std::uint64_t paint_end_ns); private: std::shared_ptr d; diff --git a/Core/plot/Plot_Frame_Pipeline.cpp b/Core/plot/Plot_Frame_Pipeline.cpp index 78dfab6..50206b8 100644 --- a/Core/plot/Plot_Frame_Pipeline.cpp +++ b/Core/plot/Plot_Frame_Pipeline.cpp @@ -47,12 +47,12 @@ Plot_Frame_Pipeline::~Plot_Frame_Pipeline() { cancel_all_update_states(); } -void Plot_Frame_Pipeline::mark_edit_state() { - edit_state_version.fetch_add(1, std::memory_order_release); +void Plot_Frame_Pipeline::advance_edit_version() { + edit_version.fetch_add(1, std::memory_order_release); } -bool Plot_Frame_Pipeline::has_new_state() const { - return buffer_version_newer(edit_state_version.load(std::memory_order_acquire), render_state_version); +bool Plot_Frame_Pipeline::has_unrendered_edit() const { + return buffer_version_newer(edit_version.load(std::memory_order_acquire), rendered_edit_version); } Plot_Frame* Plot_Frame_Pipeline::frame_by_index(std::uint8_t index) { @@ -71,16 +71,16 @@ const Plot_Frame* Plot_Frame_Pipeline::frame_by_role(std::uint8_t role) const { return frame_by_index(frame_control.read_view()[role]); } -Plot_Frame_Lease Plot_Frame_Pipeline::try_begin_render() { +Plot_Frame_Lease Plot_Frame_Pipeline::try_acquire_render_frame() { auto record = frame_control.try_acquire_role(Frame_Rendering); if (record.result != Triple_Buffer_Result::Success) { - ++attempts.render_role_busy_count; + ++attempt_counters.render_role_busy_count; return {}; } return {frame_by_index(record.lease.index), &frame_control, record.lease}; } -Plot_Frame_Pipeline::Frame_Publish_Result Plot_Frame_Pipeline::try_publish_rendered(std::uint64_t now_ns) { +Plot_Frame_Pipeline::Frame_Publish_Result Plot_Frame_Pipeline::try_publish_rendered_frame(std::uint64_t now_ns) { Frame_Publish_Result result; Plot_Frame* rendered = frame_by_role(Frame_Rendering); @@ -100,7 +100,7 @@ Plot_Frame_Pipeline::Frame_Publish_Result Plot_Frame_Pipeline::try_publish_rende if (supersede_middle && old_middle->metadata && old_middle->metadata->frame_id) { old_middle->metadata->superseded_time_ns = now_ns; old_middle->metadata->outcome = Frame_Outcome::Superseded; - result.superseded_middle = old_middle->metadata; + result.superseded_frame_record = old_middle->metadata; supersede_update_states(old_middle->presented_update_states); } @@ -110,34 +110,34 @@ Plot_Frame_Pipeline::Frame_Publish_Result Plot_Frame_Pipeline::try_publish_rende }); if (swap.result != Triple_Buffer_Result::Success) { rendered->metadata->outcome = Frame_Outcome::Publish_Dropped; - result.dropped_frame = rendered->metadata; + result.dropped_frame_record = rendered->metadata; supersede_update_states(rendered->presented_update_states); - ++attempts.publish_dropped_count; + ++attempt_counters.publish_dropped_count; return result; } - Frame_Publish_Result update_result = request_paint_update(now_ns); - update_result.superseded_middle = result.superseded_middle; - update_result.dropped_frame = result.dropped_frame; + Frame_Publish_Result update_result = request_present(now_ns); + update_result.superseded_frame_record = result.superseded_frame_record; + update_result.dropped_frame_record = result.dropped_frame_record; return update_result; } -Plot_Frame_Pipeline::Frame_Publish_Result Plot_Frame_Pipeline::request_paint_update(std::uint64_t now_ns) { +Plot_Frame_Pipeline::Frame_Publish_Result Plot_Frame_Pipeline::request_present(std::uint64_t now_ns) { Frame_Publish_Result result; - if (!middle_has_new_frame()) + if (!middle_frame_ready()) return result; Plot_Frame* middle = frame_by_role(Frame_Middle); if (paint_request_pending.load(std::memory_order_acquire)) { - middle->metadata->update_request_id = pending_update_request_id.load(std::memory_order_acquire); - middle->metadata->update_request_time_ns = pending_update_request_time.load(std::memory_order_acquire); + middle->metadata->update_request_id = pending_present_request_id.load(std::memory_order_acquire); + middle->metadata->update_request_time_ns = pending_present_request_time_ns.load(std::memory_order_acquire); return result; } - result.update_request_id = ++next_update_request_id; + result.update_request_id = ++next_present_request_id; result.update_request_time = now_ns; middle->metadata->update_request_id = result.update_request_id; middle->metadata->update_request_time_ns = result.update_request_time; - pending_update_request_id.store(result.update_request_id, std::memory_order_release); - pending_update_request_time.store(result.update_request_time, std::memory_order_release); + pending_present_request_id.store(result.update_request_id, std::memory_order_release); + pending_present_request_time_ns.store(result.update_request_time, std::memory_order_release); paint_request_pending.store(true, std::memory_order_release); Size size = middle->image.size(); result.dirty_rect = Rect{0, 0, size.width, size.height}; @@ -145,11 +145,11 @@ Plot_Frame_Pipeline::Frame_Publish_Result Plot_Frame_Pipeline::request_paint_upd return result; } -Plot_Frame_Pipeline::Frame_Consume_Result Plot_Frame_Pipeline::try_begin_paint(std::uint64_t now_ns) { +Plot_Frame_Pipeline::Frame_Consume_Result Plot_Frame_Pipeline::try_acquire_paint_frame(std::uint64_t now_ns) { Frame_Consume_Result result; bool pending = paint_request_pending.load(std::memory_order_acquire); - if (middle_has_new_frame()) { + if (middle_frame_ready()) { auto swap = frame_control.try_swap_role(Frame_Middle, Frame_Painting, [this](const Triple_Buffer_View& view) { const Plot_Frame* middle = frame_by_index(view[Frame_Middle]); const Plot_Frame* painting = frame_by_index(view[Frame_Painting]); @@ -157,40 +157,40 @@ Plot_Frame_Pipeline::Frame_Consume_Result Plot_Frame_Pipeline::try_begin_paint(s }, [this, &result, now_ns](const Triple_Buffer_View& old_view, const Triple_Buffer_View&) { Plot_Frame* old_painting = frame_by_index(old_view[Frame_Painting]); Plot_Frame* new_painting = frame_by_index(old_view[Frame_Middle]); - result.new_frame = true; + result.has_new_frame = true; if (old_painting->metadata && old_painting->metadata->frame_id && old_painting->metadata->paint_end_ns) { old_painting->metadata->transition_32_ns = now_ns; old_painting->metadata->wait_32_ns = now_ns > old_painting->metadata->paint_end_ns ? now_ns - old_painting->metadata->paint_end_ns : 0; - result.returned_frame = old_painting->metadata; + result.returned_frame_record = old_painting->metadata; } new_painting->metadata->transition_23_ns = now_ns; new_painting->metadata->wait_23_ns = now_ns > new_painting->metadata->transition_12_ns ? now_ns - new_painting->metadata->transition_12_ns : 0; }); if (swap.result != Triple_Buffer_Result::Success) { - result.paint_acquire_dropped = true; - ++attempts.paint_role_busy_count; + result.paint_frame_unavailable = true; + ++attempt_counters.paint_role_busy_count; } } auto record = frame_control.try_acquire_role(Frame_Painting); if (record.result == Triple_Buffer_Result::Success) { result.lease = {frame_by_index(record.lease.index), &frame_control, record.lease}; - result.update_was_pending = pending && paint_request_pending.exchange(false, std::memory_order_acq_rel); + result.present_request_was_pending = pending && paint_request_pending.exchange(false, std::memory_order_acq_rel); } else { - result.paint_acquire_dropped = true; - ++attempts.paint_role_busy_count; + result.paint_frame_unavailable = true; + ++attempt_counters.paint_role_busy_count; } return result; } -bool Plot_Frame_Pipeline::middle_has_new_frame() const { +bool Plot_Frame_Pipeline::middle_frame_ready() const { const Plot_Frame* middle = frame_by_role(Frame_Middle); const Plot_Frame* painting = frame_by_role(Frame_Painting); return buffer_version_newer(middle->version.load(std::memory_order_acquire), painting->version.load(std::memory_order_acquire)); } -bool Plot_Frame_Pipeline::paint_active() const { +bool Plot_Frame_Pipeline::painting_frame_in_use() const { return frame_control.role_busy(Frame_Painting); } diff --git a/Core/plot/Plot_Frame_Pipeline.h b/Core/plot/Plot_Frame_Pipeline.h index 24706ed..522e26d 100644 --- a/Core/plot/Plot_Frame_Pipeline.h +++ b/Core/plot/Plot_Frame_Pipeline.h @@ -10,16 +10,12 @@ #include #include #include - namespace renderive { - struct Update_State; - -enum class Plot_Render_Job_State { +enum class Frame_Job_State { Idle, Running }; - struct Plot_Frame { Plot_Frame(); std::atomic version{0}; @@ -27,7 +23,6 @@ struct Plot_Frame { std::pmr::vector> presented_update_states; std::shared_ptr metadata; }; - struct Plot_Frame_Lease : Move_Only { Plot_Frame_Lease() = default; Plot_Frame_Lease(Plot_Frame* buffer, Triple_Role_Buffer_Control* control, Triple_Buffer_Lease lease); @@ -42,53 +37,47 @@ struct Plot_Frame_Lease : Move_Only { return frame && lease; } }; - class Plot_Frame_Pipeline { public: struct Frame_Publish_Result { Rect dirty_rect; - std::shared_ptr superseded_middle; - std::shared_ptr dropped_frame; + std::shared_ptr superseded_frame_record; + std::shared_ptr dropped_frame_record; std::uint64_t update_request_id{}; std::uint64_t update_request_time{}; bool request_present{}; }; - struct Frame_Consume_Result { Plot_Frame_Lease lease; - std::shared_ptr returned_frame; - bool new_frame{}; - bool update_was_pending{}; - bool paint_acquire_dropped{}; + std::shared_ptr returned_frame_record; + bool has_new_frame{}; + bool present_request_was_pending{}; + bool paint_frame_unavailable{}; }; - Plot_Frame_Pipeline(); ~Plot_Frame_Pipeline(); - - void mark_edit_state(); - [[nodiscard]] bool has_new_state() const; + void advance_edit_version(); + [[nodiscard]] bool has_unrendered_edit() const; [[nodiscard]] Plot_Frame* frame_by_index(std::uint8_t index); [[nodiscard]] const Plot_Frame* frame_by_index(std::uint8_t index) const; [[nodiscard]] Plot_Frame* frame_by_role(std::uint8_t role); [[nodiscard]] const Plot_Frame* frame_by_role(std::uint8_t role) const; - [[nodiscard]] Plot_Frame_Lease try_begin_render(); - [[nodiscard]] Frame_Publish_Result try_publish_rendered(std::uint64_t now_ns); - [[nodiscard]] Frame_Publish_Result request_paint_update(std::uint64_t now_ns); - [[nodiscard]] Frame_Consume_Result try_begin_paint(std::uint64_t now_ns); - [[nodiscard]] bool middle_has_new_frame() const; - [[nodiscard]] bool paint_active() const; + [[nodiscard]] Plot_Frame_Lease try_acquire_render_frame(); + [[nodiscard]] Frame_Publish_Result try_publish_rendered_frame(std::uint64_t now_ns); + [[nodiscard]] Frame_Publish_Result request_present(std::uint64_t now_ns); + [[nodiscard]] Frame_Consume_Result try_acquire_paint_frame(std::uint64_t now_ns); + [[nodiscard]] bool middle_frame_ready() const; + [[nodiscard]] bool painting_frame_in_use() const; void cancel_all_update_states(); - Triple_Role_Buffer_Control frame_control; std::array frames; - std::atomic edit_state_version{1}; - std::uint64_t render_state_version = 0; - Plot_Render_Job_State job_state = Plot_Render_Job_State::Idle; - Frame_Attempt_Accumulator attempts; + std::atomic edit_version{1}; + std::uint64_t rendered_edit_version = 0; + Frame_Job_State render_job_state = Frame_Job_State::Idle; + Frame_Attempt_Accumulator attempt_counters; std::atomic_bool paint_request_pending{false}; - std::atomic pending_update_request_id{0}; - std::atomic pending_update_request_time{0}; - std::uint64_t next_update_request_id{}; + std::atomic pending_present_request_id{0}; + std::atomic pending_present_request_time_ns{0}; + std::uint64_t next_present_request_id{}; }; - } // namespace renderive diff --git a/Core/plot/Present_Frame.cpp b/Core/plot/Present_Frame.cpp deleted file mode 100644 index b8d8562..0000000 --- a/Core/plot/Present_Frame.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "Present_Frame.h" - -namespace renderive { - -Present_Frame::Present_Frame() = default; -Present_Frame::Present_Frame(Present_Frame&&) noexcept = default; -Present_Frame& Present_Frame::operator=(Present_Frame&&) noexcept = default; -Present_Frame::~Present_Frame() = default; - -Present_Frame::operator bool() const { - return lease_ && lease_->operator bool(); -} - -bool Present_Frame::new_frame() const { - return is_new_frame; -} - -bool Present_Frame::request_was_pending() const { - return update_was_pending; -} - -Image_View Present_Frame::image() const { - if (!lease_ || !lease_->frame) - return {}; - return lease_->frame->image.view(); -} - -} // namespace renderive diff --git a/Core/plot/Present_Frame_Lease.cpp b/Core/plot/Present_Frame_Lease.cpp new file mode 100644 index 0000000..96d14d4 --- /dev/null +++ b/Core/plot/Present_Frame_Lease.cpp @@ -0,0 +1,21 @@ +#include "Present_Frame_Lease.h" +namespace renderive { +Present_Frame_Lease::Present_Frame_Lease() = default; +Present_Frame_Lease::Present_Frame_Lease(Present_Frame_Lease&&) noexcept = default; +Present_Frame_Lease& Present_Frame_Lease::operator=(Present_Frame_Lease&&) noexcept = default; +Present_Frame_Lease::~Present_Frame_Lease() = default; +Present_Frame_Lease::operator bool() const { + return lease_ && lease_->operator bool(); +} +bool Present_Frame_Lease::new_frame() const { + return is_new_frame; +} +bool Present_Frame_Lease::request_was_pending() const { + return update_was_pending; +} +Image_View Present_Frame_Lease::image() const { + if (!lease_ || !lease_->frame) + return {}; + return lease_->frame->image.view(); +} +} // namespace renderive diff --git a/Core/plot/Present_Frame.h b/Core/plot/Present_Frame_Lease.h similarity index 70% rename from Core/plot/Present_Frame.h rename to Core/plot/Present_Frame_Lease.h index fa15b70..b30ceb4 100644 --- a/Core/plot/Present_Frame.h +++ b/Core/plot/Present_Frame_Lease.h @@ -3,26 +3,21 @@ #include "../render/Image_View.h" #include #include - namespace renderive { - -class Present_Frame { +class Present_Frame_Lease { public: - Present_Frame(); - Present_Frame(Present_Frame&&) noexcept; - Present_Frame& operator=(Present_Frame&&) noexcept; - ~Present_Frame(); - + Present_Frame_Lease(); + Present_Frame_Lease(Present_Frame_Lease&&) noexcept; + Present_Frame_Lease& operator=(Present_Frame_Lease&&) noexcept; + ~Present_Frame_Lease(); [[nodiscard]] explicit operator bool() const; [[nodiscard]] bool new_frame() const; [[nodiscard]] bool request_was_pending() const; [[nodiscard]] Image_View image() const; - private: friend class Plot_Core; std::unique_ptr lease_; bool is_new_frame{}; bool update_was_pending{}; }; - } // namespace renderive diff --git a/Core/plottable/Afterglow.cpp b/Core/plottable/Afterglow.cpp index f69ae9a..8d0fd2c 100644 --- a/Core/plottable/Afterglow.cpp +++ b/Core/plottable/Afterglow.cpp @@ -34,28 +34,28 @@ void Afterglow::set_power_range(Range value) { edit->color_scale.set_range(value); } int Afterglow::frequency_point_size() { - return d()->edit_state_value(&Afterglow_Render_State::frequency_point_size); + return d()->edit_state_value(&Afterglow_Render_State::frequency_bin_count); } int Afterglow::power_point_size() { - return d()->edit_state_value(&Afterglow_Render_State::power_point_size); + return d()->edit_state_value(&Afterglow_Render_State::power_bin_count); } bool Afterglow::interpolate() { - return d()->edit_state_value(&Afterglow_Render_State::interpolate); + return d()->edit_state_value(&Afterglow_Render_State::interpolate_power_bins); } void Afterglow::set_interpolate(bool value) { - d()->set_state_value(&Afterglow_Render_State::interpolate, value); + d()->set_state_value(&Afterglow_Render_State::interpolate_power_bins, value); } double Afterglow::attenuation_rate() { - return d()->edit_state_value(&Afterglow_Render_State::attenuation_rate); + return d()->edit_state_value(&Afterglow_Render_State::decay_rate); } void Afterglow::set_attenuation_rate(double value) { - d()->set_state_value(&Afterglow_Render_State::attenuation_rate, std::clamp(value, 0.0, 1.0)); + d()->set_state_value(&Afterglow_Render_State::decay_rate, std::clamp(value, 0.0, 1.0)); } int Afterglow::init_strong_value() { - return d()->edit_state_value(&Afterglow_Render_State::init_strong_value); + return d()->edit_state_value(&Afterglow_Render_State::initial_intensity_threshold); } void Afterglow::set_init_strong_value(int value) { - d()->set_state_value(&Afterglow_Render_State::init_strong_value, std::max(1, value)); + d()->set_state_value(&Afterglow_Render_State::initial_intensity_threshold, std::max(1, value)); } Color_Map Afterglow::color_map() { return d()->edit_state_value(&Afterglow_Render_State::color_scale).color_map(); @@ -65,19 +65,19 @@ void Afterglow::set_color_map(Color_Map value) { edit->color_scale.set_color_map(std::move(value)); } std::shared_ptr Afterglow::color_bar() const { - return const_cast(this)->d()->color_bar_item.lock(); + return const_cast(this)->d()->color_bar.lock(); } void Afterglow::set_frequency_point_size(int t) { Afterglow_Private* pd = d(); Render_Edit_Lease edit(pd); - edit->frequency_point_size = std::max(1, t); - edit->power_point_size = std::max(1, edit->power_point_size); + edit->frequency_bin_count = std::max(1, t); + edit->power_bin_count = std::max(1, edit->power_bin_count); } void Afterglow::set_power_point_size(int t) { Afterglow_Private* pd = d(); Render_Edit_Lease edit(pd); - edit->frequency_point_size = std::max(1, edit->frequency_point_size); - edit->power_point_size = std::max(1, t); + edit->frequency_bin_count = std::max(1, edit->frequency_bin_count); + edit->power_bin_count = std::max(1, t); } Afterglow::Builder::Builder(std::shared_ptr parent, std::shared_ptr frequency_axis, std::shared_ptr power_axis) { init(parent, frequency_axis, power_axis); @@ -87,65 +87,65 @@ std::shared_ptr Afterglow::Builder::build() { set(ret.get()); return ret; } -void Afterglow::give_data(std::span power_range_data) { +void Afterglow::append_spectrum(std::span power_range_data) { if (!ok()) return; Afterglow_Private* pd = d(); int frequency_point_size{}; { Render_State_Lease state(pd); - frequency_point_size = state->frequency_point_size; + frequency_point_size = state->frequency_bin_count; } if (power_range_data.size() != frequency_point_size) return; Render_Input_Lease input(pd); - input->data_list.push(power_range_data, Afterglow_Input_Data::Max_Pending_Frame_Count); + input->pending_spectra.push(power_range_data, Afterglow_Input_Data::Max_Pending_Frame_Count); } -void Afterglow::give_data(std::pmr::vector&& power_range_data) { +void Afterglow::append_spectrum(std::pmr::vector&& power_range_data) { if (!ok()) return; Afterglow_Private* pd = d(); int frequency_point_size{}; { Render_State_Lease state(pd); - frequency_point_size = state->frequency_point_size; + frequency_point_size = state->frequency_bin_count; } if (power_range_data.size() != frequency_point_size) return; Render_Input_Lease input(pd); - input->data_list.push(std::move(power_range_data), Afterglow_Input_Data::Max_Pending_Frame_Count); + input->pending_spectra.push(std::move(power_range_data), Afterglow_Input_Data::Max_Pending_Frame_Count); } void Afterglow_Private::push_data(std::span power_range_data, const Afterglow_Render_State* s, const Color_Scale_Snapshot& color_scale) { - if (power_range_data.size() != s->frequency_point_size || - s->init_strong_value <= 0 || + if (power_range_data.size() != s->frequency_bin_count || + s->initial_intensity_threshold <= 0 || color_scale.range.size() == 0.0 || - s->frequency_point_size <= 0 || - s->power_point_size <= 0) + s->frequency_bin_count <= 0 || + s->power_bin_count <= 0) return; - std::pmr::vector index_list(s->frequency_point_size, frame_memory_resource()); - double rate = (double)s->power_point_size / color_scale.range.size(); - for (int i = 0; i < s->frequency_point_size; ++i) { + std::pmr::vector index_list(s->frequency_bin_count, frame_memory_resource()); + double rate = (double)s->power_bin_count / color_scale.range.size(); + for (int i = 0; i < s->frequency_bin_count; ++i) { int line_index = (int)((power_range_data[i] - color_scale.range.origin) * rate); if (line_index < 0) line_index = 0; - if (line_index > s->power_point_size - 1) - line_index = s->power_point_size - 1; + if (line_index > s->power_bin_count - 1) + line_index = s->power_bin_count - 1; index_list[i] = line_index; } - if (!s->interpolate) { - for (int i = 0; i < s->frequency_point_size; ++i) { - int index = index_list[i] * s->frequency_point_size + i; - cached_power_data[index]++; + if (!s->interpolate_power_bins) { + for (int i = 0; i < s->frequency_bin_count; ++i) { + int index = index_list[i] * s->frequency_bin_count + i; + current_intensity_grid[index]++; } } else { int last_lower = -1, last_upper = -1; - for (int i = 0; i < s->frequency_point_size; ++i) { + for (int i = 0; i < s->frequency_bin_count; ++i) { int y = index_list[i]; - cached_power_data[y * s->frequency_point_size + i]++; + current_intensity_grid[y * s->frequency_bin_count + i]++; if (y - last_upper >= 2) { for (int cur_y = last_upper + 1; cur_y < y; ++cur_y) { - cached_power_data[cur_y * s->frequency_point_size + i]++; + current_intensity_grid[cur_y * s->frequency_bin_count + i]++; } last_upper = y; last_lower = last_lower + 1; @@ -153,7 +153,7 @@ void Afterglow_Private::push_data(std::span power_range_data, cons } if (last_lower - y >= 2) { for (int cur_y = y + 1; cur_y < last_lower; ++cur_y) { - cached_power_data[cur_y * s->frequency_point_size + i]++; + current_intensity_grid[cur_y * s->frequency_bin_count + i]++; } last_upper = last_lower - 1; last_lower = y; @@ -163,17 +163,17 @@ void Afterglow_Private::push_data(std::span power_range_data, cons last_lower = y; } } - cur_index++; - if (cur_index < s->init_strong_value) + current_history_index++; + if (current_history_index < s->initial_intensity_threshold) return; - cur_index = 0; - double old_remain = s->attenuation_rate == 1.0 ? 1.0 : 1.0 - s->attenuation_rate; - double cache_remain = s->attenuation_rate / (double)s->init_strong_value; - for (int i = 0; i < cache_buffer_buffer_size; ++i) { - merged_power_data[i] = old_remain * old_cache_power_data[i] + cache_remain * cached_power_data[i]; - cached_power_data[i] = 0; + current_history_index = 0; + double old_remain = s->decay_rate == 1.0 ? 1.0 : 1.0 - s->decay_rate; + double cache_remain = s->decay_rate / (double)s->initial_intensity_threshold; + for (int i = 0; i < cached_cell_count; ++i) { + merged_intensity_grid[i] = old_remain * previous_intensity_grid[i] + cache_remain * current_intensity_grid[i]; + current_intensity_grid[i] = 0; } - old_cache_power_data = merged_power_data; - cache_image_dirty = true; + previous_intensity_grid = merged_intensity_grid; + image_dirty = true; } } // namespace renderive diff --git a/Core/plottable/Afterglow.h b/Core/plottable/Afterglow.h index c2ae4cb..132db3e 100644 --- a/Core/plottable/Afterglow.h +++ b/Core/plottable/Afterglow.h @@ -41,16 +41,16 @@ public: /// @brief 返回构造时启用的颜色条。 std::shared_ptr color_bar() const; /// @brief 写入一帧功率数据。 - void give_data(std::span power_range_data); + void append_spectrum(std::span power_range_data); /// @brief 移动写入一帧功率数据。 - void give_data(std::pmr::vector&& power_range_data); + void append_spectrum(std::pmr::vector&& power_range_data); /// @brief 用 writer 填充并写入一帧功率数据。 template void write_data(std::size_t count, Writer&& writer) { std::pmr::vector values(memory_resource(Memory_Domain::Afterglow)); values.resize(count); std::forward(writer)(std::span(values.data(), values.size())); - give_data(std::move(values)); + append_spectrum(std::move(values)); } template struct Builder_T; @@ -65,11 +65,11 @@ struct Afterglow_Prop { std::weak_ptr frequency_axis{}; std::weak_ptr power_axis{}; Range frequency_range{0, 10}; - int frequency_point_size{}; - int power_point_size{}; - bool interpolate = true; - double attenuation_rate = 0.2; - int init_strong_value = 100; + int frequency_bin_count{}; + int power_bin_count{}; + bool interpolate_power_bins = true; + double decay_rate = 0.2; + int initial_intensity_threshold = 100; Color_Scale color_scale{Color_Map{}, Range{0, 10}}; bool color_bar_enabled = false; }; @@ -82,11 +82,11 @@ struct Afterglow::Builder_T { static_cast(this)->color_scale.set_range(value); return *static_cast(this); } - PROP_BT(int, frequency_point_size) - PROP_BT(int, power_point_size) - PROP_BT(bool, interpolate) - PROP_BT(double, attenuation_rate) - PROP_BT(int, init_strong_value) + PROP_BT(int, frequency_bin_count) + PROP_BT(int, power_bin_count) + PROP_BT(bool, interpolate_power_bins) + PROP_BT(double, decay_rate) + PROP_BT(int, initial_intensity_threshold) That& set_color_map(Color_Map value) { static_cast(this)->color_scale.set_color_map(std::move(value)); return *static_cast(this); diff --git a/Core/plottable/Afterglow_p.h b/Core/plottable/Afterglow_p.h index e315ff9..c8d3d4d 100644 --- a/Core/plottable/Afterglow_p.h +++ b/Core/plottable/Afterglow_p.h @@ -14,34 +14,34 @@ namespace renderive { struct Afterglow_Render_State : Render_State, Afterglow_Prop {}; struct Afterglow_Input_Data : Input_Data { static constexpr std::size_t Max_Pending_Frame_Count = 4; - Bounded_Vector_Double_Input_Buffer data_list; + Bounded_Vector_Double_Input_Buffer pending_spectra; void clear() override { - data_list.clear(); + pending_spectra.clear(); } }; struct Afterglow_Private : Typed_Render_Data { Raster_Image_Buffer image; - std::weak_ptr color_bar_item; - bool cache_image_dirty = false; - int cur_index = 0; - int cache_frequency_point_size{}; - int cache_power_point_point_size{}; - int cache_buffer_buffer_size{}; + std::weak_ptr color_bar; + bool image_dirty = false; + int current_history_index = 0; + int cached_frequency_bin_count{}; + int cached_power_bin_count{}; + int cached_cell_count{}; std::uint64_t cache_color_map_hash{}; - std::pmr::vector cached_power_data{memory_resource(Memory_Domain::Afterglow)}; - std::pmr::vector old_cache_power_data{memory_resource(Memory_Domain::Afterglow)}; - std::pmr::vector merged_power_data{memory_resource(Memory_Domain::Afterglow)}; + std::pmr::vector current_intensity_grid{memory_resource(Memory_Domain::Afterglow)}; + std::pmr::vector previous_intensity_grid{memory_resource(Memory_Domain::Afterglow)}; + std::pmr::vector merged_intensity_grid{memory_resource(Memory_Domain::Afterglow)}; void update_cache_size(int frequency_point_size, int power_point_size) { - cache_frequency_point_size = frequency_point_size; - cache_power_point_point_size = power_point_size; - cache_buffer_buffer_size = frequency_point_size * power_point_size; - cached_power_data.resize(cache_buffer_buffer_size); - std::fill(cached_power_data.begin(), cached_power_data.end(), 0.0); - old_cache_power_data.resize(cache_buffer_buffer_size); - std::fill(old_cache_power_data.begin(), old_cache_power_data.end(), 0.0); - merged_power_data.resize(cache_buffer_buffer_size); - std::fill(merged_power_data.begin(), merged_power_data.end(), 0.0); - cur_index = 0; + cached_frequency_bin_count = frequency_point_size; + cached_power_bin_count = power_point_size; + cached_cell_count = frequency_point_size * power_point_size; + current_intensity_grid.resize(cached_cell_count); + std::fill(current_intensity_grid.begin(), current_intensity_grid.end(), 0.0); + previous_intensity_grid.resize(cached_cell_count); + std::fill(previous_intensity_grid.begin(), previous_intensity_grid.end(), 0.0); + merged_intensity_grid.resize(cached_cell_count); + std::fill(merged_intensity_grid.begin(), merged_intensity_grid.end(), 0.0); + current_history_index = 0; } void push_data(std::span power_range_data, const Afterglow_Render_State* s, const Color_Scale_Snapshot& color_scale); void draw_image(Canvas& canvas, const Afterglow_Render_State* s, const Color_Scale_Snapshot& color_scale) { @@ -72,33 +72,33 @@ struct Afterglow_Private : Typed_Render_Datafrequency_point_size <= 0 || s->power_point_size <= 0) + if (s->frequency_bin_count <= 0 || s->power_bin_count <= 0) return; auto color_scale = s->color_scale.snapshot(); - if (cache_frequency_point_size != s->frequency_point_size || cache_power_point_point_size != s->power_point_size) { - update_cache_size(s->frequency_point_size, s->power_point_size); + if (cached_frequency_bin_count != s->frequency_bin_count || cached_power_bin_count != s->power_bin_count) { + update_cache_size(s->frequency_bin_count, s->power_bin_count); } - bool image_size_changed = image.width() != s->frequency_point_size || image.height() != s->power_point_size; + bool image_size_changed = image.width() != s->frequency_bin_count || image.height() != s->power_bin_count; std::uint64_t color_map_hash = color_scale->color_map.hash(); if (cache_color_map_hash != color_map_hash) { cache_color_map_hash = color_map_hash; - cache_image_dirty = true; + image_dirty = true; } if (image_size_changed) { - image.resize(s->frequency_point_size, s->power_point_size); + image.resize(s->frequency_bin_count, s->power_bin_count); image.fill(Color::transparent()); - cache_image_dirty = true; + image_dirty = true; } Afterglow_Input_Data* input = render_input_data(); - input->data_list.read_all([this, s, color_scale](const auto& data) { - if (data.size() != s->frequency_point_size) { + input->pending_spectra.read_all([this, s, color_scale](const auto& data) { + if (data.size() != s->frequency_bin_count) { return; } push_data(data, s, *color_scale); }); - if (cache_image_dirty) { - image.write_normalized_grid(old_cache_power_data.data(), s->frequency_point_size, s->power_point_size, color_scale->color_map); - cache_image_dirty = false; + if (image_dirty) { + image.write_normalized_grid(previous_intensity_grid.data(), s->frequency_bin_count, s->power_bin_count, color_scale->color_map); + image_dirty = false; } clear_render_input(); } @@ -124,19 +124,19 @@ void Afterglow::Builder_T::set(Afterglow* ret) { PROP_RT(std::weak_ptr, frequency_axis) PROP_RT(std::weak_ptr, power_axis) PROP_RT(Range, frequency_range) - PROP_RT(int, frequency_point_size) - PROP_RT(int, power_point_size) - PROP_RT(bool, interpolate) - PROP_RT(double, attenuation_rate) - PROP_RT(int, init_strong_value) + PROP_RT(int, frequency_bin_count) + PROP_RT(int, power_bin_count) + PROP_RT(bool, interpolate_power_bins) + PROP_RT(double, decay_rate) + PROP_RT(int, initial_intensity_threshold) sc->color_scale = static_cast(this)->color_scale.clone(); - sc->frequency_point_size = std::max(1, sc->frequency_point_size); - sc->power_point_size = std::max(1, sc->power_point_size); - sc->attenuation_rate = std::clamp(sc->attenuation_rate, 0.0, 1.0); - sc->init_strong_value = std::max(1, sc->init_strong_value); + sc->frequency_bin_count = std::max(1, sc->frequency_bin_count); + sc->power_bin_count = std::max(1, sc->power_bin_count); + sc->decay_rate = std::clamp(sc->decay_rate, 0.0, 1.0); + sc->initial_intensity_threshold = std::max(1, sc->initial_intensity_threshold); if (static_cast(this)->color_bar_enabled) { auto bar = Color_Bar::Builder(owner).set_color_scale(sc->color_scale).set_name("Afterglow").build(); - pd->color_bar_item = bar; + pd->color_bar = bar; } } } // namespace renderive diff --git a/Core/plottable/Planisphere.cpp b/Core/plottable/Constellation_Diagram.cpp similarity index 60% rename from Core/plottable/Planisphere.cpp rename to Core/plottable/Constellation_Diagram.cpp index 607a5e6..258ec33 100644 --- a/Core/plottable/Planisphere.cpp +++ b/Core/plottable/Constellation_Diagram.cpp @@ -2,74 +2,74 @@ #include #include "../Axis/Abs_Axis_p.h" #include "../base/Memory.h" -#include "Planisphere_p.h" +#include "Constellation_Diagram_p.h" namespace renderive { -RENDERIVE_DEFINE_RENDERABLE_BINDING(Planisphere, Planisphere_Private, Planisphere_Render_State, Planisphere_Input_Data, "Planisphere") -std::shared_ptr Planisphere::i_axis() { +RENDERIVE_DEFINE_RENDERABLE_BINDING(Constellation_Diagram, Constellation_Diagram_Private, Planisphere_Render_State, Planisphere_Input_Data, "Planisphere") +std::shared_ptr Constellation_Diagram::i_axis() { return d()->edit_state_value(&Planisphere_Render_State::i_axis).lock(); } -void Planisphere::set_i_axis(std::shared_ptr value) { +void Constellation_Diagram::set_i_axis(std::shared_ptr value) { d()->set_state_value(&Planisphere_Render_State::i_axis, std::weak_ptr(value)); } -std::shared_ptr Planisphere::q_axis() { +std::shared_ptr Constellation_Diagram::q_axis() { return d()->edit_state_value(&Planisphere_Render_State::q_axis).lock(); } -void Planisphere::set_q_axis(std::shared_ptr value) { +void Constellation_Diagram::set_q_axis(std::shared_ptr value) { d()->set_state_value(&Planisphere_Render_State::q_axis, std::weak_ptr(value)); } -Range Planisphere::i_range() { +Range Constellation_Diagram::i_range() { return d()->edit_state_value(&Planisphere_Render_State::i_range); } -void Planisphere::set_i_range(Range value) { +void Constellation_Diagram::set_i_range(Range value) { if (value.length() == 0.0) return; d()->set_state_value(&Planisphere_Render_State::i_range, std::move(value)); } -Range Planisphere::q_range() { +Range Constellation_Diagram::q_range() { return d()->edit_state_value(&Planisphere_Render_State::q_range); } -void Planisphere::set_q_range(Range value) { +void Constellation_Diagram::set_q_range(Range value) { if (value.length() == 0.0) return; d()->set_state_value(&Planisphere_Render_State::q_range, std::move(value)); } -Color Planisphere::point_color() { +Color Constellation_Diagram::point_color() { return d()->edit_state_value(&Planisphere_Render_State::point_color); } -void Planisphere::set_point_color(Color value) { +void Constellation_Diagram::set_point_color(Color value) { d()->set_state_value(&Planisphere_Render_State::point_color, std::move(value)); } -Color Planisphere::anchor_color() { +Color Constellation_Diagram::anchor_color() { return d()->edit_state_value(&Planisphere_Render_State::anchor_color); } -void Planisphere::set_anchor_color(Color value) { +void Constellation_Diagram::set_anchor_color(Color value) { d()->set_state_value(&Planisphere_Render_State::anchor_color, std::move(value)); } -int Planisphere::continue_millisecond() { - return d()->edit_state_value(&Planisphere_Render_State::continue_millisecond); +int Constellation_Diagram::point_lifetime_ms() { + return d()->edit_state_value(&Planisphere_Render_State::point_lifetime_ms); } -void Planisphere::set_continue_millisecond(int value) { - d()->set_state_value(&Planisphere_Render_State::continue_millisecond, std::max(1, value)); +void Constellation_Diagram::set_point_lifetime_ms(int value) { + d()->set_state_value(&Planisphere_Render_State::point_lifetime_ms, std::max(1, value)); } -Planisphere_Type Planisphere::type() { +Constellation_Diagram_Type Constellation_Diagram::type() { return d()->edit_state_value(&Planisphere_Render_State::type); } -void Planisphere::set_type(Planisphere_Type value) { +void Constellation_Diagram::set_type(Constellation_Diagram_Type value) { d()->set_state_value(&Planisphere_Render_State::type, value); } -double Planisphere::phase_offset_radians() { +double Constellation_Diagram::phase_offset_radians() { return d()->edit_state_value(&Planisphere_Render_State::phase_offset_radians); } -void Planisphere::set_phase_offset_radians(double value) { +void Constellation_Diagram::set_phase_offset_radians(double value) { d()->set_state_value(&Planisphere_Render_State::phase_offset_radians, value); } -void Planisphere::give_data(PointF pos) { +void Constellation_Diagram::append_point(PointF pos) { if (!ok()) return; - Render_Input_Lease input(d()); + Render_Input_Lease input(d()); input->push(pos); } -Planisphere::Builder::Builder(std::shared_ptr parent, std::shared_ptr i_axis, std::shared_ptr q_axis) { +Constellation_Diagram::Builder::Builder(std::shared_ptr parent, std::shared_ptr i_axis, std::shared_ptr q_axis) { ASSERT(parent, "Planisphere build error! parent == nullptr"); ASSERT(i_axis && q_axis, "Planisphere build error! axis == nullptr"); ASSERT(i_axis->attached_to_plot(), "Planisphere build error! i_axis->plot == nullptr"); @@ -80,10 +80,10 @@ Planisphere::Builder::Builder(std::shared_ptr parent, std::shared_pt this->i_axis = i_axis; this->q_axis = q_axis; } -std::shared_ptr Planisphere::Builder::build() { - auto ret = renderive::make_shared(); +std::shared_ptr Constellation_Diagram::Builder::build() { + auto ret = renderive::make_shared(); ret->init(parent); - Planisphere_Private* pd = ret->d(); + Constellation_Diagram_Private* pd = ret->d(); Planisphere_Render_State* sc = reinterpret_cast(pd->state(State_Edit)); PROP_R(std::weak_ptr, i_axis) PROP_R(std::weak_ptr, q_axis) @@ -91,29 +91,29 @@ std::shared_ptr Planisphere::Builder::build() { PROP_R(Range, q_range) PROP_R(Color, point_color) PROP_R(Color, anchor_color) - PROP_R(int, continue_millisecond) + PROP_R(int, point_lifetime_ms) PROP_R(Planisphere_Type, type) PROP_R(double, phase_offset_radians) if (sc->i_range.length() == 0.0) sc->i_range = {0.0, 1.0}; if (sc->q_range.length() == 0.0) sc->q_range = {0.0, 1.0}; - sc->continue_millisecond = std::max(1, sc->continue_millisecond); + sc->point_lifetime_ms = std::max(1, sc->point_lifetime_ms); return ret; } -void Planisphere::set_to_axis_center() { +void Constellation_Diagram::fit_square_to_axes() { Planisphere_Render_State* s = reinterpret_cast(d()->state(State_Edit)); auto i_axis = s->i_axis.lock(); auto q_axis = s->q_axis.lock(); if (!i_axis || !q_axis) return; - double w = i_axis->pixel_size(), h = q_axis->pixel_size(); + double w = i_axis->pixel_length(), h = q_axis->pixel_length(); if (w <= 0.0 || h <= 0.0) return; double l = w < h ? w : h; double i_l = i_axis->coord_range().size() / w * l / 2; double q_l = q_axis->coord_range().size() / h * l / 2; - double im = i_axis->coord_range().middle(), qm = q_axis->coord_range().middle(); + double im = i_axis->coord_range().center(), qm = q_axis->coord_range().center(); set_i_range({im - i_l, im + i_l}); set_q_range({qm - q_l, qm + q_l}); } diff --git a/Core/plottable/Planisphere.h b/Core/plottable/Constellation_Diagram.h similarity index 75% rename from Core/plottable/Planisphere.h rename to Core/plottable/Constellation_Diagram.h index 4051436..83118d4 100644 --- a/Core/plottable/Planisphere.h +++ b/Core/plottable/Constellation_Diagram.h @@ -5,7 +5,7 @@ namespace renderive { /// @brief 星座图调制类型。 /// @brief PSK constellation phase-state count. -enum class Planisphere_Type : std::uint8_t { +enum class Constellation_Diagram_Type : std::uint8_t { /// @brief 8PSK 星座图。 /// @brief 4PSK constellation, commonly also called QPSK. Psk4 = 4, @@ -14,15 +14,15 @@ enum class Planisphere_Type : std::uint8_t { /// @brief 16PSK constellation. Psk16 = 16 }; -struct Planisphere_Private; +struct Constellation_Diagram_Private; class Grid; /// @brief I/Q 星座图元。 -class LIB_DECL Planisphere : public Renderable { +class LIB_DECL Constellation_Diagram : public Renderable { public: /// @brief 创建 I/Q 星座图元。 - Planisphere(); + Constellation_Diagram(); /// @brief 写入一个 I/Q 点。 - void give_data(PointF pos); + void append_point(PointF pos); /// @brief 绑定 I 轴。 PROP(std::shared_ptr, i_axis) /// @brief 绑定 Q 轴。 @@ -36,16 +36,16 @@ public: /// @brief 锚点颜色。 PROP(Color, anchor_color) /// @brief 输入点保留时间。 - PROP(int, continue_millisecond) + PROP(int, point_lifetime_ms) /// @brief 星座调制类型。 - PROP(Planisphere_Type, type) + PROP(Constellation_Diagram_Type, type) /// @brief PSK constellation phase offset in radians. PROP(double, phase_offset_radians) /// @brief 设置坐标轴到星座图中心范围。 - void set_to_axis_center(); + void fit_square_to_axes(); struct Builder; private: - Planisphere_Private* d(); + Constellation_Diagram_Private* d(); Render_Object_Owner create_render_data() override; Render_Object_Owner create_render_state() override; Render_Object_Owner create_input_data() override; @@ -55,14 +55,14 @@ struct Planisphere_Prop { std::weak_ptr q_axis{}; Range i_range{0, 100}; Range q_range{0, 100}; - Color point_color = Color::red_color(); + Color point_color = Color::red(); Color anchor_color = Color::yellow(); - int continue_millisecond = 1000; - Planisphere_Type type = Planisphere_Type::Psk8; + int point_lifetime_ms = 1000; + Constellation_Diagram_Type type = Constellation_Diagram_Type::Psk8; double phase_offset_radians = 0.0; }; /// @brief 星座图构造器。 -struct LIB_DECL Planisphere::Builder : Planisphere_Prop { +struct LIB_DECL Constellation_Diagram::Builder : Planisphere_Prop { PROP_B(std::shared_ptr, parent) PROP_B(std::shared_ptr, i_axis) PROP_B(std::shared_ptr, q_axis) @@ -70,13 +70,13 @@ struct LIB_DECL Planisphere::Builder : Planisphere_Prop { PROP_B(Range, q_range) PROP_B(Color, point_color) PROP_B(Color, anchor_color) - PROP_B(int, continue_millisecond) - PROP_B(Planisphere_Type, type) + PROP_B(int, point_lifetime_ms) + PROP_B(Constellation_Diagram_Type, type) PROP_B(double, phase_offset_radians) /// 创建星座图构造器。 Builder(std::shared_ptr parent, std::shared_ptr i_axis, std::shared_ptr q_axis); /// 构建并返回星座图对象。 - std::shared_ptr build(); + std::shared_ptr build(); std::shared_ptr parent{}; }; } // namespace renderive diff --git a/Core/plottable/Planisphere_p.h b/Core/plottable/Constellation_Diagram_p.h similarity index 93% rename from Core/plottable/Planisphere_p.h rename to Core/plottable/Constellation_Diagram_p.h index fde07de..dcd93a5 100644 --- a/Core/plottable/Planisphere_p.h +++ b/Core/plottable/Constellation_Diagram_p.h @@ -14,7 +14,7 @@ #include "../base/Geometry.h" #include "../base/Style.h" #include "../render/Canvas.h" -#include "Planisphere.h" +#include "Constellation_Diagram.h" namespace renderive { struct Planisphere_Data { PointF pos; @@ -46,7 +46,7 @@ struct Planisphere_Input_Data : Input_Data { } }; struct Planisphere_Render_State : Render_State, Planisphere_Prop {}; -struct Planisphere_Private : Typed_Render_Data { +struct Constellation_Diagram_Private : Typed_Render_Data { std::pmr::list data_list{memory_resource(Memory_Domain::Planisphere)}; std::pmr::vector prepared_points{memory_resource(Memory_Domain::Planisphere)}; std::pmr::vector prepared_colors{memory_resource(Memory_Domain::Planisphere)}; @@ -57,8 +57,8 @@ struct Planisphere_Private : Typed_Render_Datai_range.middle(); - const double center_y = s->q_range.middle(); + const double center_x = s->i_range.center(); + const double center_y = s->q_range.center(); const double radius = std::min(s->i_range.size(), s->q_range.size()) / 3.0; points.reserve(order); for (unsigned i = 0; i < order; ++i) { @@ -80,7 +80,7 @@ struct Planisphere_Private : Typed_Render_Data(std::max(1, s->continue_millisecond)) * 1000000ull; + const std::uint64_t lifetime_ns = static_cast(std::max(1, s->point_lifetime_ms)) * 1000000ull; d->read_all([this, now_ns, lifetime_ns](const PointF& pos) { Planisphere_Data data; data.pos = pos; @@ -98,7 +98,7 @@ struct Planisphere_Private : Typed_Render_Datapoint_color; const std::uint64_t total_ns = data.expire_time_ns > data.birth_time_ns ? data.expire_time_ns - data.birth_time_ns : 1; const std::uint64_t remain_ns = data.expire_time_ns > now_ns ? data.expire_time_ns - now_ns : 0; - color.alpha = static_cast(static_cast(color.alpha) * remain_ns / total_ns); + color.a = static_cast(static_cast(color.a) * remain_ns / total_ns); prepared_points.push_back(data.pos); prepared_colors.push_back(color); } @@ -122,7 +122,7 @@ struct Planisphere_Private : Typed_Render_Data Audio_Frequency::time_axis() { +RENDERIVE_DEFINE_RENDERABLE_BINDING(Frequency_Trace, Frequency_Trace_Private, Audio_Frequency_Render_State, Audio_Frequency_Input_Data, "Audio_Frequency") +std::shared_ptr Frequency_Trace::time_axis() { return d()->edit_state_value(&Audio_Frequency_Render_State::time_axis).lock(); } -void Audio_Frequency::set_time_axis(std::shared_ptr value) { +void Frequency_Trace::set_time_axis(std::shared_ptr value) { d()->set_state_value(&Audio_Frequency_Render_State::time_axis, std::weak_ptr(value)); } -std::shared_ptr Audio_Frequency::value_axis() { +std::shared_ptr Frequency_Trace::value_axis() { return d()->edit_state_value(&Audio_Frequency_Render_State::value_axis).lock(); } -void Audio_Frequency::set_value_axis(std::shared_ptr value) { +void Frequency_Trace::set_value_axis(std::shared_ptr value) { d()->set_state_value(&Audio_Frequency_Render_State::value_axis, std::weak_ptr(value)); } -Audio_Frequency::Builder::Builder(std::shared_ptr parent, std::shared_ptr time_axis, std::shared_ptr value_axis) { +Frequency_Trace::Builder::Builder(std::shared_ptr parent, std::shared_ptr time_axis, std::shared_ptr value_axis) { ASSERT(parent && parent->attached_to_plot(), "Audio_Frequency build error! parent invalid"); ASSERT(time_axis && value_axis, "Audio_Frequency build error! axis == nullptr"); ASSERT(time_axis->attached_to_plot(), "Audio_Frequency build error! time_axis->plot == nullptr"); @@ -26,23 +26,23 @@ Audio_Frequency::Builder::Builder(std::shared_ptr parent, std::share this->time_axis = time_axis; this->value_axis = value_axis; } -std::shared_ptr Audio_Frequency::Builder::build() { - auto ret = renderive::make_shared(); +std::shared_ptr Frequency_Trace::Builder::build() { + auto ret = renderive::make_shared(); ret->init(parent); - Audio_Frequency_Private* pd = ret->d(); + Frequency_Trace_Private* pd = ret->d(); Audio_Frequency_Render_State* sc = reinterpret_cast(pd->state(State_Edit)); PROP_R(std::weak_ptr, time_axis) PROP_R(std::weak_ptr, value_axis) sc->pen = Pen{.color = color, .width = 1.0}; return ret; } -void Audio_Frequency::give_data(int tick, double data) { +void Frequency_Trace::append_sample(int tick, double data) { if (!ok()) return; - Render_Input_Lease input(d()); + Render_Input_Lease input(d()); input->push(tick, data); } -void Audio_Frequency::give_data(Time_Of_Day time, double data) { +void Frequency_Trace::append_sample(Time_Of_Day time, double data) { if (!ok()) return; auto axis = time_axis(); @@ -51,8 +51,8 @@ void Audio_Frequency::give_data(Time_Of_Day time, double data) { auto stream = axis->timeline_stream(); if (!stream) return; - int tick = stream->push_time(time); - Render_Input_Lease input(d()); + int tick = stream->append_time(time); + Render_Input_Lease input(d()); input->push(tick, data); } } // namespace renderive diff --git a/Core/plottable/Audio_Frequency.h b/Core/plottable/Frequency_Trace.h similarity index 78% rename from Core/plottable/Audio_Frequency.h rename to Core/plottable/Frequency_Trace.h index 621b563..202fdc9 100644 --- a/Core/plottable/Audio_Frequency.h +++ b/Core/plottable/Frequency_Trace.h @@ -6,16 +6,16 @@ #include "global.h" namespace renderive { class Time_Axis; -struct Audio_Frequency_Private; +struct Frequency_Trace_Private; /// @brief 音频频率随时间变化的折线图元。 -class LIB_DECL Audio_Frequency : public Renderable { +class LIB_DECL Frequency_Trace : public Renderable { public: /// @brief 创建音频频率图元。 - Audio_Frequency(); + Frequency_Trace(); /// @brief 写入指定 tick 对应的音频频率值。 - void give_data(int tick, double data); + void append_sample(int tick, double data); /// @brief 写入指定时间对应的音频频率值。 - void give_data(Time_Of_Day time, double data); + void append_sample(Time_Of_Day time, double data); /// @brief 绑定时间轴。 PROP(std::shared_ptr, time_axis) /// @brief 绑定数值轴。 @@ -23,24 +23,24 @@ public: /// @brief 曲线颜色。 struct Builder; private: - Audio_Frequency_Private* d(); + Frequency_Trace_Private* d(); Render_Object_Owner create_render_data() override; Render_Object_Owner create_render_state() override; Render_Object_Owner create_input_data() override; }; -struct Audio_Frequency_Prop { +struct Frequency_Trace_Prop { std::weak_ptr time_axis; std::weak_ptr value_axis{}; Pen pen{.color = Color::yellow(), .width = 1.0}; }; -struct LIB_DECL Audio_Frequency::Builder : Audio_Frequency_Prop { +struct LIB_DECL Frequency_Trace::Builder : Frequency_Trace_Prop { PROP_B(std::shared_ptr, time_axis) PROP_B(std::shared_ptr, value_axis) PROP_B(Color, color) /// 创建音频频率构造器。 Builder(std::shared_ptr parent, std::shared_ptr time_axis, std::shared_ptr value_axis); /// 构建并返回音频频率对象。 - std::shared_ptr build(); + std::shared_ptr build(); std::shared_ptr parent{}; Color color = Color::yellow(); }; diff --git a/Core/plottable/Audio_Frequency_p.h b/Core/plottable/Frequency_Trace_p.h similarity index 94% rename from Core/plottable/Audio_Frequency_p.h rename to Core/plottable/Frequency_Trace_p.h index 42cad1b..ba561aa 100644 --- a/Core/plottable/Audio_Frequency_p.h +++ b/Core/plottable/Frequency_Trace_p.h @@ -9,7 +9,7 @@ #include "../base/Memory.h" #include "../primitive/Curve_Utils_p.h" #include "Psc_Cpp_Core/Base/RingBuffer.hpp" -#include "Audio_Frequency.h" +#include "Frequency_Trace.h" namespace renderive { struct Audio_Frequency_Data { int tick{}; @@ -35,8 +35,8 @@ struct Audio_Frequency_Input_Data : Input_Data { data_list.clear(); } }; -struct Audio_Frequency_Render_State : Render_State, Audio_Frequency_Prop {}; -struct Audio_Frequency_Private : Typed_Render_Data { +struct Audio_Frequency_Render_State : Render_State, Frequency_Trace_Prop {}; +struct Frequency_Trace_Private : Typed_Render_Data { Psc::StreamRingBuffer_ST buffer{memory_resource(Memory_Domain::Audio)}; std::pmr::vector data_snapshot{memory_resource(Memory_Domain::Audio)}; std::pmr::vector prepared_points{memory_resource(Memory_Domain::Audio)}; diff --git a/Core/plottable/Hover_Info.h b/Core/plottable/Hover_Info.h deleted file mode 100644 index 00ae6d8..0000000 --- a/Core/plottable/Hover_Info.h +++ /dev/null @@ -1,166 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include "../Axis/export.h" -#include "../base/Color.h" -#include "../base/Geometry.h" -#include "../base/Style.h" -#include "../base/Text.h" -#include "../render/Canvas.h" -namespace renderive { -struct Hover_Info_Render_State; -struct Hover_Info_Renderable_Interface; -struct LIB_DECL Hover_Info_Render_State { - virtual ~Hover_Info_Render_State() = default; - Hover_Info_Render_State() { - hover_info_brush = Brush{Color::white(), Brush_Style::Solid}; - hover_info_pen = Pen{Color::black()}; - } - int hover_info_left = 4; - int hover_info_top = 4; - int hover_info_right = 4; - int hover_info_bottom = 4; - Brush hover_info_brush; - Font hover_info_font; - Pen hover_info_pen; - bool use_hover_info = true; - bool hover_info_active = false; - Point hover_info_pos; - void draw_hover(Canvas* canvas, Abs_Axis* h, Abs_Axis* v, Hover_Info_Renderable_Interface* renderable); - bool hover_ok(Renderable* able) const; -}; -struct LIB_DECL Hover_Info_Renderable_Interface { - struct Hover_Edit { - Hover_Edit() = default; - Hover_Edit(Hover_Info_Renderable_Interface* owner, Hover_Info_Render_State* state, std::function on_finish) - : owner(owner), state(state), on_finish(std::move(on_finish)) {} - Hover_Edit(const Hover_Edit&) = delete; - Hover_Edit& operator=(const Hover_Edit&) = delete; - Hover_Edit(Hover_Edit&& other) noexcept - : owner(std::exchange(other.owner, nullptr)), - state(std::exchange(other.state, nullptr)), - on_finish(std::move(other.on_finish)) {} - Hover_Edit& operator=(Hover_Edit&& other) noexcept { - if (this == &other) - return *this; - finish(); - owner = std::exchange(other.owner, nullptr); - state = std::exchange(other.state, nullptr); - on_finish = std::move(other.on_finish); - return *this; - } - ~Hover_Edit() { - finish(); - } - Hover_Info_Render_State* operator->() const { - return state; - } - private: - void finish() { - if (!owner) - return; - if (on_finish) - on_finish(); - on_finish = {}; - owner = nullptr; - state = nullptr; - } - Hover_Info_Renderable_Interface* owner{}; - Hover_Info_Render_State* state{}; - std::function on_finish{}; - }; - virtual std::vector create_hover_string(Abs_Axis* h, Abs_Axis* v, Point pos); - virtual ~Hover_Info_Renderable_Interface() = default; - virtual void draw_hover(Canvas* canvas, Abs_Axis* h, Abs_Axis* v) { - return hover_render_state()->draw_hover(canvas, h, v, this); - } - virtual bool hover_ok(Renderable* able) { - return hover_render_state()->hover_ok(able); - } - virtual bool hover_test(Point pos) { - (void)pos; - return true; - } - bool use_hover_info() { - return hover_edit_state()->use_hover_info; - } - void set_use_hover_info(bool use) { - auto edit = begin_hover_edit(); - edit->use_hover_info = use; - } - void set_hover_info_font(const Font& font) { - auto edit = begin_hover_edit(); - edit->hover_info_font = font; - } - Font hover_info_font() { - return hover_edit_state()->hover_info_font; - } - Brush hover_info_background_brush() { - return hover_edit_state()->hover_info_brush; - } - void set_hover_info_background_brush(const Brush& brush) { - auto edit = begin_hover_edit(); - edit->hover_info_brush = brush.color.alpha != 0 ? brush : Brush{}; - } - Pen hover_info_pen() { - return hover_edit_state()->hover_info_pen; - } - void set_hover_info_pen(const Pen& pen) { - auto edit = begin_hover_edit(); - edit->hover_info_pen = pen.color.alpha != 0 ? pen : Pen{.style = Line_Style::None}; - } - void get_hover_info_contents_margins(int& left, int& top, int& right, int& bottom) { - auto s = hover_edit_state(); - left = s->hover_info_left; - top = s->hover_info_top; - right = s->hover_info_right; - bottom = s->hover_info_bottom; - } - void set_hover_info_contents_margins(int left, int top, int right, int bottom) { - auto edit = begin_hover_edit(); - edit->hover_info_left = left; - edit->hover_info_top = top; - edit->hover_info_right = right; - edit->hover_info_bottom = bottom; - } - Hover_Edit begin_hover_edit() { - return begin_hover_edit_impl(); - } -private: - virtual Hover_Info_Render_State* hover_edit_state() = 0; - virtual Hover_Info_Render_State* hover_render_state() = 0; - virtual Hover_Edit begin_hover_edit_impl() = 0; -}; -template -struct LIB_DECL Hover_Info_Renderable : Hover_Info_Renderable_Interface { -private: - That* that() { - return static_cast(this); - } - Hover_Info_Render_State* hover_edit_state() override { - auto t = that(); - return dynamic_cast(t->d_ptr->state(State_Edit)); - } - Hover_Info_Render_State* hover_render_state() override { - auto t = that(); - return dynamic_cast(t->d_ptr->state(State_Render)); - } - Hover_Edit begin_hover_edit_impl() override { - auto t = that(); - auto record = t->d_ptr->state_control.try_acquire_role(State_Edit); - if (record.result != Triple_Buffer_Result::Success) - return {}; - auto lease = record.lease; - auto* data = t->d_ptr; - auto* state = dynamic_cast(data->state_by_index(lease.index)); - return Hover_Edit(this, state, [data, lease]() mutable { - ++data->state_by_index(lease.index)->version; - if (data->q_ptr) - data->q_ptr->mark_render_dirty(); - data->state_control.unmark_use(lease); - }); - } -}; -} // namespace renderive diff --git a/Core/plottable/Hover_Info.cpp b/Core/plottable/Hover_Tooltip.cpp similarity index 68% rename from Core/plottable/Hover_Info.cpp rename to Core/plottable/Hover_Tooltip.cpp index b420ab8..64a7c57 100644 --- a/Core/plottable/Hover_Info.cpp +++ b/Core/plottable/Hover_Tooltip.cpp @@ -1,9 +1,9 @@ -#include "Hover_Info.h" +#include "Hover_Tooltip.h" #include "../Axis/Abs_Axis_p.h" namespace renderive { -void Hover_Info_Render_State::draw_hover(Canvas* canvas, Abs_Axis* h, Abs_Axis* v, Hover_Info_Renderable_Interface* renderable) { - Point pos = hover_info_pos; - std::vector lines = renderable->create_hover_string(h, v, pos); +void Hover_Tooltip_State::draw_hover_tooltip(Canvas* canvas, Abs_Axis* domain_axis, Abs_Axis* value_axis, Hover_Tooltip_Provider* renderable) { + Point pos = hover_position; + std::vector lines = renderable->build_hover_lines(domain_axis, value_axis, pos); double max_width = 0; double line_height = 0; for (const std::string& s : lines) { @@ -14,9 +14,9 @@ void Hover_Info_Render_State::draw_hover(Canvas* canvas, Abs_Axis* h, Abs_Axis* Rect rect(pos.x + hover_info_left, pos.y + hover_info_top, static_cast(max_width) + hover_info_right + hover_info_left, static_cast(line_height * lines.size()) + hover_info_bottom); - canvas->set_brush(hover_info_brush); + canvas->set_brush(tooltip_background_brush); canvas->fill_rect(RectF{(double)rect.x, (double)rect.y, (double)rect.width, (double)rect.height}); - canvas->set_pen(hover_info_pen); + canvas->set_pen(tooltip_text_pen); canvas->set_font(hover_info_font); int lh = static_cast(line_height); for (int i = 0; i < (int)lines.size(); ++i) { @@ -24,11 +24,11 @@ void Hover_Info_Render_State::draw_hover(Canvas* canvas, Abs_Axis* h, Abs_Axis* canvas->draw_text(line_rect, Text_Align::Center, lines[i]); } } -bool Hover_Info_Render_State::hover_ok(Renderable* able) const { - auto tmp = dynamic_cast(able); - return use_hover_info && hover_info_active && tmp->hover_test(hover_info_pos); +bool Hover_Tooltip_State::can_show_hover(Renderable* able) const { + auto tmp = dynamic_cast(able); + return use_hover_tooltip && hover_info_active && tmp->hit_test_hover(hover_position); } -std::vector Hover_Info_Renderable_Interface::create_hover_string(Abs_Axis* h, Abs_Axis* v, Point pos) { +std::vector Hover_Tooltip_Provider::build_hover_lines(Abs_Axis* h, Abs_Axis* v, Point pos) { Axis_Mapping_2D mapping = Axis_Render_Access::mapping(h, v); PointF screen_point{static_cast(pos.x), static_cast(pos.y)}; double tick1 = mapping.domain.pixel_to_coord(mapping.domain_pixel(screen_point)); diff --git a/Core/plottable/Hover_Tooltip.h b/Core/plottable/Hover_Tooltip.h new file mode 100644 index 0000000..cbb9c27 --- /dev/null +++ b/Core/plottable/Hover_Tooltip.h @@ -0,0 +1,166 @@ +#pragma once +#include +#include +#include +#include +#include "../Axis/export.h" +#include "../base/Color.h" +#include "../base/Geometry.h" +#include "../base/Style.h" +#include "../base/Text.h" +#include "../render/Canvas.h" +namespace renderive { +struct Hover_Tooltip_State; +struct Hover_Tooltip_Provider; +struct LIB_DECL Hover_Tooltip_State { + virtual ~Hover_Tooltip_State() = default; + Hover_Tooltip_State() { + tooltip_background_brush = Brush{Color::white(), Brush_Style::Solid}; + tooltip_text_pen = Pen{Color::black()}; + } + int hover_info_left = 4; + int hover_info_top = 4; + int hover_info_right = 4; + int hover_info_bottom = 4; + Brush tooltip_background_brush; + Font hover_info_font; + Pen tooltip_text_pen; + bool use_hover_tooltip = true; + bool hover_info_active = false; + Point hover_position; + void draw_hover_tooltip(Canvas* canvas, Abs_Axis* domain_axis, Abs_Axis* value_axis, Hover_Tooltip_Provider* renderable); + bool can_show_hover(Renderable* able) const; +}; +struct LIB_DECL Hover_Tooltip_Provider { + struct Hover_State_Edit { + Hover_State_Edit() = default; + Hover_State_Edit(Hover_Tooltip_Provider* owner, Hover_Tooltip_State* state, std::function on_finish) + : owner(owner), state(state), on_finish(std::move(on_finish)) {} + Hover_State_Edit(const Hover_State_Edit&) = delete; + Hover_State_Edit& operator=(const Hover_State_Edit&) = delete; + Hover_State_Edit(Hover_State_Edit&& other) noexcept + : owner(std::exchange(other.owner, nullptr)), + state(std::exchange(other.state, nullptr)), + on_finish(std::move(other.on_finish)) {} + Hover_State_Edit& operator=(Hover_State_Edit&& other) noexcept { + if (this == &other) + return *this; + finish(); + owner = std::exchange(other.owner, nullptr); + state = std::exchange(other.state, nullptr); + on_finish = std::move(other.on_finish); + return *this; + } + ~Hover_State_Edit() { + finish(); + } + Hover_Tooltip_State* operator->() const { + return state; + } + private: + void finish() { + if (!owner) + return; + if (on_finish) + on_finish(); + on_finish = {}; + owner = nullptr; + state = nullptr; + } + Hover_Tooltip_Provider* owner{}; + Hover_Tooltip_State* state{}; + std::function on_finish{}; + }; + virtual std::vector build_hover_lines(Abs_Axis* h, Abs_Axis* v, Point pos); + virtual ~Hover_Tooltip_Provider() = default; + virtual void draw_hover_tooltip(Canvas* canvas, Abs_Axis* h, Abs_Axis* v) { + return hover_render_state()->draw_hover_tooltip(canvas, h, v, this); + } + virtual bool hover_ok(Renderable* able) { + return hover_render_state()->can_show_hover(able); + } + virtual bool hit_test_hover(Point pos) { + (void)pos; + return true; + } + bool hover_tooltip_enabled() { + return hover_edit_state()->use_hover_tooltip; + } + void set_use_hover_info(bool use) { + auto edit = begin_hover_edit(); + edit->use_hover_tooltip = use; + } + void set_hover_tooltip_font(const Font& font) { + auto edit = begin_hover_edit(); + edit->hover_info_font = font; + } + Font hover_tooltip_font() { + return hover_edit_state()->hover_info_font; + } + Brush hover_info_background_brush() { + return hover_edit_state()->tooltip_background_brush; + } + void set_hover_tooltip_background_brush(const Brush& brush) { + auto edit = begin_hover_edit(); + edit->tooltip_background_brush = brush.color.a != 0 ? brush : Brush{}; + } + Pen tooltip_text_pen() { + return hover_edit_state()->tooltip_text_pen; + } + void set_tooltip_text_pen(const Pen& pen) { + auto edit = begin_hover_edit(); + edit->tooltip_text_pen = pen.color.a != 0 ? pen : Pen{.style = Line_Style::None}; + } + void get_hover_tooltip_contents_margins(int& left, int& top, int& right, int& bottom) { + auto s = hover_edit_state(); + left = s->hover_info_left; + top = s->hover_info_top; + right = s->hover_info_right; + bottom = s->hover_info_bottom; + } + void set_hover_tooltip_contents_margins(int left, int top, int right, int bottom) { + auto edit = begin_hover_edit(); + edit->hover_info_left = left; + edit->hover_info_top = top; + edit->hover_info_right = right; + edit->hover_info_bottom = bottom; + } + Hover_State_Edit begin_hover_edit() { + return begin_hover_edit_impl(); + } +private: + virtual Hover_Tooltip_State* hover_edit_state() = 0; + virtual Hover_Tooltip_State* hover_render_state() = 0; + virtual Hover_State_Edit begin_hover_edit_impl() = 0; +}; +template +struct LIB_DECL Hover_Info_Renderable : Hover_Tooltip_Provider { +private: + That* that() { + return static_cast(this); + } + Hover_Tooltip_State* hover_edit_state() override { + auto t = that(); + return dynamic_cast(t->d_ptr->state(State_Edit)); + } + Hover_Tooltip_State* hover_render_state() override { + auto t = that(); + return dynamic_cast(t->d_ptr->state(State_Render)); + } + Hover_State_Edit begin_hover_edit_impl() override { + auto t = that(); + auto record = t->d_ptr->state_control.try_acquire_role(State_Edit); + if (record.result != Triple_Buffer_Result::Success) + return {}; + auto lease = record.lease; + auto* data = t->d_ptr; + auto* state = dynamic_cast(data->state_by_index(lease.index)); + return Hover_State_Edit(this, state, [data, lease]() mutable { + ++data->state_by_index(lease.index)->version; + if (data->q_ptr) + data->q_ptr->mark_render_dirty(); + data->state_control.unmark_use(lease); + }); + } +}; +} // namespace renderive diff --git a/Core/plottable/Interpolation.h b/Core/plottable/Interpolation.h index b55bf90..e5cf682 100644 --- a/Core/plottable/Interpolation.h +++ b/Core/plottable/Interpolation.h @@ -1,16 +1,13 @@ #pragma once #include "../render/Image_Interpolation_Mode.h" #include - namespace renderive { - enum class Line_Interpolation_Mode : std::uint8_t { - Nearest_Bin, - Linear_Display, - Linear_Power, + Nearest_Sample, + Linear_Value, + Linear_Power_Domain, Step_Left, Step_Right, - Cubic_Display + Cubic_Value }; - -} // namespace renderive +} diff --git a/Core/plottable/Interpolation_p.h b/Core/plottable/Interpolation_p.h index f6097aa..c18ca29 100644 --- a/Core/plottable/Interpolation_p.h +++ b/Core/plottable/Interpolation_p.h @@ -10,7 +10,7 @@ #include "../render/Image.h" #include "Interpolation.h" namespace renderive { -struct Line_Sample_Window { +struct Visible_Sample_Window { double first_index{}; double last_index{}; int sample_count{}; @@ -30,21 +30,21 @@ inline bool intersect_range(const Range& data_range, const Range& clip_range, Ra result = data_range.origin <= data_range.target ? Range{lower, upper} : Range{upper, lower}; return true; } -inline double source_index_to_coord(const Range& data_range, int total_count, double index) { +inline double source_index_to_coordinate(const Range& data_range, int total_count, double index) { return data_range.origin + data_range.length() * index / static_cast(total_count - 1); } -inline double coord_to_source_index(const Range& data_range, int total_count, double coord) { +inline double coordinate_to_source_index(const Range& data_range, int total_count, double coord) { return static_cast(total_count - 1) * (coord - data_range.origin) / data_range.length(); } -inline Line_Sample_Window line_sample_window(const Axis_Frame_Snapshot& axis, const Range& data_range, int total_count, int available_count, bool visible_range_only) { +inline Visible_Sample_Window compute_visible_sample_window(const Axis_Frame_Snapshot& axis, const Range& data_range, int total_count, int available_count, bool visible_range_only) { if (total_count < 2 || available_count < 1 || data_range.length() == 0.0) return {}; - Range available_range{data_range.origin, source_index_to_coord(data_range, total_count, available_count - 1)}; + Range available_range{data_range.origin, source_index_to_coordinate(data_range, total_count, available_count - 1)}; Range sample_range = available_range; if (visible_range_only && !intersect_range(available_range, axis.coord_range, sample_range)) return {}; - double first_index = coord_to_source_index(data_range, total_count, sample_range.origin); - double last_index = coord_to_source_index(data_range, total_count, sample_range.target); + double first_index = coordinate_to_source_index(data_range, total_count, sample_range.origin); + double last_index = coordinate_to_source_index(data_range, total_count, sample_range.target); double first_pixel = axis.coord_to_pixel(sample_range.origin); double last_pixel = axis.coord_to_pixel(sample_range.target); int source_samples = static_cast(std::ceil(std::abs(last_index - first_index))) + 1; @@ -52,11 +52,11 @@ inline Line_Sample_Window line_sample_window(const Axis_Frame_Snapshot& axis, co pixel_samples = std::min(pixel_samples, axis.pixel_size() + 1); return {first_index, last_index, std::max(source_samples, pixel_samples)}; } -inline Line_Sample_Window line_sample_window(Abs_Axis* axis, const Range& data_range, int total_count, int available_count, bool visible_range_only) { - return line_sample_window(Axis_Render_Access::snapshot(axis), data_range, total_count, available_count, visible_range_only); +inline Visible_Sample_Window compute_visible_sample_window(Abs_Axis* axis, const Range& data_range, int total_count, int available_count, bool visible_range_only) { + return compute_visible_sample_window(Axis_Render_Access::snapshot(axis), data_range, total_count, available_count, visible_range_only); } template -double interpolate_line_value(double index, int count, Line_Interpolation_Mode mode, Value_At value_at) { +double interpolate_sample_value(double index, int count, Line_Interpolation_Mode mode, Value_At value_at) { index = std::clamp(index, 0.0, static_cast(count - 1)); int left = static_cast(std::floor(index)); int right = std::min(left + 1, count - 1); @@ -64,11 +64,11 @@ double interpolate_line_value(double index, int count, Line_Interpolation_Mode m double left_value = value_at(left); double right_value = value_at(right); switch (mode) { - case Line_Interpolation_Mode::Nearest_Bin: + case Line_Interpolation_Mode::Nearest_Sample: return value_at(static_cast(std::round(index))); - case Line_Interpolation_Mode::Linear_Display: + case Line_Interpolation_Mode::Linear_Value: return left_value + (right_value - left_value) * t; - case Line_Interpolation_Mode::Linear_Power: { + case Line_Interpolation_Mode::Linear_Power_Domain: { double left_power = std::pow(10.0, left_value / 10.0); double right_power = std::pow(10.0, right_value / 10.0); return 10.0 * std::log10(left_power + (right_power - left_power) * t); @@ -77,7 +77,7 @@ double interpolate_line_value(double index, int count, Line_Interpolation_Mode m return left_value; case Line_Interpolation_Mode::Step_Right: return t == 0.0 ? left_value : right_value; - case Line_Interpolation_Mode::Cubic_Display: { + case Line_Interpolation_Mode::Cubic_Value: { double p0 = value_at(std::max(left - 1, 0)); double p1 = left_value; double p2 = right_value; @@ -91,23 +91,23 @@ double interpolate_line_value(double index, int count, Line_Interpolation_Mode m return left_value; } template -std::pmr::vector create_line_points(const Axis_Mapping_2D& mapping, const Range& data_range, int total_count, int available_count, bool visible_range_only, Line_Interpolation_Mode mode, Value_At value_at, std::pmr::memory_resource* resource = frame_memory_resource()) { - Line_Sample_Window window = line_sample_window(mapping.domain, data_range, total_count, available_count, visible_range_only); +std::pmr::vector build_interpolated_line_points(const Axis_Mapping_2D& mapping, const Range& data_range, int total_count, int available_count, bool visible_range_only, Line_Interpolation_Mode mode, Value_At value_at, std::pmr::memory_resource* resource = frame_memory_resource()) { + Visible_Sample_Window window = compute_visible_sample_window(mapping.domain, data_range, total_count, available_count, visible_range_only); if (!window) return {}; std::pmr::vector points(window.sample_count, resource); double denominator = static_cast(std::max(window.sample_count - 1, 1)); for (int i = 0; i < window.sample_count; ++i) { double index = window.first_index + (window.last_index - window.first_index) * static_cast(i) / denominator; - double coord = source_index_to_coord(data_range, total_count, index); - double value = interpolate_line_value(index, available_count, mode, value_at); + double coord = source_index_to_coordinate(data_range, total_count, index); + double value = interpolate_sample_value(index, available_count, mode, value_at); points[i] = mapping.map(coord, value); } return points; } template -std::pmr::vector create_line_points(Abs_Axis* domain_axis, Abs_Axis* value_axis, const Range& data_range, int total_count, int available_count, bool visible_range_only, Line_Interpolation_Mode mode, Value_At value_at) { - return create_line_points(Axis_Render_Access::mapping(domain_axis, value_axis), data_range, total_count, available_count, visible_range_only, mode, value_at, frame_memory_resource()); +std::pmr::vector build_interpolated_line_points(Abs_Axis* domain_axis, Abs_Axis* value_axis, const Range& data_range, int total_count, int available_count, bool visible_range_only, Line_Interpolation_Mode mode, Value_At value_at) { + return build_interpolated_line_points(Axis_Render_Access::mapping(domain_axis, value_axis), data_range, total_count, available_count, visible_range_only, mode, value_at, frame_memory_resource()); } inline double cubic_channel(double p0, double p1, double p2, double p3, double t) { double a = -0.5 * p0 + 1.5 * p1 - 1.5 * p2 + 0.5 * p3; diff --git a/Core/plottable/Multi_Select_Rect.cpp b/Core/plottable/Multi_Select_Rect.cpp deleted file mode 100644 index 13f8a50..0000000 --- a/Core/plottable/Multi_Select_Rect.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include "Multi_Select_Rect_p.h" -#include "../base/Memory.h" -namespace renderive { -RENDERIVE_DEFINE_RENDERABLE_BINDING(Multi_Select_Rect, Multi_Select_Rect_Private, Multi_Select_Rect_Render_State, Multi_Select_Rect_Input_Data, "Multi_Select_Rect") -Multi_Select_Rect::Builder::Builder(std::shared_ptr parent, std::shared_ptr key_axis, std::shared_ptr value_axis) { - ASSERT(parent && parent->attached_to_plot(), "Multi_Select_Rect build error! parent invalid"); - ASSERT(key_axis && value_axis, "Multi_Select_Rect build error! axis == nullptr"); - ASSERT(key_axis->attached_to_plot(), "Multi_Select_Rect build error! key_axis->plot == nullptr"); - ASSERT(key_axis->shares_plot_with(*value_axis), "Multi_Select_Rect build error! key_axis->plot != value_axis->plot"); - ASSERT(parent->shares_plot_with(*key_axis), "Multi_Select_Rect build error! parent->plot != key_axis->plot"); - ASSERT(key_axis->orientation() != value_axis->orientation(), "Multi_Select_Rect build error! axes must be orthogonal"); - this->parent = parent; - this->key_axis = key_axis; - this->value_axis = value_axis; -} -std::shared_ptr Multi_Select_Rect::Builder::build() { - auto ret = renderive::make_shared(); - ret->init(parent); - Multi_Select_Rect_Private* pd = ret->d(); - Multi_Select_Rect_Render_State* sc = reinterpret_cast(pd->state(State_Edit)); - sc->horizontal_axis = key_axis; - sc->vertical_axis = value_axis; - sc->font = font; - sc->font_pen = font_pen; - sc->rect_brush = rect_brush; - sc->border_pen = border_pen; - return ret; -} -void Multi_Select_Rect::set_horizontal_axis(std::shared_ptr axis) { - Render_Edit_Lease edit(d()); - edit->horizontal_axis = std::weak_ptr(axis); -} -void Multi_Select_Rect::set_vertical_axis(std::shared_ptr axis) { - Render_Edit_Lease edit(d()); - edit->vertical_axis = std::weak_ptr(axis); -} -Font Multi_Select_Rect::font() { - return d()->state_data(SRC::Edit)->font; -} -Pen Multi_Select_Rect::font_pen() { - return d()->state_data(SRC::Edit)->font_pen; -} -Brush Multi_Select_Rect::rect_brush() { - return d()->state_data(SRC::Edit)->rect_brush; -} -Pen Multi_Select_Rect::border_pen() { - return d()->state_data(SRC::Edit)->border_pen; -} -void Multi_Select_Rect::set_font(const Font& font) { - Render_Edit_Lease edit(d()); - edit->font = font; -} -void Multi_Select_Rect::set_font_pen(const Pen& pen) { - Render_Edit_Lease edit(d()); - edit->font_pen = pen.color.alpha != 0 ? pen : Pen{.style = Line_Style::None}; -} -void Multi_Select_Rect::set_rect_brush(const Brush& brush) { - Render_Edit_Lease edit(d()); - edit->rect_brush = brush.color.alpha != 0 ? brush : Brush{}; -} -void Multi_Select_Rect::set_border_pen(const Pen& pen) { - Render_Edit_Lease edit(d()); - edit->border_pen = pen.color.alpha != 0 ? pen : Pen{.style = Line_Style::None}; -} -std::vector Multi_Select_Rect::selection_rects() { - return d()->state_data(SRC::Edit)->rects; -} -void Multi_Select_Rect::clear_selection() { - Render_Edit_Lease edit(d()); - edit->rects.clear(); - d()->active.store(false, std::memory_order_release); -} -} // namespace renderive diff --git a/Core/plottable/Performance_Shower.cpp b/Core/plottable/Performance_Overlay.cpp similarity index 77% rename from Core/plottable/Performance_Shower.cpp rename to Core/plottable/Performance_Overlay.cpp index ee9edf4..8d27f46 100644 --- a/Core/plottable/Performance_Shower.cpp +++ b/Core/plottable/Performance_Overlay.cpp @@ -1,4 +1,4 @@ -#include "Performance_Shower_p.h" +#include "Performance_Overlay_p.h" #include #include #include @@ -8,12 +8,11 @@ #include "../plot/Plot_Core.h" namespace renderive { namespace { -class Performance_Background_Service { +class Performance_Overlay_Service { public: - ~Performance_Background_Service() { + ~Performance_Overlay_Service() { shutdown(); } - bool try_submit(Task task) { if (!task || shutting_down.load(std::memory_order_acquire)) return false; @@ -25,23 +24,19 @@ public: executor.run(*topology, [topology]() {}); return true; } - void shutdown() { if (shutting_down.exchange(true, std::memory_order_acq_rel)) return; executor.wait_for_all(); } - private: tf::Executor executor{1}; std::atomic_bool shutting_down{false}; }; - -Performance_Background_Service& performance_background_service() { - static Performance_Background_Service service; +Performance_Overlay_Service& performance_background_service() { + static Performance_Overlay_Service service; return service; } - double duration_ms(std::uint64_t begin_ns, std::uint64_t end_ns) { return end_ns > begin_ns ? static_cast(end_ns - begin_ns) / 1000000.0 : 0.0; } @@ -137,12 +132,11 @@ std::string renderable_stats_text(const Frame_Lifecycle_Record& frame) { } return stream.str(); } -class Performance_Frame_Log { +class Frame_Performance_Logger { public: bool is_enabled() const { return enabled(); } - void write(const Frame_Lifecycle_Record& frame) { if (!enabled()) return; @@ -216,25 +210,23 @@ private: return "frame_id,input_version,outcome,limit_source,render_period_ns,paint_period_ns,user_period_ns,target_period_ns,request_wait_ms,prepare_ms,draw_ms,render_ms,middle_wait_ms,update_wait_ms,paint_ms,frame_age_ms,wait_21_ns,wait_12_ns,wait_23_ns,wait_32_ns,raw_input_count,prepared_output_count,cache_hit_count,cache_miss_count,cache_rebuild_count,cache_rebuild_time_ns,cache_compose_time_ns,cache_image_bytes,cache_image_area,cache_hit_ratio,pixel_width,pixel_height,core_data_time_ns,render_begin_time_ns,render_end_time_ns,transition_12_ns,transition_23_ns,paint_begin_time_ns,paint_end_time_ns,transition_32_ns,superseded_time_ns,renderable_stats,renderable_cache_stats"; } }; -Performance_Frame_Log& frame_log() { - static Performance_Frame_Log value; +Frame_Performance_Logger& frame_log() { + static Frame_Performance_Logger value; return value; } -static std::shared_ptr performance_shower_owner(const std::shared_ptr& ctx) { +static std::shared_ptr performance_overlay_owner(const std::shared_ptr& ctx) { if (!ctx) return {}; auto observer = std::atomic_load_explicit(&ctx->frame_lifecycle_observer, std::memory_order_acquire); - return std::dynamic_pointer_cast(observer); + return std::dynamic_pointer_cast(observer); } - static std::function performance_update_callback(const std::shared_ptr& ctx) { if (!ctx) return {}; std::lock_guard lock(ctx->performance_update_callback_mutex); return ctx->performance_update_callback; } - -static void request_performance_update(const std::shared_ptr& worker) { +static void request_performance_update(const std::shared_ptr& worker) { if (!worker) return; std::function callback; @@ -246,92 +238,83 @@ static void request_performance_update(const std::shared_ptr& state) { +void schedule_performance_metrics_worker(const std::shared_ptr& state) { if (!state || state->cancelled.load(std::memory_order_acquire)) return; state->work_requested.store(true, std::memory_order_release); if (state->worker_active.exchange(true, std::memory_order_acq_rel)) return; if (!performance_background_service().try_submit(Task([state]() { - Performance_Shower_Private::run_metrics_worker(state); - }))) { + Performance_Overlay_Private::run_metrics_worker(state); + }))) { state->worker_active.store(false, std::memory_order_release); } } - -Performance_Shower::Performance_Shower() - : private_data(std::make_unique()) {} - -Performance_Shower::~Performance_Shower() = default; - -Performance_Shower_Private* Performance_Shower::d() { +Performance_Overlay::Performance_Overlay() + : private_data(std::make_unique()) {} +Performance_Overlay::~Performance_Overlay() = default; +Performance_Overlay_Private* Performance_Overlay::d() { return private_data.get(); } - -static std::shared_ptr attach_performance_shower_impl(Plot_Core& plot, const Performance_Shower_Options* options) { +static std::shared_ptr attach_performance_overlay_impl(Plot_Core& plot, const Performance_Overlay_Options* options) { auto ctx = plot.render_context(); if (!ctx) return {}; - auto shower = performance_shower_owner(ctx); + auto shower = performance_overlay_owner(ctx); if (shower) { if (options) shower->set_options(*options); return shower; } - auto created_shower = renderive::make_shared(); + auto created_shower = renderive::make_shared(); if (options) created_shower->set_options(*options); created_shower->set_update_callback(performance_update_callback(ctx)); std::atomic_store_explicit(&ctx->frame_lifecycle_observer, std::static_pointer_cast(created_shower), std::memory_order_release); return created_shower; } - -std::shared_ptr attach_performance_shower(Plot_Core& plot) { - return attach_performance_shower_impl(plot, nullptr); +std::shared_ptr attach_performance_overlay(Plot_Core& plot) { + return attach_performance_overlay_impl(plot, nullptr); } - -std::shared_ptr attach_performance_shower(Plot_Core& plot, const Performance_Shower_Options& options) { - return attach_performance_shower_impl(plot, &options); +std::shared_ptr attach_performance_overlay(Plot_Core& plot, const Performance_Overlay_Options& options) { + return attach_performance_overlay_impl(plot, &options); } - -std::shared_ptr performance_shower(Plot_Core& plot) { - return performance_shower_owner(plot.render_context()); +std::shared_ptr performance_overlay(Plot_Core& plot) { + return performance_overlay_owner(plot.render_context()); } - -void detach_performance_shower(Plot_Core& plot) { +void detach_performance_overlay(Plot_Core& plot) { auto ctx = plot.render_context(); if (!ctx) return; - auto shower = performance_shower_owner(ctx); + auto shower = performance_overlay_owner(ctx); std::atomic_store_explicit(&ctx->frame_lifecycle_observer, std::shared_ptr{}, std::memory_order_release); if (shower) - shower->setEnabled(false); + shower->set_enabled(false); } -bool performance_shower_enabled(const Plot_Core& plot) { - auto shower = performance_shower_owner(plot.render_context()); +bool performance_overlay_enabled(const Plot_Core& plot) { + auto shower = performance_overlay_owner(plot.render_context()); return shower && shower->enabled(); } -void set_performance_shower_enabled(Plot_Core& plot, bool enabled) { +void set_performance_overlay_enabled(Plot_Core& plot, bool enabled) { if (!enabled) { - auto shower = performance_shower_owner(plot.render_context()); + auto shower = performance_overlay_owner(plot.render_context()); if (shower) - shower->setEnabled(false); + shower->set_enabled(false); return; } - auto shower = attach_performance_shower(plot); + auto shower = attach_performance_overlay(plot); if (shower) { - shower->setEnabled(true); + shower->set_enabled(true); shower->set_viewport(plot.viewport_size(), plot.render_context() ? plot.render_context()->viewport_version.load(std::memory_order_acquire) : 0); } } -std::shared_ptr performance_shower_snapshot(const Plot_Core& plot) { - auto shower = performance_shower_owner(plot.render_context()); +std::shared_ptr performance_overlay_snapshot(const Plot_Core& plot) { + auto shower = performance_overlay_owner(plot.render_context()); if (!shower || !shower->enabled()) return {}; return shower->display_snapshot(); } -void set_performance_shower_update_callback(Plot_Core& plot, std::function callback) { +void set_performance_overlay_update_callback(Plot_Core& plot, std::function callback) { auto ctx = plot.render_context(); if (!ctx) return; @@ -339,39 +322,39 @@ void set_performance_shower_update_callback(Plot_Core& plot, std::function lock(ctx->performance_update_callback_mutex); ctx->performance_update_callback = std::move(callback); } - auto shower = performance_shower_owner(ctx); + auto shower = performance_overlay_owner(ctx); if (shower) shower->set_update_callback(performance_update_callback(ctx)); } -void notify_performance_shower_viewport_changed(Plot_Core& plot) { - auto shower = performance_shower_owner(plot.render_context()); +void notify_performance_overlay_viewport_changed(Plot_Core& plot) { + auto shower = performance_overlay_owner(plot.render_context()); if (!shower || !shower->enabled()) return; auto ctx = plot.render_context(); shower->set_viewport(plot.viewport_size(), ctx ? ctx->viewport_version.load(std::memory_order_acquire) : 0); } -bool performance_shower_handle_wheel(Plot_Core& plot, PointF position, double angle_delta_y, double pixel_delta_y) { - auto shower = performance_shower_owner(plot.render_context()); +bool performance_overlay_handle_wheel(Plot_Core& plot, PointF position, double angle_delta_y, double pixel_delta_y) { + auto shower = performance_overlay_owner(plot.render_context()); return shower && shower->enabled() && shower->handle_wheel(position, angle_delta_y, pixel_delta_y); } -bool performance_shower_handle_pointer_press(Plot_Core& plot, PointF position) { - auto shower = performance_shower_owner(plot.render_context()); +bool performance_overlay_handle_pointer_press(Plot_Core& plot, PointF position) { + auto shower = performance_overlay_owner(plot.render_context()); return shower && shower->enabled() && shower->handle_pointer_press(position); } -bool performance_shower_handle_pointer_move(Plot_Core& plot, PointF position) { - auto shower = performance_shower_owner(plot.render_context()); +bool performance_overlay_handle_pointer_move(Plot_Core& plot, PointF position) { + auto shower = performance_overlay_owner(plot.render_context()); return shower && shower->enabled() && shower->handle_pointer_move(position); } -bool performance_shower_handle_pointer_release(Plot_Core& plot, PointF position) { - auto shower = performance_shower_owner(plot.render_context()); +bool performance_overlay_handle_pointer_release(Plot_Core& plot, PointF position) { + auto shower = performance_overlay_owner(plot.render_context()); return shower && shower->enabled() && shower->handle_pointer_release(position); } -void Performance_Shower::setEnabled(bool enabled) { +void Performance_Overlay::set_enabled(bool enabled) { auto worker = d()->metrics_worker; d()->enabled_value.store(enabled, std::memory_order_release); worker->enabled.store(enabled, std::memory_order_release); if (!enabled) { - worker->display_snapshot_slot.store({}, std::memory_order_release); + worker->published_snapshot.store({}, std::memory_order_release); request_performance_update(worker); return; } @@ -379,13 +362,13 @@ void Performance_Shower::setEnabled(bool enabled) { worker->snapshot_rebuild_requested.store(true, std::memory_order_release); schedule_performance_metrics_worker(worker); } -bool Performance_Shower::enabled() const { - return const_cast(this)->d()->enabled_value.load(std::memory_order_acquire); +bool Performance_Overlay::enabled() const { + return const_cast(this)->d()->enabled_value.load(std::memory_order_acquire); } -std::shared_ptr Performance_Shower::display_snapshot() const { - return const_cast(this)->d()->metrics_worker->display_snapshot_slot.load(std::memory_order_acquire); +std::shared_ptr Performance_Overlay::display_snapshot() const { + return const_cast(this)->d()->metrics_worker->published_snapshot.load(std::memory_order_acquire); } -void Performance_Shower::set_options(Performance_Shower_Options options) { +void Performance_Overlay::set_options(Performance_Overlay_Options options) { auto worker = d()->metrics_worker; { std::lock_guard lock(worker->options_mutex); @@ -395,40 +378,40 @@ void Performance_Shower::set_options(Performance_Shower_Options options) { if (enabled()) schedule_performance_metrics_worker(worker); } -Performance_Shower_Options Performance_Shower::options() const { - auto worker = const_cast(this)->d()->metrics_worker; +Performance_Overlay_Options Performance_Overlay::options() const { + auto worker = const_cast(this)->d()->metrics_worker; std::lock_guard lock(worker->options_mutex); return worker->options; } -void Performance_Shower::set_font(Font font) { - Performance_Shower_Options value = options(); +void Performance_Overlay::set_font(Font font) { + Performance_Overlay_Options value = options(); value.font = std::move(font); set_options(std::move(value)); } -void Performance_Shower::set_foreground(Color color) { - Performance_Shower_Options value = options(); +void Performance_Overlay::set_foreground(Color color) { + Performance_Overlay_Options value = options(); value.foreground = color; set_options(std::move(value)); } -void Performance_Shower::set_background(Color color) { - Performance_Shower_Options value = options(); +void Performance_Overlay::set_background(Color color) { + Performance_Overlay_Options value = options(); value.background = color; set_options(std::move(value)); } -void Performance_Shower::collect_frame(std::shared_ptr frame) { +void Performance_Overlay::collect_frame(std::shared_ptr frame) { if (!enabled()) return; d()->enqueue_frame_metric(frame); write_frame_performance_log(frame); } -void Performance_Shower::set_viewport(Size viewport, std::uint64_t version) { +void Performance_Overlay::set_viewport(Size viewport, std::uint64_t version) { d()->metrics_worker->viewport_width.store(viewport.width, std::memory_order_release); d()->metrics_worker->viewport_height.store(viewport.height, std::memory_order_release); d()->metrics_worker->viewport_version.store(version, std::memory_order_release); d()->metrics_worker->snapshot_rebuild_requested.store(true, std::memory_order_release); schedule_performance_metrics_worker(d()->metrics_worker); } -bool Performance_Shower::handle_wheel(PointF position, double angle_delta_y, double pixel_delta_y) { +bool Performance_Overlay::handle_wheel(PointF position, double angle_delta_y, double pixel_delta_y) { auto snapshot = display_snapshot(); if (!snapshot || !snapshot->destination_rect.contains(position)) return false; @@ -444,7 +427,7 @@ bool Performance_Shower::handle_wheel(PointF position, double angle_delta_y, dou } return true; } -bool Performance_Shower::handle_pointer_press(PointF position) { +bool Performance_Overlay::handle_pointer_press(PointF position) { auto snapshot = display_snapshot(); if (!snapshot || snapshot->max_scroll_offset <= 0.0) return false; @@ -464,14 +447,14 @@ bool Performance_Shower::handle_pointer_press(PointF position) { } return false; } -bool Performance_Shower::handle_pointer_move(PointF position) { +bool Performance_Overlay::handle_pointer_move(PointF position) { if (!d()->metrics_worker->drag_active.load(std::memory_order_acquire)) return false; d()->metrics_worker->drag_position_y.store(position.y, std::memory_order_release); schedule_performance_metrics_worker(d()->metrics_worker); return true; } -bool Performance_Shower::handle_pointer_release(PointF position) { +bool Performance_Overlay::handle_pointer_release(PointF position) { if (!d()->metrics_worker->drag_active.load(std::memory_order_acquire)) return false; d()->metrics_worker->drag_position_y.store(position.y, std::memory_order_release); @@ -479,7 +462,7 @@ bool Performance_Shower::handle_pointer_release(PointF position) { schedule_performance_metrics_worker(d()->metrics_worker); return true; } -void Performance_Shower::set_update_callback(std::function callback) { +void Performance_Overlay::set_update_callback(std::function callback) { std::lock_guard lock(d()->metrics_worker->update_callback_mutex); d()->metrics_worker->update_callback = std::move(callback); } diff --git a/Core/plottable/Performance_Shower.h b/Core/plottable/Performance_Overlay.h similarity index 74% rename from Core/plottable/Performance_Shower.h rename to Core/plottable/Performance_Overlay.h index 4c5e8d2..77f6518 100644 --- a/Core/plottable/Performance_Shower.h +++ b/Core/plottable/Performance_Overlay.h @@ -11,9 +11,9 @@ namespace renderive { -struct Performance_Shower_Private; +struct Performance_Overlay_Private; -struct Performance_Shower_Options { +struct Performance_Overlay_Options { Font font; int top_margin = 4; int left_margin = 6; @@ -27,18 +27,18 @@ struct Performance_Shower_Options { Color scroll_thumb = Color{80, 80, 80}; }; -class LIB_DECL Performance_Shower : public Frame_Lifecycle_Observer { +class LIB_DECL Performance_Overlay : public Frame_Lifecycle_Observer { public: - Performance_Shower(); - ~Performance_Shower(); + Performance_Overlay(); + ~Performance_Overlay(); - void setEnabled(bool enabled); + void set_enabled(bool enabled); bool enabled() const override; void collect_frame(std::shared_ptr frame) override; [[nodiscard]] std::shared_ptr display_snapshot() const; - void set_options(Performance_Shower_Options options); - [[nodiscard]] Performance_Shower_Options options() const; + void set_options(Performance_Overlay_Options options); + [[nodiscard]] Performance_Overlay_Options options() const; void set_font(Font font); void set_foreground(Color color); void set_background(Color color); @@ -51,8 +51,8 @@ public: void set_update_callback(std::function callback); private: - Performance_Shower_Private* d(); - std::unique_ptr private_data; + Performance_Overlay_Private* d(); + std::unique_ptr private_data; }; } // namespace renderive diff --git a/Core/plottable/Performance_Shower_p.h b/Core/plottable/Performance_Overlay_p.h similarity index 86% rename from Core/plottable/Performance_Shower_p.h rename to Core/plottable/Performance_Overlay_p.h index 9076536..b97042e 100644 --- a/Core/plottable/Performance_Shower_p.h +++ b/Core/plottable/Performance_Overlay_p.h @@ -24,12 +24,12 @@ #include "../base/String_Format.h" #include "../base/Text.h" #include "../render/Canvas.h" -#include "Performance_Shower.h" +#include "Performance_Overlay.h" #include "Psc_Cpp_Core/Statistics/Statistics.h" namespace renderive { void write_frame_performance_log(std::shared_ptr frame); -struct Performance_Shower_Render_State : Render_State, Performance_Shower_Options {}; -struct Performance_Shower_Input_Data : Input_Data {}; +struct Performance_Overlay_Render_State : Render_State, Performance_Overlay_Options {}; +struct Performance_Overlay_Input_Data : Input_Data {}; struct Renderable_Cache_Aggregate_Stat { std::string object_name; std::string parent_object_name; @@ -66,7 +66,7 @@ struct Renderable_Aggregate_Stat { Psc::Value_Statistics total_render_ratio; Psc::Value_Statistics self_draw_ratio; }; -struct Frame_Performance_Aggregate { +struct Performance_Aggregate { Psc::Value_Statistics request_wait_ms; Psc::Value_Statistics render_queue_wait_ms; Psc::Value_Statistics prepare_ms; @@ -194,7 +194,7 @@ private: renderable_stats.push_back(std::move(stat)); return renderable_stats.back(); } - void update_cache_subtree_compose(const std::vector& frame_stats) { + void update_cache_subtree_compose(const std::vector& frame_stats) { for (const auto& stat : frame_stats) { std::uint64_t subtree_compose_time_ns = renderable_cache_subtree_compose_time(frame_stats, stat); if (!subtree_compose_time_ns) @@ -227,8 +227,7 @@ private: statistics.update(static_cast(end_ns - begin_ns) / 1000000.0); } }; - -enum class Performance_Field_Id : std::uint16_t { +enum class Performance_Metric_Id : std::uint16_t { Frame_Id, Input_Version, Render_Period, @@ -243,14 +242,14 @@ enum class Performance_Field_Id : std::uint16_t { Active_Workers, Queued_Frame_Jobs, Active_Frame_Jobs, - Submitted_Tasks, - Started_Tasks, - Completed_Tasks, + Submitted_Jobs, + Started_Task_Nodes, + Completed_Task_Nodes, Rejected_Frame_Jobs, Queue_Wait_Avg, - Queue_Wait_P95, + Queue_Wait_Max, Task_Run_Avg, - Task_Run_P95, + Task_Run_Max, Frame_Task_Count, Frame_Peak_Parallelism, Frame_Wait_Max, @@ -285,34 +284,28 @@ enum class Performance_Field_Id : std::uint16_t { Generic_Number, Count }; - -inline constexpr std::size_t performance_field_count = static_cast(Performance_Field_Id::Count); - +inline constexpr std::size_t performance_field_count = static_cast(Performance_Metric_Id::Count); struct Performance_Field_Layout_State { double max_value_width{}; }; - -struct Performance_Text_Run { +struct Performance_Text_Span { bool value{}; - Performance_Field_Id field_id = Performance_Field_Id::Generic_Number; + Performance_Metric_Id field_id = Performance_Metric_Id::Generic_Number; std::string text; double measured_width{}; double reserved_width{}; }; - -struct Performance_Render_Line { - std::vector runs; +struct Performance_Line_Layout { + std::vector runs; double width{}; }; - using Performance_Frame_Record = std::shared_ptr; - -struct Performance_Metrics_Worker_State { +struct Performance_Worker_State { static constexpr std::size_t Capacity = 256; - Performance_Metrics_Worker_State() + Performance_Worker_State() : metric_queue(Capacity) {} rigtorp::MPMCQueue metric_queue; - std::atomic metric_capacity_dropped{0}; + std::atomic dropped_frame_record_count{0}; std::atomic_bool enabled{false}; std::atomic_bool worker_active{false}; std::atomic_bool work_requested{false}; @@ -330,21 +323,20 @@ struct Performance_Metrics_Worker_State { std::atomic viewport_height{0}; std::atomic viewport_version{0}; std::atomic next_content_version{1}; - Frame_Performance_Aggregate aggregate; + Performance_Aggregate aggregate; std::array field_layout_states{}; RectF last_scroll_track_rect; RectF last_scroll_thumb_rect; double last_content_viewport_height{}; double last_line_height{1.0}; - double last_max_scroll_offset{}; - double held_content_width{}; + double maximum_scroll_offset{}; + double maximum_content_width{}; mutable std::mutex options_mutex; - Performance_Shower_Options options; + Performance_Overlay_Options options; std::mutex update_callback_mutex; std::function update_callback; - std::atomic> display_snapshot_slot; + std::atomic> published_snapshot; }; - inline double performance_clamp_scroll_offset(double offset, double max_offset) { if (!std::isfinite(offset)) return 0.0; @@ -352,32 +344,28 @@ inline double performance_clamp_scroll_offset(double offset, double max_offset) return 0.0; return std::clamp(offset, 0.0, max_offset); } - inline double performance_atomic_exchange(std::atomic& value, double replacement = 0.0) { double current = value.load(std::memory_order_acquire); while (!value.compare_exchange_weak(current, replacement, std::memory_order_acq_rel, std::memory_order_acquire)) {} return current; } - inline void performance_atomic_add(std::atomic& value, double delta) { double current = value.load(std::memory_order_acquire); while (!value.compare_exchange_weak(current, current + delta, std::memory_order_acq_rel, std::memory_order_acquire)) {} } - -void schedule_performance_metrics_worker(const std::shared_ptr& state); - -struct Performance_Shower_Private { - Frame_Performance_Aggregate aggregate; +void schedule_performance_metrics_worker(const std::shared_ptr& state); +struct Performance_Overlay_Private { + Performance_Aggregate aggregate; std::atomic_bool enabled_value{false}; - std::shared_ptr metrics_worker = std::make_shared(); + std::shared_ptr metrics_worker = std::make_shared(); std::vector lines; - std::vector render_lines; + std::vector render_lines; std::array field_layout_states{}; RectF panel_rect; RectF scroll_bar_rect; RectF scroll_thumb_rect; double content_width{}; - ~Performance_Shower_Private() { + ~Performance_Overlay_Private() { metrics_worker->cancelled.store(true, std::memory_order_release); Performance_Frame_Record frame; while (metrics_worker->metric_queue.try_pop(frame)) {} @@ -386,12 +374,12 @@ struct Performance_Shower_Private { if (!frame) return; if (!metrics_worker->metric_queue.try_push(std::move(frame))) { - metrics_worker->metric_capacity_dropped.fetch_add(1, std::memory_order_relaxed); + metrics_worker->dropped_frame_record_count.fetch_add(1, std::memory_order_relaxed); return; } schedule_performance_metrics_worker(metrics_worker); } - static void run_metrics_worker(const std::shared_ptr& state) { + static void run_metrics_worker(const std::shared_ptr& state) { if (!state) return; while (!state->cancelled.load(std::memory_order_acquire)) { @@ -406,7 +394,7 @@ struct Performance_Shower_Private { changed = true; if (consume_scroll_commands(*state)) changed = true; - std::uint64_t dropped = state->metric_capacity_dropped.exchange(0, std::memory_order_acq_rel); + std::uint64_t dropped = state->dropped_frame_record_count.exchange(0, std::memory_order_acq_rel); if (dropped) { state->aggregate.input_capacity_dropped += dropped; changed = true; @@ -418,21 +406,19 @@ struct Performance_Shower_Private { changed = true; } if (changed && state->enabled.load(std::memory_order_acquire)) { - state->display_snapshot_slot.store(build_display_snapshot(*state), std::memory_order_release); + state->published_snapshot.store(build_display_snapshot(*state), std::memory_order_release); invoke_update_callback(*state); } - if (state->work_requested.load(std::memory_order_acquire)) continue; - state->worker_active.store(false, std::memory_order_release); if (!state->work_requested.load(std::memory_order_acquire) || state->worker_active.exchange(true, std::memory_order_acq_rel)) return; } state->worker_active.store(false, std::memory_order_release); } - static std::shared_ptr build_display_snapshot(Performance_Metrics_Worker_State& worker_state) { - Performance_Shower_Private builder; + static std::shared_ptr build_display_snapshot(Performance_Worker_State& worker_state) { + Performance_Overlay_Private builder; builder.aggregate = worker_state.aggregate; builder.field_layout_states = worker_state.field_layout_states; builder.rebuild_lines(); @@ -446,11 +432,10 @@ struct Performance_Shower_Private { snapshot->lines = builder.stripped_lines(); return snapshot; } - - Performance_Shower_Render_State state; + Performance_Overlay_Render_State state; { std::lock_guard lock(worker_state.options_mutex); - static_cast(state) = worker_state.options; + static_cast(state) = worker_state.options; } Image measure_image(1, 1); measure_image.fill(Color::transparent()); @@ -467,20 +452,18 @@ struct Performance_Shower_Private { } worker_state.field_layout_states = builder.field_layout_states; snapshot->lines = builder.display_lines(); - builder.update_content_width(&state, worker_state.held_content_width, viewport.width); + builder.update_content_width(&state, worker_state.maximum_content_width, viewport.width); double line_height = std::max(1.0, metrics.line_height()); double panel_width = std::min(builder.content_width, static_cast(std::max(0, viewport.width))); double height = builder.panel_height(line_height, &state, viewport.height); if (panel_width <= 0.0 || height <= 0.0) return snapshot; - double content_height = builder.content_height(line_height, &state); double content_viewport_height = builder.content_viewport_height(&state, height); double max_scroll = std::max(0.0, content_height - content_viewport_height); double scroll = performance_clamp_scroll_offset(worker_state.scroll_offset.load(std::memory_order_acquire), max_scroll); worker_state.scroll_offset.store(scroll, std::memory_order_release); builder.panel_rect = RectF{0.0, 0.0, panel_width, height}; - Image image(static_cast(std::ceil(panel_width)), static_cast(std::ceil(height))); image.fill(Color::transparent()); Canvas canvas(image); @@ -524,11 +507,11 @@ struct Performance_Shower_Private { worker_state.last_scroll_thumb_rect = builder.scroll_thumb_rect; worker_state.last_content_viewport_height = content_viewport_height; worker_state.last_line_height = line_height; - worker_state.last_max_scroll_offset = max_scroll; + worker_state.maximum_scroll_offset = max_scroll; return snapshot; } private: - static Size current_viewport(const Performance_Metrics_Worker_State& worker_state) { + static Size current_viewport(const Performance_Worker_State& worker_state) { int width = worker_state.viewport_width.load(std::memory_order_acquire); int height = worker_state.viewport_height.load(std::memory_order_acquire); if (width > 0 && height > 0) @@ -541,13 +524,13 @@ private: static_cast(std::min(frame.pixel_height, static_cast(std::numeric_limits::max()))) }; } - static std::uint64_t current_viewport_version(const Performance_Metrics_Worker_State& worker_state) { + static std::uint64_t current_viewport_version(const Performance_Worker_State& worker_state) { std::uint64_t version = worker_state.viewport_version.load(std::memory_order_acquire); if (version || !worker_state.aggregate.has_frame) return version; return worker_state.aggregate.latest.viewport_version; } - static void invoke_update_callback(Performance_Metrics_Worker_State& worker_state) { + static void invoke_update_callback(Performance_Worker_State& worker_state) { std::function callback; { std::lock_guard lock(worker_state.update_callback_mutex); @@ -556,7 +539,7 @@ private: if (callback) callback(); } - static bool consume_scroll_commands(Performance_Metrics_Worker_State& worker_state) { + static bool consume_scroll_commands(Performance_Worker_State& worker_state) { double offset = worker_state.scroll_offset.load(std::memory_order_acquire); double previous = offset; double line_height = std::max(1.0, worker_state.last_line_height); @@ -568,36 +551,36 @@ private: offset += static_cast(page_delta) * std::max(line_height, worker_state.last_content_viewport_height * 0.8); bool dragging = worker_state.drag_active.load(std::memory_order_acquire); bool drag_end = worker_state.drag_end_requested.exchange(false, std::memory_order_acq_rel); - if (dragging && worker_state.last_max_scroll_offset > 0.0) { + if (dragging && worker_state.maximum_scroll_offset > 0.0) { const RectF& track = worker_state.last_scroll_track_rect; const RectF& thumb = worker_state.last_scroll_thumb_rect; double travel = track.height - thumb.height; if (track.height > 0.0 && thumb.height > 0.0 && travel > 0.0) { double thumb_top = worker_state.drag_position_y.load(std::memory_order_acquire) - - worker_state.drag_anchor_y.load(std::memory_order_acquire); + - worker_state.drag_anchor_y.load(std::memory_order_acquire); double ratio = (thumb_top - track.y) / travel; - offset = std::clamp(ratio, 0.0, 1.0) * worker_state.last_max_scroll_offset; + offset = std::clamp(ratio, 0.0, 1.0) * worker_state.maximum_scroll_offset; } } if (drag_end) worker_state.drag_active.store(false, std::memory_order_release); - offset = performance_clamp_scroll_offset(offset, worker_state.last_max_scroll_offset); + offset = performance_clamp_scroll_offset(offset, worker_state.maximum_scroll_offset); worker_state.scroll_offset.store(offset, std::memory_order_release); return wheel_delta != 0.0 || page_delta != 0 || drag_end || std::abs(offset - previous) > 0.01; } static std::string value(double number, int precision = 2) { return format_number(number, {.precision = precision}); } - double panel_height(double line_height, Performance_Shower_Render_State* state, int plot_height) const { + double panel_height(double line_height, Performance_Overlay_Render_State* state, int plot_height) const { return std::min(content_height(line_height, state), static_cast(std::max(0, plot_height))); } - double content_height(double line_height, Performance_Shower_Render_State* state) const { + double content_height(double line_height, Performance_Overlay_Render_State* state) const { return line_height * static_cast(render_lines.size()) + state->top_margin + state->bottom_margin; } - double content_viewport_height(Performance_Shower_Render_State* state, double height) const { + double content_viewport_height(Performance_Overlay_Render_State* state, double height) const { return std::max(0.0, height - state->top_margin - state->bottom_margin); } - void update_scroll_bar_rects(Performance_Shower_Render_State* state, double max_scroll, double scroll, double visible_height, double total_height) { + void update_scroll_bar_rects(Performance_Overlay_Render_State* state, double max_scroll, double scroll, double visible_height, double total_height) { if (max_scroll <= 0.0 || panel_rect.width <= 0.0 || panel_rect.height <= 0.0 || total_height <= 0.0) { scroll_bar_rect = {}; scroll_thumb_rect = {}; @@ -622,125 +605,125 @@ private: static bool contains(std::string_view text, std::string_view needle) { return text.find(needle) != std::string_view::npos; } - static Performance_Field_Id field_id_from_key(std::string_view key) { + static Performance_Metric_Id field_id_from_key(std::string_view key) { if (key == "frame_id") - return Performance_Field_Id::Frame_Id; + return Performance_Metric_Id::Frame_Id; if (key == "input_version") - return Performance_Field_Id::Input_Version; + return Performance_Metric_Id::Input_Version; if (key == "render_period") - return Performance_Field_Id::Render_Period; + return Performance_Metric_Id::Render_Period; if (key == "paint_period") - return Performance_Field_Id::Paint_Period; + return Performance_Metric_Id::Paint_Period; if (key == "user_period") - return Performance_Field_Id::User_Period; + return Performance_Metric_Id::User_Period; if (key == "target_period") - return Performance_Field_Id::Target_Period; + return Performance_Metric_Id::Target_Period; if (key == "wait_21") - return Performance_Field_Id::Wait_21; + return Performance_Metric_Id::Wait_21; if (key == "wait_12") - return Performance_Field_Id::Wait_12; + return Performance_Metric_Id::Wait_12; if (key == "wait_23") - return Performance_Field_Id::Wait_23; + return Performance_Metric_Id::Wait_23; if (key == "wait_32") - return Performance_Field_Id::Wait_32; + return Performance_Metric_Id::Wait_32; if (key == "taskflow_workers") - return Performance_Field_Id::Worker_Count; + return Performance_Metric_Id::Worker_Count; if (key == "taskflow_active") - return Performance_Field_Id::Active_Workers; + return Performance_Metric_Id::Active_Workers; if (key == "taskflow_queued_frames") - return Performance_Field_Id::Queued_Frame_Jobs; + return Performance_Metric_Id::Queued_Frame_Jobs; if (key == "taskflow_active_frames") - return Performance_Field_Id::Active_Frame_Jobs; + return Performance_Metric_Id::Active_Frame_Jobs; if (key == "taskflow_submitted") - return Performance_Field_Id::Submitted_Tasks; + return Performance_Metric_Id::Submitted_Jobs; if (key == "taskflow_started") - return Performance_Field_Id::Started_Tasks; + return Performance_Metric_Id::Started_Task_Nodes; if (key == "taskflow_completed") - return Performance_Field_Id::Completed_Tasks; + return Performance_Metric_Id::Completed_Task_Nodes; if (key == "taskflow_rejected") - return Performance_Field_Id::Rejected_Frame_Jobs; + return Performance_Metric_Id::Rejected_Frame_Jobs; if (key == "taskflow_queue_wait_avg") - return Performance_Field_Id::Queue_Wait_Avg; + return Performance_Metric_Id::Queue_Wait_Avg; if (key == "taskflow_queue_wait_p95") - return Performance_Field_Id::Queue_Wait_P95; + return Performance_Metric_Id::Queue_Wait_Max; if (key == "taskflow_run_avg") - return Performance_Field_Id::Task_Run_Avg; + return Performance_Metric_Id::Task_Run_Avg; if (key == "taskflow_run_p95") - return Performance_Field_Id::Task_Run_P95; + return Performance_Metric_Id::Task_Run_Max; if (key == "frame_worker_tasks") - return Performance_Field_Id::Frame_Task_Count; + return Performance_Metric_Id::Frame_Task_Count; if (key == "frame_worker_peak") - return Performance_Field_Id::Frame_Peak_Parallelism; + return Performance_Metric_Id::Frame_Peak_Parallelism; if (key == "frame_worker_wait_max") - return Performance_Field_Id::Frame_Wait_Max; + return Performance_Metric_Id::Frame_Wait_Max; if (key == "frame_worker_run_total") - return Performance_Field_Id::Frame_Run_Total; + return Performance_Metric_Id::Frame_Run_Total; if (key == "frame_outcome") - return Performance_Field_Id::Outcome; + return Performance_Metric_Id::Outcome; if (key == "cache_hit_count") - return Performance_Field_Id::Cache_Hit; + return Performance_Metric_Id::Cache_Hit; if (key == "cache_miss_count") - return Performance_Field_Id::Cache_Miss; + return Performance_Metric_Id::Cache_Miss; if (key == "cache_hit_ratio") - return Performance_Field_Id::Cache_Ratio; + return Performance_Metric_Id::Cache_Ratio; if (key == "cache_rebuild_count") - return Performance_Field_Id::Cache_Rebuild_Count; + return Performance_Metric_Id::Cache_Rebuild_Count; if (key == "cache_rebuild_time") - return Performance_Field_Id::Cache_Rebuild_Time; + return Performance_Metric_Id::Cache_Rebuild_Time; if (key == "cache_compose_time") - return Performance_Field_Id::Cache_Compose_Time; + return Performance_Metric_Id::Cache_Compose_Time; if (key == "raw_input_count") - return Performance_Field_Id::Raw_Input_Count; + return Performance_Metric_Id::Raw_Input_Count; if (key == "prepared_output_count") - return Performance_Field_Id::Prepared_Output_Count; + return Performance_Metric_Id::Prepared_Output_Count; if (key == "observed_frame_count") - return Performance_Field_Id::Observed_Frame_Count; + return Performance_Metric_Id::Observed_Frame_Count; if (key == "consumed_outcome_count") - return Performance_Field_Id::Consumed_Frame_Count; + return Performance_Metric_Id::Consumed_Frame_Count; if (key == "superseded_outcome_count") - return Performance_Field_Id::Superseded_Frame_Count; + return Performance_Metric_Id::Superseded_Frame_Count; if (key == "cancelled_outcome_count") - return Performance_Field_Id::Cancelled_Frame_Count; + return Performance_Metric_Id::Cancelled_Frame_Count; if (key == "input_capacity_dropped") - return Performance_Field_Id::Dropped_Input_Count; + return Performance_Metric_Id::Dropped_Input_Count; if (ends_with(key, "_cache_hit")) - return Performance_Field_Id::Cache_Hit; + return Performance_Metric_Id::Cache_Hit; if (ends_with(key, "_cache_miss")) - return Performance_Field_Id::Cache_Miss; + return Performance_Metric_Id::Cache_Miss; if (ends_with(key, "_cache_rebuild")) - return Performance_Field_Id::Cache_Rebuild_Count; + return Performance_Metric_Id::Cache_Rebuild_Count; if (ends_with(key, "_cache_ratio")) - return Performance_Field_Id::Cache_Ratio; + return Performance_Metric_Id::Cache_Ratio; if (ends_with(key, "_cache_image_area")) - return Performance_Field_Id::Cache_Image_Area; + return Performance_Metric_Id::Cache_Image_Area; if (ends_with(key, "_cache_image_bytes")) - return Performance_Field_Id::Cache_Image_Bytes; + return Performance_Metric_Id::Cache_Image_Bytes; if (ends_with(key, "_cache_edit_version")) - return Performance_Field_Id::Cache_Edit_Version; + return Performance_Metric_Id::Cache_Edit_Version; if (ends_with(key, "_cache_ready_version")) - return Performance_Field_Id::Cache_Ready_Version; + return Performance_Metric_Id::Cache_Ready_Version; if (contains(key, "ratio")) { if (ends_with(key, "_instant")) - return Performance_Field_Id::Current_Percent; + return Performance_Metric_Id::Current_Percent; if (ends_with(key, "_smooth")) - return Performance_Field_Id::Smooth_Percent; + return Performance_Metric_Id::Smooth_Percent; if (ends_with(key, "_variation")) - return Performance_Field_Id::Variation_Percent; + return Performance_Metric_Id::Variation_Percent; if (ends_with(key, "_p95")) - return Performance_Field_Id::P95_Percent; - return Performance_Field_Id::Current_Percent; + return Performance_Metric_Id::P95_Percent; + return Performance_Metric_Id::Current_Percent; } if (ends_with(key, "_instant")) - return Performance_Field_Id::Current_Ms; + return Performance_Metric_Id::Current_Ms; if (ends_with(key, "_smooth") || ends_with(key, "_srtt")) - return Performance_Field_Id::Smooth_Ms; + return Performance_Metric_Id::Smooth_Ms; if (ends_with(key, "_variation") || ends_with(key, "_jitter")) - return Performance_Field_Id::Variation_Ms; + return Performance_Metric_Id::Variation_Ms; if (ends_with(key, "_p95")) - return Performance_Field_Id::P95_Ms; + return Performance_Metric_Id::P95_Ms; if (ends_with(key, "_fps") || ends_with(key, "_count")) - return Performance_Field_Id::Generic_Count; - return Performance_Field_Id::Generic_Number; + return Performance_Metric_Id::Generic_Count; + return Performance_Metric_Id::Generic_Number; } static constexpr std::array outcome_values() { return { @@ -755,14 +738,14 @@ private: } void seed_static_field_widths(Canvas& canvas) { for (Frame_Outcome outcome : outcome_values()) { - Performance_Text_Run run; + Performance_Text_Span run; run.value = true; - run.field_id = Performance_Field_Id::Outcome; + run.field_id = Performance_Metric_Id::Outcome; run.text = outcome_text(outcome); measure_run(canvas, run); } } - static std::string marked_value(Performance_Field_Id field_id, std::string text) { + static std::string marked_value(Performance_Metric_Id field_id, std::string text) { std::string result; result.reserve(text.size() + 12); result.push_back('\x1f'); @@ -952,18 +935,18 @@ private: } const Frame_Lifecycle_Record& frame = aggregate.latest; const Refresh_Control_Snapshot& refresh = frame.refresh; - const Frame_Worker_Stat& worker = frame.worker; + const Frame_Worker_Stats& worker = frame.worker; const Render_Executor_Snapshot& executor = worker.executor_at_finish; std::uint64_t aggregate_cache_total = aggregate.cache_hit_count + aggregate.cache_miss_count; std::uint64_t latest_render_time = frame_render_time_ns(frame); double cache_hit_ratio = aggregate_cache_total ? static_cast(aggregate.cache_hit_count) * 100.0 / static_cast(aggregate_cache_total) : 0.0; lines.clear(); - lines.push_back("frame:" + count_text("frame_id", frame.frame_id) + " input_ver:" + count_text("input_version", frame.input_version) + " outcome:" + marked_value(Performance_Field_Id::Outcome, outcome_text(frame.outcome)) + " limit:" + limit_source_text(refresh.source)); + lines.push_back("frame:" + count_text("frame_id", frame.frame_id) + " input_ver:" + count_text("input_version", frame.input_version) + " outcome:" + marked_value(Performance_Metric_Id::Outcome, outcome_text(frame.outcome)) + " limit:" + limit_source_text(refresh.source)); lines.push_back("period render:" + period_text("render_period", refresh.render_period_ns) + " paint:" + period_text("paint_period", refresh.paint_period_ns) + " user:" + period_text("user_period", refresh.user_period_ns) + " target:" + period_text("target_period", refresh.target_period_ns)); lines.push_back("wait 21:" + ns_text("wait_21", frame.wait_21_ns) + "ms 12:" + ns_text("wait_12", frame.wait_12_ns) + "ms 23:" + ns_text("wait_23", frame.wait_23_ns) + "ms 32:" + ns_text("wait_32", frame.wait_32_ns) + "ms"); lines.push_back("taskflow workers:" + count_text("taskflow_workers", static_cast(executor.worker_count)) + " active:" + count_text("taskflow_active", static_cast(executor.active_workers)) + " queued_frames:" + count_text("taskflow_queued_frames", static_cast(executor.queued_frame_jobs)) + " active_frames:" + count_text("taskflow_active_frames", static_cast(executor.active_frame_jobs))); - lines.push_back("taskflow tasks submitted:" + count_text("taskflow_submitted", executor.submitted_tasks) + " started:" + count_text("taskflow_started", executor.started_tasks) + " completed:" + count_text("taskflow_completed", executor.completed_tasks) + " rejected_frames:" + count_text("taskflow_rejected", executor.rejected_frame_jobs)); - lines.push_back("taskflow wait avg:" + ns_text("taskflow_queue_wait_avg", executor.average_queue_wait_ns) + "ms p95:" + ns_text("taskflow_queue_wait_p95", executor.p95_queue_wait_ns) + "ms run avg:" + ns_text("taskflow_run_avg", executor.average_task_duration_ns) + "ms p95:" + ns_text("taskflow_run_p95", executor.p95_task_duration_ns) + "ms"); + lines.push_back("taskflow tasks submitted:" + count_text("taskflow_submitted", executor.submitted_jobs) + " started:" + count_text("taskflow_started", executor.started_task_nodes) + " completed:" + count_text("taskflow_completed", executor.completed_task_nodes) + " rejected_frames:" + count_text("taskflow_rejected", executor.rejected_frame_jobs)); + lines.push_back("taskflow wait avg:" + ns_text("taskflow_queue_wait_avg", executor.average_queue_wait_ns) + "ms p95:" + ns_text("taskflow_queue_wait_p95", executor.max_queue_wait_ns) + "ms run avg:" + ns_text("taskflow_run_avg", executor.average_task_duration_ns) + "ms p95:" + ns_text("taskflow_run_p95", executor.max_task_duration_ns) + "ms"); lines.push_back("frame worker tasks:" + count_text("frame_worker_tasks", worker.task_count) + " peak_parallel:" + count_text("frame_worker_peak", worker.peak_parallelism) + " wait_max:" + ns_text("frame_worker_wait_max", worker.queue_wait_max_ns) + "ms run_total:" + ns_text("frame_worker_run_total", worker.worker_run_total_ns) + "ms"); lines.push_back(duration_line("request_wait", "lifecycle request_wait", aggregate.request_wait_ms)); lines.push_back(duration_line("render_queue_wait", "lifecycle queue_wait", aggregate.render_queue_wait_ms)); @@ -1005,30 +988,30 @@ private: render_lines.clear(); available_width = std::max(1.0, available_width); for (const auto& raw_line : lines) { - std::vector runs = parse_runs(raw_line, canvas); + std::vector runs = parse_runs(raw_line, canvas); append_wrapped_runs(std::move(runs), canvas, available_width); } if (render_lines.empty()) { - Performance_Render_Line line; - Performance_Text_Run run; + Performance_Line_Layout line; + Performance_Text_Span run; run.text = "waiting for frame stats"; measure_run(canvas, run); append_run(line, run); render_lines.push_back(std::move(line)); } } - void update_content_width(Performance_Shower_Render_State* state, double& held_width, int viewport_width) { + void update_content_width(Performance_Overlay_Render_State* state, double& held_width, int viewport_width) { double max_width = 0.0; for (const auto& line : render_lines) max_width = std::max(max_width, line.width); double measured_width = max_width - + static_cast(state->left_margin + state->right_margin + state->scroll_bar_width + state->scroll_bar_margin * 2); + + static_cast(state->left_margin + state->right_margin + state->scroll_bar_width + state->scroll_bar_margin * 2); held_width = std::max(held_width, measured_width); content_width = std::min(held_width, static_cast(std::max(0, viewport_width))); if (content_width <= 0.0) content_width = std::min(measured_width, static_cast(std::max(0, viewport_width))); } - void draw_render_line(Canvas& canvas, const Performance_Render_Line& line, double x, double y) const { + void draw_render_line(Canvas& canvas, const Performance_Line_Layout& line, double x, double y) const { double cursor = x; for (const auto& run : line.runs) { if (run.text.empty()) @@ -1044,17 +1027,17 @@ private: } } } - static double run_width(const Performance_Text_Run& run) { + static double run_width(const Performance_Text_Span& run) { return run.value ? run.reserved_width : run.measured_width; } - static void append_run(Performance_Render_Line& line, const Performance_Text_Run& run) { + static void append_run(Performance_Line_Layout& line, const Performance_Text_Span& run) { line.runs.push_back(run); line.width += run_width(run); } - void append_wrapped_runs(std::vector runs, Canvas& canvas, double available_width) { - Performance_Render_Line current; + void append_wrapped_runs(std::vector runs, Canvas& canvas, double available_width) { + Performance_Line_Layout current; for (auto& original_run : runs) { - Performance_Text_Run run = std::move(original_run); + Performance_Text_Span run = std::move(original_run); while (!run.text.empty()) { double remaining = available_width - current.width; double width = run_width(run); @@ -1063,7 +1046,7 @@ private: append_run(current, run); break; } - Performance_Text_Run fragment = split_text_run(canvas, run, available_width); + Performance_Text_Span fragment = split_text_run(canvas, run, available_width); if (fragment.text.empty()) { append_run(current, run); break; @@ -1077,14 +1060,14 @@ private: } push_non_empty_line(current); } - void push_non_empty_line(Performance_Render_Line& line) { + void push_non_empty_line(Performance_Line_Layout& line) { if (line.runs.empty()) return; render_lines.push_back(std::move(line)); line = {}; } - Performance_Text_Run split_text_run(Canvas& canvas, Performance_Text_Run& run, double available_width) { - Performance_Text_Run fragment; + Performance_Text_Span split_text_run(Canvas& canvas, Performance_Text_Span& run, double available_width) { + Performance_Text_Span fragment; if (run.value || run.text.empty()) return fragment; std::size_t split = split_utf8_text_to_width(canvas, run.text, available_width); @@ -1133,8 +1116,8 @@ private: return best; return next_utf8_boundary(text, 0); } - std::vector parse_runs(const std::string& line, Canvas& canvas) { - std::vector runs; + std::vector parse_runs(const std::string& line, Canvas& canvas) { + std::vector runs; std::size_t pos = 0; while (pos < line.size()) { if (line[pos] == '\x1f') { @@ -1142,10 +1125,10 @@ private: std::size_t end = sep == std::string::npos ? std::string::npos : line.find('\x1d', sep + 1); if (sep != std::string::npos && end != std::string::npos) { unsigned long id = std::stoul(line.substr(pos + 1, sep - pos - 1)); - Performance_Text_Run run; + Performance_Text_Span run; run.value = true; if (id < performance_field_count) - run.field_id = static_cast(id); + run.field_id = static_cast(id); run.text = line.substr(sep + 1, end - sep - 1); measure_run(canvas, run); runs.push_back(std::move(run)); @@ -1154,7 +1137,7 @@ private: } } std::size_t next = line.find('\x1f', pos); - Performance_Text_Run run; + Performance_Text_Span run; run.text = line.substr(pos, next == std::string::npos ? std::string::npos : next - pos); measure_run(canvas, run); runs.push_back(std::move(run)); @@ -1164,7 +1147,7 @@ private: } return runs; } - void measure_run(Canvas& canvas, Performance_Text_Run& run) { + void measure_run(Canvas& canvas, Performance_Text_Span& run) { run.measured_width = run.text.empty() ? 0.0 : canvas.measure_text(run.text).width; if (!run.value) { run.reserved_width = run.measured_width; @@ -1172,11 +1155,11 @@ private: } auto index = static_cast(run.field_id); if (index >= field_layout_states.size()) - index = static_cast(Performance_Field_Id::Generic_Number); + index = static_cast(Performance_Metric_Id::Generic_Number); field_layout_states[index].max_value_width = std::max(field_layout_states[index].max_value_width, run.measured_width); run.reserved_width = field_layout_states[index].max_value_width; } - static std::string render_line_text(const Performance_Render_Line& line) { + static std::string render_line_text(const Performance_Line_Layout& line) { std::string text; for (const auto& run : line.runs) text += run.text; diff --git a/Core/plottable/Selection_Rectangle_Overlay.cpp b/Core/plottable/Selection_Rectangle_Overlay.cpp new file mode 100644 index 0000000..011f8cf --- /dev/null +++ b/Core/plottable/Selection_Rectangle_Overlay.cpp @@ -0,0 +1,73 @@ +#include "Selection_Rectangle_Overlay_p.h" +#include "../base/Memory.h" +namespace renderive { +RENDERIVE_DEFINE_RENDERABLE_BINDING(Selection_Rectangle_Overlay, Selection_Rectangle_Overlay_Private, Selection_Rectangle_Overlay_Render_State, Selection_Rectangle_Overlay_Input_Data, "Selection_Rectangle_Overlay") +Selection_Rectangle_Overlay::Builder::Builder(std::shared_ptr parent, std::shared_ptr key_axis, std::shared_ptr value_axis) { + ASSERT(parent && parent->attached_to_plot(), "Selection_Rectangle_Overlay build error! parent invalid"); + ASSERT(key_axis && value_axis, "Selection_Rectangle_Overlay build error! axis == nullptr"); + ASSERT(key_axis->attached_to_plot(), "Selection_Rectangle_Overlay build error! key_axis->plot == nullptr"); + ASSERT(key_axis->shares_plot_with(*value_axis), "Selection_Rectangle_Overlay build error! key_axis->plot != value_axis->plot"); + ASSERT(parent->shares_plot_with(*key_axis), "Selection_Rectangle_Overlay build error! parent->plot != key_axis->plot"); + ASSERT(key_axis->orientation() != value_axis->orientation(), "Selection_Rectangle_Overlay build error! axes must be orthogonal"); + this->parent = parent; + this->domain_axis = key_axis; + this->value_axis = value_axis; +} +std::shared_ptr Selection_Rectangle_Overlay::Builder::build() { + auto ret = renderive::make_shared(); + ret->init(parent); + Selection_Rectangle_Overlay_Private* pd = ret->d(); + Selection_Rectangle_Overlay_Render_State* sc = reinterpret_cast(pd->state(State_Edit)); + sc->horizontal_axis = domain_axis; + sc->vertical_axis = value_axis; + sc->label_font = font; + sc->label_pen = font_pen; + sc->selection_brush = rect_brush; + sc->selection_border_pen = border_pen; + return ret; +} +void Selection_Rectangle_Overlay::set_horizontal_axis(std::shared_ptr axis) { + Render_Edit_Lease edit(d()); + edit->horizontal_axis = std::weak_ptr(axis); +} +void Selection_Rectangle_Overlay::set_vertical_axis(std::shared_ptr axis) { + Render_Edit_Lease edit(d()); + edit->vertical_axis = std::weak_ptr(axis); +} +Font Selection_Rectangle_Overlay::label_font() { + return d()->state_data(State_Edit)->label_font; +} +Pen Selection_Rectangle_Overlay::label_pen() { + return d()->state_data(State_Edit)->label_pen; +} +Brush Selection_Rectangle_Overlay::selection_brush() { + return d()->state_data(State_Edit)->selection_brush; +} +Pen Selection_Rectangle_Overlay::selection_border_pen() { + return d()->state_data(State_Edit)->selection_border_pen; +} +void Selection_Rectangle_Overlay::set_label_font(const Font& font) { + Render_Edit_Lease edit(d()); + edit->label_font = font; +} +void Selection_Rectangle_Overlay::set_label_pen(const Pen& pen) { + Render_Edit_Lease edit(d()); + edit->label_pen = pen.color.a != 0 ? pen : Pen{.style = Line_Style::None}; +} +void Selection_Rectangle_Overlay::set_selection_brush(const Brush& brush) { + Render_Edit_Lease edit(d()); + edit->selection_brush = brush.color.a != 0 ? brush : Brush{}; +} +void Selection_Rectangle_Overlay::set_selection_border_pen(const Pen& pen) { + Render_Edit_Lease edit(d()); + edit->selection_border_pen = pen.color.a != 0 ? pen : Pen{.style = Line_Style::None}; +} +std::vector Selection_Rectangle_Overlay::selected_regions() { + return d()->state_data(State_Edit)->rects; +} +void Selection_Rectangle_Overlay::clear_selected_regions() { + Render_Edit_Lease edit(d()); + edit->rects.clear(); + d()->active.store(false, std::memory_order_release); +} +} // namespace renderive diff --git a/Core/plottable/Multi_Select_Rect.h b/Core/plottable/Selection_Rectangle_Overlay.h similarity index 61% rename from Core/plottable/Multi_Select_Rect.h rename to Core/plottable/Selection_Rectangle_Overlay.h index eb35f0b..9d8f06e 100644 --- a/Core/plottable/Multi_Select_Rect.h +++ b/Core/plottable/Selection_Rectangle_Overlay.h @@ -6,58 +6,58 @@ #include "../base/Text.h" #include "global.h" namespace renderive { -struct Multi_Select_Rect_Private; -inline Brush default_multi_select_rect_brush() { +struct Selection_Rectangle_Overlay_Private; +inline Brush default_selection_rectangle_overlay_brush() { return Brush{Color{0, 0, 255, 50}, Brush_Style::Solid}; } -inline Pen default_multi_select_border_pen() { +inline Pen default_selection_rectangle_overlay_pen() { return Pen{Color::white(), 1.0, Line_Style::Dash}; } /// @brief 多区域框选图元。 -class LIB_DECL Multi_Select_Rect : public Renderable { +class LIB_DECL Selection_Rectangle_Overlay : public Renderable { public: /// @brief 创建多区域框选图元。 - Multi_Select_Rect(); + Selection_Rectangle_Overlay(); /// @brief 设置水平坐标轴。 void set_horizontal_axis(std::shared_ptr axis); /// @brief 设置垂直坐标轴。 void set_vertical_axis(std::shared_ptr axis); /// @brief 返回标注字体。 - Font font(); + Font label_font(); /// @brief 返回标注画笔。 - Pen font_pen(); + Pen label_pen(); /// @brief 返回矩形填充刷。 - Brush rect_brush(); + Brush selection_brush(); /// @brief 返回矩形边框画笔。 - Pen border_pen(); + Pen selection_border_pen(); /// @brief 设置标注字体。 - void set_font(const Font& font); + void set_label_font(const Font& font); /// @brief 设置标注画笔。 - void set_font_pen(const Pen& pen); + void set_label_pen(const Pen& pen); /// @brief 设置矩形填充刷。 - void set_rect_brush(const Brush& brush); + void set_selection_brush(const Brush& brush); /// @brief 设置矩形边框画笔。 - void set_border_pen(const Pen& pen); - std::vector selection_rects(); - void clear_selection(); + void set_selection_border_pen(const Pen& pen); + std::vector selected_regions(); + void clear_selected_regions(); struct Builder; private: - Multi_Select_Rect_Private* d(); + Selection_Rectangle_Overlay_Private* d(); Render_Object_Owner create_render_data() override; Render_Object_Owner create_render_state() override; Render_Object_Owner create_input_data() override; }; /// @brief 多区域框选构造器。 -struct LIB_DECL Multi_Select_Rect::Builder { +struct LIB_DECL Selection_Rectangle_Overlay::Builder { SETTER(Font, font, Font()) SETTER(Pen, font_pen, Pen{.color = Color::white()}) - SETTER(Brush, rect_brush, default_multi_select_rect_brush()) - SETTER(Pen, border_pen, default_multi_select_border_pen()) + SETTER(Brush, rect_brush, default_selection_rectangle_overlay_brush()) + SETTER(Pen, border_pen, default_selection_rectangle_overlay_pen()) /// @brief 创建多区域框选构造器。 Builder(std::shared_ptr parent, std::shared_ptr key_axis, std::shared_ptr value_axis); /// @brief 构建并返回多区域框选对象。 - std::shared_ptr build(); - std::weak_ptr key_axis; + std::shared_ptr build(); + std::weak_ptr domain_axis; std::weak_ptr value_axis{}; std::shared_ptr parent{}; }; diff --git a/Core/plottable/Multi_Select_Rect_p.h b/Core/plottable/Selection_Rectangle_Overlay_p.h similarity index 81% rename from Core/plottable/Multi_Select_Rect_p.h rename to Core/plottable/Selection_Rectangle_Overlay_p.h index d9eb0c1..c5fe13c 100644 --- a/Core/plottable/Multi_Select_Rect_p.h +++ b/Core/plottable/Selection_Rectangle_Overlay_p.h @@ -10,26 +10,22 @@ #include "../event/Pointer_Event.h" #include "../base/String_Format.h" #include "../render/Canvas.h" -#include "Multi_Select_Rect.h" - +#include "Selection_Rectangle_Overlay.h" namespace renderive { - -struct Multi_Select_Rect_Render_State : Render_State { +struct Selection_Rectangle_Overlay_Render_State : Render_State { std::vector rects; - Font font; - Pen border_pen, font_pen = Pen{Color::white()}; - Brush rect_brush = Brush{Color{0, 0, 255, 50}, Brush_Style::Solid}; + Font label_font; + Pen selection_border_pen, label_pen = Pen{Color::white()}; + Brush selection_brush = Brush{Color{0, 0, 255, 50}, Brush_Style::Solid}; std::weak_ptr horizontal_axis{}, vertical_axis{}; - Multi_Select_Rect_Render_State() { - border_pen.style = Line_Style::Dash; - border_pen.color = Color::white(); + Selection_Rectangle_Overlay_Render_State() { + selection_border_pen.style = Line_Style::Dash; + selection_border_pen.color = Color::white(); } }; - -struct Multi_Select_Rect_Input_Data : Input_Data {}; -struct Multi_Select_Rect_Private : Typed_Render_Data, Hit_Testable, Pointer_Interactive, Key_Press_Interactive { +struct Selection_Rectangle_Overlay_Input_Data : Input_Data {}; +struct Selection_Rectangle_Overlay_Private : Typed_Render_Data, Hit_Testable, Pointer_Interactive, Key_Press_Interactive { std::atomic_bool active{false}; - bool select_test(const PointF& pos) override { auto s = render_state(); auto horizontal_axis = s->horizontal_axis.lock(); @@ -45,11 +41,10 @@ struct Multi_Select_Rect_Private : Typed_Render_Data edit(this); + Render_Edit_Lease edit(this); auto horizontal_axis = edit->horizontal_axis.lock(); auto vertical_axis = edit->vertical_axis.lock(); if (!horizontal_axis || !vertical_axis) @@ -58,7 +53,8 @@ struct Multi_Select_Rect_Private : Typed_Render_Data& rect_list = edit->rects; if (!static_cast(event.modifiers & Keyboard_Modifier::Ctrl)) { rect_list.clear(); - } else { + } + else { int n = static_cast(rect_list.size()); for (int i = n - 1; i >= 0; i--) { auto& rect = rect_list[i]; @@ -73,13 +69,12 @@ struct Multi_Select_Rect_Private : Typed_Render_Data edit(this); + Render_Edit_Lease edit(this); auto horizontal_axis = edit->horizontal_axis.lock(); auto vertical_axis = edit->vertical_axis.lock(); if (!horizontal_axis || !vertical_axis) @@ -95,22 +90,20 @@ struct Multi_Select_Rect_Private : Typed_Render_Data edit(this); + Render_Edit_Lease edit(this); if (!edit->rects.empty() && (std::abs(edit->rects.back().width) < 1e-12 || std::abs(edit->rects.back().height) < 1e-12)) edit->rects.pop_back(); event.accept(); } - void key_press_event(const Key_Event& event) override { if (event.key != Key::Escape || !active.load(std::memory_order_acquire)) return; - Render_Edit_Lease edit(this); + Render_Edit_Lease edit(this); active.store(false, std::memory_order_release); std::vector& rect_list = edit->rects; if (rect_list.empty()) @@ -118,9 +111,8 @@ struct Multi_Select_Rect_Private : Typed_Render_Datahorizontal_axis.lock(); auto vertical_axis = s->vertical_axis.lock(); if (!horizontal_axis || !vertical_axis) @@ -142,12 +134,12 @@ struct Multi_Select_Rect_Private : Typed_Render_Dataunit_text_font()); Text_Metrics yfm = canvas.measure_text("M"); - canvas.set_pen(s->border_pen); - canvas.set_brush(s->rect_brush); + canvas.set_pen(s->selection_border_pen); + canvas.set_brush(s->selection_brush); for (auto& rect : draw_rect_list) canvas.draw_rect(rect); - canvas.set_pen(s->font_pen); - canvas.set_font(s->font); + canvas.set_pen(s->label_pen); + canvas.set_font(s->label_font); int n = static_cast(draw_rect_list.size()); for (int i = 0; i < n; ++i) { RectF& rect = draw_rect_list[i]; @@ -155,9 +147,9 @@ struct Multi_Select_Rect_Private : Typed_Render_Dataunit_text(); + + horizontal_axis->unit_text(); std::string text2 = "offset_y == " + format_number(offset_y, Number_Format{Number_Notation::General, 6}) - + vertical_axis->unit_text(); + + vertical_axis->unit_text(); double width1 = canvas.measure_text(text1).width + 32.0; double width2 = canvas.measure_text(text2).width + 32.0; double rect1_x = rect.x + rect.width / 2.0 - width1 / 2.0; @@ -170,5 +162,4 @@ struct Multi_Select_Rect_Private : Typed_Render_Dataedit_state_value(&Spectrum_Render_State::frequency_range); } -double Spectrum::middle_sweep_frequency() { - return d()->edit_state_value(&Spectrum_Render_State::middle_sweep_frequency); +double Spectrum::center_frequency() { + return d()->edit_state_value(&Spectrum_Render_State::center_frequency); } -void Spectrum::set_middle_sweep_frequency(double value) { - d()->set_state_value(&Spectrum_Render_State::middle_sweep_frequency, value); +void Spectrum::set_center_frequency(double value) { + d()->set_state_value(&Spectrum_Render_State::center_frequency, value); } Range Spectrum::sweep_frequency_range() { return d()->edit_state_value(&Spectrum_Render_State::sweep_frequency_range); @@ -41,23 +41,23 @@ void Spectrum::set_sweep_frequency_range(Range value) { return; d()->set_state_value(&Spectrum_Render_State::sweep_frequency_range, std::move(value)); } -bool Spectrum::use_max_line() { - return d()->edit_state_value(&Spectrum_Render_State::use_max_line); +bool Spectrum::max_hold_visible() { + return d()->edit_state_value(&Spectrum_Render_State::max_hold_visible); } -void Spectrum::set_use_max_line(bool value) { - d()->set_state_value(&Spectrum_Render_State::use_max_line, value); +void Spectrum::set_max_hold_visible(bool value) { + d()->set_state_value(&Spectrum_Render_State::max_hold_visible, value); } -bool Spectrum::use_min_line() { - return d()->edit_state_value(&Spectrum_Render_State::use_min_line); +bool Spectrum::min_hold_visible() { + return d()->edit_state_value(&Spectrum_Render_State::min_hold_visible); } -void Spectrum::set_use_min_line(bool value) { - d()->set_state_value(&Spectrum_Render_State::use_min_line, value); +void Spectrum::set_min_hold_visible(bool value) { + d()->set_state_value(&Spectrum_Render_State::min_hold_visible, value); } -bool Spectrum::use_max_marker() { - return d()->edit_state_value(&Spectrum_Render_State::use_max_marker); +bool Spectrum::max_marker_visible() { + return d()->edit_state_value(&Spectrum_Render_State::max_marker_visible); } -void Spectrum::set_use_max_marker(bool value) { - d()->set_state_value(&Spectrum_Render_State::use_max_marker, value); +void Spectrum::set_max_marker_visible(bool value) { + d()->set_state_value(&Spectrum_Render_State::max_marker_visible, value); } bool Spectrum::use_min_marker() { return d()->edit_state_value(&Spectrum_Render_State::use_min_marker); @@ -65,11 +65,11 @@ bool Spectrum::use_min_marker() { void Spectrum::set_use_min_marker(bool value) { d()->set_state_value(&Spectrum_Render_State::use_min_marker, value); } -bool Spectrum::use_sweep_frequency_rect() { - return d()->edit_state_value(&Spectrum_Render_State::use_sweep_frequency_rect); +bool Spectrum::sweep_region_visible() { + return d()->edit_state_value(&Spectrum_Render_State::sweep_region_visible); } -void Spectrum::set_use_sweep_frequency_rect(bool value) { - d()->set_state_value(&Spectrum_Render_State::use_sweep_frequency_rect, value); +void Spectrum::set_sweep_region_visible(bool value) { + d()->set_state_value(&Spectrum_Render_State::sweep_region_visible, value); } bool Spectrum::visible_range_only() { return d()->edit_state_value(&Spectrum_Render_State::visible_range_only); @@ -83,11 +83,11 @@ Line_Interpolation_Mode Spectrum::interpolation_mode() { void Spectrum::set_interpolation_mode(Line_Interpolation_Mode value) { d()->set_state_value(&Spectrum_Render_State::interpolation_mode, value); } -Line_Sampling_Mode Spectrum::sample_mode() { - return d()->edit_state_value(&Spectrum_Render_State::sample_mode); +Line_Sampling_Strategy Spectrum::sample_mode() { + return d()->edit_state_value(&Spectrum_Render_State::sampling_strategy); } -void Spectrum::set_sample_mode(Line_Sampling_Mode value) { - d()->set_state_value(&Spectrum_Render_State::sample_mode, value); +void Spectrum::set_sample_mode(Line_Sampling_Strategy value) { + d()->set_state_value(&Spectrum_Render_State::sampling_strategy, value); } Brush Spectrum::max_brush() { return d()->edit_state_value(&Spectrum_Render_State::max_brush); @@ -95,11 +95,11 @@ Brush Spectrum::max_brush() { void Spectrum::set_max_brush(Brush value) { d()->set_state_value(&Spectrum_Render_State::max_brush, std::move(value)); } -Brush Spectrum::cur_brush() { - return d()->edit_state_value(&Spectrum_Render_State::cur_brush); +Brush Spectrum::current_brush() { + return d()->edit_state_value(&Spectrum_Render_State::current_brush); } -void Spectrum::set_cur_brush(Brush value) { - d()->set_state_value(&Spectrum_Render_State::cur_brush, std::move(value)); +void Spectrum::set_current_brush(Brush value) { + d()->set_state_value(&Spectrum_Render_State::current_brush, std::move(value)); } Brush Spectrum::min_brush() { return d()->edit_state_value(&Spectrum_Render_State::min_brush); @@ -113,10 +113,10 @@ Pen Spectrum::max_pen() { void Spectrum::set_max_pen(Pen value) { d()->set_state_value(&Spectrum_Render_State::max_pen, std::move(value)); } -Pen Spectrum::cur_pen() { +Pen Spectrum::current_pen() { return d()->edit_state_value(&Spectrum_Render_State::cur_pen); } -void Spectrum::set_cur_pen(Pen value) { +void Spectrum::set_current_pen(Pen value) { d()->set_state_value(&Spectrum_Render_State::cur_pen, std::move(value)); } Pen Spectrum::min_pen() { @@ -125,11 +125,11 @@ Pen Spectrum::min_pen() { void Spectrum::set_min_pen(Pen value) { d()->set_state_value(&Spectrum_Render_State::min_pen, std::move(value)); } -Pen Spectrum::select_marker_pen() { - return d()->edit_state_value(&Spectrum_Render_State::select_marker_pen); +Pen Spectrum::selected_marker_pen() { + return d()->edit_state_value(&Spectrum_Render_State::selected_marker_pen); } -void Spectrum::set_select_marker_pen(Pen value) { - d()->set_state_value(&Spectrum_Render_State::select_marker_pen, std::move(value)); +void Spectrum::set_selected_marker_pen(Pen value) { + d()->set_state_value(&Spectrum_Render_State::selected_marker_pen, std::move(value)); } Pen Spectrum::marker_pen() { return d()->edit_state_value(&Spectrum_Render_State::marker_pen); @@ -143,11 +143,11 @@ Pen Spectrum::middle_frequency_pen() { void Spectrum::set_middle_frequency_pen(Pen value) { d()->set_state_value(&Spectrum_Render_State::middle_frequency_pen, std::move(value)); } -Brush Spectrum::sweep_rect_brush() { - return d()->edit_state_value(&Spectrum_Render_State::sweep_rect_brush); +Brush Spectrum::sweep_region_brush() { + return d()->edit_state_value(&Spectrum_Render_State::sweep_region_brush); } -void Spectrum::set_sweep_rect_brush(Brush value) { - d()->set_state_value(&Spectrum_Render_State::sweep_rect_brush, std::move(value)); +void Spectrum::set_sweep_region_brush(Brush value) { + d()->set_state_value(&Spectrum_Render_State::sweep_region_brush, std::move(value)); } void Spectrum::set_frequency_point_size(int frequency_point_size) { Render_Edit_Lease edit(d()); @@ -179,26 +179,26 @@ std::shared_ptr Spectrum::Builder::build() { PROP_R(std::weak_ptr, power_axis); PROP_R(int, frequency_point_size); PROP_R(Range, frequency_range); - PROP_R(double, middle_sweep_frequency); + PROP_R(double, center_frequency); PROP_R(Range, sweep_frequency_range); - PROP_R(bool, use_max_line); - PROP_R(bool, use_min_line); - PROP_R(bool, use_max_marker); + PROP_R(bool, max_hold_visible); + PROP_R(bool, min_hold_visible); + PROP_R(bool, max_marker_visible); PROP_R(bool, use_min_marker); - PROP_R(bool, use_sweep_frequency_rect); + PROP_R(bool, sweep_region_visible); PROP_R(bool, visible_range_only); PROP_R(Line_Interpolation_Mode, interpolation_mode); - PROP_R(Line_Sampling_Mode, sample_mode); + PROP_R(Line_Sampling_Mode, sampling_strategy); PROP_R(Brush, max_brush); - PROP_R(Brush, cur_brush); + PROP_R(Brush, current_brush); PROP_R(Brush, min_brush); PROP_R(Pen, max_pen); PROP_R(Pen, cur_pen); PROP_R(Pen, min_pen); - PROP_R(Pen, select_marker_pen); + PROP_R(Pen, selected_marker_pen); PROP_R(Pen, marker_pen); PROP_R(Pen, middle_frequency_pen); - PROP_R(Brush, sweep_rect_brush); + PROP_R(Brush, sweep_region_brush); sc->frequency_point_size = std::max(1, sc->frequency_point_size); if (sc->frequency_range.length() == 0.0) sc->frequency_range = {0.0, 1.0}; @@ -254,17 +254,17 @@ void Spectrum_Private::set_frequency_data(std::pmr::vector& line_data, c int min_index = 0, max_index = 0; for (int i = 0; i < s->frequency_point_size; ++i) { double& cur_data = cur_powers[i]; - if (s->use_max_line) { + if (s->max_hold_visible) { double hold_max = max_data ? max_data->at(i) : cur_data; if (hold_max > max_powers.at(i)) max_powers[i] = hold_max; } - if (s->use_min_line) { + if (s->min_hold_visible) { double hold_min = min_data ? min_data->at(i) : cur_data; if (hold_min < min_powers.at(i)) min_powers[i] = hold_min; } - if (s->use_max_marker && cur_data > max) { + if (s->max_marker_visible && cur_data > max) { max = cur_data; max_index = i; } @@ -283,9 +283,9 @@ double Spectrum_Private::get_y(double x, bool& ok, Line_Interpolation_Mode mode) ok = false; return -1; } - double index = coord_to_source_index(cache_frequency_range, cur_powers.size(), x); + double index = coordinate_to_source_index(cache_frequency_range, cur_powers.size(), x); ok = true; - return interpolate_line_value(index, cur_powers.size(), mode, [this](int i) { + return interpolate_sample_value(index, cur_powers.size(), mode, [this](int i) { return cur_powers.at(i); }); } @@ -299,13 +299,13 @@ void Spectrum_Private::draw_power_curve(Canvas& canvas, Spectrum_Render_State* s Axis_Mapping_2D mapping = Axis_Render_Access::mapping(frequency_axis.get(), power_axis.get()); std::pmr::vector points(frame_memory_resource()); int point_count = static_cast(powers.size()); - if (s->sample_mode == Line_Sampling_Mode::Pixel_Peak_Envelope) { - points = Curve_Utils::create_peak_bucket_points(mapping, s->frequency_range, point_count, point_count, s->visible_range_only, [&powers](int i) { + if (s->sampling_strategy == Line_Sampling_Strategy::Pixel_Min_Max_Envelope) { + points = Curve_Utils::build_pixel_envelope_points(mapping, s->frequency_range, point_count, point_count, s->visible_range_only, [&powers](int i) { return powers.at(i); }); } else { - points = Curve_Utils::create_sampled_points(mapping, s->frequency_range, point_count, point_count, s->visible_range_only, s->interpolation_mode, [&powers](int i) { + points = Curve_Utils::build_resampled_points(mapping, s->frequency_range, point_count, point_count, s->visible_range_only, s->interpolation_mode, [&powers](int i) { return powers.at(i); }); } @@ -321,13 +321,13 @@ void Spectrum_Private::update_marker_items(const Spectrum_Render_State* s) { prepared_label_items.clear(); if (!frequency_axis || !power_axis) return; - auto append_marker = [&](double frequency, double power, bool drawLine, bool selected) { - Pen pen = selected ? s->select_marker_pen : s->marker_pen; + auto append_marker = [&](double frequency, double power, bool draw_line, bool selected) { + Pen pen = selected ? s->selected_marker_pen : s->marker_pen; Marker_Item marker; marker.position = PointF(frequency, power); marker.radius = 2.0; marker.pen = pen; - marker.mode = drawLine ? Marker_Mode::Domain_Line : Marker_Mode::Point; + marker.mode = draw_line ? Marker_Mode::Domain_Line : Marker_Mode::Point; prepared_marker_items.push_back(marker); std::string frequency_text = std::to_string(frequency) + frequency_axis->unit_text(); std::string power_text = std::to_string(power) + power_axis->unit_text(); @@ -335,7 +335,7 @@ void Spectrum_Private::update_marker_items(const Spectrum_Render_State* s) { frequency_label.position = marker.position; frequency_label.offset = PointF(0.0, -28.0); frequency_label.text = frequency_text; - frequency_label.alignment = Text_Align::HCenter | Text_Align::Bottom; + frequency_label.alignment = Text_Align::Horizontal_Center | Text_Align::Bottom; frequency_label.text_pen = pen; prepared_label_items.push_back(frequency_label); Label_Item power_label = frequency_label; @@ -343,7 +343,7 @@ void Spectrum_Private::update_marker_items(const Spectrum_Render_State* s) { power_label.text = power_text; prepared_label_items.push_back(power_label); }; - if (s->use_max_marker) + if (s->max_marker_visible) append_marker(max_marker_key, max_marker_value, false, false); if (s->use_min_marker) append_marker(min_marker_key, min_marker_value, false, false); @@ -352,12 +352,12 @@ void Spectrum_Private::update_marker_items(const Spectrum_Render_State* s) { bool ok; double value = get_y(custom_marker.frequency, ok, s->interpolation_mode); if (ok) - append_marker(custom_marker.frequency, value, custom_marker.draw_line, i == s->cur_select_index); + append_marker(custom_marker.frequency, value, custom_marker.is_line_marker, i == s->cur_select_index); } } void Spectrum_Private::draw_spectrum(Canvas& canvas, Spectrum_Render_State* s) { - if (s->use_sweep_frequency_rect) { - s->draw_axis_rect(canvas, s->sweep_frequency_range, s->middle_sweep_frequency); + if (s->sweep_region_visible) { + s->draw_axis_rect(canvas, s->sweep_frequency_range, s->center_frequency); } } void Spectrum_Private::draw_marker_items(Canvas& canvas, Spectrum_Render_State* s) { @@ -405,11 +405,11 @@ void Spectrum_Private::draw_label_items(Canvas& canvas, Spectrum_Render_State* s Text_Metrics tm = canvas.measure_text(item.text); PointF anchor = mapping.map(item.position); PointF top_left{anchor.x + item.offset.x, anchor.y + item.offset.y}; - if ((item.alignment & Text_Align::HCenter) == Text_Align::HCenter) + if ((item.alignment & Text_Align::Horizontal_Center) == Text_Align::Horizontal_Center) top_left.x -= tm.width / 2.0; else if ((item.alignment & Text_Align::Right) == Text_Align::Right) top_left.x -= tm.width; - if ((item.alignment & Text_Align::VCenter) == Text_Align::VCenter) + if ((item.alignment & Text_Align::Vertical_Center) == Text_Align::Vertical_Center) top_left.y -= tm.height / 2.0; else if ((item.alignment & Text_Align::Bottom) == Text_Align::Bottom) top_left.y -= tm.height; @@ -420,17 +420,17 @@ void Spectrum_Private::draw_label_items(Canvas& canvas, Spectrum_Render_State* s canvas.draw_rect(rect); } canvas.set_pen(item.text_pen); - canvas.draw_text(rect, Text_Align::Left | Text_Align::VCenter, item.text); + canvas.draw_text(rect, Text_Align::Left | Text_Align::Vertical_Center, item.text); canvas.restore(); } } void Spectrum_Private::draw(Canvas& canvas, const Plot_Render_Snapshot&) { auto s = render_state(); - draw_power_curve(canvas, s, cur_powers, s->cur_pen, s->cur_brush); + draw_power_curve(canvas, s, cur_powers, s->cur_pen, s->current_brush); draw_spectrum(canvas, s); - if (s->use_max_line) + if (s->max_hold_visible) draw_power_curve(canvas, s, max_powers, s->max_pen, s->max_brush); - if (s->use_min_line) + if (s->min_hold_visible) draw_power_curve(canvas, s, min_powers, s->min_pen, s->min_brush); draw_marker_items(canvas, s); draw_label_items(canvas, s); @@ -438,10 +438,10 @@ void Spectrum_Private::draw(Canvas& canvas, const Plot_Render_Snapshot&) { auto frequency_axis = s->frequency_axis.lock(); auto power_axis = s->power_axis.lock(); if (frequency_axis && power_axis) - q()->draw_hover(&canvas, frequency_axis.get(), power_axis.get()); + q()->draw_hover_tooltip(&canvas, frequency_axis.get(), power_axis.get()); } } -void Spectrum::give_data(std::span line_data) { +void Spectrum::update_samples(std::span line_data) { if (!ok()) return; Spectrum_Private* pd = d(); @@ -451,15 +451,15 @@ void Spectrum::give_data(std::span line_data) { { Render_State_Lease state(pd); frequency_point_size = state->frequency_point_size; - use_max_line = state->use_max_line; - use_min_line = state->use_min_line; + use_max_line = state->max_hold_visible; + use_min_line = state->min_hold_visible; } if (line_data.size() != frequency_point_size) return; Render_Input_Lease input(pd); input->push(line_data, use_max_line, use_min_line); } -void Spectrum::give_data(std::pmr::vector&& line_data) { +void Spectrum::update_samples(std::pmr::vector&& line_data) { if (!ok()) return; Spectrum_Private* pd = d(); @@ -469,8 +469,8 @@ void Spectrum::give_data(std::pmr::vector&& line_data) { { Render_State_Lease state(pd); frequency_point_size = state->frequency_point_size; - use_max_line = state->use_max_line; - use_min_line = state->use_min_line; + use_max_line = state->max_hold_visible; + use_min_line = state->min_hold_visible; } if (line_data.size() != frequency_point_size) return; @@ -490,8 +490,8 @@ Update_Ticket Spectrum::submit_data(std::span line_data) { { Render_State_Lease state(pd); frequency_point_size = state->frequency_point_size; - use_max_line = state->use_max_line; - use_min_line = state->use_min_line; + use_max_line = state->max_hold_visible; + use_min_line = state->min_hold_visible; } if (line_data.size() != frequency_point_size) { update_state->complete_all(std::make_error_code(std::errc::invalid_argument), Update_Outcome::Cancelled); @@ -518,8 +518,8 @@ Update_Ticket Spectrum::submit_data(std::pmr::vector&& line_data) { { Render_State_Lease state(pd); frequency_point_size = state->frequency_point_size; - use_max_line = state->use_max_line; - use_min_line = state->use_min_line; + use_max_line = state->max_hold_visible; + use_min_line = state->min_hold_visible; } if (line_data.size() != frequency_point_size) { update_state->complete_all(std::make_error_code(std::errc::invalid_argument), Update_Outcome::Cancelled); @@ -550,19 +550,19 @@ void Spectrum::remove_custom_marker(double frequency) { } } } -void Spectrum::remove_current_marker() { +void Spectrum::remove_selected_marker() { Render_Edit_Lease edit(d()); if (edit->cur_select_index < 0 || edit->cur_select_index >= (int)edit->marker_list.size()) return; edit->marker_list.erase(edit->marker_list.begin() + edit->cur_select_index); edit->cur_select_index = -1; } -void Spectrum::clear_all_custom_marker() { +void Spectrum::clear_custom_markers() { Render_Edit_Lease edit(d()); edit->marker_list.clear(); } -double Spectrum::get_mark_frequency(int mark_index) { - auto render_state = d()->state_data(SRC::Edit); +double Spectrum::marker_frequency(int mark_index) { + auto render_state = d()->state_data(State_Edit); if (mark_index < 0 || mark_index >= (int)render_state->marker_list.size()) return -1; return render_state->marker_list[mark_index].frequency; @@ -578,31 +578,31 @@ void Spectrum::set_current_marker_frequency(double frequency) { Render_Edit_Lease edit(d()); edit->set_cur_frequency(frequency); } -int Spectrum::select_line_marker_size() { - auto render_state = d()->state_data(SRC::Edit); +int Spectrum::selectable_line_marker_count() { + auto render_state = d()->state_data(State_Edit); return (int)render_state->marker_list.size(); } -int Spectrum::cur_select_marker_index() { - auto render_state = d()->state_data(SRC::Edit); +int Spectrum::selected_marker_index() { + auto render_state = d()->state_data(State_Edit); return render_state->cur_select_index; } -void Spectrum::set_selected_line_marker(int marker_index) { +void Spectrum::set_selected_marker_index(int marker_index) { Render_Edit_Lease edit(d()); edit->set_select_index(marker_index); } -void Spectrum::select_next() { +void Spectrum::select_next_marker() { Render_Edit_Lease edit(d()); edit->select_next_marker(); } -void Spectrum::select_previous() { +void Spectrum::select_previous_marker() { Render_Edit_Lease edit(d()); edit->select_prev_marker(); } -void Spectrum::un_select_marker() { +void Spectrum::clear_marker_selection() { Render_Edit_Lease edit(d()); edit->un_select(); } -double Spectrum::get_power(double frequency, bool& ok) { +double Spectrum::power_at(double frequency, bool& ok) { return d()->get_y(frequency, ok, interpolation_mode()); } } // namespace renderive diff --git a/Core/plottable/Spectrum.h b/Core/plottable/Spectrum.h index b6d10ab..f918d64 100644 --- a/Core/plottable/Spectrum.h +++ b/Core/plottable/Spectrum.h @@ -9,7 +9,7 @@ #include "../base/Memory.h" #include "../base/Style.h" #include "../primitive/Curve.h" -#include "Hover_Info.h" +#include "Hover_Tooltip.h" #include "Interpolation.h" namespace renderive { struct Spectrum_Private; @@ -29,49 +29,55 @@ public: /// @brief 频率数据范围。 PROP(Range, frequency_range); /// @brief 中心扫频频率。 - PROP(double, middle_sweep_frequency); + PROP(double, center_frequency); /// @brief 扫频高亮频率范围。 PROP(Range, sweep_frequency_range); /// @brief 是否绘制最大保持线。 - PROP(bool, use_max_line); + PROP(bool, max_hold_visible); /// @brief 是否绘制最小保持线。 - PROP(bool, use_min_line); + PROP(bool, min_hold_visible); /// @brief 是否显示最大值标记。 - PROP(bool, use_max_marker); + bool max_marker_visible(); + void set_max_marker_visible(bool); /// @brief 是否显示最小值标记。 PROP(bool, use_min_marker); /// @brief 是否显示扫频高亮区域。 - PROP(bool, use_sweep_frequency_rect); + bool sweep_region_visible(); + void set_sweep_region_visible(bool); /// @brief 是否只生成当前可见频率范围。 PROP(bool, visible_range_only); /// @brief 折线插值模式。 PROP(Line_Interpolation_Mode, interpolation_mode); /// @brief 采样降采样模式。 - PROP(Line_Sampling_Mode, sample_mode); + PROP(Line_Sampling_Strategy, sample_mode); /// @brief 最大保持线填充刷。 PROP(Brush, max_brush); /// @brief 当前频谱线填充刷。 - PROP(Brush, cur_brush); + Brush current_brush(); + void set_current_brush(Brush); /// @brief 最小保持线填充刷。 PROP(Brush, min_brush); /// @brief 最大保持线画笔。 PROP(Pen, max_pen); /// @brief 当前频谱线画笔。 - PROP(Pen, cur_pen); + Pen current_pen(); + void set_current_pen(Pen); /// @brief 最小保持线画笔。 PROP(Pen, min_pen); /// @brief 选中标记画笔。 - PROP(Pen, select_marker_pen); + Pen selected_marker_pen(); + void set_selected_marker_pen(Pen); /// @brief 普通标记画笔。 PROP(Pen, marker_pen); /// @brief 中心频率线画笔。 PROP(Pen, middle_frequency_pen); /// @brief 扫频区域填充刷。 - PROP(Brush, sweep_rect_brush); + Brush sweep_region_brush(); + void set_sweep_region_brush(Brush); /// @brief 写入一帧频谱线数据。 - void give_data(std::span line_data); + void update_samples(std::span line_data); /// @brief 移动写入一帧频谱线数据。 - void give_data(std::pmr::vector&& line_data); + void update_samples(std::pmr::vector&& line_data); /// @brief 提交一帧频谱线数据并返回完成票据。 Update_Ticket submit_data(std::span line_data); /// @brief 移动提交一帧频谱线数据并返回完成票据。 @@ -82,10 +88,10 @@ public: std::pmr::vector values(memory_resource(Memory_Domain::Spectrum)); values.resize(count); std::forward(writer)(std::span(values.data(), values.size())); - give_data(std::move(values)); + update_samples(std::move(values)); } /// 查询指定频率位置的功率值。 - double get_power(double frequency, bool& ok); + double power_at(double frequency, bool& ok); /// 添加自定义频率标记。 void add_custom_marker(double frequency); /// 添加自定义线标记。 @@ -93,23 +99,23 @@ public: /// 删除指定频率附近的自定义标记。 void remove_custom_marker(double frequency); /// 删除当前选中的标记。 - void remove_current_marker(); + void remove_selected_marker(); /// 清空所有自定义标记。 - void clear_all_custom_marker(); + void clear_custom_markers(); /// 返回可选择线标记数量。 - int select_line_marker_size(); + int selectable_line_marker_count(); /// 返回当前选中线标记索引。 - int cur_select_marker_index(); + int selected_marker_index(); /// 设置当前选中线标记索引。 - void set_selected_line_marker(int marker_index); + void set_selected_marker_index(int marker_index); /// 选择下一个线标记。 - void select_next(); + void select_next_marker(); /// 取消当前线标记选择。 - void un_select_marker(); + void clear_marker_selection(); /// 选择上一个线标记。 - void select_previous(); + void select_previous_marker(); /// 返回指定标记索引对应频率。 - double get_mark_frequency(int mark_index); + double marker_frequency(int mark_index); /// 设置指定标记频率。 void set_marker_frequency(int marker_index, double frequency); /// 设置当前选中标记频率。 @@ -121,64 +127,64 @@ private: Render_Object_Owner create_render_state() override; Render_Object_Owner create_input_data() override; }; -struct Spectrum_PROP { +struct Spectrum_Prop { std::weak_ptr frequency_axis{}; std::weak_ptr power_axis{}; int frequency_point_size{}; Range frequency_range{}; - double middle_sweep_frequency = 50; + double center_frequency = 50; Range sweep_frequency_range{40, 60}; - bool use_max_line = false; - bool use_min_line = false; - bool use_max_marker = false; + bool max_hold_visible = false; + bool min_hold_visible = false; + bool max_marker_visible = false; bool use_min_marker = false; - bool use_sweep_frequency_rect = false; + bool sweep_region_visible = false; bool visible_range_only = true; - Line_Interpolation_Mode interpolation_mode = Line_Interpolation_Mode::Linear_Display; - Line_Sampling_Mode sample_mode = Line_Sampling_Mode::All_Samples; + Line_Interpolation_Mode interpolation_mode = Line_Interpolation_Mode::Linear_Value; + Line_Sampling_Strategy sampling_strategy = Line_Sampling_Strategy::All_Samples; Brush max_brush; - Brush cur_brush; + Brush current_brush; Brush min_brush; - Pen max_pen = Pen{Color::red_color()}; - Pen cur_pen = Pen{Color::green_color()}; + Pen max_pen = Pen{Color::red()}; + Pen cur_pen = Pen{Color::green()}; Pen min_pen = Pen{Color::white()}; - Pen select_marker_pen = Pen{Color{0, 0, 139, 255}, 2.0}; - Pen marker_pen = Pen{Color::red_color()}; - Pen middle_frequency_pen = Pen{Color::red_color()}; - Brush sweep_rect_brush = Brush{Color{255, 255, 0, 100}, Brush_Style::Solid}; - Spectrum_PROP() { + Pen selected_marker_pen = Pen{Color{0, 0, 139, 255}, 2.0}; + Pen marker_pen = Pen{Color::red()}; + Pen middle_frequency_pen = Pen{Color::red()}; + Brush sweep_region_brush = Brush{Color{255, 255, 0, 100}, Brush_Style::Solid}; + Spectrum_Prop() { max_brush = Brush{}; - cur_brush = Brush{}; + current_brush = Brush{}; min_brush = Brush{}; } }; /// @brief 频谱线构造器。 -struct LIB_DECL Spectrum::Builder : Spectrum_PROP { +struct LIB_DECL Spectrum::Builder : Spectrum_Prop { PROP_B(std::shared_ptr, parent) PROP_B(std::shared_ptr, frequency_axis) PROP_B(std::shared_ptr, power_axis); PROP_B(int, frequency_point_size); PROP_B(Range, frequency_range); - PROP_B(double, middle_sweep_frequency); + PROP_B(double, center_frequency); PROP_B(Range, sweep_frequency_range); - PROP_B(bool, use_max_line); - PROP_B(bool, use_min_line); - PROP_B(bool, use_max_marker); + PROP_B(bool, max_hold_visible); + PROP_B(bool, min_hold_visible); + PROP_B(bool, max_marker_visible); PROP_B(bool, use_min_marker); - PROP_B(bool, use_sweep_frequency_rect); + PROP_B(bool, sweep_region_visible); PROP_B(bool, visible_range_only); PROP_B(Line_Interpolation_Mode, interpolation_mode); - PROP_B(Line_Sampling_Mode, sample_mode); + PROP_B(Line_Sampling_Strategy, sampling_strategy); PROP_B(Brush, max_brush); - PROP_B(Brush, cur_brush); + PROP_B(Brush, current_brush); PROP_B(Brush, min_brush); PROP_B(Pen, max_pen); PROP_B(Pen, cur_pen); PROP_B(Pen, min_pen); - PROP_B(Pen, select_marker_pen); + PROP_B(Pen, selected_marker_pen); PROP_B(Pen, marker_pen); PROP_B(Pen, middle_frequency_pen); - PROP_B(Brush, sweep_rect_brush); + PROP_B(Brush, sweep_region_brush); /// 创建频谱线构造器。 Builder(std::shared_ptr parent, std::shared_ptr frequency_axis, std::shared_ptr axis); /// 构建并返回频谱线对象。 diff --git a/Core/plottable/Spectrum_p.h b/Core/plottable/Spectrum_p.h index 02b0ee2..066da55 100644 --- a/Core/plottable/Spectrum_p.h +++ b/Core/plottable/Spectrum_p.h @@ -13,7 +13,7 @@ #include "../base/Geometry.h" #include "../base/Style.h" #include "../render/Canvas.h" -#include "Hover_Info.h" +#include "Hover_Tooltip.h" #include "Interpolation_p.h" #include "../primitive/Label.h" #include "../primitive/Marker.h" @@ -21,11 +21,11 @@ namespace renderive { struct Spectrum_Marker { Spectrum_Marker() = default; - Spectrum_Marker(double frequency, bool drawLine) : frequency(frequency), draw_line(drawLine) {} + Spectrum_Marker(double frequency, bool is_line_marker) : frequency(frequency), is_line_marker(is_line_marker) {} double frequency{}; - bool draw_line = true; + bool is_line_marker = true; bool operator==(const Spectrum_Marker& other) const { - return std::abs(frequency - other.frequency) < 1e-12 && draw_line == other.draw_line; + return std::abs(frequency - other.frequency) < 1e-12 && is_line_marker == other.is_line_marker; } }; struct Spectrum_Input_Data : Latest_Input_Data { @@ -109,7 +109,7 @@ struct Spectrum_Input_Data : Latest_Input_Data { clear_latest(); } }; -struct Spectrum_Render_State : Render_State, Hover_Info_Render_State, Spectrum_PROP { +struct Spectrum_Render_State : Render_State, Hover_Tooltip_State, Spectrum_Prop { std::pmr::vector marker_list{memory_resource(Memory_Domain::Spectrum)}; int cur_select_index = -1; void un_select() { @@ -146,12 +146,13 @@ struct Spectrum_Render_State : Render_State, Hover_Info_Render_State, Spectrum_P Axis_Mapping_2D mapping = Axis_Render_Access::mapping(frequency_axis.get(), power_axis.get()); canvas.save(); canvas.set_pen(Pen{.style = Line_Style::None}); - canvas.set_brush(sweep_rect_brush); + canvas.set_brush(sweep_region_brush); std::array rect_points{ mapping.map(range.origin, mapping.value.coord_range.origin), mapping.map(range.target, mapping.value.coord_range.origin), mapping.map(range.target, mapping.value.coord_range.target), - mapping.map(range.origin, mapping.value.coord_range.target)}; + mapping.map(range.origin, mapping.value.coord_range.target) + }; canvas.draw_polygon(std::span(rect_points.data(), rect_points.size()), true); canvas.set_pen(middle_frequency_pen); canvas.draw_line( @@ -214,7 +215,7 @@ struct Spectrum_Private : Typed_Render_Data edit(this); - edit->hover_info_pos = pos; + edit->hover_position = pos; edit->hover_info_active = active; } }; diff --git a/Core/plottable/Sweep_Frequency.cpp b/Core/plottable/Sweep_Frequency.cpp deleted file mode 100644 index ee2c213..0000000 --- a/Core/plottable/Sweep_Frequency.cpp +++ /dev/null @@ -1,122 +0,0 @@ -#include -#include "../Axis/Abs_Axis.h" -#include "../base/Memory.h" -#include "Sweep_Frequency_p.h" -namespace renderive { -RENDERIVE_DEFINE_RENDERABLE_BINDING(Sweep_Frequency, Sweep_Frequency_Private, Sweep_Frequency_Render_State, Sweep_Frequency_Input_Data, "Sweep_Frequency") -std::shared_ptr Sweep_Frequency::frequency_axis() { - return d()->edit_state_value(&Sweep_Frequency_Render_State::frequency_axis).lock(); -} -void Sweep_Frequency::set_frequency_axis(std::shared_ptr value) { - d()->set_state_value(&Sweep_Frequency_Render_State::frequency_axis, std::weak_ptr(value)); -} -std::shared_ptr Sweep_Frequency::power_axis() { - return d()->edit_state_value(&Sweep_Frequency_Render_State::power_axis).lock(); -} -void Sweep_Frequency::set_power_axis(std::shared_ptr value) { - d()->set_state_value(&Sweep_Frequency_Render_State::power_axis, std::weak_ptr(value)); -} -Range Sweep_Frequency::frequency_range() { - return d()->edit_state_value(&Sweep_Frequency_Render_State::frequency_range); -} -void Sweep_Frequency::set_frequency_range(Range value) { - if (value.length() == 0.0) - return; - d()->set_state_value(&Sweep_Frequency_Render_State::frequency_range, std::move(value)); -} -int Sweep_Frequency::block_frequency_point_size() { - return d()->edit_state_value(&Sweep_Frequency_Render_State::block_frequency_point_size); -} -void Sweep_Frequency::set_block_frequency_point_size(int value) { - d()->set_state_value(&Sweep_Frequency_Render_State::block_frequency_point_size, std::max(1, value)); -} -int Sweep_Frequency::block_num() { - return d()->edit_state_value(&Sweep_Frequency_Render_State::block_num); -} -void Sweep_Frequency::set_block_num(int value) { - d()->set_state_value(&Sweep_Frequency_Render_State::block_num, std::max(1, value)); -} -Pen Sweep_Frequency::pen() { - return d()->edit_state_value(&Sweep_Frequency_Render_State::pen); -} -void Sweep_Frequency::set_pen(Pen value) { - d()->set_state_value(&Sweep_Frequency_Render_State::pen, std::move(value)); -} -Pen Sweep_Frequency::cur_frequency_pen() { - return d()->edit_state_value(&Sweep_Frequency_Render_State::cur_frequency_pen); -} -void Sweep_Frequency::set_cur_frequency_pen(Pen value) { - d()->set_state_value(&Sweep_Frequency_Render_State::cur_frequency_pen, std::move(value)); -} -bool Sweep_Frequency::visible_range_only() { - return d()->edit_state_value(&Sweep_Frequency_Render_State::visible_range_only); -} -void Sweep_Frequency::set_visible_range_only(bool value) { - d()->set_state_value(&Sweep_Frequency_Render_State::visible_range_only, value); -} -Line_Interpolation_Mode Sweep_Frequency::interpolation_mode() { - return d()->edit_state_value(&Sweep_Frequency_Render_State::interpolation_mode); -} -void Sweep_Frequency::set_interpolation_mode(Line_Interpolation_Mode value) { - d()->set_state_value(&Sweep_Frequency_Render_State::interpolation_mode, value); -} -void Sweep_Frequency::give_data(std::span data) { - if (!ok()) - return; - Sweep_Frequency_Private* pd = d(); - int block_frequency_point_size{}; - { - Render_State_Lease state(pd); - block_frequency_point_size = state->block_frequency_point_size; - } - if (data.size() != block_frequency_point_size) - return; - Render_Input_Lease input(pd); - input->data.push(data, Sweep_Frequency_Input_Data::Latest_Only_Count); -} -void Sweep_Frequency::give_data(std::pmr::vector&& data) { - if (!ok()) - return; - Sweep_Frequency_Private* pd = d(); - int block_frequency_point_size{}; - { - Render_State_Lease state(pd); - block_frequency_point_size = state->block_frequency_point_size; - } - if (data.size() != block_frequency_point_size) - return; - Render_Input_Lease input(pd); - input->data.push(std::move(data), Sweep_Frequency_Input_Data::Latest_Only_Count); -} -Sweep_Frequency::Builder::Builder(std::shared_ptr parent, std::shared_ptr frequency_axis, std::shared_ptr power_axis) { - ASSERT(parent, "Sweep_Frequency build error! parent == nullptr"); - ASSERT(frequency_axis && power_axis, "Sweep_Frequency build error! axis == nullptr"); - ASSERT(frequency_axis->attached_to_plot(), "Sweep_Frequency build error! frequency_axis->plot == nullptr"); - ASSERT(frequency_axis->shares_plot_with(*power_axis), "Sweep_Frequency build error! frequency_axis->plot != power_axis->plot"); - ASSERT(parent->shares_plot_with(*frequency_axis), "Sweep_Frequency build error! parent->plot != axis->plot"); - ASSERT(frequency_axis->orientation() != power_axis->orientation(), "Sweep_Frequency build error! axes must be orthogonal"); - this->parent = parent; - this->frequency_axis = frequency_axis; - this->power_axis = power_axis; -} -std::shared_ptr Sweep_Frequency::Builder::build() { - auto ret = renderive::make_shared(); - ret->init(parent); - Sweep_Frequency_Private* pd = ret->d(); - Sweep_Frequency_Render_State* sc = reinterpret_cast(pd->state(State_Edit)); - PROP_R(std::weak_ptr, frequency_axis) - PROP_R(std::weak_ptr, power_axis) - PROP_R(Range, frequency_range) - PROP_R(int, block_frequency_point_size) - PROP_R(int, block_num) - PROP_R(Pen, pen) - PROP_R(Pen, cur_frequency_pen) - PROP_R(bool, visible_range_only) - PROP_R(Line_Interpolation_Mode, interpolation_mode) - sc->block_frequency_point_size = std::max(1, sc->block_frequency_point_size); - sc->block_num = std::max(1, sc->block_num); - if (sc->frequency_range.length() == 0.0) - sc->frequency_range = {0.0, 1.0}; - return ret; -} -} // namespace renderive diff --git a/Core/plottable/Sweep_Frequency_p.h b/Core/plottable/Sweep_Frequency_p.h deleted file mode 100644 index 5179d5e..0000000 --- a/Core/plottable/Sweep_Frequency_p.h +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once -#include "../Axis/Axis_p.h" -#include "../architecture/Bounded_Input_Buffer.h" -#include "../base/Frame_Memory.h" -#include "../base/Geometry.h" -#include "../base/Style.h" -#include "../event/Pointer_Event.h" -#include "../render/Canvas.h" -#include "../primitive/Curve.h" -#include "../primitive/Curve_Utils_p.h" -#include "Sweep_Frequency.h" -namespace renderive { -struct Sweep_Frequency_Render_State : renderive::Render_State, Sweep_Frequency_Prop {}; -struct Sweep_Frequency_Input_Data : renderive::Input_Data { - static constexpr std::size_t Latest_Only_Count = 1; - Bounded_Vector_Double_Input_Buffer data; - void clear() override { - data.clear(); - } -}; -struct Sweep_Frequency_Private : renderive::Typed_Render_Data { - std::vector frequency_list; - int offset{}; - int block_frequency_point_size{}; - int block_num{}; - Range frequency_range; - bool first_loop = true; - void set_up_frequency(int block_frequency_point_size, int block_num, Range frequency_range) { - this->block_frequency_point_size = block_frequency_point_size; - this->block_num = block_num; - this->frequency_range = frequency_range; - int point_size = block_num * block_frequency_point_size; - if (point_size <= 0) { - frequency_list.clear(); - first_loop = true; - return; - } - frequency_list.resize(point_size); - int space_size = point_size - 1; - if (space_size == 0) { - frequency_list[0].x = frequency_range.origin; - first_loop = true; - return; - } - double step = frequency_range.length() / space_size; - double cur = frequency_range.origin; - for (int i = 0; i < space_size; ++i) { - frequency_list[i].x = cur; - cur += step; - } - frequency_list.back().x = frequency_range.target; - first_loop = true; - } - void prepare_data(const Plot_Render_Snapshot&) override { - sync_state_pipeline(); - Sweep_Frequency_Render_State* s = render_state(); - Sweep_Frequency_Input_Data* d = render_input_data(); - if ( - block_frequency_point_size != s->block_frequency_point_size || - block_num != s->block_num || - frequency_range != s->frequency_range) { - set_up_frequency(s->block_frequency_point_size, s->block_num, s->frequency_range); - offset = 0; - } - d->data.read_all([this, d](const auto& data) { - if ((int)data.size() != block_frequency_point_size || frequency_list.empty()) { - return; - } - PointF* start = &frequency_list[offset * block_frequency_point_size]; - for (int i = 0; i < block_frequency_point_size; ++i) { - start[i].y = data[i]; - } - offset++; - if (offset == block_num) { - offset = 0; - first_loop = false; - } - }); - clear_render_input(); - } - void draw(Canvas& canvas, const Plot_Render_Snapshot& snapshot) override { - (void)snapshot; - Sweep_Frequency_Render_State* s = render_state(); - auto frequency_axis = s->frequency_axis.lock(); - auto power_axis = s->power_axis.lock(); - if (!frequency_axis || !power_axis) - return; - Axis_Mapping_2D mapping = Axis_Render_Access::mapping(frequency_axis.get(), power_axis.get()); - int n = (int)frequency_list.size(); - int available_count = !first_loop ? n : offset * block_frequency_point_size; - std::pmr::vector data(frame_memory_resource()); - data = Curve_Utils::create_sampled_points(mapping, s->frequency_range, n, available_count, s->visible_range_only, s->interpolation_mode, [this](int i) { - return frequency_list.at(i).y; - }); - Curve_Utils::draw_polyline(&canvas, data, s->pen); - canvas.set_pen(s->cur_frequency_pen); - double f = block_num > 1 ? frequency_range.origin + offset * frequency_range.length() / (block_num - 1.0) : frequency_range.origin; - canvas.draw_line( - mapping.map(f, mapping.value.coord_range.origin), - mapping.map(f, mapping.value.coord_range.target)); - } -}; -} // namespace renderive diff --git a/Core/plottable/Sweep_Spectrum.cpp b/Core/plottable/Sweep_Spectrum.cpp new file mode 100644 index 0000000..0a2c469 --- /dev/null +++ b/Core/plottable/Sweep_Spectrum.cpp @@ -0,0 +1,122 @@ +#include +#include "../Axis/Abs_Axis.h" +#include "../base/Memory.h" +#include "Sweep_Spectrum_p.h" +namespace renderive { +RENDERIVE_DEFINE_RENDERABLE_BINDING(Sweep_Spectrum, Sweep_Spectrum_Private, Sweep_Spectrum_Render_State, Sweep_Spectrum_Input_Data, "Sweep_Frequency") +std::shared_ptr Sweep_Spectrum::frequency_axis() { + return d()->edit_state_value(&Sweep_Spectrum_Render_State::frequency_axis).lock(); +} +void Sweep_Spectrum::set_frequency_axis(std::shared_ptr value) { + d()->set_state_value(&Sweep_Spectrum_Render_State::frequency_axis, std::weak_ptr(value)); +} +std::shared_ptr Sweep_Spectrum::power_axis() { + return d()->edit_state_value(&Sweep_Spectrum_Render_State::power_axis).lock(); +} +void Sweep_Spectrum::set_power_axis(std::shared_ptr value) { + d()->set_state_value(&Sweep_Spectrum_Render_State::power_axis, std::weak_ptr(value)); +} +Range Sweep_Spectrum::frequency_range() { + return d()->edit_state_value(&Sweep_Spectrum_Render_State::frequency_range); +} +void Sweep_Spectrum::set_frequency_range(Range value) { + if (value.length() == 0.0) + return; + d()->set_state_value(&Sweep_Spectrum_Render_State::frequency_range, std::move(value)); +} +int Sweep_Spectrum::bins_per_block() { + return d()->edit_state_value(&Sweep_Spectrum_Render_State::bins_per_block); +} +void Sweep_Spectrum::set_bins_per_block(int value) { + d()->set_state_value(&Sweep_Spectrum_Render_State::bins_per_block, std::max(1, value)); +} +int Sweep_Spectrum::block_count() { + return d()->edit_state_value(&Sweep_Spectrum_Render_State::block_num); +} +void Sweep_Spectrum::set_block_count(int value) { + d()->set_state_value(&Sweep_Spectrum_Render_State::block_num, std::max(1, value)); +} +Pen Sweep_Spectrum::pen() { + return d()->edit_state_value(&Sweep_Spectrum_Render_State::pen); +} +void Sweep_Spectrum::set_pen(Pen value) { + d()->set_state_value(&Sweep_Spectrum_Render_State::pen, std::move(value)); +} +Pen Sweep_Spectrum::cur_frequency_pen() { + return d()->edit_state_value(&Sweep_Spectrum_Render_State::current_frequency_pen); +} +void Sweep_Spectrum::set_cur_frequency_pen(Pen value) { + d()->set_state_value(&Sweep_Spectrum_Render_State::current_frequency_pen, std::move(value)); +} +bool Sweep_Spectrum::visible_range_only() { + return d()->edit_state_value(&Sweep_Spectrum_Render_State::visible_range_only); +} +void Sweep_Spectrum::set_visible_range_only(bool value) { + d()->set_state_value(&Sweep_Spectrum_Render_State::visible_range_only, value); +} +Line_Interpolation_Mode Sweep_Spectrum::interpolation_mode() { + return d()->edit_state_value(&Sweep_Spectrum_Render_State::interpolation_mode); +} +void Sweep_Spectrum::set_interpolation_mode(Line_Interpolation_Mode value) { + d()->set_state_value(&Sweep_Spectrum_Render_State::interpolation_mode, value); +} +void Sweep_Spectrum::append_block(std::span data) { + if (!ok()) + return; + Sweep_Spectrum_Private* pd = d(); + int block_frequency_point_size{}; + { + Render_State_Lease state(pd); + block_frequency_point_size = state->bins_per_block; + } + if (data.size() != block_frequency_point_size) + return; + Render_Input_Lease input(pd); + input->data.push(data, Sweep_Spectrum_Input_Data::Latest_Only_Count); +} +void Sweep_Spectrum::append_block(std::pmr::vector&& data) { + if (!ok()) + return; + Sweep_Spectrum_Private* pd = d(); + int block_frequency_point_size{}; + { + Render_State_Lease state(pd); + block_frequency_point_size = state->bins_per_block; + } + if (data.size() != block_frequency_point_size) + return; + Render_Input_Lease input(pd); + input->data.push(std::move(data), Sweep_Spectrum_Input_Data::Latest_Only_Count); +} +Sweep_Spectrum::Builder::Builder(std::shared_ptr parent, std::shared_ptr frequency_axis, std::shared_ptr power_axis) { + ASSERT(parent, "Sweep_Frequency build error! parent == nullptr"); + ASSERT(frequency_axis && power_axis, "Sweep_Frequency build error! axis == nullptr"); + ASSERT(frequency_axis->attached_to_plot(), "Sweep_Frequency build error! frequency_axis->plot == nullptr"); + ASSERT(frequency_axis->shares_plot_with(*power_axis), "Sweep_Frequency build error! frequency_axis->plot != power_axis->plot"); + ASSERT(parent->shares_plot_with(*frequency_axis), "Sweep_Frequency build error! parent->plot != axis->plot"); + ASSERT(frequency_axis->orientation() != power_axis->orientation(), "Sweep_Frequency build error! axes must be orthogonal"); + this->parent = parent; + this->frequency_axis = frequency_axis; + this->power_axis = power_axis; +} +std::shared_ptr Sweep_Spectrum::Builder::build() { + auto ret = renderive::make_shared(); + ret->init(parent); + Sweep_Spectrum_Private* pd = ret->d(); + Sweep_Spectrum_Render_State* sc = reinterpret_cast(pd->state(State_Edit)); + PROP_R(std::weak_ptr, frequency_axis) + PROP_R(std::weak_ptr, power_axis) + PROP_R(Range, frequency_range) + PROP_R(int, bins_per_block) + PROP_R(int, block_num) + PROP_R(Pen, pen) + PROP_R(Pen, current_frequency_pen) + PROP_R(bool, visible_range_only) + PROP_R(Line_Interpolation_Mode, interpolation_mode) + sc->bins_per_block = std::max(1, sc->bins_per_block); + sc->block_num = std::max(1, sc->block_num); + if (sc->frequency_range.length() == 0.0) + sc->frequency_range = {0.0, 1.0}; + return ret; +} +} // namespace renderive diff --git a/Core/plottable/Sweep_Frequency.h b/Core/plottable/Sweep_Spectrum.h similarity index 75% rename from Core/plottable/Sweep_Frequency.h rename to Core/plottable/Sweep_Spectrum.h index 7da04b7..03d8099 100644 --- a/Core/plottable/Sweep_Frequency.h +++ b/Core/plottable/Sweep_Spectrum.h @@ -10,23 +10,23 @@ #include "Interpolation.h" #include "global.h" namespace renderive { -struct Sweep_Frequency_Private; +struct Sweep_Spectrum_Private; /// @brief 扫频频谱图元,按块组织输入频率数据。 -class LIB_DECL Sweep_Frequency : public Renderable { +class LIB_DECL Sweep_Spectrum : public Renderable { public: /// @brief 创建扫频频谱图元。 - Sweep_Frequency(); + Sweep_Spectrum(); /// @brief 写入一块扫频数据。 - void give_data(std::span data); + void append_block(std::span data); /// @brief 移动写入一块扫频数据。 - void give_data(std::pmr::vector&& data); + void append_block(std::pmr::vector&& data); /// @brief 用 writer 填充并写入一块扫频数据。 template - void write_data(std::size_t count, Writer&& writer) { + void write_block(std::size_t count, Writer&& writer) { std::pmr::vector values(memory_resource(Memory_Domain::Other)); values.resize(count); std::forward(writer)(std::span(values.data(), values.size())); - give_data(std::move(values)); + append_block(std::move(values)); } /// @brief 绑定频率轴。 PROP(std::shared_ptr, frequency_axis) @@ -35,9 +35,9 @@ public: /// @brief 扫频频率范围。 PROP(Range, frequency_range) /// @brief 每块频率采样点数。 - PROP(int, block_frequency_point_size) + PROP(int, bins_per_block) /// @brief 扫频块数量。 - PROP(int, block_num) + PROP(int, block_count) /// @brief 频谱线画笔。 PROP(Pen, pen) /// @brief 当前扫频位置画笔。 @@ -48,42 +48,42 @@ public: PROP(Line_Interpolation_Mode, interpolation_mode) struct Builder; private: - Sweep_Frequency_Private* d(); + Sweep_Spectrum_Private* d(); Render_Object_Owner create_render_data() override; Render_Object_Owner create_render_state() override; Render_Object_Owner create_input_data() override; }; -struct Sweep_Frequency_Prop { +struct Sweep_Spectrum_Prop { std::weak_ptr frequency_axis{}; std::weak_ptr power_axis{}; Range frequency_range{}; - int block_frequency_point_size{}; + int bins_per_block{}; int block_num{}; Pen pen; - Pen cur_frequency_pen; + Pen current_frequency_pen; bool visible_range_only = true; - Line_Interpolation_Mode interpolation_mode = Line_Interpolation_Mode::Linear_Display; - Sweep_Frequency_Prop() { + Line_Interpolation_Mode interpolation_mode = Line_Interpolation_Mode::Linear_Value; + Sweep_Spectrum_Prop() { pen = Pen{Color::yellow()}; - cur_frequency_pen = Pen{Color::red_color(), 2.0}; + current_frequency_pen = Pen{Color::red(), 2.0}; } }; /// @brief 扫频频谱构造器。 -struct LIB_DECL Sweep_Frequency::Builder : Sweep_Frequency_Prop { +struct LIB_DECL Sweep_Spectrum::Builder : Sweep_Spectrum_Prop { PROP_B(std::shared_ptr, parent) PROP_B(std::shared_ptr, frequency_axis) PROP_B(std::shared_ptr, power_axis) PROP_B(Range, frequency_range) - PROP_B(int, block_frequency_point_size) + PROP_B(int, bins_per_block) PROP_B(int, block_num) PROP_B(Pen, pen) - PROP_B(Pen, cur_frequency_pen) + PROP_B(Pen, current_frequency_pen) PROP_B(bool, visible_range_only) PROP_B(Line_Interpolation_Mode, interpolation_mode) /// 创建扫频构造器。 Builder(std::shared_ptr parent, std::shared_ptr frequency_axis, std::shared_ptr power_axis); /// 构建并返回扫频对象。 - std::shared_ptr build(); + std::shared_ptr build(); std::shared_ptr parent{}; }; } // namespace renderive diff --git a/Core/plottable/Sweep_Spectrum_p.h b/Core/plottable/Sweep_Spectrum_p.h new file mode 100644 index 0000000..5ef2ed1 --- /dev/null +++ b/Core/plottable/Sweep_Spectrum_p.h @@ -0,0 +1,103 @@ +#pragma once +#include "../Axis/Axis_p.h" +#include "../architecture/Bounded_Input_Buffer.h" +#include "../base/Frame_Memory.h" +#include "../base/Geometry.h" +#include "../base/Style.h" +#include "../event/Pointer_Event.h" +#include "../render/Canvas.h" +#include "../primitive/Curve.h" +#include "../primitive/Curve_Utils_p.h" +#include "Sweep_Spectrum.h" +namespace renderive { +struct Sweep_Spectrum_Render_State : renderive::Render_State, Sweep_Spectrum_Prop {}; +struct Sweep_Spectrum_Input_Data : renderive::Input_Data { + static constexpr std::size_t Latest_Only_Count = 1; + Bounded_Vector_Double_Input_Buffer data; + void clear() override { + data.clear(); + } +}; +struct Sweep_Spectrum_Private : renderive::Typed_Render_Data { + std::vector sweep_points; + int next_block_index{}; + int bins_per_block{}; + int block_count{}; + Range frequency_range; + bool first_sweep_incomplete = true; + void reset_sweep_grid(int block_frequency_point_size, int block_num, Range frequency_range) { + this->bins_per_block = block_frequency_point_size; + this->block_count = block_num; + this->frequency_range = frequency_range; + int total_point_count = block_num * block_frequency_point_size; + if (total_point_count <= 0) { + sweep_points.clear(); + first_sweep_incomplete = true; + return; + } + sweep_points.resize(total_point_count); + int interval_count = total_point_count - 1; + if (interval_count == 0) { + sweep_points[0].x = frequency_range.origin; + first_sweep_incomplete = true; + return; + } + double step = frequency_range.length() / interval_count; + double frequency = frequency_range.origin; + for (int i = 0; i < interval_count; ++i) { + sweep_points[i].x = frequency; + frequency += step; + } + sweep_points.back().x = frequency_range.target; + first_sweep_incomplete = true; + } + void prepare_data(const Plot_Render_Snapshot&) override { + sync_state_pipeline(); + Sweep_Spectrum_Render_State* s = render_state(); + Sweep_Spectrum_Input_Data* d = render_input_data(); + if ( + bins_per_block != s->bins_per_block || + block_count != s->block_num || + frequency_range != s->frequency_range) { + reset_sweep_grid(s->bins_per_block, s->block_num, s->frequency_range); + next_block_index = 0; + } + d->data.read_all([this, d](const auto& data) { + if ((int)data.size() != bins_per_block || sweep_points.empty()) { + return; + } + PointF* start = &sweep_points[next_block_index * bins_per_block]; + for (int i = 0; i < bins_per_block; ++i) { + start[i].y = data[i]; + } + next_block_index++; + if (next_block_index == block_count) { + next_block_index = 0; + first_sweep_incomplete = false; + } + }); + clear_render_input(); + } + void draw(Canvas& canvas, const Plot_Render_Snapshot& snapshot) override { + (void)snapshot; + Sweep_Spectrum_Render_State* s = render_state(); + auto frequency_axis = s->frequency_axis.lock(); + auto power_axis = s->power_axis.lock(); + if (!frequency_axis || !power_axis) + return; + Axis_Mapping_2D mapping = Axis_Render_Access::mapping(frequency_axis.get(), power_axis.get()); + int total_point_count = (int)sweep_points.size(); + int available_count = !first_sweep_incomplete ? total_point_count : next_block_index * bins_per_block; + std::pmr::vector data(frame_memory_resource()); + data = Curve_Utils::build_resampled_points(mapping, s->frequency_range, total_point_count, available_count, s->visible_range_only, s->interpolation_mode, [this](int i) { + return sweep_points.at(i).y; + }); + Curve_Utils::draw_polyline(&canvas, data, s->pen); + canvas.set_pen(s->current_frequency_pen); + double current_frequency = block_count > 1 ? frequency_range.origin + next_block_index * frequency_range.length() / (block_count - 1.0) : frequency_range.origin; + canvas.draw_line( + mapping.map(current_frequency, mapping.value.coord_range.origin), + mapping.map(current_frequency, mapping.value.coord_range.target)); + } +}; +} // namespace renderive diff --git a/Core/plottable/Waterfall.cpp b/Core/plottable/Waterfall.cpp index 99b28f9..2183984 100644 --- a/Core/plottable/Waterfall.cpp +++ b/Core/plottable/Waterfall.cpp @@ -32,11 +32,11 @@ void Waterfall::set_power_range(Range value) { Render_Edit_Lease edit(d()); edit->color_scale.set_range(value); } -int Waterfall::frequency_point_size() { - return d()->edit_state_value(&Waterfall_Render_State::frequency_point_size); +int Waterfall::frequency_bin_count() { + return d()->edit_state_value(&Waterfall_Render_State::frequency_bin_count); } -void Waterfall::set_frequency_point_size(int value) { - d()->set_state_value(&Waterfall_Render_State::frequency_point_size, std::max(1, value)); +void Waterfall::set_frequency_bin_count(int value) { + d()->set_state_value(&Waterfall_Render_State::frequency_bin_count, std::max(1, value)); } bool Waterfall::visible_range_only() { return d()->edit_state_value(&Waterfall_Render_State::visible_range_only); @@ -72,17 +72,17 @@ void Waterfall::set_color_map(Color_Map value) { std::shared_ptr Waterfall::get_color_bar() const { return const_cast(this)->d()->color_bar.lock(); } -void Waterfall::give_data(int tick, std::span data) { +void Waterfall::append_row(int tick, std::span data) { if (!ok()) return; d()->enqueue_row(tick, data); } -void Waterfall::give_data(int tick, std::pmr::vector&& data) { +void Waterfall::append_row(int tick, std::pmr::vector&& data) { if (!ok()) return; d()->enqueue_row(tick, std::move(data)); } -void Waterfall::give_data(Time_Of_Day time, std::span data) { +void Waterfall::append_row(Time_Of_Day time, std::span data) { if (!ok()) return; auto axis = time_axis(); @@ -91,10 +91,10 @@ void Waterfall::give_data(Time_Of_Day time, std::span data) { auto stream = axis->timeline_stream(); if (!stream) return; - int tick = stream->push_time(time); + int tick = stream->append_time(time); d()->enqueue_row(tick, data); } -void Waterfall::give_data(Time_Of_Day time, std::pmr::vector&& data) { +void Waterfall::append_row(Time_Of_Day time, std::pmr::vector&& data) { if (!ok()) return; auto axis = time_axis(); @@ -103,7 +103,7 @@ void Waterfall::give_data(Time_Of_Day time, std::pmr::vector&& data) { auto stream = axis->timeline_stream(); if (!stream) return; - int tick = stream->push_time(time); + int tick = stream->append_time(time); d()->enqueue_row(tick, std::move(data)); } Update_Ticket Waterfall::submit_data(int tick, std::span data) { @@ -143,13 +143,13 @@ std::shared_ptr Waterfall::Builder::build() { PROP_R(std::weak_ptr, frequency_axis) PROP_R(std::weak_ptr, time_axis) PROP_R(Range, frequency_range) - PROP_R(int, frequency_point_size) + PROP_R(int, frequency_bin_count) PROP_R(bool, visible_range_only) PROP_R(Image_Interpolation_Mode, interpolation_mode) PROP_R(Waterfall_Row_Update_Policy, row_update_policy) PROP_R(int, latest_row_min_interval_ms) sc->color_scale = color_scale.clone(); - sc->frequency_point_size = std::max(1, sc->frequency_point_size); + sc->frequency_bin_count = std::max(1, sc->frequency_bin_count); sc->latest_row_min_interval_ms = std::max(1, sc->latest_row_min_interval_ms); if (color_bar_enabled) { auto bar = Color_Bar::Builder(ret).set_color_scale(sc->color_scale).set_name("Waterfall").build(); diff --git a/Core/plottable/Waterfall.h b/Core/plottable/Waterfall.h index 3b8340c..2082a18 100644 --- a/Core/plottable/Waterfall.h +++ b/Core/plottable/Waterfall.h @@ -9,7 +9,7 @@ #include "../base/Time_Of_Day.h" #include "../primitive/Color_Bar.h" #include "../primitive/Color_Scale.h" -#include "Hover_Info.h" +#include "Hover_Tooltip.h" #include "Interpolation.h" namespace renderive { struct Waterfall_Private; @@ -30,13 +30,13 @@ public: /// @brief 创建瀑布图图元。 Waterfall(); /// @brief 写入指定 tick 对应的一行频谱数据。 - void give_data(int tick, std::span data); + void append_row(int tick, std::span data); /// @brief 移动写入指定 tick 对应的一行频谱数据。 - void give_data(int tick, std::pmr::vector&& data); + void append_row(int tick, std::pmr::vector&& data); /// @brief 写入指定时间对应的一行频谱数据。 - void give_data(Time_Of_Day time, std::span data); + void append_row(Time_Of_Day time, std::span data); /// @brief 移动写入指定时间对应的一行频谱数据。 - void give_data(Time_Of_Day time, std::pmr::vector&& data); + void append_row(Time_Of_Day time, std::pmr::vector&& data); /// @brief 提交指定 tick 对应的一行频谱数据并返回完成票据。 Update_Ticket submit_data(int tick, std::span data); /// @brief 移动提交指定 tick 对应的一行频谱数据并返回完成票据。 @@ -47,7 +47,7 @@ public: std::pmr::vector values(memory_resource(Memory_Domain::Waterfall)); values.resize(count); std::forward(writer)(std::span(values.data(), values.size())); - give_data(tick, std::move(values)); + append_row(tick, std::move(values)); } /// @brief 绑定频率轴。 PROP(std::shared_ptr, frequency_axis) @@ -58,7 +58,7 @@ public: /// @brief 功率数据范围。 PROP(Range, power_range) /// @brief 每行频率采样点数。 - PROP(int, frequency_point_size) + PROP(int, frequency_bin_count) /// @brief 是否只生成当前可见频率范围。 PROP(bool, visible_range_only) /// @brief 图像缩放插值模式。 @@ -82,7 +82,7 @@ struct Waterfall_Prop { std::weak_ptr frequency_axis{}; std::weak_ptr time_axis{}; Range frequency_range{0, 10}; - int frequency_point_size{}; + int frequency_bin_count{}; bool visible_range_only = true; Image_Interpolation_Mode interpolation_mode = Image_Interpolation_Mode::Nearest; Waterfall_Row_Update_Policy row_update_policy = Waterfall_Row_Update_Policy::All_Pending; @@ -99,7 +99,7 @@ struct LIB_DECL Waterfall::Builder : Waterfall_Prop { color_scale.set_range(value); return *this; } - PROP_B(int, frequency_point_size) + PROP_B(int, frequency_bin_count) PROP_B(bool, visible_range_only) PROP_B(Image_Interpolation_Mode, interpolation_mode) PROP_B(Waterfall_Row_Update_Policy, row_update_policy) diff --git a/Core/plottable/Waterfall_p.h b/Core/plottable/Waterfall_p.h index 4bc6de2..0d70637 100644 --- a/Core/plottable/Waterfall_p.h +++ b/Core/plottable/Waterfall_p.h @@ -30,7 +30,7 @@ struct Waterfall_Data { std::shared_ptr completion_state; }; struct Waterfall_Input_Data : Input_Data {}; -struct Waterfall_Render_State : Render_State, Hover_Info_Render_State, Waterfall_Prop {}; +struct Waterfall_Render_State : Render_State, Hover_Tooltip_State, Waterfall_Prop {}; struct Waterfall_Ring_Buffer { Psc::StreamRingBuffer_ST buffer{memory_resource(Memory_Domain::Waterfall)}; std::pmr::vector record_buffer{memory_resource(Memory_Domain::Waterfall)}; @@ -283,7 +283,7 @@ struct Waterfall_Private : Typed_Render_Data edit(this); - edit->hover_info_pos = pos; + edit->hover_position = pos; edit->hover_info_active = active; } ~Waterfall_Private() override { @@ -382,7 +382,7 @@ struct Waterfall_Private : Typed_Render_Datafrequency_point_size, row_count = timeline->time_point_size; + int col_count = s->frequency_bin_count, row_count = timeline->time_point_size; if (col_count <= 0 || row_count <= 0) return; if (!ring_buffer.match(col_count, row_count)) { @@ -468,12 +468,12 @@ struct Waterfall_Private : Typed_Render_Datacolor_scale.snapshot(); Abs_Axis* h_axis = frequency_axis.get(); Range h_range = s->frequency_range; - Range v_range{static_cast(timeline.lower), static_cast(timeline.lower + timeline.time_point_size)}; + Range v_range{static_cast(timeline.coordinate_begin), static_cast(timeline.coordinate_begin + timeline.time_point_size)}; if (s->visible_range_only && !intersect_range(s->frequency_range, Axis_Render_Access::coord_range(h_axis), h_range)) { image_draw_visible = false; return; } - int col_count = s->frequency_point_size, row_count = timeline.time_point_size; + int col_count = s->frequency_bin_count, row_count = timeline.time_point_size; if (col_count <= 0 || row_count <= 0 || s->frequency_range.length() == 0.0 || color_scale->range.size() == 0.0) return; double source_start = static_cast(col_count) * (h_range.origin - s->frequency_range.origin) / s->frequency_range.length(); @@ -485,7 +485,7 @@ struct Waterfall_Private : Typed_Render_Datarange.origin; double rate = static_cast(color_scale->color_map.size()) / color_scale->range.size(); int buffer_data_count = ring_buffer.snapshot(); - int start_tick = timeline.lower; + int start_tick = timeline.coordinate_begin; std::uint64_t color_map_hash = color_scale->color_map.hash(); Waterfall_Image_Cache_Key key{ start_tick, @@ -509,10 +509,10 @@ struct Waterfall_Private : Typed_Render_Datacolor_map = color_scale->color_map; request->value_start_coord = value_start_coord; request->rate = rate; - request->lower_stream_tick = timeline.lower_stream_tick; - request->upper_stream_tick = timeline.upper_stream_tick; + request->lower_stream_tick = timeline.first_stream_tick; + request->upper_stream_tick = timeline.last_stream_tick; request->visible_time_count = static_cast(timeline.times.size()); - request->start_coord_to_end_coord = timeline.start_coord_to_end_coord; + request->start_coord_to_end_coord = timeline.newest_at_axis_start; request->draw_frequency_range = h_range; request->draw_time_range = v_range; request->draw_source_rect = RectF(source_start, 0.0, source_end - source_start, static_cast(row_count)); @@ -583,7 +583,7 @@ struct Waterfall_Private : Typed_Render_Datahover_ok(q())) { - q()->draw_hover(&canvas, h_axis, v_axis); + q()->draw_hover_tooltip(&canvas, h_axis, v_axis); } } }; diff --git a/Core/plottable/export.h b/Core/plottable/export.h index 4b6e037..242efcd 100644 --- a/Core/plottable/export.h +++ b/Core/plottable/export.h @@ -2,29 +2,28 @@ #include #include #include "Afterglow.h" -#include "Audio_Frequency.h" -#include "Hover_Info.h" +#include "Frequency_Trace.h" +#include "Hover_Tooltip.h" #include "Interpolation.h" -#include "Multi_Select_Rect.h" -#include "Planisphere.h" -#include "Performance_Shower.h" +#include "Selection_Rectangle_Overlay.h" +#include "Constellation_Diagram.h" +#include "Performance_Overlay.h" #include "Spectrum.h" -#include "Sweep_Frequency.h" +#include "Sweep_Spectrum.h" #include "Waterfall.h" - namespace renderive { class Plot_Core; -LIB_DECL std::shared_ptr attach_performance_shower(Plot_Core& plot); -LIB_DECL std::shared_ptr attach_performance_shower(Plot_Core& plot, const Performance_Shower_Options& options); -LIB_DECL std::shared_ptr performance_shower(Plot_Core& plot); -LIB_DECL void detach_performance_shower(Plot_Core& plot); -LIB_DECL bool performance_shower_enabled(const Plot_Core& plot); -LIB_DECL void set_performance_shower_enabled(Plot_Core& plot, bool enabled); -LIB_DECL std::shared_ptr performance_shower_snapshot(const Plot_Core& plot); -LIB_DECL void set_performance_shower_update_callback(Plot_Core& plot, std::function callback); -LIB_DECL void notify_performance_shower_viewport_changed(Plot_Core& plot); -LIB_DECL bool performance_shower_handle_wheel(Plot_Core& plot, PointF position, double angle_delta_y, double pixel_delta_y); -LIB_DECL bool performance_shower_handle_pointer_press(Plot_Core& plot, PointF position); -LIB_DECL bool performance_shower_handle_pointer_move(Plot_Core& plot, PointF position); -LIB_DECL bool performance_shower_handle_pointer_release(Plot_Core& plot, PointF position); +LIB_DECL std::shared_ptr attach_performance_overlay(Plot_Core& plot); +LIB_DECL std::shared_ptr attach_performance_overlay(Plot_Core& plot, const Performance_Overlay_Options& options); +LIB_DECL std::shared_ptr performance_overlay(Plot_Core& plot); +LIB_DECL void detach_performance_overlay(Plot_Core& plot); +LIB_DECL bool performance_overlay_enabled(const Plot_Core& plot); +LIB_DECL void set_performance_overlay_enabled(Plot_Core& plot, bool enabled); +LIB_DECL std::shared_ptr performance_overlay_snapshot(const Plot_Core& plot); +LIB_DECL void set_performance_overlay_update_callback(Plot_Core& plot, std::function callback); +LIB_DECL void notify_performance_overlay_viewport_changed(Plot_Core& plot); +LIB_DECL bool performance_overlay_handle_wheel(Plot_Core& plot, PointF position, double angle_delta_y, double pixel_delta_y); +LIB_DECL bool performance_overlay_handle_pointer_press(Plot_Core& plot, PointF position); +LIB_DECL bool performance_overlay_handle_pointer_move(Plot_Core& plot, PointF position); +LIB_DECL bool performance_overlay_handle_pointer_release(Plot_Core& plot, PointF position); } // namespace renderive diff --git a/Core/primitive/Curve.cpp b/Core/primitive/Curve.cpp index d50859b..7b567b0 100644 --- a/Core/primitive/Curve.cpp +++ b/Core/primitive/Curve.cpp @@ -18,13 +18,11 @@ enum class Curve_Input_Mode : std::uint8_t { }; struct Curve_Input_Data : Input_Data {}; struct Curve_Render_State : Render_State, Curve_Prop {}; - struct Curve_Input_Block { Curve_Input_Mode mode = Curve_Input_Mode::None; std::pmr::vector samples{memory_resource(Memory_Domain::Curve)}; std::pmr::vector points{memory_resource(Memory_Domain::Curve)}; std::shared_ptr completion_state; - static std::shared_ptr samples_block(std::span values, std::shared_ptr state = {}) { auto block = std::make_shared(); block->mode = Curve_Input_Mode::Samples; @@ -32,7 +30,6 @@ struct Curve_Input_Block { block->completion_state = std::move(state); return block; } - static std::shared_ptr samples_block(std::pmr::vector&& values, std::shared_ptr state = {}) { auto block = std::make_shared(); block->mode = Curve_Input_Mode::Samples; @@ -40,7 +37,6 @@ struct Curve_Input_Block { block->completion_state = std::move(state); return block; } - static std::shared_ptr points_block(std::span values, std::shared_ptr state = {}) { auto block = std::make_shared(); block->mode = Curve_Input_Mode::Points; @@ -48,7 +44,6 @@ struct Curve_Input_Block { block->completion_state = std::move(state); return block; } - static std::shared_ptr points_block(std::pmr::vector&& values, std::shared_ptr state = {}) { auto block = std::make_shared(); block->mode = Curve_Input_Mode::Points; @@ -57,69 +52,61 @@ struct Curve_Input_Block { return block; } }; - struct Curve_Axis_Geometry_Key { Orientation orientation = Orientation::Horizontal; Range coord_range{0.0, 1.0}; Range pixel_range{0.0, 1.0}; - bool operator==(const Curve_Axis_Geometry_Key& other) const { return orientation == other.orientation && coord_range == other.coord_range && pixel_range == other.pixel_range; } }; - struct Curve_Geometry_Key { std::uint64_t input_generation{}; std::uint64_t state_version{}; Curve_Input_Mode mode = Curve_Input_Mode::None; - Line_Sampling_Mode sample_mode = Line_Sampling_Mode::Pixel_Peak_Envelope; - Line_Interpolation_Mode interpolation_mode = Line_Interpolation_Mode::Linear_Display; + Line_Sampling_Strategy sample_mode = Line_Sampling_Strategy::Pixel_Min_Max_Envelope; + Line_Interpolation_Mode interpolation_mode = Line_Interpolation_Mode::Linear_Value; bool visible_range_only{}; Range data_range{0.0, 1.0}; std::size_t sample_count{}; std::size_t point_count{}; Curve_Axis_Geometry_Key domain; Curve_Axis_Geometry_Key value; - bool operator==(const Curve_Geometry_Key& other) const { return input_generation == other.input_generation && - state_version == other.state_version && - mode == other.mode && - sample_mode == other.sample_mode && - interpolation_mode == other.interpolation_mode && - visible_range_only == other.visible_range_only && - data_range == other.data_range && - sample_count == other.sample_count && - point_count == other.point_count && - domain == other.domain && - value == other.value; + state_version == other.state_version && + mode == other.mode && + sample_mode == other.sample_mode && + interpolation_mode == other.interpolation_mode && + visible_range_only == other.visible_range_only && + data_range == other.data_range && + sample_count == other.sample_count && + point_count == other.point_count && + domain == other.domain && + value == other.value; } }; - struct Curve_Geometry_Result { Curve_Geometry_Result() : points(memory_resource(Memory_Domain::Curve)), update_states(memory_resource(Memory_Domain::Update_Completion)) {} Axis_Mapping_2D mapping; std::pmr::vector points; std::pmr::vector> update_states; }; - struct Curve_Geometry_Request { Curve_Geometry_Request() : samples(memory_resource(Memory_Domain::Curve)), data_points(memory_resource(Memory_Domain::Curve)), update_states(memory_resource(Memory_Domain::Update_Completion)) {} Curve_Input_Mode mode = Curve_Input_Mode::None; Axis_Mapping_2D mapping; Range data_range{0.0, 1.0}; bool visible_range_only{}; - Line_Interpolation_Mode interpolation_mode = Line_Interpolation_Mode::Linear_Display; - Line_Sampling_Mode sample_mode = Line_Sampling_Mode::Pixel_Peak_Envelope; + Line_Interpolation_Mode interpolation_mode = Line_Interpolation_Mode::Linear_Value; + Line_Sampling_Strategy sample_mode = Line_Sampling_Strategy::Pixel_Min_Max_Envelope; std::pmr::vector samples; std::pmr::vector data_points; std::pmr::vector> update_states; }; - static Curve_Axis_Geometry_Key curve_axis_key(const Axis_Frame_Snapshot& axis) { return {axis.orientation, axis.coord_range, axis.pixel_range}; } - static void complete_curve_update_states(Curve_Geometry_Request& request, std::error_code error, Update_Outcome outcome) { for (auto& state : request.update_states) { if (state) @@ -127,7 +114,6 @@ static void complete_curve_update_states(Curve_Geometry_Request& request, std::e } request.update_states.clear(); } - static void complete_curve_result_states(Curve_Geometry_Result& result, std::error_code error, Update_Outcome outcome) { for (const auto& state : result.update_states) { if (state) @@ -135,7 +121,6 @@ static void complete_curve_result_states(Curve_Geometry_Result& result, std::err } result.update_states.clear(); } - static void build_curve_geometry(Curve_Geometry_Result& result, const Curve_Geometry_Request& request) { std::pmr::vector& points = result.points; if (request.mode == Curve_Input_Mode::Points) { @@ -146,27 +131,26 @@ static void build_curve_geometry(Curve_Geometry_Result& result, const Curve_Geom } if (request.mode != Curve_Input_Mode::Samples || request.samples.size() < 2 || request.data_range.length() == 0.0) return; - if (request.sample_mode == Line_Sampling_Mode::Pixel_Peak_Envelope) { - points = Curve_Utils::create_peak_bucket_points(request.mapping, request.data_range, static_cast(request.samples.size()), static_cast(request.samples.size()), request.visible_range_only, [&request](int i) { + if (request.sample_mode == Line_Sampling_Strategy::Pixel_Min_Max_Envelope) { + points = Curve_Utils::build_pixel_envelope_points(request.mapping, request.data_range, static_cast(request.samples.size()), static_cast(request.samples.size()), request.visible_range_only, [&request](int i) { return request.samples[static_cast(i)]; }, memory_resource(Memory_Domain::Curve)); return; } - Line_Sample_Window window = line_sample_window(request.mapping.domain, request.data_range, static_cast(request.samples.size()), static_cast(request.samples.size()), request.visible_range_only); + Visible_Sample_Window window = compute_visible_sample_window(request.mapping.domain, request.data_range, static_cast(request.samples.size()), static_cast(request.samples.size()), request.visible_range_only); if (!window) return; points.reserve(static_cast(std::max(0, window.sample_count))); double denominator = static_cast(std::max(window.sample_count - 1, 1)); for (int i = 0; i < window.sample_count; ++i) { double index = window.first_index + (window.last_index - window.first_index) * static_cast(i) / denominator; - double coord = source_index_to_coord(request.data_range, static_cast(request.samples.size()), index); - double value = interpolate_line_value(index, static_cast(request.samples.size()), request.interpolation_mode, [&request](int sample_index) { + double coord = source_index_to_coordinate(request.data_range, static_cast(request.samples.size()), index); + double value = interpolate_sample_value(index, static_cast(request.samples.size()), request.interpolation_mode, [&request](int sample_index) { return request.samples[static_cast(sample_index)]; }); points.push_back(request.mapping.map(coord, value)); } } - struct Curve_Private : Typed_Render_Data { static constexpr std::size_t Input_Queue_Capacity = 8; std::pmr::vector samples{memory_resource(Memory_Domain::Curve)}; @@ -180,10 +164,8 @@ struct Curve_Private : Typed_Render_Data block; @@ -197,7 +179,6 @@ struct Curve_Private : Typed_Render_Data block) { if (!block) return; @@ -212,7 +193,6 @@ struct Curve_Private : Typed_Render_Datamark_render_dirty(); } - void consume_input_queue() { std::shared_ptr selected; std::shared_ptr block; @@ -234,7 +214,6 @@ struct Curve_Private : Typed_Render_Datacompletion_state)); } } - void prepare_data(const Plot_Render_Snapshot& snapshot) override { (void)snapshot; sync_state_pipeline(); @@ -307,12 +286,12 @@ struct Curve_Private : Typed_Render_Data values) { +void Curve::update_samples(std::span values) { if (!ok()) return; d()->enqueue_input(Curve_Input_Block::samples_block(values)); } -void Curve::give_samples(std::pmr::vector&& values) { +void Curve::update_samples(std::pmr::vector&& values) { if (!ok()) return; d()->enqueue_input(Curve_Input_Block::samples_block(std::move(values))); @@ -335,12 +314,12 @@ Update_Ticket Curve::submit_samples(std::pmr::vector&& values) { d()->enqueue_input(Curve_Input_Block::samples_block(std::move(values), state)); return Update_Ticket(state); } -void Curve::give_points(std::span points) { +void Curve::update_points(std::span points) { if (!ok()) return; d()->enqueue_input(Curve_Input_Block::points_block(points)); } -void Curve::give_points(std::pmr::vector&& points) { +void Curve::update_points(std::pmr::vector&& points) { if (!ok()) return; d()->enqueue_input(Curve_Input_Block::points_block(std::move(points))); @@ -378,7 +357,7 @@ RENDERIVE_DEFINE_STATE_PROP(Curve, Curve_Render_State, Brush, fill_brush) RENDERIVE_DEFINE_STATE_PROP(Curve, Curve_Render_State, bool, visible_range_only) RENDERIVE_DEFINE_STATE_PROP(Curve, Curve_Render_State, bool, antialias) RENDERIVE_DEFINE_STATE_PROP(Curve, Curve_Render_State, Line_Interpolation_Mode, interpolation_mode) -RENDERIVE_DEFINE_STATE_PROP(Curve, Curve_Render_State, Line_Sampling_Mode, sample_mode) +RENDERIVE_DEFINE_STATE_PROP(Curve, Curve_Render_State, Line_Sampling_Strategy, sample_mode) Curve::Builder::Builder(std::shared_ptr parent, std::shared_ptr domain_axis, std::shared_ptr value_axis) { ASSERT(parent, "Curve build error! parent == nullptr"); ASSERT(domain_axis && value_axis, "Curve build error! axis == nullptr"); @@ -427,10 +406,10 @@ void Curve_Utils::draw_fill_to_value(Canvas* canvas, std::span poi canvas->set_brush(brush); canvas->fill_polygon(std::span(fill_points.data(), fill_points.size())); } -void Curve_Utils::append_peak_point(std::pmr::vector& points, const Axis_Mapping_2D& mapping, const Range& data_range, int total_count, int index, double value) { +void Curve_Utils::append_envelope_point(std::pmr::vector& points, const Axis_Mapping_2D& mapping, const Range& data_range, int total_count, int index, double value) { if (index < 0) return; - PointF point = mapping.map(source_index_to_coord(data_range, total_count, index), value); + PointF point = mapping.map(source_index_to_coordinate(data_range, total_count, index), value); if (!points.empty() && points.back().x == point.x && points.back().y == point.y) return; points.push_back(point); diff --git a/Core/primitive/Curve.h b/Core/primitive/Curve.h index 5beb6c6..5b6c82a 100644 --- a/Core/primitive/Curve.h +++ b/Core/primitive/Curve.h @@ -17,13 +17,13 @@ namespace renderive { struct Curve_Private; /// @brief 曲线采样模式。 /// @brief Sampling strategy used when converting a continuous sample sequence to screen polyline points. -enum class Line_Sampling_Mode : std::uint8_t { +enum class Line_Sampling_Strategy : std::uint8_t { /// @brief 直接按输入数据采样。 /// @brief Use every input sample. All_Samples, /// @brief 按像素峰值桶降采样。 /// @brief Keep a local peak envelope per screen-pixel bucket to limit the number of drawn points. - Pixel_Peak_Envelope + Pixel_Min_Max_Envelope }; /// @brief 曲线构造属性。 struct Curve_Prop { @@ -34,24 +34,24 @@ struct Curve_Prop { Brush fill_brush = Brush{}; bool visible_range_only = true; bool antialias = false; - Line_Interpolation_Mode interpolation_mode = Line_Interpolation_Mode::Linear_Display; - Line_Sampling_Mode sample_mode = Line_Sampling_Mode::All_Samples; + Line_Interpolation_Mode interpolation_mode = Line_Interpolation_Mode::Linear_Value; + Line_Sampling_Strategy sample_mode = Line_Sampling_Strategy::All_Samples; }; /// @brief 按坐标轴绘制折线或填充曲线的图元。 class LIB_DECL Curve : public Renderable { public: /// @brief 写入按 data_range 均匀分布的采样值。 - void give_samples(std::span values); + void update_samples(std::span values); /// @brief 移动写入按 data_range 均匀分布的采样值。 - void give_samples(std::pmr::vector&& values); + void update_samples(std::pmr::vector&& values); /// @brief 提交采样值并返回完成票据。 Update_Ticket submit_samples(std::span values); /// @brief 移动提交采样值并返回完成票据。 Update_Ticket submit_samples(std::pmr::vector&& values); /// @brief 写入容器中的采样值。 template - void give_samples(const Values& values) { - give_samples(std::span(values.data(), values.size())); + void update_samples(const Values& values) { + update_samples(std::span(values.data(), values.size())); } /// @brief 用 writer 填充并写入采样值。 template @@ -59,20 +59,20 @@ public: std::pmr::vector values(memory_resource(Memory_Domain::Curve)); values.resize(count); std::forward(writer)(std::span(values.data(), values.size())); - give_samples(std::move(values)); + update_samples(std::move(values)); } /// @brief 写入显式坐标点。 - void give_points(std::span points); + void update_points(std::span points); /// @brief 移动写入显式坐标点。 - void give_points(std::pmr::vector&& points); + void update_points(std::pmr::vector&& points); /// @brief 提交显式坐标点并返回完成票据。 Update_Ticket submit_points(std::span points); /// @brief 移动提交显式坐标点并返回完成票据。 Update_Ticket submit_points(std::pmr::vector&& points); /// @brief 写入容器中的显式坐标点。 template - void give_points(const Points& points) { - give_points(std::span(points.data(), points.size())); + void update_points(const Points& points) { + update_points(std::span(points.data(), points.size())); } /// @brief 用 writer 填充并写入显式坐标点。 template @@ -80,7 +80,7 @@ public: std::pmr::vector points(memory_resource(Memory_Domain::Curve)); points.resize(count); std::forward(writer)(std::span(points.data(), points.size())); - give_points(std::move(points)); + update_points(std::move(points)); } /// @brief 绑定 X 轴。 PROP(std::shared_ptr, domain_axis) @@ -99,7 +99,7 @@ public: /// @brief 折线插值模式。 PROP(Line_Interpolation_Mode, interpolation_mode) /// @brief 曲线采样模式。 - PROP(Line_Sampling_Mode, sample_mode) + PROP(Line_Sampling_Strategy, sample_mode) struct Builder; /// @brief 创建曲线图元。 Curve(); @@ -120,7 +120,7 @@ struct LIB_DECL Curve::Builder : Curve_Prop { PROP_B(bool, visible_range_only) PROP_B(bool, antialias) PROP_B(Line_Interpolation_Mode, interpolation_mode) - PROP_B(Line_Sampling_Mode, sample_mode) + PROP_B(Line_Sampling_Strategy, sample_mode) /// @brief 创建曲线构造器。 Builder(std::shared_ptr parent, std::shared_ptr domain_axis, std::shared_ptr value_axis); /// @brief 构建并返回曲线对象。 diff --git a/Core/primitive/Curve_Utils_p.h b/Core/primitive/Curve_Utils_p.h index b65fc2e..97422e1 100644 --- a/Core/primitive/Curve_Utils_p.h +++ b/Core/primitive/Curve_Utils_p.h @@ -10,19 +10,16 @@ #include "../base/Frame_Memory.h" #include "../plottable/Interpolation_p.h" #include "Curve.h" - namespace renderive { - -struct Curve_Peak_Bucket { - bool used = false; - int first = -1; - int last = -1; - int min = -1; - int max = -1; - double min_value = std::numeric_limits::max(); - double max_value = std::numeric_limits::lowest(); +struct Pixel_Envelope_Bucket { + bool has_samples = false; + int first_index = -1; + int last_index = -1; + int minimum_index = -1; + int maximum_index = -1; + double minimum_value = std::numeric_limits::max(); + double maximum_value = std::numeric_limits::lowest(); }; - class Curve_Utils { public: template @@ -34,82 +31,80 @@ public: return points; } template - static std::pmr::vector create_sampled_points(Abs_Axis* domain_axis, Abs_Axis* value_axis, const Range& data_range, int total_count, int available_count, bool visible_range_only, Line_Interpolation_Mode mode, Value_At value_at) { - return create_line_points(domain_axis, value_axis, data_range, total_count, available_count, visible_range_only, mode, value_at); + static std::pmr::vector build_resampled_points(Abs_Axis* domain_axis, Abs_Axis* value_axis, const Range& sample_domain_range, int source_sample_count, int available_sample_count, bool visible_range_only, Line_Interpolation_Mode mode, Value_At value_at) { + return build_interpolated_line_points(domain_axis, value_axis, sample_domain_range, source_sample_count, available_sample_count, visible_range_only, mode, value_at); } template - static std::pmr::vector create_sampled_points(const Axis_Mapping_2D& mapping, const Range& data_range, int total_count, int available_count, bool visible_range_only, Line_Interpolation_Mode mode, Value_At value_at, std::pmr::memory_resource* resource = frame_memory_resource()) { - return create_line_points(mapping, data_range, total_count, available_count, visible_range_only, mode, value_at, resource); + static std::pmr::vector build_resampled_points(const Axis_Mapping_2D& mapping, const Range& sample_domain_range, int source_sample_count, int available_sample_count, bool visible_range_only, Line_Interpolation_Mode mode, Value_At value_at, std::pmr::memory_resource* resource = frame_memory_resource()) { + return build_interpolated_line_points(mapping, sample_domain_range, source_sample_count, available_sample_count, visible_range_only, mode, value_at, resource); } template - static std::pmr::vector create_peak_bucket_points(const Axis_Mapping_2D& mapping, const Range& data_range, int total_count, int available_count, bool visible_range_only, Value_At value_at, std::pmr::memory_resource* resource = frame_memory_resource()) { - Line_Sample_Window window = line_sample_window(mapping.domain, data_range, total_count, available_count, visible_range_only); + static std::pmr::vector build_pixel_envelope_points(const Axis_Mapping_2D& mapping, const Range& sample_domain_range, int source_sample_count, int available_sample_count, bool visible_range_only, Value_At value_at, std::pmr::memory_resource* resource = frame_memory_resource()) { + Visible_Sample_Window window = compute_visible_sample_window(mapping.domain, sample_domain_range, source_sample_count, available_sample_count, visible_range_only); if (!window) return {}; - int first_source = std::clamp(static_cast(std::floor(std::min(window.first_index, window.last_index))), 0, available_count - 1); - int last_source = std::clamp(static_cast(std::ceil(std::max(window.first_index, window.last_index))), first_source, available_count - 1); - double first_pixel = mapping.domain.coord_to_pixel(source_index_to_coord(data_range, total_count, window.first_index)); - double last_pixel = mapping.domain.coord_to_pixel(source_index_to_coord(data_range, total_count, window.last_index)); + int first_source = std::clamp(static_cast(std::floor(std::min(window.first_index, window.last_index))), 0, available_sample_count - 1); + int last_source = std::clamp(static_cast(std::ceil(std::max(window.first_index, window.last_index))), first_source, available_sample_count - 1); + double first_pixel = mapping.domain.coord_to_pixel(source_index_to_coordinate(sample_domain_range, source_sample_count, window.first_index)); + double last_pixel = mapping.domain.coord_to_pixel(source_index_to_coordinate(sample_domain_range, source_sample_count, window.last_index)); double pixel_min = std::min(first_pixel, last_pixel); double pixel_max = std::max(first_pixel, last_pixel); int bucket_count = std::max(1, static_cast(std::ceil(pixel_max - pixel_min)) + 1); bucket_count = std::min(bucket_count, mapping.domain.pixel_size() + 1); - std::pmr::vector buckets(bucket_count, resource); + std::pmr::vector buckets(bucket_count, resource); double pixel_span = std::max(1.0, pixel_max - pixel_min); for (int i = first_source; i <= last_source; ++i) { - double coord = source_index_to_coord(data_range, total_count, i); + double coord = source_index_to_coordinate(sample_domain_range, source_sample_count, i); double pixel = mapping.domain.coord_to_pixel(coord); int bucket_index = std::clamp(static_cast((pixel - pixel_min) * static_cast(bucket_count - 1) / pixel_span), 0, bucket_count - 1); - Curve_Peak_Bucket& bucket = buckets[bucket_index]; + Pixel_Envelope_Bucket& bucket = buckets[bucket_index]; double value = value_at(i); - if (!bucket.used) { - bucket.used = true; - bucket.first = i; - bucket.min = i; - bucket.max = i; - bucket.min_value = value; - bucket.max_value = value; + if (!bucket.has_samples) { + bucket.has_samples = true; + bucket.first_index = i; + bucket.minimum_index = i; + bucket.maximum_index = i; + bucket.minimum_value = value; + bucket.maximum_value = value; } - bucket.last = i; - if (value < bucket.min_value) { - bucket.min_value = value; - bucket.min = i; + bucket.last_index = i; + if (value < bucket.minimum_value) { + bucket.minimum_value = value; + bucket.minimum_index = i; } - if (value > bucket.max_value) { - bucket.max_value = value; - bucket.max = i; + if (value > bucket.maximum_value) { + bucket.maximum_value = value; + bucket.maximum_index = i; } } std::pmr::vector points(resource); points.reserve(bucket_count * 4); bool pixel_forward = first_pixel <= last_pixel; for (int b = pixel_forward ? 0 : bucket_count - 1; pixel_forward ? b < bucket_count : b >= 0; pixel_forward ? ++b : --b) { - const Curve_Peak_Bucket& bucket = buckets[b]; - if (!bucket.used) + const Pixel_Envelope_Bucket& bucket = buckets[b]; + if (!bucket.has_samples) continue; - std::array indexes{bucket.first, bucket.min, bucket.max, bucket.last}; + std::array indexes{bucket.first_index, bucket.minimum_index, bucket.maximum_index, bucket.last_index}; std::sort(indexes.begin(), indexes.end()); auto end = std::unique(indexes.begin(), indexes.end()); if (pixel_forward) { for (auto it = indexes.begin(); it != end; ++it) - append_peak_point(points, mapping, data_range, total_count, *it, value_at(*it)); + append_envelope_point(points, mapping, sample_domain_range, source_sample_count, *it, value_at(*it)); } else { for (auto it = std::make_reverse_iterator(end); it != indexes.rend(); ++it) - append_peak_point(points, mapping, data_range, total_count, *it, value_at(*it)); + append_envelope_point(points, mapping, sample_domain_range, source_sample_count, *it, value_at(*it)); } } return points; } template - static std::pmr::vector create_peak_bucket_points(Abs_Axis* domain_axis, Abs_Axis* value_axis, const Range& data_range, int total_count, int available_count, bool visible_range_only, Value_At value_at) { - return create_peak_bucket_points(Axis_Render_Access::mapping(domain_axis, value_axis), data_range, total_count, available_count, visible_range_only, value_at, frame_memory_resource()); + static std::pmr::vector build_pixel_envelope_points(Abs_Axis* domain_axis, Abs_Axis* value_axis, const Range& sample_domain_range, int source_sample_count, int available_sample_count, bool visible_range_only, Value_At value_at) { + return build_pixel_envelope_points(Axis_Render_Access::mapping(domain_axis, value_axis), sample_domain_range, source_sample_count, available_sample_count, visible_range_only, value_at, frame_memory_resource()); } static void draw_polyline(Canvas* painter, std::span points, const Pen& pen); static void draw_fill_to_value(Canvas* painter, std::span points, const Axis_Mapping_2D& mapping, double baseline_value, const Brush& brush); - private: - static void append_peak_point(std::pmr::vector& points, const Axis_Mapping_2D& mapping, const Range& data_range, int total_count, int index, double value); + static void append_envelope_point(std::pmr::vector& points, const Axis_Mapping_2D& mapping, const Range& sample_domain_range, int source_sample_count, int index, double value); }; - } // namespace renderive diff --git a/Core/primitive/Fill_Area.cpp b/Core/primitive/Fill_Area.cpp index de153c3..d765c0f 100644 --- a/Core/primitive/Fill_Area.cpp +++ b/Core/primitive/Fill_Area.cpp @@ -69,13 +69,13 @@ struct Fill_Area_Private : Typed_Render_Data points) { +void Fill_Area::update_points(std::span points) { if (!ok()) return; Render_Input_Lease input(d()); input->push(points); } -void Fill_Area::give_points(std::pmr::vector&& points) { +void Fill_Area::update_points(std::pmr::vector&& points) { if (!ok()) return; Render_Input_Lease input(d()); diff --git a/Core/primitive/Fill_Area.h b/Core/primitive/Fill_Area.h index 48c13e2..abd6a4e 100644 --- a/Core/primitive/Fill_Area.h +++ b/Core/primitive/Fill_Area.h @@ -33,13 +33,13 @@ struct Fill_Area_Prop { class LIB_DECL Fill_Area : public Renderable { public: /// @brief 写入填充区域坐标点。 - void give_points(std::span points); + void update_points(std::span points); /// @brief 移动写入填充区域坐标点。 - void give_points(std::pmr::vector&& points); + void update_points(std::pmr::vector&& points); /// @brief 写入容器中的填充区域坐标点。 template - void give_points(const Points& points) { - give_points(std::span(points.data(), points.size())); + void update_points(const Points& points) { + update_points(std::span(points.data(), points.size())); } /// @brief 用 writer 填充并写入坐标点。 template @@ -47,7 +47,7 @@ public: std::pmr::vector points(memory_resource(Memory_Domain::Curve)); points.resize(count); std::forward(writer)(std::span(points.data(), points.size())); - give_points(std::move(points)); + update_points(std::move(points)); } /// @brief 绑定 X 轴。 PROP(std::shared_ptr, domain_axis) diff --git a/Core/primitive/Grid.cpp b/Core/primitive/Grid.cpp index 873118c..a8f2a91 100644 --- a/Core/primitive/Grid.cpp +++ b/Core/primitive/Grid.cpp @@ -22,11 +22,11 @@ struct Grid_Private : Typed_Render_Data { return; double cross0 = cross_frame.coord_to_pixel(cross_range.origin); double cross1 = cross_frame.coord_to_pixel(cross_range.target); - double step = axis->get_tick_step(axis_range); + double step = axis->tick_step(axis_range); std::vector ticks = axis->create_tick_vector(step, axis_range); if (sub_grid && sub_pen.style != Line_Style::None) { canvas.set_pen(sub_pen); - std::vector sub_ticks = axis->create_sub_tick_vector(axis->get_sub_tick_count(step), ticks, axis_range); + std::vector sub_ticks = axis->create_sub_tick_vector(axis->sub_tick_count(step), ticks, axis_range); draw_ticks(canvas, axis_frame, cross0, cross1, sub_ticks); } if (pen.style != Line_Style::None) { diff --git a/Core/primitive/Label.cpp b/Core/primitive/Label.cpp index 14bc848..74c2588 100644 --- a/Core/primitive/Label.cpp +++ b/Core/primitive/Label.cpp @@ -41,11 +41,11 @@ struct Label_Private : Typed_Render_Data items) { +void Label::update_items(std::span items) { if (!ok()) return; Render_Input_Lease input(d()); input->push(items); } -void Label::give_items(std::pmr::vector&& items) { +void Label::update_items(std::pmr::vector&& items) { if (!ok()) return; Render_Input_Lease input(d()); diff --git a/Core/primitive/Label.h b/Core/primitive/Label.h index 9be4099..a7d8747 100644 --- a/Core/primitive/Label.h +++ b/Core/primitive/Label.h @@ -60,13 +60,13 @@ public: /// @brief 边框画笔。 PROP(Pen, border_pen) /// @brief 写入批量标签项。 - void give_items(std::span items); + void update_items(std::span items); /// @brief 移动写入批量标签项。 - void give_items(std::pmr::vector&& items); + void update_items(std::pmr::vector&& items); /// @brief 写入容器中的批量标签项。 template - void give_items(const Items& items) { - give_items(std::span(items.data(), items.size())); + void update_items(const Items& items) { + update_items(std::span(items.data(), items.size())); } struct Builder; /// @brief 创建标签图元。 diff --git a/Core/primitive/Marker.cpp b/Core/primitive/Marker.cpp index 1b34e6b..14f4256 100644 --- a/Core/primitive/Marker.cpp +++ b/Core/primitive/Marker.cpp @@ -79,13 +79,13 @@ struct Marker_Private : Typed_Render_Data items) { +void Marker::update_items(std::span items) { if (!ok()) return; Render_Input_Lease input(d()); input->push(items); } -void Marker::give_items(std::pmr::vector&& items) { +void Marker::update_items(std::pmr::vector&& items) { if (!ok()) return; Render_Input_Lease input(d()); diff --git a/Core/primitive/Marker.h b/Core/primitive/Marker.h index 60cf76d..8d346a0 100644 --- a/Core/primitive/Marker.h +++ b/Core/primitive/Marker.h @@ -58,13 +58,13 @@ public: /// @brief 标记绘制模式。 PROP(Marker_Mode, mode) /// @brief 写入批量标记项。 - void give_items(std::span items); + void update_items(std::span items); /// @brief 移动写入批量标记项。 - void give_items(std::pmr::vector&& items); + void update_items(std::pmr::vector&& items); /// @brief 写入容器中的批量标记项。 template - void give_items(const Items& items) { - give_items(std::span(items.data(), items.size())); + void update_items(const Items& items) { + update_items(std::span(items.data(), items.size())); } struct Builder; /// @brief 创建标记图元。 diff --git a/Core/primitive/Point_Set.cpp b/Core/primitive/Point_Set.cpp index e1eac11..b9740b4 100644 --- a/Core/primitive/Point_Set.cpp +++ b/Core/primitive/Point_Set.cpp @@ -109,19 +109,19 @@ struct Point_Set_Private : Typed_Render_Data points) { +void Point_Set::update_points(std::span points) { if (!ok()) return; Render_Input_Lease input(d()); input->push(points); } -void Point_Set::give_points(std::pmr::vector&& points) { +void Point_Set::update_points(std::pmr::vector&& points) { if (!ok()) return; Render_Input_Lease input(d()); input->push(std::move(points)); } -void Point_Set::give_colored_points(std::span points, std::span colors) { +void Point_Set::update_colored_points(std::span points, std::span colors) { if (points.size() != colors.size()) return; if (!ok()) @@ -129,7 +129,7 @@ void Point_Set::give_colored_points(std::span points, std::span input(d()); input->push(points, colors); } -void Point_Set::give_colored_points(std::pmr::vector&& points, std::pmr::vector&& colors) { +void Point_Set::update_colored_points(std::pmr::vector&& points, std::pmr::vector&& colors) { if (points.size() != colors.size()) return; if (!ok()) diff --git a/Core/primitive/Point_Set.h b/Core/primitive/Point_Set.h index 4df4627..21ce66e 100644 --- a/Core/primitive/Point_Set.h +++ b/Core/primitive/Point_Set.h @@ -38,13 +38,13 @@ struct Point_Set_Prop { class LIB_DECL Point_Set : public Renderable { public: /// @brief 写入点集坐标。 - void give_points(std::span points); + void update_points(std::span points); /// @brief 移动写入点集坐标。 - void give_points(std::pmr::vector&& points); + void update_points(std::pmr::vector&& points); /// @brief 写入容器中的点集坐标。 template - void give_points(const Points& points) { - give_points(std::span(points.data(), points.size())); + void update_points(const Points& points) { + update_points(std::span(points.data(), points.size())); } /// @brief 用 writer 填充并写入点集坐标。 template @@ -52,16 +52,16 @@ public: std::pmr::vector points(memory_resource(Memory_Domain::Point_Set)); points.resize(count); std::forward(writer)(std::span(points.data(), points.size())); - give_points(std::move(points)); + update_points(std::move(points)); } /// @brief 写入带逐点颜色的点集。 - void give_colored_points(std::span points, std::span colors); + void update_colored_points(std::span points, std::span colors); /// @brief 移动写入带逐点颜色的点集。 - void give_colored_points(std::pmr::vector&& points, std::pmr::vector&& colors); + void update_colored_points(std::pmr::vector&& points, std::pmr::vector&& colors); /// @brief 写入容器中的带逐点颜色点集。 template - void give_colored_points(const Points& points, const Colors& colors) { - give_colored_points(std::span(points.data(), points.size()), std::span(colors.data(), colors.size())); + void update_colored_points(const Points& points, const Colors& colors) { + update_colored_points(std::span(points.data(), points.size()), std::span(colors.data(), colors.size())); } /// @brief 绑定 X 轴。 PROP(std::shared_ptr, domain_axis) diff --git a/Core/primitive/Raster_Image.cpp b/Core/primitive/Raster_Image.cpp index 8e30dd9..1e7855c 100644 --- a/Core/primitive/Raster_Image.cpp +++ b/Core/primitive/Raster_Image.cpp @@ -57,13 +57,13 @@ struct Raster_Image_Private : Typed_Render_Data input(d()); input->push(image); } -void Raster_Image::give_image_frame(const Image& image, Range domain_range, Range value_range, RectF source_rect, Image_Interpolation_Mode interpolation_mode) { +void Raster_Image::update_image_frame(const Image& image, Range domain_range, Range value_range, RectF source_rect, Image_Interpolation_Mode interpolation_mode) { if (domain_range.length() == 0.0 || value_range.length() == 0.0) return; if (!ok()) diff --git a/Core/primitive/Raster_Image.h b/Core/primitive/Raster_Image.h index f0fc8eb..d657039 100644 --- a/Core/primitive/Raster_Image.h +++ b/Core/primitive/Raster_Image.h @@ -1,17 +1,12 @@ #pragma once - #include - #include "../architecture/Renderable.h" #include "../Axis/Abs_Axis.h" #include "../base/Geometry.h" #include "../plottable/Interpolation.h" #include "../render/Image.h" - namespace renderive { - struct Raster_Image_Private; - struct Raster_Image_Prop { std::weak_ptr domain_axis{}; std::weak_ptr value_axis{}; @@ -20,36 +15,29 @@ struct Raster_Image_Prop { RectF source_rect{}; Image_Interpolation_Mode interpolation_mode = Image_Interpolation_Mode::Nearest; }; - class LIB_DECL Raster_Image : public Renderable { public: - void give_image(const Image& image); - - void give_image_frame( + void update_image(const Image& image); + void update_image_frame( const Image& image, Range domain_range, Range value_range, RectF source_rect, Image_Interpolation_Mode interpolation_mode); - PROP(std::shared_ptr, domain_axis) PROP(std::shared_ptr, value_axis) PROP(Range, domain_range) PROP(Range, value_range) PROP(RectF, source_rect) PROP(Image_Interpolation_Mode, interpolation_mode) - struct Builder; - Raster_Image(); - private: Raster_Image_Private* d(); Render_Object_Owner create_render_data() override; Render_Object_Owner create_render_state() override; Render_Object_Owner create_input_data() override; }; - struct LIB_DECL Raster_Image::Builder : Raster_Image_Prop { PROP_B(std::shared_ptr, parent) PROP_B(std::shared_ptr, domain_axis) @@ -58,12 +46,8 @@ struct LIB_DECL Raster_Image::Builder : Raster_Image_Prop { PROP_B(Range, value_range) PROP_B(RectF, source_rect) PROP_B(Image_Interpolation_Mode, interpolation_mode) - Builder(std::shared_ptr parent, std::shared_ptr domain_axis, std::shared_ptr value_axis); - std::shared_ptr build(); - std::shared_ptr parent{}; }; - } // namespace renderive diff --git a/Core/render/Blend2D_Convert.cpp b/Core/render/Blend2D_Convert.cpp index 9aa663a..42e1bab 100644 --- a/Core/render/Blend2D_Convert.cpp +++ b/Core/render/Blend2D_Convert.cpp @@ -18,11 +18,11 @@ std::uint8_t byte_from_normalized(double value) { } // namespace BLRgba Convert::to_bl(const Color& color) { - return BLRgba(normalized(color.red), normalized(color.green), normalized(color.blue), normalized(color.alpha)); + return BLRgba(normalized(color.r), normalized(color.g), normalized(color.b), normalized(color.a)); } BLRgba Convert::to_bl_premultiplied(const Color& color) { - auto alpha = normalized(color.alpha); - return BLRgba(normalized(color.red) * alpha, normalized(color.green) * alpha, normalized(color.blue) * alpha, alpha); + auto alpha = normalized(color.a); + return BLRgba(normalized(color.r) * alpha, normalized(color.g) * alpha, normalized(color.b) * alpha, alpha); } BLPoint Convert::to_bl(const PointF& point) { return BLPoint(point.x, point.y); diff --git a/Core/render/Canvas.cpp b/Core/render/Canvas.cpp index 9883f3f..ab2486c 100644 --- a/Core/render/Canvas.cpp +++ b/Core/render/Canvas.cpp @@ -250,11 +250,11 @@ void Canvas::draw_text(const RectF& rect, Text_Align align, std::string_view tex auto metrics = measure_text(text); double x = rect.x; double y = rect.y; - if ((align & Text_Align::HCenter) == Text_Align::HCenter) + if ((align & Text_Align::Horizontal_Center) == Text_Align::Horizontal_Center) x += (rect.width - metrics.width) / 2.0; else if ((align & Text_Align::Right) == Text_Align::Right) x += rect.width - metrics.width; - if ((align & Text_Align::VCenter) == Text_Align::VCenter) + if ((align & Text_Align::Vertical_Center) == Text_Align::Vertical_Center) y += (rect.height - metrics.height) / 2.0; else if ((align & Text_Align::Bottom) == Text_Align::Bottom) y += rect.height - metrics.height; diff --git a/Core/render/Image.cpp b/Core/render/Image.cpp index 32c8eb2..372a411 100644 --- a/Core/render/Image.cpp +++ b/Core/render/Image.cpp @@ -45,7 +45,7 @@ bool Image::empty() const { return impl_->image.is_empty(); } -std::size_t Image::size_bytes() const { +std::size_t Image::byte_size() const { BLImageData d; if (impl_->image.get_data(&d) != BL_SUCCESS) return 0; diff --git a/Core/render/Image.h b/Core/render/Image.h index 6d19c10..a35aec4 100644 --- a/Core/render/Image.h +++ b/Core/render/Image.h @@ -19,7 +19,7 @@ public: [[nodiscard]] int height() const; [[nodiscard]] Size size() const; [[nodiscard]] bool empty() const; - [[nodiscard]] std::size_t size_bytes() const; + [[nodiscard]] std::size_t byte_size() const; void clear(); void resize(int width, int height); void fill(Color color); diff --git a/Demo_Gallery/Afterglow_Plot.h b/Demo_Gallery/Afterglow_Plot.h deleted file mode 100644 index b4c9737..0000000 --- a/Demo_Gallery/Afterglow_Plot.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once -#include "base/Tool.h" -static QWidget* create_afterglow() { - class Afterglow_Plot : public renderive::Latency_Eager_Plot { - public: - std::shared_ptr x_axis{}; - std::shared_ptr y_axis{}; - std::shared_ptr ag{}; - std::shared_ptr msr{}; - QMenu* menu{}; - void init() override { - Latency_Eager_Plot::init(); - object_name = "Afterglow_Plot"; - auto data = create_renderable_node(get_root_renderable(), "Data_Renderable"); - auto axis = create_renderable_node(get_root_renderable(), "Axis_Renderable"); - auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); - x_axis = renderive::Frequency_Axis::Builder(axis, Qt::Horizontal).build(); - y_axis = renderive::Axis::Builder(axis, Qt::Vertical).build(); - ag = renderive::Afterglow::Builder(data, x_axis, y_axis) - .set_frequency_range({0, 100}) - .set_power_range({0, 100}) - .build(); - msr = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); - } - protected: - void resizeEvent(QResizeEvent* event) override { - x_axis->set_x(0); - x_axis->set_y(height() - 1); - x_axis->set_pixel_size(width()); - y_axis->set_x(0); - y_axis->set_y(0); - y_axis->set_pixel_size(height()); - ag->set_frequency_point_size(ag->frequency_axis()->get_pixel_point_size()); - ag->set_power_point_size(ag->power_axis()->get_pixel_point_size()); - } - void contextMenuEvent(QContextMenuEvent* event) override { - if (!menu) { - auto ws = concat_widgets( - bw(cw(ag.get(), -1), "余辉图"), - bw(cw(x_axis.get()), "频率轴"), - bw(cw(y_axis.get()), "功率概率轴"), - bw(cw(msr.get()), "多选框")); - menu = create_menu(this, ws); - } - menu->exec(event->globalPos()); - } - }; - auto w = new Afterglow_Plot; - w->init(); - return w; -} diff --git a/Demo_Gallery/Audio_Plot.h b/Demo_Gallery/Audio_Plot.h deleted file mode 100644 index 42c120e..0000000 --- a/Demo_Gallery/Audio_Plot.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once -#include "base/Tool.h" -static QWidget* create_audio_plot() { - class Audio_Plot : public renderive::Latency_Eager_Plot { - public: - std::shared_ptr x_axis{}; - std::shared_ptr y_axis{}; - std::shared_ptr audio{}; - std::shared_ptr msr{}; - QMenu* menu{}; - void init() override { - Latency_Eager_Plot::init(); - object_name = "Audio_Plot"; - auto data = create_renderable_node(get_root_renderable(), "Data_Renderable"); - auto axis = create_renderable_node(get_root_renderable(), "Axis_Renderable"); - auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); - x_axis = renderive::Time_Axis::Builder(axis, Qt::Horizontal) - .set_tick_length(-10) - .set_sub_tick_length(-5) - .build(); - y_axis = renderive::Axis::Builder(axis, Qt::Vertical).build(); - audio = renderive::Audio_Frequency::Builder(data, x_axis, y_axis).build(); - msr = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); - } - protected: - void resizeEvent(QResizeEvent* event) override { - x_axis->set_x(0); - x_axis->set_y(height() - 1); - x_axis->set_pixel_size(width()); - y_axis->set_x(0); - y_axis->set_y(0); - y_axis->set_pixel_size(height()); - x_axis->set_time_point_size(x_axis->get_pixel_point_size()); - } - void contextMenuEvent(QContextMenuEvent* event) override { - if (!menu) { - auto ws = concat_widgets( - bw(cw(audio.get(), -1), "音频图"), - bw(cw(y_axis.get()), "功率y轴"), - bw(cw(x_axis.get()), "时间轴"), - bw(cw(msr.get()), "多选框")); - menu = create_menu(this, ws); - } - menu->exec(event->globalPos()); - } - }; - auto w = new Audio_Plot; - w->init(); - return w; -} diff --git a/Demo_Gallery/Demo_Gallery.cpp b/Demo_Gallery/Demo_Gallery.cpp deleted file mode 100644 index dadd3d8..0000000 --- a/Demo_Gallery/Demo_Gallery.cpp +++ /dev/null @@ -1,164 +0,0 @@ -#include "Demo_Gallery.h" -#include -#include "Widget/Qt/export.h" -using namespace Psc; -QStandardItem* Demo_Gallery::get_from_data(const T_Data& data) { - auto w = new QWidget; - auto l = new QVBoxLayout(w); - l->setContentsMargins({0, 0, 0, 0}); - l->setSpacing(0); - l->addWidget(data.plot); - // l->addStretch(); - data_map[data.name] = w; - return new QStandardItem(data.name); -} -std::vector Demo_Gallery::get_list(const std::vector& datas) { - std::vector ret; - for (const T_Data& data : datas) { - ret.push_back(get_from_data(data)); - } - return ret; -} -void Demo_Gallery::change_to(const QString& name) { - if (data_map.contains(name)) { - QWidget* associatedWidget = data_map[name]; - int i = tab_widget->indexOf(associatedWidget); - if (i == -1) { - // 标签页不存在,添加新的标签页 - tab_widget->addTab(associatedWidget, name); - tab_widget->setCurrentIndex(tab_widget->indexOf(associatedWidget)); - } - else { - // 标签页已经存在,设置为当前标签页 - tab_widget->setCurrentIndex(i); - } - } -} -class Combo_Box_Example : public QWidget { -public: - Combo_Box_Example(QWidget* parent = nullptr) : QWidget(parent) { - // 创建一个QComboBox - QComboBox* combo_box = new QComboBox(this); - // 向QComboBox添加一些选项 - combo_box->addItem("Option 1"); - combo_box->addItem("Option 2"); - combo_box->addItem("Option 3"); - // 创建一个标签用来显示选中的选项 - QLabel* label = new QLabel("Selected: ", this); - QObject::connect(combo_box, QOverload::of(&QComboBox::currentIndexChanged), [=](int index) { - // 这里你可以获取当前选择项的索引 - label->setText("Selected: " + combo_box->currentText()); - }); - // 布局 - QVBoxLayout* layout = new QVBoxLayout; - layout->addWidget(combo_box); - layout->addWidget(label); - setLayout(layout); - } -}; -Demo_Gallery::Demo_Gallery() : - tree_view(new QTreeView(this)), - standard_model(new QStandardItemModel(this)), - tab_widget(new QTabWidget) { - main_layout = new QHBoxLayout(this); - main_layout->setContentsMargins(0, 0, 0, 0); - main_layout->setSpacing(0); - tree_view->setFixedWidth(200); - tree_view->setEditTriggers(QAbstractItemView::NoEditTriggers); - main_layout->addWidget(tree_view); - tab_widget->setTabsClosable(true); - main_layout->addWidget(tab_widget); - // tree_view->setItemDelegate(new Delegate); - tree_view->setHeaderHidden(true); - QStandardItem* root = standard_model->invisibleRootItem(); - auto append_rows = [](QStandardItem* parent, const std::vector& rows) { - for (QStandardItem* row : rows) - parent->appendRow(row); - }; - auto plottable = new QStandardItem("plottable"); - append_rows(plottable, get_list({ - {"余晖图", create_afterglow()}, - {"音频图", create_audio_plot()}, - {"星座图", create_planisphere_plot()}, - {"频谱图", create_spectrun_plot()}, - {"瀑布图", create_water_fall_plot()}, - {"扫频图", create_sweep_frequent_plot()}, - })); - auto base = new QStandardItem("基础元素"); - append_rows(base, get_list({ - {"轴测试", create_axis_test_plot()}, - {"时间轴测试", create_time_axis_test_plot()}, - {"频率轴测试", create_frequent_axis_test_plot()}, - {"多选框测试", create_Multi_Select_Plot()}, - })); - auto t1 = new Byte_Select; - auto t2 = new Test_File_Gather_Widget; - auto t3 = new Test_File_Play_Widget; - auto custom_widget = new QStandardItem("自定义控件"); - append_rows(custom_widget, get_list({ - {"Enum_Select", t1}, - {"Test_File_Gather_Widget", t2}, - {"Test_File_Play_Widget", t3}, - {"表格", create_table_view()}, - {"树", create_Tree_View()}, - })); - auto Qt_raw_widget = new QStandardItem("Qt原生元素"); - append_rows(Qt_raw_widget, get_list({ - // QSizeGrip 一个改变大小的注脚 - // QDesktopWidget 不知道干嘛的 - // QFocusFrame 不知道干嘛的 - {"QKeySequenceEdit", new QKeySequenceEdit}, - {"Combo_Box_Example", new Combo_Box_Example}, - // 像QWidget 但不知到有什么区别 - {"QPushButton", new QPushButton}, - {"QFrame", new QFrame}, - {"QStatusBar", new QStatusBar}, - {"QGroupBox", new QGroupBox}, - {"QSplashScreen", new QSplashScreen}, - {"QAbstractSlider", new QAbstractSlider}, - {"QRubberBand::Line", new QRubberBand(QRubberBand::Line)}, - {"QRubberBand::Rectangle", new QRubberBand(QRubberBand::Rectangle)}, - {"QProgressBar", new QProgressBar()}, - {"QDialog", new QDialog}, - {"QTabBar", new QTabBar}, - {"QDialogButtonBox", new QDialogButtonBox}, - {"QCalendarWidget", new QCalendarWidget}, - {"QMenuBar", new QMenuBar}, - {"QTabWidget", new QTabWidget}, - {"QOpenGLWidget", new QOpenGLWidget}, - {"QMdiSubWindow", new QMdiSubWindow}, - {"QDockWidget", new QDockWidget}, - {"QAbstractSpinBox", new QAbstractSpinBox}, - //{"QAbstractButton", new QAbstractButton}, - {"QTabBar", new QTabBar}, - {"QComboBox", new QComboBox}, - {"QMainWindow", new QMainWindow}, - {"QMenu", new QMenu}, - //{"QWindowContainer", new QWindowContainer}, - //{"QDesktopScreenWidget", new QDesktopScreenWidget}, - {"QColumnView", new QColumnView}, - {"QWizardPage", new QWizardPage}, - })); - // change_to("表格"); - change_to("Test_File_Gather_Widget"); - // change_to("树"); - root->appendRow(plottable); - root->appendRow(base); - root->appendRow(custom_widget); - root->appendRow(Qt_raw_widget); - tree_view->setModel(standard_model); - tree_view->expandAll(); - QObject::connect(tab_widget, &QTabWidget::tabCloseRequested, [this](int index) { - // 处理标签页关闭请求 - qDebug() << "Closing tab at index:" << index; - // 从 QTabWidget 中移除指定的标签页 - tab_widget->removeTab(index); - }); - QObject::connect(tree_view, &QTreeView::clicked, [this](const QModelIndex& index) { - QStandardItem* item = this->standard_model->itemFromIndex(index); - if (item) { - QString item_name = item->text(); - change_to(item_name); - } - }); -} diff --git a/Demo_Gallery/Demo_Gallery.h b/Demo_Gallery/Demo_Gallery.h deleted file mode 100644 index ef52838..0000000 --- a/Demo_Gallery/Demo_Gallery.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include "../Widget/component/export.h" -#include "Afterglow_Plot.h" -#include "Audio_Plot.h" -#include "Normal_test.h" -#include "Planisphere_Plot.h" -#include "Spectrum_Plot.h" -#include "Sweep_Frequent_Plot.h" -#include "Waterfall_Plot.h" -#include "base/Axis_Test.h" -#include "base/Frequency_Axis_Test.h" -#include "base/Multi_Select_Test.h" -#include "base/Time_Axis_Test.h" -class QTreeView; -class QStandardItemModel; -class QStandardItem; -class Demo_Gallery : public QWidget { -public: - Demo_Gallery(); - QTreeView* tree_view; - QStandardItemModel* standard_model; - QHBoxLayout* main_layout; - QTabWidget* tab_widget{}; - QWidget* cur_widget{}; - struct T_Data { - QString name; - QWidget* plot; - }; - std::map data_map; - QStandardItem* get_from_data(const T_Data& data); - std::vector get_list(const std::vector& datas); - void change_to(const QString& name); -}; diff --git a/Demo_Gallery/Normal_test.h b/Demo_Gallery/Normal_test.h deleted file mode 100644 index 0ac227e..0000000 --- a/Demo_Gallery/Normal_test.h +++ /dev/null @@ -1,296 +0,0 @@ -#pragma once -#include "../Widget/component/Table/export.h" -#include "base/Tool.h" -namespace Psc { -// -// static std::vector cw(Table_View* view) { -// std::vector ret; -// ret.append({ -// renderive::create_edit_widget("隐藏行", [view, m](const int& value) { -// m->row_info_list[value]->hide = true; -// view->update(); -// }, 1), -// renderive::create_edit_widget("显示行", [view, m](const int& value) { -// m->row_info_list[value]->hide = false; -// view->update(); -// }, 1), -// renderive::create_edit_widget("隐藏列", [view, m](const int& value) { -// m->col_info_list[value]->hide = true; -// view->update(); -// }, 1), -// renderive::create_edit_widget("显示列", [view, m](const int& value) { -// m->col_info_list[value]->hide = false; -// view->update(); -// }, 1), -// -// -// renderive::create_edit_widget_list("合并单元格", [view, m](const std::vector& values) { -// int row = values[0]; -// int col = values[1]; -// int row_span = values[2]; -// int col_span = values[3]; -// m->merge(row, col, row_span, col_span); -// view->update(); -// }, {4, 4, 4, 4}), -// renderive::create_edit_widget_list("拆分单元格", [view, m](const std::vector& values) { -// int row = values[0]; -// int col = values[1]; -// int row_span = values[2]; -// int col_span = values[3]; -// m->split(row, col, row_span, col_span); -// view->update(); -// }, {4, 4, 2, 4}), -// -// renderive::create_edit_widget_list("添加行", [view, m](const std::vector& values) { -// int pos = values[0]; -// int num = values[1]; -// int col_num = m->col_info_list.size(); -// std::vector row_infos; -// for (int i = 0; i < num; i++) -// { -// auto info = std::make_shared(10, "asdasdasd"); -// row_infos.append(info); -// } -// std::vector> data; -// for (int i = 0; i < num; i++) -// { -// std::vector row; -// for (int j = 0; j < col_num; j++) -// { -// auto cur = std::make_shared(); -// cur->content = "2222"; -// row.append(cur); -// } -// data.append(row); -// } -// -// m->insert_row(pos, row_infos, data); -// view->update(); -// }, {4, 1}), -// -// renderive::create_edit_widget_list("添加列", [view, m](const std::vector& values) { -// int pos = values[0]; -// int num = values[1]; -// int row_num = m->row_info_list.size(); -// std::vector col_infos; -// for (int i = 0; i < num; i++) -// { -// auto info = std::make_shared(10, "asdasdasd"); -// col_infos.append(info); -// } -// std::vector> data; -// for (int i = 0; i < num; i++) -// { -// std::vector col; -// for (int j = 0; j < row_num; j++) -// { -// auto cur = std::make_shared(); -// cur->content = "2222"; -// col.append(cur); -// } -// data.append(col); -// } -// -// m->insert_col(pos, col_infos, data); -// view->update(); -// }, {5, 1}), -// -// renderive::create_edit_widget_list("重新设置所有行列内容", [view, m](const std::vector& values) { -// for (int i = 0; i < m->total_col(); i++) -// { -// m->col_info_list[i]->content = QString("%1").arg(i); -// } -// for (int i = 0; i < m->total_row(); i++) -// { -// m->row_info_list[i]->content = QString("%1").arg(i); -// } -// for (int i = 0; i < m->total_row(); i++) -// { -// -// for (int j = 0; j < m->total_col(); j++) -// { -// auto d = m->data[i][j]; -// d->content = QString("[%1,%2]").arg(i).arg(j); -// } -// } -// view->update(); -// }, {}), -// }); -// -// return ret; -// } -static std::vector cw(Table_View* view) { - std::vector ret; - auto m = dynamic_cast(view->model); - ret = { - renderive::create_edit_widget("隐藏行", [view, m](const int& value) { - m->get_row_info(value)->hide = true; - view->update(); }, 1), - renderive::create_edit_widget("显示行", [view, m](const int& value) { - m->get_row_info(value)->hide = false; - view->update(); }, 1), - renderive::create_edit_widget("隐藏列", [view, m](const int& value) { - m->get_col_info(value)->hide = true; - view->update(); }, 1), - renderive::create_edit_widget("显示列", [view, m](const int& value) { - m->get_col_info(value)->hide = false; - view->update(); }, 1), - renderive::create_edit_widget_list("合并单元格", [view, m](const std::vector& values) { - int row = values[0]; - int col = values[1]; - int row_span = values[2]; - int col_span = values[3]; - m->merge(row, col, row_span, col_span); - view->update(); }, {4, 4, 4, 4}), - renderive::create_edit_widget_list("拆分单元格", [view, m](const std::vector& values) { - int row = values[0]; - int col = values[1]; - int row_span = values[2]; - int col_span = values[3]; - m->split(row, col, row_span, col_span); - view->update(); }, {4, 4, 2, 4}), - renderive::create_edit_widget_list("添加行", [view, m](const std::vector& values) { - int pos = values[0]; - int num = values[1]; - int col_num = m->total_col(); - std::vector row_infos; - for (int i = 0; i < num; i++) { - auto info = new Row_Info(10, "asdasdasd"); - row_infos.push_back(info); - } - std::vector> data; - for (int i = 0; i < num; i++) { - std::vector row; - for (int j = 0; j < col_num; j++) { - auto cur = new Table_Paint_Data(""); - cur->content = "2222"; - row.push_back(cur); - } - data.push_back(row); - } - m->insert_row(pos, row_infos, data, Edge_Expand_Type::None); - view->update(); }, {4, 1}), - renderive::create_edit_widget_list("添加列", [view, m](const std::vector& values) { - int pos = values[0]; - int num = values[1]; - int row_num = m->total_row(); - std::vector col_infos; - for (int i = 0; i < num; i++) { - auto info = new Col_Info(10, "asdasdasd"); - col_infos.push_back(info); - } - std::vector> data; - for (int i = 0; i < num; i++) { - std::vector col; - for (int j = 0; j < row_num; j++) { - auto cur = new Table_Paint_Data(""); - cur->content = "2222"; - col.push_back(cur); - } - data.push_back(col); - } - m->insert_col(pos, col_infos, data, Edge_Expand_Type::None); - view->update(); }, {5, 1}), - renderive::create_edit_widget_list("重新设置所有行列内容", [view, m](const std::vector& values) { - for (int i = 0; i < m->total_col(); i++) { - m->get_col_info(i)->content = QString("%1").arg(i); - } - for (int i = 0; i < m->total_row(); i++) { - m->get_row_info(i)->content = QString("%1").arg(i); - } - for (int i = 0; i < m->total_row(); i++) { - for (int j = 0; j < m->total_col(); j++) { - auto d = (Table_Paint_Data*)m->get_table_data(i, j); - d->content = QString("[%1,%2]").arg(i).arg(j); - } - } - view->update(); }, {}), - }; - return ret; -} -inline Table_View* create_table_view2() { - struct Table_View2 : Table_View { - QMenu* menu{}; - void contextMenuEvent(QContextMenuEvent* event) override { - if (!menu) { - // menu = create_menu_normal(this, cw(this)); - menu = create_menu_normal(this, cw(this)); - } - menu->exec(event->globalPos()); - } - }; - auto ret = new Table_View2; - int row_num = 10; - int col_num = 10; - // int row_num = 14; - // int col_num = 15; - auto m = new Memory_Table_Model(); - ret->model = m; - std::vector col_infos; - for (int i = 0; i < col_num; ++i) { - col_infos.push_back(new Col_Info(80, QString::number(i))); - } - std::vector> data; - data.resize(col_infos.size()); - m->insert_col(0, col_infos, data, Edge_Expand_Type::None); - for (int i = 0; i < row_num; ++i) { - auto row_info = new Row_Info(50, QString::number(i)); - std::vector row; - for (int j = 0; j < col_num; ++j) { - auto d = new Table_Paint_Data(""); - d->parent = d; - d->content = QString("(%1,%2)").arg(i).arg(j); - row.push_back(d); - } - m->insert_row(m->total_row(), {row_info}, {row}, Edge_Expand_Type::Positive); - } - return ret; -} -inline Table_View* create_table_view() { - struct Table_View2 : Table_View { - QMenu* menu{}; - void contextMenuEvent(QContextMenuEvent* event) override { - if (!menu) { - // menu = create_menu_normal(this, cw(this)); - menu = create_menu_normal(this, cw(this)); - } - menu->exec(event->globalPos()); - } - }; - auto ret = new Table_View2; - int row_num = 10; - int col_num = 10; - // int row_num = 14; - // int col_num = 15; - auto m = new Memory_Table_Model; - ret->model = m; - for (int i = 0; i < col_num; ++i) { - m->col_info_list.push_back(new Col_Info(80, QString::number(i))); - } - for (int i = 0; i < row_num; ++i) { - m->row_info_list.push_back(new Row_Info(50, QString::number(i))); - } - for (int i = 0; i < col_num; ++i) { - std::vector row; - for (int j = 0; j < row_num; ++j) { - auto d = new Table_Paint_Data(""); - d->parent = d; - d->content = QString("(%1,%2)").arg(i).arg(j); - row.push_back(d); - } - m->data.push_back(row); - } - { - auto t = new Widget_Data(); - t->widget = new QPushButton("222222"); - m->data[2][2] = t; - } - // ret->model->merage(2, 2, 4, 4); - // - // ret->model->row_info_list[2]->hide = true; - // ret->model->col_info_list[2]->hide = true; - // ret->model->col_info_list[3]->hide = true; - // ret->model->col_info_list[4]->hide = true; - return ret; -} -} // namespace Psc diff --git a/Demo_Gallery/Planisphere_Plot.h b/Demo_Gallery/Planisphere_Plot.h deleted file mode 100644 index 6c9d719..0000000 --- a/Demo_Gallery/Planisphere_Plot.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once -#include "base/Tool.h" -static QWidget* create_planisphere_plot() { - class Time_Axis; - class Planisphere_Plot : public renderive::Latency_Eager_Plot { - public: - std::shared_ptr x_axis{}; - std::shared_ptr y_axis{}; - std::shared_ptr planisphere{}; - std::shared_ptr msr{}; - QMenu* menu{}; - void init() override { - Latency_Eager_Plot::init(); - object_name = "PlanispherePlot"; - auto data = create_renderable_node(get_root_renderable(), "Data_Renderable"); - auto axis = create_renderable_node(get_root_renderable(), "Axis_Renderable"); - auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); - x_axis = renderive::Axis::Builder(axis, Qt::Horizontal) - .set_tick_length(-10) - .set_sub_tick_length(-5) - .build(); - y_axis = renderive::Axis::Builder(axis, Qt::Vertical).build(); - planisphere = renderive::Planisphere::Builder(data, x_axis, y_axis) - .set_continue_millisecond(2000) - .build(); - msr = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); - } - protected: - void resizeEvent(QResizeEvent* event) override { - x_axis->set_x(0); - x_axis->set_y(height() - 1); - x_axis->set_pixel_size(width()); - y_axis->set_x(0); - y_axis->set_y(0); - y_axis->set_pixel_size(height()); - planisphere->set_to_axis_center(); - } - void contextMenuEvent(QContextMenuEvent* event) override { - if (!menu) { - auto ws = concat_widgets( - bw(cw(planisphere.get(), -1), "星座图"), - bw(cw(x_axis.get()), "I轴"), - bw(cw(y_axis.get()), "Q轴")); - menu = create_menu(this, ws); - } - menu->exec(event->globalPos()); - } - }; - auto w = new Planisphere_Plot; - w->init(); - return w; -} diff --git a/Demo_Gallery/Spectrum_Plot.h b/Demo_Gallery/Spectrum_Plot.h deleted file mode 100644 index 83823a2..0000000 --- a/Demo_Gallery/Spectrum_Plot.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once -#include "base/Tool.h" -static QWidget* create_spectrun_plot() { - class Spectrum_Plot : public renderive::Latency_Eager_Plot { - public: - std::shared_ptr x_axis{}; - std::shared_ptr y_axis{}; - std::shared_ptr msr{}; - std::shared_ptr sp{}; - QMenu* menu{}; - void init() override { - Latency_Eager_Plot::init(); - object_name = "Spectrum_Plot"; - auto data = create_renderable_node(get_root_renderable(), "Data_Renderable"); - auto axis = create_renderable_node(get_root_renderable(), "Axis_Renderable"); - auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); - x_axis = renderive::Frequency_Axis::Builder(axis, Qt::Horizontal) - .set_coord_range({0, 100}) - .set_tick_length(-10) - .set_sub_tick_length(-5) - .set_use_wheel(true) - .set_use_drag(true) - .build(); - y_axis = renderive::Axis::Builder(axis, Qt::Vertical) - .set_coord_range({100, 0}) - .set_unit_text("功率") - .set_use_drag(true) - .build(); - sp = renderive::Spectrum::Builder(data, x_axis, y_axis) - .set_frequency_range({0, 100}) - .build(); - msr = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); - } - protected: - void resizeEvent(QResizeEvent* event) override { - int left_margin = 20, right_margin = 20, top_margin = 20, bottom_margin = 20; - int w = width() - left_margin - right_margin; - int h = height() - top_margin - bottom_margin; - x_axis->set_x(left_margin); - x_axis->set_y(height() - bottom_margin); - x_axis->set_pixel_size(w); - y_axis->set_x(left_margin); - y_axis->set_y(top_margin); - y_axis->set_pixel_size(h); - sp->set_frequency_point_size(sp->frequency_axis()->get_pixel_point_size()); - } - void contextMenuEvent(QContextMenuEvent* event) override { - if (!menu) { - auto ws = concat_widgets( - bw(cw(sp.get(), -1), "频谱图"), - bw(cw(x_axis.get()), "频率x轴"), - bw(cw(y_axis.get()), "功率y轴"), - bw(cw(msr.get()), "多选框")); - menu = create_menu(this, ws); - } - menu->exec(event->globalPos()); - } - }; - auto w = new Spectrum_Plot; - w->init(); - return w; -} diff --git a/Demo_Gallery/Sweep_Frequent_Plot.h b/Demo_Gallery/Sweep_Frequent_Plot.h deleted file mode 100644 index e864974..0000000 --- a/Demo_Gallery/Sweep_Frequent_Plot.h +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once -#include "base/Tool.h" -static QWidget* create_sweep_frequent_plot() { - class Sweep_Frequent_Plot : public renderive::Latency_Eager_Plot { - public: - std::shared_ptr x_axis{}; - std::shared_ptr y_axis{}; - std::shared_ptr msr{}; - std::shared_ptr sf{}; - QMenu* menu{}; - void init() override { - Latency_Eager_Plot::init(); - object_name = "Axis_Test_Plot"; - auto data = create_renderable_node(get_root_renderable(), "Data_Renderable"); - auto axis = create_renderable_node(get_root_renderable(), "Axis_Renderable"); - auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); - x_axis = renderive::Axis::Builder(axis, Qt::Horizontal) - .set_coord_range({0, 100}) - .set_tick_length(-10) - .build(); - y_axis = renderive::Axis::Builder(axis, Qt::Vertical) - .set_coord_range({100, 0}) - .build(); - sf = renderive::Sweep_Frequency::Builder(data, x_axis, y_axis) - .set_block_num(200) - .set_block_frequency_point_size(20) - .set_frequency_range({0, 100}) - .build(); - msr = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); - } - protected: - void resizeEvent(QResizeEvent* event) override { - x_axis->set_x(0); - x_axis->set_y(height() - 1); - x_axis->set_pixel_size(width()); - y_axis->set_x(0); - y_axis->set_y(0); - y_axis->set_pixel_size(height()); - } - void contextMenuEvent(QContextMenuEvent* event) override { - if (!menu) { - auto ws = concat_widgets( - bw(cw(sf.get(), -1), "扫频图"), - bw(cw(x_axis.get()), "x轴"), - bw(cw(y_axis.get()), "y轴"), - bw(cw(msr.get()), "多选框")); - menu = create_menu(this, ws); - } - menu->exec(event->globalPos()); - } - }; - auto w = new Sweep_Frequent_Plot; - w->init(); - return w; -} diff --git a/Demo_Gallery/Waterfall_Plot.h b/Demo_Gallery/Waterfall_Plot.h deleted file mode 100644 index d7c4add..0000000 --- a/Demo_Gallery/Waterfall_Plot.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once -#include "base/Tool.h" -static QWidget* create_water_fall_plot() { - class Waterfall_Plot : public renderive::Latency_Eager_Plot { - public: - std::shared_ptr x_axis{}; - std::shared_ptr y_axis{}; - std::shared_ptr msr{}; - std::shared_ptr wf{}; - QMenu* menu{}; - void init() override { - Latency_Eager_Plot::init(); - object_name = "Water_Fall_Plot"; - auto data = create_renderable_node(get_root_renderable(), "Data_Renderable"); - auto axis = create_renderable_node(get_root_renderable(), "Axis_Renderable"); - auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); - x_axis = renderive::Frequency_Axis::Builder(axis, Qt::Horizontal) - .set_tick_length(-10) - .set_sub_tick_length(-5) - .build(); - y_axis = renderive::Time_Axis::Builder(axis, Qt::Vertical) - .set_time_point_size(800) - .build(); - wf = renderive::Waterfall::Builder(data, x_axis, y_axis) - .set_frequency_range({0, 20}) - .build(); - msr = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); - } - protected: - void resizeEvent(QResizeEvent* event) override { - x_axis->set_x(0); - x_axis->set_y(height()); - x_axis->set_pixel_size(width()); - y_axis->set_x(0); - y_axis->set_y(0); - y_axis->set_pixel_size(height()); - y_axis->set_time_point_size(height()); - // wf->set_frequency_point_size(wf->frequency_axis()->get_pixel_point_size()); - wf->set_frequency_point_size(width()); - } - void contextMenuEvent(QContextMenuEvent* event) override { - if (!menu) { - auto ws = concat_widgets( - bw(cw(wf.get(), -1), "瀑布图"), - bw(cw(x_axis.get()), "频率轴"), - bw(cw(y_axis.get()), "时间轴"), - bw(cw(msr.get()), "多选框")); - menu = create_menu(this, ws); - } - menu->exec(event->globalPos()); - } - }; - auto w = new Waterfall_Plot; - w->init(); - return w; -} diff --git a/Demo_Gallery/base/Axis_Test.h b/Demo_Gallery/base/Axis_Test.h deleted file mode 100644 index 3d92b61..0000000 --- a/Demo_Gallery/base/Axis_Test.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once -#include "Tool.h" -static QWidget* create_axis_test_plot() { - class Axis_Test_Plot : public renderive::Latency_Eager_Plot { - public: - std::shared_ptr axis{}; - QMenu* menu{}; - void init() override { - Latency_Eager_Plot::init(); - object_name = "Axis_Test_Plot"; - auto axis_node = create_renderable_node(get_root_renderable(), "Axis_Renderable"); - axis = renderive::Axis::Builder(axis_node, Qt::Horizontal) - .set_tick_length(-10) - .set_sub_tick_length(-5) - .set_coord_range({-12000, 12000}) - .set_use_wheel(true) - .build(); - } - protected: - void resizeEvent(QResizeEvent* event) override { - int space = 50; - axis->set_x(space); - axis->set_y(height() / 2); - axis->set_pixel_size(width() - space * 2); - } - void contextMenuEvent(QContextMenuEvent* event) override { - if (!menu) { - auto ws = - bw(cw(axis.get()), "轴"); - menu = create_menu(this, ws); - } - menu->exec(event->globalPos()); - } - }; - auto w = new Axis_Test_Plot; - w->init(); - return w; -} diff --git a/Demo_Gallery/base/Frequency_Axis.h b/Demo_Gallery/base/Frequency_Axis.h deleted file mode 100644 index fe1e35d..0000000 --- a/Demo_Gallery/base/Frequency_Axis.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include "Tool.h" -static QWidget* create_frequent_axis_test_plot() { - class Axis_Test_Plot : public renderive::Latency_Eager_Plot { - public: - std::shared_ptr axis{}; - QMenu* menu{}; - void init() override { - Latency_Eager_Plot::init(); - object_name = "Axis_Test_Plot"; - auto axis_node = create_renderable_node(get_root_renderable(), "Axis_Renderable"); - axis = renderive::Frequency_Axis::Builder(axis_node, Qt::Horizontal) - .set_tick_length(-10) - .set_sub_tick_length(-5) - .set_coord_range({-12000, 12000}) - .build(); - } - protected: - void resizeEvent(QResizeEvent* event) override { - int space = 50; - axis->set_x(space); - axis->set_y(height() / 2); - axis->set_pixel_size(width() - space * 2); - } - void contextMenuEvent(QContextMenuEvent* event) override { - if (!menu) { - auto ws = bw(cw(axis.get()), "轴"); - menu = create_menu(this, ws); - } - menu->exec(event->globalPos()); - } - }; - auto w = new Axis_Test_Plot; - w->init(); - return w; -} diff --git a/Demo_Gallery/base/Frequency_Axis_Test.h b/Demo_Gallery/base/Frequency_Axis_Test.h deleted file mode 100644 index fe1e35d..0000000 --- a/Demo_Gallery/base/Frequency_Axis_Test.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once -#include "Tool.h" -static QWidget* create_frequent_axis_test_plot() { - class Axis_Test_Plot : public renderive::Latency_Eager_Plot { - public: - std::shared_ptr axis{}; - QMenu* menu{}; - void init() override { - Latency_Eager_Plot::init(); - object_name = "Axis_Test_Plot"; - auto axis_node = create_renderable_node(get_root_renderable(), "Axis_Renderable"); - axis = renderive::Frequency_Axis::Builder(axis_node, Qt::Horizontal) - .set_tick_length(-10) - .set_sub_tick_length(-5) - .set_coord_range({-12000, 12000}) - .build(); - } - protected: - void resizeEvent(QResizeEvent* event) override { - int space = 50; - axis->set_x(space); - axis->set_y(height() / 2); - axis->set_pixel_size(width() - space * 2); - } - void contextMenuEvent(QContextMenuEvent* event) override { - if (!menu) { - auto ws = bw(cw(axis.get()), "轴"); - menu = create_menu(this, ws); - } - menu->exec(event->globalPos()); - } - }; - auto w = new Axis_Test_Plot; - w->init(); - return w; -} diff --git a/Demo_Gallery/base/Multi_Select_Test.h b/Demo_Gallery/base/Multi_Select_Test.h deleted file mode 100644 index 9e2b3c2..0000000 --- a/Demo_Gallery/base/Multi_Select_Test.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once -#include "Tool.h" -static QWidget* create_Multi_Select_Plot() { - class Multi_Select_Plot : public renderive::Latency_Eager_Plot { - public: - std::shared_ptr x_axis{}; - std::shared_ptr y_axis{}; - std::shared_ptr multi_select_rect{}; - QMenu* menu{}; - void init() override { - Latency_Eager_Plot::init(); - object_name = "PlanispherePlot"; - auto axis = create_renderable_node(get_root_renderable(), "Axis_Renderable"); - auto overlay = create_renderable_node(get_root_renderable(), "Overlay_Renderable"); - x_axis = renderive::Axis::Builder(axis, Qt::Horizontal) - .set_tick_length(-10) - .set_sub_tick_length(-5) - .build(); - y_axis = renderive::Axis::Builder(axis, Qt::Vertical).build(); - multi_select_rect = renderive::Multi_Select_Rect::Builder(overlay, x_axis, y_axis).build(); - } - protected: - void resizeEvent(QResizeEvent* event) override { - x_axis->set_x(0); - x_axis->set_y(height() - 1); - x_axis->set_pixel_size(width()); - y_axis->set_x(0); - y_axis->set_y(0); - // y_axis->setCoordReserve(true); - y_axis->set_pixel_size(height()); - } - void contextMenuEvent(QContextMenuEvent* event) override { - if (!menu) { - auto ws = bw(cw(multi_select_rect.get()), "多选框"); - menu = create_menu(this, ws); - } - menu->exec(event->globalPos()); - } - }; - auto w = new Multi_Select_Plot; - w->init(); - return w; -} diff --git a/Demo_Gallery/base/Time_Axis_Test.h b/Demo_Gallery/base/Time_Axis_Test.h deleted file mode 100644 index 421e35c..0000000 --- a/Demo_Gallery/base/Time_Axis_Test.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once -#include "Tool.h" -static QWidget* create_time_axis_test_plot() { - class Axis_Test_Plot : public renderive::Latency_Eager_Plot { - public: - std::shared_ptr axis{}; - QMenu* menu{}; - void init() override { - Latency_Eager_Plot::init(); - object_name = "TimeAxisTestPlot"; - auto axis_node = create_renderable_node(get_root_renderable(), "Axis_Renderable"); - axis = renderive::Time_Axis::Builder(axis_node, Qt::Horizontal) - .set_tick_length(-10) - .set_sub_tick_length(-5) - .build(); - } - protected: - void resizeEvent(QResizeEvent* event) override { - int space = 50; - axis->set_x(space); - axis->set_y(height() / 2); - axis->set_pixel_size(width() - space * 2); - } - void contextMenuEvent(QContextMenuEvent* event) override { - if (!menu) { - auto ws = bw(cw(axis.get(), 30), "时间轴"); - menu = create_menu(this, ws); - } - menu->exec(event->globalPos()); - } - }; - auto w = new Axis_Test_Plot; - w->init(); - return w; -} diff --git a/Demo_Gallery/base/Tool.h b/Demo_Gallery/base/Tool.h deleted file mode 100644 index d35d5bc..0000000 --- a/Demo_Gallery/base/Tool.h +++ /dev/null @@ -1,761 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -namespace renderive { -static Time_Of_Day current_time_of_day() { - return renderive::qt_to_time_of_day(QTime::currentTime()); -} -static QColor get_color(int lowest, int highest) { - int r = QRandomGenerator::global()->bounded(lowest, highest); - int g = QRandomGenerator::global()->bounded(lowest, highest); - int b = QRandomGenerator::global()->bounded(lowest, highest); - return {r, g, b}; -} -static QString get_background_style_sheet() { - QString color = QString("background-color: %1;").arg(get_color(176, 256).name()); - return color; -} -static QString get_button_style_sheet() { - QString color = QString("background-color: %1; color: #000000;").arg(get_color(200, 256).name()); - return color; -} -template -QString get_init_value(const T& value) { - return QString::number(value); -} -template <> -inline QString get_init_value(const QString& value) { - return value; -} -template -T get_value_from_string(const QString& value) { - return value.toDouble(); -} -template <> -inline QString get_value_from_string(const QString& value) { - return value; -} -template -static QWidget* create_edit_widget_list(const QString& button_text, - const std::function&)>& click, const std::vector& init_values) { - auto container = new QWidget; - auto layout = new QHBoxLayout(container); - layout->setAlignment(Qt::AlignLeft); - layout->setContentsMargins(0, 0, 0, 0); - auto confirm = new QPushButton(button_text); - // QApplication* app = (QApplication*)QApplication::instance(); - // qDebug() << "Global StyleSheet:" << app->styleSheet(); - confirm->setStyleSheet(get_button_style_sheet()); - // 清除 QSS - QFont font; - font.setFamily("Segoe UI"); - confirm->setFont(font); - confirm->setMinimumWidth(QFontMetrics(confirm->font()).horizontalAdvance(button_text) + 8); - confirm->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - layout->addWidget(confirm); - std::vector lineEditList; - for (const T& init_value : init_values) { - QString init_value_str = get_init_value(init_value); - auto cur_edit = new QLineEdit(init_value_str); - cur_edit->setStyleSheet(get_button_style_sheet()); - // cur_edit->setMaximumWidth(50); - auto fm = QFontMetrics(QFont()); - int width = fm.horizontalAdvance(init_value_str); - // cur_edit->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); - cur_edit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - int w = qMax((int)((double)width * 1.4) + 16, 50); - cur_edit->setMinimumWidth(w); - lineEditList.push_back(cur_edit); - layout->addWidget(cur_edit); - } - QObject::connect(confirm, &QPushButton::clicked, [lineEditList, click]() { - std::vector values; - for (QLineEdit* line_edit : lineEditList) { - values.push_back(get_value_from_string(line_edit->text())); - } - click(values); - }); - return container; -} -template -static QWidget* create_edit_widget(const QString& button_text, - const std::function& click, const T& init_values) { - return create_edit_widget_list(button_text, [click](const std::vector& data) { - click(data.front()); - }, std::vector{init_values}); -} -static QWidget* create_range(Axis* axis, const QString& text = "更改轴范围") { - return create_edit_widget_list(text, [axis](const std::vector& values) { - axis->set_coord_range(Range{values[0], values[1]}); - }, - {axis->coord_range().origin, axis->coord_range().target}); -} -static QMenu* find_parent_menu(QWidget* widget) { - // 从当前窗口开始,逐步检查父窗口 - QWidget* parent = widget->parentWidget(); - while (parent) { - if (QMenu* menu = qobject_cast(parent)) { - return menu; // 找到第一个 QMenu 类型的父窗口 - } - parent = parent->parentWidget(); - } - return nullptr; // 如果没有找到 QMenu 类型的父窗口 -} -static QWidget* create_select_color(const QString& text, const std::function& click, const QColor& color = QColor()) { - auto ret = new QWidget; - auto l = new QHBoxLayout(ret); - l->setContentsMargins(0, 0, 0, 0); - // l->setSpacing(0); - QString bs = get_button_style_sheet(); - auto show_color = new QWidget; - show_color->setStyleSheet(QString("background-color: %1; border: 2px solid #000000;").arg(color.name(QColor::HexArgb))); - show_color->setFixedWidth(30); - static QPushButton* btn = nullptr; - // static auto dialog = new CustomColorDialog(Qt::white, QApplication::activeWindow()); - static auto dialog = new Select_Color_Dialog; - dialog->resize(800, 600); - // dialog->adjustSize(); - auto label = new QLineEdit(color.isValid() ? color.name(QColor::HexArgb) : "无效"); - label->setAlignment(Qt::AlignCenter); - label->setStyleSheet("background-color: #ffffff; color: #000000;"); - // label->setAlignment(Qt::AlignRight | Qt::AlignVCenter); - auto button = new QPushButton(text); - button->setStyleSheet(bs); - QObject::connect(button, &QPushButton::clicked, [button, label]() { - btn = button; - dialog->set_current_color(QColor(label->text())); - dialog->show(); - }); - QObject::connect(dialog, &QDialog::finished, [ret, button, click, label, show_color](int result) { - if (btn != button) - return; - if (result == QDialog::Accepted) { - QColor select_color = dialog->current_color(); - click(select_color); - label->setText(select_color.name(QColor::HexArgb)); - show_color->setStyleSheet(QString("background-color: %1; border: 2px solid #000000;") - .arg(select_color.name(QColor::HexArgb))); - } - else if (result == -1) { - click(QColor()); - label->setText("无颜色"); - show_color->setStyleSheet(QString("background-color: rgba(255, 255, 255, 0); border: 2px solid #000000;")); - } - QMenu* menu = find_parent_menu(ret); - if (menu) { - menu->show(); - } - }); - l->addWidget(button); - l->addWidget(label); - l->addWidget(show_color); - return ret; -} -static QPushButton* create_button(const QString& text, const std::function& click) { - auto button = new QPushButton(text); - button->setStyleSheet(get_button_style_sheet()); - QObject::connect(button, &QPushButton::clicked, [click]() { - click(); - }); - return button; -} -static QPushButton* create_toggle_button(const QString& text, const QString& text2, const std::function& click, bool first_state) { - auto button = new QPushButton(first_state ? text : text2); - button->setStyleSheet(get_button_style_sheet()); - QObject::connect(button, &QPushButton::clicked, [button, click, text, text2]() { - click(); - if (button->text() == text2) { - button->setText(text); - } - else { - button->setText(text2); - } - }); - return button; -} -static QLabel* create_label(const QString& text, int h = 50, const QColor& color = Qt::black) { - auto l = new QLabel(text); - QFont font; - font.setFamily("Segoe UI"); - font.setBold(true); - l->setFont(font); - l->setFixedHeight(h); - l->setAlignment(Qt::AlignHCenter | Qt::AlignBottom); - l->setStyleSheet(QString("color: %1;").arg(color.name(QColor::HexArgb))); - return l; -} -} // namespace renderive -template -static std::vector concat_widgets(const Vectors&... vectors) { - std::vector result; - result.reserve((vectors.size() + ... + 0)); - (result.insert(result.end(), vectors.begin(), vectors.end()), ...); - return result; -} -static std::vector bw(const std::vector& widgets, const QString& name) { - if (widgets.empty()) - return {}; - auto ret = new QWidget; - ret->setStyleSheet(renderive::get_background_style_sheet()); - auto l = new QVBoxLayout(ret); - auto label = new QLabel(name); - label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter); - QFontMetrics fm(label->font()); - label->setFixedSize(fm.horizontalAdvance(name) + 16, fm.height() + 8); - label->setStyleSheet(QString("color: %1; background-color: %2; padding: 0px; margin: 0px;") - .arg( - QColor(Qt::white).name(QColor::HexArgb), - QColor(Qt::black).name(QColor::HexArgb))); - l->addWidget(label, 0, Qt::AlignHCenter | Qt::AlignBottom); - for (QWidget* w : widgets) { - l->addWidget(w); - } - return {ret}; -} -template -static QWidget* create_line_interpolation_combo(T* renderable) { - auto container = new QWidget; - auto layout = new QHBoxLayout(container); - layout->setContentsMargins(0, 0, 0, 0); - auto label = new QLabel("线图插值"); - auto combo = new QComboBox; - label->setStyleSheet(renderive::get_button_style_sheet()); - combo->setStyleSheet(renderive::get_button_style_sheet()); - combo->addItem("Nearest_Bin", static_cast(renderive::Line_Interpolation_Mode::Nearest_Bin)); - combo->addItem("Linear_Display", static_cast(renderive::Line_Interpolation_Mode::Linear_Display)); - combo->addItem("Linear_Power", static_cast(renderive::Line_Interpolation_Mode::Linear_Power)); - combo->addItem("Step_Left", static_cast(renderive::Line_Interpolation_Mode::Step_Left)); - combo->addItem("Step_Right", static_cast(renderive::Line_Interpolation_Mode::Step_Right)); - combo->addItem("Cubic_Display", static_cast(renderive::Line_Interpolation_Mode::Cubic_Display)); - combo->setCurrentIndex(combo->findData(static_cast(renderable->interpolation_mode()))); - QObject::connect(combo, QOverload::of(&QComboBox::currentIndexChanged), [renderable, combo](int index) { - renderable->set_interpolation_mode(static_cast(combo->itemData(index).toInt())); - }); - layout->addWidget(label); - layout->addWidget(combo); - return container; -} -static QWidget* create_image_interpolation_combo(renderive::Waterfall* waterfall) { - auto container = new QWidget; - auto layout = new QHBoxLayout(container); - layout->setContentsMargins(0, 0, 0, 0); - auto label = new QLabel("二维插值"); - auto combo = new QComboBox; - label->setStyleSheet(renderive::get_button_style_sheet()); - combo->setStyleSheet(renderive::get_button_style_sheet()); - combo->addItem("Nearest", static_cast(renderive::Image_Interpolation_Mode::Nearest)); - combo->addItem("Bilinear", static_cast(renderive::Image_Interpolation_Mode::Bilinear)); - combo->addItem("Bicubic", static_cast(renderive::Image_Interpolation_Mode::Bicubic)); - combo->setCurrentIndex(combo->findData(static_cast(waterfall->interpolation_mode()))); - QObject::connect(combo, QOverload::of(&QComboBox::currentIndexChanged), [waterfall, combo](int index) { - waterfall->set_interpolation_mode(static_cast(combo->itemData(index).toInt())); - }); - layout->addWidget(label); - layout->addWidget(combo); - return container; -} -static QWidget* create_control(renderive::Abs_Plot* plot, const std::vector& widgets = {}) { - auto control = new QWidget; - auto l = new QVBoxLayout(control); - l->setAlignment(Qt::AlignTop); - l->setContentsMargins({0, 0, 0, 0}); - l->setSpacing(0); - auto* core = renderive::plot_core(plot); - std::vector ws = { - renderive::create_toggle_button("暂停渲染", "开始渲染", [plot]() { - plot->is_rendering() ? plot->pause_render() : plot->start_render(); - }, plot->is_rendering()), - renderive::create_toggle_button("停止性能测试", "启动性能测试", [plot]() { - if (auto* current_core = renderive::plot_core(plot)) - renderive::set_performance_shower_enabled(*current_core, !renderive::performance_shower_enabled(*current_core)); - }, core ? renderive::performance_shower_enabled(*core) : false), - renderive::create_select_color("更改背景色", [plot](const QColor& color) { - plot->set_background_color(color); - }, plot->background_color()), - }; - if (auto latency_plot = dynamic_cast(plot)) { - ws.push_back(renderive::create_edit_widget_list("最大渲染FPS", [latency_plot](std::vector data) { - latency_plot->set_max_render_fps(data[0]); - }, {latency_plot->get_max_render_fps()})); - } - for (QWidget* cur : concat_widgets(bw(ws, "plot基础"), widgets)) { - l->addWidget(cur); - } - return control; -} -static std::vector cw(renderive::Abs_Axis* it) { - if (it == nullptr) - return {}; - auto t = std::vector{ - renderive::create_button("反转轴整体方向", [it]() { - it->set_orientation(it->orientation() == renderive::Orientation::Horizontal ? renderive::Orientation::Vertical : renderive::Orientation::Horizontal); - }), - renderive::create_edit_widget_list("主刻度值", [it](const std::vector& values) { - it->set_tick_length(values[0]); - }, - {it->tick_length()}), - renderive::create_edit_widget_list("子刻度值", [it](const std::vector& values) { - it->set_sub_tick_length(values[0]); - }, - {it->sub_tick_length()}), - renderive::create_select_color("更改轴颜色", [it](const QColor& color) { - it->set_color(renderive::qt_to_color(color)); - }, renderive::to_qcolor(it->color())), - renderive::create_edit_widget_list("设置单位", [it](const std::vector& values) { - it->set_unit_text(renderive::qt_to_string(values[0])); - }, {renderive::to_qstring(it->unit_text())}), - renderive::create_select_color("更改UnitText颜色", [it](const QColor& color) { - it->set_unit_text_pen(renderive::qt_to_pen(color)); - }, renderive::to_qcolor(it->unit_text_pen().color)), - renderive::create_select_color("更改UnitText背景色", [it](const QColor& color) { - it->set_unit_text_background_brush(renderive::qt_to_brush(color)); - }, renderive::to_qcolor(it->unit_text_background_brush().color)), - renderive::create_edit_widget_list("更改刻度斜度", [it](const std::vector& values) { - it->set_rotate(values[0]); - }, {it->rotate()}), - }; - return t; -} -static std::vector cw(renderive::Axis* it) { - if (it == nullptr) - return {}; - auto t = std::vector{ - renderive::create_range(it), - }; - return concat_widgets(cw(dynamic_cast(it)), t); -} -static std::vector cw(renderive::Frequency_Axis* it) { - if (it == nullptr) - return {}; - auto t = std::vector{}; - return concat_widgets(cw(dynamic_cast(it)), t); -} -static std::vector cw(renderive::Time_Axis* it, int num_pre_second = -1) { - if (it == nullptr) - return {}; - auto t = std::vector{ - renderive::create_edit_widget_list("时间格式", [it](std::vector data) { - it->set_time_format(renderive::qt_to_string(data[0])); - }, - {renderive::to_qstring(it->time_format())}), - renderive::create_edit_widget_list("单位间隔pixel", [it](std::vector data) { - it->set_tick_pixel_space(data[0]); - }, - {it->tick_pixel_space()}), - }; - auto timer = new QTimer(QApplication::instance()); - if (num_pre_second > 0) - timer->start(static_cast(1000.0 / static_cast(num_pre_second))); - QObject::connect(timer, &QTimer::timeout, [it]() { - it->give_data(renderive::current_time_of_day()); - }); - t.push_back(renderive::create_edit_widget_list("推数据Timer(次/s)", [timer](std::vector data) { - if (data[0] < 0) { - timer->stop(); - } - else { - timer->start((int)(1000.0 / data[0])); - } - }, - {timer->interval() > 0 ? 1000.0 / timer->interval() : -1})); - std::vector axis_widgets = cw(dynamic_cast(it)); - t.insert(t.end(), axis_widgets.begin(), axis_widgets.end()); - return t; -} -static std::vector cw(renderive::Multi_Select_Rect* it) { - if (it == nullptr) - return {}; - auto t = std::vector{ - renderive::create_select_color("更改填充色", [it](const QColor& color) { - it->set_rect_brush(renderive::qt_to_brush(color)); - }, renderive::to_qcolor(it->rect_brush().color)), - renderive::create_select_color("更改边框色", [it](const QColor& color) { - qDebug() << " color.isValid() == " << color.isValid(); - auto pen = renderive::qt_to_pen(color); - pen.style = renderive::Line_Style::Dash; - it->set_border_pen(pen); - qDebug() << " color.isValid() == " << renderive::to_qcolor(pen.color).isValid(); - }, renderive::to_qcolor(it->border_pen().color)), - renderive::create_select_color("更改字色", [it](const QColor& color) { - it->set_font_pen(renderive::qt_to_pen(color)); - }, renderive::to_qcolor(it->font_pen().color)) - }; - return t; -} -template -static std::vector cw(renderive::Hover_Info_Renderable* it) { - if (it == nullptr) - return {}; - auto t = std::vector{ - renderive::create_label("悬浮信息"), - renderive::create_toggle_button("启动悬浮信息", "停止悬浮信息", [it]() { - it->set_use_hover_info(!it->use_hover_info()); - }, !it->use_hover_info()), - renderive::create_select_color("设置文字颜色", [it](const QColor& c) { - it->set_hover_info_pen(renderive::qt_to_pen(c)); - }, renderive::to_qcolor(it->hover_info_pen().color)), - renderive::create_select_color("设置背景颜色", [it](const QColor& c) { - it->set_hover_info_background_brush(renderive::qt_to_brush(c)); - }, renderive::to_qcolor(it->hover_info_background_brush().color)) - }; - return t; -} -static std::vector cw(renderive::Waterfall* it, int num_pre_second = -1) { - if (it == nullptr) - return {}; - auto timer = new QTimer(QApplication::instance()); - if (num_pre_second > 0) - timer->start(static_cast(1000.0 / static_cast(num_pre_second))); - QObject::connect(timer, &QTimer::timeout, [it]() { - std::vector d = renderive::get_data(it->power_range(), it->frequency_point_size()); - it->give_data(renderive::current_time_of_day(), d); - }); - auto t = std::vector{ - renderive::create_toggle_button("关闭可见区裁剪", "开启可见区裁剪", [it]() { - it->set_visible_range_only(!it->visible_range_only()); - }, it->visible_range_only()), - create_image_interpolation_combo(it), - renderive::create_edit_widget_list("推数据Timer(次/s)", [timer](std::vector data) { - if (data[0] < 0) { - timer->stop(); - } - else { - timer->start((int)(1000.0 / data[0])); - } - }, {timer->interval() > 0 ? 1000.0 / timer->interval() : -1}), - }; - std::vector hover_widgets = cw(static_cast*>(it)); - t.insert(t.end(), hover_widgets.begin(), hover_widgets.end()); - return t; -} -static std::vector cw(renderive::Audio_Frequency* it, int num_pre_second = -1) { - if (it == nullptr) - return {}; - auto timer = new QTimer(QApplication::instance()); - if (num_pre_second > 0) - timer->start(static_cast(1000.0 / static_cast(num_pre_second))); - QObject::connect(timer, &QTimer::timeout, [it]() { - it->give_data(renderive::current_time_of_day(), renderive::get_data({0, 20})); - }); - auto t = std::vector{ - renderive::create_edit_widget_list("推数据Timer(次/s)", [timer](std::vector data) { - if (data[0] < 0) { - timer->stop(); - } - else { - timer->start((int)(1000.0 / data[0])); - } - }, - {timer->interval() > 0 ? 1000.0 / timer->interval() : -1}), - }; - return t; -} -static std::vector cw(renderive::Planisphere* it, int num_pre_second = -1) { - if (it == nullptr) - return {}; - auto timer = new QTimer(QApplication::instance()); - QObject::connect(timer, &QTimer::timeout, [it]() { - for (int i = 0; i < 10; ++i) { - double x = renderive::get_data(it->i_range()); - double y = renderive::get_data(it->q_range()); - it->give_data({x, y}); - } - }); - if (num_pre_second > 0) - timer->start(static_cast(1000.0 / static_cast(num_pre_second))); - auto t = std::vector{ - renderive::create_edit_widget_list("推数据Timer(次/s)", [timer](std::vector data) { - if (data[0] < 0) { - timer->stop(); - } - else { - timer->start((int)(1000.0 / data[0])); - } - }, - {timer->interval() > 0 ? 1000.0 / timer->interval() : -1}), - renderive::create_edit_widget_list("设置持续时间(ms)", [it](std::vector data) { - it->set_continue_millisecond(data[0]); - }, - {it->continue_millisecond()}), - renderive::create_select_color("更改IQ点颜色", [it](const QColor& color) { - it->set_point_color(renderive::qt_to_color(color)); - }, renderive::to_qcolor(it->point_color())), - renderive::create_select_color("更改锚点颜色", [it](const QColor& color) { - it->set_anchor_color(renderive::qt_to_color(color)); - }, renderive::to_qcolor(it->anchor_color())), - renderive::create_edit_widget_list("I范围", [it](std::vector data) { - it->set_i_range({data[0], data[1]}); - }, {it->i_range().origin, it->i_range().target}), - renderive::create_edit_widget_list("Q范围", [it](std::vector data) { - it->set_q_range({data[0], data[1]}); - }, {it->q_range().origin, it->q_range().target}), - renderive::create_button("设置到轴中心", [it]() { - it->set_to_axis_center(); - }), - }; - return t; -} -static std::vector cw(renderive::Afterglow* it, int num_pre_second = -1) { - if (it == nullptr) - return {}; - static auto create_base_data = [it]() { - renderive::Range r = it->power_range(); - std::vector ret(it->frequency_point_size()); - ret[0] = get_data(r); - for (int i = 1; i < it->frequency_point_size(); ++i) { - double rate; - if (i % 20 == 0) { - double that = qAbs(ret[i - 1] - r.origin) / r.size() - 0.5; - rate = (1.0 - that) * renderive::get_data({0.8, 1.2}); - } - else { - rate = renderive::get_data({0.8, 1.2}); - } - ret[i] = std::clamp(ret[i - 1] * rate, r.origin, r.target); - } - return ret; - }; - static std::vector base_data = create_base_data(); - auto timer = new QTimer(QApplication::instance()); - QObject::connect(timer, &QTimer::timeout, [it]() { - renderive::Range r = it->power_range(); - int n = base_data.size(); - std::vector cur_data(n); - for (int i = 0; i < n; ++i) { - double rate = renderive::get_data({0.8, 1.2}); - cur_data[i] = std::clamp(base_data[i] * rate, r.origin, r.target); - } - it->give_data(cur_data); - }); - if (num_pre_second > 0) - timer->start(static_cast(1000.0 / static_cast(num_pre_second))); - auto t = std::vector{ - renderive::create_edit_widget_list("推数据Timer(次/s)", [timer](std::vector data) { - if (data[0] < 0) { - timer->stop(); - } - else { - timer->start((int)(1000.0 / data[0])); - } - }, - {timer->interval() > 0 ? 1000.0 / timer->interval() : -1}), - renderive::create_edit_widget_list("频率范围", [it](std::vector data) { - it->set_frequency_range({data[0], data[1]}); - }, - {it->frequency_range().origin, it->frequency_range().target}), - renderive::create_edit_widget_list("功率概率范围", [it](std::vector data) { - it->set_power_range({data[0], data[1]}); - }, - {it->power_range().origin, it->power_range().target}), - renderive::create_button("更改基础线", []() { - base_data = create_base_data(); - }), - }; - return t; -} -static std::vector cw(renderive::Spectrum* it, int num_pre_second = -1) { - if (it == nullptr) - return {}; - auto timer = new QTimer(QApplication::instance()); - if (num_pre_second > 0) - timer->start(static_cast(1000.0 / static_cast(num_pre_second))); - QObject::connect(timer, &QTimer::timeout, [it]() { - it->give_data(renderive::get_data(it->power_axis()->coord_range(), it->frequency_point_size())); - }); - auto t = std::vector{ - renderive::create_toggle_button("关闭可见区裁剪", "开启可见区裁剪", [it]() { - it->set_visible_range_only(!it->visible_range_only()); - }, it->visible_range_only()), - create_line_interpolation_combo(it), - renderive::create_edit_widget_list("推数据Timer(次/s)", [timer](std::vector data) { - if (data[0] < 0) { - timer->stop(); - } - else { - timer->start((int)(1000.0 / data[0])); - } - }, {timer->interval() > 0 ? 1000.0 / timer->interval() : -1}), - renderive::create_edit_widget_list("频率范围", [it](std::vector data) { - it->set_frequency_range({data[0], data[1]}); - }, {it->frequency_range().origin, it->frequency_range().target}), - renderive::create_edit_widget_list("设置频率点数", [it](std::vector data) { - it->set_frequency_point_size(data[0]); - }, {it->frequency_point_size()}), - renderive::create_label("sweepRect"), - renderive::create_toggle_button("停止sweepRect", "启动sweepRect", [it]() { - it->set_use_sweep_frequency_rect(!it->use_sweep_frequency_rect()); - }, it->use_sweep_frequency_rect()), - renderive::create_edit_widget_list("sweepRect 范围", [it](std::vector data) { - if (!it->use_sweep_frequency_rect()) it->set_use_sweep_frequency_rect(true); - it->set_sweep_frequency_range({data[0], data[1]}); - }, {it->sweep_frequency_range().origin, it->sweep_frequency_range().target}), - renderive::create_edit_widget_list("中频", [it](std::vector data) { - if (!it->use_sweep_frequency_rect()) it->set_use_sweep_frequency_rect(true); - it->set_middle_sweep_frequency(data[0]); - }, {it->middle_sweep_frequency()}), - renderive::create_select_color("扫频矩形", [it](const QColor& c) { - it->set_sweep_rect_brush(renderive::qt_to_brush(c)); - }), - renderive::create_select_color("中频", [it](const QColor& c) { - if (!c.isValid()) { - it->set_middle_frequency_pen(renderive::Pen{.style = renderive::Line_Style::None}); - return; - } - it->set_middle_frequency_pen(renderive::qt_to_pen(c)); - }, renderive::to_qcolor(it->middle_frequency_pen().color)), - renderive::create_label("marker"), - renderive::create_toggle_button("停止最大值marker", "启动最大值marker", [it]() { - it->set_use_max_marker(!it->use_max_marker()); - }, it->use_max_marker()), - renderive::create_toggle_button("停止最小值marker", "启动最小值marker", [it]() { - it->set_use_min_marker(!it->use_min_marker()); - }, it->use_min_marker()), - renderive::create_edit_widget_list("添加自定义marker", [it](std::vector data) { - it->add_custom_marker(data[0]); - }, {0}), - renderive::create_edit_widget_list("添加自定义Linemarker", [it](std::vector data) { - it->add_custom_line_marker(data[0]); - }, {0}), - renderive::create_edit_widget_list("删除marker", [it](std::vector data) { - it->remove_custom_marker(data[0]); - }, {0}), - renderive::create_edit_widget_list("清楚所有marker", [it](std::vector data) { - it->clear_all_custom_marker(); - }, {}), - renderive::create_edit_widget_list("选择当前marker", [it](std::vector data) { - it->set_selected_line_marker(data[0]); - }, {0}), - renderive::create_edit_widget_list("选择下一个marker", [it](std::vector data) { - it->select_next(); - }, {}), - renderive::create_edit_widget_list("选择上一个marker", [it](std::vector data) { - it->select_previous(); - }, {}), - renderive::create_label("当前线"), - renderive::create_select_color("当前线色", [it](const QColor& c) { - if (!c.isValid()) { - it->set_cur_pen(renderive::Pen{.style = renderive::Line_Style::None}); - return; - } - it->set_cur_pen(renderive::qt_to_pen(c)); - }, renderive::to_qcolor(it->cur_pen().color)), - renderive::create_select_color("当前线填充色", [it](const QColor& c) { - it->set_cur_brush(renderive::qt_to_brush(c)); - }, renderive::to_qcolor(it->cur_brush().color)), - renderive::create_label("最大值线"), - renderive::create_toggle_button("停止最大值线", "启动最大值线", [it]() { - it->set_use_max_line(!it->use_max_line()); - }, it->use_max_line()), - renderive::create_select_color("最大值线色", [it](const QColor& c) { - if (!c.isValid()) { - it->set_max_pen(renderive::Pen{.style = renderive::Line_Style::None}); - return; - } - it->set_max_pen(renderive::qt_to_pen(c)); - }, renderive::to_qcolor(it->max_pen().color)), - renderive::create_select_color("最大值线填充色", [it](const QColor& c) { - it->set_max_brush(renderive::qt_to_brush(c)); - }, renderive::to_qcolor(it->max_brush().color)), - renderive::create_label("最小值线"), - renderive::create_toggle_button("停止最小值线", "启动最小值线", [it]() { - it->set_use_min_line(!it->use_min_line()); - }, it->use_min_line()), - renderive::create_select_color("最小值线色", [it](const QColor& c) { - it->set_min_pen(renderive::qt_to_pen(c)); - }, renderive::to_qcolor(it->min_pen().color)), - renderive::create_select_color("最小值线填充色", [it](const QColor& c) { - it->set_min_brush(renderive::qt_to_brush(c)); - }, renderive::to_qcolor(it->min_brush().color)), - }; - return concat_widgets(cw(static_cast*>(it)), t); -} -static std::vector cw(renderive::Sweep_Frequency* it, int num_pre_second = -1) { - if (it == nullptr) - return {}; - auto timer = new QTimer(QApplication::instance()); - if (num_pre_second > 0) - timer->start(static_cast(1000.0 / static_cast(num_pre_second))); - QObject::connect(timer, &QTimer::timeout, [it]() { - it->give_data(renderive::get_data(it->power_axis()->coord_range(), it->block_frequency_point_size())); - }); - auto t = std::vector{ - renderive::create_toggle_button("关闭可见区裁剪", "开启可见区裁剪", [it]() { - it->set_visible_range_only(!it->visible_range_only()); - }, it->visible_range_only()), - create_line_interpolation_combo(it), renderive::create_edit_widget_list("推数据Timer(次/s)", [timer](std::vector data) { - if (data[0] < 0) { - timer->stop(); - } - else { - timer->start((int)(1000.0 / data[0])); - } - }, {timer->interval() > 0 ? 1000.0 / timer->interval() : -1}), - renderive::create_select_color("线颜色", [it](const QColor& color) { - it->set_pen(renderive::qt_to_pen(color)); - }, renderive::to_qcolor(it->pen().color)), - renderive::create_select_color("扫频线颜色", [it](const QColor& color) { - auto p = it->cur_frequency_pen(); - p.color = renderive::qt_to_color(color); - it->set_cur_frequency_pen(p); - }, renderive::to_qcolor(it->cur_frequency_pen().color)), - renderive::create_edit_widget_list("频率范围", [it](const std::vector& data) { - it->set_frequency_range({data[0], data[1]}); - }, {it->frequency_range().origin, it->frequency_range().target}) - }; - return t; -} -static QMenu* create_menu(renderive::Abs_Plot* plot, const std::vector& widgets) { - auto menu = new QMenu(plot); - menu->setObjectName("memu"); - // menu->setStyle(nullptr); - menu->hide(); - menu->setContentsMargins(0, 0, 0, 0); - auto container = create_control(plot, widgets); - auto scroll_area = new QScrollArea; - scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - scroll_area->setContentsMargins(0, 0, 0, 0); - scroll_area->setWidget(container); - scroll_area->setWidgetResizable(true); - scroll_area->setObjectName("scroll_area"); - auto scrollAction = new QWidgetAction(menu); - scrollAction->setDefaultWidget(scroll_area); - menu->addAction(scrollAction); - return menu; -} -static QMenu* create_menu_normal(QWidget* w, const std::vector& widgets) { - auto menu = new QMenu(w); - menu->setObjectName("memu_normal"); - // menu->setStyle(nullptr); - menu->hide(); - menu->setContentsMargins(0, 0, 0, 0); - auto container = new QWidget; - auto l = new QVBoxLayout(container); - l->setAlignment(Qt::AlignTop); - l->setContentsMargins({0, 0, 0, 0}); - l->setSpacing(4); - for (auto widget : widgets) { - l->addWidget(widget); - } - auto scroll_area = new QScrollArea; - scroll_area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - scroll_area->setContentsMargins(0, 0, 0, 0); - scroll_area->setWidget(container); - scroll_area->setWidgetResizable(true); - scroll_area->setObjectName("scrollArea2"); - auto scrollAction = new QWidgetAction(menu); - scrollAction->setDefaultWidget(scroll_area); - menu->addAction(scrollAction); - return menu; -} diff --git a/Demo_Gallery/base/export.h b/Demo_Gallery/base/export.h deleted file mode 100644 index c3bcdd1..0000000 --- a/Demo_Gallery/base/export.h +++ /dev/null @@ -1,2 +0,0 @@ -#pragma once -#include "Tool.h" diff --git a/Demo_Gallery/demo_gallery_main.cpp b/Demo_Gallery/demo_gallery_main.cpp deleted file mode 100644 index 8506ff7..0000000 --- a/Demo_Gallery/demo_gallery_main.cpp +++ /dev/null @@ -1,203 +0,0 @@ -#include -#ifdef _WINDOWS -#include -#include -#endif -#include -#include -#include -#include "export.h" -#include "Renderive/export.h" -namespace Table_Space { -struct Base_Table_Model { - virtual ~Base_Table_Model() = default; - using Len_Type = int; - using Index_Type = int; - enum Expand_Type { - None, - Left_UP, - Right_Down, - }; - enum Data_Type { - Parent, - Son, - Normal - }; - struct Base_Data { - virtual ~Base_Data() = default; - virtual void paint(QPainter* painter, QRect rect) = 0; - QWidget* widget{}; - }; - struct Base_Info { - virtual ~Base_Info() = default; - Len_Type len = 0; - virtual void paint(QPainter* painter, QRect rect) = 0; - }; - virtual void insert_row(Index_Type pos, std::vector> rows, Expand_Type expand) = 0; - virtual void insert_col(Index_Type pos, std::vector> cols, Expand_Type expand) = 0; - virtual void remove_row(Index_Type pos, Index_Type row) = 0; - virtual void remove_col(Index_Type pos, Index_Type col) = 0; - virtual void merge(Index_Type col, Index_Type row, Index_Type col_len, Index_Type row_len) = 0; - virtual void split(Index_Type col, Index_Type row, Index_Type col_len, Index_Type row_len) = 0; - virtual QPoint span(Index_Type col, Index_Type row) = 0; // 获取某一个元素 横跨行数,列数 - virtual std::shared_ptr data(Index_Type col, Index_Type row) = 0; - virtual std::shared_ptr parent(Index_Type col, Index_Type row) = 0; - virtual Data_Type type(Index_Type col, Index_Type row) = 0; - int col_space = 14; - int row_space = 14; -}; -struct Table_Model : public Base_Table_Model { - struct Data : Base_Data { - std::shared_ptr parent = nullptr; - void paint(QPainter* painter, QRect rect) override { - painter->fillRect(rect, Qt::red); - painter->drawText(rect, Qt::AlignCenter, text); - } - QString text; - Data_Type type; - }; - using Dp = std::shared_ptr; - using Dpl = std::vector; - struct Info : Base_Info { - void paint(QPainter* painter, QRect rect) override { - painter->fillRect(rect, Qt::red); - painter->drawText(rect, Qt::AlignCenter, text); - } - QString text; - Dpl data; - }; - ~Table_Model() override; - void check_all() {} - void insert_row(Index_Type pos, std::vector> rows, Expand_Type expand) override {} - void insert_col(Index_Type pos, std::vector> insert_cols, Expand_Type expand) override {} - void remove_row(Index_Type pos, Index_Type num) override { - auto start = rows.begin() + pos; - rows.erase(start, start + num); - const auto n = rows.size(); - for (int i = 0; i < n; ++i) { - auto& l = cols.at(i); - auto s = l->data.begin() + pos; - l->data.erase(s, s + num); - } - } - void remove_col(Index_Type pos, Index_Type num) override { - auto start = cols.begin() + pos; - cols.erase(start, start + num); - const auto n = rows.size(); - for (int i = 0; i < n; ++i) { - auto& l = rows.at(i); - auto s = l->data.begin() + pos; - l->data.erase(s, s + num); - } - } - void merge(Index_Type col, Index_Type row, Index_Type col_len, Index_Type row_len) override { - const auto par = cols.at(col)->data.at(row); - const auto cn = cols.size(); - const auto rn = rows.size(); - for (auto c = col; c < cn; ++c) { - for (auto r = row; r < rn; ++r) { - const auto d = cols.at(c)->data.at(r); - d->type = Son; - d->parent = par; - } - } - par->type = Parent; - } - void split(Index_Type col, Index_Type row, Index_Type col_len, Index_Type row_len) override { - const auto cn = cols.size(); - const auto rn = rows.size(); - for (auto c = col; c < cn; ++c) { - for (auto r = row; r < rn; ++r) { - const auto d = cols.at(c)->data.at(r); - d->type = Normal; - d->parent = d; - } - } - } - QPoint span(Index_Type col, Index_Type row) override { - const auto d = cols.at(col)->data.at(row); - if (d->type == Normal) - return {1, 1}; - if (d->type == Son) - return {0, 0}; - if (d->type == Parent) { - Index_Type cur_col = col + 1; - while (cur_col < cols.size()) { - auto c = cols.at(cur_col)->data.at(row); - if (c->parent != d) - break; - cur_col++; - } - Index_Type cur_row = row + 1; - while (cur_row < rows.size()) { - auto c = rows.at(col)->data.at(cur_row); - if (c->parent != d) - break; - cur_row++; - } - return {cur_col - col, cur_row - row}; - } - printf("span unknown type[%d]!", d->type); - ASSERT(false, "span unknown type!"); - } - std::shared_ptr data(Index_Type col, Index_Type row) override { - return cols.at(col)->data.at(row); - } - std::shared_ptr parent(Index_Type col, Index_Type row) override { - auto d = cols.at(col)->data.at(row); - return d->parent; - } - Data_Type type(Index_Type col, Index_Type row) override { - auto d = cols.at(col)->data.at(row); - return d->type; - } -private: - std::vector> cols; - std::vector> rows; -}; -} // namespace Table_Space -class Base_Widget : public QWidget { -public: - Base_Widget() { - // 初始化按钮,放置在 widget 中 - QPushButton* btn = new QPushButton("你好", this); - btn->setGeometry(50, 50, 500, 30); // 设置按钮的位置和大小 - QPushButton* btn2 = new QPushButton("按钮2", this); - btn2->setGeometry(150, 150, 100, 30); // 这个按钮部分会超出父控件区域 - } -protected: - void paintEvent(QPaintEvent* event) override { - QPainter painter(this); - // 设置父控件背景颜色 - painter.fillRect(rect(), Qt::black); - // 定义裁剪区域(在父控件内的有效区域) - QRegion region(0, 0, 300, 300); // 设置裁剪区域为 300x300,超出部分隐藏 - setMask(region); // 设置掩膜,超出区域将不会显示 - QWidget::paintEvent(event); // 默认绘制子控件 - } -}; -int main(int argc, char* argv[]) { - QApplication app(argc, argv); - QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8")); -#ifdef _WINDOWS - SetConsoleOutputCP(CP_UTF8); - system("chcp 65001"); - // setbuf(stdout, 0); -#endif - QElapsedTimer timer; - timer.start(); - Demo_Gallery w; - // Base_Widget w; - w.resize(1000, 600); - w.show(); - // renderive::Graphic g; - // g.resize(1000, 600); - // g.show(); - // auto it = new renderive::SelectColorDialog(); - // it->resize(1000, 600); - // it->show(); - renderive::start_render_scheduler(); - qDebug() << "启动耗时 " << timer.elapsed(); - // f(); - return QApplication::exec(); -} diff --git a/Demo_Gallery/export.h b/Demo_Gallery/export.h deleted file mode 100644 index 8305a4a..0000000 --- a/Demo_Gallery/export.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once -#include "Afterglow_Plot.h" -#include "Audio_Plot.h" -#include "Demo_Gallery.h" -#include "Normal_test.h" -#include "Planisphere_Plot.h" -#include "Spectrum_Plot.h" -#include "Sweep_Frequent_Plot.h" -#include "base/Tool.h" -#include "Waterfall_Plot.h" -#include "base/Axis_Test.h" -#include "base/Frequency_Axis_Test.h" -#include "base/Multi_Select_Test.h" -#include "base/Time_Axis_Test.h" diff --git a/Qt/plot/Latency_Eager_Plot.cpp b/Qt/plot/Latency_Eager_Plot.cpp index 15ceaaa..15ce26e 100644 --- a/Qt/plot/Latency_Eager_Plot.cpp +++ b/Qt/plot/Latency_Eager_Plot.cpp @@ -1,20 +1,15 @@ #include "Latency_Eager_Plot_p.h" - namespace renderive { - Latency_Eager_Plot_Private::Latency_Eager_Plot_Private() : Abs_Plot_Private(std::make_unique()) { latency_strategy = static_cast(strategy); } - Latency_Eager_Plot::Latency_Eager_Plot() : Abs_Plot(new Latency_Eager_Plot_Private()) {} - -double Latency_Eager_Plot::get_max_render_fps() const { +double Latency_Eager_Plot::max_render_fps() const { auto* data = static_cast(d); return data->latency_strategy ? data->latency_strategy->max_render_fps() : 0.0; } - void Latency_Eager_Plot::set_max_render_fps(double fps) { auto* data = static_cast(d); if (data->latency_strategy) { @@ -22,15 +17,12 @@ void Latency_Eager_Plot::set_max_render_fps(double fps) { data->core->mark_render_state_dirty(); } } - -Refresh_Control_Snapshot Latency_Eager_Plot::get_frame_feedback_state() const { +Refresh_Control_Snapshot Latency_Eager_Plot::refresh_feedback_snapshot() const { auto* data = static_cast(d); return data->latency_strategy ? data->latency_strategy->feedback_state() : Refresh_Control_Snapshot{}; } - void Latency_Eager_Plot::start_render(int max_render_fps) { set_max_render_fps(max_render_fps); Abs_Plot::start_render(); } - } // namespace renderive diff --git a/Qt/plot/Latency_Eager_Plot.h b/Qt/plot/Latency_Eager_Plot.h index dd073a9..aaaebc1 100644 --- a/Qt/plot/Latency_Eager_Plot.h +++ b/Qt/plot/Latency_Eager_Plot.h @@ -5,9 +5,9 @@ class LIB_DECL Latency_Eager_Plot : public Abs_Plot { public: Latency_Eager_Plot(); ~Latency_Eager_Plot() override = default; - [[nodiscard]] double get_max_render_fps() const; + [[nodiscard]] double max_render_fps() const; void set_max_render_fps(double fps); - [[nodiscard]] Refresh_Control_Snapshot get_frame_feedback_state() const; + [[nodiscard]] Refresh_Control_Snapshot refresh_feedback_snapshot() const; void start_render(int max_render_fps); }; } // namespace renderive diff --git a/Qt/plot/Plot.cpp b/Qt/plot/Plot.cpp index c577e75..ffd1e5c 100644 --- a/Qt/plot/Plot.cpp +++ b/Qt/plot/Plot.cpp @@ -24,7 +24,7 @@ Color from_qcolor(const QColor& color) { } QColor to_qcolor(Color color) { - return QColor(color.red, color.green, color.blue, color.alpha); + return QColor(color.r, color.g, color.b, color.a); } std::string to_utf8_string(const QString& text) { @@ -49,7 +49,7 @@ void Abs_Plot_Private::attach_widget(Abs_Plot* plot) { core->set_presentation_sink(presentation_sink); QPointer guarded_plot(plot); auto pending = performance_update_pending; - set_performance_shower_update_callback(*core, [guarded_plot, pending]() mutable { + set_performance_overlay_update_callback(*core, [guarded_plot, pending]() mutable { if (!guarded_plot || pending->exchange(true, std::memory_order_acq_rel)) return; QTimer::singleShot(0, guarded_plot.data(), [guarded_plot, pending]() mutable { @@ -70,7 +70,7 @@ Abs_Plot::Abs_Plot(Abs_Plot_Private* private_data) Abs_Plot::~Abs_Plot() { if (d) { - set_performance_shower_update_callback(*d->core, {}); + set_performance_overlay_update_callback(*d->core, {}); d->core->pause_render(); delete d; d = nullptr; @@ -89,7 +89,7 @@ Plot_Core* Abs_Plot::core() const { return d ? d->core.get() : nullptr; } -std::shared_ptr Abs_Plot::get_root_renderable() const { +std::shared_ptr Abs_Plot::root_renderable() const { return d->core->root_renderable(); } @@ -147,7 +147,7 @@ void Abs_Plot_Private::paint_event(Abs_Plot* plot, QPaintEvent* event) { else { painter.fillRect(plot->rect(), plot->background_color()); } - auto performance_snapshot = performance_shower_snapshot(*core); + auto performance_snapshot = performance_overlay_snapshot(*core); if (performance_snapshot && !performance_snapshot->image.empty()) { Size current_size = core->viewport_size(); auto ctx = core->render_context(); @@ -180,7 +180,7 @@ bool Abs_Plot_Private::event(Abs_Plot* plot, QEvent* event, bool base_result) { case QEvent::Resize: { auto* resize_event = static_cast(event); core->set_viewport_size(Qt_Event_Adapter::to_size(resize_event->size())); - notify_performance_shower_viewport_changed(*core); + notify_performance_overlay_viewport_changed(*core); core->dispatch_event(Qt_Event_Adapter::to_resize_event(resize_event)); core->mark_render_state_dirty(); break; @@ -204,7 +204,7 @@ bool Abs_Plot_Private::event(Abs_Plot* plot, QEvent* event, bool base_result) { } case QEvent::Wheel: { auto wheel_event = Qt_Event_Adapter::to_wheel_event(static_cast(event)); - if (performance_shower_handle_wheel(*core, wheel_event.position, wheel_event.angle_delta_y, wheel_event.pixel_delta_y)) { + if (performance_overlay_handle_wheel(*core, wheel_event.position, wheel_event.angle_delta_y, wheel_event.pixel_delta_y)) { event->accept(); request_performance_overlay_update(plot); return true; @@ -214,7 +214,7 @@ bool Abs_Plot_Private::event(Abs_Plot* plot, QEvent* event, bool base_result) { } case QEvent::MouseMove: { auto pointer_event = Qt_Event_Adapter::to_pointer_event(static_cast(event), Event_Type::Pointer_Move); - if (performance_shower_handle_pointer_move(*core, pointer_event.position)) { + if (performance_overlay_handle_pointer_move(*core, pointer_event.position)) { event->accept(); request_performance_overlay_update(plot); return true; @@ -225,7 +225,7 @@ bool Abs_Plot_Private::event(Abs_Plot* plot, QEvent* event, bool base_result) { case QEvent::MouseButtonPress: { auto* mouse_event = static_cast(event); auto pointer_event = Qt_Event_Adapter::to_pointer_event(mouse_event, Event_Type::Pointer_Press); - if (mouse_event->button() == Qt::LeftButton && performance_shower_handle_pointer_press(*core, pointer_event.position)) { + if (mouse_event->button() == Qt::LeftButton && performance_overlay_handle_pointer_press(*core, pointer_event.position)) { event->accept(); request_performance_overlay_update(plot); return true; @@ -236,7 +236,7 @@ bool Abs_Plot_Private::event(Abs_Plot* plot, QEvent* event, bool base_result) { case QEvent::MouseButtonRelease: { auto* mouse_event = static_cast(event); auto pointer_event = Qt_Event_Adapter::to_pointer_event(mouse_event, Event_Type::Pointer_Release); - if (mouse_event->button() == Qt::LeftButton && performance_shower_handle_pointer_release(*core, pointer_event.position)) { + if (mouse_event->button() == Qt::LeftButton && performance_overlay_handle_pointer_release(*core, pointer_event.position)) { event->accept(); request_performance_overlay_update(plot); return true; diff --git a/Qt/plot/Plot.h b/Qt/plot/Plot.h index c9298d6..baf3851 100644 --- a/Qt/plot/Plot.h +++ b/Qt/plot/Plot.h @@ -8,24 +8,20 @@ #include #include #include - namespace renderive { - void LIB_DECL start_render_scheduler(Render_Runtime_Config config = {}); - struct Abs_Plot_Private; class Plot_Core; -class Performance_Shower; +class Performance_Overlay; class Latency_Eager_Plot; class Explicit_Plot; - class LIB_DECL Abs_Plot : public QWidget { Q_OBJECT public: virtual void init(); QColor background_color(); [[nodiscard]] Plot_Core* core() const; - [[nodiscard]] std::shared_ptr get_root_renderable() const; + [[nodiscard]] std::shared_ptr root_renderable() const; [[nodiscard]] std::shared_ptr create_renderable_node(const std::shared_ptr& parent, const QString& object_name = {}) const; QString object_name; void set_background_color(const QColor& color); @@ -36,12 +32,10 @@ public: void start_render(); void pause_render(); ~Abs_Plot() override; - protected: explicit Abs_Plot(Abs_Plot_Private* private_data); bool event(QEvent* event) final; void paintEvent(QPaintEvent* event) final; Abs_Plot_Private* d{}; }; - } // namespace renderive diff --git a/export.h b/export.h index 1d87c91..bd63907 100644 --- a/export.h +++ b/export.h @@ -43,7 +43,7 @@ inline Color qt_to_color(const QColor& color) { } inline QColor to_qcolor(Color color) { - return QColor(color.red, color.green, color.blue, color.alpha); + return QColor(color.r, color.g, color.b, color.a); } inline Line_Style qt_to_line_style(Qt::PenStyle style) { diff --git a/main.cmake b/main.cmake index 81f8ee9..1ab6ccb 100644 --- a/main.cmake +++ b/main.cmake @@ -59,6 +59,6 @@ set_property(TARGET Psc_Widget PROPERTY AUTORCC ON) target_link_libraries(Psc_Widget PUBLIC ${qt_libraries}) target_link_libraries(Psc_Widget PUBLIC Psc_Core_Static) # Demo 画廊 -append_glob_source(Demo_Gallery_src ${root_dir}/Demo_Gallery) -add_executable(Demo_Gallery ${Demo_Gallery_src}) -target_link_libraries(Demo_Gallery PUBLIC Renderive_Qt Psc_Widget) +#append_glob_source(Demo_Gallery_src ${root_dir}/Demo_Gallery) +#add_executable(Demo_Gallery ${Demo_Gallery_src}) +#target_link_libraries(Demo_Gallery PUBLIC Renderive_Qt Psc_Widget) diff --git a/test/Renderive_Core_Tests.cpp b/test/Renderive_Core_Tests.cpp index 87a2a25..b07c286 100644 --- a/test/Renderive_Core_Tests.cpp +++ b/test/Renderive_Core_Tests.cpp @@ -4,7 +4,7 @@ #include "Core/plot/Plot_Frame_Pipeline.h" #include "Core/plot/Plot_Core.h" #include "Core/execution/Render_Executor.h" -#include "Core/plottable/Performance_Shower_p.h" +#include "Core/plottable/Performance_Overlay_p.h" #include "Core/plottable/export.h" #include "Core/render/Image.h" #include @@ -65,7 +65,7 @@ std::shared_ptr performance_frame(std::uint64_t frame_id frame->outcome = Frame_Outcome::Presented; frame->worker.executor_at_finish.worker_count = 4; frame->worker.executor_at_finish.active_workers = 1; - frame->worker.executor_at_finish.completed_tasks = frame_id; + frame->worker.executor_at_finish.completed_task_nodes = frame_id; return frame; } @@ -121,7 +121,7 @@ TEST(Renderive_Canvas, TextUsesPenAndFillUsesBrush) { ASSERT_NE(row, nullptr); for (int x = 8; x < 320; ++x) { Color color = premultiplied_to_color(row[x]); - if (color.alpha && color.red < 120 && color.green < 120 && color.blue < 120) + if (color.a && color.r < 120 && color.g < 120 && color.b < 120) ++dark_pixels; } } @@ -162,7 +162,7 @@ TEST(Renderive_Triple_Buffer, RoleSwapsAreTryOnlyAndDeterministic) { TEST(Renderive_Frame_Pipeline, PublishAndPaintUseMiddleVersionOnly) { Plot_Frame_Pipeline pipeline; - auto lease = pipeline.try_begin_render(); + auto lease = pipeline.try_acquire_render_frame(); ASSERT_TRUE(static_cast(lease)); ASSERT_TRUE(lease.frame->metadata); lease.frame->metadata->frame_id = 1; @@ -171,20 +171,20 @@ TEST(Renderive_Frame_Pipeline, PublishAndPaintUseMiddleVersionOnly) { lease.frame->version.store(1, std::memory_order_release); lease.reset(); - auto published = pipeline.try_publish_rendered(25); - EXPECT_TRUE(pipeline.middle_has_new_frame()); + auto published = pipeline.try_publish_rendered_frame(25); + EXPECT_TRUE(pipeline.middle_frame_ready()); EXPECT_TRUE(published.request_present); - EXPECT_EQ(published.dropped_frame, nullptr); + EXPECT_EQ(published.dropped_frame_record, nullptr); - auto painting = pipeline.try_begin_paint(30); - EXPECT_TRUE(painting.new_frame); + auto painting = pipeline.try_acquire_paint_frame(30); + EXPECT_TRUE(painting.has_new_frame); EXPECT_TRUE(static_cast(painting.lease)); - EXPECT_FALSE(pipeline.middle_has_new_frame()); + EXPECT_FALSE(pipeline.middle_frame_ready()); } TEST(Renderive_Frame_Pipeline, PaintAcquireFailureKeepsPendingRequest) { Plot_Frame_Pipeline pipeline; - auto lease = pipeline.try_begin_render(); + auto lease = pipeline.try_acquire_render_frame(); ASSERT_TRUE(static_cast(lease)); ASSERT_TRUE(lease.frame->metadata); lease.frame->metadata->frame_id = 1; @@ -193,20 +193,20 @@ TEST(Renderive_Frame_Pipeline, PaintAcquireFailureKeepsPendingRequest) { lease.frame->version.store(1, std::memory_order_release); lease.reset(); - auto published = pipeline.try_publish_rendered(25); + auto published = pipeline.try_publish_rendered_frame(25); ASSERT_TRUE(published.request_present); EXPECT_TRUE(pipeline.paint_request_pending.load(std::memory_order_acquire)); auto busy = pipeline.frame_control.try_acquire_role(Frame_Painting); ASSERT_EQ(busy.result, Triple_Buffer_Result::Success); - auto failed = pipeline.try_begin_paint(30); - EXPECT_TRUE(failed.paint_acquire_dropped); - EXPECT_FALSE(failed.update_was_pending); + auto failed = pipeline.try_acquire_paint_frame(30); + EXPECT_TRUE(failed.paint_frame_unavailable); + EXPECT_FALSE(failed.present_request_was_pending); EXPECT_TRUE(pipeline.paint_request_pending.load(std::memory_order_acquire)); pipeline.frame_control.unmark_use(busy.lease); - auto consumed = pipeline.try_begin_paint(35); - EXPECT_TRUE(consumed.update_was_pending); + auto consumed = pipeline.try_acquire_paint_frame(35); + EXPECT_TRUE(consumed.present_request_was_pending); EXPECT_TRUE(static_cast(consumed.lease)); } @@ -262,7 +262,7 @@ TEST(Renderive_Render_Executor, FrameAdmissionIsBounded) { std::atomic_bool entered{false}; std::atomic_bool release{false}; std::atomic_int completed{0}; - auto first_stat = std::make_shared(); + auto first_stat = std::make_shared(); ASSERT_TRUE(executor.try_submit(Render_Executor_Task{ 1, 1, @@ -283,7 +283,7 @@ TEST(Renderive_Render_Executor, FrameAdmissionIsBounded) { ASSERT_TRUE(wait_until([&]() { return entered.load(std::memory_order_acquire); })); - auto second_stat = std::make_shared(); + auto second_stat = std::make_shared(); EXPECT_TRUE(executor.try_submit(Render_Executor_Task{ 2, 1, @@ -297,7 +297,7 @@ TEST(Renderive_Render_Executor, FrameAdmissionIsBounded) { 1, true })); - auto third_stat = std::make_shared(); + auto third_stat = std::make_shared(); EXPECT_TRUE(executor.try_submit(Render_Executor_Task{ 3, 1, @@ -311,7 +311,7 @@ TEST(Renderive_Render_Executor, FrameAdmissionIsBounded) { 1, true })); - auto duplicate_stat = std::make_shared(); + auto duplicate_stat = std::make_shared(); EXPECT_FALSE(executor.try_submit(Render_Executor_Task{ 2, 2, @@ -323,7 +323,7 @@ TEST(Renderive_Render_Executor, FrameAdmissionIsBounded) { 1, true })); - auto overflow_stat = std::make_shared(); + auto overflow_stat = std::make_shared(); EXPECT_FALSE(executor.try_submit(Render_Executor_Task{ 4, 1, @@ -346,7 +346,7 @@ TEST(Renderive_Render_Executor, TaskflowTopologyRunsInFrameOrder) { Render_Executor executor(Render_Runtime_Config{2}); std::atomic_int sequence{0}; std::atomic_bool completed{false}; - auto stat = std::make_shared(); + auto stat = std::make_shared(); ASSERT_TRUE(executor.try_submit(Render_Executor_Task{ 1, @@ -406,7 +406,7 @@ TEST(Renderive_Render_Executor, QueuedFramesRunRoundRobinByPlot) { }), {}, Task([]() {}), - std::make_shared(), + std::make_shared(), 1, true })); @@ -423,7 +423,7 @@ TEST(Renderive_Render_Executor, QueuedFramesRunRoundRobinByPlot) { }), {}, Task([]() {}), - std::make_shared(), + std::make_shared(), 1, true })); @@ -436,7 +436,7 @@ TEST(Renderive_Render_Executor, QueuedFramesRunRoundRobinByPlot) { }), {}, Task([]() {}), - std::make_shared(), + std::make_shared(), 1, true })); @@ -457,31 +457,31 @@ TEST(Renderive_Performance_Shower, ToggleDoesNotReenterRenderableTreeUnsafely) { auto root = plot.root_renderable(); ASSERT_TRUE(root); EXPECT_TRUE(root->children_snapshot().empty()); - set_performance_shower_enabled(plot, true); - EXPECT_TRUE(performance_shower_enabled(plot)); + set_performance_overlay_enabled(plot, true); + EXPECT_TRUE(performance_overlay_enabled(plot)); EXPECT_TRUE(root->children_snapshot().empty()); - set_performance_shower_enabled(plot, false); - EXPECT_FALSE(performance_shower_enabled(plot)); + set_performance_overlay_enabled(plot, false); + EXPECT_FALSE(performance_overlay_enabled(plot)); EXPECT_TRUE(root->children_snapshot().empty()); } TEST(Renderive_Performance_Shower, TogglePreservesAttachedOptions) { Plot_Core plot(std::make_unique()); plot.init(); - Performance_Shower_Options options; + Performance_Overlay_Options options; options.font.size = 17.0; options.background = Color{10, 20, 30, 255}; options.foreground = Color{240, 240, 240, 255}; - auto original = attach_performance_shower(plot, options); + auto original = attach_performance_overlay(plot, options); ASSERT_TRUE(original); - set_performance_shower_enabled(plot, true); - EXPECT_TRUE(performance_shower_enabled(plot)); - set_performance_shower_enabled(plot, false); - EXPECT_FALSE(performance_shower_enabled(plot)); - set_performance_shower_enabled(plot, true); + set_performance_overlay_enabled(plot, true); + EXPECT_TRUE(performance_overlay_enabled(plot)); + set_performance_overlay_enabled(plot, false); + EXPECT_FALSE(performance_overlay_enabled(plot)); + set_performance_overlay_enabled(plot, true); - auto toggled = performance_shower(plot); + auto toggled = performance_overlay(plot); ASSERT_EQ(toggled, original); EXPECT_EQ(toggled->options().font.size, options.font.size); EXPECT_EQ(toggled->options().background, options.background); @@ -489,13 +489,13 @@ TEST(Renderive_Performance_Shower, TogglePreservesAttachedOptions) { } TEST(Renderive_Hover_Info, DefaultTextPenContrastsWithDefaultBackground) { - Hover_Info_Render_State state; - EXPECT_EQ(state.hover_info_brush.color, Color::white()); - EXPECT_EQ(state.hover_info_pen.color, Color::black()); + Hover_Tooltip_State state; + EXPECT_EQ(state.tooltip_background_brush.color, Color::white()); + EXPECT_EQ(state.tooltip_text_pen.color, Color::black()); } TEST(Renderive_Performance_Shower, WorkerConsumesSharedFrameRecord) { - auto state = std::make_shared(); + auto state = std::make_shared(); state->enabled.store(true, std::memory_order_release); auto frame = std::make_shared(); frame->frame_id = 7; @@ -516,7 +516,7 @@ TEST(Renderive_Performance_Shower, WorkerConsumesSharedFrameRecord) { auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds(2); std::shared_ptr snapshot; while (std::chrono::steady_clock::now() < deadline) { - snapshot = state->display_snapshot_slot.load(std::memory_order_acquire); + snapshot = state->published_snapshot.load(std::memory_order_acquire); if (snapshot && !state->worker_active.load(std::memory_order_acquire)) break; std::this_thread::sleep_for(std::chrono::milliseconds(1)); @@ -530,13 +530,13 @@ TEST(Renderive_Performance_Shower, WorkerConsumesSharedFrameRecord) { } TEST(Renderive_Performance_Shower, OptionsAffectSnapshotRendering) { - Performance_Shower shower; - Performance_Shower_Options options; + Performance_Overlay shower; + Performance_Overlay_Options options; options.font.size = 18.0; options.background = Color{10, 20, 30, 255}; options.foreground = Color{240, 240, 240, 255}; shower.set_options(options); - shower.setEnabled(true); + shower.set_enabled(true); shower.set_viewport(Size{260, 120}, 1); shower.collect_frame(performance_frame(1, 260, 120)); @@ -553,10 +553,10 @@ TEST(Renderive_Performance_Shower, OptionsAffectSnapshotRendering) { } TEST(Renderive_Performance_Shower, OutcomeWidthIsSeededWithLongestEnumText) { - auto state = std::make_shared(); + auto state = std::make_shared(); state->enabled.store(true, std::memory_order_release); auto outcome_width = [&]() { - return state->field_layout_states[static_cast(Performance_Field_Id::Outcome)].max_value_width; + return state->field_layout_states[static_cast(Performance_Metric_Id::Outcome)].max_value_width; }; auto presented = performance_frame(1, 260, 120); @@ -581,10 +581,10 @@ TEST(Renderive_Performance_Shower, OutcomeWidthIsSeededWithLongestEnumText) { } TEST(Renderive_Performance_Shower, NumericFieldWidthIsMonotonicAcrossResetAndResize) { - auto state = std::make_shared(); + auto state = std::make_shared(); state->enabled.store(true, std::memory_order_release); auto frame_width = [&]() { - return state->field_layout_states[static_cast(Performance_Field_Id::Frame_Id)].max_value_width; + return state->field_layout_states[static_cast(Performance_Metric_Id::Frame_Id)].max_value_width; }; double previous = 0.0; double wide = 0.0; @@ -593,7 +593,7 @@ TEST(Renderive_Performance_Shower, NumericFieldWidthIsMonotonicAcrossResetAndRes ASSERT_TRUE(state->metric_queue.try_push(record)); schedule_performance_metrics_worker(state); ASSERT_TRUE(wait_until([&]() { - auto snapshot = state->display_snapshot_slot.load(std::memory_order_acquire); + auto snapshot = state->published_snapshot.load(std::memory_order_acquire); return snapshot && state->aggregate.latest.frame_id == frame_id && !state->worker_active.load(std::memory_order_acquire); })); double current = frame_width(); @@ -618,7 +618,7 @@ TEST(Renderive_Performance_Shower, NumericFieldWidthIsMonotonicAcrossResetAndRes state->snapshot_rebuild_requested.store(true, std::memory_order_release); schedule_performance_metrics_worker(state); ASSERT_TRUE(wait_until([&]() { - auto snapshot = state->display_snapshot_slot.load(std::memory_order_acquire); + auto snapshot = state->published_snapshot.load(std::memory_order_acquire); return snapshot && snapshot->viewport_version == 2 && !state->worker_active.load(std::memory_order_acquire); })); EXPECT_EQ(frame_width(), wide); @@ -626,8 +626,8 @@ TEST(Renderive_Performance_Shower, NumericFieldWidthIsMonotonicAcrossResetAndRes } TEST(Renderive_Performance_Shower, ScrollCommandsUpdateOffsetAndClamp) { - Performance_Shower shower; - shower.setEnabled(true); + Performance_Overlay shower; + shower.set_enabled(true); shower.set_viewport(Size{220, 70}, 1); auto frame = performance_frame(1, 220, 70); shower.collect_frame(frame); @@ -666,8 +666,8 @@ TEST(Renderive_Performance_Shower, ScrollCommandsUpdateOffsetAndClamp) { } TEST(Renderive_Performance_Shower, Utf8WrappingKeepsValidText) { - Performance_Shower shower; - shower.setEnabled(true); + Performance_Overlay shower; + shower.set_enabled(true); shower.set_viewport(Size{120, 90}, 1); auto frame = performance_frame(1, 120, 90); Renderable_Frame_Stat stat;