Here’s the function I use for building a VAO for my 3DS models:
void TDS_BuildVAO(TDS_Model_t *Model)
{
int i, j;
for(i=0;iNumMesh;i++)
{
int index=0;
float *data=NULL;
Model->Mesh[i].VAOID=glNewObjectBufferATI(sizeof(float)*Model->Mesh[i].NumVertex*14, NULL, GL_DYNAMIC_ATI);
if(HasMOB)
data=(float *)glMapObjectBufferATI(Model->Mesh[i].VAOID);
else
data=(float *)malloc(sizeof(float)*Model->Mesh[i].NumVertex*14);
if(data==NULL)
{
char temp[1024];
sprintf(temp, "VAO data buffer memory allocate/map failed for object: %s", Model->Mesh[i].Name);
MessageBox(NULL, temp, "OpenGL", MB_OK);
glFreeObjectBufferATI(Model->Mesh[i].VAOID);
Model->Mesh[i].VAOID=0;
break;
}
for(j=0;j<Model->Mesh[i].NumVertex;j++)
{
data[index++]=Model->Mesh[i].Vertex[3*j];
data[index++]=Model->Mesh[i].Vertex[3*j+1];
data[index++]=Model->Mesh[i].Vertex[3*j+2];
data[index++]=Model->Mesh[i].UV[2*j];
data[index++]=Model->Mesh[i].UV[2*j+1];
data[index++]=Model->Mesh[i].Tangent[3*j];
data[index++]=Model->Mesh[i].Tangent[3*j+1];
data[index++]=Model->Mesh[i].Tangent[3*j+2];
data[index++]=Model->Mesh[i].Binormal[3*j];
data[index++]=Model->Mesh[i].Binormal[3*j+1];
data[index++]=Model->Mesh[i].Binormal[3*j+2];
data[index++]=Model->Mesh[i].Normal[3*j];
data[index++]=Model->Mesh[i].Normal[3*j+1];
data[index++]=Model->Mesh[i].Normal[3*j+2];
}
if(HasMOB)
glUnmapObjectBufferATI(Model->Mesh[i].VAOID);
else
{
glUpdateObjectBufferATI(Model->Mesh[i].VAOID, 0, sizeof(float)*index, data, GL_DISCARD_ATI);
FREE(data);
}
}
}
And then I use this to render:
void TDS_DrawModel(TDS_Model_t *Model)
{
int i;
glColor3f(1.0f, 1.0f, 1.0f);
for(i=0;iNumMesh;i++)
{
int index=Model->Mesh[i].MaterialIndex;
if(index>=Model->NumMaterial)
{
glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, Kd[0], Kd[1], Kd[2], 0.0f);
glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, Ks[0], Ks[1], Ks[2], SpecularExpoent);
glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 3, Ka[0], Ka[1], Ka[2], 0.0f);
}
else
{
glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 1, Model->Material[index].Diffuse[0], Model->Material[index].Diffuse[1], Model->Material[index].Diffuse[2], 0.0f);
glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 2, Model->Material[index].Specular[0], Model->Material[index].Specular[1], Model->Material[index].Specular[2], Model->Material[index].Shininess*100.0f);
glProgramEnvParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, 3, Model->Material[index].Ambient[0], Model->Material[index].Ambient[1], Model->Material[index].Ambient[2], 0.0f);
if(Model->Material[index].BaseTexID!=0)
{
glActiveTextureARB(GL_TEXTURE0_ARB);
glBindTexture(GL_TEXTURE_2D, Model->Material[index].BaseTexID);
}
if(Model->Material[index].BumpTexID!=0)
{
glActiveTextureARB(GL_TEXTURE1_ARB);
glBindTexture(GL_TEXTURE_2D, Model->Material[index].BumpTexID);
}
}
if(HasVAO&&Model->Mesh[i].VAOID)
{
glArrayObjectATI(GL_VERTEX_ARRAY, 3, GL_FLOAT, sizeof(float)*14, Model->Mesh[i].VAOID, 0);
glEnableClientState(GL_VERTEX_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glArrayObjectATI(GL_TEXTURE_COORD_ARRAY, 2, GL_FLOAT, sizeof(float)*14, Model->Mesh[i].VAOID, sizeof(float)*3);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glArrayObjectATI(GL_TEXTURE_COORD_ARRAY, 3, GL_FLOAT, sizeof(float)*14, Model->Mesh[i].VAOID, sizeof(float)*5);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glArrayObjectATI(GL_TEXTURE_COORD_ARRAY, 3, GL_FLOAT, sizeof(float)*14, Model->Mesh[i].VAOID, sizeof(float)*8);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glArrayObjectATI(GL_NORMAL_ARRAY, 3, GL_FLOAT, sizeof(float)*14, Model->Mesh[i].VAOID, sizeof(float)*11);
glEnableClientState(GL_NORMAL_ARRAY);
}
else
{
glVertexPointer(3, GL_FLOAT, 0, Model->Mesh[i].Vertex);
glEnableClientState(GL_VERTEX_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glTexCoordPointer(2, GL_FLOAT, 0, Model->Mesh[i].UV);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glTexCoordPointer(3, GL_FLOAT, 0, Model->Mesh[i].Tangent);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glTexCoordPointer(3, GL_FLOAT, 0, Model->Mesh[i].Binormal);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glNormalPointer(GL_FLOAT, 0, Model->Mesh[i].Normal);
glEnableClientState(GL_NORMAL_ARRAY);
}
glDrawElements(GL_TRIANGLES, Model->Mesh[i].NumFace*3, GL_UNSIGNED_SHORT, Model->Mesh[i].Face);
glClientActiveTextureARB(GL_TEXTURE2_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE1_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glClientActiveTextureARB(GL_TEXTURE0_ARB);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
glActiveTextureARB(GL_TEXTURE0_ARB);
}
HasVAO is a bool that tells the function weather or not the extension is supported, same with HasMOB only for the ATI_map_object_buffer extension. Everything else should be easy enough to figure out.
I create one object buffer per mesh in the model (one VAO ID per mesh).