commit 248a27825a11177ab696e821746e41a44e8aebe1
Author: Leszek Koltunski <leszek@distoretedandroid.org>
Date:   Fri Nov 11 16:23:54 2016 +0000

    Progress with "Around The World"

diff --git a/src/main/java/org/distorted/examples/aroundtheworld/AroundTheWorldRendererPicker.java b/src/main/java/org/distorted/examples/aroundtheworld/AroundTheWorldRendererPicker.java
new file mode 100644
index 0000000..111fd1e
--- /dev/null
+++ b/src/main/java/org/distorted/examples/aroundtheworld/AroundTheWorldRendererPicker.java
@@ -0,0 +1,228 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Copyright 2016 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.examples.aroundtheworld;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.opengl.GLES20;
+import android.opengl.GLSurfaceView;
+import android.opengl.Matrix;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+class AroundTheWorldRendererPicker implements GLSurfaceView.Renderer
+  {
+	private float[] mModelMatrix      = new float[16];
+	private float[] mViewMatrix       = new float[16];
+	private float[] mProjectionMatrix = new float[16];
+	private float[] mMVPMatrix        = new float[16];
+
+	private final FloatBuffer mTriangleVertices;
+
+  private int mMVPMatrixHandle;
+  private int mPositionHandle;
+	private int mColorHandle;
+
+	private final int mBytesPerFloat    = 4;
+	private final int mStrideBytes      = 7 * mBytesPerFloat;
+	private final int mPositionOffset   = 0;
+	private final int mPositionDataSize = 3;
+	private final int mColorOffset      = 3;
+	private final int mColorDataSize    = 4;
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+	AroundTheWorldRendererPicker()
+	  {
+		final float[] triangle1VerticesData = {
+				      -0.25f, 0.5f, 0.0f,      // x,y,z
+	            1.0f, 1.0f, 1.0f, 1.0f,  // r,g,b
+
+	            -0.25f, -0.5f, 0.0f,
+	            0.0f, 0.0f, 0.0f, 1.0f,
+
+	            0.559f, 0.0f, 0.0f,
+	            0.3f, 0.3f, 0.0f, 1.0f };
+
+		mTriangleVertices = ByteBuffer.allocateDirect(triangle1VerticesData.length * mBytesPerFloat).order(ByteOrder.nativeOrder()).asFloatBuffer();
+    mTriangleVertices.put(triangle1VerticesData).position(0);
+	  }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+	@Override public void onSurfaceCreated(GL10 glUnused, EGLConfig config)
+	  {
+		GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+
+		final float eyeX = 0.0f;
+		final float eyeY = 0.0f;
+		final float eyeZ = 1.5f;
+
+		final float lookX = 0.0f;
+		final float lookY = 0.0f;
+		final float lookZ = -5.0f;
+
+		final float upX = 0.0f;
+		final float upY = 1.0f;
+		final float upZ = 0.0f;
+
+		Matrix.setLookAtM(mViewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);
+
+		final String vertexShader =
+			  "uniform mat4 u_MVPMatrix;                 \n"
+		  + "attribute vec4 a_Position;                \n"
+		  + "attribute vec4 a_Color;                   \n"
+		  + "varying vec4 v_Color;                     \n"
+
+		  + "void main()                               \n"
+		  + "{                                         \n"
+		  + "   v_Color = a_Color;                     \n"
+		  + "   gl_Position = u_MVPMatrix* a_Position; \n"
+		  + "}                                         \n";
+
+		final String fragmentShader =
+			  "precision mediump float;       \n"
+		  + "varying vec4 v_Color;          \n"
+
+		  + "void main()                    \n"
+		  + "{                              \n"
+		  + "   gl_FragColor = v_Color;     \n"
+		  + "}                              \n";
+
+		int vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
+
+		if (vertexShaderHandle != 0)
+		  {
+			GLES20.glShaderSource(vertexShaderHandle, vertexShader);
+      GLES20.glCompileShader(vertexShaderHandle);
+
+      final int[] compileStatus = new int[1];
+			GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
+
+			if (compileStatus[0] == 0)
+  			{
+				GLES20.glDeleteShader(vertexShaderHandle);
+				vertexShaderHandle = 0;
+	  		}
+		  }
+
+		if (vertexShaderHandle == 0)
+		  {
+			throw new RuntimeException("Error creating vertex shader.");
+		  }
+
+		int fragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
+
+		if (fragmentShaderHandle != 0)
+		  {
+			GLES20.glShaderSource(fragmentShaderHandle, fragmentShader);
+      GLES20.glCompileShader(fragmentShaderHandle);
+
+			final int[] compileStatus = new int[1];
+			GLES20.glGetShaderiv(fragmentShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
+
+			if (compileStatus[0] == 0)
+			  {
+				GLES20.glDeleteShader(fragmentShaderHandle);
+				fragmentShaderHandle = 0;
+			  }
+		  }
+
+		if (fragmentShaderHandle == 0)
+		  {
+			throw new RuntimeException("Error creating fragment shader.");
+		  }
+
+		int programHandle = GLES20.glCreateProgram();
+
+		if (programHandle != 0)
+		  {
+			GLES20.glAttachShader(programHandle, vertexShaderHandle);
+      GLES20.glAttachShader(programHandle, fragmentShaderHandle);
+			GLES20.glBindAttribLocation(programHandle, 0, "a_Position");
+			GLES20.glBindAttribLocation(programHandle, 1, "a_Color");
+			GLES20.glLinkProgram(programHandle);
+
+			final int[] linkStatus = new int[1];
+			GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);
+
+			if (linkStatus[0] == 0)
+			  {
+				GLES20.glDeleteProgram(programHandle);
+				programHandle = 0;
+			  }
+		  }
+
+		if (programHandle == 0)
+		  {
+			throw new RuntimeException("Error creating program.");
+		  }
+
+    mMVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVPMatrix");
+    mPositionHandle = GLES20.glGetAttribLocation(programHandle, "a_Position");
+    mColorHandle = GLES20.glGetAttribLocation(programHandle, "a_Color");
+
+    GLES20.glUseProgram(programHandle);
+	  }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+	@Override public void onSurfaceChanged(GL10 glUnused, int width, int height)
+	  {
+		GLES20.glViewport(0, 0, width, height);
+
+		final float ratio = (float) width / height;
+		final float left = -ratio;
+		final float right = ratio;
+		final float bottom = -1.0f;
+		final float top = 1.0f;
+		final float near = 1.0f;
+		final float far = 10.0f;
+
+		Matrix.frustumM(mProjectionMatrix, 0, left, right, bottom, top, near, far);
+	  }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+	@Override public void onDrawFrame(GL10 glUnused)
+	  {
+		GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
+
+    Matrix.setIdentityM(mModelMatrix, 0);
+
+    mTriangleVertices.position(mPositionOffset);
+    GLES20.glVertexAttribPointer(mPositionHandle, mPositionDataSize, GLES20.GL_FLOAT, false, mStrideBytes, mTriangleVertices);
+    GLES20.glEnableVertexAttribArray(mPositionHandle);
+
+    mTriangleVertices.position(mColorOffset);
+    GLES20.glVertexAttribPointer(mColorHandle, mColorDataSize, GLES20.GL_FLOAT, false, mStrideBytes, mTriangleVertices);
+    GLES20.glEnableVertexAttribArray(mColorHandle);
+
+		Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
+    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);
+    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
+    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
+	  }
+  }
diff --git a/src/main/java/org/distorted/examples/aroundtheworld/AroundTheWorldSurfaceViewPicker.java b/src/main/java/org/distorted/examples/aroundtheworld/AroundTheWorldSurfaceViewPicker.java
index ebd7f64..cd37209 100644
--- a/src/main/java/org/distorted/examples/aroundtheworld/AroundTheWorldSurfaceViewPicker.java
+++ b/src/main/java/org/distorted/examples/aroundtheworld/AroundTheWorldSurfaceViewPicker.java
@@ -20,85 +20,16 @@
 package org.distorted.examples.aroundtheworld;
 
 import android.content.Context;
-import android.graphics.Canvas;
+import android.opengl.GLSurfaceView;
+import android.os.Build;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-class AroundTheWorldSurfaceViewPicker extends SurfaceView implements SurfaceHolder.Callback
+class AroundTheWorldSurfaceViewPicker extends GLSurfaceView
 {
-    private static final int FRAME_INTERVAL = 70;
-
-    private boolean refreshScreen = true;
-    private boolean mFinishedBooting=false;
-    private int scrWidth, scrHeight;
-    private GraphicsThread mThread;
-    private int mX, mY;
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    private class GraphicsThread extends Thread
-      {
-      private SurfaceHolder mSurfaceHolder;
-      private AroundTheWorldSurfaceViewPicker mPicker;
-      private boolean mRun = false;
-
-      /////////////////////////////////////////////////////////////////////////////////////
-
-      GraphicsThread(SurfaceHolder surfaceHolder, AroundTheWorldSurfaceViewPicker p)
-        {
-        mSurfaceHolder = surfaceHolder;
-        mPicker = p;
-        }
-
-      /////////////////////////////////////////////////////////////////////////////////////
-
-      void setRunning(boolean run)
-        {
-        mRun = run;
-        }
-
-      /////////////////////////////////////////////////////////////////////////////////////
-
-      public void run()
-        {
-        Canvas c;
-        long time;
-
-        while (mRun)
-          {
-          c = null;
-          time = 0;
-
-          if( refreshScreen && mFinishedBooting )
-            {
-            refreshScreen=false;
-            time = System.currentTimeMillis();
-
-            try
-              {
-              c = mSurfaceHolder.lockCanvas(null);
-              synchronized (mSurfaceHolder) { mPicker.draw(c); }
-              }
-            finally
-              {
-              if (c != null)  mSurfaceHolder.unlockCanvasAndPost(c);
-              }
-
-            time = System.currentTimeMillis() -time;
-            }
-
-          if( time<FRAME_INTERVAL )
-            {
-            try { Thread.sleep(FRAME_INTERVAL-time); }
-            catch(InterruptedException ex) {}
-            }
-          }
-        }
-    }
+    private AroundTheWorldRendererPicker mRenderer;
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -106,98 +37,36 @@ class AroundTheWorldSurfaceViewPicker extends SurfaceView implements SurfaceHold
       {
       super(c, attrs);
 
-      mX = -100;
-      mY = -100;
-
-      getHolder().addCallback(this);
-      setFocusable(true);
-      setFocusableInTouchMode(true);
-
-      mFinishedBooting=true;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public void surfaceCreated(SurfaceHolder holder)
-      {
-      android.util.Log.e( "Picker", "surfaceCreated");
-
-      mThread = new GraphicsThread(getHolder(), this);
-      mThread.setRunning(true);
-      mThread.start();
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
-      {
-      android.util.Log.e( "Picker", "surfaceChanged: width="+w+" height="+h);
-
-      scrWidth = w;
-      scrHeight= h;
-      refreshScreen = true;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    public void surfaceDestroyed(SurfaceHolder holder)
-      {
-      android.util.Log.e( "Picker", "surfaceDestroyed");
-
-      stopThread();
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-    private void stopThread()
-      {
-      if( mThread!=null )
+      if(!isInEditMode())
         {
-        boolean retry = true;
-        mThread.setRunning(false);
+        setEGLContextClientVersion(2);
 
-        while (retry)
+        if( Build.FINGERPRINT.startsWith("generic") )
           {
-          try
-            {
-            mThread.join();
-            retry = false;
-            }
-          catch (InterruptedException e) { android.util.Log.e( "Picker", "Joining thread interrupted!"); }
+          setEGLConfigChooser(8, 8, 8, 8, 16, 0);
           }
 
-        mThread=null;
+        mRenderer = new AroundTheWorldRendererPicker();
+        setRenderer(mRenderer);
         }
       }
-
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void draw(Canvas c)
+    public AroundTheWorldRendererPicker getRenderer()
       {
-      if( c!=null )
-        {
-
-        }
+      return mRenderer;
       }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public void setRepaint()
+    @Override public boolean onTouchEvent(MotionEvent event)
       {
-      refreshScreen=true;
-      }
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
+      int x = (int)event.getX();
+      int y = (int)event.getY();
 
-    public boolean onTouchEvent(MotionEvent event)
-      {
-      mX = (int)event.getX();
-      mY = (int)event.getY();
-
-      android.util.Log.e( "Picker", "onTouchEvent: x="+mX+" y="+mY);
-
-      setRepaint();
+      android.util.Log.e("Picker", "touched at x="+x+" y="+y);
 
       return true;
       }
 }
+
diff --git a/src/main/res/layout/aroundtheworldlayout.xml b/src/main/res/layout/aroundtheworldlayout.xml
index b228579..a67ebe9 100644
--- a/src/main/res/layout/aroundtheworldlayout.xml
+++ b/src/main/res/layout/aroundtheworldlayout.xml
@@ -10,10 +10,6 @@
         android:layout_height="0dp"
         android:layout_weight="1" />
 
-    <Space
-        android:layout_width="match_parent"
-        android:layout_height="5dp"/>
-
     <org.distorted.examples.aroundtheworld.AroundTheWorldSurfaceViewPicker
         android:id="@+id/aroundTheWorldSurfaceViewPicker"
         android:layout_width="fill_parent"
