Quantcast
Channel: OpenGL – Thorn Technologies
Viewing all articles
Browse latest Browse all 3

Using OpenGL and GLKit in Objective-C: Sawbix Case Study Part III

$
0
0

In Part I, we discussed the common code base written in C, and overviewed the methods required to bind this code base to the graphics systems in each platform. In Part II, we discussed the steps required to connect the common code base to the Android Java widgets using Java Native Interface (JNI).

In this part, we will discuss how to bind the common code base to Objective-C methods.

Much of the code we need to write is simply connecting the C code to the Objective-C code; the methods which are called by the Cocoa/UIKit runtime. For example, the glkView:drawInRect method is:

- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
    CubeWorld_draw(world);
}

This requires that we have a place to store the world object in our ViewController:

@interface CubeViewController : GLKViewController
{
@private
    EAGLContext *context;
    CubeWorld *world;
    // ...
}

Sawbix was designed as a single touch application, so there is a some impedance mismatch between single touch and the way that iOS touch events are sent to the application, this is where we need to use the anyObject method to get one of the touch events. To quote Apple’s documentation,

The object returned is chosen at the set’s convenience
— the selection is not guaranteed to be random.

The benefit of the anyObject method is that it may return the event that is closest to the previous event, instead of just getting the first event. The following code show how we use this method to connect to our C code to CubeViewController:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    if ([touches count] < 1) return;
    CGPoint point = [[touches anyObject] locationInView:[self view]];
    CubeWorld_touch_down(world, point.x, point.y);
}
 
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    if ([touches count] < 1) return;
    CGPoint point = [[touches anyObject] locationInView:[self view]];
    CubeWorld_touch_move(world, point.x, point.y);
}
 
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if ([touches count] < 1) return;
    CGPoint point = [[touches anyObject] locationInView:[self view]];
    CubeWorld_touch_up(world, point.x, point.y);
}

The most difficult portion of the code was the OpenGL initialization and tear-down. Before GLKit (circa iOS 4), there were no helpers aside from those found in OpenGLES2 itself, such as the Framebuffer and Renderbuffer functions, which are not easy to use. GLKit helps quite a bit with these state management functions, and calls setupGL and tearDownGL functions on the GLKitViewController:

- (void)setupGL
{
    [EAGLContext setCurrentContext:self.context];
 
    // allocate cube-world
    world = CubeWorld_new();
    CGSize viewport = self.view.frame.size;
    CubeWorld_create(world, viewport.width, viewport.height);
}
 
- (void)tearDownGL
{
    [EAGLContext setCurrentContext:self.context];
 
    // deallocate cube-world
    CubeWorld_delete(world);
    world = NULL;
}

Comparing this code with the same code before GLKit, it is obvious that if you’re going to be using OpenGLES on iOS, GLKit is certainly the way to go. Another benefit of using GLKit is that it provides matrix functions, which are required to manipulate camera angles and the like.

Now that we have our sources in order, how do we build it? First thing to do is to add the sources to the project, so that XCode knows how to find the sources. If necessary, you may also want to add the headers to Build Settings / Header Search Paths so that XCode knows where to find the headers. You may also want to add some device-specific #defines to help with porting between iPhone and iPad, or for different screen resolutions. To help you get started, XCode also has a nice OpenGLES project template, so you can get up and running quickly. Once the project is in working order, select a simulator, and click Run.

Conclusion

In Part I we discussed the common code base in C, in Part II we discussed binding it to Java native calls, and in this part we discussed binding it to Objective-C methods. As mentioned in the previous part, this is an application of the Don’t Repeat Yourself (DRY) principle, which states that

Every piece of knowledge must have a single, unambiguous,
authoritative representation within a system.

Now that we have bound our common code, we have a single point of maintainance, so that any of our changes are instantly reflected in each platform. To take this one step further, there is no reason why you have to write the whole source yourself. We could use any open source libraries (with compatible licenses) and encorporate them in our source to reduce the amount of work to get up and running. I would recommend considering using some portable C runtime such as CFLite, GLib, or libAPR, since they are all pure C, and have a proven track record of usability and portability.


Viewing all articles
Browse latest Browse all 3

Latest Images

Trending Articles



Latest Images