commit cab7c165efe72859b8f4f5d1ae3e9522b5e6d6ef
Author: Leszek Koltunski <leszek@distoretedandroid.org>
Date:   Tue May 9 16:38:18 2017 +0100

    Beginning of support for actual Transform Feedback.

diff --git a/src/main/java/org/distorted/library/DistortedEffects.java b/src/main/java/org/distorted/library/DistortedEffects.java
index 892f230..9124578 100644
--- a/src/main/java/org/distorted/library/DistortedEffects.java
+++ b/src/main/java/org/distorted/library/DistortedEffects.java
@@ -38,6 +38,7 @@ import org.distorted.library.type.Data5D;
 import org.distorted.library.type.Static3D;
 
 import java.io.InputStream;
+import java.nio.Buffer;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.FloatBuffer;
@@ -103,6 +104,7 @@ public class DistortedEffects
   static void createProgram(Resources resources)
   throws FragmentCompilationException,VertexCompilationException,VertexUniformsException,FragmentUniformsException,LinkingException
     {
+    // MAIN PROGRAM ////////////////////////////////////
     final InputStream mainVertStream = resources.openRawResource(R.raw.main_vertex_shader);
     final InputStream mainFragStream = resources.openRawResource(R.raw.main_fragment_shader);
 
@@ -140,7 +142,9 @@ public class DistortedEffects
     //android.util.Log.e("Effects", "vertHeader= "+mainVertHeader);
     //android.util.Log.e("Effects", "fragHeader= "+mainFragHeader);
 
-    mMainProgram = new DistortedProgram(mainVertStream,mainFragStream, mainVertHeader, mainFragHeader, Distorted.GLSL);
+    String[] feedback = { "v_Position","v_Normal","v_TexCoordinate" };
+
+    mMainProgram = new DistortedProgram(mainVertStream,mainFragStream, mainVertHeader, mainFragHeader, Distorted.GLSL, feedback);
 
     int mainProgramH = mMainProgram.getProgramHandle();
     EffectQueueFragment.getUniforms(mainProgramH);
@@ -169,7 +173,7 @@ public class DistortedEffects
     mBlitTextureH  = GLES30.glGetUniformLocation( blitProgramH, "u_Texture");
     mBlitDepthH    = GLES30.glGetUniformLocation( blitProgramH, "u_Depth");
 
-    // DEBUG ONLY //////////////////////////////////////
+    // DEBUG PROGRAM //////////////////////////////////////
     final InputStream debugVertexStream   = resources.openRawResource(R.raw.test_vertex_shader);
     final InputStream debugFragmentStream = resources.openRawResource(R.raw.test_fragment_shader);
 
@@ -184,9 +188,8 @@ public class DistortedEffects
       }
 
     int debugProgramH = mDebugProgram.getProgramHandle();
-    mDebugObjDH = GLES30.glGetUniformLocation( debugProgramH, "u_objD");
+    mDebugObjDH      = GLES30.glGetUniformLocation( debugProgramH, "u_objD");
     mDebugMVPMatrixH = GLES30.glGetUniformLocation( debugProgramH, "u_MVPMatrix");
-    // END DEBUG  //////////////////////////////////////
     }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -280,6 +283,39 @@ public class DistortedEffects
     GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4);
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  private void displayTransformFeedback(MeshObject mesh)
+    {
+    GLES30.glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, mesh.mAttTFO[0]);
+    GLES30.glBeginTransformFeedback( GLES30.GL_POINTS);
+
+    DistortedRenderState.switchOffDrawing();
+    GLES30.glDrawArrays( GLES30.GL_POINTS, 0, mesh.numVertices);
+    DistortedRenderState.restoreDrawing();
+
+    int error = GLES30.glGetError();
+
+      if( error != GLES30.GL_NO_ERROR )
+        {
+        throw new RuntimeException("DrawArrays: glError 0x" + Integer.toHexString(error));
+        }
+
+    int size = (MeshObject.POS_DATA_SIZE+MeshObject.NOR_DATA_SIZE+MeshObject.TEX_DATA_SIZE)*mesh.numVertices;
+
+    Buffer mappedBuffer =  GLES30.glMapBufferRange(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, 4*size, GLES30.GL_MAP_READ_BIT);
+    FloatBuffer fb = ((ByteBuffer) mappedBuffer).order(ByteOrder.nativeOrder()).asFloatBuffer();
+    String msg = "";
+
+    for(int i=0; i<size; i++) msg += (" "+fb.get(i));
+
+    android.util.Log.d( "Feedback", msg);
+
+    GLES30.glUnmapBuffer(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER);
+    GLES30.glEndTransformFeedback();
+    GLES30.glBindBufferBase(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0, 0);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void drawPriv(float halfW, float halfH, MeshObject mesh, DistortedOutputSurface surface, long currTime)
@@ -293,18 +329,23 @@ public class DistortedEffects
     GLES30.glViewport(0, 0, surface.mWidth, surface.mHeight );
 
     mMainProgram.useProgram();
-    GLES30.glUniform1i(mMainTextureH, 0);
     surface.setAsOutput(currTime);
+    GLES30.glUniform1i(mMainTextureH, 0);
+
+    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mesh.mAttVBO[0]);
+    GLES30.glVertexAttribPointer(mMainProgram.mAttribute[0], MeshObject.POS_DATA_SIZE, GLES30.GL_FLOAT, false, MeshObject.VERTSIZE, MeshObject.OFFSET0);
+    GLES30.glVertexAttribPointer(mMainProgram.mAttribute[1], MeshObject.NOR_DATA_SIZE, GLES30.GL_FLOAT, false, MeshObject.VERTSIZE, MeshObject.OFFSET1);
+    GLES30.glVertexAttribPointer(mMainProgram.mAttribute[2], MeshObject.TEX_DATA_SIZE, GLES30.GL_FLOAT, false, MeshObject.VERTSIZE, MeshObject.OFFSET2);
+    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0 );
+
     mM.send(surface,halfW,halfH,halfZ);
     mV.send(halfW,halfH,halfZ);
+
+    displayTransformFeedback(mesh);
+
     mF.send(halfW,halfH);
 
-    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mesh.mAttVBO[0]);
-    GLES30.glVertexAttribPointer(mMainProgram.mAttribute[0], MeshObject.POSITION_DATA_SIZE, GLES30.GL_FLOAT, false, MeshObject.VERTSIZE, MeshObject.OFFSET0);
-    GLES30.glVertexAttribPointer(mMainProgram.mAttribute[1], MeshObject.NORMAL_DATA_SIZE  , GLES30.GL_FLOAT, false, MeshObject.VERTSIZE, MeshObject.OFFSET1);
-    GLES30.glVertexAttribPointer(mMainProgram.mAttribute[2], MeshObject.TEX_DATA_SIZE     , GLES30.GL_FLOAT, false, MeshObject.VERTSIZE, MeshObject.OFFSET2);
     GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, mesh.numVertices);
-    GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0 );
 
     /// DEBUG ONLY //////
     // displayBoundingRect(halfW, halfH, halfZ, surface, mM.getMVP(), mesh.getBoundingVertices() );
diff --git a/src/main/java/org/distorted/library/DistortedRenderState.java b/src/main/java/org/distorted/library/DistortedRenderState.java
index 9d0d071..7632319 100644
--- a/src/main/java/org/distorted/library/DistortedRenderState.java
+++ b/src/main/java/org/distorted/library/DistortedRenderState.java
@@ -124,6 +124,21 @@ class DistortedRenderState
       }
     }
 
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  static void switchOffDrawing()
+    {
+    GLES30.glEnable(GLES30.GL_SCISSOR_TEST);
+    GLES30.glScissor(0,0,0,0);
+    }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+  static void restoreDrawing()
+    {
+    GLES30.glDisable(GLES30.GL_SCISSOR_TEST);
+    }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
   void apply()
diff --git a/src/main/java/org/distorted/library/MeshCubes.java b/src/main/java/org/distorted/library/MeshCubes.java
index a68a87a..c1da802 100644
--- a/src/main/java/org/distorted/library/MeshCubes.java
+++ b/src/main/java/org/distorted/library/MeshCubes.java
@@ -891,7 +891,7 @@ public class MeshCubes extends MeshObject
   private void build(boolean frontOnly)
      {
      int vertSoFar=0;
-     float[] attribs= new float[(POSITION_DATA_SIZE+NORMAL_DATA_SIZE+TEX_DATA_SIZE)*numVertices];
+     float[] attribs= new float[(POS_DATA_SIZE+NOR_DATA_SIZE+TEX_DATA_SIZE)*numVertices];
 
      //android.util.Log.d("MeshCubes","building front grid...");
 
diff --git a/src/main/java/org/distorted/library/MeshFlat.java b/src/main/java/org/distorted/library/MeshFlat.java
index 1219419..548e50a 100644
--- a/src/main/java/org/distorted/library/MeshFlat.java
+++ b/src/main/java/org/distorted/library/MeshFlat.java
@@ -188,7 +188,7 @@ public class MeshFlat extends MeshObject
     super(0.0f);
     computeNumberOfVertices(cols,rows);
 
-    float[] attribs= new float[(POSITION_DATA_SIZE+NORMAL_DATA_SIZE+TEX_DATA_SIZE)*numVertices];
+    float[] attribs= new float[(POS_DATA_SIZE+NOR_DATA_SIZE+TEX_DATA_SIZE)*numVertices];
 
     buildGrid(attribs);
 
diff --git a/src/main/java/org/distorted/library/MeshObject.java b/src/main/java/org/distorted/library/MeshObject.java
index 17d2da8..4655be6 100644
--- a/src/main/java/org/distorted/library/MeshObject.java
+++ b/src/main/java/org/distorted/library/MeshObject.java
@@ -35,18 +35,19 @@ public abstract class MeshObject extends DistortedObject
    {
    private static final int BYTES_PER_FLOAT = 4;
 
-   static final int POSITION_DATA_SIZE= 3;
-   static final int NORMAL_DATA_SIZE  = 3;
-   static final int TEX_DATA_SIZE     = 2;
+   static final int POS_DATA_SIZE= 3;
+   static final int NOR_DATA_SIZE= 3;
+   static final int TEX_DATA_SIZE= 2;
 
-   static final int OFFSET0 =                                                                   0;
-   static final int OFFSET1 = (POSITION_DATA_SIZE                               )*BYTES_PER_FLOAT;
-   static final int OFFSET2 = (POSITION_DATA_SIZE+NORMAL_DATA_SIZE              )*BYTES_PER_FLOAT;
-   static final int VERTSIZE= (POSITION_DATA_SIZE+NORMAL_DATA_SIZE+TEX_DATA_SIZE)*BYTES_PER_FLOAT;
+   static final int OFFSET0 =                                                           0;
+   static final int OFFSET1 = (POS_DATA_SIZE                            )*BYTES_PER_FLOAT;
+   static final int OFFSET2 = (POS_DATA_SIZE+NOR_DATA_SIZE              )*BYTES_PER_FLOAT;
+   static final int VERTSIZE= (POS_DATA_SIZE+NOR_DATA_SIZE+TEX_DATA_SIZE)*BYTES_PER_FLOAT;
 
    int numVertices;
    FloatBuffer mVertAttribs;   // packed: PosX,PosY,PosZ, NorX, NorY,NorZ, TexS, TexT
    int[] mAttVBO = new int[1]; // server-side packed vertex attributes
+   int[] mAttTFO = new int[1]; // transform feedback
 
    final float zFactor;        // strange workaround for the fact that we need to somehow store the 'depth'
                                // of the Mesh. Used in DistortedEffects. See DistortedTexture.getDepth().
@@ -76,6 +77,13 @@ public abstract class MeshObject extends DistortedObject
        GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, numVertices*VERTSIZE, mVertAttribs, GLES30.GL_STATIC_READ);
        GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0);
        }
+     if( mAttTFO[0]<0 )
+       {
+       GLES30.glGenBuffers(1, mAttTFO, 0);
+       GLES30.glBindBuffer(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, mAttTFO[0]);
+       GLES30.glBufferData(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, numVertices*VERTSIZE, null, GLES30.GL_STATIC_READ);
+       GLES30.glBindBuffer(GLES30.GL_TRANSFORM_FEEDBACK_BUFFER, 0);
+       }
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -88,6 +96,11 @@ public abstract class MeshObject extends DistortedObject
        GLES30.glDeleteBuffers(1, mAttVBO, 0);
        mAttVBO[0] = -1;
        }
+     if( mAttTFO[0]>=0 )
+       {
+       GLES30.glDeleteBuffers(1, mAttTFO, 0);
+       mAttTFO[0] = -1;
+       }
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -95,6 +108,7 @@ public abstract class MeshObject extends DistortedObject
    void recreate()
      {
      mAttVBO[0] = -1;
+     mAttTFO[0] = -1;
      }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
