Zhang
Zhang

Reputation: 11607

OpenGL ES 2.0 draw simple triangle not showing anything

I am completely out of ideas.

I have the OpenGL ES 2.0 Programming Guide book, I have Apple's template OpenGL ES 2.0 code, I have followed this page: http://open.gl/drawing

I can't seem to get a simple triangle drawn, I am not sure what I am doing wrong.

Note: I have a GameViewController.xib file too that is a subclass of GLKView just like Apple's template code.

My vertex shader:

attribute vec4 position;

void main()
{
    gl_Position = position;
}

My fragment shader:

void main()
{
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

My GameViewController Header File:

#import <UIKit/UIKit.h>
#import <GLKit/GLKit.h>

@interface GameViewController : GLKViewController

@end

My GameViewController Implementation File:

#import "GameViewController.h"

const GLfloat vertices[] =
{
    0.0f, 0.5f,
    -0.5f, -0.5f,
    0.5f, -0.5f
};

// Class extension to keep data private
@interface GameViewController()
{        
    // vertex buffer object
    GLuint vbo;

    // vertex array object
    GLuint vao;

    // shader program
    GLuint shaderProgram;
}

@property (strong, nonatomic) EAGLContext *context;
@property (strong, nonatomic) GLKBaseEffect *effect;

@end

@implementation GameViewController

// setup our OpenGL context
-(void)viewDidLoad
{
    [super viewDidLoad];

    [self setupContext];

    // -------------------------------------------------------------
    // create a vertex array object that will hold
    // all the linking between attributes and vertex data
    // -------------------------------------------------------------
    [self createVertexArrayObject];

    [self createVertexBufferObject];

    [self loadShaders];

    [self checkErrors];
}

-(void)checkErrors
{
    GLenum error = glGetError();

    switch (error) {
        case GL_NO_ERROR:
            NSLog(@"No errors");
            break;
        case GL_INVALID_ENUM:
            NSLog(@"An unacceptable value is specified for an enumerated argument. The offending command is ignored and has no other side effect than to set the error flag.");
            break;
        case GL_INVALID_VALUE:
            NSLog(@"A numeric argument is out of range. The offending command is ignored and has no other side effect than to set the error flag.");
            break;
        case GL_INVALID_OPERATION:
            NSLog(@"The specified operation is not allowed in the current state. The offending command is ignored and has no other side effect than to set the error flag.");
            break;
        case GL_INVALID_FRAMEBUFFER_OPERATION:
            NSLog(@"The frameBuffer object is not complete. The offending command is ignored and has no other side effect than to set the error flag.");
            break;
        case GL_OUT_OF_MEMORY:
            NSLog(@"There is not enough memory left to execute the command. The state of the GL is undefined, except for the state of the error flags, after this error is recorded.");
            break;
        case GL_STACK_UNDERFLOW:
            NSLog(@"An attempt has been made to perform an operation that would cause an internal stack to underflow.");
            break;
        case GL_STACK_OVERFLOW:
            NSLog(@"An attempt has been made to perform an operation that would cause an internal stack to overflow.");
            break;
        default:
            break;
    }
}

#pragma mark - Setup Context -

-(void)setupContext
{
    self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

    if(!self.context)
    {
        NSLog(@"Failed to create OpenGL ES Context");
    }

    // tell our view the context is an OpenGL context
    GLKView *view = (GLKView *)self.view;
    view.context = self.context;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;

    [EAGLContext setCurrentContext:self.context];

    self.effect = [[GLKBaseEffect alloc] init];

    glEnable(GL_DEPTH_TEST);
}

#pragma mark - Vertex Array Object Methods -

-(void)createVertexArrayObject
{
    glGenVertexArraysOES(1, &vao);
    glBindVertexArrayOES(vao);
}

#pragma mark - Create Vertex Buffer Object Method -

-(void)createVertexBufferObject;
{
    glGenBuffers(1, &vbo); // Generate 1 memory buffer for the VBO

    // Make our VBO the current buffer object to receive data
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    // -------------------------------------------------------------
    // Start copying data to our VBO
    //
    // GL_STATIC_DRAW will upload once and drawn many times
    // -------------------------------------------------------------
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

}

#pragma mark - Shader Code -

-(void)loadShaders
{
    // load both vertex shader and fragment shader
    GLuint vertexShader = [self compileVertexShader];
    GLuint fragmentShader = [self compileFragmentShader];

    // create a shader program from the vertex shader and fragment shader
    shaderProgram = [self combineVertexShader:vertexShader AndFragmentShader:fragmentShader];

    // linking vertex data and attributes
    GLint positionAttrib = glGetAttribLocation(shaderProgram, "position");

    glVertexAttribPointer(positionAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);

    glEnableVertexAttribArray(positionAttrib);
}

-(GLuint)compileVertexShader
{
    // get the path to the shader file as a C string
    const GLchar *vertexShaderPath = (GLchar *)[[NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"]
                                                                          encoding:NSUTF8StringEncoding
                                                                             error:nil] UTF8String];

    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderPath, NULL);
    glCompileShader(vertexShader);

    // Checking if shader compiled properly
    GLint status;
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);

    if(status == GL_TRUE)
    {
        NSLog(@"Vertex shader compiled correctly");
    }
    else
    {
        NSLog(@"Vertex shader compiled failed");
    }

    GLint logLength;
    glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetShaderInfoLog(vertexShader, logLength, &logLength, log);
        NSLog(@"Vertex Shader compile log:\n%s", log);
        free(log);
    }

    return vertexShader;
}

-(GLuint)compileFragmentShader
{
    // get the path to the shader as a C string
    const GLchar *fragmentShaderPath = (GLchar *)[[NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"]
                                                                          encoding:NSUTF8StringEncoding
                                                                             error:nil] UTF8String];

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderPath, NULL);
    glCompileShader(fragmentShader);

    // Checking if shader compiled properly
    GLint status;
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status);

    if(status == GL_TRUE)
    {
        NSLog(@"Fragment shader compiled correctly");
    }
    else
    {
        NSLog(@"Fragment shader compiled failed");
    }

    GLint logLength;
    glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetShaderInfoLog(fragmentShader, logLength, &logLength, log);
        NSLog(@"Fragment Shader compile log:\n%s", log);
        free(log);
    }

    return fragmentShader;
}

-(void)linkProgram:(GLuint)paramShaderProgram
{
    // link shader to program now and become active shader program
    glLinkProgram(paramShaderProgram);

    GLint status;
    // test if the program linked correctly
    glGetProgramiv(paramShaderProgram, GL_LINK_STATUS, &status);

    if(status == GL_TRUE)
    {
        NSLog(@"Shader program linked correctly");
    }
    else
    {
        NSLog(@"Shader program linked failed");
    }
}

-(void)validateProgram:(GLuint)paramShaderProgram
{
    GLint status, logLength;

    glValidateProgram(paramShaderProgram);

    glGetProgramiv(paramShaderProgram, GL_VALIDATE_STATUS, &status);

    if(status == GL_TRUE)
    {
        NSLog(@"Shader program validated correctly");
    }
    else
    {
        NSLog(@"Shader program validate failed");
    }

    glGetProgramiv(paramShaderProgram, GL_INFO_LOG_LENGTH, &logLength);

    if(logLength > 0)
    {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetProgramInfoLog(paramShaderProgram, logLength, &logLength, log);
        NSLog(@"Program validate log:\n%s", log);
        free(log);
    }
}

-(GLuint)combineVertexShader:(GLuint)paramVertexShader AndFragmentShader:(GLuint)paramFragmentShader
{
    GLuint newShaderProgram = glCreateProgram();

    glAttachShader(newShaderProgram, paramVertexShader);
    glAttachShader(newShaderProgram, paramFragmentShader);

    [self linkProgram:newShaderProgram];

    [self validateProgram:newShaderProgram];

    // start using shader now, will use the active shader program
    glUseProgram(newShaderProgram);

    return newShaderProgram;
}

#pragma mark - GLKViewController Render Delegate Methods -

-(void)setupViewport
{
    glViewport(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);

    self.effect.transform.projectionMatrix = GLKMatrix4MakeOrtho(-3, 3, -2, 2, 1, -1);
}

-(void)update
{
    [self setupViewport];
}

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    [self.effect prepareToDraw];

    glDrawArrays(GL_TRIANGLES, 0, 3);
}

#pragma mark - Cleanup Memory -

-(void)tearDownContext
{
    [EAGLContext setCurrentContext:self.context];

    // delete vertex buffer object and vertex array object
    glDeleteBuffers(1, &vbo);
    glDeleteVertexArraysOES(1, &vao);

    // delete shader program
    if(shaderProgram)
    {
        glDeleteProgram(shaderProgram);
        shaderProgram = 0;
    }

    // unset OpenGL context
    if ([EAGLContext currentContext] == self.context)
    {
        [EAGLContext setCurrentContext:nil];
    }

    self.context = nil;
}

-(void)dealloc
{
    [self tearDownContext];
}

-(void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];

    if([self isViewLoaded] && self.view.window == nil)
    {
        self.view = nil;

        [self tearDownContext];

        if([EAGLContext currentContext] == self.context)
        {
            [EAGLContext setCurrentContext:nil];
        }

        self.context = nil;
    }

    // Dispose of any resources that can be recreated
}

@end

All I see is my grey background screen that I cleared color to.

If anyone can point out where I went wrong, that would be great.

EDIT

I've decided to put my personal dislike for Ray's site aside and just bit the bullet, went through this tutorial:

http://www.raywenderlich.com/3664/opengl-es-2-0-for-iphone-tutorial

This tutorial does not use GLKit which is an extra bonus because the learner write their own frame buffer and render buffer, present them to screen.

I feel this is closer to the OpenGL ES 2.0 pipeline than using GLKit.

As Ricardo suggested, using GLKit is more effort to understand than its worth at this point in time.

I also strongly recommend using above Ray's website tutorial link to get a working program going rather than trying to follow Apple's template code.

In my case, Apple's template code and the book had too much contradiction, causing many wasted hours.

I have also solved it using GLKit for those that are still interested in using the GLKit method.

The solution was a mix of setting my projection matrix and binding the correct vertex shader position attribute location.

Also one very important note I want to point out is:

MAKE SURE COPY BUNDLE RESOURCES FOR TARGET HAS VERTEX AND FRAGMENT SHADER!

I was at the point where the triangle was a black color and I couldn't change the color of my triangle no matter what I typed in my fragment shader file. The problem was these shader files are not copied to the bundle resource by default.

Anyhow, my working updated code is provided in full below:

#import "GameViewController.h"

#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
};


const GLfloat vertices[] =
{
    0.0f, 0.5f,
    -0.5f, -0.5f,
    0.5f, -0.5f
};

// Class extension to keep data private
@interface GameViewController()
{
    // vertex buffer object
    GLuint vbo;

    // vertex array object
    GLuint vao;

    // shader program
    GLuint shaderProgram;

    GLKMatrix4 modelViewProjectionMatrix;
    GLKMatrix3 normalMatrix;
}

@property (strong, nonatomic) EAGLContext *context;
@property (strong, nonatomic) GLKBaseEffect *effect;

@end

@implementation GameViewController

// setup our OpenGL context
-(void)viewDidLoad
{
    [super viewDidLoad];

    [self setupContext];

    [self loadShaders];

    // -------------------------------------------------------------
    // create a vertex array object that will hold
    // all the linking between attributes and vertex data
    // -------------------------------------------------------------
    [self createVertexArrayObject];

    [self createVertexBufferObject];

    [self linkAttributes];

    [self checkErrors];
}

-(void)checkErrors
{
    GLenum error = glGetError();

    switch (error) {
        case GL_NO_ERROR:
            NSLog(@"No errors");
            break;
        case GL_INVALID_ENUM:
            NSLog(@"An unacceptable value is specified for an enumerated argument. The offending command is ignored and has no other side effect than to set the error flag.");
            break;
        case GL_INVALID_VALUE:
            NSLog(@"A numeric argument is out of range. The offending command is ignored and has no other side effect than to set the error flag.");
            break;
        case GL_INVALID_OPERATION:
            NSLog(@"The specified operation is not allowed in the current state. The offending command is ignored and has no other side effect than to set the error flag.");
            break;
        case GL_INVALID_FRAMEBUFFER_OPERATION:
            NSLog(@"The frameBuffer object is not complete. The offending command is ignored and has no other side effect than to set the error flag.");
            break;
        case GL_OUT_OF_MEMORY:
            NSLog(@"There is not enough memory left to execute the command. The state of the GL is undefined, except for the state of the error flags, after this error is recorded.");
            break;
        case GL_STACK_UNDERFLOW:
            NSLog(@"An attempt has been made to perform an operation that would cause an internal stack to underflow.");
            break;
        case GL_STACK_OVERFLOW:
            NSLog(@"An attempt has been made to perform an operation that would cause an internal stack to overflow.");
            break;
        default:
            break;
    }
}

#pragma mark - Setup Context -

-(void)setupContext
{
    self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];

    if(!self.context)
    {
        NSLog(@"Failed to create OpenGL ES Context");
    }

    // tell our view the context is an OpenGL context
    GLKView *view = (GLKView *)self.view;
    view.context = self.context;
    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;

    [EAGLContext setCurrentContext:self.context];

    self.effect = [[GLKBaseEffect alloc] init];

    //glEnable(GL_DEPTH_TEST);
}

#pragma mark - Vertex Array Object Methods -

-(void)createVertexArrayObject
{
    glGenVertexArraysOES(1, &vao);
    glBindVertexArrayOES(vao);
}

#pragma mark - Create Vertex Buffer Object Method -

-(void)createVertexBufferObject;
{
    glGenBuffers(1, &vbo); // Generate 1 memory buffer for the VBO

    // Make our VBO the current buffer object to receive data
    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    // -------------------------------------------------------------
    // Start copying data to our VBO
    //
    // GL_STATIC_DRAW will upload once and drawn many times
    // -------------------------------------------------------------
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
}

-(void)linkAttributes
{
    /*
    // linking vertex data and attributes
    GLint positionAttrib = glGetAttribLocation(shaderProgram, "position");
    glVertexAttribPointer(positionAttrib, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    glEnableVertexAttribArray(positionAttrib);
    */

    glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
    glEnableVertexAttribArray(GLKVertexAttribPosition);

    glBindVertexArrayOES(0);
}

#pragma mark - Shader Code -

-(void)loadShaders
{
    shaderProgram = glCreateProgram();

    // load both vertex shader and fragment shader
    GLuint vertexShader = [self compileVertexShader];
    GLuint fragmentShader = [self compileFragmentShader];

    // create a shader program from the vertex shader and fragment shader
    [self combineVertexShader:vertexShader AndFragmentShader:fragmentShader];

    [self linkProgram:shaderProgram];


    // Release vertex and fragment shaders.
    if (vertexShader) {
        glDetachShader(shaderProgram, vertexShader);
        glDeleteShader(vertexShader);
    }
    if (fragmentShader) {
        glDetachShader(shaderProgram, fragmentShader);
        glDeleteShader(fragmentShader);
    }

    //NSLog(@"uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] before = %d", uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX]);

    uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] = glGetUniformLocation(shaderProgram, "modelViewProjectionMatrix");

    //NSLog(@"uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX] after = %d", uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX]);
}

-(GLuint)compileVertexShader
{
    // get the path to the shader file as a C string
    const GLchar *vertexShaderPath = (GLchar *)[[NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"vsh"]
                                                                          encoding:NSUTF8StringEncoding
                                                                             error:nil] UTF8String];

    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderPath, NULL);
    glCompileShader(vertexShader);

    // Checking if shader compiled properly
    GLint status;
    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status);

    if(status == GL_TRUE)
    {
        NSLog(@"Vertex shader compiled correctly");
    }
    else
    {
        NSLog(@"Vertex shader compiled failed");
    }

    GLint logLength;
    glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetShaderInfoLog(vertexShader, logLength, &logLength, log);
        NSLog(@"Vertex Shader compile log:\n%s", log);
        free(log);
    }

    return vertexShader;
}

-(GLuint)compileFragmentShader
{
    // get the path to the shader as a C string
    const GLchar *fragmentShaderPath = (GLchar *)[[NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Shader" ofType:@"fsh"]
                                                                            encoding:NSUTF8StringEncoding
                                                                               error:nil] UTF8String];

    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(fragmentShader, 1, &fragmentShaderPath, NULL);
    glCompileShader(fragmentShader);

    // Checking if shader compiled properly
    GLint status;
    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status);

    if(status == GL_TRUE)
    {
        NSLog(@"Fragment shader compiled correctly");
    }
    else
    {
        NSLog(@"Fragment shader compiled failed");
    }

    GLint logLength;
    glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetShaderInfoLog(fragmentShader, logLength, &logLength, log);
        NSLog(@"Fragment Shader compile log:\n%s", log);
        free(log);
    }

    return fragmentShader;
}

-(void)combineVertexShader:(GLuint)paramVertexShader AndFragmentShader:(GLuint)paramFragmentShader
{
    glAttachShader(shaderProgram, paramVertexShader);
    glAttachShader(shaderProgram, paramFragmentShader);

    glBindAttribLocation(shaderProgram, GLKVertexAttribPosition, "position");

    //[self validateProgram:shaderProgram];
}

-(void)linkProgram:(GLuint)paramShaderProgram
{
    // link shader to program now and become active shader program
    glLinkProgram(paramShaderProgram);

    GLint status;
    // test if the program linked correctly
    glGetProgramiv(paramShaderProgram, GL_LINK_STATUS, &status);

    if(status == GL_TRUE)
    {
        NSLog(@"Shader program linked correctly");
    }
    else
    {
        NSLog(@"Shader program linked failed");
    }

    GLint logLength;
    glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &logLength);
    if (logLength > 0) {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetProgramInfoLog(shaderProgram, logLength, &logLength, log);
        NSLog(@"Program link log:\n%s", log);
        free(log);
    }
}

-(void)validateProgram:(GLuint)paramShaderProgram
{
    GLint status, logLength;

    glValidateProgram(paramShaderProgram);

    glGetProgramiv(paramShaderProgram, GL_VALIDATE_STATUS, &status);

    if(status == GL_TRUE)
    {
        NSLog(@"Shader program validated correctly");
    }
    else
    {
        NSLog(@"Shader program validate failed");
    }

    glGetProgramiv(paramShaderProgram, GL_INFO_LOG_LENGTH, &logLength);

    if(logLength > 0)
    {
        GLchar *log = (GLchar *)malloc(logLength);
        glGetProgramInfoLog(paramShaderProgram, logLength, &logLength, log);
        NSLog(@"Program validate log:\n%s", log);
        free(log);
    }
}

#pragma mark - GLKViewController Render Delegate Methods -

-(void)setupViewport
{
    //float aspect = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);

    //GLKMatrix4 projectionMatrix = GLKMatrix4MakePerspective(GLKMathDegreesToRadians(65.0f), aspect, 1.0f, -10.0f);
    GLKMatrix4 projectionMatrix = GLKMatrix4MakeOrtho(-1, 1, -1, 1, 1, -1);
    self.effect.transform.projectionMatrix = projectionMatrix;

    GLKMatrix4 modelViewMatrix = GLKMatrix4MakeTranslation(0.0f, 0.0f, 0.0f);
    self.effect.transform.modelviewMatrix = modelViewMatrix;

    modelViewProjectionMatrix = GLKMatrix4Multiply(projectionMatrix, modelViewMatrix);
    normalMatrix = GLKMatrix3InvertAndTranspose(GLKMatrix4GetMatrix3(modelViewMatrix), NULL);

    glUniformMatrix4fv(uniforms[UNIFORM_MODELVIEWPROJECTION_MATRIX], 1, GL_FALSE, modelViewProjectionMatrix.m);
    glUniformMatrix3fv(uniforms[UNIFORM_NORMAL_MATRIX], 1, 0, normalMatrix.m);
}

-(void)update
{
    [self setupViewport];
}

-(void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    glClearColor(0.65f, 0.65f, 0.65f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glBindVertexArrayOES(vao);

    [self.effect prepareToDraw];

    glUseProgram(shaderProgram);

    glDrawArrays(GL_TRIANGLES, 0, 3);
}

#pragma mark - Cleanup Memory -

-(void)tearDownContext
{
    [EAGLContext setCurrentContext:self.context];

    // delete vertex buffer object and vertex array object
    glDeleteBuffers(1, &vbo);
    glDeleteVertexArraysOES(1, &vao);

    // delete shader program
    if(shaderProgram)
    {
        glDeleteProgram(shaderProgram);
        shaderProgram = 0;
    }

    // unset OpenGL context
    if ([EAGLContext currentContext] == self.context)
    {
        [EAGLContext setCurrentContext:nil];
    }

    self.context = nil;
}

-(void)dealloc
{
    [self tearDownContext];
}

-(void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];

    if([self isViewLoaded] && self.view.window == nil)
    {
        self.view = nil;

        [self tearDownContext];

        if([EAGLContext currentContext] == self.context)
        {
            [EAGLContext setCurrentContext:nil];
        }

        self.context = nil;
    }

    // Dispose of any resources that can be recreated
}

@end

Hope that helps everyone else.

Upvotes: 3

Views: 5508

Answers (1)

Ricardo RendonCepeda
Ricardo RendonCepeda

Reputation: 3251

Forget about Apple's OpenGL ES 2.0 template code. If you are a beginner, there is far too much going on in there to understand properly and it mixes OpenGL ES 1.1 (GLKBaseEffect) and 2.0 (shaders).

You're better off creating an app from scratch and getting to know the pros/cons of GLKit and shaders.

This tutorial gives a great introduction to GLKit using the fixed-pipeline functionality of GLKBaseEffect:

And if you want more in-depth knowledge and learn how to use shaders in an iPhone environment, I strongly recommend this book:

Ultimately, you would want to combine a GLKView to bypass all the buffer boilerplate code, and shaders to have the best control over your program. OpenGL ES has a difficult learning curve, but once you get over the first hump things become a lot clearer.

Upvotes: 2

Related Questions