commit b7074bc6f4c2e08d88195c2badcad0f2a77d433f
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Mon Apr 13 11:31:09 2020 +0100

    Lower requirements - now only OpenGL ES 3.0 is required; if running on such platform, OIT part of the API ( which is the only one which actually requires 3.1) is switched off.

diff --git a/src/main/java/org/distorted/library/effect/PostprocessEffect.java b/src/main/java/org/distorted/library/effect/PostprocessEffect.java
index 8e0b754..a5e04ae 100644
--- a/src/main/java/org/distorted/library/effect/PostprocessEffect.java
+++ b/src/main/java/org/distorted/library/effect/PostprocessEffect.java
@@ -79,7 +79,7 @@ public abstract class PostprocessEffect extends Effect implements InternalMaster
   private static ArrayList<Source> mSources = new ArrayList<>();
   private static int mNumSources = 0;
 
-  private class Job
+  private static class Job
     {
     int type;
     int level;
@@ -92,8 +92,8 @@ public abstract class PostprocessEffect extends Effect implements InternalMaster
     }
 
   private ArrayList<Job> mJobs = new ArrayList<>();
+  private int mQualityLevel;
 
-  int mQualityLevel;
   float mQualityScale;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -111,20 +111,20 @@ public abstract class PostprocessEffect extends Effect implements InternalMaster
  *
  * @y.exclude
  */
-  public static void createPrograms()
+  public static void createPrograms(int GLSL)
     {
     Source source;
     int len = mSources.size();
 
+    String version = "#version "+GLSL+" es\n";
+
     for(int i=0; i<len; i++)
       {
       source = mSources.remove(0);
 
-      //android.util.Log.d("postprocess", "compiling: "+source.mName);
-
       try
         {
-        mPrograms.add (new DistortedProgram(source.mVertexShader,source.mFragmentShader));
+        mPrograms.add (new DistortedProgram(version+source.mVertexShader,version+source.mFragmentShader));
         }
       catch(Exception e)
         {
diff --git a/src/main/java/org/distorted/library/effect/PostprocessEffectBlur.java b/src/main/java/org/distorted/library/effect/PostprocessEffectBlur.java
index ba2213d..873d6ef 100644
--- a/src/main/java/org/distorted/library/effect/PostprocessEffectBlur.java
+++ b/src/main/java/org/distorted/library/effect/PostprocessEffectBlur.java
@@ -19,9 +19,8 @@
 
 package org.distorted.library.effect;
 
-import android.opengl.GLES31;
+import android.opengl.GLES30;
 
-import org.distorted.library.main.DistortedLibrary;
 import org.distorted.library.main.DistortedFramebuffer;
 import org.distorted.library.main.InternalRenderState;
 import org.distorted.library.program.DistortedProgram;
@@ -37,7 +36,7 @@ public class PostprocessEffectBlur extends PostprocessEffect
 
   private Data1D mBlurRadius;
 
-  private static final float GAUSSIAN[] =   // G(0.00), G(0.03), G(0.06), ..., G(3.00), 0
+  private static final float[] GAUSSIAN =   // G(0.00), G(0.03), G(0.06), ..., G(3.00), 0
     {                                       // where G(x)= (1/(sqrt(2*PI))) * e^(-(x^2)/2). The last 0 terminates.
     0.398948f, 0.398769f, 0.398231f, 0.397336f, 0.396086f, 0.394485f, 0.392537f, 0.390247f, 0.387622f, 0.384668f,
     0.381393f, 0.377806f, 0.373916f, 0.369733f, 0.365268f, 0.360532f, 0.355538f, 0.350297f, 0.344823f, 0.339129f,
@@ -188,7 +187,7 @@ public class PostprocessEffectBlur extends PostprocessEffect
 
     int offset = radius + radius*radius/4;
     radius = (radius+1)/2;
-    GLES31.glViewport(0, 0, (int)w, (int)h);
+    GLES30.glViewport(0, 0, (int)w, (int)h);
 
     // horizontal blur
     for(int i=0; i<=radius; i++) mOffsets[i] = offsetsCache[offset+i]*offsetCorrW;
@@ -197,19 +196,19 @@ public class PostprocessEffectBlur extends PostprocessEffect
     buffer.bindForOutput(1);
     buffer.setAsInput(0);
 
-    GLES31.glColorMask(true,true,true,true);
-    GLES31.glClearColor(1.0f,1.0f,1.0f,0.0f);
-    GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT);
+    GLES30.glColorMask(true,true,true,true);
+    GLES30.glClearColor(1.0f,1.0f,1.0f,0.0f);
+    GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
 
-    GLES31.glUniform1f ( mProgram1.mUniform[0] , n );
-    GLES31.glUniform2f ( mProgram1.mUniform[1] , corrW, corrH );
-    GLES31.glUniform1i ( mProgram1.mUniform[2] , 0 );
-    GLES31.glUniform1fv( mProgram1.mUniform[3] , radius+1, mOffsets,0);
-    GLES31.glUniform1fv( mProgram1.mUniform[4] , radius+1, weightsCache,offset);
-    GLES31.glUniform1i ( mProgram1.mUniform[5] , radius);
-    GLES31.glVertexAttribPointer(mProgram1.mAttribute[0], POS_DATA_SIZE, GLES31.GL_FLOAT, false, 0, mQuadPositions);
-    GLES31.glVertexAttribPointer(mProgram1.mAttribute[1], TEX_DATA_SIZE, GLES31.GL_FLOAT, false, 0, mQuadTexture);
-    GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4);
+    GLES30.glUniform1f ( mProgram1.mUniform[0] , n );
+    GLES30.glUniform2f ( mProgram1.mUniform[1] , corrW, corrH );
+    GLES30.glUniform1i ( mProgram1.mUniform[2] , 0 );
+    GLES30.glUniform1fv( mProgram1.mUniform[3] , radius+1, mOffsets,0);
+    GLES30.glUniform1fv( mProgram1.mUniform[4] , radius+1, weightsCache,offset);
+    GLES30.glUniform1i ( mProgram1.mUniform[5] , radius);
+    GLES30.glVertexAttribPointer(mProgram1.mAttribute[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions);
+    GLES30.glVertexAttribPointer(mProgram1.mAttribute[1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadTexture);
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
 
     // vertical blur
     for(int i=0; i<=radius; i++) mOffsets[i] = offsetsCache[offset+i]*offsetCorrH;
@@ -218,17 +217,17 @@ public class PostprocessEffectBlur extends PostprocessEffect
     buffer.bindForOutput(0);
     buffer.setAsInput(1);
 
-    GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT);
+    GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
 
-    GLES31.glUniform1f ( mProgram2.mUniform[0] , n );
-    GLES31.glUniform2f ( mProgram2.mUniform[1] , corrW, corrH );
-    GLES31.glUniform1i ( mProgram2.mUniform[2] , 0 );
-    GLES31.glUniform1fv( mProgram2.mUniform[3] , radius+1, mOffsets,0);
-    GLES31.glUniform1fv( mProgram2.mUniform[4] , radius+1, weightsCache,offset);
-    GLES31.glUniform1i ( mProgram2.mUniform[5] , radius);
-    GLES31.glVertexAttribPointer(mProgram2.mAttribute[0], POS_DATA_SIZE, GLES31.GL_FLOAT, false, 0, mQuadPositions);
-    GLES31.glVertexAttribPointer(mProgram2.mAttribute[1], TEX_DATA_SIZE, GLES31.GL_FLOAT, false, 0, mQuadTexture);
-    GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4);
+    GLES30.glUniform1f ( mProgram2.mUniform[0] , n );
+    GLES30.glUniform2f ( mProgram2.mUniform[1] , corrW, corrH );
+    GLES30.glUniform1i ( mProgram2.mUniform[2] , 0 );
+    GLES30.glUniform1fv( mProgram2.mUniform[3] , radius+1, mOffsets,0);
+    GLES30.glUniform1fv( mProgram2.mUniform[4] , radius+1, weightsCache,offset);
+    GLES30.glUniform1i ( mProgram2.mUniform[5] , radius);
+    GLES30.glVertexAttribPointer(mProgram2.mAttribute[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions);
+    GLES30.glVertexAttribPointer(mProgram2.mAttribute[1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadTexture);
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
 
     InternalRenderState.unuseStencilMark();
 
@@ -245,7 +244,6 @@ public class PostprocessEffectBlur extends PostprocessEffect
     {
     final String blurVertex =
 
-        DistortedLibrary.GLSL_VERSION   +
       "precision lowp float;  \n"+
       "in vec2 a_Position;    \n"+
       "in vec2 a_TexCoord;    \n"+
@@ -261,7 +259,6 @@ public class PostprocessEffectBlur extends PostprocessEffect
 
     final String blurFragment1 =
 
-        DistortedLibrary.GLSL_VERSION               +
       "#define MAX_BLUR "+MAX_HALO+      "\n"+
       "precision lowp float;              \n"+
       "in vec2 v_TexCoord;                \n"+
@@ -284,7 +281,6 @@ public class PostprocessEffectBlur extends PostprocessEffect
 
     final String blurFragment2 =
 
-        DistortedLibrary.GLSL_VERSION               +
       "#define MAX_BLUR "+MAX_HALO+      "\n"+
       "precision lowp float;              \n"+
       "in vec2 v_TexCoord;                \n"+
diff --git a/src/main/java/org/distorted/library/effect/PostprocessEffectGlow.java b/src/main/java/org/distorted/library/effect/PostprocessEffectGlow.java
index 29097f2..686f863 100644
--- a/src/main/java/org/distorted/library/effect/PostprocessEffectGlow.java
+++ b/src/main/java/org/distorted/library/effect/PostprocessEffectGlow.java
@@ -19,9 +19,8 @@
 
 package org.distorted.library.effect;
 
-import android.opengl.GLES31;
+import android.opengl.GLES30;
 
-import org.distorted.library.main.DistortedLibrary;
 import org.distorted.library.main.DistortedFramebuffer;
 import org.distorted.library.main.InternalRenderState;
 import org.distorted.library.program.DistortedProgram;
@@ -39,7 +38,7 @@ public class PostprocessEffectGlow extends PostprocessEffect
   private Data1D mGlowRadius;
   private Data4D mColor;
 
-  private static final float GAUSSIAN[] =   // G(0.00), G(0.03), G(0.06), ..., G(3.00), 0
+  private static final float[] GAUSSIAN =   // G(0.00), G(0.03), G(0.06), ..., G(3.00), 0
     {                                       // where G(x)= (1/(sqrt(2*PI))) * e^(-(x^2)/2). The last 0 terminates.
     0.398948f, 0.398769f, 0.398231f, 0.397336f, 0.396086f, 0.394485f, 0.392537f, 0.390247f, 0.387622f, 0.384668f,
     0.381393f, 0.377806f, 0.373916f, 0.369733f, 0.365268f, 0.360532f, 0.355538f, 0.350297f, 0.344823f, 0.339129f,
@@ -191,7 +190,7 @@ public class PostprocessEffectGlow extends PostprocessEffect
 
     int offset = radius + radius*radius/4;
     radius = (radius+1)/2;
-    GLES31.glViewport(0, 0, (int)w, (int)h);
+    GLES30.glViewport(0, 0, (int)w, (int)h);
 
     // horizontal blur
     for(int i=0; i<=radius; i++) mOffsets[i] = offsetsCache[offset+i]*offsetCorrW;
@@ -200,19 +199,19 @@ public class PostprocessEffectGlow extends PostprocessEffect
     buffer.bindForOutput(1);
     buffer.setAsInput(0);
 
-    GLES31.glColorMask(true,true,true,true);
-    GLES31.glClearColor(1.0f,1.0f,1.0f,0.0f);
-    GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT);
+    GLES30.glColorMask(true,true,true,true);
+    GLES30.glClearColor(1.0f,1.0f,1.0f,0.0f);
+    GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
 
-    GLES31.glUniform1f ( mProgram1.mUniform[0] , n );
-    GLES31.glUniform2f ( mProgram1.mUniform[1] , corrW, corrH );
-    GLES31.glUniform1i ( mProgram1.mUniform[2] , 0 );
-    GLES31.glUniform1fv( mProgram1.mUniform[3] , radius+1, mOffsets,0);
-    GLES31.glUniform1fv( mProgram1.mUniform[4] , radius+1, weightsCache,offset);
-    GLES31.glUniform1i ( mProgram1.mUniform[5] , radius);
-    GLES31.glVertexAttribPointer(mProgram1.mAttribute[0], POS_DATA_SIZE, GLES31.GL_FLOAT, false, 0, mQuadPositions);
-    GLES31.glVertexAttribPointer(mProgram1.mAttribute[1], TEX_DATA_SIZE, GLES31.GL_FLOAT, false, 0, mQuadTexture);
-    GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4);
+    GLES30.glUniform1f ( mProgram1.mUniform[0] , n );
+    GLES30.glUniform2f ( mProgram1.mUniform[1] , corrW, corrH );
+    GLES30.glUniform1i ( mProgram1.mUniform[2] , 0 );
+    GLES30.glUniform1fv( mProgram1.mUniform[3] , radius+1, mOffsets,0);
+    GLES30.glUniform1fv( mProgram1.mUniform[4] , radius+1, weightsCache,offset);
+    GLES30.glUniform1i ( mProgram1.mUniform[5] , radius);
+    GLES30.glVertexAttribPointer(mProgram1.mAttribute[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions);
+    GLES30.glVertexAttribPointer(mProgram1.mAttribute[1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadTexture);
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
 
     // vertical blur
     for(int i=0; i<=radius; i++) mOffsets[i] = offsetsCache[offset+i]*offsetCorrH;
@@ -221,17 +220,17 @@ public class PostprocessEffectGlow extends PostprocessEffect
     buffer.bindForOutput(0);
     buffer.setAsInput(1);
 
-    GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT);
+    GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
 
-    GLES31.glUniform1f ( mProgram2.mUniform[0] , n );
-    GLES31.glUniform2f ( mProgram2.mUniform[1] , corrW, corrH );
-    GLES31.glUniform1i ( mProgram2.mUniform[2] , 0 );
-    GLES31.glUniform1fv( mProgram2.mUniform[3] , radius+1, mOffsets,0);
-    GLES31.glUniform1fv( mProgram2.mUniform[4] , radius+1, weightsCache,offset);
-    GLES31.glUniform1i ( mProgram2.mUniform[5] , radius);
-    GLES31.glVertexAttribPointer(mProgram2.mAttribute[0], POS_DATA_SIZE, GLES31.GL_FLOAT, false, 0, mQuadPositions);
-    GLES31.glVertexAttribPointer(mProgram2.mAttribute[1], TEX_DATA_SIZE, GLES31.GL_FLOAT, false, 0, mQuadTexture);
-    GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4);
+    GLES30.glUniform1f ( mProgram2.mUniform[0] , n );
+    GLES30.glUniform2f ( mProgram2.mUniform[1] , corrW, corrH );
+    GLES30.glUniform1i ( mProgram2.mUniform[2] , 0 );
+    GLES30.glUniform1fv( mProgram2.mUniform[3] , radius+1, mOffsets,0);
+    GLES30.glUniform1fv( mProgram2.mUniform[4] , radius+1, weightsCache,offset);
+    GLES30.glUniform1i ( mProgram2.mUniform[5] , radius);
+    GLES30.glVertexAttribPointer(mProgram2.mAttribute[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions);
+    GLES30.glVertexAttribPointer(mProgram2.mAttribute[1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadTexture);
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
 
     InternalRenderState.unuseStencilMark();
 
@@ -248,7 +247,6 @@ public class PostprocessEffectGlow extends PostprocessEffect
     {
     final String glowVertex =
 
-        DistortedLibrary.GLSL_VERSION   +
             "precision lowp float;  \n"+
             "in vec2 a_Position;    \n"+
             "in vec2 a_TexCoord;    \n"+
@@ -264,7 +262,6 @@ public class PostprocessEffectGlow extends PostprocessEffect
 
     final String glowFragment1 =
 
-        DistortedLibrary.GLSL_VERSION               +
             "#define MAX_BLUR "+MAX_HALO+      "\n"+
             "precision lowp float;              \n"+
             "in vec2 v_TexCoord;                \n"+
@@ -287,7 +284,6 @@ public class PostprocessEffectGlow extends PostprocessEffect
 
     final String glowFragment2 =
 
-        DistortedLibrary.GLSL_VERSION               +
             "#define MAX_BLUR "+MAX_HALO+      "\n"+
             "precision lowp float;              \n"+
             "in vec2 v_TexCoord;                \n"+
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.java b/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.java
index 8cf411e..e0c16e8 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.java
@@ -19,7 +19,7 @@
 
 package org.distorted.library.effectqueue;
 
-import android.opengl.GLES31;
+import android.opengl.GLES30;
 
 import org.distorted.library.effect.EffectType;
 import org.distorted.library.effect.FragmentEffect;
@@ -47,9 +47,9 @@ class EffectQueueFragment extends EffectQueue
 
   static void uniforms(int mProgramH, int variant)
     {
-    mNumEffectsH[variant]= GLES31.glGetUniformLocation( mProgramH, "fNumEffects");
-    mNameH[variant]      = GLES31.glGetUniformLocation( mProgramH, "fName");
-    mUniformsH[variant]  = GLES31.glGetUniformLocation( mProgramH, "fUniforms");
+    mNumEffectsH[variant]= GLES30.glGetUniformLocation( mProgramH, "fNumEffects");
+    mNameH[variant]      = GLES30.glGetUniformLocation( mProgramH, "fName");
+    mUniformsH[variant]  = GLES30.glGetUniformLocation( mProgramH, "fUniforms");
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -77,12 +77,12 @@ class EffectQueueFragment extends EffectQueue
   
   void send(int variant)
     {
-    GLES31.glUniform1i( mNumEffectsH[variant], mNumEffects);
+    GLES30.glUniform1i( mNumEffectsH[variant], mNumEffects);
 
     if( mNumEffects>0 )
       {
-      GLES31.glUniform1iv( mNameH[variant]    ,                 mNumEffects, mName    ,0);
-      GLES31.glUniform4fv( mUniformsH[variant],(NUM_UNIFORMS/4)*mNumEffects, mUniforms,0);
+      GLES30.glUniform1iv( mNameH[variant]    ,                 mNumEffects, mName    ,0);
+      GLES30.glUniform4fv( mUniformsH[variant],(NUM_UNIFORMS/4)*mNumEffects, mUniforms,0);
       }  
     }
   }
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueueMatrix.java b/src/main/java/org/distorted/library/effectqueue/EffectQueueMatrix.java
index 614cf67..949f779 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueueMatrix.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueueMatrix.java
@@ -19,7 +19,7 @@
 
 package org.distorted.library.effectqueue;
 
-import android.opengl.GLES31;
+import android.opengl.GLES30;
 import android.opengl.Matrix;
 
 import org.distorted.library.effect.EffectType;
@@ -58,10 +58,10 @@ class EffectQueueMatrix extends EffectQueue
 
   static void uniforms(int mProgramH, int variant)
     {
-    mBoundingH[variant] = GLES31.glGetUniformLocation(mProgramH, "u_Bounding");
-    mStretchH[variant]  = GLES31.glGetUniformLocation(mProgramH, "u_Stretch");
-    mMVPMatrixH[variant]= GLES31.glGetUniformLocation(mProgramH, "u_MVPMatrix");
-    mMVMatrixH[variant] = GLES31.glGetUniformLocation(mProgramH, "u_MVMatrix");
+    mBoundingH[variant] = GLES30.glGetUniformLocation(mProgramH, "u_Bounding");
+    mStretchH[variant]  = GLES30.glGetUniformLocation(mProgramH, "u_Stretch");
+    mMVPMatrixH[variant]= GLES30.glGetUniformLocation(mProgramH, "u_MVPMatrix");
+    mMVMatrixH[variant] = GLES30.glGetUniformLocation(mProgramH, "u_MVMatrix");
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -164,9 +164,9 @@ class EffectQueueMatrix extends EffectQueue
     // combined Model-View-Projection matrix
     Matrix.multiplyMM(mMVPMatrix, 0, projection, 0, mModelViewMatrix, 0);
 
-    GLES31.glUniform3f( mBoundingH[variant] , mesh.getBoundingX(), mesh.getBoundingY(), mesh.getBoundingZ());
-    GLES31.glUniform3f( mStretchH[variant]  , mesh.getStretchX() , mesh.getStretchY() , mesh.getStretchZ() );
-    GLES31.glUniformMatrix4fv(mMVMatrixH[variant] , 1, false, mModelViewMatrix, 0);
-    GLES31.glUniformMatrix4fv(mMVPMatrixH[variant], 1, false, mMVPMatrix      , 0);
+    GLES30.glUniform3f( mBoundingH[variant] , mesh.getBoundingX(), mesh.getBoundingY(), mesh.getBoundingZ());
+    GLES30.glUniform3f( mStretchH[variant]  , mesh.getStretchX() , mesh.getStretchY() , mesh.getStretchZ() );
+    GLES30.glUniformMatrix4fv(mMVMatrixH[variant] , 1, false, mModelViewMatrix, 0);
+    GLES30.glUniformMatrix4fv(mMVPMatrixH[variant], 1, false, mMVPMatrix      , 0);
     }
   }
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java b/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
index d01d9ac..dade475 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
@@ -20,7 +20,7 @@
 package org.distorted.library.effectqueue;
 
 import android.content.res.Resources;
-import android.opengl.GLES31;
+import android.opengl.GLES30;
 import android.util.Log;
 
 import org.distorted.library.R;
@@ -108,22 +108,23 @@ public class EffectQueuePostprocess extends EffectQueue
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public static void createPrograms(Resources resources)
+  public static void createPrograms(Resources resources, int GLSL)
     {
     final InputStream mainVertStream = resources.openRawResource(R.raw.main_vertex_shader);
     final InputStream mainFragStream = resources.openRawResource(R.raw.preprocess_fragment_shader);
 
     int numV = VertexEffect.getNumEnabled();
 
-    String mainVertHeader= DistortedLibrary.GLSL_VERSION + ("#define NUM_VERTEX "   + ( numV>0 ? DistortedLibrary.getMax(EffectType.VERTEX  ) : 0 ) + "\n");
-    String mainFragHeader= DistortedLibrary.GLSL_VERSION + "\n";
+    String version = "#version "+GLSL+" es\n";
+    String mainVertHeader= version + ("#define NUM_VERTEX "   + ( numV>0 ? DistortedLibrary.getMax(EffectType.VERTEX  ) : 0 ) + "\n");
+    String mainFragHeader= version + "\n";
 
     String enabledEffectV= VertexEffect.getGLSL();
 
     try
       {
       mPreProgram = new DistortedProgram(mainVertStream, mainFragStream, mainVertHeader, mainFragHeader,
-                                         enabledEffectV, null, DistortedLibrary.GLSL, null);
+                                         enabledEffectV, null, GLSL, null);
       }
     catch(Exception e)
       {
@@ -134,8 +135,8 @@ public class EffectQueuePostprocess extends EffectQueue
     int preProgramH = mPreProgram.getProgramHandle();
     EffectQueueVertex.getUniforms( preProgramH,2 );
     EffectQueueMatrix.getUniforms( preProgramH,2 );
-    mPreColorH  = GLES31.glGetUniformLocation( preProgramH, "u_Color"  );
-    mPreTextureH= GLES31.glGetUniformLocation( preProgramH, "u_Texture");
+    mPreColorH  = GLES30.glGetUniformLocation( preProgramH, "u_Color"  );
+    mPreTextureH= GLES30.glGetUniformLocation( preProgramH, "u_Texture");
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -167,7 +168,7 @@ public class EffectQueuePostprocess extends EffectQueue
     InternalRenderState.setUpStencilMark(mA!=0.0f);
     InternalRenderState.disableBlending();
 
-    GLES31.glViewport(0, 0, width, height );
+    GLES30.glViewport(0, 0, width, height );
 
     mPreProgram.useProgram();
 
@@ -190,11 +191,11 @@ public class EffectQueuePostprocess extends EffectQueue
 
     if( mA!=0.0f )
       {
-      GLES31.glUniform4f(mPreColorH, mR, mG, mB, mA);
-      GLES31.glUniform1i(mPreTextureH, 0);
+      GLES30.glUniform4f(mPreColorH, mR, mG, mB, mA);
+      GLES30.glUniform1i(mPreTextureH, 0);
       }
 
-    GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices() );
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices() );
 
     InternalRenderState.restoreBlending();
     InternalRenderState.unsetUpStencilMark();
@@ -208,14 +209,14 @@ public class EffectQueuePostprocess extends EffectQueue
     {
     int numRenders = 0;
 
-    GLES31.glDisable(GLES31.GL_BLEND);
+    GLES30.glDisable(GLES30.GL_BLEND);
 
     for(int i=0; i<mNumEffects; i++)
       {
       numRenders += ((PostprocessEffect)mEffects[i]).apply(mUniforms,NUM_UNIFORMS*i, buffer);
       }
 
-    GLES31.glEnable(GLES31.GL_BLEND);
+    GLES30.glEnable(GLES30.GL_BLEND);
 
     return numRenders;
     }
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueueVertex.java b/src/main/java/org/distorted/library/effectqueue/EffectQueueVertex.java
index ca24236..6bde3df 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueueVertex.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueueVertex.java
@@ -19,7 +19,7 @@
 
 package org.distorted.library.effectqueue;
 
-import android.opengl.GLES31;
+import android.opengl.GLES30;
 
 import org.distorted.library.effect.EffectType;
 import org.distorted.library.effect.VertexEffect;
@@ -48,10 +48,10 @@ class EffectQueueVertex extends EffectQueue
 
   static void uniforms(int mProgramH, int variant)
     {
-    mNumEffectsH[variant]= GLES31.glGetUniformLocation( mProgramH, "vNumEffects");
-    mNameH[variant]      = GLES31.glGetUniformLocation( mProgramH, "vName");
-    mUniformsH[variant]  = GLES31.glGetUniformLocation( mProgramH, "vUniforms");
-    mInflateH[variant]   = GLES31.glGetUniformLocation( mProgramH, "u_Inflate");
+    mNumEffectsH[variant]= GLES30.glGetUniformLocation( mProgramH, "vNumEffects");
+    mNameH[variant]      = GLES30.glGetUniformLocation( mProgramH, "vName");
+    mUniformsH[variant]  = GLES30.glGetUniformLocation( mProgramH, "vUniforms");
+    mInflateH[variant]   = GLES30.glGetUniformLocation( mProgramH, "u_Inflate");
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -79,13 +79,13 @@ class EffectQueueVertex extends EffectQueue
 
   void send(float inflate, int variant)
     {
-    GLES31.glUniform1i( mNumEffectsH[variant], mNumEffects);
-    GLES31.glUniform1f( mInflateH[variant]   , inflate    );
+    GLES30.glUniform1i( mNumEffectsH[variant], mNumEffects);
+    GLES30.glUniform1f( mInflateH[variant]   , inflate    );
 
     if( mNumEffects>0 )
       {
-      GLES31.glUniform1iv( mNameH[variant]    ,                 mNumEffects, mName    ,0);
-      GLES31.glUniform4fv( mUniformsH[variant],(NUM_UNIFORMS/4)*mNumEffects, mUniforms,0);
+      GLES30.glUniform1iv( mNameH[variant]    ,                 mNumEffects, mName    ,0);
+      GLES30.glUniform4fv( mUniformsH[variant],(NUM_UNIFORMS/4)*mNumEffects, mUniforms,0);
       }
     }
   }
diff --git a/src/main/java/org/distorted/library/main/DistortedFramebuffer.java b/src/main/java/org/distorted/library/main/DistortedFramebuffer.java
index c7a22b1..2351509 100644
--- a/src/main/java/org/distorted/library/main/DistortedFramebuffer.java
+++ b/src/main/java/org/distorted/library/main/DistortedFramebuffer.java
@@ -19,7 +19,8 @@
 
 package org.distorted.library.main;
 
-import android.opengl.GLES31;
+import android.opengl.GLES30;
+import android.util.Log;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -41,30 +42,30 @@ public class DistortedFramebuffer extends InternalOutputSurface
 
     if( mColorCreated==NOT_CREATED_YET )
       {
-      GLES31.glGenTextures( mNumFBOs*mNumColors, mColorH, 0);
-      GLES31.glGenFramebuffers(mNumFBOs, mFBOH, 0);
+      GLES30.glGenTextures( mNumFBOs*mNumColors, mColorH, 0);
+      GLES30.glGenFramebuffers(mNumFBOs, mFBOH, 0);
 
       for(int i=0; i<mNumFBOs; i++)
         {
-        GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, mFBOH[i]);
+        GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFBOH[i]);
 
         for(int j=0; j<mNumColors; j++)
           {
-          GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, mColorH[i*mNumColors+j]);
-          GLES31.glTexParameteri(GLES31.GL_TEXTURE_2D, GLES31.GL_TEXTURE_WRAP_S, GLES31.GL_REPEAT);
-          GLES31.glTexParameteri(GLES31.GL_TEXTURE_2D, GLES31.GL_TEXTURE_WRAP_T, GLES31.GL_REPEAT);
-          GLES31.glTexParameterf(GLES31.GL_TEXTURE_2D, GLES31.GL_TEXTURE_MIN_FILTER, GLES31.GL_NEAREST);
-          GLES31.glTexParameterf(GLES31.GL_TEXTURE_2D, GLES31.GL_TEXTURE_MAG_FILTER, GLES31.GL_LINEAR);
-          GLES31.glTexImage2D(GLES31.GL_TEXTURE_2D, 0, GLES31.GL_RGBA, mRealWidth, mRealHeight, 0, GLES31.GL_RGBA, GLES31.GL_UNSIGNED_BYTE, null);
+          GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mColorH[i*mNumColors+j]);
+          GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_REPEAT);
+          GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_REPEAT);
+          GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);
+          GLES30.glTexParameterf(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);
+          GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_RGBA, mRealWidth, mRealHeight, 0, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, null);
           }
 
-        GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, mColorH[i*mNumColors], 0);
-        GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, 0);
+        GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, mColorH[i*mNumColors], 0);
+        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
         }
 
       // TODO
       mColorCreated = checkStatus("color");
-      GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, 0);
+      GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
       }
 
     //////////////////////////////////////////////////////////////
@@ -72,44 +73,44 @@ public class DistortedFramebuffer extends InternalOutputSurface
 
     if( mDepthStencilCreated==NOT_CREATED_YET ) // we need to create a new DEPTH or STENCIL attachment
       {
-      GLES31.glGenTextures(mNumFBOs, mDepthStencilH, 0);
+      GLES30.glGenTextures(mNumFBOs, mDepthStencilH, 0);
 
       for(int i=0; i<mNumFBOs; i++)
         {
-        GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, mDepthStencilH[i]);
-        GLES31.glTexParameteri(GLES31.GL_TEXTURE_2D, GLES31.GL_TEXTURE_WRAP_S, GLES31.GL_REPEAT);
-        GLES31.glTexParameteri(GLES31.GL_TEXTURE_2D, GLES31.GL_TEXTURE_WRAP_T, GLES31.GL_REPEAT);
-        GLES31.glTexParameteri(GLES31.GL_TEXTURE_2D, GLES31.GL_TEXTURE_MIN_FILTER, GLES31.GL_NEAREST);
-        GLES31.glTexParameteri(GLES31.GL_TEXTURE_2D, GLES31.GL_TEXTURE_MAG_FILTER, GLES31.GL_NEAREST);
+        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mDepthStencilH[i]);
+        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_REPEAT);
+        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_REPEAT);
+        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_NEAREST);
+        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_NEAREST);
 
         if (mDepthStencil == DEPTH_NO_STENCIL)
           {
-          GLES31.glTexImage2D(GLES31.GL_TEXTURE_2D, 0, GLES31.GL_DEPTH_COMPONENT, mRealWidth, mRealHeight, 0, GLES31.GL_DEPTH_COMPONENT, GLES31.GL_UNSIGNED_INT, null);
+          GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_DEPTH_COMPONENT, mRealWidth, mRealHeight, 0, GLES30.GL_DEPTH_COMPONENT, GLES30.GL_UNSIGNED_INT, null);
           }
         else if (mDepthStencil == BOTH_DEPTH_STENCIL)
           {
-          GLES31.glTexImage2D(GLES31.GL_TEXTURE_2D, 0, GLES31.GL_DEPTH24_STENCIL8, mRealWidth, mRealHeight, 0, GLES31.GL_DEPTH_STENCIL, GLES31.GL_UNSIGNED_INT_24_8, null);
+          GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_DEPTH24_STENCIL8, mRealWidth, mRealHeight, 0, GLES30.GL_DEPTH_STENCIL, GLES30.GL_UNSIGNED_INT_24_8, null);
           }
         }
-      GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, 0);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
 
       for(int i=0; i<mNumFBOs; i++)
         {
-        GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, mFBOH[i]);
+        GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFBOH[i]);
 
         if (mDepthStencil == DEPTH_NO_STENCIL)
           {
-          GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_DEPTH_ATTACHMENT, GLES31.GL_TEXTURE_2D, mDepthStencilH[i], 0);
+          GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_DEPTH_ATTACHMENT, GLES30.GL_TEXTURE_2D, mDepthStencilH[i], 0);
           }
         else if (mDepthStencil == BOTH_DEPTH_STENCIL)
           {
-          GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_DEPTH_STENCIL_ATTACHMENT, GLES31.GL_TEXTURE_2D, mDepthStencilH[i], 0);
+          GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_DEPTH_STENCIL_ATTACHMENT, GLES30.GL_TEXTURE_2D, mDepthStencilH[i], 0);
           }
         }
 
       // TODO
       mDepthStencilCreated = checkStatus("depth");
-      GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, 0);
+      GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
       }
 
     //////////////////////////////////////////////////////////////
@@ -124,14 +125,14 @@ public class DistortedFramebuffer extends InternalOutputSurface
 
       for(int i=0; i<mNumFBOs; i++)
         {
-        GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, mFBOH[i]);
-        GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_DEPTH_ATTACHMENT, GLES31.GL_TEXTURE_2D, 0, 0);
-        GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_DEPTH_STENCIL_ATTACHMENT, GLES31.GL_TEXTURE_2D, 0, 0);
+        GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFBOH[i]);
+        GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_DEPTH_ATTACHMENT, GLES30.GL_TEXTURE_2D, 0, 0);
+        GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_DEPTH_STENCIL_ATTACHMENT, GLES30.GL_TEXTURE_2D, 0, 0);
         mDepthStencilH[i]=0;
         }
 
-      GLES31.glDeleteTextures(mNumFBOs, mDepthStencilH, 0);
-      GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, 0);
+      GLES30.glDeleteTextures(mNumFBOs, mDepthStencilH, 0);
+      GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
       }
     }
 
@@ -140,15 +141,15 @@ public class DistortedFramebuffer extends InternalOutputSurface
 
   private int checkStatus(String message)
     {
-    int status = GLES31.glCheckFramebufferStatus(GLES31.GL_FRAMEBUFFER);
+    int status = GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER);
 
-    if(status != GLES31.GL_FRAMEBUFFER_COMPLETE)
+    if(status != GLES30.GL_FRAMEBUFFER_COMPLETE)
       {
-      android.util.Log.e("DistortedFramebuffer", "FRAMEBUFFER INCOMPLETE, "+message+" error="+status);
+      Log.e("DistortedFramebuffer", "FRAMEBUFFER INCOMPLETE, "+message+" error="+status);
 
-      GLES31.glDeleteTextures(1, mColorH, 0);
-      GLES31.glDeleteTextures(1, mDepthStencilH, 0);
-      GLES31.glDeleteFramebuffers(1, mFBOH, 0);
+      GLES30.glDeleteTextures(1, mColorH, 0);
+      GLES30.glDeleteTextures(1, mDepthStencilH, 0);
+      GLES30.glDeleteFramebuffers(1, mFBOH, 0);
       mFBOH[0]= 0;
 
       return FAILED_TO_CREATE;
@@ -164,7 +165,7 @@ public class DistortedFramebuffer extends InternalOutputSurface
     {
     if( mColorH[0]>0 )
       {
-      GLES31.glDeleteTextures(mNumFBOs*mNumColors, mColorH, 0);
+      GLES30.glDeleteTextures(mNumFBOs*mNumColors, mColorH, 0);
       mColorCreated = NOT_CREATED_YET;
 
       for(int i=0; i<mNumFBOs*mNumColors; i++) mColorH[i] = 0;
@@ -172,13 +173,13 @@ public class DistortedFramebuffer extends InternalOutputSurface
 
     if( mDepthStencilH[0]>0 )
       {
-      GLES31.glDeleteTextures(mNumFBOs, mDepthStencilH, 0);
+      GLES30.glDeleteTextures(mNumFBOs, mDepthStencilH, 0);
       mDepthStencilCreated = NOT_CREATED_YET;
 
       for(int i=0; i<mNumFBOs; i++) mDepthStencilH[i] = 0;
       }
 
-    GLES31.glDeleteFramebuffers(mNumFBOs, mFBOH, 0);
+    GLES30.glDeleteFramebuffers(mNumFBOs, mFBOH, 0);
     for(int i=0; i<mNumFBOs; i++) mFBOH[i] = 0;
     }
 
@@ -205,8 +206,8 @@ public class DistortedFramebuffer extends InternalOutputSurface
     {
     if( texture>=0 && texture<mNumColors && fbo>=0 && fbo<mNumFBOs && mColorH[mNumColors*fbo + texture]>0 )
       {
-      GLES31.glActiveTexture(GLES31.GL_TEXTURE0);
-      GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, mColorH[mNumColors*fbo + texture]);
+      GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mColorH[mNumColors*fbo + texture]);
       return true;
       }
 
@@ -262,8 +263,8 @@ public class DistortedFramebuffer extends InternalOutputSurface
     {
     if( texture>=0 && texture<mNumColors && mColorH[texture]>0 )
       {
-      GLES31.glActiveTexture(GLES31.GL_TEXTURE0);
-      GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, mColorH[2*mCurrFBO+texture]);
+      GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mColorH[2*mCurrFBO+texture]);
       return true;
       }
 
@@ -280,7 +281,7 @@ public class DistortedFramebuffer extends InternalOutputSurface
     {
     if( texture>=0 && texture<mNumColors && mColorH[texture]>0 )
       {
-      GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, mColorH[2*mCurrFBO+texture], 0);
+      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, mColorH[2*mCurrFBO+texture], 0);
       }
     }
 
diff --git a/src/main/java/org/distorted/library/main/DistortedLibrary.java b/src/main/java/org/distorted/library/main/DistortedLibrary.java
index 629ee7c..8bd1f84 100644
--- a/src/main/java/org/distorted/library/main/DistortedLibrary.java
+++ b/src/main/java/org/distorted/library/main/DistortedLibrary.java
@@ -23,6 +23,7 @@ import android.app.ActivityManager;
 import android.content.Context;
 import android.content.pm.ConfigurationInfo;
 import android.content.res.Resources;
+import android.opengl.GLES30;
 import android.opengl.GLES31;
 import android.util.Log;
 
@@ -37,6 +38,7 @@ import org.distorted.library.effect.VertexEffect;
 import org.distorted.library.mesh.MeshBase;
 import org.distorted.library.message.EffectMessageSender;
 import org.distorted.library.program.DistortedProgram;
+import org.distorted.library.program.VertexCompilationException;
 
 import java.io.InputStream;
 import java.nio.ByteBuffer;
@@ -50,8 +52,9 @@ import java.nio.IntBuffer;
  */
 public class DistortedLibrary
   {
-  public static final int GLSL = 310;
-  public static final String GLSL_VERSION= "#version 310 es\n";
+  private static int mGLSL;
+  private static String mGLSL_VERSION;
+  private static boolean mOITCompilationSuccessful;
   /**
    * When creating an instance of a DistortedTexture from another instance, clone the Bitmap that's
    * backing up our DistortedTexture.
@@ -207,8 +210,8 @@ public class DistortedLibrary
     int numF = FragmentEffect.getNumEnabled();
     int numV = VertexEffect.getNumEnabled();
 
-    String mainVertHeader= DistortedLibrary.GLSL_VERSION + ("#define NUM_VERTEX "   + ( numV>0 ? getMax(EffectType.VERTEX  ) : 0 ) + "\n");
-    String mainFragHeader= DistortedLibrary.GLSL_VERSION + ("#define NUM_FRAGMENT " + ( numF>0 ? getMax(EffectType.FRAGMENT) : 0 ) + "\n");
+    String mainVertHeader= mGLSL_VERSION + ("#define NUM_VERTEX "   + ( numV>0 ? getMax(EffectType.VERTEX  ) : 0 ) + "\n");
+    String mainFragHeader= mGLSL_VERSION + ("#define NUM_FRAGMENT " + ( numF>0 ? getMax(EffectType.FRAGMENT) : 0 ) + "\n");
     String enabledEffectV= VertexEffect.getGLSL();
     String enabledEffectF= FragmentEffect.getGLSL();
 
@@ -217,7 +220,7 @@ public class DistortedLibrary
     try
       {
       mMainProgram = new DistortedProgram(mainVertStream, mainFragStream, mainVertHeader, mainFragHeader,
-                                          enabledEffectV, enabledEffectF, DistortedLibrary.GLSL, feedback);
+                                          enabledEffectV, enabledEffectF, mGLSL, feedback);
       }
     catch(Exception e)
       {
@@ -227,7 +230,7 @@ public class DistortedLibrary
 
     int mainProgramH = mMainProgram.getProgramHandle();
     EffectQueue.getUniforms(mainProgramH,0);
-    mMainTextureH= GLES31.glGetUniformLocation( mainProgramH, "u_Texture");
+    mMainTextureH= GLES30.glGetUniformLocation( mainProgramH, "u_Texture");
 
     // BLIT PROGRAM ////////////////////////////////////
     final InputStream blitVertStream = resources.openRawResource(R.raw.blit_vertex_shader);
@@ -235,7 +238,7 @@ public class DistortedLibrary
 
     try
       {
-      mBlitProgram = new DistortedProgram(blitVertStream,blitFragStream, DistortedLibrary.GLSL_VERSION, DistortedLibrary.GLSL_VERSION, DistortedLibrary.GLSL);
+      mBlitProgram = new DistortedProgram(blitVertStream,blitFragStream, mGLSL_VERSION, mGLSL_VERSION, mGLSL);
       }
     catch(Exception e)
       {
@@ -244,8 +247,8 @@ public class DistortedLibrary
       }
 
     int blitProgramH = mBlitProgram.getProgramHandle();
-    mBlitTextureH  = GLES31.glGetUniformLocation( blitProgramH, "u_Texture");
-    mBlitDepthH    = GLES31.glGetUniformLocation( blitProgramH, "u_Depth");
+    mBlitTextureH  = GLES30.glGetUniformLocation( blitProgramH, "u_Texture");
+    mBlitDepthH    = GLES30.glGetUniformLocation( blitProgramH, "u_Depth");
 
     // BLIT DEPTH PROGRAM ////////////////////////////////////
     final InputStream blitDepthVertStream = resources.openRawResource(R.raw.blit_depth_vertex_shader);
@@ -253,7 +256,7 @@ public class DistortedLibrary
 
     try
       {
-      mBlitDepthProgram = new DistortedProgram(blitDepthVertStream,blitDepthFragStream, DistortedLibrary.GLSL_VERSION, DistortedLibrary.GLSL_VERSION, DistortedLibrary.GLSL);
+      mBlitDepthProgram = new DistortedProgram(blitDepthVertStream,blitDepthFragStream, mGLSL_VERSION, mGLSL_VERSION, mGLSL);
       }
     catch(Exception e)
       {
@@ -262,10 +265,10 @@ public class DistortedLibrary
       }
 
     int blitDepthProgramH   = mBlitDepthProgram.getProgramHandle();
-    mBlitDepthTextureH      = GLES31.glGetUniformLocation( blitDepthProgramH, "u_Texture");
-    mBlitDepthDepthTextureH = GLES31.glGetUniformLocation( blitDepthProgramH, "u_DepthTexture");
-    mBlitDepthDepthH        = GLES31.glGetUniformLocation( blitDepthProgramH, "u_Depth");
-    mBlitDepthTexCorrH      = GLES31.glGetUniformLocation( blitDepthProgramH, "u_TexCorr");
+    mBlitDepthTextureH      = GLES30.glGetUniformLocation( blitDepthProgramH, "u_Texture");
+    mBlitDepthDepthTextureH = GLES30.glGetUniformLocation( blitDepthProgramH, "u_DepthTexture");
+    mBlitDepthDepthH        = GLES30.glGetUniformLocation( blitDepthProgramH, "u_Depth");
+    mBlitDepthTexCorrH      = GLES30.glGetUniformLocation( blitDepthProgramH, "u_TexCorr");
 
     // NORMAL PROGRAM //////////////////////////////////////
     final InputStream normalVertexStream   = resources.openRawResource(R.raw.normal_vertex_shader);
@@ -273,7 +276,7 @@ public class DistortedLibrary
 
     try
       {
-      mNormalProgram = new DistortedProgram(normalVertexStream,normalFragmentStream, DistortedLibrary.GLSL_VERSION, DistortedLibrary.GLSL_VERSION, DistortedLibrary.GLSL);
+      mNormalProgram = new DistortedProgram(normalVertexStream,normalFragmentStream, mGLSL_VERSION, mGLSL_VERSION, mGLSL);
       }
     catch(Exception e)
       {
@@ -282,7 +285,7 @@ public class DistortedLibrary
       }
 
     int normalProgramH = mNormalProgram.getProgramHandle();
-    mNormalMVPMatrixH  = GLES31.glGetUniformLocation( normalProgramH, "u_MVPMatrix");
+    mNormalMVPMatrixH  = GLES30.glGetUniformLocation( normalProgramH, "u_MVPMatrix");
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -296,12 +299,8 @@ public class DistortedLibrary
     int numF = FragmentEffect.getNumEnabled();
     int numV = VertexEffect.getNumEnabled();
 
-    String mainVertHeader= DistortedLibrary.GLSL_VERSION +
-                           ("#define NUM_VERTEX "   + ( numV>0 ? getMax(EffectType.VERTEX  ) : 0 ) + "\n") +
-                           ("#define OIT\n");
-    String mainFragHeader= DistortedLibrary.GLSL_VERSION +
-                           ("#define NUM_FRAGMENT " + ( numF>0 ? getMax(EffectType.FRAGMENT) : 0 ) + "\n") +
-                           ("#define OIT\n");
+    String mainVertHeader= mGLSL_VERSION + ("#define NUM_VERTEX "   + ( numV>0 ? getMax(EffectType.VERTEX  ) : 0 ) + "\n") + ("#define OIT\n");
+    String mainFragHeader= mGLSL_VERSION + ("#define NUM_FRAGMENT " + ( numF>0 ? getMax(EffectType.FRAGMENT) : 0 ) + "\n") + ("#define OIT\n");
 
     String enabledEffectV= VertexEffect.getGLSL();
     String enabledEffectF= FragmentEffect.getGLSL();
@@ -309,7 +308,7 @@ public class DistortedLibrary
     try
       {
       mMainOITProgram = new DistortedProgram(mainVertStream, mainFragStream, mainVertHeader, mainFragHeader,
-                                             enabledEffectV, enabledEffectF, DistortedLibrary.GLSL, null);
+                                             enabledEffectV, enabledEffectF, mGLSL, null);
       }
     catch(Exception e)
       {
@@ -319,9 +318,9 @@ public class DistortedLibrary
 
     int mainOITProgramH = mMainOITProgram.getProgramHandle();
     EffectQueue.getUniforms(mainOITProgramH,1);
-    mMainOITTextureH    = GLES31.glGetUniformLocation( mainOITProgramH, "u_Texture");
-    mMainOITSizeH       = GLES31.glGetUniformLocation( mainOITProgramH, "u_Size");
-    mMainOITNumRecordsH = GLES31.glGetUniformLocation( mainOITProgramH, "u_numRecords");
+    mMainOITTextureH    = GLES30.glGetUniformLocation( mainOITProgramH, "u_Texture");
+    mMainOITSizeH       = GLES30.glGetUniformLocation( mainOITProgramH, "u_Size");
+    mMainOITNumRecordsH = GLES30.glGetUniformLocation( mainOITProgramH, "u_numRecords");
 
     // OIT CLEAR PROGRAM ////////////////////////////////////
     final InputStream oitClearVertStream = resources.openRawResource(R.raw.oit_vertex_shader);
@@ -329,7 +328,7 @@ public class DistortedLibrary
 
     try
       {
-      mOITClearProgram = new DistortedProgram(oitClearVertStream,oitClearFragStream, DistortedLibrary.GLSL_VERSION, DistortedLibrary.GLSL_VERSION, DistortedLibrary.GLSL);
+      mOITClearProgram = new DistortedProgram(oitClearVertStream,oitClearFragStream, mGLSL_VERSION, mGLSL_VERSION, mGLSL);
       }
     catch(Exception e)
       {
@@ -338,9 +337,9 @@ public class DistortedLibrary
       }
 
     int oitClearProgramH   = mOITClearProgram.getProgramHandle();
-    mOITClearDepthH        = GLES31.glGetUniformLocation( oitClearProgramH, "u_Depth");
-    mOITClearTexCorrH      = GLES31.glGetUniformLocation( oitClearProgramH, "u_TexCorr");
-    mOITClearSizeH         = GLES31.glGetUniformLocation( oitClearProgramH, "u_Size");
+    mOITClearDepthH        = GLES30.glGetUniformLocation( oitClearProgramH, "u_Depth");
+    mOITClearTexCorrH      = GLES30.glGetUniformLocation( oitClearProgramH, "u_TexCorr");
+    mOITClearSizeH         = GLES30.glGetUniformLocation( oitClearProgramH, "u_Size");
 
     // OIT BUILD PROGRAM ////////////////////////////////////
     final InputStream oitBuildVertStream = resources.openRawResource(R.raw.oit_vertex_shader);
@@ -348,7 +347,7 @@ public class DistortedLibrary
 
     try
       {
-      mOITBuildProgram = new DistortedProgram(oitBuildVertStream,oitBuildFragStream, DistortedLibrary.GLSL_VERSION, DistortedLibrary.GLSL_VERSION, DistortedLibrary.GLSL);
+      mOITBuildProgram = new DistortedProgram(oitBuildVertStream,oitBuildFragStream, mGLSL_VERSION, mGLSL_VERSION, mGLSL);
       }
     catch(Exception e)
       {
@@ -357,12 +356,12 @@ public class DistortedLibrary
       }
 
     int oitBuildProgramH   = mOITBuildProgram.getProgramHandle();
-    mOITBuildTextureH      = GLES31.glGetUniformLocation( oitBuildProgramH, "u_Texture");
-    mOITBuildDepthTextureH = GLES31.glGetUniformLocation( oitBuildProgramH, "u_DepthTexture");
-    mOITBuildDepthH        = GLES31.glGetUniformLocation( oitBuildProgramH, "u_Depth");
-    mOITBuildTexCorrH      = GLES31.glGetUniformLocation( oitBuildProgramH, "u_TexCorr");
-    mOITBuildSizeH         = GLES31.glGetUniformLocation( oitBuildProgramH, "u_Size");
-    mOITBuildNumRecordsH   = GLES31.glGetUniformLocation( oitBuildProgramH, "u_numRecords");
+    mOITBuildTextureH      = GLES30.glGetUniformLocation( oitBuildProgramH, "u_Texture");
+    mOITBuildDepthTextureH = GLES30.glGetUniformLocation( oitBuildProgramH, "u_DepthTexture");
+    mOITBuildDepthH        = GLES30.glGetUniformLocation( oitBuildProgramH, "u_Depth");
+    mOITBuildTexCorrH      = GLES30.glGetUniformLocation( oitBuildProgramH, "u_TexCorr");
+    mOITBuildSizeH         = GLES30.glGetUniformLocation( oitBuildProgramH, "u_Size");
+    mOITBuildNumRecordsH   = GLES30.glGetUniformLocation( oitBuildProgramH, "u_numRecords");
 
     // OIT COLLAPSE PROGRAM ///////////////////////////
     final InputStream oitCollapseVertStream = resources.openRawResource(R.raw.oit_vertex_shader);
@@ -370,7 +369,7 @@ public class DistortedLibrary
 
     try
       {
-      mOITCollapseProgram = new DistortedProgram(oitCollapseVertStream,oitCollapseFragStream, DistortedLibrary.GLSL_VERSION, DistortedLibrary.GLSL_VERSION, DistortedLibrary.GLSL);
+      mOITCollapseProgram = new DistortedProgram(oitCollapseVertStream,oitCollapseFragStream, mGLSL_VERSION, mGLSL_VERSION, mGLSL);
       }
     catch(Exception e)
       {
@@ -379,10 +378,10 @@ public class DistortedLibrary
       }
 
     int oitCollapseProgramH   = mOITCollapseProgram.getProgramHandle();
-    mOITCollapseDepthTextureH = GLES31.glGetUniformLocation( oitCollapseProgramH, "u_DepthTexture");
-    mOITCollapseDepthH        = GLES31.glGetUniformLocation( oitCollapseProgramH, "u_Depth");
-    mOITCollapseTexCorrH      = GLES31.glGetUniformLocation( oitCollapseProgramH, "u_TexCorr");
-    mOITCollapseSizeH         = GLES31.glGetUniformLocation( oitCollapseProgramH, "u_Size");
+    mOITCollapseDepthTextureH = GLES30.glGetUniformLocation( oitCollapseProgramH, "u_DepthTexture");
+    mOITCollapseDepthH        = GLES30.glGetUniformLocation( oitCollapseProgramH, "u_Depth");
+    mOITCollapseTexCorrH      = GLES30.glGetUniformLocation( oitCollapseProgramH, "u_TexCorr");
+    mOITCollapseSizeH         = GLES30.glGetUniformLocation( oitCollapseProgramH, "u_Size");
 
     // OIT RENDER PROGRAM ///////////////////////////
     final InputStream oitRenderVertStream = resources.openRawResource(R.raw.oit_vertex_shader);
@@ -390,7 +389,7 @@ public class DistortedLibrary
 
     try
       {
-      mOITRenderProgram = new DistortedProgram(oitRenderVertStream,oitRenderFragStream, DistortedLibrary.GLSL_VERSION, DistortedLibrary.GLSL_VERSION, DistortedLibrary.GLSL);
+      mOITRenderProgram = new DistortedProgram(oitRenderVertStream,oitRenderFragStream, mGLSL_VERSION, mGLSL_VERSION, mGLSL);
       }
     catch(Exception e)
       {
@@ -399,9 +398,9 @@ public class DistortedLibrary
       }
 
     int oitRenderProgramH   = mOITRenderProgram.getProgramHandle();
-    mOITRenderDepthH        = GLES31.glGetUniformLocation( oitRenderProgramH, "u_Depth");
-    mOITRenderTexCorrH      = GLES31.glGetUniformLocation( oitRenderProgramH, "u_TexCorr");
-    mOITRenderSizeH         = GLES31.glGetUniformLocation( oitRenderProgramH, "u_Size");
+    mOITRenderDepthH        = GLES30.glGetUniformLocation( oitRenderProgramH, "u_Depth");
+    mOITRenderTexCorrH      = GLES30.glGetUniformLocation( oitRenderProgramH, "u_TexCorr");
+    mOITRenderSizeH         = GLES30.glGetUniformLocation( oitRenderProgramH, "u_Size");
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -411,19 +410,19 @@ public class DistortedLibrary
     int num = mesh.getNumVertices();
     int tfo = mesh.getTFO();
 
-    GLES31.glBindBufferBase(GLES31.GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfo );
-    GLES31.glBeginTransformFeedback( GLES31.GL_POINTS);
+    GLES30.glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfo );
+    GLES30.glBeginTransformFeedback( GLES30.GL_POINTS);
     InternalRenderState.switchOffDrawing();
-    GLES31.glDrawArrays( GLES31.GL_POINTS, 0, num );
+    GLES30.glDrawArrays( GLES30.GL_POINTS, 0, num );
     InternalRenderState.restoreDrawing();
-    GLES31.glEndTransformFeedback();
-    GLES31.glBindBufferBase(GLES31.GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
+    GLES30.glEndTransformFeedback();
+    GLES30.glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
 
     DistortedLibrary.mNormalProgram.useProgram();
-    GLES31.glUniformMatrix4fv(DistortedLibrary.mNormalMVPMatrixH, 1, false, EffectQueue.getMVP(queues) , 0);
+    GLES30.glUniformMatrix4fv(DistortedLibrary.mNormalMVPMatrixH, 1, false, EffectQueue.getMVP(queues) , 0);
     mesh.bindTransformAttribs(DistortedLibrary.mNormalProgram);
-    GLES31.glLineWidth(8.0f);
-    GLES31.glDrawArrays(GLES31.GL_LINES, 0, 2*num);
+    GLES30.glLineWidth(8.0f);
+    GLES30.glDrawArrays(GLES30.GL_LINES, 0, 2*num);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -433,12 +432,12 @@ public class DistortedLibrary
     EffectQueue[] queues = effects.getQueues();
 
     EffectQueue.compute(queues, currTime);
-    GLES31.glViewport(0, 0, surface.mWidth, surface.mHeight );
+    GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
 
     DistortedLibrary.mMainOITProgram.useProgram();
-    GLES31.glUniform1i(DistortedLibrary.mMainOITTextureH, 0);
-    GLES31.glUniform2ui(DistortedLibrary.mMainOITSizeH, surface.mWidth, surface.mHeight);
-    GLES31.glUniform1ui(DistortedLibrary.mMainOITNumRecordsH, (int)(DistortedLibrary.mBufferSize*surface.mWidth*surface.mHeight) );
+    GLES30.glUniform1i(DistortedLibrary.mMainOITTextureH, 0);
+    GLES30.glUniform2ui(DistortedLibrary.mMainOITSizeH, surface.mWidth, surface.mHeight);
+    GLES30.glUniform1ui(DistortedLibrary.mMainOITNumRecordsH, (int)(DistortedLibrary.mBufferSize*surface.mWidth*surface.mHeight) );
     mesh.bindVertexAttribs(DistortedLibrary.mMainOITProgram);
 
     float inflate     = mesh.getInflate();
@@ -447,7 +446,7 @@ public class DistortedLibrary
     float[] projection= surface.mProjectionMatrix;
 
     EffectQueue.send(queues, distance, mipmap, projection, inflate, mesh, 1 );
-    GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices() );
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices() );
 
     if( mesh.getShowNormals() )
       {
@@ -464,10 +463,10 @@ public class DistortedLibrary
     EffectQueue[] queues = effects.getQueues();
 
     EffectQueue.compute(queues, currTime);
-    GLES31.glViewport(0, 0, surface.mWidth, surface.mHeight );
+    GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
 
     DistortedLibrary.mMainProgram.useProgram();
-    GLES31.glUniform1i(DistortedLibrary.mMainTextureH, 0);
+    GLES30.glUniform1i(DistortedLibrary.mMainTextureH, 0);
     mesh.bindVertexAttribs(DistortedLibrary.mMainProgram);
 
     float inflate     = mesh.getInflate();
@@ -476,7 +475,7 @@ public class DistortedLibrary
     float[] projection= surface.mProjectionMatrix;
 
     EffectQueue.send(queues, distance, mipmap, projection, inflate, mesh, 0 );
-    GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices() );
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices() );
 
     if( mesh.getShowNormals() ) displayNormals(queues,mesh);
     }
@@ -487,11 +486,11 @@ public class DistortedLibrary
     {
     mBlitProgram.useProgram();
 
-    GLES31.glViewport(0, 0, surface.mWidth, surface.mHeight );
-    GLES31.glUniform1i(mBlitTextureH, 0);
-    GLES31.glUniform1f( mBlitDepthH , 1.0f-surface.mNear);
-    GLES31.glVertexAttribPointer(mBlitProgram.mAttribute[0], 2, GLES31.GL_FLOAT, false, 0, mQuadPositions);
-    GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4);
+    GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
+    GLES30.glUniform1i(mBlitTextureH, 0);
+    GLES30.glUniform1f( mBlitDepthH , 1.0f-surface.mNear);
+    GLES30.glVertexAttribPointer(mBlitProgram.mAttribute[0], 2, GLES30.GL_FLOAT, false, 0, mQuadPositions);
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -500,23 +499,24 @@ public class DistortedLibrary
     {
     mBlitDepthProgram.useProgram();
 
-    GLES31.glViewport(0, 0, surface.mWidth, surface.mHeight );
-    GLES31.glUniform1i(mBlitDepthTextureH, 0);
-    GLES31.glUniform1i(mBlitDepthDepthTextureH, 1);
-    GLES31.glUniform2f(mBlitDepthTexCorrH, corrW, corrH );
-    GLES31.glUniform1f( mBlitDepthDepthH , 1.0f-surface.mNear);
-    GLES31.glVertexAttribPointer(mBlitDepthProgram.mAttribute[0], 2, GLES31.GL_FLOAT, false, 0, mQuadPositions);
-    GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4);
+    GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
+    GLES30.glUniform1i(mBlitDepthTextureH, 0);
+    GLES30.glUniform1i(mBlitDepthDepthTextureH, 1);
+    GLES30.glUniform2f(mBlitDepthTexCorrH, corrW, corrH );
+    GLES30.glUniform1f( mBlitDepthDepthH , 1.0f-surface.mNear);
+    GLES30.glVertexAttribPointer(mBlitDepthProgram.mAttribute[0], 2, GLES30.GL_FLOAT, false, 0, mQuadPositions);
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+// yes it is safe to be mixing 3.0 and 3.1 like that, senior members of the OpenGL discussions forum assert
 
   private static int printPreviousBuffer()
     {
     int counter = 0;
 
-    ByteBuffer atomicBuf = (ByteBuffer)GLES31.glMapBufferRange( GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, 4,
-                                                                GLES31.GL_MAP_READ_BIT);
+    ByteBuffer atomicBuf = (ByteBuffer)GLES30.glMapBufferRange( GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, 4,
+                                                                GLES30.GL_MAP_READ_BIT);
     if( atomicBuf!=null )
       {
       IntBuffer atomicIntBuf = atomicBuf.order(ByteOrder.nativeOrder()).asIntBuffer();
@@ -524,10 +524,10 @@ public class DistortedLibrary
       }
     else
       {
-      android.util.Log.e("effects", "print: failed to map atomic buffer");
+      Log.e("effects", "print: failed to map atomic buffer");
       }
 
-    GLES31.glUnmapBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER);
+    GLES30.glUnmapBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER);
 
     return counter;
     }
@@ -536,8 +536,8 @@ public class DistortedLibrary
 
   private static void zeroBuffer()
     {
-    ByteBuffer atomicBuf = (ByteBuffer)GLES31.glMapBufferRange( GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, 4,
-        GLES31.GL_MAP_WRITE_BIT|GLES31.GL_MAP_INVALIDATE_BUFFER_BIT);
+    ByteBuffer atomicBuf = (ByteBuffer)GLES30.glMapBufferRange( GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, 4,
+        GLES30.GL_MAP_WRITE_BIT|GLES30.GL_MAP_INVALIDATE_BUFFER_BIT);
     if( atomicBuf!=null )
       {
       IntBuffer atomicIntBuf = atomicBuf.order(ByteOrder.nativeOrder()).asIntBuffer();
@@ -545,10 +545,10 @@ public class DistortedLibrary
       }
     else
       {
-      android.util.Log.e("effects", "zero: failed to map atomic buffer");
+      Log.e("effects", "zero: failed to map atomic buffer");
       }
 
-    GLES31.glUnmapBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER);
+    GLES30.glUnmapBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -560,12 +560,12 @@ public class DistortedLibrary
 
     if( mAtomicCounter[0]<0 )
       {
-      GLES31.glGenBuffers(DistortedLibrary.FBO_QUEUE_SIZE,mAtomicCounter,0);
+      GLES30.glGenBuffers(DistortedLibrary.FBO_QUEUE_SIZE,mAtomicCounter,0);
 
       for(int i = 0; i< DistortedLibrary.FBO_QUEUE_SIZE; i++)
         {
-        GLES31.glBindBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER, mAtomicCounter[i]);
-        GLES31.glBufferData(GLES31.GL_ATOMIC_COUNTER_BUFFER, 4, null, GLES31.GL_DYNAMIC_DRAW);
+        GLES30.glBindBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER, mAtomicCounter[i]);
+        GLES30.glBufferData(GLES31.GL_ATOMIC_COUNTER_BUFFER, 4, null, GLES30.GL_DYNAMIC_DRAW);
         zeroBuffer();
         }
       }
@@ -574,13 +574,13 @@ public class DistortedLibrary
     // dialog_about 3%; doing it only once every 5 frames affects speed by less than 1%.
     if( mCurrBuffer==0 )
       {
-      GLES31.glBindBufferBase(GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, mAtomicCounter[mCurrBuffer]);
+      GLES30.glBindBufferBase(GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, mAtomicCounter[mCurrBuffer]);
       counter = printPreviousBuffer();
       }
 
     if( ++mCurrBuffer>= DistortedLibrary.FBO_QUEUE_SIZE ) mCurrBuffer = 0;
 
-    GLES31.glBindBufferBase(GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, mAtomicCounter[mCurrBuffer]);
+    GLES30.glBindBufferBase(GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, mAtomicCounter[mCurrBuffer]);
     zeroBuffer();
 
     return counter;
@@ -593,14 +593,14 @@ public class DistortedLibrary
     {
     if( mLinkedListSSBO[0]<0 )
       {
-      GLES31.glGenBuffers(1,mLinkedListSSBO,0);
+      GLES30.glGenBuffers(1,mLinkedListSSBO,0);
 
       int size = (int)(surface.mWidth*surface.mHeight*(3*mBufferSize+1)*4);
-      GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, mLinkedListSSBO[0]);
-      GLES31.glBufferData(GLES31.GL_SHADER_STORAGE_BUFFER, size, null, GLES31.GL_DYNAMIC_READ|GLES31.GL_DYNAMIC_DRAW);
-      GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, 0);
+      GLES30.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, mLinkedListSSBO[0]);
+      GLES30.glBufferData(GLES31.GL_SHADER_STORAGE_BUFFER, size, null, GLES30.GL_DYNAMIC_READ|GLES30.GL_DYNAMIC_DRAW);
+      GLES30.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, 0);
 
-      GLES31.glBindBufferBase(GLES31.GL_SHADER_STORAGE_BUFFER, 1, mLinkedListSSBO[0]);
+      GLES30.glBindBufferBase(GLES31.GL_SHADER_STORAGE_BUFFER, 1, mLinkedListSSBO[0]);
       }
 
     // See if we have overflown the SSBO in one of the previous frames.
@@ -614,19 +614,19 @@ public class DistortedLibrary
 
       mBufferSize *= (int)(overflow+1.0f);
       int size = (int)(surface.mWidth*surface.mHeight*(3*mBufferSize+1)*4);
-      GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, mLinkedListSSBO[0]);
-      GLES31.glBufferData(GLES31.GL_SHADER_STORAGE_BUFFER, size, null, GLES31.GL_DYNAMIC_READ|GLES31.GL_DYNAMIC_DRAW);
-      GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, 0);
+      GLES30.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, mLinkedListSSBO[0]);
+      GLES30.glBufferData(GLES31.GL_SHADER_STORAGE_BUFFER, size, null, GLES30.GL_DYNAMIC_READ|GLES30.GL_DYNAMIC_DRAW);
+      GLES30.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, 0);
       }
 
     mOITClearProgram.useProgram();
 
-    GLES31.glViewport(0, 0, surface.mWidth, surface.mHeight );
-    GLES31.glUniform2f(mOITClearTexCorrH, 1.0f, 1.0f );   // corrections do not really matter here - only present because of common vertex shader.
-    GLES31.glUniform1f( mOITClearDepthH , 1.0f);          // likewise depth
-    GLES31.glUniform2ui(mOITClearSizeH, surface.mWidth, surface.mHeight);
-    GLES31.glVertexAttribPointer(mOITClearProgram.mAttribute[0], 2, GLES31.GL_FLOAT, false, 0, mQuadPositions);
-    GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4);
+    GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
+    GLES30.glUniform2f(mOITClearTexCorrH, 1.0f, 1.0f );   // corrections do not really matter here - only present because of common vertex shader.
+    GLES30.glUniform1f( mOITClearDepthH , 1.0f);          // likewise depth
+    GLES30.glUniform2ui(mOITClearSizeH, surface.mWidth, surface.mHeight);
+    GLES30.glVertexAttribPointer(mOITClearProgram.mAttribute[0], 2, GLES30.GL_FLOAT, false, 0, mQuadPositions);
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -636,15 +636,15 @@ public class DistortedLibrary
     {
     mOITBuildProgram.useProgram();
 
-    GLES31.glViewport(0, 0, surface.mWidth, surface.mHeight );
-    GLES31.glUniform1i(mOITBuildTextureH, 0);
-    GLES31.glUniform1i(mOITBuildDepthTextureH, 1);
-    GLES31.glUniform2f(mOITBuildTexCorrH, corrW, corrH );
-    GLES31.glUniform2ui(mOITBuildSizeH, surface.mWidth, surface.mHeight);
-    GLES31.glUniform1ui(mOITBuildNumRecordsH, (int)(mBufferSize*surface.mWidth*surface.mHeight) );
-    GLES31.glUniform1f(mOITBuildDepthH , 1.0f-surface.mNear);
-    GLES31.glVertexAttribPointer(mOITBuildProgram.mAttribute[0], 2, GLES31.GL_FLOAT, false, 0, mQuadPositions);
-    GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4);
+    GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
+    GLES30.glUniform1i(mOITBuildTextureH, 0);
+    GLES30.glUniform1i(mOITBuildDepthTextureH, 1);
+    GLES30.glUniform2f(mOITBuildTexCorrH, corrW, corrH );
+    GLES30.glUniform2ui(mOITBuildSizeH, surface.mWidth, surface.mHeight);
+    GLES30.glUniform1ui(mOITBuildNumRecordsH, (int)(mBufferSize*surface.mWidth*surface.mHeight) );
+    GLES30.glUniform1f(mOITBuildDepthH , 1.0f-surface.mNear);
+    GLES30.glVertexAttribPointer(mOITBuildProgram.mAttribute[0], 2, GLES30.GL_FLOAT, false, 0, mQuadPositions);
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -654,13 +654,13 @@ public class DistortedLibrary
     {
     mOITCollapseProgram.useProgram();
 
-    GLES31.glViewport(0, 0, surface.mWidth, surface.mHeight );
-    GLES31.glUniform1i(mOITCollapseDepthTextureH, 1);
-    GLES31.glUniform2f(mOITCollapseTexCorrH, corrW, corrH );
-    GLES31.glUniform2ui(mOITCollapseSizeH, surface.mWidth, surface.mHeight);
-    GLES31.glUniform1f( mOITCollapseDepthH , 1.0f-surface.mNear);
-    GLES31.glVertexAttribPointer(mOITCollapseProgram.mAttribute[0], 2, GLES31.GL_FLOAT, false, 0, mQuadPositions);
-    GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4);
+    GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
+    GLES30.glUniform1i(mOITCollapseDepthTextureH, 1);
+    GLES30.glUniform2f(mOITCollapseTexCorrH, corrW, corrH );
+    GLES30.glUniform2ui(mOITCollapseSizeH, surface.mWidth, surface.mHeight);
+    GLES30.glUniform1f( mOITCollapseDepthH , 1.0f-surface.mNear);
+    GLES30.glVertexAttribPointer(mOITCollapseProgram.mAttribute[0], 2, GLES30.GL_FLOAT, false, 0, mQuadPositions);
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -670,12 +670,12 @@ public class DistortedLibrary
     {
     mOITRenderProgram.useProgram();
 
-    GLES31.glViewport(0, 0, surface.mWidth, surface.mHeight );
-    GLES31.glUniform2f(mOITRenderTexCorrH, corrW, corrH );
-    GLES31.glUniform2ui(mOITRenderSizeH, surface.mWidth, surface.mHeight);
-    GLES31.glUniform1f( mOITRenderDepthH , 1.0f-surface.mNear);
-    GLES31.glVertexAttribPointer(mOITRenderProgram.mAttribute[0], 2, GLES31.GL_FLOAT, false, 0, mQuadPositions);
-    GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4);
+    GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
+    GLES30.glUniform2f(mOITRenderTexCorrH, corrW, corrH );
+    GLES30.glUniform2ui(mOITRenderSizeH, surface.mWidth, surface.mHeight);
+    GLES30.glUniform1f( mOITRenderDepthH , 1.0f-surface.mNear);
+    GLES30.glVertexAttribPointer(mOITRenderProgram.mAttribute[0], 2, GLES30.GL_FLOAT, false, 0, mQuadPositions);
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -687,37 +687,61 @@ public class DistortedLibrary
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // ARM Mali driver r12 has problems when we keep swapping many FBOs (fixed in r22)
-// PowerVR GE8100 compiler fails to compile OIT programs.
+// PowerVR GE8100 / GE8300 compiler fails to compile OIT programs.
 
   private static void detectBuggyDrivers()
     {
-    String vendor  = GLES31.glGetString(GLES31.GL_VENDOR);
-    String version = GLES31.glGetString(GLES31.GL_VERSION);
-    String renderer= GLES31.glGetString(GLES31.GL_RENDERER);
+    String vendor  = GLES30.glGetString(GLES30.GL_VENDOR);
+    String version = GLES30.glGetString(GLES30.GL_VERSION);
+    String renderer= GLES30.glGetString(GLES30.GL_RENDERER);
 
     /*
-    android.util.Log.e("DISTORTED", "GLSL Version "+GLES31.glGetString(GLES31.GL_SHADING_LANGUAGE_VERSION));
-    android.util.Log.e("DISTORTED", "GL Version "  +GLES31.glGetString(GLES31.GL_VERSION));
-    android.util.Log.e("DISTORTED", "GL Vendor "   +GLES31.glGetString(GLES31.GL_VENDOR));
-    android.util.Log.e("DISTORTED", "GL Renderer " +GLES31.glGetString(GLES31.GL_RENDERER));
+    android.util.Log.e("DISTORTED", "GLSL Version "+GLES30.glGetString(GLES31.GL_SHADING_LANGUAGE_VERSION));
+    android.util.Log.e("DISTORTED", "GL Version "  +GLES30.glGetString(GLES31.GL_VERSION));
+    android.util.Log.e("DISTORTED", "GL Vendor "   +GLES30.glGetString(GLES31.GL_VENDOR));
+    android.util.Log.e("DISTORTED", "GL Renderer " +GLES30.glGetString(GLES31.GL_RENDERER));
     */
 
     if( vendor.contains("ARM") )
       {
       if( version.contains("r12") )
         {
-        android.util.Log.e("DISTORTED", "You are running this on a ARM Mali driver r12.\nThis is a buggy driver, please update to r22. Problems with flashing expected.");
+        Log.e("DISTORTED", "You are running this on a ARM Mali driver r12.\nThis is a buggy driver, please update to r22. Problems with flashing expected.");
         }
       }
     else if( vendor.contains("Imagination") )
       {
       if( renderer.contains("GE8") )
         {
-        android.util.Log.e("DISTORTED", "You are running this on a PowerVR GE8XXX.\nDue to a buggy compiler OIT rendering will not work");
+        Log.e("DISTORTED", "You are running this on a PowerVR GE8XXX.\nDue to a buggy compiler OIT rendering will not work");
         }
       }
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Return OpenGL ES version supported by the hardware we are running on.
+ * There are only two possibilities: 300 (OpenGL ES 3.0) or 310 (at least OpenGL ES 3.1)
+ */
+  static int getGLSL()
+    {
+    return mGLSL;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Have we successfully managed to compile the OIT programs?
+ * Some hardware ( Imagination GE8100 / 8300, driver build 1.8@4490469 present in my HTC phone and,
+ * sadly, Amazon Fire Stick 4K ) fails to compile the shaders. See relevant thread in Imagination's
+ * support forum:
+ *
+ * https://forums.imgtec.com/t/ge8100-in-htc-desire-12-android-7-1-1-fragment-shader-fails-to-compile/2708
+ */
+  public static boolean OITCompilationSuccessful()
+    {
+    return mOITCompilationSuccessful;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Have we called onCreate yet, ie have we initialized the library?
@@ -741,9 +765,26 @@ public class DistortedLibrary
     {
     final ActivityManager activityManager     = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
     final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
-    android.util.Log.e("DISTORTED", "Using OpenGL ES "+configurationInfo.getGlEsVersion());
+
+    int glESversion = configurationInfo.reqGlEsVersion;
+    int major = glESversion >> 16;
+    int minor = glESversion & 0xff;
+
+    if( major< 3 )
+      {
+      mGLSL = 100*major + 10*minor;
+      throw new VertexCompilationException("at least OpenGL ES 3.0 required, this device supports only "+major+"."+minor);
+      }
+    else
+      {
+      mGLSL = (major==3 && minor==0) ? 300 : 310;
+      }
+
+    android.util.Log.e("DISTORTED", "Using OpenGL ES "+major+"."+minor);
+    mGLSL_VERSION = "#version "+mGLSL+" es\n";
 
     mInitialized = true;
+    mOITCompilationSuccessful = false;
 
     detectBuggyDrivers();
 
@@ -762,18 +803,22 @@ public class DistortedLibrary
       exception = ex;
       }
 
-    try
+    if( mGLSL>=310)
       {
-      createProgramsOIT(resources);
-      }
-    catch(Exception ex)
-      {
-      exception = ex;
+      try
+        {
+        createProgramsOIT(resources);
+        mOITCompilationSuccessful = true;
+        }
+      catch(Exception ex)
+        {
+        exception = ex;
+        }
       }
 
     try
       {
-      EffectQueuePostprocess.createPrograms(resources);
+      EffectQueuePostprocess.createPrograms(resources, mGLSL);
       }
     catch(Exception ex)
       {
@@ -782,7 +827,7 @@ public class DistortedLibrary
 
     try
       {
-      PostprocessEffect.createPrograms();
+      PostprocessEffect.createPrograms(mGLSL);
       }
     catch(Exception ex)
       {
diff --git a/src/main/java/org/distorted/library/main/DistortedNode.java b/src/main/java/org/distorted/library/main/DistortedNode.java
index 1314411..d5cf03c 100644
--- a/src/main/java/org/distorted/library/main/DistortedNode.java
+++ b/src/main/java/org/distorted/library/main/DistortedNode.java
@@ -19,7 +19,7 @@
 
 package org.distorted.library.main;
 
-import android.opengl.GLES31;
+import android.opengl.GLES30;
 
 import org.distorted.library.mesh.MeshBase;
 
@@ -159,9 +159,9 @@ public class DistortedNode implements InternalChildrenList.Parent
     if( input.setAsInput() )
       {
       mState.apply();
-      GLES31.glDisable(GLES31.GL_BLEND);
+      GLES30.glDisable(GLES30.GL_BLEND);
       DistortedLibrary.drawPriv(mEffects, mMesh, surface, currTime);
-      GLES31.glEnable(GLES31.GL_BLEND);
+      GLES30.glEnable(GLES30.GL_BLEND);
       return 1;
       }
 
diff --git a/src/main/java/org/distorted/library/main/DistortedScreen.java b/src/main/java/org/distorted/library/main/DistortedScreen.java
index 3e2c71c..4e1c742 100644
--- a/src/main/java/org/distorted/library/main/DistortedScreen.java
+++ b/src/main/java/org/distorted/library/main/DistortedScreen.java
@@ -24,7 +24,7 @@ package org.distorted.library.main;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Paint;
-import android.opengl.GLES31;
+import android.opengl.GLES30;
 
 import org.distorted.library.effect.MatrixEffectMove;
 import org.distorted.library.effect.MatrixEffectScale;
@@ -115,7 +115,7 @@ public class DistortedScreen extends DistortedFramebuffer
 
     int numrender = super.render(time,mCurRenderedFBO);
 
-    GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, 0);
+    GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
 
     // workaround for the Mali issues: blit the framebuffer we have computed DistortedLibrary.FBO_QUEUE_SIZE
     // frames ago. Looks like FBO_QUEUE_SIZE=2 solves the issue already but I decided to play it safe and
@@ -124,11 +124,11 @@ public class DistortedScreen extends DistortedFramebuffer
     // on speed. Maybe a slight positive effect if any!
     setAsInput(mToBeBlittedFBO,0);
 
-    GLES31.glColorMask(true,true,true,true);
-    GLES31.glDepthMask(false);
-    GLES31.glDisable(GLES31.GL_STENCIL_TEST);
-    GLES31.glDisable(GLES31.GL_DEPTH_TEST);
-    GLES31.glDisable(GLES31.GL_BLEND);
+    GLES30.glColorMask(true,true,true,true);
+    GLES30.glDepthMask(false);
+    GLES30.glDisable(GLES30.GL_STENCIL_TEST);
+    GLES30.glDisable(GLES30.GL_DEPTH_TEST);
+    GLES30.glDisable(GLES30.GL_BLEND);
 
     DistortedLibrary.blitPriv(this);
 
diff --git a/src/main/java/org/distorted/library/main/DistortedTexture.java b/src/main/java/org/distorted/library/main/DistortedTexture.java
index 34e1639..804bd3f 100644
--- a/src/main/java/org/distorted/library/main/DistortedTexture.java
+++ b/src/main/java/org/distorted/library/main/DistortedTexture.java
@@ -23,7 +23,7 @@ import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Paint;
-import android.opengl.GLES31;
+import android.opengl.GLES30;
 import android.opengl.GLUtils;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -64,18 +64,18 @@ public class DistortedTexture extends InternalSurface
       if( mColorCreated==NOT_CREATED_YET )
         {
         mColorCreated = CREATED;
-        GLES31.glGenTextures(1, mColorH, 0);
-        GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, mColorH[0]);
-        GLES31.glTexParameteri ( GLES31.GL_TEXTURE_2D, GLES31.GL_TEXTURE_MIN_FILTER, GLES31.GL_LINEAR );
-        GLES31.glTexParameteri ( GLES31.GL_TEXTURE_2D, GLES31.GL_TEXTURE_MAG_FILTER, GLES31.GL_LINEAR );
-        GLES31.glTexParameteri ( GLES31.GL_TEXTURE_2D, GLES31.GL_TEXTURE_WRAP_S, GLES31.GL_CLAMP_TO_EDGE );
-        GLES31.glTexParameteri ( GLES31.GL_TEXTURE_2D, GLES31.GL_TEXTURE_WRAP_T, GLES31.GL_CLAMP_TO_EDGE );
-        GLUtils.texImage2D(GLES31.GL_TEXTURE_2D, 0, flipBitmap(mBmp), 0);
+        GLES30.glGenTextures(1, mColorH, 0);
+        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mColorH[0]);
+        GLES30.glTexParameteri ( GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR );
+        GLES30.glTexParameteri ( GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR );
+        GLES30.glTexParameteri ( GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_S, GLES30.GL_CLAMP_TO_EDGE );
+        GLES30.glTexParameteri ( GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_WRAP_T, GLES30.GL_CLAMP_TO_EDGE );
+        GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, flipBitmap(mBmp), 0);
         }
       else
         {
-        GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, mColorH[0]);
-        GLUtils.texSubImage2D(GLES31.GL_TEXTURE_2D, 0,0,0,flipBitmap(mBmp));
+        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mColorH[0]);
+        GLUtils.texSubImage2D(GLES30.GL_TEXTURE_2D, 0,0,0,flipBitmap(mBmp));
         }
 
       mBmp = null;
@@ -89,7 +89,7 @@ public class DistortedTexture extends InternalSurface
     {
     if( mColorH[0]>0 )
       {
-      GLES31.glDeleteTextures(1, mColorH, 0);
+      GLES30.glDeleteTextures(1, mColorH, 0);
       mColorH[0] = 0;
       mColorCreated = NOT_CREATED_YET;
       }
diff --git a/src/main/java/org/distorted/library/main/InternalBuffer.java b/src/main/java/org/distorted/library/main/InternalBuffer.java
index 2cc820d..ccfa2cc 100644
--- a/src/main/java/org/distorted/library/main/InternalBuffer.java
+++ b/src/main/java/org/distorted/library/main/InternalBuffer.java
@@ -19,7 +19,7 @@
 
 package org.distorted.library.main;
 
-import android.opengl.GLES31;
+import android.opengl.GLES30;
 import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
@@ -82,10 +82,10 @@ public class InternalBuffer extends InternalObject
         mBuffer = null;
         }
 
-      GLES31.glGenBuffers( 1, mIndex, 0);
-      GLES31.glBindBuffer( mTarget, mIndex[0]);
-      GLES31.glBufferData( mTarget, mSize, mBuffer, mUsage);
-      GLES31.glBindBuffer( mTarget, 0);
+      GLES30.glGenBuffers( 1, mIndex, 0);
+      GLES30.glBindBuffer( mTarget, mIndex[0]);
+      GLES30.glBufferData( mTarget, mSize, mBuffer, mUsage);
+      GLES30.glBindBuffer( mTarget, 0);
 
       markWasCreatedImmediately();
       }
@@ -107,10 +107,10 @@ public class InternalBuffer extends InternalObject
     {
     if( mIndex[0]<0 )
       {
-      GLES31.glGenBuffers( 1, mIndex, 0);
-      GLES31.glBindBuffer( mTarget, mIndex[0]);
-      GLES31.glBufferData( mTarget, mSize, mBuffer, mUsage);
-      GLES31.glBindBuffer( mTarget, 0);
+      GLES30.glGenBuffers( 1, mIndex, 0);
+      GLES30.glBindBuffer( mTarget, mIndex[0]);
+      GLES30.glBufferData( mTarget, mSize, mBuffer, mUsage);
+      GLES30.glBindBuffer( mTarget, 0);
       }
     }
 
@@ -121,7 +121,7 @@ public class InternalBuffer extends InternalObject
     {
     if( mIndex[0]>=0 )
       {
-      GLES31.glDeleteBuffers(1, mIndex, 0);
+      GLES30.glDeleteBuffers(1, mIndex, 0);
       mIndex[0] = -1;
       }
     }
diff --git a/src/main/java/org/distorted/library/main/InternalOutputSurface.java b/src/main/java/org/distorted/library/main/InternalOutputSurface.java
index 4388334..254aa69 100644
--- a/src/main/java/org/distorted/library/main/InternalOutputSurface.java
+++ b/src/main/java/org/distorted/library/main/InternalOutputSurface.java
@@ -19,6 +19,7 @@
 
 package org.distorted.library.main;
 
+import android.opengl.GLES30;
 import android.opengl.GLES31;
 import android.opengl.Matrix;
 
@@ -97,7 +98,7 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
 
     mClearDepth = 1.0f;
     mClearStencil = 0;
-    mClear = GLES31.GL_DEPTH_BUFFER_BIT | GLES31.GL_COLOR_BUFFER_BIT;
+    mClear = GLES30.GL_DEPTH_BUFFER_BIT | GLES30.GL_COLOR_BUFFER_BIT;
 
     mMipmap = 1.0f;
 
@@ -167,22 +168,22 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
     InternalObject.toDo(); // create the FBOs immediately. This is safe as we must be holding the OpenGL context now.
 
     InternalRenderState.colorDepthStencilOn();
-    GLES31.glClearColor(CLEAR_R, CLEAR_G, CLEAR_B, CLEAR_A);
-    GLES31.glClearDepthf(CLEAR_D);
-    GLES31.glClearStencil(CLEAR_S);
+    GLES30.glClearColor(CLEAR_R, CLEAR_G, CLEAR_B, CLEAR_A);
+    GLES30.glClearDepthf(CLEAR_D);
+    GLES30.glClearStencil(CLEAR_S);
 
     for(int k = 0; k< DistortedLibrary.FBO_QUEUE_SIZE; k++)
       {
-      GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, mBuffer[quality].mFBOH[k]);
-      GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, mBuffer[quality].mColorH[2*k+1], 0);
-      GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT | GLES31.GL_DEPTH_BUFFER_BIT | GLES31.GL_STENCIL_BUFFER_BIT);
-      GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, mBuffer[quality].mColorH[2*k  ], 0);
-      GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT);
+      GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mBuffer[quality].mFBOH[k]);
+      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, mBuffer[quality].mColorH[2*k+1], 0);
+      GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT | GLES30.GL_DEPTH_BUFFER_BIT | GLES30.GL_STENCIL_BUFFER_BIT);
+      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, mBuffer[quality].mColorH[2*k  ], 0);
+      GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
       }
 
     InternalRenderState.colorDepthStencilRestore();
 
-    GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, 0);
+    GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -236,35 +237,35 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
 
   private int blitWithDepth(long currTime, InternalOutputSurface buffer, int fbo)
     {
-    GLES31.glViewport(0, 0, mWidth, mHeight);
+    GLES30.glViewport(0, 0, mWidth, mHeight);
     setAsOutput(currTime);
-    GLES31.glActiveTexture(GLES31.GL_TEXTURE0);
-    GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, buffer.mColorH[2*fbo]);
-    GLES31.glActiveTexture(GLES31.GL_TEXTURE1);
-    GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, buffer.mDepthStencilH[fbo]);
+    GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
+    GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, buffer.mColorH[2*fbo]);
+    GLES30.glActiveTexture(GLES30.GL_TEXTURE1);
+    GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, buffer.mDepthStencilH[fbo]);
 
-    GLES31.glDisable(GLES31.GL_STENCIL_TEST);
-    GLES31.glStencilMask(0x00);
+    GLES30.glDisable(GLES30.GL_STENCIL_TEST);
+    GLES30.glStencilMask(0x00);
 
     DistortedLibrary.blitDepthPriv(this, buffer.getWidthCorrection(), buffer.getHeightCorrection() );
-    GLES31.glActiveTexture(GLES31.GL_TEXTURE0);
-    GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, 0);
-    GLES31.glActiveTexture(GLES31.GL_TEXTURE1);
-    GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, 0);
+    GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
+    GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
+    GLES30.glActiveTexture(GLES30.GL_TEXTURE1);
+    GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
 
     // clear buffers
-    GLES31.glStencilMask(0xff);
-    GLES31.glDepthMask(true);
-    GLES31.glColorMask(true,true,true,true);
-    GLES31.glClearColor(buffer.mClearR,buffer.mClearG,buffer.mClearB,buffer.mClearA);
-    GLES31.glClearDepthf(buffer.mClearDepth);
-    GLES31.glClearStencil(buffer.mClearStencil);
+    GLES30.glStencilMask(0xff);
+    GLES30.glDepthMask(true);
+    GLES30.glColorMask(true,true,true,true);
+    GLES30.glClearColor(buffer.mClearR,buffer.mClearG,buffer.mClearB,buffer.mClearA);
+    GLES30.glClearDepthf(buffer.mClearDepth);
+    GLES30.glClearStencil(buffer.mClearStencil);
 
     buffer.setAsOutput();
-    GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, buffer.mColorH[2*fbo+1], 0);
-    GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT|GLES31.GL_DEPTH_BUFFER_BIT|GLES31.GL_STENCIL_BUFFER_BIT);
-    GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, buffer.mColorH[2*fbo  ], 0);
-    GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT);
+    GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, buffer.mColorH[2*fbo+1], 0);
+    GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT|GLES30.GL_DEPTH_BUFFER_BIT|GLES30.GL_STENCIL_BUFFER_BIT);
+    GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, buffer.mColorH[2*fbo  ], 0);
+    GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
 
     return 1;
     }
@@ -282,21 +283,21 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
 
   private int oitBuild(long time, InternalOutputSurface buffer, int fbo)
     {
-    GLES31.glViewport(0, 0, mWidth, mHeight);
+    GLES30.glViewport(0, 0, mWidth, mHeight);
     setAsOutput(time);
-    GLES31.glActiveTexture(GLES31.GL_TEXTURE0);
-    GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, buffer.mColorH[2*fbo]);
-    GLES31.glActiveTexture(GLES31.GL_TEXTURE1);
-    GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, buffer.mDepthStencilH[fbo]);
+    GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
+    GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, buffer.mColorH[2*fbo]);
+    GLES30.glActiveTexture(GLES30.GL_TEXTURE1);
+    GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, buffer.mDepthStencilH[fbo]);
 
     InternalRenderState.colorDepthStencilOn();
     InternalRenderState.enableDepthTest();
 
     DistortedLibrary.oitBuild(this, buffer.getWidthCorrection(), buffer.getHeightCorrection() );
-    GLES31.glActiveTexture(GLES31.GL_TEXTURE0);
-    GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, 0);
-    GLES31.glActiveTexture(GLES31.GL_TEXTURE1);
-    GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, 0);
+    GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
+    GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
+    GLES30.glActiveTexture(GLES30.GL_TEXTURE1);
+    GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
 
     InternalRenderState.colorDepthStencilRestore();
     InternalRenderState.restoreDepthTest();
@@ -317,12 +318,12 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
 
     if( mDepthStencilH[fbo] != 0 )
       {
-      GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, 0);
-      GLES31.glActiveTexture(GLES31.GL_TEXTURE1);
-      GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, mDepthStencilH[fbo]);
+      GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0);
+      GLES30.glActiveTexture(GLES30.GL_TEXTURE1);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mDepthStencilH[fbo]);
       InternalRenderState.switchOffColorDepthStencil();
       DistortedLibrary.oitCollapse(this, corrW, corrH);
-      GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, 0);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0);
       }
 
     setAsOutput(currTime);
@@ -338,10 +339,10 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
   private void clear()
     {
     InternalRenderState.colorDepthStencilOn();
-    GLES31.glClearColor(mClearR, mClearG, mClearB, mClearA);
-    GLES31.glClearDepthf(mClearDepth);
-    GLES31.glClearStencil(mClearStencil);
-    GLES31.glClear(mClear);
+    GLES30.glClearColor(mClearR, mClearG, mClearB, mClearA);
+    GLES30.glClearDepthf(mClearDepth);
+    GLES30.glClearStencil(mClearStencil);
+    GLES30.glClear(mClear);
     InternalRenderState.colorDepthStencilRestore();
     }
 
@@ -533,15 +534,15 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
     {
     InternalRenderState.colorDepthStencilOn();
 
-    GLES31.glClearColor(mClearR, mClearG, mClearB, mClearA);
-    GLES31.glClearDepthf(mClearDepth);
-    GLES31.glClearStencil(mClearStencil);
+    GLES30.glClearColor(mClearR, mClearG, mClearB, mClearA);
+    GLES30.glClearDepthf(mClearDepth);
+    GLES30.glClearStencil(mClearStencil);
 
-    GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, mFBOH[fbo]);
-    GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, mColorH[2*fbo+1], 0);
-    GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT|GLES31.GL_DEPTH_BUFFER_BIT|GLES31.GL_STENCIL_BUFFER_BIT);
-    GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, mColorH[2*fbo  ], 0);
-    GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT);
+    GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFBOH[fbo]);
+    GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, mColorH[2*fbo+1], 0);
+    GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT|GLES30.GL_DEPTH_BUFFER_BIT|GLES30.GL_STENCIL_BUFFER_BIT);
+    GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, mColorH[2*fbo  ], 0);
+    GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT);
 
     InternalRenderState.colorDepthStencilRestore();
     }
@@ -550,7 +551,7 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
 
   void setAsOutput(long time)
     {
-    GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, mFBOH[mCurrFBO]);
+    GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFBOH[mCurrFBO]);
 
     if( mTime[mCurrFBO]!=time )
       {
@@ -617,7 +618,7 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
  */
   public void setAsOutput()
     {
-    GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, mFBOH[mCurrFBO]);
+    GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFBOH[mCurrFBO]);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -811,6 +812,10 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
 /**
  * When rendering this Node, should we use the Order Independent Transparency render mode?
  * <p>
+ * This feature requires OpenGL ES 3.1. If we are running on OpenGL 3.0, this will do nothing.
+ * Also, if you are running on a buggy driver ( Imagination GE8100/8300 driver build 1.8@4490469 )
+ * then do nothing.
+ *
  * There are two modes of rendering: the fast 'normal' way, which however renders transparent
  * fragments in different ways depending on which fragments get rendered first, or the slower
  * 'oit' way, which renders transparent fragments correctly regardless of their order.
@@ -819,13 +824,20 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
  */
   public void setOrderIndependentTransparency(boolean oit)
     {
-    mRenderWayOIT = oit;
+    if( DistortedLibrary.getGLSL()>=310 && DistortedLibrary.OITCompilationSuccessful() )
+      {
+      mRenderWayOIT = oit;
+      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * When rendering this Node, should we use the Order Independent Transparency render mode?
  * <p>
+ * This feature requires OpenGL ES 3.1. If we are running on OpenGL 3.0, this will do nothing.
+ * Also, if you are running on a buggy driver ( Imagination GE8100/8300 driver build 1.8@4490469 )
+ * then do nothing.
+ *
  * There are two modes of rendering: the fast 'normal' way, which however renders transparent
  * fragments in different ways depending on which fragments get rendered first, or the slower
  * 'oit' way, which renders transparent fragments correctly regardless of their order.
@@ -840,11 +852,14 @@ public abstract class InternalOutputSurface extends InternalSurface implements I
  */
   public void setOrderIndependentTransparency(boolean oit, float initialSize)
     {
-    mRenderWayOIT = oit;
-
-    if( initialSize>0.0f && initialSize<10.0f )
+    if( DistortedLibrary.getGLSL()>=310 && DistortedLibrary.OITCompilationSuccessful() )
       {
-      DistortedLibrary.setSSBOSize(initialSize);
+      mRenderWayOIT = oit;
+
+      if( initialSize>0.0f && initialSize<10.0f )
+        {
+        DistortedLibrary.setSSBOSize(initialSize);
+        }
       }
     }
 
diff --git a/src/main/java/org/distorted/library/main/InternalRenderState.java b/src/main/java/org/distorted/library/main/InternalRenderState.java
index a9eca6d..7e99f8d 100644
--- a/src/main/java/org/distorted/library/main/InternalRenderState.java
+++ b/src/main/java/org/distorted/library/main/InternalRenderState.java
@@ -19,7 +19,7 @@
 
 package org.distorted.library.main;
 
-import android.opengl.GLES31;
+import android.opengl.GLES30;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -71,20 +71,20 @@ public class InternalRenderState
 
     mState.depthTest  = 1;
     mState.depthMask  = 1;
-    mState.depthFunc  = GLES31.GL_LEQUAL;
+    mState.depthFunc  = GLES30.GL_LEQUAL;
 
     mState.blend      = 1;
-    mState.blendSrc   = GLES31.GL_SRC_ALPHA;
-    mState.blendDst   = GLES31.GL_ONE_MINUS_SRC_ALPHA;
+    mState.blendSrc   = GLES30.GL_SRC_ALPHA;
+    mState.blendDst   = GLES30.GL_ONE_MINUS_SRC_ALPHA;
 
     mState.stencilTest     = 0;
     mState.stencilMask     = STENCIL_MASK;
-    mState.stencilFuncFunc = GLES31.GL_NEVER;
+    mState.stencilFuncFunc = GLES30.GL_NEVER;
     mState.stencilFuncRef  = 0;
     mState.stencilFuncMask = STENCIL_MASK;
-    mState.stencilOpSfail  = GLES31.GL_KEEP;
-    mState.stencilOpDpfail = GLES31.GL_KEEP;
-    mState.stencilOpDppass = GLES31.GL_KEEP;
+    mState.stencilOpSfail  = GLES30.GL_KEEP;
+    mState.stencilOpDpfail = GLES30.GL_KEEP;
+    mState.stencilOpDppass = GLES30.GL_KEEP;
 
     mClear = 0;
     }
@@ -98,31 +98,31 @@ public class InternalRenderState
     cState.colorMaskG = 1;
     cState.colorMaskB = 1;
     cState.colorMaskA = 1;
-    GLES31.glColorMask(true,true,true,true);
+    GLES30.glColorMask(true,true,true,true);
 
     cState.depthTest = 1;
     cState.depthMask = 1;
-    cState.depthFunc = GLES31.GL_LEQUAL;
-    GLES31.glEnable(GLES31.GL_DEPTH_TEST);
-    GLES31.glDepthMask(true);
-    GLES31.glDepthFunc(cState.depthFunc);
+    cState.depthFunc = GLES30.GL_LEQUAL;
+    GLES30.glEnable(GLES30.GL_DEPTH_TEST);
+    GLES30.glDepthMask(true);
+    GLES30.glDepthFunc(cState.depthFunc);
 
     cState.stencilTest     = 0;
     cState.stencilMask     = STENCIL_MASK;
-    cState.stencilFuncFunc = GLES31.GL_NEVER;
+    cState.stencilFuncFunc = GLES30.GL_NEVER;
     cState.stencilFuncRef  = 0;
     cState.stencilFuncMask = STENCIL_MASK;
-    cState.stencilOpSfail  = GLES31.GL_KEEP;
-    cState.stencilOpDpfail = GLES31.GL_KEEP;
-    cState.stencilOpDppass = GLES31.GL_KEEP;
-    GLES31.glDisable(GLES31.GL_STENCIL_TEST);
-    GLES31.glStencilMask(cState.stencilMask);
+    cState.stencilOpSfail  = GLES30.GL_KEEP;
+    cState.stencilOpDpfail = GLES30.GL_KEEP;
+    cState.stencilOpDppass = GLES30.GL_KEEP;
+    GLES30.glDisable(GLES30.GL_STENCIL_TEST);
+    GLES30.glStencilMask(cState.stencilMask);
 
     cState.blend      = 1;
-    cState.blendSrc   = GLES31.GL_SRC_ALPHA;
-    cState.blendDst   = GLES31.GL_ONE_MINUS_SRC_ALPHA;
-    GLES31.glEnable(GLES31.GL_BLEND);
-    GLES31.glBlendFunc(cState.blendSrc,cState.blendDst);
+    cState.blendSrc   = GLES30.GL_SRC_ALPHA;
+    cState.blendDst   = GLES30.GL_ONE_MINUS_SRC_ALPHA;
+    GLES30.glEnable(GLES30.GL_BLEND);
+    GLES30.glBlendFunc(cState.blendSrc,cState.blendDst);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -140,7 +140,7 @@ public class InternalRenderState
       cState.colorMaskG = 1;
       cState.colorMaskB = 1;
       cState.colorMaskA = 1;
-      GLES31.glColorMask(true,true,true,true);
+      GLES30.glColorMask(true,true,true,true);
       }
 
     sState.depthMask = cState.depthMask;
@@ -148,7 +148,7 @@ public class InternalRenderState
     if( cState.depthMask!=1 )
       {
       cState.depthMask = 1;
-      GLES31.glDepthMask(true);
+      GLES30.glDepthMask(true);
       }
 
     sState.stencilMask = cState.stencilMask;
@@ -156,7 +156,7 @@ public class InternalRenderState
     if( cState.stencilMask!= STENCIL_MASK )
       {
       cState.stencilMask = STENCIL_MASK;
-      GLES31.glStencilMask(cState.stencilMask);
+      GLES30.glStencilMask(cState.stencilMask);
       }
     }
 
@@ -170,17 +170,17 @@ public class InternalRenderState
       cState.colorMaskG = sState.colorMaskG;
       cState.colorMaskB = sState.colorMaskB;
       cState.colorMaskA = sState.colorMaskA;
-      GLES31.glColorMask(cState.colorMaskR==1,cState.colorMaskG==1,cState.colorMaskB==1,cState.colorMaskA==1);
+      GLES30.glColorMask(cState.colorMaskR==1,cState.colorMaskG==1,cState.colorMaskB==1,cState.colorMaskA==1);
       }
     if( sState.depthMask!=cState.depthMask )
       {
       cState.depthMask = sState.depthMask;
-      GLES31.glDepthMask(cState.depthMask==1);
+      GLES30.glDepthMask(cState.depthMask==1);
       }
     if( sState.stencilMask!=cState.stencilMask )
       {
       cState.stencilMask = sState.stencilMask;
-      GLES31.glStencilMask(cState.stencilMask);
+      GLES30.glStencilMask(cState.stencilMask);
       }
     }
 
@@ -193,7 +193,7 @@ public class InternalRenderState
     if (cState.blend != 0)
       {
       cState.blend = 0;
-      GLES31.glDisable(GLES31.GL_BLEND);
+      GLES30.glDisable(GLES30.GL_BLEND);
       }
     }
 
@@ -207,11 +207,11 @@ public class InternalRenderState
 
       if (cState.blend == 0)
         {
-        GLES31.glDisable(GLES31.GL_BLEND);
+        GLES30.glDisable(GLES30.GL_BLEND);
         }
       else
         {
-        GLES31.glEnable(GLES31.GL_BLEND);
+        GLES30.glEnable(GLES30.GL_BLEND);
         }
       }
     }
@@ -225,7 +225,7 @@ public class InternalRenderState
     if (cState.depthTest != 1)
       {
       cState.depthTest = 1;
-      GLES31.glEnable(GLES31.GL_DEPTH_TEST);
+      GLES30.glEnable(GLES30.GL_DEPTH_TEST);
       }
     }
 
@@ -239,11 +239,11 @@ public class InternalRenderState
 
       if (cState.depthTest == 0)
         {
-        GLES31.glDisable(GLES31.GL_DEPTH_TEST);
+        GLES30.glDisable(GLES30.GL_DEPTH_TEST);
         }
       else
         {
-        GLES31.glEnable(GLES31.GL_DEPTH_TEST);
+        GLES30.glEnable(GLES30.GL_DEPTH_TEST);
         }
       }
     }
@@ -252,15 +252,15 @@ public class InternalRenderState
 
   static void switchOffDrawing()
     {
-    GLES31.glEnable(GLES31.GL_SCISSOR_TEST);
-    GLES31.glScissor(0,0,0,0);
+    GLES30.glEnable(GLES30.GL_SCISSOR_TEST);
+    GLES30.glScissor(0,0,0,0);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   static void restoreDrawing()
     {
-    GLES31.glDisable(GLES31.GL_SCISSOR_TEST);
+    GLES30.glDisable(GLES30.GL_SCISSOR_TEST);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -273,7 +273,7 @@ public class InternalRenderState
       {
       cState.stencilTest = 0;
       //android.util.Log.d("State", "stencil test off");
-      GLES31.glDisable(GLES31.GL_STENCIL_TEST);
+      GLES30.glDisable(GLES30.GL_STENCIL_TEST);
       }
 
     sState.depthTest = cState.depthTest;
@@ -282,7 +282,7 @@ public class InternalRenderState
       {
       cState.depthTest = 0;
       //android.util.Log.d("State", "depth test off");
-      GLES31.glDisable(GLES31.GL_DEPTH_TEST);
+      GLES30.glDisable(GLES30.GL_DEPTH_TEST);
       }
 
     sState.colorMaskR = cState.colorMaskR;
@@ -297,7 +297,7 @@ public class InternalRenderState
       cState.colorMaskB = 0;
       cState.colorMaskA = 0;
       //android.util.Log.d("State", "switch off color writing");
-      GLES31.glColorMask(false,false,false,false);
+      GLES30.glColorMask(false,false,false,false);
       }
 
     sState.depthMask = cState.depthMask;
@@ -306,7 +306,7 @@ public class InternalRenderState
       {
       cState.depthMask = 0;
       //android.util.Log.d("State", "switch off depth writing");
-      GLES31.glDepthMask(false);
+      GLES30.glDepthMask(false);
       }
 
     sState.stencilMask = cState.stencilMask;
@@ -315,7 +315,7 @@ public class InternalRenderState
       {
       cState.stencilMask = 0x00;
       //android.util.Log.d("State", "stencil mask off");
-      GLES31.glStencilMask(cState.stencilMask);
+      GLES30.glStencilMask(cState.stencilMask);
       }
     }
 
@@ -329,7 +329,7 @@ public class InternalRenderState
       {
       cState.stencilTest = 0;
       //android.util.Log.d("State", "stencil test off");
-      GLES31.glDisable(GLES31.GL_STENCIL_TEST);
+      GLES30.glDisable(GLES30.GL_STENCIL_TEST);
       }
 
     sState.depthTest = cState.depthTest;
@@ -338,7 +338,7 @@ public class InternalRenderState
       {
       cState.depthTest = 0;
       //android.util.Log.d("State", "depth test off");
-      GLES31.glDisable(GLES31.GL_DEPTH_TEST);
+      GLES30.glDisable(GLES30.GL_DEPTH_TEST);
       }
 
     sState.colorMaskR = cState.colorMaskR;
@@ -353,7 +353,7 @@ public class InternalRenderState
       cState.colorMaskB = 1;
       cState.colorMaskA = 1;
       //android.util.Log.d("State", "switch on color writing");
-      GLES31.glColorMask(true,true,true,true);
+      GLES30.glColorMask(true,true,true,true);
       }
 
     sState.depthMask = cState.depthMask;
@@ -362,7 +362,7 @@ public class InternalRenderState
       {
       cState.depthMask = 1;
       //android.util.Log.d("State", "switch on depth writing");
-      GLES31.glDepthMask(true);
+      GLES30.glDepthMask(true);
       }
 
     sState.stencilMask = cState.stencilMask;
@@ -371,7 +371,7 @@ public class InternalRenderState
       {
       cState.stencilMask = 0x00;
       //android.util.Log.d("State", "stencil mask off");
-      GLES31.glStencilMask(cState.stencilMask);
+      GLES30.glStencilMask(cState.stencilMask);
       }
     }
 
@@ -385,11 +385,11 @@ public class InternalRenderState
 
       if (cState.stencilTest == 0)
         {
-        GLES31.glDisable(GLES31.GL_STENCIL_TEST);
+        GLES30.glDisable(GLES30.GL_STENCIL_TEST);
         }
       else
         {
-        GLES31.glEnable(GLES31.GL_STENCIL_TEST);
+        GLES30.glEnable(GLES30.GL_STENCIL_TEST);
         }
       }
     if( sState.depthTest!=cState.depthTest )
@@ -398,11 +398,11 @@ public class InternalRenderState
 
       if (cState.depthTest == 0)
         {
-        GLES31.glDisable(GLES31.GL_DEPTH_TEST);
+        GLES30.glDisable(GLES30.GL_DEPTH_TEST);
         }
       else
         {
-        GLES31.glEnable(GLES31.GL_DEPTH_TEST);
+        GLES30.glEnable(GLES30.GL_DEPTH_TEST);
         }
       }
     if( sState.colorMaskR!=cState.colorMaskR || sState.colorMaskG!=cState.colorMaskG || sState.colorMaskB!=cState.colorMaskB || sState.colorMaskA!=cState.colorMaskA)
@@ -411,17 +411,17 @@ public class InternalRenderState
       cState.colorMaskG = sState.colorMaskG;
       cState.colorMaskB = sState.colorMaskB;
       cState.colorMaskA = sState.colorMaskA;
-      GLES31.glColorMask(cState.colorMaskR==1,cState.colorMaskG==1,cState.colorMaskB==1,cState.colorMaskA==1);
+      GLES30.glColorMask(cState.colorMaskR==1,cState.colorMaskG==1,cState.colorMaskB==1,cState.colorMaskA==1);
       }
     if( sState.depthMask!=cState.depthMask )
       {
       cState.depthMask = sState.depthMask;
-      GLES31.glDepthMask(cState.depthMask==1);
+      GLES30.glDepthMask(cState.depthMask==1);
       }
     if( sState.stencilMask!=cState.stencilMask )
       {
       cState.stencilMask = sState.stencilMask;
-      GLES31.glStencilMask(cState.stencilMask);
+      GLES30.glStencilMask(cState.stencilMask);
       }
     }
 
@@ -435,33 +435,33 @@ public class InternalRenderState
       {
       cState.stencilTest = 1;
       //android.util.Log.d("State", "stencil test on");
-      GLES31.glEnable(GLES31.GL_STENCIL_TEST);
+      GLES30.glEnable(GLES30.GL_STENCIL_TEST);
       }
 
     sState.stencilFuncFunc = cState.stencilFuncFunc;
     sState.stencilFuncRef  = cState.stencilFuncRef;
     sState.stencilFuncMask = cState.stencilFuncMask;
 
-    if( cState.stencilFuncFunc!=GLES31.GL_ALWAYS || cState.stencilFuncRef!=1 || cState.stencilFuncMask!=STENCIL_MASK )
+    if( cState.stencilFuncFunc!=GLES30.GL_ALWAYS || cState.stencilFuncRef!=1 || cState.stencilFuncMask!=STENCIL_MASK )
       {
-      cState.stencilFuncFunc = GLES31.GL_ALWAYS;
+      cState.stencilFuncFunc = GLES30.GL_ALWAYS;
       cState.stencilFuncRef  = 1;
       cState.stencilFuncMask = STENCIL_MASK;
       //android.util.Log.d("State", "stencil func on");
-      GLES31.glStencilFunc(cState.stencilFuncFunc,cState.stencilFuncRef,cState.stencilFuncMask);
+      GLES30.glStencilFunc(cState.stencilFuncFunc,cState.stencilFuncRef,cState.stencilFuncMask);
       }
 
     sState.stencilOpSfail = cState.stencilOpSfail;
     sState.stencilOpDpfail= cState.stencilOpDpfail;
     sState.stencilOpDppass= cState.stencilOpDppass;
 
-    if( cState.stencilOpSfail!=GLES31.GL_KEEP || cState.stencilOpDpfail!=GLES31.GL_KEEP || cState.stencilOpDppass!=GLES31.GL_REPLACE )
+    if( cState.stencilOpSfail!=GLES30.GL_KEEP || cState.stencilOpDpfail!=GLES30.GL_KEEP || cState.stencilOpDppass!=GLES30.GL_REPLACE )
       {
-      cState.stencilOpSfail = GLES31.GL_KEEP;
-      cState.stencilOpDpfail= GLES31.GL_KEEP;
-      cState.stencilOpDppass= GLES31.GL_REPLACE;
+      cState.stencilOpSfail = GLES30.GL_KEEP;
+      cState.stencilOpDpfail= GLES30.GL_KEEP;
+      cState.stencilOpDppass= GLES30.GL_REPLACE;
       //android.util.Log.d("State", "stencil op on");
-      GLES31.glStencilOp(cState.stencilOpSfail,cState.stencilOpDpfail,cState.stencilOpDppass);
+      GLES30.glStencilOp(cState.stencilOpSfail,cState.stencilOpDpfail,cState.stencilOpDppass);
       }
 
     sState.colorMaskR = cState.colorMaskR;
@@ -478,7 +478,7 @@ public class InternalRenderState
       cState.colorMaskB = clr;
       cState.colorMaskA = clr;
       //android.util.Log.d("State", "switch off color writing");
-      GLES31.glColorMask(color,color,color,color);
+      GLES30.glColorMask(color,color,color,color);
       }
 
     sState.depthMask = cState.depthMask;
@@ -487,7 +487,7 @@ public class InternalRenderState
       {
       cState.depthMask = 1;
       //android.util.Log.d("State", "switch on depth writing");
-      GLES31.glDepthMask(true);
+      GLES30.glDepthMask(true);
       }
 
     sState.stencilMask = cState.stencilMask;
@@ -496,7 +496,7 @@ public class InternalRenderState
       {
       cState.stencilMask = STENCIL_MASK;
       //android.util.Log.d("State", "stencil mask on");
-      GLES31.glStencilMask(cState.stencilMask);
+      GLES30.glStencilMask(cState.stencilMask);
       }
     }
 
@@ -510,11 +510,11 @@ public class InternalRenderState
 
       if (cState.stencilTest == 0)
         {
-        GLES31.glDisable(GLES31.GL_STENCIL_TEST);
+        GLES30.glDisable(GLES30.GL_STENCIL_TEST);
         }
       else
         {
-        GLES31.glEnable(GLES31.GL_STENCIL_TEST);
+        GLES30.glEnable(GLES30.GL_STENCIL_TEST);
         }
       }
     if( sState.colorMaskR!=cState.colorMaskR || sState.colorMaskG!=cState.colorMaskG || sState.colorMaskB!=cState.colorMaskB || sState.colorMaskA!=cState.colorMaskA)
@@ -523,17 +523,17 @@ public class InternalRenderState
       cState.colorMaskG = sState.colorMaskG;
       cState.colorMaskB = sState.colorMaskB;
       cState.colorMaskA = sState.colorMaskA;
-      GLES31.glColorMask(cState.colorMaskR==1,cState.colorMaskG==1,cState.colorMaskB==1,cState.colorMaskA==1);
+      GLES30.glColorMask(cState.colorMaskR==1,cState.colorMaskG==1,cState.colorMaskB==1,cState.colorMaskA==1);
       }
     if( sState.depthMask!=cState.depthMask )
       {
       cState.depthMask = sState.depthMask;
-      GLES31.glDepthMask(cState.depthMask==1);
+      GLES30.glDepthMask(cState.depthMask==1);
       }
     if( sState.stencilMask!=cState.stencilMask )
       {
       cState.stencilMask = sState.stencilMask;
-      GLES31.glStencilMask(cState.stencilMask);
+      GLES30.glStencilMask(cState.stencilMask);
       }
     }
 
@@ -550,19 +550,19 @@ public class InternalRenderState
     if( cState.stencilTest!=1 )
       {
       cState.stencilTest = 1;
-      GLES31.glEnable(GLES31.GL_STENCIL_TEST);
+      GLES30.glEnable(GLES30.GL_STENCIL_TEST);
       }
 
     sState.stencilFuncFunc = cState.stencilFuncFunc;
     sState.stencilFuncRef  = cState.stencilFuncRef;
     sState.stencilFuncMask = cState.stencilFuncMask;
 
-    if( cState.stencilFuncFunc!=GLES31.GL_EQUAL || cState.stencilFuncRef!=1 || cState.stencilFuncMask!=STENCIL_MASK )
+    if( cState.stencilFuncFunc!=GLES30.GL_EQUAL || cState.stencilFuncRef!=1 || cState.stencilFuncMask!=STENCIL_MASK )
       {
-      cState.stencilFuncFunc = GLES31.GL_EQUAL;
+      cState.stencilFuncFunc = GLES30.GL_EQUAL;
       cState.stencilFuncRef  = 1;
       cState.stencilFuncMask = STENCIL_MASK;
-      GLES31.glStencilFunc(cState.stencilFuncFunc,cState.stencilFuncRef,cState.stencilFuncMask);
+      GLES30.glStencilFunc(cState.stencilFuncFunc,cState.stencilFuncRef,cState.stencilFuncMask);
       }
 
     sState.stencilMask = cState.stencilMask;
@@ -570,7 +570,7 @@ public class InternalRenderState
     if( cState.stencilMask!= 0x00 )
       {
       cState.stencilMask = 0x00;
-      GLES31.glStencilMask(cState.stencilMask);
+      GLES30.glStencilMask(cState.stencilMask);
       }
 
     sState.depthMask = cState.depthMask;
@@ -578,7 +578,7 @@ public class InternalRenderState
     if( cState.depthMask!=0 )
       {
       cState.depthMask = 0;
-      GLES31.glDepthMask(false);
+      GLES30.glDepthMask(false);
       }
 
     sState.depthTest = cState.depthTest;
@@ -586,7 +586,7 @@ public class InternalRenderState
     if( cState.depthTest!=0 )
       {
       cState.depthTest = 0;
-      GLES31.glDisable(GLES31.GL_DEPTH_TEST);
+      GLES30.glDisable(GLES30.GL_DEPTH_TEST);
       }
     }
 
@@ -604,11 +604,11 @@ public class InternalRenderState
 
       if (cState.stencilTest == 0)
         {
-        GLES31.glDisable(GLES31.GL_STENCIL_TEST);
+        GLES30.glDisable(GLES30.GL_STENCIL_TEST);
         }
       else
         {
-        GLES31.glEnable(GLES31.GL_STENCIL_TEST);
+        GLES30.glEnable(GLES30.GL_STENCIL_TEST);
         }
       }
     if( sState.stencilFuncFunc!=cState.stencilFuncFunc || sState.stencilFuncRef!=cState.stencilFuncRef || sState.stencilFuncMask!=cState.stencilFuncMask )
@@ -616,17 +616,17 @@ public class InternalRenderState
       cState.stencilFuncFunc = sState.stencilFuncFunc;
       cState.stencilFuncRef  = sState.stencilFuncRef ;
       cState.stencilFuncMask = sState.stencilFuncMask;
-      GLES31.glStencilFunc(cState.stencilFuncFunc,cState.stencilFuncRef,cState.stencilFuncMask);
+      GLES30.glStencilFunc(cState.stencilFuncFunc,cState.stencilFuncRef,cState.stencilFuncMask);
       }
     if( sState.stencilMask!=cState.stencilMask )
       {
       cState.stencilMask = sState.stencilMask;
-      GLES31.glStencilMask(cState.stencilMask);
+      GLES30.glStencilMask(cState.stencilMask);
       }
     if( sState.depthMask!=cState.depthMask )
       {
       cState.depthMask = sState.depthMask;
-      GLES31.glDepthMask(cState.depthMask==1);
+      GLES30.glDepthMask(cState.depthMask==1);
       }
     if( sState.depthTest!=cState.depthTest )
       {
@@ -634,11 +634,11 @@ public class InternalRenderState
 
       if (cState.depthTest == 0)
         {
-        GLES31.glDisable(GLES31.GL_DEPTH_TEST);
+        GLES30.glDisable(GLES30.GL_DEPTH_TEST);
         }
       else
         {
-        GLES31.glEnable(GLES31.GL_DEPTH_TEST);
+        GLES30.glEnable(GLES30.GL_DEPTH_TEST);
         }
       }
     }
@@ -658,7 +658,7 @@ public class InternalRenderState
       cState.colorMaskG = mState.colorMaskG;
       cState.colorMaskB = mState.colorMaskB;
       cState.colorMaskA = mState.colorMaskA;
-      GLES31.glColorMask(cState.colorMaskR==1,cState.colorMaskG==1,cState.colorMaskB==1,cState.colorMaskA==1);
+      GLES30.glColorMask(cState.colorMaskR==1,cState.colorMaskG==1,cState.colorMaskB==1,cState.colorMaskA==1);
       }
 
     /////////////////////////////////////////////////////
@@ -670,12 +670,12 @@ public class InternalRenderState
       if (cState.depthTest == 0)
         {
         //android.util.Log.d("State", "disabling depth test");
-        GLES31.glDisable(GLES31.GL_DEPTH_TEST);
+        GLES30.glDisable(GLES30.GL_DEPTH_TEST);
         }
       else
         {
         //android.util.Log.d("State", "enable depth test");
-        GLES31.glEnable(GLES31.GL_DEPTH_TEST);
+        GLES30.glEnable(GLES30.GL_DEPTH_TEST);
         }
       }
 
@@ -685,7 +685,7 @@ public class InternalRenderState
       {
       //android.util.Log.d("State", "setting depth func");
       cState.depthFunc = mState.depthFunc;
-      GLES31.glDepthFunc(cState.depthFunc);
+      GLES30.glDepthFunc(cState.depthFunc);
       }
 
     /////////////////////////////////////////////////////
@@ -694,7 +694,7 @@ public class InternalRenderState
       {
       //android.util.Log.d("State", "setting depth mask");
       cState.depthMask = mState.depthMask;
-      GLES31.glDepthMask(cState.depthMask==1);
+      GLES30.glDepthMask(cState.depthMask==1);
       }
 
     /////////////////////////////////////////////////////
@@ -706,12 +706,12 @@ public class InternalRenderState
       if (cState.blend == 0)
         {
         //android.util.Log.d("State", "disabling blending");
-        GLES31.glDisable(GLES31.GL_BLEND);
+        GLES30.glDisable(GLES30.GL_BLEND);
         }
       else
         {
         //android.util.Log.d("State", "enabling blending");
-        GLES31.glEnable(GLES31.GL_BLEND);
+        GLES30.glEnable(GLES30.GL_BLEND);
         }
       }
 
@@ -722,7 +722,7 @@ public class InternalRenderState
       //android.util.Log.d("State", "setting blend function");
       cState.blendSrc = mState.blendSrc;
       cState.blendDst = mState.blendDst;
-      GLES31.glBlendFunc(cState.blendSrc,cState.blendDst);
+      GLES30.glBlendFunc(cState.blendSrc,cState.blendDst);
       }
 
     /////////////////////////////////////////////////////
@@ -734,12 +734,12 @@ public class InternalRenderState
       if (cState.stencilTest == 0)
         {
         //android.util.Log.d("State", "disabling stencil test");
-        GLES31.glDisable(GLES31.GL_STENCIL_TEST);
+        GLES30.glDisable(GLES30.GL_STENCIL_TEST);
         }
       else
         {
         //android.util.Log.d("State", "enabling stencil test");
-        GLES31.glEnable(GLES31.GL_STENCIL_TEST);
+        GLES30.glEnable(GLES30.GL_STENCIL_TEST);
         }
       }
 
@@ -751,7 +751,7 @@ public class InternalRenderState
       cState.stencilFuncFunc = mState.stencilFuncFunc;
       cState.stencilFuncRef  = mState.stencilFuncRef ;
       cState.stencilFuncMask = mState.stencilFuncMask;
-      GLES31.glStencilFunc(cState.stencilFuncFunc,cState.stencilFuncRef,cState.stencilFuncMask);
+      GLES30.glStencilFunc(cState.stencilFuncFunc,cState.stencilFuncRef,cState.stencilFuncMask);
       }
 
     /////////////////////////////////////////////////////
@@ -762,7 +762,7 @@ public class InternalRenderState
       cState.stencilOpSfail = mState.stencilOpSfail;
       cState.stencilOpDpfail= mState.stencilOpDpfail;
       cState.stencilOpDppass= mState.stencilOpDppass;
-      GLES31.glStencilOp(cState.stencilOpSfail,cState.stencilOpDpfail,cState.stencilOpDppass);
+      GLES30.glStencilOp(cState.stencilOpSfail,cState.stencilOpDpfail,cState.stencilOpDppass);
       }
 
     /////////////////////////////////////////////////////
@@ -771,7 +771,7 @@ public class InternalRenderState
       {
       //android.util.Log.d("State", "setting stencil mask");
       cState.stencilMask = mState.stencilMask;
-      GLES31.glStencilMask(cState.stencilMask);
+      GLES30.glStencilMask(cState.stencilMask);
       }
 
     /////////////////////////////////////////////////////
@@ -779,7 +779,7 @@ public class InternalRenderState
     if( mClear!=0 )
       {
       //android.util.Log.d("State", "clearing buffer");
-      GLES31.glClear(mClear);
+      GLES30.glClear(mClear);
       }
     }
 
@@ -811,18 +811,18 @@ public class InternalRenderState
 
   void glEnable(int test)
     {
-         if( test==GLES31.GL_DEPTH_TEST   ) mState.depthTest   = 1;
-    else if( test==GLES31.GL_STENCIL_TEST ) mState.stencilTest = 1;
-    else if( test==GLES31.GL_BLEND        ) mState.blend       = 1;
+         if( test==GLES30.GL_DEPTH_TEST   ) mState.depthTest   = 1;
+    else if( test==GLES30.GL_STENCIL_TEST ) mState.stencilTest = 1;
+    else if( test==GLES30.GL_BLEND        ) mState.blend       = 1;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void glDisable(int test)
     {
-         if( test==GLES31.GL_DEPTH_TEST   ) mState.depthTest   = 0;
-    else if( test==GLES31.GL_STENCIL_TEST ) mState.stencilTest = 0;
-    else if( test==GLES31.GL_BLEND        ) mState.blend       = 0;
+         if( test==GLES30.GL_DEPTH_TEST   ) mState.depthTest   = 0;
+    else if( test==GLES30.GL_STENCIL_TEST ) mState.stencilTest = 0;
+    else if( test==GLES30.GL_BLEND        ) mState.blend       = 0;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/main/InternalSurface.java b/src/main/java/org/distorted/library/main/InternalSurface.java
index a4fd845..a149865 100644
--- a/src/main/java/org/distorted/library/main/InternalSurface.java
+++ b/src/main/java/org/distorted/library/main/InternalSurface.java
@@ -19,7 +19,7 @@
 
 package org.distorted.library.main;
 
-import android.opengl.GLES31;
+import android.opengl.GLES30;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // common parent class of Texture & OutputSurface; so that we can store either in Nodes.
@@ -64,8 +64,8 @@ abstract class InternalSurface extends InternalObject
     {
     if( mColorH[0]>0 )
       {
-      GLES31.glActiveTexture(GLES31.GL_TEXTURE0);
-      GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, mColorH[0]);
+      GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mColorH[0]);
       return true;
       }
 
diff --git a/src/main/java/org/distorted/library/mesh/MeshBase.java b/src/main/java/org/distorted/library/mesh/MeshBase.java
index fb9afc3..6fb410a 100644
--- a/src/main/java/org/distorted/library/mesh/MeshBase.java
+++ b/src/main/java/org/distorted/library/mesh/MeshBase.java
@@ -19,11 +19,10 @@
 
 package org.distorted.library.mesh;
 
-import android.opengl.GLES31;
+import android.opengl.GLES30;
 import android.opengl.Matrix;
 
 import org.distorted.library.effect.MatrixEffect;
-import org.distorted.library.main.DistortedLibrary;
 import org.distorted.library.main.InternalBuffer;
 import org.distorted.library.program.DistortedProgram;
 import org.distorted.library.type.Static4D;
@@ -114,8 +113,8 @@ public abstract class MeshBase
      mInflate     = 0.0f;
      mComponent   = new ArrayList<>();
 
-     mVBO = new InternalBuffer(GLES31.GL_ARRAY_BUFFER             , GLES31.GL_STATIC_READ);
-     mTFO = new InternalBuffer(GLES31.GL_TRANSFORM_FEEDBACK_BUFFER, GLES31.GL_STATIC_READ);
+     mVBO = new InternalBuffer(GLES30.GL_ARRAY_BUFFER             , GLES30.GL_STATIC_READ);
+     mTFO = new InternalBuffer(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, GLES30.GL_STATIC_READ);
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -142,8 +141,8 @@ public abstract class MeshBase
        mComponent.add(comp);
        }
 
-     mVBO = new InternalBuffer(GLES31.GL_ARRAY_BUFFER             , GLES31.GL_STATIC_READ);
-     mTFO = new InternalBuffer(GLES31.GL_TRANSFORM_FEEDBACK_BUFFER, GLES31.GL_STATIC_READ);
+     mVBO = new InternalBuffer(GLES30.GL_ARRAY_BUFFER             , GLES30.GL_STATIC_READ);
+     mTFO = new InternalBuffer(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, GLES30.GL_STATIC_READ);
 
      System.arraycopy(original.mVertAttribs,0,mVertAttribs,0,original.mNumVertices*VERT_ATTRIBS);
      setAttribs(mVertAttribs);
@@ -308,12 +307,12 @@ public abstract class MeshBase
      {
      int index = mVBO.createImmediately(mNumVertices*VERT_SIZE, mVertAttribs);
 
-     GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, index );
-     GLES31.glVertexAttribPointer(program.mAttribute[0], POS_DATA_SIZE, GLES31.GL_FLOAT, false, VERT_SIZE, OFFSET_POS);
-     GLES31.glVertexAttribPointer(program.mAttribute[1], NOR_DATA_SIZE, GLES31.GL_FLOAT, false, VERT_SIZE, OFFSET_NOR);
-     GLES31.glVertexAttribPointer(program.mAttribute[2], INF_DATA_SIZE, GLES31.GL_FLOAT, false, VERT_SIZE, OFFSET_INF);
-     GLES31.glVertexAttribPointer(program.mAttribute[3], TEX_DATA_SIZE, GLES31.GL_FLOAT, false, VERT_SIZE, OFFSET_TEX);
-     GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, 0);
+     GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, index );
+     GLES30.glVertexAttribPointer(program.mAttribute[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, VERT_SIZE, OFFSET_POS);
+     GLES30.glVertexAttribPointer(program.mAttribute[1], NOR_DATA_SIZE, GLES30.GL_FLOAT, false, VERT_SIZE, OFFSET_NOR);
+     GLES30.glVertexAttribPointer(program.mAttribute[2], INF_DATA_SIZE, GLES30.GL_FLOAT, false, VERT_SIZE, OFFSET_INF);
+     GLES30.glVertexAttribPointer(program.mAttribute[3], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, VERT_SIZE, OFFSET_TEX);
+     GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -326,9 +325,9 @@ public abstract class MeshBase
      {
      int index = mTFO.createImmediately(mNumVertices*TRAN_SIZE, null);
 
-     GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, index );
-     GLES31.glVertexAttribPointer(program.mAttribute[0], POS_DATA_SIZE, GLES31.GL_FLOAT, false, 0, 0);
-     GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, 0);
+     GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, index );
+     GLES30.glVertexAttribPointer(program.mAttribute[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, 0);
+     GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -365,7 +364,7 @@ public abstract class MeshBase
  */
    public void setShowNormals(boolean show)
      {
-     mShowNormals = (DistortedLibrary.GLSL >= 300 && show);
+     mShowNormals = show;
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/program/DistortedProgram.java b/src/main/java/org/distorted/library/program/DistortedProgram.java
index e876216..0d4f1cd 100644
--- a/src/main/java/org/distorted/library/program/DistortedProgram.java
+++ b/src/main/java/org/distorted/library/program/DistortedProgram.java
@@ -19,7 +19,7 @@
 
 package org.distorted.library.program;
 
-import android.opengl.GLES31;
+import android.opengl.GLES30;
 
 import java.io.BufferedReader;
 import java.io.IOException;
@@ -54,16 +54,16 @@ public class DistortedProgram
   private int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes, final String[] feedbackVaryings)
   throws LinkingException
     {
-    int programHandle = GLES31.glCreateProgram();
+    int programHandle = GLES30.glCreateProgram();
 
     if (programHandle != 0)
       {
-      GLES31.glAttachShader(programHandle, vertexShaderHandle);
-      GLES31.glAttachShader(programHandle, fragmentShaderHandle);
+      GLES30.glAttachShader(programHandle, vertexShaderHandle);
+      GLES30.glAttachShader(programHandle, fragmentShaderHandle);
 
       if( feedbackVaryings!=null )
         {
-        GLES31.glTransformFeedbackVaryings(programHandle, feedbackVaryings, GLES31.GL_INTERLEAVED_ATTRIBS);
+        GLES30.glTransformFeedbackVaryings(programHandle, feedbackVaryings, GLES30.GL_INTERLEAVED_ATTRIBS);
         }
 
       if (attributes != null)
@@ -72,24 +72,24 @@ public class DistortedProgram
 
         for (int i = 0; i < size; i++)
           {
-          GLES31.glBindAttribLocation(programHandle, i, attributes[i]);
+          GLES30.glBindAttribLocation(programHandle, i, attributes[i]);
           }
         }
 
-      GLES31.glLinkProgram(programHandle);
+      GLES30.glLinkProgram(programHandle);
 
       final int[] linkStatus = new int[1];
-      GLES31.glGetProgramiv(programHandle, GLES31.GL_LINK_STATUS, linkStatus, 0);
+      GLES30.glGetProgramiv(programHandle, GLES30.GL_LINK_STATUS, linkStatus, 0);
 
-      if (linkStatus[0] != GLES31.GL_TRUE )
+      if (linkStatus[0] != GLES30.GL_TRUE )
         {
-        String error = GLES31.glGetProgramInfoLog(programHandle);
-        GLES31.glDeleteProgram(programHandle);
+        String error = GLES30.glGetProgramInfoLog(programHandle);
+        GLES30.glDeleteProgram(programHandle);
         throw new LinkingException(error);
         }
 
       final int[] numberOfUniforms = new int[1];
-      GLES31.glGetProgramiv(programHandle, GLES31.GL_ACTIVE_UNIFORMS, numberOfUniforms, 0);
+      GLES30.glGetProgramiv(programHandle, GLES30.GL_ACTIVE_UNIFORMS, numberOfUniforms, 0);
 
       //android.util.Log.d("program", "number of active uniforms="+numberOfUniforms[0]);
       }
@@ -283,27 +283,25 @@ public class DistortedProgram
   private static int compileShader(final int shaderType, final String shaderSource)
   throws FragmentCompilationException,VertexCompilationException
     {
-    int shaderHandle = GLES31.glCreateShader(shaderType);
+    int shaderHandle = GLES30.glCreateShader(shaderType);
 
     if (shaderHandle != 0)
       {
-      GLES31.glShaderSource(shaderHandle, shaderSource);
-      GLES31.glCompileShader(shaderHandle);
+      GLES30.glShaderSource(shaderHandle, shaderSource);
+      GLES30.glCompileShader(shaderHandle);
       final int[] compileStatus = new int[1];
-      GLES31.glGetShaderiv(shaderHandle, GLES31.GL_COMPILE_STATUS, compileStatus, 0);
+      GLES30.glGetShaderiv(shaderHandle, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
 
-      if (compileStatus[0] != GLES31.GL_TRUE)
+      if (compileStatus[0] != GLES30.GL_TRUE)
         {
-        String error = GLES31.glGetShaderInfoLog(shaderHandle);
+        String error = GLES30.glGetShaderInfoLog(shaderHandle);
 
-        //android.util.Log.e("Program", "error compiling :" + error);
-
-        GLES31.glDeleteShader(shaderHandle);
+        GLES30.glDeleteShader(shaderHandle);
 
         switch (shaderType)
           {
-          case GLES31.GL_VERTEX_SHADER:   throw new VertexCompilationException(error);
-          case GLES31.GL_FRAGMENT_SHADER: throw new FragmentCompilationException(error);
+          case GLES30.GL_VERTEX_SHADER:   throw new VertexCompilationException(error);
+          case GLES30.GL_FRAGMENT_SHADER: throw new FragmentCompilationException(error);
           default:                        throw new RuntimeException(error);
           }
         }
@@ -357,8 +355,8 @@ android.util.Log.d("Program", end.substring(0,40));
     final String vertShader = readTextFileFromRawResource(vert, true );
     final String fragShader = readTextFileFromRawResource(frag, false);
 
-    final int vertShaderHandle = compileShader(GLES31.GL_VERTEX_SHADER  , vertHeader + vertShader);
-    final int fragShaderHandle = compileShader(GLES31.GL_FRAGMENT_SHADER, fragHeader + fragShader);
+    final int vertShaderHandle = compileShader(GLES30.GL_VERTEX_SHADER  , vertHeader + vertShader);
+    final int fragShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragHeader + fragShader);
 
     mProgramHandle = createAndLinkProgram(vertShaderHandle, fragShaderHandle, mAttributeName, glslVersion>= 300 ? feedback:null );
 
@@ -366,7 +364,7 @@ android.util.Log.d("Program", end.substring(0,40));
 
     for(int i=0; i<mNumAttributes; i++)
       {
-      mAttribute[i] = GLES31.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
+      mAttribute[i] = GLES30.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
       }
 
     if( mNumUniforms>0 )
@@ -376,7 +374,7 @@ android.util.Log.d("Program", end.substring(0,40));
 
       for(int i=0; i<mNumUniforms; i++)
         {
-        mUniform[i] = GLES31.glGetUniformLocation( mProgramHandle, mUniformName[i]);
+        mUniform[i] = GLES30.glGetUniformLocation( mProgramHandle, mUniformName[i]);
         }
       }
     else mUniform = null;
@@ -400,8 +398,8 @@ android.util.Log.d("Program", end.substring(0,40));
     if( enabledVert!=null ) vertShader = insertEnabledEffects(vertShader,enabledVert);
     if( enabledFrag!=null ) fragShader = insertEnabledEffects(fragShader,enabledFrag);
 
-    final int vertShaderHandle = compileShader(GLES31.GL_VERTEX_SHADER  , vertHeader + vertShader);
-    final int fragShaderHandle = compileShader(GLES31.GL_FRAGMENT_SHADER, fragHeader + fragShader);
+    final int vertShaderHandle = compileShader(GLES30.GL_VERTEX_SHADER  , vertHeader + vertShader);
+    final int fragShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragHeader + fragShader);
 
     mProgramHandle = createAndLinkProgram(vertShaderHandle, fragShaderHandle, mAttributeName, glslVersion>= 300 ? feedback:null );
 
@@ -409,7 +407,7 @@ android.util.Log.d("Program", end.substring(0,40));
 
     for(int i=0; i<mNumAttributes; i++)
       {
-      mAttribute[i] = GLES31.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
+      mAttribute[i] = GLES30.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
       }
 
     if( mNumUniforms>0 )
@@ -419,7 +417,7 @@ android.util.Log.d("Program", end.substring(0,40));
 
       for(int i=0; i<mNumUniforms; i++)
         {
-        mUniform[i] = GLES31.glGetUniformLocation( mProgramHandle, mUniformName[i]);
+        mUniform[i] = GLES30.glGetUniformLocation( mProgramHandle, mUniformName[i]);
         }
       }
     else mUniform = null;
@@ -461,8 +459,8 @@ android.util.Log.d("Program", end.substring(0,40));
     doAttributes(vertex  , true );
     doAttributes(fragment, false);
 
-    final int vertexShaderHandle   = compileShader(GLES31.GL_VERTEX_SHADER  , vertex  );
-    final int fragmentShaderHandle = compileShader(GLES31.GL_FRAGMENT_SHADER, fragment);
+    final int vertexShaderHandle   = compileShader(GLES30.GL_VERTEX_SHADER  , vertex  );
+    final int fragmentShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragment);
 
     mProgramHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, mAttributeName, null );
 
@@ -470,7 +468,7 @@ android.util.Log.d("Program", end.substring(0,40));
 
     for(int i=0; i<mNumAttributes; i++)
       {
-      mAttribute[i] = GLES31.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
+      mAttribute[i] = GLES30.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
       }
 
     if( mNumUniforms>0 )
@@ -480,7 +478,7 @@ android.util.Log.d("Program", end.substring(0,40));
 
       for(int i=0; i<mNumUniforms; i++)
         {
-        mUniform[i] = GLES31.glGetUniformLocation( mProgramHandle, mUniformName[i]);
+        mUniform[i] = GLES30.glGetUniformLocation( mProgramHandle, mUniformName[i]);
         }
       }
     else mUniform = null;
@@ -503,10 +501,10 @@ android.util.Log.d("Program", end.substring(0,40));
  */
   public void useProgram()
     {
-    GLES31.glUseProgram(mProgramHandle);
+    GLES30.glUseProgram(mProgramHandle);
 
     for(int i=0; i<mNumAttributes; i++)
-      GLES31.glEnableVertexAttribArray(mAttribute[i]);
+      GLES30.glEnableVertexAttribArray(mAttribute[i]);
     }
   }
 
