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"