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 */
__gluMakeIdentityd(GLdouble m[16])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 
__gluMakeIdentityf(GLfloat m[16])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*/
gluOrtho2D(GLdouble left,GLdouble right,GLdouble bottom,GLdouble top)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*/
gluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear,GLdouble zFar)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 
normalize(float v[3])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 
cross(float v1[3],float v2[3],float result[3])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*/
gluLookAt(GLdouble eyex,GLdouble eyey,GLdouble eyez,GLdouble centerx,GLdouble centery,GLdouble centerz,GLdouble upx,GLdouble upy,GLdouble upz)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 
__gluMultMatrixVecd(const GLdouble matrix[16],const GLdouble in[4],GLdouble out[4])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 */
__gluInvertMatrixd(const GLdouble m[16],GLdouble invOut[16])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 
__gluMultMatricesd(const GLdouble a[16],const GLdouble b[16],GLdouble r[16])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*/
gluProject(GLdouble objx,GLdouble objy,GLdouble objz,const GLdouble modelMatrix[16],const GLdouble projMatrix[16],const GLint viewport[4],GLdouble * winx,GLdouble * winy,GLdouble * winz)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*/
gluUnProject(GLdouble winx,GLdouble winy,GLdouble winz,const GLdouble modelMatrix[16],const GLdouble projMatrix[16],const GLint viewport[4],GLdouble * objx,GLdouble * objy,GLdouble * objz)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*/
gluUnProject4(GLdouble winx,GLdouble winy,GLdouble winz,GLdouble clipw,const GLdouble modelMatrix[16],const GLdouble projMatrix[16],const GLint viewport[4],GLclampd nearVal,GLclampd farVal,GLdouble * objx,GLdouble * objy,GLdouble * objz,GLdouble * objw)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*/
gluPickMatrix(GLdouble x,GLdouble y,GLdouble deltax,GLdouble deltay,GLint viewport[4])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 }
360