glDrawElements- my nemesis

I am rendering a cube and I would like someone to explain how I can achieve this with one call to glDrawElements. I have looked at the red book and it says this is possible but gives no explanation as to how to do this. For me, the difficulty is understanding how glDrawElements will know which normal from the normal array to asssociate with the correctly corresponding face from the array of vertex indices.
Also, any example code would be manna from heaven.

Ta muchly.

With vertex arrays, you need to have a 1 to 1 mapping of all the arrays you enable. For instance if you enable the vertex array, normal array, and texture coordinate array, index 0 of each of those will define one vertex, index 1 will define another one, etc.

You have to think of all of these properties as defining the vertex, not just the vertex position. So if you have 2 vertices with the same position, but different normals, or different texcoords, you need to consider them as completely separate vertices, and duplicate the position data.

So in the position vertex array for a cube I would duplicate the data 3 times, because there are 3 different normals for each positional vertice?

wouldnt I have to duplicate the normal data as well because the same normal is used for each side of the cube, that is to say one normal is used for every 4 positions.

but probably the quickest way to clear this up would be with some sample code. got any?

Yup. You’d have to duplicate the normals as well.

Here’s some sample code using interleaved arrays. I pulled some of the pertinent code out of a project of mine.

struct GL_Vertex
{
float normX, normY, normZ;
float posX, posY, posZ;
};

struct GL_Vertex_array
{
int nVertexCount;
GL_Vertex* pVerts;
};

struct GL_Primitive
{
GLenum ePrimitiveType;
int nIndexCount;
unsigned int* pIndices;
};

struct GL_Primitive_array
{
int nPrimitiveCount;
GL_Primitive* pPrimitives;
};

// These are filled in in a create function
// I won’t post the code for that as it’s got
// a lot of extra stuff that would probably
// just confuse the example.

GL_Vertex_array m_tVerts; // List of all vertices
GL_Primitive_array m_tPrimitiveArray; // List of triangle strips and fans

void Blob::Render(void)
{
// Tell OpenGL where to find the array
glInterleavedArrays(GL_N3F_V3F, 0, m_tVerts.pVerts);

// Draw the triangle strips and fans
for (int c=0;c<m_tPrimitiveArray.nPrimitiveCount;c++)
{
glDrawElements(m_tPrimitiveArray.pPrimitives[c].ePrimitiveType,
m_tPrimitiveArray.pPrimitives[c].nIndexCount, GL_UNSIGNED_INT,
m_tPrimitiveArray.pPrimitives[c].pIndices);
}
}

The above code basically lets me keep an array of triangle strips and fans together. Might be a bit more involved than a simple example, but I hope it helps at least.

The important thing to note is that the GL_Vertex has both normal and position data.