commit 62c869adbd41289fd2a3f8065a6811a5dc17d6cb
Author: Leszek Koltunski <leszek@koltunski.pl>
Date:   Fri Aug 7 00:50:36 2020 +0100

    Fix normals in case of MatrixEffectScale / Shear.
    Fix displaying the normal vector.

diff --git a/src/main/java/org/distorted/library/effect/MatrixEffect.java b/src/main/java/org/distorted/library/effect/MatrixEffect.java
index bd3b250..e556494 100644
--- a/src/main/java/org/distorted/library/effect/MatrixEffect.java
+++ b/src/main/java/org/distorted/library/effect/MatrixEffect.java
@@ -37,7 +37,7 @@ public abstract class MatrixEffect extends Effect
  *
  * @y.exclude
  */
-  public abstract void apply(float[] matrix, float[] uniforms, int index);
+  public abstract void apply(float[] matrixP, float[] matrixV, float[] uniforms, int index);
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // empty function for completeness
diff --git a/src/main/java/org/distorted/library/effect/MatrixEffectMove.java b/src/main/java/org/distorted/library/effect/MatrixEffectMove.java
index 6be6a7f..e153ab9 100644
--- a/src/main/java/org/distorted/library/effect/MatrixEffectMove.java
+++ b/src/main/java/org/distorted/library/effect/MatrixEffectMove.java
@@ -48,13 +48,14 @@ public class MatrixEffectMove extends MatrixEffect
  *
  * @y.exclude
  */
-  public void apply(float[] matrix, float[] uniforms, int index)
+  public void apply(float[] matrixP, float[] matrixV, float[] uniforms, int index)
     {
     float sx = uniforms[NUM_UNIFORMS*index  ];
     float sy = uniforms[NUM_UNIFORMS*index+1];
     float sz = uniforms[NUM_UNIFORMS*index+2];
 
-    Matrix.translateM(matrix, 0, sx, sy, sz);
+    Matrix.translateM(matrixP, 0, sx, sy, sz);
+    Matrix.translateM(matrixV, 0, sx, sy, sz);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/effect/MatrixEffectQuaternion.java b/src/main/java/org/distorted/library/effect/MatrixEffectQuaternion.java
index 5483326..37fdb06 100644
--- a/src/main/java/org/distorted/library/effect/MatrixEffectQuaternion.java
+++ b/src/main/java/org/distorted/library/effect/MatrixEffectQuaternion.java
@@ -54,7 +54,7 @@ public class MatrixEffectQuaternion extends MatrixEffect
  *
  * @y.exclude
  */
-  public void apply(float[] matrix, float[] uniforms, int index)
+  public void apply(float[] matrixP, float[] matrixV, float[] uniforms, int index)
     {
     float qX = uniforms[NUM_UNIFORMS*index  ];
     float qY = uniforms[NUM_UNIFORMS*index+1];
@@ -65,9 +65,13 @@ public class MatrixEffectQuaternion extends MatrixEffect
     float y = uniforms[NUM_UNIFORMS*index+CENTER_OFFSET+1];
     float z = uniforms[NUM_UNIFORMS*index+CENTER_OFFSET+2];
 
-    Matrix.translateM(matrix, 0, x, y, z);
-    multiplyByQuat( matrix, qX, qY, qZ, qW);
-    Matrix.translateM(matrix, 0,-x,-y,-z);
+    Matrix.translateM(matrixP, 0, x, y, z);
+    multiplyByQuat   (matrixP, qX, qY, qZ, qW);
+    Matrix.translateM(matrixP, 0,-x,-y,-z);
+
+    Matrix.translateM(matrixV, 0, x, y, z);
+    multiplyByQuat   (matrixV, qX, qY, qZ, qW);
+    Matrix.translateM(matrixV, 0,-x,-y,-z);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/effect/MatrixEffectRotate.java b/src/main/java/org/distorted/library/effect/MatrixEffectRotate.java
index e75cc36..a2c1694 100644
--- a/src/main/java/org/distorted/library/effect/MatrixEffectRotate.java
+++ b/src/main/java/org/distorted/library/effect/MatrixEffectRotate.java
@@ -52,7 +52,7 @@ public class MatrixEffectRotate extends MatrixEffect
  *
  * @y.exclude
  */
-  public void apply(float[] matrix, float[] uniforms, int index)
+  public void apply(float[] matrixP, float[] matrixV, float[] uniforms, int index)
     {
     float angle = uniforms[NUM_UNIFORMS*index  ];
     float axisX = uniforms[NUM_UNIFORMS*index+1];
@@ -63,9 +63,13 @@ public class MatrixEffectRotate extends MatrixEffect
     float y = uniforms[NUM_UNIFORMS*index+CENTER_OFFSET+1];
     float z = uniforms[NUM_UNIFORMS*index+CENTER_OFFSET+2];
 
-    Matrix.translateM(matrix, 0, x, y, z);
-    Matrix.rotateM( matrix, 0, angle, axisX, axisY, axisZ);
-    Matrix.translateM(matrix, 0,-x,-y,-z);
+    Matrix.translateM(matrixP, 0, x, y, z);
+    Matrix.rotateM   (matrixP, 0, angle, axisX, axisY, axisZ);
+    Matrix.translateM(matrixP, 0,-x,-y,-z);
+
+    Matrix.translateM(matrixV, 0, x, y, z);
+    Matrix.rotateM   (matrixV, 0, angle, axisX, axisY, axisZ);
+    Matrix.translateM(matrixV, 0,-x,-y,-z);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/effect/MatrixEffectScale.java b/src/main/java/org/distorted/library/effect/MatrixEffectScale.java
index 4d36383..9019063 100644
--- a/src/main/java/org/distorted/library/effect/MatrixEffectScale.java
+++ b/src/main/java/org/distorted/library/effect/MatrixEffectScale.java
@@ -46,16 +46,23 @@ public class MatrixEffectScale extends MatrixEffect
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Only for use by the library itself.
+ * <p>
+ * Here and in Shear we have the whole reason why there are two separate 'P' and 'V' (Point and
+ * Vector) matrices - Scale and Shear have to manipulate Points and Normal Vectors differently.
+ *
+ * Points get multiplied by (sx,sy,sz) - and vectors by (1/sx,1/sy,1/sz) (think about it!) - or
+ * better by sx*sy*sz*(1/sx,1/sy,1/sz) to avoid dividing my zero (vectors are normalized after)
  *
  * @y.exclude
  */
-  public void apply(float[] matrix, float[] uniforms, int index)
+  public void apply(float[] matrixP, float[] matrixV, float[] uniforms, int index)
     {
     float sx = uniforms[NUM_UNIFORMS*index  ];
     float sy = uniforms[NUM_UNIFORMS*index+1];
     float sz = uniforms[NUM_UNIFORMS*index+2];
 
-    Matrix.scaleM(matrix, 0, sx, sy, sz);
+    Matrix.scaleM(matrixP, 0, sx, sy, sz);
+    Matrix.scaleM(matrixV, 0, sy*sz, sx*sz, sx*sy);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/effect/MatrixEffectShear.java b/src/main/java/org/distorted/library/effect/MatrixEffectShear.java
index 93e83ff..b5c5a09 100644
--- a/src/main/java/org/distorted/library/effect/MatrixEffectShear.java
+++ b/src/main/java/org/distorted/library/effect/MatrixEffectShear.java
@@ -46,10 +46,13 @@ public class MatrixEffectShear extends MatrixEffect
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 /**
  * Only for use by the library itself.
+ * <p>
+ * Here and in Shear we have the whole reason why there are two separate 'P' and 'V' (Point and
+ * Vector) matrices - Scale and Shear have to manipulate Points and Normal Vectors differently.
  *
  * @y.exclude
  */
-  public void apply(float[] matrix, float[] uniforms, int index)
+  public void apply(float[] matrixP, float[] matrixV, float[] uniforms, int index)
     {
     float sx = uniforms[NUM_UNIFORMS*index  ];
     float sy = uniforms[NUM_UNIFORMS*index+1];
@@ -59,24 +62,43 @@ public class MatrixEffectShear extends MatrixEffect
     float y  = uniforms[NUM_UNIFORMS*index+CENTER_OFFSET+1];
     float z  = uniforms[NUM_UNIFORMS*index+CENTER_OFFSET+2];
 
-    Matrix.translateM(matrix, 0, x, y, z);
+    Matrix.translateM(matrixP, 0, x, y, z);
 
-    matrix[4] += sx*matrix[0]; // Multiply viewMatrix by 1 x 0 0 , i.e. X-shear.
-    matrix[5] += sx*matrix[1]; //                        0 1 0 0
-    matrix[6] += sx*matrix[2]; //                        0 0 1 0
-    matrix[7] += sx*matrix[3]; //                        0 0 0 1
+    matrixP[4] += sx*matrixP[0]; // Multiply viewMatrix by 1 x 0 0 , i.e. X-shear.
+    matrixP[5] += sx*matrixP[1]; //                        0 1 0 0
+    matrixP[6] += sx*matrixP[2]; //                        0 0 1 0
+    matrixP[7] += sx*matrixP[3]; //                        0 0 0 1
 
-    matrix[0] += sy*matrix[4]; // Multiply viewMatrix by 1 0 0 0 , i.e. Y-shear.
-    matrix[1] += sy*matrix[5]; //                        y 1 0 0
-    matrix[2] += sy*matrix[6]; //                        0 0 1 0
-    matrix[3] += sy*matrix[7]; //                        0 0 0 1
+    matrixP[0] += sy*matrixP[4]; // Multiply viewMatrix by 1 0 0 0 , i.e. Y-shear.
+    matrixP[1] += sy*matrixP[5]; //                        y 1 0 0
+    matrixP[2] += sy*matrixP[6]; //                        0 0 1 0
+    matrixP[3] += sy*matrixP[7]; //                        0 0 0 1
 
-    matrix[4] += sz*matrix[8]; // Multiply viewMatrix by 1 0 0 0 , i.e. Z-shear.
-    matrix[5] += sz*matrix[9]; //                        0 1 0 0
-    matrix[6] += sz*matrix[10];//                        0 z 1 0
-    matrix[7] += sz*matrix[11];//                        0 0 0 1
+    matrixP[4] += sz*matrixP[8]; // Multiply viewMatrix by 1 0 0 0 , i.e. Z-shear.
+    matrixP[5] += sz*matrixP[9]; //                        0 1 0 0
+    matrixP[6] += sz*matrixP[10];//                        0 z 1 0
+    matrixP[7] += sz*matrixP[11];//                        0 0 0 1
 
-    Matrix.translateM(matrix, 0,-x,-y,-z);
+    Matrix.translateM(matrixP, 0,-x,-y,-z);
+
+    Matrix.translateM(matrixV, 0, x, y, z);
+
+    matrixV[0] -= sx*matrixV[4]; // Multiply viewMatrix by 1 0 0 0 , i.e. vector X-shear.
+    matrixV[1] -= sx*matrixV[5]; //                       -x 1 0 0
+    matrixV[2] -= sx*matrixV[6]; //                        0 0 1 0
+    matrixV[3] -= sx*matrixV[7]; //                        0 0 0 1
+
+    matrixV[4] -= sy*matrixV[0]; // Multiply viewMatrix by 1-y 0 0 , i.e. vector Y-shear.
+    matrixV[5] -= sy*matrixV[1]; //                        0 1 0 0
+    matrixV[6] -= sy*matrixV[2]; //                        0 0 1 0
+    matrixV[7] -= sy*matrixV[3]; //                        0 0 0 1
+
+    matrixV[8] -= sz*matrixV[4]; // Multiply viewMatrix by 1 0 0 0 , i.e. vector Z-shear.
+    matrixV[9] -= sz*matrixV[5]; //                        0 1-z 0
+    matrixV[10]-= sz*matrixV[6]; //                        0 0 1 0
+    matrixV[11]-= sz*matrixV[7]; //                        0 0 0 1
+
+    Matrix.translateM(matrixV, 0,-x,-y,-z);
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueue.java b/src/main/java/org/distorted/library/effectqueue/EffectQueue.java
index 15c3869..493ccf3 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueue.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueue.java
@@ -179,20 +179,13 @@ public abstract class EffectQueue implements InternalMaster.Slave
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   public static void send(EffectQueue[] queues, float distance, float mipmap,
-                          float[] projection, float inflate, MeshBase mesh, int variant )
+                          float[] projection, float inflate, int variant )
     {
-    ((EffectQueueMatrix  )queues[0]).send(distance, mipmap, projection, mesh, variant);
+    ((EffectQueueMatrix  )queues[0]).send(distance, mipmap, projection, variant);
     ((EffectQueueVertex  )queues[1]).send(inflate, variant);
     ((EffectQueueFragment)queues[2]).send(variant);
     }
 
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-  public static float[] getMVP(EffectQueue[] queues)
-    {
-    return ((EffectQueueMatrix)queues[0]).getMVP();
-    }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // variant: 0 --> MAIN  1 --> OIT  2 --> prePOST  3 --> FULL
 
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueueMatrix.java b/src/main/java/org/distorted/library/effectqueue/EffectQueueMatrix.java
index 66db325..111002a 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueueMatrix.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueueMatrix.java
@@ -24,7 +24,6 @@ import android.opengl.Matrix;
 
 import org.distorted.library.effect.EffectType;
 import org.distorted.library.effect.MatrixEffect;
-import org.distorted.library.mesh.MeshBase;
 import org.distorted.library.message.EffectMessageSender;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -35,10 +34,12 @@ class EffectQueueMatrix extends EffectQueue
   private static final int INDEX = EffectType.MATRIX.ordinal();
 
   private static float[] mMVPMatrix       = new float[16];
-  private static float[] mModelViewMatrix = new float[16];
+  private static float[] mModelViewMatrixP= new float[16];
+  private static float[] mModelViewMatrixV= new float[16];
 
   private static int[] mMVPMatrixH = new int[MAIN_VARIANTS];
-  private static int[] mMVMatrixH  = new int[MAIN_VARIANTS];
+  private static int[] mMVMatrixPH = new int[MAIN_VARIANTS];
+  private static int[] mMVMatrixVH = new int[MAIN_VARIANTS];
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
    
@@ -59,7 +60,8 @@ class EffectQueueMatrix extends EffectQueue
   static void uniforms(int mProgramH, int variant)
     {
     mMVPMatrixH[variant]= GLES30.glGetUniformLocation(mProgramH, "u_MVPMatrix");
-    mMVMatrixH[variant] = GLES30.glGetUniformLocation(mProgramH, "u_MVMatrix");
+    mMVMatrixPH[variant]= GLES30.glGetUniformLocation(mProgramH, "u_MVMatrixP");
+    mMVMatrixVH[variant]= GLES30.glGetUniformLocation(mProgramH, "u_MVMatrixV");
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -83,28 +85,44 @@ class EffectQueueMatrix extends EffectQueue
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  float[] getMVP()
+  void send(float distance, float mipmap, float[] projection, int variant)
     {
-    return mMVPMatrix;
-    }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
+    Matrix.setIdentityM(mModelViewMatrixP, 0);
+    Matrix.translateM(mModelViewMatrixP, 0, 0,0, -distance);
 
-  void send(float distance, float mipmap, float[] projection, MeshBase mesh, int variant)
-    {
-    Matrix.setIdentityM(mModelViewMatrix, 0);
+    if( mipmap!=1 )
+      {
+      Matrix.scaleM(mModelViewMatrixP, 0, mipmap, mipmap, mipmap);
+      }
 
-    // The 'View' part of the MV matrix
-    Matrix.translateM(mModelViewMatrix, 0, 0,0, -distance);
-    if( mipmap!=1 ) Matrix.scaleM(mModelViewMatrix, 0, mipmap, mipmap, mipmap);
+    mModelViewMatrixV[ 0] = mModelViewMatrixP[ 0];
+    mModelViewMatrixV[ 1] = mModelViewMatrixP[ 1];
+    mModelViewMatrixV[ 2] = mModelViewMatrixP[ 2];
+    mModelViewMatrixV[ 3] = mModelViewMatrixP[ 3];
+    mModelViewMatrixV[ 4] = mModelViewMatrixP[ 4];
+    mModelViewMatrixV[ 5] = mModelViewMatrixP[ 5];
+    mModelViewMatrixV[ 6] = mModelViewMatrixP[ 6];
+    mModelViewMatrixV[ 7] = mModelViewMatrixP[ 7];
+    mModelViewMatrixV[ 8] = mModelViewMatrixP[ 8];
+    mModelViewMatrixV[ 9] = mModelViewMatrixP[ 9];
+    mModelViewMatrixV[10] = mModelViewMatrixP[10];
+    mModelViewMatrixV[11] = mModelViewMatrixP[11];
+    mModelViewMatrixV[12] = mModelViewMatrixP[12];
+    mModelViewMatrixV[13] = mModelViewMatrixP[13];
+    mModelViewMatrixV[14] = mModelViewMatrixP[14];
+    mModelViewMatrixV[15] = mModelViewMatrixP[15];
 
     // the 'Model' part of the MV matrix
-    for(int i=mNumEffects-1; i>=0; i--) ((MatrixEffect)mEffects[i]).apply(mModelViewMatrix,mUniforms,i);
+    for(int i=mNumEffects-1; i>=0; i--)
+      {
+      ((MatrixEffect)mEffects[i]).apply(mModelViewMatrixP,mModelViewMatrixV,mUniforms,i);
+      }
 
     // combined Model-View-Projection matrix
-    Matrix.multiplyMM(mMVPMatrix, 0, projection, 0, mModelViewMatrix, 0);
+    Matrix.multiplyMM(mMVPMatrix, 0, projection, 0, mModelViewMatrixP, 0);
 
-    GLES30.glUniformMatrix4fv(mMVMatrixH[variant] , 1, false, mModelViewMatrix, 0);
-    GLES30.glUniformMatrix4fv(mMVPMatrixH[variant], 1, false, mMVPMatrix      , 0);
+    GLES30.glUniformMatrix4fv(mMVMatrixVH[variant], 1, false, mModelViewMatrixV, 0);
+    GLES30.glUniformMatrix4fv(mMVMatrixPH[variant], 1, false, mModelViewMatrixP, 0);
+    GLES30.glUniformMatrix4fv(mMVPMatrixH[variant], 1, false, mMVPMatrix       , 0);
     }
   }
diff --git a/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java b/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
index a66108c..848ca71 100644
--- a/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
+++ b/src/main/java/org/distorted/library/effectqueue/EffectQueuePostprocess.java
@@ -187,7 +187,7 @@ public class EffectQueuePostprocess extends EffectQueue
     EffectQueueMatrix matrix = (EffectQueueMatrix)queues[0];
     EffectQueueVertex vertex = (EffectQueueVertex)queues[1];
 
-    matrix.send(distance, mipmap, projection, mesh, 2);
+    matrix.send(distance, mipmap, projection, 2);
     vertex.send(mHalo*0.01f,2);
 
     if( mA!=0.0f )
diff --git a/src/main/java/org/distorted/library/main/DistortedLibrary.java b/src/main/java/org/distorted/library/main/DistortedLibrary.java
index 05f387a..0e89ead 100644
--- a/src/main/java/org/distorted/library/main/DistortedLibrary.java
+++ b/src/main/java/org/distorted/library/main/DistortedLibrary.java
@@ -123,10 +123,11 @@ public class DistortedLibrary
   /// MAIN PROGRAM ///
   private static DistortedProgram mMainProgram;
   private static int mMainTextureH;
+  private static int mTransformFeedbackH;
 
   /// NORMAL PROGRAM /////
   private static DistortedProgram mNormalProgram;
-  private static int mNormalMVPMatrixH;
+  private static int mNormalProjectionH;
 
   /// MAIN OIT PROGRAM ///
   private static DistortedProgram mMainOITProgram;
@@ -262,6 +263,7 @@ public class DistortedLibrary
     EffectQueue.getUniforms(mainProgramH,0);
     MeshBase.getUniforms(mainProgramH,0);
     mMainTextureH= GLES30.glGetUniformLocation( mainProgramH, "u_Texture");
+    mTransformFeedbackH= GLES30.glGetUniformLocation( mainProgramH, "u_TransformFeedback");
 
     // BLIT PROGRAM ////////////////////////////////////
     final InputStream blitVertStream = mResources.openRawResource(R.raw.blit_vertex_shader);
@@ -321,7 +323,7 @@ public class DistortedLibrary
       }
 
     int normalProgramH = mNormalProgram.getProgramHandle();
-    mNormalMVPMatrixH  = GLES30.glGetUniformLocation( normalProgramH, "u_MVPMatrix");
+    mNormalProjectionH = GLES30.glGetUniformLocation( normalProgramH, "u_Projection");
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -481,7 +483,7 @@ public class DistortedLibrary
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-  private static void displayNormals(EffectQueue[] queues, MeshBase mesh)
+  private static void displayNormals(float[] projection, MeshBase mesh)
     {
     if( mNormalProgram==null )
       {
@@ -499,6 +501,7 @@ public class DistortedLibrary
     int num = mesh.getNumVertices();
     int tfo = mesh.getTFO();
 
+    GLES30.glUniform1i(DistortedLibrary.mTransformFeedbackH, 1);
     GLES30.glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfo );
     GLES30.glBeginTransformFeedback( GLES30.GL_POINTS);
     InternalRenderState.switchOffDrawing();
@@ -508,7 +511,7 @@ public class DistortedLibrary
     GLES30.glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
 
     mNormalProgram.useProgram();
-    GLES30.glUniformMatrix4fv(mNormalMVPMatrixH, 1, false, EffectQueue.getMVP(queues) , 0);
+    GLES30.glUniformMatrix4fv(mNormalProjectionH, 1, false, projection, 0);
     mesh.bindTransformAttribs(mNormalProgram);
     GLES30.glLineWidth(8.0f);
     GLES30.glDrawArrays(GLES30.GL_LINES, 0, 2*num);
@@ -574,15 +577,15 @@ public class DistortedLibrary
       float mipmap      = surface.mMipmap;
       float[] projection= surface.mProjectionMatrix;
 
-      EffectQueue.send(queues, distance, mipmap, projection, inflate, mesh, 1 );
+      EffectQueue.send(queues, distance, mipmap, projection, inflate, 1 );
       GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices() );
 
       if( mesh.getShowNormals() )
         {
         mMainProgram.useProgram();
         mesh.send(0);
-        EffectQueue.send(queues, distance, mipmap, projection, inflate, mesh, 0 );
-        displayNormals(queues,mesh);
+        EffectQueue.send(queues, distance, mipmap, projection, inflate, 0 );
+        displayNormals(projection,mesh);
         }
       }
     }
@@ -608,10 +611,10 @@ public class DistortedLibrary
       float mipmap      = surface.mMipmap;
       float[] projection= surface.mProjectionMatrix;
 
-      EffectQueue.send(queues, distance, mipmap, projection, inflate, mesh, 0 );
+      EffectQueue.send(queues, distance, mipmap, projection, inflate, 0 );
       GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mesh.getNumVertices() );
 
-      if( mesh.getShowNormals() ) displayNormals(queues,mesh);
+      if( mesh.getShowNormals() ) displayNormals(projection,mesh);
       }
     }
 
diff --git a/src/main/java/org/distorted/library/mesh/MeshBase.java b/src/main/java/org/distorted/library/mesh/MeshBase.java
index 49552c2..babe239 100644
--- a/src/main/java/org/distorted/library/mesh/MeshBase.java
+++ b/src/main/java/org/distorted/library/mesh/MeshBase.java
@@ -255,13 +255,15 @@ public abstract class MeshBase
 
    void applyMatrix(MatrixEffect effect, int andAssoc, int equAssoc)
      {
-     float[] matrix   = new float[16];
+     float[] matrixP  = new float[16];
+     float[] matrixV  = new float[16];
      float[] uniforms = new float[7];
      int start, end=-1, numComp = mEffComponent.size();
 
-     Matrix.setIdentityM(matrix,0);
+     Matrix.setIdentityM(matrixP,0);
+     Matrix.setIdentityM(matrixV,0);
      effect.compute(uniforms,0,0,0);
-     effect.apply(matrix, uniforms, 0);
+     effect.apply(matrixP, matrixV, uniforms, 0);
 
      for(int i=0; i<numComp; i++)
        {
@@ -270,7 +272,7 @@ public abstract class MeshBase
 
        if( (andAssoc & mAndAssociation[i]) != 0 || (equAssoc == mEquAssociation[i]) )
          {
-         applyMatrixToComponent(matrix,start,end);
+         applyMatrixToComponent(matrixP, matrixV, start, end);
          }
        }
 
@@ -279,7 +281,7 @@ public abstract class MeshBase
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-   private void applyMatrixToComponent(float[] matrix, int start, int end)
+   private void applyMatrixToComponent(float[] matrixP, float[] matrixV, int start, int end)
      {
      float x,y,z;
 
@@ -289,25 +291,51 @@ public abstract class MeshBase
        y = mVertAttribs1[index+POS_ATTRIB+1];
        z = mVertAttribs1[index+POS_ATTRIB+2];
 
-       mVertAttribs1[index+POS_ATTRIB  ] = matrix[0]*x + matrix[4]*y + matrix[ 8]*z + matrix[12];
-       mVertAttribs1[index+POS_ATTRIB+1] = matrix[1]*x + matrix[5]*y + matrix[ 9]*z + matrix[13];
-       mVertAttribs1[index+POS_ATTRIB+2] = matrix[2]*x + matrix[6]*y + matrix[10]*z + matrix[14];
+       mVertAttribs1[index+POS_ATTRIB  ] = matrixP[0]*x + matrixP[4]*y + matrixP[ 8]*z + matrixP[12];
+       mVertAttribs1[index+POS_ATTRIB+1] = matrixP[1]*x + matrixP[5]*y + matrixP[ 9]*z + matrixP[13];
+       mVertAttribs1[index+POS_ATTRIB+2] = matrixP[2]*x + matrixP[6]*y + matrixP[10]*z + matrixP[14];
 
        x = mVertAttribs1[index+NOR_ATTRIB  ];
        y = mVertAttribs1[index+NOR_ATTRIB+1];
        z = mVertAttribs1[index+NOR_ATTRIB+2];
 
-       mVertAttribs1[index+NOR_ATTRIB  ] = matrix[0]*x + matrix[4]*y + matrix[ 8]*z;
-       mVertAttribs1[index+NOR_ATTRIB+1] = matrix[1]*x + matrix[5]*y + matrix[ 9]*z;
-       mVertAttribs1[index+NOR_ATTRIB+2] = matrix[2]*x + matrix[6]*y + matrix[10]*z;
+       mVertAttribs1[index+NOR_ATTRIB  ] = matrixV[0]*x + matrixV[4]*y + matrixV[ 8]*z;
+       mVertAttribs1[index+NOR_ATTRIB+1] = matrixV[1]*x + matrixV[5]*y + matrixV[ 9]*z;
+       mVertAttribs1[index+NOR_ATTRIB+2] = matrixV[2]*x + matrixV[6]*y + matrixV[10]*z;
+
+       x = mVertAttribs1[index+NOR_ATTRIB  ];
+       y = mVertAttribs1[index+NOR_ATTRIB+1];
+       z = mVertAttribs1[index+NOR_ATTRIB+2];
+
+       float len1 = (float)Math.sqrt(x*x + y*y + z*z);
+
+       if( len1>0.0f )
+         {
+         mVertAttribs1[index+NOR_ATTRIB  ] /= len1;
+         mVertAttribs1[index+NOR_ATTRIB+1] /= len1;
+         mVertAttribs1[index+NOR_ATTRIB+2] /= len1;
+         }
 
        x = mVertAttribs1[index+INF_ATTRIB  ];
        y = mVertAttribs1[index+INF_ATTRIB+1];
        z = mVertAttribs1[index+INF_ATTRIB+2];
 
-       mVertAttribs1[index+INF_ATTRIB  ] = matrix[0]*x + matrix[4]*y + matrix[ 8]*z;
-       mVertAttribs1[index+INF_ATTRIB+1] = matrix[1]*x + matrix[5]*y + matrix[ 9]*z;
-       mVertAttribs1[index+INF_ATTRIB+2] = matrix[2]*x + matrix[6]*y + matrix[10]*z;
+       mVertAttribs1[index+INF_ATTRIB  ] = matrixV[0]*x + matrixV[4]*y + matrixV[ 8]*z;
+       mVertAttribs1[index+INF_ATTRIB+1] = matrixV[1]*x + matrixV[5]*y + matrixV[ 9]*z;
+       mVertAttribs1[index+INF_ATTRIB+2] = matrixV[2]*x + matrixV[6]*y + matrixV[10]*z;
+
+       x = mVertAttribs1[index+INF_ATTRIB  ];
+       y = mVertAttribs1[index+INF_ATTRIB+1];
+       z = mVertAttribs1[index+INF_ATTRIB+2];
+
+       float len2 = (float)Math.sqrt(x*x + y*y + z*z);
+
+       if( len2>0.0f )
+         {
+         mVertAttribs1[index+INF_ATTRIB  ] /= len2;
+         mVertAttribs1[index+INF_ATTRIB+1] /= len2;
+         mVertAttribs1[index+INF_ATTRIB+2] /= len2;
+         }
        }
      }
 
diff --git a/src/main/res/raw/main_vertex_shader.glsl b/src/main/res/raw/main_vertex_shader.glsl
index 88fa565..223e125 100644
--- a/src/main/res/raw/main_vertex_shader.glsl
+++ b/src/main/res/raw/main_vertex_shader.glsl
@@ -40,8 +40,11 @@ out vec3 v_Normal;                   //
 out vec2 v_TexCoordinate;            //
 
 uniform mat4 u_MVPMatrix;            // the combined model/view/projection matrix.
-uniform mat4 u_MVMatrix;             // the combined model/view matrix.
+uniform mat4 u_MVMatrixP;            // the combined model/view matrix. (for points)
+uniform mat4 u_MVMatrixV;            // the combined model/view matrix. (for vectors)
+                                     // which need to work differently on points and vectors
 uniform float u_Inflate;             // how much should we inflate (>0.0) or deflate (<0.0) the mesh.
+uniform int u_TransformFeedback;     // are we doing the transform feedback now?
 
 #if NUM_VERTEX>0
 uniform int vNumEffects;             // total number of vertex effects
@@ -119,17 +122,23 @@ void main()
     effect+=3;
     }
 #endif
-   
-  v_Position      = v;
 
 #ifdef PREAPPLY
-  v_endPosition   = n;
-  v_Inflate       = inf;
+  v_Position   = v;
+  v_endPosition= n;
+  v_Inflate    = inf;
 #else
-  v_endPosition   = v + 0.5*n;
+  if( u_TransformFeedback == 1 )
+    {
+    vec4 tmp1 =  u_MVMatrixP * vec4(v,1.0);
+    vec4 tmp2 =  normalize(u_MVMatrixV * vec4(n,0.0));
+
+    v_Position    = vec3(tmp1);
+    v_endPosition = vec3(tmp1+100.0*tmp2);
+    }
 #endif
 
   v_TexCoordinate = a_TexCoordinate;
-  v_Normal        = normalize(vec3(u_MVMatrix*vec4(n,0.0)));
+  v_Normal        = normalize(vec3(u_MVMatrixV*vec4(n,0.0)));
   gl_Position     = u_MVPMatrix*vec4(v,1.0);
   }                               
diff --git a/src/main/res/raw/normal_vertex_shader.glsl b/src/main/res/raw/normal_vertex_shader.glsl
index 83ab55b..45705ea 100644
--- a/src/main/res/raw/normal_vertex_shader.glsl
+++ b/src/main/res/raw/normal_vertex_shader.glsl
@@ -20,11 +20,11 @@
 precision lowp float;
 
 in vec3 a_Position;
-uniform mat4 u_MVPMatrix;
+uniform mat4 u_Projection;
 
 //////////////////////////////////////////////////////////////////////////////////////////////
 
 void main()
   {
-  gl_Position = u_MVPMatrix * vec4(a_Position, 1.0);
+  gl_Position = u_Projection * vec4(a_Position, 1.0);
   }
\ No newline at end of file
