Displaying The Model
To manipulate the model, the method updatModelTrans() takes the cumulative rotation values in the variables xDegrees and yDegrees and applies a rotation transformation to the model's transformation array. This method also uses the cumulative values in xTrans, yTrans, and zTrans to apply a Z-axis translation to the transformation array. Both the rotation and translation variables are modified by Canvas key event methods. Pressing the proper key on the phone's keypad increments/decrements the rotation and translation values. Pressing the FIRE game key performs a "reset" that clears these variables and returns the model to the origin.
To display the model, I use Canvas's paint() method to handle screen updates (Listing Five, available electronically). For 3D rendering, paint() first attaches (binds) the rendering engine's output to the Canvas, sets the camera and lighting, invokes Graphics3D's immediate-mode render() method on the model, and releases the Canvas. A set of M3G API calls position the Camera and add any active Lights. The model's orientation is updated with updatModelTrans(). The final step is to call render(), while providing the rendering engine with the data sources in the model's VertexBuffer, IndexBuffer, Appearance, and transformation arrays.
Lessons Learned
On my first attempt, I collided with Java ME's 32-KB code limit when I tried to display the model as a high-resolution (high polygon) model. I had to generate a low-resolution model to get the array sizes below this limit. You can use either Milkshape's DirectX Mesh Tools or Blender3D's Decimate modifier to reduce the polygon count of a model. Using both of these tools, I trimmed the original brocket model from 1728 surfaces to 518 surfaces before the demo MIDlet worked. When compared to the brocket model rendered in a 3D authoring program, the resulting display of the brocket model on the phone looks pretty good (Figure 5).
The fewer polygons a model uses, the faster it renders, leaving more processor cycles available for other game logic. In the interest of performance, it becomes a matter of "how low can you go" in shaving off polygons until the model's geometry becomes distorted. I was able to reduce brocket to 240 polygons, which is a huge savings in processor cycles when you consider that rendering each polygon requires many floating-point operations.
I've written a demo MIDlet (available electronically) that displays brocket in the immediate mode using the techniques described here. The MIDlet also presents a menu so that you can pick a different POV, or switch to a second light of a different color and in a different position. Because the model and environment are represented in code, the only resource I had to add to the MIDlet was the texture image, brocket2.png. The MIDlet has been tested on a Sony Ericsson K700, a Samsung A940, and a Sanyo MM-9000. The demo's source code comes with the ObjView output of the medium-polygon model (brocket16TriStrip.txt) and low-polygon model (brocket18TriStrip.txt) for performance experiments.