1
votes

I need to add some 3D graphics to an existing Qt application. I'm using Qt 5.2, but I'm using the old QGL* classes, at least for the moment. To start, I just want to draw a single triangle.

I had things working, but then I tried to explicitly set the OpenGL version by calling QGLWidget::setFormat, and suddenly my triangle doesn't draw anymore. I commented out the line where I actually set the version, and it made no difference: calling QGLWidget::setFormat with the value returned by QGLWidget::format suddenly makes drawing not happen. What happened?

testGL.cpp:

#include <QApplication>
#include <QDialog>
#include <QVBoxLayout>

#include "GLWidget.h"

class GLDialog : public QDialog
{
public:
  GLDialog()
  {
    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->addWidget(new GLWidget);
  }
};

int main(int argc, char **argv)
{
  QApplication app(argc, argv);

  GLDialog dlg;
  dlg.resize(200,200);
  dlg.show();

  return app.exec();

}

GLWidget.h:

#ifndef GLWIDGET_H
#define GLWIDGET_H

#include <QColor>
#include <QGLWidget>
#include <QVector>
#include <QVector3D>

class GLWidget : public QGLWidget
{
  Q_OBJECT
public:
  GLWidget(QWidget * = 0, const QGLWidget * = 0, Qt::WindowFlags = 0);

protected:
  virtual void initializeGL();
  virtual void paintGL();
  virtual void resizeGL(int, int);
  //virtual void mousePressEvent(QMouseEvent *);
  //virtual void mouseMoveEvent(QMouseEvent *);

private:
  QVector<QVector3D> _triangle;
  QColor _backgroundColour;
  QColor _triangleColour;
};

#endif

GLWidget.cpp:

#include <QtOpenGL>
#include <QGLContext>
#include <QGLFormat>
#include <QGLShader>
#include <QGLShaderProgram>

#include <QDebug>

#include "GLWidget.h"


GLWidget::GLWidget(QWidget *parent, const QGLWidget *shareWidget, Qt::WindowFlags f)
: QGLWidget(parent, shareWidget, f)
{ 
  QGLFormat newFormat(format());
  //newFormat.setVersion(3,3);
  /* Comment out the following line and a triangle appears */
  setFormat(newFormat);
}

void GLWidget::initializeGL()
{
  _backgroundColour = Qt::black;
  _triangleColour = Qt::white;
  _triangle.push_back(QVector3D(-0.75, 0.75, 0));
  _triangle.push_back(QVector3D(-0.75, -0.75, 0));
  _triangle.push_back(QVector3D(0.75, -0.75, 0));


}

void GLWidget::paintGL()
{
  qglClearColor(_backgroundColour);
  glClear(GL_COLOR_BUFFER_BIT);

  glEnableClientState(GL_VERTEX_ARRAY);
  glVertexPointer(3, GL_FLOAT, 0, _triangle.constData());
  glDrawArrays(GL_TRIANGLES, 0, 3);


}

void GLWidget::resizeGL(int width, int height)
{
  int side = qMin(width, height);

  int hoffset = (int)((width - side) / 2.0 + 0.5);
  int voffset = (int)((height - side) / 2.0 + 0.5);

  glViewport(hoffset, voffset, side, side);
}

testGL.pro:

######################################################################
# Automatically generated by qmake (3.0) Fri Apr 18 16:09:15 2014
######################################################################

TEMPLATE = app
TARGET = testGL
INCLUDEPATH += .
CONFIG += qt warn_on debug

QT += opengl

# Input
HEADERS += GLWidget.h
SOURCES += GLWidget.cpp testGL.cpp

I'm a total beginner to OpenGL, so please excuse silliness in my code. Note that I'm not explicitly setting shaders. That was going to be my next step.

UPDATE:

I followed this advice and used the alternate QGLWidget constructor that takes a QGLFormat object. I get some interesting behaviour.

  1. If I just create a QGLFormat, but don't set its version, I get a triangle. The version requested is 2.0, but checking the version inside my GLWidget constructor reveals that it's 3.0.
  2. If I explicitly call QGLFormat::setVersion(3,0), I get version 3.3, and I don't get a triangle.
  3. If I explicitly call QGLFormat::setVersion(2,0), I get a triangle, and the version that's set is 3.0.

The new GLDialog code:

class GLDialog : public QDialog
{
public:
  GLDialog()
  {
    QVBoxLayout *layout = new QVBoxLayout(this);
    QGLFormat format;

    /* Comment this line out or change to 2,0 to get a triangle */
    format.setVersion(3,0); 

    layout->addWidget(new GLWidget(format,this));
  }
};

Outputs this format string in the GLWidget constructor:

QGLFormat(options QFlags(0x1|0x2|0x4|0x8|0x20|0x80|0x400) , plane  0 , depthBufferSize  24 , accumBufferSize  -1 , stencilBufferSize  8 , redBufferSize  8 , greenBufferSize  8 , blueBufferSize  8 , alphaBufferSize  8 , samples  -1 , swapInterval  -1 , majorVersion  3 , minorVersion  3 , profile  1 )

And if I comment out the line indicated:

QGLFormat(options QFlags(0x1|0x2|0x4|0x8|0x20|0x80|0x400) , plane  0 , depthBufferSize  24 , accumBufferSize  -1 , stencilBufferSize  8 , redBufferSize  8 , greenBufferSize  8 , blueBufferSize  8 , alphaBufferSize  8 , samples  -1 , swapInterval  -1 , majorVersion  3 , minorVersion  0 , profile  0 )

And if I change the requested version to 2.0:

QGLFormat(options QFlags(0x1|0x2|0x4|0x8|0x20|0x80|0x400) , plane  0 , depthBufferSize  24 , accumBufferSize  -1 , stencilBufferSize  8 , redBufferSize  8 , greenBufferSize  8 , blueBufferSize  8 , alphaBufferSize  8 , samples  -1 , swapInterval  -1 , majorVersion  3 , minorVersion  0 , profile  0 )
1
What is the version of Qt that you're using, and what platform? Note that setFormat is obsolete. Don't use it. Deal with the context directly.Kuba hasn't forgotten Monica
Qt 5.2 on Arch Linux. QGLContext doesn't seem to let me set the OpenGL version... unless you mean call QGLWidget::context()->setFormat(...). The background doesn't even get cleared when I do that.rainbowgoblin

1 Answers

0
votes

A call to makeCurrent() inside my GLWidget constructor, after I've called setFormat() does the trick. With Qt 5.2, setting the format doesn't actually give me the format I request (i.e., requesting OpenGL 2.1 actually sets OpenGL 3.0, whereas requesting 3.0 actually sets 3.3). And although my system supports OpenGL 3.3, I don't get a triangle unless the version used is 3.0 or less. But setting the version works.

A call to the alternate constructor that takes a QGLFormat object also works (up to version 3.0... again, requesting 3.0 gives me 3.3, requesting 2.1 gives me 3.0).

With Qt 4.8, the same code works, and can request up to version 3.3, and the version I request is the version I get.

A working example:

testGL.cpp:

#include <QApplication>
#include <QDialog>
#include <QGLFormat>
#include <QVBoxLayout>

#include <QDebug>
#include "GLWidget.h"

class GLDialog : public QDialog
{
public:
  GLDialog()
  {
    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->addWidget(new GLWidget(this));//format,this));
  }
};

int main(int argc, char **argv)
{
  QApplication app(argc, argv);

  GLDialog dlg;
  dlg.resize(200,200);
  dlg.show();

  return app.exec();

}

GLWidget.h:

#ifndef GLWIDGET_H
#define GLWIDGET_H

#include <QColor>
#include <QGLWidget>
#include <QGLFormat>
#include <QGLFunctions>
#include <QGLShader>
#include <QGLShaderProgram>

#include <QVector>
#include <QVector3D>

class GLWidget : public QGLWidget, protected QGLFunctions
{
  Q_OBJECT
public:
  GLWidget(QWidget * = 0, const QGLWidget * = 0, Qt::WindowFlags = 0);

protected:
  virtual void initializeGL();
  virtual void paintGL();
  virtual void resizeGL(int, int);

private: 
  QVector<QVector3D> _triangle;
  QColor _backgroundColour;
};

#endif

GLWidget.cpp:

#include <QtOpenGL>
#include <QGLContext>
#include <QGLFormat>

#include <QDebug>

#include <string>
#include <cstring>
#include "GLWidget.h"

GLWidget::GLWidget(QWidget *parent, const QGLWidget *shareWidget, Qt::WindowFlags f)
: QGLWidget(parent, shareWidget, f)
{ 
  QGLFormat newFormat(format());
  newFormat.setVersion(2,1);
  setFormat(newFormat);

  makeCurrent();
  resizeGL(width(), height());
}

void GLWidget::initializeGL()
{  
  _backgroundColour = Qt::black;

  _triangle.push_back(QVector3D(-0.75, 0.75, 0));
  _triangle.push_back(QVector3D(-0.75, -0.75, 0));
  _triangle.push_back(QVector3D(0.75, -0.75, 0));
}

void GLWidget::paintGL()
{
  qglClearColor(_backgroundColour);
  glClear(GL_COLOR_BUFFER_BIT);

  glEnableClientState(GL_VERTEX_ARRAY);
  glVertexPointer(3, GL_FLOAT, 0, _triangle.constData());
  glDrawArrays(GL_TRIANGLES, 0, 3);

}

void GLWidget::resizeGL(int width, int height)
{
  int side = qMin(width, height);

  int hoffset = (int)((width - side) / 2.0 + 0.5);
  int voffset = (int)((height - side) / 2.0 + 0.5);

  glViewport(hoffset, voffset, side, side);
}

testGL.pro:

######################################################################
# Automatically generated by qmake (3.0) Fri Apr 18 16:09:15 2014
######################################################################

TEMPLATE = app
TARGET = testGL
INCLUDEPATH += .
CONFIG += qt warn_on debug

QT += opengl

# Input
HEADERS += GLWidget.h
SOURCES += GLWidget.cpp testGL.cpp