commit 86eb00a913a0d87c87e2a7c17c3ffbdcb64ffee1
Author: Leszek Koltunski <leszek@distorted.org>
Date:   Fri Jan 6 23:27:49 2017 +0000

    Initial version of the first post-processing effect - BLUR - ready for the first app!

diff --git a/src/main/java/org/distorted/library/Distorted.java b/src/main/java/org/distorted/library/Distorted.java
index b182608..c34d1ac 100644
--- a/src/main/java/org/distorted/library/Distorted.java
+++ b/src/main/java/org/distorted/library/Distorted.java
@@ -90,15 +90,6 @@ public class Distorted
     
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  static DistortedFramebuffer getFBO(int w, int h)
-    {
-    // TODO: a static factory of Framebuffers.
-
-    return null;
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   static boolean isInitialized()
@@ -106,15 +97,6 @@ public class Distorted
     return (mMainProgramAttributes!=null);
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Release all internal memory caches (in particular the FBOs used as buffers for postprocessing)
- */
-  public static void clean()
-    {
-    // TODO
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * When OpenGL context gets created, you need to call this method so that the library can initialise its internal data structures.
@@ -209,5 +191,6 @@ public class Distorted
     EffectMessageSender.stopSending();
 
     mMainProgramAttributes = null;
+    mPostProgramAttributes = null;
     }
   }
diff --git a/src/main/java/org/distorted/library/DistortedEffects.java b/src/main/java/org/distorted/library/DistortedEffects.java
index d1a88fb..5497484 100644
--- a/src/main/java/org/distorted/library/DistortedEffects.java
+++ b/src/main/java/org/distorted/library/DistortedEffects.java
@@ -49,6 +49,8 @@ public class DistortedEffects
   private static long mNextID =0;
   private long mID;
 
+  private static DistortedFramebuffer mBufferFBO;
+
   private EffectQueueMatrix      mM;
   private EffectQueueFragment    mF;
   private EffectQueueVertex      mV;
@@ -67,6 +69,8 @@ public class DistortedEffects
     mQuadPositions.put(positionData).position(0);
     mQuadTexture   = ByteBuffer.allocateDirect(TEX_DATA_SIZE     *dataLength*BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
     mQuadTexture.put(textureData).position(0);
+
+    mBufferFBO = new DistortedFramebuffer(1,1);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -130,11 +134,10 @@ public class DistortedEffects
     float halfZ = halfInputW*mesh.zFactor;
 
     GLES20.glUseProgram(Distorted.mainProgramH);
+    GLES20.glViewport(0, 0, df.mWidth, df.mHeight);
 
     if( mP.mNumEffects==0 )
       {
-      GLES20.glViewport(0, 0, df.mWidth, df.mHeight);
-
       mM.send(df,halfInputW,halfInputH,halfZ);
       mV.send(halfInputW,halfInputH,halfZ);
       mF.send(halfInputW,halfInputH);
@@ -143,12 +146,10 @@ public class DistortedEffects
       }
     else
       {
-      DistortedFramebuffer buffer = Distorted.getFBO(df.mWidth,df.mHeight);
-
-      GLES20.glViewport(0, 0, buffer.mWidth, buffer.mHeight);
-      buffer.setAsOutput();
+      mBufferFBO.resizeFast(df.mWidth, df.mHeight);
+      mBufferFBO.setAsOutput();
 
-      mM.send(buffer,halfInputW,halfInputH,halfZ);
+      mM.send(mBufferFBO,halfInputW,halfInputH,halfZ);
       mV.send(halfInputW,halfInputH,halfZ);
       mF.send(halfInputW,halfInputH);
 
@@ -156,7 +157,7 @@ public class DistortedEffects
 
       GLES20.glUseProgram(Distorted.postProgramH);
       GLES20.glViewport(0, 0, df.mWidth, df.mHeight);
-      buffer.setAsInput();
+      mBufferFBO.setAsInput();
       df.setAsOutput();
       mP.send(halfInputW,halfInputH);
 
diff --git a/src/main/java/org/distorted/library/DistortedFramebuffer.java b/src/main/java/org/distorted/library/DistortedFramebuffer.java
index 135e402..b1d6869 100644
--- a/src/main/java/org/distorted/library/DistortedFramebuffer.java
+++ b/src/main/java/org/distorted/library/DistortedFramebuffer.java
@@ -55,6 +55,8 @@ public class DistortedFramebuffer
   private boolean mMarked;
   private boolean mDepthWanted;
 
+  private int mTexWidth, mTexHeight;
+
   // Projection stuff
   private float mX, mY, mFOV;
   int mWidth,mHeight,mDepth;
@@ -74,18 +76,15 @@ public class DistortedFramebuffer
       GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
       GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
       GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
-      GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, mWidth, mHeight, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
+      GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, mTexWidth, mTexHeight, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, null);
 
       GLES20.glGenFramebuffers(1, fboIds, 0);
       GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboIds[0]);
       GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, colorIds[0], 0);
 
       checkStatus("color");
-
-      mList.add(this);
       }
-
-    if(  mDepthWanted && depthIds[0]==NOT_CREATED_YET ) // we need to create a new DEPTH attachment
+    if( mDepthWanted && depthIds[0]==NOT_CREATED_YET ) // we need to create a new DEPTH attachment
       {
       GLES20.glGenTextures(1, depthIds, 0);
       GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, depthIds[0]);
@@ -93,7 +92,7 @@ public class DistortedFramebuffer
       GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
       GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
       GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
-      GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_DEPTH_COMPONENT, mWidth, mHeight, 0, GLES20.GL_DEPTH_COMPONENT, GLES20.GL_UNSIGNED_SHORT, null);
+      GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_DEPTH_COMPONENT, mTexWidth, mTexHeight, 0, GLES20.GL_DEPTH_COMPONENT, GLES20.GL_UNSIGNED_SHORT, null);
 
       GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboIds[0]);
       GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_TEXTURE_2D, depthIds[0], 0);
@@ -265,6 +264,31 @@ public class DistortedFramebuffer
       }
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// if new size fits into the size of the underlying Texture, just change the projection without
+// reallocating the Texture. Otherwise, we need to reallocate.
+//
+// Must be called form a thread holding the OpenGL context.
+
+  void resizeFast(int width, int height)
+    {
+    if( mWidth!=width || mHeight!=height )
+      {
+      mWidth = width;
+      mHeight= height;
+
+      createProjection();
+
+      if( mWidth>mTexWidth || mHeight>mTexHeight )
+        {
+        mTexWidth = mWidth;
+        mTexHeight= mHeight;
+        deleteFBO();
+        createFBO();
+        }
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // PUBLIC API
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -281,6 +305,8 @@ public class DistortedFramebuffer
 
     mHeight     = height;
     mWidth      = width;
+    mTexHeight  = height;
+    mTexWidth   = width;
     mFOV        = 60.0f;
     mX          = 0.0f;
     mY          = 0.0f;
@@ -292,6 +318,8 @@ public class DistortedFramebuffer
     depthIds[0]= NOT_CREATED_YET;
 
     createProjection();
+
+    mList.add(this);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -345,11 +373,11 @@ public class DistortedFramebuffer
     {
     tex.createTexture();
     tex.setAsInput();
+    DistortedFramebuffer.deleteAllMarked();
+    DistortedTexture.deleteAllMarked();
     createFBO();
     setAsOutput();
     effects.drawPriv(tex.mHalfX, tex.mHalfY, mesh, this, time);
-    DistortedFramebuffer.deleteAllMarked();
-    DistortedTexture.deleteAllMarked();
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -371,12 +399,12 @@ public class DistortedFramebuffer
 
     if( fbo.colorIds[0]>0 )    // fbo created with the first constructor
       {
+      DistortedFramebuffer.deleteAllMarked();
+      DistortedTexture.deleteAllMarked();
       createFBO();
       setAsOutput();
       GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fbo.colorIds[0]);
       effects.drawPriv(fbo.mWidth/2, fbo.mHeight/2, mesh, this, time);
-      DistortedFramebuffer.deleteAllMarked();
-      DistortedTexture.deleteAllMarked();
       }
     }
 
@@ -391,11 +419,11 @@ public class DistortedFramebuffer
  */
   public void renderTo(DistortedTree dt, long time)
     {
+    DistortedFramebuffer.deleteAllMarked();
+    DistortedTexture.deleteAllMarked();
     createFBO();
     setAsOutput();
     dt.drawRecursive(time,this);
-    DistortedFramebuffer.deleteAllMarked();
-    DistortedTexture.deleteAllMarked();
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -445,8 +473,10 @@ public class DistortedFramebuffer
     {
     if( mWidth!=width || mHeight!=height )
       {
-      mWidth = width;
-      mHeight= height;
+      mWidth    = width;
+      mHeight   = height;
+      mTexWidth = width;
+      mTexHeight= height;
 
       createProjection();
 
