odin-blend2d

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

bl_demo_sprites.cpp (8549B)


      1 #include <stdlib.h>
      2 #include <vector>
      3 
      4 #include "bl_qt_headers.h"
      5 #include "bl_qt_canvas.h"
      6 
      7 #include "../bench/images_data.h"
      8 
      9 class MainWindow : public QWidget {
     10   Q_OBJECT
     11 
     12 public:
     13   QTimer _timer;
     14   QSlider _count_slider;
     15   QComboBox _renderer_select;
     16   QComboBox _comp_op_select;
     17   QCheckBox _limit_fps_check;
     18   QBLCanvas _canvas;
     19 
     20   BLRandom _random;
     21   std::vector<BLPoint> _coords;
     22   std::vector<BLPoint> _steps;
     23   std::vector<uint32_t> _sprite_ids;
     24 
     25   bool _animate = true;
     26   BLCompOp _comp_op = BL_COMP_OP_SRC_OVER;
     27 
     28   BLImage _sprites_blend2d[4];
     29   QImage _sprites_qt[4];
     30 
     31   enum ShapeType {
     32     kShapeRect,
     33     kShapeRectPath,
     34     kShapeRoundRect,
     35     kShapePolyPath,
     36   };
     37 
     38   MainWindow() : _random(0x1234) {
     39     QVBoxLayout* vBox = new QVBoxLayout();
     40     vBox->setContentsMargins(0, 0, 0, 0);
     41     vBox->setSpacing(0);
     42 
     43     QGridLayout* grid = new QGridLayout();
     44     grid->setContentsMargins(5, 5, 5, 5);
     45     grid->setSpacing(5);
     46 
     47     QBLCanvas::init_renderer_select_box(&_renderer_select);
     48     _comp_op_select.addItem("SrcOver", QVariant(int(BL_COMP_OP_SRC_OVER)));
     49     _comp_op_select.addItem("SrcCopy", QVariant(int(BL_COMP_OP_SRC_COPY)));
     50     _comp_op_select.addItem("SrcAtop", QVariant(int(BL_COMP_OP_SRC_ATOP)));
     51     _comp_op_select.addItem("DstAtop", QVariant(int(BL_COMP_OP_DST_ATOP)));
     52     _comp_op_select.addItem("Xor", QVariant(int(BL_COMP_OP_XOR)));
     53     _comp_op_select.addItem("Plus", QVariant(int(BL_COMP_OP_PLUS)));
     54     _comp_op_select.addItem("Multiply", QVariant(int(BL_COMP_OP_MULTIPLY)));
     55     _comp_op_select.addItem("Screen", QVariant(int(BL_COMP_OP_SCREEN)));
     56     _comp_op_select.addItem("Overlay", QVariant(int(BL_COMP_OP_OVERLAY)));
     57     _comp_op_select.addItem("Darken", QVariant(int(BL_COMP_OP_DARKEN)));
     58     _comp_op_select.addItem("Lighten", QVariant(int(BL_COMP_OP_LIGHTEN)));
     59     _comp_op_select.addItem("Color Dodge", QVariant(int(BL_COMP_OP_COLOR_DODGE)));
     60     _comp_op_select.addItem("Color Burn", QVariant(int(BL_COMP_OP_COLOR_BURN)));
     61     _comp_op_select.addItem("Hard Light", QVariant(int(BL_COMP_OP_HARD_LIGHT)));
     62     _comp_op_select.addItem("Soft Light", QVariant(int(BL_COMP_OP_SOFT_LIGHT)));
     63     _comp_op_select.addItem("Difference", QVariant(int(BL_COMP_OP_DIFFERENCE)));
     64     _comp_op_select.addItem("Exclusion", QVariant(int(BL_COMP_OP_EXCLUSION)));
     65 
     66     _limit_fps_check.setText(QLatin1String("Limit FPS"));
     67 
     68     _count_slider.setOrientation(Qt::Horizontal);
     69     _count_slider.setMinimum(1);
     70     _count_slider.setMaximum(10000);
     71     _count_slider.setSliderPosition(200);
     72 
     73     _canvas.on_render_blend2d = std::bind(&MainWindow::on_render_blend2d, this, std::placeholders::_1);
     74     _canvas.on_render_qt = std::bind(&MainWindow::on_render_qt, this, std::placeholders::_1);
     75 
     76     connect(&_renderer_select, SIGNAL(activated(int)), SLOT(onRendererChanged(int)));
     77     connect(&_comp_op_select, SIGNAL(activated(int)), SLOT(onCompOpChanged(int)));
     78     connect(&_limit_fps_check, SIGNAL(stateChanged(int)), SLOT(onLimitFpsChanged(int)));
     79     connect(&_count_slider, SIGNAL(valueChanged(int)), SLOT(onCountChanged(int)));
     80 
     81     grid->addWidget(new QLabel("Renderer:"), 0, 0);
     82     grid->addWidget(&_renderer_select, 0, 1);
     83 
     84     grid->addWidget(new QLabel("Comp Op:"), 0, 2);
     85     grid->addWidget(&_comp_op_select, 0, 3);
     86 
     87     grid->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding), 0, 4);
     88     grid->addWidget(&_limit_fps_check, 0, 5, Qt::AlignRight);
     89 
     90     grid->addWidget(new QLabel("Count:"), 1, 0, 1, 1, Qt::AlignRight);
     91     grid->addWidget(&_count_slider, 1, 1, 1, 7);
     92 
     93     vBox->addLayout(grid);
     94     vBox->addWidget(&_canvas);
     95     setLayout(vBox);
     96 
     97     connect(&_timer, SIGNAL(timeout()), this, SLOT(onTimer()));
     98     connect(new QShortcut(QKeySequence(Qt::Key_P), this), SIGNAL(activated()), SLOT(onToggleAnimate()));
     99 
    100     onInit();
    101   }
    102 
    103   void showEvent(QShowEvent* event) override { _timer.start(); }
    104   void hideEvent(QHideEvent* event) override { _timer.stop(); }
    105   void keyPressEvent(QKeyEvent* event) override {}
    106 
    107   void onInit() {
    108     _sprites_blend2d[0].read_from_data(_resource_babelfish_png, sizeof(_resource_babelfish_png));
    109     _sprites_blend2d[1].read_from_data(_resource_ksplash_png  , sizeof(_resource_ksplash_png  ));
    110     _sprites_blend2d[2].read_from_data(_resource_ktip_png     , sizeof(_resource_ktip_png     ));
    111     _sprites_blend2d[3].read_from_data(_resource_firewall_png , sizeof(_resource_firewall_png ));
    112 
    113     for (uint32_t i = 0; i < 4; i++) {
    114       const BLImage& sprite = _sprites_blend2d[i];
    115 
    116       BLImageData sprite_data;
    117       sprite.get_data(&sprite_data);
    118 
    119       _sprites_qt[i] = QImage(
    120         static_cast<unsigned char*>(sprite_data.pixel_data),
    121         sprite_data.size.w,
    122         sprite_data.size.h,
    123         int(sprite_data.stride), QImage::Format_ARGB32_Premultiplied);
    124     }
    125 
    126     setCount(_count_slider.sliderPosition());
    127     _limit_fps_check.setChecked(true);
    128     _updateTitle();
    129   }
    130 
    131   double randomSign() noexcept { return _random.next_double() < 0.5 ? 1.0 : -1.0; }
    132 
    133   Q_SLOT void onToggleAnimate() { _animate = !_animate; }
    134   Q_SLOT void onRendererChanged(int index) { _canvas.set_renderer_type(_renderer_select.itemData(index).toInt());  }
    135   Q_SLOT void onCompOpChanged(int index) { _comp_op = (BLCompOp)_comp_op_select.itemData(index).toInt(); };
    136   Q_SLOT void onLimitFpsChanged(int value) { _timer.setInterval(value ? 1000 / 120 : 0); }
    137   Q_SLOT void onCountChanged(int value) { setCount(size_t(value)); }
    138 
    139   Q_SLOT void onTimer() {
    140     if (_animate) {
    141       double w = _canvas.image_width();
    142       double h = _canvas.image_height();
    143 
    144       size_t size = _coords.size();
    145       for (size_t i = 0; i < size; i++) {
    146         BLPoint& vertex = _coords[i];
    147         BLPoint& step = _steps[i];
    148 
    149         vertex += step;
    150         if (vertex.x < 0 || vertex.x >= w) {
    151           vertex.x -= step.x;
    152           if (vertex.x < 0) vertex.x = 0;
    153           if (vertex.x >= w) vertex.x = w - 1;
    154           step.x = -step.x;
    155         }
    156 
    157         if (vertex.y < 0 || vertex.y >= h) {
    158           vertex.y -= step.y;
    159           if (vertex.y < 0) vertex.y = 0;
    160           if (vertex.y >= h) vertex.y = h - 1;
    161           step.y = -step.y;
    162         }
    163       }
    164     }
    165 
    166     _canvas.update_canvas(true);
    167     _updateTitle();
    168   }
    169 
    170   void on_render_blend2d(BLContext& ctx) noexcept {
    171     ctx.set_comp_op(BL_COMP_OP_SRC_COPY);
    172     ctx.fill_all(bl_background_for_comp_op(_comp_op));
    173     ctx.set_comp_op(_comp_op);
    174 
    175     size_t size = _coords.size();
    176     int rectSize = 128;
    177     int halfSize = rectSize / 2;
    178 
    179     for (size_t i = 0; i < size; i++) {
    180       int x = int(_coords[i].x) - halfSize;
    181       int y = int(_coords[i].y) - halfSize;
    182       ctx.blit_image(BLPointI(x, y), _sprites_blend2d[_sprite_ids[i]]);
    183     }
    184   }
    185 
    186   void on_render_qt(QPainter& ctx) noexcept {
    187     ctx.setCompositionMode(QPainter::CompositionMode_Source);
    188     ctx.fillRect(0, 0, _canvas.image_width(), _canvas.image_height(), bl_rgba_to_qcolor(bl_background_for_comp_op(_comp_op)));
    189     ctx.setRenderHint(QPainter::Antialiasing, true);
    190     ctx.setCompositionMode(bl_comp_op_to_qt_composition_mode(_comp_op));
    191 
    192     size_t size = _coords.size();
    193     int rectSize = 128;
    194     int halfSize = rectSize / 2;
    195 
    196     for (size_t i = 0; i < size; i++) {
    197       int x = int(_coords[i].x) - halfSize;
    198       int y = int(_coords[i].y) - halfSize;
    199       ctx.drawImage(QPoint(x, y), _sprites_qt[_sprite_ids[i]]);
    200     }
    201   }
    202 
    203   void setCount(size_t size) {
    204     int w = _canvas.image_width();
    205     int h = _canvas.image_height();
    206     size_t i = _coords.size();
    207 
    208     if (w < 16) w = 128;
    209     if (h < 16) h = 128;
    210 
    211     _coords.resize(size);
    212     _steps.resize(size);
    213     _sprite_ids.resize(size);
    214 
    215     while (i < size) {
    216       _coords[i].reset(_random.next_double() * (w - 1),
    217                        _random.next_double() * (h - 1));
    218       _steps[i].reset((_random.next_double() * 2 + 1) * randomSign(),
    219                       (_random.next_double() * 2 + 1) * randomSign());
    220       _sprite_ids[i] = _random.next_uint32() % 4u;
    221       i++;
    222     }
    223   }
    224 
    225   void _updateTitle() {
    226     char buf[256];
    227     snprintf(buf, 256, "Sprites [%dx%d] [Count=%zu] [RenderTime=%.2fms FPS=%.1f]",
    228       _canvas.image_width(),
    229       _canvas.image_height(),
    230       _coords.size(),
    231       _canvas.average_render_time(),
    232       _canvas.fps());
    233 
    234     QString title = QString::fromUtf8(buf);
    235     if (title != windowTitle())
    236       setWindowTitle(title);
    237   }
    238 };
    239 
    240 int main(int argc, char *argv[]) {
    241   QApplication app(argc, argv);
    242   MainWindow win;
    243 
    244   win.setMinimumSize(QSize(400, 320));
    245   win.resize(QSize(580, 520));
    246   win.show();
    247 
    248   return app.exec();
    249 }
    250 
    251 #include "bl_demo_sprites.moc"