commit 8c32765362d8bbbfd33b8e079945433d8de31736
Author: Leszek Koltunski <leszek@distoretedandroid.org>
Date:   Wed Jan 4 17:57:06 2017 +0000

    First attempt at making it possible to dynamically add and remove DEPTH attachments from an FBO.

diff --git a/src/main/java/org/distorted/library/Distorted.java b/src/main/java/org/distorted/library/Distorted.java
index 9923d06..be932b2 100644
--- a/src/main/java/org/distorted/library/Distorted.java
+++ b/src/main/java/org/distorted/library/Distorted.java
@@ -112,7 +112,6 @@ public class Distorted
     mainProgram.bindAndEnableAttributes();
     mMainProgramAttributes = mainProgram.getAttributes();
 
-    GLES20.glEnable (GLES20.GL_DEPTH_TEST);
     GLES20.glDepthFunc(GLES20.GL_LEQUAL);
     GLES20.glEnable(GLES20.GL_BLEND);
     GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
diff --git a/src/main/java/org/distorted/library/DistortedFramebuffer.java b/src/main/java/org/distorted/library/DistortedFramebuffer.java
index 477b6bc..cc6ae28 100644
--- a/src/main/java/org/distorted/library/DistortedFramebuffer.java
+++ b/src/main/java/org/distorted/library/DistortedFramebuffer.java
@@ -41,17 +41,19 @@ import java.util.LinkedList;
  */
 public class DistortedFramebuffer
   {
-  private static final int TEXTURE_FAILED_TO_CREATE = -1;
-  private static final int TEXTURE_NOT_CREATED_YET  = -2;
-  private static final int TEXTURE_DONT_CREATE      = -3;
+  private static final int FAILED_TO_CREATE = -1;
+  private static final int NOT_CREATED_YET  = -2;
+  private static final int DONT_CREATE      = -3;
 
   private static boolean mListMarked = false;
   private static LinkedList<DistortedFramebuffer> mList = new LinkedList<>();
 
-  private int[] texIds = new int[1];
-  private int[] fboIds = new int[1];
+  private int[] colorIds = new int[1];
+  private int[] depthIds = new int[1];
+  private int[] fboIds   = new int[1];
 
   private boolean mMarked;
+  private boolean mDepthWanted;
 
   // Projection stuff
   private float mX, mY, mFOV;
@@ -64,10 +66,10 @@ public class DistortedFramebuffer
 
   boolean createFBO()
     {
-    if( texIds[0]==TEXTURE_NOT_CREATED_YET )
+    if( colorIds[0]==NOT_CREATED_YET )
       {
-      GLES20.glGenTextures(1, texIds, 0);
-      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texIds[0]);
+      GLES20.glGenTextures(1, colorIds, 0);
+      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, colorIds[0]);
       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.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
@@ -76,17 +78,17 @@ public class DistortedFramebuffer
 
       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, texIds[0], 0);
+      GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, colorIds[0], 0);
 
       int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
 
       if(status != GLES20.GL_FRAMEBUFFER_COMPLETE)
         {
         android.util.Log.e("DistortedFramebuffer", "failed to create framebuffer, error="+status);
-        GLES20.glDeleteTextures(1, texIds, 0);
+        GLES20.glDeleteTextures(1, colorIds, 0);
         GLES20.glDeleteFramebuffers(1, fboIds, 0);
-        fboIds[0] = 0;
-        texIds[0] = TEXTURE_FAILED_TO_CREATE;
+        fboIds[0]   = 0;
+        colorIds[0] = FAILED_TO_CREATE;
         return false;
         }
 
@@ -94,6 +96,37 @@ public class DistortedFramebuffer
       //android.util.Log.e("FBO", "created ("+mWidth+","+mHeight+") "+fboIds[0]);
       }
 
+    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]);
+      GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
+      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_FLOAT, null);
+
+      GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboIds[0]);
+      GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_TEXTURE_2D, depthIds[0], 0);
+
+      int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
+
+      if(status != GLES20.GL_FRAMEBUFFER_COMPLETE)
+        {
+        android.util.Log.e("DistortedFramebuffer", "failed to create depth, error="+status);
+        GLES20.glDeleteTextures(1, colorIds, 0);
+        GLES20.glDeleteFramebuffers(1, fboIds, 0);
+        fboIds[0]   = 0;
+        depthIds[0] = FAILED_TO_CREATE;
+        return false;
+        }
+      }
+    if( !mDepthWanted && depthIds[0]!=NOT_CREATED_YET ) // we need to detach and destroy the DEPTH attachment.
+      {
+      GLES20.glDeleteTextures(1, depthIds, 0);
+      depthIds[0]=NOT_CREATED_YET;
+      }
+
     return true;
     }
 
@@ -102,15 +135,21 @@ public class DistortedFramebuffer
 
   private void deleteFBO()
     {
-    if( texIds[0]>=0 )
+    if( colorIds[0]>=0 )
       {
       //android.util.Log.e("FBO", "deleting ("+mWidth+","+mHeight+") "+fboIds[0]);
 
-      GLES20.glDeleteTextures(1, texIds, 0);
-      GLES20.glDeleteFramebuffers(1, fboIds, 0);
+      if( depthIds[0]>=0 )
+        {
+        GLES20.glDeleteTextures(1, depthIds, 0);
+        depthIds[0]=NOT_CREATED_YET;
+        }
+
+      GLES20.glDeleteTextures(1, colorIds, 0);
+      colorIds[0] = NOT_CREATED_YET;
 
+      GLES20.glDeleteFramebuffers(1, fboIds, 0);
       fboIds[0] = 0;
-      texIds[0] = TEXTURE_NOT_CREATED_YET;
       }
 
     mMarked = false;
@@ -120,8 +159,10 @@ public class DistortedFramebuffer
 
   void reset()
     {
-    if( texIds[0]!=TEXTURE_DONT_CREATE)
-      texIds[0] = TEXTURE_NOT_CREATED_YET;
+    if( colorIds[0]!=DONT_CREATE )
+      colorIds[0] = NOT_CREATED_YET;
+
+    if( mDepthWanted ) depthIds[0] = NOT_CREATED_YET;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -129,13 +170,24 @@ public class DistortedFramebuffer
   void setAsOutput()
     {
     GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboIds[0]);
+
+    if( depthIds[0]!=NOT_CREATED_YET )
+      {
+      GLES20.glEnable(GLES20.GL_DEPTH_TEST);
+      GLES20.glDepthMask(true);
+      }
+    else
+      {
+      GLES20.glDisable(GLES20.GL_DEPTH_TEST);
+      GLES20.glDepthMask(false);
+      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void setAsInput()
     {
-    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texIds[0]);
+    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, colorIds[0]);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -227,14 +279,17 @@ public class DistortedFramebuffer
     {
     mProjectionMatrix = new float[16];
 
-    mHeight  = height;
-    mWidth   = width;
-    fboIds[0]= -1;
-    texIds[0]= TEXTURE_NOT_CREATED_YET;
-    mFOV     = 60.0f;
-    mX       = 0.0f;
-    mY       = 0.0f;
-    mMarked  = false;
+    mHeight     = height;
+    mWidth      = width;
+    mFOV        = 60.0f;
+    mX          = 0.0f;
+    mY          = 0.0f;
+    mMarked     = false;
+    mDepthWanted= false;
+
+    fboIds[0]  =-1;
+    colorIds[0]= NOT_CREATED_YET;
+    depthIds[0]= NOT_CREATED_YET;
 
     createProjection();
     }
@@ -251,15 +306,31 @@ public class DistortedFramebuffer
     {
     mProjectionMatrix = new float[16];
 
-    fboIds[0]= fbo;
-    texIds[0]= TEXTURE_DONT_CREATE;
-    mFOV     = 60.0f;
-    mX       = 0.0f;
-    mY       = 0.0f;
-    mMarked  = false;
+    mFOV        = 60.0f;
+    mX          = 0.0f;
+    mY          = 0.0f;
+    mMarked     = false;
+    mDepthWanted= true;
+
+    fboIds[0]  = fbo;
+    colorIds[0]= DONT_CREATE;
+    depthIds[0]= DONT_CREATE;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Create a new DEPTH buffer and attach it or (param=false) detach an existing DEPTh attachment and destroy it.
+ *
+ * @param hasDepthAttachment <bold>true</bold> if we want to attach a new DEPTH buffer to the FBO.<br>
+ *                           <bold>false</bold> if we want to detach the DEPTH attachment.
+ */
+  public void setDepthAttachment(boolean hasDepthAttachment)
+    {
+    mDepthWanted = hasDepthAttachment;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+
 /**
  * Draw the (texture,mesh,effects) object to the Framebuffer.
  * <p>
@@ -275,7 +346,7 @@ public class DistortedFramebuffer
     tex.createTexture();
     tex.setAsInput();
     createFBO();
-    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboIds[0]);
+    setAsOutput();
     effects.drawPriv(tex.mHalfX, tex.mHalfY, mesh, this, time);
     DistortedFramebuffer.deleteAllMarked();
     DistortedTexture.deleteAllMarked();
@@ -298,11 +369,11 @@ public class DistortedFramebuffer
     {
     fbo.createFBO();
 
-    if( fbo.texIds[0]>0 )    // fbo created with the first constructor
+    if( fbo.colorIds[0]>0 )    // fbo created with the first constructor
       {
       createFBO();
-      GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboIds[0]);
-      GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fbo.texIds[0]);
+      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();
@@ -321,7 +392,7 @@ public class DistortedFramebuffer
   public void renderTo(DistortedTree dt, long time)
     {
     createFBO();
-    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fboIds[0]);
+    setAsOutput();
     dt.drawRecursive(time,this);
     DistortedFramebuffer.deleteAllMarked();
     DistortedTexture.deleteAllMarked();
@@ -379,7 +450,7 @@ public class DistortedFramebuffer
 
       createProjection();
 
-      if( texIds[0]>0 ) markForDeletion();
+      if( colorIds[0]>0 ) markForDeletion();
       }
     }
 
@@ -396,6 +467,17 @@ public class DistortedFramebuffer
  */
   public int getTextureID()
     {
-    return texIds[0];
+    return colorIds[0];
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Return true if the FBO contains a DEPTH attachment.
+ *
+ * @return <bold>true</bold> if the FBO contains a DEPTH attachment.
+ */
+  public boolean hasDepth()
+    {
+    return mDepthWanted;
     }
   }
diff --git a/src/main/java/org/distorted/library/DistortedTree.java b/src/main/java/org/distorted/library/DistortedTree.java
index d1dc588..df8f853 100644
--- a/src/main/java/org/distorted/library/DistortedTree.java
+++ b/src/main/java/org/distorted/library/DistortedTree.java
@@ -50,14 +50,14 @@ public class DistortedTree
     long ID;
     int numPointingNodes;
     int numRendered;
-    DistortedFramebuffer mDF;
+    DistortedFramebuffer mFBO;
 
     NodeData(long id)
       {
       ID              = id;
       numPointingNodes= 1;
       numRendered     = 0;
-      mDF             = null;
+      mFBO            = null;
       }
     }
  
@@ -124,15 +124,15 @@ public class DistortedTree
 
       if( newList.size()>1 )
         {
-        if( mData.mDF==null )
-          mData.mDF = new DistortedFramebuffer(mTexture.getWidth(), mTexture.getHeight());
+        if( mData.mFBO ==null )
+          mData.mFBO = new DistortedFramebuffer(mTexture.getWidth(), mTexture.getHeight());
         }
       else
         {
-        if( mData.mDF!=null )
+        if( mData.mFBO !=null )
           {
-          mData.mDF.markForDeletion();
-          mData.mDF = null;
+          mData.mFBO.markForDeletion();
+          mData.mFBO = null;
           }
         else
           {
@@ -160,9 +160,9 @@ public class DistortedTree
       {
       tmp = mMapNodeID.get(key);
           
-      if( tmp.mDF != null )
+      if( tmp.mFBO != null )
         {
-    	  tmp.mDF.reset();
+    	  tmp.mFBO.reset();
         tmp.numRendered = 0;
         }
       }
@@ -212,23 +212,23 @@ public class DistortedTree
       }
     else
       {
-      mData.mDF.createFBO();
+      mData.mFBO.createFBO();
 
       if( mData.numRendered==0 )
         {
-        mData.mDF.setAsOutput();
+        mData.mFBO.setAsOutput();
 
         GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
         GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
 
         if( mTexture.setAsInput() )
-          mEffects.drawNoEffectsPriv(mTexture.mHalfX, mTexture.mHalfY, mMesh, mData.mDF);
+          mEffects.drawNoEffectsPriv(mTexture.mHalfX, mTexture.mHalfY, mMesh, mData.mFBO);
 
         synchronized(this)
           {
           for(int i=0; i<mNumChildren[0]; i++)
             {
-            mChildren.get(i).drawRecursive(currTime, mData.mDF);
+            mChildren.get(i).drawRecursive(currTime, mData.mFBO);
             }
           }
         }
@@ -237,7 +237,7 @@ public class DistortedTree
       mData.numRendered %= mData.numPointingNodes;
 
       df.setAsOutput();
-      mData.mDF.setAsInput();
+      mData.mFBO.setAsInput();
       }
 
     mEffects.drawPriv(mTexture.mHalfX, mTexture.mHalfY, mMesh, df, currTime);
@@ -476,5 +476,15 @@ public class DistortedTree
     return mTexture;
     }
 
-  }
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Returns the DistortedFramebuffer object that's in the Node.
+ *
+ * @return The DistortedFramebuffer contained in the Node.
+ */
+  public DistortedFramebuffer getFramebuffer()
+    {
+    return mData.mFBO;
+    }
 
+  }
