/******************************************************************************* * Breakout Cave Survey Visualizer * * Copyright (C) 2014 James Edwards * * jedwards8 at fastmail dot fm * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *******************************************************************************/ package org.andork.jogl.util; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.util.HashMap; import java.util.Map; public class NormalGenerator { private static class TriangleListNode { public int triangleIndex; public TriangleListNode next; public TriangleListNode(int triangleIndex, TriangleListNode next) { super(); this.triangleIndex = triangleIndex; this.next = next; } } public static void generateNormals(ByteBuffer verts, int normalOffset, int vertsStride, CharBuffer indices, int indicesStart, int indicesEnd) { Map<Integer, TriangleListNode> connectedTris = new HashMap<Integer, TriangleListNode>(); float[] triNormals = new float[indicesEnd - indicesStart]; int normalIndex = 0; indices.position(indicesStart); int i = indicesStart; while (i < indicesEnd) { int triangleIndex = i; int coord0 = indices.get() * vertsStride; int coord1 = indices.get() * vertsStride; int coord2 = indices.get() * vertsStride; // remember that these points are connected to this triangle connectedTris.put(coord0, new TriangleListNode(triangleIndex, connectedTris.get(coord0))); connectedTris.put(coord1, new TriangleListNode(triangleIndex, connectedTris.get(coord1))); connectedTris.put(coord2, new TriangleListNode(triangleIndex, connectedTris.get(coord2))); // compute the normal of the triangle float ux = verts.getFloat(coord1) - verts.getFloat(coord0); float uy = verts.getFloat(coord1 + 4) - verts.getFloat(coord0 + 4); float uz = verts.getFloat(coord1 + 8) - verts.getFloat(coord0 + 8); float vx = verts.getFloat(coord2) - verts.getFloat(coord0); float vy = verts.getFloat(coord2 + 4) - verts.getFloat(coord0 + 4); float vz = verts.getFloat(coord2 + 8) - verts.getFloat(coord0 + 8); triNormals[normalIndex++] = uy * vz - uz * vy; triNormals[normalIndex++] = uz * vx - ux * vz; triNormals[normalIndex++] = ux * vy - uy * vx; i += 3; } // set the normal of each point to the normalized sum of the normals of // the triangles connected to that point for (Map.Entry<Integer, TriangleListNode> entry : connectedTris.entrySet()) { int pi = entry.getKey(); TriangleListNode node = entry.getValue(); float x = 0; float y = 0; float z = 0; while (node != null) { int triNormalIndex = node.triangleIndex - indicesStart; x += triNormals[triNormalIndex]; y += triNormals[triNormalIndex + 1]; z += triNormals[triNormalIndex + 2]; node = node.next; } float normFactor = 1f / (float) Math.sqrt(x * x + y * y + z * z); normalIndex = pi + normalOffset; verts.putFloat(normalIndex, x * normFactor); verts.putFloat(normalIndex + 4, y * normFactor); verts.putFloat(normalIndex + 8, z * normFactor); } } public static void generateNormals(float[] verts, int normalOffset, int vertsStride, char[] indices, int indicesStart, int indicesEnd) { Map<Integer, TriangleListNode> connectedTris = new HashMap<Integer, TriangleListNode>(); float[] triNormals = new float[indicesEnd - indicesStart]; int normalIndex = 0; int i = indicesStart; while (i < indicesEnd) { int triangleIndex = i; int coord0 = indices[i++] * vertsStride; int coord1 = indices[i++] * vertsStride; int coord2 = indices[i++] * vertsStride; // remember that these points are connected to this triangle connectedTris.put(coord0, new TriangleListNode(triangleIndex, connectedTris.get(coord0))); connectedTris.put(coord1, new TriangleListNode(triangleIndex, connectedTris.get(coord1))); connectedTris.put(coord2, new TriangleListNode(triangleIndex, connectedTris.get(coord2))); // compute the normal of the triangle float ux = verts[coord1] - verts[coord0]; float uy = verts[coord1 + 1] - verts[coord0 + 1]; float uz = verts[coord1 + 2] - verts[coord0 + 2]; float vx = verts[coord2] - verts[coord0]; float vy = verts[coord2 + 1] - verts[coord0 + 1]; float vz = verts[coord2 + 2] - verts[coord0 + 2]; triNormals[normalIndex++] = uy * vz - uz * vy; triNormals[normalIndex++] = uz * vx - ux * vz; triNormals[normalIndex++] = ux * vy - uy * vx; } // set the normal of each point to the normalized sum of the normals of // the triangles connected to that point for (Map.Entry<Integer, TriangleListNode> entry : connectedTris.entrySet()) { int pi = entry.getKey(); TriangleListNode node = entry.getValue(); float x = 0; float y = 0; float z = 0; while (node != null) { int triNormalIndex = node.triangleIndex - indicesStart; x += triNormals[triNormalIndex]; y += triNormals[triNormalIndex + 1]; z += triNormals[triNormalIndex + 2]; node = node.next; } float normFactor = 1f / (float) Math.sqrt(x * x + y * y + z * z); normalIndex = pi + normalOffset; verts[normalIndex++] = x * normFactor; verts[normalIndex++] = y * normFactor; verts[normalIndex++] = z * normFactor; } } public static void generateNormals3fi(ByteBuffer verts, int normalOffset, int vertsStride, ByteBuffer indices, int indicesStart, int indicesEnd) { Map<Integer, TriangleListNode> connectedTris = new HashMap<Integer, TriangleListNode>(); float[] triNormals = new float[indicesEnd - indicesStart]; int normalIndex = 0; indices.position(indicesStart); int i = indicesStart; while (i < indicesEnd) { int triangleIndex = i; int coord0 = indices.getInt() * vertsStride; int coord1 = indices.getInt() * vertsStride; int coord2 = indices.getInt() * vertsStride; // remember that these points are connected to this triangle connectedTris.put(coord0, new TriangleListNode(triangleIndex, connectedTris.get(coord0))); connectedTris.put(coord1, new TriangleListNode(triangleIndex, connectedTris.get(coord1))); connectedTris.put(coord2, new TriangleListNode(triangleIndex, connectedTris.get(coord2))); // compute the normal of the triangle float ux = verts.getFloat(coord1) - verts.getFloat(coord0); float uy = verts.getFloat(coord1 + 4) - verts.getFloat(coord0 + 4); float uz = verts.getFloat(coord1 + 8) - verts.getFloat(coord0 + 8); float vx = verts.getFloat(coord2) - verts.getFloat(coord0); float vy = verts.getFloat(coord2 + 4) - verts.getFloat(coord0 + 4); float vz = verts.getFloat(coord2 + 8) - verts.getFloat(coord0 + 8); triNormals[normalIndex++] = uy * vz - uz * vy; triNormals[normalIndex++] = uz * vx - ux * vz; triNormals[normalIndex++] = ux * vy - uy * vx; i += 3; } // set the normal of each point to the normalized sum of the normals of // the triangles connected to that point for (Map.Entry<Integer, TriangleListNode> entry : connectedTris.entrySet()) { int pi = entry.getKey(); TriangleListNode node = entry.getValue(); float x = 0; float y = 0; float z = 0; while (node != null) { int triNormalIndex = node.triangleIndex - indicesStart; x += triNormals[triNormalIndex]; y += triNormals[triNormalIndex + 1]; z += triNormals[triNormalIndex + 2]; node = node.next; } float normFactor = 1f / (float) Math.sqrt(x * x + y * y + z * z); normalIndex = pi + normalOffset; verts.putFloat(normalIndex, x * normFactor); verts.putFloat(normalIndex + 4, y * normFactor); verts.putFloat(normalIndex + 8, z * normFactor); } } }