Paint a rect on qglwidget at specifit times

This is a minimal sample application which mixes OpenGL code and QPainter in paint handler:

#include <QtWidgets>
#include <QOpenGLFunctions_1_1>

// manually added types (normally provided by glib)
typedef unsigned guint;
typedef unsigned char guint8;

extern const struct Image {
  guint      width;
  guint      height;
  guint      bytes_per_pixel; /* 3:RGB, 4:RGBA */
  guint8     pixel_data[1];
} fluffyCat;

class GLWidget: public QOpenGLWidget, protected QOpenGLFunctions_1_1 {
  private:
    float _step;
    GLuint _idTex;
    QTimer _qTimer;
  public:
    GLWidget(QWidget *parent = 0):
      QOpenGLWidget(parent),
      _step(0.0f), _idTex(0)
    {
      _qTimer.setInterval(100); // 100 ms -> 10 Hz
      QObject::connect(&_qTimer, &QTimer::timeout,
        this, &GLWidget::timeout);
    }
  protected:
    virtual void initializeGL();
    virtual void paintGL();
  private:
    void timeout();
};

void GLWidget::initializeGL()
{
  initializeOpenGLFunctions();
  glClearColor(0.525, 0.733f, 0.851, 1.0);
  glGenTextures(1, &_idTex);
  glBindTexture(GL_TEXTURE_2D, _idTex);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, fluffyCat.width, fluffyCat.height, 0,
    GL_RGB, GL_UNSIGNED_BYTE, fluffyCat.pixel_data);
  glBindTexture(GL_TEXTURE_2D, 0);
  _qTimer.start();
}

void GLWidget::paintGL()
{
  // prepare OpenGL rendering
  QPainter qPainter(this);
  qPainter.beginNativePainting();
  // do OpenGL rendering
  glColor3f(1.0f, 1.0f, 1.0f);
  bool tex2dOld = glIsEnabled(GL_TEXTURE_2D);
  glEnable(GL_TEXTURE_2D);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  static GLfloat envColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, envColor);
  glBindTexture(GL_TEXTURE_2D, _idTex);
  float x = sin(_step) * 0.5f, y = cos(_step) * 0.5f;
#if 0 // does not work (no tex-coords)
  glRectf(x - 0.5f, y - 0.5f, x + 0.5f, y + 0.5f);
#else // (not) 0
  glBegin(GL_QUADS);
  glColor3f(1.0f, 1.0f, 1.0f);
  glTexCoord2i(0, 1);
  glVertex2f(x - 0.5f, y - 0.5f);
  glTexCoord2i(1, 1);
  glVertex2f(x + 0.5f, y - 0.5f);
  glTexCoord2i(1, 0);
  glVertex2f(x + 0.5f, y + 0.5f);
  glTexCoord2i(0, 0);
  glVertex2f(x - 0.5f, y + 0.5f);
  glEnd();
#endif // 0
  glBindTexture(GL_TEXTURE_2D, 0);
  //if (!tex2dOld) glDisable(GL_TEXTURE_2D);
  // prepare Qt painting
  qPainter.endNativePainting();
  // do Qt painting (HUD)
  QPen qPen;
  qPen.setWidth(1);
  qPen.setColor(QColor(Qt::black));
  qPen.setStyle(Qt::SolidLine);
  qPainter.resetMatrix();
  qPainter.setPen(qPen);
  qPainter.drawLine(0, 0, width(), height());
  qPainter.drawLine(0, height(), width(), 0);
}

void GLWidget::timeout()
{
  _step = fmod(_step + 0.1, 2 * 3.141);
  update(); // force redraw
}

int main(int argc, char **argv)
{
  QApplication app(argc, argv);
  QMainWindow win;
  GLWidget view3d;
  win.setCentralWidget(&view3d);
  win.show();
  return app.exec();
}

and the source for the texture image:

/* GIMP RGB C-Source image dump (fluffyCat.cc) */

// manually added types (normally provided by glib)
typedef unsigned guint;
typedef unsigned char guint8;

struct Image {
  guint      width;
  guint      height;
  guint      bytes_per_pixel; /* 3:RGB, 4:RGBA */ 
  guint8     pixel_data[16 * 16 * 3 + 1];
};
extern const Image fluffyCat;
const Image fluffyCat = {
  16, 16, 3,
  "x\211s\215\232\200gw`fx`at[cx^cw^fu\\itZerWn|ap~cv\204jnzedq^fr^kzfhv^Ra"
  "GRbMWdR\\jXer^qw_\311\256\226\271\253\235\275\264\252\315\277\260\304\255"
  "\231u~i\213\225\207l{fly`jx\\^nRlz_z\206nlx`t~i\221\211s\372\276\243\375"
  "\336\275\376\352\340\356\312\301\235\216\212judgwcl~f\212\226u}\206h\212"
  "\224q\231\237z\232\236{\216\225v\225\230\200\306\274\244\376\360\327\376"
  "\361\331\376\360\341\326\275\272\253\240\244{\203p\202\220xp~e{\204^\222"
  "\230n\212\217g\240\242{\234\236z\214\222r\270\271\247\360\353\340\376\370"
  "\336\376\363\334\375\357\336\310\254\262\232\223\234\\gRfrX\204\220z\212"
  "\225g\225\232j\254\255\177\252\250{\225\226u\304\302\265\374\365\351\376"
  "\375\366\376\367\341\376\361\320\374\346\324\306\241\242\237\232\235n{fj"
  "xckyfu~fUX@VZCfnT\231\231\207\374\374\371\377\372\354\376\376\374\376\376"
  "\372\376\362\332\375\340\301\341\300\264\260\253\262jvdbq\\XkVJTDNTCCG8O"
  "TE\322\321\313\377\377\375\376\376\373\376\377\376\376\376\375\376\374\362"
  "\376\360\342\344\311\306\250\244\254R_PL^HXkT<@2OP@`dP\217\220\177\374\374"
  "\370\377\377\374\376\375\371\377\377\376\376\374\360\377\367\336\376\350"
  "\316\342\303\274\246\236\245jtbXdQTdNQYGU\\KchV\317\315\302\377\376\372\377"
  "\376\367\376\373\360\377\376\367\376\366\337\376\355\312\374\331\271\323"
  "\263\251\216\214\214\\hTP^HL\\FR[LMXI^dW\355\352\342\376\375\366\377\374"
  "\360\376\374\361\376\374\361\376\356\321\374\331\264\374\330\266\330\270"
  "\260\200||Y`SLVE>K9BJ<CN?VYP\347\330\322\376\366\345\376\363\330\376\367"
  "\337\377\372\350\374\342\314\326\243\210\375\350\314\352\317\304shc^`TV`"
  "RVbT>B4IS?PTD\244\232\216\374\355\320\376\354\311\376\351\306\376\362\332"
  "\374\344\321\267\206u\375\362\337\326\274\272\\POMNBT]LNZH:<*<A*TV>OI;\242"
  "\222\207\340\304\243\375\335\262\372\336\272\376\361\334\320\241\212\374"
  "\352\322\266\233\237c\\WFH;MR>\\`F~xP\220\214[pqE\211\202\\g]=\230\214`\313"
  "\266\207\344\303\240\362\336\274\323\257\201\333\304\240\305\252\204\254"
  "\232p\216\206\\\206\203U\232\224b\234\244b\246\257m\220\232`\224\227h~\202"
  "W\206\213]\204\210W\227\227i|\177RvzNlsGrtJwtLz}N{\204RlxF",
};

(Sorry, for the low image quality. Hi-res picture whould have been too large for this site.)

The two files have to compiled and to to be linked together. (Instead of using a header, I simply (re-)declared the variable in fluffyCat.cc at the beginning of the other file.)

The Qt project file testQGLWidgetHUD.pro:

SOURCES = testQGLWidgetHUD.cc fluffyCat.cc

QT += widgets opengl

Snapshot of the testQGLWidgetHUD

By the way, I didn’t realize the OP was asking for QGLWidget. The sample uses the new QOpenGLWidget which is recommended since Qt5+.

The QTimer is used for very simple kind of animation (to show that periodical painting is done).

Btw. I stumbled upon a mistake (which hit me not the first time…)
It is important to set GL_TEXTURE_MIN_FILTER and GL_TEXTURE_MAG_FILTER because these are two of the rare OpenGL states which do not work if left with default values.

Leave a Comment