commit 5ceea14811c4278ee8db22187df972d5669d07d9
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Fri Dec 14 16:50:44 2018 +0000

    - new icon for the GLOW app
    - rename the BitmapTree app to ObjectTree

diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 802874d..8bf894c 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -29,7 +29,7 @@
         <activity android:name=".differentbitmaps.DifferentBitmapsActivity" />    
         <activity android:name=".effectqueue.EffectQueueActivity" />
         <activity android:name=".check.CheckActivity" />    
-        <activity android:name=".bitmaptree.BitmapTreeActivity" />
+        <activity android:name=".objecttree.ObjectTreeActivity" />
         <activity android:name=".starwars.StarWarsActivity" />      
         <activity android:name=".olimpic.OlimpicActivity" />  
         <activity android:name=".cubes.CubesActivity" />       
diff --git a/src/main/java/org/distorted/examples/TableOfContents.java b/src/main/java/org/distorted/examples/TableOfContents.java
index 40e0a32..dc8f054 100644
--- a/src/main/java/org/distorted/examples/TableOfContents.java
+++ b/src/main/java/org/distorted/examples/TableOfContents.java
@@ -49,7 +49,7 @@ import org.distorted.examples.differentbitmaps.DifferentBitmapsActivity;
 import org.distorted.examples.effectqueue.EffectQueueActivity;
 import org.distorted.examples.check.CheckActivity;
 import org.distorted.examples.bean.BeanActivity;
-import org.distorted.examples.bitmaptree.BitmapTreeActivity;
+import org.distorted.examples.objecttree.ObjectTreeActivity;
 import org.distorted.examples.starwars.StarWarsActivity;
 import org.distorted.examples.cubes.CubesActivity;
 import org.distorted.examples.quaternion.QuaternionActivity;
@@ -220,10 +220,10 @@ public class TableOfContents extends ListActivity
    {
       final Map<String, Object> item = new HashMap<>();
       item.put(ITEM_IMAGE, R.drawable.icon_example_fbo);
-      item.put(ITEM_TITLE, (i+1)+". "+getText(R.string.example_bitmaptree));
-      item.put(ITEM_SUBTITLE, getText(R.string.example_bitmaptree_subtitle));
+      item.put(ITEM_TITLE, (i+1)+". "+getText(R.string.example_objecttree));
+      item.put(ITEM_SUBTITLE, getText(R.string.example_objecttree_subtitle));
       data.add(item);
-      activityMapping.put(i++, BitmapTreeActivity.class);
+      activityMapping.put(i++, ObjectTreeActivity.class);
    }
       
    {
@@ -381,7 +381,7 @@ public class TableOfContents extends ListActivity
 
    {
       final Map<String, Object> item = new HashMap<>();
-      item.put(ITEM_IMAGE, R.drawable.icon_example_wip);
+      item.put(ITEM_IMAGE, R.drawable.icon_example_glow);
       item.put(ITEM_TITLE, (i+1)+". "+getText(R.string.example_glow));
       item.put(ITEM_SUBTITLE, getText(R.string.example_glow_subtitle));
       data.add(item);
diff --git a/src/main/java/org/distorted/examples/bitmaptree/BitmapTreeActivity.java b/src/main/java/org/distorted/examples/bitmaptree/BitmapTreeActivity.java
deleted file mode 100644
index a830e35..0000000
--- a/src/main/java/org/distorted/examples/bitmaptree/BitmapTreeActivity.java
+++ /dev/null
@@ -1,125 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2016 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.examples.bitmaptree;
-
-import org.distorted.examples.R;
-import org.distorted.library.main.Distorted;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.View;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-public class BitmapTreeActivity extends Activity
-{
-    private boolean mDepth;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-    
-    @Override
-    protected void onCreate(Bundle savedState)
-      {
-      super.onCreate(savedState);
-      setContentView(R.layout.bitmaptreelayout);
-
-      if( savedState==null )
-        {
-        mDepth = true;
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-    
-    @Override
-    protected void onPause() 
-      {
-      BitmapTreeSurfaceView view = (BitmapTreeSurfaceView) this.findViewById(R.id.bitmaptreeSurfaceView);
-
-      view.onPause();
-      Distorted.onPause();
-      super.onPause();
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-    
-    @Override
-    protected void onResume() 
-      {
-      BitmapTreeSurfaceView view = (BitmapTreeSurfaceView) this.findViewById(R.id.bitmaptreeSurfaceView);
-
-      super.onResume();
-      view.onResume();
-      }
-    
-///////////////////////////////////////////////////////////////////////////////////////////////////
-    
-    @Override
-    protected void onDestroy() 
-      {
-      Distorted.onDestroy();  
-      super.onDestroy();
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public void DepthYes(View v)
-      {
-      BitmapTreeSurfaceView view = (BitmapTreeSurfaceView) this.findViewById(R.id.bitmaptreeSurfaceView);
-      BitmapTreeRenderer renderer = view.getRenderer();
-
-      renderer.setDepth(true);
-      mDepth = true;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public void DepthNo(View v)
-      {
-      BitmapTreeSurfaceView view = (BitmapTreeSurfaceView) this.findViewById(R.id.bitmaptreeSurfaceView);
-      BitmapTreeRenderer renderer = view.getRenderer();
-
-      renderer.setDepth(false);
-      mDepth = false;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public void onSaveInstanceState(Bundle savedInstanceState)
-      {
-      super.onSaveInstanceState(savedInstanceState);
-      savedInstanceState.putBoolean("depth", mDepth);
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    @Override
-    public void onRestoreInstanceState(Bundle savedInstanceState)
-      {
-      super.onRestoreInstanceState(savedInstanceState);
-
-      mDepth = savedInstanceState.getBoolean("depth");
-
-      if(mDepth) DepthYes(null);
-      else       DepthNo(null);
-      }
-
-}
diff --git a/src/main/java/org/distorted/examples/bitmaptree/BitmapTreeRenderer.java b/src/main/java/org/distorted/examples/bitmaptree/BitmapTreeRenderer.java
deleted file mode 100644
index a9075b5..0000000
--- a/src/main/java/org/distorted/examples/bitmaptree/BitmapTreeRenderer.java
+++ /dev/null
@@ -1,227 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2016 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.examples.bitmaptree;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.opengles.GL10;
-
-import org.distorted.examples.R;
-
-import org.distorted.library.effect.FragmentEffectChroma;
-import org.distorted.library.effect.MatrixEffectMove;
-import org.distorted.library.effect.MatrixEffectRotate;
-import org.distorted.library.effect.MatrixEffectScale;
-import org.distorted.library.effect.VertexEffectSink;
-import org.distorted.library.main.DistortedEffects;
-import org.distorted.library.main.DistortedFramebuffer;
-import org.distorted.library.main.DistortedNode;
-import org.distorted.library.main.DistortedScreen;
-import org.distorted.library.main.Distorted;
-import org.distorted.library.mesh.MeshCubes;
-import org.distorted.library.mesh.MeshFlat;
-import org.distorted.library.main.DistortedTexture;
-import org.distorted.library.type.Dynamic;
-import org.distorted.library.type.Dynamic1D;
-import org.distorted.library.type.Static1D;
-import org.distorted.library.type.Static3D;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.opengl.GLES31;
-import android.opengl.GLSurfaceView;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-class BitmapTreeRenderer implements GLSurfaceView.Renderer
-{
-   private GLSurfaceView mView;
-   private DistortedEffects mEffects;
-   private DistortedTexture mLisaTexture, mGridTexture;
-   private DistortedScreen mScreen;
-   private DistortedNode mRoot;
-   private MeshFlat mMeshFlat;
-   private MeshCubes mMeshCubes;
-   private int lisaHeight, lisaWidth;
-   private boolean mDepth;
-   private Static3D mScale, mMove;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-   BitmapTreeRenderer(GLSurfaceView v)
-      {
-      mView   = v;
-      mDepth  = true;
-      mScale  = new Static3D(1,1,1);
-      mMove   = new Static3D(0,0,0);
-      Dynamic1D chromaDyn = new Dynamic1D(5000,0.0f);
-      chromaDyn.add(new Static1D(0.0f));
-      chromaDyn.add(new Static1D(0.8f));
-
-      mEffects= new DistortedEffects();
-      mEffects.apply(new MatrixEffectMove(mMove));
-      mEffects.apply(new MatrixEffectScale(mScale));
-      mEffects.apply(new FragmentEffectChroma(chromaDyn, new Static3D(0,0,1)));
-
-      mScreen = new DistortedScreen();
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-   private void setDepthPriv()
-     {
-     if( mDepth ) mRoot.glEnable (GLES31.GL_DEPTH_TEST);
-     else         mRoot.glDisable(GLES31.GL_DEPTH_TEST);
-
-     mRoot.glDepthMask(mDepth);
-
-     // we can also, to save memory, delete/recreate
-     // the depth buffer each time. This is optional.
-     mRoot.enableDepthStencil(mDepth ? DistortedFramebuffer.DEPTH_NO_STENCIL:DistortedFramebuffer.NO_DEPTH_NO_STENCIL);
-     }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-   void setDepth(boolean depth)
-      {
-      mDepth = depth;
-      if( mRoot!=null ) setDepthPriv();
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-   
-   public void onDrawFrame(GL10 glUnused)
-      {
-      mScreen.render(System.currentTimeMillis());
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-    
-   public void onSurfaceChanged(GL10 glUnused, int width, int height)
-      { 
-      if( (float)lisaHeight/lisaWidth > (float)height/width )
-        {
-        int w = (height*lisaWidth)/lisaHeight;
-        float factor = (float)height/lisaHeight;
-
-        mMove.set((width-w)/2,0,0);
-        mScale.set(factor,factor,factor);
-        }
-      else
-        {
-        int h = (width*lisaHeight)/lisaWidth;
-        float factor = (float)width/lisaWidth;
-
-        mMove.set(0,(height-h)/2,0);
-        mScale.set(factor,factor,factor);
-        }
-      
-      mScreen.resize(width, height);
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-    
-   public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
-      {
-      // TODO
-      // This appears to be needed in case we create the app anew with NO DEPTH
-      // (i.e. we set 'no depth' and then rotate screen). Investigate.
-      GLES31.glEnable(GLES31.GL_CULL_FACE);
-      GLES31.glCullFace(GLES31.GL_BACK);
-      GLES31.glFrontFace(GLES31.GL_CW);
-
-      InputStream is1 = mView.getContext().getResources().openRawResource(R.raw.monalisa);
-      InputStream is2 = mView.getContext().getResources().openRawResource(R.raw.grid);
-      
-      Bitmap bitmap1, bitmap2;
-       
-      try 
-        {
-        bitmap1 = BitmapFactory.decodeStream(is1);
-        bitmap2 = BitmapFactory.decodeStream(is2);
-        } 
-      finally 
-        {
-        try 
-          {
-          is1.close();
-          is2.close();
-          } 
-        catch(IOException e) { }
-        }  
-      
-      lisaWidth     = bitmap1.getWidth();
-      lisaHeight    = bitmap1.getHeight();
-      int gridWidth = bitmap2.getWidth();
-      int gridHeight= bitmap2.getHeight();
-
-      if( mLisaTexture==null ) mLisaTexture = new DistortedTexture(lisaWidth,lisaHeight);
-      if( mGridTexture==null ) mGridTexture = new DistortedTexture(gridWidth,gridHeight);
-      mLisaTexture.setTexture(bitmap1);
-      mGridTexture.setTexture(bitmap2);
-      DistortedEffects gridEffects = new DistortedEffects();
-
-      final int GRID = 10;
-
-      if( mMeshFlat==null ) mMeshFlat = new MeshFlat(1,1);
-      if( mMeshCubes==null) mMeshCubes= new MeshCubes(GRID,GRID,1);
-
-      mRoot = new DistortedNode(mLisaTexture, mEffects, mMeshFlat);
-      mRoot.attach(mGridTexture,gridEffects,mMeshCubes);
-
-      setDepthPriv();
-
-      mScreen.detachAll();
-      mScreen.attach(mRoot);
-
-      float factor = lisaWidth/(2.0f*gridWidth);
-      MatrixEffectMove move = new MatrixEffectMove( new Static3D((lisaWidth-factor*gridWidth)/2,(lisaHeight-factor*gridHeight)/2, gridWidth/(2.0f*GRID)));
-      MatrixEffectScale scale = new MatrixEffectScale( new Static3D(factor,factor,factor) );
-      gridEffects.apply(move);
-      gridEffects.apply(scale);
-
-      Dynamic1D rotDyn = new Dynamic1D(12000,0.0f);
-      rotDyn.add(new Static1D(  0));
-      rotDyn.add(new Static1D(360));
-      rotDyn.setMode(Dynamic.MODE_JUMP);
-      MatrixEffectRotate rotate = new MatrixEffectRotate(rotDyn, new Static3D(1,0,0), new Static3D(gridWidth/2,gridHeight/2,gridWidth/(2*GRID)));
-      gridEffects.apply(rotate);
-
-      Dynamic1D sinkDyn = new Dynamic1D(3000,0.0f);
-      sinkDyn.add(new Static1D(1.0f));
-      sinkDyn.add(new Static1D(0.3f));
-      VertexEffectSink sink = new VertexEffectSink(sinkDyn, new Static3D(gridWidth/2,gridHeight/2, 0));
-      gridEffects.apply(sink);
-
-      VertexEffectSink.enable();
-      FragmentEffectChroma.enable();
-
-      try
-        {
-        Distorted.onCreate(mView.getContext());
-        }
-      catch(Exception ex)
-        {
-        android.util.Log.e("BitmapTree", ex.getMessage() );
-        }
-      }
-}
diff --git a/src/main/java/org/distorted/examples/bitmaptree/BitmapTreeSurfaceView.java b/src/main/java/org/distorted/examples/bitmaptree/BitmapTreeSurfaceView.java
deleted file mode 100644
index f9bee7d..0000000
--- a/src/main/java/org/distorted/examples/bitmaptree/BitmapTreeSurfaceView.java
+++ /dev/null
@@ -1,57 +0,0 @@
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Copyright 2016 Leszek Koltunski                                                               //
-//                                                                                               //
-// This file is part of Distorted.                                                               //
-//                                                                                               //
-// Distorted is free software: you can redistribute it and/or modify                             //
-// it under the terms of the GNU General Public License as published by                          //
-// the Free Software Foundation, either version 2 of the License, or                             //
-// (at your option) any later version.                                                           //
-//                                                                                               //
-// Distorted is distributed in the hope that it will be useful,                                  //
-// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
-// GNU General Public License for more details.                                                  //
-//                                                                                               //
-// You should have received a copy of the GNU General Public License                             //
-// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-package org.distorted.examples.bitmaptree;
-
-import android.app.ActivityManager;
-import android.content.Context;
-import android.content.pm.ConfigurationInfo;
-import android.opengl.GLSurfaceView;
-import android.util.AttributeSet;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-class BitmapTreeSurfaceView extends GLSurfaceView
-{
-    private BitmapTreeRenderer mRenderer;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-   
-    public BitmapTreeSurfaceView(Context context, AttributeSet attrs)
-      {
-      super(context, attrs);
-
-      if(!isInEditMode())
-        {
-        mRenderer = new BitmapTreeRenderer(this);
-        final ActivityManager activityManager     = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
-        final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
-        setEGLContextClientVersion( (configurationInfo.reqGlEsVersion>>16) >= 3 ? 3:2 );
-        setRenderer(mRenderer);
-        }
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public BitmapTreeRenderer getRenderer()
-      {
-      return mRenderer;
-      }
-}
-
diff --git a/src/main/java/org/distorted/examples/objecttree/ObjectTreeActivity.java b/src/main/java/org/distorted/examples/objecttree/ObjectTreeActivity.java
new file mode 100644
index 0000000..a4c9b5b
--- /dev/null
+++ b/src/main/java/org/distorted/examples/objecttree/ObjectTreeActivity.java
@@ -0,0 +1,125 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.examples.objecttree;
+
+import org.distorted.examples.R;
+import org.distorted.library.main.Distorted;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class ObjectTreeActivity extends Activity
+{
+    private boolean mDepth;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    @Override
+    protected void onCreate(Bundle savedState)
+      {
+      super.onCreate(savedState);
+      setContentView(R.layout.objecttreelayout);
+
+      if( savedState==null )
+        {
+        mDepth = true;
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    @Override
+    protected void onPause() 
+      {
+      ObjectTreeSurfaceView view = (ObjectTreeSurfaceView) this.findViewById(R.id.objecttreeSurfaceView);
+
+      view.onPause();
+      Distorted.onPause();
+      super.onPause();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    @Override
+    protected void onResume() 
+      {
+      ObjectTreeSurfaceView view = (ObjectTreeSurfaceView) this.findViewById(R.id.objecttreeSurfaceView);
+
+      super.onResume();
+      view.onResume();
+      }
+    
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+    @Override
+    protected void onDestroy() 
+      {
+      Distorted.onDestroy();  
+      super.onDestroy();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void DepthYes(View v)
+      {
+      ObjectTreeSurfaceView view = (ObjectTreeSurfaceView) this.findViewById(R.id.objecttreeSurfaceView);
+      ObjectTreeRenderer renderer = view.getRenderer();
+
+      renderer.setDepth(true);
+      mDepth = true;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void DepthNo(View v)
+      {
+      ObjectTreeSurfaceView view = (ObjectTreeSurfaceView) this.findViewById(R.id.objecttreeSurfaceView);
+      ObjectTreeRenderer renderer = view.getRenderer();
+
+      renderer.setDepth(false);
+      mDepth = false;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void onSaveInstanceState(Bundle savedInstanceState)
+      {
+      super.onSaveInstanceState(savedInstanceState);
+      savedInstanceState.putBoolean("depth", mDepth);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    @Override
+    public void onRestoreInstanceState(Bundle savedInstanceState)
+      {
+      super.onRestoreInstanceState(savedInstanceState);
+
+      mDepth = savedInstanceState.getBoolean("depth");
+
+      if(mDepth) DepthYes(null);
+      else       DepthNo(null);
+      }
+
+}
diff --git a/src/main/java/org/distorted/examples/objecttree/ObjectTreeRenderer.java b/src/main/java/org/distorted/examples/objecttree/ObjectTreeRenderer.java
new file mode 100644
index 0000000..c0fcc21
--- /dev/null
+++ b/src/main/java/org/distorted/examples/objecttree/ObjectTreeRenderer.java
@@ -0,0 +1,227 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.examples.objecttree;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import org.distorted.examples.R;
+
+import org.distorted.library.effect.FragmentEffectChroma;
+import org.distorted.library.effect.MatrixEffectMove;
+import org.distorted.library.effect.MatrixEffectRotate;
+import org.distorted.library.effect.MatrixEffectScale;
+import org.distorted.library.effect.VertexEffectSink;
+import org.distorted.library.main.DistortedEffects;
+import org.distorted.library.main.DistortedFramebuffer;
+import org.distorted.library.main.DistortedNode;
+import org.distorted.library.main.DistortedScreen;
+import org.distorted.library.main.Distorted;
+import org.distorted.library.mesh.MeshCubes;
+import org.distorted.library.mesh.MeshFlat;
+import org.distorted.library.main.DistortedTexture;
+import org.distorted.library.type.Dynamic;
+import org.distorted.library.type.Dynamic1D;
+import org.distorted.library.type.Static1D;
+import org.distorted.library.type.Static3D;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.opengl.GLES31;
+import android.opengl.GLSurfaceView;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class ObjectTreeRenderer implements GLSurfaceView.Renderer
+{
+   private GLSurfaceView mView;
+   private DistortedEffects mEffects;
+   private DistortedTexture mLisaTexture, mGridTexture;
+   private DistortedScreen mScreen;
+   private DistortedNode mRoot;
+   private MeshFlat mMeshFlat;
+   private MeshCubes mMeshCubes;
+   private int lisaHeight, lisaWidth;
+   private boolean mDepth;
+   private Static3D mScale, mMove;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   ObjectTreeRenderer(GLSurfaceView v)
+      {
+      mView   = v;
+      mDepth  = true;
+      mScale  = new Static3D(1,1,1);
+      mMove   = new Static3D(0,0,0);
+      Dynamic1D chromaDyn = new Dynamic1D(5000,0.0f);
+      chromaDyn.add(new Static1D(0.0f));
+      chromaDyn.add(new Static1D(0.8f));
+
+      mEffects= new DistortedEffects();
+      mEffects.apply(new MatrixEffectMove(mMove));
+      mEffects.apply(new MatrixEffectScale(mScale));
+      mEffects.apply(new FragmentEffectChroma(chromaDyn, new Static3D(0,0,1)));
+
+      mScreen = new DistortedScreen();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   private void setDepthPriv()
+     {
+     if( mDepth ) mRoot.glEnable (GLES31.GL_DEPTH_TEST);
+     else         mRoot.glDisable(GLES31.GL_DEPTH_TEST);
+
+     mRoot.glDepthMask(mDepth);
+
+     // we can also, to save memory, delete/recreate
+     // the depth buffer each time. This is optional.
+     mRoot.enableDepthStencil(mDepth ? DistortedFramebuffer.DEPTH_NO_STENCIL:DistortedFramebuffer.NO_DEPTH_NO_STENCIL);
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   void setDepth(boolean depth)
+      {
+      mDepth = depth;
+      if( mRoot!=null ) setDepthPriv();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+   
+   public void onDrawFrame(GL10 glUnused)
+      {
+      mScreen.render(System.currentTimeMillis());
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+   public void onSurfaceChanged(GL10 glUnused, int width, int height)
+      { 
+      if( (float)lisaHeight/lisaWidth > (float)height/width )
+        {
+        int w = (height*lisaWidth)/lisaHeight;
+        float factor = (float)height/lisaHeight;
+
+        mMove.set((width-w)/2,0,0);
+        mScale.set(factor,factor,factor);
+        }
+      else
+        {
+        int h = (width*lisaHeight)/lisaWidth;
+        float factor = (float)width/lisaWidth;
+
+        mMove.set(0,(height-h)/2,0);
+        mScale.set(factor,factor,factor);
+        }
+      
+      mScreen.resize(width, height);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+    
+   public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
+      {
+      // TODO
+      // This appears to be needed in case we create the app anew with NO DEPTH
+      // (i.e. we set 'no depth' and then rotate screen). Investigate.
+      GLES31.glEnable(GLES31.GL_CULL_FACE);
+      GLES31.glCullFace(GLES31.GL_BACK);
+      GLES31.glFrontFace(GLES31.GL_CW);
+
+      InputStream is1 = mView.getContext().getResources().openRawResource(R.raw.monalisa);
+      InputStream is2 = mView.getContext().getResources().openRawResource(R.raw.grid);
+      
+      Bitmap bitmap1, bitmap2;
+       
+      try 
+        {
+        bitmap1 = BitmapFactory.decodeStream(is1);
+        bitmap2 = BitmapFactory.decodeStream(is2);
+        } 
+      finally 
+        {
+        try 
+          {
+          is1.close();
+          is2.close();
+          } 
+        catch(IOException e) { }
+        }  
+      
+      lisaWidth     = bitmap1.getWidth();
+      lisaHeight    = bitmap1.getHeight();
+      int gridWidth = bitmap2.getWidth();
+      int gridHeight= bitmap2.getHeight();
+
+      if( mLisaTexture==null ) mLisaTexture = new DistortedTexture(lisaWidth,lisaHeight);
+      if( mGridTexture==null ) mGridTexture = new DistortedTexture(gridWidth,gridHeight);
+      mLisaTexture.setTexture(bitmap1);
+      mGridTexture.setTexture(bitmap2);
+      DistortedEffects gridEffects = new DistortedEffects();
+
+      final int GRID = 10;
+
+      if( mMeshFlat==null ) mMeshFlat = new MeshFlat(1,1);
+      if( mMeshCubes==null) mMeshCubes= new MeshCubes(GRID,GRID,1);
+
+      mRoot = new DistortedNode(mLisaTexture, mEffects, mMeshFlat);
+      mRoot.attach(mGridTexture,gridEffects,mMeshCubes);
+
+      setDepthPriv();
+
+      mScreen.detachAll();
+      mScreen.attach(mRoot);
+
+      float factor = lisaWidth/(2.0f*gridWidth);
+      MatrixEffectMove move = new MatrixEffectMove( new Static3D((lisaWidth-factor*gridWidth)/2,(lisaHeight-factor*gridHeight)/2, gridWidth/(2.0f*GRID)));
+      MatrixEffectScale scale = new MatrixEffectScale( new Static3D(factor,factor,factor) );
+      gridEffects.apply(move);
+      gridEffects.apply(scale);
+
+      Dynamic1D rotDyn = new Dynamic1D(12000,0.0f);
+      rotDyn.add(new Static1D(  0));
+      rotDyn.add(new Static1D(360));
+      rotDyn.setMode(Dynamic.MODE_JUMP);
+      MatrixEffectRotate rotate = new MatrixEffectRotate(rotDyn, new Static3D(1,0,0), new Static3D(gridWidth/2,gridHeight/2,gridWidth/(2*GRID)));
+      gridEffects.apply(rotate);
+
+      Dynamic1D sinkDyn = new Dynamic1D(3000,0.0f);
+      sinkDyn.add(new Static1D(1.0f));
+      sinkDyn.add(new Static1D(0.3f));
+      VertexEffectSink sink = new VertexEffectSink(sinkDyn, new Static3D(gridWidth/2,gridHeight/2, 0));
+      gridEffects.apply(sink);
+
+      VertexEffectSink.enable();
+      FragmentEffectChroma.enable();
+
+      try
+        {
+        Distorted.onCreate(mView.getContext());
+        }
+      catch(Exception ex)
+        {
+        android.util.Log.e("ObjectTree", ex.getMessage() );
+        }
+      }
+}
diff --git a/src/main/java/org/distorted/examples/objecttree/ObjectTreeSurfaceView.java b/src/main/java/org/distorted/examples/objecttree/ObjectTreeSurfaceView.java
new file mode 100644
index 0000000..11690c6
--- /dev/null
+++ b/src/main/java/org/distorted/examples/objecttree/ObjectTreeSurfaceView.java
@@ -0,0 +1,57 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.examples.objecttree;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ConfigurationInfo;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class ObjectTreeSurfaceView extends GLSurfaceView
+{
+    private ObjectTreeRenderer mRenderer;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+   
+    public ObjectTreeSurfaceView(Context context, AttributeSet attrs)
+      {
+      super(context, attrs);
+
+      if(!isInEditMode())
+        {
+        mRenderer = new ObjectTreeRenderer(this);
+        final ActivityManager activityManager     = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+        final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
+        setEGLContextClientVersion( (configurationInfo.reqGlEsVersion>>16) >= 3 ? 3:2 );
+        setRenderer(mRenderer);
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public ObjectTreeRenderer getRenderer()
+      {
+      return mRenderer;
+      }
+}
+
diff --git a/src/main/res/drawable-hdpi/icon_example_glow.png b/src/main/res/drawable-hdpi/icon_example_glow.png
new file mode 100644
index 0000000..e959f9f
Binary files /dev/null and b/src/main/res/drawable-hdpi/icon_example_glow.png differ
diff --git a/src/main/res/layout/bitmaptreelayout.xml b/src/main/res/layout/bitmaptreelayout.xml
deleted file mode 100644
index c3c80dc..0000000
--- a/src/main/res/layout/bitmaptreelayout.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?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.bitmaptree.BitmapTreeSurfaceView
-        android:id="@+id/bitmaptreeSurfaceView"
-        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/depthYesButton"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:checked="true"
-                android:onClick="DepthYes"
-                android:text="@string/DepthYes"/>
-
-            <RadioButton
-                android:id="@+id/depthNoButton"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:onClick="DepthNo"
-                android:text="@string/DepthNo"/>
-
-        </RadioGroup>
-
-    </LinearLayout>
-
-</LinearLayout>
diff --git a/src/main/res/layout/objecttreelayout.xml b/src/main/res/layout/objecttreelayout.xml
new file mode 100644
index 0000000..a5c9586
--- /dev/null
+++ b/src/main/res/layout/objecttreelayout.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.objecttree.ObjectTreeSurfaceView
+        android:id="@+id/objecttreeSurfaceView"
+        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/depthYesButton"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:checked="true"
+                android:onClick="DepthYes"
+                android:text="@string/DepthYes"/>
+
+            <RadioButton
+                android:id="@+id/depthNoButton"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:onClick="DepthNo"
+                android:text="@string/DepthNo"/>
+
+        </RadioGroup>
+
+    </LinearLayout>
+
+</LinearLayout>
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index d055d44..27a3ee6 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -137,8 +137,8 @@
     <string name="example_effectqueue_subtitle">Add, remove and list all effects currently acting on a Bitmap.</string>
     <string name="example_check">Check</string>
     <string name="example_check_subtitle">Check the maximum number of effects (separately for vertex and fragment shaders) we can apply to a single bitmap.</string>
-    <string name="example_bitmaptree">Bitmap Tree</string>
-    <string name="example_bitmaptree_subtitle">Render one bitmap on top of another.</string>
+    <string name="example_objecttree">Object Tree</string>
+    <string name="example_objecttree_subtitle">Render one object on top of another.</string>
     <string name="example_starwars">Star Wars</string>
     <string name="example_starwars_subtitle">Shows how to create the opening crawl from Star Wars Episode IV.</string>
     <string name="example_olimpic">Olimpic Rings</string>
