Undefined reference to gl functions when using QGLWidget

2.8k views Asked by At

I'm trying to port my old Qt/OpenGL game from Linux to Windows. I'm using Qt Creator. It compiled fine right away but gave a lot of errors like undefined reference to 'glUniform4fv@12' at linking stage.

I've tried to link more libs -lopengl32 -lglaux -lGLU32 -lglut -lglew32 but it gave the same result.

Qt also uses -lQt5OpenGLd by default.

I'm including QGLWIdget with :

#define GL_GLEXT_PROTOTYPES
#include <QGLWidget>

I've also tried using GLEW but it confilcts with Qt (or QOpenGL?).

How can I get rid of those undefined references? Is there any other library that i have to link to?

Thanks in advance.

Tomxey

1

There are 1 answers

0
peppe On BEST ANSWER

Windows doesn't provide the prototypes of any OpenGL function introduced after OpenGL 1.1. You must resolve the pointers to those functions at runtime (via GetProcAddress -- or better QOpenGLContext::getProcAddress, see below).


Qt offers excellent enablers to ease this job:

  • QOpenGLShader and QOpenGLShaderProgram allow you manage your shaders, shader programs, and their uniforms. QOpenGLShaderProgram provides nice overloads allowing you to seamlessly pass QVector<N>D or QMatrix<N>x<N> classes:

    QMatrix4x4 modelMatrix = model->transform();
    QMatrix4x4 modelViewMatrix = camera->viewMatrix() * modelMatrix;
    QMatrix4x4 modelViewProjMatrix = camera->projMatrix() * modelViewMatrix;
    ...
    program->setUniform("mv", modelViewmatrix);
    program->setUniform("mvp", modelViewProjMatrix);
    
  • QOpenGLContext::getProcAddress() is a platform-independent function resolver (useful in combination with QOpenGLContext::hasExtension() to load extension-specific functions)

  • QOpenGLContext::functions() returns a QOpenGLFunctions object (owned by the context), which offers as public API the common subset between OpenGL 2 (+FBO) / OpenGL ES 2.¹ It will resolve the pointers behind the scenes for you, so all you have to do is calling

    functions->glUniform4f(...);
    
  • QOpenGLContext::versionFunctions<VERSION>() will return a QAbstractOpenGLFunctions subclass, namely, the one matching the VERSION template parameter (or NULL if the request can't be satisfied):

    QOpenGLFunctions_3_3_Core *functions = 0;
    functions = context->versionFunctions<QOpenGLFunctions_3_3_Core>();
    if (!functions) 
         error(); // context doesn't support the requested version+profile
    functions->initializeOpenGLFunctions(context);
    
    functions->glSamplerParameterf(...); // OpenGL 3.3 API
    functions->glPatchParameteri(...); // COMPILE TIME ERROR, this is OpenGL 4.0 API
    
  • As an alternative way, you can make your "drawing" classes /inherit/ from QOpenGLFunctionsX. You can initalize them as usual, but this way you can keep your code like:

    class DrawThings : public QObject, protected QOpenGLFunctions_2_1
    {
        explicit DrawThings(QObject *parent = 0) { ... }
        bool initialize(QOpenGLContext *context)
        {
            return initializeOpenGLFunctions(context);
        }
        void draw()
        {
            Q_ASSERT(isInitialized());
            // works, it's calling the one in the QOpenGLFunctions_2_1 scope...
            glUniform4f(...); 
        }
    }
    

¹ There are also "matching" classes in the QtOpenGL module, i.e. QGLContext and QGLFunctions. If possible, avoid using QtOpenGL in new code, as it's going to be deprecated in a couple of releases in favour of the QOpenGL* classes.