Browse Source

Refactor renderer system
* Support OpenGL ES 2 in GLRenderer (various error fixes)
* Get rid of OpenGL 1 remenants
* Other minor cleanups

shadowislord 10 years ago
parent
commit
6ca111b13d
24 changed files with 224 additions and 331 deletions
  1. 2 11
      jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java
  2. 2 4
      jme3-core/src/main/java/com/jme3/material/Material.java
  3. 3 34
      jme3-core/src/main/java/com/jme3/renderer/RenderContext.java
  4. 4 23
      jme3-core/src/main/java/com/jme3/renderer/RenderManager.java
  5. 6 35
      jme3-core/src/main/java/com/jme3/renderer/Renderer.java
  6. 5 0
      jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java
  7. 2 0
      jme3-core/src/main/java/com/jme3/renderer/opengl/GL2.java
  8. 1 1
      jme3-core/src/main/java/com/jme3/renderer/opengl/GLExt.java
  9. 1 0
      jme3-core/src/main/java/com/jme3/renderer/opengl/GLFbo.java
  10. 1 0
      jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java
  11. 172 181
      jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java
  12. 1 1
      jme3-core/src/main/java/com/jme3/system/NullRenderer.java
  13. 1 1
      jme3-ios/src/main/java/com/jme3/renderer/ios/IGLESShaderRenderer.java
  14. 1 22
      jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglRenderer.java
  15. 1 1
      jme3-jogl/src/main/java/com/jme3/system/jogl/JoglCanvas.java
  16. 1 1
      jme3-jogl/src/main/java/com/jme3/system/jogl/JoglDisplay.java
  17. 1 1
      jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtCanvas.java
  18. 1 1
      jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtDisplay.java
  19. 1 1
      jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java
  20. 4 2
      jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java
  21. 9 7
      jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java
  22. 2 2
      jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java
  23. 1 1
      jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java
  24. 1 1
      jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java

+ 2 - 11
jme3-android/src/main/java/com/jme3/renderer/android/OGLESShaderRenderer.java

@@ -643,18 +643,12 @@ public class OGLESShaderRenderer implements Renderer {
         }
     }
 
-    public void onFrame() {
+    public void postFrame() {
         RendererUtil.checkGLErrorForced();
 
         objManager.deleteUnused(this);
     }
-
-    public void setWorldMatrix(Matrix4f worldMatrix) {
-    }
-
-    public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix) {
-    }
-
+    
     /*********************************************************************\
     |* Shaders                                                           *|
     \*********************************************************************/
@@ -1072,9 +1066,6 @@ public class OGLESShaderRenderer implements Renderer {
     /*********************************************************************\
     |* Framebuffers                                                      *|
     \*********************************************************************/
-    public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) {
-        copyFrameBuffer(src, dst, true);
-    }
 
     public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) {
             throw new RendererException("Copy framebuffer not implemented yet.");

+ 2 - 4
jme3-core/src/main/java/com/jme3/material/Material.java

@@ -1199,20 +1199,18 @@ public class Material implements CloneableSmartAsset, Cloneable, Savable {
         // send lighting information, if needed
         switch (techDef.getLightMode()) {
             case Disable:
-                r.setLighting(null);
                 break;
             case SinglePass:
                 int nbRenderedLights = 0;
                 resetUniformsNotSetByCurrent(shader);
-                while(nbRenderedLights < lights.size()){
+                while (nbRenderedLights < lights.size()) {
                     nbRenderedLights = updateLightListUniforms(shader, geom, lights, rm.getSinglePassLightBatchSize(), rm, nbRenderedLights);
                     r.setShader(shader);
                     renderMeshFromGeometry(r, geom);
                 }
                 return;
             case FixedPipeline:
-                r.setLighting(lights);
-                break;
+                throw new IllegalArgumentException("OpenGL1 is not supported");
             case MultiPass:
                 // NOTE: Special case!
                 resetUniformsNotSetByCurrent(shader);

+ 3 - 34
jme3-core/src/main/java/com/jme3/renderer/RenderContext.java

@@ -250,36 +250,6 @@ public class RenderContext {
      */
     public IDList attribIndexList = new IDList();
     
-    /**
-     * Ambient color (GL1 only)
-     */
-    public ColorRGBA ambient;
-    
-    /**
-     * Diffuse color (GL1 only)
-     */
-    public ColorRGBA diffuse;
-    
-    /**
-     * Specular color (GL1 only)
-     */
-    public ColorRGBA specular;
-    
-    /**
-     * Material color (GL1 only)
-     */
-    public ColorRGBA color;
-    
-    /**
-     * Shininess (GL1 only)
-     */
-    public float shininess;
-    
-    /**
-     * Use vertex color (GL1 only)
-     */
-    public boolean useVertexColor;
-    
     /**
      * depth tets function
      */
@@ -290,10 +260,11 @@ public class RenderContext {
      */
     public RenderState.TestFunction alphaFunc = RenderState.TestFunction.Greater;
 
-    
     public int initialDrawBuf;
     public int initialReadBuf;
     
+    public ColorRGBA clearColor = new ColorRGBA(0,0,0,0);
+    
     /**
      * Reset the RenderContext to default GL state
      */
@@ -343,10 +314,8 @@ public class RenderContext {
         frontStencilFunction = RenderState.TestFunction.Always;
         backStencilFunction = RenderState.TestFunction.Always;
         
-        ambient = diffuse = specular = color = null;
-        shininess = 0;
-        useVertexColor = false;
         depthFunc = RenderState.TestFunction.LessOrEqual;    
         alphaFunc = RenderState.TestFunction.Greater;
+        clearColor.set(0,0,0,0);
     }
 }

+ 4 - 23
jme3-core/src/main/java/com/jme3/renderer/RenderManager.java

@@ -82,7 +82,6 @@ public class RenderManager {
     private Material forcedMaterial = null;
     private String forcedTechnique = null;
     private RenderState forcedRenderState = null;
-    private boolean shader;
     private int viewX, viewY, viewWidth, viewHeight;
     private Matrix4f orthoMatrix = new Matrix4f();
     private LightList filteredLightList = new LightList(null);
@@ -476,11 +475,7 @@ public class RenderManager {
      * @param mat The world matrix to set
      */
     public void setWorldMatrix(Matrix4f mat) {
-        if (shader) {
-            uniformBindingManager.setWorldMatrix(mat);
-        } else {
-            renderer.setWorldMatrix(mat);
-        }
+        uniformBindingManager.setWorldMatrix(mat);
     }
 
     /**
@@ -927,19 +922,10 @@ public class RenderManager {
     }
 
     private void setViewProjection(Camera cam, boolean ortho) {
-        if (shader) {
-            if (ortho) {
-                uniformBindingManager.setCamera(cam, Matrix4f.IDENTITY, orthoMatrix, orthoMatrix);
-            } else {
-                uniformBindingManager.setCamera(cam, cam.getViewMatrix(), cam.getProjectionMatrix(), cam.getViewProjectionMatrix());
-            }
+        if (ortho) {
+            uniformBindingManager.setCamera(cam, Matrix4f.IDENTITY, orthoMatrix, orthoMatrix);
         } else {
-            if (ortho) {
-                renderer.setViewProjectionMatrices(Matrix4f.IDENTITY, orthoMatrix);
-            } else {
-                renderer.setViewProjectionMatrices(cam.getViewMatrix(),
-                        cam.getProjectionMatrix());
-            }
+            uniformBindingManager.setCamera(cam, cam.getViewMatrix(), cam.getProjectionMatrix(), cam.getViewProjectionMatrix());
         }
     }
 
@@ -1087,10 +1073,6 @@ public class RenderManager {
         
         if (prof!=null) prof.vpStep(VpStep.EndRender, vp, null);
     }
-
-    public void setUsingShaders(boolean usingShaders) { 
-        this.shader = usingShaders;
-    }
     
     /**
      * Called by the application to render any ViewPorts
@@ -1110,7 +1092,6 @@ public class RenderManager {
             return;
         }
 
-        this.shader = renderer.getCaps().contains(Caps.GLSL100);
         uniformBindingManager.newFrame();        
 
         if (prof!=null) prof.appStep(AppStep.RenderPreviewViewPorts);        

+ 6 - 35
jme3-core/src/main/java/com/jme3/renderer/Renderer.java

@@ -31,10 +31,8 @@
  */
 package com.jme3.renderer;
 
-import com.jme3.light.LightList;
 import com.jme3.material.RenderState;
 import com.jme3.math.ColorRGBA;
-import com.jme3.math.Matrix4f;
 import com.jme3.scene.Mesh;
 import com.jme3.scene.VertexBuffer;
 import com.jme3.shader.Shader;
@@ -55,6 +53,11 @@ import java.util.EnumSet;
  */
 public interface Renderer {
 
+    /**
+     * Detects available capabilities of the GPU. 
+     * 
+     * Must be called prior to any other Renderer methods.
+     */
     public void initialize();
     
     /**
@@ -113,24 +116,7 @@ public interface Renderer {
     /**
      * Called when a new frame has been rendered.
      */
-    public void onFrame();
-
-    /**
-     * Set the world matrix to use. Does nothing if the Renderer is 
-     * shader based.
-     * 
-     * @param worldMatrix World matrix to use.
-     */
-    public void setWorldMatrix(Matrix4f worldMatrix);
-
-    /**
-     * Sets the view and projection matrices to use. Does nothing if the Renderer 
-     * is shader based.
-     * 
-     * @param viewMatrix The view matrix to use.
-     * @param projMatrix The projection matrix to use.
-     */
-    public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix);
+    public void postFrame();
 
     /**
      * Set the viewport location and resolution on the screen.
@@ -160,16 +146,6 @@ public interface Renderer {
      */
     public void clearClipRect();
 
-    /**
-     * Set lighting state.
-     * Does nothing if the renderer is shader based.
-     * The lights should be provided in world space. 
-     * Specify <code>null</code> to disable lighting.
-     * 
-     * @param lights The light list to set.
-     */
-    public void setLighting(LightList lights);
-
     /**
      * Sets the shader to use for rendering.
      * If the shader has not been uploaded yet, it is compiled
@@ -195,11 +171,6 @@ public interface Renderer {
      */
     public void deleteShaderSource(ShaderSource source);
 
-    /**
-     * Copies contents from src to dst, scaling if necessary.
-     */
-    public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst);
-
     /**
      * Copies contents from src to dst, scaling if necessary.
      * set copyDepth to false to only copy the color buffers.

+ 5 - 0
jme3-core/src/main/java/com/jme3/renderer/opengl/GL.java

@@ -79,6 +79,9 @@ public interface GL {
 	public static final int GL_INCR_WRAP = 0x8507;
 	public static final int GL_INFO_LOG_LENGTH = 0x8B84;
 	public static final int GL_INT = 0x1404;
+        public static final int GL_INVALID_ENUM = 0x500;
+        public static final int GL_INVALID_VALUE = 0x501;
+        public static final int GL_INVALID_OPERATION = 0x502;
 	public static final int GL_INVERT = 0x150A;
 	public static final int GL_KEEP = 0x1E00;
 	public static final int GL_LEQUAL = 0x203;
@@ -102,12 +105,14 @@ public interface GL {
 	public static final int GL_NEAREST_MIPMAP_LINEAR = 0x2702;
 	public static final int GL_NEAREST_MIPMAP_NEAREST = 0x2700;
 	public static final int GL_NEVER = 0x200;
+        public static final int GL_NO_ERROR = 0x0;
 	public static final int GL_NONE = 0x0;
 	public static final int GL_NOTEQUAL = 0x205;
 	public static final int GL_ONE = 0x1;
 	public static final int GL_ONE_MINUS_DST_COLOR = 0x307;
 	public static final int GL_ONE_MINUS_SRC_ALPHA = 0x303;
 	public static final int GL_ONE_MINUS_SRC_COLOR = 0x301;
+        public static final int GL_OUT_OF_MEMORY = 0x505;
 	public static final int GL_POINTS = 0x0;
 	public static final int GL_POLYGON_OFFSET_FILL = 0x8037;
 	public static final int GL_REPEAT = 0x2901;

+ 2 - 0
jme3-core/src/main/java/com/jme3/renderer/opengl/GL2.java

@@ -62,6 +62,8 @@ public interface GL2 extends GL {
     public static final int GL_MAX_VERTEX_UNIFORM_COMPONENTS = 0x8B4A;
     public static final int GL_READ_BUFFER = 0xC02;
     public static final int GL_RGB8 = 0x8051;
+    public static final int GL_STACK_OVERFLOW = 0x503;
+    public static final int GL_STACK_UNDERFLOW = 0x504;
     public static final int GL_TEXTURE_3D = 0x806F;
     public static final int GL_POINT_SPRITE = 0x8861;
     public static final int GL_TEXTURE_COMPARE_FUNC = 0x884D;

+ 1 - 1
jme3-core/src/main/java/com/jme3/renderer/opengl/GLExt.java

@@ -43,7 +43,6 @@ import java.nio.IntBuffer;
  */
 public interface GLExt extends GLFbo {
 
-        public static final int GL_ETC1_RGB8_OES = 0x8D64;
 	public static final int GL_COMPRESSED_RGB8_ETC2 = 0x9274;
 	public static final int GL_COMPRESSED_RGBA_S3TC_DXT1_EXT = 0x83F1;
 	public static final int GL_COMPRESSED_RGBA_S3TC_DXT3_EXT = 0x83F2;
@@ -56,6 +55,7 @@ public interface GLExt extends GLFbo {
         public static final int GL_DEPTH_COMPONENT32F = 0x8CAC;
 	public static final int GL_DEPTH24_STENCIL8_EXT = 0x88F0;
 	public static final int GL_DEPTH_STENCIL_EXT = 0x84F9;
+        public static final int GL_ETC1_RGB8_OES = 0x8D64;
 	public static final int GL_FRAMEBUFFER_SRGB_CAPABLE_EXT = 0x8DBA;
 	public static final int GL_FRAMEBUFFER_SRGB_EXT = 0x8DB9;
 	public static final int GL_HALF_FLOAT_ARB = 0x140B;

+ 1 - 0
jme3-core/src/main/java/com/jme3/renderer/opengl/GLFbo.java

@@ -60,6 +60,7 @@ public interface GLFbo {
     public static final int GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT = 0x8D56;
     public static final int GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT = 0x8CDC;
     public static final int GL_FRAMEBUFFER_UNSUPPORTED_EXT = 0x8CDD;
+    public static final int GL_INVALID_FRAMEBUFFER_OPERATION_EXT = 0x506;
     public static final int GL_MAX_COLOR_ATTACHMENTS_EXT = 0x8CDF;
     public static final int GL_MAX_RENDERBUFFER_SIZE_EXT = 0x84E8;
     public static final int GL_READ_FRAMEBUFFER_BINDING_EXT = 0x8CAA;

+ 1 - 0
jme3-core/src/main/java/com/jme3/renderer/opengl/GLImageFormats.java

@@ -126,6 +126,7 @@ public final class GLImageFormats {
             format(formatToGL, Format.RGB8,             GLExt.GL_RGBA8, GL.GL_RGB,             GL.GL_UNSIGNED_BYTE);
             format(formatToGL, Format.RGBA8,            GLExt.GL_RGBA8, GL.GL_RGBA,            GL.GL_UNSIGNED_BYTE);
         } else {
+            // Actually, the internal format isn't used for OpenGL ES 2! This is the same as the above..
             format(formatToGL, Format.Alpha8,           GL.GL_RGBA4,   GL.GL_ALPHA,           GL.GL_UNSIGNED_BYTE);
             format(formatToGL, Format.Luminance8,       GL.GL_RGB565,  GL.GL_LUMINANCE,       GL.GL_UNSIGNED_BYTE);
             format(formatToGL, Format.Luminance8Alpha8, GL.GL_RGBA4,   GL.GL_LUMINANCE_ALPHA, GL.GL_UNSIGNED_BYTE);

+ 172 - 181
jme3-core/src/main/java/com/jme3/renderer/opengl/GLRenderer.java

@@ -70,6 +70,8 @@ public class GLRenderer implements Renderer {
 
     private static final Logger logger = Logger.getLogger(GLRenderer.class.getName());
     private static final boolean VALIDATE_SHADER = false;
+    private static final Pattern GLVERSION_PATTERN = Pattern.compile(".*?(\\d+)\\.(\\d+).*");
+    
     private final ByteBuffer nameBuf = BufferUtils.createByteBuffer(250);
     private final StringBuilder stringBuf = new StringBuilder(250);
     private final IntBuffer intBuf1 = BufferUtils.createIntBuffer(1);
@@ -117,18 +119,6 @@ public class GLRenderer implements Renderer {
         this.texUtil = new TextureUtil(gl, gl2, glext);
     }
 
-    protected void updateNameBuffer() {
-        int len = stringBuf.length();
-
-        nameBuf.position(0);
-        nameBuf.limit(len);
-        for (int i = 0; i < len; i++) {
-            nameBuf.put((byte) stringBuf.charAt(i));
-        }
-
-        nameBuf.rewind();
-    }
-
     @Override
     public Statistics getStatistics() {
         return statistics;
@@ -147,12 +137,8 @@ public class GLRenderer implements Renderer {
         return extensionSet;
     }
     
-    private static final Pattern VERSION = Pattern.compile(".*?(\\d+)\\.(\\d+).*");
-
-
     public static int extractVersion(String version) {
-
-        Matcher m = VERSION.matcher(version);
+        Matcher m = GLVERSION_PATTERN.matcher(version);
         if (m.matches()) {
             int major = Integer.parseInt(m.group(1));
             int minor = Integer.parseInt(m.group(2));
@@ -492,12 +478,6 @@ public class GLRenderer implements Renderer {
         invalidateState();
     }
 
-    private void checkCap(Caps cap) {
-        if (!caps.contains(cap)) {
-            throw new UnsupportedOperationException("Required capability missing: " + cap.name());
-        }
-    }
-
     /*********************************************************************\
     |* Render State                                                      *|
     \*********************************************************************/
@@ -516,11 +496,10 @@ public class GLRenderer implements Renderer {
             bits = GL.GL_COLOR_BUFFER_BIT;
         }
         if (depth) {
-
-            //glClear(GL.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
+            // glClear(GL.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;
@@ -528,6 +507,8 @@ public class GLRenderer implements Renderer {
             bits |= GL.GL_DEPTH_BUFFER_BIT;
         }
         if (stencil) {
+            // May need to set glStencilMask(0xFF) here if we ever allow users
+            // to change the stencil mask.
             bits |= GL.GL_STENCIL_BUFFER_BIT;
         }
         if (bits != 0) {
@@ -536,7 +517,10 @@ public class GLRenderer implements Renderer {
     }
 
     public void setBackgroundColor(ColorRGBA color) {
-        gl.glClearColor(color.r, color.g, color.b, color.a);
+        if (!context.clearColor.equals(color)) {
+            gl.glClearColor(color.r, color.g, color.b, color.a);
+            context.clearColor.set(color);
+        }
     }
 
     public void setAlphaToCoverage(boolean value) {
@@ -608,30 +592,28 @@ public class GLRenderer implements Renderer {
             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;
-                }
-                if (gl2 != null) {
+        if (gl2 != null) {
+            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;
+                    }
                     gl2.glEnable(GL2.GL_POINT_SPRITE);
                     gl2.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;
-                }
-                if (gl2 != null) {
+                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;
+                    }
                     gl2.glDisable(GL2.GL_POINT_SPRITE);
                     gl2.glDisable(GL2.GL_VERTEX_PROGRAM_POINT_SIZE);
+                    context.pointSprite = false;
                 }
-                context.pointSprite = false;
             }
         }
 
@@ -858,24 +840,15 @@ public class GLRenderer implements Renderer {
         }
     }
 
-    public void onFrame() {
+    public void postFrame() {
         objManager.deleteUnused(this);
-//        statistics.clearFrame();
-    }
-
-    public void setWorldMatrix(Matrix4f worldMatrix) {
-    }
-
-    public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix) {
     }
 
     /*********************************************************************\
     |* Shaders                                                           *|
     \*********************************************************************/
     protected void updateUniformLocation(Shader shader, Uniform uniform) {
-        stringBuf.setLength(0);
-        stringBuf.append(uniform.getName()).append('\0');
-        int loc = gl.glGetUniformLocation(shader.getId(), stringBuf.toString());
+        int loc = gl.glGetUniformLocation(shader.getId(), uniform.getName());
         if (loc < 0) {
             uniform.setLocation(-1);
             // uniform is not declared in shader
@@ -1020,13 +993,6 @@ public class GLRenderer implements Renderer {
         }
     }
 
-    /*
-     * (Non-javadoc)
-     * Only used for fixed-function. Ignored.
-     */
-    public void setLighting(LightList list) {
-    }
-
     public int convertShaderType(ShaderType type) {
         switch (type) {
             case Fragment:
@@ -1052,9 +1018,16 @@ public class GLRenderer implements Renderer {
             throw new RendererException("Cannot recompile shader source");
         }
 
+        boolean gles2 = caps.contains(Caps.OpenGLES20);
+        String language = source.getLanguage();
+        
+        if (gles2 && !language.equals("GLSL100")) {
+            throw new RendererException("This shader cannot run in OpenGL ES 2. "
+                                      + "Only GLSL 1.00 shaders are supported.");
+        }
+        
         // Upload shader source.
         // Merge the defines and source code.
-        String language = source.getLanguage();
         stringBuf.setLength(0);
         if (language.startsWith("GLSL")) {
             int version = Integer.parseInt(language.substring(4));
@@ -1066,11 +1039,20 @@ public class GLRenderer implements Renderer {
                 }
                 stringBuf.append("\n");
             } else {
-                // version 100 does not exist in desktop GLSL.
-                // put version 110 in that case to enable strict checking
-                stringBuf.append("#version 110\n");
+                if (gles2) {
+                    if (source.getType() == ShaderType.Fragment) {
+                        // GLES2 requires precision qualifier.
+                        stringBuf.append("precision mediump float;\n");
+                    }
+                } else {
+                    // version 100 does not exist in desktop GLSL.
+                    // put version 110 in that case to enable strict checking
+                    // (Only enabled for desktop GL)
+                    stringBuf.append("#version 110\n");
+                }
             }
         }
+        
         stringBuf.append(source.getDefines());
         stringBuf.append(source.getSource());
         
@@ -1309,8 +1291,7 @@ public class GLRenderer implements Renderer {
                 throw ex;
             }
         } else {
-            throw new RendererException("EXT_framebuffer_blit required.");
-            // TODO: support non-blit copies?
+            throw new RendererException("Framebuffer blitting not supported by the video hardware");
         }
     }
 
@@ -1504,10 +1485,10 @@ public class GLRenderer implements Renderer {
         }
 
         if (!caps.contains(Caps.FrameBuffer)) {
-            throw new RendererException("Framebuffer objects are not supported" +
-                                        " by the video hardware");
+            throw new RendererException("Framebuffer objects are not supported"
+                    + " by the video hardware");
         }
-        
+
         // generate mipmaps for last FB if needed
         if (context.boundFB != null) {
             for (int i = 0; i < context.boundFB.getNumColorBuffers(); i++) {
@@ -1518,14 +1499,18 @@ public class GLRenderer implements Renderer {
                     setTexture(0, rb.getTexture());
 
                     int textureType = convertTextureType(tex.getType(), tex.getImage().getMultiSamples(), rb.getFace());
-                    if (gl2 != null) gl2.glEnable(textureType);
+                    if (gl2 != null) {
+                        gl2.glEnable(textureType);
+                    }
                     glfbo.glGenerateMipmapEXT(textureType);
-                    if (gl2 != null) gl2.glDisable(textureType);
+                    if (gl2 != null) {
+                        gl2.glDisable(textureType);
+                    }
                 }
             }
         }
 
-    if (fb == null) {
+        if (fb == null) {
             // unbind any fbos
             if (context.boundFBO != 0) {
                 glfbo.glBindFramebufferEXT(GLExt.GL_FRAMEBUFFER_EXT, 0);
@@ -1579,7 +1564,7 @@ public class GLRenderer implements Renderer {
                         gl2.glReadBuffer(GL.GL_NONE);
                         context.boundReadBuf = -2;
                     }
-                    }
+                }
             } else {
                 if (fb.getNumColorBuffers() > maxFBOAttachs) {
                     throw new RendererException("Framebuffer has more color "
@@ -1588,8 +1573,8 @@ public class GLRenderer implements Renderer {
                 }
                 if (fb.isMultiTarget()) {
                     if (!caps.contains(Caps.FrameBufferMRT)) {
-                        throw new RendererException("Multiple render targets " +
-                                " are not supported by the video hardware");
+                        throw new RendererException("Multiple render targets "
+                                + " are not supported by the video hardware");
                     }
                     if (fb.getNumColorBuffers() > maxMRTFBOAttachs) {
                         throw new RendererException("Framebuffer has more"
@@ -1694,14 +1679,6 @@ public class GLRenderer implements Renderer {
             throw new RendererException("Multisample textures are not supported" + 
                                         " by the video hardware.");
         }
-        if (type == Texture.Type.ThreeDimensional && gl2 == null) {
-            throw new RendererException("3D textures are not supported" + 
-                                        " by the video hardware.");
-        } else if (type == Texture.Type.TwoDimensionalArray && !caps.contains(Caps.TextureArray)) {
-            throw new RendererException("Array textures are not supported" + 
-                                        " by the video hardware.");
-        }
-        
         
         switch (type) {
             case TwoDimensional:
@@ -1711,13 +1688,21 @@ public class GLRenderer implements Renderer {
                     return GL.GL_TEXTURE_2D;
                 }
             case TwoDimensionalArray:
+                if (!caps.contains(Caps.TextureArray)) {
+                    throw new RendererException("Array textures are not supported"
+                            + " by the video hardware.");
+                }
                 if (samples > 1) {
                     return GLExt.GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
                 } else {
                     return GLExt.GL_TEXTURE_2D_ARRAY_EXT;
                 }
             case ThreeDimensional:
-                return GL3.GL_TEXTURE_3D;
+                if (!caps.contains(Caps.OpenGL20)) {
+                    throw new RendererException("3D textures are not supported" + 
+                                        " by the video hardware.");
+                }
+                return GL2.GL_TEXTURE_3D;
             case CubeMap:
                 if (face < 0) {
                     return GL.GL_TEXTURE_CUBE_MAP;
@@ -2140,7 +2125,7 @@ public class GLRenderer implements Renderer {
                 //statistics.onVertexBufferUse(vb, false);
             }
         }
-
+        
         int usage = convertUsage(vb.getUsage());
         vb.getData().rewind();
 
@@ -2158,10 +2143,6 @@ public class GLRenderer implements Renderer {
                     break;
                 case Int:
                 case UnsignedInt:
-                    if (!caps.contains(Caps.IntegerIndexBuffer)) {
-                        throw new RendererException("32-bit index buffers are not supported by the video hardware");
-                    }
-                    
                     glext.glBufferData(target, (IntBuffer) vb.getData(), usage);
                     break;
                 case Float:
@@ -2230,108 +2211,103 @@ public class GLRenderer implements Renderer {
             throw new IllegalArgumentException("Index buffers not allowed to be set to vertex attrib");
         }
 
-        int programId = context.boundShaderProgram;
+        if (context.boundShaderProgram <= 0) {
+            throw new IllegalStateException("Cannot render mesh without shader bound");
+        }
+        
+        Attribute attrib = context.boundShader.getAttribute(vb.getBufferType());
+        int loc = attrib.getLocation();
+        if (loc == -1) {
+            return; // not defined
+        }
+        if (loc == -2) {
+            loc = gl.glGetAttribLocation(context.boundShaderProgram, "in" + vb.getBufferType().name());
 
-        if (programId > 0) {
-            Attribute attrib = context.boundShader.getAttribute(vb.getBufferType());
-            int loc = attrib.getLocation();
-            if (loc == -1) {
-                return; // not defined
+            // not really the name of it in the shader (inPosition) but
+            // the internal name of the enum (Position).
+            if (loc < 0) {
+                attrib.setLocation(-1);
+                return; // not available in shader.
+            } else {
+                attrib.setLocation(loc);
             }
-            if (loc == -2) {
-                stringBuf.setLength(0);
-                stringBuf.append("in").append(vb.getBufferType().name()).append('\0');
-                loc = gl.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.isInstanced()) {
-                if (!caps.contains(Caps.MeshInstancing)) {
-                    throw new RendererException("Instancing is required, "
-                            + "but not supported by the "
-                            + "graphics hardware");
-                }
+        if (vb.isInstanced()) {
+            if (!caps.contains(Caps.MeshInstancing)) {
+                throw new RendererException("Instancing is required, "
+                        + "but not supported by the "
+                        + "graphics hardware");
             }
-            int slotsRequired = 1;
-            if (vb.getNumComponents() > 4) {
-                if (vb.getNumComponents() % 4 != 0) {
-                    throw new RendererException("Number of components in multi-slot "
-                            + "buffers must be divisible by 4");
-                }
-                slotsRequired = vb.getNumComponents() / 4;
+        }
+        int slotsRequired = 1;
+        if (vb.getNumComponents() > 4) {
+            if (vb.getNumComponents() % 4 != 0) {
+                throw new RendererException("Number of components in multi-slot "
+                        + "buffers must be divisible by 4");
             }
+            slotsRequired = vb.getNumComponents() / 4;
+        }
 
-            if (vb.isUpdateNeeded() && idb == null) {
-                updateBufferData(vb);
-            }
+        if (vb.isUpdateNeeded() && idb == null) {
+            updateBufferData(vb);
+        }
 
-            VertexBuffer[] attribs = context.boundAttribs;
-            for (int i = 0; i < slotsRequired; i++) {
-                if (!context.attribIndexList.moveToNew(loc + i)) {
-                    gl.glEnableVertexAttribArray(loc + i);
-                    //System.out.println("Enabled ATTRIB IDX: "+loc);
-                }
+        VertexBuffer[] attribs = context.boundAttribs;
+        for (int i = 0; i < slotsRequired; i++) {
+            if (!context.attribIndexList.moveToNew(loc + i)) {
+                gl.glEnableVertexAttribArray(loc + i);
+            }
+        }
+        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);
             }
-            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);
-                }
 
-                if (slotsRequired == 1) {
-                    gl.glVertexAttribPointer(loc,
-                            vb.getNumComponents(),
+            if (slotsRequired == 1) {
+                gl.glVertexAttribPointer(loc,
+                        vb.getNumComponents(),
+                        convertFormat(vb.getFormat()),
+                        vb.isNormalized(),
+                        vb.getStride(),
+                        vb.getOffset());
+            } else {
+                for (int i = 0; i < slotsRequired; i++) {
+                    // The pointer maps the next 4 floats in the slot.
+                    // E.g.
+                    // P1: XXXX____________XXXX____________
+                    // P2: ____XXXX____________XXXX________
+                    // P3: ________XXXX____________XXXX____
+                    // P4: ____________XXXX____________XXXX
+                    // stride = 4 bytes in float * 4 floats in slot * num slots
+                    // offset = 4 bytes in float * 4 floats in slot * slot index
+                    gl.glVertexAttribPointer(loc + i,
+                            4,
                             convertFormat(vb.getFormat()),
                             vb.isNormalized(),
-                            vb.getStride(),
-                            vb.getOffset());
-                } else {
-                    for (int i = 0; i < slotsRequired; i++) {
-                        // The pointer maps the next 4 floats in the slot.
-                        // E.g.
-                        // P1: XXXX____________XXXX____________
-                        // P2: ____XXXX____________XXXX________
-                        // P3: ________XXXX____________XXXX____
-                        // P4: ____________XXXX____________XXXX
-                        // stride = 4 bytes in float * 4 floats in slot * num slots
-                        // offset = 4 bytes in float * 4 floats in slot * slot index
-                        gl.glVertexAttribPointer(loc + i,
-                                4,
-                                convertFormat(vb.getFormat()),
-                                vb.isNormalized(),
-                                4 * 4 * slotsRequired,
-                                4 * 4 * i);
-                    }
+                            4 * 4 * slotsRequired,
+                            4 * 4 * i);
                 }
+            }
 
-                for (int i = 0; i < slotsRequired; i++) {
-                    int slot = loc + i;
-                    if (vb.isInstanced() && (attribs[slot] == null || !attribs[slot].isInstanced())) {
-                        // non-instanced -> instanced
-                        glext.glVertexAttribDivisorARB(slot, vb.getInstanceSpan());
-                    } else if (!vb.isInstanced() && attribs[slot] != null && attribs[slot].isInstanced()) {
-                        // instanced -> non-instanced
-                        glext.glVertexAttribDivisorARB(slot, 0);
-                    }
-                    attribs[slot] = vb;
+            for (int i = 0; i < slotsRequired; i++) {
+                int slot = loc + i;
+                if (vb.isInstanced() && (attribs[slot] == null || !attribs[slot].isInstanced())) {
+                    // non-instanced -> instanced
+                    glext.glVertexAttribDivisorARB(slot, vb.getInstanceSpan());
+                } else if (!vb.isInstanced() && attribs[slot] != null && attribs[slot].isInstanced()) {
+                    // instanced -> non-instanced
+                    glext.glVertexAttribDivisorARB(slot, 0);
                 }
+                attribs[slot] = vb;
             }
-        } else {
-            throw new IllegalStateException("Cannot render mesh without shader bound");
         }
     }
 
@@ -2354,6 +2330,21 @@ public class GLRenderer implements Renderer {
             throw new IllegalArgumentException("Only index buffers are allowed as triangle lists.");
         }
 
+        switch (indexBuf.getFormat()) {
+            case UnsignedShort:
+                // OK: Works on all platforms.
+                break;
+            case UnsignedInt:
+                // Requres extension on OpenGL ES 2.
+                if (!caps.contains(Caps.IntegerIndexBuffer)) {
+                    throw new RendererException("32-bit index buffers are not supported by the video hardware");
+                }
+                break;
+            default:
+                // What is this?
+                throw new RendererException("Unexpected format for index buffer: " + indexBuf.getFormat());
+        }
+        
         if (indexBuf.isUpdateNeeded()) {
             updateBufferData(indexBuf);
         }

+ 1 - 1
jme3-core/src/main/java/com/jme3/system/NullRenderer.java

@@ -80,7 +80,7 @@ public class NullRenderer implements Renderer {
     public void setDepthRange(float start, float end) {
     }
 
-    public void onFrame() {
+    public void postFrame() {
     }
 
     public void setWorldMatrix(Matrix4f worldMatrix) {

+ 1 - 1
jme3-ios/src/main/java/com/jme3/renderer/ios/IGLESShaderRenderer.java

@@ -335,7 +335,7 @@ public class IGLESShaderRenderer implements Renderer {
     /**
      * Called when a new frame has been rendered.
      */
-    public void onFrame() {
+    public void postFrame() {
         logger.log(Level.FINE, "IGLESShaderRenderer onFrame");
         //JmeIosGLES.checkGLErrorForced();
         JmeIosGLES.checkGLError();

+ 1 - 22
jme3-jogl/src/main/java/com/jme3/renderer/jogl/JoglRenderer.java

@@ -832,17 +832,9 @@ public class JoglRenderer implements Renderer {
     }
 
     @Override
-	public void onFrame() {
+	public void postFrame() {
         objManager.deleteUnused(this);
     }
-    
-    @Override
-	public void setViewProjectionMatrices(Matrix4f viewMatrix, Matrix4f projMatrix) {
-    }
-
-    @Override
-	public void setWorldMatrix(Matrix4f worldMatrix) {
-    }
 
     /*********************************************************************\
     |* Shaders                                                           *|
@@ -997,14 +989,6 @@ public class JoglRenderer implements Renderer {
             uniform.reset(); // e.g check location again
         }
     }
-
-    /*
-     * (Non-javadoc)
-     * Only used for fixed-function. Ignored.
-     */
-    @Override
-	public void setLighting(LightList list) {
-    }
     
     public int convertShaderType(Shader.ShaderType type) {
         switch (type) {
@@ -1248,11 +1232,6 @@ public class JoglRenderer implements Renderer {
     /*********************************************************************\
     |* Framebuffers                                                      *|
     \*********************************************************************/
-    @Override
-	public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst) {
-        copyFrameBuffer(src, dst, true);
-    }
-
     @Override
 	public void copyFrameBuffer(FrameBuffer src, FrameBuffer dst, boolean copyDepth) {
         GL gl = GLContext.getCurrentGL();

+ 1 - 1
jme3-jogl/src/main/java/com/jme3/system/jogl/JoglCanvas.java

@@ -125,7 +125,7 @@ public class JoglCanvas extends JoglAbstractDisplay implements JmeCanvasContext
         }
 
         listener.update();
-        renderer.onFrame();
+        renderer.postFrame();
 
     }
 

+ 1 - 1
jme3-jogl/src/main/java/com/jme3/system/jogl/JoglDisplay.java

@@ -351,6 +351,6 @@ public class JoglDisplay extends JoglAbstractDisplay {
         }
 
         listener.update();
-        renderer.onFrame();
+        renderer.postFrame();
     }
 }

+ 1 - 1
jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtCanvas.java

@@ -145,7 +145,7 @@ public class JoglNewtCanvas extends JoglNewtAbstractDisplay implements JmeCanvas
         }
             
         listener.update();
-        renderer.onFrame();
+        renderer.postFrame();
 
     }
 

+ 1 - 1
jme3-jogl/src/main/java/com/jme3/system/jogl/JoglNewtDisplay.java

@@ -239,7 +239,7 @@ public class JoglNewtDisplay extends JoglNewtAbstractDisplay {
         }
 
         listener.update();
-        renderer.onFrame();
+        renderer.postFrame();
     }
 }
 

+ 1 - 1
jme3-jogl/src/main/java/com/jme3/system/jogl/JoglOffscreenBuffer.java

@@ -101,7 +101,7 @@ public class JoglOffscreenBuffer extends JoglContext implements Runnable {
         listener.update();
         checkGLError();
 
-        renderer.onFrame();
+        renderer.postFrame();
 
         int frameRate = settings.getFrameRate();
         if (frameRate >= 1) {

+ 4 - 2
jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglGL.java

@@ -343,11 +343,13 @@ public class LwjglGL implements GL, GL2 {
     }
 
     public int glGetAttribLocation(int param1, String param2) {
-        return GL20.glGetAttribLocation(param1, param2);
+        // NOTE: LWJGL requires null-terminated strings
+        return GL20.glGetAttribLocation(param1, param2 + "\0");
     }
 
     public int glGetUniformLocation(int param1, String param2) {
-        return GL20.glGetUniformLocation(param1, param2);
+        // NOTE: LWJGL requires null-terminated strings
+        return GL20.glGetUniformLocation(param1, param2 + "\0");
     }
 
     public void glShaderSource(int param1, String[] param2, IntBuffer param3) {

+ 9 - 7
jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/LwjglRenderer.java

@@ -424,11 +424,13 @@ public class LwjglRenderer  {
                 logger.log(Level.FINER, "Texture Multisample Depth Samples: {0}", maxDepthTexSamples);
             }
 
-            glGetInteger(GL_MAX_DRAW_BUFFERS, intBuf16);
-            maxMRTFBOAttachs = intBuf16.get(0);
-            if (maxMRTFBOAttachs > 1) {
-                caps.add(Caps.FrameBufferMRT);
-                logger.log(Level.FINER, "FBO Max MRT renderbuffers: {0}", maxMRTFBOAttachs);
+            if (hasExtension("GL_ARB_draw_buffers")) {
+                glGetInteger(GL_MAX_DRAW_BUFFERS, intBuf16);
+                maxMRTFBOAttachs = intBuf16.get(0);
+                if (maxMRTFBOAttachs > 1) {
+                    caps.add(Caps.FrameBufferMRT);
+                    logger.log(Level.FINER, "FBO Max MRT renderbuffers: {0}", maxMRTFBOAttachs);
+                }
             }
         }
 
@@ -832,7 +834,7 @@ public class LwjglRenderer  {
         }
     }
 
-    public void onFrame() {
+    public void postFrame() {
         objManager.deleteUnused(this);
 //        statistics.clearFrame();
     }
@@ -1945,7 +1947,7 @@ public class LwjglRenderer  {
             // Image does not have mipmaps, but they are required.
             // Generate from base level.
 
-            if (!caps.contains(Caps.OpenGL30)) {
+            if (!caps.contains(Caps.OpenGL30) && !caps.contains(Caps.OpenGLES20)) {
                 glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE);
                 img.setMipmapsGenerated(true);
             } else {

+ 2 - 2
jme3-lwjgl/src/main/java/com/jme3/renderer/lwjgl/TextureUtil.java

@@ -42,7 +42,7 @@ import java.util.EnumSet;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import static org.lwjgl.opengl.ARBDepthBufferFloat.*;
-import org.lwjgl.opengl.ARBES3Compatibility;
+import static org.lwjgl.opengl.ARBES3Compatibility.*;
 import static org.lwjgl.opengl.ARBHalfFloatPixel.*;
 import static org.lwjgl.opengl.ARBTextureFloat.*;
 import static org.lwjgl.opengl.ARBTextureMultisample.*;
@@ -139,7 +139,7 @@ class TextureUtil {
         // ETC1 support on regular OpenGL requires ES3 compatibility extension.
         // NOTE: ETC2 is backwards compatible with ETC1, so we can 
         // upload ETC1 textures as ETC2.
-        setFormat(Format.ETC1, ARBES3Compatibility.GL_COMPRESSED_RGB8_ETC2, GL_RGB, GL_UNSIGNED_BYTE, true);
+        setFormat(Format.ETC1, GL_COMPRESSED_RGB8_ETC2, GL_RGB, GL_UNSIGNED_BYTE, true);
     }
     
     //sRGB formats        

+ 1 - 1
jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglAbstractDisplay.java

@@ -184,7 +184,7 @@ public abstract class LwjglAbstractDisplay extends LwjglContext implements Runna
 
         // Subclasses just call GLObjectManager clean up objects here
         // it is safe .. for now.
-        renderer.onFrame();
+        renderer.postFrame();
     }
 
     /**

+ 1 - 1
jme3-lwjgl/src/main/java/com/jme3/system/lwjgl/LwjglOffscreenBuffer.java

@@ -125,7 +125,7 @@ public class LwjglOffscreenBuffer extends LwjglContext implements Runnable {
         listener.update();
         checkGLError();
 
-        renderer.onFrame();
+        renderer.postFrame();
 
         int frameRate = settings.getFrameRate();
         if (frameRate >= 1) {