commit a13dde7740a1bd259462da3e58b048faae1664dc
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Wed Jul 25 21:43:30 2018 +0100

    Progress with a more generic 'preprocess' stage of Postprocessing Effects.

diff --git a/src/main/java/org/distorted/library/main/Distorted.java b/src/main/java/org/distorted/library/main/Distorted.java
index 9927c15..79b35ed 100644
--- a/src/main/java/org/distorted/library/main/Distorted.java
+++ b/src/main/java/org/distorted/library/main/Distorted.java
@@ -89,9 +89,9 @@ public class Distorted
    */
   public static final int FBO_QUEUE_SIZE = 4;
   /**
-   * Number of Main program variants (ATM 2: main and main OIT)
+   * Number of Main program variants (ATM 3: MAIN, MAIN OIT, PREPROCESS)
    */
-  public static final int MAIN_VARIANTS = 2;
+  public static final int MAIN_VARIANTS = 3;
 
   private static boolean mInitialized=false;
 
@@ -189,6 +189,15 @@ public class Distorted
       exception = ex;
       }
 
+    try
+      {
+      EffectQueuePostprocess.createPrograms(resources);
+      }
+    catch(Exception ex)
+      {
+      exception = ex;
+      }
+
     try
       {
       PostprocessEffect.createPrograms();
diff --git a/src/main/java/org/distorted/library/main/DistortedEffects.java b/src/main/java/org/distorted/library/main/DistortedEffects.java
index d88ea08..c220fbf 100644
--- a/src/main/java/org/distorted/library/main/DistortedEffects.java
+++ b/src/main/java/org/distorted/library/main/DistortedEffects.java
@@ -443,7 +443,15 @@ public class DistortedEffects
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  void drawPrivOIT(float halfW, float halfH, MeshObject mesh, DistortedOutputSurface surface, long currTime, float marginInPixels)
+  void send(float halfW, float halfH, float halfZ, float margin, DistortedOutputSurface surface, int variant)
+    {
+    mM.send(surface,halfW,halfH,halfZ,margin,variant);
+    mV.send(variant);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void drawPrivOIT(float halfW, float halfH, MeshObject mesh, DistortedOutputSurface surface, long currTime)
     {
     float halfZ = halfW*mesh.zFactor;
 
@@ -465,7 +473,7 @@ public class DistortedEffects
     GLES31.glVertexAttribPointer(mMainOITProgram.mAttribute[2], MeshObject.TEX_DATA_SIZE, GLES31.GL_FLOAT, false, MeshObject.VERTSIZE, MeshObject.OFFSET2);
     GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, 0);
 
-    mM.send(surface,halfW,halfH,halfZ,marginInPixels,1);
+    mM.send(surface,halfW,halfH,halfZ,0,1);
     mV.send(1);
     mF.send(1);
 
@@ -476,7 +484,7 @@ public class DistortedEffects
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  void drawPriv(float halfW, float halfH, MeshObject mesh, DistortedOutputSurface surface, long currTime, float marginInPixels)
+  void drawPriv(float halfW, float halfH, MeshObject mesh, DistortedOutputSurface surface, long currTime)
     {
     float halfZ = halfW*mesh.zFactor;
 
@@ -496,7 +504,7 @@ public class DistortedEffects
     GLES31.glVertexAttribPointer(mMainProgram.mAttribute[2], MeshObject.TEX_DATA_SIZE, GLES31.GL_FLOAT, false, MeshObject.VERTSIZE, MeshObject.OFFSET2);
     GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, 0);
 
-    mM.send(surface,halfW,halfH,halfZ,marginInPixels,0);
+    mM.send(surface,halfW,halfH,halfZ,0,0);
     mV.send(0);
     mF.send(0);
 
diff --git a/src/main/java/org/distorted/library/main/DistortedNode.java b/src/main/java/org/distorted/library/main/DistortedNode.java
index f8b1e59..0a65785 100644
--- a/src/main/java/org/distorted/library/main/DistortedNode.java
+++ b/src/main/java/org/distorted/library/main/DistortedNode.java
@@ -239,23 +239,6 @@ public class DistortedNode implements DistortedMaster.Slave
     if( mParent!=null ) mParent.adjustIsomorphism();
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  int markStencilAndDepth(long currTime, DistortedOutputSurface surface, EffectQueuePostprocess queue)
-    {
-    DistortedSurface input = mNumChildren[0]==0 ? mSurface : mData.mFBO;
-
-    if( input.setAsInput() )
-      {
-      DistortedRenderState.setUpStencilMark();
-      mEffects.drawPriv(mSurface.getWidth() /2.0f, mSurface.getHeight()/2.0f, mMesh, surface, currTime, queue.getHalo()*surface.mMipmap);
-      DistortedRenderState.unsetUpStencilMark();
-
-      return 1;
-      }
-    return 0;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // return the total number of render calls issued
 
@@ -267,7 +250,7 @@ public class DistortedNode implements DistortedMaster.Slave
       {
       mState.apply();
       GLES31.glDisable(GLES31.GL_BLEND);
-      mEffects.drawPriv(mSurface.getWidth()/2.0f, mSurface.getHeight()/2.0f, mMesh, surface, currTime, 0);
+      mEffects.drawPriv(mSurface.getWidth()/2.0f, mSurface.getHeight()/2.0f, mMesh, surface, currTime);
       GLES31.glEnable(GLES31.GL_BLEND);
       return 1;
       }
@@ -285,7 +268,7 @@ public class DistortedNode implements DistortedMaster.Slave
     if( input.setAsInput() )
       {
       mState.apply();
-      mEffects.drawPrivOIT(mSurface.getWidth()/2.0f, mSurface.getHeight()/2.0f, mMesh, surface, currTime, 0);
+      mEffects.drawPrivOIT(mSurface.getWidth()/2.0f, mSurface.getHeight()/2.0f, mMesh, surface, currTime);
       return 1;
       }
 
@@ -302,7 +285,7 @@ public class DistortedNode implements DistortedMaster.Slave
     if( input.setAsInput() )
       {
       mState.apply();
-      mEffects.drawPriv(mSurface.getWidth()/2.0f, mSurface.getHeight()/2.0f, mMesh, surface, currTime, 0);
+      mEffects.drawPriv(mSurface.getWidth()/2.0f, mSurface.getHeight()/2.0f, mMesh, surface, currTime);
       return 1;
       }
 
@@ -737,15 +720,26 @@ public class DistortedNode implements DistortedMaster.Slave
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
- * Returns the DistortedInputSurface object that's in the Node.
+ * Returns the DistortedSurface object that's in the Node.
  *
- * @return The DistortedInputSurface contained in the Node.
+ * @return The DistortedSurface contained in the Node.
  */
   public DistortedSurface getSurface()
     {
     return mSurface;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+  /**
+   * Returns the DistortedSurface object that's in the Node.
+   *
+   * @return The DistortedSurface contained in the Node (if a leaf), or the FBO (if an internal Node)
+   */
+  public DistortedSurface getInternalSurface()
+    {
+    return mNumChildren[0]==0 ? mSurface : mData.mFBO;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Returns the Mesh object that's in the Node.
diff --git a/src/main/java/org/distorted/library/main/DistortedOutputSurface.java b/src/main/java/org/distorted/library/main/DistortedOutputSurface.java
index 0ee80d8..d1922a6 100644
--- a/src/main/java/org/distorted/library/main/DistortedOutputSurface.java
+++ b/src/main/java/org/distorted/library/main/DistortedOutputSurface.java
@@ -460,7 +460,7 @@ public abstract class DistortedOutputSurface extends DistortedSurface implements
             }
           else
             {
-            for(int j=bucketChange; j<i; j++) numRenders += lastQueue.preprocess( mBuffer,children.get(j), time);
+            for(int j=bucketChange; j<i; j++) numRenders += lastQueue.preprocess( mBuffer,children.get(j) );
             numRenders += lastQueue.postprocess(mBuffer);
 
             if( oit )
@@ -484,7 +484,7 @@ public abstract class DistortedOutputSurface extends DistortedSurface implements
 
         if( i==numChildren-1 )
           {
-          for(int j=bucketChange; j<numChildren; j++) numRenders += currQueue.preprocess(mBuffer,children.get(j), time);
+          for(int j=bucketChange; j<numChildren; j++) numRenders += currQueue.preprocess( mBuffer,children.get(j) );
           numRenders += currQueue.postprocess(mBuffer);
 
           if( oit )
diff --git a/src/main/java/org/distorted/library/main/DistortedRenderState.java b/src/main/java/org/distorted/library/main/DistortedRenderState.java
index dcdfde3..dde55ea 100644
--- a/src/main/java/org/distorted/library/main/DistortedRenderState.java
+++ b/src/main/java/org/distorted/library/main/DistortedRenderState.java
@@ -459,7 +459,7 @@ public class DistortedRenderState
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  static void setUpStencilMark()
+  static void setUpStencilMark(boolean color)
     {
     sState.stencilTest = cState.stencilTest;
 
@@ -501,14 +501,16 @@ public class DistortedRenderState
     sState.colorMaskB = cState.colorMaskB;
     sState.colorMaskA = cState.colorMaskA;
 
-    if( cState.colorMaskR!=0 || cState.colorMaskG!=0 || cState.colorMaskB!=0 || cState.colorMaskA!=0 )
+    int clr = color ? 1:0;
+
+    if( cState.colorMaskR!=clr || cState.colorMaskG!=clr || cState.colorMaskB!=clr || cState.colorMaskA!=clr )
       {
-      cState.colorMaskR = 0;
-      cState.colorMaskG = 0;
-      cState.colorMaskB = 0;
-      cState.colorMaskA = 0;
+      cState.colorMaskR = clr;
+      cState.colorMaskG = clr;
+      cState.colorMaskB = clr;
+      cState.colorMaskA = clr;
       //android.util.Log.d("State", "switch off color writing");
-      GLES31.glColorMask(false,false,false,false);
+      GLES31.glColorMask(color,color,color,color);
       }
 
     sState.depthMask = cState.depthMask;
diff --git a/src/main/java/org/distorted/library/main/DistortedScreen.java b/src/main/java/org/distorted/library/main/DistortedScreen.java
index f128afd..c8333e9 100644
--- a/src/main/java/org/distorted/library/main/DistortedScreen.java
+++ b/src/main/java/org/distorted/library/main/DistortedScreen.java
@@ -128,7 +128,7 @@ public class DistortedScreen extends DistortedFramebuffer
 
     if( mShowFPS && fpsTexture.setAsInput())
       {
-      fpsEffects.drawPriv(fpsW / 2.0f, fpsH / 2.0f, fpsMesh, this, time, 0);
+      fpsEffects.drawPriv(fpsW / 2.0f, fpsH / 2.0f, fpsMesh, this, time);
       }
 
     if( ++mCurRenderedFBO>=Distorted.FBO_QUEUE_SIZE )
diff --git a/src/main/java/org/distorted/library/main/EffectQueuePostprocess.java b/src/main/java/org/distorted/library/main/EffectQueuePostprocess.java
index f12e0bc..ef7613f 100644
--- a/src/main/java/org/distorted/library/main/EffectQueuePostprocess.java
+++ b/src/main/java/org/distorted/library/main/EffectQueuePostprocess.java
@@ -19,11 +19,18 @@
 
 package org.distorted.library.main;
 
+import android.content.res.Resources;
 import android.opengl.GLES31;
+import android.util.Log;
 
+import org.distorted.library.R;
 import org.distorted.library.effect.EffectType;
 import org.distorted.library.effect.PostprocessEffect;
+import org.distorted.library.effect.VertexEffect;
 import org.distorted.library.message.EffectMessage;
+import org.distorted.library.program.DistortedProgram;
+
+import java.io.InputStream;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -34,6 +41,9 @@ class EffectQueuePostprocess extends EffectQueue
 
   private int mHalo;
 
+  static DistortedProgram mPreProgram;
+  static int mPreColorH;
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   EffectQueuePostprocess(long id)
@@ -78,18 +88,53 @@ class EffectQueuePostprocess extends EffectQueue
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+  /**
+   * Only for use by the library itself.
+   *
+   * @y.exclude
+   */
+  public static void createPrograms(Resources resources)
+    {
+    final InputStream mainVertStream = resources.openRawResource(R.raw.main_vertex_shader);
+    final InputStream mainFragStream = resources.openRawResource(R.raw.preprocess_fragment_shader);
+
+    int numV = VertexEffect.getNumEnabled();
+
+    String mainVertHeader= Distorted.GLSL_VERSION + ("#define NUM_VERTEX "   + ( numV>0 ? DistortedEffects.getMax(EffectType.VERTEX  ) : 0 ) + "\n");
+    String mainFragHeader= Distorted.GLSL_VERSION + "\n";
+
+    String enabledEffectV= VertexEffect.getGLSL();
+
+    try
+      {
+      mPreProgram = new DistortedProgram(mainVertStream, mainFragStream, mainVertHeader, mainFragHeader,
+                                         enabledEffectV, null, Distorted.GLSL, null);
+      }
+    catch(Exception e)
+      {
+      Log.e("POSTPROCESS", e.getClass().getSimpleName()+" trying to compile PRE program: "+e.getMessage());
+      throw new RuntimeException(e.getMessage());
+      }
+
+    int preProgramH = mPreProgram.getProgramHandle();
+    EffectQueueVertex.getUniforms( preProgramH,2 );
+    EffectQueueMatrix.getUniforms( preProgramH,2 );
+    mPreColorH= GLES31.glGetUniformLocation( preProgramH, "u_Color");
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// TODO
 
-  int getHalo()
+  private boolean getWriteColor()
     {
-    return mNumEffects>0 ? mHalo : 0;
+    return false;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// TODO  (now only really works in case of 1 effect!)
 
-  int getQuality()
+  private int getHalo()
     {
-    return mNumEffects>0 ? ((PostprocessEffect)mEffects[0]).getQuality() : 0;
+    return mNumEffects>0 ? mHalo : 0;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -101,17 +146,54 @@ class EffectQueuePostprocess extends EffectQueue
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+// TODO  (now only really works in case of 1 effect!)
 
-  int preprocess(DistortedOutputSurface[] buffers, DistortedNode node, long time)
+  int getQuality()
+    {
+    return mNumEffects>0 ? ((PostprocessEffect)mEffects[0]).getQuality() : 0;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int preprocess(DistortedOutputSurface[] buffers, DistortedNode node)
     {
-    int numRenders = 0;
     int quality = getInternalQuality();
+    DistortedOutputSurface surface = buffers[quality];
+
+    surface.setAsOutput();
+    DistortedSurface input = node.getInternalSurface();
 
-    buffers[quality].setAsOutput();
+    if( input.setAsInput() )
+      {
+      MeshObject    mesh = node.getMesh();
+      boolean writeColor = getWriteColor();
+      float       margin = getHalo()*surface.mMipmap;
 
-    numRenders += node.markStencilAndDepth(time,buffers[quality],this);
+      float halfW = input.getWidth() / 2.0f;
+      float halfH = input.getHeight()/ 2.0f;
+      float halfZ = halfW*mesh.zFactor;
 
-    return numRenders;
+      DistortedRenderState.setUpStencilMark(writeColor);
+
+      GLES31.glViewport(0, 0, surface.mWidth, surface.mHeight );
+
+      mPreProgram.useProgram();
+
+      GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, mesh.mAttVBO[0]);
+      GLES31.glVertexAttribPointer(mPreProgram.mAttribute[0], MeshObject.POS_DATA_SIZE, GLES31.GL_FLOAT, false, MeshObject.VERTSIZE, MeshObject.OFFSET0);
+      GLES31.glVertexAttribPointer(mPreProgram.mAttribute[1], MeshObject.NOR_DATA_SIZE, GLES31.GL_FLOAT, false, MeshObject.VERTSIZE, MeshObject.OFFSET1);
+      GLES31.glVertexAttribPointer(mPreProgram.mAttribute[2], MeshObject.TEX_DATA_SIZE, GLES31.GL_FLOAT, false, MeshObject.VERTSIZE, MeshObject.OFFSET2);
+      GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, 0);
+
+      node.getEffects().send(halfW, halfH, halfZ, margin, surface, 2);
+
+      GLES31.glDrawArrays(GLES31.GL_TRIANGLE_STRIP, 0, mesh.numVertices);
+
+      DistortedRenderState.unsetUpStencilMark();
+
+      return 1;
+      }
+    return 0;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/program/DistortedProgram.java b/src/main/java/org/distorted/library/program/DistortedProgram.java
index 67214b4..e876216 100644
--- a/src/main/java/org/distorted/library/program/DistortedProgram.java
+++ b/src/main/java/org/distorted/library/program/DistortedProgram.java
@@ -348,18 +348,19 @@ android.util.Log.d("Program", end.substring(0,40));
  *
  * @y.exclude
  */
-  public DistortedProgram(final InputStream vertex, final InputStream fragment, final String vertexHeader, final String fragmentHeader, int glslVersion, final String[] feedback )
-  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
+  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 vertexShader   = readTextFileFromRawResource(vertex  , true );
-    final String fragmentShader = readTextFileFromRawResource(fragment, false);
+    final String vertShader = readTextFileFromRawResource(vert, true );
+    final String fragShader = readTextFileFromRawResource(frag, false);
 
-    final int vertexShaderHandle   = compileShader(GLES31.GL_VERTEX_SHADER  , vertexHeader   + vertexShader  );
-    final int fragmentShaderHandle = compileShader(GLES31.GL_FRAGMENT_SHADER, fragmentHeader + fragmentShader);
+    final int vertShaderHandle = compileShader(GLES31.GL_VERTEX_SHADER  , vertHeader + vertShader);
+    final int fragShaderHandle = compileShader(GLES31.GL_FRAGMENT_SHADER, fragHeader + fragShader);
 
-    mProgramHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, mAttributeName, glslVersion>= 300 ? feedback:null );
+    mProgramHandle = createAndLinkProgram(vertShaderHandle, fragShaderHandle, mAttributeName, glslVersion>= 300 ? feedback:null );
 
     mAttribute = new int[mNumAttributes];
 
@@ -387,22 +388,22 @@ android.util.Log.d("Program", end.substring(0,40));
  *
  * @y.exclude
  */
-  public DistortedProgram(final InputStream vertex, final InputStream fragment, final String vertexHeader, final String fragmentHeader,
-                          final String enabledVertex, final String enabledFragment, int glslVersion, final String[] feedback )
-  throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
+  public DistortedProgram(final InputStream vert, final InputStream frag, final String vertHeader, final String fragHeader,
+                          final String enabledVert, final String enabledFrag, int glslVersion, final String[] feedback )
+  throws FragmentCompilationException,VertexCompilationException,LinkingException
     {
     init(glslVersion);
 
-    String vertexShader   = readTextFileFromRawResource(vertex  , true );
-    String fragmentShader = readTextFileFromRawResource(fragment, false);
+    String vertShader = readTextFileFromRawResource( vert, true );
+    String fragShader = readTextFileFromRawResource( frag, false);
 
-    vertexShader   = insertEnabledEffects(vertexShader  ,enabledVertex  );
-    fragmentShader = insertEnabledEffects(fragmentShader,enabledFragment);
+    if( enabledVert!=null ) vertShader = insertEnabledEffects(vertShader,enabledVert);
+    if( enabledFrag!=null ) fragShader = insertEnabledEffects(fragShader,enabledFrag);
 
-    final int vertexShaderHandle   = compileShader(GLES31.GL_VERTEX_SHADER  , vertexHeader   + vertexShader  );
-    final int fragmentShaderHandle = compileShader(GLES31.GL_FRAGMENT_SHADER, fragmentHeader + fragmentShader);
+    final int vertShaderHandle = compileShader(GLES31.GL_VERTEX_SHADER  , vertHeader + vertShader);
+    final int fragShaderHandle = compileShader(GLES31.GL_FRAGMENT_SHADER, fragHeader + fragShader);
 
-    mProgramHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle, mAttributeName, glslVersion>= 300 ? feedback:null );
+    mProgramHandle = createAndLinkProgram(vertShaderHandle, fragShaderHandle, mAttributeName, glslVersion>= 300 ? feedback:null );
 
     mAttribute = new int[mNumAttributes];
 
diff --git a/src/main/res/raw/preprocess_fragment_shader.glsl b/src/main/res/raw/preprocess_fragment_shader.glsl
new file mode 100644
index 0000000..d24ef36
--- /dev/null
+++ b/src/main/res/raw/preprocess_fragment_shader.glsl
@@ -0,0 +1,30 @@
+//////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                          //
+//                                                                                          //
+// This file is part of Distorted.                                                          //
+//                                                                                          //
+// Distorted is free software: you can redistribute it and/or modify                        //
+// it under the terms of the GNU General Public License as published by                     //
+// the Free Software Foundation, either version 2 of the License, or                        //
+// (at your option) any later version.                                                      //
+//                                                                                          //
+// Distorted 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 General Public License for more details.                                             //
+//                                                                                          //
+// You should have received a copy of the GNU General Public License                        //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                       //
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+precision highp float;
+
+out vec4 fragColor;
+uniform vec4 u_Color;
+
+//////////////////////////////////////////////////////////////////////////////////////////////
+
+void main()
+  {
+  fragColor = u_Color;
+  }
\ No newline at end of file
