odin-blend2d

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

bl_demo_pattern.cpp (8694B)


      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 #include "../bench/images_data.h"
      9 
     10 class MainWindow : public QWidget {
     11   Q_OBJECT
     12 
     13 public:
     14   QTimer _timer;
     15   QComboBox _renderer_select;
     16   QComboBox _extend_mode_select;
     17   QCheckBox _limit_fps_check;
     18   QCheckBox _bilinear_check_box;
     19   QCheckBox _fill_path_check_box;
     20   QSlider _frac_x;
     21   QSlider _frac_y;
     22   QSlider _angle;
     23   QSlider _scale;
     24   QBLCanvas _canvas;
     25   BLImage _sprites_blend2d[4];
     26   QImage _sprites_qt[4];
     27 
     28   MainWindow() {
     29     QVBoxLayout* vBox = new QVBoxLayout();
     30     vBox->setContentsMargins(0, 0, 0, 0);
     31     vBox->setSpacing(0);
     32 
     33     QGridLayout* grid = new QGridLayout();
     34     grid->setContentsMargins(5, 5, 5, 5);
     35     grid->setSpacing(5);
     36 
     37     QBLCanvas::init_renderer_select_box(&_renderer_select);
     38     _limit_fps_check.setText(QLatin1String("Limit FPS"));
     39     _bilinear_check_box.setText(QLatin1String("Bilinear"));
     40     _fill_path_check_box.setText(QLatin1String("Fill Path"));
     41 
     42     static const char* extendModeNames[] = {
     43       "PAD",
     44       "REPEAT",
     45       "REFLECT",
     46       "PAD-X PAD-Y",
     47       "PAD-X REPEAT-Y",
     48       "PAD-X REFLECT-Y",
     49       "REPEAT-X PAD-Y",
     50       "REPEAT-X REPEAT-Y",
     51       "REPEAT-X REFLECT-Y",
     52       "REFLECT-X PAD-Y",
     53       "REFLECT-X REPEAT-Y",
     54       "REFLECT-X REFLECT-Y"
     55     };
     56 
     57     static const BLExtendMode extendModeValues[] = {
     58       BL_EXTEND_MODE_PAD,
     59       BL_EXTEND_MODE_REPEAT,
     60       BL_EXTEND_MODE_REFLECT,
     61       BL_EXTEND_MODE_PAD_X_PAD_Y,
     62       BL_EXTEND_MODE_PAD_X_REPEAT_Y,
     63       BL_EXTEND_MODE_PAD_X_REFLECT_Y,
     64       BL_EXTEND_MODE_REPEAT_X_PAD_Y,
     65       BL_EXTEND_MODE_REPEAT_X_REPEAT_Y,
     66       BL_EXTEND_MODE_REPEAT_X_REFLECT_Y,
     67       BL_EXTEND_MODE_REFLECT_X_PAD_Y,
     68       BL_EXTEND_MODE_REFLECT_X_REPEAT_Y,
     69       BL_EXTEND_MODE_REFLECT_X_REFLECT_Y
     70     };
     71 
     72     for (uint32_t i = 0; i < 12; i++) {
     73       QString s = extendModeNames[i];
     74       _extend_mode_select.addItem(s, QVariant(int(extendModeValues[i])));
     75     }
     76     _extend_mode_select.setCurrentIndex(1);
     77 
     78     _frac_x.setMinimum(0);
     79     _frac_x.setMaximum(255);
     80     _frac_x.setValue(0);
     81     _frac_x.setOrientation(Qt::Horizontal);
     82 
     83     _frac_y.setMinimum(0);
     84     _frac_y.setMaximum(255);
     85     _frac_y.setValue(0);
     86     _frac_y.setOrientation(Qt::Horizontal);
     87 
     88     _angle.setMinimum(0);
     89     _angle.setMaximum(3600);
     90     _angle.setValue(0);
     91     _angle.setOrientation(Qt::Horizontal);
     92 
     93     _scale.setMinimum(0);
     94     _scale.setMaximum(1000);
     95     _scale.setValue(0);
     96     _scale.setOrientation(Qt::Horizontal);
     97 
     98     connect(&_renderer_select, SIGNAL(activated(int)), SLOT(onRendererChanged(int)));
     99     connect(&_limit_fps_check, SIGNAL(stateChanged(int)), SLOT(onLimitFpsChanged(int)));
    100     connect(&_bilinear_check_box, SIGNAL(valueChanged(int)), SLOT(onSliderChanged(int)));
    101     connect(&_fill_path_check_box, SIGNAL(valueChanged(int)), SLOT(onSliderChanged(int)));
    102     connect(&_extend_mode_select, SIGNAL(activated(int)), SLOT(onSliderChanged(int)));
    103     connect(&_frac_x, SIGNAL(valueChanged(int)), SLOT(onSliderChanged(int)));
    104     connect(&_frac_y, SIGNAL(valueChanged(int)), SLOT(onSliderChanged(int)));
    105     connect(&_angle, SIGNAL(valueChanged(int)), SLOT(onSliderChanged(int)));
    106     connect(&_scale, SIGNAL(valueChanged(int)), SLOT(onSliderChanged(int)));
    107 
    108     grid->addWidget(new QLabel("Renderer:"), 0, 0);
    109     grid->addWidget(&_renderer_select, 0, 1);
    110 
    111     grid->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding), 0, 4);
    112     grid->addWidget(&_limit_fps_check, 0, 5);
    113 
    114     grid->addWidget(new QLabel("Extend Mode:"), 1, 0);
    115     grid->addWidget(&_extend_mode_select, 1, 1);
    116 
    117     grid->addWidget(new QLabel("Fx Offset:"), 0, 2);
    118     grid->addWidget(&_frac_x, 0, 3, 1, 2);
    119 
    120     grid->addItem(new QSpacerItem(1, 0, QSizePolicy::Expanding), 0, 4);
    121     grid->addWidget(&_bilinear_check_box, 1, 5);
    122 
    123     grid->addItem(new QSpacerItem(2, 0, QSizePolicy::Expanding), 0, 4);
    124     grid->addWidget(&_fill_path_check_box, 2, 5);
    125 
    126     grid->addWidget(new QLabel("Fy Offset:"), 1, 2);
    127     grid->addWidget(&_frac_y, 1, 3, 1, 2);
    128 
    129     grid->addWidget(new QLabel("Angle:"), 2, 0);
    130     grid->addWidget(&_angle, 2, 1, 1, 4);
    131 
    132     grid->addWidget(new QLabel("Scale:"), 3, 0);
    133     grid->addWidget(&_scale, 3, 1, 1, 4);
    134 
    135     _canvas.on_render_blend2d = std::bind(&MainWindow::on_render_blend2d, this, std::placeholders::_1);
    136     _canvas.on_render_qt = std::bind(&MainWindow::on_render_qt, this, std::placeholders::_1);
    137 
    138     vBox->addItem(grid);
    139     vBox->addWidget(&_canvas);
    140     setLayout(vBox);
    141 
    142     connect(&_timer, SIGNAL(timeout()), this, SLOT(onTimer()));
    143     onInit();
    144   }
    145 
    146   void showEvent(QShowEvent* event) override { _timer.start(); }
    147   void hideEvent(QHideEvent* event) override { _timer.stop(); }
    148   void keyPressEvent(QKeyEvent* event) override {}
    149 
    150   void onInit() {
    151     _limit_fps_check.setChecked(true);
    152     _bilinear_check_box.setChecked(true);
    153 
    154     _sprites_blend2d[0].read_from_data(_resource_babelfish_png, sizeof(_resource_babelfish_png));
    155     _sprites_blend2d[1].read_from_data(_resource_ksplash_png  , sizeof(_resource_ksplash_png  ));
    156     _sprites_blend2d[2].read_from_data(_resource_ktip_png     , sizeof(_resource_ktip_png     ));
    157     _sprites_blend2d[3].read_from_data(_resource_firewall_png , sizeof(_resource_firewall_png ));
    158 
    159     for (uint32_t i = 0; i < 4; i++) {
    160       const BLImage& sprite = _sprites_blend2d[i];
    161 
    162       BLImageData sprite_data;
    163       sprite.get_data(&sprite_data);
    164 
    165       _sprites_qt[i] = QImage(
    166         static_cast<unsigned char*>(sprite_data.pixel_data),
    167         sprite_data.size.w,
    168         sprite_data.size.h,
    169         int(sprite_data.stride), QImage::Format_ARGB32_Premultiplied);
    170     }
    171 
    172     _updateTitle();
    173   }
    174 
    175   Q_SLOT void onRendererChanged(int index) { _canvas.set_renderer_type(_renderer_select.itemData(index).toInt()); }
    176   Q_SLOT void onLimitFpsChanged(int value) { _timer.setInterval(value ? 1000 / 120 : 0); }
    177 
    178   Q_SLOT void onSliderChanged(int value) { _canvas.update_canvas(true); }
    179 
    180   Q_SLOT void onTimer() {
    181     _canvas.update_canvas(true);
    182     _updateTitle();
    183   }
    184 
    185   inline double tx() const { return 256.0 + double(_frac_x.value()) / 256.0; }
    186   inline double ty() const { return 256.0 + double(_frac_y.value()) / 256.0; }
    187   inline double angle_in_radians() const { return (double(_angle.value()) / (3600.0 / 2)) * M_PI; }
    188   inline double scale() const { return double(_scale.value() + 100) / 100.0; }
    189 
    190   void on_render_blend2d(BLContext& ctx) noexcept {
    191     int rx = _canvas.image_width() / 2;
    192     int ry = _canvas.image_height() / 2;
    193 
    194     BLPattern pattern(_sprites_blend2d[0], BLExtendMode(_extend_mode_select.currentData().toInt()));
    195     pattern.rotate(angle_in_radians(), rx, ry);
    196     pattern.translate(tx(), ty());
    197     pattern.scale(scale());
    198 
    199     ctx.set_pattern_quality(
    200       _bilinear_check_box.isChecked()
    201         ? BL_PATTERN_QUALITY_BILINEAR
    202         : BL_PATTERN_QUALITY_NEAREST);
    203 
    204     ctx.set_comp_op(BL_COMP_OP_SRC_COPY);
    205 
    206     if (_fill_path_check_box.isChecked()) {
    207       ctx.clear_all();
    208       ctx.fill_circle(rx, ry, bl_min(rx, ry), pattern);
    209     }
    210     else {
    211       ctx.fill_all(pattern);
    212     }
    213   }
    214 
    215   void on_render_qt(QPainter& ctx) noexcept {
    216     int rx = _canvas.image_width() / 2;
    217     int ry = _canvas.image_height() / 2;
    218 
    219     QTransform tr;
    220     tr.translate(rx, ry);
    221     tr.rotateRadians(angle_in_radians());
    222     tr.translate(-rx + tx(), -ry + ty());
    223     tr.scale(scale(), scale());
    224 
    225     QBrush brush(_sprites_qt[0]);
    226     brush.setTransform(tr);
    227 
    228     ctx.setRenderHint(QPainter::SmoothPixmapTransform, _bilinear_check_box.isChecked());
    229     ctx.setRenderHint(QPainter::Antialiasing, true);
    230     ctx.setCompositionMode(QPainter::CompositionMode_Source);
    231 
    232     if (_fill_path_check_box.isChecked()) {
    233       double r = bl_min(rx, ry);
    234       ctx.fillRect(QRect(0, 0, _canvas.image_width(), _canvas.image_height()), QColor(0, 0, 0, 0));
    235       ctx.setBrush(brush);
    236       ctx.setPen(Qt::NoPen);
    237       ctx.drawEllipse(QPointF(qreal(rx), qreal(ry)), qreal(r), qreal(r));
    238     }
    239     else {
    240       ctx.fillRect(QRect(0, 0, _canvas.image_width(), _canvas.image_height()), brush);
    241     }
    242   }
    243 
    244   void _updateTitle() {
    245     char buf[256];
    246 
    247     snprintf(buf, 256, "Patterns [%dx%d] [RenderTime=%.2fms FPS=%.1f]",
    248       _canvas.image_width(),
    249       _canvas.image_height(),
    250       _canvas.average_render_time(),
    251       _canvas.fps());
    252 
    253     QString title = QString::fromUtf8(buf);
    254     if (title != windowTitle())
    255       setWindowTitle(title);
    256   }
    257 };
    258 
    259 int main(int argc, char *argv[]) {
    260   QApplication app(argc, argv);
    261   MainWindow win;
    262 
    263   win.setMinimumSize(QSize(20 + (128 + 10) * 4 + 20, 20 + (128 + 10) * 4 + 20));
    264   win.resize(QSize(580, 520));
    265   win.show();
    266 
    267   return app.exec();
    268 }
    269 
    270 #include "bl_demo_pattern.moc"