content: /*
   * Copyright (C) 2007 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.opengl;
  
  import javax.microedition.khronos.opengles.GL10;
  
  /**
   * A set of GL utilities inspired by the OpenGL Utility Toolkit.
   *
   */
  
  public class GLU {
  
      /**
       * Return an error string from a GL or GLU error code.
       *
       * @param error - a GL or GLU error code.
       * @return the error string for the input error code, or NULL if the input
       *         was not a valid GL or GLU error code.
       */
      public static String gluErrorString(int error) {
          switch (error) {
          case GL10.GL_NO_ERROR:
              return "no error";
          case GL10.GL_INVALID_ENUM:
              return "invalid enum";
          case GL10.GL_INVALID_VALUE:
              return "invalid value";
          case GL10.GL_INVALID_OPERATION:
              return "invalid operation";
          case GL10.GL_STACK_OVERFLOW:
              return "stack overflow";
          case GL10.GL_STACK_UNDERFLOW:
              return "stack underflow";
          case GL10.GL_OUT_OF_MEMORY:
              return "out of memory";
          default:
              return null;
          }
      }
  
      /**
       * Define a viewing transformation in terms of an eye point, a center of
       * view, and an up vector.
       *
       * @param gl a GL10 interface
       * @param eyeX eye point X
       * @param eyeY eye point Y
       * @param eyeZ eye point Z
       * @param centerX center of view X
       * @param centerY center of view Y
       * @param centerZ center of view Z
       * @param upX up vector X
       * @param upY up vector Y
       * @param upZ up vector Z
       */
      public static void gluLookAt(GL10 gl, float eyeX, float eyeY, float eyeZ,
              float centerX, float centerY, float centerZ, float upX, float upY,
              float upZ) {
  
          float[] scratch = sScratch;
          synchronized(scratch) {
              Matrix.setLookAtM(scratch, 0, eyeX, eyeY, eyeZ, centerX, centerY, centerZ,
                      upX, upY, upZ);
              gl.glMultMatrixf(scratch, 0);
          }
      }
  
      /**
       * Set up a 2D orthographic projection matrix
       *
       * @param gl
       * @param left
       * @param right
       * @param bottom
       * @param top
       */
      public static void gluOrtho2D(GL10 gl, float left, float right,
              float bottom, float top) {
          gl.glOrthof(left, right, bottom, top, -1.0f, 1.0f);
      }
  
      /**
       * Set up a perspective projection matrix
       *
       * @param gl a GL10 interface
       * @param fovy specifies the field of view angle, in degrees, in the Y
       *        direction.
       * @param aspect specifies the aspect ration that determins the field of
       *        view in the x direction. The aspect ratio is the ratio of x
       *        (width) to y (height).
       * @param zNear specifies the distance from the viewer to the near clipping
       *        plane (always positive).
       * @param zFar specifies the distance from the viewer to the far clipping
       *        plane (always positive).
       */
      public static void gluPerspective(GL10 gl, float fovy, float aspect,
              float zNear, float zFar) {
          float top = zNear * (float) Math.tan(fovy * (Math.PI / 360.0));
          float bottom = -top;
          float left = bottom * aspect;
          float right = top * aspect;
          gl.glFrustumf(left, right, bottom, top, zNear, zFar);
      }
  
      /**
       * Map object coordinates into window coordinates. gluProject transforms the
       * specified object coordinates into window coordinates using model, proj,
       * and view. The result is stored in win.
       * <p>
       * Note that you can use the OES_matrix_get extension, if present, to get
       * the current modelView and projection matrices.
       *
       * @param objX object coordinates X
       * @param objY object coordinates Y
       * @param objZ object coordinates Z
       * @param model the current modelview matrix
       * @param modelOffset the offset into the model array where the modelview
       *        maxtrix data starts.
       * @param project the current projection matrix
       * @param projectOffset the offset into the project array where the project
       *        matrix data starts.
       * @param view the current view, {x, y, width, height}
       * @param viewOffset the offset into the view array where the view vector
       *        data starts.
       * @param win the output vector {winX, winY, winZ}, that returns the
       *        computed window coordinates.
       * @param winOffset the offset into the win array where the win vector data
       *        starts.
       * @return A return value of GL_TRUE indicates success, a return value of
       *         GL_FALSE indicates failure.
       */
      public static int gluProject(float objX, float objY, float objZ,
              float[] model, int modelOffset, float[] project, int projectOffset,
              int[] view, int viewOffset, float[] win, int winOffset) {
          float[] scratch = sScratch;
          synchronized(scratch) {
              final int M_OFFSET = 0; // 0..15
              final int V_OFFSET = 16; // 16..19
              final int V2_OFFSET = 20; // 20..23
              Matrix.multiplyMM(scratch, M_OFFSET, project, projectOffset,
                      model, modelOffset);
  
              scratch[V_OFFSET + 0] = objX;
              scratch[V_OFFSET + 1] = objY;
              scratch[V_OFFSET + 2] = objZ;
              scratch[V_OFFSET + 3] = 1.0f;
  
              Matrix.multiplyMV(scratch, V2_OFFSET,
                      scratch, M_OFFSET, scratch, V_OFFSET);
  
              float w = scratch[V2_OFFSET + 3];
              if (w == 0.0f) {
                  return GL10.GL_FALSE;
              }
  
              float rw = 1.0f / w;
  
              win[winOffset] =
                      view[viewOffset] + view[viewOffset + 2]
                              * (scratch[V2_OFFSET + 0] * rw + 1.0f)
                              * 0.5f;
              win[winOffset + 1] =
                      view[viewOffset + 1] + view[viewOffset + 3]
                              * (scratch[V2_OFFSET + 1] * rw + 1.0f) * 0.5f;
              win[winOffset + 2] = (scratch[V2_OFFSET + 2] * rw + 1.0f) * 0.5f;
          }
  
          return GL10.GL_TRUE;
      }
  
      /**
       * Map window coordinates to object coordinates. gluUnProject maps the
       * specified window coordinates into object coordinates using model, proj,
       * and view. The result is stored in obj.
       * <p>
       * Note that you can use the OES_matrix_get extension, if present, to get
       * the current modelView and projection matrices.
       *
       * @param winX window coordinates X
       * @param winY window coordinates Y
       * @param winZ window coordinates Z
       * @param model the current modelview matrix
       * @param modelOffset the offset into the model array where the modelview
       *        maxtrix data starts.
       * @param project the current projection matrix
       * @param projectOffset the offset into the project array where the project
       *        matrix data starts.
       * @param view the current view, {x, y, width, height}
       * @param viewOffset the offset into the view array where the view vector
       *        data starts.
       * @param obj the output vector {objX, objY, objZ, objW}, that returns the
       *        computed homogeneous object coordinates.
       * @param objOffset the offset into the obj array where the obj vector data
       *        starts.
       * @return A return value of GL10.GL_TRUE indicates success, a return value
       *         of GL10.GL_FALSE indicates failure.
       */
      public static int gluUnProject(float winX, float winY, float winZ,
              float[] model, int modelOffset, float[] project, int projectOffset,
              int[] view, int viewOffset, float[] obj, int objOffset) {
          float[] scratch = sScratch;
          synchronized(scratch) {
              final int PM_OFFSET = 0; // 0..15
              final int INVPM_OFFSET = 16; // 16..31
                 final int V_OFFSET = 0; // 0..3 Reuses PM_OFFSET space
              Matrix.multiplyMM(scratch, PM_OFFSET, project, projectOffset,
                      model, modelOffset);
  
              if (!Matrix.invertM(scratch, INVPM_OFFSET, scratch, PM_OFFSET)) {
                  return GL10.GL_FALSE;
              }
  
              scratch[V_OFFSET + 0] =
                      2.0f * (winX - view[viewOffset + 0]) / view[viewOffset + 2]
                              - 1.0f;
              scratch[V_OFFSET + 1] =
                      2.0f * (winY - view[viewOffset + 1]) / view[viewOffset + 3]
                              - 1.0f;
              scratch[V_OFFSET + 2] = 2.0f * winZ - 1.0f;
              scratch[V_OFFSET + 3] = 1.0f;
  
              Matrix.multiplyMV(obj, objOffset, scratch, INVPM_OFFSET,
                      scratch, V_OFFSET);
          }
  
          return GL10.GL_TRUE;
      }
  
      private static final float[] sScratch = new float[32];
   }
  