将 QImage 与 OpenGL 结合使用

发布于 2024-10-23 18:15:45 字数 3852 浏览 2 评论 0原文

我最近开始使用 Qt 并将其与 OpenGL 一起使用 但问题是,当我将 SDL 代码移动到 Qt 并更改纹理代码以使用 QImage 时,它​​会停止工作。

图像确实加载正确,如错误检查代码所示。

谢谢!

PS:请不要建议我使用glDrawPixels,我需要解决手头的问题。部分原因是 1. 速度慢 2. android(此代码最终可能在其上运行)是 OpenGL ES 并且不支持 glDrawPixels

这是代码:

//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();

这是使用 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;
}

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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

离旧人 2024-10-30 18:15:45

我有类似的代码,但使用 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);
}

以及 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);        
}

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);        
}
糖粟与秋泊 2024-10-30 18:15:45

这是我从 Qt 转换为 GL 的解决方案
这也可以反向工作,只需稍加改变即可;
干杯——戴蒙

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++;
    }
}

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++;
    }
}
凉风有信 2024-10-30 18:15:45

看起来你的问题不在这里,因为我对以下代码没有问题。
您应该检查 GL 初始化和显示设置。

你在某处有 glEnable(GL_TEXTURE_2D) 吗?

另请注意,glTexCoord2f 必须位于 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;
}

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文