528 lines
24 KiB
C++
528 lines
24 KiB
C++
#include <algorithm>
|
|
#include <utility>
|
|
#include "../base/Memory.h"
|
|
#include "../plot/Plot_Core.h"
|
|
#include "Renderable.h"
|
|
#include "Render_Time.h"
|
|
namespace renderive {
|
|
Renderable_Cache_Mode Renderable::get_cache_mode() const {
|
|
return cache_mode.load(std::memory_order_acquire);
|
|
}
|
|
void Renderable::set_cache_mode(Renderable_Cache_Mode mode) {
|
|
cache_mode.store(mode, std::memory_order_release);
|
|
mark_render_dirty();
|
|
}
|
|
bool Renderable::attached_to_plot() const {
|
|
return plot != nullptr;
|
|
}
|
|
bool Renderable::shares_plot_with(const Renderable& other) const {
|
|
return plot != nullptr && plot == other.plot;
|
|
}
|
|
const std::string& Renderable::object_name() const {
|
|
return object_name_;
|
|
}
|
|
void Renderable::set_object_name(std::string name) {
|
|
object_name_ = std::move(name);
|
|
}
|
|
bool Renderable::is_visible() const {
|
|
return visible_;
|
|
}
|
|
void Renderable::set_visible(bool value) {
|
|
if (visible_ == value)
|
|
return;
|
|
visible_ = value;
|
|
mark_render_dirty();
|
|
}
|
|
bool Renderable::should_prepare() const {
|
|
return !get_retiring() && visible_ && d_ptr;
|
|
}
|
|
void Renderable::detach_from_parent() {
|
|
if (auto parent = parent_renderable.lock())
|
|
parent->remove_child(shared_from_this());
|
|
}
|
|
std::string Renderable::cache_parent_object_name() const {
|
|
std::shared_ptr<Renderable> parent = parent_renderable.lock();
|
|
while (parent) {
|
|
if (parent->get_cache_mode() == Renderable_Cache_Mode::Local_Pixel)
|
|
return parent->object_name_;
|
|
parent = parent->parent_renderable.lock();
|
|
}
|
|
return {};
|
|
}
|
|
int Renderable::cache_tree_depth() const {
|
|
int depth = 0;
|
|
std::shared_ptr<Renderable> parent = parent_renderable.lock();
|
|
while (parent) {
|
|
if (parent->get_cache_mode() == Renderable_Cache_Mode::Local_Pixel)
|
|
++depth;
|
|
parent = parent->parent_renderable.lock();
|
|
}
|
|
return depth;
|
|
}
|
|
std::string Renderable::render_parent_object_name() const {
|
|
if (auto parent = parent_renderable.lock())
|
|
return parent->object_name_;
|
|
return {};
|
|
}
|
|
int Renderable::render_tree_depth() const {
|
|
int depth = 0;
|
|
std::shared_ptr<Renderable> parent = parent_renderable.lock();
|
|
while (parent) {
|
|
++depth;
|
|
parent = parent->parent_renderable.lock();
|
|
}
|
|
return depth;
|
|
}
|
|
void Renderable::init_root(Plot_Core* plot) {
|
|
if (!plot) {
|
|
ASSERT(plot, "Renderable root init error! plot == nullptr");
|
|
return;
|
|
}
|
|
bool initialized = this->initialized.exchange(true, std::memory_order_acq_rel);
|
|
if (initialized) {
|
|
ASSERT(!initialized, "Renderable root init error! Renderable already initialized");
|
|
return;
|
|
}
|
|
init_common(plot);
|
|
}
|
|
void Renderable::init(const std::shared_ptr<Renderable>& parent) {
|
|
if (!parent || !parent->plot) {
|
|
ASSERT(parent && parent->plot, "Renderable init error! parent invalid");
|
|
return;
|
|
}
|
|
bool initialized = this->initialized.exchange(true, std::memory_order_acq_rel);
|
|
if (initialized) {
|
|
ASSERT(!initialized, "Renderable init error! Renderable already initialized");
|
|
return;
|
|
}
|
|
init_common(parent->plot);
|
|
parent->add_child(shared_from_this());
|
|
}
|
|
void Renderable::init_common(Plot_Core* plot) {
|
|
this->plot = plot;
|
|
plot_context = plot->render_context();
|
|
retiring.store(false, std::memory_order_release);
|
|
if (!d_ptr) {
|
|
d_owner = create_render_data();
|
|
d_ptr = d_owner.get<Render_Data>();
|
|
}
|
|
d_ptr->clear_state_buffers();
|
|
d_ptr->clear_input_buffers();
|
|
d_ptr->state_buffer_owners[State_Edit] = create_render_state();
|
|
d_ptr->state_buffer_owners[State_Ready] = create_render_state();
|
|
d_ptr->state_buffer_owners[State_Render] = create_render_state();
|
|
d_ptr->state_buffers[State_Edit] = d_ptr->state_buffer_owners[State_Edit].get<Render_State>();
|
|
d_ptr->state_buffers[State_Ready] = d_ptr->state_buffer_owners[State_Ready].get<Render_State>();
|
|
d_ptr->state_buffers[State_Render] = d_ptr->state_buffer_owners[State_Render].get<Render_State>();
|
|
d_ptr->input_buffer_owners[Input_Edit] = create_input_data();
|
|
d_ptr->input_buffer_owners[Input_Ready] = create_input_data();
|
|
d_ptr->input_buffer_owners[Input_Render] = create_input_data();
|
|
d_ptr->input_buffers[Input_Edit].data = d_ptr->input_buffer_owners[Input_Edit].get<Input_Data>();
|
|
d_ptr->input_buffers[Input_Ready].data = d_ptr->input_buffer_owners[Input_Ready].get<Input_Data>();
|
|
d_ptr->input_buffers[Input_Render].data = d_ptr->input_buffer_owners[Input_Render].get<Input_Data>();
|
|
d_ptr->q_ptr = this;
|
|
d_ptr->state_buffers[State_Edit]->version = 1;
|
|
plot->mark_render_state_dirty();
|
|
}
|
|
void Renderable::add_child(const std::shared_ptr<Renderable>& child) {
|
|
if (!child || child.get() == this || child->plot != plot || !child->parent_renderable.expired() || get_retiring() || child->get_retiring()) {
|
|
ASSERT(child && child.get() != this && child->plot == plot && child->parent_renderable.expired() && !get_retiring() && !child->get_retiring(), "Renderable add_child error! invalid child");
|
|
return;
|
|
}
|
|
{
|
|
std::lock_guard<std::mutex> lock(children_mutex);
|
|
if (get_retiring())
|
|
return;
|
|
if (std::find(children.begin(), children.end(), child) != children.end())
|
|
return;
|
|
child->parent_renderable = shared_from_this();
|
|
children.push_back(child);
|
|
}
|
|
// Marking dirty may render synchronously, so the child list lock must be released first.
|
|
mark_render_dirty();
|
|
}
|
|
void Renderable::remove_child(const std::shared_ptr<Renderable>& child) {
|
|
if (!child || child->parent_renderable.lock().get() != this)
|
|
return;
|
|
std::shared_ptr<Renderable> removed;
|
|
{
|
|
std::lock_guard<std::mutex> lock(children_mutex);
|
|
auto it = std::find(children.begin(), children.end(), child);
|
|
if (it == children.end())
|
|
return;
|
|
removed = *it;
|
|
removed->parent_renderable.reset();
|
|
children.erase(it);
|
|
}
|
|
removed->detach_from_plot_tree();
|
|
mark_render_dirty();
|
|
}
|
|
std::vector<std::shared_ptr<Renderable>> Renderable::children_snapshot() const {
|
|
std::lock_guard<std::mutex> lock(children_mutex);
|
|
return children;
|
|
}
|
|
void Renderable::append_tree_snapshot(Renderable_Tree_Snapshot& snapshot, const std::string& parent_object_name, int render_tree_depth, const std::string& cache_parent_object_name, int cache_tree_depth) {
|
|
std::size_t index = snapshot.size();
|
|
Renderable_Cache_Mode mode = get_cache_mode();
|
|
snapshot.push_back(Renderable_Tree_Node{
|
|
shared_from_this(),
|
|
index + 1,
|
|
parent_object_name,
|
|
render_tree_depth,
|
|
cache_parent_object_name,
|
|
cache_tree_depth
|
|
});
|
|
std::string child_cache_parent = cache_parent_object_name;
|
|
int child_cache_depth = cache_tree_depth;
|
|
if (mode == Renderable_Cache_Mode::Local_Pixel) {
|
|
child_cache_parent = object_name_;
|
|
++child_cache_depth;
|
|
}
|
|
std::vector<std::shared_ptr<Renderable>> children = children_snapshot();
|
|
for (const auto& child : children) {
|
|
if (child)
|
|
child->append_tree_snapshot(snapshot, object_name_, render_tree_depth + 1, child_cache_parent, child_cache_depth);
|
|
}
|
|
snapshot[index].subtree_end = snapshot.size();
|
|
}
|
|
std::vector<std::shared_ptr<Renderable>> Renderable::hit_renderables(const PointF& pos) {
|
|
std::vector<std::shared_ptr<Renderable>> hits;
|
|
append_hit_renderables(hits, pos);
|
|
return hits;
|
|
}
|
|
void Renderable::append_hit_renderables(std::vector<std::shared_ptr<Renderable>>& hits, const PointF& pos) {
|
|
if (get_retiring() || !visible_)
|
|
return;
|
|
std::vector<std::shared_ptr<Renderable>> children = children_snapshot();
|
|
for (int i = static_cast<int>(children.size()) - 1; i >= 0; --i) {
|
|
const auto& child = children.at(i);
|
|
if (child)
|
|
child->append_hit_renderables(hits, pos);
|
|
}
|
|
if (select_test(pos))
|
|
hits.push_back(shared_from_this());
|
|
}
|
|
void Renderable::render(Canvas& canvas, const Plot_Render_Snapshot& snapshot) {
|
|
if (get_retiring() || !visible_)
|
|
return;
|
|
Renderable_Cache_Mode mode = get_cache_mode();
|
|
std::uint64_t begin_time = steady_now_ns();
|
|
if (mode == Renderable_Cache_Mode::Local_Pixel)
|
|
render_cached(canvas, snapshot);
|
|
else
|
|
render_direct(canvas, snapshot);
|
|
if (snapshot.frame_metadata)
|
|
snapshot.frame_metadata->record_renderable_render(object_name_, render_parent_object_name(), render_tree_depth(), mode, steady_now_ns() - begin_time);
|
|
}
|
|
void Renderable::render_tree_snapshot(Canvas& canvas, const Plot_Render_Snapshot& snapshot, const Renderable_Tree_Snapshot& tree, std::size_t index) {
|
|
render_tree_node(canvas, snapshot, tree, index);
|
|
}
|
|
void Renderable::render_direct(Canvas& canvas, const Plot_Render_Snapshot& snapshot) {
|
|
render_self(canvas, snapshot);
|
|
render_children(canvas, snapshot);
|
|
}
|
|
void Renderable::render_children(Canvas& canvas, const Plot_Render_Snapshot& snapshot) {
|
|
std::vector<std::shared_ptr<Renderable>> children = children_snapshot();
|
|
for (const auto& child : children) {
|
|
if (child)
|
|
child->render(canvas, snapshot);
|
|
}
|
|
}
|
|
void Renderable::render_cached(Canvas& canvas, const Plot_Render_Snapshot& snapshot) {
|
|
Size size = snapshot.size;
|
|
Rect bounds = d_ptr ? d_ptr->pixel_bounds(size).intersected(Rect{0, 0, size.width, size.height}) : Rect{0, 0, size.width, size.height};
|
|
if (bounds.empty())
|
|
return;
|
|
std::uint64_t edit_version = cache_edit_version.load(std::memory_order_acquire);
|
|
std::string parent_object_name = cache_parent_object_name();
|
|
int tree_depth = cache_tree_depth();
|
|
bool ready = cache_ready_version.load(std::memory_order_acquire) == edit_version && cache_image.size() == Size{bounds.width, bounds.height} && cache_bounds.x == bounds.x && cache_bounds.y == bounds.y && cache_bounds.width == bounds.width && cache_bounds.height == bounds.height;
|
|
if (ready) {
|
|
if (snapshot.frame_metadata)
|
|
snapshot.frame_metadata->record_renderable_cache_hit(object_name_, parent_object_name, tree_depth);
|
|
std::uint64_t begin_time = steady_now_ns();
|
|
canvas.draw_image(RectF{static_cast<double>(bounds.x), static_cast<double>(bounds.y), static_cast<double>(cache_image.width()), static_cast<double>(cache_image.height())}, cache_image);
|
|
if (snapshot.frame_metadata)
|
|
snapshot.frame_metadata->record_renderable_cache_compose(object_name_, parent_object_name, tree_depth, steady_now_ns() - begin_time, static_cast<std::uint64_t>(cache_image.byte_size()), static_cast<std::uint64_t>(bounds.width) * static_cast<std::uint64_t>(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire));
|
|
return;
|
|
}
|
|
if (snapshot.frame_metadata)
|
|
snapshot.frame_metadata->record_renderable_cache_miss(object_name_, parent_object_name, tree_depth);
|
|
std::uint64_t rebuild_begin_time = steady_now_ns();
|
|
render_cache_image(bounds, snapshot, edit_version);
|
|
if (snapshot.frame_metadata)
|
|
snapshot.frame_metadata->record_renderable_cache_rebuild(object_name_, parent_object_name, tree_depth, steady_now_ns() - rebuild_begin_time, cache_image.empty() ? 0 : static_cast<std::uint64_t>(cache_image.byte_size()), static_cast<std::uint64_t>(bounds.width) * static_cast<std::uint64_t>(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire));
|
|
if (!cache_image.empty()) {
|
|
std::uint64_t begin_time = steady_now_ns();
|
|
canvas.draw_image(RectF{static_cast<double>(bounds.x), static_cast<double>(bounds.y), static_cast<double>(cache_image.width()), static_cast<double>(cache_image.height())}, cache_image);
|
|
if (snapshot.frame_metadata)
|
|
snapshot.frame_metadata->record_renderable_cache_compose(object_name_, parent_object_name, tree_depth, steady_now_ns() - begin_time, static_cast<std::uint64_t>(cache_image.byte_size()), static_cast<std::uint64_t>(bounds.width) * static_cast<std::uint64_t>(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire));
|
|
}
|
|
}
|
|
std::size_t Renderable::render_tree_node(Canvas& canvas, const Plot_Render_Snapshot& snapshot, const Renderable_Tree_Snapshot& tree, std::size_t index) {
|
|
if (index >= tree.size())
|
|
return tree.size();
|
|
const Renderable_Tree_Node& node = tree[index];
|
|
Renderable* current = node.renderable.get();
|
|
if (!current)
|
|
return std::max(index + 1, node.subtree_end);
|
|
if (current != this)
|
|
return current->render_tree_node(canvas, snapshot, tree, index);
|
|
if (get_retiring() || !visible_)
|
|
return std::max(index + 1, node.subtree_end);
|
|
Renderable_Cache_Mode mode = get_cache_mode();
|
|
std::uint64_t begin_time = steady_now_ns();
|
|
if (mode == Renderable_Cache_Mode::Local_Pixel)
|
|
render_cached_tree_node(canvas, snapshot, tree, index);
|
|
else
|
|
render_direct_tree_node(canvas, snapshot, tree, index);
|
|
if (snapshot.frame_metadata)
|
|
snapshot.frame_metadata->record_renderable_render(object_name_, node.parent_object_name, node.render_tree_depth, mode, steady_now_ns() - begin_time);
|
|
return std::max(index + 1, node.subtree_end);
|
|
}
|
|
void Renderable::render_direct_tree_node(Canvas& canvas, const Plot_Render_Snapshot& snapshot, const Renderable_Tree_Snapshot& tree, std::size_t index) {
|
|
render_self(canvas, snapshot, &tree[index]);
|
|
std::size_t child_index = index + 1;
|
|
while (child_index < tree[index].subtree_end && child_index < tree.size()) {
|
|
auto child = tree[child_index].renderable;
|
|
if (!child) {
|
|
++child_index;
|
|
continue;
|
|
}
|
|
child_index = child->render_tree_node(canvas, snapshot, tree, child_index);
|
|
}
|
|
}
|
|
void Renderable::render_cached_tree_node(Canvas& canvas, const Plot_Render_Snapshot& snapshot, const Renderable_Tree_Snapshot& tree, std::size_t index) {
|
|
Size size = snapshot.size;
|
|
Rect bounds = d_ptr ? d_ptr->pixel_bounds(size).intersected(Rect{0, 0, size.width, size.height}) : Rect{0, 0, size.width, size.height};
|
|
if (bounds.empty())
|
|
return;
|
|
const Renderable_Tree_Node& node = tree[index];
|
|
std::uint64_t edit_version = cache_edit_version.load(std::memory_order_acquire);
|
|
bool ready = cache_ready_version.load(std::memory_order_acquire) == edit_version && cache_image.size() == Size{bounds.width, bounds.height} && cache_bounds.x == bounds.x && cache_bounds.y == bounds.y && cache_bounds.width == bounds.width && cache_bounds.height == bounds.height;
|
|
if (ready) {
|
|
if (snapshot.frame_metadata)
|
|
snapshot.frame_metadata->record_renderable_cache_hit(object_name_, node.cache_parent_object_name, node.cache_tree_depth);
|
|
std::uint64_t begin_time = steady_now_ns();
|
|
canvas.draw_image(RectF{static_cast<double>(bounds.x), static_cast<double>(bounds.y), static_cast<double>(cache_image.width()), static_cast<double>(cache_image.height())}, cache_image);
|
|
if (snapshot.frame_metadata)
|
|
snapshot.frame_metadata->record_renderable_cache_compose(object_name_, node.cache_parent_object_name, node.cache_tree_depth, steady_now_ns() - begin_time, static_cast<std::uint64_t>(cache_image.byte_size()), static_cast<std::uint64_t>(bounds.width) * static_cast<std::uint64_t>(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire));
|
|
return;
|
|
}
|
|
if (snapshot.frame_metadata)
|
|
snapshot.frame_metadata->record_renderable_cache_miss(object_name_, node.cache_parent_object_name, node.cache_tree_depth);
|
|
std::uint64_t rebuild_begin_time = steady_now_ns();
|
|
render_cache_image_tree_node(bounds, snapshot, tree, index, edit_version);
|
|
if (snapshot.frame_metadata)
|
|
snapshot.frame_metadata->record_renderable_cache_rebuild(object_name_, node.cache_parent_object_name, node.cache_tree_depth, steady_now_ns() - rebuild_begin_time, cache_image.empty() ? 0 : static_cast<std::uint64_t>(cache_image.byte_size()), static_cast<std::uint64_t>(bounds.width) * static_cast<std::uint64_t>(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire));
|
|
if (!cache_image.empty()) {
|
|
std::uint64_t begin_time = steady_now_ns();
|
|
canvas.draw_image(RectF{static_cast<double>(bounds.x), static_cast<double>(bounds.y), static_cast<double>(cache_image.width()), static_cast<double>(cache_image.height())}, cache_image);
|
|
if (snapshot.frame_metadata)
|
|
snapshot.frame_metadata->record_renderable_cache_compose(object_name_, node.cache_parent_object_name, node.cache_tree_depth, steady_now_ns() - begin_time, static_cast<std::uint64_t>(cache_image.byte_size()), static_cast<std::uint64_t>(bounds.width) * static_cast<std::uint64_t>(bounds.height), edit_version, cache_ready_version.load(std::memory_order_acquire));
|
|
}
|
|
}
|
|
void Renderable::render_cache_image_tree_node(const Rect& bounds, const Plot_Render_Snapshot& snapshot, const Renderable_Tree_Snapshot& tree, std::size_t index, std::uint64_t version) {
|
|
if (get_retiring())
|
|
return;
|
|
Image temp_image;
|
|
temp_image.resize(bounds.width, bounds.height);
|
|
temp_image.fill(Color::transparent());
|
|
{
|
|
Canvas cache_canvas(temp_image);
|
|
cache_canvas.translate(static_cast<double>(-bounds.x), static_cast<double>(-bounds.y));
|
|
render_direct_tree_node(cache_canvas, snapshot, tree, index);
|
|
}
|
|
cache_bounds = bounds;
|
|
this->cache_image = std::move(temp_image);
|
|
cache_ready_version.store(version, std::memory_order_release);
|
|
}
|
|
void Renderable::render_cache_image(const Rect& bounds, const Plot_Render_Snapshot& snapshot, std::uint64_t version) {
|
|
if (get_retiring())
|
|
return;
|
|
Image temp_image;
|
|
temp_image.resize(bounds.width, bounds.height);
|
|
temp_image.fill(Color::transparent());
|
|
{
|
|
Canvas cache_canvas(temp_image);
|
|
cache_canvas.translate(static_cast<double>(-bounds.x), static_cast<double>(-bounds.y));
|
|
render_direct(cache_canvas, snapshot);
|
|
}
|
|
cache_bounds = bounds;
|
|
this->cache_image = std::move(temp_image);
|
|
cache_ready_version.store(version, std::memory_order_release);
|
|
}
|
|
void Renderable::render_self(Canvas& canvas, const Plot_Render_Snapshot& snapshot) {
|
|
render_self(canvas, snapshot, nullptr);
|
|
}
|
|
void Renderable::render_self(Canvas& canvas, const Plot_Render_Snapshot& snapshot, const Renderable_Tree_Node* node) {
|
|
if (!d_ptr)
|
|
return;
|
|
auto lease = d_ptr->try_mark_state_role(State_Render);
|
|
if (!lease)
|
|
return;
|
|
Renderable_Cache_Mode mode = get_cache_mode();
|
|
std::uint64_t begin_time = steady_now_ns();
|
|
draw(canvas, snapshot);
|
|
std::uint64_t draw_time = steady_now_ns() - begin_time;
|
|
d_ptr->unmark_state(lease);
|
|
if (snapshot.frame_metadata) {
|
|
const std::string& parent_name = node ? node->parent_object_name : render_parent_object_name();
|
|
int depth = node ? node->render_tree_depth : render_tree_depth();
|
|
snapshot.frame_metadata->record_renderable_self_draw(object_name_, parent_name, depth, mode, draw_time);
|
|
}
|
|
}
|
|
void Renderable::draw(Canvas& canvas, const Plot_Render_Snapshot& snapshot) {
|
|
if (get_retiring())
|
|
return;
|
|
d_ptr->draw(canvas, snapshot);
|
|
}
|
|
void Renderable::prepare_data(const Plot_Render_Snapshot& snapshot) {
|
|
if (get_retiring())
|
|
return;
|
|
d_ptr->prepare_data(snapshot);
|
|
if (snapshot.frame_update_states)
|
|
d_ptr->drain_committed_update_states(*snapshot.frame_update_states);
|
|
}
|
|
bool Renderable::select_test(const PointF& pos) {
|
|
if (get_retiring())
|
|
return false;
|
|
auto* hit_testable = dynamic_cast<Hit_Testable*>(d_ptr);
|
|
return hit_testable && hit_testable->select_test(pos);
|
|
}
|
|
void Renderable::plot_event(const Event& event) {
|
|
if (get_retiring() || event.is_accepted())
|
|
return;
|
|
switch (event.type) {
|
|
case Event_Type::Resize:
|
|
resize_event(static_cast<const Resize_Event&>(event));
|
|
break;
|
|
case Event_Type::Pointer_Move:
|
|
mouse_move_event(static_cast<const Pointer_Event&>(event));
|
|
break;
|
|
case Event_Type::Pointer_Press:
|
|
mouse_press_event(static_cast<const Pointer_Event&>(event));
|
|
break;
|
|
case Event_Type::Pointer_Release:
|
|
mouse_release_event(static_cast<const Pointer_Event&>(event));
|
|
break;
|
|
case Event_Type::Wheel:
|
|
wheel_event(static_cast<const Wheel_Event&>(event));
|
|
break;
|
|
case Event_Type::Key_Press:
|
|
key_press_event(static_cast<const Key_Event&>(event));
|
|
break;
|
|
case Event_Type::Key_Release:
|
|
key_release_event(static_cast<const Key_Event&>(event));
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
void Renderable::mouse_press_event(const Pointer_Event& event) {
|
|
if (get_retiring() || event.is_accepted())
|
|
return;
|
|
auto* interactive = dynamic_cast<Pointer_Interactive*>(d_ptr);
|
|
if (interactive)
|
|
interactive->mouse_press_event(event);
|
|
}
|
|
void Renderable::mouse_move_event(const Pointer_Event& event) {
|
|
if (get_retiring() || event.is_accepted())
|
|
return;
|
|
auto* interactive = dynamic_cast<Pointer_Interactive*>(d_ptr);
|
|
if (interactive)
|
|
interactive->mouse_move_event(event);
|
|
}
|
|
void Renderable::mouse_release_event(const Pointer_Event& event) {
|
|
if (get_retiring() || event.is_accepted())
|
|
return;
|
|
auto* interactive = dynamic_cast<Pointer_Interactive*>(d_ptr);
|
|
if (interactive)
|
|
interactive->mouse_release_event(event);
|
|
}
|
|
void Renderable::set_hover_state(Point pos, bool active) {
|
|
if (get_retiring())
|
|
return;
|
|
auto* interactive = dynamic_cast<Hover_Interactive*>(d_ptr);
|
|
if (interactive)
|
|
interactive->set_hover_state(pos, active);
|
|
}
|
|
void Renderable::key_press_event(const Key_Event& event) {
|
|
if (get_retiring() || event.is_accepted())
|
|
return;
|
|
auto* interactive = dynamic_cast<Key_Press_Interactive*>(d_ptr);
|
|
if (interactive)
|
|
interactive->key_press_event(event);
|
|
}
|
|
void Renderable::key_release_event(const Key_Event& event) {
|
|
if (get_retiring() || event.is_accepted())
|
|
return;
|
|
auto* interactive = dynamic_cast<Key_Release_Interactive*>(d_ptr);
|
|
if (interactive)
|
|
interactive->key_release_event(event);
|
|
}
|
|
void Renderable::resize_event(const Resize_Event& event) {
|
|
if (get_retiring())
|
|
return;
|
|
(void)event;
|
|
}
|
|
void Renderable::wheel_event(const Wheel_Event& event) {
|
|
if (get_retiring() || event.is_accepted())
|
|
return;
|
|
auto* interactive = dynamic_cast<Wheel_Interactive*>(d_ptr);
|
|
if (interactive)
|
|
interactive->wheel_event(event);
|
|
}
|
|
void Renderable::mark_render_dirty() {
|
|
if (get_retiring())
|
|
return;
|
|
auto context = plot_context.lock();
|
|
if (!context || context->destroying.load(std::memory_order_acquire))
|
|
return;
|
|
cache_edit_version.fetch_add(1, std::memory_order_acq_rel);
|
|
if (auto parent = parent_renderable.lock()) {
|
|
parent->mark_render_dirty();
|
|
return;
|
|
}
|
|
Plot_Core* target_plot = context->owner.load(std::memory_order_acquire);
|
|
if (!context->destroying.load(std::memory_order_acquire) && target_plot)
|
|
target_plot->mark_render_state_dirty();
|
|
}
|
|
bool Renderable::ok() const {
|
|
auto context = plot_context.lock();
|
|
return d_ptr && initialized.load(std::memory_order_acquire) && !get_retiring() && context && !context->destroying.load(std::memory_order_acquire);
|
|
}
|
|
bool Renderable::get_retiring() const {
|
|
return retiring.load(std::memory_order_acquire);
|
|
}
|
|
void Renderable::detach_from_plot_tree() {
|
|
bool was_retiring = retiring.exchange(true, std::memory_order_acq_rel);
|
|
if (was_retiring && plot == nullptr)
|
|
return;
|
|
if (d_ptr)
|
|
d_ptr->cancel_pending_completions();
|
|
std::vector<std::shared_ptr<Renderable>> detached_children;
|
|
{
|
|
std::lock_guard<std::mutex> lock(children_mutex);
|
|
detached_children = std::move(children);
|
|
for (const auto& child : detached_children) {
|
|
if (child)
|
|
child->parent_renderable.reset();
|
|
}
|
|
children.clear();
|
|
}
|
|
for (const auto& child : detached_children) {
|
|
if (child)
|
|
child->detach_from_plot_tree();
|
|
}
|
|
plot = nullptr;
|
|
cache_image.clear();
|
|
cache_bounds = {};
|
|
}
|
|
Renderable::~Renderable() {
|
|
detach_from_plot_tree();
|
|
d_owner.reset();
|
|
d_ptr = nullptr;
|
|
}
|
|
} // namespace renderive
|