commit 9519d1b1b279b3fc02e18457b7a2278a08386cef
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Wed Nov 11 15:26:32 2020 +0100

    1) Beginnings of support for using the library from more than one activity
    2) rename DistortedLibrary.onCreate() to onSurfaceCreated()
    3) (rubik) add Cambodia's flag.

diff --git a/src/main/java/org/distorted/library/main/DistortedLibrary.java b/src/main/java/org/distorted/library/main/DistortedLibrary.java
index e446c0a..a1ce06b 100644
--- a/src/main/java/org/distorted/library/main/DistortedLibrary.java
+++ b/src/main/java/org/distorted/library/main/DistortedLibrary.java
@@ -950,30 +950,30 @@ public class DistortedLibrary
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * When OpenGL context gets created, call this method so that the library can initialise its internal data structures.
- * I.e. best called from GLSurfaceView.onCreate().
+ * I.e. best called from GLSurfaceView.Renderer.onSurfaceCreated().
  * <p>
  * Needs to be called from a thread holding the OpenGL context.
  *
  * @param context Context of the App using the library - used to open up Resources and read Shader code.
  * @param listener The library will send all (asynchronous!) exceptions there.
  */
-  public static void onCreate(final Context context, final ExceptionListener listener)
+  public static void onSurfaceCreated(final Context context, final ExceptionListener listener)
     {
-    onCreate(context,listener,4);
+    onSurfaceCreated(context,listener,4);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * When OpenGL context gets created, call this method so that the library can initialise its internal data structures.
- * I.e. best called from GLSurfaceView.onCreate().
+ * I.e. best called from GLSurfaceView.Renderer.onSurfaceCreated().
  * <p>
  * Needs to be called from a thread holding the OpenGL context.
  *   
  * @param context Context of the App using the library - used to open up Resources and read Shader code.
  * @param listener The library will send all (asynchronous!) exceptions there.
- * @param queueSize the size of the FBO queue, a workaround for the bug on Mali drivers.
+ * @param queueSize the size of the FBO queue, a workaround for the bug on Mali drivers. Use a small integer - 1,...,4
  */
-  public static void onCreate(final Context context, final ExceptionListener listener, int queueSize)
+  public static void onSurfaceCreated(final Context context, final ExceptionListener listener, int queueSize)
     {
     final ActivityManager activityManager     = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
     final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
@@ -1006,7 +1006,6 @@ public class DistortedLibrary
     mOITCompilationAttempted = false;
 
     detectBuggyDriversAndSetQueueSize(queueSize);
-
     EffectMessageSender.startSending();
 
     mResources = context.getResources();
@@ -1118,7 +1117,7 @@ public class DistortedLibrary
  * <ul>
  * <li>the value of 'max' is outside permitted range (0 &le; max &le; Byte.MAX_VALUE)
  * <li>We try to increase the value of 'max' when it is too late to do so already. It needs to be called
- *     before the Vertex Shader gets compiled, i.e. before the call to {@link DistortedLibrary#onCreate}. After this
+ *     before the Vertex Shader gets compiled, i.e. before the call to {@link DistortedLibrary#onSurfaceCreated}. After this
  *     time only decreasing the value of 'max' is permitted.
  * <li>Furthermore, this needs to be called before any instances of the DistortedEffects class get created.
  * </ul>
diff --git a/src/main/java/org/distorted/library/main/InternalObject.java b/src/main/java/org/distorted/library/main/InternalObject.java
index c397649..f1a670d 100644
--- a/src/main/java/org/distorted/library/main/InternalObject.java
+++ b/src/main/java/org/distorted/library/main/InternalObject.java
@@ -19,6 +19,7 @@
 
 package org.distorted.library.main;
 
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.LinkedList;
 
@@ -47,6 +48,13 @@ abstract class InternalObject
   private static final int JOB_CREATE = 0;
   private static final int JOB_DELETE = 1;
 
+  private final static Object mLock = new Object();
+
+  private long mID;
+  private int mType;
+
+  /////////////////////////////////////////////////////////////////
+
   private static class Job
     {
     InternalObject object;
@@ -59,17 +67,122 @@ abstract class InternalObject
       }
     }
 
+  /////////////////////////////////////////////////////////////////
+
   private static boolean mToDo = false;
-  private static LinkedList<InternalObject> mDoneList = new LinkedList<>();
-  private static HashMap<Long,Job> mToDoMap = new HashMap<>();
-  private static long mNextClientID = 0;
-  private static long mNextSystemID = 0;
+  private static StackFrame mCurrentFrame = null;
+  private static ArrayList<StackFrame> mFrameList = new ArrayList<>();
 
-  private final static Object mDoneLock = new Object();
-  private final static Object mToDoLock = new Object();
+  /////////////////////////////////////////////////////////////////
 
-  private long mID;
-  private int mType;
+  private static class StackFrame
+    {
+    private LinkedList<InternalObject> mDoneList;
+    private HashMap<Long,Job> mToDoMap;
+    private long mNextClientID;
+    private long mNextSystemID;
+
+    /////////////////////////////////////////////////////////
+
+    StackFrame()
+      {
+      mDoneList = new LinkedList<>();
+      mToDoMap  = new HashMap<>();
+      mNextClientID = 0;
+      mNextSystemID = 0;
+      }
+
+    /////////////////////////////////////////////////////////
+
+    void onPause()
+      {
+      int num = mDoneList.size();
+
+      try
+        {
+        for (int i=0; i<num; i++)
+          {
+          InternalObject object = mDoneList.removeFirst();
+          Job job = new Job(object, JOB_CREATE);
+          mToDoMap.put(object.mID,job);
+          object.recreate();
+          }
+        }
+      catch( Exception ignored )
+        {
+        // something else removed an object in the meantime; ignore
+        }
+      }
+
+    /////////////////////////////////////////////////////////
+
+    void toDo()
+      {
+      for(Long key: mToDoMap.keySet())
+        {
+        Job job = mToDoMap.get(key);
+        InternalObject object = job.object;
+
+        if( job.action==JOB_CREATE )
+          {
+          object.create();
+          mDoneList.add(object);
+          }
+        else if( job.action==JOB_DELETE )
+          {
+          object.delete();
+          }
+        }
+
+      mToDoMap.clear();
+      }
+
+    /////////////////////////////////////////////////////////
+
+    long generateID(int type)
+      {
+      return type==TYPE_SYST ? --mNextSystemID : ++mNextClientID;
+      }
+
+    /////////////////////////////////////////////////////////
+
+    void addToDoneList(InternalObject obj)
+      {
+      mDoneList.add(obj);
+      }
+
+
+    /////////////////////////////////////////////////////////
+
+    void markFor(InternalObject obj, long id, int jobType)
+      {
+      mDoneList.remove(obj);
+      mToDoMap.put(id, new Job(obj,jobType) );
+      }
+
+    /////////////////////////////////////////////////////////
+
+    void debugLists(String frameMarker)
+      {
+      android.util.Log.e("Object", frameMarker);
+      android.util.Log.e("Object", "  Done list:");
+
+      for(InternalObject object : mDoneList)
+        {
+        object.print("  ");
+        }
+
+      android.util.Log.e("Object", "  ToDo list:");
+
+      Job job;
+
+      for(Long key: mToDoMap.keySet())
+        {
+        job = mToDoMap.get(key);
+        job.object.print(job.action==JOB_CREATE ? " create":" delete");
+        }
+      }
+    }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -85,31 +198,12 @@ abstract class InternalObject
     {
     if( mToDo )
       {
-      Job job;
-      InternalObject object;
+      mToDo = false;
 
-      synchronized(mToDoLock)
+      synchronized(mLock)
         {
-        for(Long key: mToDoMap.keySet())
-          {
-          job = mToDoMap.get(key);
-          object = job.object;
-
-          if( job.action==JOB_CREATE )
-            {
-            object.create();
-            mDoneList.add(object);
-            }
-          else if( job.action==JOB_DELETE )
-            {
-            object.delete();
-            }
-          }
-
-        mToDoMap.clear();
-        mToDo = false;
+        mCurrentFrame.toDo();
         }
-
       return true;
       }
 
@@ -118,49 +212,49 @@ abstract class InternalObject
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  static void onPause()
+  static void onCreate()
     {
-    InternalObject object;
-
-    synchronized(mDoneLock)
+    synchronized(mLock)
       {
-      synchronized(mToDoLock)
-        {
-        int num = mDoneList.size();
-
-        try
-          {
-          for (int i = 0; i < num; i++)
-            {
-            object = mDoneList.removeFirst();
-            Job job = new Job(object, JOB_CREATE);
-            mToDoMap.put(object.mID,job);
-            object.recreate();
-            }
-          }
-        catch( Exception ex )
-          {
-          // something else removed an object in the meantime; ignore
-          }
-        }
+      mCurrentFrame = new StackFrame();
+      mFrameList.add(mCurrentFrame);
+      mToDo = false;
       }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    mToDo = true;
+  static void onPause()
+    {
+    synchronized(mLock)
+      {
+      mCurrentFrame.onPause();
+      mToDo = true;
+      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   static void onDestroy()
     {
-    synchronized(mToDoLock)
+    synchronized(mLock)
       {
-      synchronized(mDoneLock)
+      int num = mFrameList.size();
+
+      if( num>0 )
         {
-        mToDoMap.clear();
-        mDoneList.clear();
+        mFrameList.remove(num-1);
 
-        mToDo = true;
-        mNextClientID = 0;
+        if( num>1 )
+          {
+          mCurrentFrame = mFrameList.get(num-2);
+          mToDo = true;
+          }
+        else
+          {
+          mCurrentFrame = null;
+          mToDo = false;
+          }
         }
       }
     }
@@ -170,21 +264,13 @@ abstract class InternalObject
   @SuppressWarnings("unused")
   static void debugLists()
     {
-    android.util.Log.e("Object", "Done list:");
+    int num = mFrameList.size();
+    StackFrame frame;
 
-    for(InternalObject object : mDoneList)
+    for(int i=0; i<num; i++)
       {
-      object.print("");
-      }
-
-    android.util.Log.e("Object", "ToDo list:");
-
-    Job job;
-
-    for(Long key: mToDoMap.keySet())
-      {
-      job = mToDoMap.get(key);
-      job.object.print(job.action==JOB_CREATE ? " create":" delete");
+      frame = mFrameList.get(i);
+      frame.debugLists("frame "+i);
       }
     }
 
@@ -209,7 +295,9 @@ abstract class InternalObject
 
   InternalObject(int type)
     {
-    mID  = type==TYPE_SYST ? --mNextSystemID : ++mNextClientID;
+    if( mCurrentFrame==null ) onCreate();
+
+    mID = mCurrentFrame.generateID(type);
     mType= type;
     }
 
@@ -217,21 +305,16 @@ abstract class InternalObject
 
   void markWasCreatedImmediately()
     {
-    mDoneList.add(this);
+    mCurrentFrame.addToDoneList(this);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void markForCreation()
     {
-    synchronized(mDoneLock)
+    synchronized(mLock)
       {
-      mDoneList.remove(this);
-      }
-
-    synchronized(mToDoLock)
-      {
-      mToDoMap.put(mID, new Job(this,JOB_CREATE) );
+      mCurrentFrame.markFor(this,mID,JOB_CREATE);
       mToDo = true;
       }
     }
@@ -244,14 +327,9 @@ abstract class InternalObject
  */
   public void markForDeletion()
     {
-    synchronized(mDoneLock)
-      {
-      mDoneList.remove(this);
-      }
-
-    synchronized(mToDoLock)
+    synchronized(mLock)
       {
-      mToDoMap.put(mID, new Job(this,JOB_DELETE) );
+      mCurrentFrame.markFor(this,mID,JOB_DELETE);
       mToDo = true;
       }
     }
@@ -264,5 +342,4 @@ abstract class InternalObject
     {
     return mID;
     }
-
 }
