Hey guys,
I am taking some first steps using SDL and GLEW and I've hit a snag.
void SpriteBatch::CreateVertexArray()
{
if (Sprites.empty())
{
return;
}
Log::Print(V_LOG, "Creating a vertex array with %d sprite(s)", Sprites.size());
SortSprites();
if (VertexArrayID == 0)
{
glGenVertexArrays(1, &VertexArrayID);
}
glBindVertexArray(VertexArrayID);
CreateRenderBatches();
glBindVertexArray(0);
}
void SpriteBatch::CreateRenderBatches()
{
//Gotta iterate through all the sprites, create a vbo batch for every program, then reset vertices and offsets, but keep sprite index.
VBOBatches.clear();
int CurrentSprite = 0;
do
{
CreateSingleVBO(CurrentSprite);
} while (CurrentSprite < Sprites.size());
bIsDirty = false;
}
void SpriteBatch::CreateSingleVBO(int& SpriteIndex)
{
std::vector<Vertex> Vertices;
int CurrentVertex = 0;
GLuint Offset = 0;
//RenderBatch is a struct with the following:
// GLuint Offset;
// GLuint NumVerticies;
// GLuint TextureID;
// GLint UniformTimeID;
// GLint UniformProjectionMatrixID;
// GLint UniformTextureID;
std::vector<RenderBatch> SingleVBOBatches;
GLuint ProgramID = Sprites[SpriteIndex]->GetProgramID();
GLuint CurrentTextureID = Sprites[SpriteIndex]->GetTextureID();
SingleVBOBatches.emplace_back(Offset, 6,
Sprites[SpriteIndex]->GetTextureID(),
Sprites[SpriteIndex]->GetUniformTimeID(),
Sprites[SpriteIndex]->GetUniformProjectionMatrixID(),
Sprites[SpriteIndex]->GetUniformTextureID());
std::vector<Vertex>& SpriteVerts = Sprites[SpriteIndex]->GetVertexData();
Vertices.insert(std::end(Vertices), std::begin(SpriteVerts), std::end(SpriteVerts));
CurrentVertex += 6;
Offset += 6;
SpriteIndex++;
for (; SpriteIndex < Sprites.size(); SpriteIndex++)
{
if (Sprites[SpriteIndex]->GetProgramID() != ProgramID)
{
//New program, this VBO is ready, create it and move on to next
break;
}
else if(Sprites[SpriteIndex]->GetTextureID() != CurrentTextureID)
{
//Same program different texture. Create new batch.
SingleVBOBatches.emplace_back(Offset, 6,
Sprites[SpriteIndex]->GetTextureID(),
Sprites[SpriteIndex]->GetUniformTimeID(),
Sprites[SpriteIndex]->GetUniformProjectionMatrixID(),
Sprites[SpriteIndex]->GetUniformTextureID());
}
else
{
//Same program same texture, just gonna append the vertices below.
SingleVBOBatches.back().NumVerticies+=6;
}
std::vector<Vertex>& SpriteVerts = Sprites[SpriteIndex]->GetVertexData();
Vertices.insert(std::end(Vertices), std::begin(SpriteVerts), std::end(SpriteVerts));
CurrentVertex += 6;
Offset += 6;
}
GLuint NewVBO = 0;
glGenBuffers(1, &NewVBO);
glBindBuffer(GL_ARRAY_BUFFER, NewVBO);
//SNipped out GenerateVBO below.
Sprites[SpriteIndex - 1]->GenerateVBO(NewVBO);
glBufferData(GL_ARRAY_BUFFER, Vertices.size() * sizeof(Vertex), Vertices.data(), GL_DYNAMIC_DRAW);
//glBufferData(GL_ARRAY_BUFFER, Vertices.size() * sizeof(Vertex), nullptr, GL_DYNAMIC_DRAW);
//glBufferSubData(GL_ARRAY_BUFFER, 0, Vertices.size() * sizeof(Vertex), Vertices.data());
VBOBatches.emplace_back(NewVBO, ProgramID, SingleVBOBatches);
Log::Print(V_LOG, "Generated a VBO %d", NewVBO);
return;
}
///////////////////////////
void Sprite::GenerateVBO(const GLuint& InVertexBufferID)
{
VertexBufferID = InVertexBufferID;
for (int i = 0; i < Attributes.size(); i++)
{
glEnableVertexAttribArray(i);
}
//Position attribute pointer
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, VertexPosition));
//Color attribute pointer
glVertexAttribPointer(1, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Vertex), (void*)offsetof(Vertex, VertexColor));
//UV attribute pointer
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)offsetof(Vertex, VertexUV));
}
void SpriteBatch::RenderBatches()
{
//Log::Print(V_LOG, "Number of batches: %d", VBOBatches.size());
glBindVertexArray(VertexArrayID);
glActiveTexture(GL_TEXTURE0);
for (auto& VBO : VBOBatches)
{
Log::Print(V_LOG, "Using program %d", VBO.ProgramID);
glUseProgram(VBO.ProgramID);
for (auto& Batch : VBO.VBOBatches)
{
glBindTexture(GL_TEXTURE_2D, Batch.TextureID);
SetUniforms(Batch);
glDrawArrays(GL_TRIANGLES, Batch.Offset, Batch.NumVerticies);
}
}
The result is weird. If I have one program but multiple textures, it works just fine. However, the moment I have more programs, it seems as if only the last VBO added is being used, as all my sprites are grouped on wherever the last sprite is positioned.
I'm pretty sure I've omitted something crucial but I can't put my finger on it. Perhaps I am going about this the wrong way?