commit 34998c9d219a55fa95fa3ab32bcaf67a2013168e
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Tue Apr 30 10:58:42 2019 +0100

    Port fixes for the memory leak problems from distorted-examples.

diff --git a/distorted-cube.iml b/distorted-cube.iml
index 0de1be47..42824155 100644
--- a/distorted-cube.iml
+++ b/distorted-cube.iml
@@ -105,8 +105,6 @@
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_merged_manifests" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/instant_run_split_apk_resources" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/javac" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint_jar" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifest-checker" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_assets" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/merged_jni_libs" />
@@ -118,13 +116,10 @@
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/reload-dex" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/resources" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/shader_assets" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/signing_config" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/split-apk" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
-      <excludeFolder url="file://$MODULE_DIR$/build/intermediates/tmp" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
       <excludeFolder url="file://$MODULE_DIR$/build/intermediates/validate_signing_config" />
       <excludeFolder url="file://$MODULE_DIR$/build/outputs" />
@@ -148,5 +143,8 @@
     <orderEntry type="library" name="Gradle: android.arch.core:common:1.1.0@jar" level="project" />
     <orderEntry type="module" module-name="distorted-library" />
     <orderEntry type="module" module-name="distorted-library" />
+    <orderEntry type="module" module-name="distorted-library" />
+    <orderEntry type="module" module-name="distorted-library" />
+    <orderEntry type="module" module-name="distorted-library" />
   </component>
 </module>
\ No newline at end of file
diff --git a/src/main/java/org/distorted/magic/RubikActivity.java b/src/main/java/org/distorted/magic/RubikActivity.java
index 3d8c05c2..b3e57dad 100644
--- a/src/main/java/org/distorted/magic/RubikActivity.java
+++ b/src/main/java/org/distorted/magic/RubikActivity.java
@@ -34,7 +34,7 @@ import org.distorted.library.main.Distorted;
 public class RubikActivity extends Activity
 {
             static final int DEFAULT_SIZE  = 3;
-    private static final int STARTING_SIZE = 2;
+    private static final int SMALLEST_SIZE = 2;
     private static final int[] button_ids  = {R.id.rubikSize2, R.id.rubikSize3, R.id.rubikSize4};
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -102,7 +102,7 @@ public class RubikActivity extends Activity
       for(int b=0; b<button_ids.length; b++)
         if( button_ids[b] == id )
           {
-          size = b+STARTING_SIZE;
+          size = b+SMALLEST_SIZE;
           break;
           }
 
@@ -120,7 +120,7 @@ public class RubikActivity extends Activity
        {
        Drawable d = findViewById(button_ids[b]).getBackground();
 
-       if( size == b+STARTING_SIZE )
+       if( size == b+SMALLEST_SIZE )
          {
          d.setColorFilter(ContextCompat.getColor(this,R.color.red), PorterDuff.Mode.MULTIPLY);
          }
diff --git a/src/main/java/org/distorted/magic/RubikCube.java b/src/main/java/org/distorted/magic/RubikCube.java
index 1e780938..07790540 100644
--- a/src/main/java/org/distorted/magic/RubikCube.java
+++ b/src/main/java/org/distorted/magic/RubikCube.java
@@ -29,6 +29,7 @@ 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.DistortedNode;
 import org.distorted.library.main.DistortedScreen;
 import org.distorted.library.main.DistortedTexture;
 import org.distorted.library.mesh.MeshCubes;
@@ -49,6 +50,7 @@ class RubikCube
     private static final Static3D VectY = new Static3D(0,1,0);
     private static final Static3D VectZ = new Static3D(0,0,1);
 
+    private DistortedNode[][][] mNodes;
     private MeshCubes[][][] mCubes;
     private DistortedEffects[][][] mEffects;
     private Static4D[][][] mQuatScramble;
@@ -75,6 +77,7 @@ class RubikCube
       mRotAxis= RubikSurfaceView.VECTX;
       mTexture = new DistortedTexture(TEXTURE_SIZE,TEXTURE_SIZE);
 
+      mNodes          = new DistortedNode[mSize][mSize][mSize];
       mCubes          = new MeshCubes[mSize][mSize][mSize];
       mEffects        = new DistortedEffects[mSize][mSize][mSize];
       mQuatScramble   = new Static4D[mSize][mSize][mSize];
@@ -160,7 +163,29 @@ class RubikCube
             {
             if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
               {
-              screen.attach(mTexture,mEffects[x][y][z],mCubes[x][y][z]);
+              mNodes[x][y][z] = new DistortedNode(mTexture,mEffects[x][y][z],mCubes[x][y][z]);
+              screen.attach(mNodes[x][y][z]);
+              }
+            }
+      }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// all DistortedTextures, DistortedNodes, DistortedFramebuffers, DistortedScreens and all types of
+// Meshes HAVE TO be markedForDeletion when they are no longer needed- otherwise we have a major
+// memory leak.
+
+    void releaseResources()
+      {
+      mTexture.markForDeletion();
+
+      for(int x=0; x<mSize; x++)
+        for(int y=0; y<mSize; y++)
+          for(int z=0; z<mSize; z++)
+            {
+            if( x==0 || x==mSize-1 || y==0 || y==mSize-1 || z==0 || z==mSize-1 )
+              {
+              mCubes[x][y][z].markForDeletion();
+              mNodes[x][y][z].markForDeletion();
               }
             }
       }
@@ -217,7 +242,7 @@ class RubikCube
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    void finishRotationCalledOnNextRender(EffectListener listener)
+    void finishRotationNow(EffectListener listener)
       {
       boolean first = true;
       float startingAngle = mRotationAngleStatic.get1();
@@ -249,7 +274,7 @@ class RubikCube
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    void removeRotationCalledOnNextRender(EffectListener listener)
+    void removeRotationNow(EffectListener listener)
       {
       mEffectsListeningForNow.deregisterForMessages(listener);
 
diff --git a/src/main/java/org/distorted/magic/RubikRenderer.java b/src/main/java/org/distorted/magic/RubikRenderer.java
index 6a5c8134..2816d115 100644
--- a/src/main/java/org/distorted/magic/RubikRenderer.java
+++ b/src/main/java/org/distorted/magic/RubikRenderer.java
@@ -45,6 +45,7 @@ class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
     private Static4D mQuatCurrent, mQuatAccumulated;
     private Static4D mTempCurrent, mTempAccumulated;
     private float mCubeSizeInScreenSpace;
+    private int mNextCubeSize;
     private boolean mFinishRotation, mRemoveRotation, mFinishDragCurrent, mFinishDragAccumulated;
     private boolean mCanRotate;
     private RubikCube mCube;
@@ -74,6 +75,8 @@ class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
       mFinishDragCurrent     = false;
       mFinishDragAccumulated = false;
 
+      mNextCubeSize= 0;
+
       mCanRotate = true;
       }
 
@@ -101,15 +104,23 @@ class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
         {
         mCanRotate = false;
         mFinishRotation=false;
-        mCube.finishRotationCalledOnNextRender(this);
+        mCube.finishRotationNow(this);
         }
 
       if( mRemoveRotation )
         {
         mRemoveRotation=false;
-        mCube.removeRotationCalledOnNextRender(this);
+        mCube.removeRotationNow(this);
         mCanRotate = true;
         }
+
+      if( mNextCubeSize!=0 )
+        {
+        createCubeNow(mNextCubeSize);
+        mScreen.detachAll();
+        mCube.attachToScreen(mScreen);
+        mNextCubeSize = 0;
+        }
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -180,11 +191,19 @@ class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
    void createCube(int newSize)
+     {
+     mNextCubeSize = newSize;
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   void createCubeNow(int newSize)
      {
      int oldSize = mCube==null ? 0 : mCube.getSize();
 
      if( oldSize!=newSize )
        {
+       if( mCube!=null ) mCube.releaseResources();
        mCube = new RubikCube(newSize, mMove, mScale, mQuatCurrent, mQuatAccumulated);
        mCube.createTexture();
 
@@ -192,15 +211,12 @@ class RubikRenderer implements GLSurfaceView.Renderer, EffectListener
          {
          recomputeScaleFactor(mScreenWidth,mScreenHeight);
          }
-
-       mScreen.detachAll();
-       mCube.attachToScreen(mScreen);
        }
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-   void recomputeScaleFactor(int screenWidth, int screenHeight)
+   private void recomputeScaleFactor(int screenWidth, int screenHeight)
      {
      mCubeSizeInScreenSpace = CUBE_SCREEN_RATIO*(screenWidth>screenHeight ? screenHeight:screenWidth);
      float texSize = mCube.getTextureSize();
diff --git a/src/main/java/org/distorted/magic/RubikSurfaceView.java b/src/main/java/org/distorted/magic/RubikSurfaceView.java
index 0c2c2d69..d95de4f8 100644
--- a/src/main/java/org/distorted/magic/RubikSurfaceView.java
+++ b/src/main/java/org/distorted/magic/RubikSurfaceView.java
@@ -80,7 +80,7 @@ class RubikSurfaceView extends GLSurfaceView
         mScreenWidth = mScreenHeight = mScreenMin = 0;
 
         mRenderer = new RubikRenderer(this);
-        mRenderer.createCube(RubikActivity.DEFAULT_SIZE);
+        mRenderer.createCubeNow(RubikActivity.DEFAULT_SIZE);
 
         mQuatCurrent     = new Static4D(0,0,0,1);
         mQuatAccumulated = mRenderer.initializeQuat();
