bl_demo_rects.cpp (12233B)
1 #include <stdlib.h> 2 #include <vector> 3 4 #include "bl_qt_headers.h" 5 #include "bl_qt_canvas.h" 6 7 class MainWindow : public QWidget { 8 Q_OBJECT 9 10 public: 11 QTimer _timer; 12 QSlider _size_slider; 13 QSlider _count_slider; 14 QComboBox _renderer_select; 15 QComboBox _comp_op_select; 16 QComboBox _shape_type_select; 17 QCheckBox _limit_fps_check; 18 QBLCanvas _canvas; 19 20 BLRandom _random; 21 bool _animate = true; 22 std::vector<BLPoint> _coords; 23 std::vector<BLPoint> _steps; 24 std::vector<BLRgba32> _colors; 25 BLCompOp _comp_op = BL_COMP_OP_SRC_OVER; 26 uint32_t _shape_type = 0; 27 double _rect_size = 64.0; 28 29 enum ShapeType { 30 kShapeRectA, 31 kShapeRectU, 32 kShapeRectPath, 33 kShapeRoundRect, 34 kShapePolyPath, 35 }; 36 37 MainWindow() : _random(0x123456789ABCDEF) { 38 QVBoxLayout* vBox = new QVBoxLayout(); 39 vBox->setContentsMargins(0, 0, 0, 0); 40 vBox->setSpacing(0); 41 42 QGridLayout* grid = new QGridLayout(); 43 grid->setContentsMargins(5, 5, 5, 5); 44 grid->setSpacing(5); 45 46 QBLCanvas::init_renderer_select_box(&_renderer_select); 47 _comp_op_select.addItem("SrcOver", QVariant(int(BL_COMP_OP_SRC_OVER))); 48 _comp_op_select.addItem("SrcCopy", QVariant(int(BL_COMP_OP_SRC_COPY))); 49 _comp_op_select.addItem("SrcAtop", QVariant(int(BL_COMP_OP_SRC_ATOP))); 50 _comp_op_select.addItem("DstAtop", QVariant(int(BL_COMP_OP_DST_ATOP))); 51 _comp_op_select.addItem("Xor", QVariant(int(BL_COMP_OP_XOR))); 52 _comp_op_select.addItem("Plus", QVariant(int(BL_COMP_OP_PLUS))); 53 _comp_op_select.addItem("Multiply", QVariant(int(BL_COMP_OP_MULTIPLY))); 54 _comp_op_select.addItem("Screen", QVariant(int(BL_COMP_OP_SCREEN))); 55 _comp_op_select.addItem("Overlay", QVariant(int(BL_COMP_OP_OVERLAY))); 56 _comp_op_select.addItem("Darken", QVariant(int(BL_COMP_OP_DARKEN))); 57 _comp_op_select.addItem("Lighten", QVariant(int(BL_COMP_OP_LIGHTEN))); 58 _comp_op_select.addItem("Color Dodge", QVariant(int(BL_COMP_OP_COLOR_DODGE))); 59 _comp_op_select.addItem("Color Burn", QVariant(int(BL_COMP_OP_COLOR_BURN))); 60 _comp_op_select.addItem("Hard Light", QVariant(int(BL_COMP_OP_HARD_LIGHT))); 61 _comp_op_select.addItem("Soft Light", QVariant(int(BL_COMP_OP_SOFT_LIGHT))); 62 _comp_op_select.addItem("Difference", QVariant(int(BL_COMP_OP_DIFFERENCE))); 63 _comp_op_select.addItem("Exclusion", QVariant(int(BL_COMP_OP_EXCLUSION))); 64 65 _shape_type_select.addItem("RectA", QVariant(int(kShapeRectA))); 66 _shape_type_select.addItem("RectU", QVariant(int(kShapeRectU))); 67 _shape_type_select.addItem("RectPath", QVariant(int(kShapeRectPath))); 68 _shape_type_select.addItem("RoundRect", QVariant(int(kShapeRoundRect))); 69 _shape_type_select.addItem("Polygon", QVariant(int(kShapePolyPath))); 70 71 _limit_fps_check.setText(QLatin1String("Limit FPS")); 72 73 _size_slider.setOrientation(Qt::Horizontal); 74 _size_slider.setMinimum(1); 75 _size_slider.setMaximum(128); 76 _size_slider.setSliderPosition(64); 77 78 _count_slider.setOrientation(Qt::Horizontal); 79 _count_slider.setMinimum(1); 80 _count_slider.setMaximum(20000); 81 _count_slider.setSliderPosition(200); 82 83 _canvas.on_render_blend2d = std::bind(&MainWindow::on_render_blend2d, this, std::placeholders::_1); 84 _canvas.on_render_qt = std::bind(&MainWindow::on_render_qt, this, std::placeholders::_1); 85 86 connect(&_renderer_select, SIGNAL(activated(int)), SLOT(onRendererChanged(int))); 87 connect(&_comp_op_select, SIGNAL(activated(int)), SLOT(onCompOpChanged(int))); 88 connect(&_shape_type_select, SIGNAL(activated(int)), SLOT(onShapeTypeChanged(int))); 89 connect(&_limit_fps_check, SIGNAL(stateChanged(int)), SLOT(onLimitFpsChanged(int))); 90 connect(&_size_slider, SIGNAL(valueChanged(int)), SLOT(onSizeChanged(int))); 91 connect(&_count_slider, SIGNAL(valueChanged(int)), SLOT(onCountChanged(int))); 92 93 grid->addWidget(new QLabel("Renderer:"), 0, 0); 94 grid->addWidget(&_renderer_select, 0, 1); 95 96 grid->addWidget(new QLabel("Comp Op:"), 0, 2); 97 grid->addWidget(&_comp_op_select, 0, 3); 98 99 grid->addWidget(new QLabel("Shape:"), 0, 4); 100 grid->addWidget(&_shape_type_select, 0, 5); 101 102 grid->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding), 0, 6); 103 grid->addWidget(&_limit_fps_check, 0, 7, Qt::AlignRight); 104 105 grid->addWidget(new QLabel("Count:"), 1, 0, 1, 1, Qt::AlignRight); 106 grid->addWidget(&_count_slider, 1, 1, 1, 7); 107 108 grid->addWidget(new QLabel("Size:"), 2, 0, 1, 1, Qt::AlignRight); 109 grid->addWidget(&_size_slider, 2, 1, 1, 7); 110 111 vBox->addLayout(grid); 112 vBox->addWidget(&_canvas); 113 setLayout(vBox); 114 115 connect(&_timer, SIGNAL(timeout()), this, SLOT(onTimer())); 116 connect(new QShortcut(QKeySequence(Qt::Key_P), this), SIGNAL(activated()), SLOT(onToggleAnimate())); 117 connect(new QShortcut(QKeySequence(Qt::Key_S), this), SIGNAL(activated()), SLOT(onStep())); 118 119 onInit(); 120 } 121 122 void showEvent(QShowEvent* event) override { _timer.start(); } 123 void hideEvent(QHideEvent* event) override { _timer.stop(); } 124 void keyPressEvent(QKeyEvent* event) override {} 125 126 void onInit() { 127 setCount(_count_slider.sliderPosition()); 128 _limit_fps_check.setChecked(true); 129 _updateTitle(); 130 } 131 132 double randomSign() noexcept { return _random.next_double() < 0.5 ? 1.0 : -1.0; } 133 BLRgba32 randomColor() noexcept { return BLRgba32(_random.next_uint32()); } 134 135 Q_SLOT void onToggleAnimate() { _animate = !_animate; } 136 Q_SLOT void onStep() { step(); } 137 138 Q_SLOT void onRendererChanged(int index) { _canvas.set_renderer_type(_renderer_select.itemData(index).toInt()); } 139 Q_SLOT void onCompOpChanged(int index) { _comp_op = (BLCompOp)_comp_op_select.itemData(index).toInt(); }; 140 Q_SLOT void onShapeTypeChanged(int index) { _shape_type = _shape_type_select.itemData(index).toInt(); }; 141 Q_SLOT void onLimitFpsChanged(int value) { _timer.setInterval(value ? 1000 / 120 : 0); } 142 Q_SLOT void onSizeChanged(int value) { _rect_size = value; } 143 Q_SLOT void onCountChanged(int value) { setCount(size_t(value)); } 144 145 Q_SLOT void onTimer() { 146 if (_animate) { 147 step(); 148 } 149 150 _canvas.update_canvas(true); 151 _updateTitle(); 152 } 153 154 void step() noexcept { 155 double w = _canvas.image_width(); 156 double h = _canvas.image_height(); 157 158 size_t size = _coords.size(); 159 for (size_t i = 0; i < size; i++) { 160 BLPoint& vertex = _coords[i]; 161 BLPoint& step = _steps[i]; 162 163 vertex += step; 164 if (vertex.x <= 0.0 || vertex.x >= w) { 165 step.x = -step.x; 166 vertex.x = bl_min(vertex.x + step.x, w); 167 } 168 169 if (vertex.y <= 0.0 || vertex.y >= h) { 170 step.y = -step.y; 171 vertex.y = bl_min(vertex.y + step.y, h); 172 } 173 } 174 } 175 176 void on_render_blend2d(BLContext& ctx) noexcept { 177 ctx.set_comp_op(BL_COMP_OP_SRC_COPY); 178 ctx.fill_all(bl_background_for_comp_op(_comp_op)); 179 ctx.set_comp_op(_comp_op); 180 181 size_t i; 182 size_t size = _coords.size(); 183 184 double rectSize = _rect_size; 185 double halfSize = _rect_size * 0.5; 186 187 switch (_shape_type) { 188 case kShapeRectA: { 189 int rectSizeI = int(_rect_size); 190 for (i = 0; i < size; i++) { 191 int x = int(_coords[i].x - halfSize); 192 int y = int(_coords[i].y - halfSize); 193 ctx.fill_rect(BLRectI(x, y, rectSizeI, rectSizeI), _colors[i]); 194 } 195 break; 196 } 197 198 case kShapeRectU: { 199 for (i = 0; i < size; i++) { 200 double x = _coords[i].x - halfSize; 201 double y = _coords[i].y - halfSize; 202 ctx.fill_rect(x, y, rectSize, rectSize, _colors[i]); 203 } 204 break; 205 } 206 207 case kShapeRectPath: { 208 for (i = 0; i < size; i++) { 209 double x = _coords[i].x - halfSize; 210 double y = _coords[i].y - halfSize; 211 212 BLPath path; 213 path.add_rect(x, y, rectSize, rectSize); 214 ctx.fill_path(path, _colors[i]); 215 } 216 break; 217 } 218 219 case kShapePolyPath: { 220 for (i = 0; i < size; i++) { 221 double x = _coords[i].x - halfSize; 222 double y = _coords[i].y - halfSize; 223 224 BLPath path; 225 path.move_to(x + rectSize / 2, y); 226 path.line_to(x + rectSize, y + rectSize / 3); 227 path.line_to(x + rectSize - rectSize / 3, y + rectSize); 228 path.line_to(x + rectSize / 3, y + rectSize); 229 path.line_to(x, y + rectSize / 3); 230 ctx.fill_path(path, _colors[i]); 231 } 232 break; 233 } 234 235 case kShapeRoundRect: { 236 for (i = 0; i < size; i++) { 237 double x = _coords[i].x - halfSize; 238 double y = _coords[i].y - halfSize; 239 240 ctx.fill_round_rect(BLRoundRect(x, y, rectSize, rectSize, 10), _colors[i]); 241 } 242 break; 243 } 244 } 245 } 246 247 void on_render_qt(QPainter& ctx) noexcept { 248 ctx.setCompositionMode(QPainter::CompositionMode_Source); 249 ctx.fillRect(0, 0, _canvas.image_width(), _canvas.image_height(), bl_rgba_to_qcolor(bl_background_for_comp_op(_comp_op))); 250 ctx.setRenderHint(QPainter::Antialiasing, true); 251 ctx.setCompositionMode(bl_comp_op_to_qt_composition_mode(_comp_op)); 252 253 size_t i; 254 size_t size = _coords.size(); 255 256 double rectSize = _rect_size; 257 double halfSize = _rect_size * 0.5; 258 259 switch (_shape_type) { 260 case kShapeRectA: { 261 int rectSizeI = int(_rect_size); 262 for (i = 0; i < size; i++) { 263 int x = int(_coords[i].x - halfSize); 264 int y = int(_coords[i].y - halfSize); 265 ctx.fillRect(QRect(x, y, rectSizeI, rectSizeI), bl_rgba_to_qcolor(_colors[i])); 266 } 267 break; 268 } 269 270 case kShapeRectU: { 271 for (i = 0; i < size; i++) { 272 double x = _coords[i].x - halfSize; 273 double y = _coords[i].y - halfSize; 274 ctx.fillRect(QRectF(_coords[i].x - halfSize, _coords[i].y - halfSize, rectSize, rectSize), bl_rgba_to_qcolor(_colors[i])); 275 } 276 break; 277 } 278 279 case kShapeRectPath: { 280 for (i = 0; i < size; i++) { 281 double x = _coords[i].x - halfSize; 282 double y = _coords[i].y - halfSize; 283 284 QPainterPath path; 285 path.addRect(x, y, rectSize, rectSize); 286 ctx.fillPath(path, bl_rgba_to_qcolor(_colors[i])); 287 } 288 break; 289 } 290 291 case kShapePolyPath: { 292 for (i = 0; i < size; i++) { 293 double x = _coords[i].x - halfSize; 294 double y = _coords[i].y - halfSize; 295 296 QPainterPath path; 297 path.moveTo(x + rectSize / 2, y); 298 path.lineTo(x + rectSize, y + rectSize / 3); 299 path.lineTo(x + rectSize - rectSize / 3, y + rectSize); 300 path.lineTo(x + rectSize / 3, y + rectSize); 301 path.lineTo(x, y + rectSize / 3); 302 ctx.fillPath(path, bl_rgba_to_qcolor(_colors[i])); 303 } 304 break; 305 } 306 307 case kShapeRoundRect: { 308 for (i = 0; i < size; i++) { 309 double x = _coords[i].x - halfSize; 310 double y = _coords[i].y - halfSize; 311 312 QPainterPath path; 313 path.addRoundedRect(QRectF(x, y, rectSize, rectSize), 10, 10); 314 ctx.fillPath(path, bl_rgba_to_qcolor(_colors[i])); 315 } 316 break; 317 } 318 } 319 } 320 321 void setCount(size_t size) { 322 double w = _canvas.image_width(); 323 double h = _canvas.image_height(); 324 size_t i = _coords.size(); 325 326 _coords.resize(size); 327 _steps.resize(size); 328 _colors.resize(size); 329 330 while (i < size) { 331 _coords[i].reset(_random.next_double() * w, 332 _random.next_double() * h); 333 _steps[i].reset((_random.next_double() * 0.5 + 0.04) * randomSign(), 334 (_random.next_double() * 0.5 + 0.04) * randomSign()); 335 _colors[i].reset(randomColor()); 336 i++; 337 } 338 } 339 340 void _updateTitle() { 341 char buf[256]; 342 snprintf(buf, 256, "Rects [%dx%d] [Size=%d Count=%zu] [RenderTime=%.2fms FPS=%.1f]", 343 _canvas.image_width(), 344 _canvas.image_height(), 345 int(_rect_size), 346 _coords.size(), 347 _canvas.average_render_time(), 348 _canvas.fps()); 349 350 QString title = QString::fromUtf8(buf); 351 if (title != windowTitle()) 352 setWindowTitle(title); 353 } 354 }; 355 356 int main(int argc, char *argv[]) { 357 QApplication app(argc, argv); 358 MainWindow win; 359 360 win.setMinimumSize(QSize(400, 320)); 361 win.resize(QSize(580, 520)); 362 win.show(); 363 364 return app.exec(); 365 } 366 367 #include "bl_demo_rects.moc"