diff options
Diffstat (limited to 'engine/src/core-plugins/com/jme3/scene/plugins')
-rw-r--r-- | engine/src/core-plugins/com/jme3/scene/plugins/MTLLoader.java | 325 | ||||
-rw-r--r-- | engine/src/core-plugins/com/jme3/scene/plugins/OBJLoader.java | 593 |
2 files changed, 918 insertions, 0 deletions
diff --git a/engine/src/core-plugins/com/jme3/scene/plugins/MTLLoader.java b/engine/src/core-plugins/com/jme3/scene/plugins/MTLLoader.java new file mode 100644 index 0000000..1f701cd --- /dev/null +++ b/engine/src/core-plugins/com/jme3/scene/plugins/MTLLoader.java @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions 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. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.scene.plugins; + +import com.jme3.asset.*; +import com.jme3.material.Material; +import com.jme3.material.MaterialList; +import com.jme3.material.RenderState.BlendMode; +import com.jme3.math.ColorRGBA; +import com.jme3.texture.Texture; +import com.jme3.texture.Texture.WrapMode; +import com.jme3.texture.Texture2D; +import com.jme3.util.PlaceholderAssets; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.Locale; +import java.util.NoSuchElementException; +import java.util.Scanner; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class MTLLoader implements AssetLoader { + + private static final Logger logger = Logger.getLogger(MTLLoader.class.getName()); + + protected Scanner scan; + protected MaterialList matList; + //protected Material material; + protected AssetManager assetManager; + protected String folderName; + protected AssetKey key; + + protected Texture diffuseMap, normalMap, specularMap, alphaMap; + protected ColorRGBA ambient = new ColorRGBA(); + protected ColorRGBA diffuse = new ColorRGBA(); + protected ColorRGBA specular = new ColorRGBA(); + protected float shininess = 16; + protected boolean shadeless; + protected String matName; + protected float alpha = 1; + protected boolean transparent = false; + protected boolean disallowTransparency = false; + protected boolean disallowAmbient = false; + protected boolean disallowSpecular = false; + + public void reset(){ + scan = null; + matList = null; +// material = null; + + resetMaterial(); + } + + protected ColorRGBA readColor(){ + ColorRGBA v = new ColorRGBA(); + v.set(scan.nextFloat(), scan.nextFloat(), scan.nextFloat(), 1.0f); + return v; + } + + protected String nextStatement(){ + scan.useDelimiter("\n"); + String result = scan.next(); + scan.useDelimiter("\\p{javaWhitespace}+"); + return result; + } + + protected boolean skipLine(){ + try { + scan.skip(".*\r{0,1}\n"); + return true; + } catch (NoSuchElementException ex){ + // EOF + return false; + } + } + + protected void resetMaterial(){ + ambient.set(ColorRGBA.DarkGray); + diffuse.set(ColorRGBA.LightGray); + specular.set(ColorRGBA.Black); + shininess = 16; + disallowTransparency = false; + disallowAmbient = false; + disallowSpecular = false; + shadeless = false; + transparent = false; + matName = null; + diffuseMap = null; + specularMap = null; + normalMap = null; + alphaMap = null; + alpha = 1; + } + + protected void createMaterial(){ + Material material; + + if (alpha < 1f && transparent && !disallowTransparency){ + diffuse.a = alpha; + } + + if (shadeless){ + material = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md"); + material.setColor("Color", diffuse.clone()); + material.setTexture("ColorMap", diffuseMap); + // TODO: Add handling for alpha map? + }else{ + material = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + material.setBoolean("UseMaterialColors", true); + material.setColor("Ambient", ambient.clone()); + material.setColor("Diffuse", diffuse.clone()); + material.setColor("Specular", specular.clone()); + material.setFloat("Shininess", shininess); // prevents "premature culling" bug + + if (diffuseMap != null) material.setTexture("DiffuseMap", diffuseMap); + if (specularMap != null) material.setTexture("SpecularMap", specularMap); + if (normalMap != null) material.setTexture("NormalMap", normalMap); + if (alphaMap != null) material.setTexture("AlphaMap", alphaMap); + } + + if (transparent && !disallowTransparency){ + material.setTransparent(true); + material.getAdditionalRenderState().setBlendMode(BlendMode.Alpha); + material.getAdditionalRenderState().setAlphaTest(true); + material.getAdditionalRenderState().setAlphaFallOff(0.01f); + } + + matList.put(matName, material); + } + + protected void startMaterial(String name){ + if (matName != null){ + // material is already in cache, generate it + createMaterial(); + } + + // now, reset the params and set the name to start a new material + resetMaterial(); + matName = name; + } + + protected Texture loadTexture(String path){ + String[] split = path.trim().split("\\p{javaWhitespace}+"); + + // will crash if path is an empty string + path = split[split.length-1]; + + String name = new File(path).getName(); + TextureKey texKey = new TextureKey(folderName + name); + texKey.setGenerateMips(true); + Texture texture; + try { + texture = assetManager.loadTexture(texKey); + texture.setWrap(WrapMode.Repeat); + } catch (AssetNotFoundException ex){ + logger.log(Level.WARNING, "Cannot locate {0} for material {1}", new Object[]{texKey, key}); + texture = new Texture2D(PlaceholderAssets.getPlaceholderImage()); + } + return texture; + } + + protected boolean readLine(){ + if (!scan.hasNext()){ + return false; + } + + String cmd = scan.next().toLowerCase(); + if (cmd.startsWith("#")){ + // skip entire comment until next line + return skipLine(); + }else if (cmd.equals("newmtl")){ + String name = scan.next(); + startMaterial(name); + }else if (cmd.equals("ka")){ + ambient.set(readColor()); + }else if (cmd.equals("kd")){ + diffuse.set(readColor()); + }else if (cmd.equals("ks")){ + specular.set(readColor()); + }else if (cmd.equals("ns")){ + float shiny = scan.nextFloat(); + if (shiny >= 1){ + shininess = shiny; /* (128f / 1000f)*/ + if (specular.equals(ColorRGBA.Black)){ + specular.set(ColorRGBA.White); + } + }else{ + // For some reason blender likes to export Ns 0 statements + // Ignore Ns 0 instead of setting it + } + + }else if (cmd.equals("d") || cmd.equals("tr")){ + alpha = scan.nextFloat(); + transparent = true; + }else if (cmd.equals("map_ka")){ + // ignore it for now + return skipLine(); + }else if (cmd.equals("map_kd")){ + String path = nextStatement(); + diffuseMap = loadTexture(path); + }else if (cmd.equals("map_bump") || cmd.equals("bump")){ + if (normalMap == null){ + String path = nextStatement(); + normalMap = loadTexture(path); + } + }else if (cmd.equals("map_ks")){ + String path = nextStatement(); + specularMap = loadTexture(path); + if (specularMap != null){ + // NOTE: since specular color is modulated with specmap + // make sure we have it set + if (specular.equals(ColorRGBA.Black)){ + specular.set(ColorRGBA.White); + } + } + }else if (cmd.equals("map_d")){ + String path = scan.next(); + alphaMap = loadTexture(path); + transparent = true; + }else if (cmd.equals("illum")){ + int mode = scan.nextInt(); + + switch (mode){ + case 0: + // no lighting + shadeless = true; + disallowTransparency = true; + break; + case 1: + disallowSpecular = true; + disallowTransparency = true; + break; + case 2: + case 3: + case 5: + case 8: + disallowTransparency = true; + break; + case 4: + case 6: + case 7: + case 9: + // Enable transparency + // Works best if diffuse map has an alpha channel + transparent = true; + break; + } + }else if (cmd.equals("ke") || cmd.equals("ni")){ + // Ni: index of refraction - unsupported in jME + // Ke: emission color + return skipLine(); + }else{ + logger.log(Level.WARNING, "Unknown statement in MTL! {0}", cmd); + return skipLine(); + } + + return true; + } + + @SuppressWarnings("empty-statement") + public Object load(AssetInfo info) throws IOException{ + reset(); + + this.key = info.getKey(); + this.assetManager = info.getManager(); + folderName = info.getKey().getFolder(); + matList = new MaterialList(); + + InputStream in = null; + try { + in = info.openStream(); + scan = new Scanner(in); + scan.useLocale(Locale.US); + + while (readLine()); + } finally { + if (in != null){ + in.close(); + } + } + + if (matName != null){ + // still have a material in the vars + createMaterial(); + resetMaterial(); + } + + MaterialList list = matList; + + + + return list; + } +} diff --git a/engine/src/core-plugins/com/jme3/scene/plugins/OBJLoader.java b/engine/src/core-plugins/com/jme3/scene/plugins/OBJLoader.java new file mode 100644 index 0000000..3ce7f52 --- /dev/null +++ b/engine/src/core-plugins/com/jme3/scene/plugins/OBJLoader.java @@ -0,0 +1,593 @@ +/* + * Copyright (c) 2009-2010 jMonkeyEngine + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions 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. + * + * * Neither the name of 'jMonkeyEngine' nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.jme3.scene.plugins; + +import com.jme3.asset.*; +import com.jme3.material.Material; +import com.jme3.material.MaterialList; +import com.jme3.math.Vector2f; +import com.jme3.math.Vector3f; +import com.jme3.renderer.queue.RenderQueue.Bucket; +import com.jme3.scene.Mesh.Mode; +import com.jme3.scene.*; +import com.jme3.scene.VertexBuffer.Type; +import com.jme3.scene.mesh.IndexBuffer; +import com.jme3.scene.mesh.IndexIntBuffer; +import com.jme3.scene.mesh.IndexShortBuffer; +import com.jme3.util.BufferUtils; +import com.jme3.util.IntMap; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; +import java.util.Map.Entry; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Reads OBJ format models. + */ +public final class OBJLoader implements AssetLoader { + + private static final Logger logger = Logger.getLogger(OBJLoader.class.getName()); + + protected final ArrayList<Vector3f> verts = new ArrayList<Vector3f>(); + protected final ArrayList<Vector2f> texCoords = new ArrayList<Vector2f>(); + protected final ArrayList<Vector3f> norms = new ArrayList<Vector3f>(); + + protected final ArrayList<Face> faces = new ArrayList<Face>(); + protected final HashMap<String, ArrayList<Face>> matFaces = new HashMap<String, ArrayList<Face>>(); + + protected String currentMatName; + protected String currentObjectName; + + protected final HashMap<Vertex, Integer> vertIndexMap = new HashMap<Vertex, Integer>(100); + protected final IntMap<Vertex> indexVertMap = new IntMap<Vertex>(100); + protected int curIndex = 0; + protected int objectIndex = 0; + protected int geomIndex = 0; + + protected Scanner scan; + protected ModelKey key; + protected AssetManager assetManager; + protected MaterialList matList; + + protected String objName; + protected Node objNode; + + protected static class Vertex { + + Vector3f v; + Vector2f vt; + Vector3f vn; + int index; + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Vertex other = (Vertex) obj; + if (this.v != other.v && (this.v == null || !this.v.equals(other.v))) { + return false; + } + if (this.vt != other.vt && (this.vt == null || !this.vt.equals(other.vt))) { + return false; + } + if (this.vn != other.vn && (this.vn == null || !this.vn.equals(other.vn))) { + return false; + } + return true; + } + + @Override + public int hashCode() { + int hash = 5; + hash = 53 * hash + (this.v != null ? this.v.hashCode() : 0); + hash = 53 * hash + (this.vt != null ? this.vt.hashCode() : 0); + hash = 53 * hash + (this.vn != null ? this.vn.hashCode() : 0); + return hash; + } + } + + protected static class Face { + Vertex[] verticies; + } + + protected class ObjectGroup { + + final String objectName; + + public ObjectGroup(String objectName){ + this.objectName = objectName; + } + + public Spatial createGeometry(){ + Node groupNode = new Node(objectName); + +// if (matFaces.size() > 0){ +// for (Entry<String, ArrayList<Face>> entry : matFaces.entrySet()){ +// ArrayList<Face> materialFaces = entry.getValue(); +// if (materialFaces.size() > 0){ +// Geometry geom = createGeometry(materialFaces, entry.getKey()); +// objNode.attachChild(geom); +// } +// } +// }else if (faces.size() > 0){ +// // generate final geometry +// Geometry geom = createGeometry(faces, null); +// objNode.attachChild(geom); +// } + + return groupNode; + } + } + + public void reset(){ + verts.clear(); + texCoords.clear(); + norms.clear(); + faces.clear(); + matFaces.clear(); + + vertIndexMap.clear(); + indexVertMap.clear(); + + currentMatName = null; + matList = null; + curIndex = 0; + geomIndex = 0; + scan = null; + } + + protected void findVertexIndex(Vertex vert){ + Integer index = vertIndexMap.get(vert); + if (index != null){ + vert.index = index.intValue(); + }else{ + vert.index = curIndex++; + vertIndexMap.put(vert, vert.index); + indexVertMap.put(vert.index, vert); + } + } + + protected Face[] quadToTriangle(Face f){ + assert f.verticies.length == 4; + + Face[] t = new Face[]{ new Face(), new Face() }; + t[0].verticies = new Vertex[3]; + t[1].verticies = new Vertex[3]; + + Vertex v0 = f.verticies[0]; + Vertex v1 = f.verticies[1]; + Vertex v2 = f.verticies[2]; + Vertex v3 = f.verticies[3]; + + // find the pair of verticies that is closest to each over + // v0 and v2 + // OR + // v1 and v3 + float d1 = v0.v.distanceSquared(v2.v); + float d2 = v1.v.distanceSquared(v3.v); + if (d1 < d2){ + // put an edge in v0, v2 + t[0].verticies[0] = v0; + t[0].verticies[1] = v1; + t[0].verticies[2] = v3; + + t[1].verticies[0] = v1; + t[1].verticies[1] = v2; + t[1].verticies[2] = v3; + }else{ + // put an edge in v1, v3 + t[0].verticies[0] = v0; + t[0].verticies[1] = v1; + t[0].verticies[2] = v2; + + t[1].verticies[0] = v0; + t[1].verticies[1] = v2; + t[1].verticies[2] = v3; + } + + return t; + } + + private ArrayList<Vertex> vertList = new ArrayList<Vertex>(); + + protected void readFace(){ + Face f = new Face(); + vertList.clear(); + + String line = scan.nextLine().trim(); + String[] verticies = line.split("\\s"); + for (String vertex : verticies){ + int v = 0; + int vt = 0; + int vn = 0; + + String[] split = vertex.split("/"); + if (split.length == 1){ + v = Integer.parseInt(split[0].trim()); + }else if (split.length == 2){ + v = Integer.parseInt(split[0].trim()); + vt = Integer.parseInt(split[1].trim()); + }else if (split.length == 3 && !split[1].equals("")){ + v = Integer.parseInt(split[0].trim()); + vt = Integer.parseInt(split[1].trim()); + vn = Integer.parseInt(split[2].trim()); + }else if (split.length == 3){ + v = Integer.parseInt(split[0].trim()); + vn = Integer.parseInt(split[2].trim()); + } + + Vertex vx = new Vertex(); + vx.v = verts.get(v - 1); + + if (vt > 0) + vx.vt = texCoords.get(vt - 1); + + if (vn > 0) + vx.vn = norms.get(vn - 1); + + vertList.add(vx); + } + + if (vertList.size() > 4 || vertList.size() <= 2) + logger.warning("Edge or polygon detected in OBJ. Ignored."); + + f.verticies = new Vertex[vertList.size()]; + for (int i = 0; i < vertList.size(); i++){ + f.verticies[i] = vertList.get(i); + } + + if (matList != null && matFaces.containsKey(currentMatName)){ + matFaces.get(currentMatName).add(f); + }else{ + faces.add(f); // faces that belong to the default material + } + } + + protected Vector3f readVector3(){ + Vector3f v = new Vector3f(); + + v.set(Float.parseFloat(scan.next()), + Float.parseFloat(scan.next()), + Float.parseFloat(scan.next())); + + return v; + } + + protected Vector2f readVector2(){ + Vector2f v = new Vector2f(); + + String line = scan.nextLine().trim(); + String[] split = line.split("\\s"); + v.setX( Float.parseFloat(split[0].trim()) ); + v.setY( Float.parseFloat(split[1].trim()) ); + +// v.setX(scan.nextFloat()); +// if (scan.hasNextFloat()){ +// v.setY(scan.nextFloat()); +// if (scan.hasNextFloat()){ +// scan.nextFloat(); // ignore +// } +// } + + return v; + } + + protected void loadMtlLib(String name) throws IOException{ + if (!name.toLowerCase().endsWith(".mtl")) + throw new IOException("Expected .mtl file! Got: " + name); + + // NOTE: Cut off any relative/absolute paths + name = new File(name).getName(); + AssetKey mtlKey = new AssetKey(key.getFolder() + name); + try { + matList = (MaterialList) assetManager.loadAsset(mtlKey); + } catch (AssetNotFoundException ex){ + logger.log(Level.WARNING, "Cannot locate {0} for model {1}", new Object[]{name, key}); + } + + if (matList != null){ + // create face lists for every material + for (String matName : matList.keySet()){ + matFaces.put(matName, new ArrayList<Face>()); + } + } + } + + protected boolean nextStatement(){ + try { + scan.skip(".*\r{0,1}\n"); + return true; + } catch (NoSuchElementException ex){ + // EOF + return false; + } + } + + protected boolean readLine() throws IOException{ + if (!scan.hasNext()){ + return false; + } + + String cmd = scan.next(); + if (cmd.startsWith("#")){ + // skip entire comment until next line + return nextStatement(); + }else if (cmd.equals("v")){ + // vertex position + verts.add(readVector3()); + }else if (cmd.equals("vn")){ + // vertex normal + norms.add(readVector3()); + }else if (cmd.equals("vt")){ + // texture coordinate + texCoords.add(readVector2()); + }else if (cmd.equals("f")){ + // face, can be triangle, quad, or polygon (unsupported) + readFace(); + }else if (cmd.equals("usemtl")){ + // use material from MTL lib for the following faces + currentMatName = scan.next(); +// if (!matList.containsKey(currentMatName)) +// throw new IOException("Cannot locate material " + currentMatName + " in MTL file!"); + + }else if (cmd.equals("mtllib")){ + // specify MTL lib to use for this OBJ file + String mtllib = scan.nextLine().trim(); + loadMtlLib(mtllib); + }else if (cmd.equals("s") || cmd.equals("g")){ + return nextStatement(); + }else{ + // skip entire command until next line + logger.log(Level.WARNING, "Unknown statement in OBJ! {0}", cmd); + return nextStatement(); + } + + return true; + } + + protected Geometry createGeometry(ArrayList<Face> faceList, String matName) throws IOException{ + if (faceList.isEmpty()) + throw new IOException("No geometry data to generate mesh"); + + // Create mesh from the faces + Mesh mesh = constructMesh(faceList); + + Geometry geom = new Geometry(objName + "-geom-" + (geomIndex++), mesh); + + Material material = null; + if (matName != null && matList != null){ + // Get material from material list + material = matList.get(matName); + } + if (material == null){ + // create default material + material = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md"); + material.setFloat("Shininess", 64); + } + geom.setMaterial(material); + if (material.isTransparent()) + geom.setQueueBucket(Bucket.Transparent); + else + geom.setQueueBucket(Bucket.Opaque); + + if (material.getMaterialDef().getName().contains("Lighting") + && mesh.getFloatBuffer(Type.Normal) == null){ + logger.log(Level.WARNING, "OBJ mesh {0} doesn't contain normals! " + + "It might not display correctly", geom.getName()); + } + + return geom; + } + + protected Mesh constructMesh(ArrayList<Face> faceList){ + Mesh m = new Mesh(); + m.setMode(Mode.Triangles); + + boolean hasTexCoord = false; + boolean hasNormals = false; + + ArrayList<Face> newFaces = new ArrayList<Face>(faceList.size()); + for (int i = 0; i < faceList.size(); i++){ + Face f = faceList.get(i); + + for (Vertex v : f.verticies){ + findVertexIndex(v); + + if (!hasTexCoord && v.vt != null) + hasTexCoord = true; + if (!hasNormals && v.vn != null) + hasNormals = true; + } + + if (f.verticies.length == 4){ + Face[] t = quadToTriangle(f); + newFaces.add(t[0]); + newFaces.add(t[1]); + }else{ + newFaces.add(f); + } + } + + FloatBuffer posBuf = BufferUtils.createFloatBuffer(vertIndexMap.size() * 3); + FloatBuffer normBuf = null; + FloatBuffer tcBuf = null; + + if (hasNormals){ + normBuf = BufferUtils.createFloatBuffer(vertIndexMap.size() * 3); + } + if (hasTexCoord){ + tcBuf = BufferUtils.createFloatBuffer(vertIndexMap.size() * 2); + } + + IndexBuffer indexBuf = null; + if (vertIndexMap.size() >= 65536){ + // too many verticies: use intbuffer instead of shortbuffer + IntBuffer ib = BufferUtils.createIntBuffer(newFaces.size() * 3); + m.setBuffer(VertexBuffer.Type.Index, 3, ib); + indexBuf = new IndexIntBuffer(ib); + }else{ + ShortBuffer sb = BufferUtils.createShortBuffer(newFaces.size() * 3); + m.setBuffer(VertexBuffer.Type.Index, 3, sb); + indexBuf = new IndexShortBuffer(sb); + } + + int numFaces = newFaces.size(); + for (int i = 0; i < numFaces; i++){ + Face f = newFaces.get(i); + if (f.verticies.length != 3) + continue; + + Vertex v0 = f.verticies[0]; + Vertex v1 = f.verticies[1]; + Vertex v2 = f.verticies[2]; + + posBuf.position(v0.index * 3); + posBuf.put(v0.v.x).put(v0.v.y).put(v0.v.z); + posBuf.position(v1.index * 3); + posBuf.put(v1.v.x).put(v1.v.y).put(v1.v.z); + posBuf.position(v2.index * 3); + posBuf.put(v2.v.x).put(v2.v.y).put(v2.v.z); + + if (normBuf != null){ + if (v0.vn != null){ + normBuf.position(v0.index * 3); + normBuf.put(v0.vn.x).put(v0.vn.y).put(v0.vn.z); + normBuf.position(v1.index * 3); + normBuf.put(v1.vn.x).put(v1.vn.y).put(v1.vn.z); + normBuf.position(v2.index * 3); + normBuf.put(v2.vn.x).put(v2.vn.y).put(v2.vn.z); + } + } + + if (tcBuf != null){ + if (v0.vt != null){ + tcBuf.position(v0.index * 2); + tcBuf.put(v0.vt.x).put(v0.vt.y); + tcBuf.position(v1.index * 2); + tcBuf.put(v1.vt.x).put(v1.vt.y); + tcBuf.position(v2.index * 2); + tcBuf.put(v2.vt.x).put(v2.vt.y); + } + } + + int index = i * 3; // current face * 3 = current index + indexBuf.put(index, v0.index); + indexBuf.put(index+1, v1.index); + indexBuf.put(index+2, v2.index); + } + + m.setBuffer(VertexBuffer.Type.Position, 3, posBuf); + m.setBuffer(VertexBuffer.Type.Normal, 3, normBuf); + m.setBuffer(VertexBuffer.Type.TexCoord, 2, tcBuf); + // index buffer was set on creation + + m.setStatic(); + m.updateBound(); + m.updateCounts(); + //m.setInterleaved(); + + // clear data generated face statements + // to prepare for next mesh + vertIndexMap.clear(); + indexVertMap.clear(); + curIndex = 0; + + return m; + } + + @SuppressWarnings("empty-statement") + public Object load(AssetInfo info) throws IOException{ + reset(); + + key = (ModelKey) info.getKey(); + assetManager = info.getManager(); + objName = key.getName(); + + String folderName = key.getFolder(); + String ext = key.getExtension(); + objName = objName.substring(0, objName.length() - ext.length() - 1); + if (folderName != null && folderName.length() > 0){ + objName = objName.substring(folderName.length()); + } + + objNode = new Node(objName + "-objnode"); + + if (!(info.getKey() instanceof ModelKey)) + throw new IllegalArgumentException("Model assets must be loaded using a ModelKey"); + + InputStream in = null; + try { + in = info.openStream(); + + scan = new Scanner(in); + scan.useLocale(Locale.US); + + while (readLine()); + } finally { + if (in != null){ + in.close(); + } + } + + if (matFaces.size() > 0){ + for (Entry<String, ArrayList<Face>> entry : matFaces.entrySet()){ + ArrayList<Face> materialFaces = entry.getValue(); + if (materialFaces.size() > 0){ + Geometry geom = createGeometry(materialFaces, entry.getKey()); + objNode.attachChild(geom); + } + } + }else if (faces.size() > 0){ + // generate final geometry + Geometry geom = createGeometry(faces, null); + objNode.attachChild(geom); + } + + if (objNode.getQuantity() == 1) + // only 1 geometry, so no need to send node + return objNode.getChild(0); + else + return objNode; + } + +} |