Page 1 of 1

Qt and OpenGL

Posted: Thu Aug 11, 2011 7:40 am
by N64vSNES
Okay so I've been learning Qt for some time now and I tried to implement some OpenGL which has gone well until now....

I've got rendering itself working fine, but texturing is proving to be less simple.

I load here I load the texture:

Code: Select all

void Eternal::Texture::Load(std::string file)
{
    glEnable(GL_TEXTURE_2D);
    QImage t;
    QImage b;

    // This file definitely exists
    b.load( "content/test.png" );
    t = QGLWidget::convertToGLFormat( b );
    glGenTextures( 1, &g_Tex );
    glBindTexture( GL_TEXTURE_2D, g_Tex );
    glTexImage2D( GL_TEXTURE_2D, 1, 4, t.width(), t.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, t.bits() );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glDisable(GL_TEXTURE_2D);

    // "Pos" is a rectangle , the rest can be ignored ( not being used yet )
    Pos.x = Pos.y = Crop.x = Crop.y = 0;
    Pos.w = Crop.w = fWidth = t.width();
    Pos.h = Crop.h = fHeight = t.height();
}
And draw it like this:

Code: Select all

void Eternal::Texture::Render()
{
    glEnable(GL_TEXTURE_2D);
    glBindTexture( GL_TEXTURE_2D, g_Tex );
    glColor3f(1,1,1);
    glBegin(GL_QUADS);
    glTexCoord2f(0,0);    glVertex2f(Pos.x,Pos.y);
    glTexCoord2f(1,0);    glVertex2f(Pos.x + Pos.w,Pos.y);
    glTexCoord2f(1,1);    glVertex2f(Pos.x + Pos.w,Pos.y + Pos.h);
    glTexCoord2f(0,1);    glVertex2f(Pos.x,Pos.y + Pos.h);
    glEnd();
}


And if it's any use, here is the paintGL() function:

Code: Select all

void Eternal::GLWidget::paintGL()
{
    glClear(GL_COLOR_BUFFER_BIT);
    Img.Render();
}
It gets rendered, but it's just a white square.

Unless something obvious is staring me in the face, am I missing something?

Thanks.

Re: Qt and OpenGL

Posted: Fri Aug 12, 2011 6:06 pm
by LeonBlade
You are so lucky that after I closed this I re-opened it after noticing it said "Qt and OpenGL".
I've had this problem for months and months and MONTHS trying to figure out what the hell is going on.

The best thing to do would be to create a main class that inherits QGLWidget and then do all the loading on it, then when you make new QGLWidgets, you should set the shareWidget in the constructor for all new QGLWidget classes to your main QGLWidget.
QTDocs wrote:If shareWidget is a valid QGLWidget, this widget will share OpenGL display lists and texture objects with shareWidget. But if shareWidget and this widget have different formats, sharing might not be possible. You can check whether sharing is in effect by calling isSharing().
I hope this helps.

Re: Qt and OpenGL

Posted: Sat Aug 13, 2011 9:36 am
by techboy123
After playing around with OpenGL in Qt and reading through the code. I found two things that could be cause of your texture issues. I'm assuming you have put the content folder in the working directory of the program (You do say it definitely exists; if you're unsure you can just call QDir::currentPath() and print it out somewhere) and that you know the image has loaded correctly ( simple check with QImage::isNull() ).

1. Loading the texture when the context hasn't been set will cause the texture loading to fail. The context is automatically set when the functions paintGL(), resizeGL(), or initializeGL() are called. But if you try to load the texture else where (for example, the constructor) the gl functions calls fail. To fix the problem simply call makeCurrent() inside the relevant function body. For all I know you've already known about and rectified this issue.
Qt Doc wrote: Your widget's OpenGL rendering context is made current when paintGL(), resizeGL(), or initializeGL() is called. If you need to call the standard OpenGL API functions from other places (e.g. in your widget's constructor or in your own paint functions), you must call makeCurrent() first.
2. Using 1 for the level parameter (2nd param) in the glTexImage2D call. I'm no openGL (or Qt) expert so I don't know if you're performing arcane trickery I don't understand. But to use the base texture you pass 0 to the level parameter. A quick read around shows you only should specify a level when you provide the mip-mapped images yourself (I have no idea how you go about this). When I used 1 for the level parameter; all I got was the glorious white quad you described. Using 0 gave a textured quad.

Here's the class I quickly wrote out to test OpenGL in Qt. I left out the main.cpp (just the standard main.cpp file for Qt projects).

Header

Code: Select all

#ifndef OPENGL_TEST_H
#define OPENGL_TEST_H

#include <QGLWidget>
#include <QImage>

class MyOpenGL : public QGLWidget {
    Q_OBJECT
private:
    GLuint m_textureid;

    void loadTexture();

public:
    MyOpenGL();
    ~MyOpenGL();

    void initializeGL();
    void resizeGL(int w, int h);
    void paintGL();

};


#endif // OPENGL_TEST_H
CPP

Code: Select all

#include "opengl_test.h"
#include <QMessageBox>
#include <QDir>

MyOpenGL::MyOpenGL() {
    makeCurrent(); //Set openGL context. Required for loading the texture.
    loadTexture();
}

MyOpenGL::~MyOpenGL() {

}

void MyOpenGL::initializeGL() {


    glClearColor(0.0f, 0.0f, 0.0f, 1.0f); //Black background.

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, 1.0, 1.0, 0.0, -1.0, 1.0);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    //loadTexture(); --You can also load the texture here. No need to set the context as its automatically set.


}

void MyOpenGL::loadTexture() {

    QImage img, texture;

    //Load the texture
    img.load("res/texture_test.png");
    if(img.isNull()) {
        QMessageBox::information(this,
                                 "OpenGL Test - Failed to load image",
                                 "Failed to load texture_test.png\nWorking Dir: " + QDir::currentPath(),
                                 QMessageBox::Ok
                                 );
    } else {

        texture = QGLWidget::convertToGLFormat(img);

        //Send the texture data to openGL
        glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT);

        glGenTextures(1, &m_textureid);
        glEnable(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, m_textureid);

        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width(), texture.height(), 0,
                     GL_RGBA, GL_UNSIGNED_BYTE, texture.bits());

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        glPopAttrib();

    }
}

void MyOpenGL::resizeGL(int w, int h) {
    glViewport(0, 0, w, h); //Set the viewport

    glPushAttrib(GL_TRANSFORM_BIT); //Store current matrix mode

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0, 1.0, 1.0, 0.0, -1.0, 1.0);

    glPopAttrib(); //Restore matrix mode
}

void MyOpenGL::paintGL() {

    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();

    glPushAttrib(GL_ENABLE_BIT | GL_TEXTURE_BIT);
    glEnable(GL_TEXTURE_2D);

    glBindTexture(GL_TEXTURE_2D, m_textureid); //Bind the converted texture.

    //Draw the textured quad.
    glBegin(GL_QUADS);
    glColor3f(1.0f, 1.0f, 1.0f);
    glTexCoord2f(0.0f, 1.0f); glVertex3f(0.1f, 0.1f, 0.0f); //Top Left
    glTexCoord2f(0.0f, 0.0f); glVertex3f(0.1f, 0.9f, 0.0f); //Bottom Left
    glTexCoord2f(1.0f, 0.0f); glVertex3f(0.9f, 0.9f, 0.0f); //Bottom Right
    glTexCoord2f(1.0f, 1.0f); glVertex3f(0.9f, 0.1f, 0.0f); //Top Right
    glEnd();

    glPopAttrib(); //Restore previously bound texture and state.
}
I hope this post provides some help. If it doesn't I'm sure someone with more Qt/OpenGL experience than myself can shine some light on the issue.

Re: Qt and OpenGL

Posted: Sat Aug 13, 2011 3:06 pm
by N64vSNES
Thanks a LOT for all your help guys, I'm not entirely sure what the problem was but it looks like it was because I was trying to load a texture before the OpenGL context was initialized (I think).

PS: I blame Qt entirely....

Re: Qt and OpenGL

Posted: Sun Aug 14, 2011 4:08 am
by LeonBlade
N64vSNES wrote:Thanks a LOT for all your help guys, I'm not entirely sure what the problem was but it looks like it was because I was trying to load a texture before the OpenGL context was initialized (I think).

PS: I blame Qt entirely....
That's what I do ;)