2

I'm relatively new to OpenGL and have been using the GLTools library it provides. One of the classes, GLTriangleBatch, in part, deals with batches of vertexs. The class has a global attribute pointer pVerts declared as follows:

typedef float M3DVector3f[3];
M3DVector3f *pVerts; 

When an initializing function is called, the above pointer is delegated a block of memory with the number of indexs being an int provided to the function as an argument(nMaxIndexes):

pVerts = new M3DVector3f[nMaxIndexes];

Another function is given an array of 3 M3DVector3fs that comprise vertex points of a triangle. This function determines which individual vertices are added to the batch or not.

For example, if the point to be added already exists in pVerts, the index of that point in pVerts is added to another array which holds the index of all points that will be drawn. Therefore pVerts contains only unique points. Therefore the actual index of pVerts will never reach nMaxIndexes.

However, in the case that it is a unique vertex, it is added to pVerts as follows:

memcpy(pVerts[nNumVerts], verts[iVertex], sizeof(M3DVector3f));

where nNumVerts is the current index of pVerts, verts[] is the array of 3 M3DVector3f's that comprise the triangle being added with iVertex being the index of the particular vertexbeing added.

Now i use another function that calculates the positions of vertex points to build a (rough) sphere. The sphere i build in my program ends up with nMaxIndexes = 2028, and when the sphere is completed nNumVerts = 378.

Now following all of this i assumed pVerts pointed to an array of index ranging 0 to 2027, but only indexes 0 to 377 being populated with data. But when i put a breakpoint directly after all the vertices are added, pVerts points only a single M3DVector3f.

I need access to each of these individual points as I plan to use this sphere as a collidible boundary. I have added a getVertices function that returns pVerts, but the returned pointer only points to a single M3DVector3f? What am i missing?

3
  • The line memcpy(pVerts[nNumVerts], verts[iVertex], sizeof(M3DVector3f)); is not correct as it stands, as pVerts[n] dereferences a pointer with offset n to the address pVerts points to. The correct line is memcpy(&pVerts[nNumVerts], &verts[iVertex], sizeof(M3DVector3f)); or memcpy(pVerts+nNumVerts, verts+iVertex, sizeof(M3DVector3f)); Commented Jun 20, 2011 at 22:04
  • @datenwolf: each element of pVerts is an array, so that line works with or without the &. Commented Jun 20, 2011 at 22:23
  • @interjay: Ah, that part fell of the right border of my screen in the comment. Commented Jun 20, 2011 at 22:29

2 Answers 2

1

This is not so much a 3D graphics or OpenGL problem, but a lack of understanding how arrays work in C and C++.

An array in C is a set of contigous address space backed by system memory. The contents are addressed by a base pointer and an offset against this base pointer, through a mechanism called pointer arithmetic.

Say p is a pointer of type T, in C syntax written T *p. Now let p point to some contigous memory of n elements of type T, allocated either with new T[n] (C++) or malloc(sizeof(t)). To access the i-th element you need the address of that element and dereference the pointer to that address. C has a mechanism called pointer arithmetic for this: p + i is evaluated to the pointer to the i-th element in a contigous set of elements starting at p. To get the value of the element you have to dereference using the * operator: *(p+i). A shorthand form is provided by the index operator [] and actually p[i] is exactly the same as *(p+i).

This is a little known fact and has interesting consequences. Pointer arithmetic commutes, i.e. p + i == i + p and applying that to the index operator one would expect that p[i] == i[p] which is actually the case.

Getting back to your original problem: You're using C++, so I recommend you don't bother with manually allocated arrays at all. Instead you better use a standard container, namely std::vector, available through #include <vector> (no trailing .h!)

Instead of M3DVector3f *pVerts which is just a pointer, not an full qualified array(!), you write std::vector<M3DVector3f> Verts and this actually is what you'd call array (the C++ STL calls it vector to distinguish it from plain arrays; this might sound odd at first, but once you've understood vector spaces from a higher mathematics point of view it actually makes sense). Instead of memcpy(...) you should be able to use the assignment operator = on vector elements, i.e. Verts[nNumVerts] = verts[iVertex]. If the compiler complains, overload the assignment operator:

struct M3DVertex3f {        
    float v[3] __attribute__ ((packed)); // this is a static array, so no double pointers!
    M3DVertex3f &operator=(M3DVertex3f const &src);
}

M3DVertex3f &M3DVertex3f::operator=(M3DVertex3f const &src)
{
    for(int i=0;i<3;i++)
         v[i] = src.v[i];       
    return *this;        
}

std::vector<M3DVertex3f> Verts;
Sign up to request clarification or add additional context in comments.

4 Comments

M3DVertex3f is not a class though, it is a typedef for an array of 3 floats. These arrays will be converted to a pointer type when passed to memcpy, so that call will work. And the assignment operator can't be overloaded on an array.
Yes, I saw it as you told me in the first comment. But what I said holds, you have to change only very little.
In fact, you can't even use vector<M3DVertex3f> because the compiler won't accept it. I suppose you can define a wrapper class that contains a M3DVertex3f member and put that in the vector, but then you run into problems if there's an OpenGL function that expects you to pass in an array of M3DVertex3f.
@interjay: I was thinking about a struct instead of a class (yes I know C++ treats them almost identically). However you can not pass a dynamic C array of C arrays to OpenGL either in, say glVertexAttribPointer, since the first array only contains pointers to the smaller subarrays. The only time this works is when working with static [][] arrays, because then all elements are actually packed in memory and that pointer to pointer semantic happens at compile time. However using a struct with proper alignment attributes (compiler extension) can be used in std::vector and passed to OpenGL.
1

pVerts is a pointer to a variable of type M3DVector3f. I suspect your debugger is correctly showing you the M3DVector3f that pVerts points to (i.e. the first element of your array). This doesn't necessarily mean there's an error: arrays in C and C++ do not carry any intrinsic size information, so there's no way to examine the 'array object', you can only look at what's in memory at a specified address.

5 Comments

is there any way to get access to all of the pVert entires without creating an entirely different array to hold them?
You can access the pVerts array as pVerts[0], pVerts[1], etc. How else would you like to access it?
ahh so what your saying is while the compiler at my break point only shows 1 m3Dvector3f, the vPerts will have access to all of them?
Exactly. If your array has type M3DVector3f *, which is fine, then the debugger can't do anything else. As I said in the answer above, there's no array size associated with the pointer type.
@user: I don't know which debugger you're using, but in Visual Studio you can write (for example) pVerts,1000 in the watch window, and this will show pVerts as an array of 1000 elements. Maybe your debugger has a similar capability.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.