/*********************************************************************** * mt4j Copyright (c) 2008 - 2009 C.Ruff, Fraunhofer-Gesellschaft All rights reserved. * * 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 3 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, see <http://www.gnu.org/licenses/>. * ***********************************************************************/ package org.mt4j.util.math; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.nio.IntBuffer; /** * Methods to build Buffers for use with vertex/texture/color arrays in opengl * Some methods are adapted from the JME. * * @author C.Ruff */ public class ToolsBuffers { //////////////////////////////////////////////////////////// // Methods to build Buffers for use with vertex/texture/color arrays in opengl ////////////////////////////////////////////////////// /** * Generate vertex buffer. * * @param vertices the vertices * * @return the float buffer */ public static FloatBuffer generateVertexBuffer(Vector3D[] vertices){ float[] xyz; int vertixCount = vertices.length; xyz = new float[vertixCount*3]; for (int i = 0; i < vertixCount; i++) { xyz[i*3] = vertices[i].getX(); xyz[i*3+1]= vertices[i].getY(); xyz[i*3+2]= vertices[i].getZ(); } FloatBuffer vertBuff = createFloatBuffer(xyz.length); vertBuff.put(xyz); vertBuff.rewind(); return vertBuff; } /** * Generate color buffer. * * @param vertices the vertices * * @return the float buffer */ public static FloatBuffer generateColorBuffer(Vertex[] vertices){ float[] rgb; int vertexCount = vertices.length; rgb = new float[vertexCount*4]; for (int i = 0; i < vertexCount; i++) { rgb[i*4]= vertices[i].getR()/255f; rgb[i*4+1]= vertices[i].getG()/255f; rgb[i*4+2]= vertices[i].getB()/255f; rgb[i*4+3]= vertices[i].getA()/255f; } FloatBuffer colorBuff = createFloatBuffer(rgb.length); colorBuff.put(rgb); colorBuff.rewind(); return colorBuff; } /** * Update color buffer. * * @param v the v * @param buf the buf */ public static void updateColorBuffer(Vertex[] v, FloatBuffer buf){ buf.rewind(); for (int i = 0; i < v.length; i++) { buf.put(i * 4 , v[i].getR()/255f); buf.put((i * 4) + 1, v[i].getG()/255f); buf.put((i * 4) + 2, v[i].getB()/255f); buf.put((i * 4) + 3, v[i].getA()/255f); } buf.clear(); } /** * Generate stroke color buffer. * * @param vertexCount the vertex count * @param r the r * @param g the g * @param b the b * @param a the a * * @return the float buffer */ public static FloatBuffer generateStrokeColorBuffer(int vertexCount, float r, float g, float b, float a){ float[] rgb; rgb = new float[vertexCount*4]; for (int i = 0; i < vertexCount; i++) { rgb[i*4]= r/255; rgb[i*4+1]= g/255; rgb[i*4+2]= b/255; rgb[i*4+3]= a/255; } FloatBuffer strokeColBuff = createFloatBuffer(rgb.length); strokeColBuff.put(rgb); strokeColBuff.rewind(); return strokeColBuff; } /** * Update stroke color buffer. * * @param buf the buf * @param r the r * @param g the g * @param b the b * @param a the a */ public static void updateStrokeColorBuffer(FloatBuffer buf, float r, float g, float b, float a){ float rr = r/255f; float gg = g/255f; float bb = b/255f; float aa = a/255f; buf.rewind(); while(buf.hasRemaining()){ buf.put(rr); buf.put(gg); buf.put(bb); buf.put(aa); } buf.clear(); } /** * Generate texture buffer. * * @param vertices the vertices * * @return the float buffer */ public static FloatBuffer generateTextureBuffer(Vertex[] vertices){ float[] textureCoords; int vertixCount = vertices.length; textureCoords = new float[vertixCount*2]; for (int i = 0; i < vertixCount; i++) { Vertex vertex = vertices[i]; textureCoords[i*2]= vertex.getTexCoordU(); textureCoords[i*2+1]= vertex.getTexCoordV(); } FloatBuffer tBuffer = createFloatBuffer(textureCoords.length); tBuffer.put(textureCoords); tBuffer.rewind(); return tBuffer; } /** * Generate normals buffer. * * @param normals the normals * * @return the float buffer */ public static FloatBuffer generateNormalsBuffer(Vector3D[] normals){ return generateVertexBuffer(normals); /* float[] xyz; int normalsCount = normals.length; xyz = new float[normalsCount*3]; for (int i = 0; i < normalsCount; i++) { xyz[i*3] = normals[i].getX(); xyz[i*3+1]= normals[i].getY(); xyz[i*3+2]= normals[i].getZ(); } FloatBuffer normalsBuff = createFloatBuffer(xyz.length); normalsBuff.put(xyz); normalsBuff.rewind(); return normalsBuff; */ } /** * Generate indices buffer. * * @param indicesArray the indices array * * @return the int buffer */ public static IntBuffer generateIndicesBuffer(int[] indicesArray){ IntBuffer indexBuff = createIntBuffer(indicesArray.length); indexBuff.put(indicesArray); indexBuff.rewind(); return indexBuff; } /** * Sets the data contained in the given Vector3D into the FloatBuffer at the * specified index. Should work with vector and vertex. * * @param vector the data to insert * @param buf the buffer to insert into * @param index the postion to place the data; in terms of vectors not floats */ public static void setInBuffer(Vector3D vector, FloatBuffer buf, int index) { if (buf == null) { return; } if (vector == null) { buf.put(index * 3, 0); buf.put((index * 3) + 1, 0); buf.put((index * 3) + 2, 0); } else { buf.put(index * 3, vector.x); buf.put((index * 3) + 1, vector.y); buf.put((index * 3) + 2, vector.z); } } public static void setInBuffer(float x, float y, float z, FloatBuffer buf, int index) { if (buf == null) { return; } buf.put(index * 3, x); buf.put((index * 3) + 1, y); buf.put((index * 3) + 2, z); } /** * Sets the data contained in the given Vector into the FloatBuffer at the * specified index. Should work with vector and vertex. * * @param vector the data to insert * @param buf the buffer to insert into * @param index the postion to place the data; in terms of vectors not floats */ public static void setInBuffer(float[] vector, FloatBuffer buf, int index) { if (buf == null) { return; } buf.put(index * 3, vector[0]); buf.put((index * 3) + 1, vector[1]); buf.put((index * 3) + 2, vector[2]); } /** * Generates a Vector3D array from the given FloatBuffer. * * @param buff the FloatBuffer to read from * * @return a newly generated array of Vector3D objects */ public static Vector3D[] getVector3DArray(FloatBuffer buff) { buff.clear(); //this doesent delete its contents! Vector3D[] verts = new Vector3D[buff.limit() / 3]; for (int x = 0; x < verts.length; x++) { Vector3D v = new Vector3D(buff.get(), buff.get(), buff.get()); verts[x] = v; } buff.clear(); //Reset position to 0 again return verts; } /** * Generates a Vector3D array from the given FloatBuffer. * * @param buff the FloatBuffer to read from * * @return a newly generated array of Vector3D objects */ public static float[][] getRGBAColorArray(FloatBuffer buff) { buff.rewind(); //this doesent delete its contents! float[][] colorArray = new float[buff.limit() / 4][4]; for (int x = 0; x < colorArray.length; x++) { colorArray[x][0] = buff.get(); colorArray[x][1] = buff.get(); colorArray[x][2] = buff.get(); colorArray[x][3] = buff.get(); } buff.clear(); //Reset position to 0 again return colorArray; } /** * Generates a Vector3f array from the given FloatBuffer. * * @param buff the FloatBuffer to read from * * @return a newly generated array of Vector3D objects */ public static Vertex[] getVertexArray(FloatBuffer buff) { buff.clear(); //Dosent delete its contents! Vertex[] verts = new Vertex[buff.limit() / 3]; for (int x = 0; x < verts.length; x++) { Vertex v = new Vertex(buff.get(), buff.get(), buff.get()); verts[x] = v; } buff.clear(); //Reset position to 0 again return verts; } /** * Create a new int[] array and populates * it with the given IntBuffer's contents. * * @param buff the IntBuffer to read from * * @return a new int array populated from the IntBuffer */ public static int[] getIntArray(IntBuffer buff) { if (buff == null) return null; buff.clear(); int[] inds = new int[buff.limit()]; for (int x = 0; x < inds.length; x++) { inds[x] = buff.get(); } buff.clear(); //Reset position to 0 again return inds; } /** * Create a new float[] array and populate it with the given FloatBuffer's * contents. * * @param buff the FloatBuffer to read from * * @return a new float array populated from the FloatBuffer */ public static float[] getFloatArray(FloatBuffer buff) { if (buff == null) return null; buff.clear(); float[] inds = new float[buff.limit()]; for (int x = 0; x < inds.length; x++) { inds[x] = buff.get(); } buff.clear(); //Reset position to 0 again return inds; } /** * Creates a new FloatBuffer with the same contents as the given * FloatBuffer. The new FloatBuffer is seperate from the old one and changes * are not reflected across. If you want to reflect changes, consider using * Buffer.duplicate(). * * @param buf the FloatBuffer to copy * * @return the copy */ public static FloatBuffer clone(FloatBuffer buf) { if (buf == null) return null; buf.rewind(); FloatBuffer copy = createFloatBuffer(buf.limit()); copy.put(buf); return copy; } /** * Creates a new IntBuffer with the same contents as the given IntBuffer. * The new IntBuffer is seperate from the old one and changes are not * reflected across. If you want to reflect changes, consider using * Buffer.duplicate(). * * @param buf the IntBuffer to copy * * @return the copy */ public static IntBuffer clone(IntBuffer buf) { if (buf == null) return null; buf.rewind(); IntBuffer copy = createIntBuffer(buf.limit()); copy.put(buf); return copy; } /** * Ensures there is at least the <code>required</code> number of entries left after the current position of the * buffer. If the buffer is too small a larger one is created and the old one copied to the new buffer. * * @param buffer buffer that should be checked/copied (may be null) * @param required minimum number of elements that should be remaining in the returned buffer * * @return a buffer large enough to receive at least the <code>required</code> number of entries, same position as * the input buffer, not null */ public static FloatBuffer ensureLargeEnough( FloatBuffer buffer, int required ) { if ( buffer == null || ( buffer.remaining() < required ) ) { int position = ( buffer != null ? buffer.position() : 0 ); FloatBuffer newVerts = createFloatBuffer( position + required ); if ( buffer != null ) { buffer.rewind(); newVerts.put( buffer ); newVerts.position( position ); } buffer = newVerts; } return buffer; } /** * Create a new ByteBuffer of an appropriate size to hold the specified * number of ints only if the given buffer if not already the right size. * * @param buf the buffer to first check and rewind * @param size number of bytes that need to be held by the newly created * buffer * * @return the requested new IntBuffer */ public static ByteBuffer createByteBuffer(ByteBuffer buf, int size) { if (buf != null && buf.limit() == size) { buf.rewind(); return buf; } buf = createByteBuffer(size); return buf; } /** * Create a new empty FloatBuffer of the specified size. * * @param size required number of floats to store. * * @return the new FloatBuffer */ public static FloatBuffer createFloatBuffer(int size) { FloatBuffer buf = ByteBuffer.allocateDirect(4 * size).order(ByteOrder.nativeOrder()).asFloatBuffer(); buf.clear(); return buf; } /** * Create a new FloatBuffer of an appropriate size to hold the specified * number of Vector3D object data. * * @param vertices * number of vertices that need to be held by the newly created * buffer * @return the requested new FloatBuffer */ public static FloatBuffer createVector3Buffer(int vertices) { FloatBuffer vBuff = createFloatBuffer(3 * vertices); return vBuff; } /** * Create a new IntBuffer of the specified size. * * @param size required number of ints to store. * * @return the new IntBuffer */ public static IntBuffer createIntBuffer(int size) { IntBuffer buf = ByteBuffer.allocateDirect(4 * size).order(ByteOrder.nativeOrder()).asIntBuffer(); buf.clear(); return buf; } /** * Create a new ByteBuffer of the specified size. * * @param size required number of ints to store. * * @return the new IntBuffer */ public static ByteBuffer createByteBuffer(int size) { ByteBuffer buf = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder()); buf.clear(); return buf; } /** * Updates the values of the given vector from the specified buffer at the * index provided. * * @param vector * the vector to set data on * @param buf * the buffer to read from * @param index * the position (in terms of vectors, not floats) to read from * the buf */ public static void populateFromBuffer(Vector3D vector, FloatBuffer buf, int index) { vector.x = buf.get(index*3); vector.y = buf.get(index*3+1); vector.z = buf.get(index*3+2); } /** * Copies floats from one position in the buffer to another. * * @param buf * the buffer to copy from/to * @param fromPos * the starting point to copy from * @param toPos * the starting point to copy to * @param length * the number of floats to copy */ public static void copyInternal(FloatBuffer buf, int fromPos, int toPos, int length) { float[] data = new float[length]; buf.position(fromPos); buf.get(data); buf.position(toPos); buf.put(data); } }