commit 1fad573edbd15d2df37ee37b0ce8a41667cb8f72
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Mon Jun 1 23:40:46 2020 +0100

    DeferredJobs app/lib works now

diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueue.java b/src/main/java/org/distorted/library/effectqueue/EffectQueue.java
index abfc45f..608fca6 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueue.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueue.java
@@ -398,6 +398,13 @@ public abstract class EffectQueue implements InternalMaster.Slave
     return mNumEffects;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public int getNumEffectsToBe()
+    {
+    return mNumEffectsToBe;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public Effect getEffect(int position)
diff --git a/src/main/java/org/distorted/library/mesh/DeferredJobs.java b/src/main/java/org/distorted/library/mesh/DeferredJobs.java
index de40a97..50f539b 100644
--- a/src/main/java/org/distorted/library/mesh/DeferredJobs.java
+++ b/src/main/java/org/distorted/library/mesh/DeferredJobs.java
@@ -22,9 +22,12 @@ package org.distorted.library.mesh;
 import org.distorted.library.effect.VertexEffect;
 import org.distorted.library.effectqueue.EffectQueueVertex;
 import org.distorted.library.main.DistortedLibrary;
+import org.distorted.library.type.Static4D;
 
 import java.util.ArrayList;
 
+import android.util.Log;
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Not part of public API, do not document (public only because has to be cleaned from the main package)
@@ -37,6 +40,7 @@ public class DeferredJobs
   private static final int JOB_TYPE_MERGE  = 1;
   private static final int JOB_TYPE_JOIN   = 2;
   private static final int JOB_TYPE_COPY   = 3;
+  private static final int JOB_TYPE_TEXTURE= 4;
 
   private static ArrayList<JobNode> mJobs = new ArrayList<>();
 
@@ -45,17 +49,17 @@ public class DeferredJobs
   private static class Job
     {
     private int mType;
-    private int mArg;
     private MeshBase mTarget;
     private MeshBase[] mSource;
     private EffectQueueVertex mEffects;
+    private Static4D[] mMaps;
 
-    Job(int type, MeshBase target, MeshBase[] source, VertexEffect effect, int arg)
+    Job(int type, MeshBase target, MeshBase[] source, VertexEffect effect, Static4D[] maps)
       {
       mType   = type;
       mTarget = target;
       mSource = source;
-      mArg    = arg;
+      mMaps   = maps;
 
       if( effect!=null )
         {
@@ -73,14 +77,26 @@ public class DeferredJobs
       {
       switch(mType)
         {
-        case JOB_TYPE_VERTEX: DistortedLibrary.adjustVertices(mTarget, mEffects);
-                              break;
-        case JOB_TYPE_MERGE : mTarget.merge();
-                              break;
-        case JOB_TYPE_JOIN  : mTarget.joinAttrib1(mSource,mArg);
-                              break;
-        case JOB_TYPE_COPY  : mTarget.deepCopyAttribs1(mSource[0]);
-                              break;
+        case JOB_TYPE_VERTEX : DistortedLibrary.adjustVertices(mTarget, mEffects);
+                               //Log.e("jobs", "executing vertex job");
+                               //mTarget.print();
+                               break;
+        case JOB_TYPE_MERGE  : mTarget.merge();
+                               //Log.e("jobs", "executing merge job");
+                               //mTarget.print();
+                               break;
+        case JOB_TYPE_JOIN   : mTarget.joinAttribs(mSource);
+                               //Log.e("jobs", "executing join job");
+                               //mTarget.print();
+                               break;
+        case JOB_TYPE_COPY   : mTarget.copy(mSource[0]);
+                               //Log.e("jobs", "executing copy job");
+                               //mTarget.print();
+                               break;
+        case JOB_TYPE_TEXTURE: mTarget.textureMap(mMaps);
+                               //Log.e("jobs", "executing textureMap job");
+                               //mTarget.print();
+                               break;
         }
       }
 
@@ -88,6 +104,20 @@ public class DeferredJobs
       {
       if( mEffects!=null ) mEffects.removeAll(false);
       }
+
+    String print()
+      {
+      switch(mType)
+        {
+        case JOB_TYPE_VERTEX : return "VERTEX (eff: "+mEffects.getNumEffects()+" effToBe: "+mEffects.getNumEffectsToBe()+")";
+        case JOB_TYPE_MERGE  : return "MERGE";
+        case JOB_TYPE_JOIN   : return "JOIN: "+mSource.length;
+        case JOB_TYPE_COPY   : return "COPY";
+        case JOB_TYPE_TEXTURE: return "TEXTURE";
+        }
+
+      return null;
+      }
     }
 
   //////////////////////////////////////////////////////////////////////////
@@ -112,7 +142,7 @@ public class DeferredJobs
 
       for(int i=0; i<numPrev; i++)
         {
-        node = mPrevJobs.get(i);
+        node = mPrevJobs.get(0);  // removeNode() rips the executed job out, thus the 0
         node.execute();
         }
 
@@ -130,6 +160,27 @@ public class DeferredJobs
       mJob.clear();
       mJob = null;
       }
+
+    void print(int level)
+      {
+      int numPrev = mPrevJobs.size();
+      int numNext = mNextJobs.size();
+
+      String str = "";
+      for(int i=0; i<level; i++) str+=" ";
+
+      str += mJob.print();
+
+      str += (" next: "+numNext+" prev: "+numPrev);
+
+      Log.e("job", str);
+
+      for(int i=0; i<numPrev; i++)
+        {
+        JobNode node = mPrevJobs.get(i);
+        node.print(level+1);
+        }
+      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -166,7 +217,7 @@ public class DeferredJobs
 
     if( jn==null )
       {
-      Job job = new Job(JOB_TYPE_VERTEX,target,null,effect,0);
+      Job job = new Job(JOB_TYPE_VERTEX,target,null,effect,null);
       JobNode node = new JobNode(job);
       mJobs.add(node);
       return node;
@@ -180,7 +231,7 @@ public class DeferredJobs
         }
       else
         {
-        Job job = new Job(JOB_TYPE_VERTEX,target,null,effect,0);
+        Job job = new Job(JOB_TYPE_VERTEX,target,null,effect,null);
         JobNode node = new JobNode(job);
         node.mPrevJobs.add(jn);
         jn.mNextJobs.add(node);
@@ -195,7 +246,7 @@ public class DeferredJobs
   static JobNode merge(MeshBase target)
     {
     JobNode jn = target.mJobNode[0];
-    Job job = new Job(JOB_TYPE_MERGE,target,null,null,0);
+    Job job = new Job(JOB_TYPE_MERGE,target,null,null,null);
     JobNode node = new JobNode(job);
     node.mPrevJobs.add(jn);
     jn.mNextJobs.add(node);
@@ -205,18 +256,22 @@ public class DeferredJobs
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  static JobNode join(MeshBase target, MeshBase[] meshes, int origVertices)
+  static JobNode join(MeshBase target, MeshBase[] meshes)
     {
     JobNode jn;
 
-    Job job = new Job(JOB_TYPE_JOIN,target,meshes,null,origVertices);
+    Job job = new Job(JOB_TYPE_JOIN,target,meshes,null,null);
     JobNode node = new JobNode(job);
 
     for (MeshBase mesh : meshes)
       {
       jn = mesh.mJobNode[0];
-      node.mPrevJobs.add(jn);
-      jn.mNextJobs.add(node);
+
+      if( jn!=null )
+        {
+        node.mPrevJobs.add(jn);
+        jn.mNextJobs.add(node);
+        }
       }
 
     mJobs.add(node);
@@ -230,7 +285,20 @@ 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,0);
+    Job job = new Job(JOB_TYPE_COPY,target,meshes,null,null);
+    JobNode node = new JobNode(job);
+    node.mPrevJobs.add(jn);
+    jn.mNextJobs.add(node);
+    mJobs.add(node);
+    return node;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  static JobNode textureMap(MeshBase target, Static4D[] maps)
+    {
+    JobNode jn = target.mJobNode[0];
+    Job job = new Job(JOB_TYPE_TEXTURE,target,null,null,maps);
     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 8d1244b..3fd55a4 100644
--- a/src/main/java/org/distorted/library/mesh/MeshBase.java
+++ b/src/main/java/org/distorted/library/mesh/MeshBase.java
@@ -138,74 +138,60 @@ public abstract class MeshBase
 
    MeshBase(MeshBase original, boolean deep)
      {
-     mShowNormals     = original.mShowNormals;
-     mInflate         = original.mInflate;
-     mNumVertices     = original.mNumVertices;
-
-     int size = original.mComponent.size();
-     mComponent = new ArrayList<>();
-
-     for(int i=0; i<size; i++)
-       {
-       Component comp = new Component(original.mComponent.get(i));
-       mComponent.add(comp);
-       }
+     mShowNormals= original.mShowNormals;
+     mInflate    = original.mInflate;
+     mNumVertices= original.mNumVertices;
 
      mAssociation= new int[MAX_COMPONENTS];
      System.arraycopy(original.mAssociation, 0, mAssociation, 0, MAX_COMPONENTS);
 
      if( deep )
        {
-       mVBO1= new InternalBuffer(GLES30.GL_ARRAY_BUFFER, GLES30.GL_STATIC_READ);
-       mVertAttribs1= new float[mNumVertices*VERT1_ATTRIBS];
-
        mJobNode = new DeferredJobs.JobNode[1];
-
-       if( original.mJobNode[0]!=null )
-         {
-         mJobNode[0] = DeferredJobs.copy(this,original);
-         }
-       else
-         {
-         deepCopyAttribs1(original);
-         }
+       if( original.mJobNode[0]==null ) copy(original);
+       else mJobNode[0] = DeferredJobs.copy(this,original);
        }
      else
        {
        mJobNode      = original.mJobNode;
        mVBO1         = original.mVBO1;
        mVertAttribs1 = original.mVertAttribs1;
+       shallowCopy(original);
        }
 
-     mVBO2= new InternalBuffer(GLES30.GL_ARRAY_BUFFER, GLES30.GL_STATIC_READ);
-     mVertAttribs2= new float[mNumVertices*VERT2_ATTRIBS];
-     System.arraycopy(original.mVertAttribs2,0,mVertAttribs2,0,mNumVertices*VERT2_ATTRIBS);
-     mVBO2.invalidate();
-
      mTFO = new InternalBuffer(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, GLES30.GL_STATIC_READ);
      mTFO.invalidate();
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-   public static int getMaxComponents()
+   void copy(MeshBase original)
      {
-     return MAX_COMPONENTS;
+     shallowCopy(original);
+
+     mVBO1= new InternalBuffer(GLES30.GL_ARRAY_BUFFER, GLES30.GL_STATIC_READ);
+     mVertAttribs1= new float[mNumVertices*VERT1_ATTRIBS];
+     System.arraycopy(original.mVertAttribs1,0,mVertAttribs1,0,mNumVertices*VERT1_ATTRIBS);
+     mVBO1.invalidate();
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-   public static void getUniforms(int mProgramH, int variant)
+   private void shallowCopy(MeshBase original)
      {
-     mComponentAssociationH[variant] = GLES30.glGetUniformLocation( mProgramH, "vComponAssoc");
-     }
+     int size = original.mComponent.size();
+     mComponent = new ArrayList<>();
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
+     for(int i=0; i<size; i++)
+       {
+       Component comp = new Component(original.mComponent.get(i));
+       mComponent.add(comp);
+       }
 
-   void deepCopyAttribs1(MeshBase original)
-     {
-     System.arraycopy(original.mVertAttribs1,0,mVertAttribs1,0,mNumVertices*VERT1_ATTRIBS);
-     mVBO1.invalidate();
+     mVBO2= new InternalBuffer(GLES30.GL_ARRAY_BUFFER, GLES30.GL_STATIC_READ);
+     mVertAttribs2= new float[mNumVertices*VERT2_ATTRIBS];
+     System.arraycopy(original.mVertAttribs2,0,mVertAttribs2,0,mNumVertices*VERT2_ATTRIBS);
+     mVBO2.invalidate();
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -252,75 +238,61 @@ public abstract class MeshBase
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-   void joinAttrib1(MeshBase[] meshes, int origVertices)
+   void joinAttribs(MeshBase[] meshes)
      {
      MeshBase mesh;
+     Component comp;
      int numMeshes = meshes.length;
-     int numVertices = origVertices;
-
-     float[] newAttribs1 = new float[VERT1_ATTRIBS*mNumVertices];
+     int origVertices = mNumVertices;
+     int origComponents=0,numComponents,numVertices;
 
      if( origVertices>0 )
        {
-       System.arraycopy(mVertAttribs1,                              0, newAttribs1,                         0, VERT1_ATTRIBS*numVertices);
-       System.arraycopy(mVertAttribs1, VERT1_ATTRIBS*(origVertices-1), newAttribs1, VERT1_ATTRIBS*origVertices, VERT1_ATTRIBS    );
-       origVertices++;
-
-       if( numVertices%2==1 )
-         {
-         System.arraycopy(mVertAttribs1, VERT1_ATTRIBS*(origVertices-1), newAttribs1, VERT1_ATTRIBS*origVertices, VERT1_ATTRIBS);
-         origVertices++;
-         }
+       origComponents = mComponent.size();
+       mNumVertices+= ( mNumVertices%2==1 ? 2:1 );
+       mComponent.get(origComponents-1).mEndIndex = mNumVertices-1;
        }
 
      for(int i=0; i<numMeshes; i++)
        {
        mesh = meshes[i];
+       numComponents = mesh.mComponent.size();
        numVertices = mesh.mNumVertices;
 
-       if( origVertices>0 )
-         {
-         System.arraycopy(mesh.mVertAttribs1, 0, newAttribs1, VERT1_ATTRIBS*origVertices, VERT1_ATTRIBS    );
-         origVertices++;
-         }
-       System.arraycopy(mesh.mVertAttribs1, 0, newAttribs1, VERT1_ATTRIBS*origVertices, VERT1_ATTRIBS*numVertices);
-       origVertices+=numVertices;
+       int extraVerticesBefore = mNumVertices==0 ? 0:1;
+       int extraVerticesAfter  = (i==numMeshes-1) ? 0 : (numVertices%2==1 ? 2:1);
 
-       if( i<numMeshes-1 )
+       for(int j=0; j<numComponents; j++)
          {
-         System.arraycopy(mesh.mVertAttribs1, VERT1_ATTRIBS*(numVertices-1), newAttribs1, VERT1_ATTRIBS*origVertices, VERT1_ATTRIBS);
-         origVertices++;
+         comp = new Component(mesh.mComponent.get(j));
+         comp.mEndIndex += (extraVerticesBefore+mNumVertices+extraVerticesAfter);
+         mComponent.add(comp);
 
-         if( numVertices%2==1 )
+         if( origComponents<MAX_COMPONENTS )
            {
-           System.arraycopy(mesh.mVertAttribs1, VERT1_ATTRIBS*(numVertices-1), newAttribs1, VERT1_ATTRIBS*origVertices, VERT1_ATTRIBS);
-           origVertices++;
+           mAssociation[origComponents] = mesh.mAssociation[j];
+           origComponents++;
            }
          }
-       }
-
-     mVertAttribs1 = newAttribs1;
-     mVBO1.invalidate();
-     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-   private void joinAttrib2(MeshBase[] meshes, int origVertices)
-     {
-     MeshBase mesh;
-     int numMeshes = meshes.length;
-     int numVertices = origVertices;
+       mNumVertices += (extraVerticesBefore+numVertices+extraVerticesAfter);
+       }
 
+     float[] newAttribs1 = new float[VERT1_ATTRIBS*mNumVertices];
      float[] newAttribs2 = new float[VERT2_ATTRIBS*mNumVertices];
+     numVertices = origVertices;
 
      if( origVertices>0 )
        {
+       System.arraycopy(mVertAttribs1,                              0, newAttribs1,                         0, VERT1_ATTRIBS*numVertices);
+       System.arraycopy(mVertAttribs1, VERT1_ATTRIBS*(origVertices-1), newAttribs1, VERT1_ATTRIBS*origVertices, VERT1_ATTRIBS    );
        System.arraycopy(mVertAttribs2,                              0, newAttribs2,                         0, VERT2_ATTRIBS*numVertices);
        System.arraycopy(mVertAttribs2, VERT2_ATTRIBS*(origVertices-1), newAttribs2, VERT2_ATTRIBS*origVertices, VERT2_ATTRIBS    );
        origVertices++;
 
        if( numVertices%2==1 )
          {
+         System.arraycopy(mVertAttribs1, VERT1_ATTRIBS*(origVertices-1), newAttribs1, VERT1_ATTRIBS*origVertices, VERT1_ATTRIBS);
          System.arraycopy(mVertAttribs2, VERT2_ATTRIBS*(origVertices-1), newAttribs2, VERT2_ATTRIBS*origVertices, VERT2_ATTRIBS);
          origVertices++;
          }
@@ -333,19 +305,23 @@ public abstract class MeshBase
 
        if( origVertices>0 )
          {
+         System.arraycopy(mesh.mVertAttribs1, 0, newAttribs1, VERT1_ATTRIBS*origVertices, VERT1_ATTRIBS    );
          System.arraycopy(mesh.mVertAttribs2, 0, newAttribs2, VERT2_ATTRIBS*origVertices, VERT2_ATTRIBS    );
          origVertices++;
          }
+       System.arraycopy(mesh.mVertAttribs1, 0, newAttribs1, VERT1_ATTRIBS*origVertices, VERT1_ATTRIBS*numVertices);
        System.arraycopy(mesh.mVertAttribs2, 0, newAttribs2, VERT2_ATTRIBS*origVertices, VERT2_ATTRIBS*numVertices);
        origVertices+=numVertices;
 
        if( i<numMeshes-1 )
          {
+         System.arraycopy(mesh.mVertAttribs1, VERT1_ATTRIBS*(numVertices-1), newAttribs1, VERT1_ATTRIBS*origVertices, VERT1_ATTRIBS);
          System.arraycopy(mesh.mVertAttribs2, VERT2_ATTRIBS*(numVertices-1), newAttribs2, VERT2_ATTRIBS*origVertices, VERT2_ATTRIBS);
          origVertices++;
 
          if( numVertices%2==1 )
            {
+           System.arraycopy(mesh.mVertAttribs1, VERT1_ATTRIBS*(numVertices-1), newAttribs1, VERT1_ATTRIBS*origVertices, VERT1_ATTRIBS);
            System.arraycopy(mesh.mVertAttribs2, VERT2_ATTRIBS*(numVertices-1), newAttribs2, VERT2_ATTRIBS*origVertices, VERT2_ATTRIBS);
            origVertices++;
            }
@@ -366,7 +342,9 @@ public abstract class MeshBase
        for( ; index<=endIndex; index++) newAttribs2[VERT2_ATTRIBS*index+COM_ATTRIB] = component;
        }
 
+     mVertAttribs1 = newAttribs1;
      mVertAttribs2 = newAttribs2;
+     mVBO1.invalidate();
      mVBO2.invalidate();
      }
 
@@ -375,54 +353,78 @@ public abstract class MeshBase
 
    void join(MeshBase[] meshes)
      {
-     MeshBase mesh;
-     Component comp;
-     int origComponents=0, numComponents, numVertices, numMeshes = meshes.length;
-     int origVertices = mNumVertices;
+     boolean immediateJoin = true;
 
-     if( origVertices>0 )
+     for (MeshBase mesh : meshes)
        {
-       origComponents = mComponent.size();
-       mNumVertices+= ( mNumVertices%2==1 ? 2:1 );
-       mComponent.get(origComponents-1).mEndIndex = mNumVertices-1;
+       if (mesh.mJobNode[0] != null)
+         {
+         immediateJoin = false;
+         break;
+         }
        }
 
-     for(int i=0; i<numMeshes; i++)
-       {
-       mesh = meshes[i];
-       numComponents = mesh.mComponent.size();
+     if( immediateJoin ) joinAttribs(meshes);
+     else                mJobNode[0] = DeferredJobs.join(this,meshes);
+     }
 
-       numVertices = mesh.mNumVertices;
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
-       int extraVerticesBefore = mNumVertices==0 ? 0:1;
-       int extraVerticesAfter  = (i==numMeshes-1) ? 0 : (numVertices%2==1 ? 2:1);
+   void textureMap(Static4D[] maps)
+     {
+     int num_comp = mComponent.size();
+     int num_maps = maps.length;
+     int min = Math.min(num_comp, num_maps);
+     int vertex = 0;
+     Static4D newMap, oldMap;
+     Component comp;
+     float newW, newH, ratW, ratH, movX, movY;
 
-       for(int j=0; j<numComponents; j++)
+     for(int i=0; i<min; i++)
+       {
+       newMap = maps[i];
+       comp = mComponent.get(i);
+
+       if( newMap!=null )
          {
-         comp = new Component(mesh.mComponent.get(j));
-         comp.mEndIndex += (extraVerticesBefore+mNumVertices+extraVerticesAfter);
-         mComponent.add(comp);
+         newW = newMap.get2();
+         newH = newMap.get3();
 
-         if( origComponents<MAX_COMPONENTS )
+         if( newW!=0.0f && newH!=0.0f )
            {
-           mAssociation[origComponents] = mesh.mAssociation[j];
-           origComponents++;
+           oldMap = comp.mTextureMap;
+           ratW = newW/oldMap.get2();
+           ratH = newH/oldMap.get3();
+           movX = newMap.get0() - ratW*oldMap.get0();
+           movY = newMap.get1() - ratH*oldMap.get1();
+
+           for( int index=vertex*VERT2_ATTRIBS+TEX_ATTRIB ; vertex<=comp.mEndIndex; vertex++, index+=VERT2_ATTRIBS)
+             {
+             mVertAttribs2[index  ] = ratW*mVertAttribs2[index  ] + movX;
+             mVertAttribs2[index+1] = ratH*mVertAttribs2[index+1] + movY;
+             }
+           comp.setMap(newMap);
            }
          }
 
-       mNumVertices += (extraVerticesBefore+numVertices+extraVerticesAfter);
+       vertex= comp.mEndIndex+1;
        }
 
-     if( mJobNode[0]!=null )
-       {
-       mJobNode[0] = DeferredJobs.join(this,meshes,origVertices);
-       }
-     else
-       {
-       joinAttrib1(meshes,origVertices);
-       }
+     mVBO2.invalidate();
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
 
-     joinAttrib2(meshes,origVertices);
+   public static int getMaxComponents()
+     {
+     return MAX_COMPONENTS;
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+   public static void getUniforms(int mProgramH, int variant)
+     {
+     mComponentAssociationH[variant] = GLES30.glGetUniformLocation( mProgramH, "vComponAssoc");
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -450,6 +452,56 @@ public abstract class MeshBase
      GLES30.glUnmapBuffer(GLES30.GL_TRANSFORM_FEEDBACK);
      }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Not part of public API, do not document (public only because has to be used from the main package)
+ *
+ * @y.exclude
+ */
+   public void debug()
+     {
+     if( mJobNode[0]!=null )
+       {
+       mJobNode[0].print(0);
+       }
+     else
+       {
+       android.util.Log.e("mesh", "JobNode null");
+       }
+     }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Not part of public API, do not document (public only because has to be used from the main package)
+ *
+ * @y.exclude
+ */
+   public void print()
+     {
+     StringBuffer sb = new StringBuffer();
+
+     for(int i=0; i<mNumVertices; i++)
+       {
+       sb.append('(');
+       sb.append(mVertAttribs1[VERT1_ATTRIBS*i+POS_ATTRIB  ]);
+       sb.append(',');
+       sb.append(mVertAttribs1[VERT1_ATTRIBS*i+POS_ATTRIB+1]);
+       sb.append(',');
+       sb.append(mVertAttribs1[VERT1_ATTRIBS*i+POS_ATTRIB+2]);
+       sb.append(") ");
+       }
+
+     StringBuffer sb2 = new StringBuffer();
+
+     for(int i=0; i<mNumVertices; i++)
+       {
+       sb2.append(mVertAttribs2[VERT2_ATTRIBS*i+COM_ATTRIB]);
+       sb2.append(' ');
+       }
+
+     Log.d("mesh", sb.toString()+"\n"+sb2.toString());
+     }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Not part of public API, do not document (public only because has to be used from the main package)
@@ -578,7 +630,7 @@ public abstract class MeshBase
  */
    public void mergeComponents()
      {
-     if( mJobNode==null )
+     if( mJobNode[0]==null )
        {
        merge();
        }
@@ -643,45 +695,14 @@ public abstract class MeshBase
  */
    public void setTextureMap(Static4D[] maps)
      {
-     int num_comp = mComponent.size();
-     int num_maps = maps.length;
-     int min = Math.min(num_comp, num_maps);
-     int vertex = 0;
-     Static4D newMap, oldMap;
-     Component comp;
-     float newW, newH, ratW, ratH, movX, movY;
-
-     for(int i=0; i<min; i++)
+     if( mJobNode[0]==null )
        {
-       newMap = maps[i];
-       comp = mComponent.get(i);
-
-       if( newMap!=null )
-         {
-         newW = newMap.get2();
-         newH = newMap.get3();
-
-         if( newW!=0.0f && newH!=0.0f )
-           {
-           oldMap = comp.mTextureMap;
-           ratW = newW/oldMap.get2();
-           ratH = newH/oldMap.get3();
-           movX = newMap.get0() - ratW*oldMap.get0();
-           movY = newMap.get1() - ratH*oldMap.get1();
-
-           for( int index=vertex*VERT2_ATTRIBS+TEX_ATTRIB ; vertex<=comp.mEndIndex; vertex++, index+=VERT2_ATTRIBS)
-             {
-             mVertAttribs2[index  ] = ratW*mVertAttribs2[index  ] + movX;
-             mVertAttribs2[index+1] = ratH*mVertAttribs2[index+1] + movY;
-             }
-           comp.setMap(newMap);
-           }
-         }
-
-       vertex= comp.mEndIndex+1;
+       textureMap(maps);
+       }
+     else
+       {
+       mJobNode[0] = DeferredJobs.textureMap(this,maps);
        }
-
-     mVBO2.invalidate();
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
