Explorar el Código

Added support for int arrays uniforms. thanks to abies.

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@10495 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
rem..om hace 12 años
padre
commit
05e080100e

+ 5 - 0
engine/src/android/com/jme3/renderer/android/OGLESShaderRenderer.java

@@ -643,6 +643,7 @@ public class OGLESShaderRenderer implements Renderer {
 
         uniform.clearUpdateNeeded();
         FloatBuffer fb;
+        IntBuffer ib;
         switch (uniform.getVarType()) {
             case Float:
                 Float f = (Float) uniform.getValue();
@@ -683,6 +684,10 @@ public class OGLESShaderRenderer implements Renderer {
                 assert fb.remaining() == 16;
                 GLES20.glUniformMatrix4fv(loc, 1, false, fb);
                 break;
+            case IntArray:
+                ib = (IntBuffer) uniform.getValue();
+                GLES20.glUniform1iv(loc, ib.limit(), ib);
+                break;
             case FloatArray:
                 fb = (FloatBuffer) uniform.getValue();
                 GLES20.glUniform1fv(loc, fb.limit(), fb);

+ 350 - 340
engine/src/core/com/jme3/shader/Uniform.java

@@ -1,340 +1,350 @@
-/*
- * Copyright (c) 2009-2012 jMonkeyEngine
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
- *   may be used to endorse or promote products derived from this software
- *   without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.jme3.shader;
-
-import com.jme3.math.*;
-import com.jme3.util.BufferUtils;
-import java.nio.FloatBuffer;
-
-public class Uniform extends ShaderVariable {
-
-    private static final Integer ZERO_INT = Integer.valueOf(0);
-    private static final Float ZERO_FLT = Float.valueOf(0);
-    private static final FloatBuffer ZERO_BUF = BufferUtils.createFloatBuffer(4*4);
-
-    /**
-     * Currently set value of the uniform.
-     */
-    protected Object value = null;
-    
-    /**
-     * For arrays or matrices, efficient format
-     * that can be sent to GL faster.
-     */
-    protected FloatBuffer multiData = null;
-
-    /**
-     * Type of uniform
-     */
-    protected VarType varType;
-
-    /**
-     * Binding to a renderer value, or null if user-defined uniform
-     */
-    protected UniformBinding binding;
-
-    /**
-     * Used to track which uniforms to clear to avoid
-     * values leaking from other materials that use that shader.
-     */
-    protected boolean setByCurrentMaterial = false;
-
-    @Override
-    public String toString(){
-        StringBuilder sb = new StringBuilder();
-        sb.append("Uniform[name=");
-        sb.append(name);
-        if (varType != null){
-            sb.append(", type=");
-            sb.append(varType);
-            sb.append(", value=");
-            sb.append(value);
-        }else{
-            sb.append(", value=<not set>");
-        }
-        sb.append("]");
-        return sb.toString();
-    }
-
-    public void setBinding(UniformBinding binding){
-        this.binding = binding;
-    }
-
-    public UniformBinding getBinding(){
-        return binding;
-    }
-
-    public VarType getVarType() {
-        return varType;
-    }
-
-    public Object getValue(){
-        return value;
-    }
-
-    public boolean isSetByCurrentMaterial() {
-        return setByCurrentMaterial;
-    }
-
-    public void clearSetByCurrentMaterial(){
-        setByCurrentMaterial = false;
-    }
-
-    private static void setVector4(Vector4f vec, Object value) {
-        if (value instanceof ColorRGBA) {
-            ColorRGBA color = (ColorRGBA) value;
-            vec.set(color.r, color.g, color.b, color.a);
-        } else if (value instanceof Quaternion) {
-            Quaternion quat = (Quaternion) value;
-            vec.set(quat.getX(), quat.getY(), quat.getZ(), quat.getW());
-        } else if (value instanceof Vector4f) {
-            Vector4f vec4 = (Vector4f) value;
-            vec.set(vec4);
-        } else{
-            throw new IllegalArgumentException();
-        }
-    }
-    
-    public void clearValue(){
-        updateNeeded = true;
-
-        if (multiData != null){
-            ZERO_BUF.clear();
-            multiData.clear();
-
-            while (multiData.remaining() > 0){
-                ZERO_BUF.limit( Math.min(multiData.remaining(), 16) );
-                multiData.put(ZERO_BUF);
-            }
-
-            multiData.clear();
-
-            return;
-        }
-
-        if (varType == null) {
-            return;
-        }
-            
-        switch (varType){
-            case Int:
-                this.value = ZERO_INT;
-                break;
-            case Boolean:
-                this.value = Boolean.FALSE;
-                break;
-            case Float:
-                this.value = ZERO_FLT; 
-                break;
-            case Vector2:
-                this.value = Vector2f.ZERO;
-                break;
-            case Vector3:
-                this.value = Vector3f.ZERO;
-                break;
-            case Vector4:
-                this.value = Vector4f.ZERO;
-                break;
-            default:
-                // won't happen because those are either textures
-                // or multidata types
-        }
-    }
-    
-    public void setValue(VarType type, Object value){
-        if (location == LOC_NOT_DEFINED) {
-            return;
-        }
-
-        if (varType != null && varType != type) {
-            throw new IllegalArgumentException("Expected a " + varType.name() + " value!");
-        }
-
-        if (value == null) {
-            throw new NullPointerException();
-        }
-
-        setByCurrentMaterial = true;
-
-        switch (type){
-            case Matrix3:
-                Matrix3f m3 = (Matrix3f) value;
-                if (multiData == null) {
-                    multiData = BufferUtils.createFloatBuffer(9);
-                }
-                m3.fillFloatBuffer(multiData, true);
-                multiData.clear();
-                break;
-            case Matrix4:
-                Matrix4f m4 = (Matrix4f) value;
-                if (multiData == null) {
-                    multiData = BufferUtils.createFloatBuffer(16);
-                }
-                m4.fillFloatBuffer(multiData, true);
-                multiData.clear();
-                break;
-            case FloatArray:
-                float[] fa = (float[]) value;
-                if (multiData == null) {
-                    multiData = BufferUtils.createFloatBuffer(fa);
-                } else {
-                    multiData = BufferUtils.ensureLargeEnough(multiData, fa.length);
-                }
-                multiData.put(fa);
-                multiData.clear();
-                break;
-            case Vector2Array:
-                Vector2f[] v2a = (Vector2f[]) value;
-                if (multiData == null) {
-                    multiData = BufferUtils.createFloatBuffer(v2a);
-                } else {
-                    multiData = BufferUtils.ensureLargeEnough(multiData, v2a.length * 2);
-                }
-                for (int i = 0; i < v2a.length; i++) {
-                    BufferUtils.setInBuffer(v2a[i], multiData, i);
-                }
-                multiData.clear();
-                break;
-            case Vector3Array:
-                Vector3f[] v3a = (Vector3f[]) value;
-                if (multiData == null) {
-                    multiData = BufferUtils.createFloatBuffer(v3a);
-                } else {
-                    multiData = BufferUtils.ensureLargeEnough(multiData, v3a.length * 3);
-                }
-                for (int i = 0; i < v3a.length; i++) {
-                    BufferUtils.setInBuffer(v3a[i], multiData, i);
-                }
-                multiData.clear();
-                break;
-            case Vector4Array:
-                Vector4f[] v4a = (Vector4f[]) value;
-                if (multiData == null) {
-                    multiData = BufferUtils.createFloatBuffer(v4a);
-                } else {
-                    multiData = BufferUtils.ensureLargeEnough(multiData, v4a.length * 4);
-                }
-                for (int i = 0; i < v4a.length; i++) {
-                    BufferUtils.setInBuffer(v4a[i], multiData, i);
-                }
-                multiData.clear();
-                break;
-            case Matrix3Array:
-                Matrix3f[] m3a = (Matrix3f[]) value;
-                if (multiData == null) {
-                    multiData = BufferUtils.createFloatBuffer(m3a.length * 9);
-                } else {
-                    multiData = BufferUtils.ensureLargeEnough(multiData, m3a.length * 9);
-                }
-                for (int i = 0; i < m3a.length; i++) {
-                    m3a[i].fillFloatBuffer(multiData, true);
-                }
-                multiData.clear();
-                break;
-            case Matrix4Array:
-                Matrix4f[] m4a = (Matrix4f[]) value;
-                if (multiData == null) {
-                    multiData = BufferUtils.createFloatBuffer(m4a.length * 16);
-                } else {
-                    multiData = BufferUtils.ensureLargeEnough(multiData, m4a.length * 16);
-                }
-                for (int i = 0; i < m4a.length; i++) {
-                    m4a[i].fillFloatBuffer(multiData, true);
-                }
-                multiData.clear();
-                break;
-                // Only use check if equals optimization for primitive values
-            case Int:
-            case Float:
-            case Boolean:
-                if (this.value != null && this.value.equals(value)) {
-                    return;
-                }
-                this.value = value;
-                break;
-            default:
-                this.value = value;
-                break;
-        }
-
-        if (multiData != null) {
-            this.value = multiData;
-        }
-
-        varType = type;
-        updateNeeded = true;
-    }
-
-    public void setVector4Length(int length){
-        if (location == -1)
-            return;
-
-        FloatBuffer fb = (FloatBuffer) value;
-        if (fb == null || fb.capacity() < length) {
-            value = BufferUtils.createFloatBuffer(length * 4);
-        }
-
-        varType = VarType.Vector4Array;
-        updateNeeded = true;
-        setByCurrentMaterial = true;
-    }
-
-    public void setVector4InArray(float x, float y, float z, float w, int index){
-        if (location == -1)
-            return;
-
-        if (varType != null && varType != VarType.Vector4Array)
-            throw new IllegalArgumentException("Expected a "+varType.name()+" value!");
-
-        FloatBuffer fb = (FloatBuffer) value;
-        fb.position(index * 4);
-        fb.put(x).put(y).put(z).put(w);
-        fb.rewind();
-        updateNeeded = true;
-        setByCurrentMaterial = true;
-    }
-    
-    public boolean isUpdateNeeded(){
-        return updateNeeded;
-    }
-
-    public void clearUpdateNeeded(){
-        updateNeeded = false;
-    }
-
-    public void reset(){
-        setByCurrentMaterial = false;
-        location = -2;
-        updateNeeded = true;
-    }
-
-}
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.shader;
+
+import com.jme3.math.*;
+import com.jme3.util.BufferUtils;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+
+public class Uniform extends ShaderVariable {
+
+    private static final Integer ZERO_INT = Integer.valueOf(0);
+    private static final Float ZERO_FLT = Float.valueOf(0);
+    private static final FloatBuffer ZERO_BUF = BufferUtils.createFloatBuffer(4*4);
+
+    /**
+     * Currently set value of the uniform.
+     */
+    protected Object value = null;
+    
+    /**
+     * For arrays or matrices, efficient format
+     * that can be sent to GL faster.
+     */
+    protected FloatBuffer multiData = null;
+
+    /**
+     * Type of uniform
+     */
+    protected VarType varType;
+
+    /**
+     * Binding to a renderer value, or null if user-defined uniform
+     */
+    protected UniformBinding binding;
+
+    /**
+     * Used to track which uniforms to clear to avoid
+     * values leaking from other materials that use that shader.
+     */
+    protected boolean setByCurrentMaterial = false;
+
+    @Override
+    public String toString(){
+        StringBuilder sb = new StringBuilder();
+        sb.append("Uniform[name=");
+        sb.append(name);
+        if (varType != null){
+            sb.append(", type=");
+            sb.append(varType);
+            sb.append(", value=");
+            sb.append(value);
+        }else{
+            sb.append(", value=<not set>");
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public void setBinding(UniformBinding binding){
+        this.binding = binding;
+    }
+
+    public UniformBinding getBinding(){
+        return binding;
+    }
+
+    public VarType getVarType() {
+        return varType;
+    }
+
+    public Object getValue(){
+        return value;
+    }
+
+    public boolean isSetByCurrentMaterial() {
+        return setByCurrentMaterial;
+    }
+
+    public void clearSetByCurrentMaterial(){
+        setByCurrentMaterial = false;
+    }
+
+    private static void setVector4(Vector4f vec, Object value) {
+        if (value instanceof ColorRGBA) {
+            ColorRGBA color = (ColorRGBA) value;
+            vec.set(color.r, color.g, color.b, color.a);
+        } else if (value instanceof Quaternion) {
+            Quaternion quat = (Quaternion) value;
+            vec.set(quat.getX(), quat.getY(), quat.getZ(), quat.getW());
+        } else if (value instanceof Vector4f) {
+            Vector4f vec4 = (Vector4f) value;
+            vec.set(vec4);
+        } else{
+            throw new IllegalArgumentException();
+        }
+    }
+    
+    public void clearValue(){
+        updateNeeded = true;
+
+        if (multiData != null){           
+            multiData.clear();
+
+            while (multiData.remaining() > 0){
+                ZERO_BUF.clear();
+                ZERO_BUF.limit( Math.min(multiData.remaining(), 16) );
+                multiData.put(ZERO_BUF);
+            }
+
+            multiData.clear();
+
+            return;
+        }
+
+        if (varType == null) {
+            return;
+        }
+            
+        switch (varType){
+            case Int:
+                this.value = ZERO_INT;
+                break;
+            case Boolean:
+                this.value = Boolean.FALSE;
+                break;
+            case Float:
+                this.value = ZERO_FLT; 
+                break;
+            case Vector2:
+                this.value = Vector2f.ZERO;
+                break;
+            case Vector3:
+                this.value = Vector3f.ZERO;
+                break;
+            case Vector4:
+                this.value = Vector4f.ZERO;
+                break;
+            default:
+                // won't happen because those are either textures
+                // or multidata types
+        }
+    }
+    
+    public void setValue(VarType type, Object value){
+        if (location == LOC_NOT_DEFINED) {
+            return;
+        }
+
+        if (varType != null && varType != type) {
+            throw new IllegalArgumentException("Expected a " + varType.name() + " value!");
+        }
+
+        if (value == null) {
+            throw new NullPointerException();
+        }
+
+        setByCurrentMaterial = true;
+
+        switch (type){
+            case Matrix3:
+                Matrix3f m3 = (Matrix3f) value;
+                if (multiData == null) {
+                    multiData = BufferUtils.createFloatBuffer(9);
+                }
+                m3.fillFloatBuffer(multiData, true);
+                multiData.clear();
+                break;
+            case Matrix4:
+                Matrix4f m4 = (Matrix4f) value;
+                if (multiData == null) {
+                    multiData = BufferUtils.createFloatBuffer(16);
+                }
+                m4.fillFloatBuffer(multiData, true);
+                multiData.clear();
+                break;
+            case IntArray:
+                int[] ia = (int[]) value;
+                if (this.value == null) {
+                    this.value = BufferUtils.createIntBuffer(ia);
+                } else {
+                    this.value = BufferUtils.ensureLargeEnough((IntBuffer)this.value, ia.length);
+                }
+                ((IntBuffer)this.value).clear();
+                break;
+            case FloatArray:
+                float[] fa = (float[]) value;
+                if (multiData == null) {
+                    multiData = BufferUtils.createFloatBuffer(fa);
+                } else {
+                    multiData = BufferUtils.ensureLargeEnough(multiData, fa.length);
+                }
+                multiData.put(fa);
+                multiData.clear();
+                break;
+            case Vector2Array:
+                Vector2f[] v2a = (Vector2f[]) value;
+                if (multiData == null) {
+                    multiData = BufferUtils.createFloatBuffer(v2a);
+                } else {
+                    multiData = BufferUtils.ensureLargeEnough(multiData, v2a.length * 2);
+                }
+                for (int i = 0; i < v2a.length; i++) {
+                    BufferUtils.setInBuffer(v2a[i], multiData, i);
+                }
+                multiData.clear();
+                break;
+            case Vector3Array:
+                Vector3f[] v3a = (Vector3f[]) value;
+                if (multiData == null) {
+                    multiData = BufferUtils.createFloatBuffer(v3a);
+                } else {
+                    multiData = BufferUtils.ensureLargeEnough(multiData, v3a.length * 3);
+                }
+                for (int i = 0; i < v3a.length; i++) {
+                    BufferUtils.setInBuffer(v3a[i], multiData, i);
+                }
+                multiData.clear();
+                break;
+            case Vector4Array:
+                Vector4f[] v4a = (Vector4f[]) value;
+                if (multiData == null) {
+                    multiData = BufferUtils.createFloatBuffer(v4a);
+                } else {
+                    multiData = BufferUtils.ensureLargeEnough(multiData, v4a.length * 4);
+                }
+                for (int i = 0; i < v4a.length; i++) {
+                    BufferUtils.setInBuffer(v4a[i], multiData, i);
+                }
+                multiData.clear();
+                break;
+            case Matrix3Array:
+                Matrix3f[] m3a = (Matrix3f[]) value;
+                if (multiData == null) {
+                    multiData = BufferUtils.createFloatBuffer(m3a.length * 9);
+                } else {
+                    multiData = BufferUtils.ensureLargeEnough(multiData, m3a.length * 9);
+                }
+                for (int i = 0; i < m3a.length; i++) {
+                    m3a[i].fillFloatBuffer(multiData, true);
+                }
+                multiData.clear();
+                break;
+            case Matrix4Array:
+                Matrix4f[] m4a = (Matrix4f[]) value;
+                if (multiData == null) {
+                    multiData = BufferUtils.createFloatBuffer(m4a.length * 16);
+                } else {
+                    multiData = BufferUtils.ensureLargeEnough(multiData, m4a.length * 16);
+                }
+                for (int i = 0; i < m4a.length; i++) {
+                    m4a[i].fillFloatBuffer(multiData, true);
+                }
+                multiData.clear();
+                break;
+                // Only use check if equals optimization for primitive values
+            case Int:
+            case Float:
+            case Boolean:
+                if (this.value != null && this.value.equals(value)) {
+                    return;
+                }
+                this.value = value;
+                break;
+            default:
+                this.value = value;
+                break;
+        }
+
+        if (multiData != null) {
+            this.value = multiData;
+        }
+
+        varType = type;
+        updateNeeded = true;
+    }
+
+    public void setVector4Length(int length){
+        if (location == -1)
+            return;
+
+        FloatBuffer fb = (FloatBuffer) value;
+        if (fb == null || fb.capacity() < length) {
+            value = BufferUtils.createFloatBuffer(length * 4);
+        }
+
+        varType = VarType.Vector4Array;
+        updateNeeded = true;
+        setByCurrentMaterial = true;
+    }
+
+    public void setVector4InArray(float x, float y, float z, float w, int index){
+        if (location == -1)
+            return;
+
+        if (varType != null && varType != VarType.Vector4Array)
+            throw new IllegalArgumentException("Expected a "+varType.name()+" value!");
+
+        FloatBuffer fb = (FloatBuffer) value;
+        fb.position(index * 4);
+        fb.put(x).put(y).put(z).put(w);
+        fb.rewind();
+        updateNeeded = true;
+        setByCurrentMaterial = true;
+    }
+    
+    public boolean isUpdateNeeded(){
+        return updateNeeded;
+    }
+
+    public void clearUpdateNeeded(){
+        updateNeeded = false;
+    }
+
+    public void reset(){
+        setByCurrentMaterial = false;
+        location = -2;
+        updateNeeded = true;
+    }
+
+}

+ 89 - 88
engine/src/core/com/jme3/shader/VarType.java

@@ -1,88 +1,89 @@
-/*
- * Copyright (c) 2009-2012 jMonkeyEngine
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
- *   may be used to endorse or promote products derived from this software
- *   without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.jme3.shader;
-
-public enum VarType {
-
-    Float("float"),
-    Vector2("vec2"),
-    Vector3("vec3"),
-    Vector4("vec4"),
-
-    FloatArray(true,false,"float[]"),
-    Vector2Array(true,false,"vec2[]"),
-    Vector3Array(true,false,"vec3[]"),
-    Vector4Array(true,false,"vec4[]"),
-
-    Boolean("bool"),
-
-    Matrix3(true,false,"mat3"),
-    Matrix4(true,false,"mat4"),
-
-    Matrix3Array(true,false,"mat3[]"),
-    Matrix4Array(true,false,"mat4[]"),
-    
-    TextureBuffer(false,true,"sampler1D|sampler1DShadow"),
-    Texture2D(false,true,"sampler2D|sampler2DShadow"),
-    Texture3D(false,true,"sampler3D"),
-    TextureArray(false,true,"sampler2DArray"),
-    TextureCubeMap(false,true,"samplerCube"),
-    Int("int");
-
-    private boolean usesMultiData = false;
-    private boolean textureType = false;
-    private String glslType;
-
-    
-    VarType(String glslType){
-        this.glslType = glslType;
-    }
-
-    VarType(boolean multiData, boolean textureType,String glslType){
-        usesMultiData = multiData;
-        this.textureType = textureType;
-        this.glslType = glslType;
-    }
-
-    public boolean isTextureType() {
-        return textureType;
-    }
-
-    public boolean usesMultiData() {
-        return usesMultiData;
-    }
-
-    public String getGlslType() {
-        return glslType;
-    }    
-
-}
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.shader;
+
+public enum VarType {
+
+    Float("float"),
+    Vector2("vec2"),
+    Vector3("vec3"),
+    Vector4("vec4"),
+
+    IntArray(true,false,"int[]"),
+    FloatArray(true,false,"float[]"),
+    Vector2Array(true,false,"vec2[]"),
+    Vector3Array(true,false,"vec3[]"),
+    Vector4Array(true,false,"vec4[]"),
+
+    Boolean("bool"),
+
+    Matrix3(true,false,"mat3"),
+    Matrix4(true,false,"mat4"),
+
+    Matrix3Array(true,false,"mat3[]"),
+    Matrix4Array(true,false,"mat4[]"),
+    
+    TextureBuffer(false,true,"sampler1D|sampler1DShadow"),
+    Texture2D(false,true,"sampler2D|sampler2DShadow"),
+    Texture3D(false,true,"sampler3D"),
+    TextureArray(false,true,"sampler2DArray"),
+    TextureCubeMap(false,true,"samplerCube"),
+    Int("int");
+
+    private boolean usesMultiData = false;
+    private boolean textureType = false;
+    private String glslType;
+
+    
+    VarType(String glslType){
+        this.glslType = glslType;
+    }
+
+    VarType(boolean multiData, boolean textureType,String glslType){
+        usesMultiData = multiData;
+        this.textureType = textureType;
+        this.glslType = glslType;
+    }
+
+    public boolean isTextureType() {
+        return textureType;
+    }
+
+    public boolean usesMultiData() {
+        return usesMultiData;
+    }
+
+    public String getGlslType() {
+        return glslType;
+    }    
+
+}

+ 1381 - 1363
engine/src/core/com/jme3/util/BufferUtils.java

@@ -1,1363 +1,1381 @@
-/*
- * Copyright (c) 2009-2012 jMonkeyEngine
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
- *   may be used to endorse or promote products derived from this software
- *   without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.jme3.util;
-
-import com.jme3.math.ColorRGBA;
-import com.jme3.math.Quaternion;
-import com.jme3.math.Vector2f;
-import com.jme3.math.Vector3f;
-import com.jme3.math.Vector4f;
-import java.lang.ref.PhantomReference;
-import java.lang.ref.Reference;
-import java.lang.ref.ReferenceQueue;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.nio.Buffer;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.DoubleBuffer;
-import java.nio.FloatBuffer;
-import java.nio.IntBuffer;
-import java.nio.LongBuffer;
-import java.nio.ShortBuffer;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * <code>BufferUtils</code> is a helper class for generating nio buffers from
- * jME data classes such as Vectors and ColorRGBA.
- * 
- * @author Joshua Slack
- * @version $Id: BufferUtils.java,v 1.16 2007/10/29 16:56:18 nca Exp $
- */
-public final class BufferUtils {
-
-    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;
-
-    /**
-     * 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) {
-        /**
-         * StackTraceElement[] stackTrace = new Throwable().getStackTrace(); int
-         * initialIndex = 0;
-         * 
-         * for (int i = 0; i < stackTrace.length; i++){ if
-         * (!stackTrace[i].getClassName().equals(BufferUtils.class.getName())){
-         * initialIndex = i; break; } }
-         * 
-         * int allocated = buffer.capacity(); int size = 0;
-         * 
-         * if (buffer instanceof FloatBuffer){ size = 4; }else if (buffer
-         * instanceof ShortBuffer){ size = 2; }else if (buffer instanceof
-         * ByteBuffer){ size = 1; }else if (buffer instanceof IntBuffer){ size =
-         * 4; }else if (buffer instanceof DoubleBuffer){ size = 8; }
-         * 
-         * allocated *= size;
-         * 
-         * for (int i = initialIndex; i < stackTrace.length; i++){
-         * StackTraceElement element = stackTrace[i]; if
-         * (element.getClassName().startsWith("java")){ break; }
-         * 
-         * try { Class clazz = Class.forName(element.getClassName()); if (i ==
-         * initialIndex){
-         * System.out.println(clazz.getSimpleName()+"."+element.getMethodName
-         * ()+"():" + element.getLineNumber() + " allocated " + allocated);
-         * }else{ System.out.println(" at " +
-         * clazz.getSimpleName()+"."+element.getMethodName()+"()"); } } catch
-         * (ClassNotFoundException ex) { } }
-         */
-        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 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 postion 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 postion 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);
-    }
-
-    /**
-     * 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 postions 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 postion 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 postions 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 = ByteBuffer.allocateDirect(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 seperate 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 = ByteBuffer.allocateDirect(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 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;
-        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 = ByteBuffer.allocateDirect(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 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;
-        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 = ByteBuffer.allocateDirect(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) {
-        byte[] bytes = data.getBytes();
-        ByteBuffer bb = createByteBuffer(bytes.length);
-        bb.put(bytes);
-        bb.flip();
-        return bb;
-    }
-
-    /**
-     * 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 = ByteBuffer.allocateDirect(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 seperate 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 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());
-        }
-    }
-    private static final AtomicBoolean loadedMethods = new AtomicBoolean(false);
-    private static Method cleanerMethod = null;
-    private static Method cleanMethod = null;
-    private static Method viewedBufferMethod = null;
-    private static Method freeMethod = null;
-
-    private static Method loadMethod(String className, String methodName) {
-        try {
-            Method method = Class.forName(className).getMethod(methodName);
-            method.setAccessible(true);
-            return method;
-        } catch (NoSuchMethodException ex) {
-            return null; // the method was not found
-        } catch (SecurityException ex) {
-            return null; // setAccessible not allowed by security policy
-        } catch (ClassNotFoundException ex) {
-            return null; // the direct buffer implementation was not found
-        }
-    }
-
-    private static void loadCleanerMethods() {
-        // If its already true, exit, if not, set it to true.
-        if (BufferUtils.loadedMethods.getAndSet(true)) {
-            return;
-        }
-        // This could potentially be called many times if used from multiple
-        // threads
-        synchronized (BufferUtils.loadedMethods) {
-            // Oracle JRE / OpenJDK
-            cleanerMethod = loadMethod("sun.nio.ch.DirectBuffer", "cleaner");
-            cleanMethod = loadMethod("sun.misc.Cleaner", "clean");
-            viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "viewedBuffer");
-            if (viewedBufferMethod == null) {
-                // They changed the name in Java 7 (???)
-                viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "attachment");
-            }
-
-            // Apache Harmony
-            ByteBuffer bb = BufferUtils.createByteBuffer(1);
-            Class<?> clazz = bb.getClass();
-            try {
-                freeMethod = clazz.getMethod("free");
-            } catch (NoSuchMethodException ex) {
-            } catch (SecurityException ex) {
-            }
-        }
-    }
-
-    /**
-     * 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. This function
-     * explicitly calls the Cleaner method of a direct buffer.
-     * 
-     * @param toBeDestroyed
-     *          The direct buffer that will be "cleaned". Utilizes reflection.
-     * 
-     */
-    public static void destroyDirectBuffer(Buffer toBeDestroyed) {
-        if (!isDirect(toBeDestroyed)) {
-            return;
-        }
-
-        BufferUtils.loadCleanerMethods();
-
-        try {
-            if (freeMethod != null) {
-                freeMethod.invoke(toBeDestroyed);
-            } else {
-                Object cleaner = cleanerMethod.invoke(toBeDestroyed);
-                if (cleaner != null) {
-                    cleanMethod.invoke(cleaner);
-                } else {
-                    // Try the alternate approach of getting the viewed buffer first
-                    Object viewedBuffer = viewedBufferMethod.invoke(toBeDestroyed);
-                    if (viewedBuffer != null) {
-                        destroyDirectBuffer((Buffer) viewedBuffer);
-                    } else {
-                        Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "Buffer cannot be destroyed: {0}", toBeDestroyed);
-                    }
-                }
-            }
-        } catch (IllegalAccessException ex) {
-            Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
-        } catch (IllegalArgumentException ex) {
-            Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
-        } catch (InvocationTargetException ex) {
-            Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
-        } catch (SecurityException ex) {
-            Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
-        }
-    }
-    
-    /*
-     * 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();
-            }
-        }
-    }
-}
+/*
+ * Copyright (c) 2009-2012 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.util;
+
+import com.jme3.math.ColorRGBA;
+import com.jme3.math.Quaternion;
+import com.jme3.math.Vector2f;
+import com.jme3.math.Vector3f;
+import com.jme3.math.Vector4f;
+import java.lang.ref.PhantomReference;
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.DoubleBuffer;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.LongBuffer;
+import java.nio.ShortBuffer;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * <code>BufferUtils</code> is a helper class for generating nio buffers from
+ * jME data classes such as Vectors and ColorRGBA.
+ * 
+ * @author Joshua Slack
+ * @version $Id: BufferUtils.java,v 1.16 2007/10/29 16:56:18 nca Exp $
+ */
+public final class BufferUtils {
+
+    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;
+
+    /**
+     * 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) {
+        /**
+         * StackTraceElement[] stackTrace = new Throwable().getStackTrace(); int
+         * initialIndex = 0;
+         * 
+         * for (int i = 0; i < stackTrace.length; i++){ if
+         * (!stackTrace[i].getClassName().equals(BufferUtils.class.getName())){
+         * initialIndex = i; break; } }
+         * 
+         * int allocated = buffer.capacity(); int size = 0;
+         * 
+         * if (buffer instanceof FloatBuffer){ size = 4; }else if (buffer
+         * instanceof ShortBuffer){ size = 2; }else if (buffer instanceof
+         * ByteBuffer){ size = 1; }else if (buffer instanceof IntBuffer){ size =
+         * 4; }else if (buffer instanceof DoubleBuffer){ size = 8; }
+         * 
+         * allocated *= size;
+         * 
+         * for (int i = initialIndex; i < stackTrace.length; i++){
+         * StackTraceElement element = stackTrace[i]; if
+         * (element.getClassName().startsWith("java")){ break; }
+         * 
+         * try { Class clazz = Class.forName(element.getClassName()); if (i ==
+         * initialIndex){
+         * System.out.println(clazz.getSimpleName()+"."+element.getMethodName
+         * ()+"():" + element.getLineNumber() + " allocated " + allocated);
+         * }else{ System.out.println(" at " +
+         * clazz.getSimpleName()+"."+element.getMethodName()+"()"); } } catch
+         * (ClassNotFoundException ex) { } }
+         */
+        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 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 postion 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 postion 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);
+    }
+
+    /**
+     * 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 postions 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 postion 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 postions 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 = ByteBuffer.allocateDirect(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 seperate 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 = ByteBuffer.allocateDirect(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 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;
+        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 = ByteBuffer.allocateDirect(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 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;
+        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 = ByteBuffer.allocateDirect(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) {
+        byte[] bytes = data.getBytes();
+        ByteBuffer bb = createByteBuffer(bytes.length);
+        bb.put(bytes);
+        bb.flip();
+        return bb;
+    }
+
+    /**
+     * 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 = ByteBuffer.allocateDirect(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 seperate 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());
+        }
+    }
+    private static final AtomicBoolean loadedMethods = new AtomicBoolean(false);
+    private static Method cleanerMethod = null;
+    private static Method cleanMethod = null;
+    private static Method viewedBufferMethod = null;
+    private static Method freeMethod = null;
+
+    private static Method loadMethod(String className, String methodName) {
+        try {
+            Method method = Class.forName(className).getMethod(methodName);
+            method.setAccessible(true);
+            return method;
+        } catch (NoSuchMethodException ex) {
+            return null; // the method was not found
+        } catch (SecurityException ex) {
+            return null; // setAccessible not allowed by security policy
+        } catch (ClassNotFoundException ex) {
+            return null; // the direct buffer implementation was not found
+        }
+    }
+
+    private static void loadCleanerMethods() {
+        // If its already true, exit, if not, set it to true.
+        if (BufferUtils.loadedMethods.getAndSet(true)) {
+            return;
+        }
+        // This could potentially be called many times if used from multiple
+        // threads
+        synchronized (BufferUtils.loadedMethods) {
+            // Oracle JRE / OpenJDK
+            cleanerMethod = loadMethod("sun.nio.ch.DirectBuffer", "cleaner");
+            cleanMethod = loadMethod("sun.misc.Cleaner", "clean");
+            viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "viewedBuffer");
+            if (viewedBufferMethod == null) {
+                // They changed the name in Java 7 (???)
+                viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "attachment");
+            }
+
+            // Apache Harmony
+            ByteBuffer bb = BufferUtils.createByteBuffer(1);
+            Class<?> clazz = bb.getClass();
+            try {
+                freeMethod = clazz.getMethod("free");
+            } catch (NoSuchMethodException ex) {
+            } catch (SecurityException ex) {
+            }
+        }
+    }
+
+    /**
+     * 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. This function
+     * explicitly calls the Cleaner method of a direct buffer.
+     * 
+     * @param toBeDestroyed
+     *          The direct buffer that will be "cleaned". Utilizes reflection.
+     * 
+     */
+    public static void destroyDirectBuffer(Buffer toBeDestroyed) {
+        if (!isDirect(toBeDestroyed)) {
+            return;
+        }
+
+        BufferUtils.loadCleanerMethods();
+
+        try {
+            if (freeMethod != null) {
+                freeMethod.invoke(toBeDestroyed);
+            } else {
+                Object cleaner = cleanerMethod.invoke(toBeDestroyed);
+                if (cleaner != null) {
+                    cleanMethod.invoke(cleaner);
+                } else {
+                    // Try the alternate approach of getting the viewed buffer first
+                    Object viewedBuffer = viewedBufferMethod.invoke(toBeDestroyed);
+                    if (viewedBuffer != null) {
+                        destroyDirectBuffer((Buffer) viewedBuffer);
+                    } else {
+                        Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "Buffer cannot be destroyed: {0}", toBeDestroyed);
+                    }
+                }
+            }
+        } catch (IllegalAccessException ex) {
+            Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
+        } catch (IllegalArgumentException ex) {
+            Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
+        } catch (InvocationTargetException ex) {
+            Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
+        } catch (SecurityException ex) {
+            Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex);
+        }
+    }
+    
+    /*
+     * 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();
+            }
+        }
+    }
+}

+ 5 - 0
engine/src/jogl/com/jme3/renderer/jogl/JoglRenderer.java

@@ -877,6 +877,7 @@ public class JoglRenderer implements Renderer {
 
         uniform.clearUpdateNeeded();
         FloatBuffer fb;
+        IntBuffer ib;
         GL gl = GLContext.getCurrentGL();
         switch (uniform.getVarType()) {
             case Float:
@@ -918,6 +919,10 @@ public class JoglRenderer implements Renderer {
                 assert fb.remaining() == 16;
                 gl.getGL2ES2().glUniformMatrix4fv(loc, 1, false, fb);
                 break;
+            case IntArray:
+                ib = (IntBuffer) uniform.getValue();
+                gl.getGL2ES2().glUniform1iv(loc, ib.remaining(), ib);
+                break;
             case FloatArray:
                 fb = (FloatBuffer) uniform.getValue();
                 gl.getGL2ES2().glUniform1fv(loc, fb.remaining(), fb);

+ 5 - 0
engine/src/lwjgl/com/jme3/renderer/lwjgl/LwjglRenderer.java

@@ -823,6 +823,7 @@ public class LwjglRenderer implements Renderer {
 
         uniform.clearUpdateNeeded();
         FloatBuffer fb;
+        IntBuffer ib;
         switch (uniform.getVarType()) {
             case Float:
                 Float f = (Float) uniform.getValue();
@@ -863,6 +864,10 @@ public class LwjglRenderer implements Renderer {
                 assert fb.remaining() == 16;
                 glUniformMatrix4(loc, false, fb);
                 break;
+            case IntArray:
+                ib = (IntBuffer) uniform.getValue();
+                glUniform1(loc, ib);
+                break;
             case FloatArray:
                 fb = (FloatBuffer) uniform.getValue();
                 glUniform1(loc, fb);