I'm drawing lots of images and changing the width/height of the quads I use to draw them a lot.
My suggestion would be to make a function for a single quad you want to render and batching the calls in a for loop.
I made a vertex attribute object for rendering sprites using the Sprite shader as a source for the attributes:
// sprite batches
m_SpriteBatchShader = ResourceManager::Get().GetShader("Sprite");
m_SpriteBatchArray = m_SpriteBatchShader->CreateVertexArray();
m_SpriteBatchPosition = m_SpriteBatchArray->GetAttribute("attrPosition")->GetArray<tb::Vec2>();
m_SpriteBatchPosition->SetData(AccessMode::Host | AccessMode::Write, 4, NULL);
m_SpriteBatchTexCoord = m_SpriteBatchArray->GetAttribute("attrTexCoord0")->GetArray<tb::Vec2>();
m_SpriteBatchTexCoord->SetData(AccessMode::Host | AccessMode::Write, 4, NULL);
tb::Vec2* dst_tex = m_SpriteBatchTexCoord->Lock(LockMode::Write);
dst_tex[0] = tb::Vec2(0.f, 1.f);
dst_tex[1] = tb::Vec2(1.f, 1.f);
dst_tex[2] = tb::Vec2(1.f, 0.f);
dst_tex[3] = tb::Vec2(0.f, 0.f);
m_SpriteBatchTexCoord->Unlock();
I never have to change the texture coordinates for a sprite, because they're always going to be the same, filling the entire quad.
And now you can loop over the Sprites in a batch call:
m_SpriteBatchShader->Enable();
m_SpriteBatchShader->BindVertexAttributeArray(m_SpriteBatchArray);
m_SpriteBatchShader->SetMatrix(MatrixLocation::FullTransform, m_MatOrthographic);
for (size_t i = 0; i < a_SpriteBatch.size(); i++)
{
Sprite* curr = a_SpriteBatch[i];
const tb::Vec2& pivot = curr->GetPivot();
const tb::Vec2& dim = curr->GetDimensions();
tb::Vec2 pos_ul(-pivot.x, -pivot.y );
tb::Vec2 pos_ur(-pivot.x + dim.x, -pivot.y );
tb::Vec2 pos_ll(-pivot.x , -pivot.y + dim.y);
tb::Vec2 pos_lr(-pivot.x + dim.x, -pivot.y + dim.y);
// this Lock is a wrapper around glMapBuffer, which returns a pointer
tb::Vec2* dst_pos = m_SpriteBatchPosition->Lock(LockMode::Write);
dst_pos[0] = curr->GetTransform() * pos_ul;
dst_pos[1] = curr->GetTransform() * pos_ur;
dst_pos[2] = curr->GetTransform() * pos_lr;
dst_pos[3] = curr->GetTransform() * pos_ll;
// Unlock uploads data to the GPU
m_SpriteBatchPosition->Unlock();
// bind the sprite's texture to GL_TEXTURE0 and texDiffuse in the shader
m_SpriteBatchShader->BindTexture(TextureLocation::Diffuse, 0, curr->GetTextureHandle());
glDrawArrays(GL_QUADS, 0, 4);
}
m_SpriteBatchShader->Disable();
How can you optimize this further? Well, if your sprites don't need to be rotated, you can remove that transform. If they don't need a pivot, you can remove that as well. But if you do need those things, it may be beneficial to rotate the quad in the shader.