UNPKG

ts-ritofile

Version:

TypeScript library for reading and writing League of Legends game file formats

227 lines (201 loc) 9.54 kB
import { JsonSerializable } from '../core/json-encoder'; import { Vector } from './vector'; import { Quaternion } from './quaternion'; export class Matrix4 implements JsonSerializable { public a: number; public b: number; public c: number; public d: number; public e: number; public f: number; public g: number; public h: number; public i: number; public j: number; public k: number; public l: number; public m: number; public n: number; public o: number; public p: number; constructor(...values: number[]) { if (values.length === 16) { [this.a, this.b, this.c, this.d, this.e, this.f, this.g, this.h, this.i, this.j, this.k, this.l, this.m, this.n, this.o, this.p] = values; } else { // Identity matrix this.a = this.f = this.k = this.p = 1.0; this.b = this.c = this.d = this.e = this.g = this.h = this.i = this.j = this.l = this.m = this.n = this.o = 0.0; } } get(index: number): number { return [ this.a, this.b, this.c, this.d, this.e, this.f, this.g, this.h, this.i, this.j, this.k, this.l, this.m, this.n, this.o, this.p ][index]; } set(index: number, value: number): void { const values = this.toArray(); values[index] = value; [this.a, this.b, this.c, this.d, this.e, this.f, this.g, this.h, this.i, this.j, this.k, this.l, this.m, this.n, this.o, this.p] = values; } multiply(other: Matrix4): Matrix4 { return new Matrix4( this.a * other.a + this.b * other.e + this.c * other.i + this.d * other.m, this.a * other.b + this.b * other.f + this.c * other.j + this.d * other.n, this.a * other.c + this.b * other.g + this.c * other.k + this.d * other.o, this.a * other.d + this.b * other.h + this.c * other.l + this.d * other.p, this.e * other.a + this.f * other.e + this.g * other.i + this.h * other.m, this.e * other.b + this.f * other.f + this.g * other.j + this.h * other.n, this.e * other.c + this.f * other.g + this.g * other.k + this.h * other.o, this.e * other.d + this.f * other.h + this.g * other.l + this.h * other.p, this.i * other.a + this.j * other.e + this.k * other.i + this.l * other.m, this.i * other.b + this.j * other.f + this.k * other.j + this.l * other.n, this.i * other.c + this.j * other.g + this.k * other.k + this.l * other.o, this.i * other.d + this.j * other.h + this.k * other.l + this.l * other.p, this.m * other.a + this.n * other.e + this.o * other.i + this.p * other.m, this.m * other.b + this.n * other.f + this.o * other.j + this.p * other.n, this.m * other.c + this.n * other.g + this.o * other.k + this.p * other.o, this.m * other.d + this.n * other.h + this.o * other.l + this.p * other.p ); } inverse(): Matrix4 { const d = ( (this.a * this.f - this.e * this.b) * (this.k * this.p - this.o * this.l) - (this.a * this.j - this.i * this.b) * (this.g * this.p - this.o * this.h) + (this.a * this.n - this.m * this.b) * (this.g * this.l - this.k * this.h) + (this.e * this.j - this.i * this.f) * (this.c * this.p - this.o * this.d) - (this.e * this.n - this.m * this.f) * (this.c * this.l - this.k * this.d) + (this.i * this.n - this.m * this.j) * (this.c * this.h - this.g * this.d) ); const inv = new Matrix4(); if (Math.abs(d) >= 0.001) { const invD = 1.0 / d; inv.a = invD * (this.f * (this.k * this.p - this.o * this.l) + this.j * ( this.o * this.h - this.g * this.p) + this.n * (this.g * this.l - this.k * this.h)); inv.e = invD * (this.g * (this.i * this.p - this.m * this.l) + this.k * ( this.m * this.h - this.e * this.p) + this.o * (this.e * this.l - this.i * this.h)); inv.i = invD * (this.h * (this.i * this.n - this.m * this.j) + this.l * ( this.m * this.f - this.e * this.n) + this.p * (this.e * this.j - this.i * this.f)); inv.m = invD * (this.e * (this.n * this.k - this.j * this.o) + this.i * ( this.f * this.o - this.n * this.g) + this.m * (this.j * this.g - this.f * this.k)); inv.b = invD * (this.j * (this.c * this.p - this.o * this.d) + this.n * ( this.k * this.d - this.c * this.l) + this.b * (this.o * this.l - this.k * this.p)); inv.f = invD * (this.k * (this.a * this.p - this.m * this.d) + this.o * ( this.i * this.d - this.a * this.l) + this.c * (this.m * this.l - this.i * this.p)); inv.j = invD * (this.l * (this.a * this.n - this.m * this.b) + this.p * ( this.i * this.b - this.a * this.j) + this.d * (this.m * this.j - this.i * this.n)); inv.n = invD * (this.i * (this.n * this.c - this.b * this.o) + this.m * ( this.b * this.k - this.j * this.c) + this.a * (this.j * this.o - this.n * this.k)); inv.c = invD * (this.n * (this.c * this.h - this.g * this.d) + this.b * ( this.g * this.p - this.o * this.h) + this.f * (this.o * this.d - this.c * this.p)); inv.g = invD * (this.o * (this.a * this.h - this.e * this.d) + this.c * ( this.e * this.p - this.m * this.h) + this.g * (this.m * this.d - this.a * this.p)); inv.k = invD * (this.p * (this.a * this.f - this.e * this.b) + this.d * ( this.e * this.n - this.m * this.f) + this.h * (this.m * this.b - this.a * this.n)); inv.o = invD * (this.m * (this.f * this.c - this.b * this.g) + this.a * ( this.n * this.g - this.f * this.o) + this.e * (this.b * this.o - this.n * this.c)); inv.d = invD * (this.b * (this.k * this.h - this.g * this.l) + this.f * ( this.c * this.l - this.k * this.d) + this.j * (this.g * this.d - this.c * this.h)); inv.h = invD * (this.c * (this.i * this.h - this.e * this.l) + this.g * ( this.a * this.l - this.i * this.d) + this.k * (this.e * this.d - this.a * this.h)); inv.l = invD * (this.d * (this.i * this.f - this.e * this.j) + this.h * ( this.a * this.j - this.i * this.b) + this.l * (this.e * this.b - this.a * this.f)); inv.p = invD * (this.a * (this.f * this.k - this.j * this.g) + this.e * ( this.j * this.c - this.b * this.k) + this.i * (this.b * this.g - this.f * this.c)); } // else: return identity anyway return inv; } decompose(): { translate: Vector; rotate: Quaternion; scale: Vector } { // this only support scale (1.0, 1.0, 1.0) // but we only use for update old skl, so its enough const translate = new Vector(this.m, this.n, this.o); const scale = new Vector( this.p * Math.sqrt(this.a**2 + this.b**2 + this.c**2), this.p * Math.sqrt(this.e**2 + this.f**2 + this.g**2), this.p * Math.sqrt(this.i**2 + this.j**2 + this.k**2) ); const rMat = new Matrix4( this.a/scale.x!, this.b/scale.y!, this.c/scale.z!, 0, this.e/scale.x!, this.f/scale.y!, this.g/scale.z!, 0, this.i/scale.x!, this.j/scale.y!, this.k/scale.z!, 0, 0, 0, 0, 1 ); const dott = (rMat.b * rMat.g - rMat.c * rMat.f) * rMat.i + (rMat.c * rMat.e - rMat.a * rMat.g) * rMat.j + (rMat.a * rMat.f - rMat.b * rMat.e) * rMat.k; if (dott < 0) { scale.x! *= -1; rMat.a *= -1; rMat.b *= -1; rMat.c *= -1; } const trace = rMat.a + rMat.f + rMat.k; let rotate: Quaternion; if (trace > 0.00000001) { const s = Math.sqrt(trace + 1.0); const iS = 0.5 / s; rotate = new Quaternion( (rMat.g - rMat.j) * iS, (rMat.i - rMat.c) * iS, (rMat.b - rMat.e) * iS, s * 0.5 ); } else { if (rMat.a >= rMat.f && rMat.a >= rMat.k) { const s = Math.sqrt(1.0 + rMat.a - rMat.f - rMat.k); const iS = 0.5 / s; rotate = new Quaternion( 0.5 * s, (rMat.b + rMat.e) * iS, (rMat.i + rMat.c) * iS, (rMat.g - rMat.j) * iS, ); } else if (rMat.f > rMat.k) { const s = Math.sqrt(1.0 + rMat.f - rMat.a - rMat.k); const iS = 0.5 / s; rotate = new Quaternion( (rMat.e + rMat.b) * iS, 0.5 * s, (rMat.j + rMat.g) * iS, (rMat.c - rMat.i) * iS ); } else { const s = Math.sqrt(1.0 + rMat.k - rMat.a - rMat.f); const iS = 0.5 / s; rotate = new Quaternion( (rMat.c + rMat.i) * iS, (rMat.j + rMat.g) * iS, 0.5 * s, (rMat.b - rMat.e) * iS ); } } return { translate, rotate, scale }; } toString(): string { return [ `${this.a.toFixed(4)} ${this.b.toFixed(4)} ${this.c.toFixed(4)} ${this.d.toFixed(4)}`, `${this.e.toFixed(4)} ${this.f.toFixed(4)} ${this.g.toFixed(4)} ${this.h.toFixed(4)}`, `${this.i.toFixed(4)} ${this.j.toFixed(4)} ${this.k.toFixed(4)} ${this.l.toFixed(4)}`, `${this.m.toFixed(4)} ${this.n.toFixed(4)} ${this.o.toFixed(4)} ${this.p.toFixed(4)}` ].join('\n'); } toArray(): number[] { return [ this.a, this.b, this.c, this.d, this.e, this.f, this.g, this.h, this.i, this.j, this.k, this.l, this.m, this.n, this.o, this.p ]; } __json__(): number[] { return this.toArray(); } // Keep toJSON for standard JavaScript compatibility toJSON(): number[] { return this.__json__(); } }