Question

I'm having trouble finding the correct place to do my shader setup for an OpenGLES application using GLKView and GLKViewController.

It seems like viewDidLoad is a natural place to do this, but shader creation fails when I try to do this here. My setup is something like this:

//shader helper method
int setupShaders(const char* vShader, const char* fShader); //returns a program handle

//inside GLKViewController subclass

static int program;

-(void)viewDidLoad{
    [super viewDidLoad];
    program = setupShaders(vsh, fsh); //program will be zero indicating setup failure
}

I know the setup code works because it succeeds if I call it inside -(void)glkView:(GLKView *)view drawInRect:(CGRect)rect.

So I'm assuming OpenGL isn't fully initialized when -(void)viewDidLoad is called, or something has to be done to set the correct OpenGL context for the setup I'm trying to do, I just can't find any documentation on where or how to do setup correctly.

Was it helpful?

Solution 3

So it turns out it works perfectly if you initialize from inside -(void)viewDidAppear. Jacob's solution works fine as well, but it seems slightly cleaner to me to use a callback rather than adding a conditional to the draw method.

OTHER TIPS

You are right that the earliest place you can easily set up your shaders is in the drawRect method. This is because there must be a valid GL context current. Per the GLKView documentation:

Before calling its drawRect: method, the view makes its EAGLContext object the current OpenGL ES context and binds its framebuffer object to the OpenGL ES context as the target for rendering commands.

So, the easiest thing to do is hang onto some information, like the program handle, and only initialize if it is non-zero.

if (program == 0)
    program = setupShaders(vsh, fsh);

If you don't like this approach, you can consider initializing your GLKView with a context that you provide, or overriding bindDrawable. Or you could not use GLKView and do things manually...

There needs to be a current EAGLContext before you can call any OpenGL ES API, and that includes setup work like compiling shaders. GLKView makes its context current before invoking your drawRect: (or glkView:drawInRect:) method, but you're welcome to make it the current context at any time.

The view's context is current as of viewDidAppear: because that method is called after the first time the view draws itself. I'm not sure it's guaranteed to be current at that point, though -- there's no documented API contract that a GLKView's context will remain current after the end of drawing. So it's better to call [EAGLContext setCurrentContext:myContext] yourself whenever you want to do setup work for your OpenGL ES scene (even if you choose to do it in viewDidAppear:).

See the OpenGL ES Game template when you create a new Xcode project for an example of GLKView/GLKViewController setup.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top