commit 99a80c087c88cb722b391843ba2068540aaab526
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Sun Dec 25 00:36:13 2022 +0100

    Minor.

diff --git a/src/main/java/org/distorted/examples/TableOfContents.java b/src/main/java/org/distorted/examples/TableOfContents.java
index b8ad229..5e7bc3c 100644
--- a/src/main/java/org/distorted/examples/TableOfContents.java
+++ b/src/main/java/org/distorted/examples/TableOfContents.java
@@ -88,6 +88,8 @@ public class TableOfContents extends ListActivity
 
   private enum Application
     {
+    FLATBLUR2         (R.drawable.icon_example_flatblur        , R.string.example_flatblur         , R.string.example_flatblur_subtitle         , FlatBlur2Activity.class ),
+
     MONALISA          (R.drawable.icon_example_monalisa        , R.string.example_monalisa        , R.string.example_monalisa_subtitle        ,         MonaLisaActivity.class),
     SINK              (R.drawable.icon_example_sink            , R.string.example_sink            , R.string.example_sink_subtitle            ,             SinkActivity.class),
     BEAN              (R.drawable.icon_example_bean            , R.string.example_bean            , R.string.example_bean_subtitle            ,             BeanActivity.class),
@@ -130,7 +132,6 @@ public class TableOfContents extends ListActivity
     SINGLEMESH        (R.drawable.icon_example_singlemesh      , R.string.example_singlemesh           , R.string.example_singlemesh_subtitle           ,            SingleMeshActivity.class),
     MESHFILE          (R.drawable.icon_example_meshfile        , R.string.example_meshfile           , R.string.example_meshfile_subtitle           ,            MeshFileActivity.class),
     FLATBLUR          (R.drawable.icon_example_flatblur        , R.string.example_flatblur         , R.string.example_flatblur_subtitle         , FlatBlurActivity.class ),
-    FLATBLUR2         (R.drawable.icon_example_flatblur        , R.string.example_flatblur         , R.string.example_flatblur_subtitle         , FlatBlur2Activity.class ),
 
     ;
 
diff --git a/src/main/java/org/distorted/examples/flatblur2/DataGeneric.java b/src/main/java/org/distorted/examples/flatblur2/DataGeneric.java
new file mode 100644
index 0000000..456404d
--- /dev/null
+++ b/src/main/java/org/distorted/examples/flatblur2/DataGeneric.java
@@ -0,0 +1,18 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2022 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is proprietary software licensed under an EULA which you should have received      //
+// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.examples.flatblur2;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public abstract class DataGeneric
+{
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/distorted/examples/flatblur2/DataStars.java b/src/main/java/org/distorted/examples/flatblur2/DataStars.java
new file mode 100644
index 0000000..ec85617
--- /dev/null
+++ b/src/main/java/org/distorted/examples/flatblur2/DataStars.java
@@ -0,0 +1,50 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2022 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is proprietary software licensed under an EULA which you should have received      //
+// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.examples.flatblur2;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+import android.content.res.Resources;
+
+public class DataStars extends DataGeneric
+{
+  private final int mTotStars, mNewStars;
+  private final Resources mRes;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public DataStars(int totStars, int newStars, Resources res)
+    {
+    mTotStars = totStars;
+    mNewStars = newStars;
+    mRes = res;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getTotal()
+    {
+    return mTotStars;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getNew()
+    {
+    return mNewStars;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  Resources getResources()
+    {
+    return mRes;
+    }
+}
diff --git a/src/main/java/org/distorted/examples/flatblur2/FlatBlur2Activity.java b/src/main/java/org/distorted/examples/flatblur2/FlatBlur2Activity.java
index 1fae3af..a95b750 100644
--- a/src/main/java/org/distorted/examples/flatblur2/FlatBlur2Activity.java
+++ b/src/main/java/org/distorted/examples/flatblur2/FlatBlur2Activity.java
@@ -71,10 +71,19 @@ public class FlatBlur2Activity extends Activity
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void crash(View view)
+    public void button1(View view)
       {
       FlatBlur2SurfaceView v = findViewById(R.id.flatblur2SurfaceView);
       FlatBlur2Renderer renderer = v.getRenderer();
-      renderer.crash();
+      renderer.button1();
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void button2(View view)
+      {
+      FlatBlur2SurfaceView v = findViewById(R.id.flatblur2SurfaceView);
+      FlatBlur2Renderer renderer = v.getRenderer();
+      renderer.button2();
       }
 }
diff --git a/src/main/java/org/distorted/examples/flatblur2/FlatBlur2Renderer.java b/src/main/java/org/distorted/examples/flatblur2/FlatBlur2Renderer.java
index aafd955..9f654ee 100644
--- a/src/main/java/org/distorted/examples/flatblur2/FlatBlur2Renderer.java
+++ b/src/main/java/org/distorted/examples/flatblur2/FlatBlur2Renderer.java
@@ -19,17 +19,28 @@
 
 package org.distorted.examples.flatblur2;
 
+import android.content.res.Resources;
 import android.opengl.GLSurfaceView;
 
+import org.distorted.library.effect.EffectQuality;
+import org.distorted.library.effect.EffectType;
+import org.distorted.library.effect.MatrixEffectRotate;
+import org.distorted.library.effect.MatrixEffectScale;
 import org.distorted.library.effect.PostprocessEffectGlow;
-import org.distorted.library.effect.VertexEffectScale;
 import org.distorted.library.main.DistortedEffects;
 import org.distorted.library.main.DistortedLibrary;
 import org.distorted.library.main.DistortedNode;
 import org.distorted.library.main.DistortedScreen;
 import org.distorted.library.main.DistortedTexture;
+import org.distorted.library.mesh.MeshCubes;
 import org.distorted.library.mesh.MeshQuad;
+
+import org.distorted.library.message.EffectListener;
+import org.distorted.library.type.Dynamic2D;
+import org.distorted.library.type.Dynamic4D;
+import org.distorted.library.type.Static1D;
 import org.distorted.library.type.Static2D;
+import org.distorted.library.type.Static3D;
 import org.distorted.library.type.Static4D;
 
 import javax.microedition.khronos.egl.EGLConfig;
@@ -37,11 +48,12 @@ import javax.microedition.khronos.opengles.GL10;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class FlatBlur2Renderer implements GLSurfaceView.Renderer, DistortedLibrary.ExceptionListener
+class FlatBlur2Renderer implements GLSurfaceView.Renderer, DistortedLibrary.ExceptionListener, ListenerOverlay, EffectListener
 {
     private final GLSurfaceView mView;
     private final DistortedScreen mScreen;
-    private final DistortedNode mNode;
+    private Static3D mScale1, mScale2;
+    private DistortedNode mNode;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -49,22 +61,6 @@ class FlatBlur2Renderer implements GLSurfaceView.Renderer, DistortedLibrary.Exce
       {
       mView = v;
       mScreen = new DistortedScreen();
-
-      DistortedTexture texture1 = new DistortedTexture();
-      texture1.setColorARGB(0xffff0000);
-      MeshQuad mesh1 = new MeshQuad();
-      DistortedEffects effects1 = new DistortedEffects();
-      VertexEffectScale mainScale= new VertexEffectScale(200);
-      effects1.apply(mainScale);
-      mNode = new DistortedNode(texture1,effects1,mesh1);
-      mScreen.attach(mNode);
-
-      DistortedTexture texture2 = new DistortedTexture();
-      texture2.setColorARGB(0xffff0000);
-      MeshQuad mesh2 = new MeshQuad();
-      DistortedEffects effects2 = new DistortedEffects();
-      DistortedNode node2 = new DistortedNode(texture2,effects2,mesh2);
-      mScreen.attach(node2);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -78,6 +74,9 @@ class FlatBlur2Renderer implements GLSurfaceView.Renderer, DistortedLibrary.Exce
 
     public void onSurfaceChanged(GL10 glUnused, int width, int height)
       {
+      float s = width*0.05f;
+      mScale1.set(width,width,0);
+      mScale2.set(s,s,s);
       mScreen.resize(width,height);
       }
 
@@ -85,8 +84,35 @@ class FlatBlur2Renderer implements GLSurfaceView.Renderer, DistortedLibrary.Exce
     
     public void onSurfaceCreated(GL10 glUnused, EGLConfig config) 
       {
-      VertexEffectScale.enable();
-      PostprocessEffectGlow.enable();
+      DistortedTexture surface1 = new DistortedTexture();
+      surface1.setColorARGB(0xffff0000);
+      MeshQuad mesh1 = new MeshQuad();
+      DistortedEffects effects1 = new DistortedEffects();
+
+      mScale1 = new Static3D(1,1,1);
+      MatrixEffectScale scale1 = new MatrixEffectScale(mScale1);
+      effects1.apply(scale1);
+      mNode = new DistortedNode(surface1,effects1,mesh1);
+      mScreen.attach(mNode);
+
+      DistortedTexture surface2 = new DistortedTexture();
+      surface2.setColorARGB(0xff0000ff);
+      MeshCubes mesh2 = new MeshCubes(2,2,2);
+      DistortedEffects effects2 = new DistortedEffects();
+
+      mScale2 = new Static3D(1,1,1);
+      MatrixEffectScale scale2 = new MatrixEffectScale(mScale2);
+      effects2.apply(scale2);
+      Static1D angle = new Static1D(30);
+      float SQ3 = (float)Math.sqrt(3);
+      Static3D axis = new Static3D(SQ3/3,SQ3/3,SQ3/3);
+      Static3D center = new Static3D(0,0,0);
+      MatrixEffectRotate rot = new MatrixEffectRotate(angle,axis,center);
+      effects2.apply(rot);
+      DistortedNode node2 = new DistortedNode(surface2,effects2,mesh2);
+      mNode.attach(node2);
+
+      OverlayStars.enableEffects();
       DistortedLibrary.onSurfaceCreated( mView.getContext(), this);
       }
 
@@ -99,12 +125,60 @@ class FlatBlur2Renderer implements GLSurfaceView.Renderer, DistortedLibrary.Exce
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void crash()
+    public void button1()
       {
-      Static2D haloRadius = new Static2D(15,50);
-      Static4D color      = new Static4D(1,1,1,1);
-      PostprocessEffectGlow glow = new PostprocessEffectGlow(haloRadius,color);
+      OverlayStars stars = new OverlayStars();
+      Resources res = mView.getResources();
+      DataStars data  = new DataStars(10,5,res);
+      stars.startOverlay(mScreen,this,data);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void button2()
+      {
+      PostprocessEffectGlow glow = constructGlow();
       DistortedEffects effects = mNode.getEffects();
       effects.apply(glow);
       }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   private PostprocessEffectGlow constructGlow()
+      {
+      final int DUR_GLO = 3000;
+      Dynamic2D haloRadius = new Dynamic2D(DUR_GLO,0.5f);
+      Static2D point20 = new Static2D( 0, 0);
+      Static2D point21 = new Static2D(15,50);
+      Dynamic4D color = new Dynamic4D(DUR_GLO, 0.5f);
+      Static4D point40 = new Static4D(1,1,1,0.0f);
+      Static4D point41 = new Static4D(1,1,1,0.8f);
+
+      haloRadius.add(point20);
+      haloRadius.add(point21);
+      haloRadius.add(point20);
+      color.add(point40);
+      color.add(point41);
+      color.add(point40);
+
+      PostprocessEffectGlow glow = new PostprocessEffectGlow(haloRadius,color);
+      glow.setQuality(EffectQuality.MEDIUM);
+      glow.notifyWhenFinished(this);
+      return glow;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void overlayFinished(long id)
+      {
+
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+    public void effectFinished(long id)
+      {
+      DistortedEffects effects = mNode.getEffects();
+      effects.abortByType(EffectType.POSTPROCESS);
+      }
 }
diff --git a/src/main/java/org/distorted/examples/flatblur2/ListenerOverlay.java b/src/main/java/org/distorted/examples/flatblur2/ListenerOverlay.java
new file mode 100644
index 0000000..39d4d63
--- /dev/null
+++ b/src/main/java/org/distorted/examples/flatblur2/ListenerOverlay.java
@@ -0,0 +1,17 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2022 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is proprietary software licensed under an EULA which you should have received      //
+// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.examples.flatblur2;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public interface ListenerOverlay
+{
+  void overlayFinished(long id);
+}
\ No newline at end of file
diff --git a/src/main/java/org/distorted/examples/flatblur2/OverlayGeneric.java b/src/main/java/org/distorted/examples/flatblur2/OverlayGeneric.java
new file mode 100644
index 0000000..a1127df
--- /dev/null
+++ b/src/main/java/org/distorted/examples/flatblur2/OverlayGeneric.java
@@ -0,0 +1,65 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2022 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is proprietary software licensed under an EULA which you should have received      //
+// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.examples.flatblur2;
+
+import org.distorted.library.main.DistortedScreen;
+
+import java.lang.reflect.Method;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public abstract class OverlayGeneric
+{
+   private enum Overlays
+      {
+      STARS ( OverlayStars.class )
+      ;
+
+      private final Class<? extends OverlayGeneric> mClass;
+
+      Overlays(Class<? extends OverlayGeneric> clazz)
+         {
+         mClass = clazz;
+         }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   public static void enableEffects()
+     {
+     Method method;
+
+     for(Overlays overlay: Overlays.values() )
+        {
+        try
+          {
+          method = overlay.mClass.getDeclaredMethod("enableEffects");
+          }
+        catch(NoSuchMethodException ex)
+          {
+          android.util.Log.e("OverlayGeneric", overlay.mClass.getSimpleName()+": exception getting method: "+ex.getMessage());
+          method = null;
+          }
+
+        try
+          {
+          if( method!=null ) method.invoke(null);
+          }
+        catch(Exception ex)
+          {
+          android.util.Log.e("OverlayGeneric", overlay.mClass.getSimpleName()+": exception invoking method: "+ex.getMessage());
+          }
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   public abstract long startOverlay(DistortedScreen screen, ListenerOverlay listener, DataGeneric data);
+}
\ No newline at end of file
diff --git a/src/main/java/org/distorted/examples/flatblur2/OverlayStars.java b/src/main/java/org/distorted/examples/flatblur2/OverlayStars.java
new file mode 100644
index 0000000..6870fb7
--- /dev/null
+++ b/src/main/java/org/distorted/examples/flatblur2/OverlayStars.java
@@ -0,0 +1,375 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2022 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Magic Cube.                                                              //
+//                                                                                               //
+// Magic Cube is proprietary software licensed under an EULA which you should have received      //
+// along with the code. If not, check https://distorted.org/magic/License-Magic-Cube.html        //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.examples.flatblur2;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+import org.distorted.examples.R;
+import org.distorted.library.effect.EffectQuality;
+import org.distorted.library.effect.FragmentEffectAlpha;
+import org.distorted.library.effect.MatrixEffectMove;
+import org.distorted.library.effect.MatrixEffectScale;
+import org.distorted.library.effect.PostprocessEffectGlow;
+import org.distorted.library.effect.VertexEffectMove;
+import org.distorted.library.effect.VertexEffectScale;
+import org.distorted.library.main.DistortedEffects;
+import org.distorted.library.main.DistortedNode;
+import org.distorted.library.main.DistortedScreen;
+import org.distorted.library.main.DistortedTexture;
+import org.distorted.library.main.InternalOutputSurface;
+import org.distorted.library.mesh.MeshJoined;
+import org.distorted.library.mesh.MeshQuad;
+import org.distorted.library.message.EffectListener;
+import org.distorted.library.type.Dynamic;
+import org.distorted.library.type.Dynamic1D;
+import org.distorted.library.type.Dynamic2D;
+import org.distorted.library.type.Dynamic3D;
+import org.distorted.library.type.Dynamic4D;
+import org.distorted.library.type.Static1D;
+import org.distorted.library.type.Static2D;
+import org.distorted.library.type.Static3D;
+import org.distorted.library.type.Static4D;
+
+import java.util.Random;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class OverlayStars extends OverlayGeneric implements EffectListener
+{
+   private static final int DUR_APP =  3500;
+   private static final int DUR_MOV = 17500;
+   private static final int DUR_GLO =  2600;
+
+   private ListenerOverlay mListener;
+   private DistortedNode mNodeFalling, mNodeCentral;
+   private DistortedScreen mScreen;
+   private DistortedTexture mTexture;
+   private Bitmap mCountBitmap, mStarBitmap;
+   private Canvas mCountCanvas;
+   private Paint mPaint;
+   private int mBmpW, mBmpH;
+   private float mWidth, mHeight;
+   private Random mRandom;
+   private long mMoveID, mGlow1ID, mGlow2ID, mAlphaID;
+   private int mTotalStars, mNewStars;
+   private FragmentEffectAlpha mAlpha;
+   private Dynamic1D mAlphaStrength;
+   private boolean mIncrease;
+   private float mTextHeight;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   private Dynamic3D createRandomMove(boolean increase)
+      {
+      Dynamic3D move = new Dynamic3D();
+      move.setMode(Dynamic.MODE_PATH);
+      move.setDuration(DUR_MOV);
+      move.setCount(0.5f);
+
+      float widthS = (mRandom.nextFloat()-0.5f)*mWidth*1.10f;
+      float widthM = widthS + (mRandom.nextFloat()-0.5f)*mWidth*0.2f;
+      float heighS = mRandom.nextFloat()*mHeight*0.2f;
+      float heighM = (mRandom.nextFloat()-0.5f)*mHeight*0.2f;
+
+      Static3D pointS = new Static3D(widthS,mHeight*0.55f+heighS,0);
+      Static3D pointM = new Static3D(widthM,mHeight*0.25f+heighM,0);
+      Static3D pointE = new Static3D(0,0,0);
+      Static3D pointF = new Static3D(0,0,-10000);
+
+      if( increase )
+         {
+         move.add(pointS);
+         move.add(pointM);
+         move.add(pointE);
+         move.add(pointF);
+         }
+      else
+         {
+         move.add(pointF);
+         move.add(pointE);
+         move.add(pointM);
+         move.add(pointS);
+         }
+
+      return move;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   private void createAlphaEffect(boolean appear)
+      {
+      if( mAlpha==null )
+         {
+         mAlphaStrength = new Dynamic1D();
+         mAlphaStrength.setMode(Dynamic.MODE_PATH);
+         mAlphaStrength.setDuration(DUR_APP);
+         mAlphaStrength.setCount(0.5f);
+         equipAlpha(mAlphaStrength,appear);
+         mAlpha = new FragmentEffectAlpha(mAlphaStrength);
+         }
+      else
+         {
+         mAlphaStrength.resetToBeginning();
+         equipAlpha(mAlphaStrength,appear);
+         }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   private void equipAlpha(Dynamic1D alpha, boolean appear)
+      {
+      Static1D point0 = new Static1D(0.0f);
+      Static1D point1 = new Static1D(1.0f);
+
+      alpha.removeAll();
+
+      if( appear )
+        {
+        alpha.add(point0);
+        alpha.add(point1);
+        }
+      else
+        {
+        alpha.add(point1);
+        alpha.add(point0);
+        }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   private float computeQuotientAndTextHeight(int total)
+      {
+      if( total>=10000 )
+         {
+         mTextHeight = 0.610f;
+         return 0.16f;
+         }
+      if( total>= 1000 )
+         {
+         mTextHeight = 0.625f;
+         return 0.20f;
+         }
+      if( total>=  100 )
+         {
+         mTextHeight = 0.640f;
+         return 0.26f;
+         }
+
+      mTextHeight = 0.655f;
+      return 0.28f;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   private void createBitmap(Resources res, int total)
+      {
+      mStarBitmap = BitmapFactory.decodeResource(res, R.raw.yellow_star);
+      mBmpW = mStarBitmap.getWidth();
+      mBmpH = mStarBitmap.getHeight();
+      mCountBitmap = Bitmap.createBitmap(mBmpW,mBmpH,Bitmap.Config.ARGB_8888);
+      mCountCanvas = new Canvas(mCountBitmap);
+
+      float quotient = computeQuotientAndTextHeight(total);
+
+      mPaint = new Paint();
+      mPaint.setColor(0xff000000);
+      mPaint.setTextSize(mBmpH*quotient);
+      mPaint.setAntiAlias(true);
+      mPaint.setTextAlign(Paint.Align.CENTER);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   private DistortedNode createNodeFalling(boolean increase)
+      {
+      DistortedTexture texture = new DistortedTexture();
+      texture.setTexture(mStarBitmap);
+
+      MeshQuad[] mesh = new MeshQuad[mNewStars];
+
+      for(int i=0; i<mNewStars; i++)
+         {
+         mesh[i] = new MeshQuad();
+         mesh[i].setEffectAssociation(0,1,i+1);
+         }
+
+      MeshJoined wholeMesh = new MeshJoined(mesh);
+
+      DistortedEffects effects = new DistortedEffects();
+      VertexEffectScale scaleE = new VertexEffectScale(mWidth*0.15f);
+      scaleE.setMeshAssociation(1,-1);
+      effects.apply(scaleE);
+
+      for(int i=0; i<mNewStars; i++)
+        {
+        Dynamic3D moveP = createRandomMove(increase);
+        VertexEffectMove moveE= new VertexEffectMove(moveP);
+        moveE.setMeshAssociation(0,i+1);
+        effects.apply(moveE);
+
+        if( i==0 )
+           {
+           mMoveID = moveE.getID();
+           moveE.notifyWhenFinished(this);
+           }
+        }
+
+      return new DistortedNode(texture,effects,wholeMesh);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   private DistortedNode createNodeCentral(int numStars)
+      {
+      mTexture = new DistortedTexture();
+      renderStars(numStars);
+
+      MeshQuad mesh = new MeshQuad();
+
+      DistortedEffects effects = new DistortedEffects();
+      float scaleM  = mWidth*0.40f;
+      Static3D moveM= new Static3D(0,0,1);
+      MatrixEffectMove move  = new MatrixEffectMove(moveM);
+      MatrixEffectScale scale= new MatrixEffectScale(scaleM);
+      effects.apply(move);
+      effects.apply(scale);
+      createAlphaEffect(true);
+      effects.apply(mAlpha);
+
+      return new DistortedNode(mTexture,effects,mesh);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   private void renderStars(int numStars)
+      {
+      String txt = ""+numStars;
+      mCountBitmap.eraseColor(0x00000000);
+      mCountCanvas.drawBitmap(mStarBitmap,0,0,null);
+      mCountCanvas.drawText(txt,mBmpW*0.5f,mBmpH*mTextHeight,mPaint);
+      mTexture.setTexture(mCountBitmap);
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   public long startOverlay(DistortedScreen screen, ListenerOverlay listener, DataGeneric data)
+      {
+      mRandom = new Random();
+      mScreen = screen;
+      mListener= listener;
+      DataStars stars = (DataStars)data;
+      mTotalStars = stars.getTotal();
+      mNewStars   = stars.getNew();
+      Resources res = stars.getResources();
+      mWidth = mScreen.getWidth();
+      mHeight= mScreen.getHeight();
+      mIncrease = mNewStars>0;
+      if( !mIncrease ) mNewStars = -mNewStars;
+
+      createBitmap(res, mTotalStars);
+      mNodeFalling = createNodeFalling(mIncrease);
+      mNodeFalling.enableDepthStencil(InternalOutputSurface.NO_DEPTH_NO_STENCIL);
+      mScreen.attach(mNodeFalling);
+      mNodeCentral = createNodeCentral(mTotalStars);
+      mNodeCentral.glDepthMask(false);
+      mScreen.attach(mNodeCentral);
+
+      return 0;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   private PostprocessEffectGlow constructGlow(boolean firstPhase)
+      {
+      Dynamic2D haloRadius = new Dynamic2D(DUR_GLO,0.5f);
+      Static2D point20 = new Static2D( 0, 0);
+      Static2D point21 = new Static2D(15,50);
+      Dynamic4D color = new Dynamic4D(DUR_GLO, 0.5f);
+      Static4D point40 = new Static4D(1,1,1,0.0f);
+      Static4D point41 = new Static4D(1,1,1,0.8f);
+
+      if( firstPhase )
+         {
+         haloRadius.add(point20);
+         haloRadius.add(point21);
+         color.add(point40);
+         color.add(point41);
+         }
+      else
+         {
+         haloRadius.add(point21);
+         haloRadius.add(point20);
+         color.add(point41);
+         color.add(point40);
+         }
+
+      PostprocessEffectGlow glow = new PostprocessEffectGlow(haloRadius,color);
+      glow.setQuality(EffectQuality.MEDIUM);
+      glow.notifyWhenFinished(this);
+
+      return glow;
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   public void effectFinished(long id)
+      {
+      if( id==mMoveID )
+         {
+         PostprocessEffectGlow glow = constructGlow(true);
+         mGlow1ID = glow.getID();
+         DistortedEffects effects = mNodeCentral.getEffects();
+         effects.apply(glow);
+         }
+      if( id==mGlow1ID )
+         {
+         renderStars(mTotalStars+(mIncrease ? mNewStars : -mNewStars));
+         PostprocessEffectGlow glow = constructGlow(false);
+         mGlow2ID = glow.getID();
+         DistortedEffects effects = mNodeCentral.getEffects();
+         effects.abortById(mGlow1ID);
+         effects.apply(glow);
+         }
+      if( id==mGlow2ID )
+         {
+         DistortedEffects effects = mNodeCentral.getEffects();
+         effects.abortById(mGlow2ID);
+         createAlphaEffect(false);
+         mAlphaID = mAlpha.getID();
+         mAlpha.notifyWhenFinished(this);
+         effects.apply(mAlpha);
+         }
+      if( id==mAlphaID )
+         {
+         mScreen.detach(mNodeCentral);
+         mNodeCentral.markForDeletion();
+         mNodeCentral=null;
+         mScreen.detach(mNodeFalling);
+         mNodeFalling.markForDeletion();
+         mNodeFalling=null;
+         mListener.overlayFinished(id);
+         }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  @SuppressWarnings("unused")
+  public static void enableEffects()
+     {
+     FragmentEffectAlpha.enable();
+     VertexEffectMove.enable();
+     VertexEffectScale.enable();
+     PostprocessEffectGlow.enable();
+     }
+}
\ No newline at end of file
diff --git a/src/main/res/layout/flatblur2layout.xml b/src/main/res/layout/flatblur2layout.xml
index 48a1a3e..d71c5c8 100644
--- a/src/main/res/layout/flatblur2layout.xml
+++ b/src/main/res/layout/flatblur2layout.xml
@@ -10,12 +10,27 @@
         android:layout_height="0dp"
         android:layout_weight="1" />
 
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center">
+
+        <Button
+                android:id="@+id/flatblurButton1"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:onClick="button1"
+                android:checked="false"/>
         <Button
-                android:id="@+id/flatblur2Button2"
-                android:text="CRASH"
-                android:layout_width="match_parent"
-                android:layout_height="100dp"
-                android:onClick="crash"
+                android:id="@+id/flatblurButton2"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:onClick="button2"
                 android:checked="false"/>
 
+    </LinearLayout>
+
 </LinearLayout>
diff --git a/src/main/res/raw/yellow_star.png b/src/main/res/raw/yellow_star.png
new file mode 100644
index 0000000..0abaa63
Binary files /dev/null and b/src/main/res/raw/yellow_star.png differ
