Using QImage with OpenGL

2019-01-17 23:22发布

I've very recently picked up Qt and am using it with OpenGL The thing though is that when moving my SDL code to Qt and changing the texture code to use QImage it stops working.

The image does load correctly, as shown through the error checking code.

Thanks!

P.S: Please don't suggest I use glDrawPixels, I need to fix the problem at hand. Some of the reasons for that being 1. slow 2. android (which this code may be running on eventually) is OpenGL ES and does not support glDrawPixels

Here's the code:

//original image
QImage img;
if(!img.load(":/star.png"))
{
    //loads correctly
    qWarning("ERROR LOADING IMAGE");
}

//array for holding texture ID
GLuint texture[1];

//get the OpenGL-friendly image
QImage GL_formatted_image;
GL_formatted_image = QGLWidget::convertToGLFormat(img);

//make sure its not null
if(GL_formatted_image.isNull())
    qWarning("IMAGE IS NULL");
else
    qWarning("IMAGE NOT NULL");

//generate the texture name
glGenTextures(1, texture);

//bind the texture ID
glBindTexture(GL_TEXTURE_2D, texture[0]);

//generate the texture
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, GL_formatted_image.width(),
              GL_formatted_image.height(),
              0, GL_RGBA, GL_UNSIGNED_BYTE, GL_formatted_image.bits() );

//texture parameters
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);



//draw the texture
glPushMatrix();
glTranslatef(-2.0f, 0.0f, 0.0f);
glColor3f(1.0f, 1.0f, 1.0f);
glBegin(GL_TRIANGLES);
    glVertex2f(1.0f, 0.0f);
 glTexCoord2f(1.0f, 0.0f);
    glVertex2f(0.0f, 1.0f);
 glTexCoord2f(0.0f, 1.0f);
    glVertex2f(0.0f, 0.0f);
 glTexCoord2f(0.0f, 0.0f);
glEnd();
glPopMatrix();

Here's the original texture loading function with SDL:

GLuint loadTexturewithSDL(const char* FILE, GLenum texture_format)
{
    GLuint texture;         // This is a handle to our texture object
    SDL_Surface *surface;   // This surface will tell us the details of the image
    GLint  nOfColors;



    if ( (surface = SDL_LoadBMP(FILE)) ) {

    // Check that the image's width is a power of 2
    if ( (surface->w & (surface->w - 1)) != 0 ) {
        printf("warning: image's width is not a power of 2\n");
    }

    // Also check if the height is a power of 2
    if ( (surface->h & (surface->h - 1)) != 0 ) {
        printf("warning: image's height is not a power of 2\n");
    }

        // get the number of channels in the SDL surface
        nOfColors = surface->format->BytesPerPixel;
        if (nOfColors == 4)     // contains an alpha channel
        {
                if (surface->format->Rmask == 0x000000ff)
                        texture_format = GL_RGBA;
                else
                        texture_format = GL_BGRA;
        } else if (nOfColors == 3)     // no alpha channel
        {
                if (surface->format->Rmask == 0x000000ff)
                        texture_format = GL_RGB;
                else
                        texture_format = GL_BGR;
        } else {
                printf("warning: the image is not truecolor..  this will probably break\n");
                // this error should not go unhandled
        }

    // Have OpenGL generate a texture object handle for us
    glGenTextures( 1, &texture );

    // Bind the texture object
    glBindTexture( GL_TEXTURE_2D, texture );

    // Set the texture's stretching properties
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

    // Edit the texture object's image data using the information SDL_Surface gives us
    glTexImage2D( GL_TEXTURE_2D, 0, nOfColors, surface->w, surface->h, 0,
                      texture_format, GL_UNSIGNED_BYTE, surface->pixels );
}
else {
    printf("SDL could not load image %s\n", SDL_GetError());
    SDL_Quit();
    return 1;
}

// Free the SDL_Surface only if it was successfully created
if ( surface ) {
    SDL_FreeSurface( surface );
}

    return texture;
}

3条回答
爷、活的狠高调
2楼-- · 2019-01-17 23:52

I have similar code that works but uses glTexSubImage2D :

void Widget::paintGL() 
{
    glClear (GL_COLOR_BUFFER_BIT);       
    glDisable(GL_DEPTH_TEST);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();        
    gluOrtho2D(0,win.width(),0,win.height());
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();        
    glEnable(GL_TEXTURE_2D);

    glBindTexture(GL_TEXTURE_2D,texture); 
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0 , image.width(), image.height(),  glFormat, glType, image.bits() );       
    glBegin(GL_QUADS);   // in theory triangles are better
    glTexCoord2i(0,0); glVertex2i(0,win.height());
    glTexCoord2i(0,1); glVertex2i(0,0);
    glTexCoord2i(1,1); glVertex2i(win.width(),0);
    glTexCoord2i(1,0); glVertex2i(win.width(),win.height());
    glEnd();             

    glFlush();
}


void Widget::initializeGL() 
{
    glClearColor (0.0,0.0,0.0,1.0);
    glDisable(GL_DEPTH_TEST);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();        
    gluOrtho2D(0,win.width(),0,win.height());
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();        

    glEnable(GL_TEXTURE_2D);
    glGenTextures(3,&texture);
    glBindTexture(GL_TEXTURE_2D,texture);       
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);          
    glBindTexture(GL_TEXTURE_2D,texture);               
    glTexImage2D(GL_TEXTURE_2D, 0, glFormat, image.width(), image.height(), 0, glFormat, glType, NULL );    

    glDisable(GL_TEXTURE_2D);
}

And a few perfomance tweaks in the ctor

void Widget::setDisplayOptions()
{
    glFormat = GL_RGB;  //  QImage RGBA is BGRA
    glType = GL_UNSIGNED_BYTE;

    QGL::setPreferredPaintEngine(QPaintEngine::OpenGL2);

    QGLFormat glFmt;
    glFmt.setSwapInterval(1); // 1= vsync on 
    glFmt.setAlpha(GL_RGBA==glFormat);
    glFmt.setRgba(GL_RGBA==glFormat); 
    glFmt.setDoubleBuffer(true); // default
    glFmt.setOverlay(false);
    glFmt.setSampleBuffers(false);
    QGLFormat::setDefaultFormat(glFmt);

    setAttribute(Qt::WA_OpaquePaintEvent,true);
    setAttribute(Qt::WA_PaintOnScreen,true);        
}
查看更多
乱世女痞
3楼-- · 2019-01-17 23:55

It looks like your problem is not here, as I have no problem with the following code. You should check your GL init and display setup.

Have you a glEnable(GL_TEXTURE_2D) somewhere ?

Also note glTexCoord2f must be before glVertex2f.

#include <GL/glut.h>
#include <QtOpenGL/qgl.h>
#include <iostream>

GLuint texture[1] ;

void LoadGLTextures( const char * name )
{
    QImage img;
    if( ! img.load( name ) )
    {
        std::cerr << "error loading " << name << std::endl ;
        exit( 1 );
    }

    QImage GL_formatted_image;
    GL_formatted_image = QGLWidget::convertToGLFormat(img);
    if( GL_formatted_image.isNull() )
    {
        std::cerr << "error GL_formatted_image" << std::endl ;
        exit( 1 );
    }

    glGenTextures(1, texture);
    glBindTexture(GL_TEXTURE_2D, texture[0]);
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA,
            GL_formatted_image.width(), GL_formatted_image.height(),
            0, GL_RGBA, GL_UNSIGNED_BYTE, GL_formatted_image.bits() );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); 
}

void resize(int Width, int Height)
{
    glViewport( 0 , 0 , Width , Height );
}

void draw()
{
    glClearColor( 0.0f, 0.0f, 0.0f, 0.0f);
    glClear( GL_COLOR_BUFFER_BIT );

    gluOrtho2D( -1 , 1 , -1 , 1 );

    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();

    glShadeModel( GL_FLAT );

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, texture[0]);

    glBegin(GL_TRIANGLES);
    glTexCoord2f( 1.0f, 0.0f);
    glVertex2f( 1.0f, 0.0f);
    glTexCoord2f( 0.0f, 1.0f);
    glVertex2f( 0.0f, 1.0f);
    glTexCoord2f( 0.0f, 0.0f);
    glVertex2f( 0.0f, 0.0f);
    glEnd();

    glutSwapBuffers();
}

int main(int argc, char **argv) 
{  
    glutInit(&argc, argv);  
    glutInitDisplayMode( GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA );  
    glutInitWindowSize(640, 480);

    glutCreateWindow("Texture"); 

    LoadGLTextures( "star.png" );

    glutDisplayFunc( & draw );  
    glutReshapeFunc( & resize );
    glutMainLoop();  

    return 1;
}
查看更多
4楼-- · 2019-01-18 00:07

This is my solution for conversion from Qt to GL This also can work in reverse with little changes; Cheers -- Daimon

void Image::Convert32bitARGBtoRGBA()
{
    if(!isQtImage()) return;
    QImage& q = *(m_data->image);
    U32 count=0, max=(U32)(q.height()*q.width());
    U32* p = (U32*)(q.bits());
    U32 n;
    while( count<max )
    {
        n = p[count];   //n = ARGB
        p[count] =  0x00000000 |
                ((n<<8)  & 0x0000ff00) |
                ((n<<8)  & 0x00ff0000) |
                ((n<<8)  & 0xff000000) |
                ((n>>24) & 0x000000ff);
                // p[count] = RGBA
        count++;
    }
}

void Image::Convert32bitRGBAtoARGB()
{
    if(!isQtImage()) return;
    QImage& q = *(m_data->image);
    U32 count=0, max=(U32)(q.height()*q.width());
    U32* p = (U32*)(q.bits());
    U32 n;
    while( count<max )
    {
        n = p[count];   //n = RGBA
        p[count] =  0x00000000 |
                ((n>>8)  & 0x000000ff) |
                ((n>>8)  & 0x0000ff00) |
                ((n>>8)  & 0x00ff0000) |
                ((n<<24) & 0xff000000);
                // p[count] = ARGB
        count++;
    }
}
查看更多
登录 后发表回答