commit 26671ef8d36b06d2a1a38c5a19fd8daddb6fedee
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Sat Jun 6 01:17:49 2020 +0100

    Library: make setEffectAssociation a deferred job (because we do copy the uniforms during join!)
    SingleMesh App: almost finished.

diff --git a/src/main/java/org/distorted/library/mesh/DeferredJobs.java b/src/main/java/org/distorted/library/mesh/DeferredJobs.java
index fa82c72..edd8ace 100644
--- a/src/main/java/org/distorted/library/mesh/DeferredJobs.java
+++ b/src/main/java/org/distorted/library/mesh/DeferredJobs.java
@@ -44,6 +44,7 @@ public class DeferredJobs
   private static final int JOB_TYPE_JOIN     = 4;
   private static final int JOB_TYPE_COPY     = 5;
   private static final int JOB_TYPE_TEXTURE  = 6;
+  private static final int JOB_TYPE_ASSOC    = 7;
 
   private static ArrayList<JobNode> mJobs = new ArrayList<>();
 
@@ -57,16 +58,17 @@ public class DeferredJobs
     private EffectQueueVertex mVertexEffects;
     private MatrixEffect mMatrixEffect;
     private Static4D[] mMaps;
-    private int mAndAssoc, mEcuAssoc;
+    private int mComp, mAndAssoc, mEquAssoc;
 
-    Job(int type, MeshBase target, MeshBase[] source, VertexEffect vEff, MatrixEffect mEff, Static4D[] maps, int and, int ecu)
+    Job(int type, MeshBase target, MeshBase[] source, VertexEffect vEff, MatrixEffect mEff, Static4D[] maps, int comp, int and, int equ)
       {
       mType     = type;
       mTarget   = target;
       mSource   = source;
       mMaps     = maps;
+      mComp     = comp;
       mAndAssoc = and;
-      mEcuAssoc = ecu;
+      mEquAssoc = equ;
 
       if( vEff!=null )
         {
@@ -88,7 +90,7 @@ public class DeferredJobs
         {
         case JOB_TYPE_VERTEX   : DistortedLibrary.adjustVertices(mTarget, mVertexEffects);
                                  break;
-        case JOB_TYPE_MATRIX   : mTarget.applyMatrix(mMatrixEffect,mAndAssoc,mEcuAssoc);
+        case JOB_TYPE_MATRIX   : mTarget.applyMatrix(mMatrixEffect,mAndAssoc,mEquAssoc);
                                  break;
         case JOB_TYPE_MERGE_TEX: mTarget.mergeTexComponentsNow();
                                  break;
@@ -100,6 +102,8 @@ public class DeferredJobs
                                  break;
         case JOB_TYPE_TEXTURE  : mTarget.textureMap(mMaps);
                                  break;
+        case JOB_TYPE_ASSOC    : mTarget.setEffectAssociationNow(mComp,mAndAssoc,mEquAssoc);
+                                 break;
         }
 /*
       Log.e("jobs", "executing "+print()+" job");
@@ -123,6 +127,7 @@ public class DeferredJobs
         case JOB_TYPE_JOIN     : return "JOIN";
         case JOB_TYPE_COPY     : return "COPY";
         case JOB_TYPE_TEXTURE  : return "TEXTURE";
+        case JOB_TYPE_ASSOC    : return "ASSOC";
         }
 
       return null;
@@ -226,7 +231,7 @@ public class DeferredJobs
 
     if( jn==null )
       {
-      Job job = new Job(JOB_TYPE_VERTEX,target,null,effect,null,null,0,0);
+      Job job = new Job(JOB_TYPE_VERTEX,target,null,effect,null,null,0,0,0);
       JobNode node = new JobNode(job);
       mJobs.add(node);
       return node;
@@ -240,7 +245,7 @@ public class DeferredJobs
         }
       else
         {
-        Job job = new Job(JOB_TYPE_VERTEX,target,null,effect,null,null,0,0);
+        Job job = new Job(JOB_TYPE_VERTEX,target,null,effect,null,null,0,0,0);
         JobNode node = new JobNode(job);
         node.mPrevJobs.add(jn);
         jn.mNextJobs.add(node);
@@ -255,7 +260,7 @@ public class DeferredJobs
   static JobNode matrix(MeshBase target, MatrixEffect effect, int andAssoc, int ecuAssoc)
     {
     JobNode jn = target.mJobNode[0];
-    Job job = new Job(JOB_TYPE_MATRIX,target,null,null,effect,null,andAssoc,ecuAssoc);
+    Job job = new Job(JOB_TYPE_MATRIX,target,null,null,effect,null,0,andAssoc,ecuAssoc);
     JobNode node = new JobNode(job);
     node.mPrevJobs.add(jn);
     jn.mNextJobs.add(node);
@@ -268,7 +273,7 @@ public class DeferredJobs
   static JobNode mergeTex(MeshBase target)
     {
     JobNode jn = target.mJobNode[0];
-    Job job = new Job(JOB_TYPE_MERGE_TEX,target,null,null,null,null,0,0);
+    Job job = new Job(JOB_TYPE_MERGE_TEX,target,null,null,null,null,0,0,0);
     JobNode node = new JobNode(job);
     node.mPrevJobs.add(jn);
     jn.mNextJobs.add(node);
@@ -281,7 +286,7 @@ public class DeferredJobs
   static JobNode mergeEff(MeshBase target)
     {
     JobNode jn = target.mJobNode[0];
-    Job job = new Job(JOB_TYPE_MERGE_EFF,target,null,null,null,null,0,0);
+    Job job = new Job(JOB_TYPE_MERGE_EFF,target,null,null,null,null,0,0,0);
     JobNode node = new JobNode(job);
     node.mPrevJobs.add(jn);
     jn.mNextJobs.add(node);
@@ -295,7 +300,7 @@ public class DeferredJobs
     {
     JobNode jn;
 
-    Job job = new Job(JOB_TYPE_JOIN,target,meshes,null,null,null,0,0);
+    Job job = new Job(JOB_TYPE_JOIN,target,meshes,null,null,null,0,0,0);
     JobNode node = new JobNode(job);
 
     for (MeshBase mesh : meshes)
@@ -320,7 +325,7 @@ public class DeferredJobs
     JobNode jn = mesh.mJobNode[0];
     MeshBase[] meshes = new MeshBase[1];
     meshes[0] = mesh;
-    Job job = new Job(JOB_TYPE_COPY,target,meshes,null,null,null,0,0);
+    Job job = new Job(JOB_TYPE_COPY,target,meshes,null,null,null,0,0,0);
     JobNode node = new JobNode(job);
     node.mPrevJobs.add(jn);
     jn.mNextJobs.add(node);
@@ -333,7 +338,20 @@ public class DeferredJobs
   static JobNode textureMap(MeshBase target, Static4D[] maps)
     {
     JobNode jn = target.mJobNode[0];
-    Job job = new Job(JOB_TYPE_TEXTURE,target,null,null,null,maps,0,0);
+    Job job = new Job(JOB_TYPE_TEXTURE,target,null,null,null,maps,0,0,0);
+    JobNode node = new JobNode(job);
+    node.mPrevJobs.add(jn);
+    jn.mNextJobs.add(node);
+    mJobs.add(node);
+    return node;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  static JobNode effectAssoc(MeshBase target, int comp, int andAssoc, int equAssoc)
+    {
+    JobNode jn = target.mJobNode[0];
+    Job job = new Job(JOB_TYPE_ASSOC,target,null,null,null,null,comp,andAssoc,equAssoc);
     JobNode node = new JobNode(job);
     node.mPrevJobs.add(jn);
     jn.mNextJobs.add(node);
diff --git a/src/main/java/org/distorted/library/mesh/MeshBase.java b/src/main/java/org/distorted/library/mesh/MeshBase.java
index 1a9f7f2..7b3c83c 100644
--- a/src/main/java/org/distorted/library/mesh/MeshBase.java
+++ b/src/main/java/org/distorted/library/mesh/MeshBase.java
@@ -306,6 +306,14 @@ public abstract class MeshBase
        }
      }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   void setEffectAssociationNow(int component, int andAssociation, int equAssociation)
+     {
+     mAndAssociation[component] = andAssociation;
+     mEquAssociation[component] = equAssociation;
+     }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
    int numTexComponents()
@@ -344,7 +352,7 @@ public abstract class MeshBase
      TexComponent comp;
      int numMeshes = meshes.length;
      int numVertices,origVertices = mNumVertices;
-     int origTexComponents=0,numTexComponents;
+     int origTexComponents,numTexComponents;
      int origEffComponents=0,numEffComponents;
 
      if( origVertices>0 )
@@ -591,7 +599,7 @@ public abstract class MeshBase
  */
    public void print()
      {
-     StringBuffer sb = new StringBuffer();
+     StringBuilder sb = new StringBuilder();
 
      for(int i=0; i<mNumVertices; i++)
        {
@@ -604,7 +612,7 @@ public abstract class MeshBase
        sb.append(") ");
        }
 
-     StringBuffer sb2 = new StringBuffer();
+     StringBuilder sb2 = new StringBuilder();
 
      for(int i=0; i<mNumVertices; i++)
        {
@@ -884,14 +892,20 @@ public abstract class MeshBase
  * The point: this way we can configure the system so that each Vertex Effect acts only on a certain
  * subset of a Mesh, thus potentially significantly reducing the number of render calls.
  */
-  public void setEffectAssociation(int component, int andAssociation, int equAssociation)
-    {
-    if( component>=0 && component<MAX_EFFECT_COMPONENTS )
-      {
-      mAndAssociation[component] = andAssociation;
-      mEquAssociation[component] = equAssociation;
-      }
-    }
+   public void setEffectAssociation(int component, int andAssociation, int equAssociation)
+     {
+     if( component>=0 && component<MAX_EFFECT_COMPONENTS )
+       {
+       if( mJobNode[0]==null )
+         {
+         setEffectAssociationNow(component, andAssociation, equAssociation);
+         }
+       else
+         {
+         mJobNode[0] = DeferredJobs.effectAssoc(this,component,andAssociation,equAssociation);
+         }
+       }
+     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
