PDA

View Full Version : Dynamic vertex array



03-21-2005, 07:51 PM
How can I create a dynamic vertex array with C/C++?
I need to use DrawArray or DrawRangeElements for a varied number of vertices. I want to add/remove any number of vertices per frame to the array as needed.
I'll need several arrays for different states, but I'm trying to stay simple for now. (Isn't this what some engines do ? )

So far I found the C++ "placement new" but no good example of a dynamic vertex array.

uruk
03-21-2005, 08:04 PM
i'm not sure i understand what you want, but is it realloc()?

03-21-2005, 08:49 PM
But is it ok to realloc() a lot ? I read it uses malloc() to resize.. so it might fragment the memory and eventually crash. I need to change the vertex/color/texture coords of the array as the program runs, per frame if possible.

I want to store up vertices and use a single call to DrawArray() functions to render it. I'm suprised there are no examples of this technique.. seems to be what the commands are made for.

T101
03-22-2005, 01:28 AM
Use realloc in larger increments, and don't shrink it.

E.g.:


const int increment=64; // you may want to experiment with this value
vertex *buffer=NULL;
int allocated=0;
int used=0;

// returns pointer to vertex where you can store your data - NULL if failed to allocate
vertex *addvertex()
{
vertex *newbuffer;
vertex *newvertex;

if(used==allocated) { // buffer full or no buffer
newbuffer = (vertex *)realloc(buffer,sizeof(vertex)*(allocated + increment);
if(newbuffer) {
buffer = newbuffer;
allocated+=increment;
}
}
if(used<allocated) {
newvertex = buffer+used;
used++;
return newvertex;
}
return NULL;
}

// reset the vertex pointer to the first in the array
resetbuffer()
{
used=0;
}This way, you keep the number of reallocations and therefore fragmentation and expensive copy operations down, while remaining flexible w.r.t. the maximum number of vertices.
Of course, "malloc-wise" it would be even better to allocate the buffer in its entirety if you know the maximum size tat will be used.

03-22-2005, 04:29 AM
Hey even a example, thanks!

So using this could I change for example the 3rd thru 5th indices of the array as a triangle's texture coords changes?

T101
03-22-2005, 05:00 AM
The only thing this does is it allows you to have a buffer large enough to dump your vertex array into.

When you want to fill the vertex array, just resetbuffer and use the addvertex function on every vertex you want to send to the array.
Finally, the number of elements in the vertexpointer call would be "used".

But it is a throwaway buffer in the sense that you have to fill it everytime.

If you want to allocate "static" vertex arrays (e.g. for every mesh one vertex array) you don't really need realloc at all.

03-22-2005, 05:48 AM
Thank you T101, it's giving better results so far than placement new was.

More stupid questions.. ;)

How can I assign x,y,z values to the vertices? I do this in my main loop right now to test, but I changed addvert() to accept a vertex*.


for (loop = 0; loop < num_verts; loop++){
vertex vert; vert.x=1; vert.y=5; vert.z=200;
addvert( &amp;vert );
} What array can I use for DrawArray()? I assumed "buffer" and it draws, but I'm not sure if that's right. Do I free() "buffer" ?

I guess I can malloc a big buffer as long as I can change the vertex values during runtime. But most vertex array demos I've seen so far seem to use static arrays, and I need some non-static ones ;)

T101
03-22-2005, 06:21 AM
Only free the buffer when you're completely sick of rendering - in other words, when you're ending the program, or loading up another game level or something.

If you "reset" the buffer before you fill it, it does not normally have to reallocate anything once it has grown to the necessary size.

The pointer you supply to OpenGL depends on the definition of the vertex. I kept that out of it because I don't know what you're trying to do per vertex.
But suppose you have a vertex structure as follows:


typedef struct _vertex {
struct {
GLfloat X,Y,Z;
} vector;
struct {
GLfloat S,T;
} texcoords;
struct {
GLfloat X,Y,Z;
} normal;
} vertex;You would use as the stride:
sizeof(vertex)

As the pointer for the vertex vector:
&(buffer[0].vector)

As the pointer for the vertex normal:
&(buffer[0].normal)

etc. (You may have multiple S/T coordinates, or per vertex colors, it all depends on what you want to do with it)

03-22-2005, 06:39 AM
Ok I'm getting there.. Yes I call reset() and it's steady memory wise. I'm not sure what you mean by stride, are you talking about interleaving ?
I'm not going for anything fancy here, not even normals. Just x,y,z, s,t, and colors..
Could an interleaved array work best?

I'm trying for a particle system if anyone is curious.

03-22-2005, 07:08 AM
Hmm well I guessed to use the "stride" of glVertexPointer to draw some triangles but that didn't work. Tried:
glVertexPointer( 3, GL_FLOAT, sizeof(&amp;(buffer[0].vector)) , buffer );

03-22-2005, 07:19 AM
oops! I take that back.. that did actually work. So I can go do glTexCoordPointer the same way ?

03-22-2005, 08:23 AM
Cool now I have some textured triangles flying around. Hmm but do I need the structs in struct like that ?

Is it possible to use something like this ?

struct vertex {
GLfloat x, y, z;
GLfloat s, t;
GLint color;
};

03-22-2005, 08:38 AM
OK I did that by simply adding up multiple sizeof's
glVertexPointer(3, GL_FLOAT, sizeof(&amp;(buffer[0].x)) + sizeof(&amp;(buffer[0].y)) + sizeof(&amp;(buffer[0].z)) , buffer );
glTexCoordPointer(2, GL_FLOAT, sizeof(&amp;(buffer[0].s)) + sizeof(&amp;(buffer[0].t)) , buffer ); I guess I should hack at things before asking from now on ; / I think it's working right, it looks the same but it's hard to be sure with my current test app.

03-22-2005, 07:27 PM
I dont quite understand how I should assign values to the new vertives, or render vertices with this technique. Where do I put the returned vertices? Do I need another buffer?

I try this but it crashes.

buffer[ 0 ] = addvertex();
buffer[ 1 ] = addvertex();
buffer[ 2 ] = addvertex(); If I just do 3 calls to addvertex() and not return anything, I get a triangle..but I cant seem to assign values to the x,y,z of these vertices.

T101
03-22-2005, 11:31 PM
Something like:


resetbuffer();
while( i_want_to_add_a_vertex ) {
newvertex = addvertex();
if(newvertex) {
newvertex->x= ...
newvertex->y= ...
etc.
}
...determine if i still want to add more vertices
}

glIndexPointer(INT,sizeof(vertex),&amp;(buffer[0].color));
glTexCoordPointer(2,FLOAT,sizeof(vertex),&amp;(buffer[0].s));
glVertexPointer(3,FLOAT,sizeof(vertex),&amp;(buffer[0].x));
glDrawArrays(GL_TRIANGLES,0,used);

03-23-2005, 10:05 AM
Hmm.. I have this so far, but values still aren't getting set for newvertices :confused:


const int increment=128; //I changed this..
vertex *buffer=NULL, *newvertex=NULL;// ??
int allocated=0, used=0;

vertex *addvertex(){
vertex *newbuffer;
//vertex *newvertex; //do i make this a global?

if(used==allocated) {
newbuffer=(vertex*)realloc(buffer,sizeof(vertex)*( allocated + increment);
if(newbuffer) {
buffer = newbuffer;
allocated+=increment;
}
}
if(used<allocated) {
newvertex = buffer+used;
used++;
return newvertex;
}
return NULL;
}

struct triangle { vertex v[3] };

void RenderTri( triangle *tri ){
newvertex = addvertex(); if(newvertex)newvertex=&amp;tri->v[0];
newvertex = addvertex(); if(newvertex)newvertex=&amp;tri->v[1];
newvertex = addvertex(); if(newvertex)newvertex=&amp;tri->v[2];
}


void Draw() {

// (omitting GL setup stuff...)

vertex test;
test.v[0].x = -1;
test.v[0].y = 0;
test.v[0].z = 1;
test.v[0].s = 1;
test.v[0].t = -1;
// etc etc for other verts in "test"

RenderTri( &amp;test );

glEnable(GL_VERTEX_ARRAY);
glEnable(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2,GL_FLOAT, sizeof( vertex ) , &amp;buffer[0].s );
glVertexPointer(3,GL_FLOAT,sizeof( vertex ) , &amp;buffer[0].x);
glDrawArrays(GL_TRIANGLES,0,used);

resetbuffer();
}I get the same triangle I get from just calling addvertex() 3 times.. It seems close! Just missing something in there.

T101
03-23-2005, 10:53 PM
This is wrong:

void RenderTri( triangle *tri ){
newvertex = addvertex();
if(newvertex)newvertex=&amp;tri->v[0];
newvertex = addvertex();
if(newvertex)newvertex=&amp;tri->v[1];
newvertex = addvertex();
if(newvertex)newvertex=&amp;tri->v[2];
}
"newvertex" is a pointer to a vertex structure.
The addvertex function is a bit like new and malloc. It tells you where you may store the vertex data.
Have another look at my example code, please.
You should be doing something like:

newvertex = addvertex();
if(newvertex){
newvertex->x=tri->v[0].x;
newvertex->y=tri->v[0].y;
newvertex->z=tri->v[0].z;
// etc.
}
// repeat for the other vertices
BTW: newvertex is only used by your RenderTri function, so make it local to that function.

03-24-2005, 12:43 AM
Thank you T101 ! I was thrown off by the "newvertex" local to addvertex(). That and I was feeding each triangle the same coordinate values, so I couldn't see it was actually drawing many triangles.

This is exactly what I needed ;)