Search code examples
c++qtgraphicspixelqpainter

Qt/C++ : drawing efficiently


I have designed a program which, basically, cuts a geometrical shape into many small triangles (in a "left canvas"), applies some simple mathematical transformation to the bunch of triangles, and redraws them in their new configuration. See screen capture below.

screen cap 1

In order to draw these triangles, I use QPainter::drawPolygon. Each triangle on the right corresponds to a triangle on the left, so I know what color I want to use to draw it.

So far, fine. Even if I draw many more triangles than this (when I use much smaller triangles to cut the shape), this is fast enough.

I've added a feature to my program: I can draw triangles extracted from a picture instead of plain triangles: see following screen capture.

enter image description here

The problem is that the way I do this is too slow. Here's how I do it:

  1. I run through all the triangles
  2. For each triangle, I compute the coordinates of each pixel that will be displayed.
  3. For each one of these pixels, I compute the coordinates of the corresponding pixel on the picture (this is an easy mathematical operation), and I retrieve that pixel's color.
  4. I use QPainter::setPen(QColor) and QPainter::drawPoint(QPoint) to draw the pixel.

I am new to programming in Qt and I know nothing about graphics, so this is what I could come up with. The problem is that it's "unacceptably" too slow (the paintEvent of each canvas takes about 0.15s, compared to 0.01s in the case of plain triangles).

I ran a profiler to try to understand what's going on, I noticed that in the canvas widget's paintEvent,

  1. 58% of the time is spent in QPainter::drawPoint
  2. 27% of the time is spent in QPainter::setPen

It seems that QPainter::drawPoint is far too complicated and slow: I just want it to print a pixel of a given color, that's it.

I may have found a solution to my problem: store a QImage (as a member variable of my canvas widget) that represents the whole thing I want my canvas to display, and define it entirely in my paintEvent pixel by pixel, and then draw it at once at the end of my paintEvent with QPainter::drawImage. I have a hint that this will be much faster. But before I rewrite my code all over again, I'd like to know whether that's really what I want to do.

I hope I didn't bore you to do death! Many thanks in advance for your insights.


Solution

  • Non-OpenGl solution :

    Use a RGB buffer for the destination image. Work through your 3 first steps as you did before. Once you have found the position and the pixel color, you set it on this buffer. Then you use

    QImage::QImage ( uchar * data, int width, int height, Format format )
    

    to construct the image based on the previous buffer. It is close to the solution you provided and will be much faster than what you currently have.