Przeglądaj źródła

whitespace tab to 4spaces formating only change

Signed-off-by: Kai Boernert <[email protected]>
Kai Boernert 9 lat temu
rodzic
commit
b4c6febe4c

+ 1297 - 1288
jme3-core/src/main/java/com/jme3/util/BufferUtils.java

@@ -59,1294 +59,1303 @@ import com.jme3.math.Vector4f;
  * @version $Id: BufferUtils.java,v 1.16 2007/10/29 16:56:18 nca Exp $
  */
 public final class BufferUtils {
-	private static BufferAllocator								allocator = new PrimitiveAllocator();
-
-	private static boolean										trackDirectMemory	= false;
-	private static ReferenceQueue<Buffer>						removeCollected		= new ReferenceQueue<Buffer>();
-	private static ConcurrentHashMap<BufferInfo, BufferInfo>	trackedBuffers		= new ConcurrentHashMap<BufferInfo, BufferInfo>();
-	static ClearReferences										cleanupthread;
-
-	private static boolean										used;
-
-	static {
-		try {
-			allocator = new ReflectionAllocator();
-		} catch (Throwable t) {
-			t.printStackTrace();
-			System.err.println("Error using ReflectionAllocator");
-		}
-	}
-
-	/**
-	 * Warning! do only set this before JME is started!
-	 */
-	public static void setAllocator(BufferAllocator allocator) {
-		if (used) {
-			throw new IllegalStateException(
-					"An Buffer was already allocated, since it is quite likely that other dispose methods will create native dangling pointers or other fun things, this is forbidden to be changed at runtime");
-		}
-		BufferUtils.allocator = allocator;
-	}
-
-	/**
-	 * Set it to true if you want to enable direct memory tracking for debugging
-	 * purpose. Default is false. To print direct memory usage use
-	 * BufferUtils.printCurrentDirectMemory(StringBuilder store);
-	 * 
-	 * @param enabled
-	 */
-	public static void setTrackDirectMemoryEnabled(boolean enabled) {
-		trackDirectMemory = enabled;
-	}
-
-	/**
-	 * Creates a clone of the given buffer. The clone's capacity is equal to the
-	 * given buffer's limit.
-	 * 
-	 * @param buf
-	 *            The buffer to clone
-	 * @return The cloned buffer
-	 */
-	public static Buffer clone(Buffer buf) {
-		if (buf instanceof FloatBuffer) {
-			return clone((FloatBuffer) buf);
-		} else if (buf instanceof ShortBuffer) {
-			return clone((ShortBuffer) buf);
-		} else if (buf instanceof ByteBuffer) {
-			return clone((ByteBuffer) buf);
-		} else if (buf instanceof IntBuffer) {
-			return clone((IntBuffer) buf);
-		} else if (buf instanceof DoubleBuffer) {
-			return clone((DoubleBuffer) buf);
-		} else {
-			throw new UnsupportedOperationException();
-		}
-	}
-
-	private static void onBufferAllocated(Buffer buffer) {
-		used = true;
-		if (BufferUtils.trackDirectMemory) {
-			if (BufferUtils.cleanupthread == null) {
-				BufferUtils.cleanupthread = new ClearReferences();
-				BufferUtils.cleanupthread.start();
-			}
-			if (buffer instanceof ByteBuffer) {
-				BufferInfo info = new BufferInfo(ByteBuffer.class, buffer.capacity(), buffer, BufferUtils.removeCollected);
-				BufferUtils.trackedBuffers.put(info, info);
-			} else if (buffer instanceof FloatBuffer) {
-				BufferInfo info = new BufferInfo(FloatBuffer.class, buffer.capacity() * 4, buffer, BufferUtils.removeCollected);
-				BufferUtils.trackedBuffers.put(info, info);
-			} else if (buffer instanceof IntBuffer) {
-				BufferInfo info = new BufferInfo(IntBuffer.class, buffer.capacity() * 4, buffer, BufferUtils.removeCollected);
-				BufferUtils.trackedBuffers.put(info, info);
-			} else if (buffer instanceof ShortBuffer) {
-				BufferInfo info = new BufferInfo(ShortBuffer.class, buffer.capacity() * 2, buffer, BufferUtils.removeCollected);
-				BufferUtils.trackedBuffers.put(info, info);
-			} else if (buffer instanceof DoubleBuffer) {
-				BufferInfo info = new BufferInfo(DoubleBuffer.class, buffer.capacity() * 8, buffer, BufferUtils.removeCollected);
-				BufferUtils.trackedBuffers.put(info, info);
-			}
-
-		}
-	}
-
-	/**
-	 * Generate a new FloatBuffer using the given array of Vector3f objects. The
-	 * FloatBuffer will be 3 * data.length long and contain the vector data as
-	 * data[0].x, data[0].y, data[0].z, data[1].x... etc.
-	 * 
-	 * @param data
-	 *            array of Vector3f objects to place into a new FloatBuffer
-	 */
-	public static FloatBuffer createFloatBuffer(Vector3f... data) {
-		if (data == null) {
-			return null;
-		}
-		FloatBuffer buff = createFloatBuffer(3 * data.length);
-		for (Vector3f element : data) {
-			if (element != null) {
-				buff.put(element.x).put(element.y).put(element.z);
-			} else {
-				buff.put(0).put(0).put(0);
-			}
-		}
-		buff.flip();
-		return buff;
-	}
-
-	/**
-	 * Generate a new FloatBuffer using the given array of Quaternion objects.
-	 * The FloatBuffer will be 4 * data.length long and contain the vector data.
-	 * 
-	 * @param data
-	 *            array of Quaternion objects to place into a new FloatBuffer
-	 */
-	public static FloatBuffer createFloatBuffer(Quaternion... data) {
-		if (data == null) {
-			return null;
-		}
-		FloatBuffer buff = createFloatBuffer(4 * data.length);
-		for (Quaternion element : data) {
-			if (element != null) {
-				buff.put(element.getX()).put(element.getY()).put(element.getZ()).put(element.getW());
-			} else {
-				buff.put(0).put(0).put(0).put(0);
-			}
-		}
-		buff.flip();
-		return buff;
-	}
-
-	/**
-	 * Generate a new FloatBuffer using the given array of Vector4 objects. The
-	 * FloatBuffer will be 4 * data.length long and contain the vector data.
-	 *
-	 * @param data
-	 *            array of Vector4 objects to place into a new FloatBuffer
-	 */
-	public static FloatBuffer createFloatBuffer(Vector4f... data) {
-		if (data == null) {
-			return null;
-		}
-		FloatBuffer buff = createFloatBuffer(4 * data.length);
-		for (int x = 0; x < data.length; x++) {
-			if (data[x] != null) {
-				buff.put(data[x].getX()).put(data[x].getY()).put(data[x].getZ()).put(data[x].getW());
-			} else {
-				buff.put(0).put(0).put(0).put(0);
-			}
-		}
-		buff.flip();
-		return buff;
-	}
-
-	/**
-	 * Generate a new FloatBuffer using the given array of ColorRGBA objects.
-	 * The FloatBuffer will be 4 * data.length long and contain the color data.
-	 *
-	 * @param data
-	 *            array of ColorRGBA objects to place into a new FloatBuffer
-	 */
-	public static FloatBuffer createFloatBuffer(ColorRGBA... data) {
-		if (data == null) {
-			return null;
-		}
-		FloatBuffer buff = createFloatBuffer(4 * data.length);
-		for (int x = 0; x < data.length; x++) {
-			if (data[x] != null) {
-				buff.put(data[x].getRed()).put(data[x].getGreen()).put(data[x].getBlue()).put(data[x].getAlpha());
-			} else {
-				buff.put(0).put(0).put(0).put(0);
-			}
-		}
-		buff.flip();
-		return buff;
-	}
-
-	/**
-	 * Generate a new FloatBuffer using the given array of float primitives.
-	 * 
-	 * @param data
-	 *            array of float primitives to place into a new FloatBuffer
-	 */
-	public static FloatBuffer createFloatBuffer(float... data) {
-		if (data == null) {
-			return null;
-		}
-		FloatBuffer buff = createFloatBuffer(data.length);
-		buff.clear();
-		buff.put(data);
-		buff.flip();
-		return buff;
-	}
-
-	/**
-	 * Create a new FloatBuffer of an appropriate size to hold the specified
-	 * number of Vector3f 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 FloatBuffer of an appropriate size to hold the specified
-	 * number of Vector3f object data only if the given buffer if not already
-	 * the right size.
-	 * 
-	 * @param buf
-	 *            the buffer to first check and rewind
-	 * @param vertices
-	 *            number of vertices that need to be held by the newly created
-	 *            buffer
-	 * @return the requested new FloatBuffer
-	 */
-	public static FloatBuffer createVector3Buffer(FloatBuffer buf, int vertices) {
-		if (buf != null && buf.limit() == 3 * vertices) {
-			buf.rewind();
-			return buf;
-		}
-
-		return createFloatBuffer(3 * vertices);
-	}
-
-	/**
-	 * Sets the data contained in the given color into the FloatBuffer at the
-	 * specified index.
-	 * 
-	 * @param color
-	 *            the data to insert
-	 * @param buf
-	 *            the buffer to insert into
-	 * @param index
-	 *            the postion to place the data; in terms of colors not floats
-	 */
-	public static void setInBuffer(ColorRGBA color, FloatBuffer buf, int index) {
-		buf.position(index * 4);
-		buf.put(color.r);
-		buf.put(color.g);
-		buf.put(color.b);
-		buf.put(color.a);
-	}
-
-	/**
-	 * Sets the data contained in the given quaternion into the FloatBuffer at
-	 * the specified index.
-	 * 
-	 * @param quat
-	 *            the {@link Quaternion} to insert
-	 * @param buf
-	 *            the buffer to insert into
-	 * @param index
-	 *            the position to place the data; in terms of quaternions not
-	 *            floats
-	 */
-	public static void setInBuffer(Quaternion quat, FloatBuffer buf, int index) {
-		buf.position(index * 4);
-		buf.put(quat.getX());
-		buf.put(quat.getY());
-		buf.put(quat.getZ());
-		buf.put(quat.getW());
-	}
-
-	/**
-	 * Sets the data contained in the given vector4 into the FloatBuffer at the
-	 * specified index.
-	 *
-	 * @param vec
-	 *            the {@link Vector4f} to insert
-	 * @param buf
-	 *            the buffer to insert into
-	 * @param index
-	 *            the position to place the data; in terms of vector4 not floats
-	 */
-	public static void setInBuffer(Vector4f vec, FloatBuffer buf, int index) {
-		buf.position(index * 4);
-		buf.put(vec.getX());
-		buf.put(vec.getY());
-		buf.put(vec.getZ());
-		buf.put(vec.getW());
-	}
-
-	/**
-	 * Sets the data contained in the given Vector3F into the FloatBuffer at the
-	 * specified index.
-	 * 
-	 * @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(Vector3f 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);
-		}
-	}
-
-	/**
-	 * 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(Vector3f 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);
-	}
-
-	/**
-	 * 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(Vector4f vector, FloatBuffer buf, int index) {
-		vector.x = buf.get(index * 4);
-		vector.y = buf.get(index * 4 + 1);
-		vector.z = buf.get(index * 4 + 2);
-		vector.w = buf.get(index * 4 + 3);
-	}
-
-	/**
-	 * Generates a Vector3f array from the given FloatBuffer.
-	 * 
-	 * @param buff
-	 *            the FloatBuffer to read from
-	 * @return a newly generated array of Vector3f objects
-	 */
-	public static Vector3f[] getVector3Array(FloatBuffer buff) {
-		buff.clear();
-		Vector3f[] verts = new Vector3f[buff.limit() / 3];
-		for (int x = 0; x < verts.length; x++) {
-			Vector3f v = new Vector3f(buff.get(), buff.get(), buff.get());
-			verts[x] = v;
-		}
-		return verts;
-	}
-
-	/**
-	 * Copies a Vector3f from one position in the buffer to another. The index
-	 * values are in terms of vector number (eg, vector number 0 is positions
-	 * 0-2 in the FloatBuffer.)
-	 * 
-	 * @param buf
-	 *            the buffer to copy from/to
-	 * @param fromPos
-	 *            the index of the vector to copy
-	 * @param toPos
-	 *            the index to copy the vector to
-	 */
-	public static void copyInternalVector3(FloatBuffer buf, int fromPos, int toPos) {
-		copyInternal(buf, fromPos * 3, toPos * 3, 3);
-	}
-
-	/**
-	 * Normalize a Vector3f in-buffer.
-	 * 
-	 * @param buf
-	 *            the buffer to find the Vector3f within
-	 * @param index
-	 *            the position (in terms of vectors, not floats) of the vector
-	 *            to normalize
-	 */
-	public static void normalizeVector3(FloatBuffer buf, int index) {
-		TempVars vars = TempVars.get();
-		Vector3f tempVec3 = vars.vect1;
-		populateFromBuffer(tempVec3, buf, index);
-		tempVec3.normalizeLocal();
-		setInBuffer(tempVec3, buf, index);
-		vars.release();
-	}
-
-	/**
-	 * Add to a Vector3f in-buffer.
-	 * 
-	 * @param toAdd
-	 *            the vector to add from
-	 * @param buf
-	 *            the buffer to find the Vector3f within
-	 * @param index
-	 *            the position (in terms of vectors, not floats) of the vector
-	 *            to add to
-	 */
-	public static void addInBuffer(Vector3f toAdd, FloatBuffer buf, int index) {
-		TempVars vars = TempVars.get();
-		Vector3f tempVec3 = vars.vect1;
-		populateFromBuffer(tempVec3, buf, index);
-		tempVec3.addLocal(toAdd);
-		setInBuffer(tempVec3, buf, index);
-		vars.release();
-	}
-
-	/**
-	 * Multiply and store a Vector3f in-buffer.
-	 * 
-	 * @param toMult
-	 *            the vector to multiply against
-	 * @param buf
-	 *            the buffer to find the Vector3f within
-	 * @param index
-	 *            the position (in terms of vectors, not floats) of the vector
-	 *            to multiply
-	 */
-	public static void multInBuffer(Vector3f toMult, FloatBuffer buf, int index) {
-		TempVars vars = TempVars.get();
-		Vector3f tempVec3 = vars.vect1;
-		populateFromBuffer(tempVec3, buf, index);
-		tempVec3.multLocal(toMult);
-		setInBuffer(tempVec3, buf, index);
-		vars.release();
-	}
-
-	/**
-	 * Checks to see if the given Vector3f is equals to the data stored in the
-	 * buffer at the given data index.
-	 * 
-	 * @param check
-	 *            the vector to check against - null will return false.
-	 * @param buf
-	 *            the buffer to compare data with
-	 * @param index
-	 *            the position (in terms of vectors, not floats) of the vector
-	 *            in the buffer to check against
-	 * @return true if the data is equivalent, otherwise false.
-	 */
-	public static boolean equals(Vector3f check, FloatBuffer buf, int index) {
-		TempVars vars = TempVars.get();
-		Vector3f tempVec3 = vars.vect1;
-		populateFromBuffer(tempVec3, buf, index);
-		boolean eq = tempVec3.equals(check);
-		vars.release();
-		return eq;
-	}
-
-	// // -- VECTOR2F METHODS -- ////
-	/**
-	 * Generate a new FloatBuffer using the given array of Vector2f objects. The
-	 * FloatBuffer will be 2 * data.length long and contain the vector data as
-	 * data[0].x, data[0].y, data[1].x... etc.
-	 * 
-	 * @param data
-	 *            array of Vector2f objects to place into a new FloatBuffer
-	 */
-	public static FloatBuffer createFloatBuffer(Vector2f... data) {
-		if (data == null) {
-			return null;
-		}
-		FloatBuffer buff = createFloatBuffer(2 * data.length);
-		for (Vector2f element : data) {
-			if (element != null) {
-				buff.put(element.x).put(element.y);
-			} else {
-				buff.put(0).put(0);
-			}
-		}
-		buff.flip();
-		return buff;
-	}
-
-	/**
-	 * Create a new FloatBuffer of an appropriate size to hold the specified
-	 * number of Vector2f 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 createVector2Buffer(int vertices) {
-		FloatBuffer vBuff = createFloatBuffer(2 * vertices);
-		return vBuff;
-	}
-
-	/**
-	 * Create a new FloatBuffer of an appropriate size to hold the specified
-	 * number of Vector2f object data only if the given buffer if not already
-	 * the right size.
-	 * 
-	 * @param buf
-	 *            the buffer to first check and rewind
-	 * @param vertices
-	 *            number of vertices that need to be held by the newly created
-	 *            buffer
-	 * @return the requested new FloatBuffer
-	 */
-	public static FloatBuffer createVector2Buffer(FloatBuffer buf, int vertices) {
-		if (buf != null && buf.limit() == 2 * vertices) {
-			buf.rewind();
-			return buf;
-		}
-
-		return createFloatBuffer(2 * vertices);
-	}
-
-	/**
-	 * Sets the data contained in the given Vector2F into the FloatBuffer at the
-	 * specified index.
-	 * 
-	 * @param vector
-	 *            the data to insert
-	 * @param buf
-	 *            the buffer to insert into
-	 * @param index
-	 *            the position to place the data; in terms of vectors not floats
-	 */
-	public static void setInBuffer(Vector2f vector, FloatBuffer buf, int index) {
-		buf.put(index * 2, vector.x);
-		buf.put((index * 2) + 1, vector.y);
-	}
-
-	/**
-	 * 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(Vector2f vector, FloatBuffer buf, int index) {
-		vector.x = buf.get(index * 2);
-		vector.y = buf.get(index * 2 + 1);
-	}
-
-	/**
-	 * Generates a Vector2f array from the given FloatBuffer.
-	 * 
-	 * @param buff
-	 *            the FloatBuffer to read from
-	 * @return a newly generated array of Vector2f objects
-	 */
-	public static Vector2f[] getVector2Array(FloatBuffer buff) {
-		buff.clear();
-		Vector2f[] verts = new Vector2f[buff.limit() / 2];
-		for (int x = 0; x < verts.length; x++) {
-			Vector2f v = new Vector2f(buff.get(), buff.get());
-			verts[x] = v;
-		}
-		return verts;
-	}
-
-	/**
-	 * Copies a Vector2f from one position in the buffer to another. The index
-	 * values are in terms of vector number (eg, vector number 0 is positions
-	 * 0-1 in the FloatBuffer.)
-	 * 
-	 * @param buf
-	 *            the buffer to copy from/to
-	 * @param fromPos
-	 *            the index of the vector to copy
-	 * @param toPos
-	 *            the index to copy the vector to
-	 */
-	public static void copyInternalVector2(FloatBuffer buf, int fromPos, int toPos) {
-		copyInternal(buf, fromPos * 2, toPos * 2, 2);
-	}
-
-	/**
-	 * Normalize a Vector2f in-buffer.
-	 * 
-	 * @param buf
-	 *            the buffer to find the Vector2f within
-	 * @param index
-	 *            the position (in terms of vectors, not floats) of the vector
-	 *            to normalize
-	 */
-	public static void normalizeVector2(FloatBuffer buf, int index) {
-		TempVars vars = TempVars.get();
-		Vector2f tempVec2 = vars.vect2d;
-		populateFromBuffer(tempVec2, buf, index);
-		tempVec2.normalizeLocal();
-		setInBuffer(tempVec2, buf, index);
-		vars.release();
-	}
-
-	/**
-	 * Add to a Vector2f in-buffer.
-	 * 
-	 * @param toAdd
-	 *            the vector to add from
-	 * @param buf
-	 *            the buffer to find the Vector2f within
-	 * @param index
-	 *            the position (in terms of vectors, not floats) of the vector
-	 *            to add to
-	 */
-	public static void addInBuffer(Vector2f toAdd, FloatBuffer buf, int index) {
-		TempVars vars = TempVars.get();
-		Vector2f tempVec2 = vars.vect2d;
-		populateFromBuffer(tempVec2, buf, index);
-		tempVec2.addLocal(toAdd);
-		setInBuffer(tempVec2, buf, index);
-		vars.release();
-	}
-
-	/**
-	 * Multiply and store a Vector2f in-buffer.
-	 * 
-	 * @param toMult
-	 *            the vector to multiply against
-	 * @param buf
-	 *            the buffer to find the Vector2f within
-	 * @param index
-	 *            the position (in terms of vectors, not floats) of the vector
-	 *            to multiply
-	 */
-	public static void multInBuffer(Vector2f toMult, FloatBuffer buf, int index) {
-		TempVars vars = TempVars.get();
-		Vector2f tempVec2 = vars.vect2d;
-		populateFromBuffer(tempVec2, buf, index);
-		tempVec2.multLocal(toMult);
-		setInBuffer(tempVec2, buf, index);
-		vars.release();
-	}
-
-	/**
-	 * Checks to see if the given Vector2f is equals to the data stored in the
-	 * buffer at the given data index.
-	 * 
-	 * @param check
-	 *            the vector to check against - null will return false.
-	 * @param buf
-	 *            the buffer to compare data with
-	 * @param index
-	 *            the position (in terms of vectors, not floats) of the vector
-	 *            in the buffer to check against
-	 * @return true if the data is equivalent, otherwise false.
-	 */
-	public static boolean equals(Vector2f check, FloatBuffer buf, int index) {
-		TempVars vars = TempVars.get();
-		Vector2f tempVec2 = vars.vect2d;
-		populateFromBuffer(tempVec2, buf, index);
-		boolean eq = tempVec2.equals(check);
-		vars.release();
-		return eq;
-	}
-
-	//// -- INT METHODS -- ////
-	/**
-	 * Generate a new IntBuffer using the given array of ints. The IntBuffer
-	 * will be data.length long and contain the int data as data[0], data[1]...
-	 * etc.
-	 * 
-	 * @param data
-	 *            array of ints to place into a new IntBuffer
-	 */
-	public static IntBuffer createIntBuffer(int... data) {
-		if (data == null) {
-			return null;
-		}
-		IntBuffer buff = createIntBuffer(data.length);
-		buff.clear();
-		buff.put(data);
-		buff.flip();
-		return buff;
-	}
-
-	/**
-	 * Create a new int[] array and populate 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();
-		}
-		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();
-		}
-		return inds;
-	}
-
-	//// -- GENERAL DOUBLE ROUTINES -- ////
-	/**
-	 * Create a new DoubleBuffer of the specified size.
-	 * 
-	 * @param size
-	 *            required number of double to store.
-	 * @return the new DoubleBuffer
-	 */
-	public static DoubleBuffer createDoubleBuffer(int size) {
-		DoubleBuffer buf = allocator.allocate(8 * size).order(ByteOrder.nativeOrder()).asDoubleBuffer();
-		buf.clear();
-		onBufferAllocated(buf);
-		return buf;
-	}
-
-	/**
-	 * Create a new DoubleBuffer of an appropriate size to hold the specified
-	 * number of doubles only if the given buffer if not already the right size.
-	 * 
-	 * @param buf
-	 *            the buffer to first check and rewind
-	 * @param size
-	 *            number of doubles that need to be held by the newly created
-	 *            buffer
-	 * @return the requested new DoubleBuffer
-	 */
-	public static DoubleBuffer createDoubleBuffer(DoubleBuffer buf, int size) {
-		if (buf != null && buf.limit() == size) {
-			buf.rewind();
-			return buf;
-		}
-
-		buf = createDoubleBuffer(size);
-		return buf;
-	}
-
-	/**
-	 * Creates a new DoubleBuffer with the same contents as the given
-	 * DoubleBuffer. The new DoubleBuffer is separate from the old one and
-	 * changes are not reflected across. If you want to reflect changes,
-	 * consider using Buffer.duplicate().
-	 * 
-	 * @param buf
-	 *            the DoubleBuffer to copy
-	 * @return the copy
-	 */
-	public static DoubleBuffer clone(DoubleBuffer buf) {
-		if (buf == null) {
-			return null;
-		}
-		buf.rewind();
-
-		DoubleBuffer copy;
-		if (isDirect(buf)) {
-			copy = createDoubleBuffer(buf.limit());
-		} else {
-			copy = DoubleBuffer.allocate(buf.limit());
-		}
-		copy.put(buf);
-
-		return copy;
-	}
-
-	//// -- GENERAL FLOAT ROUTINES -- ////
-	/**
-	 * Create a new 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 = allocator.allocate(4 * size).order(ByteOrder.nativeOrder()).asFloatBuffer();
-		buf.clear();
-		onBufferAllocated(buf);
-		return buf;
-	}
-
-	/**
-	 * 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);
-	}
-
-	/**
-	 * Creates a new FloatBuffer with the same contents as the given
-	 * FloatBuffer. The new FloatBuffer is separate 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;
-		if (isDirect(buf)) {
-			copy = createFloatBuffer(buf.limit());
-		} else {
-			copy = FloatBuffer.allocate(buf.limit());
-		}
-		copy.put(buf);
-
-		return copy;
-	}
-
-	//// -- GENERAL INT ROUTINES -- ////
-	/**
-	 * 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 = allocator.allocate(4 * size).order(ByteOrder.nativeOrder()).asIntBuffer();
-		buf.clear();
-		onBufferAllocated(buf);
-		return buf;
-	}
-
-	/**
-	 * Create a new IntBuffer 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 ints that need to be held by the newly created
-	 *            buffer
-	 * @return the requested new IntBuffer
-	 */
-	public static IntBuffer createIntBuffer(IntBuffer buf, int size) {
-		if (buf != null && buf.limit() == size) {
-			buf.rewind();
-			return buf;
-		}
-
-		buf = createIntBuffer(size);
-		return buf;
-	}
-
-	/**
-	 * Creates a new IntBuffer with the same contents as the given IntBuffer.
-	 * The new IntBuffer is separate 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;
-		if (isDirect(buf)) {
-			copy = createIntBuffer(buf.limit());
-		} else {
-			copy = IntBuffer.allocate(buf.limit());
-		}
-		copy.put(buf);
-
-		return copy;
-	}
-
-	//// -- GENERAL BYTE ROUTINES -- ////
-	/**
-	 * 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 = allocator.allocate(size).order(ByteOrder.nativeOrder());
-		buf.clear();
-		onBufferAllocated(buf);
-		return buf;
-	}
-
-	/**
-	 * 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;
-	}
-
-	public static ByteBuffer createByteBuffer(byte... data) {
-		ByteBuffer bb = createByteBuffer(data.length);
-		bb.put(data);
-		bb.flip();
-		return bb;
-	}
-
-	public static ByteBuffer createByteBuffer(String data) {
-		try {
-			byte[] bytes = data.getBytes("UTF-8");
-			ByteBuffer bb = createByteBuffer(bytes.length);
-			bb.put(bytes);
-			bb.flip();
-			return bb;
-		} catch (UnsupportedEncodingException ex) {
-			throw new UnsupportedOperationException(ex);
-		}
-	}
-
-	/**
-	 * Creates a new ByteBuffer with the same contents as the given ByteBuffer.
-	 * The new ByteBuffer 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 ByteBuffer to copy
-	 * @return the copy
-	 */
-	public static ByteBuffer clone(ByteBuffer buf) {
-		if (buf == null) {
-			return null;
-		}
-		buf.rewind();
-
-		ByteBuffer copy;
-		if (isDirect(buf)) {
-			copy = createByteBuffer(buf.limit());
-		} else {
-			copy = ByteBuffer.allocate(buf.limit());
-		}
-		copy.put(buf);
-
-		return copy;
-	}
-
-	//// -- GENERAL SHORT ROUTINES -- ////
-	/**
-	 * Create a new ShortBuffer of the specified size.
-	 * 
-	 * @param size
-	 *            required number of shorts to store.
-	 * @return the new ShortBuffer
-	 */
-	public static ShortBuffer createShortBuffer(int size) {
-		ShortBuffer buf = allocator.allocate(2 * size).order(ByteOrder.nativeOrder()).asShortBuffer();
-		buf.clear();
-		onBufferAllocated(buf);
-		return buf;
-	}
-
-	/**
-	 * Create a new ShortBuffer of an appropriate size to hold the specified
-	 * number of shorts only if the given buffer if not already the right size.
-	 * 
-	 * @param buf
-	 *            the buffer to first check and rewind
-	 * @param size
-	 *            number of shorts that need to be held by the newly created
-	 *            buffer
-	 * @return the requested new ShortBuffer
-	 */
-	public static ShortBuffer createShortBuffer(ShortBuffer buf, int size) {
-		if (buf != null && buf.limit() == size) {
-			buf.rewind();
-			return buf;
-		}
-
-		buf = createShortBuffer(size);
-		return buf;
-	}
-
-	public static ShortBuffer createShortBuffer(short... data) {
-		if (data == null) {
-			return null;
-		}
-		ShortBuffer buff = createShortBuffer(data.length);
-		buff.clear();
-		buff.put(data);
-		buff.flip();
-		return buff;
-	}
-
-	/**
-	 * Creates a new ShortBuffer with the same contents as the given
-	 * ShortBuffer. The new ShortBuffer is separate from the old one and changes
-	 * are not reflected across. If you want to reflect changes, consider using
-	 * Buffer.duplicate().
-	 * 
-	 * @param buf
-	 *            the ShortBuffer to copy
-	 * @return the copy
-	 */
-	public static ShortBuffer clone(ShortBuffer buf) {
-		if (buf == null) {
-			return null;
-		}
-		buf.rewind();
-
-		ShortBuffer copy;
-		if (isDirect(buf)) {
-			copy = createShortBuffer(buf.limit());
-		} else {
-			copy = ShortBuffer.allocate(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.limit(buffer.capacity());
-		}
-		if (buffer == null || (buffer.remaining() < required)) {
-			int position = (buffer != null ? buffer.position() : 0);
-			FloatBuffer newVerts = createFloatBuffer(position + required);
-			if (buffer != null) {
-				buffer.flip();
-				newVerts.put(buffer);
-				newVerts.position(position);
-			}
-			buffer = newVerts;
-		}
-		return buffer;
-	}
-
-	public static IntBuffer ensureLargeEnough(IntBuffer buffer, int required) {
-		if (buffer != null) {
-			buffer.limit(buffer.capacity());
-		}
-		if (buffer == null || (buffer.remaining() < required)) {
-			int position = (buffer != null ? buffer.position() : 0);
-			IntBuffer newVerts = createIntBuffer(position + required);
-			if (buffer != null) {
-				buffer.flip();
-				newVerts.put(buffer);
-				newVerts.position(position);
-			}
-			buffer = newVerts;
-		}
-		return buffer;
-	}
-
-	public static ShortBuffer ensureLargeEnough(ShortBuffer buffer, int required) {
-		if (buffer != null) {
-			buffer.limit(buffer.capacity());
-		}
-		if (buffer == null || (buffer.remaining() < required)) {
-			int position = (buffer != null ? buffer.position() : 0);
-			ShortBuffer newVerts = createShortBuffer(position + required);
-			if (buffer != null) {
-				buffer.flip();
-				newVerts.put(buffer);
-				newVerts.position(position);
-			}
-			buffer = newVerts;
-		}
-		return buffer;
-	}
-
-	public static ByteBuffer ensureLargeEnough(ByteBuffer buffer, int required) {
-		if (buffer != null) {
-			buffer.limit(buffer.capacity());
-		}
-		if (buffer == null || (buffer.remaining() < required)) {
-			int position = (buffer != null ? buffer.position() : 0);
-			ByteBuffer newVerts = createByteBuffer(position + required);
-			if (buffer != null) {
-				buffer.flip();
-				newVerts.put(buffer);
-				newVerts.position(position);
-			}
-			buffer = newVerts;
-		}
-		return buffer;
-	}
-
-	public static void printCurrentDirectMemory(StringBuilder store) {
-		long totalHeld = 0;
-		long heapMem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
-
-		boolean printStout = store == null;
-		if (store == null) {
-			store = new StringBuilder();
-		}
-		if (trackDirectMemory) {
-			// make a new set to hold the keys to prevent concurrency issues.
-			int fBufs = 0, bBufs = 0, iBufs = 0, sBufs = 0, dBufs = 0;
-			int fBufsM = 0, bBufsM = 0, iBufsM = 0, sBufsM = 0, dBufsM = 0;
-			for (BufferInfo b : BufferUtils.trackedBuffers.values()) {
-				if (b.type == ByteBuffer.class) {
-					totalHeld += b.size;
-					bBufsM += b.size;
-					bBufs++;
-				} else if (b.type == FloatBuffer.class) {
-					totalHeld += b.size;
-					fBufsM += b.size;
-					fBufs++;
-				} else if (b.type == IntBuffer.class) {
-					totalHeld += b.size;
-					iBufsM += b.size;
-					iBufs++;
-				} else if (b.type == ShortBuffer.class) {
-					totalHeld += b.size;
-					sBufsM += b.size;
-					sBufs++;
-				} else if (b.type == DoubleBuffer.class) {
-					totalHeld += b.size;
-					dBufsM += b.size;
-					dBufs++;
-				}
-			}
-
-			store.append("Existing buffers: ").append(BufferUtils.trackedBuffers.size()).append("\n");
-			store.append("(b: ").append(bBufs).append("  f: ").append(fBufs).append("  i: ").append(iBufs).append("  s: ").append(sBufs).append("  d: ").append(dBufs).append(")").append("\n");
-			store.append("Total   heap memory held: ").append(heapMem / 1024).append("kb\n");
-			store.append("Total direct memory held: ").append(totalHeld / 1024).append("kb\n");
-			store.append("(b: ").append(bBufsM / 1024).append("kb  f: ").append(fBufsM / 1024).append("kb  i: ").append(iBufsM / 1024).append("kb  s: ").append(sBufsM / 1024).append("kb  d: ")
-					.append(dBufsM / 1024).append("kb)").append("\n");
-		} else {
-			store.append("Total   heap memory held: ").append(heapMem / 1024).append("kb\n");
-			store.append("Only heap memory available, if you want to monitor direct memory use BufferUtils.setTrackDirectMemoryEnabled(true) during initialization.").append("\n");
-		}
-		if (printStout) {
-			System.out.println(store.toString());
-		}
-	}
-
-	/**
-	 * Direct buffers are garbage collected by using a phantom reference and a
-	 * reference queue. Every once a while, the JVM checks the reference queue
-	 * and cleans the direct buffers. However, as this doesn't happen
-	 * immediately after discarding all references to a direct buffer, it's easy
-	 * to OutOfMemoryError yourself using direct buffers.
-	 **/
-	public static void destroyDirectBuffer(Buffer toBeDestroyed) {
-		if (!isDirect(toBeDestroyed)) {
-			return;
-		}
-		allocator.destroyDirectBuffer(toBeDestroyed);
-	}
-
-	/*
-	 * FIXME when java 1.5 supprt is dropped - replace calls to this method with
-	 * Buffer.isDirect
-	 * 
-	 * Buffer.isDirect() is only java 6. Java 5 only have this method on Buffer
-	 * subclasses : FloatBuffer, IntBuffer, ShortBuffer,
-	 * ByteBuffer,DoubleBuffer, LongBuffer. CharBuffer has been excluded as we
-	 * don't use it.
-	 * 
-	 */
-	private static boolean isDirect(Buffer buf) {
-		if (buf instanceof FloatBuffer) {
-			return ((FloatBuffer) buf).isDirect();
-		}
-		if (buf instanceof IntBuffer) {
-			return ((IntBuffer) buf).isDirect();
-		}
-		if (buf instanceof ShortBuffer) {
-			return ((ShortBuffer) buf).isDirect();
-		}
-		if (buf instanceof ByteBuffer) {
-			return ((ByteBuffer) buf).isDirect();
-		}
-		if (buf instanceof DoubleBuffer) {
-			return ((DoubleBuffer) buf).isDirect();
-		}
-		if (buf instanceof LongBuffer) {
-			return ((LongBuffer) buf).isDirect();
-		}
-		throw new UnsupportedOperationException(" BufferUtils.isDirect was called on " + buf.getClass().getName());
-	}
-
-	private static class BufferInfo extends PhantomReference<Buffer> {
-
-		private Class	type;
-		private int		size;
-
-		public BufferInfo(Class type, int size, Buffer referent, ReferenceQueue<? super Buffer> q) {
-			super(referent, q);
-			this.type = type;
-			this.size = size;
-		}
-	}
-
-	private static class ClearReferences extends Thread {
-
-		ClearReferences() {
-			this.setDaemon(true);
-		}
-
-		@Override
-		public void run() {
-			try {
-				while (true) {
-					Reference<? extends Buffer> toclean = BufferUtils.removeCollected.remove();
-					BufferUtils.trackedBuffers.remove(toclean);
-				}
-
-			} catch (InterruptedException e) {
-				e.printStackTrace();
-			}
+    private static BufferAllocator allocator = new PrimitiveAllocator();
+
+    private static boolean trackDirectMemory = false;
+    private static ReferenceQueue<Buffer> removeCollected = new ReferenceQueue<Buffer>();
+    private static ConcurrentHashMap<BufferInfo, BufferInfo> trackedBuffers = new ConcurrentHashMap<BufferInfo, BufferInfo>();
+    static ClearReferences cleanupthread;
+
+    private static boolean used;
+
+    static {
+        try {
+            allocator = new ReflectionAllocator();
+        } catch (Throwable t) {
+            t.printStackTrace();
+            System.err.println("Error using ReflectionAllocator");
+        }
+    }
+
+    /**
+     * Warning! do only set this before JME is started!
+     */
+    public static void setAllocator(BufferAllocator allocator) {
+        if (used) {
+            throw new IllegalStateException(
+                    "An Buffer was already allocated, since it is quite likely that other dispose methods will create native dangling pointers or other fun things, this is forbidden to be changed at runtime");
+        }
+        BufferUtils.allocator = allocator;
+    }
+
+    /**
+     * Set it to true if you want to enable direct memory tracking for debugging
+     * purpose. Default is false. To print direct memory usage use
+     * BufferUtils.printCurrentDirectMemory(StringBuilder store);
+     * 
+     * @param enabled
+     */
+    public static void setTrackDirectMemoryEnabled(boolean enabled) {
+        trackDirectMemory = enabled;
+    }
+
+    /**
+     * Creates a clone of the given buffer. The clone's capacity is equal to the
+     * given buffer's limit.
+     * 
+     * @param buf
+     *            The buffer to clone
+     * @return The cloned buffer
+     */
+    public static Buffer clone(Buffer buf) {
+        if (buf instanceof FloatBuffer) {
+            return clone((FloatBuffer) buf);
+        } else if (buf instanceof ShortBuffer) {
+            return clone((ShortBuffer) buf);
+        } else if (buf instanceof ByteBuffer) {
+            return clone((ByteBuffer) buf);
+        } else if (buf instanceof IntBuffer) {
+            return clone((IntBuffer) buf);
+        } else if (buf instanceof DoubleBuffer) {
+            return clone((DoubleBuffer) buf);
+        } else {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    private static void onBufferAllocated(Buffer buffer) {
+        used = true;
+        if (BufferUtils.trackDirectMemory) {
+            if (BufferUtils.cleanupthread == null) {
+                BufferUtils.cleanupthread = new ClearReferences();
+                BufferUtils.cleanupthread.start();
+            }
+            if (buffer instanceof ByteBuffer) {
+                BufferInfo info = new BufferInfo(ByteBuffer.class, buffer.capacity(), buffer,
+                        BufferUtils.removeCollected);
+                BufferUtils.trackedBuffers.put(info, info);
+            } else if (buffer instanceof FloatBuffer) {
+                BufferInfo info = new BufferInfo(FloatBuffer.class, buffer.capacity() * 4, buffer,
+                        BufferUtils.removeCollected);
+                BufferUtils.trackedBuffers.put(info, info);
+            } else if (buffer instanceof IntBuffer) {
+                BufferInfo info = new BufferInfo(IntBuffer.class, buffer.capacity() * 4, buffer,
+                        BufferUtils.removeCollected);
+                BufferUtils.trackedBuffers.put(info, info);
+            } else if (buffer instanceof ShortBuffer) {
+                BufferInfo info = new BufferInfo(ShortBuffer.class, buffer.capacity() * 2, buffer,
+                        BufferUtils.removeCollected);
+                BufferUtils.trackedBuffers.put(info, info);
+            } else if (buffer instanceof DoubleBuffer) {
+                BufferInfo info = new BufferInfo(DoubleBuffer.class, buffer.capacity() * 8, buffer,
+                        BufferUtils.removeCollected);
+                BufferUtils.trackedBuffers.put(info, info);
+            }
+
+        }
+    }
+
+    /**
+     * Generate a new FloatBuffer using the given array of Vector3f objects. The
+     * FloatBuffer will be 3 * data.length long and contain the vector data as
+     * data[0].x, data[0].y, data[0].z, data[1].x... etc.
+     * 
+     * @param data
+     *            array of Vector3f objects to place into a new FloatBuffer
+     */
+    public static FloatBuffer createFloatBuffer(Vector3f... data) {
+        if (data == null) {
+            return null;
+        }
+        FloatBuffer buff = createFloatBuffer(3 * data.length);
+        for (Vector3f element : data) {
+            if (element != null) {
+                buff.put(element.x).put(element.y).put(element.z);
+            } else {
+                buff.put(0).put(0).put(0);
+            }
+        }
+        buff.flip();
+        return buff;
+    }
+
+    /**
+     * Generate a new FloatBuffer using the given array of Quaternion objects.
+     * The FloatBuffer will be 4 * data.length long and contain the vector data.
+     * 
+     * @param data
+     *            array of Quaternion objects to place into a new FloatBuffer
+     */
+    public static FloatBuffer createFloatBuffer(Quaternion... data) {
+        if (data == null) {
+            return null;
+        }
+        FloatBuffer buff = createFloatBuffer(4 * data.length);
+        for (Quaternion element : data) {
+            if (element != null) {
+                buff.put(element.getX()).put(element.getY()).put(element.getZ()).put(element.getW());
+            } else {
+                buff.put(0).put(0).put(0).put(0);
+            }
+        }
+        buff.flip();
+        return buff;
+    }
+
+    /**
+     * Generate a new FloatBuffer using the given array of Vector4 objects. The
+     * FloatBuffer will be 4 * data.length long and contain the vector data.
+     *
+     * @param data
+     *            array of Vector4 objects to place into a new FloatBuffer
+     */
+    public static FloatBuffer createFloatBuffer(Vector4f... data) {
+        if (data == null) {
+            return null;
+        }
+        FloatBuffer buff = createFloatBuffer(4 * data.length);
+        for (int x = 0; x < data.length; x++) {
+            if (data[x] != null) {
+                buff.put(data[x].getX()).put(data[x].getY()).put(data[x].getZ()).put(data[x].getW());
+            } else {
+                buff.put(0).put(0).put(0).put(0);
+            }
+        }
+        buff.flip();
+        return buff;
+    }
+
+    /**
+     * Generate a new FloatBuffer using the given array of ColorRGBA objects.
+     * The FloatBuffer will be 4 * data.length long and contain the color data.
+     *
+     * @param data
+     *            array of ColorRGBA objects to place into a new FloatBuffer
+     */
+    public static FloatBuffer createFloatBuffer(ColorRGBA... data) {
+        if (data == null) {
+            return null;
+        }
+        FloatBuffer buff = createFloatBuffer(4 * data.length);
+        for (int x = 0; x < data.length; x++) {
+            if (data[x] != null) {
+                buff.put(data[x].getRed()).put(data[x].getGreen()).put(data[x].getBlue()).put(data[x].getAlpha());
+            } else {
+                buff.put(0).put(0).put(0).put(0);
+            }
+        }
+        buff.flip();
+        return buff;
+    }
+
+    /**
+     * Generate a new FloatBuffer using the given array of float primitives.
+     * 
+     * @param data
+     *            array of float primitives to place into a new FloatBuffer
+     */
+    public static FloatBuffer createFloatBuffer(float... data) {
+        if (data == null) {
+            return null;
+        }
+        FloatBuffer buff = createFloatBuffer(data.length);
+        buff.clear();
+        buff.put(data);
+        buff.flip();
+        return buff;
+    }
+
+    /**
+     * Create a new FloatBuffer of an appropriate size to hold the specified
+     * number of Vector3f 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 FloatBuffer of an appropriate size to hold the specified
+     * number of Vector3f object data only if the given buffer if not already
+     * the right size.
+     * 
+     * @param buf
+     *            the buffer to first check and rewind
+     * @param vertices
+     *            number of vertices that need to be held by the newly created
+     *            buffer
+     * @return the requested new FloatBuffer
+     */
+    public static FloatBuffer createVector3Buffer(FloatBuffer buf, int vertices) {
+        if (buf != null && buf.limit() == 3 * vertices) {
+            buf.rewind();
+            return buf;
+        }
+
+        return createFloatBuffer(3 * vertices);
+    }
+
+    /**
+     * Sets the data contained in the given color into the FloatBuffer at the
+     * specified index.
+     * 
+     * @param color
+     *            the data to insert
+     * @param buf
+     *            the buffer to insert into
+     * @param index
+     *            the postion to place the data; in terms of colors not floats
+     */
+    public static void setInBuffer(ColorRGBA color, FloatBuffer buf, int index) {
+        buf.position(index * 4);
+        buf.put(color.r);
+        buf.put(color.g);
+        buf.put(color.b);
+        buf.put(color.a);
+    }
+
+    /**
+     * Sets the data contained in the given quaternion into the FloatBuffer at
+     * the specified index.
+     * 
+     * @param quat
+     *            the {@link Quaternion} to insert
+     * @param buf
+     *            the buffer to insert into
+     * @param index
+     *            the position to place the data; in terms of quaternions not
+     *            floats
+     */
+    public static void setInBuffer(Quaternion quat, FloatBuffer buf, int index) {
+        buf.position(index * 4);
+        buf.put(quat.getX());
+        buf.put(quat.getY());
+        buf.put(quat.getZ());
+        buf.put(quat.getW());
+    }
+
+    /**
+     * Sets the data contained in the given vector4 into the FloatBuffer at the
+     * specified index.
+     *
+     * @param vec
+     *            the {@link Vector4f} to insert
+     * @param buf
+     *            the buffer to insert into
+     * @param index
+     *            the position to place the data; in terms of vector4 not floats
+     */
+    public static void setInBuffer(Vector4f vec, FloatBuffer buf, int index) {
+        buf.position(index * 4);
+        buf.put(vec.getX());
+        buf.put(vec.getY());
+        buf.put(vec.getZ());
+        buf.put(vec.getW());
+    }
+
+    /**
+     * Sets the data contained in the given Vector3F into the FloatBuffer at the
+     * specified index.
+     * 
+     * @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(Vector3f 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);
+        }
+    }
+
+    /**
+     * 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(Vector3f 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);
+    }
+
+    /**
+     * 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(Vector4f vector, FloatBuffer buf, int index) {
+        vector.x = buf.get(index * 4);
+        vector.y = buf.get(index * 4 + 1);
+        vector.z = buf.get(index * 4 + 2);
+        vector.w = buf.get(index * 4 + 3);
+    }
+
+    /**
+     * Generates a Vector3f array from the given FloatBuffer.
+     * 
+     * @param buff
+     *            the FloatBuffer to read from
+     * @return a newly generated array of Vector3f objects
+     */
+    public static Vector3f[] getVector3Array(FloatBuffer buff) {
+        buff.clear();
+        Vector3f[] verts = new Vector3f[buff.limit() / 3];
+        for (int x = 0; x < verts.length; x++) {
+            Vector3f v = new Vector3f(buff.get(), buff.get(), buff.get());
+            verts[x] = v;
+        }
+        return verts;
+    }
+
+    /**
+     * Copies a Vector3f from one position in the buffer to another. The index
+     * values are in terms of vector number (eg, vector number 0 is positions
+     * 0-2 in the FloatBuffer.)
+     * 
+     * @param buf
+     *            the buffer to copy from/to
+     * @param fromPos
+     *            the index of the vector to copy
+     * @param toPos
+     *            the index to copy the vector to
+     */
+    public static void copyInternalVector3(FloatBuffer buf, int fromPos, int toPos) {
+        copyInternal(buf, fromPos * 3, toPos * 3, 3);
+    }
+
+    /**
+     * Normalize a Vector3f in-buffer.
+     * 
+     * @param buf
+     *            the buffer to find the Vector3f within
+     * @param index
+     *            the position (in terms of vectors, not floats) of the vector
+     *            to normalize
+     */
+    public static void normalizeVector3(FloatBuffer buf, int index) {
+        TempVars vars = TempVars.get();
+        Vector3f tempVec3 = vars.vect1;
+        populateFromBuffer(tempVec3, buf, index);
+        tempVec3.normalizeLocal();
+        setInBuffer(tempVec3, buf, index);
+        vars.release();
+    }
+
+    /**
+     * Add to a Vector3f in-buffer.
+     * 
+     * @param toAdd
+     *            the vector to add from
+     * @param buf
+     *            the buffer to find the Vector3f within
+     * @param index
+     *            the position (in terms of vectors, not floats) of the vector
+     *            to add to
+     */
+    public static void addInBuffer(Vector3f toAdd, FloatBuffer buf, int index) {
+        TempVars vars = TempVars.get();
+        Vector3f tempVec3 = vars.vect1;
+        populateFromBuffer(tempVec3, buf, index);
+        tempVec3.addLocal(toAdd);
+        setInBuffer(tempVec3, buf, index);
+        vars.release();
+    }
+
+    /**
+     * Multiply and store a Vector3f in-buffer.
+     * 
+     * @param toMult
+     *            the vector to multiply against
+     * @param buf
+     *            the buffer to find the Vector3f within
+     * @param index
+     *            the position (in terms of vectors, not floats) of the vector
+     *            to multiply
+     */
+    public static void multInBuffer(Vector3f toMult, FloatBuffer buf, int index) {
+        TempVars vars = TempVars.get();
+        Vector3f tempVec3 = vars.vect1;
+        populateFromBuffer(tempVec3, buf, index);
+        tempVec3.multLocal(toMult);
+        setInBuffer(tempVec3, buf, index);
+        vars.release();
+    }
+
+    /**
+     * Checks to see if the given Vector3f is equals to the data stored in the
+     * buffer at the given data index.
+     * 
+     * @param check
+     *            the vector to check against - null will return false.
+     * @param buf
+     *            the buffer to compare data with
+     * @param index
+     *            the position (in terms of vectors, not floats) of the vector
+     *            in the buffer to check against
+     * @return true if the data is equivalent, otherwise false.
+     */
+    public static boolean equals(Vector3f check, FloatBuffer buf, int index) {
+        TempVars vars = TempVars.get();
+        Vector3f tempVec3 = vars.vect1;
+        populateFromBuffer(tempVec3, buf, index);
+        boolean eq = tempVec3.equals(check);
+        vars.release();
+        return eq;
+    }
+
+    // // -- VECTOR2F METHODS -- ////
+    /**
+     * Generate a new FloatBuffer using the given array of Vector2f objects. The
+     * FloatBuffer will be 2 * data.length long and contain the vector data as
+     * data[0].x, data[0].y, data[1].x... etc.
+     * 
+     * @param data
+     *            array of Vector2f objects to place into a new FloatBuffer
+     */
+    public static FloatBuffer createFloatBuffer(Vector2f... data) {
+        if (data == null) {
+            return null;
+        }
+        FloatBuffer buff = createFloatBuffer(2 * data.length);
+        for (Vector2f element : data) {
+            if (element != null) {
+                buff.put(element.x).put(element.y);
+            } else {
+                buff.put(0).put(0);
+            }
+        }
+        buff.flip();
+        return buff;
+    }
+
+    /**
+     * Create a new FloatBuffer of an appropriate size to hold the specified
+     * number of Vector2f 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 createVector2Buffer(int vertices) {
+        FloatBuffer vBuff = createFloatBuffer(2 * vertices);
+        return vBuff;
+    }
+
+    /**
+     * Create a new FloatBuffer of an appropriate size to hold the specified
+     * number of Vector2f object data only if the given buffer if not already
+     * the right size.
+     * 
+     * @param buf
+     *            the buffer to first check and rewind
+     * @param vertices
+     *            number of vertices that need to be held by the newly created
+     *            buffer
+     * @return the requested new FloatBuffer
+     */
+    public static FloatBuffer createVector2Buffer(FloatBuffer buf, int vertices) {
+        if (buf != null && buf.limit() == 2 * vertices) {
+            buf.rewind();
+            return buf;
+        }
+
+        return createFloatBuffer(2 * vertices);
+    }
+
+    /**
+     * Sets the data contained in the given Vector2F into the FloatBuffer at the
+     * specified index.
+     * 
+     * @param vector
+     *            the data to insert
+     * @param buf
+     *            the buffer to insert into
+     * @param index
+     *            the position to place the data; in terms of vectors not floats
+     */
+    public static void setInBuffer(Vector2f vector, FloatBuffer buf, int index) {
+        buf.put(index * 2, vector.x);
+        buf.put((index * 2) + 1, vector.y);
+    }
+
+    /**
+     * 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(Vector2f vector, FloatBuffer buf, int index) {
+        vector.x = buf.get(index * 2);
+        vector.y = buf.get(index * 2 + 1);
+    }
+
+    /**
+     * Generates a Vector2f array from the given FloatBuffer.
+     * 
+     * @param buff
+     *            the FloatBuffer to read from
+     * @return a newly generated array of Vector2f objects
+     */
+    public static Vector2f[] getVector2Array(FloatBuffer buff) {
+        buff.clear();
+        Vector2f[] verts = new Vector2f[buff.limit() / 2];
+        for (int x = 0; x < verts.length; x++) {
+            Vector2f v = new Vector2f(buff.get(), buff.get());
+            verts[x] = v;
+        }
+        return verts;
+    }
+
+    /**
+     * Copies a Vector2f from one position in the buffer to another. The index
+     * values are in terms of vector number (eg, vector number 0 is positions
+     * 0-1 in the FloatBuffer.)
+     * 
+     * @param buf
+     *            the buffer to copy from/to
+     * @param fromPos
+     *            the index of the vector to copy
+     * @param toPos
+     *            the index to copy the vector to
+     */
+    public static void copyInternalVector2(FloatBuffer buf, int fromPos, int toPos) {
+        copyInternal(buf, fromPos * 2, toPos * 2, 2);
+    }
+
+    /**
+     * Normalize a Vector2f in-buffer.
+     * 
+     * @param buf
+     *            the buffer to find the Vector2f within
+     * @param index
+     *            the position (in terms of vectors, not floats) of the vector
+     *            to normalize
+     */
+    public static void normalizeVector2(FloatBuffer buf, int index) {
+        TempVars vars = TempVars.get();
+        Vector2f tempVec2 = vars.vect2d;
+        populateFromBuffer(tempVec2, buf, index);
+        tempVec2.normalizeLocal();
+        setInBuffer(tempVec2, buf, index);
+        vars.release();
+    }
+
+    /**
+     * Add to a Vector2f in-buffer.
+     * 
+     * @param toAdd
+     *            the vector to add from
+     * @param buf
+     *            the buffer to find the Vector2f within
+     * @param index
+     *            the position (in terms of vectors, not floats) of the vector
+     *            to add to
+     */
+    public static void addInBuffer(Vector2f toAdd, FloatBuffer buf, int index) {
+        TempVars vars = TempVars.get();
+        Vector2f tempVec2 = vars.vect2d;
+        populateFromBuffer(tempVec2, buf, index);
+        tempVec2.addLocal(toAdd);
+        setInBuffer(tempVec2, buf, index);
+        vars.release();
+    }
+
+    /**
+     * Multiply and store a Vector2f in-buffer.
+     * 
+     * @param toMult
+     *            the vector to multiply against
+     * @param buf
+     *            the buffer to find the Vector2f within
+     * @param index
+     *            the position (in terms of vectors, not floats) of the vector
+     *            to multiply
+     */
+    public static void multInBuffer(Vector2f toMult, FloatBuffer buf, int index) {
+        TempVars vars = TempVars.get();
+        Vector2f tempVec2 = vars.vect2d;
+        populateFromBuffer(tempVec2, buf, index);
+        tempVec2.multLocal(toMult);
+        setInBuffer(tempVec2, buf, index);
+        vars.release();
+    }
+
+    /**
+     * Checks to see if the given Vector2f is equals to the data stored in the
+     * buffer at the given data index.
+     * 
+     * @param check
+     *            the vector to check against - null will return false.
+     * @param buf
+     *            the buffer to compare data with
+     * @param index
+     *            the position (in terms of vectors, not floats) of the vector
+     *            in the buffer to check against
+     * @return true if the data is equivalent, otherwise false.
+     */
+    public static boolean equals(Vector2f check, FloatBuffer buf, int index) {
+        TempVars vars = TempVars.get();
+        Vector2f tempVec2 = vars.vect2d;
+        populateFromBuffer(tempVec2, buf, index);
+        boolean eq = tempVec2.equals(check);
+        vars.release();
+        return eq;
+    }
+
+    //// -- INT METHODS -- ////
+    /**
+     * Generate a new IntBuffer using the given array of ints. The IntBuffer
+     * will be data.length long and contain the int data as data[0], data[1]...
+     * etc.
+     * 
+     * @param data
+     *            array of ints to place into a new IntBuffer
+     */
+    public static IntBuffer createIntBuffer(int... data) {
+        if (data == null) {
+            return null;
+        }
+        IntBuffer buff = createIntBuffer(data.length);
+        buff.clear();
+        buff.put(data);
+        buff.flip();
+        return buff;
+    }
+
+    /**
+     * Create a new int[] array and populate 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();
+        }
+        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();
+        }
+        return inds;
+    }
+
+    //// -- GENERAL DOUBLE ROUTINES -- ////
+    /**
+     * Create a new DoubleBuffer of the specified size.
+     * 
+     * @param size
+     *            required number of double to store.
+     * @return the new DoubleBuffer
+     */
+    public static DoubleBuffer createDoubleBuffer(int size) {
+        DoubleBuffer buf = allocator.allocate(8 * size).order(ByteOrder.nativeOrder()).asDoubleBuffer();
+        buf.clear();
+        onBufferAllocated(buf);
+        return buf;
+    }
+
+    /**
+     * Create a new DoubleBuffer of an appropriate size to hold the specified
+     * number of doubles only if the given buffer if not already the right size.
+     * 
+     * @param buf
+     *            the buffer to first check and rewind
+     * @param size
+     *            number of doubles that need to be held by the newly created
+     *            buffer
+     * @return the requested new DoubleBuffer
+     */
+    public static DoubleBuffer createDoubleBuffer(DoubleBuffer buf, int size) {
+        if (buf != null && buf.limit() == size) {
+            buf.rewind();
+            return buf;
+        }
+
+        buf = createDoubleBuffer(size);
+        return buf;
+    }
+
+    /**
+     * Creates a new DoubleBuffer with the same contents as the given
+     * DoubleBuffer. The new DoubleBuffer is separate from the old one and
+     * changes are not reflected across. If you want to reflect changes,
+     * consider using Buffer.duplicate().
+     * 
+     * @param buf
+     *            the DoubleBuffer to copy
+     * @return the copy
+     */
+    public static DoubleBuffer clone(DoubleBuffer buf) {
+        if (buf == null) {
+            return null;
+        }
+        buf.rewind();
+
+        DoubleBuffer copy;
+        if (isDirect(buf)) {
+            copy = createDoubleBuffer(buf.limit());
+        } else {
+            copy = DoubleBuffer.allocate(buf.limit());
+        }
+        copy.put(buf);
+
+        return copy;
+    }
+
+    //// -- GENERAL FLOAT ROUTINES -- ////
+    /**
+     * Create a new 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 = allocator.allocate(4 * size).order(ByteOrder.nativeOrder()).asFloatBuffer();
+        buf.clear();
+        onBufferAllocated(buf);
+        return buf;
+    }
+
+    /**
+     * 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);
+    }
+
+    /**
+     * Creates a new FloatBuffer with the same contents as the given
+     * FloatBuffer. The new FloatBuffer is separate 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;
+        if (isDirect(buf)) {
+            copy = createFloatBuffer(buf.limit());
+        } else {
+            copy = FloatBuffer.allocate(buf.limit());
+        }
+        copy.put(buf);
+
+        return copy;
+    }
+
+    //// -- GENERAL INT ROUTINES -- ////
+    /**
+     * 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 = allocator.allocate(4 * size).order(ByteOrder.nativeOrder()).asIntBuffer();
+        buf.clear();
+        onBufferAllocated(buf);
+        return buf;
+    }
+
+    /**
+     * Create a new IntBuffer 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 ints that need to be held by the newly created
+     *            buffer
+     * @return the requested new IntBuffer
+     */
+    public static IntBuffer createIntBuffer(IntBuffer buf, int size) {
+        if (buf != null && buf.limit() == size) {
+            buf.rewind();
+            return buf;
+        }
+
+        buf = createIntBuffer(size);
+        return buf;
+    }
+
+    /**
+     * Creates a new IntBuffer with the same contents as the given IntBuffer.
+     * The new IntBuffer is separate 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;
+        if (isDirect(buf)) {
+            copy = createIntBuffer(buf.limit());
+        } else {
+            copy = IntBuffer.allocate(buf.limit());
+        }
+        copy.put(buf);
+
+        return copy;
+    }
+
+    //// -- GENERAL BYTE ROUTINES -- ////
+    /**
+     * 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 = allocator.allocate(size).order(ByteOrder.nativeOrder());
+        buf.clear();
+        onBufferAllocated(buf);
+        return buf;
+    }
+
+    /**
+     * 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;
+    }
+
+    public static ByteBuffer createByteBuffer(byte... data) {
+        ByteBuffer bb = createByteBuffer(data.length);
+        bb.put(data);
+        bb.flip();
+        return bb;
+    }
+
+    public static ByteBuffer createByteBuffer(String data) {
+        try {
+            byte[] bytes = data.getBytes("UTF-8");
+            ByteBuffer bb = createByteBuffer(bytes.length);
+            bb.put(bytes);
+            bb.flip();
+            return bb;
+        } catch (UnsupportedEncodingException ex) {
+            throw new UnsupportedOperationException(ex);
+        }
+    }
+
+    /**
+     * Creates a new ByteBuffer with the same contents as the given ByteBuffer.
+     * The new ByteBuffer 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 ByteBuffer to copy
+     * @return the copy
+     */
+    public static ByteBuffer clone(ByteBuffer buf) {
+        if (buf == null) {
+            return null;
+        }
+        buf.rewind();
+
+        ByteBuffer copy;
+        if (isDirect(buf)) {
+            copy = createByteBuffer(buf.limit());
+        } else {
+            copy = ByteBuffer.allocate(buf.limit());
+        }
+        copy.put(buf);
+
+        return copy;
+    }
+
+    //// -- GENERAL SHORT ROUTINES -- ////
+    /**
+     * Create a new ShortBuffer of the specified size.
+     * 
+     * @param size
+     *            required number of shorts to store.
+     * @return the new ShortBuffer
+     */
+    public static ShortBuffer createShortBuffer(int size) {
+        ShortBuffer buf = allocator.allocate(2 * size).order(ByteOrder.nativeOrder()).asShortBuffer();
+        buf.clear();
+        onBufferAllocated(buf);
+        return buf;
+    }
+
+    /**
+     * Create a new ShortBuffer of an appropriate size to hold the specified
+     * number of shorts only if the given buffer if not already the right size.
+     * 
+     * @param buf
+     *            the buffer to first check and rewind
+     * @param size
+     *            number of shorts that need to be held by the newly created
+     *            buffer
+     * @return the requested new ShortBuffer
+     */
+    public static ShortBuffer createShortBuffer(ShortBuffer buf, int size) {
+        if (buf != null && buf.limit() == size) {
+            buf.rewind();
+            return buf;
+        }
+
+        buf = createShortBuffer(size);
+        return buf;
+    }
+
+    public static ShortBuffer createShortBuffer(short... data) {
+        if (data == null) {
+            return null;
+        }
+        ShortBuffer buff = createShortBuffer(data.length);
+        buff.clear();
+        buff.put(data);
+        buff.flip();
+        return buff;
+    }
+
+    /**
+     * Creates a new ShortBuffer with the same contents as the given
+     * ShortBuffer. The new ShortBuffer is separate from the old one and changes
+     * are not reflected across. If you want to reflect changes, consider using
+     * Buffer.duplicate().
+     * 
+     * @param buf
+     *            the ShortBuffer to copy
+     * @return the copy
+     */
+    public static ShortBuffer clone(ShortBuffer buf) {
+        if (buf == null) {
+            return null;
+        }
+        buf.rewind();
+
+        ShortBuffer copy;
+        if (isDirect(buf)) {
+            copy = createShortBuffer(buf.limit());
+        } else {
+            copy = ShortBuffer.allocate(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.limit(buffer.capacity());
+        }
+        if (buffer == null || (buffer.remaining() < required)) {
+            int position = (buffer != null ? buffer.position() : 0);
+            FloatBuffer newVerts = createFloatBuffer(position + required);
+            if (buffer != null) {
+                buffer.flip();
+                newVerts.put(buffer);
+                newVerts.position(position);
+            }
+            buffer = newVerts;
+        }
+        return buffer;
+    }
+
+    public static IntBuffer ensureLargeEnough(IntBuffer buffer, int required) {
+        if (buffer != null) {
+            buffer.limit(buffer.capacity());
+        }
+        if (buffer == null || (buffer.remaining() < required)) {
+            int position = (buffer != null ? buffer.position() : 0);
+            IntBuffer newVerts = createIntBuffer(position + required);
+            if (buffer != null) {
+                buffer.flip();
+                newVerts.put(buffer);
+                newVerts.position(position);
+            }
+            buffer = newVerts;
+        }
+        return buffer;
+    }
+
+    public static ShortBuffer ensureLargeEnough(ShortBuffer buffer, int required) {
+        if (buffer != null) {
+            buffer.limit(buffer.capacity());
+        }
+        if (buffer == null || (buffer.remaining() < required)) {
+            int position = (buffer != null ? buffer.position() : 0);
+            ShortBuffer newVerts = createShortBuffer(position + required);
+            if (buffer != null) {
+                buffer.flip();
+                newVerts.put(buffer);
+                newVerts.position(position);
+            }
+            buffer = newVerts;
+        }
+        return buffer;
+    }
+
+    public static ByteBuffer ensureLargeEnough(ByteBuffer buffer, int required) {
+        if (buffer != null) {
+            buffer.limit(buffer.capacity());
+        }
+        if (buffer == null || (buffer.remaining() < required)) {
+            int position = (buffer != null ? buffer.position() : 0);
+            ByteBuffer newVerts = createByteBuffer(position + required);
+            if (buffer != null) {
+                buffer.flip();
+                newVerts.put(buffer);
+                newVerts.position(position);
+            }
+            buffer = newVerts;
+        }
+        return buffer;
+    }
+
+    public static void printCurrentDirectMemory(StringBuilder store) {
+        long totalHeld = 0;
+        long heapMem = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
+
+        boolean printStout = store == null;
+        if (store == null) {
+            store = new StringBuilder();
+        }
+        if (trackDirectMemory) {
+            // make a new set to hold the keys to prevent concurrency issues.
+            int fBufs = 0, bBufs = 0, iBufs = 0, sBufs = 0, dBufs = 0;
+            int fBufsM = 0, bBufsM = 0, iBufsM = 0, sBufsM = 0, dBufsM = 0;
+            for (BufferInfo b : BufferUtils.trackedBuffers.values()) {
+                if (b.type == ByteBuffer.class) {
+                    totalHeld += b.size;
+                    bBufsM += b.size;
+                    bBufs++;
+                } else if (b.type == FloatBuffer.class) {
+                    totalHeld += b.size;
+                    fBufsM += b.size;
+                    fBufs++;
+                } else if (b.type == IntBuffer.class) {
+                    totalHeld += b.size;
+                    iBufsM += b.size;
+                    iBufs++;
+                } else if (b.type == ShortBuffer.class) {
+                    totalHeld += b.size;
+                    sBufsM += b.size;
+                    sBufs++;
+                } else if (b.type == DoubleBuffer.class) {
+                    totalHeld += b.size;
+                    dBufsM += b.size;
+                    dBufs++;
+                }
+            }
+
+            store.append("Existing buffers: ").append(BufferUtils.trackedBuffers.size()).append("\n");
+            store.append("(b: ").append(bBufs).append("  f: ").append(fBufs).append("  i: ").append(iBufs)
+                    .append("  s: ").append(sBufs).append("  d: ").append(dBufs).append(")").append("\n");
+            store.append("Total   heap memory held: ").append(heapMem / 1024).append("kb\n");
+            store.append("Total direct memory held: ").append(totalHeld / 1024).append("kb\n");
+            store.append("(b: ").append(bBufsM / 1024).append("kb  f: ").append(fBufsM / 1024).append("kb  i: ")
+                    .append(iBufsM / 1024).append("kb  s: ").append(sBufsM / 1024).append("kb  d: ")
+                    .append(dBufsM / 1024).append("kb)").append("\n");
+        } else {
+            store.append("Total   heap memory held: ").append(heapMem / 1024).append("kb\n");
+            store.append(
+                    "Only heap memory available, if you want to monitor direct memory use BufferUtils.setTrackDirectMemoryEnabled(true) during initialization.")
+                    .append("\n");
+        }
+        if (printStout) {
+            System.out.println(store.toString());
+        }
+    }
+
+    /**
+     * Direct buffers are garbage collected by using a phantom reference and a
+     * reference queue. Every once a while, the JVM checks the reference queue
+     * and cleans the direct buffers. However, as this doesn't happen
+     * immediately after discarding all references to a direct buffer, it's easy
+     * to OutOfMemoryError yourself using direct buffers.
+     **/
+    public static void destroyDirectBuffer(Buffer toBeDestroyed) {
+        if (!isDirect(toBeDestroyed)) {
+            return;
+        }
+        allocator.destroyDirectBuffer(toBeDestroyed);
+    }
+
+    /*
+     * FIXME when java 1.5 supprt is dropped - replace calls to this method with
+     * Buffer.isDirect
+     * 
+     * Buffer.isDirect() is only java 6. Java 5 only have this method on Buffer
+     * subclasses : FloatBuffer, IntBuffer, ShortBuffer,
+     * ByteBuffer,DoubleBuffer, LongBuffer. CharBuffer has been excluded as we
+     * don't use it.
+     * 
+     */
+    private static boolean isDirect(Buffer buf) {
+        if (buf instanceof FloatBuffer) {
+            return ((FloatBuffer) buf).isDirect();
+        }
+        if (buf instanceof IntBuffer) {
+            return ((IntBuffer) buf).isDirect();
+        }
+        if (buf instanceof ShortBuffer) {
+            return ((ShortBuffer) buf).isDirect();
+        }
+        if (buf instanceof ByteBuffer) {
+            return ((ByteBuffer) buf).isDirect();
+        }
+        if (buf instanceof DoubleBuffer) {
+            return ((DoubleBuffer) buf).isDirect();
+        }
+        if (buf instanceof LongBuffer) {
+            return ((LongBuffer) buf).isDirect();
+        }
+        throw new UnsupportedOperationException(" BufferUtils.isDirect was called on " + buf.getClass().getName());
+    }
+
+    private static class BufferInfo extends PhantomReference<Buffer> {
+
+        private Class type;
+        private int size;
+
+        public BufferInfo(Class type, int size, Buffer referent, ReferenceQueue<? super Buffer> q) {
+            super(referent, q);
+            this.type = type;
+            this.size = size;
+        }
+    }
+
+    private static class ClearReferences extends Thread {
+
+        ClearReferences() {
+            this.setDaemon(true);
+        }
+
+        @Override
+        public void run() {
+            try {
+                while (true) {
+                    Reference<? extends Buffer> toclean = BufferUtils.removeCollected.remove();
+                    BufferUtils.trackedBuffers.remove(toclean);
+                }
+
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
         }
     }
 }

+ 10 - 10
jme3-core/src/main/java/com/jme3/util/PrimitiveAllocator.java

@@ -40,16 +40,16 @@ import java.nio.ByteBuffer;
  */
 public final class PrimitiveAllocator implements BufferAllocator {
 
-	@Override
-	public void destroyDirectBuffer(Buffer toBeDestroyed) {
-		// no exception by intent, as this way naivly written java7/8
-		// applications wont crash on 9 assuming they can dispose buffers
-		System.err.println("Warning destroyBuffer not supported");
-	}
+    @Override
+    public void destroyDirectBuffer(Buffer toBeDestroyed) {
+        // no exception by intent, as this way naivly written java7/8
+        // applications wont crash on 9 assuming they can dispose buffers
+        System.err.println("Warning destroyBuffer not supported");
+    }
 
-	@Override
-	public ByteBuffer allocate(int size) {
-		return ByteBuffer.allocateDirect(size);
-	}
+    @Override
+    public ByteBuffer allocate(int size) {
+        return ByteBuffer.allocateDirect(size);
+    }
 
 }