blob: 93ef63c963354d18151dd36c223b800c793f0abe [file] [log] [blame]
//
// Copyright (c) 2010 Linaro Limited
//
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the MIT License which accompanies
// this distribution, and is available at
// http://www.opensource.org/licenses/mit-license.php
//
// Contributors:
// Jesse Barker - original implementation.
//
#include <math.h>
#include "mat.h"
namespace LibMatrix
{
namespace Mat4
{
mat4
translate(float x, float y, float z)
{
mat4 t;
t[0][3] = x;
t[1][3] = y;
t[2][3] = z;
return t;
}
mat4
scale(float x, float y, float z)
{
mat4 s;
s[0][0] = x;
s[1][1] = y;
s[2][2] = z;
return s;
}
//
// As per the OpenGL "red book" definition of rotation, from the appendix
// on Homogeneous Coordinates and Transformation Matrices, the "upper left"
// 3x3 portion of the result matrix is formed by:
//
// M = uuT + (cos a)(I - uuT) + (sin a)S
//
// where u is the normalized input vector, uuT is the outer product of that
// vector and its transpose, I is the identity matrix and S is the matrix:
//
// | 0 -z' y' |
// | z' 0 -x' |
// | -y' x' 0 |
//
// where x', y' and z' are the elements of u
//
mat4
rotate(float angle, float x, float y, float z)
{
vec3 u(x, y, z);
u.normalize();
mat3 uuT = outer(u, u);
mat3 s;
s[0][0] = 0;
s[0][1] = -u.z();
s[0][2] = u.y();
s[1][0] = u.z();
s[1][1] = 0;
s[1][2] = -u.x();
s[2][0] = -u.y();
s[2][1] = u.x();
s[2][2] = 0;
mat3 i;
i -= uuT;
// degrees to radians
float angleRadians(angle * M_PI / 180.0);
i *= cos(angleRadians);
s *= sin(angleRadians);
i += s;
mat3 m = uuT + i;
mat4 r;
r[0][0] = m[0][0];
r[0][1] = m[0][1];
r[0][2] = m[0][2];
r[1][0] = m[1][0];
r[1][1] = m[1][1];
r[1][2] = m[1][2];
r[2][0] = m[2][0];
r[2][1] = m[2][1];
r[2][2] = m[2][2];
return r;
}
mat4
frustum(float left, float right, float bottom, float top, float near, float far)
{
float twiceNear(2 * near);
float width(right - left);
float height(top - bottom);
float depth(far - near);
mat4 f;
f[0][0] = twiceNear / width;
f[0][2] = (right + left) / width;
f[1][1] = twiceNear / height;
f[1][2] = (top + bottom) / height;
f[2][2] = -(far + near) / depth;
f[2][3] = -(twiceNear * far) / depth;
f[3][2] = -1;
f[3][3] = 0;
return f;
}
mat4
ortho(float left, float right, float bottom, float top, float near, float far)
{
float width(right - left);
float height(top - bottom);
float depth(far - near);
mat4 o;
o[0][0] = 2 / width;
o[0][3] = (right + left) / width;
o[1][1] = 2 / height;
o[1][3] = (top + bottom) / height;
o[2][2] = -2 / depth;
o[2][3] = (far + near) / depth;
return o;
}
mat4
perspective(float fovy, float aspect, float zNear, float zFar)
{
// degrees to radians
float fovyRadians(fovy * M_PI / 180.0);
// cotangent(x) = 1/tan(x)
float f = 1/tan(fovyRadians / 2);
float depth(zNear - zFar);
mat4 p;
p[0][0] = f / aspect;
p[1][1] = f;
p[2][2] = (zFar + zNear) / depth;
p[2][3] = (2 * zFar * zNear) / depth;
p[3][2] = -1;
p[3][3] = 0;
return p;
}
mat4 lookAt(float eyeX, float eyeY, float eyeZ,
float centerX, float centerY, float centerZ,
float upX, float upY, float upZ)
{
vec3 f(centerX - eyeX, centerY - eyeY, centerZ - eyeZ);
f.normalize();
vec3 up(upX, upY, upZ);
vec3 s = vec3::cross(f, up);
vec3 u = vec3::cross(s, f);
s.normalize();
u.normalize();
mat4 la;
la[0][0] = s.x();
la[0][1] = s.y();
la[0][2] = s.z();
la[1][0] = u.x();
la[1][1] = u.y();
la[1][2] = u.z();
la[2][0] = -f.x();
la[2][1] = -f.y();
la[2][2] = -f.z();
la *= translate(-eyeX, -eyeY, -eyeZ);
return la;
}
} // namespace Mat4
} // namespace LibMatrix