codepad
[
create a new paste
]
login
|
about
Language:
C
C++
D
Haskell
Lua
OCaml
PHP
Perl
Plain Text
Python
Ruby
Scheme
Tcl
package com.logic.engine.gfx.wavefront; /* ModelOBJ - Represents a 3D mesh, provides methods for loading, rendering, etc. * NOTE: Supports the wavefront OBJ format only * * Written by Nick "SilverLogic" Brabant * ©2010 - All Rights Reserved. */ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.nio.FloatBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import javax.microedition.khronos.opengles.GL10; import com.logic.engine.gfx.GraphicsManager; import com.logic.engine.gfx.Object3D; import com.logic.engine.gfx.TextureManager; import com.logic.engine.system.Debug; import com.logic.engine.system.ResourceLoader; public class ModelOBJ extends Object3D implements Object3D.GfxManager { // OBJ Groups - Represents individual objects of a model (i.e. the prop of a plane) private Collection<ModelOBJ> groupCollection = new ArrayList<ModelOBJ>(); // Holds all instances of OBJ groups // Coordinate Lists - These hold the arrays from each line, and are later referenced by index to build the buffers private ArrayList<float[]> vertexList = new ArrayList<float[]>(); private ArrayList<float[]> textureList = new ArrayList<float[]>(); private ArrayList<float[]> normalList = new ArrayList<float[]>(); // Indexes - These hold the actual 'faces', each index contains the arrays which correspond to the lists index private ArrayList<short[]> vertexIndex = new ArrayList<short[]>(); private ArrayList<short[]> textureIndex = new ArrayList<short[]>(); private ArrayList<short[]> normalIndex = new ArrayList<short[]>(); // Buffers - These are the arrays that actually hold all of the faces, and what gets passed to opengl for rendering private FloatBuffer indiceBuffer; private FloatBuffer textureBuffer; private FloatBuffer normalBuffer; @SuppressWarnings("unused") private ModelMTL mtlLoader; // Used for loading the model mtl private Material material = new Material(); // Holds the specific material properties of this model private String mtlName; // This is simply used so that we don't try to pass empty buffers to opengl public boolean ready = false; // Keeps track of where this file is located (used when the mtlLoader definitions and any textures are loaded) private String filepath = ""; // Constructor public ModelOBJ() {} // Overloaded Constructor - Takes a string to a filename in the assets folder, and loads the model public ModelOBJ(String fname) { LoadModel(fname); } // LoadModel - This method takes a string to a filename, retrieves a BufferedReader from the resource loader, and parses the file public void LoadModel(String fname) { // Load a BufferedReader from the specified asset file so we can read it line by line ResourceLoader res = new ResourceLoader(); InputStreamReader isr = res.getStreamReader(fname); BufferedReader br = new BufferedReader(isr); // Get the local file path of the model (useful when retrieving mtlLoaders and textures) if(fname.lastIndexOf("/") > 0) { filepath = fname.substring(0, fname.lastIndexOf("/")) + "/"; } ParseModel(br); // Parse the contents of the file and build the model try { br.close(); // Close the input stream and clean everything up isr.close(); isr = null; br = null; res = null; } catch (IOException e) { Debug.throwError(e.toString() + "\nError closing out resources"); } } // ParseModel - This method parses an obj file line by line, it should be passed a BufferedReader from LoadModel private void ParseModel(BufferedReader br) { String line; // Holds the current line that we are working with String groupName = ""; // Holds the key (name) of the group we are currently in ModelOBJ tempModel = new ModelOBJ(); // This holds the current group we are working with try { while((line = br.readLine()) != null) { // # - Comment, we can skip these lines if(line.startsWith("#")) { continue; } // g - Group, this indicates that we need to create another model instance for these values if(line.startsWith("g")) { if(groupName != "") { AttachModel(tempModel, groupName); } // If we were working in a group, add it to the list line = line.substring(2); groupName = line; // We are now working in a new group tempModel = new ModelOBJ(); // Create a new object for this group continue; } // mtllib - Material Library, this specifies attributes about the current group if(line.startsWith("mtllib")) { line = line.substring(7); mtlLoader = new ModelMTL(filepath + line); continue; } // vt - Texture coordinates, we will load these into the textureList if(line.startsWith("vt")) { line = line.substring(3); float[] tempArr = getFloatArray(line, 2); tempArr[1] = 1.0f - tempArr[1]; tempModel.textureList.add(tempArr); continue; } // vn - Normals, we will load these into the normalList if(line.startsWith("vn")) { line = line.substring(3); tempModel.normalList.add(getFloatArray(line, 3)); continue; } // v - Vertices, we will load these into the vertexList if(line.startsWith("v")) { line = line.substring(2); tempModel.vertexList.add(getFloatArray(line, 3)); continue; } // f - Face, here we fill the index lists if(line.startsWith("f")) { line = line.substring(2); String[] stemp = line.split(" ", 3); String[] v1 = stemp[0].split("/", 3); String[] v2 = stemp[1].split("/", 3); String[] v3 = stemp[2].split("/", 3); tempModel.vertexIndex.add(getIndexArray(v1, v2, v3, 0)); // Add vertice indexes to list tempModel.textureIndex.add(getIndexArray(v1, v2, v3, 1)); // Add texture indexes tempModel.normalIndex.add(getIndexArray(v1, v2, v3, 2)); // Add normals indexes continue; } // usemtl - lets us know what material group to use for this specific model group if(line.startsWith("usemtl")) { line = line.substring(7); //tempModel.material = mtlLoader.GetMaterial(line); //mtlName = tempModel.material.name; mtlName = line; continue; } } } catch (IOException e) { Debug.throwError("Unable to parse OBJ File"); } tempModel.compileBuffers(); // We are finished parsing the file, time to fill the buffers // Not all models have groups, if a group was never assigned, we can just create the model directly if(groupName == "") { this.indiceBuffer = tempModel.indiceBuffer; this.textureBuffer = tempModel.textureBuffer; this.normalBuffer = tempModel.normalBuffer; this.material = tempModel.material; this.ready = true; GraphicsManager.removeObject(tempModel); // We don't need this anymore, remove from the graphics manager } else { tempModel.setPosition(getPosX(), getPosY(), getPosZ()); // Since this is a child of our current model, render at the same coordinates tempModel.ready = true; AttachModel(tempModel, groupName); // If a group was specified, attach the group to this model } } // getFloatArray - Just a method to cleanup the clutter in the ParseModel method, it splits a line into 3 float // values, and then returns it as a float[3], which can be added to an arraylist private float[] getFloatArray(String line, int size) { String[] stemp = line.split(" ", size); float[] ftemp = new float[size]; for(int i = 0; i < size; i++) { ftemp[i] = Float.valueOf(stemp[i]).floatValue(); } return ftemp; } // getIndexArray, Another method to cleanup the clutter, this is pretty much the same thing as getFloatArray, // except you must specify an index depicting which Index you want returned // Index Key: 0 = vertexIndex, 1 = textureIndex private short[] getIndexArray(String[] v1, String[] v2, String[] v3, int index) { // Obtain the array containing the list index values (we must offset by 1, since arrays are zero based, and OBJ format has a base of 1 short[] itemp = { (short)(Integer.valueOf(v1[index]).shortValue() - 1), (short)(Integer.valueOf(v2[index]).shortValue() - 1), (short)(Integer.valueOf(v3[index]).shortValue() - 1)}; return itemp; } // AttachModel - This method is used both internally for managing object groups, and externally if you wish to // attach an outside model to this source (i.e. a weapon on a soldier, or a prop on a plane) public void AttachModel(ModelOBJ obj, String key) { groupCollection.add(obj); // add the model to this models groupCollection } // compileBuffers - This is where the buffers that will be passed to opengl are built, each face in the index list // is referenced, then based on the index values, the buffer is built using the values at the indexed location private void compileBuffers() { short[] index = new short[3]; // holds the index array we are currently working with // Compile the indiceBuffer if(vertexIndex.size() > 0) { indiceBuffer = FloatBuffer.allocate(vertexIndex.size() * 9); // Allocate the buffer Iterator<short[]> vertexIterator = vertexIndex.iterator(); while(vertexIterator.hasNext()) { index = vertexIterator.next(); // Grab the next array of index values // The following lines inserts the 3 vertex's needed to complete the face indiceBuffer.put(vertexList.get(index[0])); indiceBuffer.put(vertexList.get(index[1])); indiceBuffer.put(vertexList.get(index[2])); } } // Compile the textureBuffer if(textureIndex.size() > 0) { textureBuffer = FloatBuffer.allocate(textureIndex.size() * 6); Iterator<short[]> textureIterator = textureIndex.iterator(); while(textureIterator.hasNext()) { index = textureIterator.next(); textureBuffer.put(textureList.get(index[0])); textureBuffer.put(textureList.get(index[1])); textureBuffer.put(textureList.get(index[2])); } } // Compile the normalBuffer if(normalIndex.size() > 0) { normalBuffer = FloatBuffer.allocate(normalIndex.size() * 9); Iterator<short[]> normalIterator = normalIndex.iterator(); while(normalIterator.hasNext()) { index = normalIterator.next(); normalBuffer.put(normalList.get(index[0])); normalBuffer.put(normalList.get(index[1])); normalBuffer.put(normalList.get(index[2])); } } // Just cleanup our un-needed variables, this will help free up a lot of memory vertexList.clear(); textureList.clear(); normalList.clear(); vertexIndex.clear(); textureIndex.clear(); normalIndex.clear(); } // We override the rotate method since this object may contain children, we need to apply rotation to all groups @Override public void Rotate(float x, float y, float z) { super.Rotate(x, y, z); Iterator<ModelOBJ> groupIterator = groupCollection.iterator(); while(groupIterator.hasNext()) { groupIterator.next().Rotate(x, y, z); } } public void Duplicate(ModelOBJ obj) { indiceBuffer = obj.indiceBuffer; normalBuffer = obj.normalBuffer; textureBuffer = obj.textureBuffer; mtlName = obj.mtlName; ready = true; } @Override public void Init(GL10 gl) { super.Init(gl); // TODO init } // We can call this to destroy all children objects, and cleanup from the graphics manager @Override public void Cleanup() { ModelOBJ tempModel; Iterator<ModelOBJ> groupIterator = groupCollection.iterator(); while(groupIterator.hasNext()) { tempModel = groupIterator.next(); GraphicsManager.removeObject(tempModel); tempModel = null; } GraphicsManager.removeObject(this); } @Override public void Render(GL10 gl) { super.Render(gl); if(ready) { gl.glBindTexture(GL10.GL_TEXTURE_2D, TextureManager.GetTextureID(mtlName)); gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); gl.glEnableClientState(GL10.GL_NORMAL_ARRAY); gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY); gl.glVertexPointer(3, GL10.GL_FLOAT, 0, indiceBuffer); gl.glNormalPointer(GL10.GL_FLOAT, 0, normalBuffer); gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer); gl.glDrawArrays(GL10.GL_TRIANGLES, 0, (indiceBuffer.array().length / 3)); gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); gl.glDisableClientState(GL10.GL_NORMAL_ARRAY); gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY); } gl.glPopMatrix(); } }
Private
[
?
]
Run code
Submit