I'm having a tremendous time getting the second (or additional) sprites in my game engine to render properly. The first one always works great: it is positioned and sized properly in screen coords, and its texture is mapped properly. When I add a second sprite to the world, its texture does not get mapped properly. If I reverse the two sprites render orders, the sprite that was rendered second previously (and had corrupt texture mapping) is now correct, and the other sprite is now corrupt.
I think it has to do with something in my shader not getting cleared out properly before it is used again. I have to admit, I'm fairly new to shaders. Interestingly, I'm building this engine to support both ES1.1 and ES2.0, and the same code works great in ES1.1 for multiple sprites.
I'll attempt to provide relevant code snippets below. Any suggestions would be great - I've browsed dozens of good forums and Stack Exchange. Is there perhaps a call I should be making between primitive renders to clean out the shaders?
Here's the snippet for rendering in ES2.0
void Sprite::Render(GLuint shaderProgram, UniformHandles* uniforms, AttributeHandles* attributes)
{
// Use the shader we were sent
glUseProgram(shaderProgram);
// Enable transparent blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Performance: could pull this out and only recalculate when moved
PVRTVec2 bottomLeftPos = PVRTVec2((m_viewDims.x - m_position.x) / m_viewDims.x,
((m_viewDims.y - (m_position.y - m_drawDims.y)) / m_viewDims.y));
PVRTVec2 topRightPos = PVRTVec2((m_viewDims.x - (m_position.x + m_drawDims.x)) / m_viewDims.x,
(m_viewDims.y - m_position.y) / m_viewDims.y);
// Draw the quad for ES2 (positioning is not based on these values: do not change)
DrawQuad((bottomLeftPos.x * 2.0f) - 1.0f, (bottomLeftPos.y * 2.0f) - 1.0f, (topRightPos.x * 2.0f) - 1.0f, (topRightPos.y * 2.0f) - 1.0f, m_textureResource->texture, uniforms, attributes);
// Turn off blending
glDisable(GL_BLEND);
}
And here's the snippet for DrawQuad()
void Sprite::DrawQuad(float x1, float y1, float x2, float y2, GLuint texture,
UniformHandles* uniforms, AttributeHandles* attributes)
{
// Set the uniforms for rectangle position and width
// Landscape
glUniform2f(uniforms->LowerLeft, -y1, x1);
float scaleMatrix[4] = { 0, x2 - x1, y1 - y2, 0 };
glUniformMatrix2fv(uniforms->ScaleMatrix, 1, GL_FALSE, scaleMatrix);
// Use the given texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
// Bind the vertex buffer object
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
glEnableVertexAttribArray(attributes->in2DVertex);
glEnableVertexAttribArray(attributes->inSpriteTexCoord);
glVertexAttribPointer(attributes->in2DVertex, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 4, 0);
glVertexAttribPointer(attributes->inSpriteTexCoord, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT) * 4, (unsigned char*) (sizeof(GL_FLOAT) * 2));
// Draws a short triangle strip
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(attributes->in2DVertex);
glDisableVertexAttribArray(attributes->inSpriteTexCoord);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
And finally the vertex shader and fragment shader for 2D sprites:
Vertex Shader attribute highp vec2 in2DVertex; attribute highp vec2 inSpriteTexCoord;
uniform highp vec2 LowerLeft;
uniform highp mat2 ScaleMatrix; // Width/height and screen rotation
varying mediump vec2 TexCoord;
void main()
{
gl_Position = vec4(ScaleMatrix * in2DVertex + LowerLeft, 0, 1);
TexCoord = inSpriteTexCoord; // formerly in2DVertex
}
Fragment Shader uniform sampler2D sTexture;
varying mediump vec2 TexCoord;
void main()
{
gl_FragColor = texture2D(sTexture, TexCoord);
}