title: Android - OpenGL Image doesnt rotate (almost completed)
body: <p>I was following a OpenGL tutorial (<a href="https://developer.android.com/training/graphics/opengl/touch.html#angle" rel="nofollow noreferrer">https://developer.android.com/training/graphics/opengl/touch.html#angle</a>) and I did everything right I think. <strong>My problem is that the triangle doesnt rotate on the display.</strong> I tried to debug and <code>mGLView.requestRender();</code> is getting the values but it doesnt update the image on the screen.</p>
  
  <pre><code>public class OpenGL extends Fragment {
  
  
  private GLSurfaceView mGLView;
  private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
  private float mPreviousX;
  private float mPreviousY;
  private OpenGLRenderer mRenderer;
  public int height = 0;
  public int width = 0;
  
  public OpenGL() {
      // Required empty public constructor
  }
  
  
  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
                           Bundle savedInstanceState) {
  
  
      mGLView = new GLSurfaceView(getActivity());
      mGLView.setEGLContextClientVersion(2);
      mRenderer = new OpenGLRenderer();
      mGLView.setRenderer(mRenderer);
      // Render the view only when there is a change in the drawing data
      mGLView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
  
      DisplayMetrics displayMetrics = new DisplayMetrics();
      ((Activity) getContext()).getWindowManager()
              .getDefaultDisplay()
              .getMetrics(displayMetrics);
       height = displayMetrics.heightPixels;
       width = displayMetrics.widthPixels;
  
  
      mGLView.setOnTouchListener(new View.OnTouchListener() {
          @Override
          public boolean onTouch(View v, MotionEvent e) {
  
                  // MotionEvent reports input details from the touch screen
                  // and other input controls. In this case, you are only
                  // interested in events where the touch position changed.
  
                  float x = e.getX();
                  float y = e.getY();
  
                  switch (e.getAction()) {
                      case MotionEvent.ACTION_MOVE:
  
                          float dx = x - mPreviousX;
                          float dy = y - mPreviousY;
  
                          // reverse direction of rotation above the mid-line
                          if (y &gt; height / 2) {
                              dx = dx * -1;
                          }
  
                          // reverse direction of rotation to left of the mid-line
                          if (x &lt; width / 2) {
                              dy = dy * -1;
                          }
  
                          mRenderer.setAngle(
                                  mRenderer.getAngle() +
                                          ((dx + dy) * TOUCH_SCALE_FACTOR));
                          mGLView.requestRender();
                  }
  
                  mPreviousX = x;
                  mPreviousY = y;
                  return true;
              }
  
      });
  
      return mGLView;
  }
  
  @Override
  public void onResume() {
      super.onResume();
      mGLView.onResume();
  }
  
  @Override
  public void onPause() {
      super.onPause();
      mGLView.onPause();
  }
  </code></pre>
  
  <p>}</p>
  
  <p>class OpenGLRenderer implements GLSurfaceView.Renderer {</p>
  
  <pre><code>private Triangle mRectangle;
  private OpenGL mOpenGL = new OpenGL();
  // 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];
  private float[] mRotationMatrix = new float[16];
  float[] scratch = new float[16];
  public volatile float mAngle;
  
  
  public float getAngle() {
      return mAngle;
  }
  
  public void setAngle(float angle) {
      mAngle = angle;
  }
  
  public void onSurfaceCreated(GL10 gl, EGLConfig config) {
      // Set the background frame color
      //GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  
      GLES20.glViewport(0, 0, mOpenGL.width, mOpenGL.height);
  
      float ratio = (float) mOpenGL.width / mOpenGL.height;
  
      // this projection matrix is applied to object coordinates
      // in the onDrawFrame() method
      Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
  
      mRectangle = new Triangle();
  }
  
  public void onDrawFrame(GL10 gl) {
  
      // Redraw background color
      GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
  
      // Set the camera position (View matrix)
      Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
  
      // Calculate the projection and view transformation
      Matrix.multiplyMM(mMVPMatrix, 0, mRotationMatrix, 0, mViewMatrix, 0);
  
      // Create a rotation for the triangle
      // long time = SystemClock.uptimeMillis() % 4000L;
      // float angle = 0.090f * ((int) time);
      Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);
  
      // Combine the rotation matrix with the projection and camera view
      // Note that the mMVPMatrix factor *must be first* in order
      // for the matrix multiplication product to be correct.
      Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);
  
      // Draw triangle
      mRectangle.drawMatrix(scratch);
  }
  
  public void onSurfaceChanged(GL10 gl, int width, int height) {
      GLES20.glViewport(0, 0, width, height);
  }
  
  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;
  }
  </code></pre>
  
  <p>}</p>
  
  <p>class Triangle {</p>
  
  <pre><code> private final String vertexShaderCodeMatrix =
           // 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;" +
                   "}";
  
   // Use to access and set the view transformation
   private int mMVPMatrixHandle;
  
  
   private final String vertexShaderCode =
           "attribute vec4 vPosition;" +
                   "void main() {" +
                   "  gl_Position = vPosition;" +
                   "}";
  
   private final String fragmentShaderCode =
           "precision mediump float;" +
                   "uniform vec4 vColor;" +
                   "void main() {" +
                   "  gl_FragColor = vColor;" +
                   "}";
  
   // number of coordinates per vertex in this array
   static final int COORDS_PER_VERTEX = 3;
   static float triangleCoords[] = {   // in counterclockwise order:
           0.0f,  0.622008459f, 0.0f, // top
           -0.5f, -0.311004243f, 0.0f, // bottom left
           0.5f, -0.311004243f, 0.0f  // bottom right
   };
  
   // Set color with red, green, blue and alpha (opacity) values
   float color[] = { 0.5f, 0.5f, 0.5f, 1.0f };
  
  
   private final int mProgram;
  
  private short[] indices = {0,1,2,0,2,3};
  
  private FloatBuffer vertexBuffer;
  private ShortBuffer indexBuffer;
  
   public Triangle() {
  
       // initialize vertex byte buffer for shape coordinates
       ByteBuffer bb = ByteBuffer.allocateDirect(
               // (number of coordinate values * 4 bytes per float)
               triangleCoords.length * 4);
       // use the device hardware's native byte order
       bb.order(ByteOrder.nativeOrder());
  
       // create a floating point buffer from the ByteBuffer
       vertexBuffer = bb.asFloatBuffer();
       // add the coordinates to the FloatBuffer
       vertexBuffer.put(triangleCoords);
       // set the buffer to read the first coordinate
       vertexBuffer.position(0);
  
       int vertexShader = OpenGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER,
               vertexShaderCode);
       int fragmentShader = OpenGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER,
               fragmentShaderCode);
  
       // create empty OpenGL ES Program
       mProgram = GLES20.glCreateProgram();
  
       // add the vertex shader to program
       GLES20.glAttachShader(mProgram, vertexShader);
  
       // add the fragment shader to program
       GLES20.glAttachShader(mProgram, fragmentShader);
  
       // creates OpenGL ES program executables
       GLES20.glLinkProgram(mProgram);
   }
  
   private int mPositionHandle;
   private int mColorHandle;
  
   private final int vertexCount = triangleCoords.length / COORDS_PER_VERTEX;
   private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
  
   public void draw() {
       // Add program to OpenGL ES 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);
  
       // Draw the triangle
       GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
  
       // Disable vertex array
       GLES20.glDisableVertexAttribArray(mPositionHandle);
   }
  
   public void drawMatrix(float[] mvpMatrix) { // pass in the calculated transformation matrix
  
  
       // Add program to OpenGL ES 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");
  
       // Pass the projection and view transformation to the shader
       GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
  
       // Draw the triangle
       GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);
  
       // Disable vertex array
       GLES20.glDisableVertexAttribArray(mPositionHandle);
   }
  </code></pre>
  
  <p>}</p>