glu/sgi: Move initialization of members to top of Curve constructor.
[platform/upstream/mesa.git] / src / glu / mesa / project.c
1
2 /*
3  * Mesa 3-D graphics library
4  * Version:  3.3
5  * Copyright (C) 1995-2000  Brian Paul
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the Free
19  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22
23 #ifdef PC_HEADER
24 #include "all.h"
25 #else
26 #include <stdio.h>
27 #include <string.h>
28 #include <math.h>
29 #include "gluP.h"
30 #endif
31
32
33 /*
34  * This code was contributed by Marc Buffat (buffat@mecaflu.ec-lyon.fr).
35  * Thanks Marc!!!
36  */
37
38
39
40 /* implementation de gluProject et gluUnproject */
41 /* M. Buffat 17/2/95 */
42
43
44
45 /*
46  * Transform a point (column vector) by a 4x4 matrix.  I.e.  out = m * in
47  * Input:  m - the 4x4 matrix
48  *         in - the 4x1 vector
49  * Output:  out - the resulting 4x1 vector.
50  */
51 static void
52 transform_point(GLdouble out[4], const GLdouble m[16], const GLdouble in[4])
53 {
54 #define M(row,col)  m[col*4+row]
55    out[0] =
56       M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3];
57    out[1] =
58       M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3];
59    out[2] =
60       M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3];
61    out[3] =
62       M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3];
63 #undef M
64 }
65
66
67
68
69 /*
70  * Perform a 4x4 matrix multiplication  (product = a x b).
71  * Input:  a, b - matrices to multiply
72  * Output:  product - product of a and b
73  */
74 static void
75 matmul(GLdouble * product, const GLdouble * a, const GLdouble * b)
76 {
77    /* This matmul was contributed by Thomas Malik */
78    GLdouble temp[16];
79    GLint i;
80
81 #define A(row,col)  a[(col<<2)+row]
82 #define B(row,col)  b[(col<<2)+row]
83 #define T(row,col)  temp[(col<<2)+row]
84
85    /* i-te Zeile */
86    for (i = 0; i < 4; i++) {
87       T(i, 0) =
88          A(i, 0) * B(0, 0) + A(i, 1) * B(1, 0) + A(i, 2) * B(2, 0) + A(i,
89                                                                        3) *
90          B(3, 0);
91       T(i, 1) =
92          A(i, 0) * B(0, 1) + A(i, 1) * B(1, 1) + A(i, 2) * B(2, 1) + A(i,
93                                                                        3) *
94          B(3, 1);
95       T(i, 2) =
96          A(i, 0) * B(0, 2) + A(i, 1) * B(1, 2) + A(i, 2) * B(2, 2) + A(i,
97                                                                        3) *
98          B(3, 2);
99       T(i, 3) =
100          A(i, 0) * B(0, 3) + A(i, 1) * B(1, 3) + A(i, 2) * B(2, 3) + A(i,
101                                                                        3) *
102          B(3, 3);
103    }
104
105 #undef A
106 #undef B
107 #undef T
108    MEMCPY(product, temp, 16 * sizeof(GLdouble));
109 }
110
111
112
113 /*
114  * Compute inverse of 4x4 transformation matrix.
115  * Code contributed by Jacques Leroy jle@star.be
116  * Return GL_TRUE for success, GL_FALSE for failure (singular matrix)
117  */
118 static GLboolean
119 invert_matrix(const GLdouble * m, GLdouble * out)
120 {
121 /* NB. OpenGL Matrices are COLUMN major. */
122 #define SWAP_ROWS(a, b) { GLdouble *_tmp = a; (a)=(b); (b)=_tmp; }
123 #define MAT(m,r,c) (m)[(c)*4+(r)]
124
125    GLdouble wtmp[4][8];
126    GLdouble m0, m1, m2, m3, s;
127    GLdouble *r0, *r1, *r2, *r3;
128
129    r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
130
131    r0[0] = MAT(m, 0, 0), r0[1] = MAT(m, 0, 1),
132       r0[2] = MAT(m, 0, 2), r0[3] = MAT(m, 0, 3),
133       r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0,
134       r1[0] = MAT(m, 1, 0), r1[1] = MAT(m, 1, 1),
135       r1[2] = MAT(m, 1, 2), r1[3] = MAT(m, 1, 3),
136       r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0,
137       r2[0] = MAT(m, 2, 0), r2[1] = MAT(m, 2, 1),
138       r2[2] = MAT(m, 2, 2), r2[3] = MAT(m, 2, 3),
139       r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0,
140       r3[0] = MAT(m, 3, 0), r3[1] = MAT(m, 3, 1),
141       r3[2] = MAT(m, 3, 2), r3[3] = MAT(m, 3, 3),
142       r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0;
143
144    /* choose pivot - or die */
145    if (fabs(r3[0]) > fabs(r2[0]))
146       SWAP_ROWS(r3, r2);
147    if (fabs(r2[0]) > fabs(r1[0]))
148       SWAP_ROWS(r2, r1);
149    if (fabs(r1[0]) > fabs(r0[0]))
150       SWAP_ROWS(r1, r0);
151    if (0.0 == r0[0])
152       return GL_FALSE;
153
154    /* eliminate first variable     */
155    m1 = r1[0] / r0[0];
156    m2 = r2[0] / r0[0];
157    m3 = r3[0] / r0[0];
158    s = r0[1];
159    r1[1] -= m1 * s;
160    r2[1] -= m2 * s;
161    r3[1] -= m3 * s;
162    s = r0[2];
163    r1[2] -= m1 * s;
164    r2[2] -= m2 * s;
165    r3[2] -= m3 * s;
166    s = r0[3];
167    r1[3] -= m1 * s;
168    r2[3] -= m2 * s;
169    r3[3] -= m3 * s;
170    s = r0[4];
171    if (s != 0.0) {
172       r1[4] -= m1 * s;
173       r2[4] -= m2 * s;
174       r3[4] -= m3 * s;
175    }
176    s = r0[5];
177    if (s != 0.0) {
178       r1[5] -= m1 * s;
179       r2[5] -= m2 * s;
180       r3[5] -= m3 * s;
181    }
182    s = r0[6];
183    if (s != 0.0) {
184       r1[6] -= m1 * s;
185       r2[6] -= m2 * s;
186       r3[6] -= m3 * s;
187    }
188    s = r0[7];
189    if (s != 0.0) {
190       r1[7] -= m1 * s;
191       r2[7] -= m2 * s;
192       r3[7] -= m3 * s;
193    }
194
195    /* choose pivot - or die */
196    if (fabs(r3[1]) > fabs(r2[1]))
197       SWAP_ROWS(r3, r2);
198    if (fabs(r2[1]) > fabs(r1[1]))
199       SWAP_ROWS(r2, r1);
200    if (0.0 == r1[1])
201       return GL_FALSE;
202
203    /* eliminate second variable */
204    m2 = r2[1] / r1[1];
205    m3 = r3[1] / r1[1];
206    r2[2] -= m2 * r1[2];
207    r3[2] -= m3 * r1[2];
208    r2[3] -= m2 * r1[3];
209    r3[3] -= m3 * r1[3];
210    s = r1[4];
211    if (0.0 != s) {
212       r2[4] -= m2 * s;
213       r3[4] -= m3 * s;
214    }
215    s = r1[5];
216    if (0.0 != s) {
217       r2[5] -= m2 * s;
218       r3[5] -= m3 * s;
219    }
220    s = r1[6];
221    if (0.0 != s) {
222       r2[6] -= m2 * s;
223       r3[6] -= m3 * s;
224    }
225    s = r1[7];
226    if (0.0 != s) {
227       r2[7] -= m2 * s;
228       r3[7] -= m3 * s;
229    }
230
231    /* choose pivot - or die */
232    if (fabs(r3[2]) > fabs(r2[2]))
233       SWAP_ROWS(r3, r2);
234    if (0.0 == r2[2])
235       return GL_FALSE;
236
237    /* eliminate third variable */
238    m3 = r3[2] / r2[2];
239    r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
240       r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], r3[7] -= m3 * r2[7];
241
242    /* last check */
243    if (0.0 == r3[3])
244       return GL_FALSE;
245
246    s = 1.0 / r3[3];             /* now back substitute row 3 */
247    r3[4] *= s;
248    r3[5] *= s;
249    r3[6] *= s;
250    r3[7] *= s;
251
252    m2 = r2[3];                  /* now back substitute row 2 */
253    s = 1.0 / r2[2];
254    r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
255       r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
256    m1 = r1[3];
257    r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
258       r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
259    m0 = r0[3];
260    r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
261       r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
262
263    m1 = r1[2];                  /* now back substitute row 1 */
264    s = 1.0 / r1[1];
265    r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
266       r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
267    m0 = r0[2];
268    r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
269       r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
270
271    m0 = r0[1];                  /* now back substitute row 0 */
272    s = 1.0 / r0[0];
273    r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
274       r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
275
276    MAT(out, 0, 0) = r0[4];
277    MAT(out, 0, 1) = r0[5], MAT(out, 0, 2) = r0[6];
278    MAT(out, 0, 3) = r0[7], MAT(out, 1, 0) = r1[4];
279    MAT(out, 1, 1) = r1[5], MAT(out, 1, 2) = r1[6];
280    MAT(out, 1, 3) = r1[7], MAT(out, 2, 0) = r2[4];
281    MAT(out, 2, 1) = r2[5], MAT(out, 2, 2) = r2[6];
282    MAT(out, 2, 3) = r2[7], MAT(out, 3, 0) = r3[4];
283    MAT(out, 3, 1) = r3[5], MAT(out, 3, 2) = r3[6];
284    MAT(out, 3, 3) = r3[7];
285
286    return GL_TRUE;
287
288 #undef MAT
289 #undef SWAP_ROWS
290 }
291
292
293
294 /* projection du point (objx,objy,obz) sur l'ecran (winx,winy,winz) */
295 GLint GLAPIENTRY
296 gluProject(GLdouble objx, GLdouble objy, GLdouble objz,
297            const GLdouble model[16], const GLdouble proj[16],
298            const GLint viewport[4],
299            GLdouble * winx, GLdouble * winy, GLdouble * winz)
300 {
301    /* matrice de transformation */
302    GLdouble in[4], out[4];
303
304    /* initilise la matrice et le vecteur a transformer */
305    in[0] = objx;
306    in[1] = objy;
307    in[2] = objz;
308    in[3] = 1.0;
309    transform_point(out, model, in);
310    transform_point(in, proj, out);
311
312    /* d'ou le resultat normalise entre -1 et 1 */
313    if (in[3] == 0.0)
314       return GL_FALSE;
315
316    in[0] /= in[3];
317    in[1] /= in[3];
318    in[2] /= in[3];
319
320    /* en coordonnees ecran */
321    *winx = viewport[0] + (1 + in[0]) * viewport[2] / 2;
322    *winy = viewport[1] + (1 + in[1]) * viewport[3] / 2;
323    /* entre 0 et 1 suivant z */
324    *winz = (1 + in[2]) / 2;
325    return GL_TRUE;
326 }
327
328
329
330 /* transformation du point ecran (winx,winy,winz) en point objet */
331 GLint GLAPIENTRY
332 gluUnProject(GLdouble winx, GLdouble winy, GLdouble winz,
333              const GLdouble model[16], const GLdouble proj[16],
334              const GLint viewport[4],
335              GLdouble * objx, GLdouble * objy, GLdouble * objz)
336 {
337    /* matrice de transformation */
338    GLdouble m[16], A[16];
339    GLdouble in[4], out[4];
340
341    /* transformation coordonnees normalisees entre -1 et 1 */
342    in[0] = (winx - viewport[0]) * 2 / viewport[2] - 1.0;
343    in[1] = (winy - viewport[1]) * 2 / viewport[3] - 1.0;
344    in[2] = 2 * winz - 1.0;
345    in[3] = 1.0;
346
347    /* calcul transformation inverse */
348    matmul(A, proj, model);
349    if (!invert_matrix(A, m))
350       return GL_FALSE;
351
352    /* d'ou les coordonnees objets */
353    transform_point(out, m, in);
354    if (out[3] == 0.0)
355       return GL_FALSE;
356    *objx = out[0] / out[3];
357    *objy = out[1] / out[3];
358    *objz = out[2] / out[3];
359    return GL_TRUE;
360 }
361
362
363 /*
364  * New in GLU 1.3
365  * This is like gluUnProject but also takes near and far DepthRange values.
366  */
367 #ifdef GLU_VERSION_1_3
368 GLint GLAPIENTRY
369 gluUnProject4(GLdouble winx, GLdouble winy, GLdouble winz, GLdouble clipw,
370               const GLdouble modelMatrix[16],
371               const GLdouble projMatrix[16],
372               const GLint viewport[4],
373               GLclampd nearZ, GLclampd farZ,
374               GLdouble * objx, GLdouble * objy, GLdouble * objz,
375               GLdouble * objw)
376 {
377    /* matrice de transformation */
378    GLdouble m[16], A[16];
379    GLdouble in[4], out[4];
380    GLdouble z = nearZ + winz * (farZ - nearZ);
381
382    /* transformation coordonnees normalisees entre -1 et 1 */
383    in[0] = (winx - viewport[0]) * 2 / viewport[2] - 1.0;
384    in[1] = (winy - viewport[1]) * 2 / viewport[3] - 1.0;
385    in[2] = 2.0 * z - 1.0;
386    in[3] = clipw;
387
388    /* calcul transformation inverse */
389    matmul(A, projMatrix, modelMatrix);
390    if (!invert_matrix(A, m))
391       return GL_FALSE;
392
393    /* d'ou les coordonnees objets */
394    transform_point(out, m, in);
395    if (out[3] == 0.0)
396       return GL_FALSE;
397    *objx = out[0] / out[3];
398    *objy = out[1] / out[3];
399    *objz = out[2] / out[3];
400    *objw = out[3];
401    return GL_TRUE;
402 }
403 #endif