OpenGL ES 2.0 Multiple Instances of Textured Object - iphone

I am using Blender to create a 3D cow and obtain the correct vertices (optimized afterwards to remove duplicates). I have created a Cow Class to be able to draw multiple instances of this cow on screen.
Cow 1 is drawn at (-2,0,-10) and Cow 2 is drawn at (2,0,-10). When I render cow 1 only I see Cow 1 at (-2,0,-10). When I render either both cows or only cow 2 (comment render cow 1 out), I only get cow 2 (do not see cow 1) at (2,0,-10). I am making a game where I will have many enemies running around and I need to be able to draw multiple instances of these objects and render them independently at different locations. Can anyone tell me what I am doing wrong? Thanks
//
// Cow.m
//
#import "Cow.h"
#import "cow_verts.h"
#implementation Cow
- (id)initWithContext:(EAGLContext *)aContext {
context = aContext;
effect = [[GLKBaseEffect alloc] init];
[EAGLContext setCurrentContext:context];
sharedResourceManager = [ResourceManager sharedResourceManager];
UIImage *textureImage = [UIImage imageNamed:#"cowUV.png"];
texture = [sharedResourceManager addTexture:textureImage];
position = GLKVector3Make(0,0,0);
rotation = GLKVector3Make(0,0,0);
scale = GLKVector3Make(1,1,1);
[self setupGL];
return self;
}
- (void)setupGL {
glGenVertexArraysOES(1, &_vao);
glBindVertexArrayOES(_vao);
glGenBuffers(1, &_dynamicVBO);
glBindBuffer(GL_ARRAY_BUFFER, _dynamicVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(CowDynamicVertexData), CowDynamicVertexData, GL_DYNAMIC_DRAW);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(dynamicVertexData), (void *)offsetof(dynamicVertexData, position));
glEnableVertexAttribArray(GLKVertexAttribPosition);
glGenBuffers(1, &_staticVBO);
glBindBuffer(GL_ARRAY_BUFFER, _staticVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(CowStaticVertexData), CowStaticVertexData, GL_STATIC_DRAW);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(staticVertexData), (void *)offsetof(staticVertexData, texCoord));
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(CowIndices), CowIndices, GL_STATIC_DRAW);
glBindVertexArrayOES(0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
- (void)updateWithDelta:(float)aDelta {
float aspect = fabsf([[UIScreen mainScreen] bounds].size.width/ [[UIScreen mainScreen] bounds].size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 4.0f, 20.0f);
effect.transform.projectionMatrix = projectionMatrix;
rotation.y += 90 * aDelta;
}
- (void)render {
[EAGLContext setCurrentContext:context];
glClearColor(0, 1, 1, 1);
glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
GLKMatrix4 xRotationMatrix = GLKMatrix4MakeXRotation(GLKMathDegreesToRadians(rotation.x));
GLKMatrix4 yRotationMatrix = GLKMatrix4MakeYRotation(GLKMathDegreesToRadians(rotation.y));
GLKMatrix4 zRotationMatrix = GLKMatrix4MakeZRotation(GLKMathDegreesToRadians(rotation.z));
GLKMatrix4 scaleMatrix = GLKMatrix4MakeScale(scale.x, scale.y, scale.z);
GLKMatrix4 translateMatrix = GLKMatrix4MakeTranslation(position.x, position.y, position.z);
GLKMatrix4 modelMatrix = GLKMatrix4Multiply(translateMatrix,
GLKMatrix4Multiply(scaleMatrix,
GLKMatrix4Multiply(zRotationMatrix,
GLKMatrix4Multiply(yRotationMatrix,
xRotationMatrix))));
effect.transform.modelviewMatrix = modelMatrix;
//GLKMatrix4 viewMatrix = GLKMatrix4MakeLookAt(0, 0, 3, 0, 0, 0, 0, 1, 0);
//effect.transform.modelviewMatrix = GLKMatrix4Multiply(viewMatrix, modelMatrix);
effect.texture2d0.name = texture.name;
effect.texture2d0.target = texture.target;
effect.texture2d0.envMode = GLKTextureEnvModeReplace;
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glBindVertexArrayOES(_vao);
[effect prepareToDraw];
glDrawElements(GL_TRIANGLES, sizeof(CowIndices)/sizeof(CowIndices[0]), GL_UNSIGNED_INT, (void *)0);
glBindVertexArrayOES(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
}
#end
//
// Cow.h
//
#interface Cow : NSObject {
EAGLContext *context;
GLuint _vao;
GLuint _staticVBO;
GLuint _dynamicVBO;
GLuint _indexBuffer;
GLKTextureInfo *texture;
GLKBaseEffect *effect;
GLKVector3 position;
GLKVector3 rotation;
GLKVector3 scale;
ResourceManager *sharedResourceManager;
}
- (id)initWithContext:(EAGLContext *)aContext;
- (void)updateWithDelta:(float)aDelta;
- (void)render;
#end
//
// Scene which creates these objects and calls the functions
//
#import "Cow.h"
#implementation GameScene {
NSMutableArray *cows;
}
- (id)init {
if(self = [super init]) {
sharedDirector = [Director sharedDirector];
[EAGLContext setCurrentContext:[sharedDirector context]];
cows = [[NSMutableArray alloc] init];
AbstractEnemy *cow1 = [[Cow alloc] initWithContext:[sharedDirector context]];
cow1.position = GLKVector3Make(-2, 0, -10);
[cows addObject:cow1];
AbstractEnemy *cow2 = [[Cow alloc] initWithContext:[sharedDirector context]];
cow2.position = GLKVector3Make(2, 0, -10);
[cows addObject:cow2];
AbstractEnemy *cow3 = [[Cow alloc] initWithContext:[sharedDirector context]];
cow3.position = GLKVector3Make(0, 0, -15);
[cows addObject:cow3];
}
return self;
}
- (void)updateWithDelta:(GLfloat)aDelta {
for (int i = 0; i < cows.count; i++)
{
[cows[i] updateWithDelta:aDelta];
}
}
- (void)render {
for (int i = 0; i < cows.count; i++)
{
[cows[i] render];
}
}
#end

From the code you gave, you are calling a glClear() every time before you draw the cow. With all those clear calls, only the last cow you draw will be visible.
Move this call into the scene's render function so you only clear the scene once at the start of each frame.

Related

Using OpenGL ES to do texture mapping on simple polygons?

Intro:
I'm brand new at OpenGL. I first go familiar with texture mapping and basic transformations/translations on OpenGL on my PC.
Now it seems I'm basically re-learning everything as im trying to create a simple polygon (quad) with a PNG texture using the GLKit (the GLKView project template helped alot).
Here's the thing:
I was actually able to get up and running very quickly using the project template's out-of-box implementation using the GLKBasicEffect way of rendering. However, ive read so much in the past 24 hours about the recommendation of ignoring this route and going with "OpenGL ES2" way.
My very general idea of this is basically: fixed-pipeline vs programmable-pipeline. Whatever.
Problem:
When going with the "ES2" approach, I can see my quad polygon, but I'm unable to apply a texture on it.
Question: Anybody know of a simple tutorial/example I can follow? Or
even better, can anybody figure out what im doing wrong?
* Insert of Update comment *
I discovered that i was getting a glError thrown due to two things in
my openGL setup: I was calling glEnable(GL_TEXTURE_2D) and
glEnableClientState(GL_TEXTURE_COORD_ARRAY). How am i suppose to
enable texture mapping without these? Or maybe there is a bigger error
somewhere? FYI, I am using Opengl ES2.
* End of update insert *
My ViewController file is below.
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
// Uniform index.
enum
{
UNIFORM_MODELVIEWPROJECTION_MATRIX,
UNIFORM_NORMAL_MATRIX,
NUM_UNIFORMS
};
GLint uniforms[NUM_UNIFORMS];
// Attribute index.
enum
{
ATTRIB_VERTEX,
ATTRIB_NORMAL,
NUM_ATTRIBUTES
};
BOOL updateRotate = FALSE;
VertexData *p_meshVertexData = nil;
int g_numFaces = 0;
GLuint g_textures[2]; // 0: photo, 1: picture frame.
const int DataSize = 48;
GLfloat PortraitVertexData[DataSize] =
{
// CCW
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0,1,
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0,0,
0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1,0,
-0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0,1,
0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1,0,
0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1,1,
};
#interface ViewController () {
GLuint _program;
GLKMatrix4 _modelViewProjectionMatrix;
GLKMatrix3 _normalMatrix;
float _rotation;
GLuint _vertexArray;
GLuint _vertexBuffer;
}
#property (strong, nonatomic) EAGLContext *context;
//#property (strong, nonatomic) GLKBaseEffect *effect;
#property (strong, nonatomic) GLKTextureInfo *texture;
#property (nonatomic, retain) CaptureEngine *engine;
- (void)setupGL;
- (void)tearDownGL;
- (BOOL)loadShaders;
- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file;
- (BOOL)linkProgram:(GLuint)prog;
- (BOOL)validateProgram:(GLuint)prog;
#end
#implementation ViewController
#synthesize context = _context;
//#synthesize effect = _effect;
#synthesize texture = _texture;
#synthesize engine;
/// View did load.
- (void)viewDidLoad
{
[super viewDidLoad];
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) {
NSLog(#"Failed to create ES context");
}
GLKView *view = (GLKView *)self.view;
view.context = self.context;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
[self initEngine];
[self setupGL];
}
/// Initialize engine object.
- (void) initEngine
{
self.engine = [[CaptureEngine alloc] init];
g_numFaces = DataSize / 8;
p_meshVertexData = (VertexData *)malloc(g_numFaces * sizeof(VertexData));
int numIndex = 0;
for (int i = 0; i < DataSize; i += 8)
{
float x = PortraitVertexData[i];
float y = PortraitVertexData[i + 1];
float z = PortraitVertexData[i + 2];
float nx = PortraitVertexData[i + 3];
float ny = PortraitVertexData[i + 4];
float nz = PortraitVertexData[i + 5];
float tx = PortraitVertexData[i + 6];
float ty = PortraitVertexData[i + 7];
VertexData data;
data.vertex.x = x;
data.vertex.y = y;
data.vertex.z = z;
data.normal.x = nx;
data.normal.y = ny;
data.normal.z = nz;
data.textureCoord.x = tx;
data.textureCoord.y = ty;
p_meshVertexData[numIndex++] = data;
}
// UIImage *testImage = [UIImage imageNamed:#"frame.png"];
// self.previewImage.image = [ImageLoader ConvertToGrayedImage:testImage];
}
// Dealloc.
- (void)dealloc
{
[self tearDownGL];
if ([EAGLContext currentContext] == self.context) {
[EAGLContext setCurrentContext:nil];
}
}
// Memory warning.
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
if ([self isViewLoaded] && ([[self view] window] == nil)) {
self.view = nil;
[self tearDownGL];
if ([EAGLContext currentContext] == self.context) {
[EAGLContext setCurrentContext:nil];
}
self.context = nil;
}
// Dispose of any resources that can be recreated.
}
// Setup OpenlGL.
- (void)setupGL
{
[EAGLContext setCurrentContext:self.context];
[self loadShaders];
/*
self.effect = [[GLKBaseEffect alloc] init];
self.effect.light0.enabled = GL_TRUE;
self.effect.light0.diffuseColor = GLKVector4Make(1.0f, 1.0f, 1.0f, 0.5f);
self.effect.lightingType = GLKLightingTypePerPixel;
*/
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glGenVertexArraysOES(1, &_vertexArray);
glBindVertexArrayOES(_vertexArray);
glGenBuffers(1, &_vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(VertexData) * g_numFaces, p_meshVertexData, GL_STATIC_DRAW);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), 0);
glEnableVertexAttribArray(GLKVertexAttribNormal);
glVertexAttribPointer(GLKVertexAttribNormal, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (char *)12);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), (char *)24);
//// texture sample
/*
glActiveTexture(GL_TEXTURE0);
NSString *path = [[NSBundle mainBundle] pathForResource:#"frame" ofType:#"png"];
NSError *error;
NSDictionary *options = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES]
forKey:GLKTextureLoaderOriginBottomLeft];
self.texture = [GLKTextureLoader textureWithContentsOfFile:path
options:options error:&error];
if (self.texture == nil)
NSLog(#"Error loading texture: %#", [error localizedDescription]);
*/
/*
GLKEffectPropertyTexture *tex = [[GLKEffectPropertyTexture alloc] init];
tex.enabled = YES;
tex.envMode = GLKTextureEnvModeDecal;
tex.name = self.texture.name;
self.effect.texture2d0.name = tex.name;
*/
UIImage *textureImage = [UIImage imageNamed:#"frame.png"];
[self ApplyTexture: textureImage];
//// end of texture sample
glBindVertexArrayOES(0);
}
// Dealloc OpenlGL.
- (void)tearDownGL
{
[EAGLContext setCurrentContext:self.context];
glDeleteBuffers(1, &_vertexBuffer);
glDeleteVertexArraysOES(1, &_vertexArray);
//self.effect = nil;
if (_program)
{
glDeleteProgram(_program);
_program = 0;
}
}
#pragma mark - GLKView and GLKViewController delegate methods
// Update process.
- (void)update
{
/// Default OpenGL project template (2 cubes) ///
float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(60.0f), aspect, 0.1f, 100.0f);
//self.effect.transform.projectionMatrix = projectionMatrix;
GLKMatrix4 baseModelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, -2.0f);
baseModelViewMatrix = GLKMatrix4Rotate(baseModelViewMatrix, _rotation, 0.0f, 1.0f, 0.0f);
/*
// Compute the model view matrix for the object rendered with GLKit
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, 0.0f);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, _rotation, 0, 1.0f, 0);
modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix);
self.effect.transform.modelviewMatrix = modelViewMatrix;
*/
// Compute the model view matrix for the object rendered with ES2
GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0, 0, 0);
modelViewMatrix = GLKMatrix4Rotate(modelViewMatrix, _rotation, 0, 1.0f, 0);
modelViewMatrix = GLKMatrix4Multiply(baseModelViewMatrix, modelViewMatrix);
_normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);
_modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
if (updateRotate)
{
_rotation += self.timeSinceLastUpdate * 0.5f;
}
}
// Render process.
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(1, 1, 1, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindVertexArrayOES(_vertexArray);
/*
// Render the object with GLKit
[self.effect prepareToDraw];
glDrawArrays(GL_TRIANGLES, 0, g_numFaces);
*/
// Render the object again with ES2
glUseProgram(_program);
glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, 0, _modelViewProjectionMatrix.m);
glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, _normalMatrix.m);
glDrawArrays(GL_TRIANGLES, 0, g_numFaces);
}
- (int) ApplyTexture:(UIImage *)image
{
// 1
CGImageRef spriteImage = image.CGImage;
if (!spriteImage)
{
NSLog(#"Failed to apply texture.");
return -1;
}
// 2
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);
GLubyte * spriteData = (GLubyte *) calloc(width * width * 4, sizeof(GLubyte));
CGContextRef spriteContext = CGBitmapContextCreate(spriteData,
width,
width,
8,
width * 4,
CGImageGetColorSpace(spriteImage),
kCGImageAlphaPremultipliedLast);
// 3
CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
CGContextRelease(spriteContext);
// 4
glGenTextures(1, &g_textures[0]);
glBindTexture(GL_TEXTURE_2D, g_textures[0]);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
// glEnableClientState(GL_TEXTURE_COORD_ARRAY);
CFDataRef data = CGDataProviderCopyData(CGImageGetDataProvider(spriteImage));
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, width, 0, GL_RGBA,
GL_UNSIGNED_BYTE, CFDataGetBytePtr(data));
free(spriteData);
return 0;
}
#pragma mark - OpenGL ES 2 shader compilation
- (BOOL)loadShaders
{
GLuint vertShader, fragShader;
NSString *vertShaderPathname, *fragShaderPathname;
// Create shader program.
_program = glCreateProgram();
// Create and compile vertex shader.
vertShaderPathname = [[NSBundle mainBundle] pathForResource:#"Shader" ofType:#"vsh"];
if (![self compileShader:&vertShader type:GL_VERTEX_SHADER file:vertShaderPathname]) {
NSLog(#"Failed to compile vertex shader");
return NO;
}
// Create and compile fragment shader.
fragShaderPathname = [[NSBundle mainBundle] pathForResource:#"Shader" ofType:#"fsh"];
if (![self compileShader:&fragShader type:GL_FRAGMENT_SHADER file:fragShaderPathname]) {
NSLog(#"Failed to compile fragment shader");
return NO;
}
// Attach vertex shader to program.
glAttachShader(_program, vertShader);
// Attach fragment shader to program.
glAttachShader(_program, fragShader);
// Bind attribute locations.
// This needs to be done prior to linking.
glBindAttribLocation(_program, GLKVertexAttribPosition, "position");
glBindAttribLocation(_program, GLKVertexAttribNormal, "normal");
// Link program.
if (![self linkProgram:_program]) {
NSLog(#"Failed to link program: %d", _program);
if (vertShader) {
glDeleteShader(vertShader);
vertShader = 0;
}
if (fragShader) {
glDeleteShader(fragShader);
fragShader = 0;
}
if (_program) {
glDeleteProgram(_program);
_program = 0;
}
return NO;
}
// Get uniform locations.
uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] = glGetUniformLocation(_program, "modelViewProjectionMatrix");
uniforms[UNIFORM_NORMAL_MATRIX] = glGetUniformLocation(_program, "normalMatrix");
// Release vertex and fragment shaders.
if (vertShader) {
glDetachShader(_program, vertShader);
glDeleteShader(vertShader);
}
if (fragShader) {
glDetachShader(_program, fragShader);
glDeleteShader(fragShader);
}
return YES;
}
- (BOOL)compileShader:(GLuint *)shader type:(GLenum)type file:(NSString *)file
{
GLint status;
const GLchar *source;
source = (GLchar *)[[NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil] UTF8String];
if (!source) {
NSLog(#"Failed to load vertex shader");
return NO;
}
*shader = glCreateShader(type);
glShaderSource(*shader, 1, &source, NULL);
glCompileShader(*shader);
#if defined(DEBUG)
GLint logLength;
glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetShaderInfoLog(*shader, logLength, &logLength, log);
NSLog(#"Shader compile log:\n%s", log);
free(log);
}
#endif
glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);
if (status == 0) {
glDeleteShader(*shader);
return NO;
}
return YES;
}
- (BOOL)linkProgram:(GLuint)prog
{
GLint status;
glLinkProgram(prog);
#if defined(DEBUG)
GLint logLength;
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(prog, logLength, &logLength, log);
NSLog(#"Program link log:\n%s", log);
free(log);
}
#endif
glGetProgramiv(prog, GL_LINK_STATUS, &status);
if (status == 0) {
return NO;
}
return YES;
}
- (BOOL)validateProgram:(GLuint)prog
{
GLint logLength, status;
glValidateProgram(prog);
glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &logLength);
if (logLength > 0) {
GLchar *log = (GLchar *)malloc(logLength);
glGetProgramInfoLog(prog, logLength, &logLength, log);
NSLog(#"Program validate log:\n%s", log);
free(log);
}
glGetProgramiv(prog, GL_VALIDATE_STATUS, &status);
if (status == 0) {
return NO;
}
return YES;
}
Wow. It looks like glEnable for texture mapping is deprecated.
https://gamedev.stackexchange.com/questions/20656/is-glenable-obsolete-unneeded-in-opengl-es-2
Ugh. I guess i have no choice but to learn this pixel/fragment shader rocket surgery.

iphone opengl es 2.0, how to use objective-c class to store primitive data?

I am trying to use nsarray of objective-c class called Primitive which stores primitive data such as vertices, texture coordinates, vertexBuffer, indexBuffer and texture buffer.
But it is not drawing the rectangle with texture.
When I tried c struct that contains same info, it drew fine.
I am not sure where I am missing
Can anyone give me some hint?
//Here is my primitive class.
//It also has Vertex class which has vertex positions and texture coordinates
// This represents one primitive, in this app, it is rectangle
#interface Primitive : NSObject
{
#public
GLuint vertexBuffer;
GLuint indexBuffer;
GLuint textureBuffer;
}
#property (nonatomic, copy) NSArray * vertices; //consist 4 vertices
- (id)initWithVertices:(NSArray *)vertices;
#end
#interface Vertex : NSObject
#property (nonatomic, copy) NSArray * position; //(x,y,z) per vertex
#property (nonatomic, copy) NSArray * textureCoordinate; //(s,t) per vertex
- (id)initWithPointX:(float)x Y:(float)y Z:(float)z;
- (void)printVal;
#end
#implementation Primitive
#synthesize vertices = m_vertices;
- (id)initWithVertices:(NSArray *)vertices
{
self = [super init];
if(self)
{
m_vertices = [[NSArray alloc] initWithArray:vertices];
}
return self;
}
#end
#implementation Vertex
#synthesize position = m_position;
#synthesize textureCoordinate = m_textureCoordinate;
- (id)initWithPointX:(float)x Y:(float)y Z:(float)z
{
self = [super init];
if(self)
{
m_position = [[NSArray alloc] initWithObjects:
[NSNumber numberWithFloat:x],
[NSNumber numberWithFloat:y],
[NSNumber numberWithFloat:z], nil];
}
return self;
}
// and here is how I generate vbo. it's in other file
- (void)setupVertexBufferObjects
{
for(Primitive * primitive in m_primitives)
{
NSLog(#"setting vbo");
glGenBuffers(1, &primitive->vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, primitive->vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(primitive.vertices),
(__bridge void *)primitive.vertices, GL_STATIC_DRAW);
glGenBuffers(1, &primitive->indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, primitive->indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
}
}
// and this is how I render, this is also in other file than Primitive and above method
// this one worked fine when I had c struct to provide vertices and texture coordinate
glClearColor(0, 104.0/255, 55.0/255, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
GLuint positionSlot = glGetAttribLocation(m_programHandle, "Position");
glEnableVertexAttribArray(positionSlot);
glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE,
[m_candleModel sizeOfVertex], 0);
GLuint texCoordSlot = glGetAttribLocation(m_programHandle, "TexCoordIn");
glEnableVertexAttribArray(texCoordSlot);
GLuint textureUniform = glGetUniformLocation(m_programHandle, "Texutre");
glVertexAttribPointer(texCoordSlot, 2, GL_FLOAT, GL_FALSE,
[m_candleModel sizeOfVertex], (GLvoid *)(sizeof(float) * 3));
GLuint floorTexture = [m_candleModel getTexture];
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, floorTexture);
glUniform1i(textureUniform, 0);
glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);
glDisableVertexAttribArray(positionSlot);
[m_context presentRenderbuffer:GL_RENDERBUFFER];
If you are just trying to make a rigid object that won't change shape I would recommend taking info like position, scale, rotation, etc. and then changing the vertices to fit the info. Here's a class I'm currently working on that makes a black square which can do rotation, opacity, position, and size. Hope it helps
typedef struct {
float Position[3];
float Color[4];
} Vertex;
#interface GameSprite : NSObject
{
GLuint positionAttrib;
GLuint colorAttrib;
GLuint programHandle;
GLuint modelviewUniform;
CGSize spriteSize;
CGPoint position;
float rotation;
float alpha;
BOOL HasRotated;
}
-(id) init;
-(id) initWithSize:(CGSize)size AndPosition:(CGPoint)spritePosition;
-(void) render;
-(void) setPosition:(CGPoint)newPosition;
-(void) setRotation:(float)newRotation;
-(void) setAlpha:(float)newAlpha;
#property (readonly, nonatomic) CGPoint getPosition;
#property (readonly, nonatomic) float getRotation;
#property (readonly, nonatomic) float getAlpha;
#property (readonly, nonatomic) CGSize getSize;
#end
Implementation...
#define kPI180 0.017453
#define k180PI 57.295780
#define degreesToRadians(x) (x * kPI180)
#define radiansToDegrees(x) (x * k180PI)
const Vertex GameSpriteVertices[] = {
{{1, 1, 0}, {0, 0, 0, 1}},
{{1, 2, 0}, {0, 0, 0, 1}},
{{2, 1, 0}, {0, 0, 0, 1}},
{{2, 2, 0}, {0, 0, 0, 1}}
};
const GLubyte GameSpriteIndices[] = {
0, 1, 2,
2, 3, 1
};
#implementation GameSprite
#synthesize getPosition, getRotation, getAlpha, getSize;
-(id) initWithSize:(CGSize)size AndPosition:(CGPoint)spritePosition
{
if (self = [super init]) {
position = spritePosition;
getPosition = position;
rotation = 0;
getRotation = rotation;
alpha = 1.0;
getAlpha = alpha;
spriteSize = size;
getSize = spriteSize;
GLuint VertexShader = [self compileShader:#"VertexShader" withType:GL_VERTEX_SHADER];
GLuint FragmentShader = [self compileShader:#"FragmentShader" withType:GL_FRAGMENT_SHADER];
programHandle = glCreateProgram();
glAttachShader(programHandle, VertexShader);
glAttachShader(programHandle, FragmentShader);
glLinkProgram(programHandle);
glUseProgram(programHandle);
positionAttrib = glGetAttribLocation(programHandle, "Position");
colorAttrib = glGetAttribLocation(programHandle, "SourceColor");
glEnableVertexAttribArray(positionAttrib);
glEnableVertexAttribArray(colorAttrib);
modelviewUniform = glGetUniformLocation(programHandle, "Modelview");
}
return self;
}
-(id) init
{
if (self = [super init]) {
GLuint VertexShader = [self compileShader:#"VertexShader" withType:GL_VERTEX_SHADER];
GLuint FragmentShader = [self compileShader:#"FragmentShader" withType:GL_FRAGMENT_SHADER];
programHandle = glCreateProgram();
glAttachShader(programHandle, VertexShader);
glAttachShader(programHandle, FragmentShader);
glLinkProgram(programHandle);
glUseProgram(programHandle);
positionAttrib = glGetAttribLocation(programHandle, "Position");
colorAttrib = glGetAttribLocation(programHandle, "SourceColor");
glEnableVertexAttribArray(positionAttrib);
glEnableVertexAttribArray(colorAttrib);
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(GameSpriteVertices), GameSpriteVertices, GL_STATIC_DRAW);
GLuint indexBuffer;
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GameSpriteIndices), GameSpriteIndices, GL_STATIC_DRAW);
modelviewUniform = glGetUniformLocation(programHandle, "Modelview");
}
return self;
}
-(void) render
{
glEnable (GL_BLEND);
glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// Add the position to the square
Vertex TempVertices[] = {
{{position.x - spriteSize.width/2, position.y - spriteSize.height/2, 0}, {0, 0, 0, alpha}},
{{position.x - spriteSize.width/2, position.y + spriteSize.height/2, 0}, {0, 0, 0, alpha}},
{{position.x + spriteSize.width/2, position.y - spriteSize.height/2, 0}, {0, 0, 0, alpha}},
{{position.x + spriteSize.width/2, position.y + spriteSize.height/2, 0}, {0, 0, 0, alpha}}
};
// Add the rotation to the square
for (int i = 0; i < sizeof(TempVertices)/sizeof(TempVertices[0]); i++) {
CGPoint vertex = CGPointMake(TempVertices[i].Position[0], TempVertices[i].Position[1]);
TempVertices[i].Position[0] = [self rotatePoint:vertex by:rotation around:position].x;
TempVertices[i].Position[1] = [self rotatePoint:vertex by:rotation around:position].y;
}
const GLubyte TempIndices[] = {
0, 1, 2,
2, 3, 1
};
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(TempVertices), TempVertices, GL_STATIC_DRAW);
GLuint indexBuffer;
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(TempIndices), TempIndices, GL_STATIC_DRAW);
glVertexAttribPointer(positionAttrib, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
glVertexAttribPointer(colorAttrib, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));
glDrawElements(GL_TRIANGLES, sizeof(GameSpriteIndices)/sizeof(GameSpriteIndices[0]), GL_UNSIGNED_BYTE, 0);
glDisable(GL_BLEND);
}
/*
Porgrammer access methods
*/
-(void) setPosition:(CGPoint)newPosition
{
position = newPosition;
getPosition = position;
}
-(void) setRotation:(float)newRotation
{
rotation = newRotation;
getRotation = rotation;
}
-(void) setAlpha:(float)newAlpha
{
alpha = newAlpha;
getAlpha = alpha;
}
/*
Helper methods
*/
-(GLuint) compileShader:(NSString *)path withType:(GLenum)shaderType
{
NSString *shaderPath = [[NSBundle mainBundle] pathForResource:path ofType:#"glsl"];
NSError *error;
NSString *shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error];
GLuint shaderHandle = glCreateShader(shaderType);
const char * shaderStringUTF8 = [shaderString UTF8String];
int shaderStringLength = [shaderString length];
glShaderSource(shaderHandle, 1, &shaderStringUTF8, &shaderStringLength);
glCompileShader(shaderHandle);
return shaderHandle;
}
-(CGPoint) rotatePoint:(CGPoint)point by:(float)theta around:(CGPoint)origin
{
theta = degreesToRadians(theta);
CGPoint newPoint;
newPoint.x = cosf(theta) * (point.x - origin.x) - sinf(theta) * (point.y - origin.y) + origin.x;
newPoint.y = sinf(theta) * (point.x - origin.x) + cosf(theta) * (point.y - origin.y) + origin.y;
return newPoint;
}
#end

How to draw a line inside the fish movement (OpenGLES in iPhone)?

Am working in a simple iPhone game application using OpenGLES framework. I facing an "EXC Bad Access" error while draw a line on the images. Here i will explain you what i did and what i tried in my project.
Step:1 I draw a Background Image used GL_TRIANGLE_STRIP. Here is my sample code,
- (void)viewDidLoad
{
[super viewDidLoad];
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
Test = NO;
Test1 = NO;
if (!self.context)
{
NSLog(#"Failed to create ES context");
}
GLKView *view = (GLKView *)self.view;
view.context = self.context;
[EAGLContext setCurrentContext:self.context];
self.effect = [[GLKBaseEffect alloc] init];
GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(0, 480, 0, 320, -1024, 1024);
self.effect.transform.projectionMatrix = projectionMatrix;
self.player = [[SGGSprite alloc] initWithFile:#"bg.png" effect:self.effect];
self.player.position = GLKVector2Make(self.player.contentSize.width, 460);
self.children = [NSMutableArray array];
[self.children addObject:self.player];
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
// glClearColor(1, 1, 1, 1);
// glClear(GL_COLOR_BUFFER_BIT);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
// Condition satisfied to draw a line code given below, otherwise the background and fish image draw in else part.
if(Test1 == YES)
{
GLKView *view = (GLKView *)self.view;
view.context = self.context;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
self.effect = [[GLKBaseEffect alloc] init];
[self.effect prepareToDraw];
const GLfloat line[] =
{
0.0f, 0.5f,
-3.0f,-1.0f,
};
GLuint bufferObjectNameArray;
glGenBuffers(1, &bufferObjectNameArray);
glBindBuffer(GL_ARRAY_BUFFER, bufferObjectNameArray);
glBufferData(
GL_ARRAY_BUFFER, // the target buffer
sizeof(line), // the number of bytes to put into the buffer
line, // a pointer to the data being copied
GL_STATIC_DRAW); // the usage pattern of the data
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(
GLKVertexAttribPosition,
2, // number of coordinates per vertex
GL_FLOAT, // the data type of each component
GL_FALSE, // can the data be scaled
2*4,
NULL);
glDrawArrays(GL_LINES, 0, 2);
}
else
{
//SGGSprite is another class and self.children is mutable array.
for (SGGSprite * sprite in self.children)
{
[sprite render];
}
}
}
//render method in SGGSprite class to draw a fish and background image
- (void)render
{
self.effect.texture2d0.name = self.textureInfo.name;
self.effect.texture2d0.enabled = YES;
self.effect.transform.modelviewMatrix = self.modelMatrix;
[self.effect prepareToDraw];
long offset = (long)&_quad;
glEnableVertexAttribArray(GLKVertexAttribPosition);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
NSLog(#"TexturedVertex:%ld",offset);
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *) (offset + offsetof(TexturedVertex, geometryVertex)));
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *) (offset + offsetof(TexturedVertex, textureVertex)));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
Step:2 After i draw a background image for my view am going to draw a fish images in the screen by using GL_TRIANGLE_STRIP. The fish images are always in moving. Here is my sample code,
(void)update
{
if(Test == NO)
{
self.timeSinceLastSpawn += self.timeSinceLastUpdate;
if (self.timeSinceLastSpawn > 2.0)
{
self.timeSinceLastSpawn = 0;
[self target]; // add fish image
}
for (SGGSprite * sprite in self.children)
{
[sprite update:self.timeSinceLastUpdate];
}
}
}
(void)target
{
SGGSprite * target = [[SGGSprite alloc] initWithFile:#"img2.png" effect:self.effect];
[self.children addObject:target]; // Add fish image in NSMutable array
int minY = target.contentSize.height/2;
int maxY = 320 - target.contentSize.height/2;
int rangeY = maxY - minY;
int actualY = (arc4random() % rangeY) + minY;
if(actualY <= 100)
{
actualY = 215;
}
target.position = GLKVector2Make(480 + (target.contentSize.width), actualY);
int minVelocity = 480.0/12.0;
int maxVelocity = 480.0/6.0;
int rangeVelocity = maxVelocity - minVelocity;
int actualVelocity = (arc4random() % rangeVelocity) + minVelocity;
target.moveVelocity = GLKVector2Make(-actualVelocity, 0);
}
(void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
// glClearColor(1, 1, 1, 1);
// glClear(GL_COLOR_BUFFER_BIT);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
// Condition satisfied to draw a line code given below, otherwise the background and fish image draw in else part.
if(Test1 == YES)
{
GLKView *view = (GLKView *)self.view;
view.context = self.context;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
self.effect = [[GLKBaseEffect alloc] init];
[self.effect prepareToDraw];
const GLfloat line[] =
{
0.0f, 0.5f,
-3.0f,-1.0f,
};
GLuint bufferObjectNameArray;
glGenBuffers(1, &bufferObjectNameArray);
glBindBuffer(GL_ARRAY_BUFFER, bufferObjectNameArray);
glBufferData(
GL_ARRAY_BUFFER, // the target buffer
sizeof(line), // the number of bytes to put into the buffer
line, // a pointer to the data being copied
GL_STATIC_DRAW); // the usage pattern of the data
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(
GLKVertexAttribPosition,
2, // number of coordinates per vertex
GL_FLOAT, // the data type of each component
GL_FALSE, // can the data be scaled
2*4,
NULL);
glDrawArrays(GL_LINES, 0, 2);
}
else
{
//SGGSprite is another class and self.children is mutable array.
for (SGGSprite * sprite in self.children)
{
[sprite render];
}
}
}
Step:3 Now i draw a Background Image and fish images in my screen. It works perfect. Now am going to draw a white line (using GL_LINE) in the screen above the fish images and background image. When i draw a line by using below code,
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
Test = YES;
Test1 = YES;
}
- (void)update
{
if(Test == NO)
{
self.timeSinceLastSpawn += self.timeSinceLastUpdate;
NSLog(#"timeSinceLastUpdate:%f",self.timeSinceLastUpdate);
if (self.timeSinceLastSpawn > 2.0)
{
self.timeSinceLastSpawn = 0;
[self target];
}
NSLog(#"Children count:%d",[self.children count]);
for (SGGSprite * sprite in self.children)
{
[sprite update:self.timeSinceLastUpdate];
}
}
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
// glClearColor(1, 1, 1, 1);
// glClear(GL_COLOR_BUFFER_BIT);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
// Condition satisfied to draw a line code given below, otherwise the background and fish image draw in else part.
if(Test1 == YES)
{
GLKView *view = (GLKView *)self.view;
view.context = self.context;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
self.effect = [[GLKBaseEffect alloc] init];
[self.effect prepareToDraw];
const GLfloat line[] =
{
0.0f, 0.5f,
-3.0f,-1.0f,
};
GLuint bufferObjectNameArray;
glGenBuffers(1, &bufferObjectNameArray);
glBindBuffer(GL_ARRAY_BUFFER, bufferObjectNameArray);
glBufferData(
GL_ARRAY_BUFFER, // the target buffer
sizeof(line), // the number of bytes to put into the buffer
line, // a pointer to the data being copied
GL_STATIC_DRAW); // the usage pattern of the data
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(
GLKVertexAttribPosition,
2, // number of coordinates per vertex
GL_FLOAT, // the data type of each component
GL_FALSE, // can the data be scaled
2*4,
NULL);
glDrawArrays(GL_LINES, 0, 2);
}
else
{
//SGGSprite is another class and self.children is mutable array, Draw a fish and background image
for (SGGSprite * sprite in self.children)
{
[sprite render];
}
}
}
The app getting crash in the line "glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // ERROR -Bad excess happened here when i touch the screen"
(void)render
{
self.effect.texture2d0.name = self.textureInfo.name;
self.effect.texture2d0.enabled = YES;
self.effect.transform.modelviewMatrix = self.modelMatrix;
[self.effect prepareToDraw];
long offset = (long)&_quad;
glEnableVertexAttribArray(GLKVertexAttribPosition);
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
NSLog(#"TexturedVertex:%ld",offset);
glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *) (offset + offsetof(TexturedVertex, geometryVertex)));
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TexturedVertex), (void *) (offset + offsetof(TexturedVertex, textureVertex)));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); // ERROR comes from this line, when i touch the screen.
}
Can you please refer these code and tell what is wrong with my code? What i should do to fix this problem? Please help me. Thanks in advance.
   

Rendering Textures in OpenGL ES 2.0 with VBO/IBO (IPhone)

I'm trying to render a simple quad with a texture using a vertex buffer object and an index buffer object. I haven't seen any solutions for how to do this with an IBO using glDrawElements. In any case, all that appears to happen is that the quad is textured using only the upper left hand pixel of the texture image.
This is how initialize an entity that will be rendered:
void Entity::init(){
// create triangle verticies
numVerticies = 20;
verticies = new GLfloat[numVerticies];
// 3 verts, 2 tex coords
verticies[0] = -1.0f; verticies[1] = -1.0f; verticies[2] = 0.0f; verticies[3] = 0.0f; verticies[4] = 0.0f;
verticies[5] = 1.0f; verticies[6] = 1.0f; verticies[7] = 0.0f; verticies[8] = 1.0f; verticies[9] = 1.0f;
verticies[10] = -1.0f; verticies[11] = 1.0f; verticies[12] = 0.0f; verticies[13] = 0.0f; verticies[14] = 1.0f;
verticies[15] = 1.0f; verticies[16] = -1.0f; verticies[17] = 0.0f; verticies[18] = 1.0f; verticies[19] = 0.0f;
// create face indicies
numIndicies = 6;
indicies = new GLushort[numIndicies];
indicies[0] = 0; indicies[1] = 1; indicies[2] = 2;
indicies[3] = 0; indicies[4] = 3; indicies[5] = 1;
// generate buffers for geometry
glGenBuffers(2, geometryBuffer);
// buffer the data to the vertex buffer
glBindBuffer(GL_ARRAY_BUFFER, geometryBuffer[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(verticies) * numVerticies, verticies, GL_STATIC_DRAW);
// buffer the data to the index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometryBuffer[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indicies) * numIndicies, indicies, GL_STATIC_DRAW);
rotation = 0.0f;
// load a texure object
std::string path = [[[NSBundle mainBundle] bundlePath] UTF8String];
path += "/test.png";
NSString *fileName = [NSString stringWithUTF8String:path.c_str()];
NSError *error;
GLKTextureInfo *texture = [GLKTextureLoader textureWithContentsOfFile:fileName options:nil error:&error];
if(error || texture == nil){
NSLog(#"Error loading texture %#\n", error);
}
// get the texture id
tex = [texture name];
}
And this is how I render the object ( I should mention that I call glUseProgram before calling this method):
void Entity::render(GLint uniformPos, GLint uniformTex, GLKMatrix4 projection){
GLKMatrix4 modelViewProjection = GLKMatrix4Multiply(projection, modelView);
// bind and enable enable verticies
glBindBuffer(GL_ARRAY_BUFFER, geometryBuffer[0]);
glEnableVertexAttribArray(GLKVertexAttribPosition);
glVertexAttribPointer(GLKVertexAttribPosition, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), BUFFER_OFFSET(0));
// enable tex coords
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), BUFFER_OFFSET(12));
// bind the index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, geometryBuffer[1]);
// bind the texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex);
// render with uniforms
glUniform1i(uniformTex, 0);
glUniformMatrix4fv(uniformPos, 1, 0, modelViewProjection.m);
glDrawElements(GL_TRIANGLES, numIndicies, GL_UNSIGNED_SHORT, 0);
// disable attributes and buffers
glDisableVertexAttribArray(GLKVertexAttribPosition);
glDisableVertexAttribArray(GLKVertexAttribTexCoord0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
So I figured this out.
This:
// enable tex coords
glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), BUFFER_OFFSET(12));
Needs to be this:
GLint texCoordLoc = glGetAttributeLocation(program, texCoordAttributeName);
glEnableVertexAttribArray(texCoordLoc);
glVertexAttribPointer(texCoordLoc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), BUFFER_OFFSET(12));

exc_bad_access when using VBO's in Cocos2d

In my iPhone application I am creating a vertex buffer as shown below:
-(id)initWithPoints:(NSArray *)polygonPoints andTexture: (CCTexture2D *) fillTexture{
self = [super init];
if(self){
int vertexCount = [polygonPoints count];
CGPoint *vertices = (CGPoint*)malloc(sizeof(CGPoint)*vertexCount);
GLushort *indices = (GLushort*)malloc(sizeof(GLushort)*2*vertexCount);
int i = 0;
for(NSValue *value in polygonPoints){
CGPoint p = [value CGPointValue];
vertices[i] = ccp(p.x, p.y);
i++;
}
for (int k = 0; k<vertexCount; k++) {
indices[k] = (GLushort)k;
}
NSLog(#"count: %i", vertexCount);
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, vertexCount*sizeof(CGPoint), &vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, (vertexCount)*2*sizeof(GLushort), &indices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
self.text = fillTexture;
}
return self;
}
And I draw it using:
-(void)draw{
glBindTexture(GL_TEXTURE_2D, self.text.name);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexPointer(2, GL_FLOAT, sizeof(CGPoint), 0);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawElements(GL_TRIANGLES, 1024, GL_UNSIGNED_SHORT, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
However, I can only call glDrawElements with 1024 elements (out of ~20,000) and they render ok.
If I set it to (for example) 1025, the application crashes with EXC_BAD_ACCESS.
Obviously there's a reason the app crashes at 1024 elements, but I can't understand what it is. Any ideas would be much appreciated!