Using glDrawRangeElements with std::vector

Started by
7 comments, last by Mantear 18 years, 4 months ago
I'm trying to use a std::vector to hold my vertex data in my models. I have a Vertex object which contains vertex, color, normal, and texcoord information. I make a vector of those Vertex objects. I bind the vertex data by doing:
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &(((Vertex *) 0)->m_Coordinate));
I then try to draw a quad using:
glDrawRangeElements(GL_QUADS, 0, m_Quads.m_VertexIndex.size(), m_Quads.m_VertexIndex.size(), GL_UNSIGNED_INT, NULL);
I end up getting an "Unhandled exception in Program.exe (ATIOGLXX.DLL): 0xC0000005: Access Violation." All the other code, generating the VBOs, etc, I'm using from a version that's working fine. The only difference is how I'm storing and trying to use my data, so I'm confident that my problem resides somewhere in those 2 lines.
Advertisement
What the heck are you trying to do with &(((Vertex *) 0)->m_Coordinate)?
&(((Vertex *) 0)->m_Coordinate) obtains the offset into the Vertex class object where m_Coordinates exists (which contains the x, y, z coordinates of the vertex). According to the documentation, the parameters for glVertexPointer are:

size
The number of coordinates per vertex. The value of size must be 2, 3, or 4.
type
The data type of each coordinate in the array using the following symbolic constants: GL_SHORT, GL_INT, GL_FLOAT, and GL_DOUBLE.
stride
The byte offset between consecutive vertices. When stride is zero, the vertices are tightly packed in the array.
pointer
A pointer to the first coordinate of the first vertex in the array.

So 3 for the size (3 coordinates), GL_FLOAT for the type (x, y, and z are floats), sizeof(Vertex) for the stride, and &(((Vertex *) 0)->m_Coordinate) provides the offset into a Vertex object, pointing to the start of the data. I'm not 100% sure as to how that last parameter works, since I got the code snippet from someone else doing the same thing, but it does seem to be providing the correct value. In my current case, it has a result of 4, meaning a 4 byte offset into the Vertex object.
Yes, the last parameter looks OK. I'm not sure what the standard would have to say to it (come to that I'm not even sure where I'd look), but it's basically just offsetof(Vertex, m_Coordinate). Since VBOs use an offset into the currently bound buffer this is perfectly valid.

I'd be more suspicious of the glDrawRangeElements call, particularly the end parameter. I assume you've set up your GL_ELEMENT_ARRAY_BUFFER correctly and bound it? With your start and end parameters as they are you're stating that for every element in your GL_ELEMENT_ARRAY_BUFFER (element >= 0 && element <= m_Quads.m_VertexIndex.size()), which is probably true but only because there tend to be as many or more indicies than vertices (otherwise you have unused vertices). Best to double check anyway.

Enigma
The last argument to glVertexPointer is the address of the beginning of the index information of the vertex array that you're passing to GL. It's not an offset. Right now you're passing 0x00000004 as the start of the index information, which GL will try to read, generating an access violation as 0x00000004 is a protected memory location.
Only for Vertex Arrays. Vertex Buffer Objects "overload" the functions allowing you to specify the offset from the start of the currently bound buffer. From the VBO spec (emphasis mine):
Quote:Rendering commands ArrayElement, DrawArrays, DrawElements,
DrawRangeElements, MultiDrawArrays, and MultiDrawElements operate as
previously defined, except that data for enabled vertex, variant, and
attrib arrays are sourced from buffers if the array's buffer binding
is non-zero. When an array is sourced from a buffer object, the
pointer value of that array is used to compute an offset, in basic
machine units, into the data store of the buffer object
. This offset
is computed by subtracting a null pointer from the pointer value,
where both pointers are treated as pointers to basic machine units.

And from the examples at the end of the spec:
Quote:Convenient macro definition for specifying buffer offsets:
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
// ...
VertexPointer(4, FLOAT, 0, BUFFER_OFFSET(0));
ColorPointer(4, UNSIGNED_BYTE, 0, BUFFER_OFFSET(256));

Enigma
Quote:Original post by EnigmaI'd be more suspicious of the glDrawRangeElements call, particularly the end parameter. I assume you've set up your GL_ELEMENT_ARRAY_BUFFER correctly and bound it? With your start and end parameters as they are you're stating that for every element in your GL_ELEMENT_ARRAY_BUFFER (element >= 0 && element <= m_Quads.m_VertexIndex.size()), which is probably true but only because there tend to be as many or more indicies than vertices (otherwise you have unused vertices).


I'm generating my VBOs using:
glGenBuffersARB(1, &m_CoordinateVboName);glBindBufferARB(GL_ARRAY_BUFFER, m_CoordinateVboName);glBufferDataARB(GL_ARRAY_BUFFER, m_Vertices.size() * 3 * sizeof(float), &m_Vertices[0], GL_DYNAMIC_DRAW);glGenBuffersARB(1, &m_Quads.m_VertexIndexVboName);glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, m_Quads.m_VertexIndexVboName);glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, m_Quads.m_VertexIndex.size() * sizeof(unsigned int), &m_Quads.m_VertexIndex[0], GL_DYNAMIC_DRAW);
When I go to draw, I use:
glBindBufferARB(GL_ARRAY_BUFFER, m_CoordinateVboName);glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &(((Vertex *) 0)->m_Coordinate));glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, m_Quads.m_VertexIndexVboName);glDrawRangeElements(GL_QUADS, 0, m_Quads.m_VertexIndex.size(), m_Quads.m_VertexIndex.size(), GL_UNSIGNED_INT, NULL);


Quote:Right now you're passing 0x00000004 as the start of the index information, which GL will try to read, generating an access violation as 0x00000004 is a protected memory location.
Isn't this what I do anyways, when there isn't an offset? In my old version, I was simply using a plain old array. My offset was 0, so I had:
glVertexPointer(3, GL_FLOAT, 0, 0);
Now my offset is 4 bytes, so why shouldn't the 4th paramter be 4?
glBufferDataARB(GL_ARRAY_BUFFER, m_Vertices.size() * 3 * sizeof(float), &m_Vertices[0], GL_DYNAMIC_DRAW);
...
glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &(((Vertex *) 0)->m_Coordinate));

This look suspicious. Especially if &(((Vertex *) 0)->m_Coordinate)) is 4 like you say. What exactly are you storing in m_Vertices? I would probably have expected that first line to be:

glBufferDataARB(GL_ARRAY_BUFFER, m_Vertices.size() * sizeof(Vertex), &m_Vertices[0], GL_DYNAMIC_DRAW);

assuming m_Vertices stores Vertex objects (if so it would be useful to see a definition for Vertex).

The start and end parameters for glDrawRangeElements should be equivalent to:
unsigned int min = std::numeric_limits< unsigned int >::max();unsigned int max = 0;for (int i = 0; i < m_Quads.m_VertexIndex.size(); ++i){	min = std::min(min, m_Quads.m_VertexIndex);	max = std::max(max, m_Quads.m_VertexIndex);}glDrawRangeElements(..., min, max, ..., ..., ...);

Enigma
Yes, your suggestion of changing the glBufferData function seems to be correct. However, I changed it but have the same error.

My Vertex class is as follows:
typedef struct{   float X;   float Y;   float Z;} sCoordinates;typedef struct{   unsigned char R;   unsigned char G;   unsigned char B;   unsigned char A;} sColors;typedef struct{   float X;   float Y;   float Z;} sNormals;typedef struct{   float U;   float V;} sTexCoords;class Vertex{public:   // Constructors and Destructors   Vertex(void) {}   ~Vertex(void) {}   unsigned int   m_TimesUsed;   sCoordinates   m_Coordinate;   sColors        m_Color;   sNormals       m_Normal;   sTexCoords     m_TexCoord;};


My Polygon class, of which m_Quad is, contains a vector of unsigned ints, containing the vertex index values for all quads in the model.

I'll look into setting the proper start/end parameters once I get things drawing.

This topic is closed to new replies.

Advertisement