UNPKG

@lightningtv/renderer

Version:
245 lines (229 loc) 6.24 kB
/* * If not stated otherwise in this file or this component's LICENSE file the * following copyright and licenses apply: * * Copyright 2023 Comcast Cable Communications Management, LLC. * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * A 3D matrix representing a 2D graphics transformation * * @remarks * For convenience, entries in the first two rows can be accessed by the following * properties: * | ta tb tx | * | tc td ty | * | 0 0 1 | * * This matrix is optimized for 2D transformations and hence the last row will * always be considered [0, 0 ,1]. * * To access a column major array for WebGL, use the {@link getFloatArr} method. */ export class Matrix3d { public ta: number; public tb: number; public tx: number; public tc: number; public td: number; public ty: number; private _floatArr: Float32Array | null = null; /** * Potential Mutation Flag * * @remarks * This flag is set to true whenever the matrix is potentially modified. * We don't waste CPU trying to identify if each operation actually modifies * the matrix. Instead, we set this flag to true whenever we think the matrix * is modified. This signals that the `floatArr` should to be updated. */ private mutation: boolean; /** * Creates a new 3x3 matrix. * * @param entries Row-major 3x3 matrix */ public constructor() { this.ta = 0; this.tb = 0; this.tx = 0; this.tc = 0; this.td = 0; this.ty = 0; this.mutation = true; } /** * Returns a temporary matrix that can be used for calculations. * * @remarks * This is useful for avoiding allocations in tight loops. * * The matrix is not guaranteed to be the same between calls. * * @returns */ public static get temp(): Matrix3d { return tempMatrix; } public static multiply(a: Matrix3d, b: Matrix3d, out?: Matrix3d): Matrix3d { const e0 = a.ta * b.ta + a.tb * b.tc; const e1 = a.ta * b.tb + a.tb * b.td; const e2 = a.ta * b.tx + a.tb * b.ty + a.tx; const e3 = a.tc * b.ta + a.td * b.tc; const e4 = a.tc * b.tb + a.td * b.td; const e5 = a.tc * b.tx + a.td * b.ty + a.ty; if (!out) { out = new Matrix3d(); } out.ta = e0; out.tb = e1; out.tx = e2; out.tc = e3; out.td = e4; out.ty = e5; out.mutation = true; return out; } public static identity(out?: Matrix3d): Matrix3d { if (!out) { out = new Matrix3d(); } out.ta = 1; out.tb = 0; out.tx = 0; out.tc = 0; out.td = 1; out.ty = 0; out.mutation = true; return out; } public static translate(x: number, y: number, out?: Matrix3d): Matrix3d { if (!out) { out = new Matrix3d(); } out.ta = 1; out.tb = 0; out.tx = x; out.tc = 0; out.td = 1; out.ty = y; out.mutation = true; return out; } public static scale(sx: number, sy: number, out?: Matrix3d): Matrix3d { if (!out) { out = new Matrix3d(); } out.ta = sx; out.tb = 0; out.tx = 0; out.tc = 0; out.td = sy; out.ty = 0; out.mutation = true; return out; } public static rotate(angle: number, out?: Matrix3d): Matrix3d { const cos = Math.cos(angle); const sin = Math.sin(angle); if (!out) { out = new Matrix3d(); } out.ta = cos; out.tb = -sin; out.tx = 0; out.tc = sin; out.td = cos; out.ty = 0; out.mutation = true; return out; } public static copy(src: Matrix3d, dst?: Matrix3d): Matrix3d { if (!dst) { dst = new Matrix3d(); } dst.ta = src.ta; dst.tc = src.tc; dst.tb = src.tb; dst.td = src.td; dst.tx = src.tx; dst.ty = src.ty; dst.mutation = true; return dst; } public translate(x: number, y: number): Matrix3d { this.tx = this.ta * x + this.tb * y + this.tx; this.ty = this.tc * x + this.td * y + this.ty; this.mutation = true; return this; } public scale(sx: number, sy: number): Matrix3d { this.ta = this.ta * sx; this.tb = this.tb * sy; this.tc = this.tc * sx; this.td = this.td * sy; this.mutation = true; return this; } public rotate(angle: number): Matrix3d { if (angle === 0 || !((angle % Math.PI) * 2)) { return this; } const cos = Math.cos(angle); const sin = Math.sin(angle); const e0 = this.ta * cos + this.tb * sin; const e1 = this.tb * cos - this.ta * sin; const e3 = this.tc * cos + this.td * sin; const e4 = this.td * cos - this.tc * sin; this.ta = e0; this.tb = e1; this.tc = e3; this.td = e4; this.mutation = true; return this; } public multiply(other: Matrix3d): Matrix3d { return Matrix3d.multiply(this, other, this); } /** * Returns the matrix as a Float32Array in column-major order. * * @remarks * This method is optimized to avoid unnecessary allocations. The same array * is returned every time this method is called, and is updated in place. * * WARNING: Use the array only for passing directly to a WebGL shader uniform * during a frame render. Do not modify or hold onto the array for longer than * a frame. */ getFloatArr(): Float32Array { if (!this._floatArr) { this._floatArr = new Float32Array(9); } if (this.mutation) { this._floatArr[0] = this.ta; this._floatArr[1] = this.tc; this._floatArr[2] = 0; this._floatArr[3] = this.tb; this._floatArr[4] = this.td; this._floatArr[5] = 0; this._floatArr[6] = this.tx; this._floatArr[7] = this.ty; this._floatArr[8] = 1; this.mutation = false; } return this._floatArr; } } const tempMatrix = new Matrix3d();