Source: css3d.matrix4.js

/**
 * CSS 3D engine
 *
 * @category    css3d
 * @package     css3d.matrix4
 * @author      Jan Fischer, bitWorking <info@bitworking.de>
 * @copyright   2014 Jan Fischer
 * @license     http://www.opensource.org/licenses/mit-license.html  MIT License
 */

/**
 * 
 * @namespace
 */
css3d.matrix4 = {

    D2R : (Math.PI/180),

    /**
     * 
     * @returns {Array}
     */
    identity : function()
    {
        return [
            1, 0, 0, 0,
            0, 1, 0, 0,
            0, 0, 1, 0,
            0, 0, 0, 1
        ];
    },

    /**
     * 
     * @param {Array} a
     * @param {Array} b
     * @returns {Array}
     */
    multiply : function(a, b)
    {
        return [
            a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12],
            a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13],
            a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14],
            a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15],

            a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12],
            a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13],
            a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14],
            a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15],

            a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12],
            a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13],
            a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14],
            a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15],

            a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12],
            a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13],
            a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14],
            a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15]
        ];
    },

    /**
     * 
     * @param {Number} angle
     * @returns {Array}
     */
    rotationX : function(angle)
    {
        var c = Math.cos(angle), s = Math.sin(angle);
        return [
            1, 0,  0, 0,
            0, c, -s, 0,
            0, s,  c, 0,
            0, 0,  0, 1
        ];
    },

    /**
     * 
     * @param {Number} angle
     * @returns {Array}
     */
    rotationY : function(angle)
    {
        var c = Math.cos(angle), s = Math.sin(angle);
        return [
            c, 0, s, 0,
            0, 1, 0, 0,
           -s, 0, c, 0,
            0, 0, 0, 1
        ];
    },

    /**
     * 
     * @param {Number} angle
     * @returns {Array}
     */
    rotationZ : function(angle)
    {
        var c = Math.cos(angle), s = Math.sin(angle);
        return [
            c, -s, 0, 0,
            s,  c, 0, 0,
            0,  0, 1, 0,
            0,  0, 0, 1
        ];
    },

    /**
     * 
     * @param {css3d.vector3} axis
     * @param {Number} angle
     * @returns {Array}
     */
    rotationAxis : function(axis, angle)
    {
        var c = Math.cos(angle);
        var s = Math.sin(angle);
        var t = 1 - c;
        var x = axis.x, y = axis.y, z = axis.z;
        var tx = t * x, ty = t * y;
        return [
            tx * x + c,     tx * y - s * z, tx * z + s * y, 0,
            tx * y + s * z, ty * y + c,     ty * z - s * x, 0,
            tx * z - s * y, ty * z + s * x, t * z * z + c,  0,
            0,              0,              0,              1
        ];
    },

    /**
     * 
     * @param {Number} x
     * @param {Number} y
     * @param {Number} z
     * @returns {Array}
     */
    scale : function(x, y, z)
    {
        return [
            x, 0, 0, 0,
            0, y, 0, 0,
            0, 0, z, 0,
            0, 0, 0, 1
        ];
    },

    /**
     * 
     * @param {Number} x
     * @param {Number} y
     * @param {Number} z
     * @returns {Array}
     */
    translation : function(x, y, z)
    {
        return [
            1, 0, 0, x,
            0, 1, 0, y,
            0, 0, 1, z,
            0, 0, 0, 1
        ];
    },

    /**
     * 
     * @param {Array} matrix
     * @returns {css3d.vector3}
     */
    right : function(matrix)
    {
        return new css3d.vector3(matrix[0], matrix[4], matrix[8]);
    },

    /**
     * 
     * @param {Array} matrix
     * @returns {css3d.vector3}
     */
    up : function(matrix)
    {
        return new css3d.vector3(-matrix[1], -matrix[5], -matrix[9]);
    },

    /**
     * 
     * @param {Array} matrix
     * @returns {css3d.vector3}
     */
    back : function(matrix)
    {
        return new css3d.vector3(matrix[2], matrix[6], matrix[10]);
    },
    
    /**
     * 
     * @param {Array} matrix
     * @returns {css3d.vector3}
     */
    forward : function(matrix)
    {
        return new css3d.vector3(-matrix[2], -matrix[6], -matrix[10]);
    },

    /**
     * 
     * @param {Number} left
     * @param {Number} right
     * @param {Number} bottom
     * @param {Number} top
     * @param {Number} near
     * @param {Number} far
     * @returns {Array}
     */
    frustum : function(left, right, bottom, top, near, far)
    {
        var rMl = right - left;
        var tMb = top - bottom;
        var fMn = far - near;
        var n2 = 2 * near;
        return [
            n2/rMl, 0,      (right+left)/rMl, 0,
            0,      n2/tMb, (top+bottom)/tMb, 0,
            0,      0,      -(far+near)/fMn,  -2*(far*near)/fMn,
            0,      0,      -1,               0

        ];
    },

    /**
     * 
     * @param {Number} fov
     * @param {Number} width
     * @param {Number} height
     * @param {Number} near
     * @param {Number} far
     * @returns {Array}
     */
    projection : function(fov, width, height, near, far)
    {
        var radians = fov * this.D2R;
    	var halfHeight = (Math.tan(radians/2)*near);
    	var halfAspectRatio = halfHeight*(width/height);
    	return this.frustum(-halfAspectRatio, halfAspectRatio, -halfHeight, halfHeight, near, far);
    },

    /**
     * 
     * @param {css3d.vector3} eye
     * @param {css3d.vector3} target
     * @param {css3d.vector3} up
     * @returns {Array}
     */
    lookAt : function(eye, target, up)
    {
        //http://msdn.microsoft.com/en-us/library/windows/desktop/bb281710(v=vs.85).aspx

        var _target = new css3d.vector3(target.x, target.y, target.z);
        var _eye = new css3d.vector3(eye.x, eye.y, eye.z);

        var zaxis = _eye.sub(_target).normalize();
        var xaxis = css3d.vector3.prototype.cross(zaxis, up).normalize();
        var yaxis = css3d.vector3.prototype.cross(zaxis, xaxis);
        /*
        return [
            xaxis.x, yaxis.x, zaxis.x, eye.x,
            xaxis.y, yaxis.y, zaxis.y, eye.y,
            xaxis.z, yaxis.z, zaxis.z, eye.z,
            0,       0,       0,       1
        ];
        */
        return [
            xaxis.x, yaxis.x, zaxis.x, 0,
            xaxis.y, yaxis.y, zaxis.y, 0,
            xaxis.z, yaxis.z, zaxis.z, 0,
            0,       0,       0,       1
        ];
    },

    /**
     * 
     * @param {Array} m
     * @returns {Array}
     */
    transpose : function(m)
    {
        return [
            m[0], m[4], m[8],  m[12],
            m[1], m[5], m[9],  m[13],
            m[2], m[6], m[10], m[14],
            m[3], m[7], m[11], m[15]
        ];
    },
 
    /**
     * Works if matrix only contains rotation and translation part
     * 
     * @param {Array} m
     * @returns {Array}
     */
    fastInverse : function(m)
    {
        // http://harinadha.wordpress.com/tag/model-view-matrix-inverse/

        var x = -m[3]*m[0] + -m[7]*m[4] + -m[11]*m[8];
        var y = -m[3]*m[1] + -m[7]*m[5] + -m[11]*m[9];
        var z = -m[3]*m[2] + -m[7]*m[6] + -m[11]*m[10];

        return [
            m[0], m[4], m[8],  x,
            m[1], m[5], m[9],  y,
            m[2], m[6], m[10], z,
            0,    0,    0,     1
        ];
    },

    /**
     * Matrix has to be a rotation matrix
     * 
     * @param {Array} m
     * @returns {Object} {'axis':{css3d.vector3}, 'angle':{Number}}
     */
    toAxisAngle : function(m)
    {              
        var quaternion = css3d.quaternion.prototype.fromMatrix4(m);
        return quaternion.toAxisAngle();
    },
    
    /**
     * 
     * @param {Array} m
     * @returns {String}
     */
    toString : function(m)
    {
        var out = '';
        out += m[0].toFixed(2)+',\t'+m[1].toFixed(2)+',\t'+m[2].toFixed(2)+',\t'+m[3].toFixed(2)+','+"\n";
        out += m[4].toFixed(2)+',\t'+m[5].toFixed(2)+',\t'+m[6].toFixed(2)+',\t'+m[7].toFixed(2)+','+"\n";
        out += m[8].toFixed(2)+',\t'+m[9].toFixed(2)+',\t'+m[10].toFixed(2)+',\t'+m[11].toFixed(2)+','+"\n";
        out += m[12].toFixed(2)+',\t'+m[13].toFixed(2)+',\t'+m[14].toFixed(2)+',\t'+m[15].toFixed(2);
        out += '';
        return out;
    }
    
    



};