Imported Upstream version 9.0.0
[platform/upstream/libGLU.git] / src / libutil / project.c
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 */
40 static 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
48 static 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
56 void GLAPIENTRY
57 gluOrtho2D(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
64 void GLAPIENTRY
65 gluPerspective(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
88 static 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
100 static 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
107 void GLAPIENTRY
108 gluLookAt(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
149 static 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 */
167 static 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
217 static 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
233 GLint GLAPIENTRY
234 gluProject(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
268 GLint GLAPIENTRY
269 gluUnProject(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
307 GLint GLAPIENTRY
308 gluUnProject4(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
347 void GLAPIENTRY
348 gluPickMatrix(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 }