commit 22422a76260d4b9d65b5b342c37d1a02757fba89
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Thu Jun 11 16:03:45 2020 +0100

    Initial support for a writing a Mesh to a file and restoring it from a file (new class MeshFile).
    Untested!

diff --git a/src/main/java/org/distorted/library/mesh/MeshBase.java b/src/main/java/org/distorted/library/mesh/MeshBase.java
index 1a94444..f8e63cb 100644
--- a/src/main/java/org/distorted/library/mesh/MeshBase.java
+++ b/src/main/java/org/distorted/library/mesh/MeshBase.java
@@ -30,11 +30,11 @@ import org.distorted.library.main.InternalBuffer;
 import org.distorted.library.program.DistortedProgram;
 import org.distorted.library.type.Static4D;
 
-import java.io.InputStream;
-import java.io.OutputStream;
+import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.FloatBuffer;
+import java.nio.channels.FileChannel;
 import java.util.ArrayList;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -92,6 +92,8 @@ public abstract class MeshBase
    private static int[] mEquAssociationH = new int[EffectQueue.MAIN_VARIANTS];
    private static int[] mAndAssociationH = new int[EffectQueue.MAIN_VARIANTS];
 
+   private static final int TEX_COMP_SIZE = 5; // 5 four-bytes entities inside the component
+
    private static class TexComponent
      {
      private int mEndIndex;
@@ -767,27 +769,139 @@ public abstract class MeshBase
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// PUBLIC API
-///////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * Write tthe Mesh to an OutputStream.
- */
-   public void write(OutputStream stream)
+
+   void read(FileChannel file) throws IOException
      {
+     ByteBuffer buffer = ByteBuffer.allocate(BYTES_PER_FLOAT*4);
+     int version, numVertices=0, numEff=0, numTex=0;
+
+     try
+       {
+       file.read(buffer);
+
+       version = buffer.getInt(0);
+
+       if( version==1 )
+         {
+         numVertices = buffer.getInt(4);
+         numTex      = buffer.getInt(8);
+         numEff      = buffer.getInt(12);
+         }
+       else
+         {
+         android.util.Log.e("mesh", "Error: unknown mesh file version "+version);
+         file.close();
+         return;
+         }
+       }
+     catch(IOException e)
+       {
+       file.close();
+       throw e;
+       }
+
+     if( numVertices>0 && numEff>0 && numTex>0 )
+       {
+       int size = numEff+TEX_COMP_SIZE*numTex;
+       float[] tmp = new float[size];
+       mVertAttribs1 = new float[VERT1_SIZE*mNumVertices];
+       mVertAttribs2 = new float[VERT2_SIZE*mNumVertices];
+
+       buffer = ByteBuffer.allocate(BYTES_PER_FLOAT*size + mNumVertices*(VERT1_SIZE+VERT2_SIZE));
+
+       file.read(buffer);
+
+       buffer.asFloatBuffer().get(tmp,0,size);
+       buffer.asFloatBuffer().get(mVertAttribs1, 0, VERT1_SIZE*mNumVertices);
+       buffer.asFloatBuffer().get(mVertAttribs2, 0, VERT2_SIZE*mNumVertices);
+
+       TexComponent tex;
+       int index, texComp;
+       float x, y, z, w;
+
+       for(texComp=0; texComp<numTex; texComp++)
+         {
+         index = (int)tmp[TEX_COMP_SIZE*texComp];
+
+         x= tmp[TEX_COMP_SIZE*texComp+1];
+         y= tmp[TEX_COMP_SIZE*texComp+2];
+         z= tmp[TEX_COMP_SIZE*texComp+3];
+         w= tmp[TEX_COMP_SIZE*texComp+4];
 
+         tex = new TexComponent(index);
+         tex.setMap(new Static4D(x,y,z,w));
+
+         mTexComponent.add(tex);
+         }
+
+       for(int effComp=0; effComp<numEff; effComp++)
+         {
+         index = (int)tmp[TEX_COMP_SIZE*texComp + effComp ];
+         mEffComponent.add(index);
+         }
+       }
+
+     file.close();
      }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// PUBLIC API
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
- * Read the mesh from an InputStream.
+ * Write the Mesh to a File.
  */
-   public void read(InputStream stream)
+   public void write(FileChannel file) throws IOException
      {
+     TexComponent tex;
+
+     int numTex = mTexComponent.size();
+     int numEff = mEffComponent.size();
 
+     ByteBuffer buffer = ByteBuffer.allocate(BYTES_PER_FLOAT*(numEff+TEX_COMP_SIZE*numTex+4));
+     FloatBuffer buf  = buffer.asFloatBuffer();
+
+     buf.put(1);             // version
+     buf.put(mNumVertices);
+     buf.put(numTex);
+     buf.put(numEff);
+
+     for(int i=0; i<numTex; i++)
+       {
+       tex = mTexComponent.get(i);
+
+       buf.put(tex.mEndIndex);
+       buf.put(tex.mTextureMap.get0());
+       buf.put(tex.mTextureMap.get1());
+       buf.put(tex.mTextureMap.get2());
+       buf.put(tex.mTextureMap.get3());
+       }
+
+     for(int i=0; i<numEff; i++)
+       {
+       buf.put(mEffComponent.get(i));
+       }
+
+     ByteBuffer vertBuf1 = ByteBuffer.allocate(VERT1_SIZE*mNumVertices);
+     vertBuf1.asFloatBuffer().put(mVertAttribs1);
+     ByteBuffer vertBuf2 = ByteBuffer.allocate(VERT2_SIZE*mNumVertices);
+     vertBuf2.asFloatBuffer().put(mVertAttribs2);
+
+     try
+       {
+       file.write(buffer);
+       file.write(vertBuf1);
+       file.write(vertBuf2);
+       }
+     catch(IOException e)
+       {
+       file.close();
+       throw e;
+       }
+
+     file.close();
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-
 /**
  * When rendering this Mesh, do we want to render the Normal vectors as well?
  * <p>
diff --git a/src/main/java/org/distorted/library/mesh/MeshFile.java b/src/main/java/org/distorted/library/mesh/MeshFile.java
new file mode 100644
index 0000000..3993552
--- /dev/null
+++ b/src/main/java/org/distorted/library/mesh/MeshFile.java
@@ -0,0 +1,70 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2020 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.mesh;
+
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+public class MeshFile extends MeshBase
+{
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Read mesh description from a file.
+ * <p>
+ * File format: as written by MeshBase.write().
+ */
+  public MeshFile(FileChannel file)
+    {
+    super();
+
+    try
+      {
+      read(file);
+      }
+    catch(IOException ex)
+      {
+      android.util.Log.e("MeshFile", "exception reading file: "+ex.toString());
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Copy constructor.
+ */
+  public MeshFile(MeshFile mesh, boolean deep)
+   {
+   super(mesh,deep);
+   }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Copy the Mesh.
+ *
+ * @param deep If to be a deep or shallow copy of mVertAttribs1, i.e. the array holding vertices,
+ *             normals and inflates (the rest, in particular the mVertAttribs2 containing texture
+ *             coordinates and effect associations, is always deep copied)
+ */
+  public MeshFile copy(boolean deep)
+   {
+   return new MeshFile(this,deep);
+   }
+}
