commit 0d81d0fbdafa4fdd2b08a7d28aa5a4d39d56ec49
Author: Leszek Koltunski <leszek@distoretedandroid.org>
Date:   Tue Jan 24 14:07:05 2017 +0000

    Separable Box blur (almost) works.

diff --git a/src/main/java/org/distorted/library/EffectQueuePostprocess.java b/src/main/java/org/distorted/library/EffectQueuePostprocess.java
index 548207a..a530df1 100644
--- a/src/main/java/org/distorted/library/EffectQueuePostprocess.java
+++ b/src/main/java/org/distorted/library/EffectQueuePostprocess.java
@@ -42,6 +42,8 @@ import java.nio.FloatBuffer;
 
 class EffectQueuePostprocess extends EffectQueue
   {
+  private static final int MAX_BLUR = 50;
+
   private static final int POSITION_DATA_SIZE= 2; // Post Program: size of the position data in elements
   private static final int TEX_DATA_SIZE     = 2; // Post Program: size of the texture coordinate data in elements.
 
@@ -49,13 +51,7 @@ class EffectQueuePostprocess extends EffectQueue
   private static final int NUM_CACHE    = 0;
   private static final int INDEX = EffectTypes.POSTPROCESS.ordinal();
 
-  private static int mRadiusH;
-  private static int mOneOverH;
-  private static int mObjDH;
-  private static int mMVPMatrixH;
-
-  private static final FloatBuffer mQuadPositions, mQuadTexture;
-  private static DistortedProgram mBlurProgram;
+  private static final FloatBuffer mQuadPositions, mQuadTexture1, mQuadTexture2;
 
   static
     {
@@ -63,14 +59,26 @@ class EffectQueuePostprocess extends EffectQueue
     int bytes_per_float = 4;
 
     float[] positionData= { -0.5f, -0.5f,  -0.5f, 0.5f,  0.5f,-0.5f,  0.5f, 0.5f };
-    float[] textureData = {  0.0f,  0.0f,   0.0f, 1.0f,  1.0f, 0.0f,  1.0f, 1.0f };
+    float[] textureData1= {  0.0f,  0.0f,   0.0f, 1.0f,  1.0f, 0.0f,  1.0f, 1.0f };
+    float[] textureData2= {  0.0f,  0.0f,   1.0f, 0.0f,  0.0f, 1.0f,  1.0f, 1.0f };
 
     mQuadPositions = ByteBuffer.allocateDirect(POSITION_DATA_SIZE*dataLength*bytes_per_float).order(ByteOrder.nativeOrder()).asFloatBuffer();
     mQuadPositions.put(positionData).position(0);
-    mQuadTexture   = ByteBuffer.allocateDirect(TEX_DATA_SIZE     *dataLength*bytes_per_float).order(ByteOrder.nativeOrder()).asFloatBuffer();
-    mQuadTexture.put(textureData).position(0);
+    mQuadTexture1  = ByteBuffer.allocateDirect(TEX_DATA_SIZE     *dataLength*bytes_per_float).order(ByteOrder.nativeOrder()).asFloatBuffer();
+    mQuadTexture1.put(textureData1).position(0);
+    mQuadTexture2  = ByteBuffer.allocateDirect(TEX_DATA_SIZE     *dataLength*bytes_per_float).order(ByteOrder.nativeOrder()).asFloatBuffer();
+    mQuadTexture2.put(textureData2).position(0);
     }
 
+  private static DistortedFramebuffer mBufferFBO = new DistortedFramebuffer(1,1);
+
+  // BLUR effect
+  private static DistortedProgram mBlurProgram;
+  private static int mRadiusH,mStepH,mWeightsH,mObjDH,mMVPMatrixH;
+  private float[] mWeights = new float[MAX_BLUR];
+
+  // another effect ....
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   EffectQueuePostprocess(long id)
@@ -86,11 +94,14 @@ class EffectQueuePostprocess extends EffectQueue
     final InputStream postVertexStream   = resources.openRawResource(R.raw.blur_vertex_shader);
     final InputStream postFragmentStream = resources.openRawResource(R.raw.blur_fragment_shader);
 
-    mBlurProgram = new DistortedProgram(postVertexStream,postFragmentStream, "", "");
+    mBlurProgram = new DistortedProgram(postVertexStream,postFragmentStream,
+                                        "#version 100\n",
+                                        "#version 100\n#define MAX_BLUR "+MAX_BLUR);
 
     int blurProgramH = mBlurProgram.getProgramHandle();
     mRadiusH    = GLES30.glGetUniformLocation( blurProgramH, "u_Radius");
-    mOneOverH   = GLES30.glGetUniformLocation( blurProgramH, "one_over_objD");
+    mStepH      = GLES30.glGetUniformLocation( blurProgramH, "u_Step");
+    mWeightsH   = GLES30.glGetUniformLocation( blurProgramH, "u_Weights");
     mObjDH      = GLES30.glGetUniformLocation( blurProgramH, "u_objD");
     mMVPMatrixH = GLES30.glGetUniformLocation( blurProgramH, "u_MVPMatrix");
     }
@@ -146,15 +157,36 @@ class EffectQueuePostprocess extends EffectQueue
   synchronized void render(float w, float h, float[] mvp, DistortedFramebuffer df)
     {
     mBlurProgram.useProgram();
-    df.setAsOutput();
 
-    GLES30.glUniform1f( mRadiusH, mUniforms[0]);
-    GLES30.glUniform2f( mOneOverH, 1/w,1/h);
+    int radius = (int)mUniforms[0];
+    if( radius>=MAX_BLUR ) radius = MAX_BLUR-1;
+
+    for(int i=0; i<=radius; i++)
+      {
+      mWeights[i] = 1.0f / (2.0f*radius+1.0f);
+      }
+
+    GLES30.glUniform1fv( mWeightsH, radius+1, mWeights,0);
+    GLES30.glUniform1i( mRadiusH, radius);
     GLES30.glUniform2f( mObjDH , w, h );
     GLES30.glUniformMatrix4fv(mMVPMatrixH, 1, false, mvp , 0);
 
+    mBufferFBO.resizeFast(df.mWidth, df.mHeight);
+    mBufferFBO.setAsOutput();
+
+    // horizontal blur
+    GLES30.glUniform1f( mStepH , 1/h );
+    GLES30.glVertexAttribPointer(mBlurProgram.mAttribute[0], POSITION_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions);
+    GLES30.glVertexAttribPointer(mBlurProgram.mAttribute[1], TEX_DATA_SIZE     , GLES30.GL_FLOAT, false, 0, mQuadTexture2);
+    GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
+
+    mBufferFBO.setAsInput();
+    df.setAsOutput();
+
+    // vertical blur
+    GLES30.glUniform1f( mStepH , 1/w );
     GLES30.glVertexAttribPointer(mBlurProgram.mAttribute[0], POSITION_DATA_SIZE, GLES30.GL_FLOAT, false, 0, mQuadPositions);
-    GLES30.glVertexAttribPointer(mBlurProgram.mAttribute[1], TEX_DATA_SIZE     , GLES30.GL_FLOAT, false, 0, mQuadTexture);
+    GLES30.glVertexAttribPointer(mBlurProgram.mAttribute[1], TEX_DATA_SIZE     , GLES30.GL_FLOAT, false, 0, mQuadTexture2);
     GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
     }
 
diff --git a/src/main/res/raw/blur_fragment_shader.glsl b/src/main/res/raw/blur_fragment_shader.glsl
index 1683c79..cf5f6a7 100644
--- a/src/main/res/raw/blur_fragment_shader.glsl
+++ b/src/main/res/raw/blur_fragment_shader.glsl
@@ -21,23 +21,27 @@ precision lowp float;
 
 varying vec2 v_TexCoordinate;
 uniform sampler2D u_Texture;
-uniform vec2 one_over_objD;
-uniform float u_Radius;
+uniform float u_Step;
+uniform float u_Weights[MAX_BLUR];
+uniform int u_Radius;
 
 //////////////////////////////////////////////////////////////////////////////////////////////
 
 void main()
   {
-  vec2 tex;
-  vec4 pixel = vec4(0.0);
-  float denom = 1.0 / ((2.0*u_Radius+1.0)*(2.0*u_Radius+1.0));
+  float lCoord = v_TexCoordinate.x;
+  float rCoord = lCoord;
+  float yCoord = v_TexCoordinate.y;
 
-  for (float x = -u_Radius; x <= u_Radius; x+=1.0)
-    for (float y = -u_Radius; y <= u_Radius; y+=1.0)
-      {
-      tex = vec2(v_TexCoordinate.x + x*one_over_objD.x, v_TexCoordinate.y + y*one_over_objD.y);
-      pixel += texture2D(u_Texture,tex)*denom;
-      }
+  vec4  pixel  = texture2D(u_Texture,vec2(lCoord,yCoord)) * u_Weights[0];
+
+  for (int x = 1; x <= u_Radius; x+=1)
+    {
+    rCoord+= u_Step;
+    lCoord-= u_Step;
+    pixel += ( texture2D(u_Texture,vec2(rCoord,yCoord)) +
+               texture2D(u_Texture,vec2(lCoord,yCoord)) ) * u_Weights[x];
+    }
 
   gl_FragColor = pixel;
   }
\ No newline at end of file
