@deck.gl/mesh-layers
Version:
deck.gl layers that loads 3D meshes or scene graphs
1,730 lines (1,685 loc) • 513 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if (typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if (typeof define === 'function' && define.amd) define([], factory);
else if (typeof exports === 'object') exports['deck'] = factory();
else root['deck'] = factory();})(globalThis, function () {
"use strict";
var __exports__ = (() => {
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __export = (target, all) => {
for (var name12 in all)
__defProp(target, name12, { get: all[name12], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// external-global-plugin:@deck.gl/core
var require_core = __commonJS({
"external-global-plugin:@deck.gl/core"(exports, module) {
module.exports = globalThis.deck;
}
});
// external-global-plugin:@luma.gl/core
var require_core2 = __commonJS({
"external-global-plugin:@luma.gl/core"(exports, module) {
module.exports = globalThis.luma;
}
});
// external-global-plugin:@luma.gl/engine
var require_engine = __commonJS({
"external-global-plugin:@luma.gl/engine"(exports, module) {
module.exports = globalThis.luma;
}
});
// bundle.ts
var bundle_exports = {};
__export(bundle_exports, {
ScenegraphLayer: () => ScenegraphLayer,
SimpleMeshLayer: () => SimpleMeshLayer
});
// ../core/bundle/peer-dependency.ts
var peer_dependency_exports = {};
var import_core = __toESM(require_core(), 1);
__reExport(peer_dependency_exports, __toESM(require_core(), 1));
if (!import_core.Layer) {
throw new Error("@deck.gl/core is not found");
}
// bundle.ts
__reExport(bundle_exports, peer_dependency_exports);
// src/simple-mesh-layer/simple-mesh-layer.ts
var import_core3 = __toESM(require_core(), 1);
var import_core4 = __toESM(require_core2(), 1);
var import_engine = __toESM(require_engine(), 1);
// src/utils/matrix.ts
var import_core2 = __toESM(require_core(), 1);
var RADIAN_PER_DEGREE = Math.PI / 180;
var modelMatrix = new Float32Array(16);
var valueArray = new Float32Array(12);
function calculateTransformMatrix(targetMatrix, orientation, scale5) {
const pitch = orientation[0] * RADIAN_PER_DEGREE;
const yaw = orientation[1] * RADIAN_PER_DEGREE;
const roll = orientation[2] * RADIAN_PER_DEGREE;
const sr = Math.sin(roll);
const sp = Math.sin(pitch);
const sw = Math.sin(yaw);
const cr = Math.cos(roll);
const cp = Math.cos(pitch);
const cw = Math.cos(yaw);
const scx = scale5[0];
const scy = scale5[1];
const scz = scale5[2];
targetMatrix[0] = scx * cw * cp;
targetMatrix[1] = scx * sw * cp;
targetMatrix[2] = scx * -sp;
targetMatrix[3] = scy * (-sw * cr + cw * sp * sr);
targetMatrix[4] = scy * (cw * cr + sw * sp * sr);
targetMatrix[5] = scy * cp * sr;
targetMatrix[6] = scz * (sw * sr + cw * sp * cr);
targetMatrix[7] = scz * (-cw * sr + sw * sp * cr);
targetMatrix[8] = scz * cp * cr;
}
function getExtendedMat3FromMat4(mat4) {
mat4[0] = mat4[0];
mat4[1] = mat4[1];
mat4[2] = mat4[2];
mat4[3] = mat4[4];
mat4[4] = mat4[5];
mat4[5] = mat4[6];
mat4[6] = mat4[8];
mat4[7] = mat4[9];
mat4[8] = mat4[10];
mat4[9] = mat4[12];
mat4[10] = mat4[13];
mat4[11] = mat4[14];
return mat4.subarray(0, 12);
}
var MATRIX_ATTRIBUTES = {
size: 12,
accessor: ["getOrientation", "getScale", "getTranslation", "getTransformMatrix"],
shaderAttributes: {
instanceModelMatrixCol0: {
size: 3,
elementOffset: 0
},
instanceModelMatrixCol1: {
size: 3,
elementOffset: 3
},
instanceModelMatrixCol2: {
size: 3,
elementOffset: 6
},
instanceTranslation: {
size: 3,
elementOffset: 9
}
},
update(attribute, { startRow, endRow }) {
const { data, getOrientation, getScale, getTranslation, getTransformMatrix } = this.props;
const arrayMatrix = Array.isArray(getTransformMatrix);
const constantMatrix = arrayMatrix && getTransformMatrix.length === 16;
const constantScale = Array.isArray(getScale);
const constantOrientation = Array.isArray(getOrientation);
const constantTranslation = Array.isArray(getTranslation);
const hasMatrix = constantMatrix || !arrayMatrix && Boolean(getTransformMatrix(data[0]));
if (hasMatrix) {
attribute.constant = constantMatrix;
} else {
attribute.constant = constantOrientation && constantScale && constantTranslation;
}
const instanceModelMatrixData = attribute.value;
if (attribute.constant) {
let matrix;
if (hasMatrix) {
modelMatrix.set(getTransformMatrix);
matrix = getExtendedMat3FromMat4(modelMatrix);
} else {
matrix = valueArray;
const orientation = getOrientation;
const scale5 = getScale;
calculateTransformMatrix(matrix, orientation, scale5);
matrix.set(getTranslation, 9);
}
attribute.value = new Float32Array(matrix);
} else {
let i = startRow * attribute.size;
const { iterable, objectInfo } = (0, import_core2.createIterable)(data, startRow, endRow);
for (const object of iterable) {
objectInfo.index++;
let matrix;
if (hasMatrix) {
modelMatrix.set(
constantMatrix ? getTransformMatrix : getTransformMatrix(object, objectInfo)
);
matrix = getExtendedMat3FromMat4(modelMatrix);
} else {
matrix = valueArray;
const orientation = constantOrientation ? getOrientation : getOrientation(object, objectInfo);
const scale5 = constantScale ? getScale : getScale(object, objectInfo);
calculateTransformMatrix(matrix, orientation, scale5);
matrix.set(constantTranslation ? getTranslation : getTranslation(object, objectInfo), 9);
}
instanceModelMatrixData[i++] = matrix[0];
instanceModelMatrixData[i++] = matrix[1];
instanceModelMatrixData[i++] = matrix[2];
instanceModelMatrixData[i++] = matrix[3];
instanceModelMatrixData[i++] = matrix[4];
instanceModelMatrixData[i++] = matrix[5];
instanceModelMatrixData[i++] = matrix[6];
instanceModelMatrixData[i++] = matrix[7];
instanceModelMatrixData[i++] = matrix[8];
instanceModelMatrixData[i++] = matrix[9];
instanceModelMatrixData[i++] = matrix[10];
instanceModelMatrixData[i++] = matrix[11];
}
}
}
};
function shouldComposeModelMatrix(viewport, coordinateSystem) {
return coordinateSystem === "cartesian" || coordinateSystem === "meter-offsets" || coordinateSystem === "default" && !viewport.isGeospatial;
}
// src/simple-mesh-layer/simple-mesh-layer-uniforms.ts
var uniformBlock = `layout(std140) uniform simpleMeshUniforms {
float sizeScale;
bool composeModelMatrix;
bool hasTexture;
bool flatShading;
} simpleMesh;
`;
var simpleMeshUniforms = {
name: "simpleMesh",
vs: uniformBlock,
fs: uniformBlock,
uniformTypes: {
sizeScale: "f32",
composeModelMatrix: "f32",
hasTexture: "f32",
flatShading: "f32"
}
};
// src/simple-mesh-layer/simple-mesh-layer-vertex.glsl.ts
var simple_mesh_layer_vertex_glsl_default = `#version 300 es
#define SHADER_NAME simple-mesh-layer-vs
// Primitive attributes
in vec3 positions;
in vec3 normals;
in vec3 colors;
in vec2 texCoords;
// Instance attributes
in vec3 instancePositions;
in vec3 instancePositions64Low;
in vec4 instanceColors;
in vec3 instancePickingColors;
in vec3 instanceModelMatrixCol0;
in vec3 instanceModelMatrixCol1;
in vec3 instanceModelMatrixCol2;
in vec3 instanceTranslation;
// Outputs to fragment shader
out vec2 vTexCoord;
out vec3 cameraPosition;
out vec3 normals_commonspace;
out vec4 position_commonspace;
out vec4 vColor;
void main(void) {
geometry.worldPosition = instancePositions;
geometry.uv = texCoords;
geometry.pickingColor = instancePickingColors;
vTexCoord = texCoords;
cameraPosition = project.cameraPosition;
vColor = vec4(colors * instanceColors.rgb, instanceColors.a);
mat3 instanceModelMatrix = mat3(instanceModelMatrixCol0, instanceModelMatrixCol1, instanceModelMatrixCol2);
vec3 pos = (instanceModelMatrix * positions) * simpleMesh.sizeScale + instanceTranslation;
if (simpleMesh.composeModelMatrix) {
DECKGL_FILTER_SIZE(pos, geometry);
// using instancePositions as world coordinates
// when using globe mode, this branch does not re-orient the model to align with the surface of the earth
// call project_normal before setting position to avoid rotation
normals_commonspace = project_normal(instanceModelMatrix * normals);
geometry.worldPosition += pos;
gl_Position = project_position_to_clipspace(pos + instancePositions, instancePositions64Low, vec3(0.0), position_commonspace);
geometry.position = position_commonspace;
}
else {
pos = project_size(pos);
DECKGL_FILTER_SIZE(pos, geometry);
gl_Position = project_position_to_clipspace(instancePositions, instancePositions64Low, pos, position_commonspace);
geometry.position = position_commonspace;
normals_commonspace = project_normal(instanceModelMatrix * normals);
}
geometry.normal = normals_commonspace;
DECKGL_FILTER_GL_POSITION(gl_Position, geometry);
DECKGL_FILTER_COLOR(vColor, geometry);
}
`;
// src/simple-mesh-layer/simple-mesh-layer-fragment.glsl.ts
var simple_mesh_layer_fragment_glsl_default = `#version 300 es
#define SHADER_NAME simple-mesh-layer-fs
precision highp float;
uniform sampler2D sampler;
in vec2 vTexCoord;
in vec3 cameraPosition;
in vec3 normals_commonspace;
in vec4 position_commonspace;
in vec4 vColor;
out vec4 fragColor;
void main(void) {
geometry.uv = vTexCoord;
vec3 normal;
if (simpleMesh.flatShading) {
normal = normalize(cross(dFdx(position_commonspace.xyz), dFdy(position_commonspace.xyz)));
} else {
normal = normals_commonspace;
}
vec4 color = simpleMesh.hasTexture ? texture(sampler, vTexCoord) : vColor;
DECKGL_FILTER_COLOR(color, geometry);
vec3 lightColor = lighting_getLightColor(color.rgb, cameraPosition, position_commonspace.xyz, normal);
fragColor = vec4(lightColor, color.a * layer.opacity);
}
`;
// ../../node_modules/@loaders.gl/schema/dist/deprecated/mesh-utils.js
function getMeshBoundingBox(attributes) {
let minX = Infinity;
let minY = Infinity;
let minZ = Infinity;
let maxX = -Infinity;
let maxY = -Infinity;
let maxZ = -Infinity;
const positions = attributes.POSITION ? attributes.POSITION.value : [];
const len2 = positions && positions.length;
for (let i = 0; i < len2; i += 3) {
const x = positions[i];
const y = positions[i + 1];
const z = positions[i + 2];
minX = x < minX ? x : minX;
minY = y < minY ? y : minY;
minZ = z < minZ ? z : minZ;
maxX = x > maxX ? x : maxX;
maxY = y > maxY ? y : maxY;
maxZ = z > maxZ ? z : maxZ;
}
return [
[minX, minY, minZ],
[maxX, maxY, maxZ]
];
}
// src/simple-mesh-layer/simple-mesh-layer.ts
function normalizeGeometryAttributes(attributes) {
const positionAttribute = attributes.positions || attributes.POSITION;
import_core3.log.assert(positionAttribute, 'no "postions" or "POSITION" attribute in mesh');
const vertexCount = positionAttribute.value.length / positionAttribute.size;
let colorAttribute = attributes.COLOR_0 || attributes.colors;
if (!colorAttribute) {
colorAttribute = { size: 3, value: new Float32Array(vertexCount * 3).fill(1) };
}
let normalAttribute = attributes.NORMAL || attributes.normals;
if (!normalAttribute) {
normalAttribute = { size: 3, value: new Float32Array(vertexCount * 3).fill(0) };
}
let texCoordAttribute = attributes.TEXCOORD_0 || attributes.texCoords;
if (!texCoordAttribute) {
texCoordAttribute = { size: 2, value: new Float32Array(vertexCount * 2).fill(0) };
}
return {
positions: positionAttribute,
colors: colorAttribute,
normals: normalAttribute,
texCoords: texCoordAttribute
};
}
function getGeometry(data) {
if (data instanceof import_engine.Geometry) {
data.attributes = normalizeGeometryAttributes(data.attributes);
return data;
} else if (data.attributes) {
return new import_engine.Geometry({
...data,
topology: "triangle-list",
attributes: normalizeGeometryAttributes(data.attributes)
});
} else {
return new import_engine.Geometry({
topology: "triangle-list",
attributes: normalizeGeometryAttributes(data)
});
}
}
var DEFAULT_COLOR = [0, 0, 0, 255];
var defaultProps = {
mesh: { type: "object", value: null, async: true },
texture: { type: "image", value: null, async: true },
sizeScale: { type: "number", value: 1, min: 0 },
// _instanced is a hack to use world position instead of meter offsets in mesh
// TODO - formalize API
_instanced: true,
// NOTE(Tarek): Quick and dirty wireframe. Just draws
// the same mesh with LINE_STRIPS. Won't follow edges
// of the original mesh.
wireframe: false,
// Optional material for 'lighting' shader module
material: true,
getPosition: { type: "accessor", value: (x) => x.position },
getColor: { type: "accessor", value: DEFAULT_COLOR },
// yaw, pitch and roll are in degrees
// https://en.wikipedia.org/wiki/Euler_angles
// [pitch, yaw, roll]
getOrientation: { type: "accessor", value: [0, 0, 0] },
getScale: { type: "accessor", value: [1, 1, 1] },
getTranslation: { type: "accessor", value: [0, 0, 0] },
// 4x4 matrix
getTransformMatrix: { type: "accessor", value: [] },
textureParameters: { type: "object", ignore: true, value: null }
};
var SimpleMeshLayer = class extends import_core3.Layer {
getShaders() {
return super.getShaders({
vs: simple_mesh_layer_vertex_glsl_default,
fs: simple_mesh_layer_fragment_glsl_default,
modules: [import_core3.project32, import_core3.phongMaterial, import_core3.picking, simpleMeshUniforms]
});
}
getBounds() {
if (this.props._instanced) {
return super.getBounds();
}
let result = this.state.positionBounds;
if (result) {
return result;
}
const { mesh } = this.props;
if (!mesh) {
return null;
}
result = mesh.header?.boundingBox;
if (!result) {
const { attributes } = getGeometry(mesh);
attributes.POSITION = attributes.POSITION || attributes.positions;
result = getMeshBoundingBox(attributes);
}
this.state.positionBounds = result;
return result;
}
initializeState() {
const attributeManager = this.getAttributeManager();
attributeManager.addInstanced({
instancePositions: {
transition: true,
type: "float64",
fp64: this.use64bitPositions(),
size: 3,
accessor: "getPosition"
},
instanceColors: {
type: "unorm8",
transition: true,
size: this.props.colorFormat.length,
accessor: "getColor",
defaultValue: [0, 0, 0, 255]
},
instanceModelMatrix: MATRIX_ATTRIBUTES
});
this.setState({
// Avoid luma.gl's missing uniform warning
// TODO - add feature to luma.gl to specify ignored uniforms?
emptyTexture: this.context.device.createTexture({
data: new Uint8Array(4),
width: 1,
height: 1
})
});
}
updateState(params) {
super.updateState(params);
const { props, oldProps, changeFlags } = params;
if (props.mesh !== oldProps.mesh || changeFlags.extensionsChanged) {
this.state.positionBounds = null;
this.state.model?.destroy();
if (props.mesh) {
this.state.model = this.getModel(props.mesh);
const attributes = props.mesh.attributes || props.mesh;
this.setState({
hasNormals: Boolean(attributes.NORMAL || attributes.normals)
});
}
this.getAttributeManager().invalidateAll();
}
if (props.texture !== oldProps.texture && props.texture instanceof import_core4.Texture) {
this.setTexture(props.texture);
}
if (this.state.model) {
this.state.model.setTopology(this.props.wireframe ? "line-strip" : "triangle-list");
}
}
finalizeState(context) {
super.finalizeState(context);
this.state.emptyTexture.delete();
}
draw({ uniforms }) {
const { model } = this.state;
if (!model) {
return;
}
const { viewport, renderPass } = this.context;
const { sizeScale, coordinateSystem, _instanced } = this.props;
const simpleMeshProps = {
sizeScale,
composeModelMatrix: !_instanced || shouldComposeModelMatrix(viewport, coordinateSystem),
flatShading: !this.state.hasNormals
};
model.shaderInputs.setProps({ simpleMesh: simpleMeshProps });
model.draw(renderPass);
}
get isLoaded() {
return Boolean(this.state?.model && super.isLoaded);
}
getModel(mesh) {
const model = new import_engine.Model(this.context.device, {
...this.getShaders(),
id: this.props.id,
bufferLayout: this.getAttributeManager().getBufferLayouts(),
geometry: getGeometry(mesh),
isInstanced: true
});
const { texture } = this.props;
const { emptyTexture } = this.state;
const simpleMeshProps = {
sampler: texture || emptyTexture,
hasTexture: Boolean(texture)
};
model.shaderInputs.setProps({ simpleMesh: simpleMeshProps });
return model;
}
setTexture(texture) {
const { emptyTexture, model } = this.state;
if (model) {
const simpleMeshProps = {
sampler: texture || emptyTexture,
hasTexture: Boolean(texture)
};
model.shaderInputs.setProps({ simpleMesh: simpleMeshProps });
}
}
};
SimpleMeshLayer.defaultProps = defaultProps;
SimpleMeshLayer.layerName = "SimpleMeshLayer";
// src/scenegraph-layer/scenegraph-layer.ts
var import_core16 = __toESM(require_core(), 1);
// ../../node_modules/@math.gl/core/dist/lib/common.js
var RADIANS_TO_DEGREES = 1 / Math.PI * 180;
var DEGREES_TO_RADIANS = 1 / 180 * Math.PI;
var DEFAULT_CONFIG = {
EPSILON: 1e-12,
debug: false,
precision: 4,
printTypes: false,
printDegrees: false,
printRowMajor: true,
_cartographicRadians: false
};
globalThis.mathgl = globalThis.mathgl || { config: { ...DEFAULT_CONFIG } };
var config = globalThis.mathgl.config;
function formatValue(value, { precision = config.precision } = {}) {
value = round(value);
return `${parseFloat(value.toPrecision(precision))}`;
}
function isArray(value) {
return Array.isArray(value) || ArrayBuffer.isView(value) && !(value instanceof DataView);
}
function equals(a, b, epsilon) {
const oldEpsilon = config.EPSILON;
if (epsilon) {
config.EPSILON = epsilon;
}
try {
if (a === b) {
return true;
}
if (isArray(a) && isArray(b)) {
if (a.length !== b.length) {
return false;
}
for (let i = 0; i < a.length; ++i) {
if (!equals(a[i], b[i])) {
return false;
}
}
return true;
}
if (a && a.equals) {
return a.equals(b);
}
if (b && b.equals) {
return b.equals(a);
}
if (typeof a === "number" && typeof b === "number") {
return Math.abs(a - b) <= config.EPSILON * Math.max(1, Math.abs(a), Math.abs(b));
}
return false;
} finally {
config.EPSILON = oldEpsilon;
}
}
function round(value) {
return Math.round(value / config.EPSILON) * config.EPSILON;
}
// ../../node_modules/@math.gl/core/dist/classes/base/math-array.js
var MathArray = class extends Array {
// Common methods
/**
* Clone the current object
* @returns a new copy of this object
*/
clone() {
return new this.constructor().copy(this);
}
fromArray(array, offset = 0) {
for (let i = 0; i < this.ELEMENTS; ++i) {
this[i] = array[i + offset];
}
return this.check();
}
toArray(targetArray = [], offset = 0) {
for (let i = 0; i < this.ELEMENTS; ++i) {
targetArray[offset + i] = this[i];
}
return targetArray;
}
toObject(targetObject) {
return targetObject;
}
from(arrayOrObject) {
return Array.isArray(arrayOrObject) ? this.copy(arrayOrObject) : (
// @ts-ignore
this.fromObject(arrayOrObject)
);
}
to(arrayOrObject) {
if (arrayOrObject === this) {
return this;
}
return isArray(arrayOrObject) ? this.toArray(arrayOrObject) : this.toObject(arrayOrObject);
}
toTarget(target) {
return target ? this.to(target) : this;
}
/** @deprecated */
toFloat32Array() {
return new Float32Array(this);
}
toString() {
return this.formatString(config);
}
/** Formats string according to options */
formatString(opts) {
let string = "";
for (let i = 0; i < this.ELEMENTS; ++i) {
string += (i > 0 ? ", " : "") + formatValue(this[i], opts);
}
return `${opts.printTypes ? this.constructor.name : ""}[${string}]`;
}
equals(array) {
if (!array || this.length !== array.length) {
return false;
}
for (let i = 0; i < this.ELEMENTS; ++i) {
if (!equals(this[i], array[i])) {
return false;
}
}
return true;
}
exactEquals(array) {
if (!array || this.length !== array.length) {
return false;
}
for (let i = 0; i < this.ELEMENTS; ++i) {
if (this[i] !== array[i]) {
return false;
}
}
return true;
}
// Modifiers
/** Negates all values in this object */
negate() {
for (let i = 0; i < this.ELEMENTS; ++i) {
this[i] = -this[i];
}
return this.check();
}
lerp(a, b, t) {
if (t === void 0) {
return this.lerp(this, a, b);
}
for (let i = 0; i < this.ELEMENTS; ++i) {
const ai = a[i];
const endValue = typeof b === "number" ? b : b[i];
this[i] = ai + t * (endValue - ai);
}
return this.check();
}
/** Minimal */
min(vector) {
for (let i = 0; i < this.ELEMENTS; ++i) {
this[i] = Math.min(vector[i], this[i]);
}
return this.check();
}
/** Maximal */
max(vector) {
for (let i = 0; i < this.ELEMENTS; ++i) {
this[i] = Math.max(vector[i], this[i]);
}
return this.check();
}
clamp(minVector, maxVector) {
for (let i = 0; i < this.ELEMENTS; ++i) {
this[i] = Math.min(Math.max(this[i], minVector[i]), maxVector[i]);
}
return this.check();
}
add(...vectors) {
for (const vector of vectors) {
for (let i = 0; i < this.ELEMENTS; ++i) {
this[i] += vector[i];
}
}
return this.check();
}
subtract(...vectors) {
for (const vector of vectors) {
for (let i = 0; i < this.ELEMENTS; ++i) {
this[i] -= vector[i];
}
}
return this.check();
}
scale(scale5) {
if (typeof scale5 === "number") {
for (let i = 0; i < this.ELEMENTS; ++i) {
this[i] *= scale5;
}
} else {
for (let i = 0; i < this.ELEMENTS && i < scale5.length; ++i) {
this[i] *= scale5[i];
}
}
return this.check();
}
/**
* Multiplies all elements by `scale`
* Note: `Matrix4.multiplyByScalar` only scales its 3x3 "minor"
*/
multiplyByScalar(scalar) {
for (let i = 0; i < this.ELEMENTS; ++i) {
this[i] *= scalar;
}
return this.check();
}
// Debug checks
/** Throws an error if array length is incorrect or contains illegal values */
check() {
if (config.debug && !this.validate()) {
throw new Error(`math.gl: ${this.constructor.name} some fields set to invalid numbers'`);
}
return this;
}
/** Returns false if the array length is incorrect or contains illegal values */
validate() {
let valid = this.length === this.ELEMENTS;
for (let i = 0; i < this.ELEMENTS; ++i) {
valid = valid && Number.isFinite(this[i]);
}
return valid;
}
// three.js compatibility
/** @deprecated */
sub(a) {
return this.subtract(a);
}
/** @deprecated */
setScalar(a) {
for (let i = 0; i < this.ELEMENTS; ++i) {
this[i] = a;
}
return this.check();
}
/** @deprecated */
addScalar(a) {
for (let i = 0; i < this.ELEMENTS; ++i) {
this[i] += a;
}
return this.check();
}
/** @deprecated */
subScalar(a) {
return this.addScalar(-a);
}
/** @deprecated */
multiplyScalar(scalar) {
for (let i = 0; i < this.ELEMENTS; ++i) {
this[i] *= scalar;
}
return this.check();
}
/** @deprecated */
divideScalar(a) {
return this.multiplyByScalar(1 / a);
}
/** @deprecated */
clampScalar(min, max) {
for (let i = 0; i < this.ELEMENTS; ++i) {
this[i] = Math.min(Math.max(this[i], min), max);
}
return this.check();
}
/** @deprecated */
get elements() {
return this;
}
};
// ../../node_modules/@math.gl/core/dist/lib/validators.js
function validateVector(v, length4) {
if (v.length !== length4) {
return false;
}
for (let i = 0; i < v.length; ++i) {
if (!Number.isFinite(v[i])) {
return false;
}
}
return true;
}
function checkNumber(value) {
if (!Number.isFinite(value)) {
throw new Error(`Invalid number ${JSON.stringify(value)}`);
}
return value;
}
function checkVector(v, length4, callerName = "") {
if (config.debug && !validateVector(v, length4)) {
throw new Error(`math.gl: ${callerName} some fields set to invalid numbers'`);
}
return v;
}
// ../../node_modules/@math.gl/core/dist/lib/assert.js
function assert(condition, message) {
if (!condition) {
throw new Error(`math.gl assertion ${message}`);
}
}
// ../../node_modules/@math.gl/core/dist/classes/base/vector.js
var Vector = class extends MathArray {
// ACCESSORS
get x() {
return this[0];
}
set x(value) {
this[0] = checkNumber(value);
}
get y() {
return this[1];
}
set y(value) {
this[1] = checkNumber(value);
}
/**
* Returns the length of the vector from the origin to the point described by this vector
*
* @note `length` is a reserved word for Arrays, so `v.length()` will return number of elements
* Instead we provide `len` and `magnitude`
*/
len() {
return Math.sqrt(this.lengthSquared());
}
/**
* Returns the length of the vector from the origin to the point described by this vector
*/
magnitude() {
return this.len();
}
/**
* Returns the squared length of the vector from the origin to the point described by this vector
*/
lengthSquared() {
let length4 = 0;
for (let i = 0; i < this.ELEMENTS; ++i) {
length4 += this[i] * this[i];
}
return length4;
}
/**
* Returns the squared length of the vector from the origin to the point described by this vector
*/
magnitudeSquared() {
return this.lengthSquared();
}
distance(mathArray) {
return Math.sqrt(this.distanceSquared(mathArray));
}
distanceSquared(mathArray) {
let length4 = 0;
for (let i = 0; i < this.ELEMENTS; ++i) {
const dist = this[i] - mathArray[i];
length4 += dist * dist;
}
return checkNumber(length4);
}
dot(mathArray) {
let product = 0;
for (let i = 0; i < this.ELEMENTS; ++i) {
product += this[i] * mathArray[i];
}
return checkNumber(product);
}
// MODIFIERS
normalize() {
const length4 = this.magnitude();
if (length4 !== 0) {
for (let i = 0; i < this.ELEMENTS; ++i) {
this[i] /= length4;
}
}
return this.check();
}
multiply(...vectors) {
for (const vector of vectors) {
for (let i = 0; i < this.ELEMENTS; ++i) {
this[i] *= vector[i];
}
}
return this.check();
}
divide(...vectors) {
for (const vector of vectors) {
for (let i = 0; i < this.ELEMENTS; ++i) {
this[i] /= vector[i];
}
}
return this.check();
}
// THREE.js compatibility
lengthSq() {
return this.lengthSquared();
}
distanceTo(vector) {
return this.distance(vector);
}
distanceToSquared(vector) {
return this.distanceSquared(vector);
}
getComponent(i) {
assert(i >= 0 && i < this.ELEMENTS, "index is out of range");
return checkNumber(this[i]);
}
setComponent(i, value) {
assert(i >= 0 && i < this.ELEMENTS, "index is out of range");
this[i] = value;
return this.check();
}
addVectors(a, b) {
return this.copy(a).add(b);
}
subVectors(a, b) {
return this.copy(a).subtract(b);
}
multiplyVectors(a, b) {
return this.copy(a).multiply(b);
}
addScaledVector(a, b) {
return this.add(new this.constructor(a).multiplyScalar(b));
}
};
// ../../node_modules/@math.gl/core/dist/gl-matrix/common.js
var EPSILON = 1e-6;
var ARRAY_TYPE = typeof Float32Array !== "undefined" ? Float32Array : Array;
var degree = Math.PI / 180;
// ../../node_modules/@math.gl/core/dist/gl-matrix/vec2.js
function create() {
const out = new ARRAY_TYPE(2);
if (ARRAY_TYPE != Float32Array) {
out[0] = 0;
out[1] = 0;
}
return out;
}
function transformMat3(out, a, m) {
const x = a[0];
const y = a[1];
out[0] = m[0] * x + m[3] * y + m[6];
out[1] = m[1] * x + m[4] * y + m[7];
return out;
}
function transformMat4(out, a, m) {
const x = a[0];
const y = a[1];
out[0] = m[0] * x + m[4] * y + m[12];
out[1] = m[1] * x + m[5] * y + m[13];
return out;
}
var forEach = function() {
const vec = create();
return function(a, stride, offset, count, fn, arg) {
let i;
let l;
if (!stride) {
stride = 2;
}
if (!offset) {
offset = 0;
}
if (count) {
l = Math.min(count * stride + offset, a.length);
} else {
l = a.length;
}
for (i = offset; i < l; i += stride) {
vec[0] = a[i];
vec[1] = a[i + 1];
fn(vec, vec, arg);
a[i] = vec[0];
a[i + 1] = vec[1];
}
return a;
};
}();
// ../../node_modules/@math.gl/core/dist/lib/gl-matrix-extras.js
function vec2_transformMat4AsVector(out, a, m) {
const x = a[0];
const y = a[1];
const w = m[3] * x + m[7] * y || 1;
out[0] = (m[0] * x + m[4] * y) / w;
out[1] = (m[1] * x + m[5] * y) / w;
return out;
}
function vec3_transformMat4AsVector(out, a, m) {
const x = a[0];
const y = a[1];
const z = a[2];
const w = m[3] * x + m[7] * y + m[11] * z || 1;
out[0] = (m[0] * x + m[4] * y + m[8] * z) / w;
out[1] = (m[1] * x + m[5] * y + m[9] * z) / w;
out[2] = (m[2] * x + m[6] * y + m[10] * z) / w;
return out;
}
function vec3_transformMat2(out, a, m) {
const x = a[0];
const y = a[1];
out[0] = m[0] * x + m[2] * y;
out[1] = m[1] * x + m[3] * y;
out[2] = a[2];
return out;
}
function vec4_transformMat2(out, a, m) {
const x = a[0];
const y = a[1];
out[0] = m[0] * x + m[2] * y;
out[1] = m[1] * x + m[3] * y;
out[2] = a[2];
out[3] = a[3];
return out;
}
function vec4_transformMat3(out, a, m) {
const x = a[0];
const y = a[1];
const z = a[2];
out[0] = m[0] * x + m[3] * y + m[6] * z;
out[1] = m[1] * x + m[4] * y + m[7] * z;
out[2] = m[2] * x + m[5] * y + m[8] * z;
out[3] = a[3];
return out;
}
// ../../node_modules/@math.gl/core/dist/gl-matrix/vec3.js
function create2() {
const out = new ARRAY_TYPE(3);
if (ARRAY_TYPE != Float32Array) {
out[0] = 0;
out[1] = 0;
out[2] = 0;
}
return out;
}
function length(a) {
const x = a[0];
const y = a[1];
const z = a[2];
return Math.sqrt(x * x + y * y + z * z);
}
function fromValues(x, y, z) {
const out = new ARRAY_TYPE(3);
out[0] = x;
out[1] = y;
out[2] = z;
return out;
}
function normalize(out, a) {
const x = a[0];
const y = a[1];
const z = a[2];
let len2 = x * x + y * y + z * z;
if (len2 > 0) {
len2 = 1 / Math.sqrt(len2);
}
out[0] = a[0] * len2;
out[1] = a[1] * len2;
out[2] = a[2] * len2;
return out;
}
function dot(a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
function cross(out, a, b) {
const ax = a[0];
const ay = a[1];
const az = a[2];
const bx = b[0];
const by = b[1];
const bz = b[2];
out[0] = ay * bz - az * by;
out[1] = az * bx - ax * bz;
out[2] = ax * by - ay * bx;
return out;
}
function transformMat42(out, a, m) {
const x = a[0];
const y = a[1];
const z = a[2];
let w = m[3] * x + m[7] * y + m[11] * z + m[15];
w = w || 1;
out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
return out;
}
function transformMat32(out, a, m) {
const x = a[0];
const y = a[1];
const z = a[2];
out[0] = x * m[0] + y * m[3] + z * m[6];
out[1] = x * m[1] + y * m[4] + z * m[7];
out[2] = x * m[2] + y * m[5] + z * m[8];
return out;
}
function transformQuat(out, a, q) {
const qx = q[0];
const qy = q[1];
const qz = q[2];
const qw = q[3];
const x = a[0];
const y = a[1];
const z = a[2];
let uvx = qy * z - qz * y;
let uvy = qz * x - qx * z;
let uvz = qx * y - qy * x;
let uuvx = qy * uvz - qz * uvy;
let uuvy = qz * uvx - qx * uvz;
let uuvz = qx * uvy - qy * uvx;
const w2 = qw * 2;
uvx *= w2;
uvy *= w2;
uvz *= w2;
uuvx *= 2;
uuvy *= 2;
uuvz *= 2;
out[0] = x + uvx + uuvx;
out[1] = y + uvy + uuvy;
out[2] = z + uvz + uuvz;
return out;
}
function rotateX(out, a, b, rad) {
const p = [];
const r = [];
p[0] = a[0] - b[0];
p[1] = a[1] - b[1];
p[2] = a[2] - b[2];
r[0] = p[0];
r[1] = p[1] * Math.cos(rad) - p[2] * Math.sin(rad);
r[2] = p[1] * Math.sin(rad) + p[2] * Math.cos(rad);
out[0] = r[0] + b[0];
out[1] = r[1] + b[1];
out[2] = r[2] + b[2];
return out;
}
function rotateY(out, a, b, rad) {
const p = [];
const r = [];
p[0] = a[0] - b[0];
p[1] = a[1] - b[1];
p[2] = a[2] - b[2];
r[0] = p[2] * Math.sin(rad) + p[0] * Math.cos(rad);
r[1] = p[1];
r[2] = p[2] * Math.cos(rad) - p[0] * Math.sin(rad);
out[0] = r[0] + b[0];
out[1] = r[1] + b[1];
out[2] = r[2] + b[2];
return out;
}
function rotateZ(out, a, b, rad) {
const p = [];
const r = [];
p[0] = a[0] - b[0];
p[1] = a[1] - b[1];
p[2] = a[2] - b[2];
r[0] = p[0] * Math.cos(rad) - p[1] * Math.sin(rad);
r[1] = p[0] * Math.sin(rad) + p[1] * Math.cos(rad);
r[2] = p[2];
out[0] = r[0] + b[0];
out[1] = r[1] + b[1];
out[2] = r[2] + b[2];
return out;
}
function angle(a, b) {
const ax = a[0];
const ay = a[1];
const az = a[2];
const bx = b[0];
const by = b[1];
const bz = b[2];
const mag = Math.sqrt((ax * ax + ay * ay + az * az) * (bx * bx + by * by + bz * bz));
const cosine = mag && dot(a, b) / mag;
return Math.acos(Math.min(Math.max(cosine, -1), 1));
}
var len = length;
var forEach2 = function() {
const vec = create2();
return function(a, stride, offset, count, fn, arg) {
let i;
let l;
if (!stride) {
stride = 3;
}
if (!offset) {
offset = 0;
}
if (count) {
l = Math.min(count * stride + offset, a.length);
} else {
l = a.length;
}
for (i = offset; i < l; i += stride) {
vec[0] = a[i];
vec[1] = a[i + 1];
vec[2] = a[i + 2];
fn(vec, vec, arg);
a[i] = vec[0];
a[i + 1] = vec[1];
a[i + 2] = vec[2];
}
return a;
};
}();
// ../../node_modules/@math.gl/core/dist/classes/vector3.js
var ORIGIN = [0, 0, 0];
var ZERO;
var Vector3 = class extends Vector {
static get ZERO() {
if (!ZERO) {
ZERO = new Vector3(0, 0, 0);
Object.freeze(ZERO);
}
return ZERO;
}
/**
* @class
* @param x
* @param y
* @param z
*/
constructor(x = 0, y = 0, z = 0) {
super(-0, -0, -0);
if (arguments.length === 1 && isArray(x)) {
this.copy(x);
} else {
if (config.debug) {
checkNumber(x);
checkNumber(y);
checkNumber(z);
}
this[0] = x;
this[1] = y;
this[2] = z;
}
}
set(x, y, z) {
this[0] = x;
this[1] = y;
this[2] = z;
return this.check();
}
copy(array) {
this[0] = array[0];
this[1] = array[1];
this[2] = array[2];
return this.check();
}
fromObject(object) {
if (config.debug) {
checkNumber(object.x);
checkNumber(object.y);
checkNumber(object.z);
}
this[0] = object.x;
this[1] = object.y;
this[2] = object.z;
return this.check();
}
toObject(object) {
object.x = this[0];
object.y = this[1];
object.z = this[2];
return object;
}
// Getters/setters
get ELEMENTS() {
return 3;
}
get z() {
return this[2];
}
set z(value) {
this[2] = checkNumber(value);
}
// ACCESSORS
angle(vector) {
return angle(this, vector);
}
// MODIFIERS
cross(vector) {
cross(this, this, vector);
return this.check();
}
rotateX({ radians, origin = ORIGIN }) {
rotateX(this, this, origin, radians);
return this.check();
}
rotateY({ radians, origin = ORIGIN }) {
rotateY(this, this, origin, radians);
return this.check();
}
rotateZ({ radians, origin = ORIGIN }) {
rotateZ(this, this, origin, radians);
return this.check();
}
// Transforms
// transforms as point (4th component is implicitly 1)
transform(matrix4) {
return this.transformAsPoint(matrix4);
}
// transforms as point (4th component is implicitly 1)
transformAsPoint(matrix4) {
transformMat42(this, this, matrix4);
return this.check();
}
// transforms as vector (4th component is implicitly 0, ignores translation. slightly faster)
transformAsVector(matrix4) {
vec3_transformMat4AsVector(this, this, matrix4);
return this.check();
}
transformByMatrix3(matrix3) {
transformMat32(this, this, matrix3);
return this.check();
}
transformByMatrix2(matrix2) {
vec3_transformMat2(this, this, matrix2);
return this.check();
}
transformByQuaternion(quaternion) {
transformQuat(this, this, quaternion);
return this.check();
}
};
// ../../node_modules/@math.gl/core/dist/classes/vector4.js
var ZERO2;
var Vector4 = class extends Vector {
static get ZERO() {
if (!ZERO2) {
ZERO2 = new Vector4(0, 0, 0, 0);
Object.freeze(ZERO2);
}
return ZERO2;
}
constructor(x = 0, y = 0, z = 0, w = 0) {
super(-0, -0, -0, -0);
if (isArray(x) && arguments.length === 1) {
this.copy(x);
} else {
if (config.debug) {
checkNumber(x);
checkNumber(y);
checkNumber(z);
checkNumber(w);
}
this[0] = x;
this[1] = y;
this[2] = z;
this[3] = w;
}
}
set(x, y, z, w) {
this[0] = x;
this[1] = y;
this[2] = z;
this[3] = w;
return this.check();
}
copy(array) {
this[0] = array[0];
this[1] = array[1];
this[2] = array[2];
this[3] = array[3];
return this.check();
}
fromObject(object) {
if (config.debug) {
checkNumber(object.x);
checkNumber(object.y);
checkNumber(object.z);
checkNumber(object.w);
}
this[0] = object.x;
this[1] = object.y;
this[2] = object.z;
this[3] = object.w;
return this;
}
toObject(object) {
object.x = this[0];
object.y = this[1];
object.z = this[2];
object.w = this[3];
return object;
}
// Getters/setters
/* eslint-disable no-multi-spaces, brace-style, no-return-assign */
get ELEMENTS() {
return 4;
}
get z() {
return this[2];
}
set z(value) {
this[2] = checkNumber(value);
}
get w() {
return this[3];
}
set w(value) {
this[3] = checkNumber(value);
}
transform(matrix4) {
transformMat42(this, this, matrix4);
return this.check();
}
transformByMatrix3(matrix3) {
vec4_transformMat3(this, this, matrix3);
return this.check();
}
transformByMatrix2(matrix2) {
vec4_transformMat2(this, this, matrix2);
return this.check();
}
transformByQuaternion(quaternion) {
transformQuat(this, this, quaternion);
return this.check();
}
// three.js compatibility
applyMatrix4(m) {
m.transform(this, this);
return this;
}
};
// ../../node_modules/@math.gl/core/dist/classes/base/matrix.js
var Matrix = class extends MathArray {
// fromObject(object) {
// const array = object.elements;
// return this.fromRowMajor(array);
// }
// toObject(object) {
// const array = object.elements;
// this.toRowMajor(array);
// return object;
// }
// TODO better override formatString?
toString() {
let string = "[";
if (config.printRowMajor) {
string += "row-major:";
for (let row = 0; row < this.RANK; ++row) {
for (let col = 0; col < this.RANK; ++col) {
string += ` ${this[col * this.RANK + row]}`;
}
}
} else {
string += "column-major:";
for (let i = 0; i < this.ELEMENTS; ++i) {
string += ` ${this[i]}`;
}
}
string += "]";
return string;
}
getElementIndex(row, col) {
return col * this.RANK + row;
}
// By default assumes row major indices
getElement(row, col) {
return this[col * this.RANK + row];
}
// By default assumes row major indices
setElement(row, col, value) {
this[col * this.RANK + row] = checkNumber(value);
return this;
}
getColumn(columnIndex, result = new Array(this.RANK).fill(-0)) {
const firstIndex = columnIndex * this.RANK;
for (let i = 0; i < this.RANK; ++i) {
result[i] = this[firstIndex + i];
}
return result;
}
setColumn(columnIndex, columnVector) {
const firstIndex = columnIndex * this.RANK;
for (let i = 0; i < this.RANK; ++i) {
this[firstIndex + i] = columnVector[i];
}
return this;
}
};
// ../../node_modules/@math.gl/core/dist/gl-matrix/mat3.js
function create3() {
const out = new ARRAY_TYPE(9);
if (ARRAY_TYPE != Float32Array) {
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[5] = 0;
out[6] = 0;
out[7] = 0;
}
out[0] = 1;
out[4] = 1;
out[8] = 1;
return out;
}
function transpose(out, a) {
if (out === a) {
const a01 = a[1];
const a02 = a[2];
const a12 = a[5];
out[1] = a[3];
out[2] = a[6];
out[3] = a01;
out[5] = a[7];
out[6] = a02;
out[7] = a12;
} else {
out[0] = a[0];
out[1] = a[3];
out[2] = a[6];
out[3] = a[1];
out[4] = a[4];
out[5] = a[7];
out[6] = a[2];
out[7] = a[5];
out[8] = a[8];
}
return out;
}
function invert(out, a) {
const a00 = a[0];
const a01 = a[1];
const a02 = a[2];
const a10 = a[3];
const a11 = a[4];
const a12 = a[5];
const a20 = a[6];
const a21 = a[7];
const a22 = a[8];
const b01 = a22 * a11 - a12 * a21;
const b11 = -a22 * a10 + a12 * a20;
const b21 = a21 * a10 - a11 * a20;
let det = a00 * b01 + a01 * b11 + a02 * b21;
if (!det) {
return null;
}
det = 1 / det;
out[0] = b01 * det;
out[1] = (-a22 * a01 + a02 * a21) * det;
out[2] = (a12 * a01 - a02 * a11) * det;
out[3] = b11 * det;
out[4] = (a22 * a00 - a02 * a20) * det;
out[5] = (-a12 * a00 + a02 * a10) * det;
out[6] = b21 * det;
out[7] = (-a21 * a00 + a01 * a20) * det;
out[8] = (a11 * a00 - a01 * a10) * det;
return out;
}
function determinant(a) {
const a00 = a[0];
const a01 = a[1];
const a02 = a[2];
const a10 = a[3];
const a11 = a[4];
const a12 = a[5];
const a20 = a[6];
const a21 = a[7];
const a22 = a[8];
return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
}
function multiply(out, a, b) {
const a00 = a[0];
const a01 = a[1];
const a02 = a[2];
const a10 = a[3];
const a11 = a[4];
const a12 = a[5];
const a20 = a[6];
const a21 = a[7];
const a22 = a[8];
const b00 = b[0];
const b01 = b[1];
const b02 = b[2];
const b10 = b[3];
const b11 = b[4];
const b12 = b[5];
const b20 = b[6];
const b21 = b[7];
const b22 = b[8];
out[0] = b00 * a00 + b01 * a10 + b02 * a20;
out[1] = b00 * a01 + b01 * a11 + b02 * a21;
out[2] = b00 * a02 + b01 * a12 + b02 * a22;
out[3] = b10 * a00 + b11 * a10 + b12 * a20;
out[4] = b10 * a01 + b11 * a11 + b12 * a21;
out[5] = b10 * a02 + b11 * a12 + b12 * a22;
out[6] = b20 * a00 + b21 * a10 + b22 * a20;
out[7] = b20 * a01 + b21 * a11 + b22 * a21;
out[8] = b20 * a02 + b21 * a12 + b22 * a22;
return out;
}
function translate(out, a, v) {
const a00 = a[0];
const a01 = a[1];
const a02 = a[2];
const a10 = a[3];
const a11 = a[4];
const a12 = a[5];
const a20 = a[6];
const a21 = a[7];
const a22 = a[8];
const x = v[0];
const y = v[1];
out[0] = a00;
out[1] = a01;
out[2] = a02;
out[3] = a10;
out[4] = a11;
out[5] = a12;
out[6] = x * a00 + y * a10 + a20;
out[7] = x * a01 + y * a11 + a21;
out[8] = x * a02 + y * a12 + a22;
return out;
}
function rotate(out, a, rad) {
const a00 = a[0];
const a01 = a[1];
const a02 = a[2];
const a10 = a[3];
const a11 = a[4];
const a12 = a[5];
const a20 = a[6];
const a21 = a[7];
const a22 = a[8];
const s = Math.sin(rad);
const c = Math.cos(rad);
out[0] = c * a00 + s * a10;
out[1] = c * a01 + s * a11;
out[2] = c * a02 + s * a12;
out[3] = c * a10 - s * a00;
out[4] = c * a11 - s * a01;
out[5] = c * a12 - s * a02;
out[6] = a20;
out[7] = a21;
out[8] = a22;
return out;
}
function scale(out, a, v) {
const x = v[0];
const y = v[1];
out[0] = x * a[0];
out[1] = x * a[1];
out[2] = x * a[2];
out[3] = y * a[3];
out[4] = y * a[4];
out[5] = y * a[5];
out[6] = a[6];
out[7] = a[7];
out[8] = a[8];
return out;
}
function fromQuat(out, q) {
const x = q[0];
const y = q[1];
const z = q[2]