js/base/Matrix.js
'use strict'
import Vector3 from './Vector3'
// import Vector4 from './Vector4'
/**
* matrix class
* @access public
*/
export default class Matrix {
/**
* constructor
* @access public
* @constructor
* @param {Matrix|array} matrix - a
*/
constructor(matrix) {
if(matrix instanceof Matrix){
this.copyMatrix(matrix)
}else if(typeof matrix === 'object') {
if('length' in matrix && matrix.length >= 16){
/** @type {float} */ this.m11 = matrix[ 0]
/** @type {float} */ this.m12 = matrix[ 1]
/** @type {float} */ this.m13 = matrix[ 2]
/** @type {float} */ this.m14 = matrix[ 3]
/** @type {float} */ this.m21 = matrix[ 4]
/** @type {float} */ this.m22 = matrix[ 5]
/** @type {float} */ this.m23 = matrix[ 6]
/** @type {float} */ this.m24 = matrix[ 7]
/** @type {float} */ this.m31 = matrix[ 8]
/** @type {float} */ this.m32 = matrix[ 9]
/** @type {float} */ this.m33 = matrix[10]
/** @type {float} */ this.m34 = matrix[11]
/** @type {float} */ this.m41 = matrix[12]
/** @type {float} */ this.m42 = matrix[13]
/** @type {float} */ this.m43 = matrix[14]
/** @type {float} */ this.m44 = matrix[15]
}
}else{
// default
this.identity()
}
}
clone() {
return new Matrix(this)
}
/**
* reset matrix
* @access public
* @returns {void}
*/
identity() {
this.m11 = 1
this.m12 = 0
this.m13 = 0
this.m14 = 0
this.m21 = 0
this.m22 = 1
this.m23 = 0
this.m24 = 0
this.m31 = 0
this.m32 = 0
this.m33 = 1
this.m34 = 0
this.m41 = 0
this.m42 = 0
this.m43 = 0
this.m44 = 1
}
/**
* multiply matrix (src1 x src2), set result to this matrix
* @access public
* @param {Matrix} src1 -
* @param {Matrix} src2 -
* @returns {void}
*/
multiplyMatrix(src1, src2) {
const m11 = src1.m11 * src2.m11 + src1.m12 * src2.m21 + src1.m13 * src2.m31 + src1.m14 * src2.m41
const m12 = src1.m11 * src2.m12 + src1.m12 * src2.m22 + src1.m13 * src2.m32 + src1.m14 * src2.m42
const m13 = src1.m11 * src2.m13 + src1.m12 * src2.m23 + src1.m13 * src2.m33 + src1.m14 * src2.m43
const m14 = src1.m11 * src2.m14 + src1.m12 * src2.m24 + src1.m13 * src2.m34 + src1.m14 * src2.m44
const m21 = src1.m21 * src2.m11 + src1.m22 * src2.m21 + src1.m23 * src2.m31 + src1.m24 * src2.m41
const m22 = src1.m21 * src2.m12 + src1.m22 * src2.m22 + src1.m23 * src2.m32 + src1.m24 * src2.m42
const m23 = src1.m21 * src2.m13 + src1.m22 * src2.m23 + src1.m23 * src2.m33 + src1.m24 * src2.m43
const m24 = src1.m21 * src2.m14 + src1.m22 * src2.m24 + src1.m23 * src2.m34 + src1.m24 * src2.m44
const m31 = src1.m31 * src2.m11 + src1.m32 * src2.m21 + src1.m33 * src2.m31 + src1.m34 * src2.m41
const m32 = src1.m31 * src2.m12 + src1.m32 * src2.m22 + src1.m33 * src2.m32 + src1.m34 * src2.m42
const m33 = src1.m31 * src2.m13 + src1.m32 * src2.m23 + src1.m33 * src2.m33 + src1.m34 * src2.m43
const m34 = src1.m31 * src2.m14 + src1.m32 * src2.m24 + src1.m33 * src2.m34 + src1.m34 * src2.m44
const m41 = src1.m41 * src2.m11 + src1.m42 * src2.m21 + src1.m43 * src2.m31 + src1.m44 * src2.m41
const m42 = src1.m41 * src2.m12 + src1.m42 * src2.m22 + src1.m43 * src2.m32 + src1.m44 * src2.m42
const m43 = src1.m41 * src2.m13 + src1.m42 * src2.m23 + src1.m43 * src2.m33 + src1.m44 * src2.m43
const m44 = src1.m41 * src2.m14 + src1.m42 * src2.m24 + src1.m43 * src2.m34 + src1.m44 * src2.m44
this.m11 = m11
this.m12 = m12
this.m13 = m13
this.m14 = m14
this.m21 = m21
this.m22 = m22
this.m23 = m23
this.m24 = m24
this.m31 = m31
this.m32 = m32
this.m33 = m33
this.m34 = m34
this.m41 = m41
this.m42 = m42
this.m43 = m43
this.m44 = m44
}
/**
* blend 2 matrices.
* if rate is 0, result is equal to src1.
* if rate is 1, result is equal to src2.
* @access public
* @param {Matrix} src1 -
* @param {Matrix} src2 -
* @param {float} rate -
* @returns {void}
*/
lerp(src1, src2, rate) {
this.m11 = src1.m11 + rate * (src1.m11 - src2.m11)
this.m12 = src1.m12 + rate * (src1.m12 - src2.m12)
this.m13 = src1.m13 + rate * (src1.m13 - src2.m13)
this.m14 = src1.m14 + rate * (src1.m14 - src2.m14)
this.m21 = src1.m21 + rate * (src1.m21 - src2.m21)
this.m22 = src1.m22 + rate * (src1.m22 - src2.m22)
this.m23 = src1.m23 + rate * (src1.m23 - src2.m23)
this.m24 = src1.m24 + rate * (src1.m24 - src2.m24)
this.m31 = src1.m31 + rate * (src1.m31 - src2.m31)
this.m32 = src1.m32 + rate * (src1.m32 - src2.m32)
this.m33 = src1.m33 + rate * (src1.m33 - src2.m33)
this.m34 = src1.m34 + rate * (src1.m34 - src2.m34)
this.m41 = src1.m41 + rate * (src1.m41 - src2.m41)
this.m42 = src1.m42 + rate * (src1.m42 - src2.m42)
this.m43 = src1.m43 + rate * (src1.m43 - src2.m43)
this.m44 = src1.m44 + rate * (src1.m44 - src2.m44)
}
/**
* set rotation matrix from quaternion
* @access public
* @param {Vector4} quat - Quaternion
* @returns {void}
*/
matrixFromQuaternion(quat) {
const x2 = quat.x * quat.x * 2.0
const y2 = quat.y * quat.y * 2.0
const z2 = quat.z * quat.z * 2.0
const xy = quat.x * quat.y * 2.0
const yz = quat.y * quat.z * 2.0
const zx = quat.z * quat.x * 2.0
const xw = quat.x * quat.w * 2.0
const yw = quat.y * quat.w * 2.0
const zw = quat.z * quat.w * 2.0
this.m11 = 1.0 - y2 - z2
this.m12 = xy + zw
this.m13 = zx - yw
this.m14 = 0.0
this.m21 = xy - zw
this.m22 = 1.0 - z2 - x2
this.m23 = yz + xw
this.m24 = 0.0
this.m31 = zx + yw
this.m32 = yz - xw
this.m33 = 1.0 - x2 - y2
this.m34 = 0.0
this.m41 = 0.0
this.m42 = 0.0
this.m43 = 0.0
this.m44 = 1.0
}
/**
* copy matrix
* @access public
* @param {Matrix} src -
* @returns {void}
*/
copyMatrix(src) {
this.m11 = src.m11
this.m12 = src.m12
this.m13 = src.m13
this.m14 = src.m14
this.m21 = src.m21
this.m22 = src.m22
this.m23 = src.m23
this.m24 = src.m24
this.m31 = src.m31
this.m32 = src.m32
this.m33 = src.m33
this.m34 = src.m34
this.m41 = src.m41
this.m42 = src.m42
this.m43 = src.m43
this.m44 = src.m44
}
/**
* inverse matrix
* @access public
* @param {Matrix} src -
* @returns {void}
*/
inverseMatrix(src) {
const temp = new Matrix(src)
let buf = 0
let w1 = Math.abs(temp.m11)
let w2 = Math.abs(temp.m21)
let w3 = Math.abs(temp.m31)
let w4 = Math.abs(temp.m41)
let max = w1 > w2 ? w1 : w2
if(max < w3) max = w3
this.identity()
// 1
if(max < w4){
buf = 1.0 / temp.m41
w1 = temp.m11
w2 = temp.m12
w3 = temp.m13
w4 = temp.m14
temp.m12 = temp.m42 * buf
temp.m13 = temp.m43 * buf
temp.m14 = temp.m44 * buf
temp.m41 = w1
temp.m42 = w2
temp.m43 = w3
temp.m44 = w4
this.m11 = 0.0
this.m14 = buf
this.m41 = 1.0
this.m44 = 0.0
}else if(max === w1){
buf = 1.0 / temp.m11
temp.m12 *= buf
temp.m13 *= buf
temp.m14 *= buf
this.m11 = buf
}else if(max === w2){
buf = 1.0 / temp.m21
w1 = temp.m11
w2 = temp.m12
w3 = temp.m13
w4 = temp.m14
temp.m12 = temp.m22 * buf
temp.m13 = temp.m23 * buf
temp.m14 = temp.m24 * buf
temp.m21 = w1
temp.m22 = w2
temp.m23 = w3
temp.m24 = w4
this.m11 = 0.0
this.m12 = buf
this.m21 = 1.0
this.m22 = 0.0
}else{
buf = 1.0 / temp.m31
w1 = temp.m11
w2 = temp.m12
w3 = temp.m13
w4 = temp.m14
temp.m12 = temp.m32 * buf
temp.m13 = temp.m33 * buf
temp.m14 = temp.m34 * buf
temp.m31 = w1
temp.m32 = w2
temp.m33 = w3
temp.m34 = w4
this.m11 = 0.0
this.m13 = buf
this.m31 = 1.0
this.m33 = 0.0
}
buf = temp.m21
temp.m22 -= temp.m12 * buf
temp.m23 -= temp.m13 * buf
temp.m24 -= temp.m14 * buf
this.m21 -= this.m11 * buf
this.m22 -= this.m12 * buf
this.m23 -= this.m13 * buf
this.m24 -= this.m14 * buf
buf = temp.m31
temp.m32 -= temp.m12 * buf
temp.m33 -= temp.m13 * buf
temp.m34 -= temp.m14 * buf
this.m31 -= this.m11 * buf
this.m32 -= this.m12 * buf
this.m33 -= this.m13 * buf
this.m34 -= this.m14 * buf
buf = temp.m41
temp.m42 -= temp.m12 * buf
temp.m43 -= temp.m13 * buf
temp.m44 -= temp.m14 * buf
this.m41 -= this.m11 * buf
this.m42 -= this.m12 * buf
this.m43 -= this.m13 * buf
this.m44 -= this.m14 * buf
// 2
w2 = Math.abs(temp.m22)
w3 = Math.abs(temp.m32)
w4 = Math.abs(temp.m42)
max = w2 > w3 ? w2 : w3
if(max < w4){
buf = 1.0 / temp.m42
w2 = temp.m22
w3 = temp.m23
w4 = temp.m24
temp.m23 = temp.m43 * buf
temp.m24 = temp.m44 * buf
temp.m42 = w2
temp.m43 = w3
temp.m44 = w4
w1 = this.m21
w2 = this.m22
w3 = this.m23
w4 = this.m24
this.m21 = this.m41 * buf
this.m22 = this.m42 * buf
this.m23 = this.m43 * buf
this.m24 = this.m44 * buf
this.m41 = w1
this.m42 = w2
this.m43 = w3
this.m44 = w4
}else if(w2 > w3){
buf = 1.0 / temp.m22
temp.m23 *= buf
temp.m24 *= buf
this.m21 *= buf
this.m22 *= buf
this.m23 *= buf
this.m24 *= buf
}else{
buf = 1.0 / temp.m32
w2 = temp.m22
w3 = temp.m23
w4 = temp.m24
temp.m23 = temp.m33 * buf
temp.m24 = temp.m34 * buf
temp.m32 = w2
temp.m33 = w3
temp.m34 = w4
w1 = this.m21
w2 = this.m22
w3 = this.m23
w4 = this.m24
this.m21 = this.m31 * buf
this.m22 = this.m32 * buf
this.m23 = this.m33 * buf
this.m24 = this.m34 * buf
this.m31 = w1
this.m32 = w2
this.m33 = w3
this.m34 = w4
}
buf = temp.m12
temp.m13 -= temp.m23 * buf
temp.m14 -= temp.m24 * buf
this.m11 -= this.m21 * buf
this.m12 -= this.m22 * buf
this.m13 -= this.m23 * buf
this.m14 -= this.m24 * buf
buf = temp.m32
temp.m33 -= temp.m23 * buf
temp.m34 -= temp.m24 * buf
this.m31 -= this.m21 * buf
this.m32 -= this.m22 * buf
this.m33 -= this.m23 * buf
this.m34 -= this.m24 * buf
buf = temp.m42
temp.m43 -= temp.m23 * buf
temp.m44 -= temp.m24 * buf
this.m41 -= this.m21 * buf
this.m42 -= this.m22 * buf
this.m43 -= this.m23 * buf
this.m44 -= this.m24 * buf
// 3
if(Math.abs(temp.m33) > Math.abs(temp.m43)){
buf = 1.0 / temp.m33
temp.m34 *= buf
this.m31 *= buf
this.m32 *= buf
this.m33 *= buf
this.m34 *= buf
}else{
buf = 1.0 / temp.m43
w3 = temp.m33
w4 = temp.m34
temp.m34 = temp.m44 * buf
temp.m43 = w3
temp.m44 = w4
w1 = this.m31
w2 = this.m32
w3 = this.m33
w4 = this.m34
this.m31 = this.m41 * buf
this.m32 = this.m42 * buf
this.m33 = this.m43 * buf
this.m34 = this.m44 * buf
this.m41 = w1
this.m42 = w2
this.m43 = w3
this.m44 = w4
}
buf = temp.m13
temp.m14 -= temp.m34 * buf
this.m11 -= this.m31 * buf
this.m12 -= this.m32 * buf
this.m13 -= this.m33 * buf
this.m14 -= this.m34 * buf
buf = temp.m23
temp.m24 -= temp.m34 * buf
this.m21 -= this.m31 * buf
this.m22 -= this.m32 * buf
this.m23 -= this.m33 * buf
this.m24 -= this.m34 * buf
buf = temp.m43
temp.m44 -= temp.m34 * buf
this.m41 -= this.m31 * buf
this.m42 -= this.m32 * buf
this.m43 -= this.m33 * buf
this.m44 -= this.m34 * buf
// 4
buf = 1.0 / temp.m44
this.m41 *= buf
this.m42 *= buf
this.m43 *= buf
this.m44 *= buf
buf = temp.m14
this.m11 -= this.m41 * buf
this.m12 -= this.m42 * buf
this.m13 -= this.m43 * buf
this.m14 -= this.m44 * buf
buf = temp.m24
this.m21 -= this.m41 * buf
this.m22 -= this.m42 * buf
this.m23 -= this.m43 * buf
this.m24 -= this.m44 * buf
buf = temp.m34
this.m31 -= this.m41 * buf
this.m32 -= this.m42 * buf
this.m33 -= this.m43 * buf
this.m34 -= this.m44 * buf
}
/**
* transpose matrix
* @access public
* @param {Matrix} src -
* @returns {void}
*/
transposeMatrix(src) {
this.m11 = src.m11
this.m12 = src.m21
this.m13 = src.m31
this.m14 = src.m41
this.m21 = src.m12
this.m22 = src.m22
this.m23 = src.m32
this.m24 = src.m42
this.m31 = src.m13
this.m32 = src.m23
this.m33 = src.m33
this.m34 = src.m43
this.m41 = src.m14
this.m42 = src.m24
this.m43 = src.m34
this.m44 = src.m44
}
/**
* scale matrix
* @access public
* @param {Matrix} mat -
* @param {float} x -
* @param {float} y -
* @param {float} z -
* @returns {void}
*/
scale(mat, x, y, z) {
const r = new Matrix()
r.identity()
if(!(mat instanceof Object) && z === undefined){
r.m11 = mat
r.m22 = x
r.m33 = y
this.multiplyMatrix(this, r)
}else{
r.m11 = x
r.m22 = y
r.m33 = z
this.multiplyMatrix(mat, r)
}
}
/**
* translate matrix
* @access public
* @param {Matrix} mat -
* @param {float} x -
* @param {float} y -
* @param {float} z -
* @returns {void}
*/
translate(mat, x, y, z) {
const r = new Matrix()
r.identity()
r.m14 = x
r.m24 = y
r.m34 = z
this.multiplyMatrix(mat, r)
}
/**
* rotate matrix
* @access public
* @param {Matrix} mat -
* @param {float} angle -
* @param {float} x -
* @param {float} y -
* @param {float} z -
* @returns {void}
*/
rotate(mat, angle, x, y, z) {
const c = Math.cos(angle)
const s = Math.sin(angle)
const v = new Vector3(x, y, z)
const r = new Matrix()
v.normalize()
const nx = v.x
const ny = v.y
const nz = v.z
r.m11 = nx * nx * (1.0-c) + c
r.m12 = nx * ny * (1.0-c) - nz * s
r.m13 = nx * nz * (1.0-c) + ny * s
r.m14 = 0.0
r.m21 = ny * nx * (1.0-c) + nz * s
r.m22 = ny * ny * (1.0-c) + c
r.m23 = ny * nz * (1.0-c) - nx * s
r.m24 = 0.0
r.m31 = nz * nx * (1.0-c) - ny * s
r.m32 = nz * ny * (1.0-c) + nx * s
r.m33 = nz * nz * (1.0-c) + c
r.m34 = 0.0
r.m41 = 0.0
r.m42 = 0.0
r.m43 = 0.0
r.m44 = 1.0
this.multiplyMatrix(mat, r)
}
/**
* get Float32Array format value of matrix for WebGL
* @access public
* @returns {Float32Array} matrix value
*/
getWebGLFloatArray() {
return new Float32Array([
this.m11, this.m12, this.m13, this.m14,
this.m21, this.m22, this.m23, this.m24,
this.m31, this.m32, this.m33, this.m34,
this.m41, this.m42, this.m43, this.m44
])
}
/**
* get Float32Array format value of transposed matrix for WebGL
* @access public
* @returns {Float32Array} transposed matrix value
*/
getWebGLFloatArrayTransposed() {
return new Float32Array([
this.m11, this.m21, this.m31, this.m41,
this.m12, this.m22, this.m32, this.m42,
this.m13, this.m23, this.m33, this.m43,
this.m14, this.m24, this.m34, this.m44
])
}
/**
* get array format value of matrix for WebGL
* @access public
* @returns {array} matrix value
*/
getArray() {
return [
this.m11, this.m12, this.m13, this.m14,
this.m21, this.m22, this.m23, this.m24,
this.m31, this.m32, this.m33, this.m34,
this.m41, this.m42, this.m43, this.m44
]
}
/**
* show matrix value to console for debug
* @access public
* @returns {void}
*/
showMatrix() {
/*
console.log('matrix:<br />\n'
+ this.m11 + ' ' + this.m12 + ' ' + this.m13 + ' ' + this.m14 + '<br />\n'
+ this.m21 + ' ' + this.m22 + ' ' + this.m23 + ' ' + this.m24 + '<br />\n'
+ this.m31 + ' ' + this.m32 + ' ' + this.m33 + ' ' + this.m34 + '<br />\n'
+ this.m41 + ' ' + this.m42 + ' ' + this.m43 + ' ' + this.m44 + '<br />\n'
)
*/
}
}