commit 91cfe4621b3f7c9e0518890ae9a654a83d6b7cbc
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Thu Mar 14 15:25:50 2019 +0000

    1) new 'Rubik' app (skeleton)
    2) MeshCubes: add support for custom texture mappings on each side (Rubik needs that!)

diff --git a/src/main/java/org/distorted/library/mesh/MeshCubes.java b/src/main/java/org/distorted/library/mesh/MeshCubes.java
index 0bf90ac..7d66168 100644
--- a/src/main/java/org/distorted/library/mesh/MeshCubes.java
+++ b/src/main/java/org/distorted/library/mesh/MeshCubes.java
@@ -19,18 +19,27 @@
 
 package org.distorted.library.mesh;
 
+import org.distorted.library.type.Static4D;
+
 import java.util.ArrayList;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Create a 3D grid composed of Cubes.
  * <p>
- * Any subset of a MxNx1 cuboid is possible.
+ * Any subset of a MxNx1 cuboid is possible. (repeated arbitrary number of times into Z-dir)
  */
 public class MeshCubes extends MeshBase
    {
    private static final float R = 0.0f;//0.2f;
 
+   private static final int FRONT = 0;
+   private static final int BACK  = 1;
+   private static final int LEFT  = 2;
+   private static final int RIGHT = 3;
+   private static final int TOP   = 4;
+   private static final int BOTTOM= 5;
+
    private static final int NORTH = 0;
    private static final int WEST  = 1;
    private static final int EAST  = 2;
@@ -53,7 +62,9 @@ public class MeshCubes extends MeshBase
        col = c;
        }
      }
-   
+
+   private float[] mTexMappingX,mTexMappingY, mTexMappingW, mTexMappingH;
+
    private int mCols, mRows, mSlices;
    private int[][] mCubes;
    private byte[][] mInflateX, mInflateY;
@@ -74,6 +85,53 @@ public class MeshCubes extends MeshBase
      return ( (2*row<mRows)^(2*col<mCols) );
      }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// fill per-side texture mappings. Default: all 6 sides map to the whole texture.
+// Each Static4D describes the way its side will map. Format:
+//
+// 1st float: X-coord of the texture point that our top-left corner of the side maps to
+// 2nd float: Y-coord of the texture point that our top-left corner of the side maps to
+// 3rd float: X-coord of the texture point that our bot-right corner of the side maps to
+// 4th float: Y-coord of the texture point that our bot-right corner of the side maps to
+
+   private void fillTexMappings(Static4D front, Static4D back, Static4D left, Static4D right, Static4D top, Static4D bottom)
+     {
+     if( mTexMappingX==null ) mTexMappingX = new float[6];
+     if( mTexMappingY==null ) mTexMappingY = new float[6];
+     if( mTexMappingW==null ) mTexMappingW = new float[6];
+     if( mTexMappingH==null ) mTexMappingH = new float[6];
+
+     mTexMappingX[FRONT]  = front.get1();
+     mTexMappingY[FRONT]  = front.get2();
+     mTexMappingW[FRONT]  = front.get3() - front.get1();
+     mTexMappingH[FRONT]  = front.get4() - front.get2();
+
+     mTexMappingX[BACK]   = back.get1();
+     mTexMappingY[BACK]   = back.get2();
+     mTexMappingW[BACK]   = back.get3() - back.get1();
+     mTexMappingH[BACK]   = back.get4() - back.get2();
+
+     mTexMappingX[LEFT]   = left.get1();
+     mTexMappingY[LEFT]   = left.get2();
+     mTexMappingW[LEFT]   = left.get3() - left.get1();
+     mTexMappingH[LEFT]   = left.get4() - left.get2();
+
+     mTexMappingX[RIGHT]  = right.get1();
+     mTexMappingY[RIGHT]  = right.get2();
+     mTexMappingW[RIGHT]  = right.get3() - right.get1();
+     mTexMappingH[RIGHT]  = right.get4() - right.get2();
+
+     mTexMappingX[TOP]    = top.get1();
+     mTexMappingY[TOP]    = top.get2();
+     mTexMappingW[TOP]    = top.get3() - top.get1();
+     mTexMappingH[TOP]    = top.get4() - top.get2();
+
+     mTexMappingX[BOTTOM] = bottom.get1();
+     mTexMappingY[BOTTOM] = bottom.get2();
+     mTexMappingW[BOTTOM] = bottom.get3() - bottom.get1();
+     mTexMappingH[BOTTOM] = bottom.get4() - bottom.get2();
+     }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // return the number of vertices our grid will contain
 
@@ -126,7 +184,7 @@ public class MeshCubes extends MeshBase
      }
 */
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-
+/*
    private static String debug(float[] val, int stop)
      {
      String ret="";
@@ -156,7 +214,7 @@ public class MeshCubes extends MeshBase
 
      return ret;
      }
-
+*/
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /*
    private static String debug(Edge e)
@@ -251,23 +309,23 @@ public class MeshCubes extends MeshBase
 //   
 // This function also creates a list of 'Edges'. Each Edge is a data structure from which later on we
 // will start building the side walls of each connected block of land (and sides of holes of water
-// inside). Each Edge needs to point from Land to Water (thus the '(SOUTH,i-1,j)' below) - otherwise
+// inside). Each Edge needs to point from Land to Water (thus the '(SOUTH,row-1,col)' below) - otherwise
 // later on setting up normal vectors wouldn't work.
    
   private void markRegions()
      {
-     int i, j, numWater=1, numLand=0;
+     int row, col, numWater=1, numLand=0;
      
-     for(i=0; i<mRows;i++) if( mCubes[      i][      0]==0 ) markRegion((short)2,      i,       0);
-     for(i=0; i<mRows;i++) if( mCubes[      i][mCols-1]==0 ) markRegion((short)2,      i, mCols-1);
-     for(i=0; i<mCols;i++) if( mCubes[0      ][      i]==0 ) markRegion((short)2,      0,       i);
-     for(i=0; i<mCols;i++) if( mCubes[mRows-1][      i]==0 ) markRegion((short)2,mRows-1,       i);
+     for(row=0; row<mRows; row++) if( mCubes[    row][      0]==0 ) markRegion((short)2,    row,       0);
+     for(row=0; row<mRows; row++) if( mCubes[    row][mCols-1]==0 ) markRegion((short)2,    row, mCols-1);
+     for(col=0; col<mCols; col++) if( mCubes[0      ][    col]==0 ) markRegion((short)2,      0,     col);
+     for(col=0; col<mCols; col++) if( mCubes[mRows-1][    col]==0 ) markRegion((short)2,mRows-1,     col);
            
-     for(i=0; i<mRows; i++)
-        for(j=0; j<mCols; j++)
+     for(row=0; row<mRows; row++)
+        for(col=0; col<mCols; col++)
            {
-           if( mCubes[i][j] == 0 ) { numWater++; markRegion( (short)(2*numWater ),i,j); mEdges.add(new Edge(SOUTH,i-1,j)); }
-           if( mCubes[i][j] == 1 ) { numLand ++; markRegion( (short)(2*numLand+1),i,j); mEdges.add(new Edge(NORTH,i  ,j)); }
+           if( mCubes[row][col] == 0 ) { numWater++; markRegion( (short)(2*numWater ),row,col); mEdges.add(new Edge(SOUTH,row-1,col)); }
+           if( mCubes[row][col] == 1 ) { numLand ++; markRegion( (short)(2*numLand+1),row,col); mEdges.add(new Edge(NORTH,row  ,col)); }
            }
      
      // now we potentially need to kick out some Edges . Otherwise the following does not work:
@@ -280,9 +338,9 @@ public class MeshCubes extends MeshBase
      int initCol, initRow, initSide, lastSide;
      Edge e1,e2;
      
-     for(i=0; i<mEdgeNum; i++)
+     for(int edge=0; edge<mEdgeNum; edge++)
        {
-       e1 = mEdges.get(i);
+       e1 = mEdges.get(edge);
        initRow= e1.row;
        initCol= e1.col;
        initSide=e1.side;
@@ -295,7 +353,7 @@ public class MeshCubes extends MeshBase
 
          if( e1.side==NORTH || e1.side==SOUTH )
            {
-           for(j=i+1;j<mEdgeNum;j++)
+           for(int j=edge+1;j<mEdgeNum;j++)
              {
              e2 = mEdges.get(j);
 
@@ -450,7 +508,7 @@ public class MeshCubes extends MeshBase
                if( !lastBlockIsNE || (!front && !seenLand) ) repeatLast(attribs);
                addFrontVertex( 1, vectZ, col, row+1, attribs);
                }
-             addFrontVertex( 2, vectZ, col+1, row, attribs);
+             addFrontVertex( 2, vectZ, col+1, row  , attribs);
              addFrontVertex( 3, vectZ, col+1, row+1, attribs);
              }
            else
@@ -660,8 +718,16 @@ public class MeshCubes extends MeshBase
      attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+1] = mInflateY[row][col]/2.0f;
      attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+2] = vectZ;
 
-     attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = x;
-     attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = 1.0f-y;
+     if( vectZ>0 )
+       {
+       attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = mTexMappingX[FRONT] +       x  * mTexMappingW[FRONT];
+       attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = mTexMappingY[FRONT] + (1.0f-y) * mTexMappingH[FRONT];
+       }
+     else
+       {
+       attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = mTexMappingX[BACK]  +       x  * mTexMappingW[BACK];
+       attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = mTexMappingY[BACK]  + (1.0f-y) * mTexMappingH[BACK];
+       }
 
      currVert++;
      }
@@ -672,7 +738,7 @@ public class MeshCubes extends MeshBase
      {
      //android.util.Log.e("CUBES", "adding Side vertex!");
      float x, y, z;
-     int row, col, texX, texY;
+     int row, col;
 
      switch(curr.side)
        {
@@ -694,11 +760,8 @@ public class MeshCubes extends MeshBase
                    attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+1] = mInflateY[row][col]/2.0f;
                    attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+2] = z;
 
-                   texY = (mRows-row+slice)%(2*mRows);
-                   if( texY>mRows ) texY = 2*mRows-texY;
-
-                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = x;
-                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = (float)texY/mRows;
+                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = mTexMappingX[TOP] +       x  * mTexMappingW[TOP];
+                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = mTexMappingY[TOP] + (0.5f-z) * mTexMappingH[TOP];
 
                    break;
        case SOUTH: row = curr.row+1;
@@ -719,11 +782,8 @@ public class MeshCubes extends MeshBase
                    attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+1] = mInflateY[row][col]/2.0f;
                    attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+2] = z;
 
-                   texY = (mRows-row+slice)%(2*mRows);
-                   if( texY>mRows ) texY = 2*mRows-texY;
-
-                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = x;
-                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = (float)texY/mRows;
+                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = mTexMappingX[BOTTOM] +       x  * mTexMappingW[BOTTOM];
+                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = mTexMappingY[BOTTOM] + (0.5f-z) * mTexMappingH[BOTTOM];
 
                    break;
        case WEST : row = (back  ? (curr.row+1):(curr.row));
@@ -744,11 +804,8 @@ public class MeshCubes extends MeshBase
                    attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+1] = mInflateY[row][col]/2.0f;
                    attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+2] = z;
 
-                   texX = (col+slice)%(2*mCols);
-                   if( texX>mCols ) texX = 2*mCols-texX;
-
-                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = (float)texX/mCols;
-                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = 1.0f-y;
+                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = mTexMappingX[LEFT] + (0.5f-z) * mTexMappingW[LEFT];
+                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = mTexMappingY[LEFT] + (1.0f-y) * mTexMappingH[LEFT];
 
                    break;
        case EAST : row = (back  ? (curr.row):(curr.row+1));
@@ -769,11 +826,8 @@ public class MeshCubes extends MeshBase
                    attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+1] = mInflateY[row][col]/2.0f;
                    attribs[VERT_ATTRIBS*currVert + INF_ATTRIB+2] = z;
 
-                   texX = (col+slice)%(2*mCols);
-                   if( texX>mCols ) texX = 2*mCols-texX;
-
-                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = (float)texX/mCols;
-                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = 1.0f-y;
+                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB  ] = mTexMappingX[RIGHT] + (0.5f-z) * mTexMappingW[RIGHT];
+                   attribs[VERT_ATTRIBS*currVert + TEX_ATTRIB+1] = mTexMappingY[RIGHT] + (1.0f-y) * mTexMappingH[RIGHT];
 
                    break;
        }
@@ -845,13 +899,13 @@ public class MeshCubes extends MeshBase
  *               <p></p>
  *               <p>
  *               <pre>
- *               For example, (cols=2, desc="111010") describes the following shape:
+ *               For example, (cols=2, desc="111010", slices=1) describes the following shape:
  *
  *               XX
  *               X
  *               X
  *
- *               whereas (cols=2,desc="110001") describes
+ *               whereas (cols=2,desc="110001", slices=1) describes
  *
  *               XX
  *
@@ -863,6 +917,54 @@ public class MeshCubes extends MeshBase
  public MeshCubes(int cols, String desc, int slices)
    {
    super( (float)slices/cols);
+
+   Static4D map = new Static4D(0.0f,0.0f,1.0f,1.0f);
+   fillTexMappings(map,map,map,map,map,map);
+   prepareDataStructures(cols,desc,slices);
+   build();
+   }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Creates the underlying mesh of vertices, normals, texture coords with custom texture mappings.
+ *
+ * The mappings decide what part of the texture appears on a given side. Example:
+ * front = (0.0,0.5,0.5,1.0) means that the front side of the grid will be textured with the
+ * bottom-left quadrant of the texture.
+ *
+ * Default is: each of the 6 sides maps to the whole texture, i.e. (0.0,0.0,1.0,1.0)
+ *
+ * @param cols   Integer helping to parse the next parameter.
+ * @param desc   String describing the subset of a MxNx1 cuboid that we want to create.
+ *               Its MxN characters - all 0 or 1 - decide of appropriate field is taken or not.
+ *               <p></p>
+ *               <p>
+ *               <pre>
+ *               For example, (cols=2, desc="111010", slices=1) describes the following shape:
+ *
+ *               XX
+ *               X
+ *               X
+ *
+ *               whereas (cols=2,desc="110001", slices=1) describes
+ *
+ *               XX
+ *
+ *                X
+ *               </pre>
+ *               </p>
+ * @param slices Number of slices, i.e. 'depth' of the Mesh.
+ * @param front  Texture mapping the front side maps to.
+ * @param back   Texture mapping the back side maps to.
+ * @param left   Texture mapping the left side maps to.
+ * @param right  Texture mapping the right side maps to.
+ * @param top    Texture mapping the top side maps to.
+ * @param bottom Texture mapping the bottom side maps to.
+ */
+ public MeshCubes(int cols, String desc, int slices, Static4D front, Static4D back, Static4D left, Static4D right, Static4D top, Static4D bottom)
+   {
+   super( (float)slices/cols);
+   fillTexMappings(front,back,left,right,top,bottom);
    prepareDataStructures(cols,desc,slices);
    build();
    }
@@ -878,6 +980,38 @@ public class MeshCubes extends MeshBase
  public MeshCubes(int cols, int rows, int slices)
    {
    super( (float)slices/cols);
+
+   Static4D map = new Static4D(0.0f,0.0f,1.0f,1.0f);
+   fillTexMappings(map,map,map,map,map,map);
+   prepareDataStructures(cols,rows,slices);
+   build();
+   }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Creates a full, hole-less underlying mesh of vertices, normals, texture coords and colors with
+ * custom texture mappings.
+ *
+ * The mappings decide what part of the texture appears on a given side. Example:
+ * front = (0.0,0.5,0.5,1.0) means that the front side of the grid will be textured with the
+ * bottom-left quadrant of the texture.
+ *
+ * Default is: each of the 6 sides maps to the whole texture, i.e. (0.0,0.0,1.0,1.0)
+ *
+ * @param cols   Number of columns, i.e. 'width' of the Mesh.
+ * @param rows   Number of rows, i.e. 'height' of the Mesh.
+ * @param slices Number of slices, i.e. 'depth' of the Mesh.
+ * @param front  Texture mapping the front side maps to.
+ * @param back   Texture mapping the back side maps to.
+ * @param left   Texture mapping the left side maps to.
+ * @param right  Texture mapping the right side maps to.
+ * @param top    Texture mapping the top side maps to.
+ * @param bottom Texture mapping the bottom side maps to.
+ */
+ public MeshCubes(int cols, int rows, int slices, Static4D front, Static4D back, Static4D left, Static4D right, Static4D top, Static4D bottom)
+   {
+   super( (float)slices/cols);
+   fillTexMappings(front,back,left,right,top,bottom);
    prepareDataStructures(cols,rows,slices);
    build();
    }
