Making the Immediate Mode Model
Since I couldn't generate M3G files, the best solution for me was to assemble the model as a Mesh using VertexArrays, then perform an immediate-mode render on it. My new plan still required building the model, then either finding a plug-in or writing a translator program to convert the model's data into triangle strips.
I chose Art of Illusion (www.artofillusion .org) as the 3D authoring application because it has an option for converting models into triangle strips, a feature that might simplify writing a translator program. It also is cross-platform, which meant I could press-gang my Apple Powerbook to do the work while I wrote the Java ME code on Windows.
Because the project already involved rocket science, I designed a retro-style Buck Rogers rocketship as the 3D model. Thus, the model "brocket" was born (Figure 2). I made the texture file, brocket2.png, to apply a simple color pattern on brocket's hull. I had Art of Illusion save the model in OBJ format, a 3D file format used by many authoring programs. The resulting files were brocket.obj, which contained the model's data, and brocket.mtl, which stored some appearance information and a reference to the texture map file.
Before attempting to write a translator, I took one last stroll through Google to see if something similar was available. Luckily, I stumbled onto "Loading OBJ Models into M3G" (http://fivedots.coe .psu.ac.th/~ad/jg/objm3g/), where Andrew Davison describes his ObjView programa Java utility that reads an OBJ file, renders the 3D objects with Java 3D, and writes the object data out as M3G VertexArrays. The source code was also available. This was exactly what I needed.
To use ObjView, you need Java SE 1.4.x SDK or later installed on your PC or Mac, along with Java 3D, which implements a 3D API for Java desktop applications. Originally developed by Sun, Java 3D is an open-source technology. For Windows, Java 3D is available online (https://java3d.dev.java.net/binary-builds.html). For Mac OS 10.4.x, Java 3D comes preinstalled. For Mac OS 10.3.x, you can download Java 3D (www.apple.com/downloads/macosx/apple/ java3dandjavaadvancedimagingupdate.html).
First, I compiled the ObjView source files, per directions in objM3G.pdf. Next, I had Art of Illusion save the model in OBJ format, along with the .mtl file to preserve texture information. I copied the resulting brocket.obj, brocket.mtl, and brocket2.png files to the directory with the ObjView classes. Using the console window, I switched to that directory and had Java execute ObjView and read the OBJ file.
ObjView rendered the brocket model in Figure 3, complete with the texture image. Clicking and dragging the mouse rotates the model within the window so that you can inspect your handiwork.
One problem ObjView's display revealed was that Art of Illusion could mangle the texture maps. This is probably my fault, as I found the application's interface for applying a texture map around a complex object difficult to use. To apply the texture to the model successfully, I used Milkshape (www.milkshape3d.com/), a 3D authoring program that has versatile texture-mapping tools and can import/export a variety of 3D file formats (Figure 4).
When you're satisfied with the result, exit ObjView and it writes the model's geometry out as several M3G VertexArrays. These arrays describe the model's surfaces (as triangle strips), its surface normals (for calculating lighting effects), and its texture coordinates (which map a 2D image onto the surfaces). These VertexArrays appear as Java source code in the output file ObjView generates, examObj.txt. ObjView also writes some Appearance information and other visual attributes to this file, which are accessed through the code's built-in function setMatColours(). This file's contents can be copied and pasted directly into your application's display class, which is typically a Canvas.
Listing One shows the output ObjView generates, with the VertexArrays abbreviated for clarity. Technically, the data is actually stored as arrays, and the code's built-in methods, getVerts(), getNormals(), and getTextures(), load this data into VertextArrays. The built-in function setMatColours() sets the model's overall color to a light gray and its shininess to the maximum value of 128.0, which causes any specular highlights to be concentrated, rather than diffused.
// Methods for model in brocket.obj private short[] getVerts() // return an array holding Vertexes [2457 values / 3 = 819 points] { short[] vals = { 15,-3,-56, 16,-3,-56, 16,-4,-60, 16,-4,-60, 26,-8,-70, 15,-3,-56, ... -11,-2,-41, -11,-5,-40, -14,-4,-26 }; return vals; } // end of getVerts() private byte[] getNormals() // return an array holding Normals [2457 values / 3 = 819 points] { byte[] vals = { -110,-66,-6, -70,105,-23, -78,70,-73, -78,70,-73, -89,-77,-51, -110,-66,-6, ... 92,85,23, 120,39,21, 99,79,19 }; return vals; } // end of getNormals() private short[] getTexCoords() // return an array holding TexCoords [1638 values / 2 = 819 points] { short[] vals = { 160,72, 163,72, 164,68, 164,68, 191,58, 160,72, ... 86,87, 86,88, 78,102 }; return vals; } // end of getTexCoords() private int[] getStripLengths() // return an array holding the lengths of each triangle strip { int[] lens = { 44, 28, 40, 76, 31, 69, 15, 85, 36, 8, 21, 22, 156, 44, 28, 40, 76 }; return lens; } // end of getStripLengths() private Material setMatColours() // set the material's colour and shininess values { Material mat = new Material(); mat.setColor(Material.AMBIENT, 0x00000000); mat.setColor(Material.EMISSIVE, 0x00000000); mat.setColor(Material.DIFFUSE, 0xFFCDCDCD); mat.setColor(Material.SPECULAR, 0x00000000); mat.setShininess(128.0f); return mat; } // end of setMatColours()