重构出Core2
This commit is contained in:
+157
-127
@@ -1,21 +1,20 @@
|
||||
#include "Plot_p.h"
|
||||
|
||||
#include "../bridge/Qt_Event_Adapter.h"
|
||||
#include "../bridge/Qt_Image_Adapter.h"
|
||||
#include "../bridge/Qt_Presentation_Sink.h"
|
||||
#include "Core/architecture/Render_Time.h"
|
||||
#include "Core/base/global.h"
|
||||
#include "Core/plottable/export.h"
|
||||
#include "Core/plot/Plot_Core_Access.h"
|
||||
#include "Core/architecture/Plot_Render_Context.h"
|
||||
#include <QClipboard>
|
||||
#include <QGuiApplication>
|
||||
|
||||
#include <QFont>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QPointer>
|
||||
#include <QResizeEvent>
|
||||
#include <QTimer>
|
||||
#include <QWheelEvent>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace renderive {
|
||||
|
||||
namespace {
|
||||
|
||||
Color from_qcolor(const QColor& color) {
|
||||
@@ -32,38 +31,25 @@ QColor to_qcolor(Color color) {
|
||||
}
|
||||
|
||||
std::string to_utf8_string(const QString& text) {
|
||||
QByteArray bytes = text.toUtf8();
|
||||
return std::string(bytes.constData(), static_cast<std::size_t>(bytes.size()));
|
||||
const QByteArray bytes = text.toUtf8();
|
||||
return {bytes.constData(), static_cast<std::size_t>(bytes.size())};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void start_render_scheduler(Render_Runtime_Config config) {
|
||||
Global::instance()->start_render_scheduler(config);
|
||||
}
|
||||
|
||||
Abs_Plot_Private::Abs_Plot_Private(std::unique_ptr<Frame_Flow> frame_flow)
|
||||
: flow(frame_flow.get()),
|
||||
core(std::make_unique<Plot_Core>(std::move(frame_flow))) {}
|
||||
Abs_Plot_Private::Abs_Plot_Private(bool continuous_rendering)
|
||||
: core(std::make_unique<Plot_Core>()), continuous(continuous_rendering) {}
|
||||
|
||||
Abs_Plot_Private::~Abs_Plot_Private() = default;
|
||||
|
||||
void Abs_Plot_Private::attach_widget(Abs_Plot* plot) {
|
||||
presentation_sink = std::make_shared<Qt_Presentation_Sink>(plot);
|
||||
core->set_presentation_sink(presentation_sink);
|
||||
QPointer<Abs_Plot> guarded_plot(plot);
|
||||
auto pending = performance_update_pending;
|
||||
set_performance_overlay_update_callback(*core, [guarded_plot, pending]() mutable {
|
||||
if (!guarded_plot || pending->exchange(true, std::memory_order_acq_rel))
|
||||
return;
|
||||
QTimer::singleShot(0, guarded_plot.data(), [guarded_plot, pending]() mutable {
|
||||
pending->store(false, std::memory_order_release);
|
||||
if (guarded_plot)
|
||||
guarded_plot->update();
|
||||
});
|
||||
});
|
||||
set_performance_overlay_clipboard_callback(*core, [](std::string text) {
|
||||
QGuiApplication::clipboard()->setText(QString::fromUtf8(text.data(), static_cast<int>(text.size())));
|
||||
timer = new QTimer(plot);
|
||||
timer->setTimerType(Qt::PreciseTimer);
|
||||
QObject::connect(timer, &QTimer::timeout, plot, [this] {
|
||||
if (core->view_active())
|
||||
(void)core->render_frame();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -73,23 +59,20 @@ Abs_Plot::Abs_Plot(Abs_Plot_Private* private_data)
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, true);
|
||||
setMouseTracking(true);
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
update_render_interval();
|
||||
}
|
||||
|
||||
Abs_Plot::~Abs_Plot() {
|
||||
if (d) {
|
||||
set_performance_overlay_update_callback(*d->core, {});
|
||||
set_performance_overlay_clipboard_callback(*d->core, {});
|
||||
d->core->deactivate_view();
|
||||
delete d;
|
||||
d = nullptr;
|
||||
}
|
||||
if (!d)
|
||||
return;
|
||||
if (d->timer)
|
||||
d->timer->stop();
|
||||
d->core->deactivate_view();
|
||||
delete d;
|
||||
d = nullptr;
|
||||
}
|
||||
|
||||
void Abs_Plot::init() {
|
||||
init_renderable_tree();
|
||||
}
|
||||
|
||||
void Abs_Plot::init_renderable_tree() {
|
||||
d->core->init();
|
||||
}
|
||||
|
||||
@@ -101,15 +84,16 @@ std::shared_ptr<Renderable> Abs_Plot::root_renderable() const {
|
||||
return d->core->root_renderable();
|
||||
}
|
||||
|
||||
std::shared_ptr<Renderable> Abs_Plot::create_renderable_node(const std::shared_ptr<Renderable>& parent, const QString& object_name) const {
|
||||
std::shared_ptr<Renderable> Abs_Plot::create_renderable_node(
|
||||
const std::shared_ptr<Renderable>& parent, const QString& object_name) const {
|
||||
return d->core->create_renderable_node(parent, to_utf8_string(object_name));
|
||||
}
|
||||
|
||||
void Abs_Plot::remove_renderable(const std::shared_ptr<Renderable>& able) {
|
||||
d->core->remove_renderable(able);
|
||||
void Abs_Plot::remove_renderable(const std::shared_ptr<Renderable>& renderable) {
|
||||
d->core->remove_renderable(renderable);
|
||||
}
|
||||
|
||||
QColor Abs_Plot::background_color() {
|
||||
QColor Abs_Plot::background_color() const {
|
||||
return to_qcolor(d->core->background_color());
|
||||
}
|
||||
|
||||
@@ -117,120 +101,166 @@ void Abs_Plot::set_background_color(const QColor& color) {
|
||||
d->core->set_background_color(from_qcolor(color));
|
||||
}
|
||||
|
||||
void Abs_Plot::paintEvent(QPaintEvent* event) {
|
||||
d->paint_event(this, event);
|
||||
void Abs_Plot::start_render_timer() {
|
||||
d->core->activate_view();
|
||||
update_render_interval();
|
||||
if (d->timer && !d->timer->isActive())
|
||||
d->timer->start();
|
||||
}
|
||||
|
||||
void Abs_Plot::stop_render_timer() {
|
||||
if (d->timer)
|
||||
d->timer->stop();
|
||||
d->core->deactivate_view();
|
||||
}
|
||||
|
||||
void Abs_Plot::update_render_interval() {
|
||||
if (!d->timer)
|
||||
return;
|
||||
const double fps = std::max(1.0, d->core->max_render_fps());
|
||||
d->timer->setInterval(std::max(1, static_cast<int>(std::lround(1000.0 / fps))));
|
||||
}
|
||||
|
||||
void Abs_Plot::paintEvent(QPaintEvent*) {
|
||||
d->paint_event(this);
|
||||
}
|
||||
|
||||
void Abs_Plot_Private::paint_event(Abs_Plot* plot) {
|
||||
QPainter painter(plot);
|
||||
painter.fillRect(plot->rect(), plot->background_color());
|
||||
core->with_frame([&painter](Image_View view) {
|
||||
if (!view.empty())
|
||||
painter.drawImage(QPoint(0, 0), Qt_Image_Adapter::to_qimage(view));
|
||||
});
|
||||
draw_performance_overlay(plot, painter);
|
||||
painter.end();
|
||||
}
|
||||
|
||||
void Abs_Plot_Private::draw_performance_overlay(Abs_Plot* plot, QPainter& painter) {
|
||||
const auto overlay = core->performance_overlay();
|
||||
if (!overlay || !overlay->enabled())
|
||||
return;
|
||||
const auto snapshot = overlay->display_snapshot();
|
||||
if (!snapshot || snapshot->viewport_size != core->viewport_size())
|
||||
return;
|
||||
const auto& options = snapshot->style;
|
||||
QFont font = painter.font();
|
||||
font.setPointSizeF(std::max(1.0, options.font.size));
|
||||
font.setWeight(std::clamp(options.font.weight / 10, 0, 99));
|
||||
font.setItalic(options.font.italic);
|
||||
painter.setFont(font);
|
||||
const QFontMetrics metrics(font);
|
||||
const int line_height = std::max(1, metrics.height() + 2);
|
||||
const int left_margin = std::max(0, options.left_margin);
|
||||
const int right_margin = std::max(0, options.right_margin);
|
||||
const int top_margin = std::max(0, options.top_margin);
|
||||
const int bottom_margin = std::max(0, options.bottom_margin);
|
||||
int text_width{};
|
||||
for (const auto& line : snapshot->lines)
|
||||
text_width = std::max(text_width, metrics.horizontalAdvance(QString::fromStdString(line)));
|
||||
const int panel_width = std::min(plot->width(), left_margin + text_width + right_margin);
|
||||
const int panel_height = std::min(
|
||||
plot->height(), top_margin + bottom_margin +
|
||||
line_height * static_cast<int>(snapshot->lines.size()));
|
||||
painter.fillRect(QRect(0, 0, panel_width, panel_height), to_qcolor(options.background));
|
||||
int y = top_margin + metrics.ascent();
|
||||
for (std::size_t index = 0; index < snapshot->lines.size(); ++index) {
|
||||
const QString line = QString::fromStdString(snapshot->lines[index]);
|
||||
if (index == 0) {
|
||||
painter.setPen(to_qcolor(options.section_color));
|
||||
painter.drawText(left_margin, y, line);
|
||||
} else if (const qsizetype separator = line.indexOf(':'); separator >= 0) {
|
||||
const QString label = line.left(separator + 1);
|
||||
painter.setPen(to_qcolor(options.label_color));
|
||||
painter.drawText(left_margin, y, label);
|
||||
painter.setPen(to_qcolor(options.value_color));
|
||||
painter.drawText(left_margin + metrics.horizontalAdvance(label), y,
|
||||
line.mid(separator + 1));
|
||||
} else {
|
||||
painter.setPen(to_qcolor(options.label_color));
|
||||
painter.drawText(left_margin, y, line);
|
||||
}
|
||||
y += line_height;
|
||||
}
|
||||
}
|
||||
|
||||
bool Abs_Plot::event(QEvent* event) {
|
||||
bool base_result = QWidget::event(event);
|
||||
return d->event(event, base_result);
|
||||
}
|
||||
|
||||
void Abs_Plot_Private::paint_event(Abs_Plot* plot, QPaintEvent* event) {
|
||||
(void)event;
|
||||
std::uint64_t paint_begin_time = steady_now_ns();
|
||||
auto frame = core->begin_present();
|
||||
|
||||
QPainter painter(plot);
|
||||
if (frame && !frame.image().empty()) {
|
||||
QImage image = Qt_Image_Adapter::to_qimage(frame.image());
|
||||
painter.drawImage(QPoint(0, 0), image);
|
||||
}
|
||||
else {
|
||||
painter.fillRect(plot->rect(), plot->background_color());
|
||||
}
|
||||
auto performance_snapshot = performance_overlay_snapshot(*core);
|
||||
if (performance_snapshot && !performance_snapshot->image.empty()) {
|
||||
Size current_size = core->viewport_size();
|
||||
auto ctx = Plot_Core_Context_Access::render_context(*core);
|
||||
std::uint64_t current_viewport_version = ctx ? ctx->viewport_version.load(std::memory_order_acquire) : 0;
|
||||
if (performance_snapshot->viewport_size == current_size && performance_snapshot->viewport_version == current_viewport_version) {
|
||||
QImage overlay = Qt_Image_Adapter::to_qimage(performance_snapshot->image.view());
|
||||
const RectF& target = performance_snapshot->destination_rect;
|
||||
painter.drawImage(QRectF(target.x, target.y, target.width, target.height), overlay);
|
||||
}
|
||||
}
|
||||
painter.end();
|
||||
|
||||
core->end_present(std::move(frame), paint_begin_time, steady_now_ns());
|
||||
}
|
||||
|
||||
bool Abs_Plot_Private::event(QEvent* event, bool base_result) {
|
||||
const auto dispatch = [this, event](const Event& translated) {
|
||||
d->core->dispatch_event(translated);
|
||||
if (!translated.is_accepted())
|
||||
return false;
|
||||
event->accept();
|
||||
return true;
|
||||
};
|
||||
switch (event->type()) {
|
||||
case QEvent::Resize: {
|
||||
auto* resize_event = static_cast<QResizeEvent*>(event);
|
||||
core->set_viewport_size(Qt_Event_Adapter::to_size(resize_event->size()));
|
||||
notify_performance_overlay_viewport_changed(*core);
|
||||
core->dispatch_event(Qt_Event_Adapter::to_resize_event(resize_event));
|
||||
core->notify_model_dirty();
|
||||
auto* resize = static_cast<QResizeEvent*>(event);
|
||||
d->core->set_viewport_size(Qt_Event_Adapter::to_size(resize->size()));
|
||||
d->core->dispatch_event(Qt_Event_Adapter::to_resize_event(resize));
|
||||
break;
|
||||
}
|
||||
case QEvent::Show: {
|
||||
Event show_event(Event_Type::Show);
|
||||
core->dispatch_event(show_event);
|
||||
core->activate_view();
|
||||
case QEvent::Show:
|
||||
d->core->dispatch_event(Event(Event_Type::Show));
|
||||
if (d->continuous)
|
||||
start_render_timer();
|
||||
break;
|
||||
}
|
||||
case QEvent::Hide: {
|
||||
Event hide_event(Event_Type::Hide);
|
||||
core->dispatch_event(hide_event);
|
||||
core->deactivate_view();
|
||||
case QEvent::Hide:
|
||||
d->core->dispatch_event(Event(Event_Type::Hide));
|
||||
if (d->continuous)
|
||||
stop_render_timer();
|
||||
break;
|
||||
}
|
||||
case QEvent::Leave: {
|
||||
performance_overlay_handle_pointer_leave(*core);
|
||||
Event leave_event(Event_Type::Leave);
|
||||
core->dispatch_event(leave_event);
|
||||
const Event translated(Event_Type::Leave);
|
||||
if (dispatch(translated))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case QEvent::Wheel: {
|
||||
auto wheel_event = Qt_Event_Adapter::to_wheel_event(static_cast<QWheelEvent*>(event));
|
||||
if (performance_overlay_handle_wheel(*core, wheel_event.position, wheel_event.angle_delta_y, wheel_event.pixel_delta_y)) {
|
||||
event->accept();
|
||||
const auto translated = Qt_Event_Adapter::to_wheel_event(
|
||||
static_cast<QWheelEvent*>(event));
|
||||
if (dispatch(translated))
|
||||
return true;
|
||||
}
|
||||
core->dispatch_event(wheel_event);
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseMove: {
|
||||
auto pointer_event = Qt_Event_Adapter::to_pointer_event(static_cast<QMouseEvent*>(event), Event_Type::Pointer_Move);
|
||||
if (performance_overlay_handle_pointer_move(*core, pointer_event.position)) {
|
||||
event->accept();
|
||||
const auto translated = Qt_Event_Adapter::to_pointer_event(
|
||||
static_cast<QMouseEvent*>(event), Event_Type::Pointer_Move);
|
||||
if (dispatch(translated))
|
||||
return true;
|
||||
}
|
||||
core->dispatch_event(pointer_event);
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseButtonPress: {
|
||||
auto* mouse_event = static_cast<QMouseEvent*>(event);
|
||||
auto pointer_event = Qt_Event_Adapter::to_pointer_event(mouse_event, Event_Type::Pointer_Press);
|
||||
if (mouse_event->button() == Qt::LeftButton && performance_overlay_handle_pointer_press(*core, pointer_event.position)) {
|
||||
event->accept();
|
||||
const auto translated = Qt_Event_Adapter::to_pointer_event(
|
||||
static_cast<QMouseEvent*>(event), Event_Type::Pointer_Press);
|
||||
if (dispatch(translated))
|
||||
return true;
|
||||
}
|
||||
core->dispatch_event(pointer_event);
|
||||
break;
|
||||
}
|
||||
case QEvent::MouseButtonRelease: {
|
||||
auto* mouse_event = static_cast<QMouseEvent*>(event);
|
||||
auto pointer_event = Qt_Event_Adapter::to_pointer_event(mouse_event, Event_Type::Pointer_Release);
|
||||
if (mouse_event->button() == Qt::LeftButton && performance_overlay_handle_pointer_release(*core, pointer_event.position)) {
|
||||
event->accept();
|
||||
const auto translated = Qt_Event_Adapter::to_pointer_event(
|
||||
static_cast<QMouseEvent*>(event), Event_Type::Pointer_Release);
|
||||
if (dispatch(translated))
|
||||
return true;
|
||||
}
|
||||
core->dispatch_event(pointer_event);
|
||||
break;
|
||||
}
|
||||
case QEvent::KeyPress:
|
||||
core->dispatch_event(Qt_Event_Adapter::to_key_event(static_cast<QKeyEvent*>(event), Event_Type::Key_Press));
|
||||
case QEvent::KeyPress: {
|
||||
const auto translated = Qt_Event_Adapter::to_key_event(
|
||||
static_cast<QKeyEvent*>(event), Event_Type::Key_Press);
|
||||
if (dispatch(translated))
|
||||
return true;
|
||||
break;
|
||||
case QEvent::KeyRelease:
|
||||
core->dispatch_event(Qt_Event_Adapter::to_key_event(static_cast<QKeyEvent*>(event), Event_Type::Key_Release));
|
||||
}
|
||||
case QEvent::KeyRelease: {
|
||||
const auto translated = Qt_Event_Adapter::to_key_event(
|
||||
static_cast<QKeyEvent*>(event), Event_Type::Key_Release);
|
||||
if (dispatch(translated))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return base_result;
|
||||
return QWidget::event(event);
|
||||
}
|
||||
|
||||
} // namespace renderive
|
||||
|
||||
Reference in New Issue
Block a user