commit 2f1f75700a65cb2851ce79c70e724abac4adaf45
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Tue Dec 11 18:03:51 2018 +0000

    Properly clean up static varaibles in the Effect classes!

diff --git a/src/main/java/org/distorted/library/effect/Effect.java b/src/main/java/org/distorted/library/effect/Effect.java
index 51926d0..eb63516 100644
--- a/src/main/java/org/distorted/library/effect/Effect.java
+++ b/src/main/java/org/distorted/library/effect/Effect.java
@@ -59,7 +59,7 @@ public abstract class Effect
 
     int n = name.ordinal();
     float[] u = name.getUnity();
-    int l = name.getUnity().length;
+    int l = u.length;
 
     for(int i=0; i<l; i++)
       {
@@ -82,6 +82,10 @@ public abstract class Effect
     mNextID = 0;
 
     for(int i=0; i<NUM_EFFECTS; i++) mEnabled[i] = false;
+
+    MatrixEffect.destroyStatics();
+    VertexEffect.destroyStatics();
+    PostprocessEffect.destroyStatics();
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/effect/EffectName.java b/src/main/java/org/distorted/library/effect/EffectName.java
index e18532f..3963354 100644
--- a/src/main/java/org/distorted/library/effect/EffectName.java
+++ b/src/main/java/org/distorted/library/effect/EffectName.java
@@ -43,36 +43,35 @@ package org.distorted.library.effect;
 public enum EffectName
   {
   // EFFECT NAME /////// EFFECT TYPE ////////// EFFECT UNITY //////////// DIM REGION CENTER
-  ROTATE           ( EffectType.MATRIX  ,   new float[] {0.0f}           , 4, false, true  ),
-  QUATERNION       ( EffectType.MATRIX  ,   new float[] {0.0f,0.0f,0.0f} , 4, false, true  ),
-  MOVE             ( EffectType.MATRIX  ,   new float[] {0.0f,0.0f,0.0f} , 3, false, false ),
-  SCALE            ( EffectType.MATRIX  ,   new float[] {1.0f,1.0f,1.0f} , 3, false, false ),
-  SHEAR            ( EffectType.MATRIX  ,   new float[] {0.0f,0.0f,0.0f} , 3, false, true  ),
-
-  DISTORT          ( EffectType.VERTEX  ,   new float[] {0.0f,0.0f,0.0f} , 3, true , true  ),
-  DEFORM           ( EffectType.VERTEX  ,   new float[] {0.0f,0.0f,0.0f} , 3, true , true  ),
-  SINK             ( EffectType.VERTEX  ,   new float[] {1.0f}           , 1, true , true  ),
-  PINCH            ( EffectType.VERTEX  ,   new float[] {1.0f}           , 2, true , true  ),
-  SWIRL            ( EffectType.VERTEX  ,   new float[] {0.0f}           , 1, true , true  ),
-  WAVE             ( EffectType.VERTEX  ,   new float[] {0.0f}           , 5, true , true  ),
-
-  ALPHA            ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, true , false ),
-  SMOOTH_ALPHA     ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, true , false ),
-  CHROMA           ( EffectType.FRAGMENT,   new float[] {0.0f}           , 4, true , false ),
-  SMOOTH_CHROMA    ( EffectType.FRAGMENT,   new float[] {0.0f}           , 4, true , false ),
-  BRIGHTNESS       ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, true , false ),
-  SMOOTH_BRIGHTNESS( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, true , false ),
-  SATURATION       ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, true , false ),
-  SMOOTH_SATURATION( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, true , false ),
-  CONTRAST         ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, true , false ),
-  SMOOTH_CONTRAST  ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, true , false ),
-
-  BLUR             ( EffectType.POSTPROCESS,new float[] {0.0f}           , 1, false, false ),
-  GLOW             ( EffectType.POSTPROCESS,new float[] {0.0f}           , 5, false, false );
+  ROTATE           ( EffectType.MATRIX  ,   new float[] {0.0f}           , 4, false, true  , MatrixEffectRotate.class       ),
+  QUATERNION       ( EffectType.MATRIX  ,   new float[] {0.0f,0.0f,0.0f} , 4, false, true  , MatrixEffectQuaternion.class   ),
+  MOVE             ( EffectType.MATRIX  ,   new float[] {0.0f,0.0f,0.0f} , 3, false, false , MatrixEffectMove.class         ),
+  SCALE            ( EffectType.MATRIX  ,   new float[] {1.0f,1.0f,1.0f} , 3, false, false , MatrixEffectScale.class        ),
+  SHEAR            ( EffectType.MATRIX  ,   new float[] {0.0f,0.0f,0.0f} , 3, false, true  , MatrixEffectShear.class        ),
+
+  DISTORT          ( EffectType.VERTEX  ,   new float[] {0.0f,0.0f,0.0f} , 3, true , true  , VertexEffectDistort.class      ),
+  DEFORM           ( EffectType.VERTEX  ,   new float[] {0.0f,0.0f,0.0f} , 3, true , true  , VertexEffectDeform.class       ),
+  SINK             ( EffectType.VERTEX  ,   new float[] {1.0f}           , 1, true , true  , VertexEffectSink.class         ),
+  PINCH            ( EffectType.VERTEX  ,   new float[] {1.0f}           , 2, true , true  , VertexEffectPinch.class        ),
+  SWIRL            ( EffectType.VERTEX  ,   new float[] {0.0f}           , 1, true , true  , VertexEffectSwirl.class        ),
+  WAVE             ( EffectType.VERTEX  ,   new float[] {0.0f}           , 5, true , true  , VertexEffectWave.class         ),
+
+  ALPHA            ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, true , false , FragmentEffectAlpha.class      ),
+  SMOOTH_ALPHA     ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, true , false , FragmentEffectAlpha.class      ),
+  CHROMA           ( EffectType.FRAGMENT,   new float[] {0.0f}           , 4, true , false , FragmentEffectChroma.class     ),
+  SMOOTH_CHROMA    ( EffectType.FRAGMENT,   new float[] {0.0f}           , 4, true , false , FragmentEffectChroma.class     ),
+  BRIGHTNESS       ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, true , false , FragmentEffectBrightness.class ),
+  SMOOTH_BRIGHTNESS( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, true , false , FragmentEffectBrightness.class ),
+  SATURATION       ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, true , false , FragmentEffectSaturation.class ),
+  SMOOTH_SATURATION( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, true , false , FragmentEffectSaturation.class ),
+  CONTRAST         ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, true , false , FragmentEffectContrast.class   ),
+  SMOOTH_CONTRAST  ( EffectType.FRAGMENT,   new float[] {1.0f}           , 1, true , false , FragmentEffectContrast.class   ),
+
+  BLUR             ( EffectType.POSTPROCESS,new float[] {0.0f}           , 1, false, false , PostprocessEffectBlur.class    ),
+  GLOW             ( EffectType.POSTPROCESS,new float[] {0.0f}           , 5, false, false , PostprocessEffectGlow.class    );
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private static final int MAXDIM = 4;  // maximum supported dimension of effect's unity
   public static final int LENGTH = values().length;
 
   private final EffectType type;
@@ -80,9 +79,8 @@ public enum EffectName
   private final int dimension;
   private final boolean supportsR;
   private final boolean supportsC;
+  private final Class<? extends Effect> effectClass;
 
-  private static final float[] unities;
-  private static final int[] unityDimensions;
   private static final int[] dimensions;
   private static final boolean[] supportsRegion;
   private static final boolean[] supportsCenter;
@@ -92,8 +90,6 @@ public enum EffectName
     {
     int i=0;
 
-    unities         = new float[MAXDIM*LENGTH];
-    unityDimensions = new int[LENGTH];
     dimensions      = new int[LENGTH];
     supportsRegion  = new boolean[LENGTH];
     supportsCenter  = new boolean[LENGTH];
@@ -101,21 +97,11 @@ public enum EffectName
 
     for(EffectName name: EffectName.values())
       {
-      unityDimensions[i] = (name.unity==null ? 0 : name.unity.length);
       dimensions[i]      = name.dimension;
       supportsRegion[i]  = name.supportsR;
       supportsCenter[i]  = name.supportsC;
       names[i]           = name;
 
-      switch(unityDimensions[i])
-        {
-        case 4: unities[MAXDIM*i+3] = name.unity[3];
-        case 3: unities[MAXDIM*i+2] = name.unity[2];
-        case 2: unities[MAXDIM*i+1] = name.unity[1];
-        case 1: unities[MAXDIM*i  ] = name.unity[0];
-        case 0: break;
-        }
-
       i++;
       }
     }
@@ -129,13 +115,15 @@ public enum EffectName
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  EffectName(EffectType type, float[] unity, int dimension, boolean supportsR, boolean supportsC)
+  EffectName(EffectType type, float[] unity, int dimension, boolean supportsR,
+             boolean supportsC, Class<? extends Effect> effectClass )
     {
-    this.type      = type;
-    this.unity     = unity;
-    this.dimension = dimension;
-    this.supportsR = supportsR;
-    this.supportsC = supportsC;
+    this.type        = type;
+    this.unity       = unity;
+    this.dimension   = dimension;
+    this.supportsR   = supportsR;
+    this.supportsC   = supportsC;
+    this.effectClass = effectClass;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -151,6 +139,17 @@ public enum EffectName
     return type;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+  /**
+   * Returns the Class of an individual Effect. For example, EffectName.ROTATION.getType() will
+   * return MatrixEffectRotation.class.
+   * @return effect class.
+   */
+  public Class<? extends Effect> getEffectClass()
+    {
+    return effectClass;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Returns the i-th EffectName.
diff --git a/src/main/java/org/distorted/library/effect/FragmentEffect.java b/src/main/java/org/distorted/library/effect/FragmentEffect.java
index f21d2be..0c4eab8 100644
--- a/src/main/java/org/distorted/library/effect/FragmentEffect.java
+++ b/src/main/java/org/distorted/library/effect/FragmentEffect.java
@@ -79,12 +79,8 @@ public abstract class FragmentEffect extends Effect
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public static void onDestroy()
+
+  static void destroyStatics()
     {
     mNumEnabled = 0;
     mGLSL = "";
diff --git a/src/main/java/org/distorted/library/effect/MatrixEffect.java b/src/main/java/org/distorted/library/effect/MatrixEffect.java
index 81e0f3e..4f92444 100644
--- a/src/main/java/org/distorted/library/effect/MatrixEffect.java
+++ b/src/main/java/org/distorted/library/effect/MatrixEffect.java
@@ -38,6 +38,13 @@ public abstract class MatrixEffect extends Effect
  */
   public abstract void apply(float[] matrix, float[] uniforms, int index);
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  static void destroyStatics()
+    {
+
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   MatrixEffect(EffectName name)
diff --git a/src/main/java/org/distorted/library/effect/PostprocessEffect.java b/src/main/java/org/distorted/library/effect/PostprocessEffect.java
index 05dd943..a1f2be3 100644
--- a/src/main/java/org/distorted/library/effect/PostprocessEffect.java
+++ b/src/main/java/org/distorted/library/effect/PostprocessEffect.java
@@ -23,6 +23,7 @@ import org.distorted.library.main.DistortedFramebuffer;
 import org.distorted.library.main.DistortedMaster;
 import org.distorted.library.program.DistortedProgram;
 
+import java.lang.reflect.Method;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.FloatBuffer;
@@ -188,6 +189,43 @@ public abstract class PostprocessEffect extends Effect implements DistortedMaste
       }
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  static void destroyStatics()
+    {
+    mPrograms.clear();
+    mSources.clear();
+    mNumSources = 0;
+
+    Method method=null;
+
+    for(EffectName name: EffectName.values())
+      {
+      if( name.getType() == EffectType.POSTPROCESS )
+        {
+        Class<? extends Effect> cls = name.getEffectClass();
+
+        try
+          {
+          method = cls.getMethod("destroyStatics");
+          }
+        catch(NoSuchMethodException ex)
+          {
+          android.util.Log.e("postprocess", "exception getting method: "+ex.getMessage());
+          }
+
+        try
+          {
+          method.invoke(null);
+          }
+        catch(Exception ex)
+          {
+          android.util.Log.e("postprocess", "exception invoking method: "+ex.getMessage());
+          }
+        }
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   PostprocessEffect(EffectName name)
diff --git a/src/main/java/org/distorted/library/effect/PostprocessEffectBlur.java b/src/main/java/org/distorted/library/effect/PostprocessEffectBlur.java
index ea937e1..be6aaef 100644
--- a/src/main/java/org/distorted/library/effect/PostprocessEffectBlur.java
+++ b/src/main/java/org/distorted/library/effect/PostprocessEffectBlur.java
@@ -66,6 +66,20 @@ public class PostprocessEffectBlur extends PostprocessEffect
   private static DistortedProgram mProgram1, mProgram2;
   private static int mIndex1, mIndex2;
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Clean up of static variables on exit.
+// called by reflection from super class.
+
+  @SuppressWarnings("unused")
+  static void destroyStatics()
+    {
+    mProgram1 = null;
+    mProgram2 = null;
+
+    mIndex1 = 0;
+    mIndex2 = 0;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // This implements the 'Better separable implementation using GPU fixed function sampling' from
 // https://software.intel.com/en-us/blogs/2014/07/15/an-investigation-of-fast-real-time-gpu-based-image-blur-algorithms
diff --git a/src/main/java/org/distorted/library/effect/PostprocessEffectGlow.java b/src/main/java/org/distorted/library/effect/PostprocessEffectGlow.java
index dedc039..ec69ae9 100644
--- a/src/main/java/org/distorted/library/effect/PostprocessEffectGlow.java
+++ b/src/main/java/org/distorted/library/effect/PostprocessEffectGlow.java
@@ -67,6 +67,20 @@ public class PostprocessEffectGlow extends PostprocessEffect
   private static DistortedProgram mProgram1, mProgram2;
   private static int mIndex1, mIndex2;
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Clean up of static variables on exit.
+// called by reflection from super class.
+
+  @SuppressWarnings("unused")
+  static void destroyStatics()
+    {
+    mProgram1 = null;
+    mProgram2 = null;
+
+    mIndex1 = 0;
+    mIndex2 = 0;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // This implements the 'Better separable implementation using GPU fixed function sampling' from
 // https://software.intel.com/en-us/blogs/2014/07/15/an-investigation-of-fast-real-time-gpu-based-image-blur-algorithms
diff --git a/src/main/java/org/distorted/library/effect/VertexEffect.java b/src/main/java/org/distorted/library/effect/VertexEffect.java
index 39812e8..c8bb053 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffect.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffect.java
@@ -72,12 +72,8 @@ public abstract class VertexEffect extends Effect
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Only for use by the library itself.
- *
- * @y.exclude
- */
-  public static void onDestroy()
+
+  static void destroyStatics()
     {
     mNumEnabled = 0;
     mGLSL = "";
diff --git a/src/main/java/org/distorted/library/main/Distorted.java b/src/main/java/org/distorted/library/main/Distorted.java
index 22d5f25..28a5659 100644
--- a/src/main/java/org/distorted/library/main/Distorted.java
+++ b/src/main/java/org/distorted/library/main/Distorted.java
@@ -239,8 +239,6 @@ public class Distorted
     DistortedOutputSurface.onDestroy();
     EffectQueue.onDestroy();
     Effect.onDestroy();
-    VertexEffect.onDestroy();
-    FragmentEffect.onDestroy();
     EffectMessageSender.stopSending();
 
     mInitialized = false;
diff --git a/src/main/java/org/distorted/library/main/EffectQueueMatrix.java b/src/main/java/org/distorted/library/main/EffectQueueMatrix.java
index aae5391..afd99c4 100644
--- a/src/main/java/org/distorted/library/main/EffectQueueMatrix.java
+++ b/src/main/java/org/distorted/library/main/EffectQueueMatrix.java
@@ -103,14 +103,15 @@ class EffectQueueMatrix extends EffectQueue
     float xLenInPixels = projection.mWidth *(mMaxX-mMinX)/2;
     float yLenInPixels = projection.mHeight*(mMaxY-mMinY)/2;
 
-    // already margin / min(xLen,yLen) is the size of the halo.
+    // already margin / avg(xLen,yLen) is the size of the halo.
     // Here we need a bit more because we are marking not only the halo, but a little bit around
     // it as well so that the (blur for example) will be smooth on the edges. Thus the 2.0f.
+    // ( 4.0 because there is an extra 2.0 from the avg(xLen,yLen) )
     //
     // mMipmap ( 1.0, 0.5, 0.25, 0.125 ) - we need to make the size of the halo independent
     // of postprocessing effect quality.
 
-    return projection.mMipmap*2.0f*marginInPixels/( xLenInPixels>yLenInPixels ? yLenInPixels:xLenInPixels );
+    return projection.mMipmap*4.0f*marginInPixels/( xLenInPixels+yLenInPixels );
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
