commit f01ab8780eaa2e51565ca344adab4cab1a5861bf
Author: leszek <leszek@koltunski.pl>
Date:   Thu Dec 12 13:59:13 2024 +0100

    bugfix in the Library:
    Before, the mapping of the attributes in various shaders to the MeshBase.bindVertexAttribs() was shaky.
    In fact incorrect in case of the Preprocess program. Improve that!

diff --git a/src/main/java/org/distorted/library/effect/PostprocessEffectBlurred.java b/src/main/java/org/distorted/library/effect/PostprocessEffectBlurred.java
index 0b94e85..1bd4ee4 100644
--- a/src/main/java/org/distorted/library/effect/PostprocessEffectBlurred.java
+++ b/src/main/java/org/distorted/library/effect/PostprocessEffectBlurred.java
@@ -227,16 +227,16 @@ abstract public class PostprocessEffectBlurred extends PostprocessEffect
     {
     final String vertex =
 
-      "precision lowp float;  \n"+
-      "in vec2 a_Position;    \n"+
-      "in vec2 a_TexCoord;    \n"+
-      "out vec2 v_TexCoord;   \n"+
-      "uniform float u_Depth; \n"+
-      "uniform vec2 u_TexCorr;\n"+
+      "precision lowp float;     \n"+
+      "in vec2 a_Position;       \n"+
+      "in vec2 a_TexCoordinate;  \n"+
+      "out vec2 v_TexCoordinate; \n"+
+      "uniform float u_Depth;    \n"+
+      "uniform vec2 u_TexCorr;   \n"+
 
       "void main()                                      \n"+
       "  {                                              \n"+
-      "  v_TexCoord = a_TexCoord * u_TexCorr;           \n"+
+      "  v_TexCoordinate = a_TexCoordinate * u_TexCorr; \n"+
       "  gl_Position= vec4(2.0*a_Position,u_Depth,1.0); \n"+
       "  }";
 
@@ -244,44 +244,44 @@ abstract public class PostprocessEffectBlurred extends PostprocessEffect
 
       "#define MAX_BLUR "+MAX_RADIUS+    "\n"+
       "precision lowp float;              \n"+
-      "in vec2 v_TexCoord;                \n"+
+      "in vec2 v_TexCoordinate;           \n"+
       "out vec4 fragColor;                \n"+
       "uniform sampler2D u_ColorTexture;  \n"+
       "uniform float u_Offsets[MAX_BLUR]; \n"+
       "uniform float u_Weights[MAX_BLUR]; \n"+
       "uniform int u_Radius;              \n"+
 
-      "void main()                                                                                           \n"+
-      "  {                                                                                                   \n"+
-      "  vec4 pixel= texture(u_ColorTexture,v_TexCoord) * u_Weights[0];                                      \n"+
-      "  for (int i=1; i<=u_Radius; i+=1)                                                                    \n"+
-      "    {                                                                                                 \n"+
-      "    pixel += ( texture(u_ColorTexture,vec2(v_TexCoord.x+u_Offsets[i],v_TexCoord.y)) +                 \n"+
-      "               texture(u_ColorTexture,vec2(v_TexCoord.x-u_Offsets[i],v_TexCoord.y)) ) * u_Weights[i]; \n"+
-      "    }                                                                                                 \n"+
-      "  fragColor = pixel;                                                                                  \n"+
+      "void main()                                                                                                     \n"+
+      "  {                                                                                                             \n"+
+      "  vec4 pixel= texture(u_ColorTexture,v_TexCoordinate) * u_Weights[0];                                           \n"+
+      "  for (int i=1; i<=u_Radius; i+=1)                                                                              \n"+
+      "    {                                                                                                           \n"+
+      "    pixel += ( texture(u_ColorTexture,vec2(v_TexCoordinate.x+u_Offsets[i],v_TexCoordinate.y)) +                 \n"+
+      "               texture(u_ColorTexture,vec2(v_TexCoordinate.x-u_Offsets[i],v_TexCoordinate.y)) ) * u_Weights[i]; \n"+
+      "    }                                                                                                           \n"+
+      "  fragColor = pixel;                                                                                            \n"+
       "  }";
 
     final String fragment2 =
 
       "#define MAX_BLUR "+MAX_RADIUS+    "\n"+
       "precision lowp float;              \n"+
-      "in vec2 v_TexCoord;                \n"+
+      "in vec2 v_TexCoordinate;           \n"+
       "out vec4 fragColor;                \n"+
       "uniform sampler2D u_ColorTexture;  \n"+
       "uniform float u_Offsets[MAX_BLUR]; \n"+
       "uniform float u_Weights[MAX_BLUR]; \n"+
       "uniform int u_Radius;              \n"+
 
-      "void main()                                                                                           \n"+
-      "  {                                                                                                   \n"+
-      "  vec4 pixel= texture(u_ColorTexture,v_TexCoord) * u_Weights[0];                                      \n"+
-      "  for (int i=1; i<=u_Radius; i+=1)                                                                    \n"+
-      "    {                                                                                                 \n"+
-      "    pixel += ( texture(u_ColorTexture,vec2(v_TexCoord.x,v_TexCoord.y+u_Offsets[i])) +                 \n"+
-      "               texture(u_ColorTexture,vec2(v_TexCoord.x,v_TexCoord.y-u_Offsets[i])) ) * u_Weights[i]; \n"+
-      "    }                                                                                                 \n"+
-      "  fragColor = pixel;                                                                                  \n"+
+      "void main()                                                                                                     \n"+
+      "  {                                                                                                             \n"+
+      "  vec4 pixel= texture(u_ColorTexture,v_TexCoordinate) * u_Weights[0];                                           \n"+
+      "  for (int i=1; i<=u_Radius; i+=1)                                                                              \n"+
+      "    {                                                                                                           \n"+
+      "    pixel += ( texture(u_ColorTexture,vec2(v_TexCoordinate.x,v_TexCoordinate.y+u_Offsets[i])) +                 \n"+
+      "               texture(u_ColorTexture,vec2(v_TexCoordinate.x,v_TexCoordinate.y-u_Offsets[i])) ) * u_Weights[i]; \n"+
+      "    }                                                                                                           \n"+
+      "  fragColor = pixel;                                                                                            \n"+
       "  }";
 
     mIndex1 = PostprocessEffect.register(prog1, vertex,fragment1);
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueue.java b/src/main/java/org/distorted/library/effectqueue/EffectQueue.java
index 6a1c027..2f5eb06 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueue.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueue.java
@@ -174,7 +174,7 @@ public abstract class EffectQueue implements InternalMaster.Slave
     {
     ((EffectQueueMatrix  )queues[0]).send(distance, mipmap, projection, variant);
     ((EffectQueueVertex  )queues[1]).send(inflate, programH, variant);
-    ((EffectQueueFragment)queues[2]).send(programH, variant);
+    ((EffectQueueFragment)queues[2]).send(variant);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.java b/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.java
index e354667..b40c35e 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.java
@@ -82,7 +82,7 @@ class EffectQueueFragment extends EffectQueue
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
   
-  void send(int programH, int variant)
+  void send(int variant)
     {
     GLES30.glUniform1i( mNumEffectsH[variant], mNumEffects);
 
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java b/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
index 5a3f4b7..d70df8c 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
@@ -131,7 +131,8 @@ public class EffectQueuePostprocess extends EffectQueue
     String mainFragHeader= version + "\n";
 
     mainVertHeader += "#define MAX_COMPON " + MeshBase.getMaxEffComponents() + "\n";
-    if( MeshBase.getUseCenters() ) mainVertHeader += "#define COMP_CENTERS\n";
+    if( MeshBase.getUseCenters() )      mainVertHeader += "#define COMP_CENTERS\n";
+    if( DistortedLibrary.isUBOBuggy() ) mainVertHeader += "#define BUGGY_UBOS\n";
 
     String enabledEffectV= VertexEffect.getGLSL();
 
diff --git a/src/main/java/org/distorted/library/main/DistortedLibrary.java b/src/main/java/org/distorted/library/main/DistortedLibrary.java
index 9557fc1..994089e 100644
--- a/src/main/java/org/distorted/library/main/DistortedLibrary.java
+++ b/src/main/java/org/distorted/library/main/DistortedLibrary.java
@@ -616,8 +616,8 @@ public class DistortedLibrary
       GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
 
       mMainProgram.useProgram();
-      GLES30.glUniform1i(DistortedLibrary.mMainTextureH, 0);
-      mesh.bindVertexAttribs(DistortedLibrary.mMainProgram);
+      GLES30.glUniform1i(mMainTextureH, 0);
+      mesh.bindVertexAttribs(mMainProgram);
       mesh.send(mMainProgramH,0);
 
       float inflate     = mesh.getInflate();
@@ -1002,6 +1002,15 @@ public class DistortedLibrary
     return mGLSL;
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * Are we running this on hardware where UBOs are buggy?
+ */
+  public static boolean isUBOBuggy()
+    {
+    return mBuggyUBOs;
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * When OpenGL context gets created, call this method so that the library can initialise its internal data structures.
diff --git a/src/main/java/org/distorted/library/mesh/MeshBase.java b/src/main/java/org/distorted/library/mesh/MeshBase.java
index 4681b60..8e8a74f 100644
--- a/src/main/java/org/distorted/library/mesh/MeshBase.java
+++ b/src/main/java/org/distorted/library/mesh/MeshBase.java
@@ -858,31 +858,45 @@ public abstract class MeshBase
      int index2 = mVBO2.createImmediatelyFloat(mNumVertices*VERT2_SIZE, mVertAttribs2);
      int[] attr = program.mAttribute;
 
-     switch( attr.length )
+     switch(program.mAttributeLayout )
        {
-       // 'normal' case
-       case 4: GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, index1 );
+       case DistortedProgram.ATTR_LAYOUT_PNTC:
+               GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, index1 );
                GLES30.glVertexAttribPointer(attr[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, VERT1_SIZE, OFFSET_POS);
                GLES30.glVertexAttribPointer(attr[1], NOR_DATA_SIZE, GLES30.GL_FLOAT, false, VERT1_SIZE, OFFSET_NOR);
                GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, index2 );
                GLES30.glVertexAttribPointer(attr[2], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, VERT2_SIZE, OFFSET_TEX);
                GLES30.glVertexAttribPointer(attr[3], COM_DATA_SIZE, GLES30.GL_FLOAT, false, VERT2_SIZE, OFFSET_COM);
                break;
-       // if we are not using component centers and there are no vertex effects enabled,
-       // then component attribute does not exist in the Vertex Shader
-       case 3: GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, index1 );
+       case DistortedProgram.ATTR_LAYOUT_PNT:
+               GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, index1 );
                GLES30.glVertexAttribPointer(attr[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, VERT1_SIZE, OFFSET_POS);
                GLES30.glVertexAttribPointer(attr[1], NOR_DATA_SIZE, GLES30.GL_FLOAT, false, VERT1_SIZE, OFFSET_NOR);
                GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, index2 );
                GLES30.glVertexAttribPointer(attr[2], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, VERT2_SIZE, OFFSET_TEX);
                break;
-       // pre program used in EffectQueuePostprocessing does not have v_Normal attribute
-       // (it is not used in the fragment shader)
-       case 2: GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, index1 );
+       case DistortedProgram.ATTR_LAYOUT_PNC:
+               GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, index1 );
+               GLES30.glVertexAttribPointer(attr[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, VERT1_SIZE, OFFSET_POS);
+               GLES30.glVertexAttribPointer(attr[1], NOR_DATA_SIZE, GLES30.GL_FLOAT, false, VERT1_SIZE, OFFSET_NOR);
+               GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, index2 );
+               GLES30.glVertexAttribPointer(attr[2], COM_DATA_SIZE, GLES30.GL_FLOAT, false, VERT2_SIZE, OFFSET_COM);
+               break;
+       case DistortedProgram.ATTR_LAYOUT_PTC:
+               GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, index1 );
+               GLES30.glVertexAttribPointer(attr[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, VERT1_SIZE, OFFSET_POS);
+               GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, index2 );
+               GLES30.glVertexAttribPointer(attr[1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, VERT2_SIZE, OFFSET_TEX);
+               GLES30.glVertexAttribPointer(attr[2], COM_DATA_SIZE, GLES30.GL_FLOAT, false, VERT2_SIZE, OFFSET_COM);
+               break;
+       case DistortedProgram.ATTR_LAYOUT_PT:
+               GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, index1 );
                GLES30.glVertexAttribPointer(attr[0], POS_DATA_SIZE, GLES30.GL_FLOAT, false, VERT1_SIZE, OFFSET_POS);
                GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, index2 );
                GLES30.glVertexAttribPointer(attr[1], TEX_DATA_SIZE, GLES30.GL_FLOAT, false, VERT2_SIZE, OFFSET_TEX);
                break;
+       case DistortedProgram.ATTR_LAYOUT_UNK:
+               DistortedLibrary.logMessage("Unknown attribute layout: "+program.mAttributeLayout);
        }
 
      GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);
diff --git a/src/main/java/org/distorted/library/program/DistortedProgram.java b/src/main/java/org/distorted/library/program/DistortedProgram.java
index 5747d5e..a4feafa 100644
--- a/src/main/java/org/distorted/library/program/DistortedProgram.java
+++ b/src/main/java/org/distorted/library/program/DistortedProgram.java
@@ -35,6 +35,14 @@ import java.io.InputStreamReader;
  */
 public class DistortedProgram
   {
+  public static final int ATTR_LAYOUT_PNTC = 0;
+  public static final int ATTR_LAYOUT_PTC  = 1;
+  public static final int ATTR_LAYOUT_PNT  = 2;
+  public static final int ATTR_LAYOUT_PNC  = 3;
+  public static final int ATTR_LAYOUT_PT   = 4;
+  public static final int ATTR_LAYOUT_P    = 5;
+  public static final int ATTR_LAYOUT_UNK  = 6;
+
   private String mAttributeStr, mUniformStr, mUniList;
   private int mAttributeLen, mUniformLen;
   private int mNumAttributes;
@@ -42,6 +50,14 @@ public class DistortedProgram
   private String[] mAttributeName;
   private final int mProgramHandle;
 
+/**
+ * Various programs have different attributes (because even if the source is the same, some of them might
+ * be unused).
+ * Main, Full have 4 attributes in the order (position,normal,texcoord, component)
+ * Pre has 3 attributes (position,texcoord,component)
+ * Maybe there are other possibilities (only position and normal? 3- position,normal,texcoord?)
+ */
+  public int mAttributeLayout;
 /**
  * List of Attributes (OpenGL ES 3.0: 'in' variables), in the same order as declared in the shader source.
  */
@@ -211,13 +227,13 @@ public class DistortedProgram
 
     for (String line : lines)
       {
-      if (doAttributes)
+      if( doAttributes )
         {
         attribute = parseOutAttribute(line);
 
         if (attribute != null)
           {
-          if (attrList.length() > 0) attrList += " ";
+          if( !attrList.isEmpty() ) attrList += " ";
           attrList += attribute;
           }
         }
@@ -226,7 +242,7 @@ public class DistortedProgram
 
       if (uniform != null)
         {
-        if (mUniList.length() > 0) mUniList += " ";
+        if( !mUniList.isEmpty() ) mUniList += " ";
         mUniList += uniform;
         }
       }
@@ -262,7 +278,7 @@ public class DistortedProgram
           if( attribute!=null )
             {
             //DistortedLibrary.logMessage("DistortedProgram: new attribute: "+attribute);
-            if( attrList.length()>0 ) attrList+=" ";
+            if( !attrList.isEmpty() ) attrList += " ";
             attrList += attribute;
             }
           }
@@ -375,6 +391,52 @@ public class DistortedProgram
       {
       mAttribute = att;
       }
+
+    setUpAttributeLayout();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void setUpAttributeLayout()
+    {
+    switch(mNumAttributes)
+      {
+      case 4: mAttributeLayout = ATTR_LAYOUT_PNTC;
+              break;
+      case 3: if( mAttributeName[2].equals("a_TexCoordinate") ) mAttributeLayout = ATTR_LAYOUT_PNT;
+              else if( mAttributeName[2].equals("a_Component") )
+                {
+                if( mAttributeName[1].equals("a_TexCoordinate") ) mAttributeLayout = ATTR_LAYOUT_PTC;
+                else if( mAttributeName[1].equals("a_Normal"  ) ) mAttributeLayout = ATTR_LAYOUT_PNC;
+                else
+                  {
+                  mAttributeLayout = ATTR_LAYOUT_UNK;
+                  DistortedLibrary.logMessage("DistortedProgram: 1 Error in attribute layout: "+mAttributeName[1]);
+                  }
+                }
+              else
+                {
+                mAttributeLayout = ATTR_LAYOUT_UNK;
+                DistortedLibrary.logMessage("DistortedProgram: 2 Error in attribute layout: "+mAttributeName[2]);
+                }
+              break;
+      case 2: if( mAttributeName[1].equals("a_TexCoordinate") ) mAttributeLayout = ATTR_LAYOUT_PT;
+              else
+                {
+                mAttributeLayout = ATTR_LAYOUT_UNK;
+                DistortedLibrary.logMessage("DistortedProgram: 3 Error in attribute layout: "+mAttributeName[1]);
+                }
+              break;
+      case 1: if( mAttributeName[0].equals("a_Position") ) mAttributeLayout = ATTR_LAYOUT_P;
+              else
+                {
+                mAttributeLayout = ATTR_LAYOUT_UNK;
+                DistortedLibrary.logMessage("DistortedProgram: 4 Error in attribute layout: "+mAttributeName[0]);
+                }
+              break;
+      default:mAttributeLayout = ATTR_LAYOUT_UNK;
+              DistortedLibrary.logMessage("DistortedProgram: 5 Error in attribute layout: "+mNumAttributes);
+      }
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -500,7 +562,6 @@ public class DistortedProgram
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Use the program and enable all vertex attribute arrays.
- *
  * Needs to be called from a thread holding the OpenGL context.
  */
   public void useProgram()
@@ -516,7 +577,6 @@ public class DistortedProgram
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Disable all vertex attribute arrays.
- *
  * Needs to be called from a thread holding the OpenGL context.
  */
   public void stopUsingProgram()
