Common Code Base for Android and iPhone: Sawbix Case Study Part I

Sawbix is a cube puzzle, similar to the Rubik’s cube. The features include: randomize, reset, solve, and undo. Randomize mixes up the cube to a different state each time, where you can use your puzzle solving skills to put the cube back to it’s starting position. Reset instantly puts the cube back to it’s starting position. Undo puts the cube back to the previous move, and Solve allows you to sit back and enjoy the show as the cube solves itself.

Sawbix is an Android and iOS app that uses a common source code shared between each operating system. The Android version is on the Market, with the iOS version soon to follow. The source code is primarily written in C, with thin glue layers written in Objective-C for iOS and Java/JNI for Android. The C source code is written in a style that is similar to Gnome and GTK+ where most of the functions are written in an object-oriented style, so that the first argument of every function represents “this” object.

The CubeWorld class is used to pass touch information from the screen to the cube.

  • CubeWorld_new()
  • CubeWorld_create()
  • CubeWorld_delete()
  • CubeWorld_draw()
  • CubeWorld_touch_down()
  • CubeWorld_touch_move()
  • CubeWorld_touch_up()
  • CubeWorld_cube_mix()
  • CubeWorld_cube_reset()
  • CubeWorld_cube_solve()
  • CubeWorld_cube_undo()

The Cube class is used to hold current state and draw the cube itself.

  • Cube_new()
  • Cube_create()
  • Cube_delete()
  • Cube_draw()
  • Cube_move()
  • Cube_animate()

The main features are implemented on the CubeWorld class, which controls the world and passes instructions to the Cube class, which maintains the state of the cube, and takes care of graphics and animation. The memory management API common to all classes are the new(), create(), and delete() functions. These usually have the following prototypes:

TYPE * TYPE_new();
void TYPE_create(TYPE * _this, ... arguments ...);
void TYPE_delete(TYPE * _this);

This dovetails the way Gnome does memory management, as well as the Cocoa and UIKit APIs, which provide separate alloc (new) and init (create) methods. This also provides the greatest flexibility in C, since it allows you to allocate memory dynamically or on the stack, in which case you would use the create() method without ever calling new().

To jump in the code base in more depth, we can look at how the draw() functions are implemented using the following code block as an example:

void
CubeWorld_draw(CubeWorld * _this)
{
    CubeWorld_draw_background(_this);
    Cube_draw(_this->cube);
}

void
CubeWorld_draw_background(CubeWorld * _this)
{
    glDisable(GL_DEPTH_TEST);
    glEnableClientState(GL_COLOR_ARRAY);
    glEnableClientState(GL_VERTEX_ARRAY);

    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();

    // a quad
    char indices[] = { 0, 1, 2, 2, 1, 3 };
    glColorPointer( 4, GL_FLOAT, 0, (float *)_this->bg_colors);
    glVertexPointer(3, GL_FLOAT, 0, (float *)_this->bg_points);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, (char *)indices);

    glMatrixMode(GL_PROJECTION);
    glPopMatrix();
    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();

    glDisableClientState(GL_COLOR_ARRAY);
    glDisableClientState(GL_VERTEX_ARRAY);
    glEnable(GL_DEPTH_TEST);
}

As you can see, all of the drawing is done with native OpenGL calls. This function draws the background, which is a simple gradient from blue to black (the bg_colors and bg_points data sets are set in the create() function). The matrix mode calls are to isolate this function from the rest of the code, which may assume that it can leave a matrix on the stack without being required to save it. The client state functions are to isolate this function from code that may wish to draw using textures instead of colors, by insisting that every drawable subsystem only enable those feature that they need.

There are many OpenGL wrapper libraries such as OGRE, CrystalSpace, etc. some of which are written in C++, but in the interest of app size and speed, the decision was made to go with a minimal custom library written in C. This turned out to be sufficient to build a simple cube puzzle app. For larger projects, however, it may be wise to look into existing libraries that can help with OpenGL state management and compiling 3D models into a form that can be used within the app.

Stay tuned for Part 2, in which we will discuss how to bind these functions to Java using JNI, in order to make an Android app.

Get insights on SFTP Gateway, cloud computing and more, in your inbox.

Get smarter about all things tech. Sign up now!

Scroll to Top