bl_demo_bounces.cpp (8720B)
1 #include <stdlib.h> 2 3 #include "bl_qt_headers.h" 4 #include "bl_qt_canvas.h" 5 6 class MainWindow : public QWidget { 7 Q_OBJECT 8 9 public: 10 QTimer _timer; 11 QBLCanvas _canvas; 12 QComboBox _renderer_select; 13 QComboBox _style_select; 14 QCheckBox _limit_fps_check; 15 16 bool _animate = true; 17 double _time {}; 18 int _count {}; 19 20 enum class StyleId { 21 kSolid, 22 kLinear, 23 kRadial, 24 kConic 25 }; 26 27 MainWindow() { 28 QVBoxLayout* vBox = new QVBoxLayout(); 29 vBox->setContentsMargins(0, 0, 0, 0); 30 vBox->setSpacing(0); 31 32 QGridLayout* grid = new QGridLayout(); 33 grid->setContentsMargins(5, 5, 5, 5); 34 grid->setSpacing(5); 35 36 QBLCanvas::init_renderer_select_box(&_renderer_select); 37 _limit_fps_check.setText(QLatin1String("Limit FPS")); 38 39 _style_select.addItem("Solid Color", QVariant(int(StyleId::kSolid))); 40 _style_select.addItem("Linear Gradient", QVariant(int(StyleId::kLinear))); 41 _style_select.addItem("Radial Gradient", QVariant(int(StyleId::kRadial))); 42 _style_select.addItem("Conic Gradient", QVariant(int(StyleId::kConic))); 43 _style_select.setCurrentIndex(1); 44 45 connect(&_renderer_select, SIGNAL(activated(int)), SLOT(onRendererChanged(int))); 46 connect(&_limit_fps_check, SIGNAL(stateChanged(int)), SLOT(onLimitFpsChanged(int))); 47 48 grid->addWidget(new QLabel("Renderer:"), 0, 0); 49 grid->addWidget(&_renderer_select, 0, 1); 50 51 grid->addWidget(new QLabel("Style:"), 0, 2); 52 grid->addWidget(&_style_select, 0, 3); 53 54 grid->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding), 0, 4); 55 grid->addWidget(&_limit_fps_check, 0, 5, Qt::AlignRight); 56 57 _canvas.on_render_blend2d = std::bind(&MainWindow::on_render_blend2d, this, std::placeholders::_1); 58 _canvas.on_render_qt = std::bind(&MainWindow::on_render_qt, this, std::placeholders::_1); 59 60 vBox->addItem(grid); 61 vBox->addWidget(&_canvas); 62 setLayout(vBox); 63 64 connect(&_timer, SIGNAL(timeout()), this, SLOT(onTimer())); 65 connect(new QShortcut(QKeySequence(Qt::Key_P), this), SIGNAL(activated()), SLOT(onToggleAnimate())); 66 67 onInit(); 68 } 69 70 void showEvent(QShowEvent* event) override { _timer.start(); } 71 void hideEvent(QHideEvent* event) override { _timer.stop(); } 72 void keyPressEvent(QKeyEvent* event) override {} 73 74 void onInit() { 75 _time = 0; 76 _count = 0; 77 _limit_fps_check.setChecked(true); 78 _updateTitle(); 79 } 80 81 Q_SLOT void onToggleAnimate() { _animate = !_animate; } 82 Q_SLOT void onRendererChanged(int index) { _canvas.set_renderer_type(_renderer_select.itemData(index).toInt()); } 83 Q_SLOT void onLimitFpsChanged(int value) { _timer.setInterval(value ? 1000 / 120 : 0); } 84 85 Q_SLOT void onTimer() { 86 if (_animate) { 87 _time += 2.0; 88 } 89 90 _updateTitle(); 91 _canvas.update_canvas(true); 92 } 93 94 inline StyleId getStyleId() const noexcept { return StyleId(_style_select.currentData().toInt()); } 95 96 void on_render_blend2d(BLContext& ctx) noexcept { 97 ctx.fill_all(BLRgba32(0xFF000000)); 98 99 StyleId styleId = getStyleId(); 100 double kMarginSize = 7; 101 double kSquareSize = 45; 102 double kFullSize = kSquareSize + kMarginSize * 2.0; 103 double kHalfSize = kFullSize / 2.0; 104 105 int w = (_canvas.image_width() + kFullSize - 1) / kFullSize; 106 int h = (_canvas.image_height() + kFullSize - 1) / kFullSize; 107 108 int count = w * h; 109 _count = count; 110 111 double ix = 0; 112 double iy = 0; 113 114 double start = 0; 115 double now = _time; 116 double PI = 3.14159265359; 117 118 BLGradient gr; 119 120 switch (styleId) { 121 case StyleId::kSolid: 122 break; 123 case StyleId::kLinear: 124 gr.set_type(BL_GRADIENT_TYPE_LINEAR); 125 gr.set_values(BLLinearGradientValues(0, kMarginSize, 0, kMarginSize + kSquareSize)); 126 break; 127 case StyleId::kRadial: 128 gr.set_type(BL_GRADIENT_TYPE_RADIAL); 129 gr.set_values(BLRadialGradientValues(kHalfSize, kHalfSize, kHalfSize, kHalfSize - 15, kHalfSize)); 130 break; 131 case StyleId::kConic: 132 gr.set_type(BL_GRADIENT_TYPE_CONIC); 133 gr.set_values(BLConicGradientValues(kHalfSize, kHalfSize, M_PI / -2.0, 1.0)); 134 break; 135 } 136 137 for (int i = 0; i < count; i++) { 138 double x = ix * kFullSize; 139 double y = iy * kFullSize; 140 141 double dur = (now - start) + (i * 50); 142 double pos = fmod(dur, 3000.0) / 3000.0; 143 double bouncePos = bl_abs(pos * 2 - 1); 144 double r = (bouncePos * 50 + 50) / 100; 145 double b = ((1 - bouncePos) * 50) / 100; 146 147 double rotation = pos * (PI * 2); 148 double radius = bouncePos * 25; 149 150 ctx.rotate(rotation, x + kHalfSize, y + kHalfSize); 151 ctx.translate(x, y); 152 153 BLRoundRect round_rect(kMarginSize, kMarginSize, kSquareSize, kSquareSize, radius, radius); 154 155 switch (styleId) { 156 case StyleId::kSolid: { 157 ctx.fill_round_rect(round_rect, BLRgba32(int(r * 255), 0, int(b * 255))); 158 break; 159 } 160 161 case StyleId::kLinear: 162 case StyleId::kRadial: { 163 gr.reset_stops(); 164 gr.add_stop(0, BLRgba32(0xFFFF7F00u)); 165 gr.add_stop(1, BLRgba32(int(r * 255), 0, int(b * 255))); 166 ctx.fill_round_rect(round_rect, gr); 167 break; 168 } 169 170 case StyleId::kConic: { 171 gr.reset_stops(); 172 gr.add_stop(0.0, BLRgba32(0xFFFF7F00u)); 173 gr.add_stop(0.5, BLRgba32(int(r * 255), 0, int(b * 255))); 174 gr.add_stop(1.0, BLRgba32(0xFFFF7F00u)); 175 ctx.fill_round_rect(round_rect, gr); 176 break; 177 } 178 } 179 180 ctx.reset_transform(); 181 182 if (++ix >= w) { ix = 0; iy++; } 183 } 184 } 185 186 void on_render_qt(QPainter& ctx) noexcept { 187 ctx.fillRect(0, 0, _canvas.image_width(), _canvas.image_height(), QColor(0, 0, 0)); 188 189 ctx.setRenderHint(QPainter::Antialiasing, true); 190 ctx.setPen(Qt::NoPen); 191 192 StyleId styleId = getStyleId(); 193 double kMarginSize = 7; 194 double kSquareSize = 45; 195 double kFullSize = kSquareSize + kMarginSize * 2.0; 196 double kHalfSize = kFullSize / 2.0; 197 198 int w = (_canvas.image_width() + kFullSize - 1) / kFullSize; 199 int h = (_canvas.image_height() + kFullSize - 1) / kFullSize; 200 201 int count = w * h; 202 _count = count; 203 204 double ix = 0; 205 double iy = 0; 206 207 double start = 0; 208 double now = _time; 209 210 for (int i = 0; i < count; i++) { 211 double x = ix * kFullSize; 212 double y = iy * kFullSize; 213 214 double dur = (now - start) + (i * 50); 215 double pos = fmod(dur, 3000.0) / 3000.0; 216 double bouncePos = bl_abs(pos * 2 - 1); 217 double r = (bouncePos * 50 + 50) / 100; 218 double b = ((1 - bouncePos) * 50) / 100; 219 220 double rotation = pos * 360; 221 double radius = bouncePos * 25; 222 223 QTransform m; 224 m.translate(x + kHalfSize, y + kHalfSize); 225 m.rotate(rotation); 226 m.translate(-x - kHalfSize, -y - kHalfSize); 227 228 ctx.save(); 229 ctx.setTransform(m); 230 ctx.translate(x, y); 231 232 switch (styleId) { 233 case StyleId::kSolid: { 234 ctx.setBrush(QBrush(QColor(qRgb(r * 255, 0, int(b * 255))))); 235 break; 236 } 237 238 case StyleId::kLinear: { 239 QLinearGradient gr(0, kMarginSize, 0, kMarginSize + kSquareSize); 240 gr.setColorAt(0, QColor(qRgb(255, 127, 0))); 241 gr.setColorAt(1, QColor(qRgb(r * 255, 0, int(b * 255)))); 242 ctx.setBrush(QBrush(gr)); 243 break; 244 } 245 246 case StyleId::kRadial: { 247 QRadialGradient gr(kHalfSize, kHalfSize, kHalfSize, kHalfSize, kHalfSize - 15); 248 gr.setColorAt(0, QColor(qRgb(255, 127, 0))); 249 gr.setColorAt(1, QColor(qRgb(r * 255, 0, int(b * 255)))); 250 ctx.setBrush(QBrush(gr)); 251 break; 252 } 253 254 case StyleId::kConic: { 255 QConicalGradient gr(kHalfSize, kHalfSize, 270); 256 gr.setColorAt(0.0, QColor(qRgb(r * 255, 0, int(b * 255)))); 257 gr.setColorAt(0.5, QColor(qRgb(255, 127, 0))); 258 gr.setColorAt(1.0, QColor(qRgb(r * 255, 0, int(b * 255)))); 259 ctx.setBrush(QBrush(gr)); 260 break; 261 } 262 } 263 264 ctx.drawRoundedRect(kMarginSize, kMarginSize, kSquareSize, kSquareSize, radius, radius); 265 ctx.restore(); 266 267 if (++ix >= w) { ix = 0; iy++; } 268 } 269 } 270 271 void _updateTitle() { 272 char buf[256]; 273 snprintf(buf, 256, "Bounces [%dx%d] [Count=%d] [RenderTime=%.2fms FPS=%.1f]", 274 _canvas.image_width(), 275 _canvas.image_height(), 276 _count, 277 _canvas.average_render_time(), 278 _canvas.fps()); 279 280 QString title = QString::fromUtf8(buf); 281 if (title != windowTitle()) 282 setWindowTitle(title); 283 } 284 }; 285 286 int main(int argc, char *argv[]) { 287 QApplication app(argc, argv); 288 MainWindow win; 289 290 win.setMinimumSize(QSize(400, 320)); 291 win.resize(QSize(580, 520)); 292 win.show(); 293 294 return app.exec(); 295 } 296 297 #include "bl_demo_bounces.moc"