改结构

This commit is contained in:
2026-08-17 13:32:03 +08:00
parent 7c6b0f3e1e
commit 6a1980b920
56 changed files with 1642 additions and 649 deletions
+36 -2
View File
@@ -5,6 +5,7 @@
namespace renderive {
struct LIB_DECL Abs_Axis
: detail::Renderable<Abs_Axis> {
using Base = detail::Renderable<Abs_Axis>;
Abs_Axis();
~Abs_Axis() override;
[[nodiscard]] virtual Axis_Transform transform() const = 0;
@@ -14,8 +15,41 @@ struct LIB_DECL Abs_Axis
[[nodiscard]] int sub_tick_count(double major_step) const noexcept;
[[nodiscard]] virtual std::string tick_label(double tick) const = 0;
protected:
struct State : next_State<State> {};
struct Impl : next_Impl<Impl> {};
struct Builder : Base::template next_Builder<Builder> {};
struct State : Base::template next_State<State> {};
struct Impl : Base::template next_Impl<Impl> {};
struct Observer : Base::template next_Observer<Observer> {};
template <class Next>
using next_Builder = renderable_inheritance::Builder_Node<Next, Builder>;
template <class Next>
using next_State = renderable_inheritance::State_Node<Next, State>;
template <class Next>
using next_Impl = renderable_inheritance::Impl_Node<Next, Impl>;
template <class Next>
using next_Observer =
renderable_inheritance::Observer_Node<Next, Observer>;
static_assert(inheritance::Defines_Chain_Layer<
Builder, Base::template next_Builder<Builder>,
next_Builder<inheritance::Chain_Probe>,
renderable_inheritance::Builder_Node<
inheritance::Chain_Probe, Builder>>);
static_assert(inheritance::Defines_Chain_Layer<
State, Base::template next_State<State>,
next_State<inheritance::Chain_Probe>,
renderable_inheritance::State_Node<
inheritance::Chain_Probe, State>>);
static_assert(inheritance::Defines_Chain_Layer<
Impl, Base::template next_Impl<Impl>,
next_Impl<inheritance::Chain_Probe>,
renderable_inheritance::Impl_Node<
inheritance::Chain_Probe, Impl>>);
static_assert(inheritance::Defines_Chain_Layer<
Observer, Base::template next_Observer<Observer>,
next_Observer<inheritance::Chain_Probe>,
renderable_inheritance::Observer_Node<
inheritance::Chain_Probe, Observer>>);
using detail::Renderable<Abs_Axis>::Renderable;
};
} // namespace renderive
@@ -15,7 +15,13 @@ struct Axis_State_Strategy
: Renderable<Layer, Abs_Axis> {
using Render_Base = Renderable<Layer, Abs_Axis>;
protected:
struct Builder
: Render_Base::template next_Builder<Builder> {};
struct State : Render_Base::template next_State<State> {};
struct Observer : Render_Base::template next_Observer<Observer> {};
struct Impl : Render_Base::template next_Impl<Impl> {
static_assert(inheritance::Inherits_Chain_Parent<
Impl, Render_Base::template next_Impl<Impl>>);
using State = typename Layer::State;
[[nodiscard]] Axis_Transform transform(const Properties& state) const noexcept {
return make_transform(state, coordinate_range(state));
@@ -215,7 +221,31 @@ protected:
}
};
template <class Next>
using next_State = renderable_inheritance::State_Node<Next, State>;
template <class Next>
using next_Impl = renderable_inheritance::Impl_Node<Next, Impl>;
template <class Next>
using next_Observer =
renderable_inheritance::Observer_Node<Next, Observer>;
template <class Next>
using next_Builder =
renderable_inheritance::Builder_Node<Next, Builder>;
static_assert(inheritance::Defines_Chain_Layer<
Builder, Render_Base::template next_Builder<Builder>,
next_Builder<inheritance::Chain_Probe>,
renderable_inheritance::Builder_Node<
inheritance::Chain_Probe, Builder>>);
static_assert(inheritance::Defines_Chain_Layer<
State, Render_Base::template next_State<State>,
next_State<inheritance::Chain_Probe>,
renderable_inheritance::State_Node<
inheritance::Chain_Probe, State>>);
static_assert(inheritance::Defines_Chain_Layer<
Observer, Render_Base::template next_Observer<Observer>,
next_Observer<inheritance::Chain_Probe>,
renderable_inheritance::Observer_Node<
inheritance::Chain_Probe, Observer>>);
public:
template <auto Member, class Value>
Axis_State_Strategy& set(Value&& value) {
+13 -1
View File
@@ -8,7 +8,12 @@
namespace renderive::detail {
struct Frequency_Axis::Impl
: next_Impl<Impl> {
: Base::next_Impl<Impl> {
static_assert(inheritance::Defines_Chain_Layer<
Impl, Base::next_Impl<Impl>,
Frequency_Axis::next_Impl<inheritance::Chain_Probe>,
renderable_inheritance::Impl_Node<
inheritance::Chain_Probe, Impl>>);
private:
[[nodiscard]] std::string format_tick_label(
double tick, const Axis_Properties& state) const override {
@@ -33,4 +38,11 @@ static_assert(
Frequency_Axis::Frequency_Axis(const State& state)
: Renderable(With_Attached_Impl<Impl>{}, state) {}
Frequency_Axis::Observer Frequency_Axis::observer() const {
Observer result;
static_cast<::renderive::Axis::Observer&>(result) =
::renderive::Axis::observer();
return result;
}
} // namespace renderive::detail
+33 -1
View File
@@ -4,12 +4,44 @@ namespace renderive {
namespace detail {
struct LIB_DECL Frequency_Axis
: Renderable<Frequency_Axis, ::renderive::Axis> {
using State = ::renderive::Axis::Properties;
using Base = Renderable<Frequency_Axis, ::renderive::Axis>;
protected:
struct Builder : Base::template next_Builder<Builder> {};
public:
struct State : Base::template next_State<State> {};
struct Observer : Base::template next_Observer<Observer> {};
[[nodiscard]] Observer observer() const;
private:
friend struct renderable::attach<Frequency_Axis>;
explicit Frequency_Axis(const State& state);
protected:
struct Impl;
template <class Next>
using next_Builder = renderable_inheritance::Builder_Node<Next, Builder>;
template <class Next>
using next_State = renderable_inheritance::State_Node<Next, State>;
template <class Next>
using next_Impl = renderable_inheritance::Impl_Node<Next, Impl>;
template <class Next>
using next_Observer =
renderable_inheritance::Observer_Node<Next, Observer>;
static_assert(inheritance::Defines_Chain_Layer<
Builder, Base::template next_Builder<Builder>,
next_Builder<inheritance::Chain_Probe>,
renderable_inheritance::Builder_Node<
inheritance::Chain_Probe, Builder>>);
static_assert(inheritance::Defines_Chain_Layer<
State, Base::template next_State<State>,
next_State<inheritance::Chain_Probe>,
renderable_inheritance::State_Node<
inheritance::Chain_Probe, State>>);
static_assert(inheritance::Defines_Chain_Layer<
Observer, Base::template next_Observer<Observer>,
next_Observer<inheritance::Chain_Probe>,
renderable_inheritance::Observer_Node<
inheritance::Chain_Probe, Observer>>);
using Renderable::Renderable;
};
} // namespace detail
@@ -11,6 +11,12 @@ static_assert(!std::constructible_from<::renderive::Axis,
Axis::Axis(const State& state)
: Axis_State_Strategy(With_Attached_Impl<Impl>{}, state) {}
Axis::Observer Axis::observer() const {
Observer result;
result.state = read([](const State& state) { return state; });
return result;
}
void Axis::Impl::handle_event(const Event& event) {
auto& axis = static_cast<Axis&>(owner());
if (event.type == Event_Type::Wheel &&
+37 -1
View File
@@ -20,17 +20,53 @@ struct Axis_Properties : Axis_Base_Properties {
namespace detail {
struct LIB_DECL Axis
: Axis_State_Strategy<Axis, Axis_Properties> {
struct State : next_State<State>, Axis_Properties {
using Base = Axis_State_Strategy<Axis, Axis_Properties>;
protected:
struct Builder : Base::template next_Builder<Builder> {};
public:
struct State : Base::template next_State<State>, Axis_Properties {
State() = default;
State(const Axis_Properties& properties) : Axis_Properties(properties) {}
};
struct Observer : Base::template next_Observer<Observer> {
State state;
};
[[nodiscard]] Observer observer() const;
private:
friend struct renderable::attach<Axis>;
explicit Axis(const State& state);
protected:
struct Impl;
template <class Next>
using next_Builder = renderable_inheritance::Builder_Node<Next, Builder>;
template <class Next>
using next_State = renderable_inheritance::State_Node<Next, State>;
template <class Next>
using next_Impl = renderable_inheritance::Impl_Node<Next, Impl>;
template <class Next>
using next_Observer =
renderable_inheritance::Observer_Node<Next, Observer>;
static_assert(inheritance::Defines_Chain_Layer<
Builder, Base::template next_Builder<Builder>,
next_Builder<inheritance::Chain_Probe>,
renderable_inheritance::Builder_Node<
inheritance::Chain_Probe, Builder>>);
static_assert(inheritance::Defines_Chain_Layer<
State, Base::template next_State<State>,
next_State<inheritance::Chain_Probe>,
renderable_inheritance::State_Node<
inheritance::Chain_Probe, State>>);
static_assert(inheritance::Defines_Chain_Layer<
Observer, Base::template next_Observer<Observer>,
next_Observer<inheritance::Chain_Probe>,
renderable_inheritance::Observer_Node<
inheritance::Chain_Probe, Observer>>);
using Axis_State_Strategy::Axis_State_Strategy;
};
} // namespace detail
using Axis = renderable::attach<detail::Axis>;
} // namespace renderive
#include "Numeric_Axis_p.h"
+6 -1
View File
@@ -7,8 +7,13 @@
namespace renderive::detail {
struct Axis::Impl
: next_Impl<Impl>,
: Base::next_Impl<Impl>,
Renderable_Event_Handler {
static_assert(inheritance::Defines_Chain_Layer<
Impl, Base::next_Impl<Impl>,
Axis::next_Impl<inheritance::Chain_Probe>,
renderable_inheritance::Impl_Node<
inheritance::Chain_Probe, Impl>>);
private:
void handle_event(const Event& event) override;
+12 -1
View File
@@ -7,7 +7,12 @@
namespace renderive::detail {
struct Time_Axis::Impl
: next_Impl<Impl> {
: Base::next_Impl<Impl> {
static_assert(inheritance::Defines_Chain_Layer<
Impl, Base::next_Impl<Impl>,
Time_Axis::next_Impl<inheritance::Chain_Probe>,
renderable_inheritance::Impl_Node<
inheritance::Chain_Probe, Impl>>);
private:
[[nodiscard]] Range coordinate_range(
const Axis_Base_Properties& properties) const noexcept override {
@@ -54,6 +59,12 @@ static_assert(
Time_Axis::Time_Axis(const State& state)
: Axis_State_Strategy(With_Attached_Impl<Impl>{}, state) {}
Time_Axis::Observer Time_Axis::observer() const {
Observer result;
result.state = read([](const State& state) { return state; });
return result;
}
std::size_t Time_Axis::time_point_count() const {
return read([](const State& state) { return state.samples.size(); });
}
+35 -1
View File
@@ -8,7 +8,11 @@ namespace renderive {
namespace detail {
struct LIB_DECL Time_Axis
: Axis_State_Strategy<Time_Axis, Axis_Base_Properties> {
struct State : next_State<State>, Axis_Base_Properties {
using Base = Axis_State_Strategy<Time_Axis, Axis_Base_Properties>;
protected:
struct Builder : Base::template next_Builder<Builder> {};
public:
struct State : Base::template next_State<State>, Axis_Base_Properties {
Range_Value<int, 2, std::numeric_limits<int>::max()> visible_count{100};
Range_Value<int, 0, std::numeric_limits<int>::max()> tick_label_spacing_px{8};
std::string format = "mm:ss.zzz";
@@ -16,15 +20,45 @@ struct LIB_DECL Time_Axis
int next_tick{};
std::deque<std::pair<int, Time_Of_Day>> samples;
};
struct Observer : Base::template next_Observer<Observer> {
State state;
};
private:
friend struct renderable::attach<Time_Axis>;
explicit Time_Axis(const State& state);
public:
[[nodiscard]] Observer observer() const;
[[nodiscard]] std::size_t time_point_count() const;
int append_time(Time_Of_Day time);
[[nodiscard]] Time_Of_Day tick_to_time(int tick) const;
protected:
struct Impl;
template <class Next>
using next_Builder = renderable_inheritance::Builder_Node<Next, Builder>;
template <class Next>
using next_State = renderable_inheritance::State_Node<Next, State>;
template <class Next>
using next_Impl = renderable_inheritance::Impl_Node<Next, Impl>;
template <class Next>
using next_Observer =
renderable_inheritance::Observer_Node<Next, Observer>;
static_assert(inheritance::Defines_Chain_Layer<
Builder, Base::template next_Builder<Builder>,
next_Builder<inheritance::Chain_Probe>,
renderable_inheritance::Builder_Node<
inheritance::Chain_Probe, Builder>>);
static_assert(inheritance::Defines_Chain_Layer<
State, Base::template next_State<State>,
next_State<inheritance::Chain_Probe>,
renderable_inheritance::State_Node<
inheritance::Chain_Probe, State>>);
static_assert(inheritance::Defines_Chain_Layer<
Observer, Base::template next_Observer<Observer>,
next_Observer<inheritance::Chain_Probe>,
renderable_inheritance::Observer_Node<
inheritance::Chain_Probe, Observer>>);
using Axis_State_Strategy::Axis_State_Strategy;
};
} // namespace detail
@@ -6,9 +6,7 @@
#include <renderive/frame_control/strategy/low_latency/Low_Latency_Strategy.hpp>
#include <renderive/frame_control/strategy/manual/Manual_Refresh_Strategy.hpp>
#include <mutex>
#include <stdexcept>
#include <type_traits>
#include <utility>
namespace renderive::detail {
@@ -21,17 +19,11 @@ template <class Function>
decltype(auto) visit(Frame_Control_Strategy_Base& strategy,
Function&& function) {
if (auto* value = dynamic_cast<Manual_Strategy*>(&strategy))
return std::forward<Function>(function)(
*value, std::integral_constant<Plot_Frame_Mode,
Plot_Frame_Mode::Manual>{});
return std::forward<Function>(function)(*value);
if (auto* value = dynamic_cast<Low_Latency_Strategy_Type*>(&strategy))
return std::forward<Function>(function)(
*value, std::integral_constant<Plot_Frame_Mode,
Plot_Frame_Mode::Low_Latency>{});
return std::forward<Function>(function)(*value);
if (auto* value = dynamic_cast<Playback_Strategy*>(&strategy))
return std::forward<Function>(function)(
*value, std::integral_constant<Plot_Frame_Mode,
Plot_Frame_Mode::Playback>{});
return std::forward<Function>(function)(*value);
::renderive::error::unexpected<std::logic_error>(
"unknown plot frame strategy");
}
@@ -40,18 +32,12 @@ template <class Function>
decltype(auto) visit(const Frame_Control_Strategy_Base& strategy,
Function&& function) {
if (const auto* value = dynamic_cast<const Manual_Strategy*>(&strategy))
return std::forward<Function>(function)(
*value, std::integral_constant<Plot_Frame_Mode,
Plot_Frame_Mode::Manual>{});
return std::forward<Function>(function)(*value);
if (const auto* value =
dynamic_cast<const Low_Latency_Strategy_Type*>(&strategy))
return std::forward<Function>(function)(
*value, std::integral_constant<Plot_Frame_Mode,
Plot_Frame_Mode::Low_Latency>{});
return std::forward<Function>(function)(*value);
if (const auto* value = dynamic_cast<const Playback_Strategy*>(&strategy))
return std::forward<Function>(function)(
*value, std::integral_constant<Plot_Frame_Mode,
Plot_Frame_Mode::Playback>{});
return std::forward<Function>(function)(*value);
::renderive::error::unexpected<std::logic_error>(
"unknown plot frame strategy");
}
@@ -63,24 +49,9 @@ struct Plot_Frame_Control::Impl {
};
Plot_Frame_Control::Plot_Frame_Control(
Plot_Frame_Mode selected_mode,
std::pmr::memory_resource& memory_resource)
std::shared_ptr<Frame_Control_Strategy_Base> strategy)
: impl_(std::make_unique<Impl>()) {
switch (selected_mode) {
case Plot_Frame_Mode::Manual:
impl_->strategy = std::make_shared<Manual_Strategy>();
break;
case Plot_Frame_Mode::Low_Latency:
impl_->strategy = std::make_shared<Low_Latency_Strategy_Type>();
break;
case Plot_Frame_Mode::Playback:
impl_->strategy = std::make_shared<Playback_Strategy>(
memory_resource);
break;
}
if (!impl_->strategy)
::renderive::error::unexpected<std::invalid_argument>(
"unknown plot frame mode");
replace(std::move(strategy));
}
Plot_Frame_Control::~Plot_Frame_Control() = default;
@@ -95,92 +66,47 @@ Plot_Frame_Control::runtime() const {
return impl_->strategy;
}
double Plot_Frame_Control::frequency_hz() const {
return impl_->strategy->frequency_hz();
}
std::uint64_t Plot_Frame_Control::next_refresh_interval_ns() const {
return impl_->strategy->next_refresh_interval_ns();
}
auto Plot_Frame_Control::prepare(Render_Scene_2D& scene)
-> Expected<void, Plot_Prepare_Frame_Error> {
return visit(*impl_->strategy, [&scene](auto& strategy, auto) {
auto frame = strategy.acquire_painter();
if (!frame)
return Expected<void, Plot_Prepare_Frame_Error>(
unexpected(
Plot_Prepare_Frame_Error::painter_unavailable));
scene.publish_frame_state(*frame);
return Expected<void, Plot_Prepare_Frame_Error>{};
});
}
auto Plot_Frame_Control::refresh(Render_Scene_2D&)
-> Expected<void, Plot_Refresh_Manual_Frame_Error> {
auto* strategy = dynamic_cast<Manual_Strategy*>(impl_->strategy.get());
if (!strategy)
return unexpected(
Plot_Refresh_Manual_Frame_Error::unsupported_frame_mode);
if (strategy->refresh() != Manual_Refresh_Result::none)
return unexpected(
Plot_Refresh_Manual_Frame_Error::no_pending_frame);
return {};
}
auto Plot_Frame_Control::render(Render_Scene_2D& scene)
-> Expected<void, Plot_Render_Prepared_Frame_Error> {
return visit(*impl_->strategy, [&scene](auto& strategy, auto) {
auto frame = strategy.acquire_renderer();
if (!frame)
return Expected<void, Plot_Render_Prepared_Frame_Error>(
unexpected(
Plot_Render_Prepared_Frame_Error::renderer_unavailable));
const auto result = scene.Scene_Base::render(*frame);
if (result == Scene_Render_Result::none)
return Expected<void, Plot_Render_Prepared_Frame_Error>{};
if (result == Scene_Render_Result::shutting_down)
return Expected<void, Plot_Render_Prepared_Frame_Error>(
unexpected(
Plot_Render_Prepared_Frame_Error::scene_shutting_down));
const auto converted =
adapter::enum_cast<Plot_Render_Prepared_Frame_Error>(result);
if (!converted)
::renderive::error::unexpected<std::logic_error>(
"unknown scene render error");
return Expected<void, Plot_Render_Prepared_Frame_Error>(
unexpected(*converted));
});
}
bool Plot_Frame_Control::discard(Render_Scene_2D&) {
if (auto* strategy =
dynamic_cast<Manual_Strategy*>(impl_->strategy.get()))
return strategy->discard_pending_frame();
if (auto* strategy =
dynamic_cast<Low_Latency_Strategy_Type*>(impl_->strategy.get()))
return strategy->discard_pending_frame();
return false;
}
auto Plot_Frame_Control::request(Render_Scene_2D& scene)
-> Expected<void, Plot_Render_Frame_Error> {
if (!prepare(scene))
const bool prepared = visit(*impl_->strategy, [&scene](auto& strategy) {
auto frame = strategy.acquire_painter();
if (!frame)
return false;
scene.publish_frame_state(*frame);
return true;
});
if (!prepared)
return unexpected(Plot_Render_Frame_Error::painter_unavailable);
if (auto* strategy =
dynamic_cast<Manual_Strategy*>(impl_->strategy.get())) {
if (strategy->refresh() != Manual_Refresh_Result::none)
return unexpected(Plot_Render_Frame_Error::no_pending_frame);
}
if (const auto result = render(scene); !result) {
return visit(*impl_->strategy, [&scene](auto& strategy)
-> Expected<void, Plot_Render_Frame_Error> {
auto frame = strategy.acquire_renderer();
if (!frame)
return unexpected(
Plot_Render_Frame_Error::renderer_unavailable);
const auto result = scene.Scene_Base::render(*frame);
if (result == Scene_Render_Result::none)
return {};
const auto converted =
adapter::enum_cast<Plot_Render_Frame_Error>(result.error());
adapter::enum_cast<Plot_Render_Frame_Error>(result);
if (!converted)
::renderive::error::unexpected<std::logic_error>(
"unknown plot render error");
"unknown scene render error");
return unexpected(*converted);
}
return {};
});
}
void Plot_Frame_Control::replace(
std::shared_ptr<Frame_Control_Strategy_Base> strategy) {
if (!strategy)
::renderive::error::unexpected<std::invalid_argument>(
"Plot_Scene requires a frame strategy");
visit(*strategy, [](const auto&) {});
impl_->strategy = std::move(strategy);
}
} // namespace renderive::detail
@@ -3,14 +3,13 @@
#include "../scene/Render_Scene_2D.h"
#include <memory>
#include <memory_resource>
namespace renderive::detail {
class Plot_Frame_Control final {
public:
Plot_Frame_Control(Plot_Frame_Mode mode,
std::pmr::memory_resource& memory_resource);
explicit Plot_Frame_Control(
std::shared_ptr<Frame_Control_Strategy_Base> strategy);
~Plot_Frame_Control();
Plot_Frame_Control(const Plot_Frame_Control&) = delete;
@@ -21,17 +20,9 @@ public:
[[nodiscard]] std::shared_ptr<Frame_Control_Strategy_Base> runtime();
[[nodiscard]] std::shared_ptr<const Frame_Control_Strategy_Base>
runtime() const;
[[nodiscard]] double frequency_hz() const;
[[nodiscard]] std::uint64_t next_refresh_interval_ns() const;
[[nodiscard]] auto prepare(Render_Scene_2D& scene)
-> Expected<void, Plot_Prepare_Frame_Error>;
[[nodiscard]] auto refresh(Render_Scene_2D& scene)
-> Expected<void, Plot_Refresh_Manual_Frame_Error>;
[[nodiscard]] auto render(Render_Scene_2D& scene)
-> Expected<void, Plot_Render_Prepared_Frame_Error>;
[[nodiscard]] bool discard(Render_Scene_2D& scene);
[[nodiscard]] auto request(Render_Scene_2D& scene)
-> Expected<void, Plot_Render_Frame_Error>;
void replace(std::shared_ptr<Frame_Control_Strategy_Base> strategy);
private:
struct Impl;
std::unique_ptr<Impl> impl_;
+15 -1
View File
@@ -27,7 +27,12 @@ struct Afterglow_Prepare_Buffer {
};
}
struct Afterglow::Impl
: next_Impl<Impl>, ::Render_Frame_Completion {
: Base::next_Impl<Impl>, ::Render_Frame_Completion {
static_assert(inheritance::Defines_Chain_Layer<
Impl, Base::next_Impl<Impl>,
Afterglow::next_Impl<inheritance::Chain_Probe>,
renderable_inheritance::Impl_Node<
inheritance::Chain_Probe, Impl>>);
Impl(renderive_Owner<Frequency_Axis> frequency,
renderive_Owner<Axis> power)
: frequency_axis(std::move(frequency)),
@@ -76,6 +81,15 @@ std::size_t Afterglow::rendered_cell_count() const {
: std::max(1, static_cast<int>(d_func<Impl>().power_axis->transform().pixel_length));
return width > 0 && height > 0 ? static_cast<std::size_t>(width) * static_cast<std::size_t>(height) : 0;
}
Afterglow::Observer Afterglow::observer() const {
const auto value = Renderable::state<State>();
Observer result;
result.state = value;
result.history_count = history_count();
result.latest_spectrum_point_count = latest_spectrum_point_count();
result.rendered_cell_count = rendered_cell_count();
return result;
}
void Afterglow::append_spectrum(std::span<const double> values) {
if (get_state<State, &State::frequency_point_size>() <= 0)
set_state<State, &State::frequency_point_size>(
+19 -1
View File
@@ -7,6 +7,10 @@
namespace renderive {
namespace detail {
struct LIB_DECL Afterglow : Renderable<Afterglow> {
using Base = Renderable<Afterglow>;
protected:
struct Builder : Base::template next_Builder<Builder> {};
public:
struct State;
private:
friend struct renderable::attach<Afterglow>;
@@ -23,7 +27,7 @@ public:
void append_spectrum(const Values& values) {
append_spectrum(std::span<const double>(values.data(), values.size()));
}
struct State : next_State<State> {
struct State : Base::template next_State<State> {
Range frequency_range{0.0, 10.0};
Range power_range{0.0, 10.0};
Nonnegative_Count frequency_point_size;
@@ -34,8 +38,22 @@ public:
Unit_Interval attenuation_rate{0.2};
Color_Map color_map;
};
struct Observer : Base::template next_Observer<Observer> {
State state;
std::size_t history_count{};
std::size_t latest_spectrum_point_count{};
std::size_t rendered_cell_count{};
};
[[nodiscard]] Observer observer() const;
private:
struct Impl;
template <class Next> using next_Builder = renderable_inheritance::Builder_Node<Next, Builder>;
template <class Next> using next_State = renderable_inheritance::State_Node<Next, State>;
template <class Next> using next_Impl = renderable_inheritance::Impl_Node<Next, Impl>;
template <class Next> using next_Observer = renderable_inheritance::Observer_Node<Next, Observer>;
static_assert(inheritance::Defines_Chain_Layer<Builder, Base::template next_Builder<Builder>, next_Builder<inheritance::Chain_Probe>, renderable_inheritance::Builder_Node<inheritance::Chain_Probe, Builder>>);
static_assert(inheritance::Defines_Chain_Layer<State, Base::template next_State<State>, next_State<inheritance::Chain_Probe>, renderable_inheritance::State_Node<inheritance::Chain_Probe, State>>);
static_assert(inheritance::Defines_Chain_Layer<Observer, Base::template next_Observer<Observer>, next_Observer<inheritance::Chain_Probe>, renderable_inheritance::Observer_Node<inheritance::Chain_Probe, Observer>>);
};
}
using Afterglow = renderable::attach<detail::Afterglow>;
@@ -19,7 +19,12 @@ struct Timed_Point {
using Constellation_History = Plottable_History_Real_Time_Data<Timed_Point, std::deque<Timed_Point>>;
}
struct Constellation_Diagram::Impl
: next_Impl<Impl> {
: Base::next_Impl<Impl> {
static_assert(inheritance::Defines_Chain_Layer<
Impl, Base::next_Impl<Impl>,
Constellation_Diagram::next_Impl<inheritance::Chain_Probe>,
renderable_inheritance::Impl_Node<
inheritance::Chain_Probe, Impl>>);
struct Prepare_Buffer {
std::vector<PointF> anchors;
std::vector<PointF> points;
@@ -54,6 +59,13 @@ void Constellation_Diagram::append_point(PointF point) {
std::size_t Constellation_Diagram::point_count() const {
return d_func<Impl>().points->size();
}
Constellation_Diagram::Observer Constellation_Diagram::observer() const {
const auto value = Renderable::state<State>();
Observer result;
result.state = value;
result.point_count = point_count();
return result;
}
void Constellation_Diagram::fit_square_to_axes() {
const auto state = Renderable::state<State>();
const double side = std::max(state.i_range.size(), state.q_range.size());
@@ -9,6 +9,10 @@ enum class Constellation_Diagram_Type : std::uint8_t {
};
namespace detail {
struct LIB_DECL Constellation_Diagram : Renderable<Constellation_Diagram> {
using Base = Renderable<Constellation_Diagram>;
protected:
struct Builder : Base::template next_Builder<Builder> {};
public:
struct State;
private:
friend struct renderable::attach<Constellation_Diagram>;
@@ -19,7 +23,7 @@ public:
void append_point(PointF point);
[[nodiscard]] std::size_t point_count() const;
void fit_square_to_axes();
struct State : next_State<State> {
struct State : Base::template next_State<State> {
Range i_range{0.0, 100.0};
Range q_range{0.0, 100.0};
Color point_color = Color::red();
@@ -28,8 +32,20 @@ public:
Constellation_Diagram_Type type = Constellation_Diagram_Type::Psk8;
double phase_offset_radians{};
};
struct Observer : Base::template next_Observer<Observer> {
State state;
std::size_t point_count{};
};
[[nodiscard]] Observer observer() const;
private:
struct Impl;
template <class Next> using next_Builder = renderable_inheritance::Builder_Node<Next, Builder>;
template <class Next> using next_State = renderable_inheritance::State_Node<Next, State>;
template <class Next> using next_Impl = renderable_inheritance::Impl_Node<Next, Impl>;
template <class Next> using next_Observer = renderable_inheritance::Observer_Node<Next, Observer>;
static_assert(inheritance::Defines_Chain_Layer<Builder, Base::template next_Builder<Builder>, next_Builder<inheritance::Chain_Probe>, renderable_inheritance::Builder_Node<inheritance::Chain_Probe, Builder>>);
static_assert(inheritance::Defines_Chain_Layer<State, Base::template next_State<State>, next_State<inheritance::Chain_Probe>, renderable_inheritance::State_Node<inheritance::Chain_Probe, State>>);
static_assert(inheritance::Defines_Chain_Layer<Observer, Base::template next_Observer<Observer>, next_Observer<inheritance::Chain_Probe>, renderable_inheritance::Observer_Node<inheritance::Chain_Probe, Observer>>);
};
} // namespace detail
using Constellation_Diagram = renderable::attach<detail::Constellation_Diagram>;
@@ -13,7 +13,12 @@ namespace {
using Frequency_Trace_History = Plottable_History_Real_Time_Data<std::pair<int, double>, std::deque<std::pair<int, double>>>;
}
struct Frequency_Trace::Impl
: next_Impl<Impl> {
: Base::next_Impl<Impl> {
static_assert(inheritance::Defines_Chain_Layer<
Impl, Base::next_Impl<Impl>,
Frequency_Trace::next_Impl<inheritance::Chain_Probe>,
renderable_inheritance::Impl_Node<
inheritance::Chain_Probe, Impl>>);
struct Prepare_Buffer {
std::vector<PointF> points;
};
@@ -52,6 +57,13 @@ std::size_t Frequency_Trace::rendered_point_count() const {
const std::size_t count = sample_count();
return count >= 2 ? count : 0;
}
Frequency_Trace::Observer Frequency_Trace::observer() const {
Observer result;
result.state = Renderable::state<State>();
result.sample_count = sample_count();
result.rendered_point_count = rendered_point_count();
return result;
}
void Frequency_Trace::Impl::prepare_frame(const Prepare_Render_Context& context) {
const auto& view = context.frame.render_state;
const auto& published_samples = view.get(*samples);
@@ -4,6 +4,10 @@
namespace renderive {
namespace detail {
struct LIB_DECL Frequency_Trace : Renderable<Frequency_Trace> {
using Base = Renderable<Frequency_Trace>;
protected:
struct Builder : Base::template next_Builder<Builder> {};
public:
struct State;
private:
friend struct renderable::attach<Frequency_Trace>;
@@ -15,11 +19,24 @@ public:
void append_sample(Time_Of_Day time, double value);
[[nodiscard]] std::size_t sample_count() const;
[[nodiscard]] std::size_t rendered_point_count() const;
struct State : next_State<State> {
struct State : Base::template next_State<State> {
Pen pen{Color::yellow()};
};
struct Observer : Base::template next_Observer<Observer> {
State state;
std::size_t sample_count{};
std::size_t rendered_point_count{};
};
[[nodiscard]] Observer observer() const;
private:
struct Impl;
template <class Next> using next_Builder = renderable_inheritance::Builder_Node<Next, Builder>;
template <class Next> using next_State = renderable_inheritance::State_Node<Next, State>;
template <class Next> using next_Impl = renderable_inheritance::Impl_Node<Next, Impl>;
template <class Next> using next_Observer = renderable_inheritance::Observer_Node<Next, Observer>;
static_assert(inheritance::Defines_Chain_Layer<Builder, Base::template next_Builder<Builder>, next_Builder<inheritance::Chain_Probe>, renderable_inheritance::Builder_Node<inheritance::Chain_Probe, Builder>>);
static_assert(inheritance::Defines_Chain_Layer<State, Base::template next_State<State>, next_State<inheritance::Chain_Probe>, renderable_inheritance::State_Node<inheritance::Chain_Probe, State>>);
static_assert(inheritance::Defines_Chain_Layer<Observer, Base::template next_Observer<Observer>, next_Observer<inheritance::Chain_Probe>, renderable_inheritance::Observer_Node<inheritance::Chain_Probe, Observer>>);
};
}
using Frequency_Trace = renderable::attach<detail::Frequency_Trace>;
+52 -26
View File
@@ -52,32 +52,62 @@ template <class Layer, class Parent = ::renderive::Renderable>
struct Renderable : renderable::render_base<Layer, Parent> {
using Render_Base = renderable::render_base<Layer, Parent>;
protected:
struct Builder
: Render_Base::template next_Builder<Builder> {};
struct State
: Render_Base::template next_State<State> {};
: Render_Base::template next_State<State> {};
struct Impl : Render_Base::template next_Impl<Impl> {
using Base_Impl = typename Render_Base::template next_Impl<Impl>;
using Base_Impl::Base_Impl;
};
struct Observer : Render_Base::template next_Observer<Observer> {};
template <class Next>
using next_State =
renderable_inheritance::State_Node<Next, State>;
using next_State = renderable_inheritance::State_Node<Next, State>;
template <class Next>
using next_Impl =
renderable_inheritance::Impl_Node<Next, typename Parent::Impl>;
using next_Impl = renderable_inheritance::Impl_Node<Next, Impl>;
template <class Next>
using next_Observer =
renderable_inheritance::Observer_Node<Next, Observer>;
template <class Next>
using next_Builder =
renderable_inheritance::Builder_Node<Next, Builder>;
static_assert(inheritance::Defines_Chain_Layer<
Builder, Render_Base::template next_Builder<Builder>,
next_Builder<inheritance::Chain_Probe>,
renderable_inheritance::Builder_Node<
inheritance::Chain_Probe, Builder>>);
static_assert(inheritance::Defines_Chain_Layer<
State, Render_Base::template next_State<State>,
next_State<inheritance::Chain_Probe>,
renderable_inheritance::State_Node<
inheritance::Chain_Probe, State>>);
static_assert(inheritance::Defines_Chain_Layer<
Impl, Render_Base::template next_Impl<Impl>,
next_Impl<inheritance::Chain_Probe>,
renderable_inheritance::Impl_Node<
inheritance::Chain_Probe, Impl>>);
static_assert(inheritance::Defines_Chain_Layer<
Observer, Render_Base::template next_Observer<Observer>,
next_Observer<inheritance::Chain_Probe>,
renderable_inheritance::Observer_Node<
inheritance::Chain_Probe, Observer>>);
template <class Product, class Properties>
using Business_Builder = Renderable_Builder<Product, Properties>;
using State_Observer = Observer_State<Renderable_State_Observer>;
template <class Implementation, class State_Type, class... Args>
Renderable(With_Attached_Impl<Implementation>, State_Type state,
Args&&... args)
: Render_Base(
std::make_unique<Stateful_Impl<Implementation, State_Type,
Atomic_Spin_Mutex,
State_Observer>>(
std::move(state),
With_Observer<State_Observer>{
State_Observer(Renderable_State_Observer(this))
},
std::forward<Args>(args)...),
true) {}
Args&&... args) : Render_Base(
std::make_unique<Stateful_Impl<Implementation, State_Type,
Atomic_Spin_Mutex,
State_Observer>>(
std::move(state),
With_Observer<State_Observer>{
State_Observer(Renderable_State_Observer(this))
},
std::forward<Args>(args)...),
true) {}
using Render_Base::Render_Base;
template <class State_Type, auto Member,
Property_Member_Assignable<State_Type, Member> Value>
@@ -104,23 +134,19 @@ protected:
}
}
using Member_Value = decltype(std::declval<State_Type&>().*Member);
if constexpr (Paint_Only_Property_Value<Member_Value>)
this->d_func().paint_changed();
else
this->d_func().changed();
if constexpr (Paint_Only_Property_Value<Member_Value>) this->d_func().paint_changed();
else this->d_func().changed();
}
template <class State_Type, auto Member>
auto get_state() const {
return state_storage<State_Type>().template get<Member>();
}
template <class State_Type, class Update>
requires std::invocable<Update, State_Type&>
template <class State_Type, class Update> requires std::invocable<Update, State_Type&>
void update_state(Update&& update) {
state_storage<State_Type>().update(std::forward<Update>(update));
this->d_func().changed();
}
template <class State_Type, class Read>
requires std::invocable<Read, const State_Type&>
template <class State_Type, class Read> requires std::invocable<Read, const State_Type&>
decltype(auto) read_state(Read&& read) const {
return state_storage<State_Type>().read(std::forward<Read>(read));
}
@@ -21,9 +21,15 @@ RectF axis_content_rect(const Axis_Transform& first, const Axis_Transform& secon
}
}
struct Selection_Rectangle_Overlay::Impl
: next_Impl<Impl>,
: Base::next_Impl<Impl>,
Renderable_Event_Handler {
using Observer = Selection_Rectangle_Overlay::Observer;
static_assert(inheritance::Defines_Chain_Layer<
Impl, Base::next_Impl<Impl>,
Selection_Rectangle_Overlay::next_Impl<
inheritance::Chain_Probe>,
renderable_inheritance::Impl_Node<
inheritance::Chain_Probe, Impl>>);
struct Prepared_Region {
RectF pixels;
@@ -47,13 +53,15 @@ struct Selection_Rectangle_Overlay::Impl
protected:
void prepare_frame(const Prepare_Render_Context& context) override;
void paint(Painter& painter, const Paint_Render_Context& context) override;
public:
void handle_observation(const Renderable_Event_View& observation);
private:
void handle_event(const Event& event) override;
};
void Selection_Rectangle_Overlay::Observer::handle(
Impl& impl, const Renderable_Event_View& observation) {
void Selection_Rectangle_Overlay::Impl::handle_observation(
const Renderable_Event_View& observation) {
if (observation.event == Renderable_Observer_Event::Published)
impl.interaction.publish();
interaction.publish();
}
Selection_Rectangle_Overlay::Selection_Rectangle_Overlay(
const State& state, renderive_Owner<Abs_Axis> horizontal_axis,
@@ -66,6 +74,13 @@ Selection_Rectangle_Overlay::~Selection_Rectangle_Overlay() = default;
std::vector<RectF> Selection_Rectangle_Overlay::selected_regions() const {
return d_func<Impl>().regions->snapshot();
}
Selection_Rectangle_Overlay::Observer
Selection_Rectangle_Overlay::observer() const {
Observer result;
result.state = Renderable::state<State>();
result.selected_region_count = d_func<Impl>().regions->size();
return result;
}
void Selection_Rectangle_Overlay::clear_selected_regions() {
d_func<Impl>().regions->clear();
d_func<Impl>().interaction.update([](Selection_Interaction& interaction) {
@@ -5,6 +5,10 @@ namespace renderive {
namespace detail {
struct LIB_DECL Selection_Rectangle_Overlay
: Renderable<Selection_Rectangle_Overlay>, Paint_Overlay {
using Base = Renderable<Selection_Rectangle_Overlay>;
protected:
struct Builder : Base::template next_Builder<Builder> {};
public:
struct State;
private:
@@ -16,7 +20,7 @@ public:
~Selection_Rectangle_Overlay() override;
[[nodiscard]] std::vector<RectF> selected_regions() const;
void clear_selected_regions();
struct State : next_State<State> {
struct State : Base::template next_State<State> {
Font label_font;
Pen label_pen{Color::white()};
Brush selection_brush{Color{0, 0, 255, 50}, Brush_Style::Solid};
@@ -25,10 +29,20 @@ public:
private:
struct Impl;
public:
struct Observer : next_Observer<Impl> {
static void handle(Impl& impl,
const Renderable_Event_View& observation);
struct Observer : Base::template next_Observer<Observer> {
State state;
std::size_t selected_region_count{};
};
private:
template <class Next> using next_Builder = renderable_inheritance::Builder_Node<Next, Builder>;
template <class Next> using next_State = renderable_inheritance::State_Node<Next, State>;
template <class Next> using next_Impl = renderable_inheritance::Impl_Node<Next, Impl>;
template <class Next> using next_Observer = renderable_inheritance::Observer_Node<Next, Observer>;
static_assert(inheritance::Defines_Chain_Layer<Builder, Base::template next_Builder<Builder>, next_Builder<inheritance::Chain_Probe>, renderable_inheritance::Builder_Node<inheritance::Chain_Probe, Builder>>);
static_assert(inheritance::Defines_Chain_Layer<State, Base::template next_State<State>, next_State<inheritance::Chain_Probe>, renderable_inheritance::State_Node<inheritance::Chain_Probe, State>>);
static_assert(inheritance::Defines_Chain_Layer<Observer, Base::template next_Observer<Observer>, next_Observer<inheritance::Chain_Probe>, renderable_inheritance::Observer_Node<inheritance::Chain_Probe, Observer>>);
public:
[[nodiscard]] Observer observer() const;
};
}
using Selection_Rectangle_Overlay =
+21 -5
View File
@@ -132,11 +132,16 @@ double spectrum_power_at(const ::renderive::Spectrum::Properties& properties, co
}
}
struct Spectrum::Impl
: next_Impl<Impl>,
: Base::next_Impl<Impl>,
Spectrum_Real_Time_Data_Strategy,
Renderable_Event_Handler,
::Render_Frame_Completion {
using Observer = Spectrum::Observer;
static_assert(inheritance::Defines_Chain_Layer<
Impl, Spectrum::Base::next_Impl<Impl>,
Spectrum::next_Impl<inheritance::Chain_Probe>,
renderable_inheritance::Impl_Node<
inheritance::Chain_Probe, Impl>>);
Impl(renderive_Owner<Frequency_Axis> frequency,
renderive_Owner<Axis> power)
@@ -163,13 +168,14 @@ struct Spectrum::Impl
[[nodiscard]] std::uint64_t dependent_state_revision() const noexcept {
return revision();
}
void handle_observation(const Renderable_Event_View& observation);
};
void Spectrum::Observer::handle(
Impl& impl, const Renderable_Event_View& observation) {
void Spectrum::Impl::handle_observation(
const Renderable_Event_View& observation) {
if (observation.event != Renderable_Observer_Event::Published)
return;
impl.Spectrum_Real_Time_Data_Strategy::publish();
impl.interaction.publish();
Spectrum_Real_Time_Data_Strategy::publish();
interaction.publish();
}
Spectrum::Spectrum(const State& state,
renderive_Owner<Frequency_Axis> frequency_axis,
@@ -223,6 +229,16 @@ std::size_t Spectrum::rendered_point_count() const {
d_func<Impl>().power_axis->transform(),
state.visible_range_only, state.interpolation_mode).size();
}
Spectrum::Observer Spectrum::observer() const {
const auto value = Renderable::state<State>();
Observer result;
result.state = value;
result.sample_count = sample_count();
result.rendered_point_count = rendered_point_count();
result.selectable_marker_count = static_cast<std::size_t>(
std::max(0, selectable_line_marker_count()));
return result;
}
double Spectrum::power_at(double frequency, bool& ok) const {
const auto state = Renderable::state<State>();
return spectrum_power_at(
+20 -4
View File
@@ -32,7 +32,11 @@ struct Spectrum_Real_Time_Data_Strategy
using Base::write;
};
struct LIB_DECL Spectrum : Renderable<Spectrum> {
struct State : next_State<State>, Hover_Tooltip_Properties {
using Base = Renderable<Spectrum>;
protected:
struct Builder : Base::template next_Builder<Builder> {};
public:
struct State : Base::template next_State<State>, Hover_Tooltip_Properties {
Nonnegative_Count frequency_point_size;
Render_Partition_Mode partition_mode{Render_Partition_Mode::Automatic};
Positive_Count partition_count;
@@ -94,10 +98,22 @@ public:
private:
struct Impl;
public:
struct Observer : next_Observer<Impl> {
static void handle(Impl& impl,
const Renderable_Event_View& observation);
struct Observer : Base::template next_Observer<Observer> {
State state;
std::size_t sample_count{};
std::size_t rendered_point_count{};
std::size_t selectable_marker_count{};
};
private:
template <class Next> using next_Builder = renderable_inheritance::Builder_Node<Next, Builder>;
template <class Next> using next_State = renderable_inheritance::State_Node<Next, State>;
template <class Next> using next_Impl = renderable_inheritance::Impl_Node<Next, Impl>;
template <class Next> using next_Observer = renderable_inheritance::Observer_Node<Next, Observer>;
static_assert(inheritance::Defines_Chain_Layer<Builder, Base::template next_Builder<Builder>, next_Builder<inheritance::Chain_Probe>, renderable_inheritance::Builder_Node<inheritance::Chain_Probe, Builder>>);
static_assert(inheritance::Defines_Chain_Layer<State, Base::template next_State<State>, next_State<inheritance::Chain_Probe>, renderable_inheritance::State_Node<inheritance::Chain_Probe, State>>);
static_assert(inheritance::Defines_Chain_Layer<Observer, Base::template next_Observer<Observer>, next_Observer<inheritance::Chain_Probe>, renderable_inheritance::Observer_Node<inheritance::Chain_Probe, Observer>>);
public:
[[nodiscard]] Observer observer() const;
};
}
using Spectrum = renderable::attach<detail::Spectrum>;
@@ -19,8 +19,13 @@ std::vector<double> flatten(const std::deque<std::vector<double>>& blocks) {
}
}
struct Sweep_Spectrum::Impl
: next_Impl<Impl> {
: Base::next_Impl<Impl> {
using Observer = Sweep_Spectrum::Observer;
static_assert(inheritance::Defines_Chain_Layer<
Impl, Base::next_Impl<Impl>,
Sweep_Spectrum::next_Impl<inheritance::Chain_Probe>,
renderable_inheritance::Impl_Node<
inheritance::Chain_Probe, Impl>>);
friend struct Sweep_Spectrum::Observer;
struct Prepare_Buffer {
@@ -37,14 +42,15 @@ struct Sweep_Spectrum::Impl
Prepare_Buffer prepare_buffer;
void prepare_frame(const Prepare_Render_Context& context) override;
void paint(Painter& painter, const Paint_Render_Context& context) override;
void handle_observation(const Renderable_Event_View& observation);
};
void Sweep_Spectrum::Observer::handle(
Impl& impl, const Renderable_Event_View& observation) {
void Sweep_Spectrum::Impl::handle_observation(
const Renderable_Event_View& observation) {
if (observation.event != Renderable_Observer_Event::Published)
return;
auto& control = static_cast<Sweep_Spectrum&>(impl.owner());
auto& control = static_cast<Sweep_Spectrum&>(owner());
const int limit = control.get_state<State, &State::block_count>();
impl.blocks->retain_latest(static_cast<std::size_t>(limit));
blocks->retain_latest(static_cast<std::size_t>(limit));
}
Sweep_Spectrum::Sweep_Spectrum(const State& state,
renderive_Owner<Axis> frequency_axis,
@@ -80,6 +86,15 @@ std::size_t Sweep_Spectrum::rendered_point_count() const {
const auto values = flatten(d_func<Impl>().blocks->snapshot());
return curve_points(values, state.frequency_range, d_func<Impl>().frequency_axis->transform(), d_func<Impl>().power_axis->transform(), state.visible_range_only, state.interpolation_mode).size();
}
Sweep_Spectrum::Observer Sweep_Spectrum::observer() const {
const auto value = Renderable::state<State>();
Observer result;
result.state = value;
result.stored_block_count = stored_block_count();
result.stored_point_count = stored_point_count();
result.rendered_point_count = rendered_point_count();
return result;
}
void Sweep_Spectrum::Impl::prepare_frame(const Prepare_Render_Context& context) {
auto& control = static_cast<Sweep_Spectrum&>(owner());
const auto& view = context.frame.render_state;
+20 -4
View File
@@ -6,6 +6,10 @@
namespace renderive {
namespace detail {
struct LIB_DECL Sweep_Spectrum : Renderable<Sweep_Spectrum> {
using Base = Renderable<Sweep_Spectrum>;
protected:
struct Builder : Base::template next_Builder<Builder> {};
public:
struct State;
private:
friend struct renderable::attach<Sweep_Spectrum>;
@@ -22,7 +26,7 @@ public:
[[nodiscard]] std::size_t stored_block_count() const;
[[nodiscard]] std::size_t stored_point_count() const;
[[nodiscard]] std::size_t rendered_point_count() const;
struct State : next_State<State> {
struct State : Base::template next_State<State> {
Range frequency_range{};
Nonnegative_Count bins_per_block;
Positive_Count block_count;
@@ -35,10 +39,22 @@ public:
private:
struct Impl;
public:
struct Observer : next_Observer<Impl> {
static void handle(Impl& impl,
const Renderable_Event_View& observation);
struct Observer : Base::template next_Observer<Observer> {
State state;
std::size_t stored_block_count{};
std::size_t stored_point_count{};
std::size_t rendered_point_count{};
};
private:
template <class Next> using next_Builder = renderable_inheritance::Builder_Node<Next, Builder>;
template <class Next> using next_State = renderable_inheritance::State_Node<Next, State>;
template <class Next> using next_Impl = renderable_inheritance::Impl_Node<Next, Impl>;
template <class Next> using next_Observer = renderable_inheritance::Observer_Node<Next, Observer>;
static_assert(inheritance::Defines_Chain_Layer<Builder, Base::template next_Builder<Builder>, next_Builder<inheritance::Chain_Probe>, renderable_inheritance::Builder_Node<inheritance::Chain_Probe, Builder>>);
static_assert(inheritance::Defines_Chain_Layer<State, Base::template next_State<State>, next_State<inheritance::Chain_Probe>, renderable_inheritance::State_Node<inheritance::Chain_Probe, State>>);
static_assert(inheritance::Defines_Chain_Layer<Observer, Base::template next_Observer<Observer>, next_Observer<inheritance::Chain_Probe>, renderable_inheritance::Observer_Node<inheritance::Chain_Probe, Observer>>);
public:
[[nodiscard]] Observer observer() const;
};
}
using Sweep_Spectrum = renderable::attach<detail::Sweep_Spectrum>;
+19 -4
View File
@@ -60,10 +60,15 @@ std::size_t waterfall_work_size(const ::renderive::Waterfall::Properties& state,
}
}
struct Waterfall::Impl
: next_Impl<Impl>,
: Base::next_Impl<Impl>,
Renderable_Event_Handler,
::Render_Frame_Completion {
using Observer = Waterfall::Observer;
static_assert(inheritance::Defines_Chain_Layer<
Impl, Base::next_Impl<Impl>,
Waterfall::next_Impl<inheritance::Chain_Probe>,
renderable_inheritance::Impl_Node<
inheritance::Chain_Probe, Impl>>);
Impl(renderive_Owner<Frequency_Axis> frequency,
renderive_Owner<Time_Axis> time)
@@ -82,14 +87,15 @@ protected:
void paint(Painter& painter, const Paint_Render_Context& context) override;
void build_prepare_graph(Renderable_Graph_Builder& builder) override;
void build_paint_graph(Renderable_Graph_Builder& builder) override;
void handle_observation(const Renderable_Event_View& observation);
private:
void handle_event(const Event& event) override;
void render_frame_completed(std::uint64_t target_interval_ns) override;
};
void Waterfall::Observer::handle(
Impl& impl, const Renderable_Event_View& observation) {
void Waterfall::Impl::handle_observation(
const Renderable_Event_View& observation) {
if (observation.event == Renderable_Observer_Event::Published)
impl.interaction.publish();
interaction.publish();
}
Waterfall::Waterfall(const State& state,
renderive_Owner<Frequency_Axis> frequency_axis,
@@ -145,6 +151,15 @@ std::size_t Waterfall::rendered_cell_count() const {
state.visible_range_only);
return columns ? static_cast<std::size_t>(columns->last - columns->first + 1) * rows.size() : 0;
}
Waterfall::Observer Waterfall::observer() const {
const auto value = Renderable::state<State>();
Observer result;
result.state = value;
result.row_count = row_count();
result.stored_point_count = stored_point_count();
result.rendered_cell_count = rendered_cell_count();
return result;
}
void Waterfall::Impl::handle_event(const Event& event) {
auto& control = static_cast<Waterfall&>(owner());
bool updated{};
+20 -4
View File
@@ -8,6 +8,10 @@
namespace renderive {
namespace detail {
struct LIB_DECL Waterfall : Renderable<Waterfall> {
using Base = Renderable<Waterfall>;
protected:
struct Builder : Base::template next_Builder<Builder> {};
public:
struct State;
private:
friend struct renderable::attach<Waterfall>;
@@ -31,7 +35,7 @@ public:
[[nodiscard]] std::size_t row_count() const;
[[nodiscard]] std::size_t stored_point_count() const;
[[nodiscard]] std::size_t rendered_cell_count() const;
struct State : next_State<State>, Hover_Tooltip_Properties {
struct State : Base::template next_State<State>, Hover_Tooltip_Properties {
Range frequency_range{0.0, 10.0};
Range power_range{0.0, 10.0};
Nonnegative_Count frequency_bin_count;
@@ -45,10 +49,22 @@ public:
private:
struct Impl;
public:
struct Observer : next_Observer<Impl> {
static void handle(Impl& impl,
const Renderable_Event_View& observation);
struct Observer : Base::template next_Observer<Observer> {
State state;
std::size_t row_count{};
std::size_t stored_point_count{};
std::size_t rendered_cell_count{};
};
private:
template <class Next> using next_Builder = renderable_inheritance::Builder_Node<Next, Builder>;
template <class Next> using next_State = renderable_inheritance::State_Node<Next, State>;
template <class Next> using next_Impl = renderable_inheritance::Impl_Node<Next, Impl>;
template <class Next> using next_Observer = renderable_inheritance::Observer_Node<Next, Observer>;
static_assert(inheritance::Defines_Chain_Layer<Builder, Base::template next_Builder<Builder>, next_Builder<inheritance::Chain_Probe>, renderable_inheritance::Builder_Node<inheritance::Chain_Probe, Builder>>);
static_assert(inheritance::Defines_Chain_Layer<State, Base::template next_State<State>, next_State<inheritance::Chain_Probe>, renderable_inheritance::State_Node<inheritance::Chain_Probe, State>>);
static_assert(inheritance::Defines_Chain_Layer<Observer, Base::template next_Observer<Observer>, next_Observer<inheritance::Chain_Probe>, renderable_inheritance::Observer_Node<inheritance::Chain_Probe, Observer>>);
public:
[[nodiscard]] Observer observer() const;
};
}
using Waterfall = renderable::attach<detail::Waterfall>;
+28 -3
View File
@@ -27,11 +27,36 @@ enum struct Renderable_Observer_Event {
};
struct LIB_DECL Renderable
: renderable::render_base<Renderable, ::Renderable_Base, true> {
protected:
struct Impl;
using Render_Base =
renderable::render_base<Renderable, ::Renderable_Base, true>;
public:
struct Observer : renderable_inheritance::Observer_Root<Impl> {};
struct Builder : Render_Base::template next_Builder<Builder> {};
struct Observer : renderable_inheritance::Observer_Root<Observer> {};
protected:
struct State : Render_Base::template next_State<State> {};
struct Impl;
template <class Next>
using next_Builder = renderable_inheritance::Builder_Node<Next, Builder>;
template <class Next>
using next_State = renderable_inheritance::State_Node<Next, State>;
template <class Next>
using next_Impl = renderable_inheritance::Impl_Node<Next, Impl>;
template <class Next>
using next_Observer = renderable_inheritance::Observer_Node<Next, Observer>;
static_assert(inheritance::Defines_Chain_Layer<
Builder, Render_Base::template next_Builder<Builder>,
next_Builder<inheritance::Chain_Probe>,
renderable_inheritance::Builder_Node<
inheritance::Chain_Probe, Builder>>);
static_assert(inheritance::Defines_Chain_Layer<
State, Render_Base::template next_State<State>,
next_State<inheritance::Chain_Probe>,
renderable_inheritance::State_Node<
inheritance::Chain_Probe, State>>);
public:
explicit Renderable(bool cache_enabled = true);
~Renderable() override;
[[nodiscard]] Renderable_Cache_Mode get_cache_mode() const noexcept;
@@ -1,13 +0,0 @@
#pragma once
#include <cstdint>
namespace renderive {
enum class Plot_Frame_Mode : std::uint8_t {
Manual,
Low_Latency,
Playback,
};
} // namespace renderive
+46 -57
View File
@@ -31,18 +31,22 @@ Rect full_rect(Size size) {
} // namespace
} // namespace renderive::detail
namespace renderive {
struct Render_Scene_2D::Impl
: Render_Scene_2D::next_Impl<Impl>,
struct detail::Render_Scene_2D::Impl
: detail::Render_Scene_2D::Base::next_Impl<Impl>,
Scene_Base::Impl::Frame_Control_Capability,
Scene_Base::Impl::Scene_State_Capability,
Scene_Base::Impl::Raster_Capabilities,
Scene_Base::Impl::Compositor {
using State_Storage =
Published_State_Storage<Render_Scene_2D::State, Atomic_Spin_Mutex,
Published_State_Storage<detail::Render_Scene_2D::State, Atomic_Spin_Mutex,
Observer_State<>>;
using Observer = Render_Scene_2D::Observer;
explicit Impl(std::pmr::memory_resource& resource)
: next_Impl<Impl>(resource), scene_state(State{}),
using Observer = detail::Render_Scene_2D::Observer;
static_assert(inheritance::Defines_Chain_Layer<
Impl, detail::Render_Scene_2D::Base::next_Impl<Impl>,
detail::Render_Scene_2D::next_Impl<inheritance::Chain_Probe>,
scene_inheritance::Impl_Node<inheritance::Chain_Probe, Impl>>);
Impl(std::pmr::memory_resource& resource, const State& state)
: Base::next_Impl<Impl>(resource), scene_state(state),
final_color_cache(resource) {}
std::shared_ptr<Frame_Control_Strategy_Base>
frame_control_strategy() override {
@@ -73,7 +77,7 @@ struct Render_Scene_2D::Impl
}
void before_scene_state_swap() override {
const auto pending = scene_state.read(
[](const Render_Scene_2D::State& value) { return value; });
[](const State& value) { return value; });
const auto published = scene_state.published_state();
if (pending.viewport != published.viewport)
invalidate_renderables();
@@ -98,32 +102,29 @@ struct Render_Scene_2D::Impl
std::shared_ptr<Performance_Overlay> performance;
std::atomic_bool active{};
};
Render_Scene_2D::Render_Scene_2D(Plot_Scene_Options options)
: scene::scene_base<Render_Scene_2D, Scene_2D_Base>(
detail::Render_Scene_2D::Render_Scene_2D(
const State& state,
std::shared_ptr<Frame_Control_Strategy_Base> frame_strategy)
: detail::Scene<detail::Render_Scene_2D>(
*::renderive::memory_resource(Memory_Domain::Plot_Frame),
std::make_unique<Impl>(
*::renderive::memory_resource(Memory_Domain::Plot_Frame))) {
*::renderive::memory_resource(Memory_Domain::Plot_Frame),
state)) {
auto& impl = d_func<Impl>();
impl.frame_control = std::make_unique<detail::Plot_Frame_Control>(
options.frame_mode, impl.memory_resource());
}
Render_Scene_2D::~Render_Scene_2D() {
d_func<Impl>().shutdown();
}
std::unique_ptr<Render_Scene_2D>
Render_Scene_2D::Builder::build() const {
auto result = std::unique_ptr<Render_Scene_2D>(
new Render_Scene_2D(options_));
std::move(frame_strategy));
auto root = detail::make_renderable_group(true);
root->set_object_name("root");
auto builder = result->attach_builder();
auto builder = attach_builder();
if (builder.attach(root) != Scene_Edit_Error::none)
::renderive::error::unexpected<std::logic_error>(
"validated plot root attachment failed");
return result;
}
detail::Render_Scene_2D::~Render_Scene_2D() {
d_func<Impl>().shutdown();
}
renderive_Owner<::renderive::Renderable>
Render_Scene_2D::root_renderable() const {
detail::Render_Scene_2D::root_renderable() const {
const auto topology = topology_snapshot();
for (const auto& relationship : topology.display) {
if (relationship.parent)
@@ -136,15 +137,18 @@ Render_Scene_2D::root_renderable() const {
}
return {};
}
Render_Scene_2D::Observer Render_Scene_2D::observer() const {
const auto& frame_control = *d_func<Impl>().frame_control;
return {
{},
frame_control.frequency_hz(),
frame_control.next_refresh_interval_ns(),
};
detail::Render_Scene_2D::Observer
detail::Render_Scene_2D::observer() const {
const auto runtime = d_func<Impl>().frame_control->runtime();
Observer result;
result.state = Scene::state();
result.renderable_count = Scene_Base::renderable_count();
result.frequency_hz = runtime->frequency_hz();
result.next_refresh_interval_ns = runtime->next_refresh_interval_ns();
result.view_active = view_active();
return result;
}
void Render_Scene_2D::dispatch_event(const Event& event) {
void detail::Render_Scene_2D::dispatch_event(const Event& event) {
const auto paint_order = paint_order_snapshot();
for (auto iterator = paint_order.rbegin(); iterator != paint_order.rend();
++iterator) {
@@ -158,22 +162,7 @@ void Render_Scene_2D::dispatch_event(const Event& event) {
}
}
}
auto Render_Scene_2D::prepare_frame()
-> Expected<void, Plot_Prepare_Frame_Error> {
return d_func<Impl>().frame_control->prepare(*this);
}
auto Render_Scene_2D::refresh_manual_frame()
-> Expected<void, Plot_Refresh_Manual_Frame_Error> {
return d_func<Impl>().frame_control->refresh(*this);
}
auto Render_Scene_2D::render_prepared_frame()
-> Expected<void, Plot_Render_Prepared_Frame_Error> {
return d_func<Impl>().frame_control->render(*this);
}
bool Render_Scene_2D::discard_pending_frame() {
return d_func<Impl>().frame_control->discard(*this);
}
auto Render_Scene_2D::render_frame(bool force)
auto detail::Render_Scene_2D::render_frame(bool force)
-> Expected<Plot_Render_Status, Plot_Render_Frame_Error> {
if (!view_active() && !force)
return Plot_Render_Status::view_inactive;
@@ -206,17 +195,17 @@ auto Render_Scene_2D::render_frame(bool force)
overlay = impl.performance;
}
if (overlay) {
const auto& frame_control = *d_func<Impl>().frame_control;
const auto runtime = d_func<Impl>().frame_control->runtime();
detail::record_performance_frame(
*overlay, duration_ms, frame_control.frequency_hz(),
frame_control.next_refresh_interval_ns(),
*overlay, duration_ms, runtime->frequency_hz(),
runtime->next_refresh_interval_ns(),
renderable_count(), viewport);
}
if (sink)
sink->request_present(detail::full_rect(viewport));
return Plot_Render_Status::rendered;
}
void Render_Scene_2D::with_frame(
void detail::Render_Scene_2D::with_frame(
const std::function<void(Image_View)>& consumer) {
if (!consumer)
return;
@@ -230,32 +219,32 @@ void Render_Scene_2D::with_frame(
auto lock = d_func<Impl>().lock_render_idle();
consume();
}
void Render_Scene_2D::activate_view() {
void detail::Render_Scene_2D::activate_view() {
d_func<Impl>().active.store(true, std::memory_order_release);
notify_model_dirty();
}
void Render_Scene_2D::deactivate_view() noexcept {
void detail::Render_Scene_2D::deactivate_view() noexcept {
d_func<Impl>().active.store(false, std::memory_order_release);
}
bool Render_Scene_2D::view_active() const noexcept {
bool detail::Render_Scene_2D::view_active() const noexcept {
return d_func<Impl>().active.load(std::memory_order_acquire);
}
void Render_Scene_2D::request_redraw() noexcept {
void detail::Render_Scene_2D::request_redraw() noexcept {
notify_model_dirty();
}
void Render_Scene_2D::set_presentation_sink(
void detail::Render_Scene_2D::set_presentation_sink(
std::weak_ptr<Presentation_Sink> sink) {
auto& impl = d_func<Impl>();
std::lock_guard lock(impl.control_mutex);
impl.presentation_sink = std::move(sink);
}
std::shared_ptr<Performance_Overlay>
Render_Scene_2D::performance_overlay() const {
detail::Render_Scene_2D::performance_overlay() const {
const auto& impl = d_func<Impl>();
std::lock_guard lock(impl.control_mutex);
return impl.performance;
}
void Render_Scene_2D::set_performance_overlay(
void detail::Render_Scene_2D::set_performance_overlay(
std::shared_ptr<Performance_Overlay> overlay) {
{
auto& impl = d_func<Impl>();
+89 -59
View File
@@ -2,34 +2,17 @@
#include "../base/Types.h"
#include "../event/Event.h"
#include "../renderable/Renderable.h"
#include "Plot_Frame_Mode.h"
#include <renderive/base/adapter/Expected.hpp>
#include <renderive/frame_control/Frame_Consumer_Feedback.hpp>
#include <renderive/frame_control/Frame_Control.hpp>
#include <renderive/renderable/base/Renderive_Owner.hpp>
#include <renderive/scene/Scene_Builder.hpp>
#include <renderive/scene/base/Scene_Base.hpp>
#include <cstdint>
#include <functional>
#include <memory>
class Scene_Base;
namespace renderive {
struct Performance_Overlay;
struct Scene2D_Frame_Data : Abstract_Frame {};
struct Plot_Scene_Options {
Plot_Frame_Mode frame_mode{Plot_Frame_Mode::Low_Latency};
};
enum class Plot_Prepare_Frame_Error : std::uint8_t {
painter_unavailable
};
enum class Plot_Refresh_Manual_Frame_Error : std::uint8_t {
unsupported_frame_mode,
no_pending_frame
};
enum class Plot_Render_Prepared_Frame_Error : std::uint8_t {
renderer_unavailable,
cancelled,
deadline_exceeded,
external_failure,
scene_shutting_down
};
enum class Plot_Render_Status : std::uint8_t {
rendered,
view_inactive,
@@ -38,7 +21,6 @@ enum class Plot_Render_Status : std::uint8_t {
};
enum class Plot_Render_Frame_Error : std::uint8_t {
painter_unavailable,
manual_refresh_not_supported,
no_pending_frame,
renderer_unavailable,
cancelled,
@@ -46,29 +28,68 @@ enum class Plot_Render_Frame_Error : std::uint8_t {
external_failure,
scene_shutting_down
};
enum class Plot_Set_Max_Render_Fps_Error : std::uint8_t {
unsupported_frame_mode,
invalid_fps
};
enum class Plot_Clear_Max_Render_Fps_Error : std::uint8_t {
unsupported_frame_mode
};
enum class Plot_Set_Consumer_Feedback_Error : std::uint8_t {
unsupported_frame_mode,
invalid_consumer_feedback
};
enum class Plot_Clear_Consumer_Feedback_Error : std::uint8_t {
unsupported_frame_mode
};
struct Presentation_Sink {
virtual ~Presentation_Sink() = default;
virtual void request_present(Rect dirty_rect) = 0;
};
class LIB_DECL Render_Scene_2D final
: public scene::scene_base<Render_Scene_2D, Scene_2D_Base> {
namespace detail {
template <class Layer, class Parent = Scene_2D_Base>
struct Scene : ::renderive::scene::scene_base<Layer, Parent> {
using Base = ::renderive::scene::scene_base<Layer, Parent>;
template <class Product, class Properties>
using Business_Builder =
::renderive::scene::Scene_Builder<Product, Properties>;
protected:
struct Builder : Base::template next_Builder<Builder> {};
struct State : Base::template next_State<State> {};
struct Impl : Base::template next_Impl<Impl> {
using Base_Impl = typename Base::template next_Impl<Impl>;
using Base_Impl::Base_Impl;
};
struct Observer : Base::template next_Observer<Observer> {};
class Renderable_Editor : public Base::template next_Editor<
Renderable_Editor> {
using Editor_Base = typename Base::template next_Editor<
Renderable_Editor>;
using Editor_Base::Editor_Base;
};
template <class Next>
using next_Builder = ::renderive::scene_inheritance::Builder_Node<
Next, Builder>;
template <class Next>
using next_State = ::renderive::scene_inheritance::State_Node<
Next, State>;
template <class Next>
using next_Impl = ::renderive::scene_inheritance::Impl_Node<
Next, Impl>;
template <class Next>
using next_Observer = ::renderive::scene_inheritance::Observer_Node<
Next, Observer>;
template <class Next>
using next_Editor = ::renderive::scene_inheritance::Editor_Node<
Next, Renderable_Editor>;
static_assert(inheritance::Defines_Chain_Layer<Builder, Base::template next_Builder<Builder>, next_Builder<inheritance::Chain_Probe>, scene_inheritance::Builder_Node<inheritance::Chain_Probe, Builder>>);
static_assert(inheritance::Defines_Chain_Layer<State, Base::template next_State<State>, next_State<inheritance::Chain_Probe>, scene_inheritance::State_Node<inheritance::Chain_Probe, State>>);
static_assert(inheritance::Defines_Chain_Layer<Impl, Base::template next_Impl<Impl>, next_Impl<inheritance::Chain_Probe>, scene_inheritance::Impl_Node<inheritance::Chain_Probe, Impl>>);
static_assert(inheritance::Defines_Chain_Layer<Observer, Base::template next_Observer<Observer>, next_Observer<inheritance::Chain_Probe>, scene_inheritance::Observer_Node<inheritance::Chain_Probe, Observer>>);
static_assert(inheritance::Defines_Chain_Layer<Renderable_Editor, Base::template next_Editor<Renderable_Editor>, next_Editor<inheritance::Chain_Probe>, scene_inheritance::Editor_Node<inheritance::Chain_Probe, Renderable_Editor>>);
using Base::Base;
};
class LIB_DECL Render_Scene_2D : public Scene<Render_Scene_2D> {
using Base = Scene<Render_Scene_2D>;
public:
using Frame = Scene2D_Frame_Data;
struct State : next_State<State> {
protected:
struct Builder : Base::template next_Builder<Builder> {};
class Renderable_Editor : public Base::template next_Editor<
Renderable_Editor> {
using Editor_Base = typename Base::template next_Editor<
Renderable_Editor>;
using Editor_Base::Editor_Base;
};
public:
struct State : Base::template next_State<State> {
Size viewport;
Color background = Color::black();
[[nodiscard]] bool operator==(const State& other) const {
@@ -76,30 +97,16 @@ public:
background == other.background;
}
};
struct Observer
: scene::scene_base<Render_Scene_2D, Scene_2D_Base>::Observer {
struct Observer : Base::template next_Observer<Observer> {
State state;
std::size_t renderable_count{};
double frequency_hz{};
std::uint64_t next_refresh_interval_ns{};
};
class Builder : public next_Builder<Builder> {
public:
Builder() = default;
explicit Builder(Plot_Scene_Options options) : options_(options) {}
Builder& options(Plot_Scene_Options value) noexcept {
options_ = value;
return *this;
}
[[nodiscard]] std::unique_ptr<Render_Scene_2D> build() const;
private:
Plot_Scene_Options options_;
bool view_active{};
};
[[nodiscard]] ::renderive_Owner<::renderive::Renderable> root_renderable() const;
[[nodiscard]] Observer observer() const;
void dispatch_event(const Event& event);
[[nodiscard]] auto prepare_frame() -> Expected<void, Plot_Prepare_Frame_Error>;
[[nodiscard]] auto refresh_manual_frame() -> Expected<void, Plot_Refresh_Manual_Frame_Error>;
[[nodiscard]] auto render_prepared_frame() -> Expected<void, Plot_Render_Prepared_Frame_Error>;
[[nodiscard]] auto discard_pending_frame() -> bool;
[[nodiscard]] auto render_frame(bool force = false) -> Expected<Plot_Render_Status, Plot_Render_Frame_Error>;
void with_frame(const std::function<void(Image_View)>& consumer);
void activate_view();
@@ -108,11 +115,34 @@ public:
void request_redraw() noexcept;
void set_presentation_sink(std::weak_ptr<Presentation_Sink> sink);
[[nodiscard]] std::shared_ptr<Performance_Overlay> performance_overlay() const;
void set_performance_overlay(std::shared_ptr<Performance_Overlay> overlay);
void set_performance_overlay(
std::shared_ptr<Performance_Overlay> overlay);
~Render_Scene_2D() override;
private:
Render_Scene_2D(
const State& state,
std::shared_ptr<Frame_Control_Strategy_Base> frame_strategy);
struct Impl;
explicit Render_Scene_2D(Plot_Scene_Options options);
friend struct scene::scene_base<Render_Scene_2D, Scene_2D_Base>;
template <class Next> using next_Builder = scene_inheritance::Builder_Node<Next, Builder>;
template <class Next> using next_State = scene_inheritance::State_Node<Next, State>;
template <class Next> using next_Impl = scene_inheritance::Impl_Node<Next, Impl>;
template <class Next> using next_Observer = scene_inheritance::Observer_Node<Next, Observer>;
template <class Next> using next_Editor = scene_inheritance::Editor_Node<Next, Renderable_Editor>;
static_assert(inheritance::Defines_Chain_Layer<Builder, Base::template next_Builder<Builder>, next_Builder<inheritance::Chain_Probe>, scene_inheritance::Builder_Node<inheritance::Chain_Probe, Builder>>);
static_assert(inheritance::Defines_Chain_Layer<State, Base::template next_State<State>, next_State<inheritance::Chain_Probe>, scene_inheritance::State_Node<inheritance::Chain_Probe, State>>);
static_assert(inheritance::Defines_Chain_Layer<Observer, Base::template next_Observer<Observer>, next_Observer<inheritance::Chain_Probe>, scene_inheritance::Observer_Node<inheritance::Chain_Probe, Observer>>);
static_assert(inheritance::Defines_Chain_Layer<Renderable_Editor, Base::template next_Editor<Renderable_Editor>, next_Editor<inheritance::Chain_Probe>, scene_inheritance::Editor_Node<inheritance::Chain_Probe, Renderable_Editor>>);
friend struct ::renderive::scene::attach<Render_Scene_2D>;
friend struct ::renderive::scene::scene_base<Render_Scene_2D,
Scene_2D_Base>;
};
} // namespace detail
using Render_Scene_2D =
::renderive::scene::attach<detail::Render_Scene_2D>;
using Manual_Render_Scene_2D_Strategy =
Manual_Refresh_Strategy<detail::Render_Scene_2D>;
using Low_Latency_Render_Scene_2D_Strategy =
Low_Latency_Strategy<detail::Render_Scene_2D>;
using Playback_Render_Scene_2D_Strategy =
Flow_Refresh_Strategy<detail::Render_Scene_2D>;
} // namespace renderive