I am trying to write a game using opengl, but I am having a lot of trouble with the new glkit classes and the default template from iOS.
- (void)viewDidLoad
{
[super viewDidLoad];
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!self.context) {
NSLog(@"Failed to create ES context");
}
if(!renderer)
renderer = [RenderManager sharedManager];
tiles = [[TileSet alloc]init];
GLKView *view = (GLKView *)self.view;
view.context = self.context;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
[self setupGL];
}
- (void)setupGL
{
int width = [[self view] bounds].size.width;
int height = [[self view] bounds].size.height;
[EAGLContext setCurrentContext:self.context];
self.effect = [[GLKBaseEffect alloc] init];
self.effect.light0.enabled = GL_TRUE;
self.effect.light0.diffuseColor = GLKVector4Make(0.4f, 0.4f, 0.4f, 1.0f);
//Configure Buffers
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glGenRenderbuffers(2, &colourRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colourRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colourRenderBuffer);
glGenRenderbuffers(3, &depthRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderBuffer);
//Confirm everything happened awesomely
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;
if(status != GL_FRAMEBUFFER_COMPLETE) {
NSLog(@"failed to make complete framebuffer object %x", status);
}
glEnable(GL_DEPTH_TEST);
// Enable the OpenGL states we are going to be using when rendering
glEnableClientState(GL_VERTEX_ARRAY);
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
float iva[] = {
0.0,0.0,0.0,
0.0,1.0,0.0,
1.0,1.0,0.0,
1.0,0.0,0.0,
};
glVertexPointer(3, GL_FLOAT, sizeof(float) * 3, iva);
glDrawArrays(GL_POINTS, 0, 4);
}
@end
With this the buffer clears(to a grey colour), but nothing from the vertex array renders. I have no idea what to do from here and due to the age of the technology there is not much information available on how to properly use glkit.
I don't see anything in your setup code that loads your shaders - I presume you are doing this somewhere in your code?
In addition, in your setup code, you are creating your framebuffer. The GLKView
does this for you - indeed you are telling the view to use a 24-bit depthbuffer in your viewDidLoad
method:
GLKView *view = (GLKView *)self.view;
view.context = self.context;
view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
So what your glkView:drawInRect:
code above is doing is saying: "Bind my handmade framebuffer, and draw some stuff into it". The GLKView
then automatically presents itself, but nothing has been drawn into it, you've only drawn into your handmade buffer. Unless you need additional framebuffer objects for tasks such as rendering to texture, then you don't need to concern yourself with framebuffer creation at all - let the GLKView
do it automatically.
What you should be doing in your setupGL
method (or anywhere you like in the setup) is creating your vertex array object(s) that remember the openGL state required to perform a draw. Then, in the glkView:drawInRect:
method you should:
glClear()
.glDrawArrays()
or glDrawElements()
.The GLKView
automatically sets its context as current, and binds its framebuffer object before each draw cycle.
Perhaps try to think of GLKView
more like a regular UIView
. It handles most of the openGL code behind the scenes for you, leaving you to simply tell it what it needs to draw. It has its drawRect:
code just like a regular UIView
- with a regular UIView
in drawRect:
you just tell it what it should draw, for example using Core Graphics functions - you don't then tell it to present itself.
The GLKViewController
is then best thought of as handling the mechanics of the rendering loop behind the scenes. You don't need to implement the timers, or even worry about pausing the animation on your application entering the background. You just need to override the update
or glkViewControllerUpdate:
method (depending on whether you're subclassing or delegating) to update the state of the openGL objects or view matrix.