odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

bl_qt_canvas.cpp (4328B)


      1 #include "bl_qt_headers.h"
      2 #include "bl_qt_canvas.h"
      3 
      4 #include <chrono>
      5 
      6 QBLCanvas::QBLCanvas()
      7   : _renderer_type(RendererBlend2D),
      8     _dirty(true),
      9     _fps(0),
     10     _frame_count(0) {
     11   _elapsed_timer.start();
     12   setMouseTracking(true);
     13   setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
     14 }
     15 
     16 QBLCanvas::~QBLCanvas() {}
     17 
     18 void QBLCanvas::resizeEvent(QResizeEvent* event) {
     19   _resize_canvas();
     20 }
     21 
     22 void QBLCanvas::paintEvent(QPaintEvent *event) {
     23   QPainter painter(this);
     24   if (_dirty)
     25     _render_canvas();
     26   painter.drawImage(QPoint(0, 0), qt_image);
     27 }
     28 
     29 void QBLCanvas::mousePressEvent(QMouseEvent* event) {
     30   if (on_mouse_event)
     31     on_mouse_event(event);
     32 }
     33 
     34 void QBLCanvas::mouseReleaseEvent(QMouseEvent* event) {
     35   if (on_mouse_event)
     36     on_mouse_event(event);
     37 }
     38 
     39 void QBLCanvas::mouseMoveEvent(QMouseEvent* event) {
     40   if (on_mouse_event)
     41     on_mouse_event(event);
     42 }
     43 
     44 void QBLCanvas::set_renderer_type(uint32_t renderer_type) {
     45   _renderer_type = renderer_type;
     46   update_canvas();
     47 }
     48 
     49 void QBLCanvas::update_canvas(bool force) {
     50   if (force)
     51     _render_canvas();
     52   else
     53     _dirty = true;
     54   repaint(0, 0, image_size().w, image_size().h);
     55 }
     56 
     57 void QBLCanvas::_resize_canvas() {
     58   int w = width();
     59   int h = height();
     60 
     61   float s = devicePixelRatio();
     62   int sw = int(float(w) * s);
     63   int sh = int(float(h) * s);
     64 
     65   if (qt_image.width() == sw && qt_image.height() == sh)
     66     return;
     67 
     68   QImage::Format qimage_format = QImage::Format_ARGB32_Premultiplied;
     69 
     70   qt_image = QImage(sw, sh, qimage_format);
     71   qt_image.setDevicePixelRatio(s);
     72 
     73   unsigned char* qimage_bits = qt_image.bits();
     74   qsizetype qimage_stride = qt_image.bytesPerLine();
     75 
     76   qt_image_non_scaling = QImage(qimage_bits, sw, sh, qimage_stride, qimage_format);
     77   bl_image.create_from_data(sw, sh, BL_FORMAT_PRGB32, qimage_bits, intptr_t(qimage_stride));
     78 
     79   update_canvas(false);
     80 }
     81 
     82 void QBLCanvas::_render_canvas() {
     83   auto startTime = std::chrono::high_resolution_clock::now();
     84 
     85   if (_renderer_type == RendererQt) {
     86     if (on_render_qt) {
     87       QPainter ctx(&qt_image_non_scaling);
     88       on_render_qt(ctx);
     89     }
     90   }
     91   else {
     92     if (on_render_blend2d) {
     93       // In Blend2D case the non-zero _renderer_type specifies the number of threads.
     94       BLContextCreateInfo create_info {};
     95       create_info.thread_count = _renderer_type;
     96 
     97       BLContext ctx(bl_image, create_info);
     98       on_render_blend2d(ctx);
     99     }
    100   }
    101 
    102   auto endTime = std::chrono::high_resolution_clock::now();
    103   std::chrono::duration<double> duration = endTime - startTime;
    104 
    105   _render_time_pos = (_render_time_pos + 1) & 31;
    106   _render_time[_render_time_pos] = duration.count();
    107   _rendered_frames++;
    108 
    109   _dirty = false;
    110   _after_render();
    111 }
    112 
    113 void QBLCanvas::_after_render() {
    114   uint64_t t = _elapsed_timer.elapsed();
    115 
    116   _frame_count++;
    117   if (t >= 1000) {
    118     _fps = _frame_count / double(t) * 1000.0;
    119     _frame_count = 0;
    120     _elapsed_timer.start();
    121   }
    122 }
    123 
    124 double QBLCanvas::last_render_time() const {
    125   return _rendered_frames > 0 ? _render_time[_render_time_pos] : 0.0;
    126 }
    127 
    128 double QBLCanvas::average_render_time() const {
    129   double sum = 0.0;
    130   size_t count = _rendered_frames < 32 ? _rendered_frames : size_t(32);
    131 
    132   for (size_t i = 0; i < count; i++) {
    133     sum += _render_time[i];
    134   }
    135 
    136   return (sum * 1000.0) / double(count);
    137 }
    138 
    139 void QBLCanvas::init_renderer_select_box(QComboBox* dst, bool blend2d_only) {
    140   static const uint32_t renderer_types[] = {
    141     RendererQt,
    142     RendererBlend2D,
    143     RendererBlend2D_1t,
    144     RendererBlend2D_2t,
    145     RendererBlend2D_4t,
    146     RendererBlend2D_8t,
    147     RendererBlend2D_12t,
    148     RendererBlend2D_16t
    149   };
    150 
    151   for (const auto& renderer_type : renderer_types) {
    152     if (renderer_type == RendererQt && blend2d_only)
    153       continue;
    154     QString s = renderer_type_to_string(renderer_type);
    155     dst->addItem(s, QVariant(int(renderer_type)));
    156   }
    157 
    158   dst->setCurrentIndex(blend2d_only ? 0 : 1);
    159 }
    160 
    161 QString QBLCanvas::renderer_type_to_string(uint32_t renderer_type) {
    162   char buffer[32];
    163   switch (renderer_type) {
    164     case RendererQt:
    165       return QLatin1String("Qt");
    166 
    167     default:
    168       if (renderer_type > 32)
    169         return QString();
    170 
    171       if (renderer_type == 0)
    172         return QLatin1String("Blend2D");
    173 
    174       snprintf(buffer, sizeof(buffer), "Blend2D %uT", renderer_type);
    175       return QLatin1String(buffer);
    176   }
    177 }
    178 
    179 #include "moc_bl_qt_canvas.cpp"