The index buffer can be predifined, and will not change.
Here is some C#-ish pseudocode from a project of mine that outlines what I do:
spriteVertex[] vertices = new spriteVertex[BATCHSIZE * 4];
int[] indices = new int[BATCHSIZE * 6];
MakeBuffers(ref vertBufferID, ref indBufferID, ref vaoID);
// fill the buffer with default (0s) on creation
glBufferData(BufferTarget.ArrayBuffer, sizeof(spriteVertex) * vertices.Length, vertices);
// fill index buffer with pre-calc'd values
PreCalcIndexBuffer();
...
class TileBatch
{
public void Begin(Texture2D texture)
{
currentSprite = 0;
currentTexture = texture;
}
public void Draw(Rect dest, Rect src, Color color)
{
// if we are out of room, flush (draw) the current batch
if(currentSprite > BATCHSIZE)
{
flush();
currentSprite = 0;
}
// calc all the vertex attributes for this sprite and store them in our CPU array
int vertStart = currentSprite * 4;
vertices[vertStart].position.X = dest.X;
vertices[vertStart].texcoord.X = src.X;
...
vertices[vertStart + 3].position.Y = destRect.Bottom;
vertices[vertStart + 3].texcoord.Y = src.Bottom;
currentSprite++;
}
public void End()
{
Flush();
}
private void Flush()
{
// set program uniforms and state
shaderProgram.Texture = currentTexture;
shaderProgram.mvpMatrix = currentMVP;
...
int numberToDraw = currentSprite;
BindVAO();
// upload our CPU vertex data to GPU
glBufferSubData(BufferTarget.ArrayBuffer, 0, sizeof(SpriteVertex) * numberToDraw, vertices);
// draw the appropriate number of sprites
DrawElements(BeginMode.Triangles, numberToDraw);
}
}
In use:MyBatch.Begin(myTexture); MyBatch.Draw(Rect(0,0,32,32), Rect(50,50,32,32), Color.White); MyBatch.Draw(...) ... MyBatch.End();

Find content
Not Telling