commit a225e5aa896349c850c10da4f78fa80caac70e81
Author: Leszek Koltunski <leszek@distoretedandroid.org>
Date:   Thu Jan 26 17:11:16 2017 +0000

    Separable Gaussian Blur with linear sampling done.
    
    Linear sampling implemented - i.e. blurring by a (2N+1)x(2N+1) gaussian kernel (centeral pixel + N pixels in each direction) requires exactly 2N + (N%2==1 ? 4:2) texture fetches.

diff --git a/src/main/java/org/distorted/library/EffectQueuePostprocess.java b/src/main/java/org/distorted/library/EffectQueuePostprocess.java
index 0d6511f..3e67ca4 100644
--- a/src/main/java/org/distorted/library/EffectQueuePostprocess.java
+++ b/src/main/java/org/distorted/library/EffectQueuePostprocess.java
@@ -43,8 +43,8 @@ import java.nio.FloatBuffer;
 
 class EffectQueuePostprocess extends EffectQueue
   {
-  private static final float GAUSSIAN[] =   // G(0.00), G(0.03), G(0.06), ..., G(3.00) where G(x)= (1/(sqrt(2*PI))) * e^(-(x^2)/2)
-    {
+  private static final float GAUSSIAN[] =   // G(0.00), G(0.03), G(0.06), ..., G(3.00), 0
+    {                                       // where G(x)= (1/(sqrt(2*PI))) * e^(-(x^2)/2). The last 0 terminates.
     0.398948f, 0.398769f, 0.398231f, 0.397336f, 0.396086f, 0.394485f, 0.392537f, 0.390247f, 0.387622f, 0.384668f,
     0.381393f, 0.377806f, 0.373916f, 0.369733f, 0.365268f, 0.360532f, 0.355538f, 0.350297f, 0.344823f, 0.339129f,
     0.333229f, 0.327138f, 0.320868f, 0.314436f, 0.307856f, 0.301142f, 0.294309f, 0.287373f, 0.280348f, 0.273248f,
@@ -55,9 +55,9 @@ class EffectQueuePostprocess extends EffectQueue
     0.043984f, 0.041280f, 0.038707f, 0.036262f, 0.033941f, 0.031740f, 0.029655f, 0.027682f, 0.025817f, 0.024056f,
     0.022395f, 0.020830f, 0.019357f, 0.017971f, 0.016670f, 0.015450f, 0.014305f, 0.013234f, 0.012232f, 0.011295f,
     0.010421f, 0.009606f, 0.008847f, 0.008140f, 0.007483f, 0.006873f, 0.006307f, 0.005782f, 0.005296f, 0.004847f,
-    0.004432f
+    0.004432f, 0.000000f
     };
-  private static final float NUM_GAUSSIAN = GAUSSIAN.length-1;
+  private static final int NUM_GAUSSIAN = GAUSSIAN.length-2;
 
   private static final int MAX_BLUR = 50;
 
@@ -175,15 +175,60 @@ class EffectQueuePostprocess extends EffectQueue
     {
     if( radius>=MAX_BLUR ) radius = MAX_BLUR-1;
 
+    // Box Blur size 'radius'
+/*
     for(int i=0; i<=radius; i++)
       {
-      // Box Blur size 'radius'
       mWeights[i] = 1.0f / (2.0f*radius+1.0f);
       mOffsets[i] = i*height;
+      }
+*/
+    // Gaussian Blur size 'radius'
+
+    float P = (float)NUM_GAUSSIAN / (radius>3 ? radius:3);
+    float x = 0.0f;
+    mWeights[0] = GAUSSIAN[0];
+    mOffsets[0] = 0.0f;
+    float sum = GAUSSIAN[0];
+    int j;
+    float z;
+
+    for(int i=1; i<=radius; i++)
+      {
+      x += P;
+      j = (int)x;
+      z = x-j;
 
-      // Gaussian Blur size 'radius'
+      mWeights[i] = (1-z)*GAUSSIAN[j] + z*GAUSSIAN[j+1];
+      sum += 2*mWeights[i];
+      mOffsets[i] = i*height;
+      }
 
+    for(int i=0; i<=radius; i++)
+      {
+      mWeights[i] /= sum;
+      }
 
+    // squash the weights and offsets for linear sampling
+    int numloops = radius/2;
+
+    for(int i=0; i<numloops; i++)
+      {
+      mOffsets[i+1] = mWeights[2*i+1]*mOffsets[2*i+1] + mWeights[2*i+2]*mOffsets[2*i+2];
+      mWeights[i+1] = mWeights[2*i+1] + mWeights[2*i+2];
+      mOffsets[i+1] /= mWeights[i+1];
+      }
+
+    if( radius%2 == 1 )
+      {
+      int index = radius/2 +1;
+      mOffsets[index]=mOffsets[radius];
+      mWeights[index]=mWeights[radius];
+      radius = numloops+1;
+      }
+    else
+      {
+      radius = numloops;
       }
 
     return radius;
