bl_demo_circles.cpp (4875B)
1 #include <stdlib.h> 2 #include <cmath> 3 #include <vector> 4 5 #include "bl_qt_headers.h" 6 #include "bl_qt_canvas.h" 7 8 class MainWindow : public QWidget { 9 Q_OBJECT 10 11 public: 12 QTimer _timer; 13 QComboBox _renderer_select; 14 QCheckBox _limit_fps_check; 15 QSlider _count_slider; 16 QBLCanvas _canvas; 17 18 bool _animate = true; 19 double _angle {}; 20 int _count {}; 21 22 MainWindow() { 23 QVBoxLayout* vBox = new QVBoxLayout(); 24 vBox->setContentsMargins(0, 0, 0, 0); 25 vBox->setSpacing(0); 26 27 QGridLayout* grid = new QGridLayout(); 28 grid->setContentsMargins(5, 5, 5, 5); 29 grid->setSpacing(5); 30 31 QBLCanvas::init_renderer_select_box(&_renderer_select); 32 _limit_fps_check.setText(QLatin1String("Limit FPS")); 33 34 _count_slider.setMinimum(100); 35 _count_slider.setMaximum(2000); 36 _count_slider.setValue(500); 37 _count_slider.setOrientation(Qt::Horizontal); 38 39 connect(&_renderer_select, SIGNAL(activated(int)), SLOT(onRendererChanged(int))); 40 connect(&_limit_fps_check, SIGNAL(stateChanged(int)), SLOT(onLimitFpsChanged(int))); 41 42 grid->addWidget(new QLabel("Renderer:"), 0, 0); 43 grid->addWidget(&_renderer_select, 0, 1); 44 45 grid->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding), 0, 2); 46 grid->addWidget(&_limit_fps_check, 0, 3, Qt::AlignRight); 47 48 grid->addWidget(new QLabel("Count:"), 1, 0, Qt::AlignRight); 49 grid->addWidget(&_count_slider, 1, 1, 1, 4); 50 51 _canvas.on_render_blend2d = std::bind(&MainWindow::on_render_blend2d, this, std::placeholders::_1); 52 _canvas.on_render_qt = std::bind(&MainWindow::on_render_qt, this, std::placeholders::_1); 53 54 vBox->addItem(grid); 55 vBox->addWidget(&_canvas); 56 setLayout(vBox); 57 58 connect(&_timer, SIGNAL(timeout()), this, SLOT(onTimer())); 59 connect(new QShortcut(QKeySequence(Qt::Key_P), this), SIGNAL(activated()), SLOT(onToggleAnimate())); 60 61 onInit(); 62 } 63 64 void showEvent(QShowEvent* event) override { _timer.start(); } 65 void hideEvent(QHideEvent* event) override { _timer.stop(); } 66 void keyPressEvent(QKeyEvent* event) override {} 67 68 void onInit() { 69 _angle = 0; 70 _count = 0; 71 _limit_fps_check.setChecked(true); 72 _updateTitle(); 73 } 74 75 Q_SLOT void onToggleAnimate() { _animate = !_animate; } 76 Q_SLOT void onRendererChanged(int index) { _canvas.set_renderer_type(_renderer_select.itemData(index).toInt()); } 77 Q_SLOT void onLimitFpsChanged(int value) { _timer.setInterval(value ? 1000 / 120 : 0); } 78 79 Q_SLOT void onTimer() { 80 if (_animate) { 81 _angle += 0.05; 82 if (_angle >= 360) 83 _angle -= 360; 84 } 85 86 _canvas.update_canvas(true); 87 _updateTitle(); 88 } 89 90 // The idea is based on: 91 // https://github.com/fogleman/gg/blob/master/examples/spiral.go 92 93 void on_render_blend2d(BLContext& ctx) noexcept { 94 ctx.fill_all(BLRgba32(0xFF000000u)); 95 96 BLPath p; 97 98 int count = _count_slider.value(); 99 double PI = 3.14159265359; 100 101 double cx = _canvas.image_width() / 2; 102 double cy = _canvas.image_height() / 2; 103 double maxDist = 1000.0; 104 double baseAngle = _angle / 180.0 * PI; 105 106 for (int i = 0; i < count; i++) { 107 double t = double(i) * 1.01 / 1000; 108 double d = t * 1000.0 * 0.4 + 10; 109 double a = baseAngle + t * PI * 2 * 20; 110 double x = cx + std::cos(a) * d; 111 double y = cy + std::sin(a) * d; 112 double r = std::min(t * 8 + 0.5, 10.0); 113 p.add_circle(BLCircle(x, y, r)); 114 } 115 116 ctx.fill_path(p, BLRgba32(0xFFFFFFFFu)); 117 } 118 119 void on_render_qt(QPainter& ctx) noexcept { 120 ctx.fillRect(0, 0, _canvas.image_width(), _canvas.image_height(), QColor(0, 0, 0)); 121 ctx.setRenderHint(QPainter::Antialiasing, true); 122 123 QPainterPath p; 124 QBrush brush(QColor(qRgb(255, 255, 255))); 125 126 int count = _count_slider.value(); 127 double PI = 3.14159265359; 128 129 double cx = _canvas.image_width() / 2; 130 double cy = _canvas.image_height() / 2; 131 double baseAngle = _angle / 180.0 * PI; 132 133 for (int i = 0; i < count; i++) { 134 double t = double(i) * 1.01 / 1000; 135 double d = t * 1000.0 * 0.4 + 10; 136 double a = baseAngle + t * PI * 2 * 20; 137 double x = cx + std::cos(a) * d; 138 double y = cy + std::sin(a) * d; 139 double r = std::min(t * 8 + 0.5, 10.0); 140 p.addEllipse(x - r, y - r, r * 2.0, r * 2.0); 141 } 142 143 ctx.fillPath(p, brush); 144 } 145 146 void _updateTitle() { 147 char buf[256]; 148 snprintf(buf, 256, "Circles [%dx%d] [Count=%d] [RenderTime=%.2fms FPS=%.1f]", 149 _canvas.image_width(), 150 _canvas.image_height(), 151 _count_slider.value(), 152 _canvas.average_render_time(), 153 _canvas.fps()); 154 155 QString title = QString::fromUtf8(buf); 156 if (title != windowTitle()) 157 setWindowTitle(title); 158 } 159 }; 160 161 int main(int argc, char *argv[]) { 162 QApplication app(argc, argv); 163 MainWindow win; 164 165 win.setMinimumSize(QSize(400, 320)); 166 win.resize(QSize(580, 520)); 167 win.show(); 168 169 return app.exec(); 170 } 171 172 #include "bl_demo_circles.moc"