commit 442ccafbaa0dba622fd3a97d28c1c10df52056c9
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Tue Dec 2 02:07:17 2025 +0100

    major step forward in collecting all GLES stuff in a single class 'platform.GLES'

diff --git a/src/main/java/org/distorted/library/effect/PostprocessEffectBlurred.kt b/src/main/java/org/distorted/library/effect/PostprocessEffectBlurred.kt
index cdb90d4..9cd6aba 100644
--- a/src/main/java/org/distorted/library/effect/PostprocessEffectBlurred.kt
+++ b/src/main/java/org/distorted/library/effect/PostprocessEffectBlurred.kt
@@ -20,7 +20,7 @@
 
 package org.distorted.library.effect
 
-import android.opengl.GLES31
+import org.distorted.library.platform.GLES
 import org.distorted.library.main.DistortedFramebuffer
 import org.distorted.library.main.InternalRenderState
 import org.distorted.library.program.DistortedProgram
@@ -90,7 +90,7 @@ abstract class PostprocessEffectBlurred(name: EffectName) : PostprocessEffect(na
                 mProgram1 = mPrograms.get(mIndex1)
                 mProgram2 = mPrograms.get(mIndex2)
             }
-            catch (ex: Exception)
+            catch (_: Exception)
             {
                 return 0
             }
@@ -116,7 +116,7 @@ abstract class PostprocessEffectBlurred(name: EffectName) : PostprocessEffect(na
 
         val offset = radius+radius*radius/4
         radius = (radius+1)/2
-        GLES31.glViewport(0, 0, w.toInt(), h.toInt())
+        GLES.glViewport(0, 0, w.toInt(), h.toInt())
 
         // horizontal blur
         for (i in 0..radius) mOffsets[i] = offsetsCache[offset+i]*offsetCorrW
@@ -125,22 +125,22 @@ abstract class PostprocessEffectBlurred(name: EffectName) : PostprocessEffect(na
         buffer.bindForOutput(1)
         buffer.setAsInput(0)
 
-        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)
-
-        GLES31.glColorMask(true, true, true, true)
-        GLES31.glClearColor(1.0f, 1.0f, 1.0f, 0.0f)
-        GLES31.glClear(GLES31.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)
+        GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_WRAP_S, GLES.GL_CLAMP_TO_EDGE)
+        GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_WRAP_T, GLES.GL_CLAMP_TO_EDGE)
+
+        GLES.glColorMask(true, true, true, true)
+        GLES.glClearColor(1.0f, 1.0f, 1.0f, 0.0f)
+        GLES.glClear(GLES.GL_COLOR_BUFFER_BIT)
+
+        GLES.glUniform1f(mProgram1!!.mUniform!![0], n)
+        GLES.glUniform2f(mProgram1!!.mUniform!![1], corrW, corrH)
+        GLES.glUniform1i(mProgram1!!.mUniform!![2], 0)
+        GLES.glUniform1fv(mProgram1!!.mUniform!![3], radius+1, mOffsets, 0)
+        GLES.glUniform1fv(mProgram1!!.mUniform!![4], radius+1, weightsCache, offset)
+        GLES.glUniform1i(mProgram1!!.mUniform!![5], radius)
+        GLES.glVertexAttribPointer(mProgram1!!.mAttribute!![0], POS_DATA_SIZE, GLES.GL_FLOAT, false, 0, mQuadPositions)
+        GLES.glVertexAttribPointer(mProgram1!!.mAttribute!![1], TEX_DATA_SIZE, GLES.GL_FLOAT, false, 0, mQuadTexture)
+        GLES.glDrawArrays(GLES.GL_TRIANGLE_STRIP, 0, 4)
         mProgram1!!.stopUsingProgram()
 
         // vertical blur
@@ -150,20 +150,20 @@ abstract class PostprocessEffectBlurred(name: EffectName) : PostprocessEffect(na
         buffer.bindForOutput(0)
         buffer.setAsInput(1)
 
-        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)
+        GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_WRAP_S, GLES.GL_CLAMP_TO_EDGE)
+        GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_WRAP_T, GLES.GL_CLAMP_TO_EDGE)
 
-        GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT)
+        GLES.glClear(GLES.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)
+        GLES.glUniform1f(mProgram2!!.mUniform!![0], n)
+        GLES.glUniform2f(mProgram2!!.mUniform!![1], corrW, corrH)
+        GLES.glUniform1i(mProgram2!!.mUniform!![2], 0)
+        GLES.glUniform1fv(mProgram2!!.mUniform!![3], radius+1, mOffsets, 0)
+        GLES.glUniform1fv(mProgram2!!.mUniform!![4], radius+1, weightsCache, offset)
+        GLES.glUniform1i(mProgram2!!.mUniform!![5], radius)
+        GLES.glVertexAttribPointer(mProgram2!!.mAttribute!![0], POS_DATA_SIZE, GLES.GL_FLOAT, false, 0, mQuadPositions)
+        GLES.glVertexAttribPointer(mProgram2!!.mAttribute!![1], TEX_DATA_SIZE, GLES.GL_FLOAT, false, 0, mQuadTexture)
+        GLES.glDrawArrays(GLES.GL_TRIANGLE_STRIP, 0, 4)
         mProgram1!!.stopUsingProgram()
 
         InternalRenderState.unuseStencilMark()
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.kt b/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.kt
index 7ffe2dd..0d4e2e7 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.kt
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.kt
@@ -20,7 +20,7 @@
 
 package org.distorted.library.effectqueue
 
-import android.opengl.GLES31
+import org.distorted.library.platform.GLES
 import org.distorted.library.effect.EffectType
 import org.distorted.library.effect.FragmentEffect
 import org.distorted.library.message.EffectMessageSender
@@ -42,9 +42,9 @@ internal class EffectQueueFragment : EffectQueue
         ///////////////////////////////////////////////////////////////////////////////////////////
         fun uniforms(mProgramH: Int, variant: Int)
         {
-            mNumEffectsH[variant]  = GLES31.glGetUniformLocation(mProgramH, "fNumEffects")
-            mIntUniformsH[variant] = GLES31.glGetUniformLocation(mProgramH, "fProperties")
-            mFloUniformsH[variant] = GLES31.glGetUniformLocation(mProgramH, "fUniforms")
+            mNumEffectsH[variant]  = GLES.glGetUniformLocation(mProgramH, "fNumEffects")
+            mIntUniformsH[variant] = GLES.glGetUniformLocation(mProgramH, "fProperties")
+            mFloUniformsH[variant] = GLES.glGetUniformLocation(mProgramH, "fUniforms")
         }
     }
     ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -68,14 +68,14 @@ internal class EffectQueueFragment : EffectQueue
     ///////////////////////////////////////////////////////////////////////////////////////////////
     fun send(variant: Int)
     {
-        GLES31.glUniform1i(mNumEffectsH[variant],numEffects)
+        GLES.glUniform1i(mNumEffectsH[variant],numEffects)
 
         if (numEffects>0)
         {
             val arrayI = mUBI!!.backingArray
             val arrayF = mUBF!!.backingArray
-            GLES31.glUniform4iv(mIntUniformsH[variant],numEffects,arrayI,0)
-            GLES31.glUniform4fv(mFloUniformsH[variant],(NUM_FLOAT_UNIFORMS/4)*numEffects,arrayF,0)
+            GLES.glUniform4iv(mIntUniformsH[variant],numEffects,arrayI,0)
+            GLES.glUniform4fv(mFloUniformsH[variant],(NUM_FLOAT_UNIFORMS/4)*numEffects,arrayF,0)
         }
     }
 }
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueueMatrix.kt b/src/main/java/org/distorted/library/effectqueue/EffectQueueMatrix.kt
index 5ae7a36..7e1a76c 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueueMatrix.kt
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueueMatrix.kt
@@ -20,7 +20,7 @@
 
 package org.distorted.library.effectqueue
 
-import android.opengl.GLES31
+import org.distorted.library.platform.GLES
 import org.distorted.library.effect.EffectType
 import org.distorted.library.effect.MatrixEffect
 import org.distorted.library.helpers.MatrixHelper.multiply
@@ -48,9 +48,9 @@ internal class EffectQueueMatrix : EffectQueue
         ///////////////////////////////////////////////////////////////////////////////////////////
         fun uniforms(mProgramH: Int, variant: Int)
         {
-            mMVPMatrixH[variant] = GLES31.glGetUniformLocation(mProgramH, "u_MVPMatrix")
-            mMVMatrixPH[variant] = GLES31.glGetUniformLocation(mProgramH, "u_MVMatrixP")
-            mMVMatrixVH[variant] = GLES31.glGetUniformLocation(mProgramH, "u_MVMatrixV")
+            mMVPMatrixH[variant] = GLES.glGetUniformLocation(mProgramH, "u_MVPMatrix")
+            mMVMatrixPH[variant] = GLES.glGetUniformLocation(mProgramH, "u_MVMatrixP")
+            mMVMatrixVH[variant] = GLES.glGetUniformLocation(mProgramH, "u_MVMatrixV")
         }
     }
 
@@ -116,8 +116,8 @@ internal class EffectQueueMatrix : EffectQueue
         // combined Model-View-Projection matrix
         multiply(mMVPMatrix, projection, mModelViewMatrixP)
 
-        GLES31.glUniformMatrix4fv(mMVMatrixVH[variant], 1, false, mModelViewMatrixV, 0)
-        GLES31.glUniformMatrix4fv(mMVMatrixPH[variant], 1, false, mModelViewMatrixP, 0)
-        GLES31.glUniformMatrix4fv(mMVPMatrixH[variant], 1, false, mMVPMatrix       , 0)
+        GLES.glUniformMatrix4fv(mMVMatrixVH[variant], 1, false, mModelViewMatrixV, 0)
+        GLES.glUniformMatrix4fv(mMVMatrixPH[variant], 1, false, mModelViewMatrixP, 0)
+        GLES.glUniformMatrix4fv(mMVPMatrixH[variant], 1, false, mMVPMatrix       , 0)
     }
 }
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.kt b/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.kt
index c78de17..7d8b74f 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.kt
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.kt
@@ -20,7 +20,7 @@
 
 package org.distorted.library.effectqueue
 
-import android.opengl.GLES31
+import org.distorted.library.platform.GLES
 import org.distorted.library.effect.EffectType
 import org.distorted.library.effect.PostprocessEffect
 import org.distorted.library.effect.VertexEffect
@@ -95,8 +95,8 @@ class EffectQueuePostprocess : EffectQueue
             mPreProgramH = mPreProgram!!.programHandle
             getUniforms(mPreProgramH, 2)
             MeshBase.getUniforms(mPreProgramH, 2)
-            mPreColorH = GLES31.glGetUniformLocation(mPreProgramH, "u_Color")
-            mPreTextureH = GLES31.glGetUniformLocation(mPreProgramH, "u_Texture")
+            mPreColorH = GLES.glGetUniformLocation(mPreProgramH, "u_Color")
+            mPreTextureH = GLES.glGetUniformLocation(mPreProgramH, "u_Texture")
         }
     }
 
@@ -165,9 +165,9 @@ class EffectQueuePostprocess : EffectQueue
 
         InternalRenderState.setUpStencilMark(mA != 0.0f)
         InternalRenderState.disableBlending()
-        if (!mUseHaloDepth) GLES31.glDepthMask(false)
+        if (!mUseHaloDepth) GLES.glDepthMask(false)
 
-        GLES31.glViewport(0,0,width,height)
+        GLES.glViewport(0,0,width,height)
 
         mPreProgram!!.useProgram()
 
@@ -183,16 +183,16 @@ class EffectQueuePostprocess : EffectQueue
 
         if (mA != 0.0f)
         {
-            GLES31.glUniform4f(mPreColorH,mR,mG,mB,mA)
-            GLES31.glUniform1i(mPreTextureH, 0)
+            GLES.glUniform4f(mPreColorH,mR,mG,mB,mA)
+            GLES.glUniform1i(mPreTextureH, 0)
         }
 
-        GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices() )
+        GLES.glDrawArrays(GLES.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices() )
         mPreProgram!!.stopUsingProgram()
 
         InternalRenderState.restoreBlending()
         InternalRenderState.unsetUpStencilMark()
-        if (!mUseHaloDepth) GLES31.glDepthMask(true)
+        if (!mUseHaloDepth) GLES.glDepthMask(true)
 
         return 1
     }
@@ -203,12 +203,12 @@ class EffectQueuePostprocess : EffectQueue
         var numRenders = 0
         val array = mUBF!!.backingArray
 
-        GLES31.glDisable(GLES31.GL_BLEND)
+        GLES.glDisable(GLES.GL_BLEND)
 
         for (i in 0..<numEffects)
             numRenders += (mEffects[i] as PostprocessEffect).postprocess(array,NUM_FLOAT_UNIFORMS*i, buffer)
 
-        GLES31.glEnable(GLES31.GL_BLEND)
+        GLES.glEnable(GLES.GL_BLEND)
 
         return numRenders
     }
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueueVertex.kt b/src/main/java/org/distorted/library/effectqueue/EffectQueueVertex.kt
index 52be63b..2bd68a1 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueueVertex.kt
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueueVertex.kt
@@ -20,7 +20,7 @@
 
 package org.distorted.library.effectqueue
 
-import android.opengl.GLES31
+import org.distorted.library.platform.GLES
 import org.distorted.library.effect.EffectType
 import org.distorted.library.effect.VertexEffect
 import org.distorted.library.message.EffectMessageSender
@@ -48,10 +48,10 @@ class EffectQueueVertex : EffectQueue
         ///////////////////////////////////////////////////////////////////////////////////////////
         fun uniforms(mProgramH: Int, variant: Int)
         {
-            mNumEffectsH[variant]   = GLES31.glGetUniformLocation(mProgramH, "vNumEffects")
-            mInflateH[variant]      = GLES31.glGetUniformLocation(mProgramH, "u_Inflate")
-            mIntBlockIndex[variant] = GLES31.glGetUniformBlockIndex(mProgramH, "vUniformProperties")
-            mFloBlockIndex[variant] = GLES31.glGetUniformBlockIndex(mProgramH, "vUniformFloats")
+            mNumEffectsH[variant]   = GLES.glGetUniformLocation(mProgramH, "vNumEffects")
+            mInflateH[variant]      = GLES.glGetUniformLocation(mProgramH, "u_Inflate")
+            mIntBlockIndex[variant] = GLES.glGetUniformBlockIndex(mProgramH, "vUniformProperties")
+            mFloBlockIndex[variant] = GLES.glGetUniformBlockIndex(mProgramH, "vUniformFloats")
         }
     }
 
@@ -84,15 +84,15 @@ class EffectQueueVertex : EffectQueue
     */
     fun send(inflate: Float, programH: Int, variant: Int)
     {
-        GLES31.glUniform1i(mNumEffectsH[variant], numEffects)
-        GLES31.glUniform1f(mInflateH[variant], inflate)
+        GLES.glUniform1i(mNumEffectsH[variant], numEffects)
+        GLES.glUniform1f(mInflateH[variant], inflate)
 
         if (numEffects>0)
         {
-            GLES31.glBindBufferBase(GLES31.GL_UNIFORM_BUFFER,VERT_INT_UBO_BINDING,mUBI!!.index)
-            GLES31.glUniformBlockBinding(programH, mIntBlockIndex[variant],VERT_INT_UBO_BINDING)
-            GLES31.glBindBufferBase(GLES31.GL_UNIFORM_BUFFER,VERT_FLO_UBO_BINDING,mUBF!!.index)
-            GLES31.glUniformBlockBinding(programH,mFloBlockIndex[variant],VERT_FLO_UBO_BINDING)
+            GLES.glBindBufferBase(GLES.GL_UNIFORM_BUFFER,VERT_INT_UBO_BINDING,mUBI!!.index)
+            GLES.glUniformBlockBinding(programH, mIntBlockIndex[variant],VERT_INT_UBO_BINDING)
+            GLES.glBindBufferBase(GLES.GL_UNIFORM_BUFFER,VERT_FLO_UBO_BINDING,mUBF!!.index)
+            GLES.glUniformBlockBinding(programH,mFloBlockIndex[variant],VERT_FLO_UBO_BINDING)
         }
     }
 }
diff --git a/src/main/java/org/distorted/library/main/DistortedFramebuffer.kt b/src/main/java/org/distorted/library/main/DistortedFramebuffer.kt
index c86c4e7..1c48604 100644
--- a/src/main/java/org/distorted/library/main/DistortedFramebuffer.kt
+++ b/src/main/java/org/distorted/library/main/DistortedFramebuffer.kt
@@ -19,7 +19,7 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 package org.distorted.library.main
 
-import android.opengl.GLES31
+import org.distorted.library.platform.GLES
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -46,74 +46,74 @@ open class DistortedFramebuffer internal constructor(numfbos: Int, numcolors: In
         // COLOR
         if( mColorCreated==NOT_CREATED_YET )
         {
-            GLES31.glGenTextures(mNumFBOs*mNumColors, mColorH, 0)
-            GLES31.glGenFramebuffers(mNumFBOs, mFBOH, 0)
+            GLES.glGenTextures(mNumFBOs*mNumColors, mColorH, 0)
+            GLES.glGenFramebuffers(mNumFBOs, mFBOH, 0)
 
             for (i in 0 until mNumFBOs)
             {
-                GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, mFBOH[i])
+                GLES.glBindFramebuffer(GLES.GL_FRAMEBUFFER, mFBOH[i])
 
                 for (j in 0 until mNumColors)
                 {
-                    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.toFloat())
-                    GLES31.glTexParameterf(GLES31.GL_TEXTURE_2D, GLES31.GL_TEXTURE_MAG_FILTER, GLES31.GL_LINEAR.toFloat())
-                    GLES31.glTexImage2D(GLES31.GL_TEXTURE_2D, 0, GLES31.GL_RGBA, mRealWidth, mRealHeight, 0, GLES31.GL_RGBA, GLES31.GL_UNSIGNED_BYTE, null)
+                    GLES.glBindTexture(GLES.GL_TEXTURE_2D, mColorH!![i*mNumColors+j])
+                    GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_WRAP_S, GLES.GL_REPEAT)
+                    GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_WRAP_T, GLES.GL_REPEAT)
+                    GLES.glTexParameterf(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_MIN_FILTER, GLES.GL_NEAREST.toFloat())
+                    GLES.glTexParameterf(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_MAG_FILTER, GLES.GL_LINEAR.toFloat())
+                    GLES.glTexImage2D(GLES.GL_TEXTURE_2D, 0, GLES.GL_RGBA, mRealWidth, mRealHeight, 0, GLES.GL_RGBA, GLES.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)
+                GLES.glFramebufferTexture2D(GLES.GL_FRAMEBUFFER, GLES.GL_COLOR_ATTACHMENT0, GLES.GL_TEXTURE_2D, mColorH!![i*mNumColors], 0)
+                GLES.glBindTexture(GLES.GL_TEXTURE_2D, 0)
             }
 
             // TODO
             mColorCreated = checkStatus("color")
-            GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, 0)
+            GLES.glBindFramebuffer(GLES.GL_FRAMEBUFFER, 0)
         }
 
         //////////////////////////////////////////////////////////////
         // DEPTH / STENCIL
         if( mDepthStencilCreated==NOT_CREATED_YET )  // we need to create a new DEPTH or STENCIL attachment
         {
-            GLES31.glGenTextures(mNumFBOs, mDepthStencilH, 0)
+            GLES.glGenTextures(mNumFBOs, mDepthStencilH, 0)
 
             for (i in 0 until mNumFBOs)
             {
-                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)
+                GLES.glBindTexture(GLES.GL_TEXTURE_2D, mDepthStencilH!![i])
+                GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_WRAP_S, GLES.GL_REPEAT)
+                GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_WRAP_T, GLES.GL_REPEAT)
+                GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_MIN_FILTER, GLES.GL_NEAREST)
+                GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_MAG_FILTER, GLES.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)
+                    GLES.glTexImage2D(GLES.GL_TEXTURE_2D, 0, GLES.GL_DEPTH_COMPONENT, mRealWidth, mRealHeight, 0, GLES.GL_DEPTH_COMPONENT, GLES.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)
+                    GLES.glTexImage2D(GLES.GL_TEXTURE_2D, 0, GLES.GL_DEPTH24_STENCIL8, mRealWidth, mRealHeight, 0, GLES.GL_DEPTH_STENCIL, GLES.GL_UNSIGNED_INT_24_8, null)
                 }
             }
-            GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, 0)
+            GLES.glBindTexture(GLES.GL_TEXTURE_2D, 0)
 
             for (i in 0 until mNumFBOs)
             {
-                GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, mFBOH[i])
+                GLES.glBindFramebuffer(GLES.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)
+                    GLES.glFramebufferTexture2D(GLES.GL_FRAMEBUFFER, GLES.GL_DEPTH_ATTACHMENT, GLES.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)
+                    GLES.glFramebufferTexture2D(GLES.GL_FRAMEBUFFER, GLES.GL_DEPTH_STENCIL_ATTACHMENT, GLES.GL_TEXTURE_2D, mDepthStencilH!![i], 0)
                 }
             }
 
             // TODO
             mDepthStencilCreated = checkStatus("depth")
-            GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, 0)
+            GLES.glBindFramebuffer(GLES.GL_FRAMEBUFFER, 0)
         }
 
         //////////////////////////////////////////////////////////////
@@ -128,14 +128,14 @@ open class DistortedFramebuffer internal constructor(numfbos: Int, numcolors: In
 
             for (i in 0 until mNumFBOs)
             {
-                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)
+                GLES.glBindFramebuffer(GLES.GL_FRAMEBUFFER, mFBOH[i])
+                GLES.glFramebufferTexture2D(GLES.GL_FRAMEBUFFER, GLES.GL_DEPTH_ATTACHMENT, GLES.GL_TEXTURE_2D, 0, 0)
+                GLES.glFramebufferTexture2D(GLES.GL_FRAMEBUFFER, GLES.GL_DEPTH_STENCIL_ATTACHMENT, GLES.GL_TEXTURE_2D, 0, 0)
                 mDepthStencilH!![i] = 0
             }
 
-            GLES31.glDeleteTextures(mNumFBOs, mDepthStencilH, 0)
-            GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, 0)
+            GLES.glDeleteTextures(mNumFBOs, mDepthStencilH, 0)
+            GLES.glBindFramebuffer(GLES.GL_FRAMEBUFFER, 0)
         }
     }
 
@@ -143,15 +143,15 @@ open class DistortedFramebuffer internal constructor(numfbos: Int, numcolors: In
     // TODO
     private fun checkStatus(message: String): Int
     {
-        val status = GLES31.glCheckFramebufferStatus(GLES31.GL_FRAMEBUFFER)
+        val status = GLES.glCheckFramebufferStatus(GLES.GL_FRAMEBUFFER)
 
-        if (status!=GLES31.GL_FRAMEBUFFER_COMPLETE)
+        if (status!=GLES.GL_FRAMEBUFFER_COMPLETE)
         {
             DistortedLibrary.logMessage("DistortedFramebuffer: FRAMEBUFFER INCOMPLETE, $message error=$status")
 
-            GLES31.glDeleteTextures(1, mColorH, 0)
-            GLES31.glDeleteTextures(1, mDepthStencilH, 0)
-            GLES31.glDeleteFramebuffers(1, mFBOH, 0)
+            GLES.glDeleteTextures(1, mColorH, 0)
+            GLES.glDeleteTextures(1, mDepthStencilH, 0)
+            GLES.glDeleteFramebuffers(1, mFBOH, 0)
             mFBOH[0] = 0
 
             return FAILED_TO_CREATE
@@ -168,7 +168,7 @@ open class DistortedFramebuffer internal constructor(numfbos: Int, numcolors: In
 
         if( colorH[0]>0 )
         {
-            GLES31.glDeleteTextures(mNumFBOs*mNumColors, colorH, 0)
+            GLES.glDeleteTextures(mNumFBOs*mNumColors, colorH, 0)
             mColorCreated = NOT_CREATED_YET
             for (i in 0 until mNumFBOs*mNumColors) colorH[i] = 0
         }
@@ -177,14 +177,14 @@ open class DistortedFramebuffer internal constructor(numfbos: Int, numcolors: In
 
         if( depthStencilH[0]>0 )
         {
-            GLES31.glDeleteTextures(mNumFBOs, depthStencilH, 0)
+            GLES.glDeleteTextures(mNumFBOs, depthStencilH, 0)
             mDepthStencilCreated = NOT_CREATED_YET
             for (i in 0 until mNumFBOs) depthStencilH[i] = 0
         }
 
         if( mNumFBOs>0 && mFBOH[0]>0 )
         {
-            GLES31.glDeleteFramebuffers(mNumFBOs, mFBOH, 0)
+            GLES.glDeleteFramebuffers(mNumFBOs, mFBOH, 0)
         }
 
         for (i in 0 until mNumFBOs)
@@ -222,8 +222,8 @@ open class DistortedFramebuffer internal constructor(numfbos: Int, numcolors: In
 
             if( colorH>0 )
             {
-                GLES31.glActiveTexture(GLES31.GL_TEXTURE0)
-                GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, colorH)
+                GLES.glActiveTexture(GLES.GL_TEXTURE0)
+                GLES.glBindTexture(GLES.GL_TEXTURE_2D, colorH)
                 return true
             }
         }
@@ -277,8 +277,8 @@ open class DistortedFramebuffer internal constructor(numfbos: Int, numcolors: In
 
             if( colorH>0 )
             {
-                GLES31.glActiveTexture(GLES31.GL_TEXTURE0)
-                GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, colorH)
+                GLES.glActiveTexture(GLES.GL_TEXTURE0)
+                GLES.glBindTexture(GLES.GL_TEXTURE_2D, colorH)
                 return true
             }
         }
@@ -299,7 +299,7 @@ open class DistortedFramebuffer internal constructor(numfbos: Int, numcolors: In
             val colorH = mColorH!![2*mCurrFBO + texture]
 
             if( colorH>0 )
-                GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, colorH, 0)
+                GLES.glFramebufferTexture2D(GLES.GL_FRAMEBUFFER, GLES.GL_COLOR_ATTACHMENT0, GLES.GL_TEXTURE_2D, colorH, 0)
         }
     }
 
@@ -353,7 +353,7 @@ open class DistortedFramebuffer internal constructor(numfbos: Int, numcolors: In
     {
         if( fbo in 0..<mNumFBOs )
         {
-            GLES31.glBindFramebuffer(GLES31.GL_READ_FRAMEBUFFER, mFBOH[fbo])
+            GLES.glBindFramebuffer(GLES.GL_READ_FRAMEBUFFER, mFBOH[fbo])
             return true
         }
 
diff --git a/src/main/java/org/distorted/library/main/DistortedLibrary.kt b/src/main/java/org/distorted/library/main/DistortedLibrary.kt
index 6e1436d..90c8ba0 100644
--- a/src/main/java/org/distorted/library/main/DistortedLibrary.kt
+++ b/src/main/java/org/distorted/library/main/DistortedLibrary.kt
@@ -19,7 +19,7 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 package org.distorted.library.main
 
-import android.opengl.GLES31
+import org.distorted.library.platform.GLES
 import org.distorted.library.effect.Effect
 import org.distorted.library.effect.EffectType
 import org.distorted.library.effect.FragmentEffect
@@ -319,8 +319,8 @@ object DistortedLibrary
         mMainProgramH = mMainProgram!!.programHandle
         EffectQueue.getUniforms(mMainProgramH, 0)
         MeshBase.getUniforms(mMainProgramH, 0)
-        mMainTextureH = GLES31.glGetUniformLocation(mMainProgramH, "u_Texture")
-        mTransformFeedbackH = GLES31.glGetUniformLocation(mMainProgramH, "u_TransformFeedback")
+        mMainTextureH = GLES.glGetUniformLocation(mMainProgramH, "u_Texture")
+        mTransformFeedbackH = GLES.glGetUniformLocation(mMainProgramH, "u_TransformFeedback")
 
         // BLIT PROGRAM ////////////////////////////////////
         val blitVertStream = Blit.vertex()
@@ -337,8 +337,8 @@ object DistortedLibrary
         }
 
         val blitProgramH = mBlitProgram!!.programHandle
-        mBlitTextureH = GLES31.glGetUniformLocation(blitProgramH, "u_Texture")
-        mBlitDepthH = GLES31.glGetUniformLocation(blitProgramH, "u_Depth")
+        mBlitTextureH = GLES.glGetUniformLocation(blitProgramH, "u_Texture")
+        mBlitDepthH = GLES.glGetUniformLocation(blitProgramH, "u_Depth")
 
         // BLIT DEPTH PROGRAM ////////////////////////////////////
         val blitDepthVertStream = BlitDepth.vertex()
@@ -355,9 +355,9 @@ object DistortedLibrary
         }
 
         val blitDepthProgramH = mBlitDepthProgram!!.programHandle
-        mBlitDepthTextureH = GLES31.glGetUniformLocation(blitDepthProgramH, "u_Texture")
-        mBlitDepthDepthTextureH = GLES31.glGetUniformLocation(blitDepthProgramH, "u_DepthTexture")
-        mBlitDepthTexCorrH = GLES31.glGetUniformLocation(blitDepthProgramH, "u_TexCorr")
+        mBlitDepthTextureH = GLES.glGetUniformLocation(blitDepthProgramH, "u_Texture")
+        mBlitDepthDepthTextureH = GLES.glGetUniformLocation(blitDepthProgramH, "u_DepthTexture")
+        mBlitDepthTexCorrH = GLES.glGetUniformLocation(blitDepthProgramH, "u_TexCorr")
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -377,7 +377,7 @@ object DistortedLibrary
         }
 
         val normalProgramH = mNormalProgram!!.programHandle
-        mNormalProjectionH = GLES31.glGetUniformLocation(normalProgramH, "u_Projection")
+        mNormalProjectionH = GLES.glGetUniformLocation(normalProgramH, "u_Projection")
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -452,9 +452,9 @@ object DistortedLibrary
         mMainOITProgramH = mMainOITProgram!!.programHandle
         EffectQueue.getUniforms(mMainOITProgramH, 1)
         MeshBase.getUniforms(mMainOITProgramH, 1)
-        mMainOITTextureH = GLES31.glGetUniformLocation(mMainOITProgramH, "u_Texture")
-        mMainOITSizeH = GLES31.glGetUniformLocation(mMainOITProgramH, "u_Size")
-        mMainOITNumRecordsH = GLES31.glGetUniformLocation(mMainOITProgramH, "u_numRecords")
+        mMainOITTextureH = GLES.glGetUniformLocation(mMainOITProgramH, "u_Texture")
+        mMainOITSizeH = GLES.glGetUniformLocation(mMainOITProgramH, "u_Size")
+        mMainOITNumRecordsH = GLES.glGetUniformLocation(mMainOITProgramH, "u_numRecords")
 
         // OIT CLEAR PROGRAM ////////////////////////////////////
         val oitClearVertStream = Oit.vertex()
@@ -471,9 +471,9 @@ object DistortedLibrary
         }
 
         val oitClearProgramH = mOITClearProgram!!.programHandle
-        mOITClearDepthH = GLES31.glGetUniformLocation(oitClearProgramH, "u_Depth")
-        mOITClearTexCorrH = GLES31.glGetUniformLocation(oitClearProgramH, "u_TexCorr")
-        mOITClearSizeH = GLES31.glGetUniformLocation(oitClearProgramH, "u_Size")
+        mOITClearDepthH = GLES.glGetUniformLocation(oitClearProgramH, "u_Depth")
+        mOITClearTexCorrH = GLES.glGetUniformLocation(oitClearProgramH, "u_TexCorr")
+        mOITClearSizeH = GLES.glGetUniformLocation(oitClearProgramH, "u_Size")
 
         // OIT BUILD PROGRAM ////////////////////////////////////
         val oitBuildVertStream = Oit.vertex()
@@ -490,12 +490,12 @@ object DistortedLibrary
         }
 
         val oitBuildProgramH = mOITBuildProgram!!.programHandle
-        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      = GLES.glGetUniformLocation(oitBuildProgramH, "u_Texture")
+        mOITBuildDepthTextureH = GLES.glGetUniformLocation(oitBuildProgramH, "u_DepthTexture")
+        mOITBuildDepthH        = GLES.glGetUniformLocation(oitBuildProgramH, "u_Depth")
+        mOITBuildTexCorrH      = GLES.glGetUniformLocation(oitBuildProgramH, "u_TexCorr")
+        mOITBuildSizeH         = GLES.glGetUniformLocation(oitBuildProgramH, "u_Size")
+        mOITBuildNumRecordsH   = GLES.glGetUniformLocation(oitBuildProgramH, "u_numRecords")
 
         // OIT COLLAPSE PROGRAM ///////////////////////////
         val oitCollapseVertStream = Oit.vertex()
@@ -512,10 +512,10 @@ object DistortedLibrary
         }
 
         val oitCollapseProgramH = mOITCollapseProgram!!.programHandle
-        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 = GLES.glGetUniformLocation(oitCollapseProgramH, "u_DepthTexture")
+        mOITCollapseDepthH        = GLES.glGetUniformLocation(oitCollapseProgramH, "u_Depth")
+        mOITCollapseTexCorrH      = GLES.glGetUniformLocation(oitCollapseProgramH, "u_TexCorr")
+        mOITCollapseSizeH         = GLES.glGetUniformLocation(oitCollapseProgramH, "u_Size")
 
         // OIT RENDER PROGRAM ///////////////////////////
         val oitRenderVertStream = Oit.vertex()
@@ -532,9 +532,9 @@ object DistortedLibrary
         }
 
         val oitRenderProgramH = mOITRenderProgram!!.programHandle
-        mOITRenderDepthH   = GLES31.glGetUniformLocation(oitRenderProgramH, "u_Depth")
-        mOITRenderTexCorrH = GLES31.glGetUniformLocation(oitRenderProgramH, "u_TexCorr")
-        mOITRenderSizeH    = GLES31.glGetUniformLocation(oitRenderProgramH, "u_Size")
+        mOITRenderDepthH   = GLES.glGetUniformLocation(oitRenderProgramH, "u_Depth")
+        mOITRenderTexCorrH = GLES.glGetUniformLocation(oitRenderProgramH, "u_TexCorr")
+        mOITRenderSizeH    = GLES.glGetUniformLocation(oitRenderProgramH, "u_Size")
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -556,21 +556,21 @@ object DistortedLibrary
         val num = mesh.getNumVertices()
         val tfo = mesh.tFO
 
-        GLES31.glUniform1i(mTransformFeedbackH, 1)
-        GLES31.glBindBufferBase(GLES31.GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfo)
-        GLES31.glBeginTransformFeedback(GLES31.GL_POINTS)
+        GLES.glUniform1i(mTransformFeedbackH, 1)
+        GLES.glBindBufferBase(GLES.GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfo)
+        GLES.glBeginTransformFeedback(GLES.GL_POINTS)
         switchOffDrawing()
-        GLES31.glDrawArrays(GLES31.GL_POINTS, 0, num)
+        GLES.glDrawArrays(GLES.GL_POINTS, 0, num)
         restoreDrawing()
-        GLES31.glEndTransformFeedback()
-        GLES31.glBindBufferBase(GLES31.GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0)
-        GLES31.glUniform1i(mTransformFeedbackH, 0)
+        GLES.glEndTransformFeedback()
+        GLES.glBindBufferBase(GLES.GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0)
+        GLES.glUniform1i(mTransformFeedbackH, 0)
 
         mNormalProgram!!.useProgram()
-        GLES31.glUniformMatrix4fv(mNormalProjectionH, 1, false, projection, 0)
+        GLES.glUniformMatrix4fv(mNormalProjectionH, 1, false, projection, 0)
         mesh.bindTransformAttribs(mNormalProgram!!)
-        GLES31.glLineWidth(8.0f)
-        GLES31.glDrawArrays(GLES31.GL_LINES, 0, 2*num)
+        GLES.glLineWidth(8.0f)
+        GLES.glDrawArrays(GLES.GL_LINES, 0, 2*num)
         mNormalProgram!!.stopUsingProgram()
     }
 
@@ -602,14 +602,14 @@ object DistortedLibrary
         queue.send(0.0f, mFullProgramH, 3)
         mesh.send(mFullProgramH, 3)
 
-        GLES31.glBindBufferBase(GLES31.GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfo)
-        GLES31.glBeginTransformFeedback(GLES31.GL_POINTS)
+        GLES.glBindBufferBase(GLES.GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfo)
+        GLES.glBeginTransformFeedback(GLES.GL_POINTS)
         switchOffDrawing()
-        GLES31.glDrawArrays(GLES31.GL_POINTS, 0, num)
+        GLES.glDrawArrays(GLES.GL_POINTS, 0, num)
         restoreDrawing()
-        GLES31.glEndTransformFeedback()
+        GLES.glEndTransformFeedback()
         mesh.copyTransformToVertex()
-        GLES31.glBindBufferBase(GLES31.GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0)
+        GLES.glBindBufferBase(GLES.GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0)
         mFullProgram!!.stopUsingProgram()
     }
 
@@ -623,12 +623,12 @@ object DistortedLibrary
             val queues = effects.queues
 
             compute(queues, currTime, step)
-            GLES31.glViewport(0, 0, w, h)
+            GLES.glViewport(0, 0, w, h)
 
             mMainOITProgram!!.useProgram()
-            GLES31.glUniform1i(mMainOITTextureH, 0)
-            GLES31.glUniform2ui(mMainOITSizeH, w, h)
-            GLES31.glUniform1ui(mMainOITNumRecordsH, (mBufferSize*w*h).toInt())
+            GLES.glUniform1i(mMainOITTextureH, 0)
+            GLES.glUniform2ui(mMainOITSizeH, w, h)
+            GLES.glUniform1ui(mMainOITNumRecordsH, (mBufferSize*w*h).toInt())
             mesh.bindVertexAttribs(mMainOITProgram!!)
             mesh.send(mMainOITProgramH, 1)
 
@@ -638,7 +638,7 @@ object DistortedLibrary
             val projection = surface.mProjectionMatrix
 
             send(queues, mMainOITProgramH, distance, mipmap, projection, inflate, 1)
-            GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices())
+            GLES.glDrawArrays(GLES.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices())
             if (mesh.showNormals) displayNormals(projection, mesh)
             mMainOITProgram!!.stopUsingProgram()
         }
@@ -653,10 +653,10 @@ object DistortedLibrary
             val w = surface.getWidth()
             val h = surface.getHeight()
             compute(queues, currTime, step)
-            GLES31.glViewport(0, 0, w, h)
+            GLES.glViewport(0, 0, w, h)
 
             mMainProgram!!.useProgram()
-            GLES31.glUniform1i(mMainTextureH, 0)
+            GLES.glUniform1i(mMainTextureH, 0)
             mesh.bindVertexAttribs(mMainProgram!!)
             mesh.send(mMainProgramH, 0)
 
@@ -666,7 +666,7 @@ object DistortedLibrary
             val projection = surface.mProjectionMatrix
 
             send(queues, mMainProgramH, distance, mipmap, projection, inflate, 0)
-            GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices())
+            GLES.glDrawArrays(GLES.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices())
             if (mesh.showNormals) displayNormals(projection, mesh)
             mMainProgram!!.stopUsingProgram()
         }
@@ -681,11 +681,11 @@ object DistortedLibrary
             val h = surface.getHeight()
             val n = surface.getNear()
             mBlitProgram!!.useProgram()
-            GLES31.glViewport(0, 0, w, h)
-            GLES31.glUniform1i(mBlitTextureH, 0)
-            GLES31.glUniform1f(mBlitDepthH, 1.0f-n)
-            GLES31.glVertexAttribPointer(mBlitProgram!!.mAttribute!![0], 2, GLES31.GL_FLOAT, false, 0, mQuadPositions)
-            GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4)
+            GLES.glViewport(0, 0, w, h)
+            GLES.glUniform1i(mBlitTextureH, 0)
+            GLES.glUniform1f(mBlitDepthH, 1.0f-n)
+            GLES.glVertexAttribPointer(mBlitProgram!!.mAttribute!![0], 2, GLES.GL_FLOAT, false, 0, mQuadPositions)
+            GLES.glDrawArrays(GLES.GL_TRIANGLE_STRIP, 0, 4)
             mBlitProgram!!.stopUsingProgram()
         }
     }
@@ -698,12 +698,12 @@ object DistortedLibrary
             mBlitDepthProgram!!.useProgram()
             val w = surface.getWidth()
             val h = surface.getHeight()
-            GLES31.glViewport(0, 0, w, h)
-            GLES31.glUniform1i(mBlitDepthTextureH, 0)
-            GLES31.glUniform1i(mBlitDepthDepthTextureH, 1)
-            GLES31.glUniform2f(mBlitDepthTexCorrH, corrW, corrH)
-            GLES31.glVertexAttribPointer(mBlitDepthProgram!!.mAttribute!![0], 2, GLES31.GL_FLOAT, false, 0, mQuadPositions)
-            GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4)
+            GLES.glViewport(0, 0, w, h)
+            GLES.glUniform1i(mBlitDepthTextureH, 0)
+            GLES.glUniform1i(mBlitDepthDepthTextureH, 1)
+            GLES.glUniform2f(mBlitDepthTexCorrH, corrW, corrH)
+            GLES.glVertexAttribPointer(mBlitDepthProgram!!.mAttribute!![0], 2, GLES.GL_FLOAT, false, 0, mQuadPositions)
+            GLES.glDrawArrays(GLES.GL_TRIANGLE_STRIP, 0, 4)
             mBlitDepthProgram!!.stopUsingProgram()
         }
     }
@@ -712,11 +712,11 @@ object DistortedLibrary
     // yes it is safe to be mixing 3.0 and 3.1 like that, senior members of the OpenGL discussions forum assert
     private fun printPreviousBuffer(): Int
     {
-        val atomicBuf = GLES31.glMapBufferRange(GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, 4, GLES31.GL_MAP_READ_BIT) as ByteBuffer
+        val atomicBuf = GLES.glMapBufferRange(GLES.GL_ATOMIC_COUNTER_BUFFER, 0, 4, GLES.GL_MAP_READ_BIT)
         val atomicIntBuf = atomicBuf.order(ByteOrder.nativeOrder()).asIntBuffer()
         val counter = atomicIntBuf[0]
 
-        GLES31.glUnmapBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER)
+        GLES.glUnmapBuffer(GLES.GL_ATOMIC_COUNTER_BUFFER)
 
         return counter
     }
@@ -724,11 +724,11 @@ object DistortedLibrary
     ///////////////////////////////////////////////////////////////////////////////////////////////////
     private fun zeroBuffer()
     {
-        val atomicBuf = GLES31.glMapBufferRange(GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, 4, GLES31.GL_MAP_WRITE_BIT or GLES31.GL_MAP_INVALIDATE_BUFFER_BIT) as ByteBuffer
+        val atomicBuf = GLES.glMapBufferRange(GLES.GL_ATOMIC_COUNTER_BUFFER, 0, 4, GLES.GL_MAP_WRITE_BIT or GLES.GL_MAP_INVALIDATE_BUFFER_BIT)
         val atomicIntBuf = atomicBuf.order(ByteOrder.nativeOrder()).asIntBuffer()
         atomicIntBuf.put(0, 0)
 
-        GLES31.glUnmapBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER)
+        GLES.glUnmapBuffer(GLES.GL_ATOMIC_COUNTER_BUFFER)
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -741,12 +741,12 @@ object DistortedLibrary
         {
             mAtomicCounter = IntArray(queueSize)
 
-            GLES31.glGenBuffers(queueSize, mAtomicCounter, 0)
+            GLES.glGenBuffers(queueSize, mAtomicCounter!!, 0)
 
             for (i in 0 until queueSize)
             {
-                GLES31.glBindBuffer(GLES31.GL_ATOMIC_COUNTER_BUFFER, mAtomicCounter!![i])
-                GLES31.glBufferData(GLES31.GL_ATOMIC_COUNTER_BUFFER, 4, null, GLES31.GL_DYNAMIC_DRAW)
+                GLES.glBindBuffer(GLES.GL_ATOMIC_COUNTER_BUFFER, mAtomicCounter!![i])
+                GLES.glBufferData(GLES.GL_ATOMIC_COUNTER_BUFFER, 4, null, GLES.GL_DYNAMIC_DRAW)
                 zeroBuffer()
             }
         }
@@ -755,13 +755,13 @@ object DistortedLibrary
         // 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])
+            GLES.glBindBufferBase(GLES.GL_ATOMIC_COUNTER_BUFFER, 0, mAtomicCounter!![mCurrBuffer])
             counter = printPreviousBuffer()
         }
 
         if (++mCurrBuffer>=queueSize) mCurrBuffer = 0
 
-        GLES31.glBindBufferBase(GLES31.GL_ATOMIC_COUNTER_BUFFER, 0, mAtomicCounter!![mCurrBuffer])
+        GLES.glBindBufferBase(GLES.GL_ATOMIC_COUNTER_BUFFER, 0, mAtomicCounter!![mCurrBuffer])
         zeroBuffer()
 
         return counter
@@ -798,14 +798,14 @@ object DistortedLibrary
 
         if (mLinkedListSSBO[0]<0)
         {
-            GLES31.glGenBuffers(1, mLinkedListSSBO, 0)
+            GLES.glGenBuffers(1, mLinkedListSSBO, 0)
 
             val size = (w*h*(3*mBufferSize+1)*4).toInt()
-            GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, mLinkedListSSBO[0])
-            GLES31.glBufferData(GLES31.GL_SHADER_STORAGE_BUFFER, size, null, GLES31.GL_DYNAMIC_READ or GLES31.GL_DYNAMIC_DRAW)
-            GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, 0)
+            GLES.glBindBuffer(GLES.GL_SHADER_STORAGE_BUFFER, mLinkedListSSBO[0])
+            GLES.glBufferData(GLES.GL_SHADER_STORAGE_BUFFER, size, null, GLES.GL_DYNAMIC_READ or GLES.GL_DYNAMIC_DRAW)
+            GLES.glBindBuffer(GLES.GL_SHADER_STORAGE_BUFFER, 0)
 
-            GLES31.glBindBufferBase(GLES31.GL_SHADER_STORAGE_BUFFER, 1, mLinkedListSSBO[0])
+            GLES.glBindBufferBase(GLES.GL_SHADER_STORAGE_BUFFER, 1, mLinkedListSSBO[0])
         }
 
         // See if we have overflown the SSBO in one of the previous frames.
@@ -816,18 +816,18 @@ object DistortedLibrary
         {
             mBufferSize *= (overflow+1.0f).toInt().toFloat()
             val size = (w*h*(3*mBufferSize+1)*4).toInt()
-            GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, mLinkedListSSBO[0])
-            GLES31.glBufferData(GLES31.GL_SHADER_STORAGE_BUFFER, size, null, GLES31.GL_DYNAMIC_READ or GLES31.GL_DYNAMIC_DRAW)
-            GLES31.glBindBuffer(GLES31.GL_SHADER_STORAGE_BUFFER, 0)
+            GLES.glBindBuffer(GLES.GL_SHADER_STORAGE_BUFFER, mLinkedListSSBO[0])
+            GLES.glBufferData(GLES.GL_SHADER_STORAGE_BUFFER, size, null, GLES.GL_DYNAMIC_READ or GLES.GL_DYNAMIC_DRAW)
+            GLES.glBindBuffer(GLES.GL_SHADER_STORAGE_BUFFER, 0)
         }
 
         mOITClearProgram!!.useProgram()
-        GLES31.glViewport(0, 0, w, h)
-        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, w, h)
-        GLES31.glVertexAttribPointer(mOITClearProgram!!.mAttribute!![0], 2, GLES31.GL_FLOAT, false, 0, mQuadPositions)
-        GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4)
+        GLES.glViewport(0, 0, w, h)
+        GLES.glUniform2f(mOITClearTexCorrH, 1.0f, 1.0f) // corrections do not really matter here - only present because of common vertex shader.
+        GLES.glUniform1f(mOITClearDepthH, 1.0f) // likewise depth
+        GLES.glUniform2ui(mOITClearSizeH, w, h)
+        GLES.glVertexAttribPointer(mOITClearProgram!!.mAttribute!![0], 2, GLES.GL_FLOAT, false, 0, mQuadPositions)
+        GLES.glDrawArrays(GLES.GL_TRIANGLE_STRIP, 0, 4)
         mOITClearProgram!!.stopUsingProgram()
     }
 
@@ -841,15 +841,15 @@ object DistortedLibrary
             val h = surface.getHeight()
             val n = surface.getNear()
             mOITBuildProgram!!.useProgram()
-            GLES31.glViewport(0, 0, w, h)
-            GLES31.glUniform1i(mOITBuildTextureH, 0)
-            GLES31.glUniform1i(mOITBuildDepthTextureH, 1)
-            GLES31.glUniform2f(mOITBuildTexCorrH, corrW, corrH)
-            GLES31.glUniform2ui(mOITBuildSizeH, w, h)
-            GLES31.glUniform1ui(mOITBuildNumRecordsH, (mBufferSize*w*h).toInt())
-            GLES31.glUniform1f(mOITBuildDepthH, 1.0f-n)
-            GLES31.glVertexAttribPointer(mOITBuildProgram!!.mAttribute!![0], 2, GLES31.GL_FLOAT, false, 0, mQuadPositions)
-            GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4)
+            GLES.glViewport(0, 0, w, h)
+            GLES.glUniform1i(mOITBuildTextureH, 0)
+            GLES.glUniform1i(mOITBuildDepthTextureH, 1)
+            GLES.glUniform2f(mOITBuildTexCorrH, corrW, corrH)
+            GLES.glUniform2ui(mOITBuildSizeH, w, h)
+            GLES.glUniform1ui(mOITBuildNumRecordsH, (mBufferSize*w*h).toInt())
+            GLES.glUniform1f(mOITBuildDepthH, 1.0f-n)
+            GLES.glVertexAttribPointer(mOITBuildProgram!!.mAttribute!![0], 2, GLES.GL_FLOAT, false, 0, mQuadPositions)
+            GLES.glDrawArrays(GLES.GL_TRIANGLE_STRIP, 0, 4)
             mOITBuildProgram!!.stopUsingProgram()
         }
     }
@@ -864,13 +864,13 @@ object DistortedLibrary
             val h = surface.getHeight()
             val n = surface.getNear()
             mOITCollapseProgram!!.useProgram()
-            GLES31.glViewport(0, 0, w, h)
-            GLES31.glUniform1i(mOITCollapseDepthTextureH, 1)
-            GLES31.glUniform2f(mOITCollapseTexCorrH, corrW, corrH)
-            GLES31.glUniform2ui(mOITCollapseSizeH, w, h)
-            GLES31.glUniform1f(mOITCollapseDepthH, 1.0f-n)
-            GLES31.glVertexAttribPointer(mOITCollapseProgram!!.mAttribute!![0], 2, GLES31.GL_FLOAT, false, 0, mQuadPositions)
-            GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4)
+            GLES.glViewport(0, 0, w, h)
+            GLES.glUniform1i(mOITCollapseDepthTextureH, 1)
+            GLES.glUniform2f(mOITCollapseTexCorrH, corrW, corrH)
+            GLES.glUniform2ui(mOITCollapseSizeH, w, h)
+            GLES.glUniform1f(mOITCollapseDepthH, 1.0f-n)
+            GLES.glVertexAttribPointer(mOITCollapseProgram!!.mAttribute!![0], 2, GLES.GL_FLOAT, false, 0, mQuadPositions)
+            GLES.glDrawArrays(GLES.GL_TRIANGLE_STRIP, 0, 4)
             mOITCollapseProgram!!.stopUsingProgram()
         }
     }
@@ -885,12 +885,12 @@ object DistortedLibrary
             val h = surface.getHeight()
             val n = surface.getNear()
             mOITRenderProgram!!.useProgram()
-            GLES31.glViewport(0, 0, w, h)
-            GLES31.glUniform2f(mOITRenderTexCorrH, corrW, corrH)
-            GLES31.glUniform2ui(mOITRenderSizeH, w, h)
-            GLES31.glUniform1f(mOITRenderDepthH, 1.0f-n)
-            GLES31.glVertexAttribPointer(mOITRenderProgram!!.mAttribute!![0], 2, GLES31.GL_FLOAT, false, 0, mQuadPositions)
-            GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, 4)
+            GLES.glViewport(0, 0, w, h)
+            GLES.glUniform2f(mOITRenderTexCorrH, corrW, corrH)
+            GLES.glUniform2ui(mOITRenderSizeH, w, h)
+            GLES.glUniform1f(mOITRenderDepthH, 1.0f-n)
+            GLES.glVertexAttribPointer(mOITRenderProgram!!.mAttribute!![0], 2, GLES.GL_FLOAT, false, 0, mQuadPositions)
+            GLES.glDrawArrays(GLES.GL_TRIANGLE_STRIP, 0, 4)
             mOITRenderProgram!!.stopUsingProgram()
         }
     }
@@ -925,9 +925,9 @@ object DistortedLibrary
     // PowerVR GE8100 / GE8300 compiler fails to compile OIT programs.
     private fun detectBuggyDriversAndSetQueueSize(queueSize: Int)
     {
-        driverVendor   = GLES31.glGetString(GLES31.GL_VENDOR)
-        driverVersion  = GLES31.glGetString(GLES31.GL_VERSION)
-        driverRenderer = GLES31.glGetString(GLES31.GL_RENDERER)
+        driverVendor   = GLES.glGetString(GLES.GL_VENDOR)
+        driverVersion  = GLES.glGetString(GLES.GL_VERSION)
+        driverRenderer = GLES.glGetString(GLES.GL_RENDERER)
 
         DistortedLibrary.queueSize = 1
         mFastCompilationTF = true
@@ -955,7 +955,7 @@ object DistortedLibrary
             if ( driverRenderer!!.contains("GE8") )
             {
                 mUser.logMessage("You are running this on a PowerVR GE8XXX.\nDue to a buggy compiler OIT rendering will not work")
-                mUser.logMessage("GLSL Version "+GLES31.glGetString(GLES31.GL_SHADING_LANGUAGE_VERSION))
+                mUser.logMessage("GLSL Version "+GLES.glGetString(GLES.GL_SHADING_LANGUAGE_VERSION))
             }
         }
         else if (driverVendor!=null && driverVendor!!.contains("Qualcomm"))
@@ -981,8 +981,8 @@ object DistortedLibrary
         {
             val major = IntArray(1)
             val minor = IntArray(1)
-            GLES31.glGetIntegerv(GLES31.GL_MAJOR_VERSION, major, 0)
-            GLES31.glGetIntegerv(GLES31.GL_MINOR_VERSION, minor, 0)
+            GLES.glGetIntegerv(GLES.GL_MAJOR_VERSION, major, 0)
+            GLES.glGetIntegerv(GLES.GL_MINOR_VERSION, minor, 0)
             return major[0]*100+minor[0]*10
         }
 
@@ -1021,11 +1021,11 @@ object DistortedLibrary
         }
 
         val tmp = IntArray(1)
-        GLES31.glGetIntegerv(GLES31.GL_MAX_TEXTURE_SIZE, tmp, 0)
+        GLES.glGetIntegerv(GLES.GL_MAX_TEXTURE_SIZE, tmp, 0)
         maxTextureSize = tmp[0]
-        GLES31.glGetIntegerv(GLES31.GL_MAX_VERTEX_UNIFORM_VECTORS, tmp, 0)
+        GLES.glGetIntegerv(GLES.GL_MAX_VERTEX_UNIFORM_VECTORS, tmp, 0)
         maxVertexUniforms = tmp[0]
-        GLES31.glGetIntegerv(GLES31.GL_MAX_FRAGMENT_UNIFORM_VECTORS, tmp, 0)
+        GLES.glGetIntegerv(GLES.GL_MAX_FRAGMENT_UNIFORM_VECTORS, tmp, 0)
         maxFragmentUniforms = tmp[0]
 
         mUser.logMessage("Using OpenGL ES $major.$minor texSize=$maxTextureSize maxVerUniforms: $maxVertexUniforms maxFraUniforms: $maxFragmentUniforms")
@@ -1077,12 +1077,12 @@ object DistortedLibrary
     {
         if (on)
         {
-            GLES31.glEnable(GLES31.GL_CULL_FACE)
-            GLES31.glCullFace(GLES31.GL_FRONT)
+            GLES.glEnable(GLES.GL_CULL_FACE)
+            GLES.glCullFace(GLES.GL_FRONT)
         }
         else
         {
-            GLES31.glDisable(GLES31.GL_CULL_FACE)
+            GLES.glDisable(GLES.GL_CULL_FACE)
         }
     }
 
diff --git a/src/main/java/org/distorted/library/main/DistortedNode.kt b/src/main/java/org/distorted/library/main/DistortedNode.kt
index 649872f..639ffa1 100644
--- a/src/main/java/org/distorted/library/main/DistortedNode.kt
+++ b/src/main/java/org/distorted/library/main/DistortedNode.kt
@@ -19,7 +19,7 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 package org.distorted.library.main
 
-import android.opengl.GLES31
+import org.distorted.library.platform.GLES
 import org.distorted.library.main.InternalNodeData.Companion.returnData
 import org.distorted.library.mesh.MeshBase
 
@@ -165,11 +165,11 @@ open class DistortedNode : InternalChildrenList.Parent
         if( setAsInput() )
         {
             mState.apply()
-            GLES31.glDisable(GLES31.GL_BLEND)
+            GLES.glDisable(GLES.GL_BLEND)
             if (mLastTime==0L) mLastTime = currTime
             DistortedLibrary.drawPriv(mEffects, mMesh, surface, currTime, (currTime-mLastTime))
             mLastTime = currTime
-            GLES31.glEnable(GLES31.GL_BLEND)
+            GLES.glEnable(GLES.GL_BLEND)
             return 1
         }
 
diff --git a/src/main/java/org/distorted/library/main/DistortedScreen.kt b/src/main/java/org/distorted/library/main/DistortedScreen.kt
index b66faf9..f7d665f 100644
--- a/src/main/java/org/distorted/library/main/DistortedScreen.kt
+++ b/src/main/java/org/distorted/library/main/DistortedScreen.kt
@@ -22,7 +22,7 @@ package org.distorted.library.main
 import android.graphics.Bitmap
 import android.graphics.Canvas
 import android.graphics.Paint
-import android.opengl.GLES31
+import org.distorted.library.platform.GLES
 import org.distorted.library.effect.MatrixEffectMove
 import org.distorted.library.effect.MatrixEffectScale
 import org.distorted.library.mesh.MeshQuad
@@ -171,7 +171,7 @@ class DistortedScreen : DistortedFramebuffer(DistortedLibrary.WAIT_FOR_FBO_QUEUE
 
         val numrender = super.render(time, mCurRenderedFBO)
 
-        GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, 0)
+        GLES.glBindFramebuffer(GLES.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
@@ -180,11 +180,11 @@ class DistortedScreen : DistortedFramebuffer(DistortedLibrary.WAIT_FOR_FBO_QUEUE
         // 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)
+        GLES.glColorMask(true, true, true, true)
+        GLES.glDepthMask(false)
+        GLES.glDisable(GLES.GL_STENCIL_TEST)
+        GLES.glDisable(GLES.GL_DEPTH_TEST)
+        GLES.glDisable(GLES.GL_BLEND)
 
         DistortedLibrary.blitPriv(this)
 
@@ -208,9 +208,9 @@ class DistortedScreen : DistortedFramebuffer(DistortedLibrary.WAIT_FOR_FBO_QUEUE
             mToBeBlittedFBO = 0
         }
 /*
-    int err = GLES31.glGetError();
+    int err = GLES.glGetError();
 
-    if( err!=GLES31.GL_NO_ERROR )
+    if( err!=GLES.GL_NO_ERROR )
       {
       DistortedLibrary.logMessage("DistortedScreen: OpenGL error "+err);
       }
diff --git a/src/main/java/org/distorted/library/main/DistortedTexture.kt b/src/main/java/org/distorted/library/main/DistortedTexture.kt
index c82c017..b18474d 100644
--- a/src/main/java/org/distorted/library/main/DistortedTexture.kt
+++ b/src/main/java/org/distorted/library/main/DistortedTexture.kt
@@ -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 org.distorted.library.platform.GLES
 import android.opengl.GLUtils
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -67,16 +67,16 @@ constructor(type: Int = TYPE_USER) : InternalSurface(NOT_CREATED_YET, 1, 1, type
             if (mColorCreated==NOT_CREATED_YET)
             {
                 mColorCreated = CREATED
-                GLES31.glGenTextures(1, mColorH, 0)
+                GLES.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, if (mBitmapInverted) mBmp else flipBitmap(mBmp!!), 0)
-            GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, 0)
+            GLES.glBindTexture(GLES.GL_TEXTURE_2D, mColorH!![0])
+            GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_MIN_FILTER, GLES.GL_LINEAR)
+            GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_MAG_FILTER, GLES.GL_LINEAR)
+            GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_WRAP_S, GLES.GL_CLAMP_TO_EDGE)
+            GLES.glTexParameteri(GLES.GL_TEXTURE_2D, GLES.GL_TEXTURE_WRAP_T, GLES.GL_CLAMP_TO_EDGE)
+            GLUtils.texImage2D(GLES.GL_TEXTURE_2D, 0, if (mBitmapInverted) mBmp else flipBitmap(mBmp!!), 0)
+            GLES.glBindTexture(GLES.GL_TEXTURE_2D, 0)
 
             mBmp = null
         }
@@ -88,7 +88,7 @@ constructor(type: Int = TYPE_USER) : InternalSurface(NOT_CREATED_YET, 1, 1, type
     {
         if (mColorH!![0]>0)
         {
-            GLES31.glDeleteTextures(1, mColorH, 0)
+            GLES.glDeleteTextures(1, mColorH, 0)
             mColorH!![0] = 0
             mColorCreated = NOT_CREATED_YET
         }
diff --git a/src/main/java/org/distorted/library/main/InternalBuffer.kt b/src/main/java/org/distorted/library/main/InternalBuffer.kt
index 5d97694..4af4532 100644
--- a/src/main/java/org/distorted/library/main/InternalBuffer.kt
+++ b/src/main/java/org/distorted/library/main/InternalBuffer.kt
@@ -19,7 +19,7 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 package org.distorted.library.main
 
-import android.opengl.GLES31
+import org.distorted.library.platform.GLES
 
 import java.nio.Buffer
 import java.nio.ByteBuffer
@@ -55,8 +55,8 @@ class InternalBuffer : InternalObject
     constructor() : super(TYPE_USER, STORAGE_PRIVATE)
     {
         mIndex  = IntArray(1)
-        mTarget = GLES31.GL_UNIFORM_BUFFER
-        mUsage  = GLES31.GL_STATIC_DRAW
+        mTarget = GLES.GL_UNIFORM_BUFFER
+        mUsage  = GLES.GL_STATIC_DRAW
         mBuffer = null
         mSize   = 0
         mStatus = RECREATE
@@ -92,10 +92,10 @@ class InternalBuffer : InternalObject
                 mBuffer = null
             }
 
-            GLES31.glGenBuffers(1, mIndex, 0)
-            GLES31.glBindBuffer(mTarget, mIndex[0])
-            GLES31.glBufferData(mTarget, mSize, mBuffer, mUsage)
-            GLES31.glBindBuffer(mTarget, 0)
+            GLES.glGenBuffers(1, mIndex, 0)
+            GLES.glBindBuffer(mTarget, mIndex[0])
+            GLES.glBufferData(mTarget, mSize, mBuffer, mUsage)
+            GLES.glBindBuffer(mTarget, 0)
 
             markWasCreatedImmediately()
         }
@@ -128,10 +128,10 @@ class InternalBuffer : InternalObject
                 mBuffer = null
             }
 
-            GLES31.glGenBuffers(1, mIndex, 0)
-            GLES31.glBindBuffer(mTarget, mIndex[0])
-            GLES31.glBufferData(mTarget, mSize, mBuffer, mUsage)
-            GLES31.glBindBuffer(mTarget, 0)
+            GLES.glGenBuffers(1, mIndex, 0)
+            GLES.glBindBuffer(mTarget, mIndex[0])
+            GLES.glBufferData(mTarget, mSize, mBuffer, mUsage)
+            GLES.glBindBuffer(mTarget, 0)
 
             markWasCreatedImmediately()
         }
@@ -151,9 +151,9 @@ class InternalBuffer : InternalObject
     {
         (mBuffer as FloatBuffer).put(buffer).position(0)
 
-        GLES31.glBindBuffer(mTarget, mIndex[0])
-        GLES31.glBufferData(mTarget, mSize, mBuffer, mUsage)
-        GLES31.glBindBuffer(mTarget, 0)
+        GLES.glBindBuffer(mTarget, mIndex[0])
+        GLES.glBufferData(mTarget, mSize, mBuffer, mUsage)
+        GLES.glBindBuffer(mTarget, 0)
 
         mStatus = mStatus and (UPDATE.inv())
     }
@@ -164,9 +164,9 @@ class InternalBuffer : InternalObject
     {
         (mBuffer as IntBuffer).put(buffer).position(0)
 
-        GLES31.glBindBuffer(mTarget, mIndex[0])
-        GLES31.glBufferData(mTarget, mSize, mBuffer, mUsage)
-        GLES31.glBindBuffer(mTarget, 0)
+        GLES.glBindBuffer(mTarget, mIndex[0])
+        GLES.glBufferData(mTarget, mSize, mBuffer, mUsage)
+        GLES.glBindBuffer(mTarget, 0)
 
         mStatus = mStatus and (UPDATE.inv())
     }
@@ -190,7 +190,7 @@ class InternalBuffer : InternalObject
     // must be called from a thread holding OpenGL Context
     override fun delete()
     {
-        GLES31.glDeleteBuffers(1, mIndex, 0)
+        GLES.glDeleteBuffers(1, mIndex, 0)
         mStatus = mStatus or RECREATE
         removeFromDone()
     }
diff --git a/src/main/java/org/distorted/library/main/InternalOutputSurface.kt b/src/main/java/org/distorted/library/main/InternalOutputSurface.kt
index 04e13e4..571e3ea 100644
--- a/src/main/java/org/distorted/library/main/InternalOutputSurface.kt
+++ b/src/main/java/org/distorted/library/main/InternalOutputSurface.kt
@@ -19,7 +19,7 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 package org.distorted.library.main
 
-import android.opengl.GLES31
+import org.distorted.library.platform.GLES
 import org.distorted.library.effect.EffectQuality
 import org.distorted.library.effect.EffectQuality.Companion.getMipmap
 import org.distorted.library.effectqueue.EffectQueuePostprocess
@@ -101,24 +101,24 @@ abstract class InternalOutputSurface
             InternalStackFrameList.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)
+            GLES.glClearColor(CLEAR_R, CLEAR_G, CLEAR_B, CLEAR_A)
+            GLES.glClearDepthf(CLEAR_D)
+            GLES.glClearStencil(CLEAR_S)
 
             val colorH = mBuffer[quality]!!.mColorH!!
 
             for (k in 0 until queueSize)
             {
-                GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, mBuffer[quality]!!.mFBOH[k])
-                GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, colorH[2*k+1], 0)
-                GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT or GLES31.GL_DEPTH_BUFFER_BIT or GLES31.GL_STENCIL_BUFFER_BIT)
-                GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, colorH[2*k], 0)
-                GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT)
+                GLES.glBindFramebuffer(GLES.GL_FRAMEBUFFER, mBuffer[quality]!!.mFBOH[k])
+                GLES.glFramebufferTexture2D(GLES.GL_FRAMEBUFFER, GLES.GL_COLOR_ATTACHMENT0, GLES.GL_TEXTURE_2D, colorH[2*k+1], 0)
+                GLES.glClear(GLES.GL_COLOR_BUFFER_BIT or GLES.GL_DEPTH_BUFFER_BIT or GLES.GL_STENCIL_BUFFER_BIT)
+                GLES.glFramebufferTexture2D(GLES.GL_FRAMEBUFFER, GLES.GL_COLOR_ATTACHMENT0, GLES.GL_TEXTURE_2D, colorH[2*k], 0)
+                GLES.glClear(GLES.GL_COLOR_BUFFER_BIT)
             }
 
             InternalRenderState.colorDepthStencilRestore()
 
-            GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, 0)
+            GLES.glBindFramebuffer(GLES.GL_FRAMEBUFFER, 0)
         }
 
         ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -137,7 +137,7 @@ abstract class InternalOutputSurface
         {
             val counter = DistortedLibrary.zeroOutAtomic()
             DistortedLibrary.oitClear(buffer, counter)
-            GLES31.glMemoryBarrier(GLES31.GL_SHADER_STORAGE_BARRIER_BIT or GLES31.GL_ATOMIC_COUNTER_BARRIER_BIT)
+            GLES.glMemoryBarrier(GLES.GL_SHADER_STORAGE_BARRIER_BIT or GLES.GL_ATOMIC_COUNTER_BARRIER_BIT)
         }
     }
     ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -153,7 +153,7 @@ abstract class InternalOutputSurface
 
         mDepthStencilCreated = (if (mDepthStencil==NO_DEPTH_NO_STENCIL) DONT_CREATE else NOT_CREATED_YET)
 
-        mClear = GLES31.GL_DEPTH_BUFFER_BIT or GLES31.GL_COLOR_BUFFER_BIT
+        mClear = GLES.GL_DEPTH_BUFFER_BIT or GLES.GL_COLOR_BUFFER_BIT
 
         mChildren = InternalChildrenList(this)
 
@@ -234,35 +234,35 @@ abstract class InternalOutputSurface
     {
         val colorH = buffer.mColorH!!
 
-        GLES31.glViewport(0, 0, mWidth, mHeight)
+        GLES.glViewport(0, 0, mWidth, mHeight)
         setAsOutput(currTime)
-        GLES31.glActiveTexture(GLES31.GL_TEXTURE0)
-        GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, colorH[2*fbo])
-        GLES31.glActiveTexture(GLES31.GL_TEXTURE1)
-        GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, buffer.mDepthStencilH!![fbo])
+        GLES.glActiveTexture(GLES.GL_TEXTURE0)
+        GLES.glBindTexture(GLES.GL_TEXTURE_2D, colorH[2*fbo])
+        GLES.glActiveTexture(GLES.GL_TEXTURE1)
+        GLES.glBindTexture(GLES.GL_TEXTURE_2D, buffer.mDepthStencilH!![fbo])
 
-        GLES31.glDisable(GLES31.GL_STENCIL_TEST)
-        GLES31.glStencilMask(0x00)
+        GLES.glDisable(GLES.GL_STENCIL_TEST)
+        GLES.glStencilMask(0x00)
 
         DistortedLibrary.blitDepthPriv(this, buffer.widthCorrection, buffer.heightCorrection)
-        GLES31.glActiveTexture(GLES31.GL_TEXTURE0)
-        GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, 0)
-        GLES31.glActiveTexture(GLES31.GL_TEXTURE1)
-        GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, 0)
+        GLES.glActiveTexture(GLES.GL_TEXTURE0)
+        GLES.glBindTexture(GLES.GL_TEXTURE_2D, 0)
+        GLES.glActiveTexture(GLES.GL_TEXTURE1)
+        GLES.glBindTexture(GLES.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)
+        GLES.glStencilMask(0xff)
+        GLES.glDepthMask(true)
+        GLES.glColorMask(true, true, true, true)
+        GLES.glClearColor(buffer.mClearR, buffer.mClearG, buffer.mClearB, buffer.mClearA)
+        GLES.glClearDepthf(buffer.mClearDepth)
+        GLES.glClearStencil(buffer.mClearStencil)
 
         buffer.setAsOutput()
-        GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, colorH[2*fbo+1], 0)
-        GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT or GLES31.GL_DEPTH_BUFFER_BIT or GLES31.GL_STENCIL_BUFFER_BIT)
-        GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, colorH[2*fbo], 0)
-        GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT)
+        GLES.glFramebufferTexture2D(GLES.GL_FRAMEBUFFER, GLES.GL_COLOR_ATTACHMENT0, GLES.GL_TEXTURE_2D, colorH[2*fbo+1], 0)
+        GLES.glClear(GLES.GL_COLOR_BUFFER_BIT or GLES.GL_DEPTH_BUFFER_BIT or GLES.GL_STENCIL_BUFFER_BIT)
+        GLES.glFramebufferTexture2D(GLES.GL_FRAMEBUFFER, GLES.GL_COLOR_ATTACHMENT0, GLES.GL_TEXTURE_2D, colorH[2*fbo], 0)
+        GLES.glClear(GLES.GL_COLOR_BUFFER_BIT)
 
         return 1
     }
@@ -270,21 +270,21 @@ abstract class InternalOutputSurface
     ///////////////////////////////////////////////////////////////////////////////////////////////////
     private fun oitBuild(time: Long, buffer: InternalOutputSurface, fbo: Int): Int
     {
-        GLES31.glViewport(0, 0, mWidth, mHeight)
+        GLES.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])
+        GLES.glActiveTexture(GLES.GL_TEXTURE0)
+        GLES.glBindTexture(GLES.GL_TEXTURE_2D, buffer.mColorH!![2*fbo])
+        GLES.glActiveTexture(GLES.GL_TEXTURE1)
+        GLES.glBindTexture(GLES.GL_TEXTURE_2D, buffer.mDepthStencilH!![fbo])
 
         InternalRenderState.colorDepthStencilOn()
         InternalRenderState.enableDepthTest()
 
         DistortedLibrary.oitBuild(this, buffer.widthCorrection, buffer.heightCorrection)
-        GLES31.glActiveTexture(GLES31.GL_TEXTURE0)
-        GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, 0)
-        GLES31.glActiveTexture(GLES31.GL_TEXTURE1)
-        GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, 0)
+        GLES.glActiveTexture(GLES.GL_TEXTURE0)
+        GLES.glBindTexture(GLES.GL_TEXTURE_2D, 0)
+        GLES.glActiveTexture(GLES.GL_TEXTURE1)
+        GLES.glBindTexture(GLES.GL_TEXTURE_2D, 0)
 
         InternalRenderState.colorDepthStencilRestore()
         InternalRenderState.restoreDepthTest()
@@ -304,12 +304,12 @@ abstract class InternalOutputSurface
         // Otherwise there's no point (in fact we then would create a feedback loop!)
         if( depthStencil[fbo]!=0 )
         {
-            GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, 0)
-            GLES31.glActiveTexture(GLES31.GL_TEXTURE1)
-            GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, depthStencil[fbo])
+            GLES.glBindFramebuffer(GLES.GL_FRAMEBUFFER, 0)
+            GLES.glActiveTexture(GLES.GL_TEXTURE1)
+            GLES.glBindTexture(GLES.GL_TEXTURE_2D, depthStencil[fbo])
             InternalRenderState.switchOffColorDepthStencil()
             DistortedLibrary.oitCollapse(this, corrW, corrH)
-            GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, 0)
+            GLES.glBindTexture(GLES.GL_TEXTURE_2D, 0)
         }
 
         setAsOutput(currTime)
@@ -324,10 +324,10 @@ abstract class InternalOutputSurface
     private fun clear()
     {
         InternalRenderState.colorDepthStencilOn()
-        GLES31.glClearColor(mClearR, mClearG, mClearB, mClearA)
-        GLES31.glClearDepthf(mClearDepth)
-        GLES31.glClearStencil(mClearStencil)
-        GLES31.glClear(mClear)
+        GLES.glClearColor(mClearR, mClearG, mClearB, mClearA)
+        GLES.glClearDepthf(mClearDepth)
+        GLES.glClearStencil(mClearStencil)
+        GLES.glClear(mClear)
         InternalRenderState.colorDepthStencilRestore()
     }
 
@@ -361,7 +361,7 @@ abstract class InternalOutputSurface
         if( oit )
         {
             numRenders += oitBuild(time, buffer, fbo)
-            GLES31.glMemoryBarrier(GLES31.GL_SHADER_STORAGE_BARRIER_BIT or GLES31.GL_ATOMIC_COUNTER_BARRIER_BIT)
+            GLES.glMemoryBarrier(GLES.GL_SHADER_STORAGE_BARRIER_BIT or GLES.GL_ATOMIC_COUNTER_BARRIER_BIT)
             buffer.clearBuffer(fbo)
         }
         else
@@ -385,7 +385,7 @@ abstract class InternalOutputSurface
             if (oit)
             {
                 numRenders = child.drawOIT(time, this)
-                GLES31.glMemoryBarrier(GLES31.GL_SHADER_STORAGE_BARRIER_BIT or GLES31.GL_ATOMIC_COUNTER_BARRIER_BIT)
+                GLES.glMemoryBarrier(GLES.GL_SHADER_STORAGE_BARRIER_BIT or GLES.GL_ATOMIC_COUNTER_BARRIER_BIT)
             }
             else
             {
@@ -518,15 +518,15 @@ abstract class InternalOutputSurface
 
         InternalRenderState.colorDepthStencilOn()
 
-        GLES31.glClearColor(mClearR, mClearG, mClearB, mClearA)
-        GLES31.glClearDepthf(mClearDepth)
-        GLES31.glClearStencil(mClearStencil)
+        GLES.glClearColor(mClearR, mClearG, mClearB, mClearA)
+        GLES.glClearDepthf(mClearDepth)
+        GLES.glClearStencil(mClearStencil)
 
-        GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, mFBOH[fbo])
-        GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, colorH[2*fbo+1], 0)
-        GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT or GLES31.GL_DEPTH_BUFFER_BIT or GLES31.GL_STENCIL_BUFFER_BIT)
-        GLES31.glFramebufferTexture2D(GLES31.GL_FRAMEBUFFER, GLES31.GL_COLOR_ATTACHMENT0, GLES31.GL_TEXTURE_2D, colorH[2*fbo], 0)
-        GLES31.glClear(GLES31.GL_COLOR_BUFFER_BIT)
+        GLES.glBindFramebuffer(GLES.GL_FRAMEBUFFER, mFBOH[fbo])
+        GLES.glFramebufferTexture2D(GLES.GL_FRAMEBUFFER, GLES.GL_COLOR_ATTACHMENT0, GLES.GL_TEXTURE_2D, colorH[2*fbo+1], 0)
+        GLES.glClear(GLES.GL_COLOR_BUFFER_BIT or GLES.GL_DEPTH_BUFFER_BIT or GLES.GL_STENCIL_BUFFER_BIT)
+        GLES.glFramebufferTexture2D(GLES.GL_FRAMEBUFFER, GLES.GL_COLOR_ATTACHMENT0, GLES.GL_TEXTURE_2D, colorH[2*fbo], 0)
+        GLES.glClear(GLES.GL_COLOR_BUFFER_BIT)
 
         InternalRenderState.colorDepthStencilRestore()
     }
@@ -534,7 +534,7 @@ abstract class InternalOutputSurface
     ///////////////////////////////////////////////////////////////////////////////////////////////////
     fun setAsOutput(time: Long)
     {
-        GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, mFBOH[mCurrFBO])
+        GLES.glBindFramebuffer(GLES.GL_FRAMEBUFFER, mFBOH[mCurrFBO])
 
         if (mTime[mCurrFBO]!=time)
         {
@@ -615,7 +615,7 @@ abstract class InternalOutputSurface
      */
     fun setAsOutput()
     {
-        GLES31.glBindFramebuffer(GLES31.GL_FRAMEBUFFER, mFBOH[mCurrFBO])
+        GLES.glBindFramebuffer(GLES.GL_FRAMEBUFFER, mFBOH[mCurrFBO])
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -644,7 +644,7 @@ abstract class InternalOutputSurface
 
     ///////////////////////////////////////////////////////////////////////////////////////////////////
     /**
-     * Set the (R,G,B,A) values of GLES31.glClearColor() to set up color with which to clear
+     * Set the (R,G,B,A) values of GLES.glClearColor() to set up color with which to clear
      * this Surface at the beginning of each frame.
      *
      * @param r the Red component. Default: 0.0f
diff --git a/src/main/java/org/distorted/library/main/InternalRenderState.kt b/src/main/java/org/distorted/library/main/InternalRenderState.kt
index aca1403..889604a 100644
--- a/src/main/java/org/distorted/library/main/InternalRenderState.kt
+++ b/src/main/java/org/distorted/library/main/InternalRenderState.kt
@@ -19,7 +19,7 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 package org.distorted.library.main
 
-import android.opengl.GLES31
+import org.distorted.library.platform.GLES
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -70,20 +70,20 @@ class InternalRenderState internal constructor()
 
         mState.depthTest = 1
         mState.depthMask = 1
-        mState.depthFunc = GLES31.GL_LEQUAL
+        mState.depthFunc = GLES.GL_LEQUAL
 
         mState.blend = 1
-        mState.blendSrc = GLES31.GL_SRC_ALPHA
-        mState.blendDst = GLES31.GL_ONE_MINUS_SRC_ALPHA
+        mState.blendSrc = GLES.GL_SRC_ALPHA
+        mState.blendDst = GLES.GL_ONE_MINUS_SRC_ALPHA
 
         mState.stencilTest = 0
         mState.stencilMask = STENCIL_MASK
-        mState.stencilFuncFunc = GLES31.GL_NEVER
+        mState.stencilFuncFunc = GLES.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 = GLES.GL_KEEP
+        mState.stencilOpDpfail = GLES.GL_KEEP
+        mState.stencilOpDppass = GLES.GL_KEEP
 
         mClear = 0
     }
@@ -104,7 +104,7 @@ class InternalRenderState internal constructor()
             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)
+            GLES.glColorMask(cState.colorMaskR==1, cState.colorMaskG==1, cState.colorMaskB==1, cState.colorMaskA==1)
         }
 
         /////////////////////////////////////////////////////
@@ -116,12 +116,12 @@ class InternalRenderState internal constructor()
             if( cState.depthTest==0 )
             {
                 //DistortedLibrary.logMessage("InternalRenderState: disabling depth test");
-                GLES31.glDisable(GLES31.GL_DEPTH_TEST)
+                GLES.glDisable(GLES.GL_DEPTH_TEST)
             }
             else
             {
                 //DistortedLibrary.logMessage("InternalRenderState: enable depth test");
-                GLES31.glEnable(GLES31.GL_DEPTH_TEST)
+                GLES.glEnable(GLES.GL_DEPTH_TEST)
             }
         }
 
@@ -131,7 +131,7 @@ class InternalRenderState internal constructor()
         {
             //DistortedLibrary.logMessage("InternalRenderState: setting depth func");
             cState.depthFunc = mState.depthFunc
-            GLES31.glDepthFunc(cState.depthFunc)
+            GLES.glDepthFunc(cState.depthFunc)
         }
 
         /////////////////////////////////////////////////////
@@ -140,7 +140,7 @@ class InternalRenderState internal constructor()
         {
             //DistortedLibrary.logMessage("InternalRenderState: setting depth mask");
             cState.depthMask = mState.depthMask
-            GLES31.glDepthMask(cState.depthMask==1)
+            GLES.glDepthMask(cState.depthMask==1)
         }
 
         /////////////////////////////////////////////////////
@@ -152,12 +152,12 @@ class InternalRenderState internal constructor()
             if (cState.blend==0)
             {
                 //DistortedLibrary.logMessage("InternalRenderState: disabling blending");
-                GLES31.glDisable(GLES31.GL_BLEND)
+                GLES.glDisable(GLES.GL_BLEND)
             }
             else
             {
                 //DistortedLibrary.logMessage("InternalRenderState: enabling blending");
-                GLES31.glEnable(GLES31.GL_BLEND)
+                GLES.glEnable(GLES.GL_BLEND)
             }
         }
 
@@ -168,7 +168,7 @@ class InternalRenderState internal constructor()
             //DistortedLibrary.logMessage("InternalRenderState: setting blend function");
             cState.blendSrc = mState.blendSrc
             cState.blendDst = mState.blendDst
-            GLES31.glBlendFunc(cState.blendSrc, cState.blendDst)
+            GLES.glBlendFunc(cState.blendSrc, cState.blendDst)
         }
 
         /////////////////////////////////////////////////////
@@ -180,12 +180,12 @@ class InternalRenderState internal constructor()
             if( cState.stencilTest==0 )
             {
                 //DistortedLibrary.logMessage("InternalRenderState: disabling stencil test");
-                GLES31.glDisable(GLES31.GL_STENCIL_TEST)
+                GLES.glDisable(GLES.GL_STENCIL_TEST)
             }
             else
             {
                 //DistortedLibrary.logMessage("InternalRenderState: enabling stencil test");
-                GLES31.glEnable(GLES31.GL_STENCIL_TEST)
+                GLES.glEnable(GLES.GL_STENCIL_TEST)
             }
         }
 
@@ -199,7 +199,7 @@ class InternalRenderState internal constructor()
             cState.stencilFuncFunc = mState.stencilFuncFunc
             cState.stencilFuncRef  = mState.stencilFuncRef
             cState.stencilFuncMask = mState.stencilFuncMask
-            GLES31.glStencilFunc(cState.stencilFuncFunc, cState.stencilFuncRef, cState.stencilFuncMask)
+            GLES.glStencilFunc(cState.stencilFuncFunc, cState.stencilFuncRef, cState.stencilFuncMask)
         }
 
         /////////////////////////////////////////////////////
@@ -212,7 +212,7 @@ class InternalRenderState internal constructor()
             cState.stencilOpSfail = mState.stencilOpSfail
             cState.stencilOpDpfail = mState.stencilOpDpfail
             cState.stencilOpDppass = mState.stencilOpDppass
-            GLES31.glStencilOp(cState.stencilOpSfail, cState.stencilOpDpfail, cState.stencilOpDppass)
+            GLES.glStencilOp(cState.stencilOpSfail, cState.stencilOpDpfail, cState.stencilOpDppass)
         }
 
         /////////////////////////////////////////////////////
@@ -221,7 +221,7 @@ class InternalRenderState internal constructor()
         {
             //DistortedLibrary.logMessage("InternalRenderState: setting stencil mask");
             cState.stencilMask = mState.stencilMask
-            GLES31.glStencilMask(cState.stencilMask)
+            GLES.glStencilMask(cState.stencilMask)
         }
 
         /////////////////////////////////////////////////////
@@ -229,7 +229,7 @@ class InternalRenderState internal constructor()
         if( mClear!=0 )
         {
             //DistortedLibrary.logMessage("InternalRenderState: clearing buffer");
-            GLES31.glClear(mClear)
+            GLES.glClear(mClear)
         }
     }
 
@@ -257,17 +257,17 @@ class InternalRenderState internal constructor()
     ///////////////////////////////////////////////////////////////////////////////////////////////////
     fun glEnable(test: Int)
     {
-             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==GLES.GL_DEPTH_TEST  ) mState.depthTest   = 1
+        else if (test==GLES.GL_STENCIL_TEST) mState.stencilTest = 1
+        else if (test==GLES.GL_BLEND       ) mState.blend       = 1
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////////
     fun glDisable(test: Int)
     {
-             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==GLES.GL_DEPTH_TEST  ) mState.depthTest   = 0
+        else if (test==GLES.GL_STENCIL_TEST) mState.stencilTest = 0
+        else if (test==GLES.GL_BLEND       ) mState.blend       = 0
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -321,31 +321,31 @@ class InternalRenderState internal constructor()
             cState.colorMaskG = 1
             cState.colorMaskB = 1
             cState.colorMaskA = 1
-            GLES31.glColorMask(true, true, true, true)
+            GLES.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 = GLES.GL_LEQUAL
+            GLES.glEnable(GLES.GL_DEPTH_TEST)
+            GLES.glDepthMask(true)
+            GLES.glDepthFunc(cState.depthFunc)
 
             cState.stencilTest = 0
             cState.stencilMask = STENCIL_MASK
-            cState.stencilFuncFunc = GLES31.GL_NEVER
+            cState.stencilFuncFunc = GLES.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 = GLES.GL_KEEP
+            cState.stencilOpDpfail = GLES.GL_KEEP
+            cState.stencilOpDppass = GLES.GL_KEEP
+            GLES.glDisable(GLES.GL_STENCIL_TEST)
+            GLES.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 = GLES.GL_SRC_ALPHA
+            cState.blendDst = GLES.GL_ONE_MINUS_SRC_ALPHA
+            GLES.glEnable(GLES.GL_BLEND)
+            GLES.glBlendFunc(cState.blendSrc, cState.blendDst)
         }
 
         ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -362,7 +362,7 @@ class InternalRenderState internal constructor()
                 cState.colorMaskG = 1
                 cState.colorMaskB = 1
                 cState.colorMaskA = 1
-                GLES31.glColorMask(true, true, true, true)
+                GLES.glColorMask(true, true, true, true)
             }
 
             sState.depthMask = cState.depthMask
@@ -370,7 +370,7 @@ class InternalRenderState internal constructor()
             if( cState.depthMask!=1 )
             {
                 cState.depthMask = 1
-                GLES31.glDepthMask(true)
+                GLES.glDepthMask(true)
             }
 
             sState.stencilMask = cState.stencilMask
@@ -378,7 +378,7 @@ class InternalRenderState internal constructor()
             if( cState.stencilMask!=STENCIL_MASK )
             {
                 cState.stencilMask = STENCIL_MASK
-                GLES31.glStencilMask(cState.stencilMask)
+                GLES.glStencilMask(cState.stencilMask)
             }
         }
 
@@ -392,17 +392,17 @@ class InternalRenderState internal constructor()
                 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)
+                GLES.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)
+                GLES.glDepthMask(cState.depthMask==1)
             }
             if( sState.stencilMask!=cState.stencilMask )
             {
                 cState.stencilMask = sState.stencilMask
-                GLES31.glStencilMask(cState.stencilMask)
+                GLES.glStencilMask(cState.stencilMask)
             }
         }
 
@@ -414,7 +414,7 @@ class InternalRenderState internal constructor()
             if (cState.blend!=0)
             {
                 cState.blend = 0
-                GLES31.glDisable(GLES31.GL_BLEND)
+                GLES.glDisable(GLES.GL_BLEND)
             }
         }
 
@@ -427,11 +427,11 @@ class InternalRenderState internal constructor()
 
                 if (cState.blend==0)
                 {
-                    GLES31.glDisable(GLES31.GL_BLEND)
+                    GLES.glDisable(GLES.GL_BLEND)
                 }
                 else
                 {
-                    GLES31.glEnable(GLES31.GL_BLEND)
+                    GLES.glEnable(GLES.GL_BLEND)
                 }
             }
         }
@@ -444,7 +444,7 @@ class InternalRenderState internal constructor()
             if( cState.depthTest!=1 )
             {
                 cState.depthTest = 1
-                GLES31.glEnable(GLES31.GL_DEPTH_TEST)
+                GLES.glEnable(GLES.GL_DEPTH_TEST)
             }
         }
 
@@ -457,11 +457,11 @@ class InternalRenderState internal constructor()
 
                 if( cState.depthTest==0 )
                 {
-                    GLES31.glDisable(GLES31.GL_DEPTH_TEST)
+                    GLES.glDisable(GLES.GL_DEPTH_TEST)
                 }
                 else
                 {
-                    GLES31.glEnable(GLES31.GL_DEPTH_TEST)
+                    GLES.glEnable(GLES.GL_DEPTH_TEST)
                 }
             }
         }
@@ -469,14 +469,14 @@ class InternalRenderState internal constructor()
         ///////////////////////////////////////////////////////////////////////////////////////////////////
         fun switchOffDrawing()
         {
-            GLES31.glEnable(GLES31.GL_SCISSOR_TEST)
-            GLES31.glScissor(0, 0, 0, 0)
+            GLES.glEnable(GLES.GL_SCISSOR_TEST)
+            GLES.glScissor(0, 0, 0, 0)
         }
 
         ///////////////////////////////////////////////////////////////////////////////////////////////////
         fun restoreDrawing()
         {
-            GLES31.glDisable(GLES31.GL_SCISSOR_TEST)
+            GLES.glDisable(GLES.GL_SCISSOR_TEST)
         }
 
         ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -488,7 +488,7 @@ class InternalRenderState internal constructor()
             {
                 cState.stencilTest = 0
                 //DistortedLibrary.logMessage("InternalRenderState: stencil test off");
-                GLES31.glDisable(GLES31.GL_STENCIL_TEST)
+                GLES.glDisable(GLES.GL_STENCIL_TEST)
             }
 
             sState.depthTest = cState.depthTest
@@ -497,7 +497,7 @@ class InternalRenderState internal constructor()
             {
                 cState.depthTest = 0
                 //DistortedLibrary.logMessage("InternalRenderState: depth test off");
-                GLES31.glDisable(GLES31.GL_DEPTH_TEST)
+                GLES.glDisable(GLES.GL_DEPTH_TEST)
             }
 
             sState.colorMaskR = cState.colorMaskR
@@ -512,7 +512,7 @@ class InternalRenderState internal constructor()
                 cState.colorMaskB = 0
                 cState.colorMaskA = 0
                 //DistortedLibrary.logMessage("InternalRenderState: switch off color writing");
-                GLES31.glColorMask(false, false, false, false)
+                GLES.glColorMask(false, false, false, false)
             }
 
             sState.depthMask = cState.depthMask
@@ -521,7 +521,7 @@ class InternalRenderState internal constructor()
             {
                 cState.depthMask = 0
                 //DistortedLibrary.logMessage("InternalRenderState: switch off depth writing");
-                GLES31.glDepthMask(false)
+                GLES.glDepthMask(false)
             }
 
             sState.stencilMask = cState.stencilMask
@@ -530,7 +530,7 @@ class InternalRenderState internal constructor()
             {
                 cState.stencilMask = 0x00
                 //DistortedLibrary.logMessage("InternalRenderState: stencil mask off");
-                GLES31.glStencilMask(cState.stencilMask)
+                GLES.glStencilMask(cState.stencilMask)
             }
         }
 
@@ -543,7 +543,7 @@ class InternalRenderState internal constructor()
             {
                 cState.stencilTest = 0
                 //DistortedLibrary.logMessage("InternalRenderState: stencil test off");
-                GLES31.glDisable(GLES31.GL_STENCIL_TEST)
+                GLES.glDisable(GLES.GL_STENCIL_TEST)
             }
 
             sState.depthTest = cState.depthTest
@@ -552,7 +552,7 @@ class InternalRenderState internal constructor()
             {
                 cState.depthTest = 0
                 //DistortedLibrary.logMessage("InternalRenderState: depth test off");
-                GLES31.glDisable(GLES31.GL_DEPTH_TEST)
+                GLES.glDisable(GLES.GL_DEPTH_TEST)
             }
 
             sState.colorMaskR = cState.colorMaskR
@@ -567,7 +567,7 @@ class InternalRenderState internal constructor()
                 cState.colorMaskB = 1
                 cState.colorMaskA = 1
                 //DistortedLibrary.logMessage("InternalRenderState: switch on color writing");
-                GLES31.glColorMask(true, true, true, true)
+                GLES.glColorMask(true, true, true, true)
             }
 
             sState.depthMask = cState.depthMask
@@ -576,7 +576,7 @@ class InternalRenderState internal constructor()
             {
                 cState.depthMask = 1
                 //DistortedLibrary.logMessage("InternalRenderState: switch on depth writing");
-                GLES31.glDepthMask(true)
+                GLES.glDepthMask(true)
             }
 
             sState.stencilMask = cState.stencilMask
@@ -585,7 +585,7 @@ class InternalRenderState internal constructor()
             {
                 cState.stencilMask = 0x00
                 //DistortedLibrary.logMessage("InternalRenderState: stencil mask off");
-                GLES31.glStencilMask(cState.stencilMask)
+                GLES.glStencilMask(cState.stencilMask)
             }
         }
 
@@ -598,11 +598,11 @@ class InternalRenderState internal constructor()
 
                 if( cState.stencilTest==0 )
                 {
-                    GLES31.glDisable(GLES31.GL_STENCIL_TEST)
+                    GLES.glDisable(GLES.GL_STENCIL_TEST)
                 }
                 else
                 {
-                    GLES31.glEnable(GLES31.GL_STENCIL_TEST)
+                    GLES.glEnable(GLES.GL_STENCIL_TEST)
                 }
             }
             if( sState.depthTest!=cState.depthTest )
@@ -611,11 +611,11 @@ class InternalRenderState internal constructor()
 
                 if( cState.depthTest==0 )
                 {
-                    GLES31.glDisable(GLES31.GL_DEPTH_TEST)
+                    GLES.glDisable(GLES.GL_DEPTH_TEST)
                 }
                 else
                 {
-                    GLES31.glEnable(GLES31.GL_DEPTH_TEST)
+                    GLES.glEnable(GLES.GL_DEPTH_TEST)
                 }
             }
             if( sState.colorMaskR!=cState.colorMaskR || sState.colorMaskG!=cState.colorMaskG ||
@@ -625,17 +625,17 @@ class InternalRenderState internal constructor()
                 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)
+                GLES.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)
+                GLES.glDepthMask(cState.depthMask==1)
             }
             if( sState.stencilMask!=cState.stencilMask )
             {
                 cState.stencilMask = sState.stencilMask
-                GLES31.glStencilMask(cState.stencilMask)
+                GLES.glStencilMask(cState.stencilMask)
             }
         }
 
@@ -648,35 +648,35 @@ class InternalRenderState internal constructor()
             {
                 cState.stencilTest = 1
                 //DistortedLibrary.logMessage("InternalRenderState: stencil test on");
-                GLES31.glEnable(GLES31.GL_STENCIL_TEST)
+                GLES.glEnable(GLES.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!=GLES.GL_ALWAYS || cState.stencilFuncRef!=1 || cState.stencilFuncMask!=STENCIL_MASK )
             {
-                cState.stencilFuncFunc = GLES31.GL_ALWAYS
+                cState.stencilFuncFunc = GLES.GL_ALWAYS
                 cState.stencilFuncRef  = 1
                 cState.stencilFuncMask = STENCIL_MASK
                 //DistortedLibrary.logMessage("InternalRenderState: stencil func on");
-                GLES31.glStencilFunc(cState.stencilFuncFunc, cState.stencilFuncRef, cState.stencilFuncMask)
+                GLES.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 !=GLES.GL_KEEP   ||
+                cState.stencilOpDpfail!=GLES.GL_KEEP   ||
+                cState.stencilOpDppass!=GLES.GL_REPLACE )
             {
-                cState.stencilOpSfail  = GLES31.GL_KEEP
-                cState.stencilOpDpfail = GLES31.GL_KEEP
-                cState.stencilOpDppass = GLES31.GL_REPLACE
+                cState.stencilOpSfail  = GLES.GL_KEEP
+                cState.stencilOpDpfail = GLES.GL_KEEP
+                cState.stencilOpDppass = GLES.GL_REPLACE
                 //DistortedLibrary.logMessage("InternalRenderState: stencil op on");
-                GLES31.glStencilOp(cState.stencilOpSfail, cState.stencilOpDpfail, cState.stencilOpDppass)
+                GLES.glStencilOp(cState.stencilOpSfail, cState.stencilOpDpfail, cState.stencilOpDppass)
             }
 
             sState.colorMaskR = cState.colorMaskR
@@ -693,7 +693,7 @@ class InternalRenderState internal constructor()
                 cState.colorMaskB = clr
                 cState.colorMaskA = clr
                 //DistortedLibrary.logMessage("InternalRenderState: switch off color writing");
-                GLES31.glColorMask(color, color, color, color)
+                GLES.glColorMask(color, color, color, color)
             }
 
             sState.depthMask = cState.depthMask
@@ -702,7 +702,7 @@ class InternalRenderState internal constructor()
             {
                 cState.depthMask = 1
                 //DistortedLibrary.logMessage("InternalRenderState: switch on depth writing");
-                GLES31.glDepthMask(true)
+                GLES.glDepthMask(true)
             }
 
             sState.stencilMask = cState.stencilMask
@@ -711,7 +711,7 @@ class InternalRenderState internal constructor()
             {
                 cState.stencilMask = STENCIL_MASK
                 //DistortedLibrary.logMessage("InternalRenderState: stencil mask on");
-                GLES31.glStencilMask(cState.stencilMask)
+                GLES.glStencilMask(cState.stencilMask)
             }
         }
 
@@ -724,11 +724,11 @@ class InternalRenderState internal constructor()
 
                 if( cState.stencilTest==0 )
                 {
-                    GLES31.glDisable(GLES31.GL_STENCIL_TEST)
+                    GLES.glDisable(GLES.GL_STENCIL_TEST)
                 }
                 else
                 {
-                    GLES31.glEnable(GLES31.GL_STENCIL_TEST)
+                    GLES.glEnable(GLES.GL_STENCIL_TEST)
                 }
             }
             if( sState.colorMaskR!=cState.colorMaskR || sState.colorMaskG!=cState.colorMaskG ||
@@ -738,17 +738,17 @@ class InternalRenderState internal constructor()
                 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)
+                GLES.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)
+                GLES.glDepthMask(cState.depthMask==1)
             }
             if( sState.stencilMask!=cState.stencilMask )
             {
                 cState.stencilMask = sState.stencilMask
-                GLES31.glStencilMask(cState.stencilMask)
+                GLES.glStencilMask(cState.stencilMask)
             }
         }
 
@@ -765,19 +765,19 @@ class InternalRenderState internal constructor()
             if( cState.stencilTest!=1 )
             {
                 cState.stencilTest = 1
-                GLES31.glEnable(GLES31.GL_STENCIL_TEST)
+                GLES.glEnable(GLES.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!=GLES.GL_EQUAL || cState.stencilFuncRef!=1 || cState.stencilFuncMask!=STENCIL_MASK )
             {
-                cState.stencilFuncFunc = GLES31.GL_EQUAL
+                cState.stencilFuncFunc = GLES.GL_EQUAL
                 cState.stencilFuncRef  = 1
                 cState.stencilFuncMask = STENCIL_MASK
-                GLES31.glStencilFunc(cState.stencilFuncFunc, cState.stencilFuncRef, cState.stencilFuncMask)
+                GLES.glStencilFunc(cState.stencilFuncFunc, cState.stencilFuncRef, cState.stencilFuncMask)
             }
 
             sState.stencilMask = cState.stencilMask
@@ -785,7 +785,7 @@ class InternalRenderState internal constructor()
             if( cState.stencilMask!=0x00 )
             {
                 cState.stencilMask = 0x00
-                GLES31.glStencilMask(cState.stencilMask)
+                GLES.glStencilMask(cState.stencilMask)
             }
 
             sState.depthMask = cState.depthMask
@@ -793,7 +793,7 @@ class InternalRenderState internal constructor()
             if( cState.depthMask!=0 )
             {
                 cState.depthMask = 0
-                GLES31.glDepthMask(false)
+                GLES.glDepthMask(false)
             }
 
             sState.depthTest = cState.depthTest
@@ -801,7 +801,7 @@ class InternalRenderState internal constructor()
             if( cState.depthTest!=0 )
             {
                 cState.depthTest = 0
-                GLES31.glDisable(GLES31.GL_DEPTH_TEST)
+                GLES.glDisable(GLES.GL_DEPTH_TEST)
             }
         }
 
@@ -819,11 +819,11 @@ class InternalRenderState internal constructor()
 
                 if( cState.stencilTest==0 )
                 {
-                    GLES31.glDisable(GLES31.GL_STENCIL_TEST)
+                    GLES.glDisable(GLES.GL_STENCIL_TEST)
                 }
                 else
                 {
-                    GLES31.glEnable(GLES31.GL_STENCIL_TEST)
+                    GLES.glEnable(GLES.GL_STENCIL_TEST)
                 }
             }
             if( sState.stencilFuncFunc!=cState.stencilFuncFunc ||
@@ -833,17 +833,17 @@ class InternalRenderState internal constructor()
                 cState.stencilFuncFunc = sState.stencilFuncFunc
                 cState.stencilFuncRef  = sState.stencilFuncRef
                 cState.stencilFuncMask = sState.stencilFuncMask
-                GLES31.glStencilFunc(cState.stencilFuncFunc, cState.stencilFuncRef, cState.stencilFuncMask)
+                GLES.glStencilFunc(cState.stencilFuncFunc, cState.stencilFuncRef, cState.stencilFuncMask)
             }
             if( sState.stencilMask!=cState.stencilMask )
             {
                 cState.stencilMask = sState.stencilMask
-                GLES31.glStencilMask(cState.stencilMask)
+                GLES.glStencilMask(cState.stencilMask)
             }
             if( sState.depthMask!=cState.depthMask )
             {
                 cState.depthMask = sState.depthMask
-                GLES31.glDepthMask(cState.depthMask==1)
+                GLES.glDepthMask(cState.depthMask==1)
             }
             if( sState.depthTest!=cState.depthTest )
             {
@@ -851,11 +851,11 @@ class InternalRenderState internal constructor()
 
                 if( cState.depthTest==0 )
                 {
-                    GLES31.glDisable(GLES31.GL_DEPTH_TEST)
+                    GLES.glDisable(GLES.GL_DEPTH_TEST)
                 }
                 else
                 {
-                    GLES31.glEnable(GLES31.GL_DEPTH_TEST)
+                    GLES.glEnable(GLES.GL_DEPTH_TEST)
                 }
             }
         }
diff --git a/src/main/java/org/distorted/library/main/InternalSurface.kt b/src/main/java/org/distorted/library/main/InternalSurface.kt
index 71a8651..111845e 100644
--- a/src/main/java/org/distorted/library/main/InternalSurface.kt
+++ b/src/main/java/org/distorted/library/main/InternalSurface.kt
@@ -19,7 +19,7 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 package org.distorted.library.main
 
-import android.opengl.GLES31
+import org.distorted.library.platform.GLES
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // common parent class of Texture & OutputSurface; so that we can store either in Nodes.
@@ -62,8 +62,8 @@ abstract class InternalSurface(create: Int, numfbos: Int, numcolors: Int, type:
 
         if( handle>0 )
         {
-            GLES31.glActiveTexture(GLES31.GL_TEXTURE0)
-            GLES31.glBindTexture(GLES31.GL_TEXTURE_2D, handle)
+            GLES.glActiveTexture(GLES.GL_TEXTURE0)
+            GLES.glBindTexture(GLES.GL_TEXTURE_2D, handle)
             return true
         }
 
diff --git a/src/main/java/org/distorted/library/mesh/MeshBase.kt b/src/main/java/org/distorted/library/mesh/MeshBase.kt
index ec36c59..e6ddbd7 100644
--- a/src/main/java/org/distorted/library/mesh/MeshBase.kt
+++ b/src/main/java/org/distorted/library/mesh/MeshBase.kt
@@ -20,7 +20,7 @@
 
 package org.distorted.library.mesh
 
-import android.opengl.GLES31
+import org.distorted.library.platform.GLES
 import org.distorted.library.effect.MatrixEffect
 import org.distorted.library.effect.VertexEffect
 import org.distorted.library.effectqueue.EffectQueue
@@ -114,8 +114,8 @@ abstract class MeshBase
         ///////////////////////////////////////////////////////////////////////////////////////////////////
         fun getUniforms(programH: Int, variant: Int)
         {
-            mCenterBlockIndex[variant] = GLES31.glGetUniformBlockIndex(programH, "componentCenter")
-            mAssocBlockIndex[variant] = GLES31.glGetUniformBlockIndex(programH, "componentAssociation")
+            mCenterBlockIndex[variant] = GLES.glGetUniformBlockIndex(programH, "componentCenter")
+            mAssocBlockIndex[variant] = GLES.glGetUniformBlockIndex(programH, "componentAssociation")
 
             if (mStride==0)
             {
@@ -123,8 +123,8 @@ abstract class MeshBase
                 val indices = IntArray(1)
                 val params = IntArray(1)
 
-                GLES31.glGetUniformIndices(programH, uniformNames, indices, 0)
-                GLES31.glGetActiveUniformsiv(programH, 1, indices, 0, GLES31.GL_UNIFORM_ARRAY_STRIDE, params, 0)
+                GLES.glGetUniformIndices(programH, uniformNames, indices, 0)
+                GLES.glGetActiveUniformsiv(programH, 1, indices, 0, GLES.GL_UNIFORM_ARRAY_STRIDE, params, 0)
 
                 mStride = params[0]/4
             }
@@ -176,9 +176,9 @@ abstract class MeshBase
 
         if (useCenters) mUBC = UniformBlockCenter()
 
-        mVBO1 = InternalBuffer(GLES31.GL_ARRAY_BUFFER, GLES31.GL_STATIC_DRAW)
-        mVBO2 = InternalBuffer(GLES31.GL_ARRAY_BUFFER, GLES31.GL_STATIC_DRAW)
-        mTFO  = InternalBuffer(GLES31.GL_TRANSFORM_FEEDBACK_BUFFER, GLES31.GL_STATIC_READ)
+        mVBO1 = InternalBuffer(GLES.GL_ARRAY_BUFFER, GLES.GL_STATIC_DRAW)
+        mVBO2 = InternalBuffer(GLES.GL_ARRAY_BUFFER, GLES.GL_STATIC_DRAW)
+        mTFO  = InternalBuffer(GLES.GL_TRANSFORM_FEEDBACK_BUFFER, GLES.GL_STATIC_READ)
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -207,14 +207,14 @@ abstract class MeshBase
             shallowCopy(original)
         }
 
-        mTFO = InternalBuffer(GLES31.GL_TRANSFORM_FEEDBACK_BUFFER, GLES31.GL_STATIC_READ)
+        mTFO = InternalBuffer(GLES.GL_TRANSFORM_FEEDBACK_BUFFER, GLES.GL_STATIC_READ)
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////////
     fun copy(original: MeshBase)
     {
         shallowCopy(original)
-        mVBO1 = InternalBuffer(GLES31.GL_ARRAY_BUFFER, GLES31.GL_STATIC_DRAW)
+        mVBO1 = InternalBuffer(GLES.GL_ARRAY_BUFFER, GLES.GL_STATIC_DRAW)
         mVertAttribs1 = original.mVertAttribs1?.copyOf()
     }
 
@@ -233,7 +233,7 @@ abstract class MeshBase
         mEffComponent = ArrayList()
         mEffComponent.addAll(original.mEffComponent)
 
-        mVBO2 = InternalBuffer(GLES31.GL_ARRAY_BUFFER, GLES31.GL_STATIC_DRAW)
+        mVBO2 = InternalBuffer(GLES.GL_ARRAY_BUFFER, GLES.GL_STATIC_DRAW)
         mVertAttribs2 = original.mVertAttribs2?.copyOf()
     }
 
@@ -640,14 +640,14 @@ abstract class MeshBase
      */
     fun copyTransformToVertex()
     {
-        val buffer = GLES31.glMapBufferRange(GLES31.GL_TRANSFORM_FEEDBACK_BUFFER, 0,
-                                             TRAN_SIZE*numVertices, GLES31.GL_MAP_READ_BIT) as ByteBuffer
+        val buffer = GLES.glMapBufferRange(GLES.GL_TRANSFORM_FEEDBACK_BUFFER, 0,
+                                             TRAN_SIZE*numVertices, GLES.GL_MAP_READ_BIT)
 
         val feedback = buffer.order(ByteOrder.nativeOrder()).asFloatBuffer()
         feedback[mVertAttribs1, 0, VERT1_ATTRIBS*numVertices]
         mVBO1.updateFloat(mVertAttribs1)
 
-        GLES31.glUnmapBuffer(GLES31.GL_TRANSFORM_FEEDBACK_BUFFER)
+        GLES.glUnmapBuffer(GLES.GL_TRANSFORM_FEEDBACK_BUFFER)
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -828,14 +828,14 @@ abstract class MeshBase
         }
 
         val indexA = mUBA.index
-        GLES31.glBindBufferBase(GLES31.GL_UNIFORM_BUFFER, ASSOC_UBO_BINDING, indexA)
-        GLES31.glUniformBlockBinding(programH, mAssocBlockIndex[variant], ASSOC_UBO_BINDING)
+        GLES.glBindBufferBase(GLES.GL_UNIFORM_BUFFER, ASSOC_UBO_BINDING, indexA)
+        GLES.glUniformBlockBinding(programH, mAssocBlockIndex[variant], ASSOC_UBO_BINDING)
 
         if (useCenters)
         {
             val indexC = mUBC!!.index
-            GLES31.glBindBufferBase(GLES31.GL_UNIFORM_BUFFER, CENTER_UBO_BINDING, indexC)
-            GLES31.glUniformBlockBinding(programH, mCenterBlockIndex[variant], CENTER_UBO_BINDING)
+            GLES.glBindBufferBase(GLES.GL_UNIFORM_BUFFER, CENTER_UBO_BINDING, indexC)
+            GLES.glUniformBlockBinding(programH, mCenterBlockIndex[variant], CENTER_UBO_BINDING)
         }
     }
 
@@ -852,53 +852,53 @@ abstract class MeshBase
         {
             DistortedProgram.ATTR_LAYOUT_PNTC ->
             {
-                GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, index1)
-                GLES31.glVertexAttribPointer(attr!![0], POS_DATA_SIZE, GLES31.GL_FLOAT, false, VERT1_SIZE, OFFSET_POS)
-                GLES31.glVertexAttribPointer(attr[1], NOR_DATA_SIZE, GLES31.GL_FLOAT, false, VERT1_SIZE, OFFSET_NOR)
-                GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, index2)
-                GLES31.glVertexAttribPointer(attr[2], TEX_DATA_SIZE, GLES31.GL_FLOAT, false, VERT2_SIZE, OFFSET_TEX)
-                GLES31.glVertexAttribPointer(attr[3], COM_DATA_SIZE, GLES31.GL_FLOAT, false, VERT2_SIZE, OFFSET_COM)
+                GLES.glBindBuffer(GLES.GL_ARRAY_BUFFER, index1)
+                GLES.glVertexAttribPointer(attr!![0], POS_DATA_SIZE, GLES.GL_FLOAT, false, VERT1_SIZE, OFFSET_POS)
+                GLES.glVertexAttribPointer(attr[1], NOR_DATA_SIZE, GLES.GL_FLOAT, false, VERT1_SIZE, OFFSET_NOR)
+                GLES.glBindBuffer(GLES.GL_ARRAY_BUFFER, index2)
+                GLES.glVertexAttribPointer(attr[2], TEX_DATA_SIZE, GLES.GL_FLOAT, false, VERT2_SIZE, OFFSET_TEX)
+                GLES.glVertexAttribPointer(attr[3], COM_DATA_SIZE, GLES.GL_FLOAT, false, VERT2_SIZE, OFFSET_COM)
             }
 
             DistortedProgram.ATTR_LAYOUT_PNT ->
             {
-                GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, index1)
-                GLES31.glVertexAttribPointer(attr!![0], POS_DATA_SIZE, GLES31.GL_FLOAT, false, VERT1_SIZE, OFFSET_POS)
-                GLES31.glVertexAttribPointer(attr[1], NOR_DATA_SIZE, GLES31.GL_FLOAT, false, VERT1_SIZE, OFFSET_NOR)
-                GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, index2)
-                GLES31.glVertexAttribPointer(attr[2], TEX_DATA_SIZE, GLES31.GL_FLOAT, false, VERT2_SIZE, OFFSET_TEX)
+                GLES.glBindBuffer(GLES.GL_ARRAY_BUFFER, index1)
+                GLES.glVertexAttribPointer(attr!![0], POS_DATA_SIZE, GLES.GL_FLOAT, false, VERT1_SIZE, OFFSET_POS)
+                GLES.glVertexAttribPointer(attr[1], NOR_DATA_SIZE, GLES.GL_FLOAT, false, VERT1_SIZE, OFFSET_NOR)
+                GLES.glBindBuffer(GLES.GL_ARRAY_BUFFER, index2)
+                GLES.glVertexAttribPointer(attr[2], TEX_DATA_SIZE, GLES.GL_FLOAT, false, VERT2_SIZE, OFFSET_TEX)
             }
 
             DistortedProgram.ATTR_LAYOUT_PNC ->
             {
-                GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, index1)
-                GLES31.glVertexAttribPointer(attr!![0], POS_DATA_SIZE, GLES31.GL_FLOAT, false, VERT1_SIZE, OFFSET_POS)
-                GLES31.glVertexAttribPointer(attr[1], NOR_DATA_SIZE, GLES31.GL_FLOAT, false, VERT1_SIZE, OFFSET_NOR)
-                GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, index2)
-                GLES31.glVertexAttribPointer(attr[2], COM_DATA_SIZE, GLES31.GL_FLOAT, false, VERT2_SIZE, OFFSET_COM)
+                GLES.glBindBuffer(GLES.GL_ARRAY_BUFFER, index1)
+                GLES.glVertexAttribPointer(attr!![0], POS_DATA_SIZE, GLES.GL_FLOAT, false, VERT1_SIZE, OFFSET_POS)
+                GLES.glVertexAttribPointer(attr[1], NOR_DATA_SIZE, GLES.GL_FLOAT, false, VERT1_SIZE, OFFSET_NOR)
+                GLES.glBindBuffer(GLES.GL_ARRAY_BUFFER, index2)
+                GLES.glVertexAttribPointer(attr[2], COM_DATA_SIZE, GLES.GL_FLOAT, false, VERT2_SIZE, OFFSET_COM)
             }
 
             DistortedProgram.ATTR_LAYOUT_PTC ->
             {
-                GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, index1)
-                GLES31.glVertexAttribPointer(attr!![0], POS_DATA_SIZE, GLES31.GL_FLOAT, false, VERT1_SIZE, OFFSET_POS)
-                GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, index2)
-                GLES31.glVertexAttribPointer(attr[1], TEX_DATA_SIZE, GLES31.GL_FLOAT, false, VERT2_SIZE, OFFSET_TEX)
-                GLES31.glVertexAttribPointer(attr[2], COM_DATA_SIZE, GLES31.GL_FLOAT, false, VERT2_SIZE, OFFSET_COM)
+                GLES.glBindBuffer(GLES.GL_ARRAY_BUFFER, index1)
+                GLES.glVertexAttribPointer(attr!![0], POS_DATA_SIZE, GLES.GL_FLOAT, false, VERT1_SIZE, OFFSET_POS)
+                GLES.glBindBuffer(GLES.GL_ARRAY_BUFFER, index2)
+                GLES.glVertexAttribPointer(attr[1], TEX_DATA_SIZE, GLES.GL_FLOAT, false, VERT2_SIZE, OFFSET_TEX)
+                GLES.glVertexAttribPointer(attr[2], COM_DATA_SIZE, GLES.GL_FLOAT, false, VERT2_SIZE, OFFSET_COM)
             }
 
             DistortedProgram.ATTR_LAYOUT_PT ->
             {
-                GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, index1)
-                GLES31.glVertexAttribPointer(attr!![0], POS_DATA_SIZE, GLES31.GL_FLOAT, false, VERT1_SIZE, OFFSET_POS)
-                GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, index2)
-                GLES31.glVertexAttribPointer(attr[1], TEX_DATA_SIZE, GLES31.GL_FLOAT, false, VERT2_SIZE, OFFSET_TEX)
+                GLES.glBindBuffer(GLES.GL_ARRAY_BUFFER, index1)
+                GLES.glVertexAttribPointer(attr!![0], POS_DATA_SIZE, GLES.GL_FLOAT, false, VERT1_SIZE, OFFSET_POS)
+                GLES.glBindBuffer(GLES.GL_ARRAY_BUFFER, index2)
+                GLES.glVertexAttribPointer(attr[1], TEX_DATA_SIZE, GLES.GL_FLOAT, false, VERT2_SIZE, OFFSET_TEX)
             }
 
             DistortedProgram.ATTR_LAYOUT_UNK -> DistortedLibrary.logMessage("Unknown attribute layout: "+program.mAttributeLayout)
         }
 
-        GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, 0)
+        GLES.glBindBuffer(GLES.GL_ARRAY_BUFFER, 0)
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -906,9 +906,9 @@ abstract class MeshBase
     {
         val index = mTFO.createImmediatelyFloat(numVertices*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)
+        GLES.glBindBuffer(GLES.GL_ARRAY_BUFFER, index)
+        GLES.glVertexAttribPointer(program.mAttribute!![0], POS_DATA_SIZE, GLES.GL_FLOAT, false, 0, 0)
+        GLES.glBindBuffer(GLES.GL_ARRAY_BUFFER, 0)
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/platform/GLES.kt b/src/main/java/org/distorted/library/platform/GLES.kt
new file mode 100644
index 0000000..4c6ff60
--- /dev/null
+++ b/src/main/java/org/distorted/library/platform/GLES.kt
@@ -0,0 +1,274 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2025 Leszek Koltunski  leszek@koltunski.pl                                          //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// This library is free software; you can redistribute it and/or                                 //
+// modify it under the terms of the GNU Lesser General Public                                    //
+// License as published by the Free Software Foundation; either                                  //
+// version 2.1 of the License, or (at your option) any later version.                            //
+//                                                                                               //
+// This library is distributed in the hope that it will be useful,                               //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                             //
+// Lesser General Public License for more details.                                               //
+//                                                                                               //
+// You should have received a copy of the GNU Lesser General Public                              //
+// License along with this library; if not, write to the Free Software                           //
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA                //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.platform
+
+import android.opengl.GLES31
+import java.nio.Buffer
+import java.nio.ByteBuffer
+import java.nio.FloatBuffer
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+object GLES
+{
+   const val GL_VENDOR                       = GLES31.GL_VENDOR
+   const val GL_VERSION                      = GLES31.GL_VERSION
+   const val GL_RENDERER                     = GLES31.GL_RENDERER
+
+   const val GL_MAX_TEXTURE_SIZE             = GLES31.GL_MAX_TEXTURE_SIZE
+   const val GL_MAX_VERTEX_UNIFORM_VECTORS   = GLES31.GL_MAX_VERTEX_UNIFORM_VECTORS
+   const val GL_MAX_FRAGMENT_UNIFORM_VECTORS = GLES31.GL_MAX_FRAGMENT_UNIFORM_VECTORS
+
+   const val GL_SHADING_LANGUAGE_VERSION     = GLES31.GL_SHADING_LANGUAGE_VERSION
+   const val GL_MAJOR_VERSION                = GLES31.GL_MAJOR_VERSION
+   const val GL_MINOR_VERSION                = GLES31.GL_MINOR_VERSION
+
+   const val GL_FLOAT                        = GLES31.GL_FLOAT
+   const val GL_POINTS                       = GLES31.GL_POINTS
+   const val GL_LINES                        = GLES31.GL_LINES
+
+   const val GL_UNIFORM_ARRAY_STRIDE         = GLES31.GL_UNIFORM_ARRAY_STRIDE
+   const val GL_STATIC_DRAW                  = GLES31.GL_STATIC_DRAW
+   const val GL_STATIC_READ                  = GLES31.GL_STATIC_READ
+   const val GL_DYNAMIC_DRAW                 = GLES31.GL_DYNAMIC_DRAW
+   const val GL_DYNAMIC_READ                 = GLES31.GL_DYNAMIC_READ
+
+   const val GL_UNIFORM_BUFFER               = GLES31.GL_UNIFORM_BUFFER
+   const val GL_ARRAY_BUFFER                 = GLES31.GL_ARRAY_BUFFER
+   const val GL_TRANSFORM_FEEDBACK_BUFFER    = GLES31.GL_TRANSFORM_FEEDBACK_BUFFER
+   const val GL_ATOMIC_COUNTER_BUFFER        = GLES31.GL_ATOMIC_COUNTER_BUFFER
+   const val GL_SHADER_STORAGE_BUFFER        = GLES31.GL_SHADER_STORAGE_BUFFER
+
+   const val GL_MAP_READ_BIT                 = GLES31.GL_MAP_READ_BIT
+   const val GL_MAP_WRITE_BIT                = GLES31.GL_MAP_WRITE_BIT
+   const val GL_MAP_INVALIDATE_BUFFER_BIT    = GLES31.GL_MAP_INVALIDATE_BUFFER_BIT
+   const val GL_COLOR_BUFFER_BIT             = GLES31.GL_COLOR_BUFFER_BIT
+   const val GL_STENCIL_BUFFER_BIT           = GLES31.GL_STENCIL_BUFFER_BIT
+   const val GL_DEPTH_BUFFER_BIT             = GLES31.GL_DEPTH_BUFFER_BIT
+   const val GL_SHADER_STORAGE_BARRIER_BIT   = GLES31.GL_SHADER_STORAGE_BARRIER_BIT
+   const val GL_ATOMIC_COUNTER_BARRIER_BIT   = GLES31.GL_ATOMIC_COUNTER_BARRIER_BIT
+
+   const val GL_STENCIL_TEST                 = GLES31.GL_STENCIL_TEST
+   const val GL_CULL_FACE                    = GLES31.GL_CULL_FACE
+   const val GL_FRONT                        = GLES31.GL_FRONT
+   const val GL_BACK                         = GLES31.GL_BACK
+   const val GL_BLEND                        = GLES31.GL_BLEND
+   const val GL_DEPTH_TEST                   = GLES31.GL_DEPTH_TEST
+
+   const val GL_TEXTURE_2D                   = GLES31.GL_TEXTURE_2D
+   const val GL_TEXTURE_WRAP_S               = GLES31.GL_TEXTURE_WRAP_S
+   const val GL_TEXTURE_WRAP_T               = GLES31.GL_TEXTURE_WRAP_T
+   const val GL_CLAMP_TO_EDGE                = GLES31.GL_CLAMP_TO_EDGE
+   const val GL_TRIANGLE_STRIP               = GLES31.GL_TRIANGLE_STRIP
+
+   const val GL_TEXTURE0                     = GLES31.GL_TEXTURE0
+   const val GL_TEXTURE1                     = GLES31.GL_TEXTURE1
+   const val GL_FRAMEBUFFER                  = GLES31.GL_FRAMEBUFFER
+   const val GL_COLOR_ATTACHMENT0            = GLES31.GL_COLOR_ATTACHMENT0
+   const val GL_DEPTH_ATTACHMENT             = GLES31.GL_DEPTH_ATTACHMENT
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   fun glGetUniformBlockIndex(programH: Int, name: String): Int
+   {
+        return GLES31.glGetUniformBlockIndex(programH,name)
+   }
+   fun glGetUniformIndices(programH: Int, uniformNames: Array<String>, uniformIndices: IntArray, uIndex: Int)
+   {
+        GLES31.glGetUniformIndices(programH,uniformNames,uniformIndices,uIndex)
+   }
+   fun glGetActiveUniformsiv(programH: Int, uniformCount: Int, uniformIndices: IntArray, uIndex: Int, pname: Int, params: IntArray, pIndex: Int)
+   {
+        GLES31.glGetActiveUniformsiv(programH,uniformCount,uniformIndices,uIndex,pname,params,pIndex)
+   }
+   fun glMapBufferRange(target: Int, offset: Int, length: Int, access: Int) : ByteBuffer
+   {
+        return GLES31.glMapBufferRange(target,offset,length,access) as ByteBuffer
+   }
+   fun glUnmapBuffer(target: Int)
+   {
+        GLES31.glUnmapBuffer(target)
+   }
+   fun glBindBufferBase(target: Int, index: Int, buffer: Int)
+   {
+        GLES31.glBindBufferBase(target, index, buffer)
+   }
+   fun glUniformBlockBinding(programH: Int, uniformBlockIndex: Int, uniformBlockBinding: Int)
+   {
+        GLES31.glUniformBlockBinding(programH, uniformBlockIndex, uniformBlockBinding)
+   }
+   fun glBindBuffer(target: Int, buffer: Int)
+   {
+        GLES31.glBindBuffer(target, buffer)
+   }
+   fun glVertexAttribPointer(indx: Int, size: Int, type: Int, normalized: Boolean, stride: Int, ptr: FloatBuffer)
+   {
+        GLES31.glVertexAttribPointer(indx, size, type, normalized, stride, ptr)
+   }
+   fun glViewport(x: Int, y: Int, width: Int, height: Int)
+   {
+        GLES31.glViewport(x, y, width, height)
+   }
+   fun glTexParameteri(target: Int, pname: Int, param: Int)
+   {
+        GLES31.glTexParameteri(target, pname, param)
+   }
+   fun glColorMask(red: Boolean, green: Boolean, blue: Boolean, alpha: Boolean)
+   {
+        GLES31.glColorMask(red, green, blue, alpha)
+   }
+   fun glStencilMask(mask: Int)
+   {
+        GLES31.glStencilMask(mask)
+   }
+   fun glDepthMask(flag: Boolean)
+   {
+        GLES31.glDepthMask(flag)
+   }
+   fun glClearColor(red: Float, green: Float, blue: Float, alpha: Float)
+   {
+        GLES31.glClearColor(red, green, blue, alpha)
+   }
+   fun glClear(mask: Int)
+   {
+        GLES31.glClear(mask)
+   }
+   fun glUniform1f(location: Int, x: Float)
+   {
+        GLES31.glUniform1f(location, x)
+   }
+   fun glUniform1i(location: Int, x: Int)
+   {
+        GLES31.glUniform1i(location, x)
+   }
+   fun glUniform1ui(location: Int, v0: Int)
+   {
+        GLES31.glUniform1ui(location, v0)
+   }
+   fun glUniform1fv(location: Int, count: Int, v: FloatArray, offset: Int)
+   {
+        GLES31.glUniform1fv(location, count, v, offset)
+   }
+   fun glUniform2f(location: Int, x: Float, y: Float)
+   {
+        GLES31.glUniform2f(location, x, y)
+   }
+   fun glUniform2ui(location: Int, v0: Int, v1: Int)
+   {
+        GLES31.glUniform2ui(location, v0, v1)
+   }
+   fun glUniform4iv(location: Int, count: Int, v: IntArray, offset: Int)
+   {
+        GLES31.glUniform4iv(location, count, v, offset)
+   }
+   fun glUniform4fv(location: Int, count: Int, v: FloatArray, offset: Int)
+   {
+        GLES31.glUniform4fv(location, count, v, offset)
+   }
+   fun glUniform4f(location: Int, x: Float, y: Float, z: Float, w: Float)
+   {
+        GLES31.glUniform4f(location, x,y,z,w)
+   }
+   fun glDrawArrays(mode: Int, first: Int, count: Int)
+   {
+        GLES31.glDrawArrays(mode, first, count)
+   }
+   fun glGenBuffers(n: Int, buffers: IntArray, offset: Int)
+   {
+        GLES31.glGenBuffers(n, buffers, offset)
+   }
+   fun glBufferData(target: Int, size: Int, data: Buffer?, usage: Int)
+   {
+        GLES31.glBufferData(target, size, data, usage)
+   }
+   fun glDeleteBuffers(n: Int, buffers: IntArray, offset: Int)
+   {
+        GLES31.glDeleteBuffers(n, buffers, offset)
+   }
+   fun glClearDepthf(depth: Float)
+   {
+        GLES31.glClearDepthf(depth)
+   }
+   fun glClearStencil(s: Int)
+   {
+        GLES31.glClearStencil(s)
+   }
+   fun glBindFramebuffer(target: Int, framebuffer: Int)
+   {
+        GLES31.glBindFramebuffer(target, framebuffer)
+   }
+   fun glFramebufferTexture2D(target: Int, attachment: Int, textarget: Int, texture: Int, level: Int)
+   {
+        GLES31.glFramebufferTexture2D(target, attachment, textarget, texture, level)
+   }
+   fun glMemoryBarrier(barriers: Int)
+   {
+        GLES31.glMemoryBarrier(barriers)
+   }
+   fun glActiveTexture(texture: Int)
+   {
+        GLES31.glActiveTexture(texture)
+   }
+   fun glBindTexture(target: Int, texture: Int)
+   {
+        GLES31.glBindTexture(target,texture)
+   }
+   fun glDisable(cap: Int)
+   {
+        GLES31.glDisable(cap)
+   }
+   fun glEnable(cap: Int)
+   {
+        GLES31.glEnable(cap)
+   }
+   fun glGetUniformLocation(program: Int, name: String): Int
+   {
+        return GLES31.glGetUniformLocation(program, name)
+   }
+   fun glLineWidth(width: Float)
+   {
+        GLES31.glLineWidth(width)
+   }
+   fun glBeginTransformFeedback(primitiveMode: Int)
+   {
+        GLES31.glBeginTransformFeedback(primitiveMode)
+   }
+   fun glEndTransformFeedback()
+   {
+        GLES31.glEndTransformFeedback()
+   }
+   fun glUniformMatrix4fv(location: Int, count: Int, transpose: Boolean, value: FloatArray, offset: Int)
+   {
+        GLES31.glUniformMatrix4fv(location,count,transpose,value,offset)
+   }
+   fun glGetString(name: Int) : String
+   {
+        return GLES31.glGetString(name)
+   }
+   fun glGetIntegerv(pname: Int, params: IntArray, offset: Int)
+   {
+        GLES31.glGetIntegerv(pname, params, offset)
+   }
+   fun glCullFace(mode: Int)
+   {
+        GLES31.glCullFace(mode)
+   }
+}
\ No newline at end of file
diff --git a/src/main/java/org/distorted/library/program/DistortedProgram.kt b/src/main/java/org/distorted/library/program/DistortedProgram.kt
index e70efb6..8861afe 100644
--- a/src/main/java/org/distorted/library/program/DistortedProgram.kt
+++ b/src/main/java/org/distorted/library/program/DistortedProgram.kt
@@ -20,7 +20,7 @@
 
 package org.distorted.library.program
 
-import android.opengl.GLES31
+import org.distorted.library.platform.GLES
 import org.distorted.library.main.DistortedLibrary
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -71,25 +71,25 @@ class DistortedProgram
         @Throws(FragmentCompilationException::class, VertexCompilationException::class)
         private fun compileShader(shaderType: Int, shaderSource: String): Int
         {
-            val shaderHandle = GLES31.glCreateShader(shaderType)
+            val shaderHandle = GLES.glCreateShader(shaderType)
 
             if (shaderHandle != 0)
             {
-                GLES31.glShaderSource(shaderHandle, shaderSource)
-                GLES31.glCompileShader(shaderHandle)
+                GLES.glShaderSource(shaderHandle, shaderSource)
+                GLES.glCompileShader(shaderHandle)
                 val compileStatus = IntArray(1)
-                GLES31.glGetShaderiv(shaderHandle, GLES31.GL_COMPILE_STATUS, compileStatus, 0)
+                GLES.glGetShaderiv(shaderHandle, GLES.GL_COMPILE_STATUS, compileStatus, 0)
 
-                if (compileStatus[0] != GLES31.GL_TRUE)
+                if (compileStatus[0] != GLES.GL_TRUE)
                 {
-                    val error = GLES31.glGetShaderInfoLog(shaderHandle)
+                    val error = GLES.glGetShaderInfoLog(shaderHandle)
 
-                    GLES31.glDeleteShader(shaderHandle)
+                    GLES.glDeleteShader(shaderHandle)
 
                     when (shaderType)
                     {
-                        GLES31.GL_VERTEX_SHADER   -> throw VertexCompilationException(error)
-                        GLES31.GL_FRAGMENT_SHADER -> throw FragmentCompilationException(error)
+                        GLES.GL_VERTEX_SHADER   -> throw VertexCompilationException(error)
+                        GLES.GL_FRAGMENT_SHADER -> throw FragmentCompilationException(error)
                         else                      -> throw RuntimeException(error)
                     }
                 }
@@ -121,36 +121,36 @@ class DistortedProgram
     @Throws(LinkingException::class)
     private fun createAndLinkProgram(verHandle: Int, fraHandle: Int, attributes: Array<String>?, feedbackVaryings: Array<String>?): Int
     {
-        val programHandle = GLES31.glCreateProgram()
+        val programHandle = GLES.glCreateProgram()
 
         if (programHandle != 0)
         {
-            GLES31.glAttachShader(programHandle, verHandle)
-            GLES31.glAttachShader(programHandle, fraHandle)
+            GLES.glAttachShader(programHandle, verHandle)
+            GLES.glAttachShader(programHandle, fraHandle)
 
             if (feedbackVaryings != null)
-                GLES31.glTransformFeedbackVaryings(programHandle, feedbackVaryings, GLES31.GL_INTERLEAVED_ATTRIBS)
+                GLES.glTransformFeedbackVaryings(programHandle, feedbackVaryings, GLES.GL_INTERLEAVED_ATTRIBS)
 
             if (attributes != null)
             {
                 val size = attributes.size
-                for (i in 0..<size) GLES31.glBindAttribLocation(programHandle, i, attributes[i])
+                for (i in 0..<size) GLES.glBindAttribLocation(programHandle, i, attributes[i])
             }
 
-            GLES31.glLinkProgram(programHandle)
+            GLES.glLinkProgram(programHandle)
 
             val linkStatus = IntArray(1)
-            GLES31.glGetProgramiv(programHandle, GLES31.GL_LINK_STATUS, linkStatus, 0)
+            GLES.glGetProgramiv(programHandle, GLES.GL_LINK_STATUS, linkStatus, 0)
 
-            if (linkStatus[0] != GLES31.GL_TRUE)
+            if (linkStatus[0] != GLES.GL_TRUE)
             {
-                val error = GLES31.glGetProgramInfoLog(programHandle)
-                GLES31.glDeleteProgram(programHandle)
+                val error = GLES.glGetProgramInfoLog(programHandle)
+                GLES.glDeleteProgram(programHandle)
                 throw LinkingException(error)
             }
 
             //final int[] numberOfUniforms = new int[1];
-            //GLES31.glGetProgramiv(programHandle, GLES31.GL_ACTIVE_UNIFORMS, numberOfUniforms, 0);
+            //GLES.glGetProgramiv(programHandle, GLES.GL_ACTIVE_UNIFORMS, numberOfUniforms, 0);
             //DistortedLibrary.logMessage("DistortedProgram: number of active uniforms="+numberOfUniforms[0]);
         }
 
@@ -347,7 +347,7 @@ class DistortedProgram
         val att = IntArray(mNumAttributes)
 
         for (i in 0..<mNumAttributes)
-            att[i] = GLES31.glGetAttribLocation(programHandle, mAttributeName[i])
+            att[i] = GLES.glGetAttribLocation(programHandle, mAttributeName[i])
 
         var emptyAttrs=0
         var i=0
@@ -436,7 +436,7 @@ class DistortedProgram
             val uniformName = mUniList!!.split(" ".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
 
             for (i in 0..<mNumUniforms)
-                mUniform!![i] = GLES31.glGetUniformLocation(programHandle, uniformName[i])
+                mUniform!![i] = GLES.glGetUniformLocation(programHandle, uniformName[i])
         }
         else mUniform = null
     }
@@ -454,8 +454,8 @@ class DistortedProgram
         val vertShader = readTextFileFromRawResource(vert, true)
         val fragShader = readTextFileFromRawResource(frag, false)
 
-        val vertShaderHandle = compileShader(GLES31.GL_VERTEX_SHADER  , vertHeader + vertShader)
-        val fragShaderHandle = compileShader(GLES31.GL_FRAGMENT_SHADER, fragHeader + fragShader)
+        val vertShaderHandle = compileShader(GLES.GL_VERTEX_SHADER  , vertHeader + vertShader)
+        val fragShaderHandle = compileShader(GLES.GL_FRAGMENT_SHADER, fragHeader + fragShader)
 
         programHandle = createAndLinkProgram(
             vertShaderHandle,
@@ -484,8 +484,8 @@ class DistortedProgram
         if (enabledVert != null) vertShader = insertEnabledEffects(vertShader!!, enabledVert)
         if (enabledFrag != null) fragShader = insertEnabledEffects(fragShader!!, enabledFrag)
 
-        val vertShaderHandle = compileShader(GLES31.GL_VERTEX_SHADER  , vertHeader + vertShader)
-        val fragShaderHandle = compileShader(GLES31.GL_FRAGMENT_SHADER, fragHeader + fragShader)
+        val vertShaderHandle = compileShader(GLES.GL_VERTEX_SHADER  , vertHeader + vertShader)
+        val fragShaderHandle = compileShader(GLES.GL_FRAGMENT_SHADER, fragHeader + fragShader)
 
         programHandle = createAndLinkProgram(
             vertShaderHandle,
@@ -525,8 +525,8 @@ class DistortedProgram
         doAttributes(vert, true)
         doAttributes(frag, false)
 
-        val vertHandle = compileShader(GLES31.GL_VERTEX_SHADER  , vert)
-        val fragHandle = compileShader(GLES31.GL_FRAGMENT_SHADER, frag)
+        val vertHandle = compileShader(GLES.GL_VERTEX_SHADER  , vert)
+        val fragHandle = compileShader(GLES.GL_FRAGMENT_SHADER, frag)
 
         programHandle = createAndLinkProgram(vertHandle, fragHandle, mAttributeName, null)
 
@@ -542,10 +542,10 @@ class DistortedProgram
     */
     fun useProgram()
     {
-        GLES31.glUseProgram(programHandle)
+        GLES.glUseProgram(programHandle)
 
         for (i in 0..<mNumAttributes)
-            GLES31.glEnableVertexAttribArray(mAttribute!![i])
+            GLES.glEnableVertexAttribArray(mAttribute!![i])
     }
 
     ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -554,10 +554,10 @@ class DistortedProgram
     */
     fun stopUsingProgram()
     {
-        GLES31.glUseProgram(0)
+        GLES.glUseProgram(0)
 
         for (i in 0..<mNumAttributes)
-            GLES31.glDisableVertexAttribArray(mAttribute!![i])
+            GLES.glDisableVertexAttribArray(mAttribute!![i])
     }
 }
 
