So far, we have limited ourselves to fairly simple models. The most universal surface representation is the triangle mesh. But, there are a large varietyof file formats that store a triangle mesh. We will start by looking at a file format call SMF (simple model format). SMF which is a subset of the Wavefront OBJ file format. It basically looks like this:
v <x1> <y1> <z1> v <x2> <y2> <z2> . . . v <xn> <yn> <zn> f <u1> <v1> <w1> f <u2> <v2> <w2> . . . f <um> <vm> <wm>
The only thing to note is that vertices start at index 1, instead of index 0.
Here are some of our design concerns, first we would like the description of the data to be separate from the datastructure that we will eventually want to use. The reason for this, is that if we want to compute vertex normals, subdivide the surface, add fin geometry for shadow volume extrusion, or try to stripthe mesh we will need adjacency information. Simple Triangle Meshes are notoriously bad at providing answers to adjancency queries. Other datastructures for meshes can be used, like winged-edge, half-edge, or quad-edge and easily answer these queries at the cost of some, usually rather steep, initial computation. The constraint of describing meshes through procedures rather data pushes us towards the Builder pattern.
Using this interface, we can now write the SMF model loader.
Now, some important things to note about the SMFModelLoader, it takes an InputStream, this is *very* important. Don't make loaders load only from Files. If the code is long-lived (and even if it isn't) you will eventually rewrite the code so that it reads from a stream instead of from a file. I personally have done it more times than I can count. You are saving yourself work in the future, and IMHO you aren't adding any extra complexity. If you want the reasoning behind the madness, it can be viewed this way. SMFModelLoader knows how to process the data, but the user knows where the data should come from, don't let the SMFModelLoader think it knows better than the user that Meshes are always stored in files. You are, in reality, just making your code more brittle.
Next, we have the Mesh class. I haven't given it a lot of thought on exactly what Meshes should actually be able to do, but we definitely want to render them. The other key notion of the interface is that Meshes should be able to procedurally describe themselves using the MeshBuilder interface. Operations like mesh conversion, and saving are gained for free, using the exact same interface that we had to develop for loading the mesh! This is definitely a win.
The simple implementions of mesh are SimpleTriMesh.java and SimpleTriMeshBuilder. The majority of the functions just forward to the Vertex interface, and VertexDescription. VertexDescriptions allow us to procedurally build up an object to describe the vertices. The vertex interface provides a mix-in hierarchy of implementing classes. Note, that the vertex classes are not particularly efficient for real-time purposes. This is OK, because the big wins in performance come from producing a compatible binary representation and placing it in the graphic card's memory, or system memory where the graphics card has fast access to. We will be doing this in a later tutorial. Since the rendering functionality of vertices is going to eventually be supplanted by a superior mechanism for performance, there is no point in optimizing the implementation.