1b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/*
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Copyright (c) 2009-2010 jMonkeyEngine
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * All rights reserved.
4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *
5b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * Redistribution and use in source and binary forms, with or without
6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * modification, are permitted provided that the following conditions are
7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * met:
8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *
9b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * * Redistributions of source code must retain the above copyright
10b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *   notice, this list of conditions and the following disclaimer.
11b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *
12b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * * Redistributions in binary form must reproduce the above copyright
13b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *   notice, this list of conditions and the following disclaimer in the
14b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *   documentation and/or other materials provided with the distribution.
15b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *
16b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *   may be used to endorse or promote products derived from this software
18b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *   without specific prior written permission.
19b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *
20b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch */
32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochpackage com.jme3.util;
33b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
34b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.math.ColorRGBA;
35b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.math.FastMath;
36b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.math.Vector2f;
37b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.math.Vector3f;
38b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.scene.*;
39b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.scene.VertexBuffer.Format;
40b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.scene.VertexBuffer.Type;
41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.scene.VertexBuffer.Usage;
42b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport com.jme3.scene.mesh.IndexBuffer;
43b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport static com.jme3.util.BufferUtils.*;
44b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport java.nio.FloatBuffer;
45b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport java.nio.IntBuffer;
46b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport java.util.ArrayList;
47b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport java.util.logging.Level;
48b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochimport java.util.logging.Logger;
49b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
50b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch/**
51b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch *
52b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch * @author Lex (Aleksey Nikiforov)
53b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  */
54b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdochpublic class TangentBinormalGenerator {
55b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
56b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    private static final float ZERO_TOLERANCE = 0.0000001f;
57b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    private static final Logger log = Logger.getLogger(
58b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            TangentBinormalGenerator.class.getName());
59b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    private static float toleranceAngle;
60b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    private static float toleranceDot;
61b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
62b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    static {
63b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        setToleranceAngle(45);
64b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
65b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
66b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
67b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    private static class VertexInfo {
68b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        public final Vector3f position;
69b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        public final Vector3f normal;
70b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        public final ArrayList<Integer> indices = new ArrayList<Integer>();
71b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
72b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        public VertexInfo(Vector3f position, Vector3f normal) {
73b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            this.position = position;
74b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            this.normal = normal;
75b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
76b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
77b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
78b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    /** Collects all the triangle data for one vertex.
79b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch     */
80b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    private static class VertexData {
81b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        public final ArrayList<TriangleData> triangles = new ArrayList<TriangleData>();
82b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
83b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        public VertexData() { }
84b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
85b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
86b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    /** Keeps track of tangent, binormal, and normal for one triangle.
87b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch     */
88b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    public static class TriangleData {
89b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        public final Vector3f tangent;
90b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        public final Vector3f binormal;
91b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        public final Vector3f normal;
92b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
93b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        public TriangleData(Vector3f tangent, Vector3f binormal, Vector3f normal) {
94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            this.tangent = tangent;
95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            this.binormal = binormal;
96b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            this.normal = normal;
97b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
98b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
99b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
100b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    private static VertexData[] initVertexData(int size) {
101b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        VertexData[] vertices = new VertexData[size];
102b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        for (int i = 0; i < size; i++) {
103b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            vertices[i] = new VertexData();
104b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
105b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        return vertices;
106b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
107b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
108b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    public static void generate(Mesh mesh) {
109b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        generate(mesh, true);
110b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
111b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
112b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    public static void generate(Spatial scene) {
113b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if (scene instanceof Node) {
114b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            Node node = (Node) scene;
115b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            for (Spatial child : node.getChildren()) {
116b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                generate(child);
117b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
118b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        } else {
119b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            Geometry geom = (Geometry) scene;
120b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            Mesh mesh = geom.getMesh();
121b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
122b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            // Check to ensure mesh has texcoords and normals before generating
123b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            if (mesh.getBuffer(Type.TexCoord) != null
124b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch             && mesh.getBuffer(Type.Normal) != null){
125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                generate(geom.getMesh());
126b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
127b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
128b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
129b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
130b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    public static void generate(Mesh mesh, boolean approxTangents) {
131b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        int[] index = new int[3];
132b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f[] v = new Vector3f[3];
133b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector2f[] t = new Vector2f[3];
134b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        for (int i = 0; i < 3; i++) {
135b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            v[i] = new Vector3f();
136b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            t[i] = new Vector2f();
137b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
138b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
139b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if (mesh.getBuffer(Type.Normal) == null) {
140b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            throw new IllegalArgumentException("The given mesh has no normal data!");
141b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
142b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
143b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        VertexData[] vertices;
144b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        switch (mesh.getMode()) {
145b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            case Triangles:
146b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                vertices = processTriangles(mesh, index, v, t);
147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                break;
148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            case TriangleStrip:
149b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                vertices = processTriangleStrip(mesh, index, v, t);
150b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                break;
151b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            case TriangleFan:
152b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                vertices = processTriangleFan(mesh, index, v, t);
153b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                break;
154b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            default:
155b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                throw new UnsupportedOperationException(
156b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        mesh.getMode() + " is not supported.");
157b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
158b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
159b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        processTriangleData(mesh, vertices, approxTangents);
160b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
161b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        //if the mesh has a bind pose, we need to generate the bind pose for the tangent buffer
162b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if (mesh.getBuffer(Type.BindPosePosition) != null) {
163b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
164b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            VertexBuffer tangents = mesh.getBuffer(Type.Tangent);
165b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            if (tangents != null) {
166b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                VertexBuffer bindTangents = new VertexBuffer(Type.BindPoseTangent);
167b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                bindTangents.setupData(Usage.CpuOnly,
168b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        4,
169b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        Format.Float,
170b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        BufferUtils.clone(tangents.getData()));
171b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
172b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                if (mesh.getBuffer(Type.BindPoseTangent) != null) {
173b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    mesh.clearBuffer(Type.BindPoseTangent);
174b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                }
175b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                mesh.setBuffer(bindTangents);
176b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                tangents.setUsage(Usage.Stream);
177b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
178b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
179b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
180b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
181b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    private static VertexData[] processTriangles(Mesh mesh,
182b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            int[] index, Vector3f[] v, Vector2f[] t) {
183b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        IndexBuffer indexBuffer = mesh.getIndexBuffer();
184b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
185b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if (mesh.getBuffer(Type.TexCoord) == null) {
186b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            throw new IllegalArgumentException("Can only generate tangents for "
187b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    + "meshes with texture coordinates");
188b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
189b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
190b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer textureBuffer = (FloatBuffer) mesh.getBuffer(Type.TexCoord).getData();
191b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
192b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        VertexData[] vertices = initVertexData(vertexBuffer.capacity() / 3);
193b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
194b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        for (int i = 0; i < indexBuffer.size() / 3; i++) {
195b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            for (int j = 0; j < 3; j++) {
196b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                index[j] = indexBuffer.get(i * 3 + j);
197b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                populateFromBuffer(v[j], vertexBuffer, index[j]);
198b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                populateFromBuffer(t[j], textureBuffer, index[j]);
199b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
200b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
201b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            TriangleData triData = processTriangle(index, v, t);
202b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            if (triData != null) {
203b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                vertices[index[0]].triangles.add(triData);
204b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                vertices[index[1]].triangles.add(triData);
205b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                vertices[index[2]].triangles.add(triData);
206b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
207b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
208b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
209b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        return vertices;
210b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
211b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
212b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    private static VertexData[] processTriangleStrip(Mesh mesh,
213b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            int[] index, Vector3f[] v, Vector2f[] t) {
214b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        IndexBuffer indexBuffer = mesh.getIndexBuffer();
215b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
216b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer textureBuffer = (FloatBuffer) mesh.getBuffer(Type.TexCoord).getData();
217b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
218b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        VertexData[] vertices = initVertexData(vertexBuffer.capacity() / 3);
219b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
220b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        index[0] = indexBuffer.get(0);
221b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        index[1] = indexBuffer.get(1);
222b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
223b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        populateFromBuffer(v[0], vertexBuffer, index[0]);
224b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        populateFromBuffer(v[1], vertexBuffer, index[1]);
225b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
226b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        populateFromBuffer(t[0], textureBuffer, index[0]);
227b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        populateFromBuffer(t[1], textureBuffer, index[1]);
228b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
229b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        for (int i = 2; i < indexBuffer.size(); i++) {
230b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            index[2] = indexBuffer.get(i);
231b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            BufferUtils.populateFromBuffer(v[2], vertexBuffer, index[2]);
232b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            BufferUtils.populateFromBuffer(t[2], textureBuffer, index[2]);
233b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
234b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            boolean isDegenerate = isDegenerateTriangle(v[0], v[1], v[2]);
235b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            TriangleData triData = processTriangle(index, v, t);
236b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
237b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            if (triData != null && !isDegenerate) {
238b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                vertices[index[0]].triangles.add(triData);
239b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                vertices[index[1]].triangles.add(triData);
240b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                vertices[index[2]].triangles.add(triData);
241b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
242b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
243b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            Vector3f vTemp = v[0];
244b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            v[0] = v[1];
245b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            v[1] = v[2];
246b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            v[2] = vTemp;
247b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
248b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            Vector2f tTemp = t[0];
249b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            t[0] = t[1];
250b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            t[1] = t[2];
251b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            t[2] = tTemp;
252b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
253b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            index[0] = index[1];
254b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            index[1] = index[2];
255b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
256b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
257b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        return vertices;
258b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
259b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
260b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    private static VertexData[] processTriangleFan(Mesh mesh,
261b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            int[] index, Vector3f[] v, Vector2f[] t) {
262b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        IndexBuffer indexBuffer = mesh.getIndexBuffer();
263b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
264b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer textureBuffer = (FloatBuffer) mesh.getBuffer(Type.TexCoord).getData();
265b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
266b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        VertexData[] vertices = initVertexData(vertexBuffer.capacity() / 3);
267b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
268b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        index[0] = indexBuffer.get(0);
269b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        index[1] = indexBuffer.get(1);
270b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
271b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        populateFromBuffer(v[0], vertexBuffer, index[0]);
272b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        populateFromBuffer(v[1], vertexBuffer, index[1]);
273b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
274b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        populateFromBuffer(t[0], textureBuffer, index[0]);
275b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        populateFromBuffer(t[1], textureBuffer, index[1]);
276b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
277b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        for (int i = 2; i < vertexBuffer.capacity() / 3; i++) {
278b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            index[2] = indexBuffer.get(i);
279b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            populateFromBuffer(v[2], vertexBuffer, index[2]);
280b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            populateFromBuffer(t[2], textureBuffer, index[2]);
281b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
282b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            TriangleData triData = processTriangle(index, v, t);
283b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            if (triData != null) {
284b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                vertices[index[0]].triangles.add(triData);
285b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                vertices[index[1]].triangles.add(triData);
286b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                vertices[index[2]].triangles.add(triData);
287b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
288b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
289b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            Vector3f vTemp = v[1];
290b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            v[1] = v[2];
291b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            v[2] = vTemp;
292b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
293b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            Vector2f tTemp = t[1];
294b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            t[1] = t[2];
295b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            t[2] = tTemp;
296b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
297b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            index[1] = index[2];
298b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
299b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
300b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        return vertices;
301b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
302b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
303b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    // check if the area is greater than zero
304b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    private static boolean isDegenerateTriangle(Vector3f a, Vector3f b, Vector3f c) {
305b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        return (a.subtract(b).cross(c.subtract(b))).lengthSquared() == 0;
306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
307b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
308b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    public static TriangleData processTriangle(int[] index,
309b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            Vector3f[] v, Vector2f[] t) {
310b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f edge1 = new Vector3f();
311b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f edge2 = new Vector3f();
312b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector2f edge1uv = new Vector2f();
313b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector2f edge2uv = new Vector2f();
314b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
315b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f tangent = new Vector3f();
316b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f binormal = new Vector3f();
317b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f normal = new Vector3f();
318b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
319b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        t[1].subtract(t[0], edge1uv);
320b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        t[2].subtract(t[0], edge2uv);
321b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        float det = edge1uv.x * edge2uv.y - edge1uv.y * edge2uv.x;
322b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
323b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        boolean normalize = false;
324b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if (Math.abs(det) < ZERO_TOLERANCE) {
325b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            log.log(Level.WARNING, "Colinear uv coordinates for triangle "
326b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    + "[{0}, {1}, {2}]; tex0 = [{3}, {4}], "
327b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    + "tex1 = [{5}, {6}], tex2 = [{7}, {8}]",
328b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    new Object[]{index[0], index[1], index[2],
329b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        t[0].x, t[0].y, t[1].x, t[1].y, t[2].x, t[2].y});
330b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            det = 1;
331b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            normalize = true;
332b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
333b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
334b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        v[1].subtract(v[0], edge1);
335b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        v[2].subtract(v[0], edge2);
336b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
337b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        tangent.set(edge1);
338b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        tangent.normalizeLocal();
339b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        binormal.set(edge2);
340b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        binormal.normalizeLocal();
341b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
342b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if (Math.abs(Math.abs(tangent.dot(binormal)) - 1)
343b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                < ZERO_TOLERANCE) {
344b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            log.log(Level.WARNING, "Vertices are on the same line "
345b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    + "for triangle [{0}, {1}, {2}].",
346b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    new Object[]{index[0], index[1], index[2]});
347b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
348b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
349b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        float factor = 1 / det;
350b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        tangent.x = (edge2uv.y * edge1.x - edge1uv.y * edge2.x) * factor;
351b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        tangent.y = (edge2uv.y * edge1.y - edge1uv.y * edge2.y) * factor;
352b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        tangent.z = (edge2uv.y * edge1.z - edge1uv.y * edge2.z) * factor;
353b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if (normalize) {
354b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            tangent.normalizeLocal();
355b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
356b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
357b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        binormal.x = (edge1uv.x * edge2.x - edge2uv.x * edge1.x) * factor;
358b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        binormal.y = (edge1uv.x * edge2.y - edge2uv.x * edge1.y) * factor;
359b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        binormal.z = (edge1uv.x * edge2.z - edge2uv.x * edge1.z) * factor;
360b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if (normalize) {
361b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            binormal.normalizeLocal();
362b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
363b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
364b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        tangent.cross(binormal, normal);
365b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        normal.normalizeLocal();
366b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
367b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        return new TriangleData(
368b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                tangent,
369b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                binormal,
370b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                normal);
371b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
372b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
373b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    public static void setToleranceAngle(float angle) {
374b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if (angle < 0 || angle > 179) {
375b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            throw new IllegalArgumentException(
376b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    "The angle must be between 0 and 179 degrees.");
377b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
378b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        toleranceDot = FastMath.cos(angle * FastMath.DEG_TO_RAD);
379b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        toleranceAngle = angle;
380b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
381b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
382b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
383b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    private static boolean approxEqual(Vector3f u, Vector3f v) {
384b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        float tolerance = 1E-4f;
385b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        return (FastMath.abs(u.x - v.x) < tolerance) &&
386b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch               (FastMath.abs(u.y - v.y) < tolerance) &&
387b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch               (FastMath.abs(u.z - v.z) < tolerance);
388b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
389b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
390b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    private static ArrayList<VertexInfo> linkVertices(Mesh mesh) {
391b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        ArrayList<VertexInfo> vertexMap = new ArrayList<VertexInfo>();
392b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
393b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
394b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData();
395b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
396b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f position = new Vector3f();
397b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f normal = new Vector3f();
398b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
399b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        final int size = vertexBuffer.capacity() / 3;
400b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        for (int i = 0; i < size; i++) {
401b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
402b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            populateFromBuffer(position, vertexBuffer, i);
403b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            populateFromBuffer(normal, normalBuffer, i);
404b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
405b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            boolean found = false;
406b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
407b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            for (int j = 0; j < vertexMap.size(); j++) {
408b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                VertexInfo vertexInfo = vertexMap.get(j);
409b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                if (approxEqual(vertexInfo.position, position) &&
410b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    approxEqual(vertexInfo.normal, normal))
411b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                {
412b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    vertexInfo.indices.add(i);
413b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    found = true;
414b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    break;
415b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                }
416b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
417b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
418b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            if (!found) {
419b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                VertexInfo vertexInfo = new VertexInfo(position.clone(), normal.clone());
420b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                vertexInfo.indices.add(i);
421b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                vertexMap.add(vertexInfo);
422b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
423b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
424b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
425b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        return vertexMap;
426b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
427b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
428b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    private static void processTriangleData(Mesh mesh, VertexData[] vertices,
429b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            boolean approxTangent)
430b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    {
431b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        ArrayList<VertexInfo> vertexMap = linkVertices(mesh);
432b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
433b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData();
434b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
435b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer tangents = BufferUtils.createFloatBuffer(vertices.length * 4);
436b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch//        FloatBuffer binormals = BufferUtils.createFloatBuffer(vertices.length * 3);
437b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
438b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f tangent = new Vector3f();
439b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f binormal = new Vector3f();
440b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f normal = new Vector3f();
441b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f givenNormal = new Vector3f();
442b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
443b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f tangentUnit = new Vector3f();
444b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f binormalUnit = new Vector3f();
445b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
446b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        for (int k = 0; k < vertexMap.size(); k++) {
447b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            float wCoord = -1;
448b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
449b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            VertexInfo vertexInfo = vertexMap.get(k);
450b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
451b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            givenNormal.set(vertexInfo.normal);
452b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            givenNormal.normalizeLocal();
453b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
454b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            TriangleData firstTriangle = vertices[vertexInfo.indices.get(0)].triangles.get(0);
455b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
456b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            // check tangent and binormal consistency
457b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            tangent.set(firstTriangle.tangent);
458b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            tangent.normalizeLocal();
459b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            binormal.set(firstTriangle.binormal);
460b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            binormal.normalizeLocal();
461b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
462b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            for (int i : vertexInfo.indices) {
463b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                ArrayList<TriangleData> triangles = vertices[i].triangles;
464b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
465b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                for (int j = 0; j < triangles.size(); j++) {
466b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    TriangleData triangleData = triangles.get(j);
467b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
468b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    tangentUnit.set(triangleData.tangent);
469b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    tangentUnit.normalizeLocal();
470b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    if (tangent.dot(tangentUnit) < toleranceDot) {
471b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        log.log(Level.WARNING,
472b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                "Angle between tangents exceeds tolerance "
473b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                + "for vertex {0}.", i);
474b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        break;
475b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    }
476b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
477b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    if (!approxTangent) {
478b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        binormalUnit.set(triangleData.binormal);
479b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        binormalUnit.normalizeLocal();
480b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        if (binormal.dot(binormalUnit) < toleranceDot) {
481b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                            log.log(Level.WARNING,
482b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                    "Angle between binormals exceeds tolerance "
483b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                                    + "for vertex {0}.", i);
484b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                            break;
485b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        }
486b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    }
487b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                }
488b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
489b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
490b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
491b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            // find average tangent
492b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            tangent.set(0, 0, 0);
493b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            binormal.set(0, 0, 0);
494b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
495b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            int triangleCount = 0;
496b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            for (int i : vertexInfo.indices) {
497b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                ArrayList<TriangleData> triangles = vertices[i].triangles;
498b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                triangleCount += triangles.size();
499b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
500b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                boolean flippedNormal = false;
501b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                for (int j = 0; j < triangles.size(); j++) {
502b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    TriangleData triangleData = triangles.get(j);
503b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    tangent.addLocal(triangleData.tangent);
504b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    binormal.addLocal(triangleData.binormal);
505b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
506b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    if (givenNormal.dot(triangleData.normal) < 0) {
507b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        flippedNormal = true;
508b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    }
509b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                }
510b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                if (flippedNormal /*&& approxTangent*/) {
511b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    // Generated normal is flipped for this vertex,
512b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    // so binormal = normal.cross(tangent) will be flipped in the shader
513b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    //                log.log(Level.WARNING,
514b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    //                        "Binormal is flipped for vertex {0}.", i);
515b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
516b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    wCoord = 1;
517b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                }
518b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
519b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
520b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
521b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            int blameVertex = vertexInfo.indices.get(0);
522b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
523b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            if (tangent.length() < ZERO_TOLERANCE) {
524b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                log.log(Level.WARNING,
525b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        "Shared tangent is zero for vertex {0}.", blameVertex);
526b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                // attempt to fix from binormal
527b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                if (binormal.length() >= ZERO_TOLERANCE) {
528b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    binormal.cross(givenNormal, tangent);
529b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    tangent.normalizeLocal();
530b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                } // if all fails use the tangent from the first triangle
531b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                else {
532b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    tangent.set(firstTriangle.tangent);
533b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                }
534b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            } else {
535b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                tangent.divideLocal(triangleCount);
536b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
537b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
538b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            tangentUnit.set(tangent);
539b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            tangentUnit.normalizeLocal();
540b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            if (Math.abs(Math.abs(tangentUnit.dot(givenNormal)) - 1)
541b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    < ZERO_TOLERANCE) {
542b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                log.log(Level.WARNING,
543b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        "Normal and tangent are parallel for vertex {0}.", blameVertex);
544b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
545b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
546b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
547b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            if (!approxTangent) {
548b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                if (binormal.length() < ZERO_TOLERANCE) {
549b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    log.log(Level.WARNING,
550b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                            "Shared binormal is zero for vertex {0}.", blameVertex);
551b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    // attempt to fix from tangent
552b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    if (tangent.length() >= ZERO_TOLERANCE) {
553b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        givenNormal.cross(tangent, binormal);
554b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        binormal.normalizeLocal();
555b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    } // if all fails use the binormal from the first triangle
556b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    else {
557b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        binormal.set(firstTriangle.binormal);
558b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    }
559b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                } else {
560b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    binormal.divideLocal(triangleCount);
561b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                }
562b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
563b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                binormalUnit.set(binormal);
564b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                binormalUnit.normalizeLocal();
565b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                if (Math.abs(Math.abs(binormalUnit.dot(givenNormal)) - 1)
566b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        < ZERO_TOLERANCE) {
567b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    log.log(Level.WARNING,
568b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                            "Normal and binormal are parallel for vertex {0}.", blameVertex);
569b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                }
570b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
571b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                if (Math.abs(Math.abs(binormalUnit.dot(tangentUnit)) - 1)
572b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                        < ZERO_TOLERANCE) {
573b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    log.log(Level.WARNING,
574b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                            "Tangent and binormal are parallel for vertex {0}.", blameVertex);
575b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                }
576b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
577b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
578b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            for (int i : vertexInfo.indices) {
579b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                if (approxTangent) {
580b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    // This calculation ensures that normal and tagent have a 90 degree angle.
581b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    // Removing this will lead to visual artifacts.
582b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    givenNormal.cross(tangent, binormal);
583b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    binormal.cross(givenNormal, tangent);
584b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
585b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    tangent.normalizeLocal();
586b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
587b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    tangents.put((i * 4), tangent.x);
588b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    tangents.put((i * 4) + 1, tangent.y);
589b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    tangents.put((i * 4) + 2, tangent.z);
590b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    tangents.put((i * 4) + 3, wCoord);
591b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                } else {
592b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    tangents.put((i * 4), tangent.x);
593b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    tangents.put((i * 4) + 1, tangent.y);
594b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    tangents.put((i * 4) + 2, tangent.z);
595b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    tangents.put((i * 4) + 3, wCoord);
596b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
597b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                    //setInBuffer(binormal, binormals, i);
598b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                }
599b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
600b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
601b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
602b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        mesh.setBuffer(Type.Tangent, 4, tangents);
603b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch//        if (!approxTangent) mesh.setBuffer(Type.Binormal, 3, binormals);
604b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
605b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
606b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    public static Mesh genTbnLines(Mesh mesh, float scale) {
607b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if (mesh.getBuffer(Type.Tangent) == null) {
608b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            return genNormalLines(mesh, scale);
609b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        } else {
610b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            return genTangentLines(mesh, scale);
611b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
612b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
613b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
614b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    public static Mesh genNormalLines(Mesh mesh, float scale) {
615b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
616b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData();
617b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
618b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        ColorRGBA originColor = ColorRGBA.White;
619b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        ColorRGBA normalColor = ColorRGBA.Blue;
620b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
621b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Mesh lineMesh = new Mesh();
622b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        lineMesh.setMode(Mesh.Mode.Lines);
623b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
624b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f origin = new Vector3f();
625b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f point = new Vector3f();
626b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
627b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer lineVertex = BufferUtils.createFloatBuffer(vertexBuffer.capacity() * 2);
628b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer lineColor = BufferUtils.createFloatBuffer(vertexBuffer.capacity() / 3 * 4 * 2);
629b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
630b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        for (int i = 0; i < vertexBuffer.capacity() / 3; i++) {
631b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            populateFromBuffer(origin, vertexBuffer, i);
632b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            populateFromBuffer(point, normalBuffer, i);
633b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
634b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            int index = i * 2;
635b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
636b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            setInBuffer(origin, lineVertex, index);
637b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            setInBuffer(originColor, lineColor, index);
638b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
639b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            point.multLocal(scale);
640b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            point.addLocal(origin);
641b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            setInBuffer(point, lineVertex, index + 1);
642b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            setInBuffer(normalColor, lineColor, index + 1);
643b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
644b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
645b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        lineMesh.setBuffer(Type.Position, 3, lineVertex);
646b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        lineMesh.setBuffer(Type.Color, 4, lineColor);
647b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
648b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        lineMesh.setStatic();
649b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        //lineMesh.setInterleaved();
650b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        return lineMesh;
651b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
652b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
653b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    private static Mesh genTangentLines(Mesh mesh, float scale) {
654b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();
655b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData();
656b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer tangentBuffer = (FloatBuffer) mesh.getBuffer(Type.Tangent).getData();
657b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
658b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer binormalBuffer = null;
659b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        if (mesh.getBuffer(Type.Binormal) != null) {
660b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            binormalBuffer = (FloatBuffer) mesh.getBuffer(Type.Binormal).getData();
661b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
662b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
663b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        ColorRGBA originColor = ColorRGBA.White;
664b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        ColorRGBA tangentColor = ColorRGBA.Red;
665b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        ColorRGBA binormalColor = ColorRGBA.Green;
666b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        ColorRGBA normalColor = ColorRGBA.Blue;
667b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
668b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Mesh lineMesh = new Mesh();
669b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        lineMesh.setMode(Mesh.Mode.Lines);
670b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
671b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f origin = new Vector3f();
672b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f point = new Vector3f();
673b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f tangent = new Vector3f();
674b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        Vector3f normal = new Vector3f();
675b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
676b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        IntBuffer lineIndex = BufferUtils.createIntBuffer(vertexBuffer.capacity() / 3 * 6);
677b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer lineVertex = BufferUtils.createFloatBuffer(vertexBuffer.capacity() * 4);
678b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        FloatBuffer lineColor = BufferUtils.createFloatBuffer(vertexBuffer.capacity() / 3 * 4 * 4);
679b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
680b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        boolean hasParity = mesh.getBuffer(Type.Tangent).getNumComponents() == 4;
681b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        float tangentW = 1;
682b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
683b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        for (int i = 0; i < vertexBuffer.capacity() / 3; i++) {
684b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            populateFromBuffer(origin, vertexBuffer, i);
685b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            populateFromBuffer(normal, normalBuffer, i);
686b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
687b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            if (hasParity) {
688b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                tangent.x = tangentBuffer.get(i * 4);
689b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                tangent.y = tangentBuffer.get(i * 4 + 1);
690b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                tangent.z = tangentBuffer.get(i * 4 + 2);
691b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                tangentW = tangentBuffer.get(i * 4 + 3);
692b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            } else {
693b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                populateFromBuffer(tangent, tangentBuffer, i);
694b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
695b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
696b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            int index = i * 4;
697b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
698b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            int id = i * 6;
699b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            lineIndex.put(id, index);
700b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            lineIndex.put(id + 1, index + 1);
701b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            lineIndex.put(id + 2, index);
702b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            lineIndex.put(id + 3, index + 2);
703b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            lineIndex.put(id + 4, index);
704b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            lineIndex.put(id + 5, index + 3);
705b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
706b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            setInBuffer(origin, lineVertex, index);
707b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            setInBuffer(originColor, lineColor, index);
708b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
709b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            point.set(tangent);
710b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            point.multLocal(scale);
711b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            point.addLocal(origin);
712b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            setInBuffer(point, lineVertex, index + 1);
713b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            setInBuffer(tangentColor, lineColor, index + 1);
714b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
715b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            // wvBinormal = cross(wvNormal, wvTangent) * -inTangent.w
716b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
717b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            if (binormalBuffer == null) {
718b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                normal.cross(tangent, point);
719b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                point.multLocal(-tangentW);
720b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                point.normalizeLocal();
721b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            } else {
722b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch                populateFromBuffer(point, binormalBuffer, i);
723b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            }
724b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
725b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            point.multLocal(scale);
726b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            point.addLocal(origin);
727b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            setInBuffer(point, lineVertex, index + 2);
728b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            setInBuffer(binormalColor, lineColor, index + 2);
729b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
730b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            point.set(normal);
731b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            point.multLocal(scale);
732b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            point.addLocal(origin);
733b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            setInBuffer(point, lineVertex, index + 3);
734b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch            setInBuffer(normalColor, lineColor, index + 3);
735b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        }
736b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
737b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        lineMesh.setBuffer(Type.Index, 1, lineIndex);
738b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        lineMesh.setBuffer(Type.Position, 3, lineVertex);
739b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        lineMesh.setBuffer(Type.Color, 4, lineColor);
740b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
741b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        lineMesh.setStatic();
742b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        //lineMesh.setInterleaved();
743b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch        return lineMesh;
744b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    }
745b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch}
746b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch