commit 69ed1eb4e262e30ed36ff39590ed0b3b2d668781
Author: Leszek Koltunski <leszek@distoretedandroid.org>
Date:   Tue Jan 17 17:57:15 2017 +0000

    Progress with getting Mesh'es bounding rectangle.

diff --git a/src/main/java/org/distorted/library/DistortedEffects.java b/src/main/java/org/distorted/library/DistortedEffects.java
index 8b036f3..83b2bd9 100644
--- a/src/main/java/org/distorted/library/DistortedEffects.java
+++ b/src/main/java/org/distorted/library/DistortedEffects.java
@@ -146,7 +146,7 @@ public class DistortedEffects
       }
     else
       {
-      if( mV.mNumEffects==0 && mF.mNumEffects==0 && mesh.canUsePostprocessingShortcut() )
+      if( mV.mNumEffects==0 && mF.mNumEffects==0 && (mesh instanceof MeshFlat) && mM.canUseShortcut() )
         {
         mM.constructMatrices(df,halfInputW,halfInputH);
         mP.render(2*halfInputW, 2*halfInputH, mM.getMVP(), df);
diff --git a/src/main/java/org/distorted/library/EffectQueueMatrix.java b/src/main/java/org/distorted/library/EffectQueueMatrix.java
index 4ac3899..b320c86 100644
--- a/src/main/java/org/distorted/library/EffectQueueMatrix.java
+++ b/src/main/java/org/distorted/library/EffectQueueMatrix.java
@@ -204,6 +204,32 @@ class EffectQueueMatrix extends EffectQueue
     return mMVPMatrix;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// return true if in the queue there are only translations, scales, x- and y-shears, and rotations along
+// a vector which is perpendicular to the screen, i.e. if the resulting matrix keeps the front wall of the
+// Mesh parallel to the screen.
+
+  boolean canUseShortcut()
+    {
+    for(int i=0; i<mNumEffects; i++)
+      {
+      if (mName[i] == EffectNames.ROTATE.ordinal() )
+        {
+        if( mUniforms[NUM_UNIFORMS*i] != 0.0f || mUniforms[NUM_UNIFORMS*i+1] != 0.0f ) return false;  // rotation along vector with x or y non-zero
+        }
+      else if(mName[i] == EffectNames.QUATERNION.ordinal() )
+        {
+        if( mUniforms[NUM_UNIFORMS*i] != 0.0f || mUniforms[NUM_UNIFORMS*i+1] != 0.0f ) return false;  // quaternion rotation along vector with x or y non-zero
+        }
+      else if(mName[i] == EffectNames.SHEAR.ordinal() )
+        {
+        if( mUniforms[NUM_UNIFORMS*i+2] != 0.0f ) return false; // shear with non-zero Z
+        }
+      }
+
+    return true;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   synchronized void compute(long currTime) 
diff --git a/src/main/java/org/distorted/library/MeshCubes.java b/src/main/java/org/distorted/library/MeshCubes.java
index 11da535..6d5df7d 100644
--- a/src/main/java/org/distorted/library/MeshCubes.java
+++ b/src/main/java/org/distorted/library/MeshCubes.java
@@ -72,6 +72,22 @@ public class MeshCubes extends MeshObject
    private int mEdgeNum;
    private int mSideWalls;
 
+   private float[] mBoundingVert;
+
+   private static float[] mBoundingVert1 = new float[] { -0.5f,-0.5f, FRONTZ,
+                                                         +0.5f,-0.5f, FRONTZ,
+                                                         -0.5f,+0.5f, FRONTZ,
+                                                         +0.5f,+0.5f, FRONTZ };
+
+   private static float[] mBoundingVert2 = new float[] { -0.5f,-0.5f, FRONTZ,
+                                                         +0.5f,-0.5f, FRONTZ,
+                                                         -0.5f,+0.5f, FRONTZ,
+                                                         +0.5f,+0.5f, FRONTZ,
+                                                         -0.5f,-0.5f, BACKZ ,
+                                                         +0.5f,-0.5f, BACKZ ,
+                                                         -0.5f,+0.5f, BACKZ ,
+                                                         +0.5f,+0.5f, BACKZ  };
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // a Block is split into two triangles along the NE-SW line iff it is in the top-right
 // or bottom-left quadrant of the grid.
@@ -188,6 +204,7 @@ public class MeshCubes extends MeshObject
        dataLength = computeDataLength(frontOnly);
 
        remainingVert = dataLength;
+       buildBoundingVert(mCubes,frontOnly);
        }
      }
 
@@ -213,8 +230,146 @@ public class MeshCubes extends MeshObject
 
        remainingVert = dataLength;
        }
+
+     mBoundingVert = frontOnly ? mBoundingVert1 : mBoundingVert2;
      }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float retLeftmost(short[][] cubes, int row)
+    {
+
+    return 0.0f;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+ private float retRightmost(short[][] cubes, int row)
+    {
+    if( row==0 )
+      {
+      for(int i=0; i<mCols; i++)
+        {
+
+        }
+      }
+    else if(row==mRows)
+      {
+      for(int i=0; i<mCols; i++)
+        {
+
+        }
+      }
+    else
+      {
+      for(int i=0; i<mCols; i++)
+        {
+
+        }
+      }
+
+    return 0.0f;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private int addLeftmost(float[] temp, short[][] cubes, int row, int index)
+    {
+    float x2 = retLeftmost(cubes,row);
+    float y2 = row/mRows - 0.5f;
+
+    if( index>1 )
+      {
+      float x0 = temp[2*index-4];
+      float y0 = temp[2*index-3];
+      float x1 = temp[2*index-2];
+      float y1 = temp[2*index-1];
+
+      if( (x0-x2)*(y0-y1) <= (x0-x1)*(y0-y2) )
+        {
+        temp[2*index-2] = x2;
+        temp[2*index-1] = y2;
+        return index;
+        }
+      }
+
+    temp[2*index+0] = x2;
+    temp[2*index+1] = y2;
+    return index+1;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private int addRightmost(float[] temp, short[][] cubes, int row, int index)
+    {
+    float x2 = retRightmost(cubes,row);
+    float y2 = row/mRows - 0.5f;
+
+    if( index>1 )
+      {
+      float x0 = temp[2*index-4];
+      float y0 = temp[2*index-3];
+      float x1 = temp[2*index-2];
+      float y1 = temp[2*index-1];
+
+      if( (x0-x2)*(y0-y1) >= (x0-x1)*(y0-y2) )
+        {
+        temp[2*index-2] = x2;
+        temp[2*index-1] = y2;
+        return index;
+        }
+      }
+
+    temp[2*index+0] = x2;
+    temp[2*index+1] = y2;
+    return index+1;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// fill up the mBoundingVert array with the smallest set of vertices which form the same convex hull
+// like the whole thing.
+
+  private void buildBoundingVert(short[][] cubes, boolean frontOnly)
+    {
+    int lVert=0, rVert=0;
+    float[] tempL = new float[2*(mRows+1)];
+    float[] tempR = new float[2*(mRows+1)];
+
+    for(int i=0; i<=mRows; i++)
+      {
+      lVert = addLeftmost (tempL,cubes,i,lVert);
+      rVert = addRightmost(tempR,cubes,i,rVert);
+      }
+
+    int numVert = lVert+rVert;
+
+    mBoundingVert = new float[ numVert*(frontOnly ? 3:6) ];
+
+    for(int i=0; i<lVert; i++)
+      {
+      mBoundingVert[3*i  ] = tempL[2*i  ];
+      mBoundingVert[3*i+1] = tempL[2*i+1];
+      mBoundingVert[3*i+2] = FRONTZ;
+      }
+
+    for(int i=0; i<rVert; i++)
+      {
+      mBoundingVert[3*(i+lVert)  ] = tempR[2*i  ];
+      mBoundingVert[3*(i+lVert)+1] = tempR[2*i+1];
+      mBoundingVert[3*(i+lVert)+2] = FRONTZ;
+      }
+
+    if( !frontOnly )
+      {
+      for(int i=0; i<numVert; i++)
+        {
+        mBoundingVert[3*(i+numVert)  ] = mBoundingVert[3*i  ];
+        mBoundingVert[3*(i+numVert)+1] = mBoundingVert[3*i+1];
+        mBoundingVert[3*(i+numVert)+2] = BACKZ;
+        }
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // Mark all the 'regions' of our grid  - i.e. separate pieces of 'land' (connected blocks that will 
 // be rendered) and 'water' (connected holes in between) with integers. Each connected block of land
@@ -742,10 +897,10 @@ public class MeshCubes extends MeshObject
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-   boolean canUsePostprocessingShortcut()
-      {
-      return false;
-      }
+   float[] getBoundingVertices()
+     {
+     return mBoundingVert;
+     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // PUBLIC API
diff --git a/src/main/java/org/distorted/library/MeshFlat.java b/src/main/java/org/distorted/library/MeshFlat.java
index e0ed22c..7c147bc 100644
--- a/src/main/java/org/distorted/library/MeshFlat.java
+++ b/src/main/java/org/distorted/library/MeshFlat.java
@@ -34,6 +34,11 @@ public class MeshFlat extends MeshObject
   private int mCols, mRows;
   private int remainingVert;
 
+  private static float[] mBoundingVert = new float[] { -0.5f,-0.5f,0.0f,
+                                                       +0.5f,-0.5f,0.0f,
+                                                       -0.5f,+0.5f,0.0f,
+                                                       +0.5f,+0.5f,0.0f };
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // Create a flat, full grid.
 
@@ -60,13 +65,10 @@ public class MeshFlat extends MeshObject
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-   private int addVertex(int vertex, int col, int row, float[] position, float[] normal, float[] texture)
+   private int addVertex(int vertex, float x, float y, float[] position, float[] normal, float[] texture)
      {
      remainingVert--;
 
-     float x= (float)col/mCols;
-     float y= (float)row/mRows;
-
      position[3*vertex  ] = x-0.5f;
      position[3*vertex+1] = 0.5f-y;
      position[3*vertex+2] = 0;
@@ -115,10 +117,18 @@ public class MeshFlat extends MeshObject
      boolean currentBlockIsNE;
      int vertex = 0;
 
+     float x,y;
+     final float X = 1.0f/mCols;
+     final float Y = 1.0f/mRows;
+
      //android.util.Log.d("BITMAP", "buildGrid");
 
+     y = 0.0f;
+
      for(int row=0; row<mRows; row++)
        {
+       x = 0.0f;
+
        for(int col=0; col<mCols; col++)
          {
          currentBlockIsNE = (2*row<=mRows-1)^(2*col<=mCols-1);
@@ -126,16 +136,19 @@ public class MeshFlat extends MeshObject
          if( col==0 || (lastBlockIsNE^currentBlockIsNE) )
            {
            if( row!=0 && col==0 ) vertex = repeatLast(vertex,position,normal,texture);
-           vertex= addVertex( vertex, col, row+(currentBlockIsNE?0:1), position, normal, texture);
+           vertex= addVertex( vertex, x, y+(currentBlockIsNE?0:Y), position, normal, texture);
            if( row!=0 && col==0 ) vertex = repeatLast(vertex,position,normal,texture);
            if( lastBlockIsNE^currentBlockIsNE)  vertex = repeatLast(vertex,position,normal,texture);
-           vertex= addVertex( vertex, col, row+(currentBlockIsNE?1:0), position, normal, texture);
+           vertex= addVertex( vertex, x, y+(currentBlockIsNE?Y:0), position, normal, texture);
            }
-         vertex= addVertex( vertex, col+1, row+(currentBlockIsNE?0:1), position, normal, texture);
-         vertex= addVertex( vertex, col+1, row+(currentBlockIsNE?1:0), position, normal, texture);
+         vertex= addVertex( vertex, x+X, y+(currentBlockIsNE?0:Y), position, normal, texture);
+         vertex= addVertex( vertex, x+X, y+(currentBlockIsNE?Y:0), position, normal, texture);
 
          lastBlockIsNE = currentBlockIsNE;
+         x+=X;
          }
+
+       y+=Y;
        }
 
      //android.util.Log.d("BITMAP", "buildGrid done");
@@ -159,10 +172,10 @@ public class MeshFlat extends MeshObject
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-   boolean canUsePostprocessingShortcut()
-      {
-      return true;
-      }
+   float[] getBoundingVertices()
+     {
+     return mBoundingVert;
+     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // PUBLIC API
diff --git a/src/main/java/org/distorted/library/MeshObject.java b/src/main/java/org/distorted/library/MeshObject.java
index d33dd46..73adb14 100644
--- a/src/main/java/org/distorted/library/MeshObject.java
+++ b/src/main/java/org/distorted/library/MeshObject.java
@@ -50,6 +50,13 @@ public abstract class MeshObject
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-
-   abstract boolean canUsePostprocessingShortcut();
+/**
+ * Get the minimal set of Vertices which have the same convex hull as the whole set.
+ * <p>
+ * In case of Flat Meshes, the set is obviously just the 4 corners. In case of the Cubes Mesh,
+ * it is a subset of the set of each rightmost- and leftmost- corners in each row.
+ * <p>
+ * This is used to be able to quickly compute, in window coordinates, the Mesh'es bounding rectangle.
+ */
+   abstract float[] getBoundingVertices();
    }
