commit 78ff6ea992ca60e97cd98b300141171b15313f6c
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Thu Jan 7 17:08:15 2021 +0100

    Convert the Integer part (i.e. effect names and the two associations) of vertex and fragment shaders to Uniform Buffer Objects.
    Next: convert the last part, i.e. the float effect parameters.

diff --git a/src/main/java/org/distorted/library/effect/FragmentEffect.java b/src/main/java/org/distorted/library/effect/FragmentEffect.java
index 97bbe53..4bc8b58 100644
--- a/src/main/java/org/distorted/library/effect/FragmentEffect.java
+++ b/src/main/java/org/distorted/library/effect/FragmentEffect.java
@@ -33,9 +33,9 @@ public abstract class FragmentEffect extends Effect
    */
   public static final int NUM_FLOAT_UNIFORMS = 12;
   /**
-   * 1: the name
+   * 4: the name, unused, unused, unused
    */
-  public static final int NUM_INT_UNIFORMS = 1;
+  public static final int NUM_INT_UNIFORMS = 4;
 
   static final int VALUES_OFFSET = 0;
   static final int CENTER_OFFSET = 5;
@@ -67,13 +67,13 @@ public abstract class FragmentEffect extends Effect
 
     mGLSL +=
 
-         "if( fName[i]=="+effect1+")\n"
+         "if( fProperties[i].x =="+effect1+")\n"
         +  "{\n"
         +  "degree = sign(degree); \n"
         +   code +"\n"
         +  "}\n"
         +"else\n"
-        +"if( fName[i]=="+effect2+")\n"
+        +"if( fProperties[i].x =="+effect2+")\n"
         +  "{\n"
         +   code +"\n"
         +  "}\n"
diff --git a/src/main/java/org/distorted/library/effect/MatrixEffectShear.java b/src/main/java/org/distorted/library/effect/MatrixEffectShear.java
index d18c5ff..99a2bec 100644
--- a/src/main/java/org/distorted/library/effect/MatrixEffectShear.java
+++ b/src/main/java/org/distorted/library/effect/MatrixEffectShear.java
@@ -29,7 +29,7 @@ import org.distorted.library.type.Data3D;
  */
 public class MatrixEffectShear extends MatrixEffect
   {
-  private Data3D mShear, mCenter;
+  private final Data3D mShear, mCenter;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
diff --git a/src/main/java/org/distorted/library/effect/VertexEffectShear.java b/src/main/java/org/distorted/library/effect/VertexEffectShear.java
index 61d520d..0308cc7 100644
--- a/src/main/java/org/distorted/library/effect/VertexEffectShear.java
+++ b/src/main/java/org/distorted/library/effect/VertexEffectShear.java
@@ -29,8 +29,7 @@ public class VertexEffectShear extends VertexEffect
   {
   private static final EffectName NAME = EffectName.VERTEX_SHEAR;
 
-  private Data3D mShear;
-  private Data3D mCenter;
+  private final Data3D mShear, mCenter;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueue.java b/src/main/java/org/distorted/library/effectqueue/EffectQueue.java
index 5e778e4..09dc9e2 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueue.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueue.java
@@ -39,6 +39,9 @@ public abstract class EffectQueue implements InternalMaster.Slave
   {
   public static final int MAIN_VARIANTS = 4; // Number of Main program variants (ATM 4: MAIN, MAIN OIT, PREPROCESS, FULL)
 
+  static final int PROP_VERT_UBO_BINDING = 5;
+  static final int PROP_FRAG_UBO_BINDING = 6;
+
   private static final int CREATE = 0;
   private static final int ATTACH = 1;
   private static final int DETACH = 2;
@@ -47,14 +50,14 @@ public abstract class EffectQueue implements InternalMaster.Slave
   long mTime;
   int mNumEffects;              // 'ToBe' will be more than mNumEffects if doWork() hasn't
   private int mNumEffectsToBe;  // added them yet (or less if it hasn't removed some yet)
-  private int mNumFloatUniforms, mNumIntUniforms;
+  private final int mNumFloatUniforms;
   Effect[] mEffects;
 
   float[] mFloatUniforms;
-  int[] mIntUniforms;
+  UniformBlockProperties mUBP;
 
   private long mID;
-  private int mIndex;
+  private final int mIndex;
   private boolean mCreated;
 
   private static class Job
@@ -74,7 +77,7 @@ public abstract class EffectQueue implements InternalMaster.Slave
       }
     }
 
-  private ArrayList<Job> mJobs = new ArrayList<>();
+  private final ArrayList<Job> mJobs;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
    
@@ -87,7 +90,9 @@ public abstract class EffectQueue implements InternalMaster.Slave
     mNumEffectsToBe   = 0;
     mIndex            = index;
     mNumFloatUniforms = numFloatUniforms;
-    mNumIntUniforms   = numIntUniforms;
+
+    mUBP  = new UniformBlockProperties(numIntUniforms);
+    mJobs = new ArrayList<>();
 
     mJobs.add(new Job(CREATE,numFloatUniforms,numIntUniforms, false,null)); // create the stuff that depends on max number
     InternalMaster.newSlave(this);                                          // of uniforms later, on first render.
@@ -107,7 +112,9 @@ public abstract class EffectQueue implements InternalMaster.Slave
       mNumEffectsToBe   = 0;
       mIndex            = source.mIndex;
       mNumFloatUniforms = source.mNumFloatUniforms;
-      mNumIntUniforms   = source.mNumIntUniforms;
+
+      mUBP  = new UniformBlockProperties(source.mUBP);
+      mJobs = new ArrayList<>();
 
       int numJobs = source.mJobs.size();
 
@@ -128,7 +135,9 @@ public abstract class EffectQueue implements InternalMaster.Slave
       mNumEffectsToBe   = source.mNumEffectsToBe;
       mIndex            = source.mIndex;
       mNumFloatUniforms = source.mNumFloatUniforms;
-      mNumIntUniforms   = source.mNumIntUniforms;
+
+      mUBP  = new UniformBlockProperties(source.mUBP);
+      mJobs = new ArrayList<>();
 
       int max = InternalStackFrameList.getMax(mIndex);
 
@@ -136,17 +145,11 @@ public abstract class EffectQueue implements InternalMaster.Slave
         {
         mEffects       = new Effect[max];
         mFloatUniforms = new float[max*source.mNumFloatUniforms];
-        mIntUniforms   = new int[max*source.mNumIntUniforms];
 
         if( mNumEffects>=0 )
           {
           System.arraycopy(source.mEffects, 0, mEffects, 0, mNumEffects);
           }
-
-        if( mNumIntUniforms*mNumEffects>=0 )
-          {
-          System.arraycopy(source.mIntUniforms, 0, mIntUniforms, 0, mNumIntUniforms*mNumEffects);
-          }
         }
       }
     }
@@ -173,12 +176,12 @@ public abstract class EffectQueue implements InternalMaster.Slave
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  public static void send(EffectQueue[] queues, float distance, float mipmap,
+  public static void send(EffectQueue[] queues, int programH, float distance, float mipmap,
                           float[] projection, float inflate, int variant )
     {
     ((EffectQueueMatrix  )queues[0]).send(distance, mipmap, projection, variant);
-    ((EffectQueueVertex  )queues[1]).send(inflate, variant);
-    ((EffectQueueFragment)queues[2]).send(variant);
+    ((EffectQueueVertex  )queues[1]).send(inflate, programH, variant);
+    ((EffectQueueFragment)queues[2]).send(programH, variant);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -252,7 +255,7 @@ public abstract class EffectQueue implements InternalMaster.Slave
       mNumEffects--;
       mEffects[pos].remQueue(this);
       System.arraycopy(mEffects, pos+1, mEffects, pos, mNumEffects-pos);
-      System.arraycopy(mIntUniforms, mNumIntUniforms*(pos+1), mIntUniforms, mNumIntUniforms*pos, mNumIntUniforms*(mNumEffects-pos) );
+      mUBP.remove(pos, mNumEffects);
       mEffects[mNumEffects] = null;
       }
     }
@@ -261,14 +264,13 @@ public abstract class EffectQueue implements InternalMaster.Slave
 
   private void addNow(int pos, Effect effect)
     {
-    mEffects[pos]                     = effect;
-    mIntUniforms[mNumIntUniforms*pos] = effect.getName().ordinal();
-
+    mEffects[pos] = effect;
+    mUBP.addOrdinal(pos, effect.getName().ordinal() );
     effect.addQueue(this);
 
     if( mIndex==EffectType.VERTEX.ordinal() )
       {
-      effect.writeAssociations(mIntUniforms, mNumIntUniforms*pos+1, mNumIntUniforms*pos+3);
+      mUBP.addAssociations(pos,effect);
       }
     }
 
@@ -411,7 +413,7 @@ public abstract class EffectQueue implements InternalMaster.Slave
       {
       if (mEffects[j].getID() == effectID)
         {
-        mEffects[j].writeAssociations(mIntUniforms, mNumIntUniforms*j+1, mNumIntUniforms*j+3);
+        mUBP.addAssociations(j,mEffects[j]);
         }
       }
     }
@@ -435,7 +437,7 @@ public abstract class EffectQueue implements InternalMaster.Slave
                        {
                        mEffects       = new Effect[max];
                        mFloatUniforms = new float[max*job.num1];
-                       mIntUniforms   = new int[max*job.num2];
+                       mUBP           = new UniformBlockProperties(job.num2);
                        }
                      mCreated = true;
 
@@ -452,8 +454,8 @@ public abstract class EffectQueue implements InternalMaster.Slave
                          }
                        else if( position<=mNumEffects )
                          {
-                         System.arraycopy(mEffects    , position, mEffects    , position+1, mNumEffects-position);
-                         System.arraycopy(mIntUniforms, mNumIntUniforms*position, mIntUniforms, mNumIntUniforms*(position+1), mNumIntUniforms*(mNumEffects-position) );
+                         System.arraycopy(mEffects, position, mEffects, position+1, mNumEffects-position);
+                         mUBP.makeHole(position, mNumEffects);
                          addNow(position,job.effect);
                          mNumEffects++;
                          changed = true;
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.java b/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.java
index 1986582..3e47803 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueueFragment.java
@@ -34,9 +34,9 @@ class EffectQueueFragment extends EffectQueue
 
   private static final int INDEX = EffectType.FRAGMENT.ordinal();
 
-  private static int[] mNumEffectsH = new int[MAIN_VARIANTS];
-  private static int[] mNameH       = new int[MAIN_VARIANTS];
-  private static int[] mUniformsH   = new int[MAIN_VARIANTS];
+  private final static int[] mNumEffectsH   = new int[MAIN_VARIANTS];
+  private final static int[] mUniformsH     = new int[MAIN_VARIANTS];
+  private final static int[] mPropBlockIndex= new int[MAIN_VARIANTS];
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
    
@@ -56,9 +56,9 @@ class EffectQueueFragment extends EffectQueue
 
   static void uniforms(int mProgramH, int variant)
     {
-    mNumEffectsH[variant]= GLES30.glGetUniformLocation( mProgramH, "fNumEffects");
-    mNameH[variant]      = GLES30.glGetUniformLocation( mProgramH, "fName");
-    mUniformsH[variant]  = GLES30.glGetUniformLocation( mProgramH, "fUniforms");
+    mNumEffectsH[variant]    = GLES30.glGetUniformLocation  ( mProgramH, "fNumEffects");
+    mUniformsH[variant]      = GLES30.glGetUniformLocation  ( mProgramH, "fUniforms");
+    mPropBlockIndex[variant] = GLES30.glGetUniformBlockIndex( mProgramH, "fUniformProperties");
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -82,13 +82,15 @@ class EffectQueueFragment extends EffectQueue
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
   
-  void send(int variant)
+  void send(int programH, int variant)
     {
     GLES30.glUniform1i( mNumEffectsH[variant], mNumEffects);
 
     if( mNumEffects>0 )
       {
-      GLES30.glUniform1iv( mNameH[variant]    ,                       mNumEffects, mIntUniforms  , 0);
+      int index = mUBP.getIndex();
+      GLES30.glBindBufferBase(GLES30.GL_UNIFORM_BUFFER, PROP_FRAG_UBO_BINDING, index);
+      GLES30.glUniformBlockBinding(programH, mPropBlockIndex[variant], PROP_FRAG_UBO_BINDING);
       GLES30.glUniform4fv( mUniformsH[variant],(NUM_FLOAT_UNIFORMS/4)*mNumEffects, mFloatUniforms, 0);
       }  
     }
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java b/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
index cefe292..aa60ecf 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
@@ -190,7 +190,7 @@ public class EffectQueuePostprocess extends EffectQueue
     EffectQueueVertex vertex = (EffectQueueVertex)queues[1];
 
     matrix.send(distance, mipmap, projection, 2);
-    vertex.send(mHalo*0.01f,2);
+    vertex.send(mHalo*0.01f,mPreProgramH,2);
 
     if( mA!=0.0f )
       {
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueueVertex.java b/src/main/java/org/distorted/library/effectqueue/EffectQueueVertex.java
index 6aff552..b915cd9 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueueVertex.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueueVertex.java
@@ -38,10 +38,10 @@ public class EffectQueueVertex extends EffectQueue
 
   private static final int INDEX = EffectType.VERTEX.ordinal();
 
-  private static int[] mNumEffectsH = new int[MAIN_VARIANTS];
-  private static int[] mInflateH    = new int[MAIN_VARIANTS];
-  private static int[] mPropertiesH = new int[MAIN_VARIANTS];
-  private static int[] mUniformsH   = new int[MAIN_VARIANTS];
+  private final static int[] mNumEffectsH   = new int[MAIN_VARIANTS];
+  private final static int[] mInflateH      = new int[MAIN_VARIANTS];
+  private final static int[] mUniformsH     = new int[MAIN_VARIANTS];
+  private final static int[] mPropBlockIndex= new int[MAIN_VARIANTS];
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
    
@@ -61,10 +61,10 @@ public class EffectQueueVertex extends EffectQueue
 
   static void uniforms(int mProgramH, int variant)
     {
-    mNumEffectsH[variant]= GLES30.glGetUniformLocation( mProgramH, "vNumEffects");
-    mInflateH[variant]   = GLES30.glGetUniformLocation( mProgramH, "u_Inflate");
-    mPropertiesH[variant]= GLES30.glGetUniformLocation( mProgramH, "vProperties");
-    mUniformsH[variant]  = GLES30.glGetUniformLocation( mProgramH, "vUniforms");
+    mNumEffectsH[variant]    = GLES30.glGetUniformLocation  ( mProgramH, "vNumEffects");
+    mInflateH[variant]       = GLES30.glGetUniformLocation  ( mProgramH, "u_Inflate");
+    mUniformsH[variant]      = GLES30.glGetUniformLocation  ( mProgramH, "vUniforms");
+    mPropBlockIndex[variant] = GLES30.glGetUniformBlockIndex( mProgramH, "vUniformProperties");
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -96,14 +96,16 @@ public class EffectQueueVertex extends EffectQueue
  *
  * @y.exclude
  */
-  public void send(float inflate, int variant)
+  public void send(float inflate, int programH, int variant)
     {
     GLES30.glUniform1i( mNumEffectsH[variant], mNumEffects);
     GLES30.glUniform1f( mInflateH[variant]   , inflate    );
 
     if( mNumEffects>0 )
       {
-      GLES30.glUniform4iv( mPropertiesH[variant],                       mNumEffects, mIntUniforms   , 0);
+      int index = mUBP.getIndex();
+      GLES30.glBindBufferBase(GLES30.GL_UNIFORM_BUFFER, PROP_VERT_UBO_BINDING, index);
+      GLES30.glUniformBlockBinding(programH, mPropBlockIndex[variant], PROP_VERT_UBO_BINDING);
       GLES30.glUniform4fv( mUniformsH[variant]  ,(NUM_FLOAT_UNIFORMS/4)*mNumEffects, mFloatUniforms , 0);
       }
     }
diff --git a/src/main/java/org/distorted/library/effectqueue/UniformBlockProperties.java b/src/main/java/org/distorted/library/effectqueue/UniformBlockProperties.java
new file mode 100644
index 0000000..492dbd7
--- /dev/null
+++ b/src/main/java/org/distorted/library/effectqueue/UniformBlockProperties.java
@@ -0,0 +1,126 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2021 Leszek Koltunski                                                               //
+//                                                                                               //
+// This file is part of Distorted.                                                               //
+//                                                                                               //
+// Distorted is free software: you can redistribute it and/or modify                             //
+// it under the terms of the GNU General Public License as published by                          //
+// the Free Software Foundation, either version 2 of the License, or                             //
+// (at your option) any later version.                                                           //
+//                                                                                               //
+// Distorted is distributed in the hope that it will be useful,                                  //
+// but WITHOUT ANY WARRANTY; without even the implied warranty of                                //
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                                 //
+// GNU General Public License for more details.                                                  //
+//                                                                                               //
+// You should have received a copy of the GNU General Public License                             //
+// along with Distorted.  If not, see <http://www.gnu.org/licenses/>.                            //
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+package org.distorted.library.effectqueue;
+
+import android.opengl.GLES30;
+
+import org.distorted.library.effect.Effect;
+import org.distorted.library.main.InternalBuffer;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class UniformBlockProperties
+  {
+  private static final int NUM_BYTES = 4*100;
+
+  private final InternalBuffer mUBO;
+  private final int[] mProperties;
+  private final int mNumIntUniforms;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  UniformBlockProperties(int numUniforms)
+    {
+    mProperties= new int[NUM_BYTES/4];
+    mNumIntUniforms = numUniforms;
+    mUBO = new InternalBuffer(GLES30.GL_UNIFORM_BUFFER, GLES30.GL_STATIC_READ);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  UniformBlockProperties(UniformBlockProperties original)
+    {
+    int size = original.mProperties.length;
+    mProperties= new int[size];
+    System.arraycopy(original.mProperties, 0, mProperties, 0, size);
+    mNumIntUniforms = original.mNumIntUniforms;
+
+    mUBO = new InternalBuffer(GLES30.GL_UNIFORM_BUFFER, GLES30.GL_STATIC_READ);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  int getIndex()
+    {
+    return mUBO.createImmediatelyInt( NUM_BYTES, mProperties);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void remove(int pos, int numEffects)
+    {
+    System.arraycopy(mProperties, mNumIntUniforms*(pos+1), mProperties, mNumIntUniforms*pos, mNumIntUniforms*(numEffects-pos) );
+    mUBO.invalidate();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void makeHole(int pos, int numEffects)
+    {
+    System.arraycopy(mProperties, mNumIntUniforms*pos, mProperties, mNumIntUniforms*(pos+1), mNumIntUniforms*(numEffects-pos) );
+    mUBO.invalidate();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void addOrdinal(int pos, int ordinal)
+    {
+    mProperties[mNumIntUniforms*pos] = ordinal;
+    mUBO.invalidate();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void addAssociations(int pos, Effect effect)
+    {
+    effect.writeAssociations(mProperties, mNumIntUniforms*pos+1, mNumIntUniforms*pos+3);
+    mUBO.invalidate();
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  void print(int num)
+    {
+    StringBuilder builder = new StringBuilder();
+
+    builder.append(mUBO.getID());
+    builder.append(':');
+
+    for(int i=0; i<6; i++)
+      {
+      builder.append(' ');
+      builder.append(mProperties[4*i  ]);
+      builder.append(' ');
+      builder.append(mProperties[4*i+1]);
+      builder.append(' ');
+      builder.append(mProperties[4*i+2]);
+      builder.append(',');
+      }
+
+    builder.append(' ');
+    builder.append('(');
+    builder.append(num);
+    builder.append(')');
+
+    String res = builder.toString();
+
+    android.util.Log.e("ubp", res);
+    }
+  }
diff --git a/src/main/java/org/distorted/library/main/DistortedLibrary.java b/src/main/java/org/distorted/library/main/DistortedLibrary.java
index 71b98d0..365957d 100644
--- a/src/main/java/org/distorted/library/main/DistortedLibrary.java
+++ b/src/main/java/org/distorted/library/main/DistortedLibrary.java
@@ -116,7 +116,10 @@ public class DistortedLibrary
   private static int mGLSL;
   private static String mGLSL_VERSION;
   private static boolean mOITCompilationAttempted;
-  private static int mMaxTextureSize = Integer.MAX_VALUE;
+
+  private static int mMaxTextureSize         = Integer.MAX_VALUE;
+  private static int mMaxNumberOfVerUniforms = Integer.MAX_VALUE;
+  private static int mMaxNumberOfFraUniforms = Integer.MAX_VALUE;
 
   //////////////////////////////////////////////////////////////////////////////////////////////
   /// MAIN PROGRAM ///
@@ -547,7 +550,7 @@ public class DistortedLibrary
     mFullProgram.useProgram();
     mesh.bindVertexAttribs(mFullProgram);
     queue.compute(1);
-    queue.send(0.0f,3);
+    queue.send(0.0f,mFullProgramH,3);
     mesh.send(mFullProgramH,3);
 
     GLES30.glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfo );
@@ -583,14 +586,14 @@ public class DistortedLibrary
       float mipmap      = surface.mMipmap;
       float[] projection= surface.mProjectionMatrix;
 
-      EffectQueue.send(queues, distance, mipmap, projection, inflate, 1 );
+      EffectQueue.send(queues, mMainOITProgramH, distance, mipmap, projection, inflate, 1 );
       GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices() );
 
       if( mesh.getShowNormals() )
         {
         mMainProgram.useProgram();
         mesh.send(mMainProgramH,0);
-        EffectQueue.send(queues, distance, mipmap, projection, inflate, 0 );
+        EffectQueue.send(queues, mMainProgramH, distance, mipmap, projection, inflate, 0 );
         displayNormals(projection,mesh);
         }
       }
@@ -617,7 +620,7 @@ public class DistortedLibrary
       float mipmap      = surface.mMipmap;
       float[] projection= surface.mProjectionMatrix;
 
-      EffectQueue.send(queues, distance, mipmap, projection, inflate, 0 );
+      EffectQueue.send(queues, mMainProgramH, distance, mipmap, projection, inflate, 0 );
       GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices() );
 
       if( mesh.getShowNormals() ) displayNormals(projection,mesh);
@@ -984,11 +987,19 @@ public class DistortedLibrary
       mGLSL = (major==3 && minor==0) ? 300 : 310;
       }
 
-    int[] maxTextureSize = new int[1];
-    GLES30.glGetIntegerv(GLES30.GL_MAX_TEXTURE_SIZE, maxTextureSize, 0);
-    mMaxTextureSize = maxTextureSize[0];
+    int[] tmp = new int[1];
+    GLES30.glGetIntegerv(GLES30.GL_MAX_TEXTURE_SIZE, tmp, 0);
+    mMaxTextureSize = tmp[0];
+    GLES30.glGetIntegerv(GLES30.GL_MAX_VERTEX_UNIFORM_VECTORS  , tmp, 0);
+    mMaxNumberOfVerUniforms = tmp[0];
+    GLES30.glGetIntegerv(GLES30.GL_MAX_FRAGMENT_UNIFORM_VECTORS, tmp, 0);
+    mMaxNumberOfFraUniforms = tmp[0];
 
     android.util.Log.e("DISTORTED", "Using OpenGL ES "+major+"."+minor);
+    android.util.Log.e("DISTORTED", "max texture size: "+mMaxTextureSize);
+    android.util.Log.e("DISTORTED", "max num vert: "+mMaxNumberOfVerUniforms);
+    android.util.Log.e("DISTORTED", "max num frag: "+mMaxNumberOfFraUniforms);
+
     mGLSL_VERSION = "#version "+mGLSL+" es\n";
 
     InternalStackFrameList.setInitialized(true);
diff --git a/src/main/java/org/distorted/library/mesh/MeshBase.java b/src/main/java/org/distorted/library/mesh/MeshBase.java
index 34c454c..264c4be 100644
--- a/src/main/java/org/distorted/library/mesh/MeshBase.java
+++ b/src/main/java/org/distorted/library/mesh/MeshBase.java
@@ -83,20 +83,20 @@ public abstract class MeshBase
    private float[] mVertAttribs1;             // packed: PosX,PosY,PosZ, NorX,NorY,NorZ
    private float[] mVertAttribs2;             // packed: TexS,TexT, Component
    private float mInflate;
-   private UniformBlockAssociation mUBA;
-   private UniformBlockCenter mUBC;
+   private final UniformBlockAssociation mUBA;
+   private final UniformBlockCenter mUBC;
 
    DeferredJobs.JobNode[] mJobNode;
 
-   private static int[] mCenterBlockIndex = new int[EffectQueue.MAIN_VARIANTS];
-   private static int[] mAssocBlockIndex  = new int[EffectQueue.MAIN_VARIANTS];
+   private static final int[] mCenterBlockIndex = new int[EffectQueue.MAIN_VARIANTS];
+   private static final int[] mAssocBlockIndex  = new int[EffectQueue.MAIN_VARIANTS];
 
    private static final int TEX_COMP_SIZE = 5; // 5 four-byte entities inside the component
 
    private static class TexComponent
      {
      private int mEndIndex;
-     private Static4D mTextureMap;
+     private final Static4D mTextureMap;
 
      TexComponent(int end)
        {
diff --git a/src/main/java/org/distorted/library/mesh/UniformBlockAssociation.java b/src/main/java/org/distorted/library/mesh/UniformBlockAssociation.java
index 2c85ec6..9d79a17 100644
--- a/src/main/java/org/distorted/library/mesh/UniformBlockAssociation.java
+++ b/src/main/java/org/distorted/library/mesh/UniformBlockAssociation.java
@@ -32,8 +32,8 @@ class UniformBlockAssociation
   private static final int BLOCK_SIZE = 16*MAX_EFFECT_COMPONENTS;
   private static final int DEFAULT_ASSOCIATION = 0xffffffff;
 
-  private InternalBuffer mUBO;
-  private int[] mAssociations;
+  private final InternalBuffer mUBO;
+  private final int[] mAssociations;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
diff --git a/src/main/java/org/distorted/library/mesh/UniformBlockCenter.java b/src/main/java/org/distorted/library/mesh/UniformBlockCenter.java
index b642b9b..9dd0711 100644
--- a/src/main/java/org/distorted/library/mesh/UniformBlockCenter.java
+++ b/src/main/java/org/distorted/library/mesh/UniformBlockCenter.java
@@ -31,8 +31,8 @@ class UniformBlockCenter
   {
   private static final int BLOCK_SIZE = 16*MAX_EFFECT_COMPONENTS;
 
-  private InternalBuffer mUBO;
-  private float[] mCenter;
+  private final InternalBuffer mUBO;
+  private final float[] mCenter;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
diff --git a/src/main/java/org/distorted/library/type/Dynamic.java b/src/main/java/org/distorted/library/type/Dynamic.java
index c11216e..27fe92a 100644
--- a/src/main/java/org/distorted/library/type/Dynamic.java
+++ b/src/main/java/org/distorted/library/type/Dynamic.java
@@ -185,7 +185,7 @@ public abstract class Dynamic
     mLastPos   = -1;
     mAccessType= ACCESS_TYPE_RANDOM;
     mConvexity = 1.0f;
-    mStartTime = 0;
+    mStartTime = -1;
     mCorrectedTime = 0;
 
     baseV      = new float[mDimension][mDimension];
@@ -587,7 +587,7 @@ public abstract class Dynamic
  */
   public void resetToBeginning()
     {
-    mStartTime = 0;
+    mStartTime = -1;
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -686,7 +686,7 @@ public abstract class Dynamic
       return false;
       }
 
-    if( mStartTime==0 )
+    if( mStartTime==-1 )
       {
       mStartTime = time;
       mLastPos   = -1;
diff --git a/src/main/res/raw/main_fragment_shader.glsl b/src/main/res/raw/main_fragment_shader.glsl
index 4809b6e..8c80e1f 100644
--- a/src/main/res/raw/main_fragment_shader.glsl
+++ b/src/main/res/raw/main_fragment_shader.glsl
@@ -46,7 +46,13 @@ layout (std430,binding=1) buffer linkedlist  // first (u_Size.x*u_Size.y) uints
 
 #if NUM_FRAGMENT>0
 uniform int fNumEffects;                // total number of fragment effects
-uniform int fName[NUM_FRAGMENT];        // their namess.
+
+layout (std140) uniform fUniformProperties
+  {
+  ivec4 fProperties[NUM_FRAGMENT];      // their properties, 4 ints:
+                                        // name of the effect, unused, unused, unused
+  };
+
 uniform vec4 fUniforms[3*NUM_FRAGMENT]; // i-th effect is 3 consecutive vec4's: [3*i], [3*i+1], [3*i+2].
                                         // The first vec4 is the Interpolated values,
                                         // second vec4: first float - cache, next 3: Center, the third - the Region.
diff --git a/src/main/res/raw/main_vertex_shader.glsl b/src/main/res/raw/main_vertex_shader.glsl
index 9e04bd7..b4f2761 100644
--- a/src/main/res/raw/main_vertex_shader.glsl
+++ b/src/main/res/raw/main_vertex_shader.glsl
@@ -46,11 +46,15 @@ layout (std140) uniform componentCenter
 
 #if NUM_VERTEX>0
 uniform int vNumEffects;              // total number of vertex effects
-uniform ivec4 vProperties[NUM_VERTEX];// their properties, 4 ints:
+
+layout (std140) uniform vUniformProperties
+  {
+  ivec4 vProperties[NUM_VERTEX];      // their properties, 4 ints:
                                       // 1: name of the effect
                                       // 2: effect's AND association
                                       // 3: reserved int (probably another AND assoc in the future)
                                       // 4: effect's EQU association
+  };
 
 uniform vec4 vUniforms[3*NUM_VERTEX]; // i-th effect is 3 consecutive vec4's: [3*i], [3*i+1], [3*i+2].
                                       // The first vec4 is the Interpolated values,
