commit 22e60fba5e3e733c52cbb75490ba4c0965bc379a
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Wed Mar 4 20:58:36 2020 +0000

    Fix MeshBase.join()
    Only upload Mesh Buffers to GPU when we actually use them.

diff --git a/src/main/java/org/distorted/library/main/InternalBuffer.java b/src/main/java/org/distorted/library/main/InternalBuffer.java
index 4f3a8ca..63b12e1 100644
--- a/src/main/java/org/distorted/library/main/InternalBuffer.java
+++ b/src/main/java/org/distorted/library/main/InternalBuffer.java
@@ -21,6 +21,9 @@ package org.distorted.library.main;
 
 import android.opengl.GLES31;
 import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
@@ -33,7 +36,7 @@ import java.nio.Buffer;
  */
 public class InternalBuffer extends InternalObject
   {
-  public int[] mIndex;
+  public final int[] mIndex;
 
   private int mTarget, mSize, mUsage;
   private Buffer mBuffer;
@@ -54,15 +57,39 @@ public class InternalBuffer extends InternalObject
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// mark for creation only now, when we do have all data ready, in order to avoid the situation
-// when create() would be called before this.
+// must be called from a thread holding OpenGL Context.
 
-  public void setData(int size, Buffer buffer)
+  public void createImmediately(int size, float[] buffer)
     {
-    mSize   = size;
-    mBuffer = buffer;
+    if( mIndex[0]<0 )
+      {
+      mSize= size;
+
+      if( buffer!=null )
+        {
+        FloatBuffer buf = ByteBuffer.allocateDirect(size).order(ByteOrder.nativeOrder()).asFloatBuffer();
+        buf.put(buffer).position(0);
+        mBuffer = buf;
+        }
+      else
+        {
+        mBuffer = null;
+        }
+
+      GLES31.glGenBuffers( 1, mIndex, 0);
+      GLES31.glBindBuffer( mTarget, mIndex[0]);
+      GLES31.glBufferData( mTarget, mSize, mBuffer, mUsage);
+      GLES31.glBindBuffer( mTarget, 0);
 
-    markForCreation();
+      markWasCreatedImmediately();
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  public void invalidate()
+    {
+    recreate();
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/main/InternalObject.java b/src/main/java/org/distorted/library/main/InternalObject.java
index 4708f86..a8570f7 100644
--- a/src/main/java/org/distorted/library/main/InternalObject.java
+++ b/src/main/java/org/distorted/library/main/InternalObject.java
@@ -212,6 +212,13 @@ abstract class InternalObject
     mType= type;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void markWasCreatedImmediately()
+    {
+    mDoneList.add(this);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void markForCreation()
diff --git a/src/main/java/org/distorted/library/mesh/MeshBase.java b/src/main/java/org/distorted/library/mesh/MeshBase.java
index a1dd0b6..90f08ca 100644
--- a/src/main/java/org/distorted/library/mesh/MeshBase.java
+++ b/src/main/java/org/distorted/library/mesh/MeshBase.java
@@ -27,9 +27,6 @@ import org.distorted.library.main.DistortedLibrary;
 import org.distorted.library.main.InternalBuffer;
 import org.distorted.library.program.DistortedProgram;
 
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.FloatBuffer;
 import java.util.ArrayList;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -187,11 +184,8 @@ public abstract class MeshBase
 
      mComponent.add(new Component(mNumVertices));
 
-     FloatBuffer attribs = ByteBuffer.allocateDirect(mNumVertices*VERT_SIZE).order(ByteOrder.nativeOrder()).asFloatBuffer();
-     attribs.put(vertexAttribs).position(0);
-
-     mVBO.setData(mNumVertices*VERT_SIZE, attribs);
-     mTFO.setData(mNumVertices*TRAN_SIZE, null   );
+     mVBO.invalidate();
+     mTFO.invalidate();
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -226,7 +220,10 @@ public abstract class MeshBase
          }
 
        num = mesh.mNumVertices;
-       mNumVertices+= (i<len-1 ? ( num%2==1 ? num+2 : num+1 ) : num);
+
+       if( mNumVertices==0 ) mNumVertices += (num%2==1 ? num+2 : num+1);
+       else if( i==len-1 )   mNumVertices += (num+1);
+       else                  mNumVertices += (num%2==1 ? num+3 : num+2);
        }
 
      // allocate new attrib array
@@ -251,8 +248,11 @@ public abstract class MeshBase
        mesh = meshes[i];
        num = mesh.mNumVertices;
 
-       System.arraycopy(mesh.mVertAttribs, 0, newAttribs, VERT_ATTRIBS*origVertices, VERT_ATTRIBS    );
-       origVertices++;
+       if( origVertices>0 )
+         {
+         System.arraycopy(mesh.mVertAttribs, 0, newAttribs, VERT_ATTRIBS*origVertices, VERT_ATTRIBS    );
+         origVertices++;
+         }
        System.arraycopy(mesh.mVertAttribs, 0, newAttribs, VERT_ATTRIBS*origVertices, VERT_ATTRIBS*num);
        origVertices+=num;
 
@@ -276,11 +276,7 @@ public abstract class MeshBase
 
      mVertAttribs = newAttribs;
 
-     FloatBuffer attribs = ByteBuffer.allocateDirect(mNumVertices*VERT_SIZE).order(ByteOrder.nativeOrder()).asFloatBuffer();
-     attribs.put(mVertAttribs).position(0);
-
-     mVBO.setData(mNumVertices*VERT_SIZE, attribs);
-     mTFO.setData(mNumVertices*TRAN_SIZE, null   );
+     mVBO.invalidate();
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -313,6 +309,8 @@ public abstract class MeshBase
  */
    public void bindVertexAttribs(DistortedProgram program)
      {
+     mVBO.createImmediately(mNumVertices*VERT_SIZE, mVertAttribs);
+
      GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, mVBO.mIndex[0] );
      GLES31.glVertexAttribPointer(program.mAttribute[0], POS_DATA_SIZE, GLES31.GL_FLOAT, false, VERT_SIZE, OFFSET_POS);
      GLES31.glVertexAttribPointer(program.mAttribute[1], NOR_DATA_SIZE, GLES31.GL_FLOAT, false, VERT_SIZE, OFFSET_NOR);
@@ -329,6 +327,8 @@ public abstract class MeshBase
  */
    public void bindTransformAttribs(DistortedProgram program)
      {
+     mTFO.createImmediately(mNumVertices*TRAN_SIZE, null);
+
      GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, mTFO.mIndex[0] );
      GLES31.glVertexAttribPointer(program.mAttribute[0], POS_DATA_SIZE, GLES31.GL_FLOAT, false, 0, 0);
      GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, 0);
@@ -456,11 +456,7 @@ public abstract class MeshBase
          }
        }
 
-     FloatBuffer attribs = ByteBuffer.allocateDirect(mNumVertices*VERT_SIZE).order(ByteOrder.nativeOrder()).asFloatBuffer();
-     attribs.put(mVertAttribs).position(0);
-
-     mVBO.setData(mNumVertices*VERT_SIZE, attribs);
-     mTFO.setData(mNumVertices*TRAN_SIZE, null   );
+     mTFO.invalidate();
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -493,11 +489,7 @@ public abstract class MeshBase
          }
        }
 
-     FloatBuffer attribs = ByteBuffer.allocateDirect(mNumVertices*VERT_SIZE).order(ByteOrder.nativeOrder()).asFloatBuffer();
-     attribs.put(mVertAttribs).position(0);
-
-     mVBO.setData(mNumVertices*VERT_SIZE, attribs);
-     mTFO.setData(mNumVertices*TRAN_SIZE, null   );
+     mTFO.invalidate();
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
