commit 0da4feff1710c94a9c07be2a8e33b76df5421bca
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Thu Dec 15 23:54:40 2022 +0100

    The 'stars earned' effect is done. Works only for newStars>0.
    Also, there is a crash in the graphics driver on my physical LG phone.

diff --git a/build.gradle b/build.gradle
index fb31e7f6..d0430b21 100644
--- a/build.gradle
+++ b/build.gradle
@@ -38,7 +38,7 @@ dependencies {
     api project(':distorted-objectlib')
     api project(':distorted-flags')
 
-    implementation platform('com.google.firebase:firebase-bom:30.2.0')
+    implementation platform('com.google.firebase:firebase-bom:31.1.0')
     implementation 'com.google.firebase:firebase-messaging'
     implementation 'com.google.firebase:firebase-analytics'
     implementation 'com.google.firebase:firebase-crashlytics'
diff --git a/src/main/java/org/distorted/main/RubikObjectLibInterface.java b/src/main/java/org/distorted/main/RubikObjectLibInterface.java
index d3d87e3b..d277bc1a 100644
--- a/src/main/java/org/distorted/main/RubikObjectLibInterface.java
+++ b/src/main/java/org/distorted/main/RubikObjectLibInterface.java
@@ -22,6 +22,7 @@ import com.google.android.play.core.tasks.Task;
 import com.google.firebase.analytics.FirebaseAnalytics;
 import com.google.firebase.crashlytics.FirebaseCrashlytics;
 
+import org.distorted.library.main.DistortedScreen;
 import org.distorted.library.message.EffectMessageSender;
 
 import org.distorted.external.RubikNetwork;
@@ -35,7 +36,9 @@ import org.distorted.dialogs.RubikDialogSolved;
 import org.distorted.external.RubikScores;
 import org.distorted.objects.RubikObject;
 import org.distorted.objects.RubikObjectList;
+import org.distorted.overlays.DataStars;
 import org.distorted.overlays.ListenerOverlay;
+import org.distorted.overlays.OverlayStars;
 import org.distorted.screens.RubikScreenPlay;
 import org.distorted.screens.RubikScreenReady;
 import org.distorted.screens.RubikScreenSolver;
@@ -451,10 +454,12 @@ public class RubikObjectLibInterface implements ObjectLibInterface, ListenerOver
                              int level = play.getLevel();
                              RubikScores scores = RubikScores.getInstance();
                              int newStars = scores.computeNumStars(level);
+                             int totStars = scores.getNumStars();
                              scores.changeNumStars(newStars);
-                             RubikDialogNewRecord d1 = new RubikDialogNewRecord();
-                             d1.setArguments(bundle);
-                             d1.show( act.getSupportFragmentManager(), RubikDialogNewRecord.getDialogTag() );
+                             DistortedScreen screen = act.getScreen();
+                             OverlayStars stars = new OverlayStars();
+                             DataStars data  = new DataStars(totStars,newStars,act.getResources());
+                             stars.startOverlay(screen,this,data);
                              break;
         case RECORD_NEW    : RubikDialogNewRecord d2 = new RubikDialogNewRecord();
                              d2.setArguments(bundle);
diff --git a/src/main/java/org/distorted/objects/RubikObject.java b/src/main/java/org/distorted/objects/RubikObject.java
index 412f2226..255af796 100644
--- a/src/main/java/org/distorted/objects/RubikObject.java
+++ b/src/main/java/org/distorted/objects/RubikObject.java
@@ -219,7 +219,7 @@ public class RubikObject
 
   public boolean isFree()
     {
-    return true; // mIsFree;
+    return mIsFree;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/overlays/OverlayStars.java b/src/main/java/org/distorted/overlays/OverlayStars.java
index e09f2308..2c86585d 100644
--- a/src/main/java/org/distorted/overlays/OverlayStars.java
+++ b/src/main/java/org/distorted/overlays/OverlayStars.java
@@ -16,8 +16,7 @@ import android.graphics.Canvas;
 import android.graphics.Paint;
 
 import org.distorted.library.effect.EffectQuality;
-import org.distorted.library.effect.MatrixEffectMove;
-import org.distorted.library.effect.MatrixEffectScale;
+import org.distorted.library.effect.FragmentEffectAlpha;
 import org.distorted.library.effect.PostprocessEffectGlow;
 import org.distorted.library.effect.VertexEffectMove;
 import org.distorted.library.effect.VertexEffectScale;
@@ -30,9 +29,11 @@ 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;
@@ -44,6 +45,7 @@ import java.util.Random;
 
 public class OverlayStars extends OverlayGeneric implements EffectListener
 {
+   private static final int DUR_APP =  1000;
    private static final int DUR_MOV =  4000;
    private static final int DUR_GLO =  2000;
 
@@ -51,17 +53,19 @@ public class OverlayStars extends OverlayGeneric implements EffectListener
    private static final int INDEX = 5;
 
    private ListenerOverlay mListener;
-   private DistortedNode mStarsNode, mCountNode;
+   private DistortedNode mNode;
    private DistortedScreen mScreen;
-   private DistortedTexture mStarsTexture, mCountTexture;
-   private Bitmap mCountBitmap;
+   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, mGlowID;
+   private long mMoveID, mGlowID, mAlphaID;
    private int mTotalStars, mNewStars;
+   private FragmentEffectAlpha mAlpha;
+   private Dynamic1D mAlphaStrength;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -90,25 +94,89 @@ public class OverlayStars extends OverlayGeneric implements EffectListener
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-   private DistortedNode createStarsNode(Resources res)
+   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 DistortedNode createNode(Resources res, int numStars)
       {
       // texture /////////////////////////////////////////////////////
-      if( mStarsTexture==null )
+      if( mTexture==null )
          {
-         mStarsTexture = new DistortedTexture();
-         Bitmap star = BitmapFactory.decodeResource(res, R.drawable.star);
-         mBmpW = star.getWidth();
-         mBmpH = star.getHeight();
-         mStarsTexture.setTexture(star);
+         mTexture = new DistortedTexture();
+         mStarBitmap = BitmapFactory.decodeResource(res, R.drawable.star);
+         mBmpW = mStarBitmap.getWidth();
+         mBmpH = mStarBitmap.getHeight();
+         mCountBitmap = Bitmap.createBitmap(2*mBmpW,mBmpH,Bitmap.Config.ARGB_8888);
+         mCountCanvas = new Canvas(mCountBitmap);
+         mPaint = new Paint();
+         mPaint.setColor(0xff000000);
+         mPaint.setTextSize(mBmpH*0.28f);
+         mPaint.setAntiAlias(true);
+         mPaint.setTextAlign(Paint.Align.CENTER);
+         renderStars(numStars);
          }
 
       // mesh ////////////////////////////////////////////////////////
       MeshQuad[] mesh = new MeshQuad[mNewStars+1];
 
+      Static4D[] mapMain = new Static4D[1];
+      Static4D[] mapStar = new Static4D[1];
+
+      mapMain[0] = new Static4D(0.5f,0.0f,0.5f,1.0f);
+      mapStar[0] = new Static4D(0.0f,0.0f,0.5f,1.0f);
+
       for(int i=0; i<mNewStars+1; i++)
          {
          mesh[i] = new MeshQuad();
-         mesh[i].setEffectAssociation(0,(i>=mNewStars?2:1),i);
+
+         if( i>=mNewStars )
+           {
+           mesh[i].setEffectAssociation(0,2,i);
+           mesh[i].setTextureMap(mapMain,0);
+           }
+         else
+           {
+           mesh[i].setEffectAssociation(0,1,i);
+           mesh[i].setTextureMap(mapStar,0);
+           }
          }
 
       MeshJoined wholeMesh = new MeshJoined(mesh);
@@ -148,7 +216,10 @@ public class OverlayStars extends OverlayGeneric implements EffectListener
       effects.apply(mainMove);
       effects.apply(mainScale);
 
-      return new DistortedNode(mStarsTexture,effects,wholeMesh);
+      createAlphaEffect(true);
+      effects.apply(mAlpha);
+
+      return new DistortedNode(mTexture,effects,wholeMesh);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -156,46 +227,11 @@ public class OverlayStars extends OverlayGeneric implements EffectListener
    private void renderStars(int numStars)
       {
       String txt = ""+numStars;
-      mCountCanvas.drawText(txt,mBmpW*0.5f,mBmpH*0.64f,mPaint);
-      mCountTexture.setTexture(mCountBitmap);
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-   private DistortedNode createCountNode()
-      {
-      // texture /////////////////////////////////////////////////////
-      if( mCountTexture==null )
-         {
-         mCountTexture = new DistortedTexture();
-
-         mCountBitmap = Bitmap.createBitmap(mBmpW,mBmpH,Bitmap.Config.ARGB_8888);
-         mCountCanvas = new Canvas(mCountBitmap);
-         mPaint = new Paint();
-         mPaint.setColor(0xff000000);
-         mPaint.setTextSize(mBmpH*0.28f);
-         mPaint.setAntiAlias(true);
-         mPaint.setTextAlign(Paint.Align.CENTER);
-         renderStars(mTotalStars);
-         }
-
-      // mesh ////////////////////////////////////////////////////////
-      MeshQuad mesh = new MeshQuad();
-
-      // effects: main ///////////////////////////////////////////////
-      DistortedEffects effects = new DistortedEffects();
-
-      float scaleM  = mWidth*0.40f;
-      Static3D moveM= new Static3D(0,0,1);
-
-      MatrixEffectMove mainMove  = new MatrixEffectMove(moveM);
-      MatrixEffectScale mainScale= new MatrixEffectScale(scaleM);
-
-      // main effect queue ///////////////////////////////////////////
-      effects.apply(mainMove);
-      effects.apply(mainScale);
-
-      return new DistortedNode(mCountTexture,effects,mesh);
+      mCountBitmap.eraseColor(0x00000000);
+      mCountCanvas.drawBitmap(mStarBitmap,0,0,null);
+      mCountCanvas.drawBitmap(mStarBitmap,mBmpW,0,null);
+      mCountCanvas.drawText(txt,mBmpW*1.5f,mBmpH*0.64f,mPaint);
+      mTexture.setTexture(mCountBitmap);
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -214,17 +250,11 @@ public class OverlayStars extends OverlayGeneric implements EffectListener
       mWidth = mScreen.getWidth();
       mHeight= mScreen.getHeight();
 
-      mStarsNode = createStarsNode(res);
-      mStarsNode.glDepthMask(false);
-      mStarsNode.glStencilMask(0);
-      mStarsNode.enableDepthStencil(InternalOutputSurface.NO_DEPTH_NO_STENCIL);
-      mScreen.attach(mStarsNode);
-
-      mCountNode = createCountNode();
-      mCountNode.glDepthMask(false);
-      mCountNode.glStencilMask(0);
-      mCountNode.enableDepthStencil(InternalOutputSurface.NO_DEPTH_NO_STENCIL);
-      mScreen.attach(mCountNode);
+      mNode = createNode(res,mTotalStars);
+      mNode.glDepthMask(false);
+      mNode.glStencilMask(0);
+      mNode.enableDepthStencil(InternalOutputSurface.NO_DEPTH_NO_STENCIL);
+      mScreen.attach(mNode);
 
       return 0;
       }
@@ -251,19 +281,22 @@ public class OverlayStars extends OverlayGeneric implements EffectListener
          glow.setQuality(EffectQuality.MEDIUM);
          mGlowID = glow.getID();
          glow.notifyWhenFinished(this);
-         DistortedEffects effects = mStarsNode.getEffects();
+         DistortedEffects effects = mNode.getEffects();
          effects.apply(glow);
 
          renderStars(mTotalStars+mNewStars);
          }
       if( id==mGlowID )
          {
-         mScreen.detach(mStarsNode);
-         mStarsNode.markForDeletion();
-         mStarsNode=null;
-         mScreen.detach(mCountNode);
-         mCountNode.markForDeletion();
-         mCountNode=null;
+         createAlphaEffect(false);
+         mAlphaID = mAlpha.getID();
+         mAlpha.notifyWhenFinished(this);
+         }
+      if( id==mAlphaID )
+         {
+         mScreen.detach(mNode);
+         mNode.markForDeletion();
+         mNode=null;
          mListener.overlayFinished(id);
          }
       }
@@ -273,6 +306,7 @@ public class OverlayStars extends OverlayGeneric implements EffectListener
   @SuppressWarnings("unused")
   public static void enableEffects()
      {
+     FragmentEffectAlpha.enable();
      VertexEffectMove.enable();
      VertexEffectScale.enable();
      PostprocessEffectGlow.enable();
