summaryrefslogtreecommitdiff
path: root/cogl/cogl-matrix.c
diff options
context:
space:
mode:
Diffstat (limited to 'cogl/cogl-matrix.c')
-rw-r--r--cogl/cogl-matrix.c282
1 files changed, 282 insertions, 0 deletions
diff --git a/cogl/cogl-matrix.c b/cogl/cogl-matrix.c
new file mode 100644
index 00000000..4cc63598
--- /dev/null
+++ b/cogl/cogl-matrix.c
@@ -0,0 +1,282 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2008,2009 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Authors:
+ * Robert Bragg <robert@linux.intel.com>
+ */
+
+#include <cogl.h>
+#include <cogl-matrix.h>
+
+#include <glib.h>
+#include <math.h>
+#include <string.h>
+
+void
+cogl_matrix_init_identity (CoglMatrix *matrix)
+{
+ matrix->xx = 1; matrix->xy = 0; matrix->xz = 0; matrix->xw = 0;
+ matrix->yx = 0; matrix->yy = 1; matrix->yz = 0; matrix->yw = 0;
+ matrix->zx = 0; matrix->zy = 0; matrix->zz = 1; matrix->zw = 0;
+ matrix->wx = 0; matrix->wy = 0; matrix->wz = 0; matrix->ww = 1;
+}
+
+void
+cogl_matrix_multiply (CoglMatrix *result,
+ const CoglMatrix *a,
+ const CoglMatrix *b)
+{
+ CoglMatrix r;
+
+ /* row 0 */
+ r.xx = a->xx * b->xx + a->xy * b->yx + a->xz * b->zx + a->xw * b->wx;
+ r.xy = a->xx * b->xy + a->xy * b->yy + a->xz * b->zy + a->xw * b->wy;
+ r.xz = a->xx * b->xz + a->xy * b->yz + a->xz * b->zz + a->xw * b->wz;
+ r.xw = a->xx * b->xw + a->xy * b->yw + a->xz * b->zw + a->xw * b->ww;
+
+ /* row 1 */
+ r.yx = a->yx * b->xx + a->yy * b->yx + a->yz * b->zx + a->yw * b->wx;
+ r.yy = a->yx * b->xy + a->yy * b->yy + a->yz * b->zy + a->yw * b->wy;
+ r.yz = a->yx * b->xz + a->yy * b->yz + a->yz * b->zz + a->yw * b->wz;
+ r.yw = a->yx * b->xw + a->yy * b->yw + a->yz * b->zw + a->yw * b->ww;
+
+ /* row 2 */
+ r.zx = a->zx * b->xx + a->zy * b->yx + a->zz * b->zx + a->zw * b->wx;
+ r.zy = a->zx * b->xy + a->zy * b->yy + a->zz * b->zy + a->zw * b->wy;
+ r.zz = a->zx * b->xz + a->zy * b->yz + a->zz * b->zz + a->zw * b->wz;
+ r.zw = a->zx * b->xw + a->zy * b->yw + a->zz * b->zw + a->zw * b->ww;
+
+ /* row 3 */
+ r.wx = a->wx * b->xx + a->wy * b->yx + a->wz * b->zx + a->ww * b->wx;
+ r.wy = a->wx * b->xy + a->wy * b->yy + a->wz * b->zy + a->ww * b->wy;
+ r.wz = a->wx * b->xz + a->wy * b->yz + a->wz * b->zz + a->ww * b->wz;
+ r.ww = a->wx * b->xw + a->wy * b->yw + a->wz * b->zw + a->ww * b->ww;
+
+ /* The idea was that having this unrolled; it might be easier for the
+ * compiler to vectorize, but that's probably not true. Mesa does it
+ * using a single for (i=0; i<4; i++) approach, may that's better...
+ */
+
+ *result = r;
+}
+
+void
+cogl_matrix_rotate (CoglMatrix *matrix,
+ float angle,
+ float x,
+ float y,
+ float z)
+{
+ CoglMatrix rotation;
+ CoglMatrix result;
+ float c, s;
+
+ angle *= G_PI / 180.0f;
+ c = cosf (angle);
+ s = sinf (angle);
+
+ rotation.xx = x * x * (1.0f - c) + c;
+ rotation.yx = y * x * (1.0f - c) + z * s;
+ rotation.zx = x * z * (1.0f - c) - y * s;
+ rotation.wx = 0.0f;
+
+ rotation.xy = x * y * (1.0f - c) - z * s;
+ rotation.yy = y * y * (1.0f - c) + c;
+ rotation.zy = y * z * (1.0f - c) + x * s;
+ rotation.wy = 0.0f;
+
+ rotation.xz = x * z * (1.0f - c) + y * s;
+ rotation.yz = y * z * (1.0f - c) - x * s;
+ rotation.zz = z * z * (1.0f - c) + c;
+ rotation.wz = 0.0f;
+
+ rotation.xw = 0.0f;
+ rotation.yw = 0.0f;
+ rotation.zw = 0.0f;
+ rotation.ww = 1.0f;
+
+ cogl_matrix_multiply (&result, matrix, &rotation);
+ *matrix = result;
+}
+
+void
+cogl_matrix_translate (CoglMatrix *matrix,
+ float x,
+ float y,
+ float z)
+{
+ matrix->xw = matrix->xx * x + matrix->xy * y + matrix->xz * z + matrix->xw;
+ matrix->yw = matrix->yx * x + matrix->yy * y + matrix->yz * z + matrix->yw;
+ matrix->zw = matrix->zx * x + matrix->zy * y + matrix->zz * z + matrix->zw;
+ matrix->ww = matrix->wx * x + matrix->wy * y + matrix->wz * z + matrix->ww;
+}
+
+void
+cogl_matrix_scale (CoglMatrix *matrix,
+ float sx,
+ float sy,
+ float sz)
+{
+ matrix->xx *= sx; matrix->xy *= sy; matrix->xz *= sz;
+ matrix->yx *= sx; matrix->yy *= sy; matrix->yz *= sz;
+ matrix->zx *= sx; matrix->zy *= sy; matrix->zz *= sz;
+ matrix->wx *= sx; matrix->wy *= sy; matrix->wz *= sz;
+}
+
+#if 0
+gboolean
+cogl_matrix_invert (CoglMatrix *matrix)
+{
+ /* TODO */
+ /* Note: It might be nice to also use the flag based tricks that mesa does
+ * to alow it to track the type of transformations a matrix represents
+ * so it can use various assumptions to optimise the inversion.
+ */
+}
+#endif
+
+void
+cogl_matrix_frustum (CoglMatrix *matrix,
+ float left,
+ float right,
+ float bottom,
+ float top,
+ float z_near,
+ float z_far)
+{
+ float x, y, a, b, c, d;
+ CoglMatrix frustum;
+
+ x = (2.0f * z_near) / (right - left);
+ y = (2.0f * z_near) / (top - bottom);
+ a = (right + left) / (right - left);
+ b = (top + bottom) / (top - bottom);
+ c = -(z_far + z_near) / ( z_far - z_near);
+ d = -(2.0f * z_far* z_near) / (z_far - z_near);
+
+ frustum.xx = x;
+ frustum.yx = 0.0f;
+ frustum.zx = 0.0f;
+ frustum.wx = 0.0f;
+
+ frustum.xy = 0.0f;
+ frustum.yy = y;
+ frustum.zy = 0.0f;
+ frustum.wy = 0.0f;
+
+ frustum.xz = a;
+ frustum.yz = b;
+ frustum.zz = c;
+ frustum.wz = -1.0f;
+
+ frustum.xw = 0.0f;
+ frustum.yw = 0.0f;
+ frustum.zw = d;
+ frustum.ww = 0.0f;
+
+ cogl_matrix_multiply (matrix, matrix, &frustum);
+}
+
+void
+cogl_matrix_perspective (CoglMatrix *matrix,
+ float fov_y,
+ float aspect,
+ float z_near,
+ float z_far)
+{
+ float ymax = z_near * tan (fov_y * G_PI / 360.0);
+
+ cogl_matrix_frustum (matrix,
+ -ymax * aspect, /* left */
+ ymax * aspect, /* right */
+ -ymax, /* bottom */
+ ymax, /* top */
+ z_near,
+ z_far);
+}
+
+void
+cogl_matrix_ortho (CoglMatrix *matrix,
+ float left,
+ float right,
+ float bottom,
+ float top,
+ float near_val,
+ float far_val)
+{
+ CoglMatrix ortho;
+
+ /* column 0 */
+ ortho.xx = 2.0 / (right - left);
+ ortho.yx = 0.0;
+ ortho.zx = 0.0;
+ ortho.wx = 0.0;
+
+ /* column 1 */
+ ortho.xy = 0.0;
+ ortho.yy = 2.0 / (top - bottom);
+ ortho.zy = 0.0;
+ ortho.wy = 0.0;
+
+ /* column 2 */
+ ortho.xz = 0.0;
+ ortho.yz = 0.0;
+ ortho.zz = -2.0 / (far_val - near_val);
+ ortho.wz = 0.0;
+
+ /* column 3 */
+ ortho.xw = -(right + left) / (right - left);
+ ortho.yw = -(top + bottom) / (top - bottom);
+ ortho.zw = -(far_val + near_val) / (far_val - near_val);
+ ortho.ww = 1.0;
+
+ cogl_matrix_multiply (matrix, matrix, &ortho);
+}
+
+void
+cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array)
+{
+ memcpy (matrix, array, sizeof (float) * 16);
+}
+
+const float *
+cogl_matrix_get_array (const CoglMatrix *matrix)
+{
+ return (float *)matrix;
+}
+
+void
+cogl_matrix_transform_point (const CoglMatrix *matrix,
+ float *x,
+ float *y,
+ float *z,
+ float *w)
+{
+ float _x = *x, _y = *y, _z = *z, _w = *w;
+
+ *x = matrix->xx * _x + matrix->xy * _y + matrix->xz * _z + matrix->xw * _w;
+ *y = matrix->yx * _x + matrix->yy * _y + matrix->yz * _z + matrix->yw * _w;
+ *z = matrix->zx * _x + matrix->zy * _y + matrix->zz * _z + matrix->zw * _w;
+ *w = matrix->wx * _x + matrix->wy * _y + matrix->wz * _z + matrix->ww * _w;
+}
+
+