Fabrice Troïlo
Fabrice Troïlo

Reputation: 184

OpenGl ES 2.0 and GLKit : From GLKBaseEffect shaders to OpenGl

I'm coding a 2D game with OpenGL ES 2.0 and GLKit. My architecture is based on the Games by Ian Terrel tutorials.

I discover recently that the GLKBaseEffect (provide simple shaders mgmt) leaks and makes sometimes my app crash. I'm now using my own shaders files (based on the Ray Wenderlich tutorial) but, at this time, I've just succeed to display openGl background color. My shapes colors and textures aren't displayed anymore.

IMPORTANT : I was setting the current context badly, now openGL says invalid Drawable.

Here is a part of my shape.m code :

@implementation P3Shape

const GLushort indices[] = {
    0,1,2,3
};

typedef struct {
    float Position[2];
    float Color[4];
    float TexCoord[2];
} Vertex;

//testing
const Vertex Vertices[] = {
    // Front
    {{10, -15}, {1, 0, 0, 1}, {1, 0}},
    {{10, 15}, {0, 1, 0, 1}, {1, 0}},
    {{-10, 10}, {0, 0, 1, 1}, {0, 0}},
    {{-10, -1}, {0, 0, 0, 1}, {0, 1}},
};

- (id)initWithLayer:(CAEAGLLayer *)layer {
    self = [super init];
    if (self) {
        [...]
        _currentContext = [P3SessionState currentContext];
        _eaglLayer = layer;
        _eaglLayer.opaque = YES;
        [self setupRenderBuffer];        
        [self setupFrameBuffer]; 
        [self addToProgram];
        [self createBuffers];
    }
    return self;
}


- (int)numVertices {
    return 0;
}

- (void) addToProgram {
    // setted before in the gamemanager
    GLuint programHandle = [P3SessionState programHandle];

    _positionSlot = glGetAttribLocation(programHandle, "Position");
    _colorSlot = glGetAttribLocation(programHandle, "SourceColor");

    _projectionUniform = glGetUniformLocation(programHandle, "Projection");
    _modelViewUniform = glGetUniformLocation(programHandle, "Modelview");

    _texCoordSlot = glGetAttribLocation(programHandle, "TexCoordIn");
    _textureUniform = glGetUniformLocation(programHandle, "Texture");
}

- (void)setupRenderBuffer {
    glGenRenderbuffers(1, &_colorRenderBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, _colorRenderBuffer);        
    [_currentContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:_eaglLayer];    
}

- (void)setupFrameBuffer {    
    GLuint framebuffer;
    glGenFramebuffers(1, &framebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);   
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _colorRenderBuffer);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _depthRenderBuffer);
}

- (void)createBuffers {
    // Static index data
    glGenBuffers(1, &indexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);

    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);
}

// initialize the vertex data

- (GLKVector2 *)vertices {
    if (vertexData == nil) {
        vertexData = [NSMutableData dataWithLength:sizeof(GLKVector2)*self.numVertices];
    }
    return [vertexData mutableBytes];
}

// set a textureImage, allocate a glname and enable the GL_TEXTURE_2D and all
- (void)setTextureImage:(UIImage *)image {
    CGImageRef spriteImage = image.CGImage;
    if (!spriteImage) {
        NSLog(@"Failed to load image %@", image);
        exit(1);
    }

    size_t width = CGImageGetWidth(spriteImage);
    size_t height = CGImageGetHeight(spriteImage);

    GLubyte * spriteData = (GLubyte *) calloc(width*height*4, sizeof(GLubyte));

    CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);    

    CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);

    CGContextRelease(spriteContext);

    GLuint texName;
    glGenTextures(1, &texName);
    glBindTexture(GL_TEXTURE_2D, texName);

    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);

    free(spriteData);        
    _imageTexture = texName;
}    

- (GLKVector2 *)textureCoordinates {
    if (textureCoordinateData == nil)
        textureCoordinateData = [NSMutableData dataWithLength:sizeof(GLKVector2)*self.numVertices];
    return [textureCoordinateData mutableBytes];
}


- (void)render {

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glClearColor(0, 104.0/255.0, 55.0/255.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glUniformMatrix4fv(_modelViewUniform, 1, 0, modelview.m);
    glUniformMatrix4fv(_projectionUniform, 1, 0, projectionMatrix.m);

    glEnableVertexAttribArray(_positionSlot);

    glEnableVertexAttribArray(_colorSlot);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);

    glVertexAttribPointer(_positionSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));
    if(texture != nil) {
        glEnableVertexAttribArray(_texCoordSlot);
        glActiveTexture(GL_TEXTURE0); // unneccc in practice
        glBindTexture(GL_TEXTURE_2D, _imageTexture);
        glUniform1i(_textureUniform, 0); // unnecc in practice
        glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (GLvoid*) (sizeof(float) * 7));
    }

        glDrawElements(GL_TRIANGLE_FAN, sizeof(indices)/sizeof(GLushort), GL_UNSIGNED_SHORT, (void*)0);
    }
    //is cleanup code that tells the shader that we’re done using vertex position data.
    glDisableVertexAttribArray(GLKVertexAttribPosition);

    if (texture != nil)
        glDisableVertexAttribArray(GLKVertexAttribTexCoord0);

    [_currentContext presentRenderbuffer:GL_RENDERBUFFER];

    glDisable(GL_BLEND);
}

// draw the shape in the selected scene
- (void)renderInScene:(P3Scene *)theScene {

    projectionMatrix = [theScene projectionMatrix];

    modelview = GLKMatrix4Multiply(GLKMatrix4MakeTranslation(0, 0, 0), GLKMatrix4MakeRotation(0, 0, 0, 1));
    modelview = GLKMatrix4Multiply(modelview, GLKMatrix4MakeScale(scale.x, scale.y, 1));

    [self render];
}

-(void)update:(NSTimeInterval)dt {
    if(self.toDraw)
        [spriteAnimation update:dt];
}

@end

As you can see, I'm testing with a Vertices array and a basic color but it makes no differences. OpenGl seems to be set correctly because my view is green thanks to the glClearColor(0, 104.0/255.0, 55.0/255.0, 1.0); in the render function.

Here the files on pastebin :

P3Shape.m on pastebin

And a manager who create the ogl program

P3GameManager.m on pastebin

Any ideas ?

EDIT : maybe a problem with my shaders ?

vertex :

attribute vec4 Position; 
attribute vec4 SourceColor; 

varying vec4 DestinationColor; 

uniform mat4 Projection;
uniform mat4 Modelview;

attribute vec2 TexCoordIn; // New
varying vec2 TexCoordOut; // New

void main(void) { 
    DestinationColor = SourceColor; 
    gl_Position = Projection * Modelview * Position;
    TexCoordOut = TexCoordIn; // New
}

and fragment :

varying lowp vec4 DestinationColor;

varying lowp vec2 TexCoordOut; // New
uniform sampler2D Texture; // New

void main(void) {
    gl_FragColor = DestinationColor * texture2D(Texture, TexCoordOut); // New
}

Upvotes: 2

Views: 1090

Answers (1)

Chris Miles
Chris Miles

Reputation: 7526

I recommend using GLKViewController and GLKView to simplify your setup. Similarly, replace your texture loading with GLKTextureLoader.

I haven't seen any issues with GLKBaseEffect leaking memory and causing crashes. I would suggest posting a new question about this particular problem, and returning to using GLKBaseEffect if you don't need custom shaders (it looks like you don't). Will make your code a lot easier to manage and debug.

Upvotes: 1

Related Questions