diff --git a/src/math/index.ts b/src/math/index.ts index 09e6010c..744f3dbc 100644 --- a/src/math/index.ts +++ b/src/math/index.ts @@ -8,4 +8,7 @@ export * from "./vector2"; export * from "./vector2f"; export * from "./vector3"; export * from "./vector4"; +export * from "./mat3"; +export * from "./simple-mat3"; export * from "./mat4"; +export * from "./simple-mat4"; diff --git a/src/math/mat3.ts b/src/math/mat3.ts index fd13ad49..95f8434c 100644 --- a/src/math/mat3.ts +++ b/src/math/mat3.ts @@ -1,13 +1,53 @@ +import { SimpleMat3 } from "./simple-mat3"; +import { SimpleVector2 } from "./simple-vector2"; + /** * https://github.com/mrdoob/three.js/blob/dev/src/math/Matrix3.js */ -export class SimpleMat3 { - public constructor( - private readonly data: number[][], - ) { +export class Mat3 extends SimpleMat3 { + public static mul(a: SimpleMat3, b: SimpleMat3): SimpleMat3; + public static mul(a: SimpleMat3, b: SimpleMat3, out: T): T; + public static mul(a: SimpleMat3, b: SimpleMat3, out = SimpleMat3.create()): T { + const a00 = a.data[0]; + const a01 = a.data[1]; + const a02 = a.data[2]; + const a10 = a.data[3]; + const a11 = a.data[4]; + const a12 = a.data[5]; + const a20 = a.data[6]; + const a21 = a.data[7]; + const a22 = a.data[8]; + const b00 = b.data[0]; + const b01 = b.data[1]; + const b02 = b.data[2]; + const b10 = b.data[3]; + const b11 = b.data[4]; + const b12 = b.data[5]; + const b20 = b.data[6]; + const b21 = b.data[7]; + const b22 = b.data[8]; + out.data[0] = b00 * a00 + b01 * a10 + b02 * a20; + out.data[1] = b00 * a01 + b01 * a11 + b02 * a21; + out.data[2] = b00 * a02 + b01 * a12 + b02 * a22; + out.data[3] = b10 * a00 + b11 * a10 + b12 * a20; + out.data[4] = b10 * a01 + b11 * a11 + b12 * a21; + out.data[5] = b10 * a02 + b11 * a12 + b12 * a22; + out.data[6] = b20 * a00 + b21 * a10 + b22 * a20; + out.data[7] = b20 * a01 + b21 * a11 + b22 * a21; + out.data[8] = b20 * a02 + b21 * a12 + b22 * a22; + + return out as T; } -} -export class Mat3 extends SimpleMat3 { + public static getTranslatedVector(a: SimpleVector2, m: SimpleMat3): SimpleVector2; + public static getTranslatedVector(a: SimpleVector2, m: SimpleMat3, out: T): T; + public static getTranslatedVector(a: SimpleVector2, m: SimpleMat3, out = {x: 0, y: 0}): T { + const x = a.x; + const y = a.y; + + out.x = m.data[0] * x + m.data[3] * y + m.data[6]; + out.y = m.data[1] * x + m.data[4] * y + m.data[7]; + return out as T; + } } diff --git a/src/math/mat4.ts b/src/math/mat4.ts index 3a4035a6..bdd9f97a 100644 --- a/src/math/mat4.ts +++ b/src/math/mat4.ts @@ -1,309 +1,4 @@ -// /* eslint-disable */ -/** - * https://github.com/mrdoob/three.js/blob/dev/src/math/Matrix4.js - * https://github.com/BennyQBD/3DEngineCpp/blob/master/src/core/math3d.h - * https://glmatrix.net/docs/mat4.js.html - * https://github.com/fynnfluegge/oreon-engine/blob/master/oreonengine/oe-core/src/main/java/org/oreon/core/math/Matrix4f.java - */ -import { Quaternion } from "./quaternion"; -import { ReadonlySimpleVector3, SimpleVector3 } from "./simple-vector3"; -import { Vector3 } from "./vector3"; - -/** - * 00 04 08 12 - * 01 05 09 13 - * 02 06 10 14 - * 03 07 11 14 - */ -export class SimpleMat4 { - public constructor(public readonly data: number[]) { - } - - public set(x: number, y: number, value: number): void { - this.data[x * 4 + y] = value; - } - - public get(x: number, y: number): number { - return this.data[x * 4 + y]; - } - - public getTranslation(): SimpleVector3 { - return { - x: this.data[12], - y: this.data[13], - z: this.data[14], - }; - } - - public getScale(): SimpleVector3 { - return { - x: this.data[0], - y: this.data[5], - z: this.data[10], - }; - } - - public equalsArray(data: number[]): boolean { - if (!data?.length) { - return false; - } - - for (let i = 0; i < 16; i++) { - if (data[i] !== this.data[i]) { - return false; - } - } - - return true; - } - - public equals(mat: Mat4): boolean { - if (!mat) { - return false; - } - - return this.equalsArray(mat.data); - } - - public static create(): SimpleMat4 { - return new SimpleMat4([ - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1, - ]); - } - - public static setIdentity(result: SimpleMat4): SimpleMat4 { - result.data[0] = 1; - result.data[1] = 0; - result.data[2] = 0; - result.data[3] = 0; - result.data[4] = 0; - result.data[5] = 1; - result.data[6] = 0; - result.data[7] = 0; - result.data[8] = 0; - result.data[9] = 0; - result.data[10] = 1; - result.data[11] = 0; - result.data[12] = 0; - result.data[13] = 0; - result.data[14] = 0; - result.data[15] = 1; - - return result; - } - - private static setTranslation(x: number, y: number, z: number, result: number[]): number[] { - result[12] = x; - result[13] = y; - result[14] = z; - - return result; - } - - private static setScale(x: number, y: number, z: number, result: number[]): number[] { - result[0] = x; - result[5] = y; - result[10] = z; - - return result; - } - - public static fromTranslation(translation: SimpleVector3, result = SimpleMat4.create()): SimpleMat4 { - Mat4.setIdentity(result); - Mat4.setTranslation(translation.x, translation.y, translation.z, result.data); - - return result; - } - - public static fromScale(scale: SimpleVector3, result = SimpleMat4.create()): SimpleMat4 { - Mat4.setIdentity(result); - Mat4.setScale(scale.x, scale.y, scale.z, result.data); - - return result; - } - - public static from( - param: { - scale?: SimpleVector3 | [number, number, number]; - translation?: SimpleVector3 | [number, number, number]; - rotation?: Quaternion; - angle?: number; - axes?: number | SimpleVector3; - rotX?: number; - rotY?: number; - rotZ?: number; - }, - result = SimpleMat4.create()): SimpleMat4 { - - Mat4.setIdentity(result); - - if (param.translation) { - if (Vector3.isVector(param.translation)) { - Mat4.setTranslation(param.translation.x, param.translation.y, param.translation.z, result.data); - } else { - Mat4.setTranslation(param.translation[0], param.translation[1], param.translation[2], result.data); - } - } - - if (param.scale) { - if (Vector3.isVector(param.scale)) { - Mat4.setScale(param.scale.x, param.scale.y, param.scale.z, result.data); - } else { - Mat4.setScale(param.scale[0], param.scale[1], param.scale[2], result.data); - } - } - - return result; - } - - public static fromQuaternion(v: Quaternion, result = SimpleMat4.create()): SimpleMat4 { - const x2 = v.x + v.x; - const y2 = v.y + v.y; - const z2 = v.z + v.z; - const xx = v.x * x2; - const xy = v.x * y2; - const xz = v.x * z2; - const yy = v.y * y2; - const yz = v.y * z2; - const zz = v.z * z2; - const wx = v.w * x2; - const wy = v.w * y2; - const wz = v.w * z2; - - result.data[0] = 1 - (yy + zz); - result.data[1] = xy + wz; - result.data[2] = xz - wy; - result.data[3] = 0; - result.data[4] = xy - wz; - result.data[5] = 1 - (xx + zz); - result.data[6] = yz + wx; - result.data[7] = 0; - result.data[8] = xz + wy; - result.data[9] = yz - wx; - result.data[10] = 1 - (xx + yy); - result.data[11] = 0; - result.data[12] = v.x; - result.data[13] = v.y; - result.data[14] = v.z; - result.data[15] = 1; - - return result; - } - - public static fromRotation(rad: number, axis: SimpleVector3, result = SimpleMat4.create()): SimpleMat4 | null { - let len = Math.hypot(axis.x, axis.y, axis.z); - if (len < Number.EPSILON) { - return null; - } - len = 1 / len; - const x = axis.x * len; - const y = axis.y * len; - const z = axis.z * len; - const s = Math.sin(rad); - const c = Math.cos(rad); - const t = 1 - c; - - result.data[0] = x * x * t + c; - result.data[1] = y * x * t + z * s; - result.data[2] = z * x * t - y * s; - result.data[3] = 0; - result.data[4] = x * y * t - z * s; - result.data[5] = y * y * t + c; - result.data[6] = z * y * t + x * s; - result.data[7] = 0; - result.data[8] = x * z * t + y * s; - result.data[9] = y * z * t - x * s; - result.data[10] = z * z * t + c; - result.data[11] = 0; - result.data[12] = 0; - result.data[13] = 0; - result.data[14] = 0; - result.data[15] = 1; - - return result; - } - - private static staticSetAngleRotation(sin: number, cos: number, axe: "X" | "Y" | "Z", data: number[]): number[] { - switch (axe) { - case "X": - data[5] = cos; - data[6] = sin; - data[9] = -sin; - data[10] = cos; - - return data; - case "Y": - data[0] = cos; - data[2] = -sin; - data[8] = sin; - data[10] = cos; - - return data; - case "Z": - data[0] = cos; - data[1] = sin; - data[4] = -sin; - data[5] = cos; - - return data; - default: - throw new Error(`Unknown axe ${axe}`); - } - } - - public static fromXRotation(rad: number, result = SimpleMat4.create()): SimpleMat4 { - Mat4.setIdentity(result); - Mat4.staticSetAngleRotation(Math.sin(rad), Math.cos(rad), "X", result.data); - - return result; - } - - public static fromYRotation(rad: number, result = SimpleMat4.create()): SimpleMat4 { - Mat4.setIdentity(result); - Mat4.staticSetAngleRotation(Math.sin(rad), Math.cos(rad), "Y", result.data); - - return result; - } - - public static fromZRotation(rad: number, result = SimpleMat4.create()): SimpleMat4 { - Mat4.setIdentity(result); - Mat4.staticSetAngleRotation(Math.sin(rad), Math.cos(rad), "Z", result.data); - - return result; - } - - public transformVector(a: SimpleVector3): SimpleVector3 { - const m = this.data; - const x = a.x; - const y = a.y; - const z = a.z; - let w = m[3] * x + m[7] * y + m[11] * z + m[15]; - w = w || 1; - a.x = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w; - a.y = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w; - a.z = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w; - - return a; - } - - public getTransformedVector(a: ReadonlySimpleVector3): SimpleVector3 { - const m = this.data; - const x = a.x; - const y = a.y; - const z = a.z; - let w = m[3] * x + m[7] * y + m[11] * z + m[15]; - w = w || 1; - - return { - x: (m[0] * x + m[4] * y + m[8] * z + m[12]) / w, - y: (m[1] * x + m[5] * y + m[9] * z + m[13]) / w, - z: (m[2] * x + m[6] * y + m[10] * z + m[14]) / w, - }; - } -} +import { SimpleMat4 } from "./simple-mat4"; export class Mat4 extends SimpleMat4 { public static createViewMatrix(): void { diff --git a/src/math/simple-mat3.spec.ts b/src/math/simple-mat3.spec.ts new file mode 100644 index 00000000..aef23dad --- /dev/null +++ b/src/math/simple-mat3.spec.ts @@ -0,0 +1,28 @@ +import { expect } from "chai"; +import "mocha"; +import { Mat3 } from "./mat3"; + +describe("Mat3", () => { + describe("init", () => { + it("Test matrix creation", () => { + const emptyMatrix = [ + 1, 0, 0, + 0, 1, 0, + 0, 0, 1, + ]; + expect(Mat3.create().equalsArray(emptyMatrix)).to.be.true; + expect(Mat3.create().equals(Mat3.create())).to.be.true; + expect(Mat3.create().equals(null as any)).to.be.false; + expect(Mat3.create().equals({} as any)).to.be.false; + + expect(Mat3.fromTranslation(0, 0).equals(Mat3.create())).to.be.true; + expect(Mat3.fromScale(1, 1).equals(Mat3.create())).to.be.true; + + expect(Mat3.fromScale(1, 1)).to.deep.equal(Mat3.create()); + expect(Mat3.fromTranslation(0, 0)).to.deep.equal(Mat3.create()); + // // commented because error during comparison 0 and -0 + // expect(Mat3.fromRotation(0)).to.deep.equal(Mat3.create()); + + }); + }); +}); diff --git a/src/math/simple-mat3.ts b/src/math/simple-mat3.ts new file mode 100644 index 00000000..5e501772 --- /dev/null +++ b/src/math/simple-mat3.ts @@ -0,0 +1,199 @@ +import { Mat3 } from "./mat3"; + +/** + * 00 03 06 + * 01 04 07 + * 02 05 08 + */ + +export class SimpleMat3 { + public constructor( + public readonly data: number[], + ) { + } + + public set(x: number, y: number, value: number): void { + this.data[x * 3 + y] = value; + } + + public get(x: number, y: number): number { + return this.data[x * 3 + y]; + } + + public static setIdentity(data: number[]): number[] { + data[0] = 1; + data[1] = 0; + data[2] = 0; + data[3] = 0; + data[4] = 1; + data[5] = 0; + data[6] = 0; + data[7] = 0; + data[8] = 1; + + return data; + } + + private static setTranslation(x: number, y: number, data: number[]): number[] { + data[2] = x; + data[5] = y; + + return data; + } + + private static setScale(x: number, y: number, data: number[]): number[] { + data[0] = x; + data[4] = y; + + return data; + } + + public static fromTranslation(x: number, y: number, out = SimpleMat3.create()): T { + SimpleMat3.setIdentity(out.data); + SimpleMat3.setTranslation(x, y, out.data); + + return out as T; + } + + public static fromScale(x: number, y: number, out = SimpleMat3.create()): T { + SimpleMat3.setIdentity(out.data); + SimpleMat3.setScale(x, y, out.data); + + return out as T; + } + + private static setRotation(angle: number, data: number[]): number[] { + data[0] = Math.cos(angle); + data[1] = -Math.sin(angle); + data[3] = Math.sin(angle); + data[4] = Math.cos(angle); + + return data; + } + + public static fromRotation(angle: number, out = SimpleMat3.create()): T { + SimpleMat3.setIdentity(out.data); + SimpleMat3.setRotation(angle, out.data); + + return out as T; + } + + public static create(): SimpleMat3 { + return new SimpleMat3([ + 1, 0, 0, + 0, 1, 0, + 0, 0, 1, + ]); + } + + public static translate(a: SimpleMat3, x: number, y: number, out = SimpleMat3.create()): T { + const a00 = a.data[0]; + const a01 = a.data[1]; + const a02 = a.data[2]; + const a10 = a.data[3]; + const a11 = a.data[4]; + const a12 = a.data[5]; + const a20 = a.data[6]; + const a21 = a.data[7]; + const a22 = a.data[8]; + out.data[0] = a00; + out.data[1] = a01; + out.data[2] = a02; + out.data[3] = a10; + out.data[4] = a11; + out.data[5] = a12; + out.data[6] = x * a00 + y * a10 + a20; + out.data[7] = x * a01 + y * a11 + a21; + out.data[8] = x * a02 + y * a12 + a22; + + return out as T; + } + + public static rotate(a: SimpleMat3, rad: number, out = SimpleMat3.create()): T { + const a00 = a.data[0]; + const a01 = a.data[1]; + const a02 = a.data[2]; + const a10 = a.data[3]; + const a11 = a.data[4]; + const a12 = a.data[5]; + const a20 = a.data[6]; + const a21 = a.data[7]; + const a22 = a.data[8]; + const s = Math.sin(rad); + const c = Math.cos(rad); + out.data[0] = c * a00 + s * a10; + out.data[1] = c * a01 + s * a11; + out.data[2] = c * a02 + s * a12; + out.data[3] = c * a10 - s * a00; + out.data[4] = c * a11 - s * a01; + out.data[5] = c * a12 - s * a02; + out.data[6] = a20; + out.data[7] = a21; + out.data[8] = a22; + + return out as T; + } + + public equalsArray(data: number[]): boolean { + if (!data?.length) { + return false; + } + + for (let i = 0; i < 9; i++) { + if (data[i] !== this.data[i]) { + return false; + } + } + + return true; + } + + public static getTransformationMatrix( + transitionX: number, + transitionY: number, + rotation: number, + scaleX: number, + scaleY: number, + out = SimpleMat3.create(), + ): T { + SimpleMat3.setIdentity(out.data); + + return SimpleMat3.translate( + SimpleMat3.rotate( + SimpleMat3.scale( + out, + scaleX, + scaleY, + out, + ), + rotation, + out, + ), + transitionX, + transitionY, + out, + ); + } + + public equals(mat: Mat3): boolean { + if (!mat) { + return false; + } + + return this.equalsArray(mat.data); + } + + public static scale(a: SimpleMat3, x: number, y: number, out = SimpleMat3.create()): T { + out.data[0] = x * a.data[0]; + out.data[1] = x * a.data[1]; + out.data[2] = x * a.data[2]; + out.data[3] = y * a.data[3]; + out.data[4] = y * a.data[4]; + out.data[5] = y * a.data[5]; + out.data[6] = a.data[6]; + out.data[7] = a.data[7]; + out.data[8] = a.data[8]; + + return out as T; + } +} diff --git a/src/math/simple-mat4.ts b/src/math/simple-mat4.ts new file mode 100644 index 00000000..75b25562 --- /dev/null +++ b/src/math/simple-mat4.ts @@ -0,0 +1,299 @@ +import { Mat4 } from "./mat4"; +import { Quaternion } from "./quaternion"; +import { ReadonlySimpleVector3, SimpleVector3 } from "./simple-vector3"; +import { Vector3 } from "./vector3"; + +/** + * https://github.com/mrdoob/three.js/blob/dev/src/math/Matrix4.js + * https://github.com/BennyQBD/3DEngineCpp/blob/master/src/core/math3d.h + * https://glmatrix.net/docs/mat4.js.html + * https://github.com/fynnfluegge/oreon-engine/blob/master/oreonengine/oe-core/src/main/java/org/oreon/core/math/Matrix4f.java + * + * 00 04 08 12 + * 01 05 09 13 + * 02 06 10 14 + * 03 07 11 14 + */ +export class SimpleMat4 { + public constructor(public readonly data: number[]) { + } + + public set(x: number, y: number, value: number): void { + this.data[x * 4 + y] = value; + } + + public get(x: number, y: number): number { + return this.data[x * 4 + y]; + } + + public getTranslation(): SimpleVector3 { + return { + x: this.data[12], + y: this.data[13], + z: this.data[14], + }; + } + + public getScale(): SimpleVector3 { + return { + x: this.data[0], + y: this.data[5], + z: this.data[10], + }; + } + + public equalsArray(data: number[]): boolean { + if (!data?.length) { + return false; + } + + for (let i = 0; i < 16; i++) { + if (data[i] !== this.data[i]) { + return false; + } + } + + return true; + } + + public equals(mat: Mat4): boolean { + if (!mat) { + return false; + } + + return this.equalsArray(mat.data); + } + + public static create(): SimpleMat4 { + return new SimpleMat4([ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1, + ]); + } + + public static setIdentity(result: SimpleMat4): SimpleMat4 { + result.data[0] = 1; + result.data[1] = 0; + result.data[2] = 0; + result.data[3] = 0; + result.data[4] = 0; + result.data[5] = 1; + result.data[6] = 0; + result.data[7] = 0; + result.data[8] = 0; + result.data[9] = 0; + result.data[10] = 1; + result.data[11] = 0; + result.data[12] = 0; + result.data[13] = 0; + result.data[14] = 0; + result.data[15] = 1; + + return result; + } + + private static setTranslation(x: number, y: number, z: number, result: number[]): number[] { + result[12] = x; + result[13] = y; + result[14] = z; + + return result; + } + + private static setScale(x: number, y: number, z: number, result: number[]): number[] { + result[0] = x; + result[5] = y; + result[10] = z; + + return result; + } + + public static fromTranslation(translation: SimpleVector3, result = SimpleMat4.create()): SimpleMat4 { + Mat4.setIdentity(result); + Mat4.setTranslation(translation.x, translation.y, translation.z, result.data); + + return result; + } + + public static fromScale(scale: SimpleVector3, result = SimpleMat4.create()): SimpleMat4 { + Mat4.setIdentity(result); + Mat4.setScale(scale.x, scale.y, scale.z, result.data); + + return result; + } + + public static from( + param: { + scale?: SimpleVector3 | [number, number, number]; + translation?: SimpleVector3 | [number, number, number]; + rotation?: Quaternion; + angle?: number; + axes?: number | SimpleVector3; + rotX?: number; + rotY?: number; + rotZ?: number; + }, + result = SimpleMat4.create()): SimpleMat4 { + + Mat4.setIdentity(result); + + if (param.translation) { + if (Vector3.isVector(param.translation)) { + Mat4.setTranslation(param.translation.x, param.translation.y, param.translation.z, result.data); + } else { + Mat4.setTranslation(param.translation[0], param.translation[1], param.translation[2], result.data); + } + } + + if (param.scale) { + if (Vector3.isVector(param.scale)) { + Mat4.setScale(param.scale.x, param.scale.y, param.scale.z, result.data); + } else { + Mat4.setScale(param.scale[0], param.scale[1], param.scale[2], result.data); + } + } + + return result; + } + + public static fromQuaternion(v: Quaternion, result = SimpleMat4.create()): SimpleMat4 { + const x2 = v.x + v.x; + const y2 = v.y + v.y; + const z2 = v.z + v.z; + const xx = v.x * x2; + const xy = v.x * y2; + const xz = v.x * z2; + const yy = v.y * y2; + const yz = v.y * z2; + const zz = v.z * z2; + const wx = v.w * x2; + const wy = v.w * y2; + const wz = v.w * z2; + + result.data[0] = 1 - (yy + zz); + result.data[1] = xy + wz; + result.data[2] = xz - wy; + result.data[3] = 0; + result.data[4] = xy - wz; + result.data[5] = 1 - (xx + zz); + result.data[6] = yz + wx; + result.data[7] = 0; + result.data[8] = xz + wy; + result.data[9] = yz - wx; + result.data[10] = 1 - (xx + yy); + result.data[11] = 0; + result.data[12] = v.x; + result.data[13] = v.y; + result.data[14] = v.z; + result.data[15] = 1; + + return result; + } + + public static fromRotation(rad: number, axis: SimpleVector3, result = SimpleMat4.create()): SimpleMat4 | null { + let len = Math.hypot(axis.x, axis.y, axis.z); + if (len < Number.EPSILON) { + return null; + } + len = 1 / len; + const x = axis.x * len; + const y = axis.y * len; + const z = axis.z * len; + const s = Math.sin(rad); + const c = Math.cos(rad); + const t = 1 - c; + + result.data[0] = x * x * t + c; + result.data[1] = y * x * t + z * s; + result.data[2] = z * x * t - y * s; + result.data[3] = 0; + result.data[4] = x * y * t - z * s; + result.data[5] = y * y * t + c; + result.data[6] = z * y * t + x * s; + result.data[7] = 0; + result.data[8] = x * z * t + y * s; + result.data[9] = y * z * t - x * s; + result.data[10] = z * z * t + c; + result.data[11] = 0; + result.data[12] = 0; + result.data[13] = 0; + result.data[14] = 0; + result.data[15] = 1; + + return result; + } + + private static staticSetAngleRotation(sin: number, cos: number, axe: "X" | "Y" | "Z", mat: SimpleMat4): SimpleMat4 { + Mat4.setIdentity(mat); + const data = mat.data; + + switch (axe) { + case "X": + data[5] = cos; + data[6] = sin; + data[9] = -sin; + data[10] = cos; + + return data; + case "Y": + data[0] = cos; + data[2] = -sin; + data[8] = sin; + data[10] = cos; + + return data; + case "Z": + data[0] = cos; + data[1] = sin; + data[4] = -sin; + data[5] = cos; + + return data; + default: + throw new Error(`Unknown axe ${axe}`); + } + } + + public static fromXRotation(rad: number, result = SimpleMat4.create()): SimpleMat4 { + return Mat4.staticSetAngleRotation(Math.sin(rad), Math.cos(rad), "X", result); + } + + public static fromYRotation(rad: number, result = SimpleMat4.create()): SimpleMat4 { + return Mat4.staticSetAngleRotation(Math.sin(rad), Math.cos(rad), "Y", result); + } + + public static fromZRotation(rad: number, result = SimpleMat4.create()): SimpleMat4 { + return Mat4.staticSetAngleRotation(Math.sin(rad), Math.cos(rad), "Z", result); + } + + public transformVector(a: SimpleVector3): SimpleVector3 { + const m = this.data; + const x = a.x; + const y = a.y; + const z = a.z; + let w = m[3] * x + m[7] * y + m[11] * z + m[15]; + w = w || 1; + a.x = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w; + a.y = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w; + a.z = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w; + + return a; + } + + public getTransformedVector(a: ReadonlySimpleVector3): SimpleVector3 { + const m = this.data; + const x = a.x; + const y = a.y; + const z = a.z; + let w = m[3] * x + m[7] * y + m[11] * z + m[15]; + w = w || 1; + + return { + x: (m[0] * x + m[4] * y + m[8] * z + m[12]) / w, + y: (m[1] * x + m[5] * y + m[9] * z + m[13]) / w, + z: (m[2] * x + m[6] * y + m[10] * z + m[14]) / w, + }; + } +}