Qt Vertex Arrays not working with QImage
I'll begin by apologizing for the length of the question. I believe I've committed some smal开发者_如何转开发l, dumb error, but since I'm entirely unable to find it, I decided to post all relevant code just in case.
I finally got texture loading working using QImage, and am able to render textures in immediate mode. However, vertex arrays don't work, and I'm at a loss as to why. The most obvious things like "Have you enabled vertex arrays and texture coordinate arrays?" are probably not the answer. I'll post the initialization code.
Here's the init function:
/* general OpenGL initialization function */
int initGL()
{
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0, 0, 0, 1); // Black Background
glEnable ( GL_COLOR_MATERIAL );
glColorMaterial ( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );
glDisable(GL_DEPTH_TEST);
//ENABLED VERTEX ARRAYS AND TEXTURE COORDINATE ARRAYS
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
//ENABLED 2D TEXTURING
glEnable ( GL_TEXTURE_2D );
glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 );
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
//seed random
srand(time(NULL));
return( TRUE );
}
I have initialization, resize and draw functions that are called by a QGLWidget (which is itself just a skeleton that calls the real work functions)
The texture loading function:
GLuint LoadGLTextures( const char * name )
{
//unformatted QImage
QImage img;
//load the image from a .qrc resource
if(!img.load(":/star.bmp"))
{
qWarning("ERROR LOADING IMAGE");
}
//an OpenGL formatted QImage
QImage GL_formatted_image;
GL_formatted_image = QGLWidget::convertToGLFormat(img);
//error check
if(GL_formatted_image.isNull())
qWarning("IMAGE IS NULL");
else
qWarning("IMAGE NOT NULL");
//texture ID
GLuint _textures[1];
//enable texturing
glEnable(GL_TEXTURE_2D);
//generate textures
glGenTextures(1,&_textures[0]);
//bind the texture
glBindTexture(GL_TEXTURE_2D,_textures[0]);
//texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glBindTexture(GL_TEXTURE_2D,_textures[0]);
//generate 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());
glBindTexture(GL_TEXTURE_2D,_textures[0]);
//return the texture ID
return _textures[0];
}
Here's the draw code:
//this does draw
//get the texture ID
GLuint tex_id = LoadGLTextures(":/star.png");
glBindTexture(GL_TEXTURE_2D, tex_id); // Actually have an array of images
glColor3f(1.0f, 0.0f, 0.5f);
glBegin(GL_QUADS);
glTexCoord2f(1.0f, 0.0f);glVertex2f(1.0f, 0.0f);
glTexCoord2f(1.0f, 1.0f);glVertex2f(1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f);glVertex2f(0.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f);glVertex2f(0.0f, 0.0f);
glEnd();
//this does not draw
//translations code
glLoadIdentity();
glTranslatef(-1.0f, 0.0f, 0.0f);
//bind the texture
glBindTexture(GL_TEXTURE_2D, tex_id);
//set color state
glColor4f(0.0f, 1.0f, 0.0f, 0.5);
//vertices to be rendered
static GLfloat vertices[] =
{
1.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f
};
static GLshort coord_Data[] =
{
1, 0,
1, 1,
0, 1,
0, 0
};
//bind the texture
glBindTexture(GL_TEXTURE_2D, tex_id);
//pointer to the vertex array
glVertexPointer(2, GL_FLOAT, 0, vertices);
//texture coordinate pointer
glTexCoordPointer(2, GL_SHORT, 0, coord_Data);
//draw the arrays
glDrawArrays(GL_QUADS, 0, 4);
Thanks for all help, Dragonwrenn
One possibility is that the problem stems from calling glVertexCoordPointer before calling glTexCoordPointer. Weird things happen when you specify the texture coordinate after the vertex coordinate. I know this is true for drawing a single vertex with a texture coordinate. I'm not sure if it's true with arrays.
A few other things...
Have you tried using QPixMap instead of QImage? I doubt this is the answer to your problem since it sounds like the texture is applied to the first quad properly.
There are two calls to bindTexture.
Have you tried just drawing the vertices (without the texture) in the second part of the code?
Finally, do you get any compiler warnings?
The way you place your OpenGL state manipulations, it is difficult to keep track of things. It's a good idea to set OpenGL state on demand. So
Move this
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_CORRD_ARRAY);
right before
//bind the texture
glBindTexture(GL_TEXTURE_2D, tex_id);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_SHORT, 0, coord_Data);
//draw the arrays
glDrawArrays(GL_QUADS, 0, 4);
also you should move the other code from initGL
.
Belonging into the texture loader, before supplying the data to glTexImage:
glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 );
Belonging to the beginning of the drawing function:
glShadeModel(GL_SMOOTH);
glClearColor(0, 0, 0, 1);
glEnable( GL_COLOR_MATERIAL );
glColorMaterial ( GL_FRONT, GL_AMBIENT_AND_DIFFUSE );
glDisable(GL_DEPTH_TEST);
Following the scheme you should set viewport and projection matrices in the drawing function, too. I'm just telling this, because most of the tutorials do it differently, which tricks people into thinking this was the right way. Technically projection and viewport and on-demand-states as well.
You should not re-load the texture with every draw call. Note that initializing the texture on demand through the drawing handler is a good idea, you should just add some flag to the texture encapsulating class telling, if the referenced texture is already available to OpenGL.
Just for debugging purposes try changing the type of the texture coordinates to floats.
精彩评论