title: OpenGL glTranslatef and glScalef
body: <p>I'm trying to implement a pan and pinch-to-zoom feature into an OpenGL application I have. I was able to implement the pan feature relatively easily with a simple <code>glTranslatef</code>, but using the <code>glScalef</code> function is presenting much more difficulty. I have three classes, one for the <code>GLSurfaceView</code>, one for the <code>GLTriangle</code>, and the third (below) for the <code>GLRenderer</code>, which is where the <code>glScalef</code> and <code>glTranslatef</code> are used.</p>
  
  <p><code>GLRenderer</code> Class:</p>
  
  <pre><code>public class GLRendererEx implements Renderer, OnTouchListener {
  
      private GLTriangleEx tri;
      float ratio;
      float x = 0, y = 0;
      float dx = 0, dy = 0;
      float sx = 0, sy = 0;
      float tx = 0, ty = 0;
      float xtwo = 0, ytwo = 0;
      float sxtwo = 0, sytwo = 0;
      float screenX, screenY;
      float xscale = 1, yscale = 1;
      float xscaletwo = 1;
      float xscaletotal = 1, yscaletotal = 1;
      int NONE = 0, DRAG = 1, ZOOM = 2;
      int mode = NONE;
      int width, height;
      boolean touched = true;
      Display getOrient = getWindowManager().getDefaultDisplay();
      int orientation;
  
      public GLRendererEx() {
          tri = new GLTriangleEx();
          screenX = ourSurface.getWidth();
          screenY = ourSurface.getHeight();
          ourSurface.setOnTouchListener(this);
      }
  
      @Override
      public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) {
          gl.glDisable(GL10.GL_DITHER);
          gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
          gl.glClearColor(0f, 0f, 0f, 1f);
          gl.glClearDepthf(1f);
          orientation = getOrient.getRotation();
      }
  
      @Override
      public void onDrawFrame(GL10 gl) {
          gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
  
          gl.glMatrixMode(GL10.GL_MODELVIEW);
          gl.glLoadIdentity();
          GLU.gluLookAt(gl, 0, 0, -5, 0, 0, 0, 0, 2, 0);
  
          //warning - x is backwards
          gl.glTranslatef(tx, ty, 0);
          gl.glScalef(xscaletotal, yscaletotal, 1);
          tri.draw(gl);
      }
  
      @Override
      public void onSurfaceChanged(GL10 gl, int width, int height) {
          gl.glViewport(0, 0, width, height);
          ratio = ((float) width) / height;
          screenX = width;
          screenY = height;
          orientation = getOrient.getRotation();
          gl.glMatrixMode(GL10.GL_PROJECTION);
          gl.glLoadIdentity();
          gl.glFrustumf(-ratio, ratio, -1, 1, 1, 50);
      }
  
      @Override
      public boolean onTouch(View v, MotionEvent event) {
          switch (event.getAction()) {
          case MotionEvent.ACTION_DOWN: {
              event.getActionIndex();
              sx = x = event.getX(0);
              sy = y = event.getY(0);
              mode = DRAG;
              break;
          }
          case MotionEvent.ACTION_POINTER_DOWN: {
              event.getActionIndex();
              sxtwo = xtwo = event.getX(1);
              sytwo = ytwo = event.getY(1);
              mode = ZOOM;
              touched = true;
              break;
          }
          case MotionEvent.ACTION_MOVE: { 
              x = event.getX(0);
              y = event.getY(0);
              xtwo = event.getX(1);
              ytwo = event.getY(1);
              if (mode == ZOOM)
                  midPoint(x, y, xtwo, ytwo);
              if (mode == DRAG) {
                  dx = x - sx;
                  dy = y - sy;
                  dx *= -8;
                  dy *= -8;
                  if (orientation == Configuration.ORIENTATION_LANDSCAPE) 
                      dx *= 2;
                  dx /= screenX;
                  dy /= screenY;
                  tx += dx;
                  ty += dy;
                  sx = x;
                  sy = y;
              }
              break;
          }       
          case MotionEvent.ACTION_POINTER_UP: {
              mode = DRAG;
              break;
          }
          case MotionEvent.ACTION_UP: {
              mode = NONE;
              break;
          }
          }
          return true;
      }
  
      private float midPoint(float x, float y, float xtwo, float ytwo) {
          x -= xtwo;
          y -= ytwo;
          if (touched) {
              sxtwo = x;
              sytwo = y;
              xscaletwo = FloatMath.sqrt(sxtwo * sxtwo + sytwo * sytwo);
                              touched = false;
          }
                      xscale -= xscaletwo;
          xscale  = FloatMath.sqrt(x * x + y * y);
          xscaletotal += xscale;
          yscaletotal = xscaletotal;
          return xscale;
      }
  
  }
  </code></pre>
  
  <p><code>x/y</code>'s are coordinates, <code>dx/dy</code> are the change in the coords, <code>sx/sy</code>'s are starting coords, <code>tx/ty</code> are the total changes in coords (for panning), <code>xscale/yscale</code>'s are the floats used to calculate the scale for zooming, <code>xscaletotal/yscaletotal</code> are total changes in zoom scale, none drag zoom and mode represent the mode.</p>
  
  <p>As it stands, I can zoom in by pulling my fingers apart, but a pinch also zooms instead of zooming out. Also, the zoom is much too sensitive.</p>
  
  <p>I don't really know how to solve this problem from here. Any help would be more than appreciated.</p>