1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.opengl;
18
19import javax.microedition.khronos.opengles.GL10;
20
21/**
22 * A set of GL utilities inspired by the OpenGL Utility Toolkit.
23 *
24 */
25
26public class GLU {
27
28    /**
29     * Return an error string from a GL or GLU error code.
30     *
31     * @param error - a GL or GLU error code.
32     * @return the error string for the input error code, or NULL if the input
33     *         was not a valid GL or GLU error code.
34     */
35    public static String gluErrorString(int error) {
36        switch (error) {
37        case GL10.GL_NO_ERROR:
38            return "no error";
39        case GL10.GL_INVALID_ENUM:
40            return "invalid enum";
41        case GL10.GL_INVALID_VALUE:
42            return "invalid value";
43        case GL10.GL_INVALID_OPERATION:
44            return "invalid operation";
45        case GL10.GL_STACK_OVERFLOW:
46            return "stack overflow";
47        case GL10.GL_STACK_UNDERFLOW:
48            return "stack underflow";
49        case GL10.GL_OUT_OF_MEMORY:
50            return "out of memory";
51        default:
52            return null;
53        }
54    }
55
56    /**
57     * Define a viewing transformation in terms of an eye point, a center of
58     * view, and an up vector.
59     *
60     * @param gl a GL10 interface
61     * @param eyeX eye point X
62     * @param eyeY eye point Y
63     * @param eyeZ eye point Z
64     * @param centerX center of view X
65     * @param centerY center of view Y
66     * @param centerZ center of view Z
67     * @param upX up vector X
68     * @param upY up vector Y
69     * @param upZ up vector Z
70     */
71    public static void gluLookAt(GL10 gl, float eyeX, float eyeY, float eyeZ,
72            float centerX, float centerY, float centerZ, float upX, float upY,
73            float upZ) {
74
75        float[] scratch = sScratch;
76        synchronized(scratch) {
77            Matrix.setLookAtM(scratch, 0, eyeX, eyeY, eyeZ, centerX, centerY, centerZ,
78                    upX, upY, upZ);
79            gl.glMultMatrixf(scratch, 0);
80        }
81    }
82
83    /**
84     * Set up a 2D orthographic projection matrix
85     *
86     * @param gl
87     * @param left
88     * @param right
89     * @param bottom
90     * @param top
91     */
92    public static void gluOrtho2D(GL10 gl, float left, float right,
93            float bottom, float top) {
94        gl.glOrthof(left, right, bottom, top, -1.0f, 1.0f);
95    }
96
97    /**
98     * Set up a perspective projection matrix
99     *
100     * @param gl a GL10 interface
101     * @param fovy specifies the field of view angle, in degrees, in the Y
102     *        direction.
103     * @param aspect specifies the aspect ration that determins the field of
104     *        view in the x direction. The aspect ratio is the ratio of x
105     *        (width) to y (height).
106     * @param zNear specifies the distance from the viewer to the near clipping
107     *        plane (always positive).
108     * @param zFar specifies the distance from the viewer to the far clipping
109     *        plane (always positive).
110     */
111    public static void gluPerspective(GL10 gl, float fovy, float aspect,
112            float zNear, float zFar) {
113        float top = zNear * (float) Math.tan(fovy * (Math.PI / 360.0));
114        float bottom = -top;
115        float left = bottom * aspect;
116        float right = top * aspect;
117        gl.glFrustumf(left, right, bottom, top, zNear, zFar);
118    }
119
120    /**
121     * Map object coordinates into window coordinates. gluProject transforms the
122     * specified object coordinates into window coordinates using model, proj,
123     * and view. The result is stored in win.
124     * <p>
125     * Note that you can use the OES_matrix_get extension, if present, to get
126     * the current modelView and projection matrices.
127     *
128     * @param objX object coordinates X
129     * @param objY object coordinates Y
130     * @param objZ object coordinates Z
131     * @param model the current modelview matrix
132     * @param modelOffset the offset into the model array where the modelview
133     *        maxtrix data starts.
134     * @param project the current projection matrix
135     * @param projectOffset the offset into the project array where the project
136     *        matrix data starts.
137     * @param view the current view, {x, y, width, height}
138     * @param viewOffset the offset into the view array where the view vector
139     *        data starts.
140     * @param win the output vector {winX, winY, winZ}, that returns the
141     *        computed window coordinates.
142     * @param winOffset the offset into the win array where the win vector data
143     *        starts.
144     * @return A return value of GL_TRUE indicates success, a return value of
145     *         GL_FALSE indicates failure.
146     */
147    public static int gluProject(float objX, float objY, float objZ,
148            float[] model, int modelOffset, float[] project, int projectOffset,
149            int[] view, int viewOffset, float[] win, int winOffset) {
150        float[] scratch = sScratch;
151        synchronized(scratch) {
152            final int M_OFFSET = 0; // 0..15
153            final int V_OFFSET = 16; // 16..19
154            final int V2_OFFSET = 20; // 20..23
155            Matrix.multiplyMM(scratch, M_OFFSET, project, projectOffset,
156                    model, modelOffset);
157
158            scratch[V_OFFSET + 0] = objX;
159            scratch[V_OFFSET + 1] = objY;
160            scratch[V_OFFSET + 2] = objZ;
161            scratch[V_OFFSET + 3] = 1.0f;
162
163            Matrix.multiplyMV(scratch, V2_OFFSET,
164                    scratch, M_OFFSET, scratch, V_OFFSET);
165
166            float w = scratch[V2_OFFSET + 3];
167            if (w == 0.0f) {
168                return GL10.GL_FALSE;
169            }
170
171            float rw = 1.0f / w;
172
173            win[winOffset] =
174                    view[viewOffset] + view[viewOffset + 2]
175                            * (scratch[V2_OFFSET + 0] * rw + 1.0f)
176                            * 0.5f;
177            win[winOffset + 1] =
178                    view[viewOffset + 1] + view[viewOffset + 3]
179                            * (scratch[V2_OFFSET + 1] * rw + 1.0f) * 0.5f;
180            win[winOffset + 2] = (scratch[V2_OFFSET + 2] * rw + 1.0f) * 0.5f;
181        }
182
183        return GL10.GL_TRUE;
184    }
185
186    /**
187     * Map window coordinates to object coordinates. gluUnProject maps the
188     * specified window coordinates into object coordinates using model, proj,
189     * and view. The result is stored in obj.
190     * <p>
191     * Note that you can use the OES_matrix_get extension, if present, to get
192     * the current modelView and projection matrices.
193     *
194     * @param winX window coordinates X
195     * @param winY window coordinates Y
196     * @param winZ window coordinates Z
197     * @param model the current modelview matrix
198     * @param modelOffset the offset into the model array where the modelview
199     *        maxtrix data starts.
200     * @param project the current projection matrix
201     * @param projectOffset the offset into the project array where the project
202     *        matrix data starts.
203     * @param view the current view, {x, y, width, height}
204     * @param viewOffset the offset into the view array where the view vector
205     *        data starts.
206     * @param obj the output vector {objX, objY, objZ}, that returns the
207     *        computed object coordinates.
208     * @param objOffset the offset into the obj array where the obj vector data
209     *        starts.
210     * @return A return value of GL10.GL_TRUE indicates success, a return value
211     *         of GL10.GL_FALSE indicates failure.
212     */
213    public static int gluUnProject(float winX, float winY, float winZ,
214            float[] model, int modelOffset, float[] project, int projectOffset,
215            int[] view, int viewOffset, float[] obj, int objOffset) {
216        float[] scratch = sScratch;
217        synchronized(scratch) {
218            final int PM_OFFSET = 0; // 0..15
219            final int INVPM_OFFSET = 16; // 16..31
220               final int V_OFFSET = 0; // 0..3 Reuses PM_OFFSET space
221            Matrix.multiplyMM(scratch, PM_OFFSET, project, projectOffset,
222                    model, modelOffset);
223
224            if (!Matrix.invertM(scratch, INVPM_OFFSET, scratch, PM_OFFSET)) {
225                return GL10.GL_FALSE;
226            }
227
228            scratch[V_OFFSET + 0] =
229                    2.0f * (winX - view[viewOffset + 0]) / view[viewOffset + 2]
230                            - 1.0f;
231            scratch[V_OFFSET + 1] =
232                    2.0f * (winY - view[viewOffset + 1]) / view[viewOffset + 3]
233                            - 1.0f;
234            scratch[V_OFFSET + 2] = 2.0f * winZ - 1.0f;
235            scratch[V_OFFSET + 3] = 1.0f;
236
237            Matrix.multiplyMV(obj, objOffset, scratch, INVPM_OFFSET,
238                    scratch, V_OFFSET);
239        }
240
241        return GL10.GL_TRUE;
242    }
243
244    private static final float[] sScratch = new float[32];
245 }
246