Merge commit 'origin/gallium-0.1' into gallium-0.2
[mesa.git] / src / glu / sgi / libutil / project.c
1 /*
2 ** License Applicability. Except to the extent portions of this file are
3 ** made subject to an alternative license as permitted in the SGI Free
4 ** Software License B, Version 1.1 (the "License"), the contents of this
5 ** file are subject only to the provisions of the License. You may not use
6 ** this file except in compliance with the License. You may obtain a copy
7 ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
8 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
9 **
10 ** http://oss.sgi.com/projects/FreeB
11 **
12 ** Note that, as provided in the License, the Software is distributed on an
13 ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
14 ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
15 ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
16 ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
17 **
18 ** Original Code. The Original Code is: OpenGL Sample Implementation,
19 ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
20 ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
21 ** Copyright in any portions created by third parties is as indicated
22 ** elsewhere herein. All Rights Reserved.
23 **
24 ** Additional Notice Provisions: The application programming interfaces
25 ** established by SGI in conjunction with the Original Code are The
26 ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
27 ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
28 ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
29 ** Window System(R) (Version 1.3), released October 19, 1998. This software
30 ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
31 ** published by SGI, but has not been independently verified as being
32 ** compliant with the OpenGL(R) version 1.2.1 Specification.
33 **
34 */
35
36 #include "gluos.h"
37 #include <math.h>
38 #include <GL/gl.h>
39 #include <GL/glu.h>
40 #include "gluint.h"
41
42 /*
43 ** Make m an identity matrix
44 */
45 static void __gluMakeIdentityd(GLdouble m[16])
46 {
47 m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0;
48 m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0;
49 m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0;
50 m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1;
51 }
52
53 static void __gluMakeIdentityf(GLfloat m[16])
54 {
55 m[0+4*0] = 1; m[0+4*1] = 0; m[0+4*2] = 0; m[0+4*3] = 0;
56 m[1+4*0] = 0; m[1+4*1] = 1; m[1+4*2] = 0; m[1+4*3] = 0;
57 m[2+4*0] = 0; m[2+4*1] = 0; m[2+4*2] = 1; m[2+4*3] = 0;
58 m[3+4*0] = 0; m[3+4*1] = 0; m[3+4*2] = 0; m[3+4*3] = 1;
59 }
60
61 void GLAPIENTRY
62 gluOrtho2D(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top)
63 {
64 glOrtho(left, right, bottom, top, -1, 1);
65 }
66
67 #define __glPi 3.14159265358979323846
68
69 void GLAPIENTRY
70 gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
71 {
72 GLdouble m[4][4];
73 double sine, cotangent, deltaZ;
74 double radians = fovy / 2 * __glPi / 180;
75
76 deltaZ = zFar - zNear;
77 sine = sin(radians);
78 if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) {
79 return;
80 }
81 cotangent = COS(radians) / sine;
82
83 __gluMakeIdentityd(&m[0][0]);
84 m[0][0] = cotangent / aspect;
85 m[1][1] = cotangent;
86 m[2][2] = -(zFar + zNear) / deltaZ;
87 m[2][3] = -1;
88 m[3][2] = -2 * zNear * zFar / deltaZ;
89 m[3][3] = 0;
90 glMultMatrixd(&m[0][0]);
91 }
92
93 static void normalize(float v[3])
94 {
95 float r;
96
97 r = sqrt( v[0]*v[0] + v[1]*v[1] + v[2]*v[2] );
98 if (r == 0.0) return;
99
100 v[0] /= r;
101 v[1] /= r;
102 v[2] /= r;
103 }
104
105 static void cross(float v1[3], float v2[3], float result[3])
106 {
107 result[0] = v1[1]*v2[2] - v1[2]*v2[1];
108 result[1] = v1[2]*v2[0] - v1[0]*v2[2];
109 result[2] = v1[0]*v2[1] - v1[1]*v2[0];
110 }
111
112 void GLAPIENTRY
113 gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx,
114 GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy,
115 GLdouble upz)
116 {
117 float forward[3], side[3], up[3];
118 GLfloat m[4][4];
119
120 forward[0] = centerx - eyex;
121 forward[1] = centery - eyey;
122 forward[2] = centerz - eyez;
123
124 up[0] = upx;
125 up[1] = upy;
126 up[2] = upz;
127
128 normalize(forward);
129
130 /* Side = forward x up */
131 cross(forward, up, side);
132 normalize(side);
133
134 /* Recompute up as: up = side x forward */
135 cross(side, forward, up);
136
137 __gluMakeIdentityf(&m[0][0]);
138 m[0][0] = side[0];
139 m[1][0] = side[1];
140 m[2][0] = side[2];
141
142 m[0][1] = up[0];
143 m[1][1] = up[1];
144 m[2][1] = up[2];
145
146 m[0][2] = -forward[0];
147 m[1][2] = -forward[1];
148 m[2][2] = -forward[2];
149
150 glMultMatrixf(&m[0][0]);
151 glTranslated(-eyex, -eyey, -eyez);
152 }
153
154 static void __gluMultMatrixVecd(const GLdouble matrix[16], const GLdouble in[4],
155 GLdouble out[4])
156 {
157 int i;
158
159 for (i=0; i<4; i++) {
160 out[i] =
161 in[0] * matrix[0*4+i] +
162 in[1] * matrix[1*4+i] +
163 in[2] * matrix[2*4+i] +
164 in[3] * matrix[3*4+i];
165 }
166 }
167
168 /*
169 ** Invert 4x4 matrix.
170 ** Contributed by David Moore (See Mesa bug #6748)
171 */
172 static int __gluInvertMatrixd(const GLdouble m[16], GLdouble invOut[16])
173 {
174 double inv[16], det;
175 int i;
176
177 inv[0] = m[5]*m[10]*m[15] - m[5]*m[11]*m[14] - m[9]*m[6]*m[15]
178 + m[9]*m[7]*m[14] + m[13]*m[6]*m[11] - m[13]*m[7]*m[10];
179 inv[4] = -m[4]*m[10]*m[15] + m[4]*m[11]*m[14] + m[8]*m[6]*m[15]
180 - m[8]*m[7]*m[14] - m[12]*m[6]*m[11] + m[12]*m[7]*m[10];
181 inv[8] = m[4]*m[9]*m[15] - m[4]*m[11]*m[13] - m[8]*m[5]*m[15]
182 + m[8]*m[7]*m[13] + m[12]*m[5]*m[11] - m[12]*m[7]*m[9];
183 inv[12] = -m[4]*m[9]*m[14] + m[4]*m[10]*m[13] + m[8]*m[5]*m[14]
184 - m[8]*m[6]*m[13] - m[12]*m[5]*m[10] + m[12]*m[6]*m[9];
185 inv[1] = -m[1]*m[10]*m[15] + m[1]*m[11]*m[14] + m[9]*m[2]*m[15]
186 - m[9]*m[3]*m[14] - m[13]*m[2]*m[11] + m[13]*m[3]*m[10];
187 inv[5] = m[0]*m[10]*m[15] - m[0]*m[11]*m[14] - m[8]*m[2]*m[15]
188 + m[8]*m[3]*m[14] + m[12]*m[2]*m[11] - m[12]*m[3]*m[10];
189 inv[9] = -m[0]*m[9]*m[15] + m[0]*m[11]*m[13] + m[8]*m[1]*m[15]
190 - m[8]*m[3]*m[13] - m[12]*m[1]*m[11] + m[12]*m[3]*m[9];
191 inv[13] = m[0]*m[9]*m[14] - m[0]*m[10]*m[13] - m[8]*m[1]*m[14]
192 + m[8]*m[2]*m[13] + m[12]*m[1]*m[10] - m[12]*m[2]*m[9];
193 inv[2] = m[1]*m[6]*m[15] - m[1]*m[7]*m[14] - m[5]*m[2]*m[15]
194 + m[5]*m[3]*m[14] + m[13]*m[2]*m[7] - m[13]*m[3]*m[6];
195 inv[6] = -m[0]*m[6]*m[15] + m[0]*m[7]*m[14] + m[4]*m[2]*m[15]
196 - m[4]*m[3]*m[14] - m[12]*m[2]*m[7] + m[12]*m[3]*m[6];
197 inv[10] = m[0]*m[5]*m[15] - m[0]*m[7]*m[13] - m[4]*m[1]*m[15]
198 + m[4]*m[3]*m[13] + m[12]*m[1]*m[7] - m[12]*m[3]*m[5];
199 inv[14] = -m[0]*m[5]*m[14] + m[0]*m[6]*m[13] + m[4]*m[1]*m[14]
200 - m[4]*m[2]*m[13] - m[12]*m[1]*m[6] + m[12]*m[2]*m[5];
201 inv[3] = -m[1]*m[6]*m[11] + m[1]*m[7]*m[10] + m[5]*m[2]*m[11]
202 - m[5]*m[3]*m[10] - m[9]*m[2]*m[7] + m[9]*m[3]*m[6];
203 inv[7] = m[0]*m[6]*m[11] - m[0]*m[7]*m[10] - m[4]*m[2]*m[11]
204 + m[4]*m[3]*m[10] + m[8]*m[2]*m[7] - m[8]*m[3]*m[6];
205 inv[11] = -m[0]*m[5]*m[11] + m[0]*m[7]*m[9] + m[4]*m[1]*m[11]
206 - m[4]*m[3]*m[9] - m[8]*m[1]*m[7] + m[8]*m[3]*m[5];
207 inv[15] = m[0]*m[5]*m[10] - m[0]*m[6]*m[9] - m[4]*m[1]*m[10]
208 + m[4]*m[2]*m[9] + m[8]*m[1]*m[6] - m[8]*m[2]*m[5];
209
210 det = m[0]*inv[0] + m[1]*inv[4] + m[2]*inv[8] + m[3]*inv[12];
211 if (det == 0)
212 return GL_FALSE;
213
214 det = 1.0 / det;
215
216 for (i = 0; i < 16; i++)
217 invOut[i] = inv[i] * det;
218
219 return GL_TRUE;
220 }
221
222 static void __gluMultMatricesd(const GLdouble a[16], const GLdouble b[16],
223 GLdouble r[16])
224 {
225 int i, j;
226
227 for (i = 0; i < 4; i++) {
228 for (j = 0; j < 4; j++) {
229 r[i*4+j] =
230 a[i*4+0]*b[0*4+j] +
231 a[i*4+1]*b[1*4+j] +
232 a[i*4+2]*b[2*4+j] +
233 a[i*4+3]*b[3*4+j];
234 }
235 }
236 }
237
238 GLint GLAPIENTRY
239 gluProject(GLdouble objx, GLdouble objy, GLdouble objz,
240 const GLdouble modelMatrix[16],
241 const GLdouble projMatrix[16],
242 const GLint viewport[4],
243 GLdouble *winx, GLdouble *winy, GLdouble *winz)
244 {
245 double in[4];
246 double out[4];
247
248 in[0]=objx;
249 in[1]=objy;
250 in[2]=objz;
251 in[3]=1.0;
252 __gluMultMatrixVecd(modelMatrix, in, out);
253 __gluMultMatrixVecd(projMatrix, out, in);
254 if (in[3] == 0.0) return(GL_FALSE);
255 in[0] /= in[3];
256 in[1] /= in[3];
257 in[2] /= in[3];
258 /* Map x, y and z to range 0-1 */
259 in[0] = in[0] * 0.5 + 0.5;
260 in[1] = in[1] * 0.5 + 0.5;
261 in[2] = in[2] * 0.5 + 0.5;
262
263 /* Map x,y to viewport */
264 in[0] = in[0] * viewport[2] + viewport[0];
265 in[1] = in[1] * viewport[3] + viewport[1];
266
267 *winx=in[0];
268 *winy=in[1];
269 *winz=in[2];
270 return(GL_TRUE);
271 }
272
273 GLint GLAPIENTRY
274 gluUnProject(GLdouble winx, GLdouble winy, GLdouble winz,
275 const GLdouble modelMatrix[16],
276 const GLdouble projMatrix[16],
277 const GLint viewport[4],
278 GLdouble *objx, GLdouble *objy, GLdouble *objz)
279 {
280 double finalMatrix[16];
281 double in[4];
282 double out[4];
283
284 __gluMultMatricesd(modelMatrix, projMatrix, finalMatrix);
285 if (!__gluInvertMatrixd(finalMatrix, finalMatrix)) return(GL_FALSE);
286
287 in[0]=winx;
288 in[1]=winy;
289 in[2]=winz;
290 in[3]=1.0;
291
292 /* Map x and y from window coordinates */
293 in[0] = (in[0] - viewport[0]) / viewport[2];
294 in[1] = (in[1] - viewport[1]) / viewport[3];
295
296 /* Map to range -1 to 1 */
297 in[0] = in[0] * 2 - 1;
298 in[1] = in[1] * 2 - 1;
299 in[2] = in[2] * 2 - 1;
300
301 __gluMultMatrixVecd(finalMatrix, in, out);
302 if (out[3] == 0.0) return(GL_FALSE);
303 out[0] /= out[3];
304 out[1] /= out[3];
305 out[2] /= out[3];
306 *objx = out[0];
307 *objy = out[1];
308 *objz = out[2];
309 return(GL_TRUE);
310 }
311
312 GLint GLAPIENTRY
313 gluUnProject4(GLdouble winx, GLdouble winy, GLdouble winz, GLdouble clipw,
314 const GLdouble modelMatrix[16],
315 const GLdouble projMatrix[16],
316 const GLint viewport[4],
317 GLclampd nearVal, GLclampd farVal,
318 GLdouble *objx, GLdouble *objy, GLdouble *objz,
319 GLdouble *objw)
320 {
321 double finalMatrix[16];
322 double in[4];
323 double out[4];
324
325 __gluMultMatricesd(modelMatrix, projMatrix, finalMatrix);
326 if (!__gluInvertMatrixd(finalMatrix, finalMatrix)) return(GL_FALSE);
327
328 in[0]=winx;
329 in[1]=winy;
330 in[2]=winz;
331 in[3]=clipw;
332
333 /* Map x and y from window coordinates */
334 in[0] = (in[0] - viewport[0]) / viewport[2];
335 in[1] = (in[1] - viewport[1]) / viewport[3];
336 in[2] = (in[2] - nearVal) / (farVal - nearVal);
337
338 /* Map to range -1 to 1 */
339 in[0] = in[0] * 2 - 1;
340 in[1] = in[1] * 2 - 1;
341 in[2] = in[2] * 2 - 1;
342
343 __gluMultMatrixVecd(finalMatrix, in, out);
344 if (out[3] == 0.0) return(GL_FALSE);
345 *objx = out[0];
346 *objy = out[1];
347 *objz = out[2];
348 *objw = out[3];
349 return(GL_TRUE);
350 }
351
352 void GLAPIENTRY
353 gluPickMatrix(GLdouble x, GLdouble y, GLdouble deltax, GLdouble deltay,
354 GLint viewport[4])
355 {
356 if (deltax <= 0 || deltay <= 0) {
357 return;
358 }
359
360 /* Translate and scale the picked region to the entire window */
361 glTranslatef((viewport[2] - 2 * (x - viewport[0])) / deltax,
362 (viewport[3] - 2 * (y - viewport[1])) / deltay, 0);
363 glScalef(viewport[2] / deltax, viewport[3] / deltay, 1.0);
364 }