Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

QGLWidget appears black in Windows 7

I wrote and tested some code in a Windows XP (Qt 4.7.2) using Visual Studio 2010 and then I tried on another machine with Windows 7 installed.

The program opens a QDialog and creates a QGLWidget where I show webcam images (with some processing). While in Windows XP the images are shown correctly, at the moment that I test the program in a Windows 7 machine, the QGLWidget turns black and no image is shown. It is strange, though, that when I move around the window and it gets out of the borders of the screen, the image is shown for an instant and pitch black when I stop moving again, which makes me think that the images are correctly received/processed (some times), and that it might be a problem with a QTimer.

The relevant code is:

Initialization:

void GLVideo::initializeGL()
{   
    glEnable(GL_TEXTURE_2D);
    glShadeModel(GL_SMOOTH);

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClearDepth(1.0f);

    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);

    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

    // Some OpenCV processing

    // Here I declare the timer, might it be the problem?
    m_timer = new QTimer(this);
    connect( m_timer, SIGNAL(timeout()), this, SLOT(timeOutSlot()) );
    m_timer->start( 33 );

}

Slot that is called every timeout:

void GLVideo::timeOutSlot() 
{
    ReceiveInfo();
    LoadTextures();
}

void GLVideo::LoadTextures() 
{   
    // Get the image from the webcam
    ProcessCamera();

    glBindTexture(GL_TEXTURE_2D, texture);  
    glTexImage2D( GL_TEXTURE_2D, 0, 3, qImage->width(), 
        qImage->height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, qImage->bits());
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

    updateGL();
}

void GLVideo::resizeGL( int width, int height )
{
    height = height?height:1;
    glViewport( 0, 0, (GLint)width, (GLint)height );
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

And finally, the paint function of the Widget:

void GLVideo::paintGL()
{   
    glPushAttrib(GL_ALL_ATTRIB_BITS) ;
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    glPopAttrib() ;

    glEnable(GL_TEXTURE_2D);
    glShadeModel(GL_SMOOTH);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    glBindTexture(GL_TEXTURE_2D, texture);

    glColor4f(1.0f,1.0f,1.0f, 1.0f);
    glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.65f, 1.24f, -3.0f);
        glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.65f, 1.24f, -3.0f);
        glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.65f,-1.24f, -3.0f);
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.65f,-1.24f, -3.0f);
    glEnd();    

    glDisable(GL_TEXTURE_2D);
    glDisable(GL_DEPTH_TEST);

    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();

    // Some 2D drawing:
}

Any idea on what am I doing wrong? Might it be the QTimer that is not calling the SLOT timeOutSlot?

like image 719
sergi Avatar asked Dec 21 '22 14:12

sergi


1 Answers

You're using OpenGL API outside of paintGL(), resizeGL(), or initializeGL().

When your slot is called, modify any state to be able to draw the new frame, but don't call OpenGL API yet. Instead, call QWidget::updateGL(), and do the OpenGL calls in your reimplementation of paintGL().

The problem you're experiencing is that, outside these three functions, your GL context isn't the current one. On older OSs, that might not be a problem, but any OS with a compositing window manager will make problems. E.g., in your case, your program may have been the only OpenGL user under XP, so yours was always the current context. But in Windows 7, the desktop itself uses, if not OpenGL, then Direct3D, ie. the same hardware.

If you absolutely must call OpenGL function outside those three functions, you need to call QGLWidget::makeCurrent() first, but note that this is not idiomatic use.

Regarding the QTimer creation in initializeGL(): it's certainly more idiomatic to create that timer in the class' constructor, but it should be ok in initializeGL(), too.

like image 63
Marc Mutz - mmutz Avatar answered Dec 24 '22 03:12

Marc Mutz - mmutz