2011-03-17 32 views
9

Recientemente cogí Qt y lo estoy usando con OpenGL Sin embargo, la cuestión es que cuando muevo mi código SDL a Qt y cambio el código de textura para usar QImage, deja de funcionar.Usando QImage con OpenGL

La imagen se carga correctamente, como se muestra a través del código de comprobación de errores.

Gracias!

P.S: Por favor, no sugiera que use glDrawPixels, necesito solucionar el problema. Algunas de las razones por las que el ser 1. lenta 2. androide (que este código se estén ejecutando en el tiempo) es OpenGL ES y no es compatible con glDrawPixels

Aquí está el código:

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

Aquí está la textura original función de carga con 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; 
} 
+2

¿Podría explicar un poco más sobre lo que quiere decir con el funcionamiento "detenido"? La textura ya no se muestra? ¿Cambió algún parámetro para 'glTexImage2D' excepto el obvio' GL_formatted_image.xxx'? ¿Su imagen suministra un canal alfa, es decir, RGBA? – Thomas

+0

cambiando GL_RGBA a GL_RGB da el mismo resultado Al dejar de funcionar, quiero decir que la textura no se muestra – Prime

+0

¿El código publicado es la primera parte de una función? ¿Cómo se ve realmente tu lazo de drenaje? Consulte también la publicación de fa para ver si realizó la inicialización de una manera similar. – Thomas

Respuesta

6

que tienen un código similar que funciona pero utiliza 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); 
} 

Y algunos retoques del perfomance en el 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);   
} 
+0

Usted está haciendo demasiado en la función de pintura. No hay necesidad de establecer matrices de proyección/vista. Debería hacerse solo en la función de cambio de tamaño. También está enviando datos a la GPU en cada repintado. –

4

Parece que su problema no está aquí, ya que no tengo ningún problema con el siguiente código. Debería verificar su configuración de GL y pantalla.

¿Tiene un glEnable (GL_TEXTURE_2D) en alguna parte?

También tenga en cuenta que glTexCoord2f debe estar antes que 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; 
} 
+0

Te faltan 'glEnable (GL_TEXTURE_2D);' y 'glDisable (GL_TEXTURE_2D);' en varios lugares, pero esta sugerencia es superior a otras respuestas. –

+0

también, tenga cuidado con las imágenes, cuyas dimensiones no son de 2 –

6

Ésta es mi solución para la conversión de Qt a GL Esto también puede funcionar al revés con pocos cambios; 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++; 
    } 
} 
+3

O use 'QImage :: rgbSwapped()'? – Dreiven

+0

@Dreiven: No, 'rgbSwapped()' convierte ARGB en ABGR. – RyanCu