From 6a1980b920df8c97225fdc671d7763ae869fb5bc Mon Sep 17 00:00:00 2001 From: wyc <1104749580@qq.com> Date: Mon, 17 Aug 2026 13:32:03 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 2 + .../base/observer/concept/Observer.hpp | 2 +- .../renderive/frame_control/Inheritance.hpp | 24 ++- .../base/Frame_Control_Strategy_Base.hpp | 11 +- .../strategy/flow/Flow_Refresh_Strategy.hpp | 13 ++ .../strategy/flow/Flow_Refresh_Strategy.inl | 6 + .../low_latency/Low_Latency_Strategy.hpp | 13 ++ .../low_latency/Low_Latency_Strategy.inl | 6 + .../manual/Manual_Refresh_Strategy.hpp | 13 ++ .../manual/Manual_Refresh_Strategy.inl | 6 + Kernel/src/renderive/inheritance/Registry.hpp | 14 ++ .../src/renderive/renderable/Inheritance.hpp | 99 +++++++--- Kernel/src/renderive/scene/Inheritance.hpp | 145 ++++++++++++-- Kernel/src/renderive/scene/Scene_Builder.hpp | 61 ++++++ .../src/renderive/scene/base/Scene_Base.cpp | 3 +- .../src/renderive/scene/base/Scene_Base.hpp | 180 ++++++++++++++---- .../src/renderive/scene/base/Scene_Base.inl | 17 +- render_2D/render_2D/axis/Abs_Axis.h | 38 +++- .../render_2D/axis/Axis_State_Strategy.hpp | 30 +++ render_2D/render_2D/axis/Frequency_Axis.cpp | 14 +- render_2D/render_2D/axis/Frequency_Axis.h | 34 +++- render_2D/render_2D/axis/Numeric_Axis.cpp | 6 + render_2D/render_2D/axis/Numeric_Axis.h | 38 +++- render_2D/render_2D/axis/Numeric_Axis_p.h | 7 +- render_2D/render_2D/axis/Time_Axis.cpp | 13 +- render_2D/render_2D/axis/Time_Axis.h | 36 +++- .../frame_control/Plot_Frame_Control.cpp | 148 ++++---------- .../frame_control/Plot_Frame_Control.h | 15 +- render_2D/render_2D/plottable/Afterglow.cpp | 16 +- render_2D/render_2D/plottable/Afterglow.h | 20 +- .../plottable/Constellation_Diagram.cpp | 14 +- .../plottable/Constellation_Diagram.h | 18 +- .../render_2D/plottable/Frequency_Trace.cpp | 14 +- .../render_2D/plottable/Frequency_Trace.h | 19 +- render_2D/render_2D/plottable/Plottable.h | 78 +++++--- .../plottable/Selection_Rectangle_Overlay.cpp | 23 ++- .../plottable/Selection_Rectangle_Overlay.h | 22 ++- render_2D/render_2D/plottable/Spectrum.cpp | 26 ++- render_2D/render_2D/plottable/Spectrum.h | 24 ++- .../render_2D/plottable/Sweep_Spectrum.cpp | 25 ++- .../render_2D/plottable/Sweep_Spectrum.h | 24 ++- render_2D/render_2D/plottable/Waterfall.cpp | 23 ++- render_2D/render_2D/plottable/Waterfall.h | 24 ++- render_2D/render_2D/renderable/Renderable.h | 31 ++- render_2D/render_2D/scene/Plot_Frame_Mode.h | 13 -- render_2D/render_2D/scene/Render_Scene_2D.cpp | 103 +++++----- render_2D/render_2D/scene/Render_Scene_2D.h | 148 ++++++++------ render_3D/render_3D/Point_Visual.cpp | 26 ++- render_3D/render_3D/Point_Visual.h | 44 ++++- render_3D/render_3D/Render_Scene_3D.cpp | 107 +++++------ render_3D/render_3D/Render_Scene_3D.h | 173 +++++++++++++---- .../frame_control/Point_Frame_Control.cpp | 130 +++---------- .../frame_control/Point_Frame_Control.h | 13 +- render_3D/render_3D/renderable/Inheritance.h | 40 +++- render_3D/render_3D/renderable/Renderable.h | 37 +++- render_3D/render_3D/visuals/Basic_Visual.h | 62 +++++- 56 files changed, 1642 insertions(+), 649 deletions(-) create mode 100644 Kernel/src/renderive/scene/Scene_Builder.hpp delete mode 100644 render_2D/render_2D/scene/Plot_Frame_Mode.h diff --git a/AGENTS.md b/AGENTS.md index 16d2df6..311281b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -8,6 +8,8 @@ D:\ae\tools 可能会有有用的工具 +任何 fallback 都必须先规划,禁止直接实现 + 写函数 和模块使用下面的约定 [错误处理规范](./Error_handling_specification.md) [命名约定](./Project_naming_conventions.md) diff --git a/Kernel/src/renderive/base/observer/concept/Observer.hpp b/Kernel/src/renderive/base/observer/concept/Observer.hpp index e18814e..37a6107 100644 --- a/Kernel/src/renderive/base/observer/concept/Observer.hpp +++ b/Kernel/src/renderive/base/observer/concept/Observer.hpp @@ -3,7 +3,7 @@ #include #include template -concept Observation_Struct = std::is_class_v; +concept Observation_Struct = std::is_class_v && std::copyable; template concept Observer_Enable_Flag = requires { { That::enabled } -> std::convertible_to; diff --git a/Kernel/src/renderive/frame_control/Inheritance.hpp b/Kernel/src/renderive/frame_control/Inheritance.hpp index 7d952d5..105e527 100644 --- a/Kernel/src/renderive/frame_control/Inheritance.hpp +++ b/Kernel/src/renderive/frame_control/Inheritance.hpp @@ -34,16 +34,30 @@ namespace renderive::frame_control { template struct strategy_base : Parent { protected: - struct State_Layer - : frame_control_inheritance::State_Node< - State_Layer, typename Parent::State_Layer> {}; + struct State : Parent::template next_State {}; + + struct Impl : Parent::template next_Impl { + using Impl_Base = typename Parent::template next_Impl; + using Impl_Base::Impl_Base; + }; template - using next_State = frame_control_inheritance::State_Node; + using next_State = frame_control_inheritance::State_Node; template using next_Impl = frame_control_inheritance::Impl_Node< - Next, typename Parent::Impl>; + Next, Impl>; + + static_assert(inheritance::Defines_Chain_Layer< + State, typename Parent::template next_State, + next_State, + frame_control_inheritance::State_Node< + inheritance::Chain_Probe, State>>); + static_assert(inheritance::Defines_Chain_Layer< + Impl, typename Parent::template next_Impl, + next_Impl, + frame_control_inheritance::Impl_Node< + inheritance::Chain_Probe, Impl>>); using Parent::Parent; }; diff --git a/Kernel/src/renderive/frame_control/base/Frame_Control_Strategy_Base.hpp b/Kernel/src/renderive/frame_control/base/Frame_Control_Strategy_Base.hpp index 387e353..7e06c28 100644 --- a/Kernel/src/renderive/frame_control/base/Frame_Control_Strategy_Base.hpp +++ b/Kernel/src/renderive/frame_control/base/Frame_Control_Strategy_Base.hpp @@ -36,12 +36,19 @@ public: return static_cast(interval_ns); } protected: - struct State_Layer - : renderive::frame_control_inheritance::State_Root {}; + struct State + : renderive::frame_control_inheritance::State_Root {}; struct Impl : renderive::frame_control_inheritance::Impl_Root {}; + template + using next_State = + renderive::frame_control_inheritance::State_Node; + template + using next_Impl = + renderive::frame_control_inheritance::Impl_Node; + Frame_Control_Strategy_Base() : impl_(std::make_unique()) {} explicit Frame_Control_Strategy_Base(std::unique_ptr impl) : impl_(std::move(impl)) {} diff --git a/Kernel/src/renderive/frame_control/strategy/flow/Flow_Refresh_Strategy.hpp b/Kernel/src/renderive/frame_control/strategy/flow/Flow_Refresh_Strategy.hpp index 11c6e24..99fe31d 100644 --- a/Kernel/src/renderive/frame_control/strategy/flow/Flow_Refresh_Strategy.hpp +++ b/Kernel/src/renderive/frame_control/strategy/flow/Flow_Refresh_Strategy.hpp @@ -117,6 +117,19 @@ public: private: struct Impl; + template + using next_State = + renderive::frame_control_inheritance::State_Node; + template + using next_Impl = + renderive::frame_control_inheritance::Impl_Node; + + static_assert(renderive::inheritance::Defines_Chain_Layer< + State, Control_Base::template next_State, + next_State, + renderive::frame_control_inheritance::State_Node< + renderive::inheritance::Chain_Probe, State>>); + Impl& impl() noexcept { return this->template d_func(); } const Impl& impl() const noexcept { return this->template d_func(); diff --git a/Kernel/src/renderive/frame_control/strategy/flow/Flow_Refresh_Strategy.inl b/Kernel/src/renderive/frame_control/strategy/flow/Flow_Refresh_Strategy.inl index d59da0e..f06b8d2 100644 --- a/Kernel/src/renderive/frame_control/strategy/flow/Flow_Refresh_Strategy.inl +++ b/Kernel/src/renderive/frame_control/strategy/flow/Flow_Refresh_Strategy.inl @@ -5,6 +5,12 @@ struct Flow_Refresh_Strategy::Impl : Control_Base::template next_Impl { using Impl_Base = Control_Base::template next_Impl; using Frame_Ptr = Memory_Resource_Unique_Ptr; + static_assert(renderive::inheritance::Defines_Chain_Layer< + Impl, Control_Base::template next_Impl, + Flow_Refresh_Strategy::template next_Impl< + renderive::inheritance::Chain_Probe>, + renderive::frame_control_inheritance::Impl_Node< + renderive::inheritance::Chain_Probe, Impl>>); Impl(Flow_Refresh_Strategy& owner, std::pmr::memory_resource& resource, std::size_t capacity) diff --git a/Kernel/src/renderive/frame_control/strategy/low_latency/Low_Latency_Strategy.hpp b/Kernel/src/renderive/frame_control/strategy/low_latency/Low_Latency_Strategy.hpp index ed605f1..92ab912 100644 --- a/Kernel/src/renderive/frame_control/strategy/low_latency/Low_Latency_Strategy.hpp +++ b/Kernel/src/renderive/frame_control/strategy/low_latency/Low_Latency_Strategy.hpp @@ -187,6 +187,19 @@ public: private: struct Impl; + template + using next_State = + renderive::frame_control_inheritance::State_Node; + template + using next_Impl = + renderive::frame_control_inheritance::Impl_Node; + + static_assert(renderive::inheritance::Defines_Chain_Layer< + State, Control_Base::template next_State, + next_State, + renderive::frame_control_inheritance::State_Node< + renderive::inheritance::Chain_Probe, State>>); + Impl& impl() noexcept { return this->template d_func(); } const Impl& impl() const noexcept { return this->template d_func(); diff --git a/Kernel/src/renderive/frame_control/strategy/low_latency/Low_Latency_Strategy.inl b/Kernel/src/renderive/frame_control/strategy/low_latency/Low_Latency_Strategy.inl index 810cee5..d91e346 100644 --- a/Kernel/src/renderive/frame_control/strategy/low_latency/Low_Latency_Strategy.inl +++ b/Kernel/src/renderive/frame_control/strategy/low_latency/Low_Latency_Strategy.inl @@ -7,6 +7,12 @@ template struct Low_Latency_Strategy::Impl : Control_Base::template next_Impl { using Impl_Base = Control_Base::template next_Impl; + static_assert(renderive::inheritance::Defines_Chain_Layer< + Impl, Control_Base::template next_Impl, + Low_Latency_Strategy::template next_Impl< + renderive::inheritance::Chain_Probe>, + renderive::frame_control_inheritance::Impl_Node< + renderive::inheritance::Chain_Probe, Impl>>); Impl(Low_Latency_Strategy& owner, Configuration configuration) : Impl_Base(), owner_(&owner), paint_(&frames_[0]), diff --git a/Kernel/src/renderive/frame_control/strategy/manual/Manual_Refresh_Strategy.hpp b/Kernel/src/renderive/frame_control/strategy/manual/Manual_Refresh_Strategy.hpp index a6e793d..48544ea 100644 --- a/Kernel/src/renderive/frame_control/strategy/manual/Manual_Refresh_Strategy.hpp +++ b/Kernel/src/renderive/frame_control/strategy/manual/Manual_Refresh_Strategy.hpp @@ -117,6 +117,19 @@ public: void on_real_time_data_update(const Real_Time_Data_Observation& observation) override; private: struct Impl; + template + using next_State = + renderive::frame_control_inheritance::State_Node; + template + using next_Impl = + renderive::frame_control_inheritance::Impl_Node; + + static_assert(renderive::inheritance::Defines_Chain_Layer< + State, Control_Base::template next_State, + next_State, + renderive::frame_control_inheritance::State_Node< + renderive::inheritance::Chain_Probe, State>>); + Impl& impl() noexcept { return this->template d_func(); } diff --git a/Kernel/src/renderive/frame_control/strategy/manual/Manual_Refresh_Strategy.inl b/Kernel/src/renderive/frame_control/strategy/manual/Manual_Refresh_Strategy.inl index 9ee2174..bdb8800 100644 --- a/Kernel/src/renderive/frame_control/strategy/manual/Manual_Refresh_Strategy.inl +++ b/Kernel/src/renderive/frame_control/strategy/manual/Manual_Refresh_Strategy.inl @@ -3,6 +3,12 @@ template struct Manual_Refresh_Strategy::Impl : Control_Base::template next_Impl { using Impl_Base = Control_Base::template next_Impl; + static_assert(renderive::inheritance::Defines_Chain_Layer< + Impl, Control_Base::template next_Impl, + Manual_Refresh_Strategy::template next_Impl< + renderive::inheritance::Chain_Probe>, + renderive::frame_control_inheritance::Impl_Node< + renderive::inheritance::Chain_Probe, Impl>>); explicit Impl(Manual_Refresh_Strategy& owner) : Impl_Base(), owner_(&owner), paint_(&frames_[0]), diff --git a/Kernel/src/renderive/inheritance/Registry.hpp b/Kernel/src/renderive/inheritance/Registry.hpp index 37baad0..17795dc 100644 --- a/Kernel/src/renderive/inheritance/Registry.hpp +++ b/Kernel/src/renderive/inheritance/Registry.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -145,6 +146,19 @@ struct Type_Root { using Inheritance_Registry = Registry<>; }; +struct Chain_Probe {}; + +template +concept Inherits_Chain_Parent = requires(Entity* entity) { + static_cast(entity); +}; + +template +concept Defines_Chain_Layer = + Inherits_Chain_Parent && + std::same_as; + template struct Type_Node : Parent { diff --git a/Kernel/src/renderive/renderable/Inheritance.hpp b/Kernel/src/renderive/renderable/Inheritance.hpp index c3fdcc7..db8b0ca 100644 --- a/Kernel/src/renderive/renderable/Inheritance.hpp +++ b/Kernel/src/renderive/renderable/Inheritance.hpp @@ -11,6 +11,7 @@ namespace renderive::renderable_inheritance { struct Builder_Chain {}; struct State_Chain {}; struct Impl_Chain {}; +struct Observer_Chain {}; struct Builder_Access { class Key { @@ -37,9 +38,9 @@ struct Builder_Node using Builder_Base::Builder_Base; }; -template +template struct Builder - : Builder_Node, Business_Builder { + : Parent_Next, Business_Builder { using Business_Builder::Business_Builder; }; @@ -54,13 +55,22 @@ struct State_Node : inheritance::Type_Node { }; template -struct Observer_Root { +struct Observer_Root + : inheritance::Type_Node { + using Observer_Base = inheritance::Type_Node< + Layer, inheritance::Type_Root, Observer_Chain>; using Owner = Layer; + using Observer_Base::Observer_Base; }; template -struct Observer_Node : Parent { +struct Observer_Node + : inheritance::Type_Node { + using Observer_Base = + inheritance::Type_Node; using Owner = Layer; + using Observer_Base::Observer_Base; }; template @@ -69,11 +79,10 @@ struct Observer_Handler { static void handle(Layer& layer, const Event& event) requires requires { - typename Layer::Observer; - Layer::Observer::handle(layer, event); + layer.handle_observation(event); } { - Layer::Observer::handle(layer, event); + layer.handle_observation(event); } }; @@ -96,7 +105,6 @@ struct Impl_Node typename Parent::Renderable_Event>; using Renderable_Event = typename Parent::Renderable_Event; using Handler = Observer_Handler; - using next_Observer = Observer_Node; using Impl_Base::Impl_Base; }; @@ -109,32 +117,72 @@ struct render_base; template struct render_base : Parent { +public: + struct Builder : renderable_inheritance::Builder_Root {}; + + template + using next_Builder = renderable_inheritance::Builder_Node; + protected: - struct Builder_Layer - : renderable_inheritance::Builder_Root {}; struct State : renderable_inheritance::State_Root {}; + template + using next_State = renderable_inheritance::State_Node; + using Parent::Parent; }; template struct render_base : Parent { +public: + struct Builder : Parent::template next_Builder {}; + protected: - struct Builder_Layer - : renderable_inheritance::Builder_Node< - Builder_Layer, typename Parent::Builder_Layer> {}; + struct State : Parent::template next_State {}; + + struct Impl : Parent::template next_Impl { + using Impl_Base = typename Parent::template next_Impl; + using Impl_Base::Impl_Base; + }; + + struct Observer : Parent::template next_Observer {}; template using next_State = renderable_inheritance::State_Node< - Next, typename Parent::State>; + Next, State>; template using next_Impl = renderable_inheritance::Impl_Node< - Next, typename Parent::Impl>; + Next, Impl>; template using next_Observer = renderable_inheritance::Observer_Node< - Next, typename Parent::Observer>; + Next, Observer>; + + template + using next_Builder = renderable_inheritance::Builder_Node< + Next, Builder>; + + static_assert(inheritance::Defines_Chain_Layer< + Builder, typename Parent::template next_Builder, + next_Builder, + renderable_inheritance::Builder_Node< + inheritance::Chain_Probe, Builder>>); + static_assert(inheritance::Defines_Chain_Layer< + State, typename Parent::template next_State, + next_State, + renderable_inheritance::State_Node< + inheritance::Chain_Probe, State>>); + static_assert(inheritance::Defines_Chain_Layer< + Impl, typename Parent::template next_Impl, + next_Impl, + renderable_inheritance::Impl_Node< + inheritance::Chain_Probe, Impl>>); + static_assert(inheritance::Defines_Chain_Layer< + Observer, typename Parent::template next_Observer, + next_Observer, + renderable_inheritance::Observer_Node< + inheritance::Chain_Probe, Observer>>); using Parent::Parent; }; @@ -143,24 +191,29 @@ template struct attach : Control { using State = typename Control::State; using Properties = State; + using Observer = typename Control::Observer; using Self = attach; -protected: - struct Builder_Layer - : renderable_inheritance::Builder_Node< - Builder_Layer, typename Control::Builder_Layer> {}; - public: struct Builder : renderable_inheritance::Builder< - Builder, Builder_Layer, + Builder, typename Control::template next_Builder, typename Control::template Business_Builder> { using Builder_Base = renderable_inheritance::Builder< - Builder, Builder_Layer, + Builder, typename Control::template next_Builder, typename Control::template Business_Builder>; using Builder_Base::Builder_Base; }; + template + using next_Builder = renderable_inheritance::Builder_Node; + + static_assert(inheritance::Defines_Chain_Layer< + Builder, typename Control::template next_Builder, + next_Builder, + renderable_inheritance::Builder_Node< + inheritance::Chain_Probe, Builder>>); + template Self& set(Value&& value) { if constexpr (requires(Self& self, Value&& input) { diff --git a/Kernel/src/renderive/scene/Inheritance.hpp b/Kernel/src/renderive/scene/Inheritance.hpp index e18ff2b..c5239b3 100644 --- a/Kernel/src/renderive/scene/Inheritance.hpp +++ b/Kernel/src/renderive/scene/Inheritance.hpp @@ -2,12 +2,26 @@ #include "renderive/inheritance/Inheritance.hpp" #include #include +#include #include namespace renderive::scene_inheritance { struct Builder_Chain {}; struct State_Chain {}; struct Impl_Chain {}; struct Editor_Chain {}; +struct Observer_Chain {}; +struct Builder_Access { + class Key { + Key() = default; + friend struct Builder_Access; + }; + + template + [[nodiscard]] static std::unique_ptr make(Args&&... args) { + return std::unique_ptr( + new Product(Key{}, std::forward(args)...)); + } +}; template struct Builder_Root : inheritance::Type_Node {}; @@ -16,6 +30,11 @@ struct Builder_Node : inheritance::Type_Node { using Builder_Base = inheritance::Type_Node; using Builder_Base::Builder_Base; }; +template +struct Builder + : Parent_Next, Business_Builder { + using Business_Builder::Business_Builder; +}; template struct State_Root : inheritance::Type_Node {}; @@ -33,21 +52,28 @@ struct Editor_Node : inheritance::Type_Node { using Editor_Base::Editor_Base; }; template -struct Observer_Root { +struct Observer_Root +: inheritance::Type_Node { + using Observer_Base = inheritance::Type_Node< + Layer, inheritance::Type_Root, Observer_Chain>; using Owner = Layer; + using Observer_Base::Observer_Base; }; template -struct Observer_Node : Parent { +struct Observer_Node +: inheritance::Type_Node { + using Observer_Base = + inheritance::Type_Node; using Owner = Layer; + using Observer_Base::Observer_Base; }; template struct Observer_Handler { using Owner = Layer; static void handle(Layer& layer, const Event& event) requires requires { - typename Layer::Observer; - Layer::Observer::handle(layer, event); + layer.handle_observation(event); } { - Layer::Observer::handle(layer, event); + layer.handle_observation(event); } }; template @@ -70,7 +96,6 @@ struct Impl_Node typename Parent::Scene_Event>; using Scene_Event = typename Parent::Scene_Event; using Handler = Observer_Handler; - using next_Observer = Observer_Node; using Impl_Base::Impl_Base; }; } // namespace renderive::scene_inheritance @@ -102,25 +127,109 @@ public: }); } struct Observer - : scene_inheritance::Observer_Node {}; + : Parent::template next_Observer {}; protected: - struct Builder_Layer - : scene_inheritance::Builder_Node< - Builder_Layer, typename Parent::Builder_Layer> {}; - struct State_Layer - : scene_inheritance::State_Node< - State_Layer, typename Parent::State_Layer> {}; + struct Builder : Parent::template next_Builder {}; + struct State : Parent::template next_State {}; + struct Impl : Parent::template next_Impl { + using Impl_Base = typename Parent::template next_Impl; + using Impl_Base::Impl_Base; + }; + class Renderable_Editor : public Parent::template next_Editor< + Renderable_Editor> { + using Editor_Base = typename Parent::template next_Editor< + Renderable_Editor>; + using Editor_Base::Editor_Base; + }; template - using next_State = scene_inheritance::State_Node; + using next_State = scene_inheritance::State_Node; template - using next_Impl = scene_inheritance::Impl_Node; + using next_Impl = scene_inheritance::Impl_Node; template using next_Editor = scene_inheritance::Editor_Node< - Next, typename Parent::Renderable_Editor>; + Next, Renderable_Editor>; template using next_Builder = scene_inheritance::Builder_Node< - Next, Builder_Layer>; + Next, Builder>; + template + using next_Observer = scene_inheritance::Observer_Node< + Next, Observer>; + + static_assert(inheritance::Defines_Chain_Layer< + Builder, typename Parent::template next_Builder, + next_Builder, + scene_inheritance::Builder_Node>); + static_assert(inheritance::Defines_Chain_Layer< + State, typename Parent::template next_State, + next_State, + scene_inheritance::State_Node>); + static_assert(inheritance::Defines_Chain_Layer< + Impl, typename Parent::template next_Impl, + next_Impl, + scene_inheritance::Impl_Node>); + static_assert(inheritance::Defines_Chain_Layer< + Renderable_Editor, + typename Parent::template next_Editor, + next_Editor, + scene_inheritance::Editor_Node< + inheritance::Chain_Probe, Renderable_Editor>>); + static_assert(inheritance::Defines_Chain_Layer< + Observer, typename Parent::template next_Observer, + next_Observer, + scene_inheritance::Observer_Node< + inheritance::Chain_Probe, Observer>>); using Parent::Parent; }; + +template +struct attach : Control { + using State = typename Control::State; + using Properties = State; + using Observer = typename Control::Observer; + using Self = attach; + +public: + struct Builder + : scene_inheritance::Builder< + Builder, typename Control::template next_Builder, + typename Control::template Business_Builder> { + using Builder_Base = scene_inheritance::Builder< + Builder, typename Control::template next_Builder, + typename Control::template Business_Builder>; + using Builder_Base::Builder_Base; + }; + + template + using next_Builder = scene_inheritance::Builder_Node; + + static_assert(inheritance::Defines_Chain_Layer< + Builder, typename Control::template next_Builder, + next_Builder, + scene_inheritance::Builder_Node>); + + template + Self& set(Value&& value) { + Control::template set(std::forward(value)); + return *this; + } + + template + [[nodiscard]] auto get() const { + return Control::template get(); + } + + template + Self& update(Update&& operation) { + Control::update(std::forward(operation)); + return *this; + } + +private: + template + explicit attach(scene_inheritance::Builder_Access::Key, + Args&&... args) + : Control(std::forward(args)...) {} + + friend struct scene_inheritance::Builder_Access; +}; } // namespace renderive::scene diff --git a/Kernel/src/renderive/scene/Scene_Builder.hpp b/Kernel/src/renderive/scene/Scene_Builder.hpp new file mode 100644 index 0000000..96631d0 --- /dev/null +++ b/Kernel/src/renderive/scene/Scene_Builder.hpp @@ -0,0 +1,61 @@ +#pragma once + +#include "renderive/base/property/Concepts.hpp" +#include "renderive/base/property/Validators.hpp" +#include "renderive/scene/Inheritance.hpp" + +#include +#include +#include +#include + +namespace renderive::scene { + +template Validator_Type = + No_Property_Validator> +struct Scene_Builder { + using Product = Product_Type; + using Properties = Properties_Type; + using Validator = Validator_Type; + using Self = Scene_Builder; + + Scene_Builder() + requires std::default_initializable && + std::default_initializable + = default; + + explicit Scene_Builder(Properties properties) + requires std::default_initializable + : properties_(std::move(properties)) {} + + Scene_Builder(Properties properties, Validator validator) + : properties_(std::move(properties)), + validator_(std::move(validator)) {} + + template Value> + Self& set(Value&& value) { + properties_.*Member = std::forward(value); + return *this; + } + + template Configure> + Self& configure(Configure&& configure) { + std::invoke(std::forward(configure), properties_); + return *this; + } + + template + [[nodiscard]] std::unique_ptr build(Args&&... args) const { + validator_(properties_); + return scene_inheritance::Builder_Access::make( + properties_, std::forward(args)...); + } + +private: + Properties properties_{}; + [[no_unique_address]] Validator validator_{}; +}; + +} // namespace renderive::scene diff --git a/Kernel/src/renderive/scene/base/Scene_Base.cpp b/Kernel/src/renderive/scene/base/Scene_Base.cpp index da7f35a..370af79 100644 --- a/Kernel/src/renderive/scene/base/Scene_Base.cpp +++ b/Kernel/src/renderive/scene/base/Scene_Base.cpp @@ -468,8 +468,7 @@ Scene_2D_Base::Scene_2D_Base() : Scene_2D_Base(*std::pmr::get_default_resource() Scene_2D_Base::Scene_2D_Base(std::pmr::memory_resource& memory_resource) : Scene_2D_Base(memory_resource, std::make_unique(memory_resource)) {} Scene_2D_Base::Scene_2D_Base(std::pmr::memory_resource& memory_resource, std::unique_ptr impl) : Scene_Base(memory_resource, std::move(impl)) {} -Scene_2D_Base::Impl::Impl(std::pmr::memory_resource& memory_resource) : renderive::scene_inheritance::Impl_Node< - Impl, Scene_Base::Impl>(memory_resource), +Scene_2D_Base::Impl::Impl(std::pmr::memory_resource& memory_resource) : Scene_Base::next_Impl(memory_resource), display_resolver_(this->memory_resource()) {} Scene_2D_Base::Attach_Builder Scene_2D_Base::attach_builder() { return Attach_Builder(*this); diff --git a/Kernel/src/renderive/scene/base/Scene_Base.hpp b/Kernel/src/renderive/scene/base/Scene_Base.hpp index 3af1a90..4f6dc97 100644 --- a/Kernel/src/renderive/scene/base/Scene_Base.hpp +++ b/Kernel/src/renderive/scene/base/Scene_Base.hpp @@ -68,6 +68,9 @@ public: class Renderable_Editor : public renderive::scene_inheritance::Editor_Root { public: + template + using next_Editor = + renderive::scene_inheritance::Editor_Node; [[nodiscard]] Scene_Edit_Error attach(Renderable renderable); [[nodiscard]] Scene_Edit_Error detach(const Renderable& renderable); [[nodiscard]] Scene_Edit_Error set_dependency_parent(const Renderable& child, const Renderable& parent); @@ -88,6 +91,9 @@ public: class Attach_Builder : public renderive::scene_inheritance::Builder_Root { public: + template + using next_Builder = + renderive::scene_inheritance::Builder_Node; Attach_Builder(const Attach_Builder&) = delete; Attach_Builder& operator=(const Attach_Builder&) = delete; Attach_Builder(Attach_Builder&&) = delete; @@ -166,16 +172,32 @@ public: [[nodiscard]] auto frame_control_strategy() -> std::shared_ptr; [[nodiscard]] auto frame_control_strategy() const -> std::shared_ptr; struct Observer - : renderive::scene_inheritance::Observer_Root {}; + : renderive::scene_inheritance::Observer_Root {}; protected: Scene_Base(); explicit Scene_Base(std::pmr::memory_resource& upstream_memory_resource); virtual ~Scene_Base(); - struct Builder_Layer - : renderive::scene_inheritance::Builder_Root {}; - struct State_Layer - : renderive::scene_inheritance::State_Root {}; + struct Builder + : renderive::scene_inheritance::Builder_Root {}; + struct State + : renderive::scene_inheritance::State_Root {}; class Impl; + + template + using next_Builder = + renderive::scene_inheritance::Builder_Node; + template + using next_State = + renderive::scene_inheritance::State_Node; + template + using next_Impl = + renderive::scene_inheritance::Impl_Node; + template + using next_Observer = + renderive::scene_inheritance::Observer_Node; + template + using next_Editor = + renderive::scene_inheritance::Editor_Node; Scene_Base(std::pmr::memory_resource& upstream_memory_resource, std::unique_ptr impl); template @@ -194,30 +216,34 @@ private: class Scene_2D_Base : public Scene_Base { public: class Renderable_Editor - : public renderive::scene_inheritance::Editor_Node< - Renderable_Editor, Scene_Base::Renderable_Editor> { + : public Scene_Base::Renderable_Editor::next_Editor { public: + template + using next_Editor = + renderive::scene_inheritance::Editor_Node; [[nodiscard]] Scene_Edit_Error set_display_parent(const Renderable& child, const Renderable& parent); [[nodiscard]] Scene_Edit_Error add_display_parent(const Renderable& child, const Renderable& parent); [[nodiscard]] Scene_Edit_Error clear_display_parent(const Renderable& child); private: - explicit Renderable_Editor(Scene_2D_Base& scene) : renderive::scene_inheritance::Editor_Node< - Renderable_Editor, Scene_Base::Renderable_Editor>(scene), + explicit Renderable_Editor(Scene_2D_Base& scene) : Scene_Base::Renderable_Editor::next_Editor< + Renderable_Editor>(scene), scene_2d_(scene) {} Scene_2D_Base& scene_2d_; friend class Scene_2D_Base; friend class Attach_Builder; }; class Attach_Builder - : public renderive::scene_inheritance::Builder_Node< - Attach_Builder, Scene_Base::Attach_Builder> { + : public Scene_Base::Attach_Builder::next_Builder { public: + template + using next_Builder = + renderive::scene_inheritance::Builder_Node; [[nodiscard]] Scene_Edit_Error set_display_parent(const Renderable& child, const Renderable& parent); [[nodiscard]] Scene_Edit_Error add_display_parent(const Renderable& child, const Renderable& parent); [[nodiscard]] Scene_Edit_Error clear_display_parent(const Renderable& child); private: - explicit Attach_Builder(Scene_2D_Base& scene) : renderive::scene_inheritance::Builder_Node< - Attach_Builder, Scene_Base::Attach_Builder>(scene), + explicit Attach_Builder(Scene_2D_Base& scene) : Scene_Base::Attach_Builder::next_Builder< + Attach_Builder>(scene), scene_2d_(scene) {} Scene_2D_Base& scene_2d_; friend class Scene_2D_Base; @@ -228,16 +254,53 @@ public: Attach_Builder attach_builder(); [[nodiscard]] Edit_Operation edit_renderables(Renderable_Edit edit); struct Observer - : renderive::scene_inheritance::Observer_Node< - Scene_2D_Base, Scene_Base::Observer> {}; + : Scene_Base::next_Observer {}; protected: - struct Builder_Layer - : renderive::scene_inheritance::Builder_Node< - Builder_Layer, Scene_Base::Builder_Layer> {}; - struct State_Layer - : renderive::scene_inheritance::State_Node< - State_Layer, Scene_Base::State_Layer> {}; + struct Builder : Scene_Base::next_Builder {}; + struct State : Scene_Base::next_State {}; struct Impl; + template + using next_Builder = + renderive::scene_inheritance::Builder_Node; + template + using next_State = + renderive::scene_inheritance::State_Node; + template + using next_Impl = + renderive::scene_inheritance::Impl_Node; + template + using next_Observer = + renderive::scene_inheritance::Observer_Node; + template + using next_Editor = + renderive::scene_inheritance::Editor_Node; + static_assert(renderive::inheritance::Defines_Chain_Layer< + Builder, Scene_Base::next_Builder, + next_Builder, + renderive::scene_inheritance::Builder_Node< + renderive::inheritance::Chain_Probe, Builder>>); + static_assert(renderive::inheritance::Defines_Chain_Layer< + State, Scene_Base::next_State, + next_State, + renderive::scene_inheritance::State_Node< + renderive::inheritance::Chain_Probe, State>>); + static_assert(renderive::inheritance::Defines_Chain_Layer< + Observer, Scene_Base::next_Observer, + next_Observer, + renderive::scene_inheritance::Observer_Node< + renderive::inheritance::Chain_Probe, Observer>>); + static_assert(renderive::inheritance::Defines_Chain_Layer< + Renderable_Editor, + Scene_Base::Renderable_Editor::next_Editor, + next_Editor, + renderive::scene_inheritance::Editor_Node< + renderive::inheritance::Chain_Probe, Renderable_Editor>>); + static_assert(renderive::inheritance::Defines_Chain_Layer< + Attach_Builder, + Scene_Base::Attach_Builder::next_Builder, + Attach_Builder::next_Builder, + renderive::scene_inheritance::Builder_Node< + renderive::inheritance::Chain_Probe, Attach_Builder>>); Scene_2D_Base(std::pmr::memory_resource& memory_resource, std::unique_ptr impl); private: @@ -245,33 +308,80 @@ private: }; class Scene_3D_Base : public Scene_Base { public: - class Renderable_Editor : public renderive::scene_inheritance::Editor_Node { + class Renderable_Editor : public Scene_Base::Renderable_Editor::next_Editor { + public: + template + using next_Editor = + renderive::scene_inheritance::Editor_Node; private: - explicit Renderable_Editor(Scene_3D_Base& scene) : renderive::scene_inheritance::Editor_Node< - Renderable_Editor, Scene_Base::Renderable_Editor>(scene) {} + explicit Renderable_Editor(Scene_3D_Base& scene) : Scene_Base::Renderable_Editor::next_Editor< + Renderable_Editor>(scene) {} friend class Scene_3D_Base; }; - class Attach_Builder : public renderive::scene_inheritance::Builder_Node { + class Attach_Builder : public Scene_Base::Attach_Builder::next_Builder { + public: + template + using next_Builder = + renderive::scene_inheritance::Builder_Node; private: - explicit Attach_Builder(Scene_3D_Base& scene) : renderive::scene_inheritance::Builder_Node< - Attach_Builder, Scene_Base::Attach_Builder>(scene) {} + explicit Attach_Builder(Scene_3D_Base& scene) : Scene_Base::Attach_Builder::next_Builder< + Attach_Builder>(scene) {} friend class Scene_3D_Base; }; using Renderable_Edit = std::function; [[nodiscard]] Edit_Operation edit_renderables(Renderable_Edit edit); struct Observer - : renderive::scene_inheritance::Observer_Node< - Scene_3D_Base, Scene_Base::Observer> {}; + : Scene_Base::next_Observer {}; protected: Scene_3D_Base(); explicit Scene_3D_Base(std::pmr::memory_resource& memory_resource); - struct Builder_Layer - : renderive::scene_inheritance::Builder_Node< - Builder_Layer, Scene_Base::Builder_Layer> {}; - struct State_Layer - : renderive::scene_inheritance::State_Node< - State_Layer, Scene_Base::State_Layer> {}; + struct Builder : Scene_Base::next_Builder {}; + struct State : Scene_Base::next_State {}; struct Impl; + template + using next_Builder = + renderive::scene_inheritance::Builder_Node; + template + using next_State = + renderive::scene_inheritance::State_Node; + template + using next_Impl = + renderive::scene_inheritance::Impl_Node; + template + using next_Observer = + renderive::scene_inheritance::Observer_Node; + template + using next_Editor = + renderive::scene_inheritance::Editor_Node; + static_assert(renderive::inheritance::Defines_Chain_Layer< + Builder, Scene_Base::next_Builder, + next_Builder, + renderive::scene_inheritance::Builder_Node< + renderive::inheritance::Chain_Probe, Builder>>); + static_assert(renderive::inheritance::Defines_Chain_Layer< + State, Scene_Base::next_State, + next_State, + renderive::scene_inheritance::State_Node< + renderive::inheritance::Chain_Probe, State>>); + static_assert(renderive::inheritance::Defines_Chain_Layer< + Observer, Scene_Base::next_Observer, + next_Observer, + renderive::scene_inheritance::Observer_Node< + renderive::inheritance::Chain_Probe, Observer>>); + static_assert(renderive::inheritance::Defines_Chain_Layer< + Renderable_Editor, + Scene_Base::Renderable_Editor::next_Editor, + next_Editor, + renderive::scene_inheritance::Editor_Node< + renderive::inheritance::Chain_Probe, Renderable_Editor>>); + static_assert(renderive::inheritance::Defines_Chain_Layer< + Attach_Builder, + Scene_Base::Attach_Builder::next_Builder, + Attach_Builder::next_Builder, + renderive::scene_inheritance::Builder_Node< + renderive::inheritance::Chain_Probe, Attach_Builder>>); Scene_3D_Base(std::pmr::memory_resource& memory_resource, std::unique_ptr impl); }; + +#include "Scene_Base.inl" diff --git a/Kernel/src/renderive/scene/base/Scene_Base.inl b/Kernel/src/renderive/scene/base/Scene_Base.inl index e471d0b..367cb41 100644 --- a/Kernel/src/renderive/scene/base/Scene_Base.inl +++ b/Kernel/src/renderive/scene/base/Scene_Base.inl @@ -177,9 +177,14 @@ public: }; struct Scene_2D_Base::Impl - : renderive::scene_inheritance::Impl_Node, + : Scene_Base::next_Impl, Scene_Base::Impl::Composition_Relationships { using Observer = Scene_2D_Base::Observer; + static_assert(renderive::inheritance::Defines_Chain_Layer< + Impl, Scene_Base::next_Impl, + Scene_2D_Base::next_Impl, + renderive::scene_inheritance::Impl_Node< + renderive::inheritance::Chain_Probe, Impl>>); explicit Impl(std::pmr::memory_resource& memory_resource); void with_initial_display_edit(std::function edit); @@ -203,10 +208,14 @@ struct Scene_2D_Base::Impl }; struct Scene_3D_Base::Impl - : renderive::scene_inheritance::Impl_Node { + : Scene_Base::next_Impl { using Observer = Scene_3D_Base::Observer; + static_assert(renderive::inheritance::Defines_Chain_Layer< + Impl, Scene_Base::next_Impl, + Scene_3D_Base::next_Impl, + renderive::scene_inheritance::Impl_Node< + renderive::inheritance::Chain_Probe, Impl>>); explicit Impl(std::pmr::memory_resource& memory_resource) - : renderive::scene_inheritance::Impl_Node< - Impl, Scene_Base::Impl>(memory_resource) {} + : Scene_Base::next_Impl(memory_resource) {} }; diff --git a/render_2D/render_2D/axis/Abs_Axis.h b/render_2D/render_2D/axis/Abs_Axis.h index a6ccc22..3f81366 100644 --- a/render_2D/render_2D/axis/Abs_Axis.h +++ b/render_2D/render_2D/axis/Abs_Axis.h @@ -5,6 +5,7 @@ namespace renderive { struct LIB_DECL Abs_Axis : detail::Renderable { + using Base = detail::Renderable; 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 {}; - struct Impl : next_Impl {}; + struct Builder : Base::template next_Builder {}; + struct State : Base::template next_State {}; + struct Impl : Base::template next_Impl {}; + struct Observer : Base::template next_Observer {}; + + template + using next_Builder = renderable_inheritance::Builder_Node; + template + using next_State = renderable_inheritance::State_Node; + template + using next_Impl = renderable_inheritance::Impl_Node; + template + using next_Observer = + renderable_inheritance::Observer_Node; + + static_assert(inheritance::Defines_Chain_Layer< + Builder, Base::template next_Builder, + next_Builder, + renderable_inheritance::Builder_Node< + inheritance::Chain_Probe, Builder>>); + static_assert(inheritance::Defines_Chain_Layer< + State, Base::template next_State, + next_State, + renderable_inheritance::State_Node< + inheritance::Chain_Probe, State>>); + static_assert(inheritance::Defines_Chain_Layer< + Impl, Base::template next_Impl, + next_Impl, + renderable_inheritance::Impl_Node< + inheritance::Chain_Probe, Impl>>); + static_assert(inheritance::Defines_Chain_Layer< + Observer, Base::template next_Observer, + next_Observer, + renderable_inheritance::Observer_Node< + inheritance::Chain_Probe, Observer>>); using detail::Renderable::Renderable; }; } // namespace renderive diff --git a/render_2D/render_2D/axis/Axis_State_Strategy.hpp b/render_2D/render_2D/axis/Axis_State_Strategy.hpp index 8a68c3e..775060e 100644 --- a/render_2D/render_2D/axis/Axis_State_Strategy.hpp +++ b/render_2D/render_2D/axis/Axis_State_Strategy.hpp @@ -15,7 +15,13 @@ struct Axis_State_Strategy : Renderable { using Render_Base = Renderable; protected: + struct Builder + : Render_Base::template next_Builder {}; + struct State : Render_Base::template next_State {}; + struct Observer : Render_Base::template next_Observer {}; struct Impl : Render_Base::template next_Impl { + static_assert(inheritance::Inherits_Chain_Parent< + Impl, Render_Base::template next_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 + using next_State = renderable_inheritance::State_Node; + template using next_Impl = renderable_inheritance::Impl_Node; + template + using next_Observer = + renderable_inheritance::Observer_Node; + template + using next_Builder = + renderable_inheritance::Builder_Node; + + static_assert(inheritance::Defines_Chain_Layer< + Builder, Render_Base::template next_Builder, + next_Builder, + renderable_inheritance::Builder_Node< + inheritance::Chain_Probe, Builder>>); + static_assert(inheritance::Defines_Chain_Layer< + State, Render_Base::template next_State, + next_State, + renderable_inheritance::State_Node< + inheritance::Chain_Probe, State>>); + static_assert(inheritance::Defines_Chain_Layer< + Observer, Render_Base::template next_Observer, + next_Observer, + renderable_inheritance::Observer_Node< + inheritance::Chain_Probe, Observer>>); public: template Axis_State_Strategy& set(Value&& value) { diff --git a/render_2D/render_2D/axis/Frequency_Axis.cpp b/render_2D/render_2D/axis/Frequency_Axis.cpp index 6677b55..5e50eb4 100644 --- a/render_2D/render_2D/axis/Frequency_Axis.cpp +++ b/render_2D/render_2D/axis/Frequency_Axis.cpp @@ -8,7 +8,12 @@ namespace renderive::detail { struct Frequency_Axis::Impl - : next_Impl { + : Base::next_Impl { + static_assert(inheritance::Defines_Chain_Layer< + Impl, Base::next_Impl, + Frequency_Axis::next_Impl, + 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{}, state) {} +Frequency_Axis::Observer Frequency_Axis::observer() const { + Observer result; + static_cast<::renderive::Axis::Observer&>(result) = + ::renderive::Axis::observer(); + return result; +} + } // namespace renderive::detail diff --git a/render_2D/render_2D/axis/Frequency_Axis.h b/render_2D/render_2D/axis/Frequency_Axis.h index cc9da1e..2e2af74 100644 --- a/render_2D/render_2D/axis/Frequency_Axis.h +++ b/render_2D/render_2D/axis/Frequency_Axis.h @@ -4,12 +4,44 @@ namespace renderive { namespace detail { struct LIB_DECL Frequency_Axis : Renderable { - using State = ::renderive::Axis::Properties; + using Base = Renderable; +protected: + struct Builder : Base::template next_Builder {}; +public: + struct State : Base::template next_State {}; + struct Observer : Base::template next_Observer {}; + [[nodiscard]] Observer observer() const; private: friend struct renderable::attach; explicit Frequency_Axis(const State& state); protected: struct Impl; + + template + using next_Builder = renderable_inheritance::Builder_Node; + template + using next_State = renderable_inheritance::State_Node; + template + using next_Impl = renderable_inheritance::Impl_Node; + template + using next_Observer = + renderable_inheritance::Observer_Node; + + static_assert(inheritance::Defines_Chain_Layer< + Builder, Base::template next_Builder, + next_Builder, + renderable_inheritance::Builder_Node< + inheritance::Chain_Probe, Builder>>); + static_assert(inheritance::Defines_Chain_Layer< + State, Base::template next_State, + next_State, + renderable_inheritance::State_Node< + inheritance::Chain_Probe, State>>); + static_assert(inheritance::Defines_Chain_Layer< + Observer, Base::template next_Observer, + next_Observer, + renderable_inheritance::Observer_Node< + inheritance::Chain_Probe, Observer>>); using Renderable::Renderable; }; } // namespace detail diff --git a/render_2D/render_2D/axis/Numeric_Axis.cpp b/render_2D/render_2D/axis/Numeric_Axis.cpp index d760669..33ec7a8 100644 --- a/render_2D/render_2D/axis/Numeric_Axis.cpp +++ b/render_2D/render_2D/axis/Numeric_Axis.cpp @@ -11,6 +11,12 @@ static_assert(!std::constructible_from<::renderive::Axis, Axis::Axis(const State& state) : Axis_State_Strategy(With_Attached_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(owner()); if (event.type == Event_Type::Wheel && diff --git a/render_2D/render_2D/axis/Numeric_Axis.h b/render_2D/render_2D/axis/Numeric_Axis.h index 1949abb..627b4b7 100644 --- a/render_2D/render_2D/axis/Numeric_Axis.h +++ b/render_2D/render_2D/axis/Numeric_Axis.h @@ -20,17 +20,53 @@ struct Axis_Properties : Axis_Base_Properties { namespace detail { struct LIB_DECL Axis : Axis_State_Strategy { - struct State : next_State, Axis_Properties { + using Base = Axis_State_Strategy; +protected: + struct Builder : Base::template next_Builder {}; +public: + struct State : Base::template next_State, Axis_Properties { State() = default; State(const Axis_Properties& properties) : Axis_Properties(properties) {} }; + struct Observer : Base::template next_Observer { + State state; + }; + [[nodiscard]] Observer observer() const; private: friend struct renderable::attach; explicit Axis(const State& state); protected: struct Impl; + + template + using next_Builder = renderable_inheritance::Builder_Node; + template + using next_State = renderable_inheritance::State_Node; + template + using next_Impl = renderable_inheritance::Impl_Node; + template + using next_Observer = + renderable_inheritance::Observer_Node; + + static_assert(inheritance::Defines_Chain_Layer< + Builder, Base::template next_Builder, + next_Builder, + renderable_inheritance::Builder_Node< + inheritance::Chain_Probe, Builder>>); + static_assert(inheritance::Defines_Chain_Layer< + State, Base::template next_State, + next_State, + renderable_inheritance::State_Node< + inheritance::Chain_Probe, State>>); + static_assert(inheritance::Defines_Chain_Layer< + Observer, Base::template next_Observer, + next_Observer, + renderable_inheritance::Observer_Node< + inheritance::Chain_Probe, Observer>>); using Axis_State_Strategy::Axis_State_Strategy; }; } // namespace detail using Axis = renderable::attach; } // namespace renderive + +#include "Numeric_Axis_p.h" diff --git a/render_2D/render_2D/axis/Numeric_Axis_p.h b/render_2D/render_2D/axis/Numeric_Axis_p.h index 01a7a5a..de4e28e 100644 --- a/render_2D/render_2D/axis/Numeric_Axis_p.h +++ b/render_2D/render_2D/axis/Numeric_Axis_p.h @@ -7,8 +7,13 @@ namespace renderive::detail { struct Axis::Impl - : next_Impl, + : Base::next_Impl, Renderable_Event_Handler { + static_assert(inheritance::Defines_Chain_Layer< + Impl, Base::next_Impl, + Axis::next_Impl, + renderable_inheritance::Impl_Node< + inheritance::Chain_Probe, Impl>>); private: void handle_event(const Event& event) override; diff --git a/render_2D/render_2D/axis/Time_Axis.cpp b/render_2D/render_2D/axis/Time_Axis.cpp index 16a1829..fe77d15 100644 --- a/render_2D/render_2D/axis/Time_Axis.cpp +++ b/render_2D/render_2D/axis/Time_Axis.cpp @@ -7,7 +7,12 @@ namespace renderive::detail { struct Time_Axis::Impl - : next_Impl { + : Base::next_Impl { + static_assert(inheritance::Defines_Chain_Layer< + Impl, Base::next_Impl, + Time_Axis::next_Impl, + 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{}, 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(); }); } diff --git a/render_2D/render_2D/axis/Time_Axis.h b/render_2D/render_2D/axis/Time_Axis.h index 27f7eb1..b95258a 100644 --- a/render_2D/render_2D/axis/Time_Axis.h +++ b/render_2D/render_2D/axis/Time_Axis.h @@ -8,7 +8,11 @@ namespace renderive { namespace detail { struct LIB_DECL Time_Axis : Axis_State_Strategy { - struct State : next_State, Axis_Base_Properties { + using Base = Axis_State_Strategy; +protected: + struct Builder : Base::template next_Builder {}; +public: + struct State : Base::template next_State, Axis_Base_Properties { Range_Value::max()> visible_count{100}; Range_Value::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> samples; }; + struct Observer : Base::template next_Observer { + State state; + }; private: friend struct renderable::attach; 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 + using next_Builder = renderable_inheritance::Builder_Node; + template + using next_State = renderable_inheritance::State_Node; + template + using next_Impl = renderable_inheritance::Impl_Node; + template + using next_Observer = + renderable_inheritance::Observer_Node; + + static_assert(inheritance::Defines_Chain_Layer< + Builder, Base::template next_Builder, + next_Builder, + renderable_inheritance::Builder_Node< + inheritance::Chain_Probe, Builder>>); + static_assert(inheritance::Defines_Chain_Layer< + State, Base::template next_State, + next_State, + renderable_inheritance::State_Node< + inheritance::Chain_Probe, State>>); + static_assert(inheritance::Defines_Chain_Layer< + Observer, Base::template next_Observer, + next_Observer, + renderable_inheritance::Observer_Node< + inheritance::Chain_Probe, Observer>>); using Axis_State_Strategy::Axis_State_Strategy; }; } // namespace detail diff --git a/render_2D/render_2D/frame_control/Plot_Frame_Control.cpp b/render_2D/render_2D/frame_control/Plot_Frame_Control.cpp index 396df12..001d6a3 100644 --- a/render_2D/render_2D/frame_control/Plot_Frame_Control.cpp +++ b/render_2D/render_2D/frame_control/Plot_Frame_Control.cpp @@ -6,9 +6,7 @@ #include #include -#include #include -#include #include namespace renderive::detail { @@ -21,17 +19,11 @@ template decltype(auto) visit(Frame_Control_Strategy_Base& strategy, Function&& function) { if (auto* value = dynamic_cast(&strategy)) - return std::forward(function)( - *value, std::integral_constant{}); + return std::forward(function)(*value); if (auto* value = dynamic_cast(&strategy)) - return std::forward(function)( - *value, std::integral_constant{}); + return std::forward(function)(*value); if (auto* value = dynamic_cast(&strategy)) - return std::forward(function)( - *value, std::integral_constant{}); + return std::forward(function)(*value); ::renderive::error::unexpected( "unknown plot frame strategy"); } @@ -40,18 +32,12 @@ template decltype(auto) visit(const Frame_Control_Strategy_Base& strategy, Function&& function) { if (const auto* value = dynamic_cast(&strategy)) - return std::forward(function)( - *value, std::integral_constant{}); + return std::forward(function)(*value); if (const auto* value = dynamic_cast(&strategy)) - return std::forward(function)( - *value, std::integral_constant{}); + return std::forward(function)(*value); if (const auto* value = dynamic_cast(&strategy)) - return std::forward(function)( - *value, std::integral_constant{}); + return std::forward(function)(*value); ::renderive::error::unexpected( "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 strategy) : impl_(std::make_unique()) { - switch (selected_mode) { - case Plot_Frame_Mode::Manual: - impl_->strategy = std::make_shared(); - break; - case Plot_Frame_Mode::Low_Latency: - impl_->strategy = std::make_shared(); - break; - case Plot_Frame_Mode::Playback: - impl_->strategy = std::make_shared( - memory_resource); - break; - } - if (!impl_->strategy) - ::renderive::error::unexpected( - "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 { - return visit(*impl_->strategy, [&scene](auto& strategy, auto) { - auto frame = strategy.acquire_painter(); - if (!frame) - return Expected( - unexpected( - Plot_Prepare_Frame_Error::painter_unavailable)); - scene.publish_frame_state(*frame); - return Expected{}; - }); -} - -auto Plot_Frame_Control::refresh(Render_Scene_2D&) - -> Expected { - auto* strategy = dynamic_cast(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 { - return visit(*impl_->strategy, [&scene](auto& strategy, auto) { - auto frame = strategy.acquire_renderer(); - if (!frame) - return Expected( - unexpected( - Plot_Render_Prepared_Frame_Error::renderer_unavailable)); - const auto result = scene.Scene_Base::render(*frame); - if (result == Scene_Render_Result::none) - return Expected{}; - if (result == Scene_Render_Result::shutting_down) - return Expected( - unexpected( - Plot_Render_Prepared_Frame_Error::scene_shutting_down)); - const auto converted = - adapter::enum_cast(result); - if (!converted) - ::renderive::error::unexpected( - "unknown scene render error"); - return Expected( - unexpected(*converted)); - }); -} - -bool Plot_Frame_Control::discard(Render_Scene_2D&) { - if (auto* strategy = - dynamic_cast(impl_->strategy.get())) - return strategy->discard_pending_frame(); - if (auto* strategy = - dynamic_cast(impl_->strategy.get())) - return strategy->discard_pending_frame(); - return false; -} - auto Plot_Frame_Control::request(Render_Scene_2D& scene) -> Expected { - 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(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 { + 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(result.error()); + adapter::enum_cast(result); if (!converted) ::renderive::error::unexpected( - "unknown plot render error"); + "unknown scene render error"); return unexpected(*converted); - } - return {}; + }); +} + +void Plot_Frame_Control::replace( + std::shared_ptr strategy) { + if (!strategy) + ::renderive::error::unexpected( + "Plot_Scene requires a frame strategy"); + visit(*strategy, [](const auto&) {}); + impl_->strategy = std::move(strategy); } } // namespace renderive::detail diff --git a/render_2D/render_2D/frame_control/Plot_Frame_Control.h b/render_2D/render_2D/frame_control/Plot_Frame_Control.h index c6c2930..2e771f9 100644 --- a/render_2D/render_2D/frame_control/Plot_Frame_Control.h +++ b/render_2D/render_2D/frame_control/Plot_Frame_Control.h @@ -3,14 +3,13 @@ #include "../scene/Render_Scene_2D.h" #include -#include 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 strategy); ~Plot_Frame_Control(); Plot_Frame_Control(const Plot_Frame_Control&) = delete; @@ -21,17 +20,9 @@ public: [[nodiscard]] std::shared_ptr runtime(); [[nodiscard]] std::shared_ptr runtime() const; - [[nodiscard]] double frequency_hz() const; - [[nodiscard]] std::uint64_t next_refresh_interval_ns() const; - [[nodiscard]] auto prepare(Render_Scene_2D& scene) - -> Expected; - [[nodiscard]] auto refresh(Render_Scene_2D& scene) - -> Expected; - [[nodiscard]] auto render(Render_Scene_2D& scene) - -> Expected; - [[nodiscard]] bool discard(Render_Scene_2D& scene); [[nodiscard]] auto request(Render_Scene_2D& scene) -> Expected; + void replace(std::shared_ptr strategy); private: struct Impl; std::unique_ptr impl_; diff --git a/render_2D/render_2D/plottable/Afterglow.cpp b/render_2D/render_2D/plottable/Afterglow.cpp index cedec42..719a139 100644 --- a/render_2D/render_2D/plottable/Afterglow.cpp +++ b/render_2D/render_2D/plottable/Afterglow.cpp @@ -27,7 +27,12 @@ struct Afterglow_Prepare_Buffer { }; } struct Afterglow::Impl - : next_Impl, ::Render_Frame_Completion { + : Base::next_Impl, ::Render_Frame_Completion { + static_assert(inheritance::Defines_Chain_Layer< + Impl, Base::next_Impl, + Afterglow::next_Impl, + renderable_inheritance::Impl_Node< + inheritance::Chain_Probe, Impl>>); Impl(renderive_Owner frequency, renderive_Owner power) : frequency_axis(std::move(frequency)), @@ -76,6 +81,15 @@ std::size_t Afterglow::rendered_cell_count() const { : std::max(1, static_cast(d_func().power_axis->transform().pixel_length)); return width > 0 && height > 0 ? static_cast(width) * static_cast(height) : 0; } +Afterglow::Observer Afterglow::observer() const { + const auto value = Renderable::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 values) { if (get_state() <= 0) set_state( diff --git a/render_2D/render_2D/plottable/Afterglow.h b/render_2D/render_2D/plottable/Afterglow.h index 190dfdd..39c1a5f 100644 --- a/render_2D/render_2D/plottable/Afterglow.h +++ b/render_2D/render_2D/plottable/Afterglow.h @@ -7,6 +7,10 @@ namespace renderive { namespace detail { struct LIB_DECL Afterglow : Renderable { + using Base = Renderable; +protected: + struct Builder : Base::template next_Builder {}; +public: struct State; private: friend struct renderable::attach; @@ -23,7 +27,7 @@ public: void append_spectrum(const Values& values) { append_spectrum(std::span(values.data(), values.size())); } - struct State : next_State { + struct State : Base::template next_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 { + 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 using next_Builder = renderable_inheritance::Builder_Node; + template using next_State = renderable_inheritance::State_Node; + template using next_Impl = renderable_inheritance::Impl_Node; + template using next_Observer = renderable_inheritance::Observer_Node; + static_assert(inheritance::Defines_Chain_Layer, next_Builder, renderable_inheritance::Builder_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_State, renderable_inheritance::State_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_Observer, renderable_inheritance::Observer_Node>); }; } using Afterglow = renderable::attach; diff --git a/render_2D/render_2D/plottable/Constellation_Diagram.cpp b/render_2D/render_2D/plottable/Constellation_Diagram.cpp index c1e77fe..21beaa6 100644 --- a/render_2D/render_2D/plottable/Constellation_Diagram.cpp +++ b/render_2D/render_2D/plottable/Constellation_Diagram.cpp @@ -19,7 +19,12 @@ struct Timed_Point { using Constellation_History = Plottable_History_Real_Time_Data>; } struct Constellation_Diagram::Impl - : next_Impl { + : Base::next_Impl { + static_assert(inheritance::Defines_Chain_Layer< + Impl, Base::next_Impl, + Constellation_Diagram::next_Impl, + renderable_inheritance::Impl_Node< + inheritance::Chain_Probe, Impl>>); struct Prepare_Buffer { std::vector anchors; std::vector points; @@ -54,6 +59,13 @@ void Constellation_Diagram::append_point(PointF point) { std::size_t Constellation_Diagram::point_count() const { return d_func().points->size(); } +Constellation_Diagram::Observer Constellation_Diagram::observer() const { + const auto value = Renderable::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(); const double side = std::max(state.i_range.size(), state.q_range.size()); diff --git a/render_2D/render_2D/plottable/Constellation_Diagram.h b/render_2D/render_2D/plottable/Constellation_Diagram.h index 069b3ad..195d948 100644 --- a/render_2D/render_2D/plottable/Constellation_Diagram.h +++ b/render_2D/render_2D/plottable/Constellation_Diagram.h @@ -9,6 +9,10 @@ enum class Constellation_Diagram_Type : std::uint8_t { }; namespace detail { struct LIB_DECL Constellation_Diagram : Renderable { + using Base = Renderable; +protected: + struct Builder : Base::template next_Builder {}; +public: struct State; private: friend struct renderable::attach; @@ -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 { + struct State : Base::template next_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 { + State state; + std::size_t point_count{}; + }; + [[nodiscard]] Observer observer() const; private: struct Impl; + template using next_Builder = renderable_inheritance::Builder_Node; + template using next_State = renderable_inheritance::State_Node; + template using next_Impl = renderable_inheritance::Impl_Node; + template using next_Observer = renderable_inheritance::Observer_Node; + static_assert(inheritance::Defines_Chain_Layer, next_Builder, renderable_inheritance::Builder_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_State, renderable_inheritance::State_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_Observer, renderable_inheritance::Observer_Node>); }; } // namespace detail using Constellation_Diagram = renderable::attach; diff --git a/render_2D/render_2D/plottable/Frequency_Trace.cpp b/render_2D/render_2D/plottable/Frequency_Trace.cpp index fae588a..8a73b01 100644 --- a/render_2D/render_2D/plottable/Frequency_Trace.cpp +++ b/render_2D/render_2D/plottable/Frequency_Trace.cpp @@ -13,7 +13,12 @@ namespace { using Frequency_Trace_History = Plottable_History_Real_Time_Data, std::deque>>; } struct Frequency_Trace::Impl - : next_Impl { + : Base::next_Impl { + static_assert(inheritance::Defines_Chain_Layer< + Impl, Base::next_Impl, + Frequency_Trace::next_Impl, + renderable_inheritance::Impl_Node< + inheritance::Chain_Probe, Impl>>); struct Prepare_Buffer { std::vector 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(); + 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); diff --git a/render_2D/render_2D/plottable/Frequency_Trace.h b/render_2D/render_2D/plottable/Frequency_Trace.h index fdad038..bd5af9f 100644 --- a/render_2D/render_2D/plottable/Frequency_Trace.h +++ b/render_2D/render_2D/plottable/Frequency_Trace.h @@ -4,6 +4,10 @@ namespace renderive { namespace detail { struct LIB_DECL Frequency_Trace : Renderable { + using Base = Renderable; +protected: + struct Builder : Base::template next_Builder {}; +public: struct State; private: friend struct renderable::attach; @@ -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 { + struct State : Base::template next_State { Pen pen{Color::yellow()}; }; + struct Observer : Base::template next_Observer { + State state; + std::size_t sample_count{}; + std::size_t rendered_point_count{}; + }; + [[nodiscard]] Observer observer() const; private: struct Impl; + template using next_Builder = renderable_inheritance::Builder_Node; + template using next_State = renderable_inheritance::State_Node; + template using next_Impl = renderable_inheritance::Impl_Node; + template using next_Observer = renderable_inheritance::Observer_Node; + static_assert(inheritance::Defines_Chain_Layer, next_Builder, renderable_inheritance::Builder_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_State, renderable_inheritance::State_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_Observer, renderable_inheritance::Observer_Node>); }; } using Frequency_Trace = renderable::attach; diff --git a/render_2D/render_2D/plottable/Plottable.h b/render_2D/render_2D/plottable/Plottable.h index 12db0a3..46e1fb2 100644 --- a/render_2D/render_2D/plottable/Plottable.h +++ b/render_2D/render_2D/plottable/Plottable.h @@ -52,32 +52,62 @@ template struct Renderable : renderable::render_base { using Render_Base = renderable::render_base; protected: + struct Builder + : Render_Base::template next_Builder {}; struct State - : Render_Base::template next_State {}; - + : Render_Base::template next_State {}; + struct Impl : Render_Base::template next_Impl { + using Base_Impl = typename Render_Base::template next_Impl; + using Base_Impl::Base_Impl; + }; + struct Observer : Render_Base::template next_Observer {}; template - using next_State = - renderable_inheritance::State_Node; - + using next_State = renderable_inheritance::State_Node; template - using next_Impl = - renderable_inheritance::Impl_Node; + using next_Impl = renderable_inheritance::Impl_Node; + template + using next_Observer = + renderable_inheritance::Observer_Node; + template + using next_Builder = + renderable_inheritance::Builder_Node; + + static_assert(inheritance::Defines_Chain_Layer< + Builder, Render_Base::template next_Builder, + next_Builder, + renderable_inheritance::Builder_Node< + inheritance::Chain_Probe, Builder>>); + static_assert(inheritance::Defines_Chain_Layer< + State, Render_Base::template next_State, + next_State, + renderable_inheritance::State_Node< + inheritance::Chain_Probe, State>>); + static_assert(inheritance::Defines_Chain_Layer< + Impl, Render_Base::template next_Impl, + next_Impl, + renderable_inheritance::Impl_Node< + inheritance::Chain_Probe, Impl>>); + static_assert(inheritance::Defines_Chain_Layer< + Observer, Render_Base::template next_Observer, + next_Observer, + renderable_inheritance::Observer_Node< + inheritance::Chain_Probe, Observer>>); + template using Business_Builder = Renderable_Builder; using State_Observer = Observer_State; template Renderable(With_Attached_Impl, State_Type state, - Args&&... args) - : Render_Base( - std::make_unique>( - std::move(state), - With_Observer{ - State_Observer(Renderable_State_Observer(this)) - }, - std::forward(args)...), - true) {} + Args&&... args) : Render_Base( + std::make_unique>( + std::move(state), + With_Observer{ + State_Observer(Renderable_State_Observer(this)) + }, + std::forward(args)...), + true) {} using Render_Base::Render_Base; template Value> @@ -104,23 +134,19 @@ protected: } } using Member_Value = decltype(std::declval().*Member); - if constexpr (Paint_Only_Property_Value) - this->d_func().paint_changed(); - else - this->d_func().changed(); + if constexpr (Paint_Only_Property_Value) this->d_func().paint_changed(); + else this->d_func().changed(); } template auto get_state() const { return state_storage().template get(); } - template - requires std::invocable + template requires std::invocable void update_state(Update&& update) { state_storage().update(std::forward(update)); this->d_func().changed(); } - template - requires std::invocable + template requires std::invocable decltype(auto) read_state(Read&& read) const { return state_storage().read(std::forward(read)); } diff --git a/render_2D/render_2D/plottable/Selection_Rectangle_Overlay.cpp b/render_2D/render_2D/plottable/Selection_Rectangle_Overlay.cpp index a12a611..bdb2ebf 100644 --- a/render_2D/render_2D/plottable/Selection_Rectangle_Overlay.cpp +++ b/render_2D/render_2D/plottable/Selection_Rectangle_Overlay.cpp @@ -21,9 +21,15 @@ RectF axis_content_rect(const Axis_Transform& first, const Axis_Transform& secon } } struct Selection_Rectangle_Overlay::Impl - : next_Impl, + : Base::next_Impl, Renderable_Event_Handler { using Observer = Selection_Rectangle_Overlay::Observer; + static_assert(inheritance::Defines_Chain_Layer< + Impl, Base::next_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 horizontal_axis, @@ -66,6 +74,13 @@ Selection_Rectangle_Overlay::~Selection_Rectangle_Overlay() = default; std::vector Selection_Rectangle_Overlay::selected_regions() const { return d_func().regions->snapshot(); } +Selection_Rectangle_Overlay::Observer +Selection_Rectangle_Overlay::observer() const { + Observer result; + result.state = Renderable::state(); + result.selected_region_count = d_func().regions->size(); + return result; +} void Selection_Rectangle_Overlay::clear_selected_regions() { d_func().regions->clear(); d_func().interaction.update([](Selection_Interaction& interaction) { diff --git a/render_2D/render_2D/plottable/Selection_Rectangle_Overlay.h b/render_2D/render_2D/plottable/Selection_Rectangle_Overlay.h index 2b6341d..3b1a248 100644 --- a/render_2D/render_2D/plottable/Selection_Rectangle_Overlay.h +++ b/render_2D/render_2D/plottable/Selection_Rectangle_Overlay.h @@ -5,6 +5,10 @@ namespace renderive { namespace detail { struct LIB_DECL Selection_Rectangle_Overlay : Renderable, Paint_Overlay { + using Base = Renderable; +protected: + struct Builder : Base::template next_Builder {}; +public: struct State; private: @@ -16,7 +20,7 @@ public: ~Selection_Rectangle_Overlay() override; [[nodiscard]] std::vector selected_regions() const; void clear_selected_regions(); - struct State : next_State { + struct State : Base::template next_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 { - static void handle(Impl& impl, - const Renderable_Event_View& observation); + struct Observer : Base::template next_Observer { + State state; + std::size_t selected_region_count{}; }; +private: + template using next_Builder = renderable_inheritance::Builder_Node; + template using next_State = renderable_inheritance::State_Node; + template using next_Impl = renderable_inheritance::Impl_Node; + template using next_Observer = renderable_inheritance::Observer_Node; + static_assert(inheritance::Defines_Chain_Layer, next_Builder, renderable_inheritance::Builder_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_State, renderable_inheritance::State_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_Observer, renderable_inheritance::Observer_Node>); +public: + [[nodiscard]] Observer observer() const; }; } using Selection_Rectangle_Overlay = diff --git a/render_2D/render_2D/plottable/Spectrum.cpp b/render_2D/render_2D/plottable/Spectrum.cpp index 4300878..558e095 100644 --- a/render_2D/render_2D/plottable/Spectrum.cpp +++ b/render_2D/render_2D/plottable/Spectrum.cpp @@ -132,11 +132,16 @@ double spectrum_power_at(const ::renderive::Spectrum::Properties& properties, co } } struct Spectrum::Impl - : next_Impl, + : Base::next_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, + Spectrum::next_Impl, + renderable_inheritance::Impl_Node< + inheritance::Chain_Probe, Impl>>); Impl(renderive_Owner frequency, renderive_Owner 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, @@ -223,6 +229,16 @@ std::size_t Spectrum::rendered_point_count() const { d_func().power_axis->transform(), state.visible_range_only, state.interpolation_mode).size(); } +Spectrum::Observer Spectrum::observer() const { + const auto value = Renderable::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::max(0, selectable_line_marker_count())); + return result; +} double Spectrum::power_at(double frequency, bool& ok) const { const auto state = Renderable::state(); return spectrum_power_at( diff --git a/render_2D/render_2D/plottable/Spectrum.h b/render_2D/render_2D/plottable/Spectrum.h index 0762355..fb66465 100644 --- a/render_2D/render_2D/plottable/Spectrum.h +++ b/render_2D/render_2D/plottable/Spectrum.h @@ -32,7 +32,11 @@ struct Spectrum_Real_Time_Data_Strategy using Base::write; }; struct LIB_DECL Spectrum : Renderable { - struct State : next_State, Hover_Tooltip_Properties { + using Base = Renderable; +protected: + struct Builder : Base::template next_Builder {}; +public: + struct State : Base::template next_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 { - static void handle(Impl& impl, - const Renderable_Event_View& observation); + struct Observer : Base::template next_Observer { + State state; + std::size_t sample_count{}; + std::size_t rendered_point_count{}; + std::size_t selectable_marker_count{}; }; +private: + template using next_Builder = renderable_inheritance::Builder_Node; + template using next_State = renderable_inheritance::State_Node; + template using next_Impl = renderable_inheritance::Impl_Node; + template using next_Observer = renderable_inheritance::Observer_Node; + static_assert(inheritance::Defines_Chain_Layer, next_Builder, renderable_inheritance::Builder_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_State, renderable_inheritance::State_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_Observer, renderable_inheritance::Observer_Node>); +public: + [[nodiscard]] Observer observer() const; }; } using Spectrum = renderable::attach; diff --git a/render_2D/render_2D/plottable/Sweep_Spectrum.cpp b/render_2D/render_2D/plottable/Sweep_Spectrum.cpp index de2089e..856744a 100644 --- a/render_2D/render_2D/plottable/Sweep_Spectrum.cpp +++ b/render_2D/render_2D/plottable/Sweep_Spectrum.cpp @@ -19,8 +19,13 @@ std::vector flatten(const std::deque>& blocks) { } } struct Sweep_Spectrum::Impl - : next_Impl { + : Base::next_Impl { using Observer = Sweep_Spectrum::Observer; + static_assert(inheritance::Defines_Chain_Layer< + Impl, Base::next_Impl, + Sweep_Spectrum::next_Impl, + 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(impl.owner()); + auto& control = static_cast(owner()); const int limit = control.get_state(); - impl.blocks->retain_latest(static_cast(limit)); + blocks->retain_latest(static_cast(limit)); } Sweep_Spectrum::Sweep_Spectrum(const State& state, renderive_Owner frequency_axis, @@ -80,6 +86,15 @@ std::size_t Sweep_Spectrum::rendered_point_count() const { const auto values = flatten(d_func().blocks->snapshot()); return curve_points(values, state.frequency_range, d_func().frequency_axis->transform(), d_func().power_axis->transform(), state.visible_range_only, state.interpolation_mode).size(); } +Sweep_Spectrum::Observer Sweep_Spectrum::observer() const { + const auto value = Renderable::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(owner()); const auto& view = context.frame.render_state; diff --git a/render_2D/render_2D/plottable/Sweep_Spectrum.h b/render_2D/render_2D/plottable/Sweep_Spectrum.h index 7b4c021..63160f4 100644 --- a/render_2D/render_2D/plottable/Sweep_Spectrum.h +++ b/render_2D/render_2D/plottable/Sweep_Spectrum.h @@ -6,6 +6,10 @@ namespace renderive { namespace detail { struct LIB_DECL Sweep_Spectrum : Renderable { + using Base = Renderable; +protected: + struct Builder : Base::template next_Builder {}; +public: struct State; private: friend struct renderable::attach; @@ -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 { + struct State : Base::template next_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 { - static void handle(Impl& impl, - const Renderable_Event_View& observation); + struct Observer : Base::template next_Observer { + State state; + std::size_t stored_block_count{}; + std::size_t stored_point_count{}; + std::size_t rendered_point_count{}; }; +private: + template using next_Builder = renderable_inheritance::Builder_Node; + template using next_State = renderable_inheritance::State_Node; + template using next_Impl = renderable_inheritance::Impl_Node; + template using next_Observer = renderable_inheritance::Observer_Node; + static_assert(inheritance::Defines_Chain_Layer, next_Builder, renderable_inheritance::Builder_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_State, renderable_inheritance::State_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_Observer, renderable_inheritance::Observer_Node>); +public: + [[nodiscard]] Observer observer() const; }; } using Sweep_Spectrum = renderable::attach; diff --git a/render_2D/render_2D/plottable/Waterfall.cpp b/render_2D/render_2D/plottable/Waterfall.cpp index 6c8f947..5833ed1 100644 --- a/render_2D/render_2D/plottable/Waterfall.cpp +++ b/render_2D/render_2D/plottable/Waterfall.cpp @@ -60,10 +60,15 @@ std::size_t waterfall_work_size(const ::renderive::Waterfall::Properties& state, } } struct Waterfall::Impl - : next_Impl, + : Base::next_Impl, Renderable_Event_Handler, ::Render_Frame_Completion { using Observer = Waterfall::Observer; + static_assert(inheritance::Defines_Chain_Layer< + Impl, Base::next_Impl, + Waterfall::next_Impl, + renderable_inheritance::Impl_Node< + inheritance::Chain_Probe, Impl>>); Impl(renderive_Owner frequency, renderive_Owner 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, @@ -145,6 +151,15 @@ std::size_t Waterfall::rendered_cell_count() const { state.visible_range_only); return columns ? static_cast(columns->last - columns->first + 1) * rows.size() : 0; } +Waterfall::Observer Waterfall::observer() const { + const auto value = Renderable::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(owner()); bool updated{}; diff --git a/render_2D/render_2D/plottable/Waterfall.h b/render_2D/render_2D/plottable/Waterfall.h index 6c0b98b..178c823 100644 --- a/render_2D/render_2D/plottable/Waterfall.h +++ b/render_2D/render_2D/plottable/Waterfall.h @@ -8,6 +8,10 @@ namespace renderive { namespace detail { struct LIB_DECL Waterfall : Renderable { + using Base = Renderable; +protected: + struct Builder : Base::template next_Builder {}; +public: struct State; private: friend struct renderable::attach; @@ -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, Hover_Tooltip_Properties { + struct State : Base::template next_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 { - static void handle(Impl& impl, - const Renderable_Event_View& observation); + struct Observer : Base::template next_Observer { + State state; + std::size_t row_count{}; + std::size_t stored_point_count{}; + std::size_t rendered_cell_count{}; }; +private: + template using next_Builder = renderable_inheritance::Builder_Node; + template using next_State = renderable_inheritance::State_Node; + template using next_Impl = renderable_inheritance::Impl_Node; + template using next_Observer = renderable_inheritance::Observer_Node; + static_assert(inheritance::Defines_Chain_Layer, next_Builder, renderable_inheritance::Builder_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_State, renderable_inheritance::State_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_Observer, renderable_inheritance::Observer_Node>); +public: + [[nodiscard]] Observer observer() const; }; } using Waterfall = renderable::attach; diff --git a/render_2D/render_2D/renderable/Renderable.h b/render_2D/render_2D/renderable/Renderable.h index 72f8b38..2a6b013 100644 --- a/render_2D/render_2D/renderable/Renderable.h +++ b/render_2D/render_2D/renderable/Renderable.h @@ -27,11 +27,36 @@ enum struct Renderable_Observer_Event { }; struct LIB_DECL Renderable : renderable::render_base { -protected: - struct Impl; + using Render_Base = + renderable::render_base; public: - struct Observer : renderable_inheritance::Observer_Root {}; + struct Builder : Render_Base::template next_Builder {}; + struct Observer : renderable_inheritance::Observer_Root {}; +protected: + struct State : Render_Base::template next_State {}; + struct Impl; + template + using next_Builder = renderable_inheritance::Builder_Node; + template + using next_State = renderable_inheritance::State_Node; + template + using next_Impl = renderable_inheritance::Impl_Node; + template + using next_Observer = renderable_inheritance::Observer_Node; + + static_assert(inheritance::Defines_Chain_Layer< + Builder, Render_Base::template next_Builder, + next_Builder, + renderable_inheritance::Builder_Node< + inheritance::Chain_Probe, Builder>>); + static_assert(inheritance::Defines_Chain_Layer< + State, Render_Base::template next_State, + next_State, + 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; diff --git a/render_2D/render_2D/scene/Plot_Frame_Mode.h b/render_2D/render_2D/scene/Plot_Frame_Mode.h deleted file mode 100644 index 66c117f..0000000 --- a/render_2D/render_2D/scene/Plot_Frame_Mode.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include - -namespace renderive { - -enum class Plot_Frame_Mode : std::uint8_t { - Manual, - Low_Latency, - Playback, -}; - -} // namespace renderive diff --git a/render_2D/render_2D/scene/Render_Scene_2D.cpp b/render_2D/render_2D/scene/Render_Scene_2D.cpp index b2c9f8d..1334573 100644 --- a/render_2D/render_2D/scene/Render_Scene_2D.cpp +++ b/render_2D/render_2D/scene/Render_Scene_2D.cpp @@ -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, +struct detail::Render_Scene_2D::Impl +: detail::Render_Scene_2D::Base::next_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>; - using Observer = Render_Scene_2D::Observer; - explicit Impl(std::pmr::memory_resource& resource) - : next_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, + detail::Render_Scene_2D::next_Impl, + scene_inheritance::Impl_Node>); + Impl(std::pmr::memory_resource& resource, const State& state) + : Base::next_Impl(resource), scene_state(state), final_color_cache(resource) {} std::shared_ptr 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; std::atomic_bool active{}; }; -Render_Scene_2D::Render_Scene_2D(Plot_Scene_Options options) - : scene::scene_base( +detail::Render_Scene_2D::Render_Scene_2D( + const State& state, + std::shared_ptr frame_strategy) + : detail::Scene( *::renderive::memory_resource(Memory_Domain::Plot_Frame), std::make_unique( - *::renderive::memory_resource(Memory_Domain::Plot_Frame))) { + *::renderive::memory_resource(Memory_Domain::Plot_Frame), + state)) { auto& impl = d_func(); impl.frame_control = std::make_unique( - options.frame_mode, impl.memory_resource()); -} -Render_Scene_2D::~Render_Scene_2D() { - d_func().shutdown(); -} -std::unique_ptr -Render_Scene_2D::Builder::build() const { - auto result = std::unique_ptr( - 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( "validated plot root attachment failed"); - return result; +} +detail::Render_Scene_2D::~Render_Scene_2D() { + d_func().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().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().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 { - return d_func().frame_control->prepare(*this); -} -auto Render_Scene_2D::refresh_manual_frame() - -> Expected { - return d_func().frame_control->refresh(*this); -} -auto Render_Scene_2D::render_prepared_frame() - -> Expected { - return d_func().frame_control->render(*this); -} -bool Render_Scene_2D::discard_pending_frame() { - return d_func().frame_control->discard(*this); -} -auto Render_Scene_2D::render_frame(bool force) +auto detail::Render_Scene_2D::render_frame(bool force) -> Expected { 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().frame_control; + const auto runtime = d_func().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& consumer) { if (!consumer) return; @@ -230,32 +219,32 @@ void Render_Scene_2D::with_frame( auto lock = d_func().lock_render_idle(); consume(); } -void Render_Scene_2D::activate_view() { +void detail::Render_Scene_2D::activate_view() { d_func().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().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().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 sink) { auto& impl = d_func(); std::lock_guard lock(impl.control_mutex); impl.presentation_sink = std::move(sink); } std::shared_ptr -Render_Scene_2D::performance_overlay() const { +detail::Render_Scene_2D::performance_overlay() const { const auto& impl = d_func(); 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 overlay) { { auto& impl = d_func(); diff --git a/render_2D/render_2D/scene/Render_Scene_2D.h b/render_2D/render_2D/scene/Render_Scene_2D.h index ef089d5..ac19159 100644 --- a/render_2D/render_2D/scene/Render_Scene_2D.h +++ b/render_2D/render_2D/scene/Render_Scene_2D.h @@ -2,34 +2,17 @@ #include "../base/Types.h" #include "../event/Event.h" #include "../renderable/Renderable.h" -#include "Plot_Frame_Mode.h" #include -#include +#include #include +#include #include +#include #include #include -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 { +namespace detail { +template +struct Scene : ::renderive::scene::scene_base { + using Base = ::renderive::scene::scene_base; + template + using Business_Builder = + ::renderive::scene::Scene_Builder; +protected: + struct Builder : Base::template next_Builder {}; + struct State : Base::template next_State {}; + struct Impl : Base::template next_Impl { + using Base_Impl = typename Base::template next_Impl; + using Base_Impl::Base_Impl; + }; + struct Observer : Base::template next_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 + using next_Builder = ::renderive::scene_inheritance::Builder_Node< + Next, Builder>; + template + using next_State = ::renderive::scene_inheritance::State_Node< + Next, State>; + template + using next_Impl = ::renderive::scene_inheritance::Impl_Node< + Next, Impl>; + template + using next_Observer = ::renderive::scene_inheritance::Observer_Node< + Next, Observer>; + template + using next_Editor = ::renderive::scene_inheritance::Editor_Node< + Next, Renderable_Editor>; + + static_assert(inheritance::Defines_Chain_Layer, next_Builder, scene_inheritance::Builder_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_State, scene_inheritance::State_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_Impl, scene_inheritance::Impl_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_Observer, scene_inheritance::Observer_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_Editor, scene_inheritance::Editor_Node>); + using Base::Base; +}; +class LIB_DECL Render_Scene_2D : public Scene { + using Base = Scene; public: using Frame = Scene2D_Frame_Data; - struct State : next_State { +protected: + struct Builder : Base::template next_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 { 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::Observer { + struct Observer : Base::template next_Observer { + State state; + std::size_t renderable_count{}; double frequency_hz{}; std::uint64_t next_refresh_interval_ns{}; - }; - class Builder : public next_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 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; - [[nodiscard]] auto refresh_manual_frame() -> Expected; - [[nodiscard]] auto render_prepared_frame() -> Expected; - [[nodiscard]] auto discard_pending_frame() -> bool; [[nodiscard]] auto render_frame(bool force = false) -> Expected; void with_frame(const std::function& consumer); void activate_view(); @@ -108,11 +115,34 @@ public: void request_redraw() noexcept; void set_presentation_sink(std::weak_ptr sink); [[nodiscard]] std::shared_ptr performance_overlay() const; - void set_performance_overlay(std::shared_ptr overlay); + void set_performance_overlay( + std::shared_ptr overlay); ~Render_Scene_2D() override; private: + Render_Scene_2D( + const State& state, + std::shared_ptr frame_strategy); struct Impl; - explicit Render_Scene_2D(Plot_Scene_Options options); - friend struct scene::scene_base; + template using next_Builder = scene_inheritance::Builder_Node; + template using next_State = scene_inheritance::State_Node; + template using next_Impl = scene_inheritance::Impl_Node; + template using next_Observer = scene_inheritance::Observer_Node; + template using next_Editor = scene_inheritance::Editor_Node; + static_assert(inheritance::Defines_Chain_Layer, next_Builder, scene_inheritance::Builder_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_State, scene_inheritance::State_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_Observer, scene_inheritance::Observer_Node>); + static_assert(inheritance::Defines_Chain_Layer, next_Editor, scene_inheritance::Editor_Node>); + friend struct ::renderive::scene::attach; + friend struct ::renderive::scene::scene_base; }; +} // namespace detail +using Render_Scene_2D = +::renderive::scene::attach; +using Manual_Render_Scene_2D_Strategy = +Manual_Refresh_Strategy; +using Low_Latency_Render_Scene_2D_Strategy = +Low_Latency_Strategy; +using Playback_Render_Scene_2D_Strategy = +Flow_Refresh_Strategy; } // namespace renderive diff --git a/render_3D/render_3D/Point_Visual.cpp b/render_3D/render_3D/Point_Visual.cpp index 541b880..10941a5 100644 --- a/render_3D/render_3D/Point_Visual.cpp +++ b/render_3D/render_3D/Point_Visual.cpp @@ -54,9 +54,13 @@ void Point_Visual::State_Validator::operator()(const State& state) const { } } -struct Point_Visual::Impl : next_Impl, Point_Buffer_Strategy { +struct Point_Visual::Impl : Base::next_Impl, Point_Buffer_Strategy { using Observer = Point_Visual::Observer; - friend struct Point_Visual::Observer; + static_assert(::renderive::inheritance::Defines_Chain_Layer< + Impl, Base::next_Impl, + Point_Visual::next_Impl<::renderive::inheritance::Chain_Probe>, + ::renderive::renderable_inheritance::Impl_Node< + ::renderive::inheritance::Chain_Probe, Impl>>); explicit Impl(std::vector points) { if (update_points(std::move(points)) != Visual_Data_Error::none) @@ -195,11 +199,14 @@ struct Point_Visual::Impl : next_Impl, Point_Buffer_Strategy { context.publish(std::move(output)); } + void handle_observation( + const Renderable_Event_View& observation) noexcept; + }; -void Point_Visual::Observer::handle( - Impl& impl, const Renderable_Event_View& observation) noexcept { +void Point_Visual::Impl::handle_observation( + const Renderable_Event_View& observation) noexcept { if (observation.event == Renderable_Observer_Event::Published) - impl.Point_Buffer_Strategy::publish(); + Point_Buffer_Strategy::publish(); } Point_Visual::Point_Visual(const State& state, std::vector points) @@ -233,4 +240,13 @@ std::uint64_t Point_Visual::data_revision() const { return d_func().cache_revision(); } +Point_Visual::Observer Point_Visual::observer() const { + const auto value = Renderable::state(); + Observer result; + result.state = value; + result.point_count = point_count(); + result.data_revision = data_revision(); + return result; +} + } // namespace renderive::render_3d::detail diff --git a/render_3D/render_3D/Point_Visual.h b/render_3D/render_3D/Point_Visual.h index e1ff3aa..a09508c 100644 --- a/render_3D/render_3D/Point_Visual.h +++ b/render_3D/render_3D/Point_Visual.h @@ -63,7 +63,11 @@ struct Point_Style { namespace detail { struct Point_Visual : Renderable { - struct State : next_State { + using Base = Renderable; +protected: + struct Builder : Base::template next_Builder {}; +public: + struct State : Base::template next_State { Point_Style style; Matrix4 transform; bool visible{true}; @@ -111,10 +115,42 @@ protected: private: struct Impl; public: - struct Observer : next_Observer { - static void handle(Impl& impl, - const Renderable_Event_View& observation) noexcept; + struct Observer : Base::template next_Observer { + State state; + std::size_t point_count{}; + std::uint64_t data_revision{}; }; +private: + template + using next_Builder = + ::renderive::renderable_inheritance::Builder_Node; + template + using next_State = + ::renderive::renderable_inheritance::State_Node; + template + using next_Impl = + ::renderive::renderable_inheritance::Impl_Node; + template + using next_Observer = + ::renderive::renderable_inheritance::Observer_Node; + + static_assert(::renderive::inheritance::Defines_Chain_Layer< + Builder, Base::template next_Builder, + next_Builder<::renderive::inheritance::Chain_Probe>, + ::renderive::renderable_inheritance::Builder_Node< + ::renderive::inheritance::Chain_Probe, Builder>>); + static_assert(::renderive::inheritance::Defines_Chain_Layer< + State, Base::template next_State, + next_State<::renderive::inheritance::Chain_Probe>, + ::renderive::renderable_inheritance::State_Node< + ::renderive::inheritance::Chain_Probe, State>>); + static_assert(::renderive::inheritance::Defines_Chain_Layer< + Observer, Base::template next_Observer, + next_Observer<::renderive::inheritance::Chain_Probe>, + ::renderive::renderable_inheritance::Observer_Node< + ::renderive::inheritance::Chain_Probe, Observer>>); +public: + [[nodiscard]] Observer observer() const; }; } // namespace detail diff --git a/render_3D/render_3D/Render_Scene_3D.cpp b/render_3D/render_3D/Render_Scene_3D.cpp index 2133585..3c17c5c 100644 --- a/render_3D/render_3D/Render_Scene_3D.cpp +++ b/render_3D/render_3D/Render_Scene_3D.cpp @@ -120,33 +120,37 @@ struct Point_Backend_State final { } // namespace -struct Render_Scene_3D::Impl - : Render_Scene_3D::next_Impl, +void detail::Render_Scene_3D::State_Validator::operator()( + const State& state) const { + if (!valid(state.viewport)) + ::renderive::error::unexpected( + "Point_Scene viewport must be nonempty"); + if (!valid(state.clear_color)) + ::renderive::error::unexpected( + "Point_Scene clear color must be in [0, 1]"); +} + +struct detail::Render_Scene_3D::Impl + : detail::Render_Scene_3D::Base::next_Impl, Scene_Base::Impl::Frame_Control_Capability, Scene_Base::Impl::Scene_State_Capability, Scene_Base::Impl::Renderer { using State_Storage = Render_Acquired_State_Storage< State, Atomic_Spin_Mutex, Observer_State<>>; - using Observer = Render_Scene_3D::Observer; + using Observer = detail::Render_Scene_3D::Observer; + static_assert(::renderive::inheritance::Defines_Chain_Layer< + Impl, detail::Render_Scene_3D::Base::next_Impl, + detail::Render_Scene_3D::next_Impl< + ::renderive::inheritance::Chain_Probe>, + ::renderive::scene_inheritance::Impl_Node< + ::renderive::inheritance::Chain_Probe, Impl>>); - Impl(std::pmr::memory_resource& resource, const Scene_Options& options) - : next_Impl(resource), scene_state([&options] { - State state; - state.viewport = options.viewport; - state.clear_color = options.clear_color; - state.visual_family = options.visual_family; - return state; - }()), + Impl(std::pmr::memory_resource& resource, const State& state, + std::uint32_t gpu_index) + : Base::next_Impl(resource), scene_state(state), backend_state( - std::make_shared(options.gpu_index)) { - if (!valid(options.viewport)) - ::renderive::error::unexpected( - "Point_Scene viewport must be nonempty"); - if (!valid(options.clear_color)) - ::renderive::error::unexpected( - "Point_Scene clear color must be in [0, 1]"); - } + std::make_shared(gpu_index)) {} Scene_Control_Error dispatch_pointer( Render_Scene_3D& scene, ::renderive::Event_Type type, float x, @@ -454,28 +458,23 @@ struct Render_Scene_3D::Impl std::shared_ptr backend_state; }; -Render_Scene_3D::Render_Scene_3D(Scene_Options options) - : ::renderive::scene::scene_base( +detail::Render_Scene_3D::Render_Scene_3D( + const State& state, std::shared_ptr visual, + std::shared_ptr frame_strategy, + std::uint32_t gpu_index, bool validation_enabled) + : detail::Scene( *std::pmr::get_default_resource(), std::make_unique(*std::pmr::get_default_resource(), - options)) { - auto& impl = d_func(); - impl.frame_control = std::make_unique( - options.frame_mode, options.maximum_frames_per_second, - impl.memory_resource()); -} - -std::unique_ptr -Render_Scene_3D::Builder::build() const { - if (!visual_) + state, gpu_index)) { + if (!visual) ::renderive::error::unexpected( "Point_Scene requires a Point_Visual"); - auto result = std::unique_ptr( - new Render_Scene_3D(options_)); - auto& impl = result->d_func(); - impl.visual = visual_; + auto& impl = d_func(); + impl.frame_control = std::make_unique( + std::move(frame_strategy)); + impl.visual = std::move(visual); impl.point_id = impl.visual->renderable_id(); - const auto attachment = result->edit_renderables( + const auto attachment = edit_renderables( [&impl](Scene_3D_Base::Renderable_Editor& editor) { static_cast(editor.attach( renderive_Owner(impl.visual))); @@ -487,32 +486,34 @@ Render_Scene_3D::Builder::build() const { [](const State& value) { return value; }); const auto backend = impl.backend_state; const auto invocation = backend->render_domain->invoke( - [backend, options = options_, initial] { + [backend, gpu_index, validation_enabled, initial] { backend->backend = std::make_unique( - options.gpu_index, options.validation_enabled, - initial); + gpu_index, validation_enabled, initial); }); if (!invocation) ::renderive::error::unexpected( "render domain stopped during Point_Scene initialization"); +} + +detail::Render_Scene_3D::~Render_Scene_3D() { d_func().shutdown(); } + +detail::Render_Scene_3D::Observer +detail::Render_Scene_3D::observer() const { + const auto value = state(); + const auto& impl = d_func(); + const auto runtime = impl.frame_control->runtime(); + Observer result; + result.state = value; + result.renderable_count = Scene_Base::renderable_count(); + result.point_count = impl.visual->point_count(); + result.frequency_hz = runtime->frequency_hz(); + result.next_refresh_interval_ns = runtime->next_refresh_interval_ns(); + result.backend_available = impl.backend_state->backend_available(); return result; } -Render_Scene_3D::~Render_Scene_3D() { d_func().shutdown(); } - -Render_Scene_3D::Observer Render_Scene_3D::observer() const { - const auto& frame_control = *d_func().frame_control; - const auto runtime = frame_control.runtime(); - return { - {}, - frame_control.mode(), - runtime->frequency_hz(), - runtime->next_refresh_interval_ns(), - }; -} - -Scene_Control_Error Render_Scene_3D::dispatch( +Scene_Control_Error detail::Render_Scene_3D::dispatch( const ::renderive::Event& event) { if (const auto* wheel = dynamic_cast(&event)) { diff --git a/render_3D/render_3D/Render_Scene_3D.h b/render_3D/render_3D/Render_Scene_3D.h index d5abf2b..c5b5cad 100644 --- a/render_3D/render_3D/Render_Scene_3D.h +++ b/render_3D/render_3D/Render_Scene_3D.h @@ -1,39 +1,50 @@ #pragma once + #include "Point_Visual.h" + #include +#include +#include #include + #include #include #include -#include #include -class Scene_Base; + namespace renderive::render_3d { + struct Scene3D_Frame_Data : Abstract_Frame {}; + struct Extent { std::uint32_t width{}; std::uint32_t height{}; + [[nodiscard]] constexpr bool empty() const noexcept { return width == 0 || height == 0; } + bool operator==(const Extent&) const = default; }; + struct Clear_Color { float red{0.035F}; float green{0.045F}; float blue{0.07F}; float alpha{1.0F}; + bool operator==(const Clear_Color&) const = default; }; + enum class Scene_Control_Error : std::uint8_t { none, invalid_event, backend_unavailable }; + enum class Frame_Request_Result : std::uint8_t { none, painter_unavailable, - manual_refresh_not_supported, no_pending_frame, renderer_unavailable, cancelled, @@ -41,11 +52,7 @@ enum class Frame_Request_Result : std::uint8_t { external_failure, scene_shutting_down }; -enum class Frame_Mode : std::uint8_t { - Manual, - Low_Latency, - Playback, -}; + enum struct Visual_Family : std::uint8_t { Point, Splat, @@ -63,63 +70,149 @@ enum struct Visual_Family : std::uint8_t { Text, Volume, }; -struct Scene_Options { - Extent viewport{560, 320}; - Clear_Color clear_color; - Frame_Mode frame_mode{Frame_Mode::Low_Latency}; - double maximum_frames_per_second{60.0}; - std::uint32_t gpu_index{}; - bool validation_enabled{}; - Visual_Family visual_family{Visual_Family::Point}; -}; + struct Pixel_Frame { Extent extent; std::uint64_t sequence{}; std::vector rgba8; }; + +namespace detail { + +template +struct Scene : ::renderive::scene::scene_base { + using Base = ::renderive::scene::scene_base; + + template + using Business_Builder = + ::renderive::scene::Scene_Builder; + +protected: + struct Builder : Base::template next_Builder {}; + struct State : Base::template next_State {}; + struct Impl : Base::template next_Impl { + using Base_Impl = typename Base::template next_Impl; + using Base_Impl::Base_Impl; + }; + struct Observer : Base::template next_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 + using next_Builder = ::renderive::scene_inheritance::Builder_Node< + Next, Builder>; + + template + using next_State = ::renderive::scene_inheritance::State_Node< + Next, State>; + + template + using next_Impl = ::renderive::scene_inheritance::Impl_Node< + Next, Impl>; + + template + using next_Observer = ::renderive::scene_inheritance::Observer_Node< + Next, Observer>; + + template + using next_Editor = ::renderive::scene_inheritance::Editor_Node< + Next, Renderable_Editor>; + + static_assert(::renderive::inheritance::Defines_Chain_Layer, next_Builder<::renderive::inheritance::Chain_Probe>, ::renderive::scene_inheritance::Builder_Node<::renderive::inheritance::Chain_Probe, Builder>>); + static_assert(::renderive::inheritance::Defines_Chain_Layer, next_State<::renderive::inheritance::Chain_Probe>, ::renderive::scene_inheritance::State_Node<::renderive::inheritance::Chain_Probe, State>>); + static_assert(::renderive::inheritance::Defines_Chain_Layer, next_Impl<::renderive::inheritance::Chain_Probe>, ::renderive::scene_inheritance::Impl_Node<::renderive::inheritance::Chain_Probe, Impl>>); + static_assert(::renderive::inheritance::Defines_Chain_Layer, next_Observer<::renderive::inheritance::Chain_Probe>, ::renderive::scene_inheritance::Observer_Node<::renderive::inheritance::Chain_Probe, Observer>>); + static_assert(::renderive::inheritance::Defines_Chain_Layer, next_Editor<::renderive::inheritance::Chain_Probe>, ::renderive::scene_inheritance::Editor_Node<::renderive::inheritance::Chain_Probe, Renderable_Editor>>); + + using Base::Base; +}; + // Owns frame scheduling and the single Datoviz mutation/render domain. -class Render_Scene_3D final -: public ::renderive::scene::scene_base { +class Render_Scene_3D : public Scene { + using Base = Scene; public: using Frame = Scene3D_Frame_Data; - struct State : next_State { + +protected: + struct Builder : Base::template next_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 { Extent viewport{560, 320}; Clear_Color clear_color; Visual_Family visual_family{Visual_Family::Point}; + [[nodiscard]] bool operator==(const State& other) const { return viewport == other.viewport && clear_color == other.clear_color && visual_family == other.visual_family; } }; - struct Observer - : ::renderive::scene::scene_base::Observer { - Frame_Mode mode{Frame_Mode::Low_Latency}; + + struct State_Validator { + void operator()(const State& state) const; + }; + + template + using Business_Builder = ::renderive::scene::Scene_Builder< + Product, Properties, State_Validator>; + + struct Observer : Base::template next_Observer { + State state; + std::size_t renderable_count{}; + std::size_t point_count{}; double frequency_hz{}; std::uint64_t next_refresh_interval_ns{}; + bool backend_available{}; }; - class Builder : public next_Builder { - public: - explicit Builder(std::shared_ptr visual) - : visual_(std::move(visual)) {} - Builder& options(Scene_Options value) noexcept { - options_ = value; - return *this; - } - [[nodiscard]] std::unique_ptr build() const; - private: - std::shared_ptr visual_; - Scene_Options options_; - }; + [[nodiscard]] Observer observer() const; - [[nodiscard]] Scene_Control_Error dispatch(const ::renderive::Event& event); + [[nodiscard]] Scene_Control_Error dispatch( + const ::renderive::Event& event); ~Render_Scene_3D() override; + private: - explicit Render_Scene_3D(Scene_Options options); + Render_Scene_3D( + const State& state, std::shared_ptr visual, + std::shared_ptr frame_strategy, + std::uint32_t gpu_index = 0, bool validation_enabled = false); + struct Impl; + + template using next_Builder = ::renderive::scene_inheritance::Builder_Node; + template using next_State = ::renderive::scene_inheritance::State_Node; + template using next_Impl = ::renderive::scene_inheritance::Impl_Node; + template using next_Observer = ::renderive::scene_inheritance::Observer_Node; + template using next_Editor = ::renderive::scene_inheritance::Editor_Node; + static_assert(::renderive::inheritance::Defines_Chain_Layer, next_Builder<::renderive::inheritance::Chain_Probe>, ::renderive::scene_inheritance::Builder_Node<::renderive::inheritance::Chain_Probe, Builder>>); + static_assert(::renderive::inheritance::Defines_Chain_Layer, next_State<::renderive::inheritance::Chain_Probe>, ::renderive::scene_inheritance::State_Node<::renderive::inheritance::Chain_Probe, State>>); + static_assert(::renderive::inheritance::Defines_Chain_Layer, next_Observer<::renderive::inheritance::Chain_Probe>, ::renderive::scene_inheritance::Observer_Node<::renderive::inheritance::Chain_Probe, Observer>>); + static_assert(::renderive::inheritance::Defines_Chain_Layer, next_Editor<::renderive::inheritance::Chain_Probe>, ::renderive::scene_inheritance::Editor_Node<::renderive::inheritance::Chain_Probe, Renderable_Editor>>); + + friend struct ::renderive::scene::attach; friend struct ::renderive::scene::scene_base; }; + +} // namespace detail + +using Render_Scene_3D = + ::renderive::scene::attach; +using Manual_Render_Scene_3D_Strategy = + Manual_Refresh_Strategy; +using Low_Latency_Render_Scene_3D_Strategy = + Low_Latency_Strategy; +using Playback_Render_Scene_3D_Strategy = + Flow_Refresh_Strategy; + } // namespace renderive::render_3d diff --git a/render_3D/render_3D/frame_control/Point_Frame_Control.cpp b/render_3D/render_3D/frame_control/Point_Frame_Control.cpp index 51e4ebb..fcdf117 100644 --- a/render_3D/render_3D/frame_control/Point_Frame_Control.cpp +++ b/render_3D/render_3D/frame_control/Point_Frame_Control.cpp @@ -5,10 +5,7 @@ #include #include -#include -#include #include -#include #include namespace renderive::render_3d::detail { @@ -22,17 +19,11 @@ template decltype(auto) visit(Frame_Control_Strategy_Base& strategy, Function&& function) { if (auto* value = dynamic_cast(&strategy)) - return std::forward(function)( - *value, - std::integral_constant{}); + return std::forward(function)(*value); if (auto* value = dynamic_cast(&strategy)) - return std::forward(function)( - *value, - std::integral_constant{}); + return std::forward(function)(*value); if (auto* value = dynamic_cast(&strategy)) - return std::forward(function)( - *value, - std::integral_constant{}); + return std::forward(function)(*value); ::renderive::error::unexpected( "unknown Point_Scene frame strategy"); } @@ -41,50 +32,16 @@ template decltype(auto) visit(const Frame_Control_Strategy_Base& strategy, Function&& function) { if (const auto* value = dynamic_cast(&strategy)) - return std::forward(function)( - *value, - std::integral_constant{}); + return std::forward(function)(*value); if (const auto* value = dynamic_cast(&strategy)) - return std::forward(function)( - *value, - std::integral_constant{}); + return std::forward(function)(*value); if (const auto* value = dynamic_cast(&strategy)) - return std::forward(function)( - *value, - std::integral_constant{}); + return std::forward(function)(*value); ::renderive::error::unexpected( "unknown Point_Scene frame strategy"); } -std::shared_ptr -make_strategy(Frame_Mode mode, double maximum_frames_per_second, - std::pmr::memory_resource& memory_resource) { - switch (mode) { - case Frame_Mode::Manual: - return std::make_shared(); - case Frame_Mode::Low_Latency: - return std::make_shared( - Observer_State<>{}, - Low_Latency_Strategy_Type::Configuration{ - .frequency_hz = maximum_frames_per_second, - .replace_pending_frame = true}); - case Frame_Mode::Playback: - return std::make_shared( - memory_resource); - } - ::renderive::error::unexpected( - "unknown Point_Scene frame mode"); -} - -Frame_Mode strategy_mode(const Frame_Control_Strategy_Base& strategy) { - return visit(strategy, []( - const Strategy&, - std::integral_constant) { - return Mode; - }); -} - } // namespace struct Point_Frame_Control::Impl { @@ -92,10 +49,9 @@ struct Point_Frame_Control::Impl { }; Point_Frame_Control::Point_Frame_Control( - Frame_Mode mode, double maximum_frames_per_second, - std::pmr::memory_resource& memory_resource) + std::shared_ptr strategy) : impl_(std::make_unique()) { - replace(mode, maximum_frames_per_second, memory_resource); + replace(std::move(strategy)); } Point_Frame_Control::~Point_Frame_Control() = default; @@ -110,46 +66,25 @@ Point_Frame_Control::runtime() const { return impl_->strategy.load(std::memory_order_acquire); } -Frame_Request_Result Point_Frame_Control::prepare(Render_Scene_3D& scene) { +Frame_Request_Result Point_Frame_Control::request(Render_Scene_3D& scene) { const auto current = runtime(); - return visit(*current, [&scene](auto& strategy, auto) { + const auto prepared = visit(*current, [&scene](auto& strategy) { auto frame = strategy.acquire_painter(); if (!frame) - return Frame_Request_Result::painter_unavailable; + return false; scene.publish_frame_state(*frame); - return Frame_Request_Result::none; + return true; }); -} - -Frame_Request_Result Point_Frame_Control::refresh(Render_Scene_3D&) { - const auto current = runtime(); - auto* strategy = dynamic_cast(current.get()); - if (!strategy) - return Frame_Request_Result::manual_refresh_not_supported; - return strategy->refresh() == Manual_Refresh_Result::none - ? Frame_Request_Result::none - : Frame_Request_Result::no_pending_frame; -} - -bool Point_Frame_Control::discard(Render_Scene_3D&) { - const auto current = runtime(); - if (auto* strategy = dynamic_cast(current.get())) - return strategy->discard_pending_frame(); - if (auto* strategy = - dynamic_cast(current.get())) - return strategy->discard_pending_frame(); - return false; -} - -Frame_Request_Result Point_Frame_Control::render(Render_Scene_3D& scene) { - const auto current = runtime(); - return visit(*current, [&scene](auto& strategy, auto) { + if (!prepared) + return Frame_Request_Result::painter_unavailable; + if (auto* strategy = dynamic_cast(current.get()); + strategy && strategy->refresh() != Manual_Refresh_Result::none) + return Frame_Request_Result::no_pending_frame; + return visit(*current, [&scene](auto& strategy) { auto frame = strategy.acquire_renderer(); if (!frame) return Frame_Request_Result::renderer_unavailable; const auto result = scene.Scene_Base::render(*frame); - if (result == Scene_Render_Result::shutting_down) - return Frame_Request_Result::scene_shutting_down; const auto converted = adapter::enum_cast(result); if (!converted) @@ -159,32 +94,13 @@ Frame_Request_Result Point_Frame_Control::render(Render_Scene_3D& scene) { }); } -Frame_Request_Result Point_Frame_Control::request(Render_Scene_3D& scene) { - if (const auto result = prepare(scene); - result != Frame_Request_Result::none) - return result; - if (mode() == Frame_Mode::Manual) { - if (const auto result = refresh(scene); - result != Frame_Request_Result::none) - return result; - } - return render(scene); -} - -Frame_Mode Point_Frame_Control::mode() const { - return strategy_mode(*runtime()); -} - void Point_Frame_Control::replace( - Frame_Mode mode, double maximum_frames_per_second, - std::pmr::memory_resource& memory_resource) { - if (!std::isfinite(maximum_frames_per_second) || - maximum_frames_per_second <= 0.0) + std::shared_ptr strategy) { + if (!strategy) ::renderive::error::unexpected( - "Point_Scene frame frequency must be positive"); - impl_->strategy.store( - make_strategy(mode, maximum_frames_per_second, memory_resource), - std::memory_order_release); + "Point_Scene requires a frame strategy"); + visit(*strategy, [](const auto&) {}); + impl_->strategy.store(std::move(strategy), std::memory_order_release); } } // namespace renderive::render_3d::detail diff --git a/render_3D/render_3D/frame_control/Point_Frame_Control.h b/render_3D/render_3D/frame_control/Point_Frame_Control.h index f331401..22e30fe 100644 --- a/render_3D/render_3D/frame_control/Point_Frame_Control.h +++ b/render_3D/render_3D/frame_control/Point_Frame_Control.h @@ -3,14 +3,13 @@ #include "../Render_Scene_3D.h" #include -#include namespace renderive::render_3d::detail { class Point_Frame_Control final { public: - Point_Frame_Control(Frame_Mode mode, double maximum_frames_per_second, - std::pmr::memory_resource& memory_resource); + explicit Point_Frame_Control( + std::shared_ptr strategy); ~Point_Frame_Control(); Point_Frame_Control(const Point_Frame_Control&) = delete; @@ -21,14 +20,8 @@ public: [[nodiscard]] std::shared_ptr runtime(); [[nodiscard]] std::shared_ptr runtime() const; - [[nodiscard]] Frame_Request_Result prepare(Render_Scene_3D& scene); - [[nodiscard]] Frame_Request_Result refresh(Render_Scene_3D& scene); - [[nodiscard]] bool discard(Render_Scene_3D& scene); - [[nodiscard]] Frame_Request_Result render(Render_Scene_3D& scene); [[nodiscard]] Frame_Request_Result request(Render_Scene_3D& scene); - [[nodiscard]] Frame_Mode mode() const; - void replace(Frame_Mode mode, double maximum_frames_per_second, - std::pmr::memory_resource& memory_resource); + void replace(std::shared_ptr strategy); private: struct Impl; std::unique_ptr impl_; diff --git a/render_3D/render_3D/renderable/Inheritance.h b/render_3D/render_3D/renderable/Inheritance.h index f457661..17ac062 100644 --- a/render_3D/render_3D/renderable/Inheritance.h +++ b/render_3D/render_3D/renderable/Inheritance.h @@ -21,7 +21,14 @@ struct Renderable ::renderive::renderable::render_base; protected: + struct Builder + : Render_Base::template next_Builder {}; struct State : Render_Base::template next_State {}; + struct Impl : Render_Base::template next_Impl { + using Base_Impl = typename Render_Base::template next_Impl; + using Base_Impl::Base_Impl; + }; + struct Observer : Render_Base::template next_Observer {}; template using next_State = @@ -29,7 +36,38 @@ protected: template using next_Impl = ::renderive::renderable_inheritance::Impl_Node< - Next, typename Parent::Impl>; + Next, Impl>; + + template + using next_Observer = + ::renderive::renderable_inheritance::Observer_Node< + Next, Observer>; + + template + using next_Builder = + ::renderive::renderable_inheritance::Builder_Node< + Next, Builder>; + + static_assert(::renderive::inheritance::Defines_Chain_Layer< + Builder, Render_Base::template next_Builder, + next_Builder<::renderive::inheritance::Chain_Probe>, + ::renderive::renderable_inheritance::Builder_Node< + ::renderive::inheritance::Chain_Probe, Builder>>); + static_assert(::renderive::inheritance::Defines_Chain_Layer< + State, Render_Base::template next_State, + next_State<::renderive::inheritance::Chain_Probe>, + ::renderive::renderable_inheritance::State_Node< + ::renderive::inheritance::Chain_Probe, State>>); + static_assert(::renderive::inheritance::Defines_Chain_Layer< + Impl, Render_Base::template next_Impl, + next_Impl<::renderive::inheritance::Chain_Probe>, + ::renderive::renderable_inheritance::Impl_Node< + ::renderive::inheritance::Chain_Probe, Impl>>); + static_assert(::renderive::inheritance::Defines_Chain_Layer< + Observer, Render_Base::template next_Observer, + next_Observer<::renderive::inheritance::Chain_Probe>, + ::renderive::renderable_inheritance::Observer_Node< + ::renderive::inheritance::Chain_Probe, Observer>>); template using Business_Builder = diff --git a/render_3D/render_3D/renderable/Renderable.h b/render_3D/render_3D/renderable/Renderable.h index ea0df24..90ed549 100644 --- a/render_3D/render_3D/renderable/Renderable.h +++ b/render_3D/render_3D/renderable/Renderable.h @@ -29,13 +29,42 @@ struct Renderable_Event_View { struct Renderable : ::renderive::renderable::render_base { -protected: - struct Impl; + true> { + using Render_Base = ::renderive::renderable::render_base< + Renderable, ::Renderable_Base, true>; public: + struct Builder : Render_Base::template next_Builder {}; struct Observer - : ::renderive::renderable_inheritance::Observer_Root {}; + : ::renderive::renderable_inheritance::Observer_Root {}; +protected: + struct State : Render_Base::template next_State {}; + struct Impl; + template + using next_Builder = + ::renderive::renderable_inheritance::Builder_Node; + template + using next_State = + ::renderive::renderable_inheritance::State_Node; + template + using next_Impl = + ::renderive::renderable_inheritance::Impl_Node; + template + using next_Observer = + ::renderive::renderable_inheritance::Observer_Node; + + static_assert(::renderive::inheritance::Defines_Chain_Layer< + Builder, Render_Base::template next_Builder, + next_Builder<::renderive::inheritance::Chain_Probe>, + ::renderive::renderable_inheritance::Builder_Node< + ::renderive::inheritance::Chain_Probe, Builder>>); + static_assert(::renderive::inheritance::Defines_Chain_Layer< + State, Render_Base::template next_State, + next_State<::renderive::inheritance::Chain_Probe>, + ::renderive::renderable_inheritance::State_Node< + ::renderive::inheritance::Chain_Probe, State>>); + +public: Renderable(); ~Renderable() override; diff --git a/render_3D/render_3D/visuals/Basic_Visual.h b/render_3D/render_3D/visuals/Basic_Visual.h index 5288f83..b2c8bb2 100644 --- a/render_3D/render_3D/visuals/Basic_Visual.h +++ b/render_3D/render_3D/visuals/Basic_Visual.h @@ -31,6 +31,10 @@ struct Basic_Visual : Renderable> { ::Double_Buffer_Layout<::Buffered_Data, Payload>>, std::mutex, Observer_State<::Double_Buffer_Frame_Observer>>; +protected: + struct Builder + : Base::template next_Builder {}; +public: struct State : Base::template next_State, Spec::Settings { Matrix4 transform; bool visible{true}; @@ -76,7 +80,6 @@ struct Basic_Visual : Renderable> { struct Observer; struct Impl : Base::template next_Impl, Buffer { using Observer = Basic_Visual::Observer; - friend struct Basic_Visual::Observer; explicit Impl(std::vector items) { if (update(std::move(items)) != Visual_Data_Error::none) @@ -126,14 +129,52 @@ struct Basic_Visual : Renderable> { } context.template publish(input); } - }; - struct Observer : Impl::next_Observer { - static void handle(Impl& impl, - const Renderable_Event_View& observation) noexcept { + + void handle_observation( + const Renderable_Event_View& observation) noexcept { if (observation.event == Renderable_Observer_Event::Published) - impl.Buffer::publish(); + this->Buffer::publish(); } }; + struct Observer : Base::template next_Observer { + State state; + std::size_t item_count{}; + std::uint64_t data_revision{}; + }; + + template + using next_Builder = + ::renderive::renderable_inheritance::Builder_Node; + template + using next_State = + ::renderive::renderable_inheritance::State_Node; + template + using next_Impl = + ::renderive::renderable_inheritance::Impl_Node; + template + using next_Observer = + ::renderive::renderable_inheritance::Observer_Node; + + static_assert(::renderive::inheritance::Defines_Chain_Layer< + Builder, Base::template next_Builder, + next_Builder<::renderive::inheritance::Chain_Probe>, + ::renderive::renderable_inheritance::Builder_Node< + ::renderive::inheritance::Chain_Probe, Builder>>); + static_assert(::renderive::inheritance::Defines_Chain_Layer< + State, Base::template next_State, + next_State<::renderive::inheritance::Chain_Probe>, + ::renderive::renderable_inheritance::State_Node< + ::renderive::inheritance::Chain_Probe, State>>); + static_assert(::renderive::inheritance::Defines_Chain_Layer< + Impl, Base::template next_Impl, + next_Impl<::renderive::inheritance::Chain_Probe>, + ::renderive::renderable_inheritance::Impl_Node< + ::renderive::inheritance::Chain_Probe, Impl>>); + static_assert(::renderive::inheritance::Defines_Chain_Layer< + Observer, Base::template next_Observer, + next_Observer<::renderive::inheritance::Chain_Probe>, + ::renderive::renderable_inheritance::Observer_Node< + ::renderive::inheritance::Chain_Probe, Observer>>); private: friend struct ::renderive::renderable::attach; @@ -146,6 +187,15 @@ private: public: ~Basic_Visual() override = default; + [[nodiscard]] Observer observer() const { + const auto value = Base::template state(); + Observer result; + result.state = value; + result.item_count = item_count(); + result.data_revision = data_revision(); + return result; + } + [[nodiscard]] Visual_Data_Error update_items(std::vector items) { const auto error = this->template d_func().update(std::move(items)); if (error == Visual_Data_Error::none)