commit b11171e8350ae71b90a9cdc8ebf64f6a294b1c61
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Thu Dec 16 22:44:36 2021 +0100

    Add DistortedProgram.stopUsingProgram()

diff --git a/src/main/java/org/distorted/library/effect/PostprocessEffectBlurred.java b/src/main/java/org/distorted/library/effect/PostprocessEffectBlurred.java
index 33df079..d2299cf 100644
--- a/src/main/java/org/distorted/library/effect/PostprocessEffectBlurred.java
+++ b/src/main/java/org/distorted/library/effect/PostprocessEffectBlurred.java
@@ -186,6 +186,7 @@ abstract public class PostprocessEffectBlurred extends PostprocessEffect
     GLES30.glVertexAttribPointer(mProgram1.mAttribute[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions);
     GLES30.glVertexAttribPointer(mProgram1.mAttribute[1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadTexture);
     GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
+    mProgram1.stopUsingProgram();
 
     // vertical blur
     for(int i=0; i<=radius; i++) mOffsets[i] = offsetsCache[offset+i]*offsetCorrH;
@@ -208,6 +209,7 @@ abstract public class PostprocessEffectBlurred extends PostprocessEffect
     GLES30.glVertexAttribPointer(mProgram2.mAttribute[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions);
     GLES30.glVertexAttribPointer(mProgram2.mAttribute[1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadTexture);
     GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
+    mProgram1.stopUsingProgram();
 
     InternalRenderState.unuseStencilMark();
 
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java b/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
index 40a8036..304f95d 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
@@ -202,6 +202,7 @@ public class EffectQueuePostprocess extends EffectQueue
       }
 
     GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices() );
+    mPreProgram.stopUsingProgram();
 
     InternalRenderState.restoreBlending();
     InternalRenderState.unsetUpStencilMark();
diff --git a/src/main/java/org/distorted/library/main/DistortedLibrary.java b/src/main/java/org/distorted/library/main/DistortedLibrary.java
index 4bd23ea..31b024e 100644
--- a/src/main/java/org/distorted/library/main/DistortedLibrary.java
+++ b/src/main/java/org/distorted/library/main/DistortedLibrary.java
@@ -529,6 +529,7 @@ public class DistortedLibrary
     mesh.bindTransformAttribs(mNormalProgram);
     GLES30.glLineWidth(8.0f);
     GLES30.glDrawArrays(GLES30.GL_LINES, 0, 2*num);
+    mNormalProgram.stopUsingProgram();
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -569,6 +570,7 @@ public class DistortedLibrary
     GLES30.glEndTransformFeedback();
     mesh.copyTransformToVertex();
     GLES30.glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
+    mFullProgram.stopUsingProgram();
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -596,14 +598,9 @@ public class DistortedLibrary
 
       EffectQueue.send(queues, mMainOITProgramH, distance, mipmap, projection, inflate, 1 );
       GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices() );
+      mMainOITProgram.stopUsingProgram();
 
-      if( mesh.getShowNormals() )
-        {
-        mMainProgram.useProgram();
-        mesh.send(mMainProgramH,0);
-        EffectQueue.send(queues, mMainProgramH, distance, mipmap, projection, inflate, 0 );
-        displayNormals(projection,mesh);
-        }
+      if( mesh.getShowNormals() ) displayNormals(projection,mesh);
       }
     }
 
@@ -630,6 +627,7 @@ public class DistortedLibrary
 
       EffectQueue.send(queues, mMainProgramH, distance, mipmap, projection, inflate, 0 );
       GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices() );
+      mMainProgram.stopUsingProgram();
 
       if( mesh.getShowNormals() ) displayNormals(projection,mesh);
       }
@@ -642,12 +640,12 @@ public class DistortedLibrary
     if( mBlitProgram!=null )
       {
       mBlitProgram.useProgram();
-
       GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
       GLES30.glUniform1i(mBlitTextureH, 0);
       GLES30.glUniform1f( mBlitDepthH , 1.0f-surface.mNear);
       GLES30.glVertexAttribPointer(mBlitProgram.mAttribute[0], 2, GLES30.GL_FLOAT, false, 0, mQuadPositions);
       GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
+      mBlitProgram.stopUsingProgram();
       }
     }
 
@@ -658,13 +656,13 @@ public class DistortedLibrary
     if( mBlitDepthProgram!=null )
       {
       mBlitDepthProgram.useProgram();
-
       GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
       GLES30.glUniform1i(mBlitDepthTextureH, 0);
       GLES30.glUniform1i(mBlitDepthDepthTextureH, 1);
       GLES30.glUniform2f(mBlitDepthTexCorrH, corrW, corrH );
       GLES30.glVertexAttribPointer(mBlitDepthProgram.mAttribute[0], 2, GLES30.GL_FLOAT, false, 0, mQuadPositions);
       GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
+      mBlitDepthProgram.stopUsingProgram();
       }
     }
 
@@ -801,13 +799,13 @@ public class DistortedLibrary
       }
 
     mOITClearProgram.useProgram();
-
     GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
     GLES30.glUniform2f(mOITClearTexCorrH, 1.0f, 1.0f );   // corrections do not really matter here - only present because of common vertex shader.
     GLES30.glUniform1f( mOITClearDepthH , 1.0f);          // likewise depth
     GLES30.glUniform2ui(mOITClearSizeH, surface.mWidth, surface.mHeight);
     GLES30.glVertexAttribPointer(mOITClearProgram.mAttribute[0], 2, GLES30.GL_FLOAT, false, 0, mQuadPositions);
     GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
+    mOITClearProgram.stopUsingProgram();
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -818,7 +816,6 @@ public class DistortedLibrary
     if( mOITBuildProgram!=null )
       {
       mOITBuildProgram.useProgram();
-
       GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
       GLES30.glUniform1i(mOITBuildTextureH, 0);
       GLES30.glUniform1i(mOITBuildDepthTextureH, 1);
@@ -828,6 +825,7 @@ public class DistortedLibrary
       GLES30.glUniform1f(mOITBuildDepthH , 1.0f-surface.mNear);
       GLES30.glVertexAttribPointer(mOITBuildProgram.mAttribute[0], 2, GLES30.GL_FLOAT, false, 0, mQuadPositions);
       GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
+      mOITBuildProgram.stopUsingProgram();
       }
     }
 
@@ -839,7 +837,6 @@ public class DistortedLibrary
     if( mOITCollapseProgram!=null )
       {
       mOITCollapseProgram.useProgram();
-
       GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
       GLES30.glUniform1i(mOITCollapseDepthTextureH, 1);
       GLES30.glUniform2f(mOITCollapseTexCorrH, corrW, corrH );
@@ -847,6 +844,7 @@ public class DistortedLibrary
       GLES30.glUniform1f( mOITCollapseDepthH , 1.0f-surface.mNear);
       GLES30.glVertexAttribPointer(mOITCollapseProgram.mAttribute[0], 2, GLES30.GL_FLOAT, false, 0, mQuadPositions);
       GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
+      mOITCollapseProgram.stopUsingProgram();
       }
     }
 
@@ -858,13 +856,13 @@ public class DistortedLibrary
     if( mOITRenderProgram!=null )
       {
       mOITRenderProgram.useProgram();
-
       GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
       GLES30.glUniform2f(mOITRenderTexCorrH, corrW, corrH );
       GLES30.glUniform2ui(mOITRenderSizeH, surface.mWidth, surface.mHeight);
       GLES30.glUniform1f( mOITRenderDepthH , 1.0f-surface.mNear);
       GLES30.glVertexAttribPointer(mOITRenderProgram.mAttribute[0], 2, GLES30.GL_FLOAT, false, 0, mQuadPositions);
       GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
+      mOITRenderProgram.stopUsingProgram();
       }
     }
 
diff --git a/src/main/java/org/distorted/library/program/DistortedProgram.java b/src/main/java/org/distorted/library/program/DistortedProgram.java
index 95a4741..89ed554 100644
--- a/src/main/java/org/distorted/library/program/DistortedProgram.java
+++ b/src/main/java/org/distorted/library/program/DistortedProgram.java
@@ -43,11 +43,11 @@ public class DistortedProgram
 /**
  * List of Attributes (OpenGL ES 3.0: 'in' variables), in the same order as declared in the shader source.
  */
-  public final int[] mAttribute;
+  public int[] mAttribute;
 /**
  * List of Uniforms, in the same order as declared in the shader source.
  */
-  public final int[] mUniform;
+  public int[] mUniform;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -330,25 +330,9 @@ public class DistortedProgram
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public DistortedProgram(final InputStream vert, final InputStream frag, final String vertHeader, final String fragHeader,
-                          int glslVersion, final String[] feedback )
-  throws FragmentCompilationException,VertexCompilationException,LinkingException
-    {
-    init(glslVersion);
-
-    final String vertShader = readTextFileFromRawResource(vert, true );
-    final String fragShader = readTextFileFromRawResource(frag, false);
-
-    final int vertShaderHandle = compileShader(GLES30.GL_VERTEX_SHADER  , vertHeader + vertShader);
-    final int fragShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragHeader + fragShader);
-
-    mProgramHandle = createAndLinkProgram(vertShaderHandle, fragShaderHandle, mAttributeName, glslVersion>= 300 ? feedback:null );
 
+  private void setUpAttributes()
+    {
     mAttribute = new int[mNumAttributes];
 
     for(int i=0; i<mNumAttributes; i++)
@@ -356,6 +340,29 @@ public class DistortedProgram
       mAttribute[i] = GLES30.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
       }
 
+    int emptyAttrs = 0;
+
+    for(int i=0; i<mNumAttributes; i++)
+      {
+      if( mAttribute[i] < 0 )
+        {
+        emptyAttrs++;
+
+        for(int j=i; j<mNumAttributes-1; j++)
+          {
+          mAttribute[j] = mAttribute[j+1];
+          mAttributeName[j] = mAttributeName[j+1];
+          }
+        }
+      }
+
+    mNumAttributes -= emptyAttrs;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void setUpUniforms()
+    {
     if( mNumUniforms>0 )
       {
       mUniform = new int[mNumUniforms];
@@ -369,6 +376,30 @@ public class DistortedProgram
     else mUniform = null;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Only for use by the library itself.
+ *
+ * @y.exclude
+ */
+  public DistortedProgram(final InputStream vert, final InputStream frag, final String vertHeader, final String fragHeader,
+                          int glslVersion, final String[] feedback )
+  throws FragmentCompilationException,VertexCompilationException,LinkingException
+    {
+    init(glslVersion);
+
+    final String vertShader = readTextFileFromRawResource(vert, true );
+    final String fragShader = readTextFileFromRawResource(frag, false);
+
+    final int vertShaderHandle = compileShader(GLES30.GL_VERTEX_SHADER  , vertHeader + vertShader);
+    final int fragShaderHandle = compileShader(GLES30.GL_FRAGMENT_SHADER, fragHeader + fragShader);
+
+    mProgramHandle = createAndLinkProgram(vertShaderHandle, fragShaderHandle, mAttributeName, glslVersion>= 300 ? feedback:null );
+
+    setUpAttributes();
+    setUpUniforms();
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Only for use by the library itself.
@@ -392,24 +423,8 @@ public class DistortedProgram
 
     mProgramHandle = createAndLinkProgram(vertShaderHandle, fragShaderHandle, mAttributeName, glslVersion>= 300 ? feedback:null );
 
-    mAttribute = new int[mNumAttributes];
-
-    for(int i=0; i<mNumAttributes; i++)
-      {
-      mAttribute[i] = GLES30.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
-      }
-
-    if( mNumUniforms>0 )
-      {
-      mUniform = new int[mNumUniforms];
-      mUniformName = mUniList.split(" ");
-
-      for(int i=0; i<mNumUniforms; i++)
-        {
-        mUniform[i] = GLES30.glGetUniformLocation( mProgramHandle, mUniformName[i]);
-        }
-      }
-    else mUniform = null;
+    setUpAttributes();
+    setUpUniforms();
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -434,9 +449,9 @@ public class DistortedProgram
  *
  * @param vertex   Vertex shader code.
  * @param fragment Fragment shader code.
- * @throws FragmentCompilationException
- * @throws VertexCompilationException
- * @throws LinkingException
+ * @throws FragmentCompilationException fragment shader failed to compile
+ * @throws VertexCompilationException vertex shader failed to compile
+ * @throws LinkingException shaders failed to link
  */
   public DistortedProgram(final String vertex, final String fragment)
   throws FragmentCompilationException,VertexCompilationException,LinkingException
@@ -451,24 +466,8 @@ public class DistortedProgram
 
     mProgramHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, mAttributeName, null );
 
-    mAttribute = new int[mNumAttributes];
-
-    for(int i=0; i<mNumAttributes; i++)
-      {
-      mAttribute[i] = GLES30.glGetAttribLocation( mProgramHandle, mAttributeName[i]);
-      }
-
-    if( mNumUniforms>0 )
-      {
-      mUniform = new int[mNumUniforms];
-      mUniformName = mUniList.split(" ");
-
-      for(int i=0; i<mNumUniforms; i++)
-        {
-        mUniform[i] = GLES30.glGetUniformLocation( mProgramHandle, mUniformName[i]);
-        }
-      }
-    else mUniform = null;
+    setUpAttributes();
+    setUpUniforms();
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -491,7 +490,25 @@ public class DistortedProgram
     GLES30.glUseProgram(mProgramHandle);
 
     for(int i=0; i<mNumAttributes; i++)
+      {
       GLES30.glEnableVertexAttribArray(mAttribute[i]);
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Disable all vertex attribute arrays.
+ *
+ * Needs to be called from a thread holding the OpenGL context.
+ */
+  public void stopUsingProgram()
+    {
+    GLES30.glUseProgram(0);
+
+    for(int i=0; i<mNumAttributes; i++)
+      {
+      GLES30.glDisableVertexAttribArray(mAttribute[i]);
+      }
     }
   }
 
