commit d3287c14ac1ba19093aa92e9bde0587a886106bc
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Mon Jun 12 10:17:19 2023 +0200

    MeshPolygon: support for an arbitrary subset of edges being 'up' (i.e. buildup to MeshMultigon)

diff --git a/src/main/java/org/distorted/library/mesh/MeshPolygon.java b/src/main/java/org/distorted/library/mesh/MeshPolygon.java
index ddee9d8..3a7ba31 100644
--- a/src/main/java/org/distorted/library/mesh/MeshPolygon.java
+++ b/src/main/java/org/distorted/library/mesh/MeshPolygon.java
@@ -33,7 +33,7 @@ import org.distorted.library.main.DistortedLibrary;
  */
 public class MeshPolygon extends MeshBase
   {
-  private static final float NOT_DONE_YET = -1000;
+  private static final int NUM_CACHE = 20;
   private static final int SHAPE_DD = 0;
   private static final int SHAPE_DU = 1;
   private static final int SHAPE_UD = 2;
@@ -50,7 +50,7 @@ public class MeshPolygon extends MeshBase
   private int numVertices;
   private int extraIndex, extraVertices;
 
-  private float[] mBandQuot;
+  private float[] mCurveCache;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // polygonVertices>=3 , polygonBands>=2
@@ -74,17 +74,46 @@ public class MeshPolygon extends MeshBase
 
   private void computeCache()
     {
-    mBandQuot = new float[mNumPolygonBands];
+    mCurveCache = new float[NUM_CACHE];
+    float[] tmpD = new float[mNumPolygonBands+1];
+    float[] tmpX = new float[mNumPolygonBands+1];
 
-    int next, prev;
+    for(int i=1; i<mNumPolygonBands; i++)
+      {
+      tmpD[i] = (mPolygonBands[2*i-1]-mPolygonBands[2*i+1]) / (mPolygonBands[2*i]-mPolygonBands[2*i-2]);
+      tmpX[i] = 1.0f - (mPolygonBands[2*i]+mPolygonBands[2*i-2])/2;
+      }
+
+    tmpD[0] = tmpD[1];
+    tmpD[mNumPolygonBands] = tmpD[mNumPolygonBands-1];
+    tmpX[0] = 0.0f;
+    tmpX[mNumPolygonBands] = 1.0f;
 
-    for(int band=0; band<mNumPolygonBands; band++)
+    int prev = 0;
+    int next = 0;
+
+    for(int i=0; i<NUM_CACHE-1; i++)
       {
-      next = (band==mNumPolygonBands-1 ? band : band+1);
-      prev = (band==                 0 ? band : band-1);
+      float x = i/(NUM_CACHE-1.0f);
 
-      mBandQuot[band] = (mPolygonBands[2*prev+1]-mPolygonBands[2*next+1]) / (mPolygonBands[2*next]-mPolygonBands[2*prev]);
+      if( x>=tmpX[next] )
+        {
+        prev = next;
+        while( next<=mNumPolygonBands && x>=tmpX[next] ) next++;
+        }
+
+      if( next>prev )
+        {
+        float t = (x-tmpX[prev]) / (tmpX[next]-tmpX[prev]);
+        mCurveCache[i] = t*(tmpD[next]-tmpD[prev]) + tmpD[prev];
+        }
+      else
+        {
+        mCurveCache[i] = tmpD[next];
+        }
       }
+
+    mCurveCache[NUM_CACHE-1] = tmpD[mNumPolygonBands];
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -160,6 +189,54 @@ public class MeshPolygon extends MeshBase
     return 0.0f;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private float derivative(float x)
+    {
+    if( x>=1.0f )
+      {
+      return mCurveCache[NUM_CACHE-1];
+      }
+    else
+      {
+      float tmp = x*(NUM_CACHE-1);
+      int i1 = (int)tmp;
+      int i2 = i1+1;
+      return (tmp-i1)*(mCurveCache[i2]-mCurveCache[i1]) + mCurveCache[i1];
+      }
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void doNormals(float[] attribs1, int index, float quot, int edgeShape,
+                         float xEdge, float yEdge, float zEdge, int polyBand)
+    {
+    if( ( quot<=0.5f && (edgeShape==SHAPE_UD || edgeShape==SHAPE_UU) ) ||
+        ( quot> 0.5f && (edgeShape==SHAPE_DU || edgeShape==SHAPE_UU) )  )
+      {
+      attribs1[index  ] = 0;
+      attribs1[index+1] = 0;
+      attribs1[index+2] = 1;
+      }
+    else
+      {
+      float t = mPolygonBands[2*mNumPolygonBands-1];
+      float x = 1.0f - mPolygonBands[2*polyBand];
+      float d = derivative(x);
+
+      d *= ((t-zEdge)/t);
+
+      float vx = d*xEdge;
+      float vy = d*yEdge;
+      float vz = xEdge*xEdge + yEdge*yEdge;
+      float len = (float)Math.sqrt(vx*vx + vy*vy + vz*vz);
+
+      attribs1[index  ] = vx/len;
+      attribs1[index+1] = vy/len;
+      attribs1[index+2] = vz/len;
+      }
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private int addVertex(int vertex, int polyBand, int polyVertex, int polyEndVer, float quot,
@@ -176,47 +253,29 @@ public class MeshPolygon extends MeshBase
     float yEdge = Yfirst + quot*(Ylast-Yfirst);
     float zEdge;
 
+    float q = mPolygonBands[2*polyBand];
+    float o = mPolygonBands[2*polyBand+1];
+    float t = mPolygonBands[2*mNumPolygonBands-1];
+
     switch(edgeShape)
       {
-      case SHAPE_DD : zEdge = 0.0f;
-                      break;
-      case SHAPE_UU : zEdge = mPolygonBands[2*mNumPolygonBands-1];
-                      break;
-      case SHAPE_DU : zEdge = quot>=0.5f ? mPolygonBands[2*mNumPolygonBands-1] : computeZEdge(1-2*quot);
-                      break;
-      case SHAPE_UD : zEdge = quot<=0.5f ? mPolygonBands[2*mNumPolygonBands-1] : computeZEdge(2*quot-1);
-                      break;
-      default       : zEdge = quot<=0.5f ? computeZEdge(1-2*quot) : computeZEdge(2*quot-1);
-                      break;
+      case SHAPE_DD : zEdge = 0.0f; break;
+      case SHAPE_UU : zEdge = t;    break;
+      case SHAPE_DU : zEdge = quot>=0.5f ? t : computeZEdge(1-2*quot); break;
+      case SHAPE_UD : zEdge = quot<=0.5f ? t : computeZEdge(2*quot-1); break;
+      default       : zEdge = quot<=0.5f ? computeZEdge(1-2*quot) : computeZEdge(2*quot-1); break;
       }
 
-    float q =  mPolygonBands[2*polyBand];
-
     float x = q*xEdge;
     float y = q*yEdge;
-    float z = q*zEdge + mPolygonBands[2*polyBand+1];
+    float z = o + (t-o)*(zEdge/t);
 
     attribs1[VERT1_ATTRIBS*vertex + POS_ATTRIB  ] = x;
     attribs1[VERT1_ATTRIBS*vertex + POS_ATTRIB+1] = y;
     attribs1[VERT1_ATTRIBS*vertex + POS_ATTRIB+2] = z;
 
     int index = VERT1_ATTRIBS*vertex + NOR_ATTRIB;
-
-    if( quot==0.0f || quot==1.0f )
-      {
-      float vx = mBandQuot[polyBand]*xEdge;
-      float vy = mBandQuot[polyBand]*yEdge;
-      float vz = xEdge*xEdge + yEdge*yEdge;
-      float len = (float)Math.sqrt(vx*vx + vy*vy + vz*vz);
-
-      attribs1[index  ] = vx/len;
-      attribs1[index+1] = vy/len;
-      attribs1[index+2] = vz/len;
-      }
-    else
-      {
-      attribs1[index  ] = NOT_DONE_YET;
-      }
+    doNormals(attribs1,index, quot, edgeShape, xEdge, yEdge, zEdge, polyBand);
 
     attribs2[VERT2_ATTRIBS*vertex + TEX_ATTRIB  ] = x+0.5f;
     attribs2[VERT2_ATTRIBS*vertex + TEX_ATTRIB+1] = y+0.5f;
@@ -224,58 +283,10 @@ public class MeshPolygon extends MeshBase
     return vertex+1;
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  private void addVertexNormal(int vertex, int end1, int end2, float[] attribs1)
-    {
-    // android.util.Log.e("D", "vertex="+vertex+" end1="+end1+" end2="+end2);
-
-    int index = VERT1_ATTRIBS*vertex + NOR_ATTRIB;
-
-    if( attribs1[index] == NOT_DONE_YET)
-      {
-      int iv = VERT1_ATTRIBS*vertex + POS_ATTRIB;
-      int i1 = VERT1_ATTRIBS*end1   + POS_ATTRIB;
-      int i2 = VERT1_ATTRIBS*end2   + POS_ATTRIB;
-
-      float vx = attribs1[iv  ];
-      float vy = attribs1[iv+1];
-      float vz = attribs1[iv+2];
-
-      float x1 = attribs1[i1  ];
-      float y1 = attribs1[i1+1];
-      float z1 = attribs1[i1+2];
-
-      float x2 = attribs1[i2  ];
-      float y2 = attribs1[i2+1];
-      float z2 = attribs1[i2+2];
-
-      float dx1 = vx-x1;
-      float dy1 = vy-y1;
-      float dz1 = vz-z1;
-
-      float dx2 = vx-x2;
-      float dy2 = vy-y2;
-      float dz2 = vz-z2;
-
-      float cx = dy1*dz2 - dz1*dy2;
-      float cy = dz1*dx2 - dx1*dz2;
-      float cz = dx1*dy2 - dy1*dx2;
-
-      float len = (float)Math.sqrt(cx*cx + cy*cy + cz*cz);
-
-      attribs1[index  ] = cx/len;
-      attribs1[index+1] = cy/len;
-      attribs1[index+2] = cz/len;
-      }
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private int createBandStrip(int vertex, int polyBand, int polyVertex, int edgeShape, float[] attribs1, float[] attribs2)
     {
-    int initVertex = vertex;
-
     if( polyVertex==0 )
       {
       vertex = addVertex(vertex,polyBand,0,1,0,edgeShape,attribs1,attribs2);
@@ -307,26 +318,6 @@ public class MeshPolygon extends MeshBase
       vertex = addVertex(vertex,polyBand  ,polyVertex,polyEndVer,quot2,edgeShape,attribs1,attribs2);
       }
 
-    if( polyVertex==0 )
-      {
-      if( polyBand>0 ) addVertexNormal(initVertex,initVertex+3,initVertex+2,attribs1);
-      else             addVertexNormal(initVertex,initVertex+2,initVertex+1,attribs1);
-      }
-    else
-      {
-      addVertexNormal(initVertex,initVertex-1,initVertex+1,attribs1);
-      }
-
-    boolean lower = (polyVertex>0 || polyBand>0);
-
-    for(int index=initVertex+1; index<vertex-1; index++)
-      {
-      addVertexNormal(index,(lower ? index+2 : index-1),index+1,attribs1);
-      lower = !lower;
-      }
-
-    addVertexNormal(vertex-1,vertex-2,vertex-3,attribs1);
-
     return vertex;
     }
 
