# Source: math/Matrix44.js

``````/**
*  @class Matrix44
*  @memberof SQR
*
*  @description A multi-purpose 4x4 matrix.
*/
SQR.Matrix44 = function(data) {

this.data = data || new Float32Array(16);

this.identity = function(m) {
var d = m || this.data;
d[0] = 1,d[4] = 0,d[8] = 0,d[12] = 0;
d[1] = 0,d[5] = 1,d[9] = 0,d[13] = 0;
d[2] = 0,d[6] = 0,d[10] = 1,d[14] = 0;
d[3] = 0,d[7] = 0,d[11] = 0,d[15] = 1;
return this;
}

/**
*  @memberof SQR.Matrix44.prototype
*  @description Multiplies the vector v by my this matrix and stores the result in the vector pv.
*
*  @param {SQR.V3} v - the vector to be multiplies by this matrix
*  @param {SQR.V3=} pv - the vector in which to store the result. If ommited, result is stored in v.
*/
this.transformVector = function (v, pv) {
var d = this.data;
var x = v.x, y = v.y, z = v.z, w = v.w;
pv = pv || v;

pv.x = d[0] * x + d[4] * y + d[8] * z + d[12] * w;
pv.y = d[1] * x + d[5] * y + d[9] * z + d[13] * w;
pv.z = d[2] * x + d[6] * y + d[10] * z + d[14] * w;
// pv.w = d[3] * x + d[7] * y + d[11] * z + d[15] * w;

return pv;
}

this.rotateVector = function (v, pv) {
var d = this.data;
var x = v.x, y = v.y, z = v.z, w = v.w;
pv = pv || v;

pv.x = d[0] * x + d[4] * y + d[8] * z;
pv.y = d[1] * x + d[5] * y + d[9] * z;
pv.z = d[2] * x + d[6] * y + d[10] * z;
// pv.w = d[3] * x + d[7] * y + d[11] * z + d[15] * w;

return pv;
}

/**
*  @memberof SQR.Matrix44.prototype
*  @description Multiplies this matrix by m
*  @param {SQR.Matrix44} m - matrix to multiply this matrix by
*/
this.multiply = function(m) {
var a = this.data, b = m.data || m;

var a00, a01, a02, a03, a04, a05, a06, a07, a08, a09, a10, a11, a12, a13, a14, a15;
var b00, b01, b02, b03, b04, b05, b06, b07, b08, b09, b10, b11, b12, b13, b14, b15;

a00 = a[0],a01 = a[1],a02 = a[2],a03 = a[3];
a04 = a[4],a05 = a[5],a06 = a[6],a07 = a[7];
a08 = a[8],a09 = a[9],a10 = a[10],a11 = a[11];
a12 = a[12],a13 = a[13],a14 = a[14],a15 = a[15];

b00 = b[0],b01 = b[1],b02 = b[2],b03 = b[3];
b04 = b[4],b05 = b[5],b06 = b[6],b07 = b[7];
b08 = b[8],b09 = b[9],b10 = b[10],b11 = b[11];
b12 = b[12],b13 = b[13],b14 = b[14],b15 = b[15];

a[0] = a00 * b00 + a04 * b01 + a08 * b02 + a12 * b03;
a[1] = a01 * b00 + a05 * b01 + a09 * b02 + a13 * b03;
a[2] = a02 * b00 + a06 * b01 + a10 * b02 + a14 * b03;
a[3] = a03 * b00 + a07 * b01 + a11 * b02 + a15 * b03;

a[4] = a00 * b04 + a04 * b05 + a08 * b06 + a12 * b07;
a[5] = a01 * b04 + a05 * b05 + a09 * b06 + a13 * b07;
a[6] = a02 * b04 + a06 * b05 + a10 * b06 + a14 * b07;
a[7] = a03 * b04 + a07 * b05 + a11 * b06 + a15 * b07;

a[8] = a00 * b08 + a04 * b09 + a08 * b10 + a12 * b11;
a[9] = a01 * b08 + a05 * b09 + a09 * b10 + a13 * b11;
a[10] = a02 * b08 + a06 * b09 + a10 * b10 + a14 * b11;
a[11] = a03 * b08 + a07 * b09 + a11 * b10 + a15 * b11;

a[12] = a00 * b12 + a04 * b13 + a08 * b14 + a12 * b15;
a[13] = a01 * b12 + a05 * b13 + a09 * b14 + a13 * b15;
a[14] = a02 * b12 + a06 * b13 + a10 * b14 + a14 * b15;
a[15] = a03 * b12 + a07 * b13 + a11 * b14 + a15 * b15;

return this;
}

/**
*  @method setTQS
*  @memberof SQR.Matrix44.prototype
*  @description Sets the translation/rotation/scale values at once.
*  Similar to setTRS but the rotation is defined as a quaternion.
*  @param tx x translation
*  @param ty y translation
*  @param tz y translation
*  @param qw w compoment of the quaternion
*  @param qx x compoment of the quaternion
*  @param qx y compoment of the quaternion
*  @param qx z compoment of the quaternion
*  @param sx x scale
*  @param sy y scale
*  @param sz z scale
*  @param m the matrix to set scale to, applies to `this` if ommited
*/
this.setTQS = function(tx, ty, tz, qw, qx, qy, qz, sx, sy, sz, m) {

var d = m || this.data;
this.identity(m);

var sqx = qx * qx;
var sqy = qy * qy;
var sqz = qz * qz;

// fliping this part changes from left handed to right handed (I think)
if(SQR.flipMatrix) {
d[0] = (1 - 2 * sqy - 2 * sqz) * sx;
d[1] = (2 * qx * qy - 2 * qz * qw) * sx;
d[2] = (2 * qx * qz + 2 * qy * qw) * sx;

d[4] = (2 * qx * qy + 2 * qz * qw) * sy;
d[5] = (1 - 2 * sqx - 2 * sqz) * sy;
d[6] = (2 * qy * qz - 2 * qx * qw) * sy;

d[8] = (2 * qx * qz - 2 * qy * qw) * sz;
d[9] = (2 * qy * qz + 2 * qx * qw) * sz;
d[10] = (1 - 2 * sqx - 2 * sqy) * sz;
} else {
d[0] = (1 - 2 * sqy - 2 * sqz) * sx;
d[4] = (2 * qx * qy - 2 * qz * qw) * sx;
d[8] = (2 * qx * qz + 2 * qy * qw) * sx;

d[1] = (2 * qx * qy + 2 * qz * qw) * sy;
d[5] = (1 - 2 * sqx - 2 * sqz) * sy;
d[9] = (2 * qy * qz - 2 * qx * qw) * sy;

d[2] = (2 * qx * qz - 2 * qy * qw) * sz;
d[6] = (2 * qy * qz + 2 * qx * qw) * sz;
d[10] = (1 - 2 * sqx - 2 * sqy) * sz;
}

d[12] = tx;
d[13] = ty;
d[14] = tz;

return m || this;
}

/**
*  @method setTRS
*  @memberof SQR.Matrix44.prototype
*  @description Sets the translation/rotation/scale values at once.
*  @param tx x translation
*  @param ty y translation
*  @param tz y translation
*  @param rx rotation angle in radians on the x axis
*  @param ry rotation angle in radians on the y axis
*  @param rz rotation angle in radians on the z axis
*  @param sx x scale
*  @param sy y scale
*  @param sz z scale
*  @param m the matrix to set scale to, applies to `this` if ommited
*/
this.setTRS = function(tx, ty, tz, rx, ry, rz, sx, sy, sz, m) {

var d = m || this.data;
this.identity(m);

var six = Math.sin(rx), cox = Math.cos(rx), siy = Math.sin(ry), coy = Math.cos(ry), siz = Math.sin(rz), coz = Math.cos(rz);

// fliping this part changes from left handed to right handed (I think)
if(SQR.flipMatrix) {
d[0] = (coy * coz + siy * six * siz) * sx;
d[1] = (-coy * siz + siy * six * coz) * sx;
d[2] = siy * cox * sx;

d[4] = siz * cox * sy;
d[5] = coz * cox * sy;
d[6] = -six * sy;

d[8] = (-siy * coz + coy * six * siz) * sz;
d[9] = (siz * siy + coy * six * coz) * sz;
d[10] = coy * cox * sz;
} else {
d[0] = (coy * coz + siy * six * siz) * sx;
d[4] = (-coy * siz + siy * six * coz) * sx;
d[8] = siy * cox * sx;

d[1] = siz * cox * sy;
d[5] = coz * cox * sy;
d[9] = -six * sy;

d[2] = (-siy * coz + coy * six * siz) * sz;
d[6] = (siz * siy + coy * six * coz) * sz;
d[10] = coy * cox * sz;
}

d[12] = tx;
d[13] = ty;
d[14] = tz;

return m || this;
}

/**
*  @method setScale
*  @memberof SQR.Matrix44.prototype
*  @description Sets the scale values.
*  @param sx x scale
*  @param sy y scale
*  @param sz z scale
*  @param m the matrix to set scale to, applies to `this` if ommited
*/
this.setScale = function(sx, sy, sz, m) {
var d = m || this.data;
d[0] = sx, d[5] = sy, d[10] = sz;
return m || this;
}

/**
*  @method setTranslation
*  @memberof SQR.Matrix44.prototype
*  @description Sets the translation values.
*  @param tx x translation
*  @param ty y translation
*  @param tz z translation
*  @param m the matrix to set translation to, applies to `this` if ommited
*/
this.setTranslation = function(tx, ty, tz, m) {
var d = m || this.data;
d[12] = tx, d[13] = ty, d[14] = tz;
return m || this;
}

/**
*  @method setRotation
*  @memberof SQR.Matrix44.prototype
*  @description Sets the rotation value.
*  @param rx angle in radians of the rotation on x axis
*  @param ry angle in radians of the rotation on y axis
*  @param rz angle in radians of the rotation on z axis
*  @param m the matrix to set rotation to, applies to `this` if ommited
*/
this.setRotation = function(rx, ry, rz, m) {
var d = m || this.data;
var six = Math.sin(rx), cox = Math.cos(rx),
siy = Math.sin(ry), coy = Math.cos(ry),
siz = Math.sin(rz), coz = Math.cos(rz);

d[0] = coy * coz + siy * six * siz;
d[1] = -coy * siz + siy * six * coz;
d[2] = siy * cox;

d[4] = siz * cox;
d[5] = coz * cox;
d[6] = -six;

d[8] = -siy * coz + coy * six * siz;
d[9] = siz * siy + coy * six * coz;
d[10] = coy * cox;

return m || this;
}

/**
*  @method translate
*  @memberof SQR.Matrix44.prototype
*  @description Applies translation to matrix
*  @param tx x translation
*  @param ty y translation
*  @param tz z translation
*/
this.translate = function(tx, ty, tz) {
this.identity(SQR.Matrix44.__temp);
this.setTranslation(tx, ty, tz, SQR.Matrix44.__temp);
return this.multiply(SQR.Matrix44.__temp);
}

/**
*  @method rotate
*  @memberof SQR.Matrix44.prototype
*  @param rx angle in radians of the rotation on x axis
*  @param ry angle in radians of the rotation on y axis
*  @param rz angle in radians of the rotation on z axis
*  @description Applies rotation to matrix
*/
this.rotate = function(rx, ry, rz) {
this.identity(SQR.Matrix44.__temp);
this.setRotation(rx, ry, rz, SQR.Matrix44.__temp);
return this.multiply(SQR.Matrix44.__temp);
}

/**
*  @method scale
*  @memberof SQR.Matrix44.prototype
*  @param sx x scale
*  @param sy y scale
*  @param sz z scale
*  @description Applies scale to matrix
*/
this.scale = function(sx, sy, sz) {
this.identity(SQR.Matrix44.__temp);
this.setScale(sx, sy, sz, SQR.Matrix44.__temp);
return this.multiply(SQR.Matrix44.__temp);
}

/**
*  @method copyTo
*  @memberof SQR.Matrix44.prototype
*  Copies the values from this matrix into m
*
*  @param {SQR.Matrix44|Float32Array} m - the matrix or 16-compoment array to copy the values to
*/
this.copyTo = function(m) {
var a = this.data, b = m.data || m;
for (var i = 0; i < 16; i++) b[i] = a[i];
return this;
}

this.copyFrom = function(m) {
var a = this.data, b = m.data || m;
for (var i = 0; i < 16; i++) a[i] = b[i];
return this;
}

/**
*  @method copyRotationTo
*  @memberof SQR.Matrix44.prototype
*  Copies only the rotation/scale portion of the matrix into m to the current matrix
*
*  @param {SQR.Matrix44|Float32Array} m - the matrix or 16-compoment array to copy the values to
*/
this.copyRotationTo = function(m) {
var a = this.data, b = m.data || m;

b[0] = a[0];
b[1] = a[1];
b[2] = a[2];

b[3] = a[4];
b[4] = a[5];
b[5] = a[6];

b[6] = a[8];
b[7] = a[9];
b[8] = a[10];

return m;
}

/**
*  @method extractPosition
*  @memberof SQR.Matrix44.prototype
*  Sets v to the translation vakue of this matrix. Useful for extracting position of an element
*  based on it's transformation matrix, ex. this is how the the global position of a {@link SQR.Transform}
*  is obtained.
*
*  @param {SQR.V3} v - the vector to copy the translation values to
*/
this.extractPosition = function(v) {
var d = this.data;
v.set(d[12], d[13], d[14]);
return v;
}

this.determinant = function() {
var d = this.data;

return d[0] * (d[5] * d[10] - d[9] * d[6]) +
d[4] * (d[9] * d[2] - d[1] * d[10]) +
d[8] * (d[1] * d[6] - d[5] * d[2]);
}

this.inverse = function(m) {
var a = this.data;
var d = (m) ? m.data || m : this.data;

var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],

b00 = a00 * a11 - a01 * a10,
b01 = a00 * a12 - a02 * a10,
b02 = a00 * a13 - a03 * a10,
b03 = a01 * a12 - a02 * a11,
b04 = a01 * a13 - a03 * a11,
b05 = a02 * a13 - a03 * a12,
b06 = a20 * a31 - a21 * a30,
b07 = a20 * a32 - a22 * a30,
b08 = a20 * a33 - a23 * a30,
b09 = a21 * a32 - a22 * a31,
b10 = a21 * a33 - a23 * a31,
b11 = a22 * a33 - a23 * a32,

// Calculate the determinant
det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;

if (!det) {
return null;
}
det = 1.0 / det;

d[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
d[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
d[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
d[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
d[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
d[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
d[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
d[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
d[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
d[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
d[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
d[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
d[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
d[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
d[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
d[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;

return m;
};

this.inverseMat3 = function(m) {
var d = this.data;
var a = m.data;
var det = this.determinant();

if (Math.abs(det) < 0.0001) {
console.warn("> SQR.Matrix44 - Attempt to inverse a singular matrix44. ", this.data);
console.trace();
return m;
}

var d0 = d[0], d4 = d[4], d8 = d[8],   d12 = d[12],
d1 = d[1], d5 = d[5], d9 = d[9],   d13 = d[13],
d2 = d[2], d6 = d[6], d10 = d[10], d14 = d[14];

det = 1 / det;

// To make a NormalMatrix - needs to be transposed
a[0] = (d5 * d10 - d9 * d6) * det;
a[1] = (d8 * d6 - d4 * d10) * det;
a[2] = (d4 * d9 - d8 * d5) * det;

a[3] = (d9 * d2 - d1 * d10) * det;
a[4] = (d0 * d10 - d8 * d2) * det;
a[5] = (d8 * d1 - d0 * d9) * det;

a[6] = (d1 * d6 - d5 * d2) * det;
a[7] = (d4 * d2 - d0 * d6) * det;
a[8] = (d0 * d5 - d4 * d1) * det;

// To make a NormalMatrix - doesn't need to be transposed
// a[0] = (d5 * d10 - d9 * d6) * det;
// a[3] = (d8 * d6 - d4 * d10) * det;
// a[6] = (d4 * d9 - d8 * d5) * det;

// a[1] = (d9 * d2 - d1 * d10) * det;
// a[4] = (d0 * d10 - d8 * d2) * det;
// a[7] = (d8 * d1 - d0 * d9) * det;

// a[2] = (d1 * d6 - d5 * d2) * det;
// a[5] = (d4 * d2 - d0 * d6) * det;
// a[8] = (d0 * d5 - d4 * d1) * det;

return m;
}

this.transpose = function(m) {
var d = this.data;
var a = (m) ? m.data || m : this.data;

var d0 = d[0], d4 = d[4], d8 = d[8],
d1 = d[1], d5 = d[5], d9 = d[9],
d2 = d[2], d6 = d[6], d10 = d[10];

a[0] = d0;
a[1] = d4;
a[2] = d8;

a[4] = d1;
a[5] = d5;
a[6] = d9;

a[8] = d2;
a[9] = d6;
a[10] = d10;
}

this.lookAt = function (target, up) {
var d = this.data;
var x = SQR.V3.__tv1;
var y = SQR.V3.__tv2;
var z = SQR.V3.__tv3;

up = up || SQR.V3.up;

// console.log(target, up);

z.set(d[12], d[13], d[14]);
z.sub(z, target).norm();
if (z.magsq() === 0) z.z = 1;

x.cross(up, z).norm();
if (x.magsq() === 0) {
z.x += 0.0001;
x.cross(up, z).norm();
}

y.cross(z, x);

d[0] = x.x, d[4] = y.x, d[8] = z.x;
d[1] = x.y, d[5] = y.y, d[9] = z.y;
d[2] = x.z, d[6] = y.z, d[10] = z.z;

return this;
}

if(!data) this.identity();
}

SQR.Matrix44.__temp = new Float32Array(16);

``````