From b0a1575c35a5eadc18aaa1ce2ed7a27da4cf0694 Mon Sep 17 00:00:00 2001 From: pissang Date: Sun, 24 Apr 2022 16:48:03 +0800 Subject: [PATCH] wip(type): add types to vector and matrix --- src/glmatrix/mat2.ts | 2 +- src/math/Matrix2.ts | 311 ++++------ src/math/Matrix2d.ts | 293 ++++----- src/math/Matrix3.ts | 444 ++++++-------- src/math/Matrix4.ts | 909 ++++++++++++---------------- src/math/Quaternion.ts | 996 +++++++++++++----------------- src/math/Vector2.ts | 812 +++++++++++-------------- src/math/Vector3.ts | 1310 ++++++++++++++++++---------------------- src/math/Vector4.ts | 893 ++++++++++++--------------- src/math/util.ts | 34 +- 10 files changed, 2587 insertions(+), 3417 deletions(-) diff --git a/src/glmatrix/mat2.ts b/src/glmatrix/mat2.ts index 80e5c539..807b4567 100644 --- a/src/glmatrix/mat2.ts +++ b/src/glmatrix/mat2.ts @@ -26,7 +26,7 @@ import { Mat2Array, Vec2Array } from './common'; -export type { Vec2Array }; +export type { Mat2Array }; /** * Creates a new identity mat2 * diff --git a/src/math/Matrix2.ts b/src/math/Matrix2.ts index 0bd2dffd..93837c86 100644 --- a/src/math/Matrix2.ts +++ b/src/math/Matrix2.ts @@ -1,286 +1,227 @@ -// @ts-nocheck -import mat2 from '../glmatrix/mat2'; +import * as mat2 from '../glmatrix/mat2'; +import { matrixOrVectorClassToString } from './util'; +import type Vector2 from './Vector2'; -/** - * @constructor - * @alias clay.Matrix2 - */ -const Matrix2 = function () { +class Matrix2 { /** * Storage of Matrix2 - * @name array - * @type {Float32Array} - * @memberOf clay.Matrix2# */ - this.array = mat2.create(); - - /** - * @name _dirty - * @type {boolean} - * @memberOf clay.Matrix2# - */ - this._dirty = true; -}; - -Matrix2.prototype = { - constructor: Matrix2, + array = mat2.create(); + constructor() {} /** * Set components from array - * @param {Float32Array|number[]} arr + * @param arr */ - setArray: function (arr) { + setArray(arr: mat2.Mat2Array) { for (let i = 0; i < this.array.length; i++) { this.array[i] = arr[i]; } - this._dirty = true; return this; - }, + } /** * Clone a new Matrix2 - * @return {clay.Matrix2} */ - clone: function () { + clone() { return new Matrix2().copy(this); - }, + } /** * Copy from b - * @param {clay.Matrix2} b - * @return {clay.Matrix2} + * @param b */ - copy: function (b) { + copy(b: Matrix2) { mat2.copy(this.array, b.array); - this._dirty = true; return this; - }, + } /** * Calculate the adjugate of self, in-place - * @return {clay.Matrix2} */ - adjoint: function () { + adjoint() { mat2.adjoint(this.array, this.array); - this._dirty = true; return this; - }, + } /** * Calculate matrix determinant - * @return {number} */ - determinant: function () { + determinant() { return mat2.determinant(this.array); - }, + } /** * Set to a identity matrix - * @return {clay.Matrix2} */ - identity: function () { + identity() { mat2.identity(this.array); - this._dirty = true; return this; - }, + } /** * Invert self - * @return {clay.Matrix2} */ - invert: function () { + invert() { mat2.invert(this.array, this.array); - this._dirty = true; return this; - }, + } /** * Alias for mutiply - * @param {clay.Matrix2} b - * @return {clay.Matrix2} + * @param b */ - mul: function (b) { + mul(b: Matrix2) { mat2.mul(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Alias for multiplyLeft - * @param {clay.Matrix2} a - * @return {clay.Matrix2} + * @param a */ - mulLeft: function (a) { + mulLeft(a: Matrix2) { mat2.mul(this.array, a.array, this.array); - this._dirty = true; return this; - }, + } /** * Multiply self and b - * @param {clay.Matrix2} b - * @return {clay.Matrix2} + * @param b */ - multiply: function (b) { + multiply(b: Matrix2) { mat2.multiply(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Multiply a and self, a is on the left - * @param {clay.Matrix2} a - * @return {clay.Matrix2} + * @param a */ - multiplyLeft: function (a) { + multiplyLeft(a: Matrix2) { mat2.multiply(this.array, a.array, this.array); - this._dirty = true; return this; - }, + } /** * Rotate self by a given radian - * @param {number} rad - * @return {clay.Matrix2} + * @param {number} rad */ - rotate: function (rad) { + rotate(rad: number) { mat2.rotate(this.array, this.array, rad); - this._dirty = true; return this; - }, + } /** * Scale self by s - * @param {clay.Vector2} s - * @return {clay.Matrix2} + * @param s */ - scale: function (v) { + scale(v: Vector2) { mat2.scale(this.array, this.array, v.array); - this._dirty = true; return this; - }, + } /** * Transpose self, in-place. - * @return {clay.Matrix2} */ - transpose: function () { + transpose() { mat2.transpose(this.array, this.array); - this._dirty = true; return this; - }, + } - toString: function () { - return '[' + Array.prototype.join.call(this.array, ',') + ']'; - }, + toString() { + return matrixOrVectorClassToString(this, 2); + } - toArray: function () { + toArray() { return Array.prototype.slice.call(this.array); } -}; -/** - * @param {Matrix2} out - * @param {Matrix2} a - * @return {Matrix2} - */ -Matrix2.adjoint = function (out, a) { - mat2.adjoint(out.array, a.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + */ + static adjoint(out: Matrix2, a: Matrix2) { + mat2.adjoint(out.array, a.array); + return out; + } -/** - * @param {clay.Matrix2} out - * @param {clay.Matrix2} a - * @return {clay.Matrix2} - */ -Matrix2.copy = function (out, a) { - mat2.copy(out.array, a.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + */ + static copy(out: Matrix2, a: Matrix2) { + mat2.copy(out.array, a.array); + return out; + } -/** - * @param {clay.Matrix2} a - * @return {number} - */ -Matrix2.determinant = function (a) { - return mat2.determinant(a.array); -}; + /** + * @param a + */ + static determinant(a: Matrix2) { + return mat2.determinant(a.array); + } -/** - * @param {clay.Matrix2} out - * @return {clay.Matrix2} - */ -Matrix2.identity = function (out) { - mat2.identity(out.array); - out._dirty = true; - return out; -}; + /** + * @param out + */ + static identity(out: Matrix2) { + mat2.identity(out.array); + return out; + } -/** - * @param {clay.Matrix2} out - * @param {clay.Matrix2} a - * @return {clay.Matrix2} - */ -Matrix2.invert = function (out, a) { - mat2.invert(out.array, a.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + */ + static invert(out: Matrix2, a: Matrix2) { + mat2.invert(out.array, a.array); + return out; + } -/** - * @param {clay.Matrix2} out - * @param {clay.Matrix2} a - * @param {clay.Matrix2} b - * @return {clay.Matrix2} - */ -Matrix2.mul = function (out, a, b) { - mat2.mul(out.array, a.array, b.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + * @param b + */ + static mul(out: Matrix2, a: Matrix2, b: Matrix2) { + mat2.mul(out.array, a.array, b.array); + return out; + } -/** - * @function - * @param {clay.Matrix2} out - * @param {clay.Matrix2} a - * @param {clay.Matrix2} b - * @return {clay.Matrix2} - */ -Matrix2.multiply = Matrix2.mul; + /** + * @function + * @param out + * @param a + * @param b + */ + static multiply = Matrix2.mul; -/** - * @param {clay.Matrix2} out - * @param {clay.Matrix2} a - * @param {number} rad - * @return {clay.Matrix2} - */ -Matrix2.rotate = function (out, a, rad) { - mat2.rotate(out.array, a.array, rad); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + * @param {number} rad + */ + static rotate(out: Matrix2, a: Matrix2, rad: number) { + mat2.rotate(out.array, a.array, rad); + return out; + } -/** - * @param {clay.Matrix2} out - * @param {clay.Matrix2} a - * @param {clay.Vector2} v - * @return {clay.Matrix2} - */ -Matrix2.scale = function (out, a, v) { - mat2.scale(out.array, a.array, v.array); - out._dirty = true; - return out; -}; -/** - * @param {Matrix2} out - * @param {Matrix2} a - * @return {Matrix2} - */ -Matrix2.transpose = function (out, a) { - mat2.transpose(out.array, a.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + * @param v + */ + static scale(out: Matrix2, a: Matrix2, v: Vector2) { + mat2.scale(out.array, a.array, v.array); + return out; + } + /** + * @param out + * @param a + */ + static transpose(out: Matrix2, a: Matrix2) { + mat2.transpose(out.array, a.array); + return out; + } +} export default Matrix2; diff --git a/src/math/Matrix2d.ts b/src/math/Matrix2d.ts index a73886c0..6dc7d392 100644 --- a/src/math/Matrix2d.ts +++ b/src/math/Matrix2d.ts @@ -1,269 +1,210 @@ -// @ts-nocheck -import mat2d from '../glmatrix/mat2d'; +import * as mat2d from '../glmatrix/mat2d'; +import { matrixOrVectorClassToString } from './util'; +import type Vector2 from './Vector2'; -/** - * @constructor - * @alias clay.Matrix2d - */ -const Matrix2d = function () { - /** - * Storage of Matrix2d - * @name array - * @type {Float32Array} - * @memberOf clay.Matrix2d# - */ - this.array = mat2d.create(); - - /** - * @name _dirty - * @type {boolean} - * @memberOf clay.Matrix2d# - */ - this._dirty = true; -}; - -Matrix2d.prototype = { - constructor: Matrix2d, +class Matrix2d { + array = mat2d.create(); /** * Set components from array - * @param {Float32Array|number[]} arr + * @param arr */ - setArray: function (arr) { + setArray(arr: mat2d.Mat2dArray) { for (let i = 0; i < this.array.length; i++) { this.array[i] = arr[i]; } - this._dirty = true; return this; - }, + } /** * Clone a new Matrix2d - * @return {clay.Matrix2d} */ - clone: function () { + clone() { return new Matrix2d().copy(this); - }, + } /** * Copy from b - * @param {clay.Matrix2d} b - * @return {clay.Matrix2d} + * @param b */ - copy: function (b) { + copy(b: Matrix2d) { mat2d.copy(this.array, b.array); - this._dirty = true; return this; - }, + } /** * Calculate matrix determinant - * @return {number} */ - determinant: function () { + determinant() { return mat2d.determinant(this.array); - }, + } /** * Set to a identity matrix - * @return {clay.Matrix2d} */ - identity: function () { + identity() { mat2d.identity(this.array); - this._dirty = true; return this; - }, + } /** * Invert self - * @return {clay.Matrix2d} */ - invert: function () { + invert() { mat2d.invert(this.array, this.array); - this._dirty = true; return this; - }, + } /** * Alias for mutiply - * @param {clay.Matrix2d} b - * @return {clay.Matrix2d} + * @param b */ - mul: function (b) { + mul(b: Matrix2d) { mat2d.mul(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Alias for multiplyLeft - * @param {clay.Matrix2d} a - * @return {clay.Matrix2d} + * @param a */ - mulLeft: function (b) { + mulLeft(b: Matrix2d) { mat2d.mul(this.array, b.array, this.array); - this._dirty = true; return this; - }, + } /** * Multiply self and b - * @param {clay.Matrix2d} b - * @return {clay.Matrix2d} + * @param b */ - multiply: function (b) { + multiply(b: Matrix2d) { mat2d.multiply(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Multiply a and self, a is on the left - * @param {clay.Matrix2d} a - * @return {clay.Matrix2d} + * @param a */ - multiplyLeft: function (b) { + multiplyLeft(b: Matrix2d) { mat2d.multiply(this.array, b.array, this.array); - this._dirty = true; return this; - }, + } /** * Rotate self by a given radian - * @param {number} rad - * @return {clay.Matrix2d} + * @param {number} rad */ - rotate: function (rad) { + rotate(rad: number) { mat2d.rotate(this.array, this.array, rad); - this._dirty = true; return this; - }, + } /** * Scale self by s - * @param {clay.Vector2} s - * @return {clay.Matrix2d} + * @param {clay.Vector2} s */ - scale: function (s) { + scale(s: Vector2) { mat2d.scale(this.array, this.array, s.array); - this._dirty = true; return this; - }, + } /** * Translate self by v - * @param {clay.Vector2} v - * @return {clay.Matrix2d} + * @param {clay.Vector2} v */ - translate: function (v) { + translate(v: Vector2) { mat2d.translate(this.array, this.array, v.array); - this._dirty = true; return this; - }, + } - toString: function () { - return '[' + Array.prototype.join.call(this.array, ',') + ']'; - }, + toString() { + return matrixOrVectorClassToString(this, 3); + } - toArray: function () { + toArray() { return Array.prototype.slice.call(this.array); } -}; -/** - * @param {clay.Matrix2d} out - * @param {clay.Matrix2d} a - * @return {clay.Matrix2d} - */ -Matrix2d.copy = function (out, a) { - mat2d.copy(out.array, a.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + */ + static copy(out: Matrix2d, a: Matrix2d) { + mat2d.copy(out.array, a.array); + return out; + } -/** - * @param {clay.Matrix2d} a - * @return {number} - */ -Matrix2d.determinant = function (a) { - return mat2d.determinant(a.array); -}; + /** + * @param a + */ + static determinant(a: Matrix2d) { + return mat2d.determinant(a.array); + } -/** - * @param {clay.Matrix2d} out - * @return {clay.Matrix2d} - */ -Matrix2d.identity = function (out) { - mat2d.identity(out.array); - out._dirty = true; - return out; -}; + /** + * @param out + */ + static identity(out: Matrix2d) { + mat2d.identity(out.array); + return out; + } -/** - * @param {clay.Matrix2d} out - * @param {clay.Matrix2d} a - * @return {clay.Matrix2d} - */ -Matrix2d.invert = function (out, a) { - mat2d.invert(out.array, a.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + */ + static invert(out: Matrix2d, a: Matrix2d) { + mat2d.invert(out.array, a.array); + return out; + } -/** - * @param {clay.Matrix2d} out - * @param {clay.Matrix2d} a - * @param {clay.Matrix2d} b - * @return {clay.Matrix2d} - */ -Matrix2d.mul = function (out, a, b) { - mat2d.mul(out.array, a.array, b.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + * @param b + */ + static mul(out: Matrix2d, a: Matrix2d, b: Matrix2d) { + mat2d.mul(out.array, a.array, b.array); + return out; + } -/** - * @function - * @param {clay.Matrix2d} out - * @param {clay.Matrix2d} a - * @param {clay.Matrix2d} b - * @return {clay.Matrix2d} - */ -Matrix2d.multiply = Matrix2d.mul; + /** + * @function + * @param out + * @param a + * @param b + */ + static multiply = Matrix2d.mul; -/** - * @param {clay.Matrix2d} out - * @param {clay.Matrix2d} a - * @param {number} rad - * @return {clay.Matrix2d} - */ -Matrix2d.rotate = function (out, a, rad) { - mat2d.rotate(out.array, a.array, rad); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + * @param {number} rad + */ + static rotate(out: Matrix2d, a: Matrix2d, rad: number) { + mat2d.rotate(out.array, a.array, rad); + return out; + } -/** - * @param {clay.Matrix2d} out - * @param {clay.Matrix2d} a - * @param {clay.Vector2} v - * @return {clay.Matrix2d} - */ -Matrix2d.scale = function (out, a, v) { - mat2d.scale(out.array, a.array, v.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + * @param {clay.Vector2} v + */ + static scale(out: Matrix2d, a: Matrix2d, v: Vector2) { + mat2d.scale(out.array, a.array, v.array); + return out; + } -/** - * @param {clay.Matrix2d} out - * @param {clay.Matrix2d} a - * @param {clay.Vector2} v - * @return {clay.Matrix2d} - */ -Matrix2d.translate = function (out, a, v) { - mat2d.translate(out.array, a.array, v.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + * @param {clay.Vector2} v + */ + static translate(out: Matrix2d, a: Matrix2d, v: Vector2) { + mat2d.translate(out.array, a.array, v.array); + return out; + } +} export default Matrix2d; diff --git a/src/math/Matrix3.ts b/src/math/Matrix3.ts index 1f884d0d..c592b278 100644 --- a/src/math/Matrix3.ts +++ b/src/math/Matrix3.ts @@ -1,395 +1,321 @@ -// @ts-nocheck -import mat3 from '../glmatrix/mat3'; +import * as mat3 from '../glmatrix/mat3'; +import type Matrix2d from './Matrix2d'; +import type Matrix4 from './Matrix4'; +import type Quaternion from './Quaternion'; +import { matrixOrVectorClassToString } from './util'; +import type Vector2 from './Vector2'; -/** - * @constructor - * @alias clay.Matrix3 - */ -const Matrix3 = function () { +class Matrix3 { /** * Storage of Matrix3 - * @name array - * @type {Float32Array} - * @memberOf clay.Matrix3# */ - this.array = mat3.create(); - - /** - * @name _dirty - * @type {boolean} - * @memberOf clay.Matrix3# - */ - this._dirty = true; -}; - -Matrix3.prototype = { - constructor: Matrix3, + array = mat3.create(); + constructor() {} /** * Set components from array - * @param {Float32Array|number[]} arr */ - setArray: function (arr) { + setArray(arr: mat3.Mat3Array) { for (let i = 0; i < this.array.length; i++) { this.array[i] = arr[i]; } - this._dirty = true; return this; - }, + } /** * Calculate the adjugate of self, in-place - * @return {clay.Matrix3} */ - adjoint: function () { + adjoint() { mat3.adjoint(this.array, this.array); - this._dirty = true; return this; - }, + } /** * Clone a new Matrix3 - * @return {clay.Matrix3} */ - clone: function () { + clone() { return new Matrix3().copy(this); - }, + } /** * Copy from b - * @param {clay.Matrix3} b - * @return {clay.Matrix3} + * @param b */ - copy: function (b) { + copy(b: Matrix3) { mat3.copy(this.array, b.array); - this._dirty = true; return this; - }, + } /** * Calculate matrix determinant - * @return {number} */ - determinant: function () { + determinant() { return mat3.determinant(this.array); - }, + } /** * Copy the values from Matrix2d a - * @param {clay.Matrix2d} a - * @return {clay.Matrix3} + * @param a */ - fromMat2d: function (a) { + fromMat2d(a: Matrix2d) { mat3.fromMat2d(this.array, a.array); - this._dirty = true; return this; - }, + } /** * Copies the upper-left 3x3 values of Matrix4 - * @param {clay.Matrix4} a - * @return {clay.Matrix3} + * @param a */ - fromMat4: function (a) { + fromMat4(a: Matrix4) { mat3.fromMat4(this.array, a.array); - this._dirty = true; return this; - }, + } /** * Calculates a rotation matrix from the given quaternion - * @param {clay.Quaternion} q - * @return {clay.Matrix3} + * @param q */ - fromQuat: function (q) { + fromQuat(q: Quaternion) { mat3.fromQuat(this.array, q.array); - this._dirty = true; return this; - }, + } /** * Set to a identity matrix - * @return {clay.Matrix3} */ - identity: function () { + identity() { mat3.identity(this.array); - this._dirty = true; return this; - }, + } /** * Invert self - * @return {clay.Matrix3} */ - invert: function () { + invert() { mat3.invert(this.array, this.array); - this._dirty = true; return this; - }, + } /** * Alias for mutiply - * @param {clay.Matrix3} b - * @return {clay.Matrix3} + * @param b */ - mul: function (b) { + mul(b: Matrix3) { mat3.mul(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Alias for multiplyLeft - * @param {clay.Matrix3} a - * @return {clay.Matrix3} + * @param a */ - mulLeft: function (a) { + mulLeft(a: Matrix3) { mat3.mul(this.array, a.array, this.array); - this._dirty = true; return this; - }, + } /** * Multiply self and b - * @param {clay.Matrix3} b - * @return {clay.Matrix3} + * @param b */ - multiply: function (b) { + multiply(b: Matrix3) { mat3.multiply(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Multiply a and self, a is on the left - * @param {clay.Matrix3} a - * @return {clay.Matrix3} + * @param a */ - multiplyLeft: function (a) { + multiplyLeft(a: Matrix3) { mat3.multiply(this.array, a.array, this.array); - this._dirty = true; return this; - }, + } /** * Rotate self by a given radian - * @param {number} rad - * @return {clay.Matrix3} + * @param rad */ - rotate: function (rad) { + rotate(rad: number) { mat3.rotate(this.array, this.array, rad); - this._dirty = true; return this; - }, + } /** * Scale self by s - * @param {clay.Vector2} s - * @return {clay.Matrix3} + * @param v */ - scale: function (v) { + scale(v: Vector2) { mat3.scale(this.array, this.array, v.array); - this._dirty = true; return this; - }, + } /** * Translate self by v - * @param {clay.Vector2} v - * @return {clay.Matrix3} + * @param v */ - translate: function (v) { + translate(v: Vector2) { mat3.translate(this.array, this.array, v.array); - this._dirty = true; return this; - }, + } /** * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix - * @param {clay.Matrix4} a + * @param a */ - normalFromMat4: function (a) { + normalFromMat4(a: Matrix4) { mat3.normalFromMat4(this.array, a.array); - this._dirty = true; return this; - }, + } /** * Transpose self, in-place. - * @return {clay.Matrix2} */ - transpose: function () { + transpose() { mat3.transpose(this.array, this.array); - this._dirty = true; return this; - }, + } - toString: function () { - return '[' + Array.prototype.join.call(this.array, ',') + ']'; - }, + toString() { + return matrixOrVectorClassToString(this, 3); + } - toArray: function () { + toArray() { return Array.prototype.slice.call(this.array); } -}; -/** - * @param {clay.Matrix3} out - * @param {clay.Matrix3} a - * @return {clay.Matrix3} - */ -Matrix3.adjoint = function (out, a) { - mat3.adjoint(out.array, a.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.Matrix3} out - * @param {clay.Matrix3} a - * @return {clay.Matrix3} - */ -Matrix3.copy = function (out, a) { - mat3.copy(out.array, a.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + */ + static adjoint(out: Matrix3, a: Matrix3) { + mat3.adjoint(out.array, a.array); + return out; + } -/** - * @param {clay.Matrix3} a - * @return {number} - */ -Matrix3.determinant = function (a) { - return mat3.determinant(a.array); -}; + /** + * @param out + * @param a + */ + static copy(out: Matrix3, a: Matrix3) { + mat3.copy(out.array, a.array); + return out; + } -/** - * @param {clay.Matrix3} out - * @return {clay.Matrix3} - */ -Matrix3.identity = function (out) { - mat3.identity(out.array); - out._dirty = true; - return out; -}; + /** + * @param a + */ + static determinant(a: Matrix3) { + return mat3.determinant(a.array); + } -/** - * @param {clay.Matrix3} out - * @param {clay.Matrix3} a - * @return {clay.Matrix3} - */ -Matrix3.invert = function (out, a) { - mat3.invert(out.array, a.array); - return out; -}; + /** + * @param out + */ + static identity(out: Matrix3) { + mat3.identity(out.array); + return out; + } -/** - * @param {clay.Matrix3} out - * @param {clay.Matrix3} a - * @param {clay.Matrix3} b - * @return {clay.Matrix3} - */ -Matrix3.mul = function (out, a, b) { - mat3.mul(out.array, a.array, b.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + */ + static invert(out: Matrix3, a: Matrix3) { + mat3.invert(out.array, a.array); + return out; + } -/** - * @function - * @param {clay.Matrix3} out - * @param {clay.Matrix3} a - * @param {clay.Matrix3} b - * @return {clay.Matrix3} - */ -Matrix3.multiply = Matrix3.mul; + /** + * @param out + * @param a + * @param b + */ + static mul(out: Matrix3, a: Matrix3, b: Matrix3) { + mat3.mul(out.array, a.array, b.array); + return out; + } -/** - * @param {clay.Matrix3} out - * @param {clay.Matrix2d} a - * @return {clay.Matrix3} - */ -Matrix3.fromMat2d = function (out, a) { - mat3.fromMat2d(out.array, a.array); - out._dirty = true; - return out; -}; + /** + * @function + * @param out + * @param a + * @param b + */ + static multiply = Matrix3.mul; -/** - * @param {clay.Matrix3} out - * @param {clay.Matrix4} a - * @return {clay.Matrix3} - */ -Matrix3.fromMat4 = function (out, a) { - mat3.fromMat4(out.array, a.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + */ + static fromMat2d(out: Matrix3, a: Matrix2d) { + mat3.fromMat2d(out.array, a.array); + return out; + } -/** - * @param {clay.Matrix3} out - * @param {clay.Quaternion} a - * @return {clay.Matrix3} - */ -Matrix3.fromQuat = function (out, q) { - mat3.fromQuat(out.array, q.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + */ + static fromMat4(out: Matrix3, a: Matrix4) { + mat3.fromMat4(out.array, a.array); + return out; + } -/** - * @param {clay.Matrix3} out - * @param {clay.Matrix4} a - * @return {clay.Matrix3} - */ -Matrix3.normalFromMat4 = function (out, a) { - mat3.normalFromMat4(out.array, a.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + */ + static fromQuat(out: Matrix3, q: Quaternion) { + mat3.fromQuat(out.array, q.array); + return out; + } -/** - * @param {clay.Matrix3} out - * @param {clay.Matrix3} a - * @param {number} rad - * @return {clay.Matrix3} - */ -Matrix3.rotate = function (out, a, rad) { - mat3.rotate(out.array, a.array, rad); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + */ + static normalFromMat4(out: Matrix3, a: Matrix4) { + mat3.normalFromMat4(out.array, a.array); + return out; + } -/** - * @param {clay.Matrix3} out - * @param {clay.Matrix3} a - * @param {clay.Vector2} v - * @return {clay.Matrix3} - */ -Matrix3.scale = function (out, a, v) { - mat3.scale(out.array, a.array, v.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + * @param rad + */ + static rotate(out: Matrix3, a: Matrix3, rad: number) { + mat3.rotate(out.array, a.array, rad); + return out; + } -/** - * @param {clay.Matrix3} out - * @param {clay.Matrix3} a - * @return {clay.Matrix3} - */ -Matrix3.transpose = function (out, a) { - mat3.transpose(out.array, a.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + * @param v + */ + static scale(out: Matrix3, a: Matrix3, v: Vector2) { + mat3.scale(out.array, a.array, v.array); + return out; + } -/** - * @param {clay.Matrix3} out - * @param {clay.Matrix3} a - * @param {clay.Vector2} v - * @return {clay.Matrix3} - */ -Matrix3.translate = function (out, a, v) { - mat3.translate(out.array, a.array, v.array); - out._dirty = true; - return out; -}; + /** + * @param out + * @param a + */ + static transpose(out: Matrix3, a: Matrix3) { + mat3.transpose(out.array, a.array); + return out; + } + + /** + * @param out + * @param a + * @param v + */ + static translate(out: Matrix3, a: Matrix3, v: Vector2) { + mat3.translate(out.array, a.array, v.array); + return out; + } +} export default Matrix3; diff --git a/src/math/Matrix4.ts b/src/math/Matrix4.ts index 015ead0e..ad7266ce 100644 --- a/src/math/Matrix4.ts +++ b/src/math/Matrix4.ts @@ -1,400 +1,317 @@ -// @ts-nocheck -import mat4 from '../glmatrix/mat4'; -import vec3 from '../glmatrix/vec3'; -import quat from '../glmatrix/quat'; -import mat3 from '../glmatrix/mat3'; +import * as mat4 from '../glmatrix/mat4'; +import * as vec3 from '../glmatrix/vec3'; +import * as quat from '../glmatrix/quat'; +import * as mat3 from '../glmatrix/mat3'; +import { matrixOrVectorClassToString } from './util'; import Vector3 from './Vector3'; +import type Quaternion from './Quaternion'; +import Matrix2d from './Matrix2d'; -/** - * @constructor - * @alias clay.Matrix4 - */ -const Matrix4 = function () { - this._axisX = new Vector3(); - this._axisY = new Vector3(); - this._axisZ = new Vector3(); +const x = vec3.create(); +const y = vec3.create(); +const z = vec3.create(); - /** - * Storage of Matrix4 - * @name array - * @type {Float32Array} - * @memberOf clay.Matrix4# - */ - this.array = mat4.create(); +const m3 = mat3.create(); - /** - * @name _dirty - * @type {boolean} - * @memberOf clay.Matrix4# - */ - this._dirty = true; -}; +class Matrix4 { + private _axisX = new Vector3(); + private _axisY = new Vector3(); + private _axisZ = new Vector3(); -Matrix4.prototype = { - constructor: Matrix4, + array = mat4.create(); /** * Set components from array - * @param {Float32Array|number[]} arr + * @param arr */ - setArray: function (arr) { + setArray(arr: mat4.Mat4Array) { for (let i = 0; i < this.array.length; i++) { this.array[i] = arr[i]; } - this._dirty = true; return this; - }, + } /** * Calculate the adjugate of self, in-place - * @return {clay.Matrix4} */ - adjoint: function () { + adjoint() { mat4.adjoint(this.array, this.array); - this._dirty = true; return this; - }, + } /** * Clone a new Matrix4 - * @return {clay.Matrix4} */ - clone: function () { + clone() { return new Matrix4().copy(this); - }, + } /** * Copy from b - * @param {clay.Matrix4} b - * @return {clay.Matrix4} + * @param b */ - copy: function (a) { + copy(a: Matrix4) { mat4.copy(this.array, a.array); - this._dirty = true; return this; - }, + } /** * Calculate matrix determinant - * @return {number} */ - determinant: function () { + determinant() { return mat4.determinant(this.array); - }, + } /** * Set upper 3x3 part from quaternion - * @param {clay.Quaternion} q - * @return {clay.Matrix4} + * @param q */ - fromQuat: function (q) { + fromQuat(q: Quaternion) { mat4.fromQuat(this.array, q.array); - this._dirty = true; return this; - }, + } /** * Set from a quaternion rotation and a vector translation - * @param {clay.Quaternion} q - * @param {clay.Vector3} v - * @return {clay.Matrix4} + * @param q + * @param v */ - fromRotationTranslation: function (q, v) { + fromRotationTranslation(q: Quaternion, v: Vector3) { mat4.fromRotationTranslation(this.array, q.array, v.array); - this._dirty = true; return this; - }, + } /** * Set from Matrix2d, it is used when converting a 2d shape to 3d space. * In 3d space it is equivalent to ranslate on xy plane and rotate about z axis - * @param {clay.Matrix2d} m2d - * @return {clay.Matrix4} + * @param m2d */ - fromMat2d: function (m2d) { + fromMat2d(m2d: Matrix2d) { Matrix4.fromMat2d(this, m2d); return this; - }, + } /** * Set from frustum bounds - * @param {number} left - * @param {number} right - * @param {number} bottom - * @param {number} top - * @param {number} near - * @param {number} far - * @return {clay.Matrix4} + * @param left + * @param right + * @param bottom + * @param top + * @param near + * @param far */ - frustum: function (left, right, bottom, top, near, far) { + frustum(left: number, right: number, bottom: number, top: number, near: number, far: number) { mat4.frustum(this.array, left, right, bottom, top, near, far); - this._dirty = true; return this; - }, + } /** * Set to a identity matrix - * @return {clay.Matrix4} */ - identity: function () { + identity() { mat4.identity(this.array); - this._dirty = true; return this; - }, + } /** * Invert self - * @return {clay.Matrix4} */ - invert: function () { + invert() { mat4.invert(this.array, this.array); - this._dirty = true; return this; - }, + } /** * Set as a matrix with the given eye position, focal point, and up axis - * @param {clay.Vector3} eye - * @param {clay.Vector3} center - * @param {clay.Vector3} up - * @return {clay.Matrix4} + * @param eye + * @param center + * @param up */ - lookAt: function (eye, center, up) { + lookAt(eye: Vector3, center: Vector3, up: Vector3) { mat4.lookAt(this.array, eye.array, center.array, up.array); - this._dirty = true; return this; - }, + } /** * Alias for mutiply - * @param {clay.Matrix4} b - * @return {clay.Matrix4} + * @param b */ - mul: function (b) { + mul(b: Matrix4) { mat4.mul(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Alias for multiplyLeft - * @param {clay.Matrix4} a - * @return {clay.Matrix4} + * @param a */ - mulLeft: function (a) { + mulLeft(a: Matrix4) { mat4.mul(this.array, a.array, this.array); - this._dirty = true; return this; - }, + } /** * Multiply self and b - * @param {clay.Matrix4} b - * @return {clay.Matrix4} + * @param b */ - multiply: function (b) { + multiply(b: Matrix4) { mat4.multiply(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Multiply a and self, a is on the left - * @param {clay.Matrix3} a - * @return {clay.Matrix3} + * @param a */ - multiplyLeft: function (a) { + multiplyLeft(a: Matrix4) { mat4.multiply(this.array, a.array, this.array); - this._dirty = true; return this; - }, + } /** * Set as a orthographic projection matrix - * @param {number} left - * @param {number} right - * @param {number} bottom - * @param {number} top - * @param {number} near - * @param {number} far - * @return {clay.Matrix4} + * @param left + * @param right + * @param bottom + * @param top + * @param near + * @param far */ - ortho: function (left, right, bottom, top, near, far) { + ortho(left: number, right: number, bottom: number, top: number, near: number, far: number) { mat4.ortho(this.array, left, right, bottom, top, near, far); - this._dirty = true; return this; - }, + } /** * Set as a perspective projection matrix - * @param {number} fovy - * @param {number} aspect - * @param {number} near - * @param {number} far - * @return {clay.Matrix4} + * @param fovy + * @param aspect + * @param near + * @param far */ - perspective: function (fovy, aspect, near, far) { + perspective(fovy: number, aspect: number, near: number, far: number) { mat4.perspective(this.array, fovy, aspect, near, far); - this._dirty = true; return this; - }, + } /** * Rotate self by rad about axis. * Equal to right-multiply a rotaion matrix - * @param {number} rad - * @param {clay.Vector3} axis - * @return {clay.Matrix4} + * @param rad + * @param axis */ - rotate: function (rad, axis) { + rotate(rad: number, axis: Vector3) { mat4.rotate(this.array, this.array, rad, axis.array); - this._dirty = true; return this; - }, + } /** * Rotate self by a given radian about X axis. * Equal to right-multiply a rotaion matrix - * @param {number} rad - * @return {clay.Matrix4} + * @param rad */ - rotateX: function (rad) { + rotateX(rad: number) { mat4.rotateX(this.array, this.array, rad); - this._dirty = true; return this; - }, + } /** * Rotate self by a given radian about Y axis. * Equal to right-multiply a rotaion matrix - * @param {number} rad - * @return {clay.Matrix4} + * @param rad */ - rotateY: function (rad) { + rotateY(rad: number) { mat4.rotateY(this.array, this.array, rad); - this._dirty = true; return this; - }, + } /** * Rotate self by a given radian about Z axis. * Equal to right-multiply a rotaion matrix - * @param {number} rad - * @return {clay.Matrix4} + * @param rad */ - rotateZ: function (rad) { + rotateZ(rad: number) { mat4.rotateZ(this.array, this.array, rad); - this._dirty = true; return this; - }, + } /** * Scale self by s * Equal to right-multiply a scale matrix - * @param {clay.Vector3} s - * @return {clay.Matrix4} + * @param s */ - scale: function (v) { + scale(v: Vector3) { mat4.scale(this.array, this.array, v.array); - this._dirty = true; return this; - }, + } /** * Translate self by v. * Equal to right-multiply a translate matrix - * @param {clay.Vector3} v - * @return {clay.Matrix4} + * @param v */ - translate: function (v) { + translate(v: Vector3) { mat4.translate(this.array, this.array, v.array); - this._dirty = true; return this; - }, + } /** * Transpose self, in-place. - * @return {clay.Matrix2} */ - transpose: function () { + transpose() { mat4.transpose(this.array, this.array); - this._dirty = true; return this; - }, + } /** * Decompose a matrix to SRT - * @param {clay.Vector3} [scale] - * @param {clay.Quaternion} rotation - * @param {clay.Vector} position + * @param scale + * @param rotation + * @param position * @see http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.matrix.decompose.aspx */ - decomposeMatrix: (function () { - const x = vec3.create(); - const y = vec3.create(); - const z = vec3.create(); + decomposeMatrixfunction(scale: Vector3, rotation: Quaternion, position: Vector3) { + const el = this.array; + vec3.set(x, el[0], el[1], el[2]); + vec3.set(y, el[4], el[5], el[6]); + vec3.set(z, el[8], el[9], el[10]); - const m3 = mat3.create(); + let sx = vec3.length(x); + const sy = vec3.length(y); + const sz = vec3.length(z); - return function (scale, rotation, position) { - const el = this.array; - vec3.set(x, el[0], el[1], el[2]); - vec3.set(y, el[4], el[5], el[6]); - vec3.set(z, el[8], el[9], el[10]); + // if determine is negative, we need to invert one scale + const det = this.determinant(); + if (det < 0) { + sx = -sx; + } - let sx = vec3.length(x); - const sy = vec3.length(y); - const sz = vec3.length(z); + if (scale) { + scale.set(sx, sy, sz); + } - // if determine is negative, we need to invert one scale - const det = this.determinant(); - if (det < 0) { - sx = -sx; - } + position.set(el[12], el[13], el[14]); - if (scale) { - scale.set(sx, sy, sz); - } + mat3.fromMat4(m3, el); + // Not like mat4, mat3 in glmatrix seems to be row-based + // Seems fixed in gl-matrix 2.2.2 + // https://github.com/toji/gl-matrix/issues/114 + // mat3.transpose(m3, m3); - position.set(el[12], el[13], el[14]); + m3[0] /= sx; + m3[1] /= sx; + m3[2] /= sx; - mat3.fromMat4(m3, el); - // Not like mat4, mat3 in glmatrix seems to be row-based - // Seems fixed in gl-matrix 2.2.2 - // https://github.com/toji/gl-matrix/issues/114 - // mat3.transpose(m3, m3); + m3[3] /= sy; + m3[4] /= sy; + m3[5] /= sy; - m3[0] /= sx; - m3[1] /= sx; - m3[2] /= sx; + m3[6] /= sz; + m3[7] /= sz; + m3[8] /= sz; - m3[3] /= sy; - m3[4] /= sy; - m3[5] /= sy; - - m3[6] /= sz; - m3[7] /= sz; - m3[8] /= sz; - - quat.fromMat3(rotation.array, m3); - quat.normalize(rotation.array, rotation.array); - - rotation._dirty = true; - position._dirty = true; - }; - })(), - - toString: function () { - return '[' + Array.prototype.join.call(this.array, ',') + ']'; - }, - - toArray: function () { - return Array.prototype.slice.call(this.array); + quat.fromMat3(rotation.array, m3); + quat.normalize(rotation.array, rotation.array); } -}; -const defineProperty = Object.defineProperty; - -if (defineProperty) { - const proto = Matrix4.prototype; /** * Z Axis of local transform * @name z @@ -402,24 +319,20 @@ if (defineProperty) { * @memberOf clay.Matrix4 * @instance */ - defineProperty(proto, 'z', { - get: function () { - const el = this.array; - this._axisZ.set(el[8], el[9], el[10]); - return this._axisZ; - }, - set: function (v) { - // TODO Here has a problem - // If only set an item of vector will not work - const el = this.array; - v = v.array; - el[8] = v[0]; - el[9] = v[1]; - el[10] = v[2]; - - this._dirty = true; - } - }); + get z() { + const el = this.array; + this._axisZ.set(el[8], el[9], el[10]); + return this._axisZ; + } + set z(v: Vector3) { + // TODO Here has a problem + // If only set an item of vector will not work + const el = this.array; + const arr = v.array; + el[8] = arr[0]; + el[9] = arr[1]; + el[10] = arr[2]; + } /** * Y Axis of local transform @@ -428,22 +341,18 @@ if (defineProperty) { * @memberOf clay.Matrix4 * @instance */ - defineProperty(proto, 'y', { - get: function () { - const el = this.array; - this._axisY.set(el[4], el[5], el[6]); - return this._axisY; - }, - set: function (v) { - const el = this.array; - v = v.array; - el[4] = v[0]; - el[5] = v[1]; - el[6] = v[2]; - - this._dirty = true; - } - }); + get y() { + const el = this.array; + this._axisY.set(el[4], el[5], el[6]); + return this._axisY; + } + set y(v: Vector3) { + const el = this.array; + const arr = v.array; + el[4] = arr[0]; + el[5] = arr[1]; + el[6] = arr[2]; + } /** * X Axis of local transform @@ -452,265 +361,239 @@ if (defineProperty) { * @memberOf clay.Matrix4 * @instance */ - defineProperty(proto, 'x', { - get: function () { - const el = this.array; - this._axisX.set(el[0], el[1], el[2]); - return this._axisX; - }, - set: function (v) { - const el = this.array; - v = v.array; - el[0] = v[0]; - el[1] = v[1]; - el[2] = v[2]; + get x() { + const el = this.array; + this._axisX.set(el[0], el[1], el[2]); + return this._axisX; + } + set x(v: Vector3) { + const el = this.array; + const arr = v.array; + el[0] = arr[0]; + el[1] = arr[1]; + el[2] = arr[2]; + } - this._dirty = true; - } - }); + toString() { + return matrixOrVectorClassToString(this, 4); + } + + toArray() { + return Array.prototype.slice.call(this.array); + } + + /** + * @param out + * @param a + */ + static adjoint(out: Matrix4, a: Matrix4) { + mat4.adjoint(out.array, a.array); + return out; + } + + /** + * @param out + * @param a + */ + static copy(out: Matrix4, a: Matrix4) { + mat4.copy(out.array, a.array); + return out; + } + + /** + * @param a + */ + static determinant(a: Matrix4) { + return mat4.determinant(a.array); + } + + /** + * @param out + */ + static identity(out: Matrix4) { + mat4.identity(out.array); + return out; + } + + /** + * @param out + * @param left + * @param right + * @param bottom + * @param top + * @param near + * @param far + */ + static ortho( + out: Matrix4, + left: number, + right: number, + bottom: number, + top: number, + near: number, + far: number + ) { + mat4.ortho(out.array, left, right, bottom, top, near, far); + return out; + } + + /** + * @param out + * @param fovy + * @param aspect + * @param near + * @param far + */ + static perspective(out: Matrix4, fovy: number, aspect: number, near: number, far: number) { + mat4.perspective(out.array, fovy, aspect, near, far); + return out; + } + + /** + * @param out + * @param eye + * @param center + * @param up + */ + static lookAt(out: Matrix4, eye: Vector3, center: Vector3, up: Vector3) { + mat4.lookAt(out.array, eye.array, center.array, up.array); + return out; + } + + /** + * @param out + * @param a + */ + static invert(out: Matrix4, a: Matrix4) { + mat4.invert(out.array, a.array); + return out; + } + + /** + * @param out + * @param a + * @param b + */ + static mul(out: Matrix4, a: Matrix4, b: Matrix4) { + mat4.mul(out.array, a.array, b.array); + return out; + } + + /** + * @function + * @param out + * @param a + * @param b + */ + static multiply = Matrix4.mul; + + /** + * @param out + * @param q + */ + static fromQuat(out: Matrix4, q: Quaternion) { + mat4.fromQuat(out.array, q.array); + return out; + } + + /** + * @param out + * @param q + * @param v + */ + static fromRotationTranslation(out: Matrix4, q: Quaternion, v: Vector3) { + mat4.fromRotationTranslation(out.array, q.array, v.array); + return out; + } + + /** + * @param m4 + * @param m2d + */ + static fromMat2d(m4: Matrix4, m2d: Matrix2d) { + const m2da = m2d.array; + const m4a = m4.array; + + m4a[0] = m2da[0]; + m4a[4] = m2da[2]; + m4a[12] = m2da[4]; + + m4a[1] = m2da[1]; + m4a[5] = m2da[3]; + m4a[13] = m2da[5]; + + return m4; + } + + /** + * @param out + * @param a + * @param rad + * @param axis + */ + static rotate(out: Matrix4, a: Matrix4, rad: number, axis: Vector3) { + mat4.rotate(out.array, a.array, rad, axis.array); + return out; + } + + /** + * @param out + * @param a + * @param rad + */ + static rotateX(out: Matrix4, a: Matrix4, rad: number) { + mat4.rotateX(out.array, a.array, rad); + return out; + } + + /** + * @param out + * @param a + * @param rad + */ + static rotateY(out: Matrix4, a: Matrix4, rad: number) { + mat4.rotateY(out.array, a.array, rad); + return out; + } + + /** + * @param out + * @param a + * @param rad + */ + static rotateZ(out: Matrix4, a: Matrix4, rad: number) { + mat4.rotateZ(out.array, a.array, rad); + return out; + } + + /** + * @param out + * @param a + * @param v + */ + static scale(out: Matrix4, a: Matrix4, v: Vector3) { + mat4.scale(out.array, a.array, v.array); + return out; + } + + /** + * @param out + * @param a + */ + static transpose(out: Matrix4, a: Matrix4) { + mat4.transpose(out.array, a.array); + return out; + } + + /** + * @param out + * @param a + * @param v + */ + static translate(out: Matrix4, a: Matrix4, v: Vector3) { + mat4.translate(out.array, a.array, v.array); + return out; + } } -/** - * @param {clay.Matrix4} out - * @param {clay.Matrix4} a - * @return {clay.Matrix4} - */ -Matrix4.adjoint = function (out, a) { - mat4.adjoint(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Matrix4} out - * @param {clay.Matrix4} a - * @return {clay.Matrix4} - */ -Matrix4.copy = function (out, a) { - mat4.copy(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Matrix4} a - * @return {number} - */ -Matrix4.determinant = function (a) { - return mat4.determinant(a.array); -}; - -/** - * @param {clay.Matrix4} out - * @return {clay.Matrix4} - */ -Matrix4.identity = function (out) { - mat4.identity(out.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Matrix4} out - * @param {number} left - * @param {number} right - * @param {number} bottom - * @param {number} top - * @param {number} near - * @param {number} far - * @return {clay.Matrix4} - */ -Matrix4.ortho = function (out, left, right, bottom, top, near, far) { - mat4.ortho(out.array, left, right, bottom, top, near, far); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Matrix4} out - * @param {number} fovy - * @param {number} aspect - * @param {number} near - * @param {number} far - * @return {clay.Matrix4} - */ -Matrix4.perspective = function (out, fovy, aspect, near, far) { - mat4.perspective(out.array, fovy, aspect, near, far); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Matrix4} out - * @param {clay.Vector3} eye - * @param {clay.Vector3} center - * @param {clay.Vector3} up - * @return {clay.Matrix4} - */ -Matrix4.lookAt = function (out, eye, center, up) { - mat4.lookAt(out.array, eye.array, center.array, up.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Matrix4} out - * @param {clay.Matrix4} a - * @return {clay.Matrix4} - */ -Matrix4.invert = function (out, a) { - mat4.invert(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Matrix4} out - * @param {clay.Matrix4} a - * @param {clay.Matrix4} b - * @return {clay.Matrix4} - */ -Matrix4.mul = function (out, a, b) { - mat4.mul(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @function - * @param {clay.Matrix4} out - * @param {clay.Matrix4} a - * @param {clay.Matrix4} b - * @return {clay.Matrix4} - */ -Matrix4.multiply = Matrix4.mul; - -/** - * @param {clay.Matrix4} out - * @param {clay.Quaternion} q - * @return {clay.Matrix4} - */ -Matrix4.fromQuat = function (out, q) { - mat4.fromQuat(out.array, q.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Matrix4} out - * @param {clay.Quaternion} q - * @param {clay.Vector3} v - * @return {clay.Matrix4} - */ -Matrix4.fromRotationTranslation = function (out, q, v) { - mat4.fromRotationTranslation(out.array, q.array, v.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Matrix4} m4 - * @param {clay.Matrix2d} m2d - * @return {clay.Matrix4} - */ -Matrix4.fromMat2d = function (m4, m2d) { - m4._dirty = true; - m2d = m2d.array; - m4 = m4.array; - - m4[0] = m2d[0]; - m4[4] = m2d[2]; - m4[12] = m2d[4]; - - m4[1] = m2d[1]; - m4[5] = m2d[3]; - m4[13] = m2d[5]; - - return m4; -}; - -/** - * @param {clay.Matrix4} out - * @param {clay.Matrix4} a - * @param {number} rad - * @param {clay.Vector3} axis - * @return {clay.Matrix4} - */ -Matrix4.rotate = function (out, a, rad, axis) { - mat4.rotate(out.array, a.array, rad, axis.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Matrix4} out - * @param {clay.Matrix4} a - * @param {number} rad - * @return {clay.Matrix4} - */ -Matrix4.rotateX = function (out, a, rad) { - mat4.rotateX(out.array, a.array, rad); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Matrix4} out - * @param {clay.Matrix4} a - * @param {number} rad - * @return {clay.Matrix4} - */ -Matrix4.rotateY = function (out, a, rad) { - mat4.rotateY(out.array, a.array, rad); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Matrix4} out - * @param {clay.Matrix4} a - * @param {number} rad - * @return {clay.Matrix4} - */ -Matrix4.rotateZ = function (out, a, rad) { - mat4.rotateZ(out.array, a.array, rad); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Matrix4} out - * @param {clay.Matrix4} a - * @param {clay.Vector3} v - * @return {clay.Matrix4} - */ -Matrix4.scale = function (out, a, v) { - mat4.scale(out.array, a.array, v.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Matrix4} out - * @param {clay.Matrix4} a - * @return {clay.Matrix4} - */ -Matrix4.transpose = function (out, a) { - mat4.transpose(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Matrix4} out - * @param {clay.Matrix4} a - * @param {clay.Vector3} v - * @return {clay.Matrix4} - */ -Matrix4.translate = function (out, a, v) { - mat4.translate(out.array, a.array, v.array); - out._dirty = true; - return out; -}; - export default Matrix4; diff --git a/src/math/Quaternion.ts b/src/math/Quaternion.ts index c0aa58bd..c1045b17 100644 --- a/src/math/Quaternion.ts +++ b/src/math/Quaternion.ts @@ -1,771 +1,615 @@ -// @ts-nocheck -import quat from '../glmatrix/quat'; -import mat3 from '../glmatrix/mat3'; - -/** - * @constructor - * @alias clay.Quaternion - * @param {number} x - * @param {number} y - * @param {number} z - * @param {number} w - */ -const Quaternion = function (x, y, z, w) { - x = x || 0; - y = y || 0; - z = z || 0; - w = w === undefined ? 1 : w; +import * as quat from '../glmatrix/quat'; +import * as mat3 from '../glmatrix/mat3'; +import type Matrix3 from './Matrix3'; +import type Matrix4 from './Matrix4'; +import Vector3, { RotateOrder } from './Vector3'; +import { matrixOrVectorClassToString } from './util'; +const m3 = mat3.create(); +class Quaternion { /** * Storage of Quaternion, read and write of x, y, z, w will change the values in array * All methods also operate on the array instead of x, y, z, w components - * @name array - * @type {Float32Array} - * @memberOf clay.Quaternion# */ - this.array = quat.fromValues(x, y, z, w); + array: quat.QuatArray; + constructor(x: number, y: number, z: number, w?: number) { + x = x || 0; + y = y || 0; + z = z || 0; + w = w === undefined ? 1 : w; - /** - * Dirty flag is used by the Node to determine - * if the matrix is updated to latest - * @name _dirty - * @type {boolean} - * @memberOf clay.Quaternion# - */ - this._dirty = true; -}; + this.array = quat.fromValues(x, y, z, w); + } -Quaternion.prototype = { - constructor: Quaternion, + get x() { + return this.array[0]; + } + set x(value: number) { + this.array[0] = value; + } + + get y() { + return this.array[1]; + } + set y(value: number) { + this.array[1] = value; + } + + get z() { + return this.array[2]; + } + set z(value: number) { + this.array[2] = value; + } + + get w() { + return this.array[3]; + } + set w(value: number) { + this.array[3] = value; + } /** * Add b to self - * @param {clay.Quaternion} b - * @return {clay.Quaternion} + * @param b */ - add: function (b) { + add(b: Quaternion) { quat.add(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Calculate the w component from x, y, z component - * @return {clay.Quaternion} */ - calculateW: function () { + calculateW() { quat.calculateW(this.array, this.array); - this._dirty = true; return this; - }, + } /** * Set x, y and z components - * @param {number} x - * @param {number} y - * @param {number} z - * @param {number} w - * @return {clay.Quaternion} + * @param x + * @param y + * @param z + * @param w */ - set: function (x, y, z, w) { - this.array[0] = x; - this.array[1] = y; - this.array[2] = z; - this.array[3] = w; - this._dirty = true; + set(x: number, y: number, z: number, w: number) { + const arr = this.array; + arr[0] = x; + arr[1] = y; + arr[2] = z; + arr[3] = w; return this; - }, + } /** * Set x, y, z and w components from array - * @param {Float32Array|number[]} arr - * @return {clay.Quaternion} + * @param arr */ - setArray: function (arr) { - this.array[0] = arr[0]; - this.array[1] = arr[1]; - this.array[2] = arr[2]; - this.array[3] = arr[3]; + setArray(arr: quat.QuatArray) { + const thisArr = this.array; + thisArr[0] = arr[0]; + thisArr[1] = arr[1]; + thisArr[2] = arr[2]; + thisArr[3] = arr[3]; - this._dirty = true; return this; - }, + } /** * Clone a new Quaternion - * @return {clay.Quaternion} */ - clone: function () { + clone() { return new Quaternion(this.x, this.y, this.z, this.w); - }, + } /** * Calculates the conjugate of self If the quaternion is normalized, * this function is faster than invert and produces the same result. * - * @return {clay.Quaternion} */ - conjugate: function () { + conjugate() { quat.conjugate(this.array, this.array); - this._dirty = true; return this; - }, + } /** * Copy from b - * @param {clay.Quaternion} b - * @return {clay.Quaternion} + * @param b */ - copy: function (b) { + copy(b: Quaternion) { quat.copy(this.array, b.array); - this._dirty = true; return this; - }, + } /** * Dot product of self and b - * @param {clay.Quaternion} b - * @return {number} + * @param b */ - dot: function (b) { + dot(b: Quaternion) { return quat.dot(this.array, b.array); - }, + } /** * Set from the given 3x3 rotation matrix - * @param {clay.Matrix3} m - * @return {clay.Quaternion} + * @param m */ - fromMat3: function (m) { + fromMat3(m: Matrix3) { quat.fromMat3(this.array, m.array); - this._dirty = true; return this; - }, + } /** * Set from the given 4x4 rotation matrix * The 4th column and 4th row will be droped - * @param {clay.Matrix4} m - * @return {clay.Quaternion} + * @param m */ - fromMat4: (function () { - const m3 = mat3.create(); - return function (m) { - mat3.fromMat4(m3, m.array); - // TODO Not like mat4, mat3 in glmatrix seems to be row-based - mat3.transpose(m3, m3); - quat.fromMat3(this.array, m3); - this._dirty = true; - return this; - }; - })(), + fromMat4(m: Matrix4) { + mat3.fromMat4(m3, m.array); + // TODO Not like mat4, mat3 in glmatrix seems to be row-based + mat3.transpose(m3, m3); + quat.fromMat3(this.array, m3); + return this; + } /** * Set to identity quaternion - * @return {clay.Quaternion} */ - identity: function () { + identity() { quat.identity(this.array); - this._dirty = true; return this; - }, + } /** * Invert self - * @return {clay.Quaternion} */ - invert: function () { + invert() { quat.invert(this.array, this.array); - this._dirty = true; return this; - }, + } /** * Alias of length - * @return {number} */ - len: function () { + len() { return quat.len(this.array); - }, + } /** * Calculate the length - * @return {number} */ - length: function () { + length() { return quat.length(this.array); - }, + } /** * Linear interpolation between a and b - * @param {clay.Quaternion} a - * @param {clay.Quaternion} b - * @param {number} t - * @return {clay.Quaternion} + * @param a + * @param b + * @param t */ - lerp: function (a, b, t) { + lerp(a: Quaternion, b: Quaternion, t: number) { quat.lerp(this.array, a.array, b.array, t); - this._dirty = true; return this; - }, + } /** * Alias for multiply - * @param {clay.Quaternion} b - * @return {clay.Quaternion} + * @param b */ - mul: function (b) { + mul(b: Quaternion) { quat.mul(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Alias for multiplyLeft - * @param {clay.Quaternion} a - * @return {clay.Quaternion} + * @param a */ - mulLeft: function (a) { + mulLeft(a: Quaternion) { quat.multiply(this.array, a.array, this.array); - this._dirty = true; return this; - }, + } /** * Mutiply self and b - * @param {clay.Quaternion} b - * @return {clay.Quaternion} + * @param b */ - multiply: function (b) { + multiply(b: Quaternion) { quat.multiply(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Mutiply a and self * Quaternion mutiply is not commutative, so the result of mutiplyLeft is different with multiply. - * @param {clay.Quaternion} a - * @return {clay.Quaternion} + * @param a */ - multiplyLeft: function (a) { + multiplyLeft(a: Quaternion) { quat.multiply(this.array, a.array, this.array); - this._dirty = true; return this; - }, + } /** * Normalize self - * @return {clay.Quaternion} */ - normalize: function () { + normalize() { quat.normalize(this.array, this.array); - this._dirty = true; return this; - }, + } /** * Rotate self by a given radian about X axis - * @param {number} rad - * @return {clay.Quaternion} + * @param rad */ - rotateX: function (rad) { + rotateX(rad: number) { quat.rotateX(this.array, this.array, rad); - this._dirty = true; return this; - }, + } /** * Rotate self by a given radian about Y axis - * @param {number} rad - * @return {clay.Quaternion} + * @param rad */ - rotateY: function (rad) { + rotateY(rad: number) { quat.rotateY(this.array, this.array, rad); - this._dirty = true; return this; - }, + } /** * Rotate self by a given radian about Z axis - * @param {number} rad - * @return {clay.Quaternion} + * @param rad */ - rotateZ: function (rad) { + rotateZ(rad: number) { quat.rotateZ(this.array, this.array, rad); - this._dirty = true; return this; - }, + } /** * Sets self to represent the shortest rotation from Vector3 a to Vector3 b. * a and b needs to be normalized - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {clay.Quaternion} + * @param a + * @param b */ - rotationTo: function (a, b) { + rotationTo(a: Vector3, b: Vector3) { quat.rotationTo(this.array, a.array, b.array); - this._dirty = true; return this; - }, + } /** * Sets self with values corresponding to the given axes - * @param {clay.Vector3} view - * @param {clay.Vector3} right - * @param {clay.Vector3} up - * @return {clay.Quaternion} + * @param view + * @param right + * @param up */ - setAxes: function (view, right, up) { + setAxes(view: Vector3, right: Vector3, up: Vector3) { quat.setAxes(this.array, view.array, right.array, up.array); - this._dirty = true; return this; - }, + } /** * Sets self with a rotation axis and rotation angle - * @param {clay.Vector3} axis - * @param {number} rad - * @return {clay.Quaternion} + * @param axis + * @param rad */ - setAxisAngle: function (axis, rad) { + setAxisAngle(axis: Vector3, rad: number) { quat.setAxisAngle(this.array, axis.array, rad); - this._dirty = true; return this; - }, + } /** * Perform spherical linear interpolation between a and b - * @param {clay.Quaternion} a - * @param {clay.Quaternion} b - * @param {number} t - * @return {clay.Quaternion} + * @param a + * @param b + * @param t */ - slerp: function (a, b, t) { + slerp(a: Quaternion, b: Quaternion, t: number) { quat.slerp(this.array, a.array, b.array, t); - this._dirty = true; return this; - }, + } /** * Alias for squaredLength - * @return {number} */ - sqrLen: function () { + sqrLen() { return quat.sqrLen(this.array); - }, + } /** * Squared length of self - * @return {number} */ - squaredLength: function () { + squaredLength() { return quat.squaredLength(this.array); - }, + } /** * Set from euler - * @param {clay.Vector3} v - * @param {String} order + * @param v + * @param order */ - fromEuler: function (v, order) { + fromEuler(v: Vector3, order: RotateOrder) { return Quaternion.fromEuler(this, v, order); - }, + } - toString: function () { - return '[' + Array.prototype.join.call(this.array, ',') + ']'; - }, + toString() { + return matrixOrVectorClassToString(this, 4); + } - toArray: function () { + toArray() { return Array.prototype.slice.call(this.array); } -}; - -const defineProperty = Object.defineProperty; -// Getter and Setter -if (defineProperty) { - const proto = Quaternion.prototype; - /** - * @name x - * @type {number} - * @memberOf clay.Quaternion - * @instance - */ - defineProperty(proto, 'x', { - get: function () { - return this.array[0]; - }, - set: function (value) { - this.array[0] = value; - this._dirty = true; - } - }); /** - * @name y - * @type {number} - * @memberOf clay.Quaternion - * @instance + * @param out + * @param a + * @param b */ - defineProperty(proto, 'y', { - get: function () { - return this.array[1]; - }, - set: function (value) { - this.array[1] = value; - this._dirty = true; - } - }); + static add(out: Quaternion, a: Quaternion, b: Quaternion) { + quat.add(out.array, a.array, b.array); + return out; + } /** - * @name z - * @type {number} - * @memberOf clay.Quaternion - * @instance + * @param out + * @param x + * @param y + * @param z + * @param w */ - defineProperty(proto, 'z', { - get: function () { - return this.array[2]; - }, - set: function (value) { - this.array[2] = value; - this._dirty = true; - } - }); + static set(out: Quaternion, x: number, y: number, z: number, w: number) { + quat.set(out.array, x, y, z, w); + } /** - * @name w - * @type {number} - * @memberOf clay.Quaternion - * @instance + * @param out + * @param b */ - defineProperty(proto, 'w', { - get: function () { - return this.array[3]; - }, - set: function (value) { - this.array[3] = value; - this._dirty = true; + static copy(out: Quaternion, b: Quaternion) { + quat.copy(out.array, b.array); + return out; + } + + /** + * @param out + * @param a + */ + static calculateW(out: Quaternion, a: Quaternion) { + quat.calculateW(out.array, a.array); + return out; + } + + /** + * @param out + * @param a + */ + static conjugate(out: Quaternion, a: Quaternion) { + quat.conjugate(out.array, a.array); + return out; + } + + /** + * @param out + */ + static identity(out: Quaternion) { + quat.identity(out.array); + return out; + } + + /** + * @param out + * @param a + */ + static invert(out: Quaternion, a: Quaternion) { + quat.invert(out.array, a.array); + return out; + } + + /** + * @param a + * @param b + */ + static dot(a: Quaternion, b: Quaternion) { + return quat.dot(a.array, b.array); + } + + /** + * @param a + */ + static len(a: Quaternion) { + return quat.length(a.array); + } + + // Quaternion.length = Quaternion.len; + + /** + * @param out + * @param a + * @param b + * @param t + */ + static lerp(out: Quaternion, a: Quaternion, b: Quaternion, t: number) { + quat.lerp(out.array, a.array, b.array, t); + return out; + } + + /** + * @param out + * @param a + * @param b + * @param t + */ + static slerp(out: Quaternion, a: Quaternion, b: Quaternion, t: number) { + quat.slerp(out.array, a.array, b.array, t); + return out; + } + + /** + * @param out + * @param a + * @param b + */ + static mul(out: Quaternion, a: Quaternion, b: Quaternion) { + quat.multiply(out.array, a.array, b.array); + return out; + } + + /** + * @function + * @param out + * @param a + * @param b + */ + static multiply = Quaternion.mul; + + /** + * @param out + * @param a + * @param rad + */ + static rotateX(out: Quaternion, a: Quaternion, rad: number) { + quat.rotateX(out.array, a.array, rad); + return out; + } + + /** + * @param out + * @param a + * @param rad + */ + static rotateY(out: Quaternion, a: Quaternion, rad: number) { + quat.rotateY(out.array, a.array, rad); + return out; + } + + /** + * @param out + * @param a + * @param rad + */ + static rotateZ(out: Quaternion, a: Quaternion, rad: number) { + quat.rotateZ(out.array, a.array, rad); + return out; + } + + /** + * @param out + * @param axis + * @param rad + */ + static setAxisAngle(out: Quaternion, axis: Vector3, rad: number) { + quat.setAxisAngle(out.array, axis.array, rad); + return out; + } + + /** + * @param out + * @param a + */ + static normalize(out: Quaternion, a: Quaternion) { + quat.normalize(out.array, a.array); + return out; + } + + /** + * @param a + */ + static sqrLen(a: Quaternion) { + return quat.sqrLen(a.array); + } + + /** + * @function + * @param a + */ + static squaredLength = Quaternion.sqrLen; + + /** + * @param out + * @param m + */ + static fromMat3(out: Quaternion, m: Matrix3) { + quat.fromMat3(out.array, m.array); + return out; + } + + /** + * @param out + * @param view + * @param right + * @param up + */ + static setAxes(out: Quaternion, view: Vector3, right: Vector3, up: Vector3) { + quat.setAxes(out.array, view.array, right.array, up.array); + return out; + } + + /** + * @param out + * @param a + * @param b + */ + static rotationTo(out: Quaternion, a: Vector3, b: Vector3) { + quat.rotationTo(out.array, a.array, b.array); + return out; + } + + /** + * Set quaternion from euler + * @param out + * @param v + * @param order + */ + static fromEuler(out: Quaternion, v: Vector3, order: RotateOrder) { + const arr = v.array; + const target = out.array; + const c1 = Math.cos(arr[0] / 2); + const c2 = Math.cos(arr[1] / 2); + const c3 = Math.cos(arr[2] / 2); + const s1 = Math.sin(arr[0] / 2); + const s2 = Math.sin(arr[1] / 2); + const s3 = Math.sin(arr[2] / 2); + + order = (order || 'XYZ').toUpperCase() as RotateOrder; + + // http://www.mathworks.com/matlabcentral/fileexchange/ + // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ + // content/SpinCalc.m + + switch (order) { + case 'XYZ': + target[0] = s1 * c2 * c3 + c1 * s2 * s3; + target[1] = c1 * s2 * c3 - s1 * c2 * s3; + target[2] = c1 * c2 * s3 + s1 * s2 * c3; + target[3] = c1 * c2 * c3 - s1 * s2 * s3; + break; + case 'YXZ': + target[0] = s1 * c2 * c3 + c1 * s2 * s3; + target[1] = c1 * s2 * c3 - s1 * c2 * s3; + target[2] = c1 * c2 * s3 - s1 * s2 * c3; + target[3] = c1 * c2 * c3 + s1 * s2 * s3; + break; + case 'ZXY': + target[0] = s1 * c2 * c3 - c1 * s2 * s3; + target[1] = c1 * s2 * c3 + s1 * c2 * s3; + target[2] = c1 * c2 * s3 + s1 * s2 * c3; + target[3] = c1 * c2 * c3 - s1 * s2 * s3; + break; + case 'ZYX': + target[0] = s1 * c2 * c3 - c1 * s2 * s3; + target[1] = c1 * s2 * c3 + s1 * c2 * s3; + target[2] = c1 * c2 * s3 - s1 * s2 * c3; + target[3] = c1 * c2 * c3 + s1 * s2 * s3; + break; + case 'YZX': + target[0] = s1 * c2 * c3 + c1 * s2 * s3; + target[1] = c1 * s2 * c3 + s1 * c2 * s3; + target[2] = c1 * c2 * s3 - s1 * s2 * c3; + target[3] = c1 * c2 * c3 - s1 * s2 * s3; + break; + case 'XZY': + target[0] = s1 * c2 * c3 - c1 * s2 * s3; + target[1] = c1 * s2 * c3 - s1 * c2 * s3; + target[2] = c1 * c2 * s3 + s1 * s2 * c3; + target[3] = c1 * c2 * c3 + s1 * s2 * s3; + break; } - }); + } } -// Supply methods that are not in place - -/** - * @param {clay.Quaternion} out - * @param {clay.Quaternion} a - * @param {clay.Quaternion} b - * @return {clay.Quaternion} - */ -Quaternion.add = function (out, a, b) { - quat.add(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Quaternion} out - * @param {number} x - * @param {number} y - * @param {number} z - * @param {number} w - * @return {clay.Quaternion} - */ -Quaternion.set = function (out, x, y, z, w) { - quat.set(out.array, x, y, z, w); - out._dirty = true; -}; - -/** - * @param {clay.Quaternion} out - * @param {clay.Quaternion} b - * @return {clay.Quaternion} - */ -Quaternion.copy = function (out, b) { - quat.copy(out.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Quaternion} out - * @param {clay.Quaternion} a - * @return {clay.Quaternion} - */ -Quaternion.calculateW = function (out, a) { - quat.calculateW(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Quaternion} out - * @param {clay.Quaternion} a - * @return {clay.Quaternion} - */ -Quaternion.conjugate = function (out, a) { - quat.conjugate(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Quaternion} out - * @return {clay.Quaternion} - */ -Quaternion.identity = function (out) { - quat.identity(out.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Quaternion} out - * @param {clay.Quaternion} a - * @return {clay.Quaternion} - */ -Quaternion.invert = function (out, a) { - quat.invert(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Quaternion} a - * @param {clay.Quaternion} b - * @return {number} - */ -Quaternion.dot = function (a, b) { - return quat.dot(a.array, b.array); -}; - -/** - * @param {clay.Quaternion} a - * @return {number} - */ -Quaternion.len = function (a) { - return quat.length(a.array); -}; - -// Quaternion.length = Quaternion.len; - -/** - * @param {clay.Quaternion} out - * @param {clay.Quaternion} a - * @param {clay.Quaternion} b - * @param {number} t - * @return {clay.Quaternion} - */ -Quaternion.lerp = function (out, a, b, t) { - quat.lerp(out.array, a.array, b.array, t); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Quaternion} out - * @param {clay.Quaternion} a - * @param {clay.Quaternion} b - * @param {number} t - * @return {clay.Quaternion} - */ -Quaternion.slerp = function (out, a, b, t) { - quat.slerp(out.array, a.array, b.array, t); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Quaternion} out - * @param {clay.Quaternion} a - * @param {clay.Quaternion} b - * @return {clay.Quaternion} - */ -Quaternion.mul = function (out, a, b) { - quat.multiply(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @function - * @param {clay.Quaternion} out - * @param {clay.Quaternion} a - * @param {clay.Quaternion} b - * @return {clay.Quaternion} - */ -Quaternion.multiply = Quaternion.mul; - -/** - * @param {clay.Quaternion} out - * @param {clay.Quaternion} a - * @param {number} rad - * @return {clay.Quaternion} - */ -Quaternion.rotateX = function (out, a, rad) { - quat.rotateX(out.array, a.array, rad); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Quaternion} out - * @param {clay.Quaternion} a - * @param {number} rad - * @return {clay.Quaternion} - */ -Quaternion.rotateY = function (out, a, rad) { - quat.rotateY(out.array, a.array, rad); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Quaternion} out - * @param {clay.Quaternion} a - * @param {number} rad - * @return {clay.Quaternion} - */ -Quaternion.rotateZ = function (out, a, rad) { - quat.rotateZ(out.array, a.array, rad); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Quaternion} out - * @param {clay.Vector3} axis - * @param {number} rad - * @return {clay.Quaternion} - */ -Quaternion.setAxisAngle = function (out, axis, rad) { - quat.setAxisAngle(out.array, axis.array, rad); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Quaternion} out - * @param {clay.Quaternion} a - * @return {clay.Quaternion} - */ -Quaternion.normalize = function (out, a) { - quat.normalize(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Quaternion} a - * @return {number} - */ -Quaternion.sqrLen = function (a) { - return quat.sqrLen(a.array); -}; - -/** - * @function - * @param {clay.Quaternion} a - * @return {number} - */ -Quaternion.squaredLength = Quaternion.sqrLen; - -/** - * @param {clay.Quaternion} out - * @param {clay.Matrix3} m - * @return {clay.Quaternion} - */ -Quaternion.fromMat3 = function (out, m) { - quat.fromMat3(out.array, m.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Quaternion} out - * @param {clay.Vector3} view - * @param {clay.Vector3} right - * @param {clay.Vector3} up - * @return {clay.Quaternion} - */ -Quaternion.setAxes = function (out, view, right, up) { - quat.setAxes(out.array, view.array, right.array, up.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Quaternion} out - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {clay.Quaternion} - */ -Quaternion.rotationTo = function (out, a, b) { - quat.rotationTo(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * Set quaternion from euler - * @param {clay.Quaternion} out - * @param {clay.Vector3} v - * @param {String} order - */ -Quaternion.fromEuler = function (out, v, order) { - out._dirty = true; - - v = v.array; - const target = out.array; - const c1 = Math.cos(v[0] / 2); - const c2 = Math.cos(v[1] / 2); - const c3 = Math.cos(v[2] / 2); - const s1 = Math.sin(v[0] / 2); - const s2 = Math.sin(v[1] / 2); - const s3 = Math.sin(v[2] / 2); - - order = (order || 'XYZ').toUpperCase(); - - // http://www.mathworks.com/matlabcentral/fileexchange/ - // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ - // content/SpinCalc.m - - switch (order) { - case 'XYZ': - target[0] = s1 * c2 * c3 + c1 * s2 * s3; - target[1] = c1 * s2 * c3 - s1 * c2 * s3; - target[2] = c1 * c2 * s3 + s1 * s2 * c3; - target[3] = c1 * c2 * c3 - s1 * s2 * s3; - break; - case 'YXZ': - target[0] = s1 * c2 * c3 + c1 * s2 * s3; - target[1] = c1 * s2 * c3 - s1 * c2 * s3; - target[2] = c1 * c2 * s3 - s1 * s2 * c3; - target[3] = c1 * c2 * c3 + s1 * s2 * s3; - break; - case 'ZXY': - target[0] = s1 * c2 * c3 - c1 * s2 * s3; - target[1] = c1 * s2 * c3 + s1 * c2 * s3; - target[2] = c1 * c2 * s3 + s1 * s2 * c3; - target[3] = c1 * c2 * c3 - s1 * s2 * s3; - break; - case 'ZYX': - target[0] = s1 * c2 * c3 - c1 * s2 * s3; - target[1] = c1 * s2 * c3 + s1 * c2 * s3; - target[2] = c1 * c2 * s3 - s1 * s2 * c3; - target[3] = c1 * c2 * c3 + s1 * s2 * s3; - break; - case 'YZX': - target[0] = s1 * c2 * c3 + c1 * s2 * s3; - target[1] = c1 * s2 * c3 + s1 * c2 * s3; - target[2] = c1 * c2 * s3 - s1 * s2 * c3; - target[3] = c1 * c2 * c3 - s1 * s2 * s3; - break; - case 'XZY': - target[0] = s1 * c2 * c3 - c1 * s2 * s3; - target[1] = c1 * s2 * c3 - s1 * c2 * s3; - target[2] = c1 * c2 * s3 + s1 * s2 * c3; - target[3] = c1 * c2 * c3 + s1 * s2 * s3; - break; - } -}; - export default Quaternion; diff --git a/src/math/Vector2.ts b/src/math/Vector2.ts index efd015ea..c4a1fdcb 100644 --- a/src/math/Vector2.ts +++ b/src/math/Vector2.ts @@ -1,75 +1,77 @@ -import vec2 from '../glmatrix/vec2'; +import * as vec2 from '../glmatrix/vec2'; +import type Matrix2 from './Matrix2'; +import type Matrix2d from './Matrix2d'; +import type Matrix3 from './Matrix3'; +import type Matrix4 from './Matrix4'; +import { matrixOrVectorClassToString } from './util'; +import Vector3 from './Vector3'; /** * @constructor * @alias clay.Vector2 - * @param {number} x - * @param {number} y + * @param + * @param */ class Vector2 { - constructor(x, y) { + /** + * Storage of Vector2, read and write of x, y will change the values in array + * All methods also operate on the array instead of x, y components + */ + array: vec2.Vec2Array; + + constructor(x?: number, y?: number) { x = x || 0; y = y || 0; - /** - * Storage of Vector2, read and write of x, y will change the values in array - * All methods also operate on the array instead of x, y components - * @name array - * @type {Float32Array} - * @memberOf clay.Vector2# - */ this.array = vec2.fromValues(x, y); + } - /** - * Dirty flag is used by the Node to determine - * if the matrix is updated to latest - * @name _dirty - * @type {boolean} - * @memberOf clay.Vector2# - */ - this._dirty = true; + get x() { + return this.array[0]; + } + set x(value: number) { + this.array[0] = value; + } + + get y() { + return this.array[1]; + } + set y(value: number) { + this.array[1] = value; } /** * Add b to self - * @param {clay.Vector2} b - * @return {clay.Vector2} + * @param b */ - add(b) { + add(b: Vector2) { vec2.add(this.array, this.array, b.array); - this._dirty = true; return this; } /** * Set x and y components - * @param {number} x - * @param {number} y - * @return {clay.Vector2} + * @param x + * @param y */ - set(x, y) { + set(x: number, y: number) { this.array[0] = x; this.array[1] = y; - this._dirty = true; return this; } /** * Set x and y components from array - * @param {Float32Array|number[]} arr - * @return {clay.Vector2} + * @param arr */ - setArray(arr) { + setArray(arr: vec2.Vec2Array) { this.array[0] = arr[0]; this.array[1] = arr[1]; - - this._dirty = true; return this; } /** * Clone a new Vector2 - * @return {clay.Vector2} */ clone() { return new Vector2(this.x, this.y); @@ -77,87 +79,74 @@ class Vector2 { /** * Copy x, y from b - * @param {clay.Vector2} b - * @return {clay.Vector2} + * @param b */ - copy(b) { + copy(b: Vector2) { vec2.copy(this.array, b.array); - this._dirty = true; return this; } /** * Cross product of self and b, written to a Vector3 out - * @param {clay.Vector3} out - * @param {clay.Vector2} b - * @return {clay.Vector2} + * @param out + * @param b */ - cross(out, b) { + cross(out: Vector3, b: Vector2) { vec2.cross(out.array, this.array, b.array); - out._dirty = true; return this; } /** * Alias for distance - * @param {clay.Vector2} b - * @return {number} + * @param b {number} */ - dist(b) { + dist(b: Vector2) { return vec2.dist(this.array, b.array); } /** * Distance between self and b - * @param {clay.Vector2} b - * @return {number} + * @param b {number} */ - distance(b) { + distance(b: Vector2) { return vec2.distance(this.array, b.array); } /** * Alias for divide - * @param {clay.Vector2} b - * @return {clay.Vector2} + * @param b */ - div(b) { + div(b: Vector2) { vec2.div(this.array, this.array, b.array); - this._dirty = true; return this; } /** * Divide self by b - * @param {clay.Vector2} b - * @return {clay.Vector2} + * @param b */ - divide(b) { + divide(b: Vector2) { vec2.divide(this.array, this.array, b.array); - this._dirty = true; return this; } /** * Dot product of self and b - * @param {clay.Vector2} b - * @return {number} + * @param b {number} */ - dot(b) { + dot(b: Vector2) { return vec2.dot(this.array, b.array); } /** - * Alias of length - * @return {number} + * Alias of length {number} */ len() { return vec2.len(this.array); } /** - * Calculate the length - * @return {number} + * Calculate the length {number} */ length() { return vec2.length(this.array); @@ -165,144 +154,120 @@ class Vector2 { /** * Linear interpolation between a and b - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @param {number} t - * @return {clay.Vector2} + * @param a + * @param b + * @param t */ - lerp(a, b, t) { + lerp(a: Vector2, b: Vector2, t: number) { vec2.lerp(this.array, a.array, b.array, t); - this._dirty = true; return this; } /** * Minimum of self and b - * @param {clay.Vector2} b - * @return {clay.Vector2} + * @param b */ - min(b) { + min(b: Vector2) { vec2.min(this.array, this.array, b.array); - this._dirty = true; return this; } /** * Maximum of self and b - * @param {clay.Vector2} b - * @return {clay.Vector2} + * @param b */ - max(b) { + max(b: Vector2) { vec2.max(this.array, this.array, b.array); - this._dirty = true; return this; } /** * Alias for multiply - * @param {clay.Vector2} b - * @return {clay.Vector2} + * @param b */ - mul(b) { + mul(b: Vector2) { vec2.mul(this.array, this.array, b.array); - this._dirty = true; return this; } /** * Mutiply self and b - * @param {clay.Vector2} b - * @return {clay.Vector2} + * @param b */ - multiply(b) { + multiply(b: Vector2) { vec2.multiply(this.array, this.array, b.array); - this._dirty = true; return this; } /** * Negate self - * @return {clay.Vector2} */ negate() { vec2.negate(this.array, this.array); - this._dirty = true; return this; } /** * Normalize self - * @return {clay.Vector2} */ normalize() { vec2.normalize(this.array, this.array); - this._dirty = true; return this; } /** * Generate random x, y components with a given scale - * @param {number} scale - * @return {clay.Vector2} + * @param cale */ - random(scale) { + random(scale: number) { vec2.random(this.array, scale); - this._dirty = true; return this; } /** * Scale self - * @param {number} scale - * @return {clay.Vector2} + * @param scale */ - scale(s) { + scale(s: number) { vec2.scale(this.array, this.array, s); - this._dirty = true; return this; } /** * Scale b and add to self - * @param {clay.Vector2} b - * @param {number} scale - * @return {clay.Vector2} + * @param b + * @param scale */ - scaleAndAdd(b, s) { + scaleAndAdd(b: Vector2, s: number) { vec2.scaleAndAdd(this.array, this.array, b.array, s); - this._dirty = true; return this; } /** * Alias for squaredDistance - * @param {clay.Vector2} b - * @return {number} + * @param b {number} */ - sqrDist(b) { + sqrDist(b: Vector2) { return vec2.sqrDist(this.array, b.array); } /** * Squared distance between self and b - * @param {clay.Vector2} b - * @return {number} + * @param b {number} */ - squaredDistance(b) { + squaredDistance(b: Vector2) { return vec2.squaredDistance(this.array, b.array); } /** - * Alias for squaredLength - * @return {number} + * Alias for squaredLength {number} */ sqrLen() { return vec2.sqrLen(this.array); } /** - * Squared length of self - * @return {number} + * Squared length of self {number} */ squaredLength() { return vec2.squaredLength(this.array); @@ -310,415 +275,318 @@ class Vector2 { /** * Alias for subtract - * @param {clay.Vector2} b - * @return {clay.Vector2} + * @param b */ - sub(b) { + sub(b: Vector2) { vec2.sub(this.array, this.array, b.array); - this._dirty = true; return this; } /** * Subtract b from self - * @param {clay.Vector2} b - * @return {clay.Vector2} + * @param b */ - subtract(b) { + subtract(b: Vector2) { vec2.subtract(this.array, this.array, b.array); - this._dirty = true; return this; } /** * Transform self with a Matrix2 m - * @param {clay.Matrix2} m - * @return {clay.Vector2} + * @param m */ - transformMat2(m) { + transformMat2(m: Matrix2) { vec2.transformMat2(this.array, this.array, m.array); - this._dirty = true; return this; } /** * Transform self with a Matrix2d m - * @param {clay.Matrix2d} m - * @return {clay.Vector2} + * @param m */ - transformMat2d(m) { + transformMat2d(m: Matrix2d) { vec2.transformMat2d(this.array, this.array, m.array); - this._dirty = true; return this; } /** * Transform self with a Matrix3 m - * @param {clay.Matrix3} m - * @return {clay.Vector2} + * @param {clay.Matrix3} m */ - transformMat3(m) { + transformMat3(m: Matrix3) { vec2.transformMat3(this.array, this.array, m.array); - this._dirty = true; return this; } /** * Transform self with a Matrix4 m - * @param {clay.Matrix4} m - * @return {clay.Vector2} + * @param m */ - transformMat4(m) { + transformMat4(m: Matrix4) { vec2.transformMat4(this.array, this.array, m.array); - this._dirty = true; return this; } toString() { - return '[' + Array.prototype.join.call(this.array, ',') + ']'; + return matrixOrVectorClassToString(this, 2); } toArray() { return Array.prototype.slice.call(this.array); } -} -// Getter and Setter -if (Object.defineProperty) { - const proto = Vector2.prototype; - /** - * @name x - * @type {number} - * @memberOf clay.Vector2 - * @instance - */ - Object.defineProperty(proto, 'x', { - get: function () { - return this.array[0]; - }, - set: function (value) { - this.array[0] = value; - this._dirty = true; - } - }); + // Supply methods that are not in place /** - * @name y - * @type {number} - * @memberOf clay.Vector2 - * @instance + * @param out + * @param a + * @param b */ - Object.defineProperty(proto, 'y', { - get: function () { - return this.array[1]; - }, - set: function (value) { - this.array[1] = value; - this._dirty = true; - } - }); + static add(out: Vector2, a: Vector2, b: Vector2) { + vec2.add(out.array, a.array, b.array); + return out; + } + + /** + * @param out + * @param x + * @param y + */ + static set(out: Vector2, x: number, y: number) { + vec2.set(out.array, x, y); + return out; + } + + /** + * @param out + * @param b + */ + static copy(out: Vector2, b: Vector2) { + vec2.copy(out.array, b.array); + return out; + } + + /** + * @param out + * @param a + * @param b + */ + static cross(out: Vector3, a: Vector2, b: Vector2) { + vec2.cross(out.array, a.array, b.array); + return out; + } + /** + * @param a + * @param b {number} + */ + static dist(a: Vector2, b: Vector2) { + return vec2.distance(a.array, b.array); + } + /** + * @function + * @param a + * @param b {number} + */ + static distance = Vector2.dist; + /** + * @param out + * @param a + * @param b + */ + static div(out: Vector2, a: Vector2, b: Vector2) { + vec2.divide(out.array, a.array, b.array); + return out; + } + /** + * @function + * @param out + * @param a + * @param b + */ + static divide = Vector2.div; + /** + * @param a + * @param b {number} + */ + static dot(a: Vector2, b: Vector2) { + return vec2.dot(a.array, b.array); + } + + /** + * @param a {number} + */ + static len(b: Vector2) { + return vec2.length(b.array); + } + + // Vector2.length = Vector2.len; + + /** + * @param out + * @param a + * @param b + * @param t + */ + static lerp(out: Vector2, a: Vector2, b: Vector2, t: number) { + vec2.lerp(out.array, a.array, b.array, t); + return out; + } + /** + * @param out + * @param a + * @param b + */ + static min(out: Vector2, a: Vector2, b: Vector2) { + vec2.min(out.array, a.array, b.array); + return out; + } + + /** + * @param out + * @param a + * @param b + */ + static max(out: Vector2, a: Vector2, b: Vector2) { + vec2.max(out.array, a.array, b.array); + return out; + } + /** + * @param out + * @param a + * @param b + */ + static mul(out: Vector2, a: Vector2, b: Vector2) { + vec2.multiply(out.array, a.array, b.array); + return out; + } + /** + * @function + * @param out + * @param a + * @param b + */ + static multiply = Vector2.mul; + /** + * @param out + * @param a + */ + static negate(out: Vector2, a: Vector2) { + vec2.negate(out.array, a.array); + return out; + } + /** + * @param out + * @param a + */ + static normalize(out: Vector2, a: Vector2) { + vec2.normalize(out.array, a.array); + return out; + } + /** + * @param out + * @param scale + */ + static random(out: Vector2, scale: number) { + vec2.random(out.array, scale); + return out; + } + /** + * @param out + * @param a + * @param scale + */ + static scale(out: Vector2, a: Vector2, scale: number) { + vec2.scale(out.array, a.array, scale); + return out; + } + /** + * @param out + * @param a + * @param b + * @param scale + */ + static scaleAndAdd(out: Vector2, a: Vector2, b: Vector2, scale: number) { + vec2.scaleAndAdd(out.array, a.array, b.array, scale); + return out; + } + /** + * @param a + * @param b {number} + */ + static sqrDist(a: Vector2, b: Vector2) { + return vec2.sqrDist(a.array, b.array); + } + /** + * @function + * @param a + * @param b {number} + */ + static squaredDistance = Vector2.sqrDist; + + /** + * @param a {number} + */ + static sqrLen(a: Vector2) { + return vec2.sqrLen(a.array); + } + /** + * @function + * @param a + */ + static squaredLength = Vector2.sqrLen; + + /** + * @param out + * @param a + * @param b + */ + static sub(out: Vector2, a: Vector2, b: Vector2) { + vec2.subtract(out.array, a.array, b.array); + return out; + } + /** + * @function + * @param out + * @param a + * @param b + */ + static subtract = Vector2.sub; + /** + * @param out + * @param a + * @param m + */ + static transformMat2(out: Vector2, a: Vector2, m: Matrix2) { + vec2.transformMat2(out.array, a.array, m.array); + return out; + } + /** + * @param out + * @param a + * @param m + */ + static transformMat2d(out: Vector2, a: Vector2, m: Matrix2d) { + vec2.transformMat2d(out.array, a.array, m.array); + return out; + } + /** + * @param out + * @param a + * @param m + */ + static transformMat3(out: Vector2, a: Vector2, m: Matrix3) { + vec2.transformMat3(out.array, a.array, m.array); + return out; + } + /** + * @param out + * @param a + * @param m + */ + static transformMat4(out: Vector2, a: Vector2, m: Matrix4) { + vec2.transformMat4(out.array, a.array, m.array); + return out; + } } -// Supply methods that are not in place - -/** - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @return {clay.Vector2} - */ -Vector2.add = function (out, a, b) { - vec2.add(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector2} out - * @param {number} x - * @param {number} y - * @return {clay.Vector2} - */ -Vector2.set = function (out, x, y) { - vec2.set(out.array, x, y); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector2} out - * @param {clay.Vector2} b - * @return {clay.Vector2} - */ -Vector2.copy = function (out, b) { - vec2.copy(out.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector3} out - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @return {clay.Vector2} - */ -Vector2.cross = function (out, a, b) { - vec2.cross(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @return {number} - */ -Vector2.dist = function (a, b) { - return vec2.distance(a.array, b.array); -}; -/** - * @function - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @return {number} - */ -Vector2.distance = Vector2.dist; -/** - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @return {clay.Vector2} - */ -Vector2.div = function (out, a, b) { - vec2.divide(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @function - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @return {clay.Vector2} - */ -Vector2.divide = Vector2.div; -/** - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @return {number} - */ -Vector2.dot = function (a, b) { - return vec2.dot(a.array, b.array); -}; - -/** - * @param {clay.Vector2} a - * @return {number} - */ -Vector2.len = function (b) { - return vec2.length(b.array); -}; - -// Vector2.length = Vector2.len; - -/** - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @param {number} t - * @return {clay.Vector2} - */ -Vector2.lerp = function (out, a, b, t) { - vec2.lerp(out.array, a.array, b.array, t); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @return {clay.Vector2} - */ -Vector2.min = function (out, a, b) { - vec2.min(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @return {clay.Vector2} - */ -Vector2.max = function (out, a, b) { - vec2.max(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @return {clay.Vector2} - */ -Vector2.mul = function (out, a, b) { - vec2.multiply(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @function - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @return {clay.Vector2} - */ -Vector2.multiply = Vector2.mul; -/** - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @return {clay.Vector2} - */ -Vector2.negate = function (out, a) { - vec2.negate(out.array, a.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @return {clay.Vector2} - */ -Vector2.normalize = function (out, a) { - vec2.normalize(out.array, a.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector2} out - * @param {number} scale - * @return {clay.Vector2} - */ -Vector2.random = function (out, scale) { - vec2.random(out.array, scale); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @param {number} scale - * @return {clay.Vector2} - */ -Vector2.scale = function (out, a, scale) { - vec2.scale(out.array, a.array, scale); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @param {number} scale - * @return {clay.Vector2} - */ -Vector2.scaleAndAdd = function (out, a, b, scale) { - vec2.scaleAndAdd(out.array, a.array, b.array, scale); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @return {number} - */ -Vector2.sqrDist = function (a, b) { - return vec2.sqrDist(a.array, b.array); -}; -/** - * @function - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @return {number} - */ -Vector2.squaredDistance = Vector2.sqrDist; - -/** - * @param {clay.Vector2} a - * @return {number} - */ -Vector2.sqrLen = function (a) { - return vec2.sqrLen(a.array); -}; -/** - * @function - * @param {clay.Vector2} a - * @return {number} - */ -Vector2.squaredLength = Vector2.sqrLen; - -/** - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @return {clay.Vector2} - */ -Vector2.sub = function (out, a, b) { - vec2.subtract(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @function - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @param {clay.Vector2} b - * @return {clay.Vector2} - */ -Vector2.subtract = Vector2.sub; -/** - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @param {clay.Matrix2} m - * @return {clay.Vector2} - */ -Vector2.transformMat2 = function (out, a, m) { - vec2.transformMat2(out.array, a.array, m.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @param {clay.Matrix2d} m - * @return {clay.Vector2} - */ -Vector2.transformMat2d = function (out, a, m) { - vec2.transformMat2d(out.array, a.array, m.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @param {Matrix3} m - * @return {clay.Vector2} - */ -Vector2.transformMat3 = function (out, a, m) { - vec2.transformMat3(out.array, a.array, m.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector2} out - * @param {clay.Vector2} a - * @param {clay.Matrix4} m - * @return {clay.Vector2} - */ -Vector2.transformMat4 = function (out, a, m) { - vec2.transformMat4(out.array, a.array, m.array); - out._dirty = true; - return out; -}; - export default Vector2; diff --git a/src/math/Vector3.ts b/src/math/Vector3.ts index f061ad8a..51f1551d 100644 --- a/src/math/Vector3.ts +++ b/src/math/Vector3.ts @@ -1,6 +1,17 @@ -// @ts-nocheck -import vec3 from '../glmatrix/vec3'; +import * as vec3 from '../glmatrix/vec3'; +import type Matrix3 from './Matrix3'; +import type Matrix4 from './Matrix4'; +import type Quaternion from './Quaternion'; +import { matrixOrVectorClassToString } from './util'; +function clamp(val: number, min: number, max: number) { + return val < min ? min : val > max ? max : val; +} +const atan2 = Math.atan2; +const asin = Math.asin; +const abs = Math.abs; + +export type RotateOrder = 'XYZ' | 'YXZ' | 'ZXY' | 'ZYX' | 'YZX' | 'XZY'; /** * @constructor * @alias clay.Vector3 @@ -8,43 +19,49 @@ import vec3 from '../glmatrix/vec3'; * @param {number} y * @param {number} z */ -const Vector3 = function (x, y, z) { - x = x || 0; - y = y || 0; - z = z || 0; - +class Vector3 { /** * Storage of Vector3, read and write of x, y, z will change the values in array * All methods also operate on the array instead of x, y, z components - * @name array - * @type {Float32Array} - * @memberOf clay.Vector3# */ - this.array = vec3.fromValues(x, y, z); + array: vec3.Vec3Array; - /** - * Dirty flag is used by the Node to determine - * if the matrix is updated to latest - * @name _dirty - * @type {boolean} - * @memberOf clay.Vector3# - */ - this._dirty = true; -}; + constructor(x?: number, y?: number, z?: number) { + x = x || 0; + y = y || 0; + z = z || 0; + this.array = vec3.fromValues(x, y, z); + } -Vector3.prototype = { - constructor: Vector3, + get x() { + return this.array[0]; + } + set x(value: number) { + this.array[0] = value; + } + get y() { + return this.array[1]; + } + set y(value: number) { + this.array[1] = value; + } + + get z() { + return this.array[2]; + } + set z(value: number) { + this.array[2] = value; + } /** * Add b to self * @param {clay.Vector3} b * @return {clay.Vector3} */ - add: function (b) { + add(b: Vector3) { vec3.add(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Set x, y and z components @@ -53,46 +70,43 @@ Vector3.prototype = { * @param {number} z * @return {clay.Vector3} */ - set: function (x, y, z) { + set(x: number, y: number, z: number) { this.array[0] = x; this.array[1] = y; this.array[2] = z; - this._dirty = true; return this; - }, + } /** * Set x, y and z components from array * @param {Float32Array|number[]} arr * @return {clay.Vector3} */ - setArray: function (arr) { + setArray(arr: number[]) { this.array[0] = arr[0]; this.array[1] = arr[1]; this.array[2] = arr[2]; - this._dirty = true; return this; - }, + } /** * Clone a new Vector3 * @return {clay.Vector3} */ - clone: function () { + clone() { return new Vector3(this.x, this.y, this.z); - }, + } /** * Copy from b * @param {clay.Vector3} b * @return {clay.Vector3} */ - copy: function (b) { + copy(b: Vector3) { vec3.copy(this.array, b.array); - this._dirty = true; return this; - }, + } /** * Cross product of self and b, written to a Vector3 out @@ -100,76 +114,73 @@ Vector3.prototype = { * @param {clay.Vector3} b * @return {clay.Vector3} */ - cross: function (a, b) { + cross(a: Vector3, b: Vector3) { vec3.cross(this.array, a.array, b.array); - this._dirty = true; return this; - }, + } /** * Alias for distance * @param {clay.Vector3} b * @return {number} */ - dist: function (b) { + dist(b: Vector3) { return vec3.dist(this.array, b.array); - }, + } /** * Distance between self and b * @param {clay.Vector3} b * @return {number} */ - distance: function (b) { + distance(b: Vector3) { return vec3.distance(this.array, b.array); - }, + } /** * Alias for divide * @param {clay.Vector3} b * @return {clay.Vector3} */ - div: function (b) { + div(b: Vector3) { vec3.div(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Divide self by b * @param {clay.Vector3} b * @return {clay.Vector3} */ - divide: function (b) { + divide(b: Vector3) { vec3.divide(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Dot product of self and b * @param {clay.Vector3} b * @return {number} */ - dot: function (b) { + dot(b: Vector3) { return vec3.dot(this.array, b.array); - }, + } /** * Alias of length * @return {number} */ - len: function () { + len() { return vec3.len(this.array); - }, + } /** * Calculate the length * @return {number} */ - length: function () { + length() { return vec3.length(this.array); - }, + } /** * Linear interpolation between a and b * @param {clay.Vector3} a @@ -177,97 +188,88 @@ Vector3.prototype = { * @param {number} t * @return {clay.Vector3} */ - lerp: function (a, b, t) { + lerp(a: Vector3, b: Vector3, t: number) { vec3.lerp(this.array, a.array, b.array, t); - this._dirty = true; return this; - }, + } /** * Minimum of self and b * @param {clay.Vector3} b * @return {clay.Vector3} */ - min: function (b) { + min(b: Vector3) { vec3.min(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Maximum of self and b * @param {clay.Vector3} b * @return {clay.Vector3} */ - max: function (b) { + max(b: Vector3) { vec3.max(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Alias for multiply * @param {clay.Vector3} b * @return {clay.Vector3} */ - mul: function (b) { + mul(b: Vector3) { vec3.mul(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Mutiply self and b * @param {clay.Vector3} b * @return {clay.Vector3} */ - multiply: function (b) { + multiply(b: Vector3) { vec3.multiply(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Negate self * @return {clay.Vector3} */ - negate: function () { + negate() { vec3.negate(this.array, this.array); - this._dirty = true; return this; - }, + } /** * Normalize self * @return {clay.Vector3} */ - normalize: function () { + normalize() { vec3.normalize(this.array, this.array); - this._dirty = true; return this; - }, + } /** * Generate random x, y, z components with a given scale * @param {number} scale * @return {clay.Vector3} */ - random: function (scale) { + random(scale: number) { vec3.random(this.array, scale); - this._dirty = true; return this; - }, + } /** * Scale self * @param {number} scale * @return {clay.Vector3} */ - scale: function (s) { + scale(s: number) { vec3.scale(this.array, this.array, s); - this._dirty = true; return this; - }, + } /** * Scale b and add to self @@ -275,725 +277,619 @@ Vector3.prototype = { * @param {number} scale * @return {clay.Vector3} */ - scaleAndAdd: function (b, s) { + scaleAndAdd(b: Vector3, s: number) { vec3.scaleAndAdd(this.array, this.array, b.array, s); - this._dirty = true; return this; - }, + } /** * Alias for squaredDistance * @param {clay.Vector3} b * @return {number} */ - sqrDist: function (b) { + sqrDist(b: Vector3) { return vec3.sqrDist(this.array, b.array); - }, + } /** * Squared distance between self and b * @param {clay.Vector3} b * @return {number} */ - squaredDistance: function (b) { + squaredDistance(b: Vector3) { return vec3.squaredDistance(this.array, b.array); - }, + } /** * Alias for squaredLength * @return {number} */ - sqrLen: function () { + sqrLen() { return vec3.sqrLen(this.array); - }, + } /** * Squared length of self * @return {number} */ - squaredLength: function () { + squaredLength() { return vec3.squaredLength(this.array); - }, + } /** * Alias for subtract * @param {clay.Vector3} b * @return {clay.Vector3} */ - sub: function (b) { + sub(b: Vector3) { vec3.sub(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Subtract b from self * @param {clay.Vector3} b * @return {clay.Vector3} */ - subtract: function (b) { + subtract(b: Vector3) { vec3.subtract(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Transform self with a Matrix3 m * @param {clay.Matrix3} m * @return {clay.Vector3} */ - transformMat3: function (m) { + transformMat3(m: Matrix3) { vec3.transformMat3(this.array, this.array, m.array); - this._dirty = true; return this; - }, + } /** * Transform self with a Matrix4 m * @param {clay.Matrix4} m * @return {clay.Vector3} */ - transformMat4: function (m) { + transformMat4(m: Matrix4) { vec3.transformMat4(this.array, this.array, m.array); - this._dirty = true; return this; - }, + } /** * Transform self with a Quaternion q * @param {clay.Quaternion} q * @return {clay.Vector3} */ - transformQuat: function (q) { + transformQuat(q: Quaternion) { vec3.transformQuat(this.array, this.array, q.array); - this._dirty = true; return this; - }, + } /** * Trasnform self into projection space with m * @param {clay.Matrix4} m * @return {clay.Vector3} */ - applyProjection: function (m) { + applyProjection(m: Matrix4) { const v = this.array; - m = m.array; + const ma = m.array; // Perspective projection - if (m[15] === 0) { + if (ma[15] === 0) { const w = -1 / v[2]; - v[0] = m[0] * v[0] * w; - v[1] = m[5] * v[1] * w; - v[2] = (m[10] * v[2] + m[14]) * w; + v[0] = ma[0] * v[0] * w; + v[1] = ma[5] * v[1] * w; + v[2] = (ma[10] * v[2] + ma[14]) * w; } else { - v[0] = m[0] * v[0] + m[12]; - v[1] = m[5] * v[1] + m[13]; - v[2] = m[10] * v[2] + m[14]; + v[0] = ma[0] * v[0] + ma[12]; + v[1] = ma[5] * v[1] + ma[13]; + v[2] = ma[10] * v[2] + ma[14]; } - this._dirty = true; return this; - }, + } - eulerFromQuat: function (q, order) { - Vector3.eulerFromQuat(this, q, order); - }, + eulerFromQuat(q: Quaternion, order: RotateOrder) { + return Vector3.eulerFromQuat(this, q, order); + } - eulerFromMat3: function (m, order) { - Vector3.eulerFromMat3(this, m, order); - }, + eulerFromMat3(m: Matrix3, order: RotateOrder) { + return Vector3.eulerFromMat3(this, m, order); + } - toString: function () { - return '[' + Array.prototype.join.call(this.array, ',') + ']'; - }, + toString() { + return matrixOrVectorClassToString(this, 3); + } - toArray: function () { + toArray() { return Array.prototype.slice.call(this.array); } -}; - -const defineProperty = Object.defineProperty; -// Getter and Setter -if (defineProperty) { - const proto = Vector3.prototype; - /** - * @name x - * @type {number} - * @memberOf clay.Vector3 - * @instance - */ - defineProperty(proto, 'x', { - get: function () { - return this.array[0]; - }, - set: function (value) { - this.array[0] = value; - this._dirty = true; - } - }); /** - * @name y - * @type {number} - * @memberOf clay.Vector3 - * @instance + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} */ - defineProperty(proto, 'y', { - get: function () { - return this.array[1]; - }, - set: function (value) { - this.array[1] = value; - this._dirty = true; - } - }); + static add(out: Vector3, a: Vector3, b: Vector3) { + vec3.add(out.array, a.array, b.array); + return out; + } /** - * @name z - * @type {number} - * @memberOf clay.Vector3 - * @instance + * @param {clay.Vector3} out + * @param {number} x + * @param {number} y + * @param {number} z + * @return {clay.Vector3} */ - defineProperty(proto, 'z', { - get: function () { - return this.array[2]; - }, - set: function (value) { - this.array[2] = value; - this._dirty = true; + static set(out: Vector3, x: number, y: number, z: number) { + vec3.set(out.array, x, y, z); + } + + /** + * @param {clay.Vector3} out + * @param {clay.Vector3} b + * @return {clay.Vector3} + */ + static copy(out: Vector3, b: Vector3) { + vec3.copy(out.array, b.array); + return out; + } + + /** + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} + */ + static cross(out: Vector3, a: Vector3, b: Vector3) { + vec3.cross(out.array, a.array, b.array); + return out; + } + + /** + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {number} + */ + static dist(a: Vector3, b: Vector3) { + return vec3.distance(a.array, b.array); + } + + /** + * @function + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {number} + */ + static distance = Vector3.dist; + + /** + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} + */ + static div(out: Vector3, a: Vector3, b: Vector3) { + vec3.divide(out.array, a.array, b.array); + return out; + } + + /** + * @function + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} + */ + static divide = Vector3.div; + + /** + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {number} + */ + static dot(a: Vector3, b: Vector3) { + return vec3.dot(a.array, b.array); + } + + /** + * @param {clay.Vector3} a + * @return {number} + */ + static len(b: Vector3) { + return vec3.length(b.array); + } + + // Vector3.length = Vector3.len; + + /** + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @param {number} t + * @return {clay.Vector3} + */ + static lerp(out: Vector3, a: Vector3, b: Vector3, t: number) { + vec3.lerp(out.array, a.array, b.array, t); + return out; + } + /** + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} + */ + static min(out: Vector3, a: Vector3, b: Vector3) { + vec3.min(out.array, a.array, b.array); + return out; + } + + /** + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} + */ + static max(out: Vector3, a: Vector3, b: Vector3) { + vec3.max(out.array, a.array, b.array); + return out; + } + /** + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} + */ + static mul(out: Vector3, a: Vector3, b: Vector3) { + vec3.multiply(out.array, a.array, b.array); + return out; + } + /** + * @function + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} + */ + static multiply = Vector3.mul; + /** + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @return {clay.Vector3} + */ + static negate(out: Vector3, a: Vector3) { + vec3.negate(out.array, a.array); + return out; + } + /** + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @return {clay.Vector3} + */ + static normalize(out: Vector3, a: Vector3) { + vec3.normalize(out.array, a.array); + return out; + } + /** + * @param {clay.Vector3} out + * @param {number} scale + * @return {clay.Vector3} + */ + static random(out: Vector3, scale: number) { + vec3.random(out.array, scale); + return out; + } + /** + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {number} scale + * @return {clay.Vector3} + */ + static scale(out: Vector3, a: Vector3, scale: number) { + vec3.scale(out.array, a.array, scale); + return out; + } + /** + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @param {number} scale + * @return {clay.Vector3} + */ + static scaleAndAdd(out: Vector3, a: Vector3, b: Vector3, scale: number) { + vec3.scaleAndAdd(out.array, a.array, b.array, scale); + return out; + } + /** + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {number} + */ + static sqrDist(a: Vector3, b: Vector3) { + return vec3.sqrDist(a.array, b.array); + } + /** + * @function + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {number} + */ + static squaredDistance = Vector3.sqrDist; + /** + * @param {clay.Vector3} a + * @return {number} + */ + static sqrLen(a: Vector3) { + return vec3.sqrLen(a.array); + } + /** + * @function + * @param {clay.Vector3} a + * @return {number} + */ + static squaredLength = Vector3.sqrLen; + + /** + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} + */ + static sub(out: Vector3, a: Vector3, b: Vector3) { + vec3.subtract(out.array, a.array, b.array); + return out; + } + /** + * @function + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Vector3} b + * @return {clay.Vector3} + */ + static subtract = Vector3.sub; + + /** + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {Matrix3} m + * @return {clay.Vector3} + */ + static transformMat3(out: Vector3, a: Vector3, m: Matrix3) { + vec3.transformMat3(out.array, a.array, m.array); + return out; + } + + /** + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Matrix4} m + * @return {clay.Vector3} + */ + static transformMat4(out: Vector3, a: Vector3, m: Matrix4) { + vec3.transformMat4(out.array, a.array, m.array); + return out; + } + /** + * @param {clay.Vector3} out + * @param {clay.Vector3} a + * @param {clay.Quaternion} q + * @return {clay.Vector3} + */ + static transformQuat(out: Vector3, a: Vector3, q: Quaternion) { + vec3.transformQuat(out.array, a.array, q.array); + return out; + } + + /** + * Convert quaternion to euler angle + * Quaternion must be normalized + * From three.js + */ + static eulerFromQuat(out: Vector3, q: Quaternion, order: RotateOrder) { + const qa = q.array; + + const target = out.array; + const x = qa[0], + y = qa[1], + z = qa[2], + w = qa[3]; + const x2 = x * x; + const y2 = y * y; + const z2 = z * z; + const w2 = w * w; + + order = (order || 'XYZ').toUpperCase() as RotateOrder; + + switch (order) { + case 'XYZ': + target[0] = atan2(2 * (x * w - y * z), w2 - x2 - y2 + z2); + target[1] = asin(clamp(2 * (x * z + y * w), -1, 1)); + target[2] = atan2(2 * (z * w - x * y), w2 + x2 - y2 - z2); + break; + case 'YXZ': + target[0] = asin(clamp(2 * (x * w - y * z), -1, 1)); + target[1] = atan2(2 * (x * z + y * w), w2 - x2 - y2 + z2); + target[2] = atan2(2 * (x * y + z * w), w2 - x2 + y2 - z2); + break; + case 'ZXY': + target[0] = asin(clamp(2 * (x * w + y * z), -1, 1)); + target[1] = atan2(2 * (y * w - z * x), w2 - x2 - y2 + z2); + target[2] = atan2(2 * (z * w - x * y), w2 - x2 + y2 - z2); + break; + case 'ZYX': + target[0] = atan2(2 * (x * w + z * y), w2 - x2 - y2 + z2); + target[1] = asin(clamp(2 * (y * w - x * z), -1, 1)); + target[2] = atan2(2 * (x * y + z * w), w2 + x2 - y2 - z2); + break; + case 'YZX': + target[0] = atan2(2 * (x * w - z * y), w2 - x2 + y2 - z2); + target[1] = atan2(2 * (y * w - x * z), w2 + x2 - y2 - z2); + target[2] = asin(clamp(2 * (x * y + z * w), -1, 1)); + break; + case 'XZY': + target[0] = atan2(2 * (x * w + y * z), w2 - x2 + y2 - z2); + target[1] = atan2(2 * (x * z + y * w), w2 + x2 - y2 - z2); + target[2] = asin(clamp(2 * (z * w - x * y), -1, 1)); + break; + default: + console.warn('Unkown order: ' + order); } - }); + return out; + } + + /** + * Convert rotation matrix to euler angle + * from three.js + */ + static eulerFromMat3(out: Vector3, m: Matrix3, order: RotateOrder) { + // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) + const te = m.array; + const m11 = te[0], + m12 = te[3], + m13 = te[6]; + const m21 = te[1], + m22 = te[4], + m23 = te[7]; + const m31 = te[2], + m32 = te[5], + m33 = te[8]; + const target = out.array; + + order = (order || 'XYZ').toUpperCase() as RotateOrder; + + switch (order) { + case 'XYZ': + target[1] = asin(clamp(m13, -1, 1)); + if (abs(m13) < 0.99999) { + target[0] = atan2(-m23, m33); + target[2] = atan2(-m12, m11); + } else { + target[0] = atan2(m32, m22); + target[2] = 0; + } + break; + case 'YXZ': + target[0] = asin(-clamp(m23, -1, 1)); + if (abs(m23) < 0.99999) { + target[1] = atan2(m13, m33); + target[2] = atan2(m21, m22); + } else { + target[1] = atan2(-m31, m11); + target[2] = 0; + } + break; + case 'ZXY': + target[0] = asin(clamp(m32, -1, 1)); + if (abs(m32) < 0.99999) { + target[1] = atan2(-m31, m33); + target[2] = atan2(-m12, m22); + } else { + target[1] = 0; + target[2] = atan2(m21, m11); + } + break; + case 'ZYX': + target[1] = asin(-clamp(m31, -1, 1)); + if (abs(m31) < 0.99999) { + target[0] = atan2(m32, m33); + target[2] = atan2(m21, m11); + } else { + target[0] = 0; + target[2] = atan2(-m12, m22); + } + break; + case 'YZX': + target[2] = asin(clamp(m21, -1, 1)); + if (abs(m21) < 0.99999) { + target[0] = atan2(-m23, m22); + target[1] = atan2(-m31, m11); + } else { + target[0] = 0; + target[1] = atan2(m13, m33); + } + break; + case 'XZY': + target[2] = asin(-clamp(m12, -1, 1)); + if (abs(m12) < 0.99999) { + target[0] = atan2(m32, m22); + target[1] = atan2(m13, m11); + } else { + target[0] = atan2(-m23, m33); + target[1] = 0; + } + break; + default: + console.warn('Unkown order: ' + order); + } + + return out; + } + + /** + * @type {clay.Vector3} + * @readOnly + * @memberOf clay.Vector3 + */ + static get POSITIVE_X() { + return new Vector3(1, 0, 0); + } + /** + * @type {clay.Vector3} + * @readOnly + * @memberOf clay.Vector3 + */ + static get NEGATIVE_X() { + return new Vector3(-1, 0, 0); + } + /** + * @type {clay.Vector3} + * @readOnly + * @memberOf clay.Vector3 + */ + static get POSITIVE_Y() { + return new Vector3(0, 1, 0); + } + /** + * @type {clay.Vector3} + * @readOnly + * @memberOf clay.Vector3 + */ + static get NEGATIVE_Y() { + return new Vector3(0, -1, 0); + } + /** + * @type {clay.Vector3} + * @readOnly + * @memberOf clay.Vector3 + */ + static get POSITIVE_Z() { + return new Vector3(0, 0, 1); + } + /** + * @type {clay.Vector3} + * @readOnly + */ + static get NEGATIVE_Z() { + return new Vector3(0, 0, -1); + } + /** + * @type {clay.Vector3} + * @readOnly + * @memberOf clay.Vector3 + */ + static get UP() { + return new Vector3(0, 1, 0); + } + /** + * @type {clay.Vector3} + * @readOnly + * @memberOf clay.Vector3 + */ + static get ZERO() { + return new Vector3(); + } } -// Supply methods that are not in place - -/** - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {clay.Vector3} - */ -Vector3.add = function (out, a, b) { - vec3.add(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector3} out - * @param {number} x - * @param {number} y - * @param {number} z - * @return {clay.Vector3} - */ -Vector3.set = function (out, x, y, z) { - vec3.set(out.array, x, y, z); - out._dirty = true; -}; - -/** - * @param {clay.Vector3} out - * @param {clay.Vector3} b - * @return {clay.Vector3} - */ -Vector3.copy = function (out, b) { - vec3.copy(out.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {clay.Vector3} - */ -Vector3.cross = function (out, a, b) { - vec3.cross(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {number} - */ -Vector3.dist = function (a, b) { - return vec3.distance(a.array, b.array); -}; - -/** - * @function - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {number} - */ -Vector3.distance = Vector3.dist; - -/** - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {clay.Vector3} - */ -Vector3.div = function (out, a, b) { - vec3.divide(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @function - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {clay.Vector3} - */ -Vector3.divide = Vector3.div; - -/** - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {number} - */ -Vector3.dot = function (a, b) { - return vec3.dot(a.array, b.array); -}; - -/** - * @param {clay.Vector3} a - * @return {number} - */ -Vector3.len = function (b) { - return vec3.length(b.array); -}; - -// Vector3.length = Vector3.len; - -/** - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @param {number} t - * @return {clay.Vector3} - */ -Vector3.lerp = function (out, a, b, t) { - vec3.lerp(out.array, a.array, b.array, t); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {clay.Vector3} - */ -Vector3.min = function (out, a, b) { - vec3.min(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {clay.Vector3} - */ -Vector3.max = function (out, a, b) { - vec3.max(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {clay.Vector3} - */ -Vector3.mul = function (out, a, b) { - vec3.multiply(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @function - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {clay.Vector3} - */ -Vector3.multiply = Vector3.mul; -/** - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @return {clay.Vector3} - */ -Vector3.negate = function (out, a) { - vec3.negate(out.array, a.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @return {clay.Vector3} - */ -Vector3.normalize = function (out, a) { - vec3.normalize(out.array, a.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector3} out - * @param {number} scale - * @return {clay.Vector3} - */ -Vector3.random = function (out, scale) { - vec3.random(out.array, scale); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @param {number} scale - * @return {clay.Vector3} - */ -Vector3.scale = function (out, a, scale) { - vec3.scale(out.array, a.array, scale); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @param {number} scale - * @return {clay.Vector3} - */ -Vector3.scaleAndAdd = function (out, a, b, scale) { - vec3.scaleAndAdd(out.array, a.array, b.array, scale); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {number} - */ -Vector3.sqrDist = function (a, b) { - return vec3.sqrDist(a.array, b.array); -}; -/** - * @function - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {number} - */ -Vector3.squaredDistance = Vector3.sqrDist; -/** - * @param {clay.Vector3} a - * @return {number} - */ -Vector3.sqrLen = function (a) { - return vec3.sqrLen(a.array); -}; -/** - * @function - * @param {clay.Vector3} a - * @return {number} - */ -Vector3.squaredLength = Vector3.sqrLen; - -/** - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {clay.Vector3} - */ -Vector3.sub = function (out, a, b) { - vec3.subtract(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @function - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @param {clay.Vector3} b - * @return {clay.Vector3} - */ -Vector3.subtract = Vector3.sub; - -/** - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @param {Matrix3} m - * @return {clay.Vector3} - */ -Vector3.transformMat3 = function (out, a, m) { - vec3.transformMat3(out.array, a.array, m.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @param {clay.Matrix4} m - * @return {clay.Vector3} - */ -Vector3.transformMat4 = function (out, a, m) { - vec3.transformMat4(out.array, a.array, m.array); - out._dirty = true; - return out; -}; -/** - * @param {clay.Vector3} out - * @param {clay.Vector3} a - * @param {clay.Quaternion} q - * @return {clay.Vector3} - */ -Vector3.transformQuat = function (out, a, q) { - vec3.transformQuat(out.array, a.array, q.array); - out._dirty = true; - return out; -}; - -function clamp(val, min, max) { - return val < min ? min : val > max ? max : val; -} -const atan2 = Math.atan2; -const asin = Math.asin; -const abs = Math.abs; -/** - * Convert quaternion to euler angle - * Quaternion must be normalized - * From three.js - */ -Vector3.eulerFromQuat = function (out, q, order) { - out._dirty = true; - q = q.array; - - const target = out.array; - const x = q[0], - y = q[1], - z = q[2], - w = q[3]; - const x2 = x * x; - const y2 = y * y; - const z2 = z * z; - const w2 = w * w; - - order = (order || 'XYZ').toUpperCase(); - - switch (order) { - case 'XYZ': - target[0] = atan2(2 * (x * w - y * z), w2 - x2 - y2 + z2); - target[1] = asin(clamp(2 * (x * z + y * w), -1, 1)); - target[2] = atan2(2 * (z * w - x * y), w2 + x2 - y2 - z2); - break; - case 'YXZ': - target[0] = asin(clamp(2 * (x * w - y * z), -1, 1)); - target[1] = atan2(2 * (x * z + y * w), w2 - x2 - y2 + z2); - target[2] = atan2(2 * (x * y + z * w), w2 - x2 + y2 - z2); - break; - case 'ZXY': - target[0] = asin(clamp(2 * (x * w + y * z), -1, 1)); - target[1] = atan2(2 * (y * w - z * x), w2 - x2 - y2 + z2); - target[2] = atan2(2 * (z * w - x * y), w2 - x2 + y2 - z2); - break; - case 'ZYX': - target[0] = atan2(2 * (x * w + z * y), w2 - x2 - y2 + z2); - target[1] = asin(clamp(2 * (y * w - x * z), -1, 1)); - target[2] = atan2(2 * (x * y + z * w), w2 + x2 - y2 - z2); - break; - case 'YZX': - target[0] = atan2(2 * (x * w - z * y), w2 - x2 + y2 - z2); - target[1] = atan2(2 * (y * w - x * z), w2 + x2 - y2 - z2); - target[2] = asin(clamp(2 * (x * y + z * w), -1, 1)); - break; - case 'XZY': - target[0] = atan2(2 * (x * w + y * z), w2 - x2 + y2 - z2); - target[1] = atan2(2 * (x * z + y * w), w2 + x2 - y2 - z2); - target[2] = asin(clamp(2 * (z * w - x * y), -1, 1)); - break; - default: - console.warn('Unkown order: ' + order); - } - return out; -}; - -/** - * Convert rotation matrix to euler angle - * from three.js - */ -Vector3.eulerFromMat3 = function (out, m, order) { - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) - const te = m.array; - const m11 = te[0], - m12 = te[3], - m13 = te[6]; - const m21 = te[1], - m22 = te[4], - m23 = te[7]; - const m31 = te[2], - m32 = te[5], - m33 = te[8]; - const target = out.array; - - order = (order || 'XYZ').toUpperCase(); - - switch (order) { - case 'XYZ': - target[1] = asin(clamp(m13, -1, 1)); - if (abs(m13) < 0.99999) { - target[0] = atan2(-m23, m33); - target[2] = atan2(-m12, m11); - } else { - target[0] = atan2(m32, m22); - target[2] = 0; - } - break; - case 'YXZ': - target[0] = asin(-clamp(m23, -1, 1)); - if (abs(m23) < 0.99999) { - target[1] = atan2(m13, m33); - target[2] = atan2(m21, m22); - } else { - target[1] = atan2(-m31, m11); - target[2] = 0; - } - break; - case 'ZXY': - target[0] = asin(clamp(m32, -1, 1)); - if (abs(m32) < 0.99999) { - target[1] = atan2(-m31, m33); - target[2] = atan2(-m12, m22); - } else { - target[1] = 0; - target[2] = atan2(m21, m11); - } - break; - case 'ZYX': - target[1] = asin(-clamp(m31, -1, 1)); - if (abs(m31) < 0.99999) { - target[0] = atan2(m32, m33); - target[2] = atan2(m21, m11); - } else { - target[0] = 0; - target[2] = atan2(-m12, m22); - } - break; - case 'YZX': - target[2] = asin(clamp(m21, -1, 1)); - if (abs(m21) < 0.99999) { - target[0] = atan2(-m23, m22); - target[1] = atan2(-m31, m11); - } else { - target[0] = 0; - target[1] = atan2(m13, m33); - } - break; - case 'XZY': - target[2] = asin(-clamp(m12, -1, 1)); - if (abs(m12) < 0.99999) { - target[0] = atan2(m32, m22); - target[1] = atan2(m13, m11); - } else { - target[0] = atan2(-m23, m33); - target[1] = 0; - } - break; - default: - console.warn('Unkown order: ' + order); - } - out._dirty = true; - - return out; -}; - -Object.defineProperties(Vector3, { - /** - * @type {clay.Vector3} - * @readOnly - * @memberOf clay.Vector3 - */ - POSITIVE_X: { - get: function () { - return new Vector3(1, 0, 0); - } - }, - /** - * @type {clay.Vector3} - * @readOnly - * @memberOf clay.Vector3 - */ - NEGATIVE_X: { - get: function () { - return new Vector3(-1, 0, 0); - } - }, - /** - * @type {clay.Vector3} - * @readOnly - * @memberOf clay.Vector3 - */ - POSITIVE_Y: { - get: function () { - return new Vector3(0, 1, 0); - } - }, - /** - * @type {clay.Vector3} - * @readOnly - * @memberOf clay.Vector3 - */ - NEGATIVE_Y: { - get: function () { - return new Vector3(0, -1, 0); - } - }, - /** - * @type {clay.Vector3} - * @readOnly - * @memberOf clay.Vector3 - */ - POSITIVE_Z: { - get: function () { - return new Vector3(0, 0, 1); - } - }, - /** - * @type {clay.Vector3} - * @readOnly - */ - NEGATIVE_Z: { - get: function () { - return new Vector3(0, 0, -1); - } - }, - /** - * @type {clay.Vector3} - * @readOnly - * @memberOf clay.Vector3 - */ - UP: { - get: function () { - return new Vector3(0, 1, 0); - } - }, - /** - * @type {clay.Vector3} - * @readOnly - * @memberOf clay.Vector3 - */ - ZERO: { - get: function () { - return new Vector3(); - } - } -}); - export default Vector3; diff --git a/src/math/Vector4.ts b/src/math/Vector4.ts index 7c8f146b..51819c5b 100644 --- a/src/math/Vector4.ts +++ b/src/math/Vector4.ts @@ -1,20 +1,17 @@ -// @ts-nocheck -import vec4 from '../glmatrix/vec4'; +import * as vec4 from '../glmatrix/vec4'; +import type Quaternion from './Quaternion'; +import type Matrix4 from './Matrix4'; +import { matrixOrVectorClassToString } from './util'; /** * @constructor * @alias clay.Vector4 - * @param {number} x - * @param {number} y - * @param {number} z - * @param {number} w + * @param x + * @param y + * @param z + * @param w */ -const Vector4 = function (x, y, z, w) { - x = x || 0; - y = y || 0; - z = z || 0; - w = w || 0; - +class Vector4 { /** * Storage of Vector4, read and write of x, y, z, w will change the values in array * All methods also operate on the array instead of x, y, z, w components @@ -22,696 +19,556 @@ const Vector4 = function (x, y, z, w) { * @type {Float32Array} * @memberOf clay.Vector4# */ - this.array = vec4.fromValues(x, y, z, w); + array: vec4.Vec4Array; - /** - * Dirty flag is used by the Node to determine - * if the matrix is updated to latest - * @name _dirty - * @type {boolean} - * @memberOf clay.Vector4# - */ - this._dirty = true; -}; + constructor(x: number, y: number, z: number, w: number) { + x = x || 0; + y = y || 0; + z = z || 0; + w = w || 0; + this.array = vec4.fromValues(x, y, z, w); + } -Vector4.prototype = { - constructor: Vector4, + get x() { + return this.array[0]; + } + set x(value: number) { + this.array[0] = value; + } + + get y() { + return this.array[1]; + } + set y(value: number) { + this.array[1] = value; + } + + get z() { + return this.array[2]; + } + set z(value: number) { + this.array[2] = value; + } + + get w() { + return this.array[3]; + } + set w(value: number) { + this.array[3] = value; + } /** * Add b to self - * @param {clay.Vector4} b - * @return {clay.Vector4} + * @param b */ - add: function (b) { + add(b: Vector4) { vec4.add(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Set x, y and z components - * @param {number} x - * @param {number} y - * @param {number} z - * @param {number} w - * @return {clay.Vector4} + * @param x + * @param y + * @param z + * @param w */ - set: function (x, y, z, w) { - this.array[0] = x; - this.array[1] = y; - this.array[2] = z; - this.array[3] = w; - this._dirty = true; + set(x: number, y: number, z: number, w: number) { + const arr = this.array; + arr[0] = x; + arr[1] = y; + arr[2] = z; + arr[3] = w; return this; - }, + } /** * Set x, y, z and w components from array - * @param {Float32Array|number[]} arr - * @return {clay.Vector4} + * @param from */ - setArray: function (arr) { - this.array[0] = arr[0]; - this.array[1] = arr[1]; - this.array[2] = arr[2]; - this.array[3] = arr[3]; + setArray(from: vec4.Vec4Array) { + const arr = this.array; + arr[0] = from[0]; + arr[1] = from[1]; + arr[2] = from[2]; + arr[3] = from[3]; - this._dirty = true; return this; - }, + } /** * Clone a new Vector4 - * @return {clay.Vector4} */ - clone: function () { + clone() { return new Vector4(this.x, this.y, this.z, this.w); - }, + } /** * Copy from b - * @param {clay.Vector4} b - * @return {clay.Vector4} + * @param b */ - copy: function (b) { + copy(b: Vector4) { vec4.copy(this.array, b.array); - this._dirty = true; return this; - }, + } /** * Alias for distance - * @param {clay.Vector4} b - * @return {number} + * @param b */ - dist: function (b) { + dist(b: Vector4) { return vec4.dist(this.array, b.array); - }, + } /** * Distance between self and b - * @param {clay.Vector4} b - * @return {number} + * @param b */ - distance: function (b) { + distance(b: Vector4) { return vec4.distance(this.array, b.array); - }, + } /** * Alias for divide - * @param {clay.Vector4} b - * @return {clay.Vector4} + * @param b */ - div: function (b) { + div(b: Vector4) { vec4.div(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Divide self by b - * @param {clay.Vector4} b - * @return {clay.Vector4} + * @param b */ - divide: function (b) { + divide(b: Vector4) { vec4.divide(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Dot product of self and b - * @param {clay.Vector4} b - * @return {number} + * @param b */ - dot: function (b) { + dot(b: Vector4) { return vec4.dot(this.array, b.array); - }, + } /** * Alias of length - * @return {number} */ - len: function () { + len() { return vec4.len(this.array); - }, + } /** * Calculate the length - * @return {number} */ - length: function () { + length() { return vec4.length(this.array); - }, + } /** * Linear interpolation between a and b - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @param {number} t - * @return {clay.Vector4} + * @param a + * @param b + * @param t */ - lerp: function (a, b, t) { + lerp(a: Vector4, b: Vector4, t: number) { vec4.lerp(this.array, a.array, b.array, t); - this._dirty = true; return this; - }, + } /** * Minimum of self and b - * @param {clay.Vector4} b - * @return {clay.Vector4} + * @param b */ - min: function (b) { + min(b: Vector4) { vec4.min(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Maximum of self and b - * @param {clay.Vector4} b - * @return {clay.Vector4} + * @param b */ - max: function (b) { + max(b: Vector4) { vec4.max(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Alias for multiply - * @param {clay.Vector4} b - * @return {clay.Vector4} + * @param b */ - mul: function (b) { + mul(b: Vector4) { vec4.mul(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Mutiply self and b - * @param {clay.Vector4} b - * @return {clay.Vector4} + * @param b */ - multiply: function (b) { + multiply(b: Vector4) { vec4.multiply(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Negate self - * @return {clay.Vector4} */ - negate: function () { + negate() { vec4.negate(this.array, this.array); - this._dirty = true; return this; - }, + } /** * Normalize self - * @return {clay.Vector4} */ - normalize: function () { + normalize() { vec4.normalize(this.array, this.array); - this._dirty = true; return this; - }, + } /** * Generate random x, y, z, w components with a given scale - * @param {number} scale - * @return {clay.Vector4} + * @param scale */ - random: function (scale) { + random(scale: number) { vec4.random(this.array, scale); - this._dirty = true; return this; - }, + } /** * Scale self - * @param {number} scale - * @return {clay.Vector4} + * @param scale */ - scale: function (s) { + scale(s: number) { vec4.scale(this.array, this.array, s); - this._dirty = true; return this; - }, + } /** * Scale b and add to self - * @param {clay.Vector4} b - * @param {number} scale - * @return {clay.Vector4} + * @param b + * @param scale */ - scaleAndAdd: function (b, s) { + scaleAndAdd(b: Vector4, s: number) { vec4.scaleAndAdd(this.array, this.array, b.array, s); - this._dirty = true; return this; - }, + } /** * Alias for squaredDistance - * @param {clay.Vector4} b - * @return {number} + * @param b */ - sqrDist: function (b) { + sqrDist(b: Vector4) { return vec4.sqrDist(this.array, b.array); - }, + } /** * Squared distance between self and b - * @param {clay.Vector4} b - * @return {number} + * @param b */ - squaredDistance: function (b) { + squaredDistance(b: Vector4) { return vec4.squaredDistance(this.array, b.array); - }, + } /** * Alias for squaredLength - * @return {number} */ - sqrLen: function () { + sqrLen() { return vec4.sqrLen(this.array); - }, + } /** * Squared length of self - * @return {number} */ - squaredLength: function () { + squaredLength() { return vec4.squaredLength(this.array); - }, + } /** * Alias for subtract - * @param {clay.Vector4} b - * @return {clay.Vector4} + * @param b */ - sub: function (b) { + sub(b: Vector4) { vec4.sub(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Subtract b from self - * @param {clay.Vector4} b - * @return {clay.Vector4} + * @param b */ - subtract: function (b) { + subtract(b: Vector4) { vec4.subtract(this.array, this.array, b.array); - this._dirty = true; return this; - }, + } /** * Transform self with a Matrix4 m - * @param {clay.Matrix4} m - * @return {clay.Vector4} + * @param {clay.Matrix4} m */ - transformMat4: function (m) { + transformMat4(m: Matrix4) { vec4.transformMat4(this.array, this.array, m.array); - this._dirty = true; return this; - }, + } /** * Transform self with a Quaternion q - * @param {clay.Quaternion} q - * @return {clay.Vector4} + * @param {clay.Quaternion} q */ - transformQuat: function (q) { + transformQuat(q: Quaternion) { vec4.transformQuat(this.array, this.array, q.array); - this._dirty = true; return this; - }, + } - toString: function () { - return '[' + Array.prototype.join.call(this.array, ',') + ']'; - }, + toString() { + return matrixOrVectorClassToString(this, 4); + } - toArray: function () { + toArray() { return Array.prototype.slice.call(this.array); } -}; - -const defineProperty = Object.defineProperty; -// Getter and Setter -if (defineProperty) { - const proto = Vector4.prototype; /** - * @name x - * @type {number} - * @memberOf clay.Vector4 - * @instance + * @param out + * @param a + * @param b */ - defineProperty(proto, 'x', { - get: function () { - return this.array[0]; - }, - set: function (value) { - this.array[0] = value; - this._dirty = true; - } - }); + static add(out: Vector4, a: Vector4, b: Vector4) { + vec4.add(out.array, a.array, b.array); + return out; + } /** - * @name y - * @type {number} - * @memberOf clay.Vector4 - * @instance + * @param out + * @param x + * @param y + * @param z */ - defineProperty(proto, 'y', { - get: function () { - return this.array[1]; - }, - set: function (value) { - this.array[1] = value; - this._dirty = true; - } - }); + static set(out: Vector4, x: number, y: number, z: number, w: number) { + vec4.set(out.array, x, y, z, w); + } /** - * @name z - * @type {number} - * @memberOf clay.Vector4 - * @instance + * @param out + * @param b */ - defineProperty(proto, 'z', { - get: function () { - return this.array[2]; - }, - set: function (value) { - this.array[2] = value; - this._dirty = true; - } - }); + static copy(out: Vector4, b: Vector4) { + vec4.copy(out.array, b.array); + return out; + } /** - * @name w - * @type {number} - * @memberOf clay.Vector4 - * @instance + * @param a + * @param b */ - defineProperty(proto, 'w', { - get: function () { - return this.array[3]; - }, - set: function (value) { - this.array[3] = value; - this._dirty = true; - } - }); + static dist(a: Vector4, b: Vector4) { + return vec4.distance(a.array, b.array); + } + + /** + * @function + * @param a + * @param b + */ + static distance = Vector4.dist; + + /** + * @param out + * @param a + * @param b + */ + static div(out: Vector4, a: Vector4, b: Vector4) { + vec4.divide(out.array, a.array, b.array); + return out; + } + + /** + * @function + * @param out + * @param a + * @param b + */ + static divide = Vector4.div; + + /** + * @param a + * @param b + */ + static dot(a: Vector4, b: Vector4) { + return vec4.dot(a.array, b.array); + } + + /** + * @param a + */ + static len(b: Vector4) { + return vec4.length(b.array); + } + + // Vector4.length = Vector4.len; + + /** + * @param out + * @param a + * @param b + * @param t + */ + static lerp(out: Vector4, a: Vector4, b: Vector4, t: number) { + vec4.lerp(out.array, a.array, b.array, t); + return out; + } + + /** + * @param out + * @param a + * @param b + */ + static min(out: Vector4, a: Vector4, b: Vector4) { + vec4.min(out.array, a.array, b.array); + return out; + } + + /** + * @param out + * @param a + * @param b + */ + static max(out: Vector4, a: Vector4, b: Vector4) { + vec4.max(out.array, a.array, b.array); + return out; + } + + /** + * @param out + * @param a + * @param b + */ + static mul(out: Vector4, a: Vector4, b: Vector4) { + vec4.multiply(out.array, a.array, b.array); + return out; + } + + /** + * @function + * @param out + * @param a + * @param b + */ + static multiply = Vector4.mul; + + /** + * @param out + * @param a + */ + static negate(out: Vector4, a: Vector4) { + vec4.negate(out.array, a.array); + return out; + } + + /** + * @param out + * @param a + */ + static normalize(out: Vector4, a: Vector4) { + vec4.normalize(out.array, a.array); + return out; + } + + /** + * @param out + * @param scale + */ + static random(out: Vector4, scale: number) { + vec4.random(out.array, scale); + return out; + } + + /** + * @param out + * @param a + * @param scale + */ + static scale(out: Vector4, a: Vector4, scale: number) { + vec4.scale(out.array, a.array, scale); + return out; + } + + /** + * @param out + * @param a + * @param b + * @param scale + */ + static scaleAndAdd(out: Vector4, a: Vector4, b: Vector4, scale: number) { + vec4.scaleAndAdd(out.array, a.array, b.array, scale); + return out; + } + + /** + * @param a + * @param b + */ + static sqrDist(a: Vector4, b: Vector4) { + return vec4.sqrDist(a.array, b.array); + } + + /** + * @function + * @param a + * @param b + */ + static squaredDistance = Vector4.sqrDist; + + /** + * @param a + */ + static sqrLen(a: Vector4) { + return vec4.sqrLen(a.array); + } + /** + * @function + * @param a + */ + static squaredLength = Vector4.sqrLen; + + /** + * @param out + * @param a + * @param b + */ + static sub(out: Vector4, a: Vector4, b: Vector4) { + vec4.subtract(out.array, a.array, b.array); + return out; + } + /** + * @function + * @param out + * @param a + * @param b + */ + static subtract = Vector4.sub; + + /** + * @param out + * @param a + * @param m + */ + static transformMat4(out: Vector4, a: Vector4, m: Matrix4) { + vec4.transformMat4(out.array, a.array, m.array); + return out; + } + + /** + * @param out + * @param a + * @param q + */ + static transformQuat(out: Vector4, a: Vector4, q: Quaternion) { + vec4.transformQuat(out.array, a.array, q.array); + return out; + } } -// Supply methods that are not in place - -/** - * @param {clay.Vector4} out - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @return {clay.Vector4} - */ -Vector4.add = function (out, a, b) { - vec4.add(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector4} out - * @param {number} x - * @param {number} y - * @param {number} z - * @return {clay.Vector4} - */ -Vector4.set = function (out, x, y, z, w) { - vec4.set(out.array, x, y, z, w); - out._dirty = true; -}; - -/** - * @param {clay.Vector4} out - * @param {clay.Vector4} b - * @return {clay.Vector4} - */ -Vector4.copy = function (out, b) { - vec4.copy(out.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @return {number} - */ -Vector4.dist = function (a, b) { - return vec4.distance(a.array, b.array); -}; - -/** - * @function - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @return {number} - */ -Vector4.distance = Vector4.dist; - -/** - * @param {clay.Vector4} out - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @return {clay.Vector4} - */ -Vector4.div = function (out, a, b) { - vec4.divide(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @function - * @param {clay.Vector4} out - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @return {clay.Vector4} - */ -Vector4.divide = Vector4.div; - -/** - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @return {number} - */ -Vector4.dot = function (a, b) { - return vec4.dot(a.array, b.array); -}; - -/** - * @param {clay.Vector4} a - * @return {number} - */ -Vector4.len = function (b) { - return vec4.length(b.array); -}; - -// Vector4.length = Vector4.len; - -/** - * @param {clay.Vector4} out - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @param {number} t - * @return {clay.Vector4} - */ -Vector4.lerp = function (out, a, b, t) { - vec4.lerp(out.array, a.array, b.array, t); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector4} out - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @return {clay.Vector4} - */ -Vector4.min = function (out, a, b) { - vec4.min(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector4} out - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @return {clay.Vector4} - */ -Vector4.max = function (out, a, b) { - vec4.max(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector4} out - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @return {clay.Vector4} - */ -Vector4.mul = function (out, a, b) { - vec4.multiply(out.array, a.array, b.array); - out._dirty = true; - return out; -}; - -/** - * @function - * @param {clay.Vector4} out - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @return {clay.Vector4} - */ -Vector4.multiply = Vector4.mul; - -/** - * @param {clay.Vector4} out - * @param {clay.Vector4} a - * @return {clay.Vector4} - */ -Vector4.negate = function (out, a) { - vec4.negate(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector4} out - * @param {clay.Vector4} a - * @return {clay.Vector4} - */ -Vector4.normalize = function (out, a) { - vec4.normalize(out.array, a.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector4} out - * @param {number} scale - * @return {clay.Vector4} - */ -Vector4.random = function (out, scale) { - vec4.random(out.array, scale); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector4} out - * @param {clay.Vector4} a - * @param {number} scale - * @return {clay.Vector4} - */ -Vector4.scale = function (out, a, scale) { - vec4.scale(out.array, a.array, scale); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector4} out - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @param {number} scale - * @return {clay.Vector4} - */ -Vector4.scaleAndAdd = function (out, a, b, scale) { - vec4.scaleAndAdd(out.array, a.array, b.array, scale); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @return {number} - */ -Vector4.sqrDist = function (a, b) { - return vec4.sqrDist(a.array, b.array); -}; - -/** - * @function - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @return {number} - */ -Vector4.squaredDistance = Vector4.sqrDist; - -/** - * @param {clay.Vector4} a - * @return {number} - */ -Vector4.sqrLen = function (a) { - return vec4.sqrLen(a.array); -}; -/** - * @function - * @param {clay.Vector4} a - * @return {number} - */ -Vector4.squaredLength = Vector4.sqrLen; - -/** - * @param {clay.Vector4} out - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @return {clay.Vector4} - */ -Vector4.sub = function (out, a, b) { - vec4.subtract(out.array, a.array, b.array); - out._dirty = true; - return out; -}; -/** - * @function - * @param {clay.Vector4} out - * @param {clay.Vector4} a - * @param {clay.Vector4} b - * @return {clay.Vector4} - */ -Vector4.subtract = Vector4.sub; - -/** - * @param {clay.Vector4} out - * @param {clay.Vector4} a - * @param {clay.Matrix4} m - * @return {clay.Vector4} - */ -Vector4.transformMat4 = function (out, a, m) { - vec4.transformMat4(out.array, a.array, m.array); - out._dirty = true; - return out; -}; - -/** - * @param {clay.Vector4} out - * @param {clay.Vector4} a - * @param {clay.Quaternion} q - * @return {clay.Vector4} - */ -Vector4.transformQuat = function (out, a, q) { - vec4.transformQuat(out.array, a.array, q.array); - out._dirty = true; - return out; -}; - export default Vector4; diff --git a/src/math/util.ts b/src/math/util.ts index e4aa8ee6..77f8c0a7 100644 --- a/src/math/util.ts +++ b/src/math/util.ts @@ -1,11 +1,8 @@ -// @ts-nocheck -const mathUtil = {}; - -mathUtil.isPowerOfTwo = function (value) { +export function isPowerOfTwo(value: number) { return (value & (value - 1)) === 0; -}; +} -mathUtil.nextPowerOfTwo = function (value) { +export function nextPowerOfTwo(value: number) { value--; value |= value >> 1; value |= value >> 2; @@ -15,10 +12,27 @@ mathUtil.nextPowerOfTwo = function (value) { value++; return value; -}; +} -mathUtil.nearestPowerOfTwo = function (value) { +export function nearestPowerOfTwo(value: number) { return Math.pow(2, Math.round(Math.log(value) / Math.LN2)); -}; +} -export default mathUtil; +export function formatMatrixString(array: number[], cols: number) { + let str = ''; + for (let i = 0; i < Math.ceil(array.length / cols); i++) { + str += array.slice(i * cols, (i + 1) * cols).join('\t') + '\n'; + } + return str; +} + +export function matrixOrVectorClassToString(obj: { array: number[] }, cols: number) { + let str = ''; + const array = obj.array; + const Clz = obj.constructor; + const className = (Clz && Clz.name) || ''; + for (let i = 0; i < Math.ceil(array.length / cols); i++) { + str += array.slice(i * cols, (i + 1) * cols).join('\t') + '\n'; + } + return className + '[\n' + str + '\n]'; +}