159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/*
259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Copyright (c) 2009-2010 jMonkeyEngine
359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * All rights reserved.
459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Redistribution and use in source and binary forms, with or without
659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * modification, are permitted provided that the following conditions are
759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * met:
859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions of source code must retain the above copyright
1059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   notice, this list of conditions and the following disclaimer.
1159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
1259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Redistributions in binary form must reproduce the above copyright
1359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   notice, this list of conditions and the following disclaimer in the
1459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   documentation and/or other materials provided with the distribution.
1559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
1659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
1759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   may be used to endorse or promote products derived from this software
1859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *   without specific prior written permission.
1959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta *
2059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
2459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
2659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
2759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
2859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
2959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
3259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
3359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapackage com.jme3.scene.plugins;
3459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
3559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.asset.*;
3659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.material.Material;
3759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.material.MaterialList;
3859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Vector2f;
3959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.math.Vector3f;
4059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.renderer.queue.RenderQueue.Bucket;
4159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.Mesh.Mode;
4259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.*;
4359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.VertexBuffer.Type;
4459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.mesh.IndexBuffer;
4559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.mesh.IndexIntBuffer;
4659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.scene.mesh.IndexShortBuffer;
4759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.util.BufferUtils;
4859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport com.jme3.util.IntMap;
4959b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.File;
5059b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.IOException;
5159b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.io.InputStream;
5259b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.FloatBuffer;
5359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.IntBuffer;
5459b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.nio.ShortBuffer;
5559b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.Map.Entry;
5659b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.*;
5759b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Level;
5859b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartaimport java.util.logging.Logger;
5959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
6059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta/**
6159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta * Reads OBJ format models.
6259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta */
6359b2e6871c65f58fdad78cd7229c292f6a177578Scott Bartapublic final class OBJLoader implements AssetLoader {
6459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
6559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private static final Logger logger = Logger.getLogger(OBJLoader.class.getName());
6659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
6759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected final ArrayList<Vector3f> verts = new ArrayList<Vector3f>();
6859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected final ArrayList<Vector2f> texCoords = new ArrayList<Vector2f>();
6959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected final ArrayList<Vector3f> norms = new ArrayList<Vector3f>();
7059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
7159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected final ArrayList<Face> faces = new ArrayList<Face>();
7259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected final HashMap<String, ArrayList<Face>> matFaces = new HashMap<String, ArrayList<Face>>();
7359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
7459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected String currentMatName;
7559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected String currentObjectName;
7659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
7759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected final HashMap<Vertex, Integer> vertIndexMap = new HashMap<Vertex, Integer>(100);
7859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected final IntMap<Vertex> indexVertMap = new IntMap<Vertex>(100);
7959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected int curIndex    = 0;
8059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected int objectIndex = 0;
8159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected int geomIndex   = 0;
8259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
8359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected Scanner scan;
8459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected ModelKey key;
8559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected AssetManager assetManager;
8659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected MaterialList matList;
8759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
8859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected String objName;
8959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected Node objNode;
9059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
9159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected static class Vertex {
9259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
9359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Vector3f v;
9459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Vector2f vt;
9559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Vector3f vn;
9659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int index;
9759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
9859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        @Override
9959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        public boolean equals(Object obj) {
10059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (obj == null) {
10159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                return false;
10259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
10359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (getClass() != obj.getClass()) {
10459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                return false;
10559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
10659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            final Vertex other = (Vertex) obj;
10759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (this.v != other.v && (this.v == null || !this.v.equals(other.v))) {
10859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                return false;
10959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
11059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (this.vt != other.vt && (this.vt == null || !this.vt.equals(other.vt))) {
11159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                return false;
11259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
11359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (this.vn != other.vn && (this.vn == null || !this.vn.equals(other.vn))) {
11459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                return false;
11559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
11659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return true;
11759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
11859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
11959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        @Override
12059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        public int hashCode() {
12159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            int hash = 5;
12259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            hash = 53 * hash + (this.v != null ? this.v.hashCode() : 0);
12359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            hash = 53 * hash + (this.vt != null ? this.vt.hashCode() : 0);
12459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            hash = 53 * hash + (this.vn != null ? this.vn.hashCode() : 0);
12559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return hash;
12659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
12759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
12859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
12959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected static class Face {
13059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Vertex[] verticies;
13159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
13259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
13359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected class ObjectGroup {
13459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
13559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        final String objectName;
13659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
13759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        public ObjectGroup(String objectName){
13859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            this.objectName = objectName;
13959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
14059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
14159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        public Spatial createGeometry(){
14259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            Node groupNode = new Node(objectName);
14359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
14459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//            if (matFaces.size() > 0){
14559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                for (Entry<String, ArrayList<Face>> entry : matFaces.entrySet()){
14659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                    ArrayList<Face> materialFaces = entry.getValue();
14759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                    if (materialFaces.size() > 0){
14859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                        Geometry geom = createGeometry(materialFaces, entry.getKey());
14959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                        objNode.attachChild(geom);
15059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                    }
15159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                }
15259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//            }else if (faces.size() > 0){
15359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                // generate final geometry
15459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                Geometry geom = createGeometry(faces, null);
15559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                objNode.attachChild(geom);
15659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//            }
15759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
15859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return groupNode;
15959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
16059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
16159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
16259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public void reset(){
16359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        verts.clear();
16459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        texCoords.clear();
16559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        norms.clear();
16659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        faces.clear();
16759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        matFaces.clear();
16859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
16959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        vertIndexMap.clear();
17059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        indexVertMap.clear();
17159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
17259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        currentMatName = null;
17359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        matList = null;
17459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        curIndex = 0;
17559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        geomIndex = 0;
17659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        scan = null;
17759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
17859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
17959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected void findVertexIndex(Vertex vert){
18059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Integer index = vertIndexMap.get(vert);
18159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (index != null){
18259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            vert.index = index.intValue();
18359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }else{
18459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            vert.index = curIndex++;
18559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            vertIndexMap.put(vert, vert.index);
18659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            indexVertMap.put(vert.index, vert);
18759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
18859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
18959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
19059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected Face[] quadToTriangle(Face f){
19159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        assert f.verticies.length == 4;
19259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
19359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Face[] t = new Face[]{ new Face(), new Face() };
19459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        t[0].verticies = new Vertex[3];
19559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        t[1].verticies = new Vertex[3];
19659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
19759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Vertex v0 = f.verticies[0];
19859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Vertex v1 = f.verticies[1];
19959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Vertex v2 = f.verticies[2];
20059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Vertex v3 = f.verticies[3];
20159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
20259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // find the pair of verticies that is closest to each over
20359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // v0 and v2
20459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // OR
20559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // v1 and v3
20659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        float d1 = v0.v.distanceSquared(v2.v);
20759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        float d2 = v1.v.distanceSquared(v3.v);
20859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (d1 < d2){
20959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // put an edge in v0, v2
21059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            t[0].verticies[0] = v0;
21159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            t[0].verticies[1] = v1;
21259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            t[0].verticies[2] = v3;
21359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
21459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            t[1].verticies[0] = v1;
21559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            t[1].verticies[1] = v2;
21659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            t[1].verticies[2] = v3;
21759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }else{
21859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // put an edge in v1, v3
21959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            t[0].verticies[0] = v0;
22059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            t[0].verticies[1] = v1;
22159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            t[0].verticies[2] = v2;
22259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
22359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            t[1].verticies[0] = v0;
22459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            t[1].verticies[1] = v2;
22559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            t[1].verticies[2] = v3;
22659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
22759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
22859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return t;
22959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
23059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
23159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    private ArrayList<Vertex> vertList = new ArrayList<Vertex>();
23259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
23359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected void readFace(){
23459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Face f = new Face();
23559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        vertList.clear();
23659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
23759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        String line = scan.nextLine().trim();
23859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        String[] verticies = line.split("\\s");
23959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        for (String vertex : verticies){
24059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            int v = 0;
24159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            int vt = 0;
24259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            int vn = 0;
24359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
24459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            String[] split = vertex.split("/");
24559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (split.length == 1){
24659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                v = Integer.parseInt(split[0].trim());
24759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }else if (split.length == 2){
24859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                v = Integer.parseInt(split[0].trim());
24959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                vt = Integer.parseInt(split[1].trim());
25059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }else if (split.length == 3 && !split[1].equals("")){
25159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                v = Integer.parseInt(split[0].trim());
25259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                vt = Integer.parseInt(split[1].trim());
25359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                vn = Integer.parseInt(split[2].trim());
25459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }else if (split.length == 3){
25559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                v = Integer.parseInt(split[0].trim());
25659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                vn = Integer.parseInt(split[2].trim());
25759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
25859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
25959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            Vertex vx = new Vertex();
26059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            vx.v = verts.get(v - 1);
26159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
26259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (vt > 0)
26359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                vx.vt = texCoords.get(vt - 1);
26459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
26559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (vn > 0)
26659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                vx.vn = norms.get(vn - 1);
26759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
26859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            vertList.add(vx);
26959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
27059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
27159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (vertList.size() > 4 || vertList.size() <= 2)
27259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            logger.warning("Edge or polygon detected in OBJ. Ignored.");
27359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
27459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        f.verticies = new Vertex[vertList.size()];
27559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        for (int i = 0; i < vertList.size(); i++){
27659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            f.verticies[i] = vertList.get(i);
27759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
27859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
27959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (matList != null && matFaces.containsKey(currentMatName)){
28059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            matFaces.get(currentMatName).add(f);
28159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }else{
28259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            faces.add(f); // faces that belong to the default material
28359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
28459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
28559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
28659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected Vector3f readVector3(){
28759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Vector3f v = new Vector3f();
28859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
28959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        v.set(Float.parseFloat(scan.next()),
29059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta              Float.parseFloat(scan.next()),
29159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta              Float.parseFloat(scan.next()));
29259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
29359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return v;
29459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
29559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
29659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected Vector2f readVector2(){
29759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Vector2f v = new Vector2f();
29859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
29959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        String line = scan.nextLine().trim();
30059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        String[] split = line.split("\\s");
30159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        v.setX( Float.parseFloat(split[0].trim()) );
30259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        v.setY( Float.parseFloat(split[1].trim()) );
30359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
30459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//        v.setX(scan.nextFloat());
30559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//        if (scan.hasNextFloat()){
30659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//            v.setY(scan.nextFloat());
30759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//            if (scan.hasNextFloat()){
30859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                scan.nextFloat(); // ignore
30959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//            }
31059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//        }
31159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
31259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return v;
31359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
31459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
31559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected void loadMtlLib(String name) throws IOException{
31659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (!name.toLowerCase().endsWith(".mtl"))
31759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            throw new IOException("Expected .mtl file! Got: " + name);
31859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
31959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // NOTE: Cut off any relative/absolute paths
32059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        name = new File(name).getName();
32159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        AssetKey mtlKey = new AssetKey(key.getFolder() + name);
32259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        try {
32359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            matList = (MaterialList) assetManager.loadAsset(mtlKey);
32459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } catch (AssetNotFoundException ex){
32559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            logger.log(Level.WARNING, "Cannot locate {0} for model {1}", new Object[]{name, key});
32659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
32759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
32859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (matList != null){
32959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // create face lists for every material
33059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            for (String matName : matList.keySet()){
33159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                matFaces.put(matName, new ArrayList<Face>());
33259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
33359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
33459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
33559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
33659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected boolean nextStatement(){
33759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        try {
33859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            scan.skip(".*\r{0,1}\n");
33959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return true;
34059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } catch (NoSuchElementException ex){
34159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // EOF
34259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return false;
34359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
34459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
34559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
34659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected boolean readLine() throws IOException{
34759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (!scan.hasNext()){
34859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return false;
34959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
35059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
35159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        String cmd = scan.next();
35259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (cmd.startsWith("#")){
35359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // skip entire comment until next line
35459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return nextStatement();
35559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }else if (cmd.equals("v")){
35659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // vertex position
35759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            verts.add(readVector3());
35859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }else if (cmd.equals("vn")){
35959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // vertex normal
36059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            norms.add(readVector3());
36159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }else if (cmd.equals("vt")){
36259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // texture coordinate
36359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            texCoords.add(readVector2());
36459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }else if (cmd.equals("f")){
36559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // face, can be triangle, quad, or polygon (unsupported)
36659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            readFace();
36759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }else if (cmd.equals("usemtl")){
36859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // use material from MTL lib for the following faces
36959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            currentMatName = scan.next();
37059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//            if (!matList.containsKey(currentMatName))
37159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta//                throw new IOException("Cannot locate material " + currentMatName + " in MTL file!");
37259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
37359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }else if (cmd.equals("mtllib")){
37459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // specify MTL lib to use for this OBJ file
37559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            String mtllib = scan.nextLine().trim();
37659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            loadMtlLib(mtllib);
37759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }else if (cmd.equals("s") || cmd.equals("g")){
37859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return nextStatement();
37959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }else{
38059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // skip entire command until next line
38159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            logger.log(Level.WARNING, "Unknown statement in OBJ! {0}", cmd);
38259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return nextStatement();
38359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
38459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
38559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return true;
38659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
38759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
38859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected Geometry createGeometry(ArrayList<Face> faceList, String matName) throws IOException{
38959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (faceList.isEmpty())
39059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            throw new IOException("No geometry data to generate mesh");
39159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
39259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // Create mesh from the faces
39359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Mesh mesh = constructMesh(faceList);
39459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
39559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Geometry geom = new Geometry(objName + "-geom-" + (geomIndex++), mesh);
39659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
39759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Material material = null;
39859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (matName != null && matList != null){
39959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // Get material from material list
40059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            material = matList.get(matName);
40159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
40259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (material == null){
40359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // create default material
40459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            material = new Material(assetManager, "Common/MatDefs/Light/Lighting.j3md");
40559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            material.setFloat("Shininess", 64);
40659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
40759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        geom.setMaterial(material);
40859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (material.isTransparent())
40959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            geom.setQueueBucket(Bucket.Transparent);
41059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        else
41159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            geom.setQueueBucket(Bucket.Opaque);
41259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
41359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (material.getMaterialDef().getName().contains("Lighting")
41459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta          && mesh.getFloatBuffer(Type.Normal) == null){
41559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            logger.log(Level.WARNING, "OBJ mesh {0} doesn't contain normals! "
41659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                                    + "It might not display correctly", geom.getName());
41759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
41859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
41959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return geom;
42059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
42159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
42259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    protected Mesh constructMesh(ArrayList<Face> faceList){
42359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        Mesh m = new Mesh();
42459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        m.setMode(Mode.Triangles);
42559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
42659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        boolean hasTexCoord = false;
42759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        boolean hasNormals  = false;
42859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
42959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        ArrayList<Face> newFaces = new ArrayList<Face>(faceList.size());
43059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        for (int i = 0; i < faceList.size(); i++){
43159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            Face f = faceList.get(i);
43259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
43359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            for (Vertex v : f.verticies){
43459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                findVertexIndex(v);
43559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
43659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                if (!hasTexCoord && v.vt != null)
43759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    hasTexCoord = true;
43859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                if (!hasNormals && v.vn != null)
43959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    hasNormals = true;
44059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
44159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
44259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (f.verticies.length == 4){
44359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                Face[] t = quadToTriangle(f);
44459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                newFaces.add(t[0]);
44559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                newFaces.add(t[1]);
44659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }else{
44759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                newFaces.add(f);
44859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
44959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
45059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
45159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        FloatBuffer posBuf  = BufferUtils.createFloatBuffer(vertIndexMap.size() * 3);
45259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        FloatBuffer normBuf = null;
45359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        FloatBuffer tcBuf   = null;
45459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
45559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (hasNormals){
45659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            normBuf = BufferUtils.createFloatBuffer(vertIndexMap.size() * 3);
457a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta            m.setBuffer(VertexBuffer.Type.Normal, 3, normBuf);
45859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
45959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (hasTexCoord){
46059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            tcBuf = BufferUtils.createFloatBuffer(vertIndexMap.size() * 2);
461a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta            m.setBuffer(VertexBuffer.Type.TexCoord, 2, tcBuf);
46259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
46359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
46459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        IndexBuffer indexBuf = null;
46559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (vertIndexMap.size() >= 65536){
46659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // too many verticies: use intbuffer instead of shortbuffer
46759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            IntBuffer ib = BufferUtils.createIntBuffer(newFaces.size() * 3);
46859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            m.setBuffer(VertexBuffer.Type.Index, 3, ib);
46959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            indexBuf = new IndexIntBuffer(ib);
47059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }else{
47159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            ShortBuffer sb = BufferUtils.createShortBuffer(newFaces.size() * 3);
47259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            m.setBuffer(VertexBuffer.Type.Index, 3, sb);
47359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            indexBuf = new IndexShortBuffer(sb);
47459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
47559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
47659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        int numFaces = newFaces.size();
47759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        for (int i = 0; i < numFaces; i++){
47859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            Face f = newFaces.get(i);
47959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (f.verticies.length != 3)
48059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                continue;
48159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
48259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            Vertex v0 = f.verticies[0];
48359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            Vertex v1 = f.verticies[1];
48459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            Vertex v2 = f.verticies[2];
48559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
48659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            posBuf.position(v0.index * 3);
48759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            posBuf.put(v0.v.x).put(v0.v.y).put(v0.v.z);
48859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            posBuf.position(v1.index * 3);
48959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            posBuf.put(v1.v.x).put(v1.v.y).put(v1.v.z);
49059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            posBuf.position(v2.index * 3);
49159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            posBuf.put(v2.v.x).put(v2.v.y).put(v2.v.z);
49259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
49359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (normBuf != null){
49459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                if (v0.vn != null){
49559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    normBuf.position(v0.index * 3);
49659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    normBuf.put(v0.vn.x).put(v0.vn.y).put(v0.vn.z);
49759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    normBuf.position(v1.index * 3);
49859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    normBuf.put(v1.vn.x).put(v1.vn.y).put(v1.vn.z);
49959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    normBuf.position(v2.index * 3);
50059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    normBuf.put(v2.vn.x).put(v2.vn.y).put(v2.vn.z);
50159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                }
50259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
50359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
50459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (tcBuf != null){
50559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                if (v0.vt != null){
50659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    tcBuf.position(v0.index * 2);
50759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    tcBuf.put(v0.vt.x).put(v0.vt.y);
50859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    tcBuf.position(v1.index * 2);
50959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    tcBuf.put(v1.vt.x).put(v1.vt.y);
51059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    tcBuf.position(v2.index * 2);
51159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    tcBuf.put(v2.vt.x).put(v2.vt.y);
51259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                }
51359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
51459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
51559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            int index = i * 3; // current face * 3 = current index
51659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            indexBuf.put(index,   v0.index);
51759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            indexBuf.put(index+1, v1.index);
51859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            indexBuf.put(index+2, v2.index);
51959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
52059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
52159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        m.setBuffer(VertexBuffer.Type.Position, 3, posBuf);
522a6b44658eb1c55295f132a36233a11aa2bd8f9cfScott Barta        // index buffer and others were set on creation
52359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
52459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        m.setStatic();
52559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        m.updateBound();
52659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        m.updateCounts();
52759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        //m.setInterleaved();
52859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
52959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // clear data generated face statements
53059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        // to prepare for next mesh
53159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        vertIndexMap.clear();
53259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        indexVertMap.clear();
53359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        curIndex = 0;
53459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
53559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        return m;
53659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
53759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
53859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    @SuppressWarnings("empty-statement")
53959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    public Object load(AssetInfo info) throws IOException{
54059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        reset();
54159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
54259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        key = (ModelKey) info.getKey();
54359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        assetManager = info.getManager();
54459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        objName    = key.getName();
54559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
54659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        String folderName = key.getFolder();
54759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        String ext        = key.getExtension();
54859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        objName = objName.substring(0, objName.length() - ext.length() - 1);
54959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (folderName != null && folderName.length() > 0){
55059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            objName = objName.substring(folderName.length());
55159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
55259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
55359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        objNode = new Node(objName + "-objnode");
55459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
55559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (!(info.getKey() instanceof ModelKey))
55659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            throw new IllegalArgumentException("Model assets must be loaded using a ModelKey");
55759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
55859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        InputStream in = null;
55959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        try {
56059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            in = info.openStream();
56159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
56259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            scan = new Scanner(in);
56359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            scan.useLocale(Locale.US);
56459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
56559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            while (readLine());
56659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        } finally {
56759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            if (in != null){
56859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                in.close();
56959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
57059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
57159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
57259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (matFaces.size() > 0){
57359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            for (Entry<String, ArrayList<Face>> entry : matFaces.entrySet()){
57459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                ArrayList<Face> materialFaces = entry.getValue();
57559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                if (materialFaces.size() > 0){
57659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    Geometry geom = createGeometry(materialFaces, entry.getKey());
57759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                    objNode.attachChild(geom);
57859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta                }
57959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            }
58059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }else if (faces.size() > 0){
58159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // generate final geometry
58259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            Geometry geom = createGeometry(faces, null);
58359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            objNode.attachChild(geom);
58459b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        }
58559b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
58659b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        if (objNode.getQuantity() == 1)
58759b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            // only 1 geometry, so no need to send node
58859b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return objNode.getChild(0);
58959b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta        else
59059b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta            return objNode;
59159b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta    }
59259b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta
59359b2e6871c65f58fdad78cd7229c292f6a177578Scott Barta}
594