7
votes

I posted a question earlier on how to get OpenGL working on Qt, but now I want to be able to use the latest functions OpenGL has for use. Before Qt, I was using glew; but Qt is saying that glew is conflicting with its QtOpenGL header file. I looked into QGLWidget and QGLFunctions, but to be frank I'm confused as to what I should really be doing in order to simply access OpenGL's functions.

Now, I got Qt 5.4 using Qt Creator 3.3.0 and am utilising the new QOpenGLWidget; however lack of guidance in how it ought to be used throws me off a little: the Qt documentation is there and does help, but it only demonstrates how to instantiate it, rather than utilise it in other locations of the program. I understand that this QOpenGLWidget functions similar to QGLWidget. Qt details that I should be inheriting from it; however I am not instantiating an OpenGL context within the class it wants to use OpenGL functions; that happens in the class 'glWidget', which inherits from QOpenGLWidget.

For example, take this excerpt from one of my classes that uses OpenGL code:

void Mesh::init()
{
    pNumIndices = pIndices.size();

    glGenVertexArrays(1, &pVAO);
    glGenBuffers(1, &pVertexBuffer);
    glGenBuffers(1, &pIndexBuffer);
    glBindVertexArray(pVAO);

    glBindBuffer(GL_ARRAY_BUFFER, pVertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, pVertices.size() * sizeof(Vertex),
                 &pVertices[0], GL_STATIC_DRAW);

    // etc..
}

Mesh is a class that doesn't inherit from anything. Originally, it only used glew so that it can get declarations of OpenGL functions; it didn't need to know whether they were valid or not, since that is glew's job. Then in the mainApp class, I would be instantiating glew. I also understand that there is also a QOpenGLFunctions class which somewhat functions similar to that of glew, but with all these GL classes it's blatantly confusing to know what to use. What's more is that I tried look for glGenVertexArrays(..) but it's not found in QOpenGLBuffer, QOpenGLFunctions or QOpenGLWidget; and as far I'm aware, as of OpenGL 4.5 it's still part of the spec; but my graphics drivers do not use OpenGL 4.5, so I use OpenGL 4.3 instead. Suffice it to say that I'm willing to abandon glew to adopt Qt's own approach to calling OpenGL functions.

In a program where various classes are using OpenGL functions, how can I utilise Qt to be able to call them without the use of glew? Mesh is one of those classes that doesn't instantiate OpenGL, but merely uses the functions thereof.

Just so people know, I have been using Qt for some time (not enough though!) and do enjoy Qt; but I do need to know how I can use Qt in conjunction with OpenGL to continue development. Most tutorials out there still use pre-5.4 stuff.

4
glGenVertexArrays is for vertex array objects, so what's the class name you should be looking for? That's right, QOpenGLVertexArrayObject!peppe
I personally don't like the Q stuff where it encapsultes OpenGL stuff centrally. I very much prefer to do that sort of stuff myself with my own classes.Poriferous

4 Answers

4
votes

In Qt 5.4, there are headers with version specific OpenGL Functions, so:

#include <QOpenGLFunctions_3_3_Core>

Or whatever version you want to use. Then somewhere with a valid OpenGL context like QOpenGLWidget::initializeGL() create and initialise a QOpenGLFunctions object:

QOpenGLFunctions_3_3_Core *fun = new QOpenGLFunctions_3_3_Core;
fun->initializeOpenGLFunctions();

And then in your draw code, just use the OpenGL functions from that object:

fun->glSomething(1,2,3)
2
votes

Using QOpenGLFunctions_X_X_* will not solve this problem! You need to set the version of the openGL context before you can use the QOpenGLFunctions_X_X_*. Qt use the default version (I think 1.X) so you need to add this code into your main.cpp file

        QSurfaceFormat format;
//        format.setDepthBufferSize(24);
    //    format.setStencilBufferSize(8);

        format.setMajorVersion( 3 ); //whatever version
        format.setMinorVersion( 3 ); //
        format.setProfile(QSurfaceFormat::CoreProfile);
        QSurfaceFormat::setDefaultFormat(format);

Cheers, Nai

1
votes

The straightforward approach with OpenGL is to create a structure containing function pointers:

struct sLGLAPI
{
    sLGLAPI() { memset( this, 0, sizeof( *this ) ); };
    PFNGLACTIVETEXTUREPROC      glActiveTexture;
    PFNGLATTACHSHADERPROC       glAttachShader;
    PFNGLBEGINQUERYPROC         glBeginQuery;
    PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
    ...

Fill it with pointers dlsym-ed from the OpenGL shared library:

API->glActiveTexture = ( PFNGLACTIVETEXTUREPROC )GetGLProc( "glActiveTexture" );
API->glAttachShader = ( PFNGLATTACHSHADERPROC )GetGLProc( "glAttachShader" );
API->glBeginQuery = ( PFNGLBEGINQUERYPROC )GetGLProc( "glBeginQuery" );
API->glBindAttribLocation = ( PFNGLBINDATTRIBLOCATIONPROC )GetGLProc( "glBindAttribLocation" );

And access OpenGL in your code only through this structure. For example:

API->glShaderSource( Shader, 1, &Code, nullptr );
API->glCompileShader( Shader );

This way you will be able to hide the complete OpenGL API and even use stub functions where necessary, for example, to log parameters or to switch between OpenGL and OpenGL ES.

1
votes
#include <QOpenGLFunctions_3_3_Core>

class Mesh : public QOpenGLFunctions_3_3_Core
{
public:
    Mesh();//initializeOpenGLFunctions()
    ~Mesh();      

    void func();//glxxx in it. when using it ,you need an opengl context.
                //for example, use makeCurrent() in QOpenGLWidget subclass.
};