title: Android OpenGL animation
body: <p>I'm at the beginning of OpenGL 2.0 and I've impemented the Google tutorial about drawing a square and a triangle. Obviously it works fine :)</p>
  
  <p>Now I'm trying to add some movement (translating the square vertically). The problem it that the square moves but only once. Someone told me that there's no loop but I think that the loop is done by the "onDrawFrame" method, ain't it?.</p>
  
  <p>Can anyone help me to understand where's my mistake(s)?</p>
  
  <p>Thankyou for your time.</p>
  
  <p>MainActivity:</p>
  
  <pre><code>public class MainActivity extends Activity {
  
  private GLSurfaceView mGLView;
  
  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
  
      // Create a GLSurfaceView instance and set it
      // as the ContentView for this Activity
      mGLView = new MyGLSurfaceView(this);
      setContentView(mGLView);
  }
  
  @Override
  protected void onPause() {
      super.onPause();
      mGLView.onPause();
  }
  
  @Override
  protected void onResume() {
      super.onResume();
      mGLView.onResume();
  }
  }
  </code></pre>
  
  <p>MyGLSurfaceView class:</p>
  
  <pre><code>public class MyGLSurfaceView extends GLSurfaceView {
  
  private final MyGLRenderer mRenderer;
  
  public MyGLSurfaceView(Context context) {
      super(context);
  
      // Create an OpenGL ES 2.0 context.
      setEGLContextClientVersion(2);
  
      // Set the Renderer for drawing on the GLSurfaceView
      mRenderer = new MyGLRenderer();
      setRenderer(mRenderer);
  
      // Render the view only when there is a change in the drawing data
      setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
  }
  
  }
  </code></pre>
  
  <p>The renderer class:</p>
  
  <pre><code>public class MyGLRenderer implements GLSurfaceView.Renderer {
  
  private static final String TAG = "MyGLRenderer";
  private Triangle mTriangle;
  private Square   mSquare;
  float i;
  int direction;
  
  // mMVPMatrix is an abbreviation for "Model View Projection Matrix"
  private final float[] mMVPMatrix = new float[16];
  private final float[] mProjectionMatrix = new float[16];
  private final float[] mViewMatrix = new float[16];
  
  
  @Override
  public void onSurfaceCreated(GL10 unused, EGLConfig config) {
  
     i = 0;
     direction = 1;
  
      // Set the background frame color
      GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  
      mTriangle = new Triangle();
      mSquare   = new Square();
  }
  
  @Override
  public void onDrawFrame(GL10 unused) {
      float[] triangleScratch = new float[16];
      float[] squareScratch = new float[16];
  
      // Draw background color
      GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
  
      // Set the camera position (View matrix)
      Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -7, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
  
      // Calculate the projection and view transformation
      Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
  
  
  
  //        Separate the square and the triangle
      Matrix.transposeM(squareScratch, 0, mMVPMatrix, 0);
      Matrix.transposeM(triangleScratch, 0, mMVPMatrix, 0);
  
      if(i&gt;1) {direction = -1;}
      if(i&lt;-1) {direction = 1;}
      i += 0.1 * direction;
  
      //Introduce a translation
      Matrix.translateM(squareScratch, 0, 0.0f, i, 0.0f);
  
      // Draw square
      mSquare.draw(squareScratch);
  
  
  
  
      // Draw triangle
      mTriangle.draw(triangleScratch);
  }
  
  @Override
  public void onSurfaceChanged(GL10 unused, int width, int height) {
      // Adjust the viewport based on geometry changes,
      // such as screen rotation
      GLES20.glViewport(0, 0, width, height);
  
      float ratio = (float) width / height;
  
      // this projection matrix is applied to object coordinates
      // in the onDrawFrame() method
      Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
  
  }
  
  /**
   * Utility method for compiling a OpenGL shader.
   *
   * &lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; When developing shaders, use the checkGlError()
   * method to debug shader coding errors.&lt;/p&gt;
   *
   * @param type - Vertex or fragment shader type.
   * @param shaderCode - String containing the shader code.
   * @return - Returns an id for the shader.
   */
  public static int loadShader(int type, String shaderCode){
  
      // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
      // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
      int shader = GLES20.glCreateShader(type);
  
      // add the source code to the shader and compile it
      GLES20.glShaderSource(shader, shaderCode);
      GLES20.glCompileShader(shader);
  
      return shader;
  }
  
  /**
   * Utility method for debugging OpenGL calls. Provide the name of the call
   * just after making it:
   *
   * &lt;pre&gt;
   * mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
   * MyGLRenderer.checkGlError("glGetUniformLocation");&lt;/pre&gt;
   *
   * If the operation is not successful, the check throws an error.
   *
   * @param glOperation - Name of the OpenGL call to check.
   */
  public static void checkGlError(String glOperation) {
      int error;
      while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
          Log.e(TAG, glOperation + ": glError " + error);
          throw new RuntimeException(glOperation + ": glError " + error);
      }
  }
  
  }
  </code></pre>
  
  <p>Square class:</p>
  
  <pre><code>public class Square {
  
  private final String vertexShaderCode =
          // This matrix member variable provides a hook to manipulate
          // the coordinates of the objects that use this vertex shader
          "uniform mat4 uMVPMatrix;" +
                  "attribute vec4 vPosition;" +
                  "void main() {" +
                  // The matrix must be included as a modifier of gl_Position.
                  // Note that the uMVPMatrix factor *must be first* in order
                  // for the matrix multiplication product to be correct.
                  "  gl_Position = uMVPMatrix * vPosition;" +
                  "}";
  
  private final String fragmentShaderCode =
          "precision mediump float;" +
                  "uniform vec4 vColor;" +
                  "void main() {" +
                  "  gl_FragColor = vColor;" +
                  "}";
  
  private final FloatBuffer vertexBuffer;
  private final ShortBuffer drawListBuffer;
  private final int mProgram;
  private int mPositionHandle;
  private int mColorHandle;
  private int mMVPMatrixHandle;
  
  // number of coordinates per vertex in this array
  static final int COORDS_PER_VERTEX = 3;
  static float squareCoords[] = {
          0.0f, 1.0f, 0.0f,   // top left
          0.0f, 0.0f, 0.0f,   // bottom left
          1.0f, 0.0f, 0.0f,   // bottom right
          1.0f, 1.0f, 0.0f }; // top right
  
  private final short drawOrder[] = { 0, 1, 2, 0, 2, 3 }; // order to draw vertices
  
  private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
  
  float color[] = { 0.2f, 0.709803922f, 0.898039216f, 1.0f };
  
  /**
   * Sets up the drawing object data for use in an OpenGL ES context.
   */
  public Square() {
      // initialize vertex byte buffer for shape coordinates
      ByteBuffer bb = ByteBuffer.allocateDirect(
              // (# of coordinate values * 4 bytes per float)
              squareCoords.length * 4);
      bb.order(ByteOrder.nativeOrder());
      vertexBuffer = bb.asFloatBuffer();
      vertexBuffer.put(squareCoords);
      vertexBuffer.position(0);
  
      // initialize byte buffer for the draw list
      ByteBuffer dlb = ByteBuffer.allocateDirect(
              // (# of coordinate values * 2 bytes per short)
              drawOrder.length * 2);
      dlb.order(ByteOrder.nativeOrder());
      drawListBuffer = dlb.asShortBuffer();
      drawListBuffer.put(drawOrder);
      drawListBuffer.position(0);
  
      // prepare shaders and OpenGL program
      int vertexShader = MyGLRenderer.loadShader(
              GLES20.GL_VERTEX_SHADER,
              vertexShaderCode);
      int fragmentShader = MyGLRenderer.loadShader(
              GLES20.GL_FRAGMENT_SHADER,
              fragmentShaderCode);
  
      mProgram = GLES20.glCreateProgram();             // create empty OpenGL Program
      GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
      GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
      GLES20.glLinkProgram(mProgram);                  // create OpenGL program executables
  }
  
  /**
   * Encapsulates the OpenGL ES instructions for drawing this shape.
   *
   * @param mvpMatrix - The Model View Project matrix in which to draw
   * this shape.
   */
  public void draw(float[] mvpMatrix) {
      // Add program to OpenGL environment
      GLES20.glUseProgram(mProgram);
  
      // get handle to vertex shader's vPosition member
      mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
  
      // Enable a handle to the triangle vertices
      GLES20.glEnableVertexAttribArray(mPositionHandle);
  
      // Prepare the triangle coordinate data
      GLES20.glVertexAttribPointer(
              mPositionHandle, COORDS_PER_VERTEX,
              GLES20.GL_FLOAT, false,
              vertexStride, vertexBuffer);
  
      // get handle to fragment shader's vColor member
      mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
  
      // Set color for drawing the triangle
      GLES20.glUniform4fv(mColorHandle, 1, color, 0);
  
      // get handle to shape's transformation matrix
      mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
      MyGLRenderer.checkGlError("glGetUniformLocation");
  
      // Apply the projection and view transformation
      GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
      MyGLRenderer.checkGlError("glUniformMatrix4fv");
  
      // Draw the square
      GLES20.glDrawElements(
              GLES20.GL_TRIANGLES, drawOrder.length,
              GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
  
      // Disable vertex array
      GLES20.glDisableVertexAttribArray(mPositionHandle);
  }
  
  }
  </code></pre>
  
  <p>The entire code is here:</p>
  
  <p><a href="https://github.com/mauroghiglia/OGLDrawTest/tree/master/java/com/appeng/tests/ogldrawtest" rel="nofollow noreferrer">Link to code repository</a></p>
  
  <p>Thanks to all the people who have the patience to take a look at it.</p>