Search code examples
c++qtgraphicsqpainter

Tiled rendering with QPainter


I'm implementing a tiled rendering system (to avoid the GL_MAX_VIEWPORT_DIMS-limitation). I need to support QWidget-overlays and must therefor implement tiled rendering for widgets as well. The plan is to do so by creating a QPainter with the correct transforms and calling QWidget::render with the "transformed" QPainter.

I have some testcode to do this:

int w = 24;
int h = 24;
QImage tiles[4];
QPushButton btn;
btn.resize(w, h);
btn.move(w/2, h/2);
for (int i = 0; i < 2; ++i) {
  for (int j = 0; j < 2; ++j) {
    int tileidx = i + 2*j;
    tiles[tileidx] = QImage(QSize(w, h), QImage::Format_ARGB32);
    tiles[tileidx].fill(0);

    QPainter painter(&tiles[tileidx]);
    painter.setViewport(i*w,i*h, w,h); // or setWindow()
    painter.save();
    painter.translate(btn.pos());
    btn.render(&painter);
    painter.restore();
  }
}
for (int i = 0; i < 4; ++i) {
  tiles[i].save(QString("c:/temp/tile%0.bmp").arg(i));
}

I would expect one forth of the button to be rendered in each tile, but the result is quite different:

Tile 0 Tile 2
Tile 1 Tile 3

Tiles numbers above are:

0 2
1 3

How do I correctly set up the QPainter (or achive what I need)?


Solution

  • I ended up bypassing the QPainter, doing the calculation myself and calling QWidget::render() directly:

    QRect viewport(i*w,j*h, w,h);
    QRect intersection = viewport.intersected(widget->frameGeometry());
    if (!intersection.isEmpty()) {
      QPoint target = intersection.topLeft() - viewport.topLeft();
      QPoint topLeft = widget->mapFromGlobal(intersection.topLeft());
      QPoint bottomRight = widget->mapFromGlobal(intersection.bottomRight());     
      widget->render(&paintDevice, target, QRegion(intersection));
    }