Ver código fonte

Adds a few missing features into the shader-based renderer relying on JOGL 2.0

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9888 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
jul..om 13 anos atrás
pai
commit
87e6ea3230
1 arquivos alterados com 389 adições e 157 exclusões
  1. 389 157
      engine/src/jogl/com/jme3/renderer/jogl/JoglRenderer.java

+ 389 - 157
engine/src/jogl/com/jme3/renderer/jogl/JoglRenderer.java

@@ -51,6 +51,7 @@ import com.jme3.scene.Mesh.Mode;
 import com.jme3.scene.VertexBuffer;
 import com.jme3.scene.VertexBuffer.Type;
 import com.jme3.scene.VertexBuffer.Usage;
+import com.jme3.shader.Attribute;
 import com.jme3.shader.Shader;
 import com.jme3.shader.Shader.ShaderSource;
 import com.jme3.shader.Uniform;
@@ -64,10 +65,7 @@ import com.jme3.util.IntMap;
 import com.jme3.util.IntMap.Entry;
 import com.jme3.util.ListMap;
 import com.jme3.util.NativeObjectManager;
-import java.nio.Buffer;
-import java.nio.ByteBuffer;
-import java.nio.FloatBuffer;
-import java.nio.IntBuffer;
+import java.nio.*;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.logging.Level;
@@ -91,6 +89,7 @@ public class JoglRenderer implements Renderer {
     private final StringBuilder stringBuf = new StringBuilder(250);
     private final IntBuffer intBuf1 = BufferUtils.createIntBuffer(1);
     private final IntBuffer intBuf16 = BufferUtils.createIntBuffer(16);
+    protected FloatBuffer fb16 = BufferUtils.createFloatBuffer(16);
     private RenderContext context = new RenderContext();
     private NativeObjectManager objManager = new NativeObjectManager();
     private EnumSet<Caps> caps = EnumSet.noneOf(Caps.class);
@@ -118,11 +117,6 @@ public class JoglRenderer implements Renderer {
     private final Statistics statistics = new Statistics();
     private int vpX, vpY, vpW, vpH;
     private int clipX, clipY, clipW, clipH;
-    //TODO: remove?
-    protected Matrix4f worldMatrix = new Matrix4f();
-    protected Matrix4f viewMatrix = new Matrix4f();
-    protected Matrix4f projMatrix = new Matrix4f();
-    protected FloatBuffer fb16 = BufferUtils.createFloatBuffer(16);
 
     public JoglRenderer() {
     }
@@ -423,15 +417,23 @@ public class JoglRenderer implements Renderer {
     }
     
     public void resetGLObjects() {
+        logger.log(Level.INFO, "Reseting objects and invalidating state");
         objManager.resetObjects();
         statistics.clearMemory();
-        boundShader = null;
-        lastFb = null;
-        context.reset();
+        invalidateState();
     }
     
     public void cleanup() {
+        logger.log(Level.INFO, "Deleting objects and invalidating state");
         objManager.deleteAllObjects(this);
+        statistics.clearMemory();
+        invalidateState();
+    }
+    
+    private void checkCap(Caps cap) {
+        if (!caps.contains(cap)) {
+            throw new UnsupportedOperationException("Required capability missing: " + cap.name());
+        }
     }
     
     /*********************************************************************\
@@ -446,9 +448,23 @@ public class JoglRenderer implements Renderer {
         GL gl = GLContext.getCurrentGL();
         int bits = 0;
         if (color) {
+            //See explanations of the depth below, we must enable color write to be able to clear the color buffer
+            if (context.colorWriteEnabled == false) {
+                gl.glColorMask(true, true, true, true);
+                context.colorWriteEnabled = true;
+            }
             bits = GL.GL_COLOR_BUFFER_BIT;
         }
         if (depth) {
+
+            //glClear(GL_DEPTH_BUFFER_BIT) seems to not work when glDepthMask is false
+            //here s some link on openl board
+            //http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=257223
+            //if depth clear is requested, we enable the depthMask
+            if (context.depthWriteEnabled == false) {
+                gl.glDepthMask(true);
+                context.depthWriteEnabled = true;
+            }
             bits |= GL.GL_DEPTH_BUFFER_BIT;
         }
         if (stencil) {
@@ -476,15 +492,15 @@ public class JoglRenderer implements Renderer {
     }
 
     public void applyRenderState(RenderState state) {
-        //FIXME implement missing features
         GL gl = GLContext.getCurrentGL();
         if (state.isWireframe() && !context.wireframe) {
-            gl.getGL2().glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_LINE);
+            gl.getGL2().glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_LINE);
             context.wireframe = true;
         } else if (!state.isWireframe() && context.wireframe) {
-            gl.getGL2().glPolygonMode(GL.GL_FRONT_AND_BACK, GL2GL3.GL_FILL);
+            gl.getGL2().glPolygonMode(GL.GL_FRONT_AND_BACK, GL2.GL_FILL);
             context.wireframe = false;
         }
+
         if (state.isDepthTest() && !context.depthTestEnabled) {
             gl.glEnable(GL.GL_DEPTH_TEST);
             gl.glDepthFunc(GL.GL_LEQUAL);
@@ -493,14 +509,16 @@ public class JoglRenderer implements Renderer {
             gl.glDisable(GL.GL_DEPTH_TEST);
             context.depthTestEnabled = false;
         }
+
         if (state.isAlphaTest() && context.alphaTestFallOff == 0) {
-            gl.glEnable(GL2ES1.GL_ALPHA_TEST);
+            gl.glEnable(GL2.GL_ALPHA_TEST);
             gl.getGL2().glAlphaFunc(GL.GL_GREATER, state.getAlphaFallOff());
             context.alphaTestFallOff = state.getAlphaFallOff();
         } else if (!state.isAlphaTest() && context.alphaTestFallOff != 0) {
-            gl.glDisable(GL2ES1.GL_ALPHA_TEST);
+            gl.glDisable(GL2.GL_ALPHA_TEST);
             context.alphaTestFallOff = 0;
         }
+
         if (state.isDepthWrite() && !context.depthWriteEnabled) {
             gl.glDepthMask(true);
             context.depthWriteEnabled = true;
@@ -508,6 +526,7 @@ public class JoglRenderer implements Renderer {
             gl.glDepthMask(false);
             context.depthWriteEnabled = false;
         }
+
         if (state.isColorWrite() && !context.colorWriteEnabled) {
             gl.glColorMask(true, true, true, true);
             context.colorWriteEnabled = true;
@@ -515,17 +534,43 @@ public class JoglRenderer implements Renderer {
             gl.glColorMask(false, false, false, false);
             context.colorWriteEnabled = false;
         }
+
+        if (state.isPointSprite() && !context.pointSprite) {
+            // Only enable/disable sprite
+            if (context.boundTextures[0] != null) {
+                if (context.boundTextureUnit != 0) {
+                    gl.glActiveTexture(GL.GL_TEXTURE0);
+                    context.boundTextureUnit = 0;
+                }
+                gl.glEnable(GL2.GL_POINT_SPRITE);
+                gl.glEnable(GL2.GL_VERTEX_PROGRAM_POINT_SIZE);
+            }
+            context.pointSprite = true;
+        } else if (!state.isPointSprite() && context.pointSprite) {
+            if (context.boundTextures[0] != null) {
+                if (context.boundTextureUnit != 0) {
+                    gl.glActiveTexture(GL.GL_TEXTURE0);
+                    context.boundTextureUnit = 0;
+                }
+                gl.glDisable(GL2.GL_POINT_SPRITE);
+                gl.glDisable(GL2.GL_VERTEX_PROGRAM_POINT_SIZE);
+                context.pointSprite = false;
+            }
+        }
+
         if (state.isPolyOffset()) {
             if (!context.polyOffsetEnabled) {
                 gl.glEnable(GL.GL_POLYGON_OFFSET_FILL);
-                gl.glPolygonOffset(state.getPolyOffsetFactor(), state.getPolyOffsetUnits());
+                gl.glPolygonOffset(state.getPolyOffsetFactor(),
+                        state.getPolyOffsetUnits());
                 context.polyOffsetEnabled = true;
                 context.polyOffsetFactor = state.getPolyOffsetFactor();
                 context.polyOffsetUnits = state.getPolyOffsetUnits();
             } else {
                 if (state.getPolyOffsetFactor() != context.polyOffsetFactor
                         || state.getPolyOffsetUnits() != context.polyOffsetUnits) {
-                    gl.glPolygonOffset(state.getPolyOffsetFactor(), state.getPolyOffsetUnits());
+                    gl.glPolygonOffset(state.getPolyOffsetFactor(),
+                            state.getPolyOffsetUnits());
                     context.polyOffsetFactor = state.getPolyOffsetFactor();
                     context.polyOffsetUnits = state.getPolyOffsetUnits();
                 }
@@ -538,6 +583,7 @@ public class JoglRenderer implements Renderer {
                 context.polyOffsetUnits = 0;
             }
         }
+
         if (state.getFaceCullMode() != context.cullMode) {
             if (state.getFaceCullMode() == RenderState.FaceCullMode.Off) {
                 gl.glDisable(GL.GL_CULL_FACE);
@@ -570,39 +616,78 @@ public class JoglRenderer implements Renderer {
                 gl.glDisable(GL.GL_BLEND);
             } else {
                 gl.glEnable(GL.GL_BLEND);
-            }
-
-            switch (state.getBlendMode()) {
-                case Off:
-                    break;
-                case Additive:
-                    gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE);
-                    break;
-                case AlphaAdditive:
-                    gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE);
-                    break;
-                case Alpha:
-                    gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
-                    break;
-                case Color:
-                    gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_COLOR);
-                    break;
-                case PremultAlpha:
-                    gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_ALPHA);
-                    break;
-                case Modulate:
-                    gl.glBlendFunc(GL.GL_DST_COLOR, GL.GL_ZERO);
-                    break;
-                case ModulateX2:
-                    gl.glBlendFunc(GL.GL_DST_COLOR, GL.GL_SRC_COLOR);
-                    break;
-                default:
-                    throw new UnsupportedOperationException("Unrecognized blend mode: "
-                            + state.getBlendMode());
+                switch (state.getBlendMode()) {
+                    case Off:
+                        break;
+                    case Additive:
+                        gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE);
+                        break;
+                    case AlphaAdditive:
+                        gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE);
+                        break;
+                    case Color:
+                        gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_COLOR);
+                        break;
+                    case Alpha:
+                        gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
+                        break;
+                    case PremultAlpha:
+                        gl.glBlendFunc(GL.GL_ONE, GL.GL_ONE_MINUS_SRC_ALPHA);
+                        break;
+                    case Modulate:
+                        gl.glBlendFunc(GL.GL_DST_COLOR, GL.GL_ZERO);
+                        break;
+                    case ModulateX2:
+                        gl.glBlendFunc(GL.GL_DST_COLOR, GL.GL_SRC_COLOR);
+                        break;
+                    default:
+                        throw new UnsupportedOperationException("Unrecognized blend mode: "
+                                + state.getBlendMode());
+                }
             }
 
             context.blendMode = state.getBlendMode();
         }
+
+        if (context.stencilTest != state.isStencilTest()
+                || context.frontStencilStencilFailOperation != state.getFrontStencilStencilFailOperation()
+                || context.frontStencilDepthFailOperation != state.getFrontStencilDepthFailOperation()
+                || context.frontStencilDepthPassOperation != state.getFrontStencilDepthPassOperation()
+                || context.backStencilStencilFailOperation != state.getBackStencilStencilFailOperation()
+                || context.backStencilDepthFailOperation != state.getBackStencilDepthFailOperation()
+                || context.backStencilDepthPassOperation != state.getBackStencilDepthPassOperation()
+                || context.frontStencilFunction != state.getFrontStencilFunction()
+                || context.backStencilFunction != state.getBackStencilFunction()) {
+
+            context.frontStencilStencilFailOperation = state.getFrontStencilStencilFailOperation();   //terrible looking, I know
+            context.frontStencilDepthFailOperation = state.getFrontStencilDepthFailOperation();
+            context.frontStencilDepthPassOperation = state.getFrontStencilDepthPassOperation();
+            context.backStencilStencilFailOperation = state.getBackStencilStencilFailOperation();
+            context.backStencilDepthFailOperation = state.getBackStencilDepthFailOperation();
+            context.backStencilDepthPassOperation = state.getBackStencilDepthPassOperation();
+            context.frontStencilFunction = state.getFrontStencilFunction();
+            context.backStencilFunction = state.getBackStencilFunction();
+
+            if (state.isStencilTest()) {
+                gl.glEnable(GL.GL_STENCIL_TEST);
+                gl.getGL2().glStencilOpSeparate(GL.GL_FRONT,
+                        convertStencilOperation(state.getFrontStencilStencilFailOperation()),
+                        convertStencilOperation(state.getFrontStencilDepthFailOperation()),
+                        convertStencilOperation(state.getFrontStencilDepthPassOperation()));
+                gl.getGL2().glStencilOpSeparate(GL.GL_BACK,
+                        convertStencilOperation(state.getBackStencilStencilFailOperation()),
+                        convertStencilOperation(state.getBackStencilDepthFailOperation()),
+                        convertStencilOperation(state.getBackStencilDepthPassOperation()));
+                gl.getGL2().glStencilFuncSeparate(GL.GL_FRONT,
+                        convertTestFunction(state.getFrontStencilFunction()),
+                        0, Integer.MAX_VALUE);
+                gl.getGL2().glStencilFuncSeparate(GL.GL_BACK,
+                        convertTestFunction(state.getBackStencilFunction()),
+                        0, Integer.MAX_VALUE);
+            } else {
+                gl.glDisable(GL.GL_STENCIL_TEST);
+            }
+        }
     }
     
     private int convertStencilOperation(RenderState.StencilOperation stencilOp) {
@@ -654,13 +739,15 @@ public class JoglRenderer implements Renderer {
     /*********************************************************************\
     |* Camera and World transforms                                       *|
     \*********************************************************************/
-    public void setViewPort(int x, int y, int width, int height) {
-        GL gl = GLContext.getCurrentGL();
-        gl.glViewport(x, y, width, height);
-        vpX = x;
-        vpY = y;
-        vpW = width;
-        vpH = height;
+    public void setViewPort(int x, int y, int w, int h) {
+        if (x != vpX || vpY != y || vpW != w || vpH != h) {
+            GL gl = GLContext.getCurrentGL();
+            gl.glViewport(x, y, w, h);
+            vpX = x;
+            vpY = y;
+            vpW = w;
+            vpH = h;
+        }
     }
 
     public void setClipRect(int x, int y, int width, int height) {
@@ -669,7 +756,13 @@ public class JoglRenderer implements Renderer {
             gl.glEnable(GL.GL_SCISSOR_TEST);
             context.clipRectEnabled = true;
         }
-        gl.glScissor(x, y, width, height);
+        if (clipX != x || clipY != y || clipW != width || clipH != height) {
+            gl.glScissor(x, y, width, height);
+            clipX = x;
+            clipY = y;
+            clipW = width;
+            clipH = height;
+        }
     }
 
     public void clearClipRect() {
@@ -677,6 +770,11 @@ public class JoglRenderer implements Renderer {
             GL gl = GLContext.getCurrentGL();
             gl.glDisable(GL.GL_SCISSOR_TEST);
             context.clipRectEnabled = false;
+
+            clipX = 0;
+            clipY = 0;
+            clipW = 0;
+            clipH = 0;
         }
     }
 
@@ -1088,13 +1186,13 @@ public class JoglRenderer implements Renderer {
         if (gl.isExtensionAvailable("GL_EXT_framebuffer_blit")) {
             int srcX0 = 0;
             int srcY0 = 0;
-            int srcX1 = 0;
-            int srcY1 = 0;
+            int srcX1/* = 0*/;
+            int srcY1/* = 0*/;
 
             int dstX0 = 0;
             int dstY0 = 0;
-            int dstX1 = 0;
-            int dstY1 = 0;
+            int dstX1/* = 0*/;
+            int dstY1/* = 0*/;
 
             int prevFBO = context.boundFBO;
 
@@ -1800,6 +1898,7 @@ public class JoglRenderer implements Renderer {
         img.clearUpdateNeeded();
     }
 
+    //FIXME remove it
     private void checkTexturingUsed() {
         IDList textureList = context.textureIndexList;
         GL gl = GLContext.getCurrentGL();
@@ -1878,6 +1977,9 @@ public class JoglRenderer implements Renderer {
         }
     }
 
+    /*********************************************************************\
+    |* Vertex Buffers and Attributes                                     *|
+    \*********************************************************************/
     private int convertUsage(Usage usage) {
         switch (usage) {
             case Static:
@@ -1890,30 +1992,69 @@ public class JoglRenderer implements Renderer {
                 throw new RuntimeException("Unknown usage type: " + usage);
         }
     }
+    
+    private int convertFormat(VertexBuffer.Format format) {
+        switch (format) {
+            case Byte:
+                return GL.GL_BYTE;
+            case UnsignedByte:
+                return GL.GL_UNSIGNED_BYTE;
+            case Short:
+                return GL.GL_SHORT;
+            case UnsignedShort:
+                return GL.GL_UNSIGNED_SHORT;
+            case Int:
+                return GL2.GL_INT;
+            case UnsignedInt:
+                return GL.GL_UNSIGNED_INT;
+//            case Half:
+//                return NVHalfFloat.GL_HALF_FLOAT_NV;
+//                return ARBHalfFloatVertex.GL_HALF_FLOAT;
+            case Float:
+                return GL.GL_FLOAT;
+            case Double:
+                return GL2.GL_DOUBLE;
+            default:
+                throw new UnsupportedOperationException("Unknown buffer format.");
+
+        }
+    }
 
     public void updateBufferData(VertexBuffer vb) {
         GL gl = GLContext.getCurrentGL();
         int bufId = vb.getId();
+        boolean created = false;
         if (bufId == -1) {
             // create buffer
             gl.glGenBuffers(1, intBuf1);
             bufId = intBuf1.get(0);
             vb.setId(bufId);
             objManager.registerForCleanup(vb);
+
+            //statistics.onNewVertexBuffer();
+
+            created = true;
         }
 
+        // bind buffer
         int target;
         if (vb.getBufferType() == VertexBuffer.Type.Index) {
             target = GL.GL_ELEMENT_ARRAY_BUFFER;
             if (context.boundElementArrayVBO != bufId) {
                 gl.glBindBuffer(target, bufId);
                 context.boundElementArrayVBO = bufId;
+                //statistics.onVertexBufferUse(vb, true);
+            } else {
+                //statistics.onVertexBufferUse(vb, false);
             }
         } else {
             target = GL.GL_ARRAY_BUFFER;
             if (context.boundArrayVBO != bufId) {
                 gl.glBindBuffer(target, bufId);
                 context.boundArrayVBO = bufId;
+                //statistics.onVertexBufferUse(vb, true);
+            } else {
+                //statistics.onVertexBufferUse(vb, false);
             }
         }
 
@@ -1921,7 +2062,12 @@ public class JoglRenderer implements Renderer {
         Buffer data = vb.getData();
         data.rewind();
 
-        gl.glBufferData(target, data.capacity() * vb.getFormat().getComponentSize(), data, usage);
+        if (created || vb.hasDataSizeChanged()) {
+            // upload data based on format
+            gl.glBufferData(target, data.capacity() * vb.getFormat().getComponentSize(), data, usage);
+        } else {
+            gl.glBufferSubData(target, 0, data.capacity() * vb.getFormat().getComponentSize(), data);
+        }
 
         vb.clearUpdateNeeded();
     }
@@ -1935,9 +2081,101 @@ public class JoglRenderer implements Renderer {
             intBuf1.position(0).limit(1);
             gl.glDeleteBuffers(1, intBuf1);
             vb.resetObject();
+
+            //statistics.onDeleteVertexBuffer();
         }
     }
+    
+    public void clearVertexAttribs() {
+        IDList attribList = context.attribIndexList;
+        for (int i = 0; i < attribList.oldLen; i++) {
+            int idx = attribList.oldList[i];
+            GL gl = GLContext.getCurrentGL();
+            gl.getGL2().glDisableVertexAttribArray(idx);
+            context.boundAttribs[idx] = null;
+        }
+        context.attribIndexList.copyNewToOld();
+    }
+    
+    public void setVertexAttrib(VertexBuffer vb, VertexBuffer idb) {
+        if (vb.getBufferType() == VertexBuffer.Type.Index) {
+            throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib");
+        }
+        
+        int programId = context.boundShaderProgram;
+        if (programId > 0) {
+            GL gl = GLContext.getCurrentGL();
+            Attribute attrib = boundShader.getAttribute(vb.getBufferType());
+            int loc = attrib.getLocation();
+            if (loc == -1) {
+                return; // not defined
+            }
+            if (loc == -2) {
+                stringBuf.setLength(0);
+                stringBuf.append("in").append(vb.getBufferType().name()).append('\0');
+                updateNameBuffer();
+                loc = gl.getGL2().glGetAttribLocation(programId, stringBuf.toString());
+
+                // not really the name of it in the shader (inPosition\0) but
+                // the internal name of the enum (Position).
+                if (loc < 0) {
+                    attrib.setLocation(-1);
+                    return; // not available in shader.
+                } else {
+                    attrib.setLocation(loc);
+                }
+            }
+
+            if (vb.isUpdateNeeded() && idb == null) {
+                updateBufferData(vb);
+            }
 
+            VertexBuffer[] attribs = context.boundAttribs;
+            if (!context.attribIndexList.moveToNew(loc)) {
+                gl.getGL2().glEnableVertexAttribArray(loc);
+                //System.out.println("Enabled ATTRIB IDX: "+loc);
+            }
+            if (attribs[loc] != vb) {
+                // NOTE: Use id from interleaved buffer if specified
+                int bufId = idb != null ? idb.getId() : vb.getId();
+                assert bufId != -1;
+                if (context.boundArrayVBO != bufId) {
+                    gl.glBindBuffer(GL.GL_ARRAY_BUFFER, bufId);
+                    context.boundArrayVBO = bufId;
+                    //statistics.onVertexBufferUse(vb, true);
+                } else {
+                    //statistics.onVertexBufferUse(vb, false);
+                }
+
+                gl.getGL2().glVertexAttribPointer(loc,
+                        vb.getNumComponents(),
+                        convertFormat(vb.getFormat()),
+                        vb.isNormalized(),
+                        vb.getStride(),
+                        vb.getOffset());
+
+                attribs[loc] = vb;
+            }
+        } else {
+            throw new IllegalStateException("Cannot render mesh without shader bound");
+        }
+    }
+
+    public void setVertexAttrib(VertexBuffer vb) {
+        setVertexAttrib(vb, null);
+    }
+    
+    public void drawTriangleArray(Mesh.Mode mode, int count, int vertCount) {
+        GL gl = GLContext.getCurrentGL();
+        if (count > 1) {
+            gl.getGL2().glDrawArraysInstanced(convertElementMode(mode), 0,
+                    vertCount, count);
+        } else {
+            gl.glDrawArrays(convertElementMode(mode), 0, vertCount);
+        }
+    }
+    
+    //FIXME remove
     private int convertArrayType(VertexBuffer.Type type) {
         switch (type) {
             case Position:
@@ -1953,6 +2191,7 @@ public class JoglRenderer implements Renderer {
         }
     }
 
+    //FIXME remove
     private int convertVertexFormat(VertexBuffer.Format fmt) {
         switch (fmt) {
             case Byte:
@@ -1977,7 +2216,94 @@ public class JoglRenderer implements Renderer {
                 throw new UnsupportedOperationException("Unrecognized vertex format: " + fmt);
         }
     }
+    
+    public void drawTriangleList(VertexBuffer indexBuf, Mesh mesh, int count) {
+        if (indexBuf.getBufferType() != VertexBuffer.Type.Index) {
+            throw new IllegalArgumentException("Only index buffers are allowed as triangle lists.");
+        }
+
+        if (indexBuf.isUpdateNeeded()) {
+            updateBufferData(indexBuf);
+        }
+
+        int bufId = indexBuf.getId();
+        assert bufId != -1;
+
+        GL gl = GLContext.getCurrentGL();
+        if (context.boundElementArrayVBO != bufId) {
+            gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, bufId);
+            context.boundElementArrayVBO = bufId;
+            //statistics.onVertexBufferUse(indexBuf, true);
+        } else {
+            //statistics.onVertexBufferUse(indexBuf, true);
+        }
+
+        int vertCount = mesh.getVertexCount();
+        boolean useInstancing = count > 1 && caps.contains(Caps.MeshInstancing);
+
+        if (mesh.getMode() == Mode.Hybrid) {
+            int[] modeStart = mesh.getModeStart();
+            int[] elementLengths = mesh.getElementLengths();
 
+            int elMode = convertElementMode(Mode.Triangles);
+            int fmt = convertFormat(indexBuf.getFormat());
+            int elSize = indexBuf.getFormat().getComponentSize();
+            int listStart = modeStart[0];
+            int stripStart = modeStart[1];
+            int fanStart = modeStart[2];
+            int curOffset = 0;
+            for (int i = 0; i < elementLengths.length; i++) {
+                if (i == stripStart) {
+                    elMode = convertElementMode(Mode.TriangleStrip);
+                } else if (i == fanStart) {
+                    elMode = convertElementMode(Mode.TriangleStrip);
+                }
+                int elementLength = elementLengths[i];
+
+                if (useInstancing) {
+                    
+                    indexBuf.getData().position(curOffset);
+                    indexBuf.getData().limit(curOffset + elementLength);
+                    
+                    gl.getGL2GL3().glDrawElementsInstanced(elMode,
+                            elementLength,
+                            fmt,
+                            indexBuf.getData(),
+                            count);
+                    
+                } else {
+                    gl.getGL2().glDrawRangeElements(elMode,
+                            0,
+                            vertCount,
+                            elementLength,
+                            fmt,
+                            curOffset);
+                }
+
+                //FIXME check whether elSize is required
+                curOffset += elementLength/* * elSize*/;
+            }
+        } else {
+            if (useInstancing) {
+                gl.getGL2GL3().glDrawElementsInstanced(convertElementMode(mesh.getMode()),
+                        indexBuf.getData().limit(),
+                        convertFormat(indexBuf.getFormat()),
+                        indexBuf.getData(),
+                        count);
+            } else {
+                gl.getGL2().glDrawRangeElements(convertElementMode(mesh.getMode()),
+                        0,
+                        vertCount,
+                        indexBuf.getData().limit(),
+                        convertFormat(indexBuf.getFormat()),
+                        0);
+            }
+        }
+    }
+
+    /*********************************************************************\
+    |* Render Calls                                                      *|
+    \*********************************************************************/
     private int convertElementMode(Mesh.Mode mode) {
         switch (mode) {
             case Points:
@@ -2095,102 +2421,8 @@ public class JoglRenderer implements Renderer {
         }
     }
 
-    public void setVertexAttrib(VertexBuffer vb, VertexBuffer idb) {
-        GL gl = GLContext.getCurrentGL();
-        int arrayType = convertArrayType(vb.getBufferType());
-        if (arrayType == -1) {
-            return; // unsupported
-        }
-
-        gl.getGL2().glEnableClientState(arrayType);
-        context.boundAttribs[vb.getBufferType().ordinal()] = vb;
-
-        if (vb.getBufferType() == Type.Normal) {
-            // normalize if requested
-            if (vb.isNormalized() && !context.normalizeEnabled) {
-                gl.glEnable(GLLightingFunc.GL_NORMALIZE);
-                context.normalizeEnabled = true;
-            } else if (!vb.isNormalized() && context.normalizeEnabled) {
-                gl.glDisable(GLLightingFunc.GL_NORMALIZE);
-                context.normalizeEnabled = false;
-            }
-        }
-
-        // NOTE: Use data from interleaved buffer if specified
-        Buffer data = idb != null ? idb.getData() : vb.getData();
-        int comps = vb.getNumComponents();
-        int type = convertVertexFormat(vb.getFormat());
-        data.clear();
-        data.position(vb.getOffset());
-
-        switch (vb.getBufferType()) {
-            case Position:
-                gl.getGL2().glVertexPointer(comps, type, vb.getStride(), data);
-                break;
-            case Normal:
-                gl.getGL2().glNormalPointer(type, vb.getStride(), data);
-                break;
-            case Color:
-                gl.getGL2().glColorPointer(comps, type, vb.getStride(), data);
-                break;
-            case TexCoord:
-                gl.getGL2().glTexCoordPointer(comps, type, vb.getStride(), data);
-                break;
-        }
-    }
-
-    public void setVertexAttrib(VertexBuffer vb) {
-        setVertexAttrib(vb, null);
-    }
-
-    public void clearVertexAttribs() {
-        GL gl = GLContext.getCurrentGL();
-        for (int i = 0; i < 16; i++) {
-            VertexBuffer vb = context.boundAttribs[i];
-            if (vb != null) {
-                int arrayType = convertArrayType(vb.getBufferType());
-                gl.getGL2().glDisableClientState(arrayType);
-                context.boundAttribs[vb.getBufferType().ordinal()] = null;
-            }
-        }
-    }
-
-    public void drawTriangleList(VertexBuffer indexBuf, Mesh mesh, int count) {
-        GL gl = GLContext.getCurrentGL();
-        Mesh.Mode mode = mesh.getMode();
-
-        Buffer indexData = indexBuf.getData();
-        indexData.clear();
-        if (mesh.getMode() == Mode.Hybrid) {
-            int[] modeStart = mesh.getModeStart();
-            int[] elementLengths = mesh.getElementLengths();
-
-            int elMode = convertElementMode(Mode.Triangles);
-            int fmt = convertVertexFormat(indexBuf.getFormat());
-            // int elSize = indexBuf.getFormat().getComponentSize();
-            // int listStart = modeStart[0];
-            int stripStart = modeStart[1];
-            int fanStart = modeStart[2];
-            int curOffset = 0;
-            for (int i = 0; i < elementLengths.length; i++) {
-                if (i == stripStart) {
-                    elMode = convertElementMode(Mode.TriangleStrip);
-                } else if (i == fanStart) {
-                    elMode = convertElementMode(Mode.TriangleStrip);
-                }
-                int elementLength = elementLengths[i];
-                indexData.position(curOffset);
-                gl.glDrawElements(elMode, elementLength, fmt, indexData);
-                curOffset += elementLength;
-            }
-        } else {
-            gl.glDrawElements(convertElementMode(mode), indexData.capacity(),
-                    convertVertexFormat(indexBuf.getFormat()), indexData);
-        }
-    }
-
     private void renderMeshDefault(Mesh mesh, int lod, int count) {
-        VertexBuffer indices = null;
+        VertexBuffer indices/* = null*/;
         VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData);
         IntMap<VertexBuffer> buffers = mesh.getBuffers();
         if (mesh.getNumLodLevels() > 0) {
@@ -2230,7 +2462,7 @@ public class JoglRenderer implements Renderer {
 
     private void renderMeshVBO(Mesh mesh, int lod, int count) {
         GL gl = GLContext.getCurrentGL();
-        VertexBuffer indices = null;
+        VertexBuffer indices/* = null*/;
         VertexBuffer interleavedData = mesh.getBuffer(Type.InterleavedData);
         if (interleavedData != null && interleavedData.isUpdateNeeded()) {
             updateBufferData(interleavedData);