commit 194ab46fef9f6017f8693fc925d7cc93e13f059c
Author: Leszek Koltunski <leszek@distorted.org>
Date:   Fri Jan 20 23:50:25 2017 +0000

    Try using OpenGL ES 3.0 everywhere (but if device does not support it, try creating 2.0 context - this is important because of the emulator!)

diff --git a/src/main/java/org/distorted/library/Distorted.java b/src/main/java/org/distorted/library/Distorted.java
index 873cd35..0b602a1 100644
--- a/src/main/java/org/distorted/library/Distorted.java
+++ b/src/main/java/org/distorted/library/Distorted.java
@@ -21,7 +21,7 @@ package org.distorted.library;
 
 import android.content.Context;
 import android.content.res.Resources;
-import android.opengl.GLES20;
+import android.opengl.GLES30;
 import org.distorted.library.program.*;
 
 import java.io.InputStream;
@@ -113,12 +113,12 @@ public class Distorted
     {
     final Resources resources = context.getResources();
 
-    GLES20.glDepthFunc(GLES20.GL_LEQUAL);
-    GLES20.glEnable(GLES20.GL_BLEND);
-    GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
-    GLES20.glEnable(GLES20.GL_CULL_FACE);
-    GLES20.glCullFace(GLES20.GL_BACK);
-    GLES20.glFrontFace(GLES20.GL_CW);
+    GLES30.glDepthFunc(GLES30.GL_LEQUAL);
+    GLES30.glEnable(GLES30.GL_BLEND);
+    GLES30.glBlendFunc(GLES30.GL_SRC_ALPHA, GLES30.GL_ONE_MINUS_SRC_ALPHA);
+    GLES30.glEnable(GLES30.GL_CULL_FACE);
+    GLES30.glCullFace(GLES30.GL_BACK);
+    GLES30.glFrontFace(GLES30.GL_CW);
 
     DistortedEffects.createProgram(resources);
     EffectQueuePostprocess.createProgram(resources);
diff --git a/src/main/java/org/distorted/library/DistortedEffects.java b/src/main/java/org/distorted/library/DistortedEffects.java
index 1275ecc..7214928 100644
--- a/src/main/java/org/distorted/library/DistortedEffects.java
+++ b/src/main/java/org/distorted/library/DistortedEffects.java
@@ -20,7 +20,7 @@
 package org.distorted.library;
 
 import android.content.res.Resources;
-import android.opengl.GLES20;
+import android.opengl.GLES30;
 import android.opengl.Matrix;
 
 import org.distorted.library.message.EffectListener;
@@ -125,8 +125,8 @@ public class DistortedEffects
     mDebugProgram = new DistortedProgram(debugVertexStream,debugFragmentStream, "#version 100\n", "#version 100\n");
 
     int debugProgramH = mDebugProgram.getProgramHandle();
-    mObjDH      = GLES20.glGetUniformLocation( debugProgramH, "u_objD");
-    mMVPMatrixH = GLES20.glGetUniformLocation( debugProgramH, "u_MVPMatrix");
+    mObjDH      = GLES30.glGetUniformLocation( debugProgramH, "u_objD");
+    mMVPMatrixH = GLES30.glGetUniformLocation( debugProgramH, "u_MVPMatrix");
     // END DEBUG  //////////////////////////////////////
     }
 
@@ -225,11 +225,11 @@ public class DistortedEffects
     Matrix.translateM  ( mTmpMatrix, 0, halfX,-halfY, 0);
     Matrix.multiplyMM  ( mMVPMatrix, 0, df.mProjectionMatrix, 0, mTmpMatrix, 0);
 
-    GLES20.glUniform2f( mObjDH , 2*halfX, 2*halfY);
-    GLES20.glUniformMatrix4fv(mMVPMatrixH, 1, false, mMVPMatrix , 0);
+    GLES30.glUniform2f( mObjDH , 2*halfX, 2*halfY);
+    GLES30.glUniformMatrix4fv(mMVPMatrixH, 1, false, mMVPMatrix , 0);
 
-    GLES20.glVertexAttribPointer(mDebugProgram.mAttribute[0], 2, GLES20.GL_FLOAT, false, 0, mQuadPositions);
-    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+    GLES30.glVertexAttribPointer(mDebugProgram.mAttribute[0], 2, GLES30.GL_FLOAT, false, 0, mQuadPositions);
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -242,7 +242,7 @@ public class DistortedEffects
     mP.compute(currTime);
 
     float halfZ = halfInputW*mesh.zFactor;
-    GLES20.glViewport(0, 0, df.mWidth, df.mHeight);
+    GLES30.glViewport(0, 0, df.mWidth, df.mHeight);
 
     if( mP.mNumEffects==0 )
       {
@@ -251,10 +251,10 @@ public class DistortedEffects
       mM.send(df,halfInputW,halfInputH,halfZ);
       mV.send(halfInputW,halfInputH,halfZ);
       mF.send(halfInputW,halfInputH);
-      GLES20.glVertexAttribPointer(mProgram.mAttribute[0], POSITION_DATA_SIZE, GLES20.GL_FLOAT, false, 0, mesh.mMeshPositions);
-      GLES20.glVertexAttribPointer(mProgram.mAttribute[1], NORMAL_DATA_SIZE  , GLES20.GL_FLOAT, false, 0, mesh.mMeshNormals);
-      GLES20.glVertexAttribPointer(mProgram.mAttribute[2], TEX_DATA_SIZE     , GLES20.GL_FLOAT, false, 0, mesh.mMeshTexture);
-      GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, mesh.dataLength);
+      GLES30.glVertexAttribPointer(mProgram.mAttribute[0], POSITION_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mesh.mMeshPositions);
+      GLES30.glVertexAttribPointer(mProgram.mAttribute[1], NORMAL_DATA_SIZE  , GLES30.GL_FLOAT, false, 0, mesh.mMeshNormals);
+      GLES30.glVertexAttribPointer(mProgram.mAttribute[2], TEX_DATA_SIZE     , GLES30.GL_FLOAT, false, 0, mesh.mMeshTexture);
+      GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mesh.dataLength);
       }
     else
       {
@@ -268,15 +268,15 @@ public class DistortedEffects
         mProgram.useProgram();
         mBufferFBO.resizeFast(df.mWidth, df.mHeight);
         mBufferFBO.setAsOutput();
-        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-        GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
+        GLES30.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+        GLES30.glClear( GLES30.GL_DEPTH_BUFFER_BIT | GLES30.GL_COLOR_BUFFER_BIT);
         mM.send(mBufferFBO,halfInputW,halfInputH,halfZ);
         mV.send(halfInputW,halfInputH,halfZ);
         mF.send(halfInputW,halfInputH);
-        GLES20.glVertexAttribPointer(mProgram.mAttribute[0], POSITION_DATA_SIZE, GLES20.GL_FLOAT, false, 0, mesh.mMeshPositions);
-        GLES20.glVertexAttribPointer(mProgram.mAttribute[1], NORMAL_DATA_SIZE  , GLES20.GL_FLOAT, false, 0, mesh.mMeshNormals);
-        GLES20.glVertexAttribPointer(mProgram.mAttribute[2], TEX_DATA_SIZE     , GLES20.GL_FLOAT, false, 0, mesh.mMeshTexture);
-        GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, mesh.dataLength);
+        GLES30.glVertexAttribPointer(mProgram.mAttribute[0], POSITION_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mesh.mMeshPositions);
+        GLES30.glVertexAttribPointer(mProgram.mAttribute[1], NORMAL_DATA_SIZE  , GLES30.GL_FLOAT, false, 0, mesh.mMeshNormals);
+        GLES30.glVertexAttribPointer(mProgram.mAttribute[2], TEX_DATA_SIZE     , GLES30.GL_FLOAT, false, 0, mesh.mMeshTexture);
+        GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mesh.dataLength);
 
         Matrix.setIdentityM(mTmpMatrix, 0);
         Matrix.translateM(mTmpMatrix, 0, 0, 0, -df.mDistance);
@@ -296,7 +296,7 @@ public class DistortedEffects
    
   static void drawNoEffectsPriv(float halfInputW, float halfInputH, MeshObject mesh, DistortedFramebuffer df)
     {
-    GLES20.glViewport(0, 0, df.mWidth, df.mHeight);
+    GLES30.glViewport(0, 0, df.mWidth, df.mHeight);
 
     Matrix.setIdentityM(mTmpMatrix, 0);
     Matrix.translateM(mTmpMatrix, 0, 0, 0, -df.mDistance);
@@ -307,10 +307,10 @@ public class DistortedEffects
     EffectQueueFragment.sendZero();
     EffectQueuePostprocess.sendZero(df.mWidth, df.mHeight, mMVPMatrix);
 
-    GLES20.glVertexAttribPointer(mProgram.mAttribute[0], POSITION_DATA_SIZE, GLES20.GL_FLOAT, false, 0, mesh.mMeshPositions);
-    GLES20.glVertexAttribPointer(mProgram.mAttribute[1], NORMAL_DATA_SIZE  , GLES20.GL_FLOAT, false, 0, mesh.mMeshNormals);
-    GLES20.glVertexAttribPointer(mProgram.mAttribute[2], TEX_DATA_SIZE     , GLES20.GL_FLOAT, false, 0, mesh.mMeshTexture);
-    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, mesh.dataLength);
+    GLES30.glVertexAttribPointer(mProgram.mAttribute[0], POSITION_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mesh.mMeshPositions);
+    GLES30.glVertexAttribPointer(mProgram.mAttribute[1], NORMAL_DATA_SIZE  , GLES30.GL_FLOAT, false, 0, mesh.mMeshNormals);
+    GLES30.glVertexAttribPointer(mProgram.mAttribute[2], TEX_DATA_SIZE     , GLES30.GL_FLOAT, false, 0, mesh.mMeshTexture);
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mesh.dataLength);
     }
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/DistortedFramebuffer.java b/src/main/java/org/distorted/library/DistortedFramebuffer.java
index fe11f58..b110a07 100644
--- a/src/main/java/org/distorted/library/DistortedFramebuffer.java
+++ b/src/main/java/org/distorted/library/DistortedFramebuffer.java
@@ -19,7 +19,7 @@
 
 package org.distorted.library;
 
-import android.opengl.GLES20;
+import android.opengl.GLES30;
 import android.opengl.Matrix;
 
 import java.util.Iterator;
@@ -70,38 +70,38 @@ public class DistortedFramebuffer
     {
     if( colorIds[0]==NOT_CREATED_YET )
       {
-      GLES20.glGenTextures(1, colorIds, 0);
-      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, colorIds[0]);
-      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
-      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
-      GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
-      GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
-      GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, mTexWidth, mTexHeight, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
-
-      GLES20.glGenFramebuffers(1, fboIds, 0);
-      GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboIds[0]);
-      GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, colorIds[0], 0);
+      GLES30.glGenTextures(1, colorIds, 0);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, colorIds[0]);
+      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, mTexWidth, mTexHeight, 0, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, null);
+
+      GLES30.glGenFramebuffers(1, fboIds, 0);
+      GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fboIds[0]);
+      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_COLOR_ATTACHMENT0, GLES30.GL_TEXTURE_2D, colorIds[0], 0);
 
       checkStatus("color");
       }
     if( mDepthWanted && depthIds[0]==NOT_CREATED_YET ) // we need to create a new DEPTH attachment
       {
-      GLES20.glGenTextures(1, depthIds, 0);
-      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, depthIds[0]);
-      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
-      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
-      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
-      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
-      GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_DEPTH_COMPONENT, mTexWidth, mTexHeight, 0, GLES20.GL_DEPTH_COMPONENT, GLES20.GL_UNSIGNED_SHORT, null);
+      GLES30.glGenTextures(1, depthIds, 0);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, depthIds[0]);
+      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);
+      GLES30.glTexImage2D(GLES30.GL_TEXTURE_2D, 0, GLES30.GL_DEPTH_COMPONENT, mTexWidth, mTexHeight, 0, GLES30.GL_DEPTH_COMPONENT, GLES30.GL_UNSIGNED_SHORT, null);
 
-      GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboIds[0]);
-      GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_TEXTURE_2D, depthIds[0], 0);
+      GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fboIds[0]);
+      GLES30.glFramebufferTexture2D(GLES30.GL_FRAMEBUFFER, GLES30.GL_DEPTH_ATTACHMENT, GLES30.GL_TEXTURE_2D, depthIds[0], 0);
 
       checkStatus("depth");
       }
     if( !mDepthWanted && depthIds[0]!=NOT_CREATED_YET ) // we need to detach and destroy the DEPTH attachment.
       {
-      GLES20.glDeleteTextures(1, depthIds, 0);
+      GLES30.glDeleteTextures(1, depthIds, 0);
       depthIds[0]=NOT_CREATED_YET;
       }
     }
@@ -110,15 +110,15 @@ public class DistortedFramebuffer
 
   private boolean checkStatus(String message)
     {
-    int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
+    int status = GLES30.glCheckFramebufferStatus(GLES30.GL_FRAMEBUFFER);
 
-    if(status != GLES20.GL_FRAMEBUFFER_COMPLETE)
+    if(status != GLES30.GL_FRAMEBUFFER_COMPLETE)
       {
       android.util.Log.e("DistortedFramebuffer", "FRAMEBUFFER INCOMPLETE, "+message+" error="+status);
 
-      GLES20.glDeleteTextures(1, colorIds, 0);
-      GLES20.glDeleteTextures(1, depthIds, 0);
-      GLES20.glDeleteFramebuffers(1, fboIds, 0);
+      GLES30.glDeleteTextures(1, colorIds, 0);
+      GLES30.glDeleteTextures(1, depthIds, 0);
+      GLES30.glDeleteFramebuffers(1, fboIds, 0);
       fboIds[0]   = 0;
       colorIds[0] = FAILED_TO_CREATE;
       depthIds[0] = FAILED_TO_CREATE;
@@ -140,14 +140,14 @@ public class DistortedFramebuffer
 
       if( depthIds[0]>=0 )
         {
-        GLES20.glDeleteTextures(1, depthIds, 0);
+        GLES30.glDeleteTextures(1, depthIds, 0);
         depthIds[0]=NOT_CREATED_YET;
         }
 
-      GLES20.glDeleteTextures(1, colorIds, 0);
+      GLES30.glDeleteTextures(1, colorIds, 0);
       colorIds[0] = NOT_CREATED_YET;
 
-      GLES20.glDeleteFramebuffers(1, fboIds, 0);
+      GLES30.glDeleteFramebuffers(1, fboIds, 0);
       fboIds[0] = 0;
       }
 
@@ -158,17 +158,17 @@ public class DistortedFramebuffer
 
   void setAsOutput()
     {
-    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboIds[0]);
+    GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, fboIds[0]);
 
     if( depthIds[0]!=NOT_CREATED_YET )
       {
-      GLES20.glEnable(GLES20.GL_DEPTH_TEST);
-      GLES20.glDepthMask(true);
+      GLES30.glEnable(GLES30.GL_DEPTH_TEST);
+      GLES30.glDepthMask(true);
       }
     else
       {
-      GLES20.glDisable(GLES20.GL_DEPTH_TEST);
-      GLES20.glDepthMask(false);
+      GLES30.glDisable(GLES30.GL_DEPTH_TEST);
+      GLES30.glDepthMask(false);
       }
     }
 
@@ -176,7 +176,7 @@ public class DistortedFramebuffer
 
   void setAsInput()
     {
-    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, colorIds[0]);
+    GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, colorIds[0]);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -388,7 +388,7 @@ public class DistortedFramebuffer
       DistortedFramebuffer.deleteAllMarked();
       DistortedTexture.deleteAllMarked();
       createFBO();
-      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fbo.colorIds[0]);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, fbo.colorIds[0]);
       effects.drawPriv(fbo.mWidth/2, fbo.mHeight/2, mesh, this, time);
       }
     }
diff --git a/src/main/java/org/distorted/library/DistortedTexture.java b/src/main/java/org/distorted/library/DistortedTexture.java
index bfa1154..f63d751 100644
--- a/src/main/java/org/distorted/library/DistortedTexture.java
+++ b/src/main/java/org/distorted/library/DistortedTexture.java
@@ -21,7 +21,7 @@ package org.distorted.library;
 
 import android.graphics.Bitmap;
 import android.graphics.Matrix;
-import android.opengl.GLES20;
+import android.opengl.GLES30;
 import android.opengl.GLUtils;
 
 import java.util.Iterator;
@@ -84,18 +84,18 @@ public class DistortedTexture
 
       if( mTextureDataH[0]==0 )
         {
-        GLES20.glGenTextures(1, mTextureDataH, 0);
-        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataH[0]);
-        GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR );
-        GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR );
-        GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE );
-        GLES20.glTexParameteri ( GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE );
-        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, flipBitmap(mBmp), 0);
+        GLES30.glGenTextures(1, mTextureDataH, 0);
+        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureDataH[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
         {
-        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataH[0]);
-        GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0,0,0,flipBitmap(mBmp));
+        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureDataH[0]);
+        GLUtils.texSubImage2D(GLES30.GL_TEXTURE_2D, 0,0,0,flipBitmap(mBmp));
         }
 
       mBmp = null;
@@ -111,7 +111,7 @@ public class DistortedTexture
       {
       //android.util.Log.e("Texture", "deleting "+mID);
 
-      GLES20.glDeleteTextures(1, mTextureDataH, 0);
+      GLES30.glDeleteTextures(1, mTextureDataH, 0);
 
       mTextureDataH[0] = 0;
       mBitmapSet= false;
@@ -133,7 +133,7 @@ public class DistortedTexture
     {
     if( mBitmapSet )
       {
-      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataH[0]);
+      GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureDataH[0]);
       return true;
       }
 
@@ -144,10 +144,10 @@ public class DistortedTexture
 
   static void getUniforms(int mProgramH)
     {
-    mTextureH= GLES20.glGetUniformLocation( mProgramH, "u_Texture");
+    mTextureH= GLES30.glGetUniformLocation( mProgramH, "u_Texture");
 
-    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
-    GLES20.glUniform1i(mTextureH, 0);
+    GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
+    GLES30.glUniform1i(mTextureH, 0);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/DistortedTree.java b/src/main/java/org/distorted/library/DistortedTree.java
index 4b16f0d..d5953eb 100644
--- a/src/main/java/org/distorted/library/DistortedTree.java
+++ b/src/main/java/org/distorted/library/DistortedTree.java
@@ -22,7 +22,7 @@ package org.distorted.library;
 import java.util.ArrayList;
 import java.util.HashMap;
 
-import android.opengl.GLES20;
+import android.opengl.GLES30;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -214,8 +214,8 @@ public class DistortedTree
         {
         mData.mFBO.setAsOutput();
 
-        GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
-        GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
+        GLES30.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+        GLES30.glClear( GLES30.GL_DEPTH_BUFFER_BIT | GLES30.GL_COLOR_BUFFER_BIT);
 
         if( mTexture.setAsInput() )
           DistortedEffects.drawNoEffectsPriv(mTexture.mHalfX, mTexture.mHalfY, mMesh, mData.mFBO);
diff --git a/src/main/java/org/distorted/library/EffectQueueFragment.java b/src/main/java/org/distorted/library/EffectQueueFragment.java
index 86e1b0f..7472eba 100644
--- a/src/main/java/org/distorted/library/EffectQueueFragment.java
+++ b/src/main/java/org/distorted/library/EffectQueueFragment.java
@@ -19,7 +19,7 @@
 
 package org.distorted.library;
 
-import android.opengl.GLES20;
+import android.opengl.GLES30;
 
 import org.distorted.library.message.EffectMessage;
 import org.distorted.library.type.Data1D;
@@ -54,9 +54,9 @@ class EffectQueueFragment extends EffectQueue
 
   static void getUniforms(int mProgramH)
     {
-    mNumEffectsH= GLES20.glGetUniformLocation( mProgramH, "fNumEffects");
-    mTypeH      = GLES20.glGetUniformLocation( mProgramH, "fType");
-    mUniformsH  = GLES20.glGetUniformLocation( mProgramH, "fUniforms");
+    mNumEffectsH= GLES30.glGetUniformLocation( mProgramH, "fNumEffects");
+    mTypeH      = GLES30.glGetUniformLocation( mProgramH, "fType");
+    mUniformsH  = GLES30.glGetUniformLocation( mProgramH, "fUniforms");
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -115,7 +115,7 @@ class EffectQueueFragment extends EffectQueue
   
   synchronized void send(float halfX, float halfY)
     {
-    GLES20.glUniform1i( mNumEffectsH, mNumEffects);
+    GLES30.glUniform1i( mNumEffectsH, mNumEffects);
 
     if( mNumEffects>0 )
       {
@@ -127,8 +127,8 @@ class EffectQueueFragment extends EffectQueue
         mUniforms[NUM_UNIFORMS*i+7] = mCache[NUM_CACHE*i+3];
         }
 
-      GLES20.glUniform1iv( mTypeH    ,                 mNumEffects, mName    ,0);
-      GLES20.glUniform4fv( mUniformsH,(NUM_UNIFORMS/4)*mNumEffects, mUniforms,0);
+      GLES30.glUniform1iv( mTypeH    ,                 mNumEffects, mName    ,0);
+      GLES30.glUniform4fv( mUniformsH,(NUM_UNIFORMS/4)*mNumEffects, mUniforms,0);
       }  
     }
 
@@ -136,7 +136,7 @@ class EffectQueueFragment extends EffectQueue
 
   synchronized static void sendZero()
     {
-    GLES20.glUniform1i( mNumEffectsH, 0);
+    GLES30.glUniform1i( mNumEffectsH, 0);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/EffectQueueMatrix.java b/src/main/java/org/distorted/library/EffectQueueMatrix.java
index b320c86..8370438 100644
--- a/src/main/java/org/distorted/library/EffectQueueMatrix.java
+++ b/src/main/java/org/distorted/library/EffectQueueMatrix.java
@@ -19,7 +19,7 @@
 
 package org.distorted.library;
 
-import android.opengl.GLES20;
+import android.opengl.GLES30;
 import android.opengl.Matrix;
 
 import org.distorted.library.message.EffectMessage;
@@ -191,10 +191,10 @@ class EffectQueueMatrix extends EffectQueue
 
   static void getUniforms(int mProgramH)
     {
-    mObjDH     = GLES20.glGetUniformLocation(mProgramH, "u_objD");
-    mDepthH    = GLES20.glGetUniformLocation(mProgramH, "u_Depth");
-    mMVPMatrixH= GLES20.glGetUniformLocation(mProgramH, "u_MVPMatrix");
-    mMVMatrixH = GLES20.glGetUniformLocation(mProgramH, "u_MVMatrix"); 
+    mObjDH     = GLES30.glGetUniformLocation(mProgramH, "u_objD");
+    mDepthH    = GLES30.glGetUniformLocation(mProgramH, "u_Depth");
+    mMVPMatrixH= GLES30.glGetUniformLocation(mProgramH, "u_MVPMatrix");
+    mMVMatrixH = GLES30.glGetUniformLocation(mProgramH, "u_MVMatrix"); 
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -288,10 +288,10 @@ class EffectQueueMatrix extends EffectQueue
     {
     constructMatrices(df,halfX,halfY);
 
-    GLES20.glUniform3f( mObjDH , halfX, halfY, halfZ);
-    GLES20.glUniform1f( mDepthH, df.mDepth);
-    GLES20.glUniformMatrix4fv(mMVMatrixH , 1, false, mViewMatrix, 0);
-    GLES20.glUniformMatrix4fv(mMVPMatrixH, 1, false, mMVPMatrix , 0);
+    GLES30.glUniform3f( mObjDH , halfX, halfY, halfZ);
+    GLES30.glUniform1f( mDepthH, df.mDepth);
+    GLES30.glUniformMatrix4fv(mMVMatrixH , 1, false, mViewMatrix, 0);
+    GLES30.glUniformMatrix4fv(mMVPMatrixH, 1, false, mMVPMatrix , 0);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -303,10 +303,10 @@ class EffectQueueMatrix extends EffectQueue
     Matrix.translateM(mTmpMatrix, 0, halfX-df.mWidth/2, df.mHeight/2-halfY, -df.mDistance);
     Matrix.multiplyMM(mMVPMatrix, 0, df.mProjectionMatrix, 0, mTmpMatrix, 0);
     
-    GLES20.glUniform3f( mObjDH , halfX, halfY, halfZ);
-    GLES20.glUniform1f( mDepthH, df.mDepth);
-    GLES20.glUniformMatrix4fv(mMVMatrixH , 1, false, mTmpMatrix, 0);
-    GLES20.glUniformMatrix4fv(mMVPMatrixH, 1, false, mMVPMatrix, 0);
+    GLES30.glUniform3f( mObjDH , halfX, halfY, halfZ);
+    GLES30.glUniform1f( mDepthH, df.mDepth);
+    GLES30.glUniformMatrix4fv(mMVMatrixH , 1, false, mTmpMatrix, 0);
+    GLES30.glUniformMatrix4fv(mMVPMatrixH, 1, false, mMVPMatrix, 0);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/EffectQueuePostprocess.java b/src/main/java/org/distorted/library/EffectQueuePostprocess.java
index ce45403..250f9ee 100644
--- a/src/main/java/org/distorted/library/EffectQueuePostprocess.java
+++ b/src/main/java/org/distorted/library/EffectQueuePostprocess.java
@@ -20,7 +20,7 @@
 package org.distorted.library;
 
 import android.content.res.Resources;
-import android.opengl.GLES20;
+import android.opengl.GLES30;
 
 import org.distorted.library.message.EffectMessage;
 import org.distorted.library.program.DistortedProgram;
@@ -105,11 +105,11 @@ class EffectQueuePostprocess extends EffectQueue
 
   private static void getUniforms(int mProgramH)
     {
-    mNumEffectsH= GLES20.glGetUniformLocation( mProgramH, "pNumEffects");
-    mTypeH      = GLES20.glGetUniformLocation( mProgramH, "pType");
-    mUniformsH  = GLES20.glGetUniformLocation( mProgramH, "pUniforms");
-    mObjDH      = GLES20.glGetUniformLocation( mProgramH, "u_objD");
-    mMVPMatrixH = GLES20.glGetUniformLocation(mProgramH, "u_MVPMatrix");
+    mNumEffectsH= GLES30.glGetUniformLocation( mProgramH, "pNumEffects");
+    mTypeH      = GLES30.glGetUniformLocation( mProgramH, "pType");
+    mUniformsH  = GLES30.glGetUniformLocation( mProgramH, "pUniforms");
+    mObjDH      = GLES30.glGetUniformLocation( mProgramH, "u_objD");
+    mMVPMatrixH = GLES30.glGetUniformLocation(mProgramH, "u_MVPMatrix");
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -160,9 +160,9 @@ class EffectQueuePostprocess extends EffectQueue
 
   synchronized static void sendZero(float w, float h, float[] mvp)
     {
-    GLES20.glUniform1i( mNumEffectsH, 0);
-    GLES20.glUniform2f( mObjDH , w, h);
-    GLES20.glUniformMatrix4fv(mMVPMatrixH, 1, false, mvp , 0);
+    GLES30.glUniform1i( mNumEffectsH, 0);
+    GLES30.glUniform2f( mObjDH , w, h);
+    GLES30.glUniformMatrix4fv(mMVPMatrixH, 1, false, mvp , 0);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -174,19 +174,19 @@ class EffectQueuePostprocess extends EffectQueue
     mProgram.useProgram();
     df.setAsOutput();
 
-    GLES20.glUniform1i( mNumEffectsH, mNumEffects);
-    GLES20.glUniform2f( mObjDH , w, h );
-    GLES20.glUniformMatrix4fv(mMVPMatrixH, 1, false, mvp , 0);
+    GLES30.glUniform1i( mNumEffectsH, mNumEffects);
+    GLES30.glUniform2f( mObjDH , w, h );
+    GLES30.glUniformMatrix4fv(mMVPMatrixH, 1, false, mvp , 0);
 
     if( mNumEffects>0 )
       {
-      GLES20.glUniform1iv( mTypeH    ,                  mNumEffects, mName    ,0);
-      GLES20.glUniform4fv( mUniformsH, (NUM_UNIFORMS/4)*mNumEffects, mUniforms,0);
+      GLES30.glUniform1iv( mTypeH    ,                  mNumEffects, mName    ,0);
+      GLES30.glUniform4fv( mUniformsH, (NUM_UNIFORMS/4)*mNumEffects, mUniforms,0);
       }
 
-    GLES20.glVertexAttribPointer(mProgram.mAttribute[0], POSITION_DATA_SIZE, GLES20.GL_FLOAT, false, 0, mQuadPositions);
-    GLES20.glVertexAttribPointer(mProgram.mAttribute[1], TEX_DATA_SIZE     , GLES20.GL_FLOAT, false, 0, mQuadTexture);
-    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+    GLES30.glVertexAttribPointer(mProgram.mAttribute[0], POSITION_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions);
+    GLES30.glVertexAttribPointer(mProgram.mAttribute[1], TEX_DATA_SIZE     , GLES30.GL_FLOAT, false, 0, mQuadTexture);
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/EffectQueueVertex.java b/src/main/java/org/distorted/library/EffectQueueVertex.java
index b34c63b..219885d 100644
--- a/src/main/java/org/distorted/library/EffectQueueVertex.java
+++ b/src/main/java/org/distorted/library/EffectQueueVertex.java
@@ -19,7 +19,7 @@
 
 package org.distorted.library;
 
-import android.opengl.GLES20;
+import android.opengl.GLES30;
 
 import org.distorted.library.message.EffectMessage;
 import org.distorted.library.type.Data1D;
@@ -60,9 +60,9 @@ class EffectQueueVertex extends EffectQueue
 
   static void getUniforms(int mProgramH)
     {
-    mNumEffectsH= GLES20.glGetUniformLocation( mProgramH, "vNumEffects");
-    mTypeH      = GLES20.glGetUniformLocation( mProgramH, "vType");
-    mUniformsH  = GLES20.glGetUniformLocation( mProgramH, "vUniforms");
+    mNumEffectsH= GLES30.glGetUniformLocation( mProgramH, "vNumEffects");
+    mTypeH      = GLES30.glGetUniformLocation( mProgramH, "vType");
+    mUniformsH  = GLES30.glGetUniformLocation( mProgramH, "vUniforms");
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -135,7 +135,7 @@ class EffectQueueVertex extends EffectQueue
 
   synchronized void send(float halfX, float halfY, float halfZ)
     {
-    GLES20.glUniform1i( mNumEffectsH, mNumEffects);
+    GLES30.glUniform1i( mNumEffectsH, mNumEffects);
       
     if( mNumEffects>0 )
       {
@@ -146,8 +146,8 @@ class EffectQueueVertex extends EffectQueue
         mUniforms[NUM_UNIFORMS*i+7] = mCache[NUM_CACHE*i+2]-halfZ;
         }
 
-      GLES20.glUniform1iv( mTypeH    ,                 mNumEffects, mName    ,0);
-      GLES20.glUniform4fv( mUniformsH,(NUM_UNIFORMS/4)*mNumEffects, mUniforms,0);
+      GLES30.glUniform1iv( mTypeH    ,                 mNumEffects, mName    ,0);
+      GLES30.glUniform4fv( mUniformsH,(NUM_UNIFORMS/4)*mNumEffects, mUniforms,0);
       }
     }
 
@@ -155,7 +155,7 @@ class EffectQueueVertex extends EffectQueue
 
   synchronized static void sendZero()
     {
-    GLES20.glUniform1i( mNumEffectsH, 0);
+    GLES30.glUniform1i( mNumEffectsH, 0);
     }
   
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/program/DistortedProgram.java b/src/main/java/org/distorted/library/program/DistortedProgram.java
index 39629ec..6ea4bc0 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.GLES20;
+import android.opengl.GLES30;
 import android.os.Build;
 
 import org.distorted.library.DistortedEffects;
@@ -47,12 +47,12 @@ public class DistortedProgram
   private int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes)
   throws LinkingException
     {
-    int programHandle = GLES20.glCreateProgram();
+    int programHandle = GLES30.glCreateProgram();
 
     if (programHandle != 0)
       {
-      GLES20.glAttachShader(programHandle, vertexShaderHandle);
-      GLES20.glAttachShader(programHandle, fragmentShaderHandle);
+      GLES30.glAttachShader(programHandle, vertexShaderHandle);
+      GLES30.glAttachShader(programHandle, fragmentShaderHandle);
 
       if (attributes != null)
         {
@@ -60,24 +60,24 @@ public class DistortedProgram
 
         for (int i = 0; i < size; i++)
           {
-          GLES20.glBindAttribLocation(programHandle, i, attributes[i]);
+          GLES30.glBindAttribLocation(programHandle, i, attributes[i]);
           }
         }
 
-      GLES20.glLinkProgram(programHandle);
+      GLES30.glLinkProgram(programHandle);
 
       final int[] linkStatus = new int[1];
-      GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
+      GLES30.glGetProgramiv(programHandle, GLES30.GL_LINK_STATUS, linkStatus, 0);
 
-      if (linkStatus[0] != GLES20.GL_TRUE )
+      if (linkStatus[0] != GLES30.GL_TRUE )
         {
-        String error = GLES20.glGetProgramInfoLog(programHandle);
-        GLES20.glDeleteProgram(programHandle);
+        String error = GLES30.glGetProgramInfoLog(programHandle);
+        GLES30.glDeleteProgram(programHandle);
         throw new LinkingException(error);
         }
 
       final int[] numberOfUniforms = new int[1];
-      GLES20.glGetProgramiv(programHandle, GLES20.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]);
       }
@@ -181,9 +181,9 @@ public class DistortedProgram
     int maxV,maxF;
     int[] param = new int[1];
 
-    GLES20.glGetIntegerv(GLES20.GL_MAX_VERTEX_UNIFORM_VECTORS, param, 0);
+    GLES30.glGetIntegerv(GLES30.GL_MAX_VERTEX_UNIFORM_VECTORS, param, 0);
     maxV = param[0];
-    GLES20.glGetIntegerv(GLES20.GL_MAX_FRAGMENT_UNIFORM_VECTORS, param, 0);
+    GLES30.glGetIntegerv(GLES30.GL_MAX_FRAGMENT_UNIFORM_VECTORS, param, 0);
     maxF = param[0];
 
     //Log.d("program", "Max vectors in vertex shader: "+maxV);
@@ -210,30 +210,30 @@ public class DistortedProgram
   private static int compileShader(final int shaderType, final String shaderSource)
   throws FragmentCompilationException,VertexCompilationException
     {
-    int shaderHandle = GLES20.glCreateShader(shaderType);
+    int shaderHandle = GLES30.glCreateShader(shaderType);
 
     if (shaderHandle != 0)
       {
-      GLES20.glShaderSource(shaderHandle, shaderSource);
-      GLES20.glCompileShader(shaderHandle);
+      GLES30.glShaderSource(shaderHandle, shaderSource);
+      GLES30.glCompileShader(shaderHandle);
       final int[] compileStatus = new int[1];
-      GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
+      GLES30.glGetShaderiv(shaderHandle, GLES30.GL_COMPILE_STATUS, compileStatus, 0);
 
-      if (compileStatus[0] != GLES20.GL_TRUE )
+      if (compileStatus[0] != GLES30.GL_TRUE )
         {
-        GLES20.glDeleteShader(shaderHandle);
+        GLES30.glDeleteShader(shaderHandle);
         shaderHandle = 0;
         }
       }
 
     if (shaderHandle == 0)
       {
-      String error = GLES20.glGetShaderInfoLog(shaderHandle);
+      String error = GLES30.glGetShaderInfoLog(shaderHandle);
 
       switch(shaderType)
         {
-        case GLES20.GL_VERTEX_SHADER  : throw new VertexCompilationException(error);
-        case GLES20.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);
         }
       }
@@ -268,8 +268,8 @@ public class DistortedProgram
 
     sanitizeMaxValues();
 
-    final int vertexShaderHandle   = compileShader(GLES20.GL_VERTEX_SHADER  , vertexHeader   + vertexShader  );
-    final int fragmentShaderHandle = compileShader(GLES20.GL_FRAGMENT_SHADER, fragmentHeader + fragmentShader);
+    final int vertexShaderHandle   = compileShader(GLES30.GL_VERTEX_SHADER  , vertexHeader   + vertexShader  );
+    final int fragmentShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragmentHeader + fragmentShader);
 
     mProgramHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, mAttributeName);
 
@@ -277,7 +277,7 @@ public class DistortedProgram
 
     for(int i=0; i<mNumAttributes; i++)
       {
-      mAttribute[i] = GLES20.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
+      mAttribute[i] = GLES30.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
       }
     }
 
@@ -298,10 +298,10 @@ public class DistortedProgram
  */
   public void useProgram()
     {
-    GLES20.glUseProgram(mProgramHandle);
+    GLES30.glUseProgram(mProgramHandle);
 
     for(int i=0; i<mNumAttributes; i++)
-      GLES20.glEnableVertexAttribArray(mAttribute[i]);
+      GLES30.glEnableVertexAttribArray(mAttribute[i]);
     }
   }
 
