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