[Piglit] [PATCH 1/2] util: add a simple set of matrix functions
Jose Fonseca
jfonseca at vmware.com
Fri May 30 09:48:13 PDT 2014
Series looks good at a glance. Just one minor remark inline.
----- Original Message -----
> For tests using the core profile we no longer have the legacy
> GL matrix functions to set up transformations. These functions
> let us easily setup transformations in such test programs.
> ---
> tests/util/CMakeLists.gl.txt | 1 +
> tests/util/piglit-matrix.c | 458
> ++++++++++++++++++++++++++++++++++++++++++
> tests/util/piglit-matrix.h | 92 +++++++++
> 3 files changed, 551 insertions(+)
> create mode 100644 tests/util/piglit-matrix.c
> create mode 100644 tests/util/piglit-matrix.h
>
> diff --git a/tests/util/CMakeLists.gl.txt b/tests/util/CMakeLists.gl.txt
> index d8fb32c..0a2cc25 100644
> --- a/tests/util/CMakeLists.gl.txt
> +++ b/tests/util/CMakeLists.gl.txt
> @@ -2,6 +2,7 @@ set(UTIL_GL_SOURCES
> ${UTIL_GL_SOURCES}
> piglit-dispatch.c
> piglit-dispatch-init.c
> + piglit-matrix.c
> piglit-shader.c
> piglit-shader-gl.c
> piglit-util-gl-enum.c
> diff --git a/tests/util/piglit-matrix.c b/tests/util/piglit-matrix.c
> new file mode 100644
> index 0000000..2e9cd66
> --- /dev/null
> +++ b/tests/util/piglit-matrix.c
> @@ -0,0 +1,458 @@
> +/*
> + * Copyright (c) VMware, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * on the rights to use, copy, modify, merge, publish, distribute, sub
> + * license, and/or sell copies of the Software, and to permit persons to
> whom
> + * the Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
> OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
> OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + */
> +
> +
> +#include <math.h>
> +#include "piglit-matrix.h"
> +
> +
> +#define DEG_TO_RAD(D) ((D) * M_PI / 180.0)
> +
> +
> +/**
> + * Create a scaling matrix.
> + */
> +void
> +piglit_identity_matrix(float mat[16])
> +{
> + mat[0] = 1.0f;
> + mat[1] = 0.0f;
> + mat[2] = 0.0f;
> + mat[3] = 0.0f;
> +
> + mat[4] = 0.0f;
> + mat[5] = 1.0f;
> + mat[6] = 0.0f;
> + mat[7] = 0.0f;
> +
> + mat[8] = 0.0f;
> + mat[9] = 0.0f;
> + mat[10] = 1.0f;
> + mat[11] = 0.0f;
> +
> + mat[12] = 0.0f;
> + mat[13] = 0.0f;
> + mat[14] = 0.0f;
> + mat[15] = 1.0f;
> +}
> +
> +
> +/**
> + * Create a scaling matrix.
> + */
> +void
> +piglit_scale_matrix(float mat[16], float sx, float sy, float sz)
> +{
> + mat[0] = sx;
> + mat[1] = 0.0f;
> + mat[2] = 0.0f;
> + mat[3] = 0.0f;
> +
> + mat[4] = 0.0f;
> + mat[5] = sy;
> + mat[6] = 0.0f;
> + mat[7] = 0.0f;
> +
> + mat[8] = 0.0f;
> + mat[9] = 0.0f;
> + mat[10] = sz;
> + mat[11] = 0.0f;
> +
> + mat[12] = 0.0f;
> + mat[13] = 0.0f;
> + mat[14] = 0.0f;
> + mat[15] = 1.0f;
> +}
> +
> +
> +/**
> + * Create a translation matrix.
> + */
> +void
> +piglit_translation_matrix(float mat[16], float tx, float ty, float tz)
> +{
> + mat[0] = 0.0f;
> + mat[1] = 0.0f;
> + mat[2] = 0.0f;
> + mat[3] = 0.0f;
> +
> + mat[4] = 0.0f;
> + mat[5] = 0.0f;
> + mat[6] = 0.0f;
> + mat[7] = 0.0f;
> +
> + mat[8] = 0.0f;
> + mat[9] = 0.0f;
> + mat[10] = 0.0f;
> + mat[11] = 0.0f;
> +
> + mat[12] = tx;
> + mat[13] = ty;
> + mat[14] = tz;
> + mat[15] = 1.0f;
> +}
> +
> +
> +void
> +piglit_rotation_matrix(float mat[16], float angle, float x, float y, float
> z)
> +{
> + /* Implementation borrowed from Mesa */
> + float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c, s, c;
> + float m[16];
> + bool optimized = false;
> +
> + s = (float) sin(DEG_TO_RAD(angle));
> + c = (float) cos(DEG_TO_RAD(angle));
> +
> + piglit_identity_matrix(m);
> +
> +#define M(row,col) m[col*4+row]
> +
> + if (x == 0.0F) {
> + if (y == 0.0F) {
> + if (z != 0.0F) {
> + optimized = true;
> + /* rotate only around z-axis */
> + M(0,0) = c;
> + M(1,1) = c;
> + if (z < 0.0F) {
> + M(0,1) = s;
> + M(1,0) = -s;
> + }
> + else {
> + M(0,1) = -s;
> + M(1,0) = s;
> + }
> + }
> + }
> + else if (z == 0.0F) {
> + optimized = true;
> + /* rotate only around y-axis */
> + M(0,0) = c;
> + M(2,2) = c;
> + if (y < 0.0F) {
> + M(0,2) = -s;
> + M(2,0) = s;
> + }
> + else {
> + M(0,2) = s;
> + M(2,0) = -s;
> + }
> + }
> + }
> + else if (y == 0.0F) {
> + if (z == 0.0F) {
> + optimized = true;
> + /* rotate only around x-axis */
> + M(1,1) = c;
> + M(2,2) = c;
> + if (x < 0.0F) {
> + M(1,2) = s;
> + M(2,1) = -s;
> + }
> + else {
> + M(1,2) = -s;
> + M(2,1) = s;
> + }
> + }
> + }
> +
> + if (!optimized) {
> + const float mag = sqrtf(x * x + y * y + z * z);
> +
> + if (mag <= 1.0e-4) {
> + /* no rotation, leave mat as-is */
> + return;
> + }
> +
> + x /= mag;
> + y /= mag;
> + z /= mag;
> +
> +
> + /*
> + * Arbitrary axis rotation matrix.
> + *
> + * This is composed of 5 matrices, Rz, Ry, T, Ry', Rz', multiplied
> + * like so: Rz * Ry * T * Ry' * Rz'. T is the final rotation
> + * (which is about the X-axis), and the two composite transforms
> + * Ry' * Rz' and Rz * Ry are (respectively) the rotations necessary
> + * from the arbitrary axis to the X-axis then back. They are
> + * all elementary rotations.
> + *
> + * Rz' is a rotation about the Z-axis, to bring the axis vector
> + * into the x-z plane. Then Ry' is applied, rotating about the
> + * Y-axis to bring the axis vector parallel with the X-axis. The
> + * rotation about the X-axis is then performed. Ry and Rz are
> + * simply the respective inverse transforms to bring the arbitrary
> + * axis back to its original orientation. The first transforms
> + * Rz' and Ry' are considered inverses, since the data from the
> + * arbitrary axis gives you info on how to get to it, not how
> + * to get away from it, and an inverse must be applied.
> + *
> + * The basic calculation used is to recognize that the arbitrary
> + * axis vector (x, y, z), since it is of unit length, actually
> + * represents the sines and cosines of the angles to rotate the
> + * X-axis to the same orientation, with theta being the angle about
> + * Z and phi the angle about Y (in the order described above)
> + * as follows:
> + *
> + * cos ( theta ) = x / sqrt ( 1 - z^2 )
> + * sin ( theta ) = y / sqrt ( 1 - z^2 )
> + *
> + * cos ( phi ) = sqrt ( 1 - z^2 )
> + * sin ( phi ) = z
> + *
> + * Note that cos ( phi ) can further be inserted to the above
> + * formulas:
> + *
> + * cos ( theta ) = x / cos ( phi )
> + * sin ( theta ) = y / sin ( phi )
> + *
> + * ...etc. Because of those relations and the standard trigonometric
> + * relations, it is pssible to reduce the transforms down to what
> + * is used below. It may be that any primary axis chosen will give
> the
> + * same results (modulo a sign convention) using thie method.
> + *
> + * Particularly nice is to notice that all divisions that might
> + * have caused trouble when parallel to certain planes or
> + * axis go away with care paid to reducing the expressions.
> + * After checking, it does perform correctly under all cases, since
> + * in all the cases of division where the denominator would have
> + * been zero, the numerator would have been zero as well, giving
> + * the expected result.
> + */
> +
> + xx = x * x;
> + yy = y * y;
> + zz = z * z;
> + xy = x * y;
> + yz = y * z;
> + zx = z * x;
> + xs = x * s;
> + ys = y * s;
> + zs = z * s;
> + one_c = 1.0F - c;
> +
> + /* We already hold the identity-matrix so we can skip some statements
> */
> + M(0,0) = (one_c * xx) + c;
> + M(0,1) = (one_c * xy) - zs;
> + M(0,2) = (one_c * zx) + ys;
> +/* M(0,3) = 0.0F; */
> +
> + M(1,0) = (one_c * xy) + zs;
> + M(1,1) = (one_c * yy) + c;
> + M(1,2) = (one_c * yz) - xs;
> +/* M(1,3) = 0.0F; */
> +
> + M(2,0) = (one_c * zx) - ys;
> + M(2,1) = (one_c * yz) + xs;
> + M(2,2) = (one_c * zz) + c;
> +/* M(2,3) = 0.0F; */
> +
> +/*
> + M(3,0) = 0.0F;
> + M(3,1) = 0.0F;
> + M(3,2) = 0.0F;
> + M(3,3) = 1.0F;
> +*/
> + }
> +#undef M
> +}
> +
> +
> +void
> +piglit_ortho_matrix(float mat[16],
> + float left, float right,
> + float bottom, float top,
> + float nearval, float farval)
> +{
> +#define M(row,col) mat[col*4+row]
> + M(0,0) = 2.0F / (right-left);
> + M(0,1) = 0.0F;
> + M(0,2) = 0.0F;
> + M(0,3) = -(right+left) / (right-left);
> +
> + M(1,0) = 0.0F;
> + M(1,1) = 2.0F / (top-bottom);
> + M(1,2) = 0.0F;
> + M(1,3) = -(top+bottom) / (top-bottom);
> +
> + M(2,0) = 0.0F;
> + M(2,1) = 0.0F;
> + M(2,2) = -2.0F / (farval-nearval);
> + M(2,3) = -(farval+nearval) / (farval-nearval);
> +
> + M(3,0) = 0.0F;
> + M(3,1) = 0.0F;
> + M(3,2) = 0.0F;
> + M(3,3) = 1.0F;
> +#undef M
> +}
> +
> +
> +void
> +piglit_frustum_matrix(float mat[16],
> + float left, float right,
> + float bottom, float top,
> + float nearval, float farval)
> +{
> + float x, y, a, b, c, d;
> +
> + x = (2.0F*nearval) / (right-left);
> + y = (2.0F*nearval) / (top-bottom);
> + a = (right+left) / (right-left);
> + b = (top+bottom) / (top-bottom);
> + c = -(farval+nearval) / ( farval-nearval);
> + d = -(2.0F*farval*nearval) / (farval-nearval); /* error? */
> +
> +#define M(row,col) mat[col*4+row]
> + M(0,0) = x; M(0,1) = 0.0F; M(0,2) = a; M(0,3) = 0.0F;
> + M(1,0) = 0.0F; M(1,1) = y; M(1,2) = b; M(1,3) = 0.0F;
> + M(2,0) = 0.0F; M(2,1) = 0.0F; M(2,2) = c; M(2,3) = d;
> + M(3,0) = 0.0F; M(3,1) = 0.0F; M(3,2) = -1.0F; M(3,3) = 0.0F;
> +#undef M
> +}
> +
> +
> +void
> +piglit_matrix_mul_matrix(float product[16],
> + const float a[16], const float b[16])
> +{
> +#define ELEM(MAT, ROW, COL) MAT[(COL) * 4 + (ROW)]
> + float tmp[16];
> + int i, j;
> +
> + for (i = 0; i < 4; i++) {
> + for (j = 0; j < 4; j++) {
> + ELEM(tmp, i, j) = (ELEM(a, i, 0) * ELEM(b, 0, j) +
> + ELEM(a, i, 1) * ELEM(b, 1, j) +
> + ELEM(a, i, 2) * ELEM(b, 2, j) +
> + ELEM(a, i, 3) * ELEM(b, 3, j));
> + }
> + }
> +
> + for (i = 0; i < 16; i++) {
> + product[i] = tmp[i];
> + }
> +#undef ELEM
> +}
> +
> +
> +/**
> + * Compute "out = mat * in" where in and out are column vectors
> + * Typically used to transform homogeneous coordinates by a matrix.
> + */
> +void
> +piglit_matrix_mul_vector(float out[4],
> + const float mat[16],
> + const float in[4])
> +{
> + const float in0 = in[0], in1 = in[1], in2 = in[2], in3 = in[3];
> +#define M(row,col) mat[row + col*4]
> + out[0] = M(0,0) * in0 + M(0,1) * in1 + M(0,2) * in2 + M(0,3) * in3;
> + out[1] = M(1,0) * in0 + M(1,1) * in1 + M(1,2) * in2 + M(1,3) * in3;
> + out[2] = M(2,0) * in0 + M(2,1) * in1 + M(2,2) * in2 + M(2,3) * in3;
> + out[3] = M(3,0) * in0 + M(3,1) * in1 + M(3,2) * in2 + M(3,3) * in3;
> +#undef M
> +}
> +
> +
> +/**
> + * Transfrom NDC coordinate to window coordinate using a viewport.
> + */
> +void
> +piglit_ndc_to_window(float win[3],
> + const float ndc[4],
> + int vp_left, int vp_bottom, int vp_width, int
> vp_height)
> +{
> + float x = ndc[0] * 0.5 + 0.5;
> + float y = ndc[1] * 0.5 + 0.5;
> + float z = ndc[2] * 0.5 + 0.5;
> + win[0] = vp_left + x * vp_width;
> + win[1] = vp_bottom + y * vp_height;
> + win[2] = z;
> +}
> +
> +
> +/**
> + * Transform an object coordinate to a window coordinate using a
> + * modelview matrix, projection matrix and viewport.
> + * \return true for success, false if coordinate is clipped away
> + */
> +bool
> +piglit_project_to_window(float win[3],
> + const float obj[4],
> + const float modelview[16],
> + const float projection[16],
> + int vp_left, int vp_bottom,
> + int vp_width, int vp_height)
> +{
> + float eye[4], clip[4], ndc[4];
> +
> + /* eye coord = modelview * object */
> + piglit_matrix_mul_vector(eye, modelview, obj);
> +
> + /* clip coord = projection * eye */
> + piglit_matrix_mul_vector(clip, projection, eye);
> +
> + /* view volume clipping */
> + if ( clip[0] > clip[3] ||
> + -clip[0] > clip[3] ||
> + clip[1] > clip[3] ||
> + -clip[1] > clip[3] ||
> + clip[2] > clip[3] ||
> + -clip[2] > clip[3]) {
> + /* clipped */
> + return false;
> + }
> +
> + /* ndc = clip / clip.w (divide by w) */
> + ndc[0] = clip[0] / clip[3];
> + ndc[1] = clip[1] / clip[3];
> + ndc[2] = clip[2] / clip[3];
> + ndc[3] = clip[3];
> +
> + /* window = viewport_map(ndc) */
> + piglit_ndc_to_window(win, ndc, vp_left, vp_bottom, vp_width, vp_height);
> +
> + return true;
> +}
> +
> +
> +void
> +piglit_print_matrix(const float mat[16])
> +{
> + printf("%f %f %f %f\n", mat[0], mat[4], mat[8], mat[12]);
> + printf("%f %f %f %f\n", mat[1], mat[5], mat[9], mat[13]);
> + printf("%f %f %f %f\n", mat[2], mat[6], mat[10], mat[14]);
> + printf("%f %f %f %f\n", mat[3], mat[7], mat[11], mat[15]);
> +}
> +
> +
> +/*
> + * XXX to do items:
> + * We could add a simple set of matrix stack functions.
> + * Could add scale/translate/rotate functions that accumulate onto
> + * the incoming matrix, similar to glScale, glTranslate, etc.
> + */
> diff --git a/tests/util/piglit-matrix.h b/tests/util/piglit-matrix.h
> new file mode 100644
> index 0000000..96d9d73
> --- /dev/null
> +++ b/tests/util/piglit-matrix.h
> @@ -0,0 +1,92 @@
> +/*
> + * Copyright (c) VMware, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the
> "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * on the rights to use, copy, modify, merge, publish, distribute, sub
> + * license, and/or sell copies of the Software, and to permit persons to
> whom
> + * the Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
> OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
> OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> + * DEALINGS IN THE SOFTWARE.
> + */
> +
> +
> +#ifndef PIGLIT_MATRIX_H
> +#define PIGLIT_MATRIX_H
> +
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +
> +#include <stdbool.h>
It's not generally safe to add #includes inside `extern "C" { ... }`, because some system headers may use C++ internally (which would cause an error), and as matter of fact, some windows headers do precisely that. (Though I'm sure stdbool.h is probably safe.) But as rule of thumb, all #includes should be before `extern "C" { ... }`.
Jose
More information about the Piglit
mailing list