I am creating a rectangle in OpenGL ES 2.0 using GLKit. This is working and I can fill up the rectangle with solid colour and a gradient.
Now I am trying to fill it up with a texture from an image, which is not working for me.
I am getting a EXC_BAD_ACCESS code=1 error on the glDrawElements line.
Here is what I have right now:
//Setup GKLView
EAGLContext *context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
self.glkView = [[GLKView alloc] initWithFrame:self.bounds
context:context];
_glkView.opaque = NO;
_glkView.backgroundColor = [UIColor clearColor];
_glkView.delegate = self;
[self addSubview:_glkView];
//Setup BaseEffect
self.effect = [[GLKBaseEffect alloc] init];
[EAGLContext setCurrentContext:_glkView.context];
GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(0, self.bounds.size.width, 0, self.bounds.size.height, 0.0, 1.0);
self.effect.transform.projectionMatrix = projectionMatrix;
GLKMatrix4 modelMatrix = GLKMatrix4Translate(GLKMatrix4Identity, 0.0, 0.0, -0.1);
self.effect.transform.modelviewMatrix = modelMatrix;
//Load image
UIImage* image = ...
CGImageRef cgImage = image.CGImage;
NSError* error;
self.textureInfo = [GLKTextureLoader textureWithCGImage:cgImage options:nil error:&error];
if (error) {
NSLog(@"could not load texture");
}
if (_textureInfo) {
self.effect.texture2d0.envMode = GLKTextureEnvModeReplace;
self.effect.texture2d0.target = GLKTextureTarget2D;
self.effect.texture2d0.name = _textureInfo.name;
}
//Bind buffers
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer (GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *) offsetof(Vertex, Position));
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 0, _currentData.texCoordinates);
//Populate buffers
glBufferData(GL_ARRAY_BUFFER, (sizeof(Vertex) * _currentData.numberOfVertices), _currentData.vertices, GL_STATIC_DRAW);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (sizeof(GLubyte) * _currentData.numberOfIndices), _currentData.indices, GL_STATIC_DRAW);
[self.effect prepareToDraw];
[self.glkView display];
//Inside - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect;
glDrawElements(GL_TRIANGLE_STRIP, (sizeof(GLubyte) * _currentData.numberOfIndices), GL_UNSIGNED_BYTE, 0);
The data for texture coordinates is:
SimpleVertex* vertices1 = (SimpleVertex *)malloc(sizeof(SimpleVertex) * 4);
vertices1[0].Position[0] = 0.0;
vertices1[0].Position[1] = 0.0;
vertices1[1].Position[0] = 0.0;
vertices1[1].Position[1] = 1.0;
vertices1[2].Position[0] = 1.0;
vertices1[2].Position[1] = 1.0;
vertices1[3].Position[0] = 1.0;
vertices1[3].Position[1] = 0.0;
typedef struct
{
GLfloat Position[2];
}
SimpleVertex;
As I said, I am sure the rectangle is being drawn correctly. I can check this by filling it up with gradient, it looks fine. Also the texture loader is loading the image correctly, I can check this in the debugger.
Can someone point out what I am missing or doing wrong here?
Ok I figured it out. The mistake was in the way I was passing texture co-ordinate data to openGL. I was passing the data for vertices and colour this way:
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer (GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *) offsetof(Vertex, Position));
But for texture coordinates I created a separate structure and was passing a pointer to that data and not an offset to the already bonded vertices array:
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 0, _currentData.texCoordinates);
The solution then was obviously to include the data within the Vertex data structure and then give the offset like so:
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (const GLvoid *) offsetof(Vertex, TexCoord));
I am still a newbie to OpenGL ES so there might have been a better way to solve this problem but this worked for me.