改结构
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 &&
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(); });
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
|
||||
@@ -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>(
|
||||
|
||||
@@ -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,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 =
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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
|
||||
@@ -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>();
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user