1f220fa62Smrg/*
2f220fa62Smrg * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3f220fa62Smrg * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
4f220fa62Smrg *
5f220fa62Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6f220fa62Smrg * copy of this software and associated documentation files (the "Software"),
7f220fa62Smrg * to deal in the Software without restriction, including without limitation
8f220fa62Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9f220fa62Smrg * and/or sell copies of the Software, and to permit persons to whom the
10f220fa62Smrg * Software is furnished to do so, subject to the following conditions:
11f220fa62Smrg *
12f220fa62Smrg * The above copyright notice including the dates of first publication and
13f220fa62Smrg * either this permission notice or a reference to
14f220fa62Smrg * http://oss.sgi.com/projects/FreeB/
15f220fa62Smrg * shall be included in all copies or substantial portions of the Software.
16f220fa62Smrg *
17f220fa62Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18f220fa62Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19f220fa62Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20f220fa62Smrg * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21f220fa62Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22f220fa62Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23f220fa62Smrg * SOFTWARE.
24f220fa62Smrg *
25f220fa62Smrg * Except as contained in this notice, the name of Silicon Graphics, Inc.
26f220fa62Smrg * shall not be used in advertising or otherwise to promote the sale, use or
27f220fa62Smrg * other dealings in this Software without prior written authorization from
28f220fa62Smrg * Silicon Graphics, Inc.
29f220fa62Smrg */
30f220fa62Smrg
31f220fa62Smrg#include "gluos.h"
32f220fa62Smrg#include <math.h>
33f220fa62Smrg#include <GL/gl.h>
34f220fa62Smrg#include <GL/glu.h>
35f220fa62Smrg#include "gluint.h"
36f220fa62Smrg
37f220fa62Smrg/*
38f220fa62Smrg** Make m an identity matrix
39f220fa62Smrg*/
40f220fa62Smrgstatic void __gluMakeIdentityd(GLdouble m[16])
41f220fa62Smrg{
42f220fa62Smrg    m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0;
43f220fa62Smrg    m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0;
44f220fa62Smrg    m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0;
45f220fa62Smrg    m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1;
46f220fa62Smrg}
47f220fa62Smrg
48f220fa62Smrgstatic void __gluMakeIdentityf(GLfloat m[16])
49f220fa62Smrg{
50f220fa62Smrg    m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0;
51f220fa62Smrg    m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0;
52f220fa62Smrg    m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0;
53f220fa62Smrg    m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1;
54f220fa62Smrg}
55f220fa62Smrg
56f220fa62Smrgvoid GLAPIENTRY
57f220fa62SmrggluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top)
58f220fa62Smrg{
59f220fa62Smrg    glOrtho(left, right, bottom, top, -1, 1);
60f220fa62Smrg}
61f220fa62Smrg
62f220fa62Smrg#define __glPi 3.14159265358979323846
63f220fa62Smrg
64f220fa62Smrgvoid GLAPIENTRY
65f220fa62SmrggluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
66f220fa62Smrg{
67f220fa62Smrg    GLdouble m[4][4];
68f220fa62Smrg    double sine, cotangent, deltaZ;
69f220fa62Smrg    double radians = fovy / 2 * __glPi / 180;
70f220fa62Smrg
71f220fa62Smrg    deltaZ = zFar - zNear;
72f220fa62Smrg    sine = sin(radians);
73f220fa62Smrg    if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) {
74f220fa62Smrg	return;
75f220fa62Smrg    }
76f220fa62Smrg    cotangent = COS(radians) / sine;
77f220fa62Smrg
78f220fa62Smrg    __gluMakeIdentityd(&m[0][0]);
79f220fa62Smrg    m[0][0] = cotangent / aspect;
80f220fa62Smrg    m[1][1] = cotangent;
81f220fa62Smrg    m[2][2] = -(zFar + zNear) / deltaZ;
82f220fa62Smrg    m[2][3] = -1;
83f220fa62Smrg    m[3][2] = -2 * zNear * zFar / deltaZ;
84f220fa62Smrg    m[3][3] = 0;
85f220fa62Smrg    glMultMatrixd(&m[0][0]);
86f220fa62Smrg}
87f220fa62Smrg
88f220fa62Smrgstatic void normalize(float v[3])
89f220fa62Smrg{
90f220fa62Smrg    float r;
91f220fa62Smrg
92f220fa62Smrg    r = sqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] );
93f220fa62Smrg    if (r == 0.0) return;
94f220fa62Smrg
95f220fa62Smrg    v[0] /= r;
96f220fa62Smrg    v[1] /= r;
97f220fa62Smrg    v[2] /= r;
98f220fa62Smrg}
99f220fa62Smrg
100f220fa62Smrgstatic void cross(float v1[3], float v2[3], float result[3])
101f220fa62Smrg{
102f220fa62Smrg    result[0] = v1[1]*v2[2] - v1[2]*v2[1];
103f220fa62Smrg    result[1] = v1[2]*v2[0] - v1[0]*v2[2];
104f220fa62Smrg    result[2] = v1[0]*v2[1] - v1[1]*v2[0];
105f220fa62Smrg}
106f220fa62Smrg
107f220fa62Smrgvoid GLAPIENTRY
108f220fa62SmrggluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx,
109f220fa62Smrg	  GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy,
110f220fa62Smrg	  GLdouble upz)
111f220fa62Smrg{
112f220fa62Smrg    float forward[3], side[3], up[3];
113f220fa62Smrg    GLfloat m[4][4];
114f220fa62Smrg
115f220fa62Smrg    forward[0] = centerx - eyex;
116f220fa62Smrg    forward[1] = centery - eyey;
117f220fa62Smrg    forward[2] = centerz - eyez;
118f220fa62Smrg
119f220fa62Smrg    up[0] = upx;
120f220fa62Smrg    up[1] = upy;
121f220fa62Smrg    up[2] = upz;
122f220fa62Smrg
123f220fa62Smrg    normalize(forward);
124f220fa62Smrg
125f220fa62Smrg    /* Side = forward x up */
126f220fa62Smrg    cross(forward, up, side);
127f220fa62Smrg    normalize(side);
128f220fa62Smrg
129f220fa62Smrg    /* Recompute up as: up = side x forward */
130f220fa62Smrg    cross(side, forward, up);
131f220fa62Smrg
132f220fa62Smrg    __gluMakeIdentityf(&m[0][0]);
133f220fa62Smrg    m[0][0] = side[0];
134f220fa62Smrg    m[1][0] = side[1];
135f220fa62Smrg    m[2][0] = side[2];
136f220fa62Smrg
137f220fa62Smrg    m[0][1] = up[0];
138f220fa62Smrg    m[1][1] = up[1];
139f220fa62Smrg    m[2][1] = up[2];
140f220fa62Smrg
141f220fa62Smrg    m[0][2] = -forward[0];
142f220fa62Smrg    m[1][2] = -forward[1];
143f220fa62Smrg    m[2][2] = -forward[2];
144f220fa62Smrg
145f220fa62Smrg    glMultMatrixf(&m[0][0]);
146f220fa62Smrg    glTranslated(-eyex, -eyey, -eyez);
147f220fa62Smrg}
148f220fa62Smrg
149f220fa62Smrgstatic void __gluMultMatrixVecd(const GLdouble matrix[16], const GLdouble in[4],
150f220fa62Smrg		      GLdouble out[4])
151f220fa62Smrg{
152f220fa62Smrg    int i;
153f220fa62Smrg
154f220fa62Smrg    for (i=0; i<4; i++) {
155f220fa62Smrg	out[i] =
156f220fa62Smrg	    in[0] * matrix[0*4+i] +
157f220fa62Smrg	    in[1] * matrix[1*4+i] +
158f220fa62Smrg	    in[2] * matrix[2*4+i] +
159f220fa62Smrg	    in[3] * matrix[3*4+i];
160f220fa62Smrg    }
161f220fa62Smrg}
162f220fa62Smrg
163f220fa62Smrg/*
164f220fa62Smrg** Invert 4x4 matrix.
165f220fa62Smrg** Contributed by David Moore (See Mesa bug #6748)
166f220fa62Smrg*/
167f220fa62Smrgstatic int __gluInvertMatrixd(const GLdouble m[16], GLdouble invOut[16])
168f220fa62Smrg{
169f220fa62Smrg    double inv[16], det;
170f220fa62Smrg    int i;
171f220fa62Smrg
172f220fa62Smrg    inv[0] =   m[5]*m[10]*m[15] - m[5]*m[11]*m[14] - m[9]*m[6]*m[15]
173f220fa62Smrg             + m[9]*m[7]*m[14] + m[13]*m[6]*m[11] - m[13]*m[7]*m[10];
174f220fa62Smrg    inv[4] =  -m[4]*m[10]*m[15] + m[4]*m[11]*m[14] + m[8]*m[6]*m[15]
175f220fa62Smrg             - m[8]*m[7]*m[14] - m[12]*m[6]*m[11] + m[12]*m[7]*m[10];
176f220fa62Smrg    inv[8] =   m[4]*m[9]*m[15] - m[4]*m[11]*m[13] - m[8]*m[5]*m[15]
177f220fa62Smrg             + m[8]*m[7]*m[13] + m[12]*m[5]*m[11] - m[12]*m[7]*m[9];
178f220fa62Smrg    inv[12] = -m[4]*m[9]*m[14] + m[4]*m[10]*m[13] + m[8]*m[5]*m[14]
179f220fa62Smrg             - m[8]*m[6]*m[13] - m[12]*m[5]*m[10] + m[12]*m[6]*m[9];
180f220fa62Smrg    inv[1] =  -m[1]*m[10]*m[15] + m[1]*m[11]*m[14] + m[9]*m[2]*m[15]
181f220fa62Smrg             - m[9]*m[3]*m[14] - m[13]*m[2]*m[11] + m[13]*m[3]*m[10];
182f220fa62Smrg    inv[5] =   m[0]*m[10]*m[15] - m[0]*m[11]*m[14] - m[8]*m[2]*m[15]
183f220fa62Smrg             + m[8]*m[3]*m[14] + m[12]*m[2]*m[11] - m[12]*m[3]*m[10];
184f220fa62Smrg    inv[9] =  -m[0]*m[9]*m[15] + m[0]*m[11]*m[13] + m[8]*m[1]*m[15]
185f220fa62Smrg             - m[8]*m[3]*m[13] - m[12]*m[1]*m[11] + m[12]*m[3]*m[9];
186f220fa62Smrg    inv[13] =  m[0]*m[9]*m[14] - m[0]*m[10]*m[13] - m[8]*m[1]*m[14]
187f220fa62Smrg             + m[8]*m[2]*m[13] + m[12]*m[1]*m[10] - m[12]*m[2]*m[9];
188f220fa62Smrg    inv[2] =   m[1]*m[6]*m[15] - m[1]*m[7]*m[14] - m[5]*m[2]*m[15]
189f220fa62Smrg             + m[5]*m[3]*m[14] + m[13]*m[2]*m[7] - m[13]*m[3]*m[6];
190f220fa62Smrg    inv[6] =  -m[0]*m[6]*m[15] + m[0]*m[7]*m[14] + m[4]*m[2]*m[15]
191f220fa62Smrg             - m[4]*m[3]*m[14] - m[12]*m[2]*m[7] + m[12]*m[3]*m[6];
192f220fa62Smrg    inv[10] =  m[0]*m[5]*m[15] - m[0]*m[7]*m[13] - m[4]*m[1]*m[15]
193f220fa62Smrg             + m[4]*m[3]*m[13] + m[12]*m[1]*m[7] - m[12]*m[3]*m[5];
194f220fa62Smrg    inv[14] = -m[0]*m[5]*m[14] + m[0]*m[6]*m[13] + m[4]*m[1]*m[14]
195f220fa62Smrg             - m[4]*m[2]*m[13] - m[12]*m[1]*m[6] + m[12]*m[2]*m[5];
196f220fa62Smrg    inv[3] =  -m[1]*m[6]*m[11] + m[1]*m[7]*m[10] + m[5]*m[2]*m[11]
197f220fa62Smrg             - m[5]*m[3]*m[10] - m[9]*m[2]*m[7] + m[9]*m[3]*m[6];
198f220fa62Smrg    inv[7] =   m[0]*m[6]*m[11] - m[0]*m[7]*m[10] - m[4]*m[2]*m[11]
199f220fa62Smrg             + m[4]*m[3]*m[10] + m[8]*m[2]*m[7] - m[8]*m[3]*m[6];
200f220fa62Smrg    inv[11] = -m[0]*m[5]*m[11] + m[0]*m[7]*m[9] + m[4]*m[1]*m[11]
201f220fa62Smrg             - m[4]*m[3]*m[9] - m[8]*m[1]*m[7] + m[8]*m[3]*m[5];
202f220fa62Smrg    inv[15] =  m[0]*m[5]*m[10] - m[0]*m[6]*m[9] - m[4]*m[1]*m[10]
203f220fa62Smrg             + m[4]*m[2]*m[9] + m[8]*m[1]*m[6] - m[8]*m[2]*m[5];
204f220fa62Smrg
205f220fa62Smrg    det = m[0]*inv[0] + m[1]*inv[4] + m[2]*inv[8] + m[3]*inv[12];
206f220fa62Smrg    if (det == 0)
207f220fa62Smrg        return GL_FALSE;
208f220fa62Smrg
209f220fa62Smrg    det = 1.0 / det;
210f220fa62Smrg
211f220fa62Smrg    for (i = 0; i < 16; i++)
212f220fa62Smrg        invOut[i] = inv[i] * det;
213f220fa62Smrg
214f220fa62Smrg    return GL_TRUE;
215f220fa62Smrg}
216f220fa62Smrg
217f220fa62Smrgstatic void __gluMultMatricesd(const GLdouble a[16], const GLdouble b[16],
218f220fa62Smrg				GLdouble r[16])
219f220fa62Smrg{
220f220fa62Smrg    int i, j;
221f220fa62Smrg
222f220fa62Smrg    for (i = 0; i < 4; i++) {
223f220fa62Smrg	for (j = 0; j < 4; j++) {
224f220fa62Smrg	    r[i*4+j] =
225f220fa62Smrg		a[i*4+0]*b[0*4+j] +
226f220fa62Smrg		a[i*4+1]*b[1*4+j] +
227f220fa62Smrg		a[i*4+2]*b[2*4+j] +
228f220fa62Smrg		a[i*4+3]*b[3*4+j];
229f220fa62Smrg	}
230f220fa62Smrg    }
231f220fa62Smrg}
232f220fa62Smrg
233f220fa62SmrgGLint GLAPIENTRY
234f220fa62SmrggluProject(GLdouble objx, GLdouble objy, GLdouble objz,
235f220fa62Smrg	      const GLdouble modelMatrix[16],
236f220fa62Smrg	      const GLdouble projMatrix[16],
237f220fa62Smrg              const GLint viewport[4],
238f220fa62Smrg	      GLdouble *winx, GLdouble *winy, GLdouble *winz)
239f220fa62Smrg{
240f220fa62Smrg    double in[4];
241f220fa62Smrg    double out[4];
242f220fa62Smrg
243f220fa62Smrg    in[0]=objx;
244f220fa62Smrg    in[1]=objy;
245f220fa62Smrg    in[2]=objz;
246f220fa62Smrg    in[3]=1.0;
247f220fa62Smrg    __gluMultMatrixVecd(modelMatrix, in, out);
248f220fa62Smrg    __gluMultMatrixVecd(projMatrix, out, in);
249f220fa62Smrg    if (in[3] == 0.0) return(GL_FALSE);
250f220fa62Smrg    in[0] /= in[3];
251f220fa62Smrg    in[1] /= in[3];
252f220fa62Smrg    in[2] /= in[3];
253f220fa62Smrg    /* Map x, y and z to range 0-1 */
254f220fa62Smrg    in[0] = in[0] * 0.5 + 0.5;
255f220fa62Smrg    in[1] = in[1] * 0.5 + 0.5;
256f220fa62Smrg    in[2] = in[2] * 0.5 + 0.5;
257f220fa62Smrg
258f220fa62Smrg    /* Map x,y to viewport */
259f220fa62Smrg    in[0] = in[0] * viewport[2] + viewport[0];
260f220fa62Smrg    in[1] = in[1] * viewport[3] + viewport[1];
261f220fa62Smrg
262f220fa62Smrg    *winx=in[0];
263f220fa62Smrg    *winy=in[1];
264f220fa62Smrg    *winz=in[2];
265f220fa62Smrg    return(GL_TRUE);
266f220fa62Smrg}
267f220fa62Smrg
268f220fa62SmrgGLint GLAPIENTRY
269f220fa62SmrggluUnProject(GLdouble winx, GLdouble winy, GLdouble winz,
270f220fa62Smrg		const GLdouble modelMatrix[16],
271f220fa62Smrg		const GLdouble projMatrix[16],
272f220fa62Smrg                const GLint viewport[4],
273f220fa62Smrg	        GLdouble *objx, GLdouble *objy, GLdouble *objz)
274f220fa62Smrg{
275f220fa62Smrg    double finalMatrix[16];
276f220fa62Smrg    double in[4];
277f220fa62Smrg    double out[4];
278f220fa62Smrg
279f220fa62Smrg    __gluMultMatricesd(modelMatrix, projMatrix, finalMatrix);
280f220fa62Smrg    if (!__gluInvertMatrixd(finalMatrix, finalMatrix)) return(GL_FALSE);
281f220fa62Smrg
282f220fa62Smrg    in[0]=winx;
283f220fa62Smrg    in[1]=winy;
284f220fa62Smrg    in[2]=winz;
285f220fa62Smrg    in[3]=1.0;
286f220fa62Smrg
287f220fa62Smrg    /* Map x and y from window coordinates */
288f220fa62Smrg    in[0] = (in[0] - viewport[0]) / viewport[2];
289f220fa62Smrg    in[1] = (in[1] - viewport[1]) / viewport[3];
290f220fa62Smrg
291f220fa62Smrg    /* Map to range -1 to 1 */
292f220fa62Smrg    in[0] = in[0] * 2 - 1;
293f220fa62Smrg    in[1] = in[1] * 2 - 1;
294f220fa62Smrg    in[2] = in[2] * 2 - 1;
295f220fa62Smrg
296f220fa62Smrg    __gluMultMatrixVecd(finalMatrix, in, out);
297f220fa62Smrg    if (out[3] == 0.0) return(GL_FALSE);
298f220fa62Smrg    out[0] /= out[3];
299f220fa62Smrg    out[1] /= out[3];
300f220fa62Smrg    out[2] /= out[3];
301f220fa62Smrg    *objx = out[0];
302f220fa62Smrg    *objy = out[1];
303f220fa62Smrg    *objz = out[2];
304f220fa62Smrg    return(GL_TRUE);
305f220fa62Smrg}
306f220fa62Smrg
307f220fa62SmrgGLint GLAPIENTRY
308f220fa62SmrggluUnProject4(GLdouble winx, GLdouble winy, GLdouble winz, GLdouble clipw,
309f220fa62Smrg	      const GLdouble modelMatrix[16],
310f220fa62Smrg	      const GLdouble projMatrix[16],
311f220fa62Smrg	      const GLint viewport[4],
312f220fa62Smrg	      GLclampd nearVal, GLclampd farVal,
313f220fa62Smrg	      GLdouble *objx, GLdouble *objy, GLdouble *objz,
314f220fa62Smrg	      GLdouble *objw)
315f220fa62Smrg{
316f220fa62Smrg    double finalMatrix[16];
317f220fa62Smrg    double in[4];
318f220fa62Smrg    double out[4];
319f220fa62Smrg
320f220fa62Smrg    __gluMultMatricesd(modelMatrix, projMatrix, finalMatrix);
321f220fa62Smrg    if (!__gluInvertMatrixd(finalMatrix, finalMatrix)) return(GL_FALSE);
322f220fa62Smrg
323f220fa62Smrg    in[0]=winx;
324f220fa62Smrg    in[1]=winy;
325f220fa62Smrg    in[2]=winz;
326f220fa62Smrg    in[3]=clipw;
327f220fa62Smrg
328f220fa62Smrg    /* Map x and y from window coordinates */
329f220fa62Smrg    in[0] = (in[0] - viewport[0]) / viewport[2];
330f220fa62Smrg    in[1] = (in[1] - viewport[1]) / viewport[3];
331f220fa62Smrg    in[2] = (in[2] - nearVal) / (farVal - nearVal);
332f220fa62Smrg
333f220fa62Smrg    /* Map to range -1 to 1 */
334f220fa62Smrg    in[0] = in[0] * 2 - 1;
335f220fa62Smrg    in[1] = in[1] * 2 - 1;
336f220fa62Smrg    in[2] = in[2] * 2 - 1;
337f220fa62Smrg
338f220fa62Smrg    __gluMultMatrixVecd(finalMatrix, in, out);
339f220fa62Smrg    if (out[3] == 0.0) return(GL_FALSE);
340f220fa62Smrg    *objx = out[0];
341f220fa62Smrg    *objy = out[1];
342f220fa62Smrg    *objz = out[2];
343f220fa62Smrg    *objw = out[3];
344f220fa62Smrg    return(GL_TRUE);
345f220fa62Smrg}
346f220fa62Smrg
347f220fa62Smrgvoid GLAPIENTRY
348f220fa62SmrggluPickMatrix(GLdouble x, GLdouble y, GLdouble deltax, GLdouble deltay,
349f220fa62Smrg		  GLint viewport[4])
350f220fa62Smrg{
351f220fa62Smrg    if (deltax <= 0 || deltay <= 0) {
352f220fa62Smrg	return;
353f220fa62Smrg    }
354f220fa62Smrg
355f220fa62Smrg    /* Translate and scale the picked region to the entire window */
356f220fa62Smrg    glTranslatef((viewport[2] - 2 * (x - viewport[0])) / deltax,
357f220fa62Smrg	    (viewport[3] - 2 * (y - viewport[1])) / deltay, 0);
358f220fa62Smrg    glScalef(viewport[2] / deltax, viewport[3] / deltay, 1.0);
359f220fa62Smrg}
360