The overpainting example

overpainting

Mixing OpenGL (3D) and QPainter (2D) drawing in the same viewer.

A semi-transparent eounded square is painted in 2D using a QPainter on top of a classical 3D OpenGL rendering. Useful to add 2D objects (annotations, menus, head-up display) to your viewers.

Inspired from the Qt's overpainting example. Note that this functionnality is only available with Qt 4.

viewer.h

#include <QGLViewer/qglviewer.h>

class QPaintEvent;
class QPainter;

class Viewer : public QGLViewer
{
public :
  Viewer(QWidget* parent = 0);

protected :
  virtual void draw();
  virtual void init();
  void drawOverpaint(QPainter *painter);

  virtual void paintGL() { update(); };
  virtual void paintEvent(QPaintEvent *event);
  // Could be overloaded to defer final initializations
  //virtual void showEvent(QShowEvent *event);

  virtual QString helpString() const;
};

main.cpp

#include "viewer.h"
#include <qapplication.h>

int main(int argc, char** argv)
{
  QApplication application(argc,argv);
  Viewer viewer;

  viewer.setWindowTitle("overpainting");

  viewer.show();
  return application.exec();
}

viewer.cpp

#include "viewer.h"

#include <QPainter>

using namespace std;

#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE  0x809D
#endif

Viewer::Viewer(QWidget* parent)
: QGLViewer(QGLFormat(QGL::SampleBuffers), parent) {
  setAttribute(Qt::WA_NoSystemBackground);
}

void Viewer::drawOverpaint(QPainter *painter) {
	painter->save();
    painter->translate(width()/2, height()/2);
	QRadialGradient radialGrad(QPointF(-40, -40), 100);
	radialGrad.setColorAt(0, QColor(255, 255, 255, 100));
	radialGrad.setColorAt(1, QColor(200, 200, 0, 100)); 
    painter->setBrush(QBrush(radialGrad));
	painter->drawRoundRect(-100, -100, 200, 200);
    painter->restore();
}

// Draws a spiral
void Viewer::draw()
{
  const float nbSteps = 200.0;

  glBegin(GL_QUAD_STRIP);
  for (int i=0; i<nbSteps; ++i)
    {
      const float ratio = i/nbSteps;
      const float angle = 21.0*ratio;
      const float c = cos(angle);
      const float s = sin(angle);
      const float r1 = 1.0 - 0.8f*ratio;
      const float r2 = 0.8f - 0.8f*ratio;
      const float alt = ratio - 0.5f;
      const float nor = 0.5f;
      const float up = sqrt(1.0-nor*nor);
      glColor3f(1.0-ratio, 0.2f , ratio);
      glNormal3f(nor*c, up, nor*s);
      glVertex3f(r1*c, alt, r1*s);
      glVertex3f(r2*c, alt+0.05f, r2*s);
    }
  glEnd();
}

void Viewer::init()
{
  restoreStateFromFile();
  help();
}

void Viewer::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event)
    QPainter painter;
    painter.begin(this);
    painter.setRenderHint(QPainter::Antialiasing);

    // Save current OpenGL state
    glPushAttrib(GL_ALL_ATTRIB_BITS);
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();

    // Reset OpenGL parameters
    glShadeModel(GL_SMOOTH);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_MULTISAMPLE);
    static GLfloat lightPosition[4] = { 1.0, 5.0, 5.0, 1.0 };
    glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
    qglClearColor(backgroundColor());
	
    // Classical 3D drawing, usually performed by paintGL().
    preDraw();
    draw();
    postDraw();
    // Restore OpenGL state
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glPopAttrib();

    drawOverpaint(&painter);

    painter.end();
}

QString Viewer::helpString() const
{
  QString text("<h2>O v e r p a i n t</h2>");
  text += "This example shows how to mix the 2D QPainter drawing with regular 3D in an OpenGL QGLViewer.<br>";
  text += "The <code>paintEvent</code> method is overloaded to interleave the two drawing codes.";
  return text;
}

Back to the examples main page.