commit aedd9013b59b13eb0b7e98bef32df79abb8b60d0
Author: leszek <leszek@koltunski.pl>
Date:   Mon May 15 22:52:25 2017 +0100

    First try to convert the Stencil app to a dual (directly to Screen / through intermediate Framebuffer) mode.
    Doesn't work yet ( API is inconvenient / plain wrong )

diff --git a/src/main/java/org/distorted/examples/stencil/StencilActivity.java b/src/main/java/org/distorted/examples/stencil/StencilActivity.java
index 95986f3..c52311f 100644
--- a/src/main/java/org/distorted/examples/stencil/StencilActivity.java
+++ b/src/main/java/org/distorted/examples/stencil/StencilActivity.java
@@ -21,23 +21,29 @@ package org.distorted.examples.stencil;
 
 import android.app.Activity;
 import android.os.Bundle;
+import android.view.View;
 
+import org.distorted.examples.R;
 import org.distorted.library.Distorted;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 public class StencilActivity extends Activity
 {
-    private StencilSurfaceView mView;
+    private boolean mScreen;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
     @Override
-    protected void onCreate(Bundle icicle)
+    protected void onCreate(Bundle savedState)
       {
-      super.onCreate(icicle);
-      mView = new StencilSurfaceView(this);
-      setContentView(mView);
+      super.onCreate(savedState);
+      setContentView(R.layout.stencillayout);
+
+      if( savedState==null )
+        {
+        mScreen = true;
+        }
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -45,7 +51,9 @@ public class StencilActivity extends Activity
     @Override
     protected void onPause() 
       {
-      mView.onPause();
+      StencilSurfaceView view = (StencilSurfaceView) this.findViewById(R.id.stencilSurfaceView);
+
+      view.onPause();
       Distorted.onPause();
       super.onPause();
       }
@@ -55,8 +63,10 @@ public class StencilActivity extends Activity
     @Override
     protected void onResume() 
       {
+      StencilSurfaceView view = (StencilSurfaceView) this.findViewById(R.id.stencilSurfaceView);
+
       super.onResume();
-      mView.onResume();
+      view.onResume();
       }
     
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -67,5 +77,48 @@ public class StencilActivity extends Activity
       Distorted.onDestroy();
       super.onDestroy();
       }
-    
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void Screen(View v)
+      {
+      StencilSurfaceView view = (StencilSurfaceView) this.findViewById(R.id.stencilSurfaceView);
+      StencilRenderer renderer = view.getRenderer();
+
+      renderer.setScreen(true);
+      mScreen = true;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void Framebuffer(View v)
+      {
+      StencilSurfaceView view = (StencilSurfaceView) this.findViewById(R.id.stencilSurfaceView);
+      StencilRenderer renderer = view.getRenderer();
+
+      renderer.setScreen(false);
+      mScreen = false;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void onSaveInstanceState(Bundle savedInstanceState)
+      {
+      super.onSaveInstanceState(savedInstanceState);
+      savedInstanceState.putBoolean("screen", mScreen);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void onRestoreInstanceState(Bundle savedInstanceState)
+      {
+      super.onRestoreInstanceState(savedInstanceState);
+
+      mScreen = savedInstanceState.getBoolean("screen");
+
+      if(mScreen) Screen(null);
+      else        Framebuffer(null);
+      }
 }
diff --git a/src/main/java/org/distorted/examples/stencil/StencilRenderer.java b/src/main/java/org/distorted/examples/stencil/StencilRenderer.java
index 4086e9c..d671e09 100644
--- a/src/main/java/org/distorted/examples/stencil/StencilRenderer.java
+++ b/src/main/java/org/distorted/examples/stencil/StencilRenderer.java
@@ -27,6 +27,7 @@ import android.opengl.GLSurfaceView;
 import org.distorted.examples.R;
 import org.distorted.library.Distorted;
 import org.distorted.library.DistortedEffects;
+import org.distorted.library.DistortedFramebuffer;
 import org.distorted.library.DistortedNode;
 import org.distorted.library.DistortedScreen;
 import org.distorted.library.DistortedTexture;
@@ -51,9 +52,40 @@ class StencilRenderer implements GLSurfaceView.Renderer
 {
     private GLSurfaceView mView;
     private DistortedScreen mScreen;
-    private DistortedTexture mCubeTex, mFloorTex;
-    private DistortedEffects mCube1Effects, mCube2Effects, mFloorEffects;
-    private MeshObject mCubeMesh, mFloorMesh;
+    private DistortedTexture mCubeTex, mFloorTex, mFBOTex;
+    private DistortedEffects mCube1Effects, mCube2Effects, mFloorEffects, mFBOEffects;
+    private DistortedNode mCube1Node, mCube2Node, mFloorNode, mFBONode;
+    private MeshObject mCubeMesh, mQuad;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    void setScreen(boolean screen)
+      {
+      if( screen )
+        {
+        mScreen.detachAll();
+        mScreen.attach(mCube1Node);
+        mScreen.attach(mFloorNode);
+        mScreen.attach(mCube2Node);
+        }
+      else
+        {
+        if( mFBONode==null ) mFBONode = new DistortedNode(mFBOTex,mFBOEffects,mQuad);
+
+        mScreen.detachAll();
+        mScreen.attach(mFBONode);
+        mFBONode.attach(mCube1Node);
+        mFBONode.attach(mCube2Node);
+        mFBONode.attach(mFloorNode);
+
+        DistortedFramebuffer fbo = mFBONode.getFramebuffer();
+        if( fbo!=null ) fbo.enableDepthStencil(DistortedFramebuffer.BOTH_DEPTH_STENCIL);
+        else
+          {
+          android.util.Log.e("stencil", "failed to enable STENCIL!");
+          }
+        }
+      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -61,45 +93,45 @@ class StencilRenderer implements GLSurfaceView.Renderer
       {
       mView = v;
 
-      mCubeMesh  = new MeshCubes(1,1,false);
-      mFloorMesh = new MeshFlat(1,1);
+      mCubeMesh = new MeshCubes(1,1,false);
+      mQuad     = new MeshFlat(1,1);
 
       mCubeTex   = new DistortedTexture(1,1);
       mFloorTex  = new DistortedTexture(1,1);
+      mFBOTex    = new DistortedTexture(1,1);
 
       mCube1Effects = new DistortedEffects();
       mCube2Effects = new DistortedEffects();
       mFloorEffects = new DistortedEffects();
+      mFBOEffects   = new DistortedEffects();
 
       mCube2Effects.brightness(new Static1D(0.5f));
 
-      DistortedNode cube1Node = new DistortedNode(mCubeTex ,mCube1Effects,mCubeMesh );
-      DistortedNode cube2Node = new DistortedNode(mCubeTex ,mCube2Effects,mCubeMesh );
-      DistortedNode floorNode = new DistortedNode(mFloorTex,mFloorEffects,mFloorMesh);
+      mCube1Node = new DistortedNode(mCubeTex ,mCube1Effects,mCubeMesh );
+      mCube2Node = new DistortedNode(mCubeTex ,mCube2Effects,mCubeMesh );
+      mFloorNode = new DistortedNode(mFloorTex,mFloorEffects,mQuad     );
 
-      floorNode.glEnable(GLES30.GL_STENCIL_TEST);                               // Enable Stencil when rendering this Node
-      floorNode.glStencilFunc(GLES30.GL_ALWAYS, 1, 0xFF);                       // Set any stencil to 1
-      floorNode.glStencilOp(GLES30.GL_KEEP, GLES30.GL_KEEP, GLES30.GL_REPLACE); // replace with 1 when we fail Depth test
-      floorNode.glStencilMask(0xFF);                                            // Write to stencil buffer
-      floorNode.glDepthMask(false);                                             // Don't write to depth buffer
-      floorNode.glClear(GLES30.GL_STENCIL_BUFFER_BIT);                          // Clear stencil buffer (0 by default)
+      mFloorNode.glEnable(GLES30.GL_STENCIL_TEST);                               // Enable Stencil when rendering this Node
+      mFloorNode.glStencilFunc(GLES30.GL_ALWAYS, 1, 0xFF);                       // Set any stencil to 1
+      mFloorNode.glStencilOp(GLES30.GL_KEEP, GLES30.GL_KEEP, GLES30.GL_REPLACE); // replace with 1 when we fail Depth test
+      mFloorNode.glStencilMask(0xFF);                                            // Write to stencil buffer
+      mFloorNode.glDepthMask(false);                                             // Don't write to depth buffer
+      mFloorNode.glClear(GLES30.GL_STENCIL_BUFFER_BIT);                          // Clear stencil buffer (0 by default)
 
-      cube2Node.glEnable(GLES30.GL_STENCIL_TEST);                               // Enable Stencil when rendering this Node
-      cube2Node.glStencilFunc(GLES30.GL_EQUAL, 1, 0xFF);                        // Pass test if stencil value is 1
-      cube2Node.glStencilMask(0x00);                                            // Don't write anything to stencil buffer
-      cube2Node.glDepthMask(true);                                              // Write to depth buffer
+      mCube2Node.glEnable(GLES30.GL_STENCIL_TEST);                               // Enable Stencil when rendering this Node
+      mCube2Node.glStencilFunc(GLES30.GL_EQUAL, 1, 0xFF);                        // Pass test if stencil value is 1
+      mCube2Node.glStencilMask(0x00);                                            // Don't write anything to stencil buffer
+      mCube2Node.glDepthMask(true);                                              // Write to depth buffer
 
       mScreen = new DistortedScreen(mView);
-      mScreen.attach(cube1Node);
-      mScreen.attach(floorNode);
-      mScreen.attach(cube2Node);
       mScreen.glClearColor(1.0f,1.0f,1.0f,1.0f);
-
       mView.setEGLConfigChooser(5,6,5,0,16,8);       // Screen: 16 bit depth, 8 bit STENCIL
+
+      setScreen(true);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-   
+
     public void onDrawFrame(GL10 glUnused) 
       {
       mScreen.render(System.currentTimeMillis());
@@ -115,7 +147,7 @@ class StencilRenderer implements GLSurfaceView.Renderer
 
       float fw = mFloorTex.getWidth();
       float fh = mFloorTex.getHeight();
-      float fd = mFloorTex.getDepth(mFloorMesh);
+      float fd = mFloorTex.getDepth(mQuad);
 
       float cubeScale = 0.4f*(width>height ? height/ch:width/cw);
       float floorScale= 0.8f*(width>height ? height/fh:width/fw);
@@ -157,6 +189,15 @@ class StencilRenderer implements GLSurfaceView.Renderer
       mFloorEffects.rotate(rotSt2, axisX, floorCenter);
       mFloorEffects.rotate(rotDyn, axisZ, floorCenter);
 
+      if( mFBONode==null ) mFBONode = new DistortedNode(mFBOTex,mFBOEffects,mQuad);
+
+      DistortedFramebuffer fbo = mFBONode.getFramebuffer();
+      if( fbo!=null ) fbo.resize(width,height);
+      else
+        {
+        android.util.Log.e("stencil", "failed to resize FBO!");
+        }
+
       mScreen.resize(width, height);
       }
 
diff --git a/src/main/java/org/distorted/examples/stencil/StencilSurfaceView.java b/src/main/java/org/distorted/examples/stencil/StencilSurfaceView.java
index ab381b5..9153803 100644
--- a/src/main/java/org/distorted/examples/stencil/StencilSurfaceView.java
+++ b/src/main/java/org/distorted/examples/stencil/StencilSurfaceView.java
@@ -21,17 +21,32 @@ package org.distorted.examples.stencil;
 
 import android.content.Context;
 import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 class StencilSurfaceView extends GLSurfaceView
 {
+   private StencilRenderer mRenderer;
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
    
-    public StencilSurfaceView(Context context)
-      {
-      super(context);
-      setRenderer(new StencilRenderer(this));
-      }
+   public StencilSurfaceView(Context context, AttributeSet attrs)
+     {
+     super(context,attrs);
+
+     if(!isInEditMode())
+       {
+       mRenderer = new StencilRenderer(this);
+       setRenderer(mRenderer);
+       }
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   public StencilRenderer getRenderer()
+     {
+     return mRenderer;
+     }
 }
 
diff --git a/src/main/res/layout/fbolayout.xml b/src/main/res/layout/fbolayout.xml
index bab6314..fd1afe1 100644
--- a/src/main/res/layout/fbolayout.xml
+++ b/src/main/res/layout/fbolayout.xml
@@ -24,7 +24,7 @@
             android:orientation="horizontal">
 
             <RadioButton
-                android:id="@+id/deformDistortButton"
+                android:id="@+id/depthYesButton"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:checked="true"
@@ -32,7 +32,7 @@
                 android:text="@string/DepthYes"/>
 
             <RadioButton
-                android:id="@+id/deformDeformButton"
+                android:id="@+id/depthNoButton"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:onClick="DepthNo"
diff --git a/src/main/res/layout/stencillayout.xml b/src/main/res/layout/stencillayout.xml
new file mode 100644
index 0000000..71e0058
--- /dev/null
+++ b/src/main/res/layout/stencillayout.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+
+    <org.distorted.examples.stencil.StencilSurfaceView
+        android:id="@+id/stencilSurfaceView"
+        android:layout_width="fill_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+
+    <LinearLayout
+        android:id="@+id/linearLayout1"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center|fill_horizontal"
+        android:orientation="vertical">
+
+        <RadioGroup
+            android:id="@+id/radioGroup1"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+
+            <RadioButton
+                android:id="@+id/screenButton"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:checked="true"
+                android:onClick="Screen"
+                android:text="@string/screen"/>
+
+            <RadioButton
+                android:id="@+id/framebufferButton"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="Framebuffer"
+                android:text="@string/framebuffer"/>
+
+        </RadioGroup>
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 05a8fd8..9ec9599 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -68,6 +68,8 @@
     <string name="show_center">Show Center</string>
     <string name="show_region">Show Region</string>
     <string name="show_normal">Show Normals</string>
+    <string name="screen">Screen</string>
+    <string name="framebuffer">Framebuffer</string>
 
     <string name="radius_placeholder">Radius: %1$s</string>
     <string name="noise_placeholder">Noise %1$s</string>
