3

I have my OpenGL code working but I am trying to improve its performance a bit (would like to bump up the frame-rate a bit on older devices). I am trying to do this using a Vertex Buffer Object.

All my code does is draw a series of 360 GL_TRIANGLES that have a texture applied to them. I interweave the coordinates and the texture coordinates into a data structure.

typedef struct {
    GLfloat vertex[2];
    GLfloat texture[2];
    GLfloat padding[4];
} TextureVertex2D;

typedef struct {
    TextureVertex2D textureVertex[3];
} TextureTriangle2D;

Here is the relevant part of my initialization

textureTriangles = (TextureTriangle2D*)malloc(360 * sizeof(TextureTriangle2D));

glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);

// This section is the only new code introduced for the VBOs.
glGenBuffers(1, &buffer[0]);
glBindBuffer(GL_ARRAY_BUFFER, buffer[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(TextureTriangle2D)*360, textureTriangles[0].textureVertex[0].vertex, GL_DYNAMIC_DRAW);
// end new code    

glVertexPointer(2, GL_FLOAT, sizeof(TextureVertex2D), textureTriangles[0].textureVertex[0].vertex);
glTexCoordPointer(2, GL_FLOAT, sizeof(TextureVertex2D), textureTriangles[0].textureVertex[0].texture);

/*
textureTriangles is filled and the texture image is loaded in
*/

For the saving to the actual VBO, I have tried two methods (both of which have had the same result)

// Option 1
GLvoid* vbo_buffer = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
memcpy(vbo_buffer, textureTriangles[0].textureVertex[0].vertex, 360 * sizeof(TextureTriangle2D));
glUnmapBufferOES(GL_ARRAY_BUFFER); 

// Option 2
glBufferSubData(GL_ARRAY_BUFFER, sizeof(TextureVertex2D), 360 * sizeof(TextureTriangle2D), textureTriangles[0].textureVertex[0].vertex);

Then I bind the buffer

glBindBuffer(GL_ARRAY_BUFFER, buffer[0]);

And finally perform the drawing

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glDrawArrays(GL_TRIANGLES, 0, 3*360);

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

Without the VBOs, the drawing works fine. After I add the VBO code above, the drawing is no longer in the right spot (offset by a few pixels) and it locks up my entire app. Any ideas?

Ross Kimes
  • 1,234
  • 1
  • 12
  • 34
  • In your `glBufferSubData` the second argument should be `0` instead of `sizeof(TextureVertex2D)`. But you should use `glBufferData` when updating the whole buffer, anyway. – Christian Rau Jan 06 '12 at 13:37

2 Answers2

2

When using VBOs, the last argument to gl...Pointer is not a pointer to some array containing the vertex data, but a byte offset into the currently bound GL_ARRAY_BUFFER. So you don't specifiy the addresses of your CPU vertex data, which you already copied into the buffer, but the offsets in this buffer data where the attributes are stored:

glVertexPointer(2, GL_FLOAT, sizeof(TextureVertex2D), 
    offsetof(TextureVertex2D,vertex));
glTexCoordPointer(2, GL_FLOAT, sizeof(TextureVertex2D), 
    offsetof(TextureVertex2D,texture));
Christian Rau
  • 45,360
  • 10
  • 108
  • 185
0

In this line:

glBufferData(GL_ARRAY_BUFFER, sizeof(TextureTriangle2D)*360, textureTriangles[0].textureVertex[0].vertex, GL_DYNAMIC_DRAW);

I think you should specify sizeof(TextureTriangle2D)*360*3 since each triangle (using GL_TRIANGLES in the draw array request) requires 3 vertices coordinates.

I don't have much information about passing 3D coordinates using just 2 coordinates (I guess having Z fixed to zero?) but the declaration itself should be subject to review on your side

I would have expected:

typedef struct {
    GLfloat vertex[3];
    GLfloat texture[2];
    GLfloat padding[3];
} TextureVertex2D;

But this depends a lot on your engine.

Christian Rau
  • 45,360
  • 10
  • 108
  • 185
Maurizio Benedetti
  • 3,557
  • 19
  • 26
  • Using 2 coordinates only is just fine, z will just be 0 (like w is 1 when not used). If you would use 3 coordinates, then of course the padding should only be 3 instead of 4 (if needed anyway). I'll correct this. – Christian Rau Jan 06 '12 at 13:33
  • Of course this size error needs to be changed in his update routines, too. – Christian Rau Jan 06 '12 at 13:38
  • @ChristianRau I don't think that this is the problem though. Like you said, z will always equal 0 (which is what I am wanting, I am only drawing 2D objects). – Ross Kimes Jan 06 '12 at 17:05
  • @RossKimes This was my point: 2D coordinates are just fine if you don't need a z other than 0. But the first part of this answer (the size error in your buffer allocation and update code) still applies and is likely to be the source of your problem. – Christian Rau Jan 06 '12 at 17:58
  • I don't think that line is the problem. Notice that I had I was using TextureTRIANGLE2D, not TextureVertex2D. The TextureTriangle2D is composed of 3 TextureVertex2Ds, so that 3 is already in there. – Ross Kimes Jan 06 '12 at 18:11
  • @RossKimes Ah indeed, completely overlooked that. – Christian Rau Jan 06 '12 at 18:25