修改一些
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include "renderive/renderable/base/Renderive_Owner.hpp"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
class Renderable_Base;
|
||||
|
||||
namespace renderive {
|
||||
struct Renderable_Build_Relationship {
|
||||
std::weak_ptr<Renderable_Base> child;
|
||||
std::weak_ptr<Renderable_Base> parent;
|
||||
};
|
||||
|
||||
struct Renderable_Build_Topology {
|
||||
std::vector<Renderable_Build_Relationship> dependency;
|
||||
std::vector<Renderable_Build_Relationship> display;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
class Renderable_Build_Access {
|
||||
public:
|
||||
static void set_object_name(Renderable_Base& renderable, std::string name);
|
||||
static void set_topology(Renderable_Base& renderable,
|
||||
Renderable_Build_Topology topology);
|
||||
[[nodiscard]] static const Renderable_Build_Topology& topology(
|
||||
const Renderable_Base& renderable) noexcept;
|
||||
static void complete(Renderable_Base& renderable) noexcept;
|
||||
};
|
||||
|
||||
template <class Child, class Parent>
|
||||
[[nodiscard]] Renderable_Build_Relationship build_relationship(
|
||||
const renderive_Owner<Child>& child,
|
||||
const renderive_Owner<Parent>& parent) {
|
||||
return {child.share(), parent.share()};
|
||||
}
|
||||
} // namespace detail
|
||||
} // namespace renderive
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <renderive/error/Error_Policy.hpp>
|
||||
#include "Renderable_Base_p.hpp"
|
||||
#include "renderive/renderable/Renderable_Build.hpp"
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
@@ -223,15 +224,33 @@ bool Renderable_Base::is_visible() const noexcept {
|
||||
return d_func().visible.load(std::memory_order_acquire);
|
||||
}
|
||||
std::string Renderable_Base::object_name() const {
|
||||
const auto& implementation = d_func();
|
||||
std::lock_guard lock(implementation.metadata_mutex);
|
||||
return implementation.object_name;
|
||||
return d_func().object_name;
|
||||
}
|
||||
void Renderable_Base::set_object_name(std::string name) {
|
||||
auto& implementation = d_func();
|
||||
std::lock_guard lock(implementation.metadata_mutex);
|
||||
void renderive::detail::Renderable_Build_Access::set_object_name(
|
||||
Renderable_Base& renderable, std::string name) {
|
||||
auto& implementation = renderable.d_func();
|
||||
if (implementation.real_time_data_state->scene_lifetime)
|
||||
::renderive::error::unexpected<std::logic_error>(
|
||||
"object_name is immutable after scene construction");
|
||||
implementation.object_name = std::move(name);
|
||||
}
|
||||
void renderive::detail::Renderable_Build_Access::set_topology(
|
||||
Renderable_Base& renderable, renderive::Renderable_Build_Topology topology) {
|
||||
auto& implementation = renderable.d_func();
|
||||
if (implementation.real_time_data_state->scene_lifetime)
|
||||
::renderive::error::unexpected<std::logic_error>(
|
||||
"renderable build topology is immutable after scene construction");
|
||||
implementation.build_topology = std::move(topology);
|
||||
}
|
||||
const renderive::Renderable_Build_Topology&
|
||||
renderive::detail::Renderable_Build_Access::topology(
|
||||
const Renderable_Base& renderable) noexcept {
|
||||
return renderable.d_func().build_topology;
|
||||
}
|
||||
void renderive::detail::Renderable_Build_Access::complete(
|
||||
Renderable_Base& renderable) noexcept {
|
||||
renderable.d_func().build_topology = {};
|
||||
}
|
||||
void Renderable_Base::set_visible(bool visible) {
|
||||
d_func().set_visible(visible);
|
||||
}
|
||||
|
||||
@@ -14,13 +14,15 @@ class Scene_2D_Base;
|
||||
namespace renderive::inheritance {
|
||||
struct Observation_Source;
|
||||
}
|
||||
namespace renderive::detail {
|
||||
class Renderable_Build_Access;
|
||||
}
|
||||
class Renderable_Base {
|
||||
public:
|
||||
virtual ~Renderable_Base();
|
||||
[[nodiscard]] Renderable_Id renderable_id() const noexcept;
|
||||
[[nodiscard]] bool is_visible() const noexcept;
|
||||
[[nodiscard]] std::string object_name() const;
|
||||
void set_object_name(std::string name);
|
||||
void set_visible(bool visible);
|
||||
void discard_stale_frame_on_latest_data_update(bool enabled) noexcept;
|
||||
protected:
|
||||
@@ -53,5 +55,6 @@ private:
|
||||
friend class Real_Time_Data_Binding;
|
||||
friend class Scene_Base;
|
||||
friend class Scene_2D_Base;
|
||||
friend class renderive::detail::Renderable_Build_Access;
|
||||
std::unique_ptr<Impl> d_ptr;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "Renderable_Base.hpp"
|
||||
#include "renderive/renderable/Renderable_Build.hpp"
|
||||
#include "renderive/inheritance/Inheritance.hpp"
|
||||
#include "renderive/inheritance/Observation.hpp"
|
||||
#include <atomic>
|
||||
@@ -76,8 +77,8 @@ public:
|
||||
const Render_Node_Id composite_node_id;
|
||||
std::atomic<Renderable_Configuration> configuration;
|
||||
std::atomic<bool> visible{true};
|
||||
mutable std::mutex metadata_mutex;
|
||||
std::string object_name;
|
||||
renderive::Renderable_Build_Topology build_topology;
|
||||
std::mutex render_graph_mutex;
|
||||
std::shared_ptr<const Renderable_Graph> render_graph;
|
||||
std::unordered_map<std::string, Render_Node_Id> node_identities;
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
|
||||
enum class Scene_Build_Result : std::uint8_t {
|
||||
null_renderable,
|
||||
foreign_renderable,
|
||||
dependency_endpoint_missing,
|
||||
dependency_self_reference,
|
||||
dependency_cycle,
|
||||
display_endpoint_missing,
|
||||
display_self_reference,
|
||||
display_cycle
|
||||
};
|
||||
@@ -1,52 +1,163 @@
|
||||
#pragma once
|
||||
#include "renderive/base/adapter/Expected.hpp"
|
||||
#include "renderive/base/property/Concepts.hpp"
|
||||
#include "renderive/base/property/Validators.hpp"
|
||||
#include "renderive/error/Error_Policy.hpp"
|
||||
#include "renderive/renderable/base/Renderable_Base.hpp"
|
||||
#include "renderive/renderable/base/Renderive_Owner.hpp"
|
||||
#include "renderive/scene/Inheritance.hpp"
|
||||
#include "renderive/scene/Scene_Build_Result.hpp"
|
||||
#include "renderive/scene/base/Scene_Base.hpp"
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace renderive::scene::detail {
|
||||
struct Scene_Build_Access {
|
||||
[[nodiscard]] static auto build_initial_topology(
|
||||
Scene_Base& scene,
|
||||
const std::vector<Scene_Base::Renderable>& renderables)
|
||||
-> Expected<void, Scene_Build_Result> {
|
||||
return scene.build_initial_topology(renderables);
|
||||
}
|
||||
};
|
||||
} // namespace renderive::scene::detail
|
||||
|
||||
namespace renderive::scene {
|
||||
template <Property_Product Product_Type, Property_Set Properties_Type, Property_Validator<Properties_Type> Validator_Type = No_Property_Validator<Properties_Type>>
|
||||
template <Property_Product Product_Type, Property_Set Properties_Type,
|
||||
Property_Validator<Properties_Type> Validator_Type =
|
||||
No_Property_Validator<Properties_Type>>
|
||||
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<Validator> : constructor_(make_constructor()) {}
|
||||
template <class... Args> requires (sizeof...(Args) > 0) && std::default_initializable<Validator>
|
||||
explicit Scene_Builder(Args&&... args) : constructor_(make_constructor(std::forward<Args>(args)...)) {}
|
||||
template <auto Member, Property_Member_Assignable<Properties, Member> Value>
|
||||
using Renderable = Scene_Base::Renderable;
|
||||
|
||||
|
||||
Scene_Builder() requires std::default_initializable<Validator>
|
||||
: constructor_(make_constructor()) {}
|
||||
|
||||
template <class... Args>
|
||||
requires (sizeof...(Args) > 0) && std::default_initializable<Validator>
|
||||
explicit Scene_Builder(Args&&... args) {
|
||||
(collect_constructor_renderable(args), ...);
|
||||
constructor_ = make_constructor(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <auto Member,
|
||||
Property_Member_Assignable<Properties, Member> Value>
|
||||
Self& set(Value&& value) {
|
||||
properties_.*Member = std::forward<Value>(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <Property_Configurator<Properties> Configure>
|
||||
Self& configure(Configure&& configure) {
|
||||
std::invoke(std::forward<Configure>(configure), properties_);
|
||||
return *this;
|
||||
}
|
||||
[[nodiscard]] std::unique_ptr<Product> build() {
|
||||
|
||||
Self& add_renderable(Renderable renderable) {
|
||||
renderables_.push_back(std::move(renderable));
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Renderable_Type>
|
||||
requires std::derived_from<Renderable_Type, Renderable_Base>
|
||||
Self& add_renderable(const renderive_Owner<Renderable_Type>& renderable) {
|
||||
renderables_.emplace_back(renderable);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class Renderable_Type>
|
||||
requires std::derived_from<Renderable_Type, Renderable_Base>
|
||||
Self& add_renderable(const std::shared_ptr<Renderable_Type>& renderable) {
|
||||
renderables_.emplace_back(
|
||||
std::static_pointer_cast<Renderable_Base>(renderable));
|
||||
return *this;
|
||||
}
|
||||
|
||||
Self& add_renderables(std::vector<Renderable> renderables) {
|
||||
for (auto& renderable : renderables)
|
||||
renderables_.push_back(std::move(renderable));
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] const Properties& properties_value() const noexcept {
|
||||
return properties_;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto build()
|
||||
-> Expected<std::unique_ptr<Product>, Scene_Build_Result> {
|
||||
static_assert(std::derived_from<Product, Scene_Base>);
|
||||
validator_(properties_);
|
||||
auto construct = std::exchange(constructor_, {});
|
||||
return construct(properties_);
|
||||
if (!construct)
|
||||
::renderive::error::unexpected<std::logic_error>(
|
||||
"scene builder can only build once");
|
||||
|
||||
auto result = construct(properties_);
|
||||
if (!result)
|
||||
::renderive::error::unexpected<std::logic_error>(
|
||||
"scene constructor returned null");
|
||||
|
||||
auto topology = detail::Scene_Build_Access::build_initial_topology(
|
||||
*result, renderables_);
|
||||
if (!topology) return unexpected(topology.error());
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
protected:
|
||||
[[nodiscard]] const std::vector<Renderable>& renderables() const noexcept {
|
||||
return renderables_;
|
||||
}
|
||||
|
||||
private:
|
||||
using Constructor = std::function<std::unique_ptr<Product>(const Properties&)>;
|
||||
using Constructor =
|
||||
std::function<std::unique_ptr<Product>(const Properties&)>;
|
||||
|
||||
template <class... Args>
|
||||
static Constructor make_constructor(Args&&... args) {
|
||||
auto stored = std::make_shared<std::tuple<std::decay_t<Args>...>>(std::forward<Args>(args)...);
|
||||
return [stored = std::move(stored)](const Properties& properties) mutable {
|
||||
auto stored =
|
||||
std::make_shared<std::tuple<std::decay_t<Args>...>>(
|
||||
std::forward<Args>(args)...);
|
||||
return [stored = std::move(stored)](
|
||||
const Properties& properties) mutable {
|
||||
return std::apply(
|
||||
[&](auto&... values) {
|
||||
return scene_inheritance::Builder_Access::make<Product>(properties, std::move(values)...);
|
||||
return scene_inheritance::Builder_Access::make<Product>(
|
||||
properties, std::move(values)...);
|
||||
},
|
||||
*stored);
|
||||
};
|
||||
}
|
||||
|
||||
template <class Renderable_Type>
|
||||
requires std::derived_from<Renderable_Type, Renderable_Base>
|
||||
void collect_constructor_renderable(
|
||||
const renderive_Owner<Renderable_Type>& renderable) {
|
||||
add_renderable(renderable);
|
||||
}
|
||||
|
||||
template <class Renderable_Type>
|
||||
requires std::derived_from<Renderable_Type, Renderable_Base>
|
||||
void collect_constructor_renderable(
|
||||
const std::shared_ptr<Renderable_Type>& renderable) {
|
||||
add_renderable(renderable);
|
||||
}
|
||||
|
||||
template <class Value>
|
||||
void collect_constructor_renderable(const Value&) {}
|
||||
|
||||
Properties properties_{};
|
||||
[[no_unique_address]] Validator validator_{};
|
||||
Constructor constructor_;
|
||||
std::vector<Renderable> renderables_;
|
||||
};
|
||||
}
|
||||
} // namespace renderive::scene
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <vector>
|
||||
#include <oneapi/tbb/concurrent_queue.h>
|
||||
#include <oneapi/tbb/flow_graph.h>
|
||||
#include "renderive/renderable/Renderable_Build.hpp"
|
||||
#include "renderive/renderable/Render_Frame_Completion.hpp"
|
||||
#include "renderive/renderable/Renderive_Id_Allocator.hpp"
|
||||
#include "renderive/renderable/base/Renderable_Base_p.hpp"
|
||||
@@ -354,6 +355,111 @@ Scene_Base::Scene_Base(std::pmr::memory_resource& upstream_memory_resource,
|
||||
Scene_Base::~Scene_Base() {
|
||||
d_func().shutdown();
|
||||
}
|
||||
auto Scene_Base::build_initial_topology(
|
||||
const std::vector<Renderable>& renderables)
|
||||
-> renderive::Expected<void, Scene_Build_Result> {
|
||||
std::unordered_set<const Renderable_Base*> build_renderables;
|
||||
build_renderables.reserve(renderables.size());
|
||||
for (const auto& renderable : renderables) {
|
||||
if (!renderable)
|
||||
return renderive::unexpected(Scene_Build_Result::null_renderable);
|
||||
build_renderables.insert(renderable.get());
|
||||
}
|
||||
|
||||
auto& implementation = d_func();
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(implementation.task_mutex_);
|
||||
if (implementation.runtime_started_)
|
||||
::renderive::error::unexpected<std::logic_error>(
|
||||
"initial scene topology must be built before runtime starts");
|
||||
}
|
||||
|
||||
const Scene_Edit_Error edit_error = implementation.execute_renderable_edit(
|
||||
[&]() -> Scene_Edit_Error {
|
||||
Renderable_Editor editor(*this);
|
||||
for (const auto& renderable : renderables) {
|
||||
if (const auto error = editor.attach(renderable);
|
||||
error != Scene_Edit_Error::none)
|
||||
return error;
|
||||
}
|
||||
|
||||
for (const auto& renderable : renderables) {
|
||||
const auto& topology =
|
||||
renderive::detail::Renderable_Build_Access::topology(
|
||||
*renderable);
|
||||
for (const auto& relationship : topology.dependency) {
|
||||
auto child = relationship.child.lock();
|
||||
auto parent = relationship.parent.lock();
|
||||
if (!child || !parent ||
|
||||
!build_renderables.contains(child.get()) ||
|
||||
!build_renderables.contains(parent.get()))
|
||||
return Scene_Edit_Error::dangling_dependency;
|
||||
const auto error = editor.add_dependency_parent(
|
||||
Renderable(std::move(child)),
|
||||
Renderable(std::move(parent)));
|
||||
if (error != Scene_Edit_Error::none) return error;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& renderable : renderables) {
|
||||
const auto& topology =
|
||||
renderive::detail::Renderable_Build_Access::topology(
|
||||
*renderable);
|
||||
for (const auto& relationship : topology.display) {
|
||||
auto child = relationship.child.lock();
|
||||
auto parent = relationship.parent.lock();
|
||||
if (!child || !parent ||
|
||||
!build_renderables.contains(child.get()) ||
|
||||
!build_renderables.contains(parent.get()))
|
||||
return Scene_Edit_Error::dangling_display;
|
||||
auto* composition = implementation.composition();
|
||||
if (!composition) return Scene_Edit_Error::dangling_display;
|
||||
const auto error = composition->add_parent(
|
||||
child->renderable_id(), parent->renderable_id());
|
||||
if (error != Scene_Edit_Error::none) return error;
|
||||
}
|
||||
}
|
||||
return Scene_Edit_Error::none;
|
||||
});
|
||||
|
||||
if (edit_error == Scene_Edit_Error::none) {
|
||||
for (const auto& renderable : renderables)
|
||||
renderive::detail::Renderable_Build_Access::complete(*renderable);
|
||||
return {};
|
||||
}
|
||||
|
||||
switch (edit_error) {
|
||||
case Scene_Edit_Error::null_renderable:
|
||||
return renderive::unexpected(Scene_Build_Result::null_renderable);
|
||||
case Scene_Edit_Error::foreign_renderable:
|
||||
return renderive::unexpected(Scene_Build_Result::foreign_renderable);
|
||||
case Scene_Edit_Error::dependency_self_reference:
|
||||
return renderive::unexpected(
|
||||
Scene_Build_Result::dependency_self_reference);
|
||||
case Scene_Edit_Error::dependency_cycle:
|
||||
return renderive::unexpected(Scene_Build_Result::dependency_cycle);
|
||||
case Scene_Edit_Error::display_self_reference:
|
||||
return renderive::unexpected(
|
||||
Scene_Build_Result::display_self_reference);
|
||||
case Scene_Edit_Error::display_cycle:
|
||||
return renderive::unexpected(Scene_Build_Result::display_cycle);
|
||||
case Scene_Edit_Error::dangling_dependency:
|
||||
return renderive::unexpected(
|
||||
Scene_Build_Result::dependency_endpoint_missing);
|
||||
case Scene_Edit_Error::dangling_display:
|
||||
return renderive::unexpected(
|
||||
Scene_Build_Result::display_endpoint_missing);
|
||||
case Scene_Edit_Error::none:
|
||||
break;
|
||||
case Scene_Edit_Error::empty_edit:
|
||||
case Scene_Edit_Error::renderable_not_attached:
|
||||
case Scene_Edit_Error::shutting_down:
|
||||
::renderive::error::unexpected<std::logic_error>(
|
||||
"unexpected result while building initial scene topology");
|
||||
}
|
||||
::renderive::error::unexpected<std::logic_error>(
|
||||
"unhandled initial scene topology result");
|
||||
}
|
||||
Scene_Base::Attach_Builder::Attach_Builder(Scene_Base& scene) : scene_(scene), task_lock_(scene.d_func().task_mutex_) {
|
||||
if (scene.d_func().runtime_started_) ::renderive::error::unexpected<std::logic_error>("scene attach builder is only available before runtime starts");
|
||||
}
|
||||
@@ -1222,6 +1328,12 @@ std::shared_ptr<const Frame_Control_Strategy_Base> Scene_Base::frame_control_str
|
||||
void Scene_2D_Base::Impl::attach(Renderable_Id id) {
|
||||
if (!display_resolver_.contains(id)) display_resolver_.attach(id);
|
||||
}
|
||||
Scene_Edit_Error Scene_2D_Base::Impl::add_parent(
|
||||
Renderable_Id child, Renderable_Id parent) {
|
||||
const auto result = display_resolver_.add_parent(child, parent);
|
||||
if (!result) return relationship_error(result.error, true);
|
||||
return Scene_Edit_Error::none;
|
||||
}
|
||||
bool Scene_2D_Base::Impl::cleanup() {
|
||||
for (const Renderable_Id id : display_resolver_.ids()) {
|
||||
if (renderables_.contains(id)) continue;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
#include "renderive/base/adapter/Expected.hpp"
|
||||
#include "renderive/base/memory/Memory_Resource.hpp"
|
||||
#include "renderive/capture/Capture.hpp"
|
||||
#include "renderive/frame_control/base/Frame_Control_Strategy_Base.hpp"
|
||||
@@ -25,6 +26,7 @@
|
||||
#include "renderive/render_graph/External_Operation.hpp"
|
||||
#include "renderive/render_graph/Render_Plan.hpp"
|
||||
#include "renderive/scene/Inheritance.hpp"
|
||||
#include "renderive/scene/Scene_Build_Result.hpp"
|
||||
#include "renderive/scene/dependency/Dependency_Resolver.hpp"
|
||||
#include "Abstract_Frame.hpp"
|
||||
#include "Frame_Render_Snapshot.hpp"
|
||||
@@ -35,6 +37,9 @@
|
||||
namespace renderive::inheritance {
|
||||
struct Observation_Source;
|
||||
}
|
||||
namespace renderive::scene::detail {
|
||||
struct Scene_Build_Access;
|
||||
}
|
||||
class Color_Cache;
|
||||
enum class Scene_Render_Result : std::uint8_t {
|
||||
none,
|
||||
@@ -218,6 +223,10 @@ protected:
|
||||
return static_cast<const Implementation&>(*impl_);
|
||||
}
|
||||
private:
|
||||
[[nodiscard]] auto build_initial_topology(
|
||||
const std::vector<Renderable>& renderables)
|
||||
-> renderive::Expected<void, Scene_Build_Result>;
|
||||
friend struct renderive::scene::detail::Scene_Build_Access;
|
||||
friend class Renderable_Base;
|
||||
friend class Scene_2D_Base;
|
||||
std::unique_ptr<Impl> impl_;
|
||||
|
||||
@@ -25,6 +25,8 @@ public:
|
||||
struct Composition_Relationships {
|
||||
virtual ~Composition_Relationships() = default;
|
||||
virtual void attach(Renderable_Id id) = 0;
|
||||
[[nodiscard]] virtual Scene_Edit_Error add_parent(
|
||||
Renderable_Id child, Renderable_Id parent) = 0;
|
||||
[[nodiscard]] virtual bool cleanup() = 0;
|
||||
[[nodiscard]] virtual bool valid() const = 0;
|
||||
virtual renderive::scene::dependency::Resolution<Renderable_Id> resolve() const = 0;
|
||||
@@ -175,6 +177,8 @@ struct Scene_2D_Base::Impl
|
||||
[[nodiscard]] Scene_Edit_Error clear_display_parent_locked(
|
||||
const Renderable& child);
|
||||
void attach(Renderable_Id id) override;
|
||||
[[nodiscard]] Scene_Edit_Error add_parent(
|
||||
Renderable_Id child, Renderable_Id parent) override;
|
||||
[[nodiscard]] bool cleanup() override;
|
||||
[[nodiscard]] bool valid() const override;
|
||||
[[nodiscard]] renderive::scene::dependency::Resolution<Renderable_Id> resolve() const override;
|
||||
|
||||
Reference in New Issue
Block a user