how to use the OBJ data with glDrawElements()?

When we want to use from glDrawElements() each vertex index has an associated normal and texture index(Index 1 means vertex 1, normal 1 and texture coordinate 1). OBJ indices don’t follow this rule. Each face has 3 vertex indices, 3 normal indices and three texture indices.As an example in an OBJ file we have:
f 12/22/10 …
It means that:
The index of vertex 0 of this face is 12
Index of Texture coordinate is 22
Index of normal is 10
But I guess that to use glDrawElements, This OBJ line should be “f 12/12/12 …” as an example.
So how to use this data with glDrawElements()?
-Ehsan-

You’re right that you must use the same index for all attributes, so you cannot directly use the data you read. The simplest way would be to just create non-indexed arrays and darw using glDrawArrays instead. Loop through all face indices and copy the indexed attributes to the end of new attribute arrays.

In this case the simplest possible thing would be to use immediate mode. While that would work it would also be slow.
What you actually need to do is preprocess the OBJ data into a format that glDrawElements can use directly. Doing so you should also account for vertex sharing and not create duplicates where not needed. So if you have 12/14/20 twice in the file you would only generate one vertex.
This preprocessing might be a bit tricky but its the way it has to be done.

Originally posted by Bob:
You’re right that you must use the same index for all attributes, so you cannot directly use the data you read. The simplest way would be to just create non-indexed arrays and darw using glDrawArrays instead. Loop through all face indices and copy the indexed attributes to the end of new attribute arrays.
Could you please give me more explanation about your idea?(Maybe with a simple example).
-Ehsan-

I don’t know what else there is to say really that what I already said. Loop through the faces and copy the indexed attributes into new arrays. Pseudo-C+±code.

struct face {GLuint v, t, n;};
struct vertex { GLfloat x, y, z;};
struct texcoord { GLfloat s, t;};
struct normal {GLfloat x, y, z;};

std::vector<face> OBJFaceIndexList;
std::vector<vertex> OBJVertexArray;
std::vector<texcoord> OBJTexCoordArray;
std::vector<normal> OBJNormalArray;

Assuming a similar structure and you read the OBJ file into the proper arrays.

std::vector<vertex> VertexArray;
std::vector<texcoord> TexCoordArray;
std::vector<normal> NormalArray;

for(std::vector<face>::iterator I = OBJFaceIndexList.begin(); I != OBJFaceIndexList.end(); ++I)
{
    VertexArray.push_back(OBJVertexArray[I->v]);
    TexCoordArray.push_back(OBJTexCoordArray[I->t]);
    NormalArray.push_back(OBJNormalArray[I->n]);
}

With the above code you have to be carefull. You need to be aware that OBJ files have their indexes starting at 1 and not 0 so you might need to offset by 1 element in the array accesses.

While this scheme will work it will create 3 unique vertices for each triangle face, so you won’t get any vertex sharing! This is bad for performance.