summaryrefslogtreecommitdiffstats
path: root/src/net
diff options
context:
space:
mode:
Diffstat (limited to 'src/net')
-rw-r--r--src/net/java/joglutils/model/loader/LoaderFactory.java62
-rw-r--r--src/net/java/joglutils/model/loader/MaxConstants.java109
-rw-r--r--src/net/java/joglutils/model/loader/MaxLoader.java876
-rw-r--r--src/net/java/joglutils/model/loader/WaveFrontLoader.java452
-rw-r--r--src/net/java/joglutils/model/loader/iLoader.java21
5 files changed, 1520 insertions, 0 deletions
diff --git a/src/net/java/joglutils/model/loader/LoaderFactory.java b/src/net/java/joglutils/model/loader/LoaderFactory.java
new file mode 100644
index 0000000..59a680f
--- /dev/null
+++ b/src/net/java/joglutils/model/loader/LoaderFactory.java
@@ -0,0 +1,62 @@
+/*
+ * LoaderFactory.java
+ *
+ * Created on February 27, 2008, 10:35 PM
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+package net.java.joglutils.model.loader;
+
+import net.java.joglutils.model.ModelLoadException;
+import net.java.joglutils.model.geometry.Model;
+
+/**
+ *
+ * @author Brian Wood
+ */
+public class LoaderFactory {
+ private static final int FILETYPE_UNKNOWN = -1;
+ private static final int FILETYPE_3DS = 1;
+ private static final int FILETYPE_OBJ = 2;
+
+ public static Model load(String source) throws ModelLoadException {
+ iLoader loader = getLoader(source);
+ if (loader == null)
+ return null;
+
+ return loader.load(source);
+ }
+
+ private static iLoader getLoader(String path) {
+ switch(determineFiletype(path)) {
+ case FILETYPE_3DS:
+ return new MaxLoader();
+
+ case FILETYPE_OBJ:
+ return new WaveFrontLoader();
+
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Parses the file suffix to determine what file format the model is in.
+ *
+ * @param path File path info
+ * @returns int Constant indicating file type
+ */
+ private static int determineFiletype(String path) {
+ int type = FILETYPE_UNKNOWN;
+ String tokens[] = path.split("\\.");
+
+ if(tokens[tokens.length - 1].equals("3ds"))
+ type = FILETYPE_3DS;
+ else if(tokens[tokens.length - 1].equals("obj"))
+ type = FILETYPE_OBJ;
+
+ return type;
+ }
+}
diff --git a/src/net/java/joglutils/model/loader/MaxConstants.java b/src/net/java/joglutils/model/loader/MaxConstants.java
new file mode 100644
index 0000000..57b0b7c
--- /dev/null
+++ b/src/net/java/joglutils/model/loader/MaxConstants.java
@@ -0,0 +1,109 @@
+/*
+ * MaxConstants.java
+ *
+ * Created on February 12, 2008, 10:20 PM
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+package net.java.joglutils.model.loader;
+
+/**
+ * Constants representing block types in the 3DS file. This is not a complete
+ * list; it only includes the types that are currently recognized. They are
+ * all of type <code>int</code> since 3DS files allocate 16 bits to the
+ * block type field.
+ *
+ * @author RodgersGB
+ * @version $Revision: 1.0 $
+ */
+interface MaxConstants {
+ // 0xMISC Administrative codes
+ public static final int TYPE_3DS_FILE = 0x4D4D;
+ public static final int TYPE_3DS_VERSION = 0x0002;
+ public static final int TYPE_MESH_DATA = 0x3D3D;
+ public static final int TYPE_MESH_VERSION = 0x3D3E;
+
+ // 0x0--- Data type codes
+ public static final int TYPE_COLOR_I = 0x0011;
+ public static final int TYPE_COLOR_F = 0x0010;
+ public static final int TYPE_COLOR_LIN_I = 0x0012;
+ public static final int TYPE_COLOR_LIN_F = 0x0013;
+ public static final int TYPE_PERCENT_I = 0x0030;
+ public static final int TYPE_PERCENT_F = 0x0031;
+
+ // 0x1--- Background codes
+ public static final int TYPE_BG_BITMAP = 0x1100;
+ public static final int TYPE_BG_USE_BITMAP = 0x1101;
+ public static final int TYPE_BACKGROUND_COLOR = 0x1200;
+ public static final int TYPE_BG_USE_SOLID = 0x1201;
+ public static final int TYPE_BG_GRADIENT = 0x1300;
+ public static final int TYPE_BG_USE_GRADIENT = 0x1301;
+
+ // 0x2--- Ambient light/fog code
+ public static final int TYPE_AMBIENT_COLOR = 0x2100;
+ public static final int TYPE_FOG = 0x2200;
+ public static final int TYPE_USE_FOG = 0x2201;
+ public static final int TYPE_FOG_BGND = 0x2210;
+ public static final int TYPE_LAYER_FOG = 0x2302;
+ public static final int TYPE_USE_LAYER_FOG = 0x2302;
+
+ // 0x3--- View codes
+
+ // 0x4--- Object data codes
+ public static final int TYPE_NAMED_OBJECT = 0x4000;
+ public static final int TYPE_TRIANGLE_OBJECT = 0x4100;
+ public static final int TYPE_POINT_LIST = 0x4110;
+ public static final int TYPE_VERTEX_OPTIONS = 0x4111;
+ public static final int TYPE_FACE_LIST = 0x4120;
+ public static final int TYPE_MAT_FACE_LIST = 0x4130;
+ public static final int TYPE_MAT_UV = 0x4140;
+ public static final int TYPE_SMOOTH_GROUP = 0x4150;
+ public static final int TYPE_MESH_MATRIX = 0x4160;
+ public static final int TYPE_MESH_COLOR = 0x4165;
+ // 0x46-- Light data codes
+ public static final int TYPE_DIRECT_LIGHT = 0x4600;
+ public static final int TYPE_SPOTLIGHT = 0x4610;
+ public static final int TYPE_ATTENUATION = 0x4625;
+ public static final int TYPE_AMBIENT_LIGHT = 0x4680;
+ // 0x47-- Camera data codes
+ public static final int TYPE_CAMERA = 0x4700;
+
+ // 0x5--- Unknown shape stuff
+
+ // 0x6--- Path/curve codes
+
+ // 0x7--- Viewport codes
+
+ // 0x8--- Unknown XDATA codes
+
+ // 0xA--- Material codes
+ public static final int TYPE_MATERIAL = 0xAFFF;
+ public static final int TYPE_MATERIAL_NAME = 0xA000;
+ public static final int TYPE_MAT_AMBIENT = 0xA010;
+ public static final int TYPE_MAT_DIFFUSE = 0xA020;
+ public static final int TYPE_MAT_SPECULAR = 0xA030;
+ public static final int TYPE_MAT_SHININESS = 0xA040;
+ public static final int TYPE_MAT_SHININESS2 = 0xA041;
+ public static final int TYPE_MAT_TRANSPARENCY = 0xA050;
+ public static final int TYPE_MAT_XPFALL = 0xA052;
+ public static final int TYPE_MAT_REFBLUR = 0xA053;
+ public static final int TYPE_MAT_2_SIDED = 0xA081;
+ public static final int TYPE_MAT_SELF_ILPCT = 0xA084;
+ public static final int TYPE_MAT_SHADING = 0xA100;
+ // 0xA2+- Texture codes
+ public static final int TYPE_MAT_TEXMAP = 0xA200;
+ public static final int TYPE_MAT_MAPNAME = 0xA300;
+
+ // 0xB--- Node codes
+ public static final int TYPE_KEY_FRAME = 0xB000;
+ public static final int TYPE_FRAME_INFO = 0xB002;
+ public static final int TYPE_FRAMES = 0xB008;
+ public static final int TYPE_PIVOT_POINT = 0xB020;
+
+
+ // 0xC--- Unknown codes
+ // 0xD--- Unknown codes
+ // 0xF--- Unknown codes
+} \ No newline at end of file
diff --git a/src/net/java/joglutils/model/loader/MaxLoader.java b/src/net/java/joglutils/model/loader/MaxLoader.java
new file mode 100644
index 0000000..d71baeb
--- /dev/null
+++ b/src/net/java/joglutils/model/loader/MaxLoader.java
@@ -0,0 +1,876 @@
+/*
+ * Copyright (c) 2006 Greg Rodgers All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistribution in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * The names of Greg Rodgers, Sun Microsystems, Inc. or the names of
+ * contributors may not be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind. ALL
+ * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. GREG ,
+ * SUN MICROSYSTEMS, INC. ("SUN"), AND SUN'S LICENSORS SHALL NOT BE LIABLE FOR
+ * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
+ * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL GREG
+ * RODGERS, SUN, OR SUN'S LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT
+ * OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
+ * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF GREG
+ * RODGERS OR SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ *
+ * You acknowledge that this software is not designed or intended for use
+ * in the design, construction, operation or maintenance of any nuclear
+ * facility.
+ */
+
+package net.java.joglutils.model.loader;
+
+import java.awt.Color;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import net.java.joglutils.model.ResourceRetriever;
+import net.java.joglutils.model.geometry.Bounds;
+import net.java.joglutils.model.geometry.Face;
+import net.java.joglutils.model.geometry.Material;
+import net.java.joglutils.model.geometry.Mesh;
+import net.java.joglutils.model.geometry.Model;
+import net.java.joglutils.model.geometry.TexCoord;
+import net.java.joglutils.model.geometry.Vec4;
+
+public class MaxLoader implements MaxConstants, iLoader {
+// File reader
+ private File file;
+ private boolean loaded = false;
+ private DataInputStream dataInputStream;
+
+// Global chunks
+ private Chunk currentChunk, tempChunk;
+
+ /** Bounds of the model */
+ private Bounds bounds = new Bounds();
+
+ /** Center of the model */
+ private Vec4 center = new Vec4(0.0f, 0.0f, 0.0f);
+
+ // Constructor
+ public MaxLoader()
+ {
+ currentChunk = new Chunk();
+ tempChunk = new Chunk();
+ }
+
+ public Model load(String source) {
+ Model model = new Model(source);
+ load(model);
+ return model;
+ }
+ // Verified
+ public boolean load(Model model)
+ {
+ try {
+ InputStream stream = ResourceRetriever.getResourceAsInputStream(model.getSource());
+ if (stream == null) {
+ System.out.println("stream is null");
+ return false;
+ }
+
+ dataInputStream = new DataInputStream(stream);
+ if (dataInputStream == null) {
+ System.out.println("dataInputStream is null");
+ return false;
+ }
+
+ readChunkHeader(currentChunk);
+
+ } catch(IOException e) {
+ System.out.println("IOException e:" + e);
+ return false;
+ }
+
+
+ if (currentChunk.id != TYPE_3DS_FILE) {
+ System.err.println("Unable to load PRIMARY chuck from file!");
+ return false;
+ }
+
+ processNextChunk(model, currentChunk);
+ computeNormals(model);
+
+ try {
+ dataInputStream.close();
+
+ } catch (IOException e) {
+ System.err.println("Error: File IO error in: Closing File");
+ return false;
+ }
+
+ loaded = true;
+
+ model.setBounds(this.bounds);
+ model.setCenterPoint(this.center);
+
+ return loaded;
+ }
+
+ /**
+ * Read the stream completely
+ *
+ * @param buffer
+ * @param offset
+ * @param length
+ * @throws IOException
+ */
+ private int readCompletely(byte buffer[], int offset, int length) throws IOException {
+ dataInputStream.readFully(buffer, offset, length);
+ return length;
+ }
+
+ // Verified
+ void processNextChunk(Model model, Chunk previousChunk)
+ {
+ int version = 0;
+ byte buffer[] = null;
+
+ currentChunk = new Chunk();
+
+ try {
+ while (previousChunk.bytesRead < previousChunk.length) {
+ readChunkHeader(currentChunk);
+
+ switch (currentChunk.id) {
+ case TYPE_3DS_VERSION:
+ version = readInt(currentChunk);
+
+ if (version > 0x03)
+ System.err.println("This 3DS file is over version 3 so it may load incorrectly");
+ break;
+
+ case TYPE_MESH_DATA:
+ readChunkHeader(tempChunk);
+ buffer = new byte[tempChunk.length - tempChunk.bytesRead];
+ tempChunk.bytesRead += readCompletely(buffer, 0, buffer.length);
+ // TODO:DELETE tempChunk.bytesRead += dataInputStream.read(buffer, 0, tempChunk.length - tempChunk.bytesRead);
+ currentChunk.bytesRead += tempChunk.bytesRead;
+ processNextChunk(model, currentChunk);
+ break;
+
+ case TYPE_MATERIAL:
+ Material mat = new Material();
+ model.addMaterial(mat);
+ processNextMaterialChunk(model, mat, currentChunk);
+ break;
+
+ case TYPE_NAMED_OBJECT:
+ Mesh obj = new Mesh();
+ obj.name = readString(currentChunk);
+ model.addMesh(obj);
+ processNextObjectChunk(model, obj, currentChunk);
+ break;
+
+ case TYPE_KEY_FRAME:
+ processKeyFrame(currentChunk);
+ break;
+
+ default:
+ buffer = new byte[currentChunk.length - currentChunk.bytesRead];
+ currentChunk.bytesRead += readCompletely(buffer, 0, buffer.length);
+ break;
+ }
+ previousChunk.bytesRead += currentChunk.bytesRead;
+ }
+ }
+ catch (IOException e) {
+ System.err.println("Error: File IO error in: Process Next Chunk");
+ return;
+ }
+ currentChunk = previousChunk;
+ }
+
+ private void processKeyFrame(Chunk root) throws IOException {
+ currentChunk = new Chunk();
+ byte buffer[] = null;
+
+ while (root.bytesRead < root.length) {
+ readChunkHeader(currentChunk);
+
+ switch (currentChunk.id) {
+ default:
+ buffer = new byte[currentChunk.length - currentChunk.bytesRead];
+ currentChunk.bytesRead += readCompletely(buffer, 0, buffer.length);
+ break;
+ }
+ root.bytesRead += currentChunk.bytesRead;
+ }
+ currentChunk = root;
+ }
+
+ // Verified
+ private void readChunkHeader(Chunk chunk) throws IOException
+ {
+ chunk.bytesRead = 0;
+ chunk.id = this.readShort(chunk);
+ chunk.length = this.readInt(chunk);
+ }
+
+ // Verified
+ private void processNextObjectChunk(Model model, Mesh object, Chunk previousChunk)
+ {
+ byte buffer[] = null;
+ int bytesread;
+
+ currentChunk = new Chunk();
+
+ try {
+ while (previousChunk.bytesRead < previousChunk.length) {
+ readChunkHeader(currentChunk);
+
+ switch (currentChunk.id) {
+ case TYPE_TRIANGLE_OBJECT:
+ processNextObjectChunk(model, object, currentChunk);
+ break;
+
+ case TYPE_DIRECT_LIGHT:
+ buffer = new byte[currentChunk.length - currentChunk.bytesRead];
+ bytesread = readCompletely(buffer, 0, buffer.length);
+ currentChunk.bytesRead += bytesread;
+ break;
+
+ case TYPE_POINT_LIST:
+ readVertices(object, currentChunk);
+ break;
+
+ case TYPE_FACE_LIST:
+ readFaceList(object, currentChunk);
+ break;
+
+ case TYPE_MAT_FACE_LIST:
+ readObjectMaterial(model, object, currentChunk);
+ break;
+
+ case TYPE_MAT_UV:
+ readUVCoordinates(object, currentChunk);
+ break;
+
+ default:
+ buffer = new byte[currentChunk.length - currentChunk.bytesRead];
+ bytesread = readCompletely(buffer, 0, buffer.length);
+ // TODO:DELETE currentChunk.bytesRead += dataInputStream.read(buffer, 0, currentChunk.length - currentChunk.bytesRead);
+ currentChunk.bytesRead += bytesread;
+ break;
+ }
+ previousChunk.bytesRead += currentChunk.bytesRead;
+ }
+ }
+ catch (IOException e) {
+ System.err.println("Error: File IO error in: Process Next Object Chunk");
+ return;
+ }
+
+ currentChunk = previousChunk;
+ }
+
+ // Verified
+ private void processNextMaterialChunk(Model model, Material material, Chunk previousChunk)
+ {
+ byte buffer[] = null;
+
+ currentChunk = new Chunk();
+
+ try {
+ while (previousChunk.bytesRead < previousChunk.length) {
+ readChunkHeader(currentChunk);
+
+ switch (currentChunk.id)
+ {
+ case TYPE_MATERIAL_NAME:
+ material.strName = readString(currentChunk);
+ buffer = new byte[currentChunk.length - currentChunk.bytesRead];
+ currentChunk.bytesRead += readCompletely(buffer, 0, buffer.length);
+ break;
+
+ case TYPE_MAT_AMBIENT:
+ material.ambientColor = readColor(currentChunk);
+ break;
+
+ case TYPE_MAT_DIFFUSE:
+ material.diffuseColor = readColor(currentChunk);
+ break;
+
+ case TYPE_MAT_SPECULAR:
+ material.specularColor = readColor(currentChunk);
+ break;
+
+ case TYPE_MAT_SHININESS:
+ material.shininess = 1.0f+127.0f*readPercentage(currentChunk);
+ break;
+
+ case TYPE_MAT_SHININESS2:
+ material.shininess2 = 1.0f+127.0f*readPercentage(currentChunk);
+ break;
+
+ case TYPE_MAT_TRANSPARENCY:
+ material.transparency = readPercentage(currentChunk);
+ break;
+
+ case TYPE_MAT_2_SIDED:
+ buffer = new byte[currentChunk.length - currentChunk.bytesRead];
+ currentChunk.bytesRead += readCompletely(buffer, 0, buffer.length);
+ break;
+
+ case TYPE_MAT_XPFALL:
+ float xpf = readPercentage(currentChunk);
+ break;
+
+ case TYPE_MAT_REFBLUR:
+ float ref = readPercentage(currentChunk);
+ break;
+
+ case TYPE_MAT_SELF_ILPCT:
+ float il = readPercentage(currentChunk);
+ break;
+
+ case TYPE_MAT_SHADING:
+ int shading = readShort(currentChunk);
+ // Some kind of code for the rendering type: 1, 3, 4, etc.
+ break;
+
+ case TYPE_MAT_TEXMAP:
+ processNextMaterialChunk(model, material, currentChunk);
+ break;
+
+ case TYPE_MAT_MAPNAME:
+ material.strFile = readString(currentChunk);
+ buffer = new byte[currentChunk.length - currentChunk.bytesRead];
+ currentChunk.bytesRead += readCompletely(buffer, 0, buffer.length);
+ break;
+
+ default:
+ buffer = new byte[currentChunk.length - currentChunk.bytesRead];
+ currentChunk.bytesRead += readCompletely(buffer, 0, buffer.length);
+ break;
+ }
+
+ previousChunk.bytesRead += currentChunk.bytesRead;
+ }
+ } catch (IOException e) {
+ System.err.println("Error: File IO error in: Process Next Material Chunk");
+ return;
+ }
+ currentChunk = previousChunk;
+ }
+
+// // Verified
+// private void readObjectMaterial(Model model, Mesh object, Chunk previousChunk) throws IOException
+// {
+// String strMaterial = new String();
+// byte buffer[] = null;
+//
+// strMaterial = readString(previousChunk);
+//
+// for (int i=0; i<model.getNumberOfMaterials(); i++) {
+// if (strMaterial.equals(model.getMaterial(i).strName)) {
+// object.materialID = i;
+// if (model.getMaterial(i).strFile != null)
+// object.hasTexture = true;
+// break;
+// }
+// }
+//
+// try {
+// // Read the faces that are associated with this material and associated the
+// // material id with each of the faces defined (per 3DS specification)
+// int numOfFaces = myReadShort(dataInputStream);
+// previousChunk.bytesRead += 2;
+//
+// // Now loop over the number of faces to get their material ids and save this info
+// for (int i=0; i<numOfFaces; i++) {
+// int faceId = myReadShort(dataInputStream);
+// object.faces[faceId].materialID = object.materialID;
+// previousChunk.bytesRead += 2;
+// }
+//
+// buffer = new byte[previousChunk.length - previousChunk.bytesRead];
+// previousChunk.bytesRead += readCompletely(buffer, 0, buffer.length);
+//
+// // TODO:DELETE buffer = new byte[previousChunk.length - previousChunk.bytesRead];
+// // TODO:DELETE previousChunk.bytesRead += dataInputStream.read(buffer, 0, previousChunk.length - previousChunk.bytesRead);
+// }
+// catch (IOException e) {
+// System.err.println("Error: File IO error in: Read Object Material");
+// return;
+// }
+// }
+
+ // mine
+ private void readObjectMaterial(Model model, Mesh mesh, Chunk root) throws IOException {
+ String strMaterial = null;
+ byte buffer[] = null;
+
+ strMaterial = readString(root);
+
+ for (int i=0; i<model.getNumberOfMaterials(); i++) {
+ if (strMaterial.equals(model.getMaterial(i).strName)) {
+ mesh.materialID = i;
+ Material mat = model.getMaterial(i);
+ if (mat.strFile != null)
+ mesh.hasTexture = true;
+ break;
+ }
+ }
+
+ try {
+ // Read the faces that are associated with this material and associated the
+ // material id with each of the faces defined (per 3DS specification)
+ int numOfFaces = this.readShort(root);
+
+ // Now loop over the number of faces to get their material ids and save this info
+ for (int i=0; i<numOfFaces; i++) {
+ int faceId = readShort(root);
+ mesh.faces[faceId].materialID = mesh.materialID;
+ }
+ }
+ catch (IOException e) {
+ System.err.println("Error: File IO error in: Read Object Material");
+ return;
+ }
+ }
+
+// // Verified
+// private void readUVCoordinates(Mesh object, Chunk previousChunk)
+// {
+// try {
+// object.numTexCoords = myReadShort(dataInputStream);
+// // TODO:DELETE object.numTexVertex = swap(dataInputStream.readShort());
+//
+// previousChunk.bytesRead += 2;
+//
+// object.texCoord = new TexCoord[object.numTexCoords];
+// for (int i=0; i<object.numTexCoords; i++) {
+// object.texCoord[i] = new TexCoord((float) mySwap(dataInputStream.readInt()),
+// (float) mySwap(dataInputStream.readInt()));
+// // TODO:DELETE object.texVerts[i] = new Vec3(swap(dataInputStream.readFloat()),
+// // swap(dataInputStream.readFloat()),
+// // 0);
+//
+// previousChunk.bytesRead += 8;
+// }
+// }
+// catch (IOException e) {
+// System.err.println("Error: File IO error.");
+// return;
+// }
+// }
+
+ // mine
+ private void readUVCoordinates(Mesh mesh, Chunk root) throws IOException {
+ mesh.numTexCoords = readShort(root);
+
+ mesh.texCoords = new TexCoord[mesh.numTexCoords];
+ for (int i=0; i<mesh.numTexCoords; i++)
+ mesh.texCoords[i] = readPoint(root);
+ }
+
+// // Verified
+// private void readVertices(Mesh object, Chunk previousChunk)
+// {
+// try {
+// object.numOfVerts = myReadShort(dataInputStream);
+// if (object.numOfVerts < 0) {
+// throw new java.lang.RuntimeException("Number of vertices is Negative: " +object.numOfVerts);
+// }
+// // TODO:DELETE object.numOfVerts = swap(dataInputStream.readShort());
+// previousChunk.bytesRead += 2;
+//
+// object.verts = new Vec3[object.numOfVerts];
+// // Create a Bounds instance for this object
+// object.bounds = new Bounds();
+// for (int i=0; i<object.numOfVerts; i++) {
+// object.verts[i] = new Vec3(mySwap(dataInputStream.readInt()),
+// mySwap(dataInputStream.readInt()),
+// mySwap(dataInputStream.readInt()));
+// // TODO:DELETE object.verts[i] = new Vec3(swap(dataInputStream.readFloat()),
+// // swap(dataInputStream.readFloat()),
+// // swap(dataInputStream.readFloat()));
+//
+// // Calculate the bounds for this current object
+// object.bounds.calc(object.verts[i]);
+//
+// // Calculate the bounds for the entire model
+// bounds.calc(object.verts[i]);
+//
+// previousChunk.bytesRead += 12;
+// }
+//
+// // Calculate the center of the model
+// center.x = 0.5f * (bounds.max.x + bounds.min.x);
+// center.y = 0.5f * (bounds.max.y + bounds.min.y);
+// center.z = 0.5f * (bounds.max.z + bounds.min.z);
+// }
+// catch (IOException e) {
+// System.err.println("Error: File IO error in: Read Vertices");
+// return;
+// }
+// }
+
+ // mine
+ private void readVertices(Mesh object, Chunk previousChunk)
+ {
+ try {
+ object.numOfVerts = readShort(previousChunk);
+ if (object.numOfVerts < 0) {
+ throw new java.lang.RuntimeException("Number of vertices is Negative: " +object.numOfVerts);
+ }
+
+ object.vertices = new Vec4[object.numOfVerts];
+ // Create a Bounds instance for this object
+ //object.bounds = new Bounds();
+ for (int i=0; i<object.numOfVerts; i++) {
+ object.vertices[i] = readVertex(previousChunk);
+
+ // Calculate the bounds for this current object
+ object.bounds.calc(object.vertices[i]);
+
+ // Calculate the bounds for the entire model
+ bounds.calc(object.vertices[i]);
+ }
+
+ // Calculate the center of the model
+ center.x = 0.5f * (bounds.max.x + bounds.min.x);
+ center.y = 0.5f * (bounds.max.y + bounds.min.y);
+ center.z = 0.5f * (bounds.max.z + bounds.min.z);
+ }
+ catch (IOException e) {
+ System.err.println("Error: File IO error in: Read Vertices");
+ return;
+ }
+ }
+
+// // Verified
+// private void readFaceList(Mesh object, Chunk previousChunk)
+// {
+// short index = 0;
+//
+// object.numOfFaces = myReadShort(dataInputStream);
+// // TODO:DELETE object.numOfFaces = swap(dataInputStream.readShort());
+//
+// previousChunk.bytesRead += 2;
+//
+// object.faces = new Face[object.numOfFaces];
+// for (int i=0; i<object.numOfFaces; i++) {
+// object.faces[i] = new Face();
+// object.faces[i].vertIndex[0] = myReadShort(dataInputStream);
+// // TODO:DELETE object.faces[i].vertIndex[0] = swap(dataInputStream.readShort());
+// object.faces[i].vertIndex[1] = myReadShort(dataInputStream);
+// // TODO:DELETE object.faces[i].vertIndex[1] = swap(dataInputStream.readShort());
+// object.faces[i].vertIndex[2] = myReadShort(dataInputStream);
+// // TODO:DELETE object.faces[i].vertIndex[2] = swap(dataInputStream.readShort());
+//
+// object.faces[i].coordIndex[0] = object.faces[i].vertIndex[0];
+// object.faces[i].coordIndex[1] = object.faces[i].vertIndex[1];
+// object.faces[i].coordIndex[2] = object.faces[i].vertIndex[2];
+//
+// // Read in the extra face info
+// myReadShort(dataInputStream);
+// // TODO:DELETE dataInputStream.readShort();
+//
+// // Account for how much data was read in (4 * 2bytes)
+// previousChunk.bytesRead += 8;
+// }
+// }
+
+ private void readFaceList(Mesh object, Chunk root) throws IOException {
+ short index = 0;
+
+ object.numOfFaces = readShort(root);
+
+ object.faces = new Face[object.numOfFaces];
+ for (int i=0; i<object.numOfFaces; i++) {
+ object.faces[i] = new Face(3);
+ object.faces[i].vertIndex[0] = readShort(root);
+ object.faces[i].vertIndex[1] = readShort(root);
+ object.faces[i].vertIndex[2] = readShort(root);
+
+ object.faces[i].coordIndex[0] = object.faces[i].vertIndex[0];
+ object.faces[i].coordIndex[1] = object.faces[i].vertIndex[1];
+ object.faces[i].coordIndex[2] = object.faces[i].vertIndex[2];
+
+
+ // Read in the extra face info
+ readShort(root); // Flags (?)
+ }
+ }
+
+ /**
+ * Reads a color from the input file.
+ */
+ protected Color readColor(Chunk c) throws IOException {
+ Color color = null;
+
+ readChunkHeader(tempChunk);
+ switch(tempChunk.id) {
+ case TYPE_COLOR_F:
+ case TYPE_COLOR_LIN_F:
+ color = new Color(readFloat(c),readFloat(c),readFloat(c));
+ break;
+ case TYPE_COLOR_I:
+ case TYPE_COLOR_LIN_I:
+ color = new Color(readUnsignedByte(c),readUnsignedByte(c),readUnsignedByte(c));
+ }
+
+ c.bytesRead += tempChunk.bytesRead;
+
+ return color;
+ }
+
+ // Verified
+ private void computeNormals(Model model)
+ {
+ Vec4 vVector1 = new Vec4();
+ Vec4 vVector2 = new Vec4();
+ //Vec4 vNormal = new Vec4();
+ Vec4 vPoly[] = new Vec4[3];
+ int numObjs = model.getNumberOfMeshes();
+
+ for (int index=0; index<numObjs; index++) {
+ Mesh object = model.getMesh(index);
+
+ //Vec4 facenormals[] = new Vec4[object.numOfFaces];
+ Vec4 tempNormals[] = new Vec4[object.numOfFaces];
+ object.normals = new Vec4[object.numOfVerts];
+
+ for (int i=0; i<object.numOfFaces; i++) {
+ vPoly[0] = new Vec4(object.vertices[object.faces[i].vertIndex[0]]);
+ vPoly[1] = new Vec4(object.vertices[object.faces[i].vertIndex[1]]);
+ vPoly[2] = new Vec4(object.vertices[object.faces[i].vertIndex[2]]);
+
+ vVector1 = vPoly[1];
+ vVector2 = vPoly[2];
+ vVector1.x -= vPoly[0].x;
+ vVector1.y -= vPoly[0].y;
+ vVector1.z -= vPoly[0].z;
+ vVector2.x -= vPoly[0].x;
+ vVector2.y -= vPoly[0].y;
+ vVector2.z -= vPoly[0].z;
+
+ tempNormals[i] = new Vec4( vVector1.y*vVector2.z - vVector1.z*vVector2.y,
+ vVector1.z*vVector2.x - vVector1.x*vVector2.z,
+ vVector1.x*vVector2.y - vVector1.y*vVector2.x );
+ }
+
+ float vSumx = 0.0f;
+ float vSumy = 0.0f;
+ float vSumz = 0.0f;
+ int shared=0;
+
+ for (int i=0; i<object.numOfVerts; i++) {
+ vSumx = 0.0f;
+ vSumy = 0.0f;
+ vSumz = 0.0f;
+ shared=0;
+
+ for (int j=0; j<object.numOfFaces; j++) {
+ if (object.faces[j].vertIndex[0] == i ||
+ object.faces[j].vertIndex[1] == i ||
+ object.faces[j].vertIndex[2] == i)
+ {
+ //////// temp ////////////
+ object.faces[j].normalIndex[0] = i;
+ object.faces[j].normalIndex[1] = i;
+ object.faces[j].normalIndex[2] = i;
+ //////////////////////////
+
+
+ // Add the vectors vSum and tempNormals
+ vSumx += tempNormals[j].x;
+ vSumy += tempNormals[j].y;
+ vSumz += tempNormals[j].z;
+ shared++;
+ }
+ }
+
+ // Divide the vector vSum by -shared
+ vSumx /= -shared;
+ vSumy /= -shared;
+ vSumz /= -shared;
+
+ object.normals[i] = new Vec4(vSumx, vSumy, vSumz);
+
+ // Normalize
+ float mag = (float)Math.sqrt(object.normals[i].x*object.normals[i].x +
+ object.normals[i].y*object.normals[i].y +
+ object.normals[i].z*object.normals[i].z);
+
+ object.normals[i].x /= mag;
+ object.normals[i].y /= mag;
+ object.normals[i].z /= mag;
+ }
+ }
+ }
+
+ /**
+ * Reads a String value from the input file.
+ */
+ protected String readString(Chunk c) throws IOException {
+ DataInputStream in = dataInputStream;
+ StringBuffer sb = new StringBuffer("");
+ c.bytesRead++;
+ byte ch = in.readByte();
+ while(ch != (byte)0) {
+ sb.append((char)ch);
+ c.bytesRead++;
+ ch = in.readByte();
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Reads a percentage value from the input file. Returns as a float
+ * between 0 and 1.
+ */
+ protected float readPercentage(Chunk c) throws IOException {
+ float value = 0;
+ readChunkHeader(tempChunk);
+
+ if (tempChunk.id == TYPE_PERCENT_I) {
+ value = (float)readShort(c) / 100.0f;
+ } else if(tempChunk.id == TYPE_PERCENT_F) {
+ value = readFloat(c);
+ }
+
+ c.bytesRead += tempChunk.bytesRead;
+
+ return value;
+ }
+
+ private float readFloat(Chunk c) throws IOException {
+ return Float.intBitsToFloat(readInt(c));
+ }
+
+ /**
+ * Reads an unsigned byte (8-bit) value from the input file.
+ */
+ protected int readUnsignedByte(Chunk c) throws IOException {
+ c.bytesRead++;
+ return dataInputStream.readUnsignedByte();
+ }
+
+ protected int readByte(Chunk c) throws IOException {
+ c.bytesRead++;
+ return dataInputStream.read() & 0xff;
+ }
+
+ /**
+ * Reads an int (32-bit) value from the input file.
+ */
+ private int readInt(Chunk c) throws IOException {
+ DataInputStream in = dataInputStream;
+ c.bytesRead += 4;
+ return (int)(in.read() + (in.read() << 8) + (in.read() << 16) + (in.read() << 24));
+ }
+
+ /**
+ * Reads a short (16-bit) value from the input file.
+ */
+ protected int readShort(Chunk c) throws IOException {
+// c.bytesRead += 2;
+ int b1 = readByte(c);
+ int b2 = readByte(c) << 8;
+
+ return b1 | b2;
+// return (short)(dataInputStream.read()+(dataInputStream.read() << 8));
+ }
+
+ private Vec4 readVertex(Chunk c) throws IOException {
+ return new Vec4(readFloat(c), readFloat(c), readFloat(c));
+ }
+
+ private TexCoord readPoint(Chunk c) throws IOException {
+ return new TexCoord(readFloat(c), readFloat(c));
+ }
+
+// private static short swap(short value)
+// {
+// int b1 = value & 0xff;
+// int b2 = (value >> 8) & 0xff;
+//
+// return (short) (b1 << 8 | b2 << 0);
+// }
+//
+// private static int getNextByte(DataInputStream stream) {
+// try {
+// return stream.read() & 0xff;
+// } catch (Exception e) {
+// return 0;
+// }
+// }
+//
+// private static int myReadShort(DataInputStream stream) {
+// int b1 = getNextByte(stream);
+// int b2 = getNextByte(stream) << 8;
+//
+// return b1 | b2;
+// }
+//
+// private static int swap(int value)
+// {
+// int b1 = (value >> 0) & 0xff;
+// int b2 = (value >> 8) & 0xff;
+// int b3 = (value >> 16) & 0xff;
+// int b4 = (value >> 24) & 0xff;
+//
+// return b1 << 24 | b2 << 16 | b3 << 8 | b4 << 0;
+// }
+//
+// private static long swap(long value)
+// {
+// long b1 = (value >> 0) & 0xff;
+// long b2 = (value >> 8) & 0xff;
+// long b3 = (value >> 16) & 0xff;
+// long b4 = (value >> 24) & 0xff;
+// long b5 = (value >> 32) & 0xff;
+// long b6 = (value >> 40) & 0xff;
+// long b7 = (value >> 48) & 0xff;
+// long b8 = (value >> 56) & 0xff;
+//
+// return b1 << 56 | b2 << 48 | b3 << 40 | b4 << 32 |
+// b5 << 24 | b6 << 16 | b7 << 8 | b8 << 0;
+// }
+//
+// private static float swap(float value)
+// {
+// int intValue = Float.floatToIntBits(value);
+// intValue = swap(intValue);
+// return Float.intBitsToFloat(intValue);
+// }
+//
+// private static float mySwap(int value) {
+// int intValue = swap(value);
+// return Float.intBitsToFloat(intValue);
+// }
+//
+// private static double swap(double value)
+// {
+// long longValue = Double.doubleToLongBits(value);
+// longValue = swap(longValue);
+// return Double.longBitsToDouble(longValue);
+// }
+
+ private class Chunk {
+ public int id = 0;
+ public int length = 0;
+ public int bytesRead = 0;
+ }
+}
diff --git a/src/net/java/joglutils/model/loader/WaveFrontLoader.java b/src/net/java/joglutils/model/loader/WaveFrontLoader.java
new file mode 100644
index 0000000..f3eeb6b
--- /dev/null
+++ b/src/net/java/joglutils/model/loader/WaveFrontLoader.java
@@ -0,0 +1,452 @@
+/*
+ * myWaveFrontLoader.java
+ *
+ * Created on March 16, 2008, 8:57 PM
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+package net.java.joglutils.model.loader;
+
+import java.awt.Color;
+import java.io.BufferedReader;
+import java.io.DataInputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Vector;
+import net.java.joglutils.model.ModelLoadException;
+import net.java.joglutils.model.ResourceRetriever;
+import net.java.joglutils.model.geometry.Bounds;
+import net.java.joglutils.model.geometry.Face;
+import net.java.joglutils.model.geometry.Material;
+import net.java.joglutils.model.geometry.Mesh;
+import net.java.joglutils.model.geometry.Model;
+import net.java.joglutils.model.geometry.TexCoord;
+import net.java.joglutils.model.geometry.Vec4;
+
+/**
+ *
+ * @author RodgersGB
+ */
+public class WaveFrontLoader implements iLoader {
+ public static final String VERTEX_DATA = "v ";
+ public static final String NORMAL_DATA = "vn ";
+ public static final String TEXTURE_DATA = "vt ";
+ public static final String FACE_DATA = "f ";
+ public static final String SMOOTHING_GROUP = "s ";
+ public static final String GROUP = "g ";
+ public static final String OBJECT = "o ";
+ public static final String COMMENT = "#";
+ public static final String EMPTY = "";
+
+ int vertexTotal = 0;
+ int textureTotal = 0;
+ int normalTotal = 0;
+
+ private DataInputStream dataInputStream;
+ // the model
+ private Model model = null;
+ /** Bounds of the model */
+ private Bounds bounds = new Bounds();
+ /** Center of the model */
+ private Vec4 center = new Vec4(0.0f, 0.0f, 0.0f);
+ private String baseDir = null;
+
+ /** Creates a new instance of myWaveFrontLoader */
+ public WaveFrontLoader() {
+ }
+
+ int numComments = 0;
+ public Model load(String path) throws ModelLoadException {
+ model = new Model(path);
+ Mesh mesh = null;
+
+ baseDir = "";
+ String tokens[] = path.split("/");
+ for(int i = 0; i < tokens.length - 1; i++) {
+ baseDir += tokens[i] + "/";
+ }
+
+ InputStream stream = null;
+ try {
+ stream = ResourceRetriever.getResourceAsInputStream(model.getSource());
+ if (stream == null) {
+ throw new ModelLoadException("Stream is null");
+ }
+ } catch(IOException e) {
+ throw new ModelLoadException("Caught IO exception: " + e);
+ }
+
+ try {
+ // Open a file handle and read the models data
+ BufferedReader br = new BufferedReader(new InputStreamReader(stream));
+ String line = null;
+ while((line = br.readLine()) != null) {
+ if (lineIs(COMMENT, line)) {
+ // ignore comments
+ numComments++;
+ continue;
+ }
+
+ if (line.isEmpty()) {
+ // igonore empty lines
+ continue;
+ }
+
+ if (lineIs(GROUP, line)) {
+ if (mesh == null) {
+ mesh = new Mesh();
+ }
+
+ mesh.name = parseName(line);
+ }
+
+ if (lineIs(OBJECT, line)) {
+
+ }
+
+ if (lineIs(VERTEX_DATA, line)) {
+ if (mesh == null)
+ mesh = new Mesh();
+
+ mesh.vertices = getPoints(VERTEX_DATA, line, br);
+ mesh.numOfVerts = mesh.vertices.length;
+ }
+
+ if (lineIs(TEXTURE_DATA, line)) {
+ if (mesh == null)
+ mesh = new Mesh();
+
+ mesh.texCoords = getTexCoords(TEXTURE_DATA, line, br);
+ mesh.hasTexture = true;
+ mesh.numTexCoords = mesh.texCoords.length;
+ }
+
+ if (lineIs(NORMAL_DATA, line)) {
+ if (mesh == null)
+ mesh = new Mesh();
+
+ mesh.normals = getPoints(NORMAL_DATA, line, br);
+ }
+
+ if (lineIs(FACE_DATA, line)) {
+ if (mesh == null)
+ mesh = new Mesh();
+
+ mesh.faces = getFaces(line, mesh, br);
+ mesh.numOfFaces = mesh.faces.length;
+
+ model.addMesh(mesh);
+ mesh = new Mesh();
+ }
+
+ if (lineIs("mtllib ", line)){
+ processMaterialLib(line);
+ }
+
+ if (lineIs("usemtl ", line)) {
+ processMaterialType(line, mesh);
+ }
+ }
+ }
+ catch (IOException e) {
+ throw new ModelLoadException("Failed to find or read OBJ: " + stream);
+ }
+ model.addMesh(mesh);
+ mesh = null;
+
+ System.out.println(this.bounds.toString());
+ model.setBounds(this.bounds);
+ model.setCenterPoint(this.center);
+
+ return model;
+ }
+
+ private boolean lineIs(String type, String line) {
+ return line.startsWith(type);
+ }
+
+ private Vec4[] getPoints(String prefix, String currLine, BufferedReader br) throws IOException {
+ Vector<Vec4> points = new Vector<Vec4>();
+ boolean isVertices = prefix.equals(VERTEX_DATA);
+
+ // we've already read in the first line (currLine)
+ // so go ahead and parse it
+ points.add(parsePoint(currLine));
+
+ // parse through the rest of the points
+ String line = null;
+ while((line = br.readLine()) != null) {
+ if (!lineIs(prefix, line))
+ break;
+
+ Vec4 point = parsePoint(line);
+ if (isVertices) {
+ // Calculate the bounds for the entire model
+ bounds.calc(point);
+ }
+ points.add(point);
+ }
+
+ if (isVertices) {
+ // Calculate the center of the model
+ center.x = 0.5f * (bounds.max.x + bounds.min.x);
+ center.y = 0.5f * (bounds.max.y + bounds.min.y);
+ center.z = 0.5f * (bounds.max.z + bounds.min.z);
+ }
+
+ // return the points
+ Vec4 values[] = new Vec4[points.size()];
+ return points.toArray(values);
+ }
+
+ private TexCoord[] getTexCoords(String prefix, String currLine, BufferedReader br) throws IOException {
+ Vector<TexCoord> texCoords = new Vector<TexCoord>();
+
+ String s[] = currLine.split("\\s+");
+ TexCoord texCoord = new TexCoord();
+ texCoord.u = Float.parseFloat(s[1]);
+ texCoord.v = Float.parseFloat(s[2]);
+
+ texCoords.add(texCoord);
+
+ // parse through the rest of the points
+ String line = null;
+ while((line = br.readLine()) != null) {
+ if (!lineIs(prefix, line))
+ break;
+
+ s = line.split("\\s+");
+
+ texCoord = new TexCoord();
+ texCoord.u = Float.parseFloat(s[1]);
+ texCoord.v = Float.parseFloat(s[2]);
+
+ texCoords.add(texCoord);
+ }
+
+ // return the texture coordinates
+ TexCoord values[] = new TexCoord[texCoords.size()];
+ return texCoords.toArray(values);
+ }
+
+ private Face[] getFaces(String currLine, Mesh mesh, BufferedReader br) throws IOException {
+ Vector<Face> faces = new Vector<Face>();
+
+ faces.add(parseFace(currLine));
+
+ // parse through the rest of the faces
+ String line = null;
+ while((line = br.readLine()) != null) {
+ if (lineIs(SMOOTHING_GROUP, line)) {
+ continue;
+ }
+ else if (lineIs("usemtl ", line)) {
+ processMaterialType(line, mesh);
+ }
+
+ else if (lineIs(FACE_DATA, line)) {
+ faces.add(parseFace(line));
+ }
+
+ else
+ break;
+ }
+
+ // return the faces
+ Face values[] = new Face[faces.size()];
+ return faces.toArray(values);
+ }
+
+ private Face parseFace(String line) {
+ String s[] = line.split("\\s+");
+ if (line.contains("//")) { // Pattern is present if obj has no texture
+ for (int loop=1; loop < s.length; loop++) {
+ s[loop] = s[loop].replaceAll("//","/-1/"); //insert -1 for missing vt data
+ }
+ }
+
+ int vdata[] = new int[s.length-1];
+ int vtdata[] = new int[s.length-1];
+ int vndata[] = new int[s.length-1];
+ Face face = new Face(s.length - 1);
+
+ for (int loop = 1; loop < s.length; loop++) {
+ String s1 = s[loop];
+ String[] temp = s1.split("/");
+
+ if (temp.length > 0) { // we have vertex data
+ if (Integer.valueOf(temp[0]) < 0) {
+ //TODO handle relative vertex data
+ }
+ else {
+ face.vertIndex[loop-1] = Integer.valueOf(temp[0]) - 1 - this.vertexTotal;
+ //System.out.println("found vertex index: " + face.vertIndex[loop-1]);
+ }
+ }
+
+ if (temp.length > 1) { // we have texture data
+ if(Integer.valueOf(temp[1]) < 0) {
+ face.coordIndex[loop - 1] = 0;
+ }
+ else {
+ face.coordIndex[loop - 1] = Integer.valueOf(temp[1]) - 1 - this.textureTotal;
+ //System.out.println("found texture index: " + face.coordIndex[loop-1]);
+ }
+ }
+
+ if (temp.length > 2) { // we have normal data
+ face.normalIndex[loop-1] = Integer.valueOf(temp[2]) - 1 - this.normalTotal;
+ //System.out.println("found normal index: " + face.normalIndex[loop-1]);
+ }
+ }
+
+ return face;
+ }
+
+ private Vec4 parsePoint(String line) {
+ Vec4 point = new Vec4();
+
+ final String s[] = line.split("\\s+");
+
+ point.x = Float.parseFloat(s[1]);
+ point.y = Float.parseFloat(s[2]);
+ point.z = Float.parseFloat(s[3]);
+
+ return point;
+ }
+
+ private String parseName(String line) {
+ String name;
+
+ final String s[] = line.split("\\s+");
+
+ name = s[1];
+
+ return name;
+ }
+
+ private void processMaterialLib(String mtlData) {
+ String s[] = mtlData.split("\\s+");
+
+ Material mat = new Material();
+ InputStream stream = null;
+ try {
+ stream = ResourceRetriever.getResourceAsInputStream(baseDir + s[1]);
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+
+ if(stream == null) {
+ try {
+ stream = new FileInputStream(baseDir + s[1]);
+ } catch (FileNotFoundException ex) {
+ ex.printStackTrace();
+ return;
+ }
+ }
+ loadMaterialFile(stream);
+ }
+
+ private void processMaterialType(String line, Mesh mesh) {
+ String s[] = line.split("\\s+");
+
+ int materialID = -1;
+ boolean hasTexture = false;
+
+ for(int i = 0; i < model.getNumberOfMaterials(); i++){
+ Material mat = model.getMaterial(i);
+
+ if(mat.strName.equals(s[1])){
+ materialID = i;
+ if(mat.strFile != null)
+ hasTexture = true;
+ else
+ hasTexture = false;
+ break;
+ }
+ }
+
+ if(materialID != -1)
+ mesh.materialID = materialID;
+ }
+
+ public Material loadMaterialFile(InputStream stream) {
+ Material mat = null;
+ int texId = 0;
+
+ try {
+ BufferedReader br = new BufferedReader(new InputStreamReader(stream));
+ String line;
+
+ while((line = br.readLine()) != null){
+
+ String parts[] = line.trim().split("\\s+");
+
+ if(parts[0].equals("newmtl")){
+ if(mat != null)
+ model.addMaterial(mat);
+
+ mat = new Material();
+ mat.strName = parts[1];
+ mat.textureId = texId++;
+
+ } else if(parts[0].equals("Ks"))
+ mat.specularColor = parseColor(line);
+
+ else if(parts[0].equals("Ns")) {
+ if (parts.length > 1)
+ mat.shininess = Float.valueOf(parts[1]);
+ }
+ else if(parts[0].equals("d"))
+ ;
+ else if(parts[0].equals("illum"))
+ ;
+ else if(parts[0].equals("Ka"))
+ mat.ambientColor = parseColor(line);
+ else if(parts[0].equals("Kd"))
+ mat.diffuseColor = parseColor(line);
+ else if(parts[0].equals("map_Kd")) {
+ if (parts.length > 1)
+ mat.strFile = /*baseDir + */parts[1];
+ }
+
+ else if(parts[0].equals("map_Ka")) {
+ if (parts.length > 1)
+ mat.strFile = /*baseDir + */parts[1];
+ }
+ }
+
+ br.close();
+ model.addMaterial(mat);
+
+ } catch (FileNotFoundException ex) {
+ ex.printStackTrace();
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ return mat;
+ }
+
+ private Color parseColor(String line) {
+ String parts[] = line.trim().split("\\s+");
+
+ Color color = new Color(Float.valueOf(parts[1]),
+ Float.valueOf(parts[2]),Float.valueOf(parts[3]));
+
+ return color;
+ }
+
+ public static void main(String[] args) {
+ WaveFrontLoader loader = new WaveFrontLoader();
+ try {
+ loader.load("C:\\Documents and Settings\\RodgersGB\\My Documents\\Projects\\JOGLUTILS\\src\\net\\java\\joglutils\\examples\\models\\obj\\penguin.obj");
+ } catch (ModelLoadException ex) {
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/src/net/java/joglutils/model/loader/iLoader.java b/src/net/java/joglutils/model/loader/iLoader.java
new file mode 100644
index 0000000..9405018
--- /dev/null
+++ b/src/net/java/joglutils/model/loader/iLoader.java
@@ -0,0 +1,21 @@
+/*
+ * iLoader.java
+ *
+ * Created on February 27, 2008, 10:36 PM
+ *
+ * To change this template, choose Tools | Template Manager
+ * and open the template in the editor.
+ */
+
+package net.java.joglutils.model.loader;
+
+import net.java.joglutils.model.ModelLoadException;
+import net.java.joglutils.model.geometry.Model;
+
+/**
+ *
+ * @author RodgersGB
+ */
+public interface iLoader {
+ public Model load(String path) throws ModelLoadException;
+}