glsl-1.10: test mesa bug conflict between globals
[piglit.git] / tests / util / piglit-matrix.c
blobdd073b75a80cd480b53797686b0bd7e2d1d0eed7
1 /*
2 * Copyright (c) VMware, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * on the rights to use, copy, modify, merge, publish, distribute, sub
8 * license, and/or sell copies of the Software, and to permit persons to whom
9 * the Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
25 #include <assert.h>
26 #include <math.h>
27 #include <stdio.h>
28 #include "piglit-matrix.h"
31 #define DEG_TO_RAD(D) ((D) * M_PI / 180.0)
34 /**
35 * Create a scaling matrix.
37 void
38 piglit_identity_matrix(float mat[16])
40 mat[0] = 1.0f;
41 mat[1] = 0.0f;
42 mat[2] = 0.0f;
43 mat[3] = 0.0f;
45 mat[4] = 0.0f;
46 mat[5] = 1.0f;
47 mat[6] = 0.0f;
48 mat[7] = 0.0f;
50 mat[8] = 0.0f;
51 mat[9] = 0.0f;
52 mat[10] = 1.0f;
53 mat[11] = 0.0f;
55 mat[12] = 0.0f;
56 mat[13] = 0.0f;
57 mat[14] = 0.0f;
58 mat[15] = 1.0f;
62 /**
63 * Create a scaling matrix.
65 void
66 piglit_scale_matrix(float mat[16], float sx, float sy, float sz)
68 mat[0] = sx;
69 mat[1] = 0.0f;
70 mat[2] = 0.0f;
71 mat[3] = 0.0f;
73 mat[4] = 0.0f;
74 mat[5] = sy;
75 mat[6] = 0.0f;
76 mat[7] = 0.0f;
78 mat[8] = 0.0f;
79 mat[9] = 0.0f;
80 mat[10] = sz;
81 mat[11] = 0.0f;
83 mat[12] = 0.0f;
84 mat[13] = 0.0f;
85 mat[14] = 0.0f;
86 mat[15] = 1.0f;
90 /**
91 * Create a translation matrix.
93 void
94 piglit_translation_matrix(float mat[16], float tx, float ty, float tz)
96 mat[0] = 0.0f;
97 mat[1] = 0.0f;
98 mat[2] = 0.0f;
99 mat[3] = 0.0f;
101 mat[4] = 0.0f;
102 mat[5] = 0.0f;
103 mat[6] = 0.0f;
104 mat[7] = 0.0f;
106 mat[8] = 0.0f;
107 mat[9] = 0.0f;
108 mat[10] = 0.0f;
109 mat[11] = 0.0f;
111 mat[12] = tx;
112 mat[13] = ty;
113 mat[14] = tz;
114 mat[15] = 1.0f;
118 void
119 piglit_rotation_matrix(float mat[16], float angle, float x, float y, float z)
121 /* Implementation borrowed from Mesa */
122 float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c, s, c;
123 float m[16];
124 bool optimized = false;
126 s = (float) sin(DEG_TO_RAD(angle));
127 c = (float) cos(DEG_TO_RAD(angle));
129 piglit_identity_matrix(m);
131 #define M(row,col) m[col*4+row]
133 if (x == 0.0F) {
134 if (y == 0.0F) {
135 if (z != 0.0F) {
136 optimized = true;
137 /* rotate only around z-axis */
138 M(0,0) = c;
139 M(1,1) = c;
140 if (z < 0.0F) {
141 M(0,1) = s;
142 M(1,0) = -s;
144 else {
145 M(0,1) = -s;
146 M(1,0) = s;
150 else if (z == 0.0F) {
151 optimized = true;
152 /* rotate only around y-axis */
153 M(0,0) = c;
154 M(2,2) = c;
155 if (y < 0.0F) {
156 M(0,2) = -s;
157 M(2,0) = s;
159 else {
160 M(0,2) = s;
161 M(2,0) = -s;
165 else if (y == 0.0F) {
166 if (z == 0.0F) {
167 optimized = true;
168 /* rotate only around x-axis */
169 M(1,1) = c;
170 M(2,2) = c;
171 if (x < 0.0F) {
172 M(1,2) = s;
173 M(2,1) = -s;
175 else {
176 M(1,2) = -s;
177 M(2,1) = s;
182 if (!optimized) {
183 const float mag = sqrtf(x * x + y * y + z * z);
185 if (mag <= 1.0e-4) {
186 /* no rotation, leave mat as-is */
187 return;
190 x /= mag;
191 y /= mag;
192 z /= mag;
196 * Arbitrary axis rotation matrix.
198 * This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied
199 * like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation
200 * (which is about the X-axis), and the two composite transforms
201 * Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary
202 * from the arbitrary axis to the X-axis then back. They are
203 * all elementary rotations.
205 * Rz' is a rotation about the Z-axis, to bring the axis vector
206 * into the x-z plane. Then Ry' is applied, rotating about the
207 * Y-axis to bring the axis vector parallel with the X-axis. The
208 * rotation about the X-axis is then performed. Ry and Rz are
209 * simply the respective inverse transforms to bring the arbitrary
210 * axis back to its original orientation. The first transforms
211 * Rz' and Ry' are considered inverses, since the data from the
212 * arbitrary axis gives you info on how to get to it, not how
213 * to get away from it, and an inverse must be applied.
215 * The basic calculation used is to recognize that the arbitrary
216 * axis vector (x, y, z), since it is of unit length, actually
217 * represents the sines and cosines of the angles to rotate the
218 * X-axis to the same orientation, with theta being the angle about
219 * Z and phi the angle about Y (in the order described above)
220 * as follows:
222 * cos ( theta ) = x / sqrt ( 1 - z^2 )
223 * sin ( theta ) = y / sqrt ( 1 - z^2 )
225 * cos ( phi ) = sqrt ( 1 - z^2 )
226 * sin ( phi ) = z
228 * Note that cos ( phi ) can further be inserted to the above
229 * formulas:
231 * cos ( theta ) = x / cos ( phi )
232 * sin ( theta ) = y / sin ( phi )
234 * ...etc. Because of those relations and the standard trigonometric
235 * relations, it is pssible to reduce the transforms down to what
236 * is used below. It may be that any primary axis chosen will give the
237 * same results (modulo a sign convention) using this method.
239 * Particularly nice is to notice that all divisions that might
240 * have caused trouble when parallel to certain planes or
241 * axis go away with care paid to reducing the expressions.
242 * After checking, it does perform correctly under all cases, since
243 * in all the cases of division where the denominator would have
244 * been zero, the numerator would have been zero as well, giving
245 * the expected result.
248 xx = x * x;
249 yy = y * y;
250 zz = z * z;
251 xy = x * y;
252 yz = y * z;
253 zx = z * x;
254 xs = x * s;
255 ys = y * s;
256 zs = z * s;
257 one_c = 1.0F - c;
259 /* We already hold the identity-matrix so we can skip some statements */
260 M(0,0) = (one_c * xx) + c;
261 M(0,1) = (one_c * xy) - zs;
262 M(0,2) = (one_c * zx) + ys;
263 /* M(0,3) = 0.0F; */
265 M(1,0) = (one_c * xy) + zs;
266 M(1,1) = (one_c * yy) + c;
267 M(1,2) = (one_c * yz) - xs;
268 /* M(1,3) = 0.0F; */
270 M(2,0) = (one_c * zx) - ys;
271 M(2,1) = (one_c * yz) + xs;
272 M(2,2) = (one_c * zz) + c;
273 /* M(2,3) = 0.0F; */
276 M(3,0) = 0.0F;
277 M(3,1) = 0.0F;
278 M(3,2) = 0.0F;
279 M(3,3) = 1.0F;
282 #undef M
286 void
287 piglit_ortho_matrix(float mat[16],
288 float left, float right,
289 float bottom, float top,
290 float nearval, float farval)
292 #define M(row,col) mat[col*4+row]
293 M(0,0) = 2.0F / (right-left);
294 M(0,1) = 0.0F;
295 M(0,2) = 0.0F;
296 M(0,3) = -(right+left) / (right-left);
298 M(1,0) = 0.0F;
299 M(1,1) = 2.0F / (top-bottom);
300 M(1,2) = 0.0F;
301 M(1,3) = -(top+bottom) / (top-bottom);
303 M(2,0) = 0.0F;
304 M(2,1) = 0.0F;
305 M(2,2) = -2.0F / (farval-nearval);
306 M(2,3) = -(farval+nearval) / (farval-nearval);
308 M(3,0) = 0.0F;
309 M(3,1) = 0.0F;
310 M(3,2) = 0.0F;
311 M(3,3) = 1.0F;
312 #undef M
316 void
317 piglit_frustum_matrix(float mat[16],
318 float left, float right,
319 float bottom, float top,
320 float nearval, float farval)
322 float x, y, a, b, c, d;
324 x = (2.0F*nearval) / (right-left);
325 y = (2.0F*nearval) / (top-bottom);
326 a = (right+left) / (right-left);
327 b = (top+bottom) / (top-bottom);
328 c = -(farval+nearval) / ( farval-nearval);
329 d = -(2.0F*farval*nearval) / (farval-nearval); /* error? */
331 #define M(row,col) mat[col*4+row]
332 M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
333 M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
334 M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
335 M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
336 #undef M
340 void
341 piglit_matrix_mul_matrix(float product[16],
342 const float a[16], const float b[16])
344 #define ELEM(MAT, ROW, COL) MAT[(COL) * 4 + (ROW)]
345 float tmp[16];
346 int i, j;
348 for (i = 0; i < 4; i++) {
349 for (j = 0; j < 4; j++) {
350 ELEM(tmp, i, j) = (ELEM(a, i, 0) * ELEM(b, 0, j) +
351 ELEM(a, i, 1) * ELEM(b, 1, j) +
352 ELEM(a, i, 2) * ELEM(b, 2, j) +
353 ELEM(a, i, 3) * ELEM(b, 3, j));
357 for (i = 0; i < 16; i++) {
358 product[i] = tmp[i];
360 #undef ELEM
365 * Compute "out = mat * in" where in and out are column vectors
366 * Typically used to transform homogeneous coordinates by a matrix.
368 void
369 piglit_matrix_mul_vector(float out[4],
370 const float mat[16],
371 const float in[4])
373 const float in0 = in[0], in1 = in[1], in2 = in[2], in3 = in[3];
374 #define M(row,col) mat[row + col*4]
375 out[0] = M(0,0) * in0 + M(0,1) * in1 + M(0,2) * in2 + M(0,3) * in3;
376 out[1] = M(1,0) * in0 + M(1,1) * in1 + M(1,2) * in2 + M(1,3) * in3;
377 out[2] = M(2,0) * in0 + M(2,1) * in1 + M(2,2) * in2 + M(2,3) * in3;
378 out[3] = M(3,0) * in0 + M(3,1) * in1 + M(3,2) * in2 + M(3,3) * in3;
379 #undef M
384 * Transform NDC coordinate to window coordinate using a viewport.
386 void
387 piglit_ndc_to_window(float win[3],
388 const float ndc[4],
389 int vp_left, int vp_bottom, int vp_width, int vp_height)
391 float x = ndc[0] * 0.5 + 0.5;
392 float y = ndc[1] * 0.5 + 0.5;
393 float z = ndc[2] * 0.5 + 0.5;
394 win[0] = vp_left + x * vp_width;
395 win[1] = vp_bottom + y * vp_height;
396 win[2] = z;
401 * Transform an object coordinate to a window coordinate using a
402 * modelview matrix, projection matrix and viewport.
403 * \return true for success, false if coordinate is clipped away
405 bool
406 piglit_project_to_window(float win[3],
407 const float obj[4],
408 const float modelview[16],
409 const float projection[16],
410 int vp_left, int vp_bottom,
411 int vp_width, int vp_height)
413 float eye[4], clip[4], ndc[4];
415 /* eye coord = modelview * object */
416 piglit_matrix_mul_vector(eye, modelview, obj);
418 /* clip coord = projection * eye */
419 piglit_matrix_mul_vector(clip, projection, eye);
421 /* view volume clipping */
422 if ( clip[0] > clip[3] ||
423 -clip[0] > clip[3] ||
424 clip[1] > clip[3] ||
425 -clip[1] > clip[3] ||
426 clip[2] > clip[3] ||
427 -clip[2] > clip[3]) {
428 /* clipped */
429 return false;
432 /* ndc = clip / clip.w (divide by w) */
433 ndc[0] = clip[0] / clip[3];
434 ndc[1] = clip[1] / clip[3];
435 ndc[2] = clip[2] / clip[3];
436 ndc[3] = clip[3];
438 /* window = viewport_map(ndc) */
439 piglit_ndc_to_window(win, ndc, vp_left, vp_bottom, vp_width, vp_height);
441 return true;
445 void
446 piglit_print_matrix(const float mat[16])
448 printf("%f %f %f %f\n", mat[0], mat[4], mat[8], mat[12]);
449 printf("%f %f %f %f\n", mat[1], mat[5], mat[9], mat[13]);
450 printf("%f %f %f %f\n", mat[2], mat[6], mat[10], mat[14]);
451 printf("%f %f %f %f\n", mat[3], mat[7], mat[11], mat[15]);
456 * Invert matrix using cramer's rule.
457 * This assumes that the matrix is non-singular (or non-near-singular).
459 void
460 piglit_matrix_inverse(float inv[16], const float m[16])
462 inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] -
463 m[9] * m[6] * m[15] + m[9] * m[7] * m[14] +
464 m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
466 inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] +
467 m[8] * m[6] * m[15] - m[8] * m[7] * m[14] -
468 m[12] * m[6] * m[11] + m[12] * m[7] * m[10];
470 inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] -
471 m[8] * m[5] * m[15] + m[8] * m[7] * m[13] +
472 m[12] * m[5] * m[11] - m[12] * m[7] * m[9];
474 inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] +
475 m[8] * m[5] * m[14] - m[8] * m[6] * m[13] -
476 m[12] * m[5] * m[10] + m[12] * m[6] * m[9];
478 inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] +
479 m[9] * m[2] * m[15] - m[9] * m[3] * m[14] -
480 m[13] * m[2] * m[11] + m[13] * m[3] * m[10];
482 inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] -
483 m[8] * m[2] * m[15] + m[8] * m[3] * m[14] +
484 m[12] * m[2] * m[11] - m[12] * m[3] * m[10];
486 inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] +
487 m[8] * m[1] * m[15] - m[8] * m[3] * m[13] -
488 m[12] * m[1] * m[11] + m[12] * m[3] * m[9];
490 inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] -
491 m[8] * m[1] * m[14] + m[8] * m[2] * m[13] +
492 m[12] * m[1] * m[10] - m[12] * m[2] * m[9];
494 inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] -
495 m[5] * m[2] * m[15] + m[5] * m[3] * m[14] +
496 m[13] * m[2] * m[7] - m[13] * m[3] * m[6];
498 inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] +
499 m[4] * m[2] * m[15] - m[4] * m[3] * m[14] -
500 m[12] * m[2] * m[7] + m[12] * m[3] * m[6];
502 inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] -
503 m[4] * m[1] * m[15] + m[4] * m[3] * m[13] +
504 m[12] * m[1] * m[7] - m[12] * m[3] * m[5];
506 inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] +
507 m[4] * m[1] * m[14] - m[4] * m[2] * m[13] -
508 m[12] * m[1] * m[6] + m[12] * m[2] * m[5];
510 inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] +
511 m[5] * m[2] * m[11] - m[5] * m[3] * m[10] -
512 m[9] * m[2] * m[7] + m[9] * m[3] * m[6];
514 inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] -
515 m[4] * m[2] * m[11] + m[4] * m[3] * m[10] +
516 m[8] * m[2] * m[7] - m[8] * m[3] * m[6];
518 inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] +
519 m[4] * m[1] * m[11] - m[4] * m[3] * m[9] -
520 m[8] * m[1] * m[7] + m[8] * m[3] * m[5];
522 inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] -
523 m[4] * m[1] * m[10] + m[4] * m[2] * m[9] +
524 m[8] * m[1] * m[6] - m[8] * m[2] * m[5];
526 float det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
528 assert(fabsf(det) > 1e-10f);
530 for (int i = 0; i < 16; i++)
531 inv[i] = inv[i] / det;
535 void
536 piglit_matrix_transpose(float out[16], const float m[16])
538 for (int i = 0; i < 4; ++i)
539 for (int j = 0; j < 4; ++j)
540 out[i+4*j] = m[4*i+j];
545 * XXX to do items:
546 * We could add a simple set of matrix stack functions.
547 * Could add scale/translate/rotate functions that accumulate onto
548 * the incoming matrix, similar to glScale, glTranslate, etc.