title: Transform objects independently in OpenGL ES 2.0
body: <p>All the tutorials I've seen always use a single object, like a triangle or cube.  But it's not clear to me how I can independently manipulate separate objects.  I've seen some tutorials that refer to the fixed function pipeline and use pushmatrix and popmatrix, but with the programmable pipeline these functions are gone.  Below are an init function and a draw function that draw a single triangle on the screen and rotates it about the Z axis.  Can someone show me the code, or even pseudocode to add a second triangle and rotate it independently of the other triangle?  Say around a different axis or in the opposite direction?</p>
  
  <p>Here they are:</p>
  
  <pre><code>int Init(ESContext* esContext)
  {
      UserData* userData = (UserData *)esContext-&gt;userData;
      const char *vShaderStr =
          "attribute vec4 vPosition;  \n"
          "uniform mat4 MVPMatrix;"
          "void main()                \n"
          "{                          \n"
          "   gl_Position = MVPMatrix * vPosition;\n"
          "}                          \n";
  
      const char *fShaderStr =
          "precision mediump float;   \n"
          "void main()                \n"
          "{                          \n"
          "   gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); \n"
          "}                          \n";
  
      GLuint vertexShader;
      GLuint fragmentShader;
      GLuint programObject;
      GLint linked;
      GLfloat ratio = 320.0f/240.0f;
  
      vertexShader = LoadShader(GL_VERTEX_SHADER, vShaderStr);
      fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fShaderStr);
  
      programObject = glCreateProgram();
  
      if (programObject == 0)
          return 0;
  
      glAttachShader(programObject, vertexShader);
      glAttachShader(programObject, fragmentShader);
  
      glBindAttribLocation(programObject, 0, "vPosition");
      glLinkProgram(programObject);
      glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &amp;linked);
  
      if (!linked)
      {
          GLint infoLen = 0;
          glGetProgramiv(programObject, GL_INFO_LOG_LENGTH, &amp;infoLen);
  
          if (infoLen &gt; 1)
          {
              char* infoLog = (char *)malloc(sizeof(char) * infoLen);
              glGetProgramInfoLog(programObject, infoLen, NULL, infoLog);
  
              free(infoLog);
          }
  
          glDeleteProgram(programObject);
          return FALSE;
      }
  
      userData-&gt;programObject = programObject;
  
      glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
  
      glViewport(0, 0, esContext-&gt;width, esContext-&gt;height);
      glClear(GL_COLOR_BUFFER_BIT);
  
  
      glUseProgram(userData-&gt;programObject);
  
      userData-&gt;angle = 0.0f;
      userData-&gt;start = time(NULL);
      userData-&gt;ProjMatrix = PVRTMat4::Perspective(ratio*2.0f, 2.0f, 3.0f, 7.0f, PVRTMat4::eClipspace::OGL, false, false);
      userData-&gt;ViewMatrix = PVRTMat4::LookAtLH(PVRTVec3(0.0f, 0.0f, -3.0f), PVRTVec3(0.0f, 0.0f, 0.0f), PVRTVec3(0.0f, 1.0f, 0.0f));
      return TRUE;
  }
  
  
  
  void Draw(ESContext *esContext)
  {
      GLfloat vVertices[] = {0.0f, 0.5f, 0.0f,
                            -0.5f, -0.5f, 0.0f,
                             0.5f, -0.5f, 0.0f};
  
      GLint MVPHandle;
      double timelapse;
  
      PVRTMat4 MVPMatrix = PVRTMat4::Identity();
      UserData* userData = (UserData *)esContext-&gt;userData;
  
      timelapse = difftime(time(NULL), userData-&gt;start) * 1000;
      if(timelapse &gt; 16.0f) //Maintain approx 60FPS
      {
          if (userData-&gt;angle &gt; 360.0f)
          {
              userData-&gt;angle = 0.0f;
          }
          else
          {
              userData-&gt;angle += 0.1f;
          }
      }
  
      userData-&gt;ModelMatrix = PVRTMat4::RotationZ(userData-&gt;angle);
  
      MVPMatrix = userData-&gt;ViewMatrix * userData-&gt;ModelMatrix;
      MVPMatrix = userData-&gt;ProjMatrix * MVPMatrix;
  
      MVPHandle = glGetUniformLocation(userData-&gt;programObject, "MVPMatrix");
      glUniformMatrix4fv(MVPHandle, 1, FALSE, MVPMatrix.ptr());
  
      glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vVertices);
      glEnableVertexAttribArray(0);
  
      glClear(GL_COLOR_BUFFER_BIT);
      glDrawArrays(GL_TRIANGLES, 0, 3);
      eglSwapBuffers(esContext-&gt;eglDisplay, esContext-&gt;eglSurface);
  }
  </code></pre>