4
votes

I can display a texture using shaders, glVertexAttribPointer and glDrawArrays like so:

Init

const GLfloat squareVertices[] = {
    -0.5f, -0.33f,
    0.5f, -0.33f,
    -0.5f,  0.33f,
    0.5f,  0.33f
};


const GLfloat squareTex[] = {
    0, 0,
    1, 0,
    0, 1,
    1, 1
};


glEnableVertexAttribArray(PositionTag);
glEnableVertexAttribArray(TexCoord0Tag);

glVertexAttribPointer(PositionTag, 2, GL_FLOAT, GL_FALSE, 0, squareVertices);
glVertexAttribPointer(TexCoord0Tag, 2, GL_FLOAT, GL_FALSE, 0, squareTex);

And for draw

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

But I'm having difficulty converting to VBOs, shaders and glDrawElements. This is the code I have so far, but nothing displays:

Header

typedef struct MyVertex
{
    float x, y, z;        //Vertex
    float nx, ny, nz;     //Normal
    float s0, t0;         //Texcoord0
} MyVertex;

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

Init

glGenBuffers(1, &VertexVBOID);

glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);

MyVertex pvertices[4];
//Fill the pvertices array
pvertices[0].x = -0.5f;
pvertices[0].y = -0.33f;
pvertices[0].z = 0.0;
pvertices[0].nx = 0.0;
pvertices[0].ny = 0.0;
pvertices[0].nz = 1.0;
pvertices[0].s0 = 0.0;
pvertices[0].t0 = 0.0;

pvertices[1].x = 0.5f;
pvertices[1].y = -0.33f;
pvertices[1].z = 0.0;
pvertices[1].nx = 0.0;
pvertices[1].ny = 0.0;
pvertices[1].nz = 1.0;
pvertices[1].s0 = 1.0;
pvertices[1].t0 = 0.0;

pvertices[2].x = -0.5f;
pvertices[2].y = 0.33f;
pvertices[2].z = 0.0;
pvertices[2].nx = 0.0;
pvertices[2].ny = 0.0;
pvertices[2].nz = 1.0;
pvertices[2].s0 = 0.0;
pvertices[2].t0 = 1.0;

pvertices[3].x = 0.5f;
pvertices[3].y = 0.33f;
pvertices[3].z = 0.0;
pvertices[3].nx = 0.0;
pvertices[3].ny = 0.0;
pvertices[3].nz = 1.0;
pvertices[3].s0 = 1.0;
pvertices[3].t0 = 1.0;

glBufferData(GL_ARRAY_BUFFER, sizeof(MyVertex)*4, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(MyVertex)*4, pvertices);


glGenBuffers(1, &IndexVBOID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);

int pindices[6];
pindices[0]=0;
pindices[1]=1;
pindices[2]=2;
pindices[3]=2;
pindices[4]=1;
pindices[5]=3;
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int)*6, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int)*6, pindices);

Draw

glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);

glEnableVertexAttribArray(PositionTag);
glEnableVertexAttribArray(NormalTag);
glEnableVertexAttribArray(TexCoord0Tag);

glVertexAttribPointer(PositionTag, 3, GL_FLOAT, GL_FALSE, 32, BUFFER_OFFSET(0));
glVertexAttribPointer(NormalTag, 3, GL_FLOAT, GL_FALSE, 32, BUFFER_OFFSET(12));
glVertexAttribPointer(TexCoord0Tag, 2, GL_FLOAT, GL_FALSE, 32, BUFFER_OFFSET(24));

//    glDrawRangeElements(GL_TRIANGLES, x, y, z, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0));
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
glDrawElements(GL_TRIANGLES, 3, GL_INT, 0);
2

2 Answers

4
votes

According to here, GL_INT is not a valid type to use for indices in glDrawElements. Try using unsigned ints for your indices (and of course GL_UNSIGNED_INT in glDrawElements). You may still use your int data as indices, but as glDrawElements needs GL_UNSIGNED_INT, it would be more consistent to make the array unsigned int.

EDIT: After looking into the specification (based on your tags I took the ES 2.0 spec), they seem to further limit it to unsigned byte and unsigned short. I don't know if it is that limited in iOS, but we can conclude that the data has at least to be unsigned. On the other hand I haven't found any statement about a possible GL_INVALID_ENUM error that is thrown on a wrong type argument, but it would be reasonable to get one.

1
votes

Your code doesn't look terribly wrong, so this time the devil is somewhere in the details. My guess is, that your use of a struct and its data fields' alignments don't match the offsets passed to OpenGL.

I suggest you use the offsetof() macro found in stddef.h to portably get the offsets of the data fields.