Manual Data Formatting (Interleaving Buffer Data)

Hello once more all,

To the point, I have three sets of data I want to merge and upload to a buffer, those sets being Vertex, Normal, and Texcoord.
Do you know of an efficient, or more viable way to combine those three sets into one, than what I am presenting below?
Is this a correct technique, or am I not comprehending the index structure well enough?

I plan on formating my three sets of data to correspond with my index pattern, being the standard (VNTVNTVNTVNT) or (Vertex,Normal,Texcoord).
OpenGL Context, 4.0+.


	int* Indices = Mesh->Index;

	int size = Mesh->Index_count;
	float* Interleaved = new float[size];

	for(int i=0; i<size;)
	{
		Interleaved[i] = Mesh->VERTEX.mData  [Indices[i]];
		i++;
		Interleaved[i] = Mesh->NORMAL.mData  [Indices[i]];
		i++;
		Interleaved[i] = Mesh->TEXCOORD.mData[Indices[i]];
		i++;
	}

	// I believe both the interleaved and index buffers to have the same element count.

        GLuint Buffer_Interleaved,Buffer_Index;

	glGenBuffers(1,&Buffer_Interleaved);
	glGenBuffers(1,&Buffer_Index);

	glBindBuffer(GL_ARRAY_BUFFER,Buffer_Interleaved);
	glBufferData(GL_ARRAY_BUFFER,size*sizeof(float),Interleaved,GL_STATIC_DRAW);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,Buffer_Index);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER,size*sizeof(int),Indices,GL_STATIC_DRAW);

	delete [] Interleaved;

Additionally, I would like to know how to use glDrawElements() with my newly formatted data.
Books and web references are lacking a good amount of clarity to me.

Any relative words of wisdom are words enough to suffice thanks.

Pedantic grammar note: Index is the singular form of indices. “Indice” or “indicie” is not a word.

Haha, I knew something felt wrong when writing it.
I’ll get to fixing my many errors.

Every bit helps, though I still need the above questions to be addressed.

Can you explain what do you mean by “an efficient” way? You are interested in how you should layout your GPU vertex data or you want to avoid the additional copy to the temporary array?

Btw, there are several problems with your code (at least as far as I understand how it should work):

  1. You actually copying your data in Vx Nx Tx Vy Ny Ty etc. order which I think it’s incorrect, but maybe I’m wrong. It’s hard to figure out what you’re doing.
  2. You read the vertex data indexed by the indices, actually that defeats the purpose of hardware indexing and in this form only DrawArrays would work for you. You should remove the indirection (i.e. replace the array index “Indices[i]” simply with “i”).

The OpenGL specification clearly describes how DrawElements is working. You should give it a try. The spec is usually the best documentation.

Also, there are tons of sample applications all around the internet. Just use your favorite search engine and search for VBO samples.

by merge do you mean display as one mesh? It makes a difference when displaying

Sorry, to clarify:

I am dealing with a mesh object, that is split into the three components that make it drawable, being Vertex, Normal, and Texcoord. I simply want to combine the three elements into a single buffer, though I’m not exactly sure how, after combined, to specify the pattern to let OpenGL know the offsets.

To sum my question up into two parts:
Is the above code I wrote (with Vertex[i] instead of Vertex[Index[i]]…ect), actually creating a valid format that matches my index pattern? (Vertex,Normal,Texcoord)

How do I use glVertexAttribPointer() before drawing to specify the correct offset for that single, combined, buffer object? I would very much appreciate a specific example, rather than yet another link to the wiki page that I’ve refereed to, and failed using.

Many thanks for your patience.

Not exactly, actually you have to do something like the following:

        int* Indices = Mesh->Index;

	int indexCount = Mesh->Index_count;
        int vertexCount = Mesh->Vertex_count;

        typedef struct _SvertexData {
            float vertex[4];
            float normal[3];
            float texcoord[2];
        } vertexData;

	vertexData* Interleaved = new vertexData[vertexCount ];

	for(int i=0; i<vertexCount; ++i)
	{
                Interleaved[i].vertex[0] = Mesh->VERTEX.mData[i*4+0];
                Interleaved[i].vertex[1] = Mesh->VERTEX.mData[i*4+1];
                Interleaved[i].vertex[2] = Mesh->VERTEX.mData[i*4+2];
                Interleaved[i].vertex[3] = Mesh->VERTEX.mData[i*4+3];

                Interleaved[i].normal[0] = Mesh->NORMAL.mData[i*3+0];
                Interleaved[i].normal[1] = Mesh->NORMAL.mData[i*3+1];
                Interleaved[i].normal[2] = Mesh->NORMAL.mData[i*3+2];

                Interleaved[i].texcoord[0] = Mesh->TEXCOORD.mData[i*2+0];
                Interleaved[i].texcoord[1] = Mesh->TEXCOORD.mData[i*2+1];
	}

        GLuint Buffer_Interleaved,Buffer_Index;

	glGenBuffers(1,&Buffer_Interleaved);
	glGenBuffers(1,&Buffer_Index);

	glBindBuffer(GL_ARRAY_BUFFER,Buffer_Interleaved);
	glBufferData(GL_ARRAY_BUFFER,vertexCount*sizeof(vertexData),Interleaved,GL_STATIC_DRAW);

	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,Buffer_Index);
	glBufferData(GL_ELEMENT_ARRAY_BUFFER,indexCount*sizeof(int),Indices,GL_STATIC_DRAW);

	delete [] Interleaved;

        glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(vertexData), offsetof(vertexData, vertex));
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(vertexData), offsetof(vertexData, normal));
        glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(vertexData), offsetof(vertexData, texcoord));

However, the code I wrote is completely based on assumptions as you haven’t described how your data is layed out in the Mesh->VERTEX, Mesh->NORMAL and Mesh->TEXCOORD arrays. The actual, properly working code could be very different.

A few questions to help me clarify my last qualms, I should be set and extremely happy after getting these tidbits.
I have no problems with short yes or no answers.

glVertexAttribPointer:

1.) Does it require me to enable states, such as glEnableClientState(GL_INDEX_ARRAY)?

2.) When referring to Position arrays, must I include the fourth coordinate W, or is it set to 0 by default?

3.) Is it needed that I pack and upload all my data in a structure, as you exemplified in the above code?

4.) I noticed you did not include a stride in the example code, but gave a byte size.
Why would it be the size of the entire array, rather than something like 3*sizeof(float)?
…sizeof(vertexData)…

5.) My offset is 0,1,2. (V,N,T). How does this translate to the buffer offset?
I find this very confusing as I can’t tell if it should be literal, or sizeof(float). Do you have any examples?

glDrawElements():

1.) When specifying the count of triangles, is it okay to use (Index_Count/3)/3?
(Vertex,Normal,Texcoord)/3 = (Vertex)/3 = (Triangle Count), is this logic correct?

I can’t thank you enough for both the examples, and continued help throughout the day.
My problems should be solved after I get these last bits of clarity.

Did you look at the Wiki?
http://www.opengl.org/wiki/VBO_-_just_examples

2)By default, W is 1.0

  1. No. Example, you can just fill in a float array. BTW, a memory location is just a memory location. As a programmer, you should know by now how RAM memory (or any kind of computer memory) works.

  2. How will GL know the start of the next vertex?

  3. Buffer offset are in bytes.
    If you want to read documents, there is the spec of course but there is also the Wiki
    http://www.opengl.org/wiki/Vertex_Buffer_Object
    http://www.opengl.org/wiki/VBO_-_more
    http://www.opengl.org/wiki/VBO_-_just_examples

  4. glDrawElements takes the number of indices

SOLVED

There we are, took me a while to absorb the info.
I do understand RAM and dynamic memory allocation, though I had rather than one big easy to solve question, I had a multitude of smaller, more prickly questions that were able to prevent me from a complete understanding.

In any case, my problems are solved, and I owe the community, and the posters on my thread such as you, Aqnuep, and with his quick grammar lesson, Reinheart.

Once again, thanks for the extended help.