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