commit ba52835a78740fc726b7fb5fbaf54401cbfcc806
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Wed May 11 17:32:02 2022 +0200

    Improve icon creation.

diff --git a/src/main/java/org/distorted/bandaged/BandagedCreatorRenderer.java b/src/main/java/org/distorted/bandaged/BandagedCreatorRenderer.java
index 24d4c79f..dce5c141 100644
--- a/src/main/java/org/distorted/bandaged/BandagedCreatorRenderer.java
+++ b/src/main/java/org/distorted/bandaged/BandagedCreatorRenderer.java
@@ -492,9 +492,9 @@ public class BandagedCreatorRenderer implements GLSurfaceView.Renderer, Distorte
    private void setupIconCreation(Activity act)
      {
      final float R=1.0f;
-     final int FBO_WIDTH  = (int)(R*240);
-     final int FBO_HEIGHT = (int)(R*360);
-     final float OBJECT_SIZE = R*0.38f;
+     final int FBO_WIDTH  = (int)(R*720);
+     final int FBO_HEIGHT = (int)(R*1280);
+     final float OBJECT_SIZE = R*0.35f;
 
      TwistyObject obj = new TwistyBandagedGeneric( mObjSize, TwistyObject.MESH_NICE, TwistyObject.MODE_ICON,
                                                    ShapeHexahedron.DEFAULT_ROT, new Static3D(0,0,0), OBJECT_SIZE, null );
diff --git a/src/main/java/org/distorted/bandaged/BandagedCreatorWorkerThread.java b/src/main/java/org/distorted/bandaged/BandagedCreatorWorkerThread.java
index 8e03c9d1..abe7b881 100644
--- a/src/main/java/org/distorted/bandaged/BandagedCreatorWorkerThread.java
+++ b/src/main/java/org/distorted/bandaged/BandagedCreatorWorkerThread.java
@@ -60,6 +60,8 @@ class BandagedCreatorWorkerThread extends Thread
       }
     }
 
+  private int mCreatedBufSize;
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   private BandagedCreatorWorkerThread()
@@ -116,14 +118,26 @@ class BandagedCreatorWorkerThread extends Thread
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private boolean containsBlackness(byte[] tmp, int width)
+  private int firstBlackPixel(byte[] tmp, int width)
     {
     for(int i=0; i<width; i++)
       {
-      if( tmp[4*i]==0 && tmp[4*i+3]==-1 ) return true;
+      if( tmp[4*i]==0 && tmp[4*i+3]==-1 ) return i;
+      }
+
+    return -1;
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private int lastBlackPixel(byte[] tmp, int width)
+    {
+    for(int i=width-1; i>=0; i--)
+      {
+      if( tmp[4*i]==0 && tmp[4*i+3]==-1 ) return i;
       }
 
-    return false;
+    return -1;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -137,7 +151,7 @@ class BandagedCreatorWorkerThread extends Thread
       buf.position(i*wBytes);
       buf.get(tmp);
 
-      if( containsBlackness(tmp,width) ) return i;
+      if( firstBlackPixel(tmp,width)>=0 ) return i;
       }
 
     return 0;
@@ -154,132 +168,115 @@ class BandagedCreatorWorkerThread extends Thread
       buf.position(i*wBytes);
       buf.get(tmp);
 
-      if( containsBlackness(tmp,width) ) return i;
+      if( firstBlackPixel(tmp,width)>=0 ) return i;
       }
 
     return width-1;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-// GL uses a coordinate system from mathematics; i.e. (0,0) is in the lower-left corner. 2D stuff
-// has the origin on the upper-left corner; we have to flip our bitmap upside down!
-//
-// We also need to figure out the topmost and bottommost rows where the object starts and cut out
-// a square section from the 'input' so that the object is vertically centralized.
 
-  private ByteBuffer adjustBuffer(ByteBuffer input, byte[] tmp, int width, int height)
+  private int computeLeftColumn(ByteBuffer buf, byte[] tmp, int width, int firstrow, int lastrow)
     {
     int wBytes = 4*width;
+    int currentBest = width;
 
-    ByteBuffer output = ByteBuffer.allocateDirect(wBytes*width);
-    output.order(ByteOrder.LITTLE_ENDIAN);
-
-    int firstRow = computeFirstRow(input,tmp,width,height);
-    int lastRow  = computeLastRow(input,tmp,width,height);
-    int startRow = (firstRow+lastRow+width)/2;
-
-    for(int i=0; i<width; i++)
+    for(int i=firstrow; i<lastrow; i++)
       {
-      input.position((startRow-i)*wBytes);
-      input.get(tmp);
-      output.position(i*wBytes);
-      output.put(tmp);
+      buf.position(i*wBytes);
+      buf.get(tmp);
+
+      int pixel = firstBlackPixel(tmp,width);
+      if( pixel>=0 && pixel<currentBest ) currentBest = pixel;
       }
 
-    output.rewind();
-    return output;
+    return currentBest;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private void replaceColor(byte[] tmp, int index, int numColors)
+  private int computeRightColumn(ByteBuffer buf, byte[] tmp, int width, int firstrow, int lastrow)
     {
-    byte A = (byte)0xab;
-    int CUTOFF = 100;
+    int wBytes = 4*width;
+    int currentBest = 0;
 
-    switch(numColors)
+    for(int i=firstrow; i<lastrow; i++)
       {
-      case 4: if( tmp[index+1]==0 ) { tmp[index]=A; tmp[index+1]=0; tmp[index+2]=0; }
-              else
-                {
-                if( tmp[index]==tmp[index+1] )
-                  {
-                  if( tmp[index]<0 || tmp[index]>CUTOFF )  { tmp[index]=A; tmp[index+1]=A; tmp[index+2]=0; }
-                  }
-                else { tmp[index]=0; tmp[index+1]=0; tmp[index+2]=A; }
-                }
-              break;
-      case 6: if( tmp[index+2]!=0 )
-                {
-                if( tmp[index]==0 ) { tmp[index]=0; tmp[index+1]=0; tmp[index+2]=A; }
-                }
-              else
-                {
-                if( tmp[index]==tmp[index+1] ) { tmp[index]=A; tmp[index+1]=A; tmp[index+2]=0; }
-                else { tmp[index]=A; tmp[index+1]=0; tmp[index+2]=0; }
-                }
-              break;
-      case 8: if( tmp[index+2]!=0 )
-                {
-                if( tmp[index+1]==0 ) { tmp[index]=A; tmp[index+1]=0; tmp[index+2]=0; }
-                }
-              else
-                {
-                if( tmp[index+1]==0 ) { tmp[index]=0; tmp[index+1]=0; tmp[index+2]=A; }
-                else
-                  {
-                  if( tmp[index]==tmp[index+1] ) { tmp[index]=A; tmp[index+1]=A; tmp[index+2]=0; }
-                  else { tmp[index]=0; tmp[index+1]=A; tmp[index+2]=0; }
-                  }
-                }
-              break;
-
-      case 12:if( tmp[index+2]==0 )
-                {
-                if( tmp[index+1]==0 )  {tmp[index]=A; tmp[index+1]=0; tmp[index+2]=0;}
-                else  {tmp[index]=0; tmp[index+1]=A; tmp[index+2]=0;}
-                }
-              else
-                {
-                if( tmp[index]==tmp[index+1] )
-                  {
-                  if( tmp[index]<0 || tmp[index]>CUTOFF ) {tmp[index]=A; tmp[index+1]=A; tmp[index+2]=0;}
-                  }
-                else  {tmp[index]=0; tmp[index+1]=0; tmp[index+2]=A;}
-                }
-              break;
+      buf.position(i*wBytes);
+      buf.get(tmp);
+
+      int pixel = lastBlackPixel(tmp,width);
+      if( pixel>=0 && pixel>currentBest ) currentBest = pixel;
       }
+
+    return currentBest;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
+// GL uses a coordinate system from mathematics; i.e. (0,0) is in the lower-left corner. 2D stuff
+// has the origin on the upper-left corner; we have to flip our bitmap upside down!
+//
+// We also need to figure out the topmost and bottommost rows where the object starts and cut out
+// a square section from the 'input' so that the object is vertically centralized.
 
-  private ByteBuffer replaceColors(ByteBuffer input, byte[] tmp, int size, int numColors)
+  private ByteBuffer adjustBuffer(ByteBuffer input, byte[] tmp, int width, int height)
     {
-    int marker = (int)(255*BandagedCreatorRenderer.BRIGHTNESS);
-    int wBytes = 4*size;
-
-    ByteBuffer output = ByteBuffer.allocateDirect(wBytes*size);
+    int firstRow   = computeFirstRow(input,tmp,width,height);
+    int lastRow    = computeLastRow(input,tmp,width,height);
+    int leftColumn = computeLeftColumn(input,tmp,width,firstRow,lastRow);
+    int rightColumn= computeRightColumn(input,tmp,width,firstRow,lastRow);
+
+    int rowHeight = lastRow-firstRow;
+    int colWidth  = rightColumn-leftColumn;
+    int size      = Math.max(rowHeight,colWidth);
+    size = (int)(1.1f*size);
+    int half = size/2;
+    int centerX = (leftColumn+rightColumn)/2;
+    int centerY = (firstRow+lastRow)/2;
+    int sL=size, sR=size, sT=size, sB=size;
+
+    if( centerX-half<    0 )
+      {
+      android.util.Log.e("D", "buffer encroaches on the left!   centerX="+centerX+" centerY="+centerY+" size="+size);
+      sL = 2*centerX;
+      }
+    if( centerX+half>width )
+      {
+      android.util.Log.e("D", "buffer encroaches on the right!  centerX="+centerX+" centerY="+centerY+" size="+size);
+      sR = 2*(width-centerX);
+      }
+    if( centerY-half<    0 )
+      {
+      android.util.Log.e("D", "buffer encroaches on the top!    centerX="+centerX+" centerY="+centerY+" size="+size);
+      sT = 2*centerY;
+      }
+    if( centerY+half>height)
+      {
+      android.util.Log.e("D", "buffer encroaches on the bottom! centerX="+centerX+" centerY="+centerY+" size="+size);
+      sB = 2*(height-centerY);
+      }
+/*
+    if( sL==size && sR==size && sT==size && sB==size )
+      {
+      android.util.Log.e("D", "EVERYTHING ALL RIGHT centerX="+centerX+" centerY="+centerY+" size="+size);
+      }
+*/
+    int minH = Math.min(sL,sR);
+    int minV = Math.min(sT,sB);
+    mCreatedBufSize = Math.min(minH,minV);
+    half = mCreatedBufSize/2;
+    int wBytes = 4*mCreatedBufSize;
+    ByteBuffer output = ByteBuffer.allocateDirect(wBytes*mCreatedBufSize);
     output.order(ByteOrder.LITTLE_ENDIAN);
+    int startRow = centerY+half;
+    int distR = width-centerX-half;
 
-    for(int i=0; i<size; i++)
+    for(int i=0; i<mCreatedBufSize; i++)
       {
-      input.position(i*wBytes);
-      input.get(tmp);
-
-      for(int j=0; j<size; j++)
-        {
-        if( tmp[4*j]==marker && tmp[4*j+1]==marker && tmp[4*j+2]==marker )
-          {
-          tmp[4*j  ]=0;
-          tmp[4*j+1]=0;
-          tmp[4*j+2]=0;
-          tmp[4*j+3]=0;
-          }
-        else if( tmp[4*j]!=0 || tmp[4*j+1]!=0 || tmp[4*j+2]!=0 ) replaceColor(tmp,4*j,numColors);
-        }
-
+      input.position((startRow-i)*4*width + 4*distR );
+      input.get(tmp,0,wBytes);
       output.position(i*wBytes);
-      output.put(tmp);
+      output.put(tmp,0,wBytes);
       }
 
     output.rewind();
@@ -290,13 +287,11 @@ class BandagedCreatorWorkerThread extends Thread
 
   private void process(WorkLoad load)
     {
-    int width = load.width;
-    int height= load.height;
+    int width  = load.width;
+    int height = load.height;
 
     byte[] tmp = new byte[4*width];
     ByteBuffer bufSquare = adjustBuffer(load.buffer,tmp,width,height);
-   // ByteBuffer bufTransp = replaceColors(bufSquare,tmp,width,load.numColors);
-
     final String filename = load.filename;
     BufferedOutputStream bos =null;
     final Activity act = mWeakAct.get();
@@ -304,7 +299,7 @@ class BandagedCreatorWorkerThread extends Thread
     try
       {
       bos = new BufferedOutputStream(new FileOutputStream(filename));
-      Bitmap bmp = Bitmap.createBitmap( width, width, Bitmap.Config.ARGB_8888);
+      Bitmap bmp = Bitmap.createBitmap( mCreatedBufSize, mCreatedBufSize, Bitmap.Config.ARGB_8888);
       bmp.copyPixelsFromBuffer(bufSquare);
       bmp.compress(Bitmap.CompressFormat.PNG, 90, bos);
 
