commit 23eecbd9ace8c69f11d5198b495ab3590cfa6377
Author: Leszek Koltunski <leszek@distoretedandroid.org>
Date:   Tue May 16 15:41:40 2017 +0100

    Progress with Stencil app. Rendering through an intermediate FBO still doesn't quite work.

diff --git a/src/main/java/org/distorted/library/DistortedFramebuffer.java b/src/main/java/org/distorted/library/DistortedFramebuffer.java
index 099a231..f9f40d7 100644
--- a/src/main/java/org/distorted/library/DistortedFramebuffer.java
+++ b/src/main/java/org/distorted/library/DistortedFramebuffer.java
@@ -183,7 +183,7 @@ public class DistortedFramebuffer extends DistortedOutputSurface implements Dist
  * @param width Width of the COLOR attachment.
  * @param height Height of the COLOR attachment.
  * @param depthStencil Add DEPTH or STENCIL attachment?
- *                     Valid values: NO_DEPTH_STENCIL, DEPTH_NO_STENCIL, BOTH_DEPTH_STENCIL.
+ *                     Valid values: NO_DEPTH_NO_STENCIL, DEPTH_NO_STENCIL, BOTH_DEPTH_STENCIL.
  */
   @SuppressWarnings("unused")
   public DistortedFramebuffer(int width, int height, int depthStencil)
@@ -202,7 +202,7 @@ public class DistortedFramebuffer extends DistortedOutputSurface implements Dist
   @SuppressWarnings("unused")
   public DistortedFramebuffer(int width, int height)
     {
-    super(width,height,NOT_CREATED_YET,NO_DEPTH_STENCIL,NOT_CREATED_YET,TYPE_USER);
+    super(width,height,NOT_CREATED_YET, NO_DEPTH_NO_STENCIL,NOT_CREATED_YET,TYPE_USER);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -227,11 +227,11 @@ public class DistortedFramebuffer extends DistortedOutputSurface implements Dist
 /**
  * Enable.disable DEPTH and STENCIL buffers.
  *
- * @param depthStencil Valid values: NO_DEPTH_STENCIL, DEPTH_NO_STENCIL, BOTH_DEPTH_STENCIL.
+ * @param depthStencil Valid values: NO_DEPTH_NO_STENCIL, DEPTH_NO_STENCIL, BOTH_DEPTH_STENCIL.
  */
   public void enableDepthStencil(int depthStencil)
     {
-    if( depthStencil!=NO_DEPTH_STENCIL && mDepthStencilCreated==DONT_CREATE )
+    if( depthStencil!= NO_DEPTH_NO_STENCIL && mDepthStencilCreated==DONT_CREATE )
       {
       mDepthStencilCreated = NOT_CREATED_YET;
       mDepthStencil = depthStencil;
@@ -243,7 +243,7 @@ public class DistortedFramebuffer extends DistortedOutputSurface implements Dist
 
       markForCreation();
       }
-    if( depthStencil==NO_DEPTH_STENCIL && mDepthStencilCreated!=DONT_CREATE )
+    if( depthStencil== NO_DEPTH_NO_STENCIL && mDepthStencilCreated!=DONT_CREATE )
       {
       mDepthStencilCreated = DONT_CREATE;
       mDepthStencil = depthStencil;
diff --git a/src/main/java/org/distorted/library/DistortedNode.java b/src/main/java/org/distorted/library/DistortedNode.java
index f50b866..8366e20 100644
--- a/src/main/java/org/distorted/library/DistortedNode.java
+++ b/src/main/java/org/distorted/library/DistortedNode.java
@@ -71,6 +71,7 @@ public class DistortedNode implements DistortedSlave
   private DistortedInputSurface mSurface;
   private DistortedRenderState mState;
   private NodeData mData;
+  private int mFboW, mFboH, mFboDepthStencil;
 
   private class NodeData
     {
@@ -245,7 +246,9 @@ public class DistortedNode implements DistortedSlave
       }
     else if( createNewFBO )
       {
-      newData.mFBO = new DistortedFramebuffer(DistortedFramebuffer.DEPTH_NO_STENCIL, DistortedSurface.TYPE_TREE, mSurface.getWidth(),mSurface.getHeight());
+      int width  = mFboW <= 0 ? mSurface.getWidth()  : mFboW;
+      int height = mFboH <= 0 ? mSurface.getHeight() : mFboH;
+      newData.mFBO = new DistortedFramebuffer(mFboDepthStencil, DistortedSurface.TYPE_TREE, width, height);
       //android.util.Log.d("NODE", "creating new FBO "+newData.mFBO.getID() );
       }
 
@@ -289,7 +292,9 @@ public class DistortedNode implements DistortedSlave
 
       if( mData.mFBO==null )
         {
-        mData.mFBO = new DistortedFramebuffer(DistortedFramebuffer.DEPTH_NO_STENCIL, DistortedSurface.TYPE_TREE, mSurface.getWidth(),mSurface.getHeight());
+        int width  = mFboW <= 0 ? mSurface.getWidth()  : mFboW;
+        int height = mFboH <= 0 ? mSurface.getHeight() : mFboH;
+        mData.mFBO = new DistortedFramebuffer(mFboDepthStencil, DistortedSurface.TYPE_TREE, width, height);
         }
 
       mData.mFBO.setAsOutput(currTime);
@@ -351,6 +356,10 @@ public class DistortedNode implements DistortedSlave
     mParent        = null;
     mSurfaceParent = null;
 
+    mFboW            = 0;  // i.e. take this from
+    mFboH            = 0;  // mSurface's dimensions
+    mFboDepthStencil = DistortedFramebuffer.DEPTH_NO_STENCIL;
+
     ArrayList<Long> list = new ArrayList<>();
     list.add(mSurface.getID());
     list.add(-mEffects.getID());
@@ -387,6 +396,10 @@ public class DistortedNode implements DistortedSlave
     mParent       = null;
     mSurfaceParent= null;
 
+    mFboW            = node.mFboW;
+    mFboH            = node.mFboH;
+    mFboDepthStencil = node.mFboDepthStencil;
+
     if( (flags & Distorted.CLONE_SURFACE) != 0 )
       {
       mSurface = node.mSurface;
@@ -402,7 +415,7 @@ public class DistortedNode implements DistortedSlave
         }
       else if( node.mSurface instanceof DistortedFramebuffer )
         {
-        int depthStencil = DistortedFramebuffer.NO_DEPTH_STENCIL;
+        int depthStencil = DistortedFramebuffer.NO_DEPTH_NO_STENCIL;
 
         if( ((DistortedFramebuffer) node.mSurface).hasDepth() )
           {
@@ -683,13 +696,33 @@ public class DistortedNode implements DistortedSlave
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
- * Returns the DistortedFramebuffer object that's in the Node.
- *
- * @return The DistortedFramebuffer contained in the Node.
+ * Resizes the DistortedFramebuffer object that we render this Node to.
  */
-  public DistortedFramebuffer getFramebuffer()
+  public void resize(int width, int height)
     {
-    return mData.mFBO;
+    mFboW = width;
+    mFboH = height;
+
+    if ( mData.mFBO !=null )
+      {
+      // TODO: potentially allocate a new NodeData if we have to
+      mData.mFBO.resize(width,height);
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Enables/disables DEPTH and STENCIL buffers in the Framebuffer object that we render this Node to.
+ */
+  public void enableDepthStencil(int depthStencil)
+    {
+    mFboDepthStencil = depthStencil;
+
+    if ( mData.mFBO !=null )
+      {
+      // TODO: potentially allocate a new NodeData if we have to
+      mData.mFBO.enableDepthStencil(depthStencil);
+      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/DistortedOutputSurface.java b/src/main/java/org/distorted/library/DistortedOutputSurface.java
index 7247c5f..4d8d5d7 100644
--- a/src/main/java/org/distorted/library/DistortedOutputSurface.java
+++ b/src/main/java/org/distorted/library/DistortedOutputSurface.java
@@ -30,15 +30,15 @@ abstract class DistortedOutputSurface extends DistortedSurface implements Distor
 /**
  * Do not create DEPTH or STENCIL attachment
  */
-  public static final int NO_DEPTH_STENCIL = 0;
+  public static final int NO_DEPTH_NO_STENCIL = 0;
 /**
  * Create DEPTH, but not STENCIL
  */
-  public static final int DEPTH_NO_STENCIL = 1;
+  public static final int DEPTH_NO_STENCIL    = 1;
 /**
  * Create both DEPTH and STENCIL
  */
-  public static final int BOTH_DEPTH_STENCIL= 2;
+  public static final int BOTH_DEPTH_STENCIL  = 2;
 
   private static final int ATTACH = 0;
   private static final int DETACH = 1;
@@ -78,6 +78,7 @@ abstract class DistortedOutputSurface extends DistortedSurface implements Distor
 
   private float mClearR, mClearG, mClearB, mClearA;
   private float mClearDepth;
+  private int mClearStencil;
   private int mClear;
 
 //private String sNew="", sOld="";
@@ -95,7 +96,7 @@ abstract class DistortedOutputSurface extends DistortedSurface implements Distor
     mFOV = 60.0f;
     mNear=  0.5f;
 
-    mDepthStencilCreated= (depthStencil==NO_DEPTH_STENCIL ? DONT_CREATE:NOT_CREATED_YET);
+    mDepthStencilCreated= (depthStencil== NO_DEPTH_NO_STENCIL ? DONT_CREATE:NOT_CREATED_YET);
     mDepthStencil = depthStencil;
 
     mFBOH[0]         = fbo;
@@ -109,6 +110,7 @@ abstract class DistortedOutputSurface extends DistortedSurface implements Distor
     mClearA = 0.0f;
 
     mClearDepth = 1.0f;
+    mClearStencil = 0;
     mClear = GLES30.GL_DEPTH_BUFFER_BIT | GLES30.GL_COLOR_BUFFER_BIT;
 
     mBuffer1 = new DistortedFramebuffer[EffectQuality.LENGTH];
@@ -196,9 +198,9 @@ abstract class DistortedOutputSurface extends DistortedSurface implements Distor
 
           for(int j=0; j<EffectQuality.LENGTH; j++)
             {
-            mBuffer1[j] = new DistortedFramebuffer( mDepthStencil   , DistortedObject.TYPE_SYST,
+            mBuffer1[j] = new DistortedFramebuffer( mDepthStencil     , DistortedObject.TYPE_SYST,
                                                     (int)(mWidth*mipmap), (int)(mHeight*mipmap) );
-            mBuffer2[j] = new DistortedFramebuffer( NO_DEPTH_STENCIL, DistortedObject.TYPE_SYST,
+            mBuffer2[j] = new DistortedFramebuffer(NO_DEPTH_NO_STENCIL, DistortedObject.TYPE_SYST,
                                                     (int)(mWidth*mipmap), (int)(mHeight*mipmap) );
             mBuffer1[j].mMipmap = mipmap;
             mipmap *= EffectQuality.MULTIPLIER;
@@ -310,9 +312,10 @@ if( !sNew.equals(sOld) )
     if( mTime!=time )
       {
       mTime = time;
-      DistortedRenderState.colorDepthOn();
+      DistortedRenderState.colorDepthStencilOn();
       GLES30.glClearColor(mClearR, mClearG, mClearB, mClearA);
       GLES30.glClearDepthf(mClearDepth);
+      GLES30.glClearStencil(mClearStencil);
       GLES30.glClear(mClear);
       }
     }
@@ -361,8 +364,8 @@ if( !sNew.equals(sOld) )
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
- * Set the Depth value of GLES30.glClearDepthf() to set up depth with which to clear
- * the Depth buffer of Surface at the beginning of each frame.
+ * Uses glClearDepthf() to set up a value with which to clear
+ * the Depth buffer of our Surface at the beginning of each frame.
  *
  * @param d the Depth. Default: 1.0f
  */
@@ -371,6 +374,18 @@ if( !sNew.equals(sOld) )
     mClearDepth = d;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Uses glClearStencil() to set up a value with which to clear the
+ * Stencil buffer of our Surface at the beginning of each frame.
+ *
+ * @param s the Stencil. Default: 0
+ */
+  public void glClearStencil(int s)
+    {
+    mClearStencil = s;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Which buffers to Clear at the beginning of each frame?
diff --git a/src/main/java/org/distorted/library/DistortedRenderState.java b/src/main/java/org/distorted/library/DistortedRenderState.java
index f9831aa..97b803a 100644
--- a/src/main/java/org/distorted/library/DistortedRenderState.java
+++ b/src/main/java/org/distorted/library/DistortedRenderState.java
@@ -30,6 +30,9 @@ import android.opengl.GLES30;
  */
 class DistortedRenderState
 {
+  // TODO: figure this out dynamically; this assumes 8 bit stencil buffer.
+  private static final int STENCIL_MASK = (1<<8)-1;
+
   private static int sColorMaskR, sColorMaskG, sColorMaskB, sColorMaskA;   //
   private static int sDepthMask;                                           //
   private static int sStencilMask;                                         //
@@ -72,10 +75,10 @@ class DistortedRenderState
     mBlendDst   = GLES30.GL_ONE_MINUS_SRC_ALPHA;
 
     mStencilTest     = 0;
-    mStencilMask     = 0x11111111;
+    mStencilMask     = STENCIL_MASK;
     mStencilFuncFunc = GLES30.GL_NEVER;
     mStencilFuncRef  = 0;
-    mStencilFuncMask = 0x11111111;
+    mStencilFuncMask = STENCIL_MASK;
     mStencilOpSfail  = GLES30.GL_KEEP;
     mStencilOpDpfail = GLES30.GL_KEEP;
     mStencilOpDppass = GLES30.GL_KEEP;
@@ -113,7 +116,7 @@ class DistortedRenderState
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  static void colorDepthOn()
+  static void colorDepthStencilOn()
     {
     if( sColorMaskR!=1 || sColorMaskG!=1 || sColorMaskB!=1 || sColorMaskA!=1 )
       {
@@ -128,6 +131,11 @@ class DistortedRenderState
       sDepthMask = 1;
       GLES30.glDepthMask(true);
       }
+    if( sStencilMask!= STENCIL_MASK )
+      {
+      sStencilMask = STENCIL_MASK;
+      GLES30.glStencilMask(sStencilMask);
+      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
