From d84f59738c242124ff6f5459943b12248865de13 Mon Sep 17 00:00:00 2001 From: parksanghyuk <zola8138@ajou.ac.kr> Date: Mon, 21 Jun 2021 05:59:27 +0900 Subject: [PATCH] Initial Commit --- LICENSE | 21 + README.md | 38 +- Script.js | 278 ++ gl-matrix.js | 7611 ++++++++++++++++++++++++++++++++++++++++ img/FragmentShader.png | Bin 0 -> 12026 bytes img/InitializeGL.png | Bin 0 -> 26383 bytes img/VertexShader.png | Bin 0 -> 14815 bytes index.html | 71 + 8 files changed, 8018 insertions(+), 1 deletion(-) create mode 100644 LICENSE create mode 100644 Script.js create mode 100644 gl-matrix.js create mode 100644 img/FragmentShader.png create mode 100644 img/InitializeGL.png create mode 100644 img/VertexShader.png create mode 100644 index.html diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..04bc01a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 PARK Sanghyuk + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 447b547..43ceafe 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,39 @@ # WebGL Tutorial -Project for 2021-Spring Computer Graphics final assignment \ No newline at end of file +Project for 2021-Spring Computer Graphics final assignment + +# Overview +This document is to describe the basic method of changing the WebGL1-based document to WebGL2. +WebGL2 is nearly 100% back compatible with WebGL1. In this document, there will be description of very basic way to change the WebGL1 script to WebGL2. +Very brief comments are here, so read the source code to see the details. + +# Initializing +<img src=img/InitializeGL.png width=50%> +First, you use "webgl2" instead of "webgl", on initializing canvas. +Note that there is no "experimental-webgl2". Many WebGL1 extensions are a standard part of WebGL2. + +# Switching the Shader Version to GLSL 3.00 ES +Add "#version 300 es" to the very first line of the shader source code. +CAUTION: NO BLANKS AND LINES ARE ALLOWED BEFORE THIS DECLARATION. + +# Some Changes in Shader Code +Add "#version 300 es" to the very first line of the shader source code. +CAUTION: NO BLANKS AND LINES ARE ALLOWED BEFORE THIS DECLARATION. + +No more gl_fragColor. In WebGL1, your fragment shader would set the specific variable gl_fragColor" to set the output value. +You can now use any name for the output, except for those starting with "gl_". + +Change "varying" to "in" or "out", and "attribute" to "in". +The output of the vertex shader would be the input of the fragment shader. We call them varying" values. +Simply change them to "out" in the vertex shader, and "in" in the fragment shader. + +# Shader Code Example +<img src=img/FragmentShader.png width=50%> +Fragment shader +<img src=img/VertexShader.png width=50%> +Vertex shader + +# References + * This page is modified from Lab 06 of the Computer Graphics course. + * WebGL1 to WebGL2: https://webgl2fundamentals.org/webgl/lessons/webgl1-to-webgl2.html + * WebGL2 Fundamentals: https://webgl2fundamentals.org/webgl/lessons/ko/webgl-fundamentals.html \ No newline at end of file diff --git a/Script.js b/Script.js new file mode 100644 index 0000000..a845f03 --- /dev/null +++ b/Script.js @@ -0,0 +1,278 @@ +// Change WebGL 1 based document to WebGL 2 +// Reference: https://webgl2fundamentals.org/webgl/lessons/webgl1-to-webgl2.html +// https://webgl2fundamentals.org/webgl/lessons/ko/webgl-fundamentals.html + + +var gl; + +const {mat2, mat3, mat4, vec2, vec3, vec4} = glMatrix; +// Now we can use function without glMatrix.~~~ + +function testGLError(functionLastCalled) { + /* gl.getError returns the last error that occurred using WebGL for debugging */ + var lastError = gl.getError(); + + if (lastError != gl.NO_ERROR) { + alert(functionLastCalled + " failed (" + lastError + ")"); + return false; + } + return true; +} + +function initialiseGL(canvas) { + try { + // Try to grab the standard context. If it fails, fallback to experimental + // gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); // in WebGL1 + gl = canvas.getContext("webgl2"); + // No experimental-webgl2 + gl.viewport(0, 0, canvas.width, canvas.height); + } + catch (e) { + } + + if (!gl) { + alert("Unable to initialise WebGL. Your browser may not support it"); + return false; + } + return true; +} + +var shaderProgram; + +var vertexData = [ + // Backface (RED/WHITE) -> z = 0.5 + // x y z r g b a + -0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 1.0, + 0.5, 0.5, -0.5, 1.0, 0.0, 0.0, 1.0, + 0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 1.0, + -0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 1.0, + -0.5, 0.5, -0.5, 1.0, 0.0, 0.0, 1.0, + 0.5, 0.5, -0.5, 1.0, 1.0, 1.0, 1.0, + // Front (BLUE/WHITE) -> z = 0.5 + -0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0, + 0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 1.0, + 0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0, + -0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0, + -0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 1.0, + 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 1.0, + // LEFT (GREEN/WHITE) -> z = 0.5 + -0.5, -0.5, -0.5, 0.0, 1.0, 0.0, 1.0, + -0.5, 0.5, 0.5, 0.0, 1.0, 0.0, 1.0, + -0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 1.0, + -0.5, -0.5, -0.5, 0.0, 1.0, 0.0, 1.0, + -0.5, -0.5, 0.5, 0.0, 1.0, 0.0, 1.0, + -0.5, 0.5, 0.5, 0.0, 1.0, 1.0, 1.0, + // RIGHT (YELLOW/WHITE) -> z = 0.5 + 0.5, -0.5, -0.5, 1.0, 1.0, 0.0, 1.0, + 0.5, 0.5, 0.5, 1.0, 1.0, 0.0, 1.0, + 0.5, 0.5, -0.5, 1.0, 1.0, 0.0, 1.0, + 0.5, -0.5, -0.5, 1.0, 1.0, 0.0, 1.0, + 0.5, -0.5, 0.5, 1.0, 1.0, 0.0, 1.0, + 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 1.0, + // BOTTON (MAGENTA/WHITE) -> z = 0.5 + -0.5, -0.5, -0.5, 1.0, 0.0, 1.0, 1.0, + 0.5, -0.5, 0.5, 1.0, 0.0, 1.0, 1.0, + 0.5, -0.5, -0.5, 1.0, 0.0, 1.0, 1.0, + -0.5, -0.5, -0.5, 1.0, 0.0, 1.0, 1.0, + -0.5, -0.5, 0.5, 1.0, 0.0, 1.0, 1.0, + 0.5, -0.5, 0.5, 1.0, 1.0, 1.0, 1.0, + // TOP (CYAN/WHITE) -> z = 0.5 + -0.5, 0.5, -0.5, 0.0, 1.0, 1.0, 1.0, + 0.5, 0.5, 0.5, 0.0, 1.0, 1.0, 1.0, + 0.5, 0.5, -0.5, 0.0, 1.0, 1.0, 1.0, + -0.5, 0.5, -0.5, 0.0, 1.0, 1.0, 1.0, + -0.5, 0.5, 0.5, 0.0, 1.0, 1.0, 1.0, + 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 1.0 +]; + +function initialiseBuffer() { + + gl.vertexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW); + + return testGLError("initialiseBuffers"); +} + +function initialiseShaders() { + + // Define "#version 300 es" at the very first line of the shader code + // Neither blanks nor lines before this context are allowed. + + // No more gl_fragColor + // Change "varying" to "in" or "out", and "attribute" to "in". + // You can make any name except for those starting with "gl_". + + var fragmentShaderSource = `#version 300 es + // varying highp vec4 col; // in WebGL1 + // You cannot use the name starting with "gl_" + + in highp vec4 col; + out highp vec4 outFragColor; + + void main(void) + { + outFragColor = col; + }`; + + gl.fragShader = gl.createShader(gl.FRAGMENT_SHADER); + gl.shaderSource(gl.fragShader, fragmentShaderSource); + gl.compileShader(gl.fragShader); + // Check if compilation succeeded + if (!gl.getShaderParameter(gl.fragShader, gl.COMPILE_STATUS)) { + alert("Failed to compile the fragment shader.\n" + gl.getShaderInfoLog(gl.fragShader)); + return false; + } + + // Vertex shader code + var vertexShaderSource = `#version 300 es + // change attribute to in + in highp vec4 myVertex; + in highp vec4 myColor; + uniform mediump mat4 transformationMatrix; + out highp vec4 col; + void main(void) + { + gl_Position = transformationMatrix * myVertex; + gl_PointSize = 5.0; + col = myColor; + }`; + + gl.vertexShader = gl.createShader(gl.VERTEX_SHADER); + gl.shaderSource(gl.vertexShader, vertexShaderSource); + gl.compileShader(gl.vertexShader); + // Check if compilation succeeded + if (!gl.getShaderParameter(gl.vertexShader, gl.COMPILE_STATUS)) { + alert("Failed to compile the vertex shader.\n" + gl.getShaderInfoLog(gl.vertexShader)); + return false; + } + + // Create the shader program + gl.programObject = gl.createProgram(); + // Attach the fragment and vertex shaders to it + gl.attachShader(gl.programObject, gl.fragShader); + gl.attachShader(gl.programObject, gl.vertexShader); + // Bind the custom vertex attribute "myVertex" to location 0 + gl.bindAttribLocation(gl.programObject, 0, "myVertex"); + gl.bindAttribLocation(gl.programObject, 1, "myColor"); + // Link the program + gl.linkProgram(gl.programObject); + // Check if linking succeeded in a similar way we checked for compilation errors + if (!gl.getProgramParameter(gl.programObject, gl.LINK_STATUS)) { + alert("Failed to link the program.\n" + gl.getProgramInfoLog(gl.programObject)); + return false; + } + + gl.useProgram(gl.programObject); + + return testGLError("initialiseShaders"); +} + +var xRot = 0.0; +var yRot = 0.0; +var zRot = 0.0; +var speedRot = 0.01; + +flag_animation = 0; +function toggleAnimation() +{ + flag_animation ^= 1; + console.log("flag_animation=", flag_animation); +} + +function speed_plus(){ + speedRot *= 1.1; +} + +function speed_minus(){ + speedRot /= 1.1; +} + +var draw_mode = 4; + +function draw_mode_change(a){ + draw_mode = a; +} + +function renderScene() { + + gl.clearColor(0.0, 0.0, 0.0, 1.0); + gl.clearDepth(1.0); // Added for depth Test + gl.clear(gl.COLOR_BUFFER_BIT); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // Added for depth Test + gl.enable(gl.DEPTH_TEST); // Added for depth Test + + var matrixLocation = gl.getUniformLocation(gl.programObject, "transformationMatrix"); + var transformationMatrix = mat4.create(); + mat4.rotateX(transformationMatrix, transformationMatrix, xRot); + mat4.rotateY(transformationMatrix, transformationMatrix, yRot); + mat4.rotateZ(transformationMatrix, transformationMatrix, zRot); + + xRot += (speedRot * flag_animation); + yRot += (speedRot * flag_animation); + zRot += (speedRot * flag_animation); + + gl.uniformMatrix4fv(matrixLocation, gl.FALSE, transformationMatrix ); + + if (!testGLError("gl.uniformMatrix4fv")) { + return false; + } + + gl.bindBuffer(gl.ARRAY_BUFFER, gl.vertexBuffer); + gl.enableVertexAttribArray(0); + gl.vertexAttribPointer(0, 3, gl.FLOAT, gl.FALSE, 28, 0); + gl.enableVertexAttribArray(1); + gl.vertexAttribPointer(1, 4, gl.FLOAT, gl.FALSE, 28, 12); + + if (!testGLError("gl.vertexAttribPointer")) { + return false; + } + + //gl.drawArrays(gl.TRIANGLES, 0, 36); + //gl.drawArrays(gl.LINE_STRIP, 0, 36); + + // Draw Mode + // 0: points + // 2: lines + // 4: triangles + + gl.drawArrays(draw_mode, 0, 36); + + if (!testGLError("gl.drawArrays")) { + return false; + } + + return true; +} + +function main() { + var canvas = document.getElementById("helloapicanvas"); + + if (!initialiseGL(canvas)) { + return; + } + + if (!initialiseBuffer()) { + return; + } + + if (!initialiseShaders()) { + return; + } + + // renderScene(); + // Render loop + requestAnimFrame = (function () { + return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || + function (callback) { + window.setTimeout(callback, 1000, 60); + }; + })(); + + (function renderLoop() { + if (renderScene()) { + // Everything was successful, request that we redraw our scene again in the future + requestAnimFrame(renderLoop); + } + })(); +} diff --git a/gl-matrix.js b/gl-matrix.js new file mode 100644 index 0000000..4553f9e --- /dev/null +++ b/gl-matrix.js @@ -0,0 +1,7611 @@ + +/*! +@fileoverview gl-matrix - High performance matrix and vector operations +@author Brandon Jones +@author Colin MacKenzie IV +@version 3.3.0 + +Copyright (c) 2015-2020, Brandon Jones, Colin MacKenzie IV. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (global = global || self, factory(global.glMatrix = {})); +}(this, (function (exports) { 'use strict'; + + /** + * Common utilities + * @module glMatrix + */ + // Configuration Constants + var EPSILON = 0.000001; + var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array; + var RANDOM = Math.random; + /** + * Sets the type of array used when creating new vectors and matrices + * + * @param {Float32ArrayConstructor | ArrayConstructor} type Array type, such as Float32Array or Array + */ + + function setMatrixArrayType(type) { + ARRAY_TYPE = type; + } + var degree = Math.PI / 180; + /** + * Convert Degree To Radian + * + * @param {Number} a Angle in Degrees + */ + + function toRadian(a) { + return a * degree; + } + /** + * Tests whether or not the arguments have approximately the same value, within an absolute + * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less + * than or equal to 1.0, and a relative tolerance is used for larger values) + * + * @param {Number} a The first number to test. + * @param {Number} b The second number to test. + * @returns {Boolean} True if the numbers are approximately equal, false otherwise. + */ + + function equals(a, b) { + return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b)); + } + if (!Math.hypot) Math.hypot = function () { + var y = 0, + i = arguments.length; + + while (i--) { + y += arguments[i] * arguments[i]; + } + + return Math.sqrt(y); + }; + + var common = /*#__PURE__*/Object.freeze({ + __proto__: null, + EPSILON: EPSILON, + get ARRAY_TYPE () { return ARRAY_TYPE; }, + RANDOM: RANDOM, + setMatrixArrayType: setMatrixArrayType, + toRadian: toRadian, + equals: equals + }); + + /** + * 2x2 Matrix + * @module mat2 + */ + + /** + * Creates a new identity mat2 + * + * @returns {mat2} a new 2x2 matrix + */ + + function create() { + var out = new ARRAY_TYPE(4); + + if (ARRAY_TYPE != Float32Array) { + out[1] = 0; + out[2] = 0; + } + + out[0] = 1; + out[3] = 1; + return out; + } + /** + * Creates a new mat2 initialized with values from an existing matrix + * + * @param {ReadonlyMat2} a matrix to clone + * @returns {mat2} a new 2x2 matrix + */ + + function clone(a) { + var out = new ARRAY_TYPE(4); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; + } + /** + * Copy the values from one mat2 to another + * + * @param {mat2} out the receiving matrix + * @param {ReadonlyMat2} a the source matrix + * @returns {mat2} out + */ + + function copy(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; + } + /** + * Set a mat2 to the identity matrix + * + * @param {mat2} out the receiving matrix + * @returns {mat2} out + */ + + function identity(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; + } + /** + * Create a new mat2 with the given values + * + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m10 Component in column 1, row 0 position (index 2) + * @param {Number} m11 Component in column 1, row 1 position (index 3) + * @returns {mat2} out A new 2x2 matrix + */ + + function fromValues(m00, m01, m10, m11) { + var out = new ARRAY_TYPE(4); + out[0] = m00; + out[1] = m01; + out[2] = m10; + out[3] = m11; + return out; + } + /** + * Set the components of a mat2 to the given values + * + * @param {mat2} out the receiving matrix + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m10 Component in column 1, row 0 position (index 2) + * @param {Number} m11 Component in column 1, row 1 position (index 3) + * @returns {mat2} out + */ + + function set(out, m00, m01, m10, m11) { + out[0] = m00; + out[1] = m01; + out[2] = m10; + out[3] = m11; + return out; + } + /** + * Transpose the values of a mat2 + * + * @param {mat2} out the receiving matrix + * @param {ReadonlyMat2} a the source matrix + * @returns {mat2} out + */ + + function transpose(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache + // some values + if (out === a) { + var a1 = a[1]; + out[1] = a[2]; + out[2] = a1; + } else { + out[0] = a[0]; + out[1] = a[2]; + out[2] = a[1]; + out[3] = a[3]; + } + + return out; + } + /** + * Inverts a mat2 + * + * @param {mat2} out the receiving matrix + * @param {ReadonlyMat2} a the source matrix + * @returns {mat2} out + */ + + function invert(out, a) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3]; // Calculate the determinant + + var det = a0 * a3 - a2 * a1; + + if (!det) { + return null; + } + + det = 1.0 / det; + out[0] = a3 * det; + out[1] = -a1 * det; + out[2] = -a2 * det; + out[3] = a0 * det; + return out; + } + /** + * Calculates the adjugate of a mat2 + * + * @param {mat2} out the receiving matrix + * @param {ReadonlyMat2} a the source matrix + * @returns {mat2} out + */ + + function adjoint(out, a) { + // Caching this value is nessecary if out == a + var a0 = a[0]; + out[0] = a[3]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = a0; + return out; + } + /** + * Calculates the determinant of a mat2 + * + * @param {ReadonlyMat2} a the source matrix + * @returns {Number} determinant of a + */ + + function determinant(a) { + return a[0] * a[3] - a[2] * a[1]; + } + /** + * Multiplies two mat2's + * + * @param {mat2} out the receiving matrix + * @param {ReadonlyMat2} a the first operand + * @param {ReadonlyMat2} b the second operand + * @returns {mat2} out + */ + + function multiply(out, a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3]; + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3]; + out[0] = a0 * b0 + a2 * b1; + out[1] = a1 * b0 + a3 * b1; + out[2] = a0 * b2 + a2 * b3; + out[3] = a1 * b2 + a3 * b3; + return out; + } + /** + * Rotates a mat2 by the given angle + * + * @param {mat2} out the receiving matrix + * @param {ReadonlyMat2} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2} out + */ + + function rotate(out, a, rad) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3]; + var s = Math.sin(rad); + var c = Math.cos(rad); + out[0] = a0 * c + a2 * s; + out[1] = a1 * c + a3 * s; + out[2] = a0 * -s + a2 * c; + out[3] = a1 * -s + a3 * c; + return out; + } + /** + * Scales the mat2 by the dimensions in the given vec2 + * + * @param {mat2} out the receiving matrix + * @param {ReadonlyMat2} a the matrix to rotate + * @param {ReadonlyVec2} v the vec2 to scale the matrix by + * @returns {mat2} out + **/ + + function scale(out, a, v) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3]; + var v0 = v[0], + v1 = v[1]; + out[0] = a0 * v0; + out[1] = a1 * v0; + out[2] = a2 * v1; + out[3] = a3 * v1; + return out; + } + /** + * Creates a matrix from a given angle + * This is equivalent to (but much faster than): + * + * mat2.identity(dest); + * mat2.rotate(dest, dest, rad); + * + * @param {mat2} out mat2 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2} out + */ + + function fromRotation(out, rad) { + var s = Math.sin(rad); + var c = Math.cos(rad); + out[0] = c; + out[1] = s; + out[2] = -s; + out[3] = c; + return out; + } + /** + * Creates a matrix from a vector scaling + * This is equivalent to (but much faster than): + * + * mat2.identity(dest); + * mat2.scale(dest, dest, vec); + * + * @param {mat2} out mat2 receiving operation result + * @param {ReadonlyVec2} v Scaling vector + * @returns {mat2} out + */ + + function fromScaling(out, v) { + out[0] = v[0]; + out[1] = 0; + out[2] = 0; + out[3] = v[1]; + return out; + } + /** + * Returns a string representation of a mat2 + * + * @param {ReadonlyMat2} a matrix to represent as a string + * @returns {String} string representation of the matrix + */ + + function str(a) { + return "mat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")"; + } + /** + * Returns Frobenius norm of a mat2 + * + * @param {ReadonlyMat2} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ + + function frob(a) { + return Math.hypot(a[0], a[1], a[2], a[3]); + } + /** + * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix + * @param {ReadonlyMat2} L the lower triangular matrix + * @param {ReadonlyMat2} D the diagonal matrix + * @param {ReadonlyMat2} U the upper triangular matrix + * @param {ReadonlyMat2} a the input matrix to factorize + */ + + function LDU(L, D, U, a) { + L[2] = a[2] / a[0]; + U[0] = a[0]; + U[1] = a[1]; + U[3] = a[3] - L[2] * U[1]; + return [L, D, U]; + } + /** + * Adds two mat2's + * + * @param {mat2} out the receiving matrix + * @param {ReadonlyMat2} a the first operand + * @param {ReadonlyMat2} b the second operand + * @returns {mat2} out + */ + + function add(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + return out; + } + /** + * Subtracts matrix b from matrix a + * + * @param {mat2} out the receiving matrix + * @param {ReadonlyMat2} a the first operand + * @param {ReadonlyMat2} b the second operand + * @returns {mat2} out + */ + + function subtract(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + return out; + } + /** + * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) + * + * @param {ReadonlyMat2} a The first matrix. + * @param {ReadonlyMat2} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ + + function exactEquals(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]; + } + /** + * Returns whether or not the matrices have approximately the same elements in the same position. + * + * @param {ReadonlyMat2} a The first matrix. + * @param {ReadonlyMat2} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ + + function equals$1(a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3]; + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3]; + return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)); + } + /** + * Multiply each element of the matrix by a scalar. + * + * @param {mat2} out the receiving matrix + * @param {ReadonlyMat2} a the matrix to scale + * @param {Number} b amount to scale the matrix's elements by + * @returns {mat2} out + */ + + function multiplyScalar(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + return out; + } + /** + * Adds two mat2's after multiplying each element of the second operand by a scalar value. + * + * @param {mat2} out the receiving vector + * @param {ReadonlyMat2} a the first operand + * @param {ReadonlyMat2} b the second operand + * @param {Number} scale the amount to scale b's elements by before adding + * @returns {mat2} out + */ + + function multiplyScalarAndAdd(out, a, b, scale) { + out[0] = a[0] + b[0] * scale; + out[1] = a[1] + b[1] * scale; + out[2] = a[2] + b[2] * scale; + out[3] = a[3] + b[3] * scale; + return out; + } + /** + * Alias for {@link mat2.multiply} + * @function + */ + + var mul = multiply; + /** + * Alias for {@link mat2.subtract} + * @function + */ + + var sub = subtract; + + var mat2 = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create, + clone: clone, + copy: copy, + identity: identity, + fromValues: fromValues, + set: set, + transpose: transpose, + invert: invert, + adjoint: adjoint, + determinant: determinant, + multiply: multiply, + rotate: rotate, + scale: scale, + fromRotation: fromRotation, + fromScaling: fromScaling, + str: str, + frob: frob, + LDU: LDU, + add: add, + subtract: subtract, + exactEquals: exactEquals, + equals: equals$1, + multiplyScalar: multiplyScalar, + multiplyScalarAndAdd: multiplyScalarAndAdd, + mul: mul, + sub: sub + }); + + /** + * 2x3 Matrix + * @module mat2d + * @description + * A mat2d contains six elements defined as: + * <pre> + * [a, b, + * c, d, + * tx, ty] + * </pre> + * This is a short form for the 3x3 matrix: + * <pre> + * [a, b, 0, + * c, d, 0, + * tx, ty, 1] + * </pre> + * The last column is ignored so the array is shorter and operations are faster. + */ + + /** + * Creates a new identity mat2d + * + * @returns {mat2d} a new 2x3 matrix + */ + + function create$1() { + var out = new ARRAY_TYPE(6); + + if (ARRAY_TYPE != Float32Array) { + out[1] = 0; + out[2] = 0; + out[4] = 0; + out[5] = 0; + } + + out[0] = 1; + out[3] = 1; + return out; + } + /** + * Creates a new mat2d initialized with values from an existing matrix + * + * @param {ReadonlyMat2d} a matrix to clone + * @returns {mat2d} a new 2x3 matrix + */ + + function clone$1(a) { + var out = new ARRAY_TYPE(6); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + return out; + } + /** + * Copy the values from one mat2d to another + * + * @param {mat2d} out the receiving matrix + * @param {ReadonlyMat2d} a the source matrix + * @returns {mat2d} out + */ + + function copy$1(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + return out; + } + /** + * Set a mat2d to the identity matrix + * + * @param {mat2d} out the receiving matrix + * @returns {mat2d} out + */ + + function identity$1(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + return out; + } + /** + * Create a new mat2d with the given values + * + * @param {Number} a Component A (index 0) + * @param {Number} b Component B (index 1) + * @param {Number} c Component C (index 2) + * @param {Number} d Component D (index 3) + * @param {Number} tx Component TX (index 4) + * @param {Number} ty Component TY (index 5) + * @returns {mat2d} A new mat2d + */ + + function fromValues$1(a, b, c, d, tx, ty) { + var out = new ARRAY_TYPE(6); + out[0] = a; + out[1] = b; + out[2] = c; + out[3] = d; + out[4] = tx; + out[5] = ty; + return out; + } + /** + * Set the components of a mat2d to the given values + * + * @param {mat2d} out the receiving matrix + * @param {Number} a Component A (index 0) + * @param {Number} b Component B (index 1) + * @param {Number} c Component C (index 2) + * @param {Number} d Component D (index 3) + * @param {Number} tx Component TX (index 4) + * @param {Number} ty Component TY (index 5) + * @returns {mat2d} out + */ + + function set$1(out, a, b, c, d, tx, ty) { + out[0] = a; + out[1] = b; + out[2] = c; + out[3] = d; + out[4] = tx; + out[5] = ty; + return out; + } + /** + * Inverts a mat2d + * + * @param {mat2d} out the receiving matrix + * @param {ReadonlyMat2d} a the source matrix + * @returns {mat2d} out + */ + + function invert$1(out, a) { + var aa = a[0], + ab = a[1], + ac = a[2], + ad = a[3]; + var atx = a[4], + aty = a[5]; + var det = aa * ad - ab * ac; + + if (!det) { + return null; + } + + det = 1.0 / det; + out[0] = ad * det; + out[1] = -ab * det; + out[2] = -ac * det; + out[3] = aa * det; + out[4] = (ac * aty - ad * atx) * det; + out[5] = (ab * atx - aa * aty) * det; + return out; + } + /** + * Calculates the determinant of a mat2d + * + * @param {ReadonlyMat2d} a the source matrix + * @returns {Number} determinant of a + */ + + function determinant$1(a) { + return a[0] * a[3] - a[1] * a[2]; + } + /** + * Multiplies two mat2d's + * + * @param {mat2d} out the receiving matrix + * @param {ReadonlyMat2d} a the first operand + * @param {ReadonlyMat2d} b the second operand + * @returns {mat2d} out + */ + + function multiply$1(out, a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3], + a4 = a[4], + a5 = a[5]; + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3], + b4 = b[4], + b5 = b[5]; + out[0] = a0 * b0 + a2 * b1; + out[1] = a1 * b0 + a3 * b1; + out[2] = a0 * b2 + a2 * b3; + out[3] = a1 * b2 + a3 * b3; + out[4] = a0 * b4 + a2 * b5 + a4; + out[5] = a1 * b4 + a3 * b5 + a5; + return out; + } + /** + * Rotates a mat2d by the given angle + * + * @param {mat2d} out the receiving matrix + * @param {ReadonlyMat2d} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2d} out + */ + + function rotate$1(out, a, rad) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3], + a4 = a[4], + a5 = a[5]; + var s = Math.sin(rad); + var c = Math.cos(rad); + out[0] = a0 * c + a2 * s; + out[1] = a1 * c + a3 * s; + out[2] = a0 * -s + a2 * c; + out[3] = a1 * -s + a3 * c; + out[4] = a4; + out[5] = a5; + return out; + } + /** + * Scales the mat2d by the dimensions in the given vec2 + * + * @param {mat2d} out the receiving matrix + * @param {ReadonlyMat2d} a the matrix to translate + * @param {ReadonlyVec2} v the vec2 to scale the matrix by + * @returns {mat2d} out + **/ + + function scale$1(out, a, v) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3], + a4 = a[4], + a5 = a[5]; + var v0 = v[0], + v1 = v[1]; + out[0] = a0 * v0; + out[1] = a1 * v0; + out[2] = a2 * v1; + out[3] = a3 * v1; + out[4] = a4; + out[5] = a5; + return out; + } + /** + * Translates the mat2d by the dimensions in the given vec2 + * + * @param {mat2d} out the receiving matrix + * @param {ReadonlyMat2d} a the matrix to translate + * @param {ReadonlyVec2} v the vec2 to translate the matrix by + * @returns {mat2d} out + **/ + + function translate(out, a, v) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3], + a4 = a[4], + a5 = a[5]; + var v0 = v[0], + v1 = v[1]; + out[0] = a0; + out[1] = a1; + out[2] = a2; + out[3] = a3; + out[4] = a0 * v0 + a2 * v1 + a4; + out[5] = a1 * v0 + a3 * v1 + a5; + return out; + } + /** + * Creates a matrix from a given angle + * This is equivalent to (but much faster than): + * + * mat2d.identity(dest); + * mat2d.rotate(dest, dest, rad); + * + * @param {mat2d} out mat2d receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat2d} out + */ + + function fromRotation$1(out, rad) { + var s = Math.sin(rad), + c = Math.cos(rad); + out[0] = c; + out[1] = s; + out[2] = -s; + out[3] = c; + out[4] = 0; + out[5] = 0; + return out; + } + /** + * Creates a matrix from a vector scaling + * This is equivalent to (but much faster than): + * + * mat2d.identity(dest); + * mat2d.scale(dest, dest, vec); + * + * @param {mat2d} out mat2d receiving operation result + * @param {ReadonlyVec2} v Scaling vector + * @returns {mat2d} out + */ + + function fromScaling$1(out, v) { + out[0] = v[0]; + out[1] = 0; + out[2] = 0; + out[3] = v[1]; + out[4] = 0; + out[5] = 0; + return out; + } + /** + * Creates a matrix from a vector translation + * This is equivalent to (but much faster than): + * + * mat2d.identity(dest); + * mat2d.translate(dest, dest, vec); + * + * @param {mat2d} out mat2d receiving operation result + * @param {ReadonlyVec2} v Translation vector + * @returns {mat2d} out + */ + + function fromTranslation(out, v) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = v[0]; + out[5] = v[1]; + return out; + } + /** + * Returns a string representation of a mat2d + * + * @param {ReadonlyMat2d} a matrix to represent as a string + * @returns {String} string representation of the matrix + */ + + function str$1(a) { + return "mat2d(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ")"; + } + /** + * Returns Frobenius norm of a mat2d + * + * @param {ReadonlyMat2d} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ + + function frob$1(a) { + return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], 1); + } + /** + * Adds two mat2d's + * + * @param {mat2d} out the receiving matrix + * @param {ReadonlyMat2d} a the first operand + * @param {ReadonlyMat2d} b the second operand + * @returns {mat2d} out + */ + + function add$1(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + return out; + } + /** + * Subtracts matrix b from matrix a + * + * @param {mat2d} out the receiving matrix + * @param {ReadonlyMat2d} a the first operand + * @param {ReadonlyMat2d} b the second operand + * @returns {mat2d} out + */ + + function subtract$1(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + out[4] = a[4] - b[4]; + out[5] = a[5] - b[5]; + return out; + } + /** + * Multiply each element of the matrix by a scalar. + * + * @param {mat2d} out the receiving matrix + * @param {ReadonlyMat2d} a the matrix to scale + * @param {Number} b amount to scale the matrix's elements by + * @returns {mat2d} out + */ + + function multiplyScalar$1(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + out[4] = a[4] * b; + out[5] = a[5] * b; + return out; + } + /** + * Adds two mat2d's after multiplying each element of the second operand by a scalar value. + * + * @param {mat2d} out the receiving vector + * @param {ReadonlyMat2d} a the first operand + * @param {ReadonlyMat2d} b the second operand + * @param {Number} scale the amount to scale b's elements by before adding + * @returns {mat2d} out + */ + + function multiplyScalarAndAdd$1(out, a, b, scale) { + out[0] = a[0] + b[0] * scale; + out[1] = a[1] + b[1] * scale; + out[2] = a[2] + b[2] * scale; + out[3] = a[3] + b[3] * scale; + out[4] = a[4] + b[4] * scale; + out[5] = a[5] + b[5] * scale; + return out; + } + /** + * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) + * + * @param {ReadonlyMat2d} a The first matrix. + * @param {ReadonlyMat2d} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ + + function exactEquals$1(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5]; + } + /** + * Returns whether or not the matrices have approximately the same elements in the same position. + * + * @param {ReadonlyMat2d} a The first matrix. + * @param {ReadonlyMat2d} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ + + function equals$2(a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3], + a4 = a[4], + a5 = a[5]; + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3], + b4 = b[4], + b5 = b[5]; + return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)); + } + /** + * Alias for {@link mat2d.multiply} + * @function + */ + + var mul$1 = multiply$1; + /** + * Alias for {@link mat2d.subtract} + * @function + */ + + var sub$1 = subtract$1; + + var mat2d = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$1, + clone: clone$1, + copy: copy$1, + identity: identity$1, + fromValues: fromValues$1, + set: set$1, + invert: invert$1, + determinant: determinant$1, + multiply: multiply$1, + rotate: rotate$1, + scale: scale$1, + translate: translate, + fromRotation: fromRotation$1, + fromScaling: fromScaling$1, + fromTranslation: fromTranslation, + str: str$1, + frob: frob$1, + add: add$1, + subtract: subtract$1, + multiplyScalar: multiplyScalar$1, + multiplyScalarAndAdd: multiplyScalarAndAdd$1, + exactEquals: exactEquals$1, + equals: equals$2, + mul: mul$1, + sub: sub$1 + }); + + /** + * 3x3 Matrix + * @module mat3 + */ + + /** + * Creates a new identity mat3 + * + * @returns {mat3} a new 3x3 matrix + */ + + function create$2() { + var 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; + } + /** + * Copies the upper-left 3x3 values into the given mat3. + * + * @param {mat3} out the receiving 3x3 matrix + * @param {ReadonlyMat4} a the source 4x4 matrix + * @returns {mat3} out + */ + + function fromMat4(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[4]; + out[4] = a[5]; + out[5] = a[6]; + out[6] = a[8]; + out[7] = a[9]; + out[8] = a[10]; + return out; + } + /** + * Creates a new mat3 initialized with values from an existing matrix + * + * @param {ReadonlyMat3} a matrix to clone + * @returns {mat3} a new 3x3 matrix + */ + + function clone$2(a) { + var out = new ARRAY_TYPE(9); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; + } + /** + * Copy the values from one mat3 to another + * + * @param {mat3} out the receiving matrix + * @param {ReadonlyMat3} a the source matrix + * @returns {mat3} out + */ + + function copy$2(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + return out; + } + /** + * Create a new mat3 with the given values + * + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m02 Component in column 0, row 2 position (index 2) + * @param {Number} m10 Component in column 1, row 0 position (index 3) + * @param {Number} m11 Component in column 1, row 1 position (index 4) + * @param {Number} m12 Component in column 1, row 2 position (index 5) + * @param {Number} m20 Component in column 2, row 0 position (index 6) + * @param {Number} m21 Component in column 2, row 1 position (index 7) + * @param {Number} m22 Component in column 2, row 2 position (index 8) + * @returns {mat3} A new mat3 + */ + + function fromValues$2(m00, m01, m02, m10, m11, m12, m20, m21, m22) { + var out = new ARRAY_TYPE(9); + out[0] = m00; + out[1] = m01; + out[2] = m02; + out[3] = m10; + out[4] = m11; + out[5] = m12; + out[6] = m20; + out[7] = m21; + out[8] = m22; + return out; + } + /** + * Set the components of a mat3 to the given values + * + * @param {mat3} out the receiving matrix + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m02 Component in column 0, row 2 position (index 2) + * @param {Number} m10 Component in column 1, row 0 position (index 3) + * @param {Number} m11 Component in column 1, row 1 position (index 4) + * @param {Number} m12 Component in column 1, row 2 position (index 5) + * @param {Number} m20 Component in column 2, row 0 position (index 6) + * @param {Number} m21 Component in column 2, row 1 position (index 7) + * @param {Number} m22 Component in column 2, row 2 position (index 8) + * @returns {mat3} out + */ + + function set$2(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) { + out[0] = m00; + out[1] = m01; + out[2] = m02; + out[3] = m10; + out[4] = m11; + out[5] = m12; + out[6] = m20; + out[7] = m21; + out[8] = m22; + return out; + } + /** + * Set a mat3 to the identity matrix + * + * @param {mat3} out the receiving matrix + * @returns {mat3} out + */ + + function identity$2(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 1; + out[5] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; + } + /** + * Transpose the values of a mat3 + * + * @param {mat3} out the receiving matrix + * @param {ReadonlyMat3} a the source matrix + * @returns {mat3} out + */ + + function transpose$1(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + var a01 = a[1], + a02 = a[2], + 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; + } + /** + * Inverts a mat3 + * + * @param {mat3} out the receiving matrix + * @param {ReadonlyMat3} a the source matrix + * @returns {mat3} out + */ + + function invert$2(out, a) { + var a00 = a[0], + a01 = a[1], + a02 = a[2]; + var a10 = a[3], + a11 = a[4], + a12 = a[5]; + var a20 = a[6], + a21 = a[7], + a22 = a[8]; + var b01 = a22 * a11 - a12 * a21; + var b11 = -a22 * a10 + a12 * a20; + var b21 = a21 * a10 - a11 * a20; // Calculate the determinant + + var det = a00 * b01 + a01 * b11 + a02 * b21; + + if (!det) { + return null; + } + + det = 1.0 / 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; + } + /** + * Calculates the adjugate of a mat3 + * + * @param {mat3} out the receiving matrix + * @param {ReadonlyMat3} a the source matrix + * @returns {mat3} out + */ + + function adjoint$1(out, a) { + var a00 = a[0], + a01 = a[1], + a02 = a[2]; + var a10 = a[3], + a11 = a[4], + a12 = a[5]; + var a20 = a[6], + a21 = a[7], + a22 = a[8]; + out[0] = a11 * a22 - a12 * a21; + out[1] = a02 * a21 - a01 * a22; + out[2] = a01 * a12 - a02 * a11; + out[3] = a12 * a20 - a10 * a22; + out[4] = a00 * a22 - a02 * a20; + out[5] = a02 * a10 - a00 * a12; + out[6] = a10 * a21 - a11 * a20; + out[7] = a01 * a20 - a00 * a21; + out[8] = a00 * a11 - a01 * a10; + return out; + } + /** + * Calculates the determinant of a mat3 + * + * @param {ReadonlyMat3} a the source matrix + * @returns {Number} determinant of a + */ + + function determinant$2(a) { + var a00 = a[0], + a01 = a[1], + a02 = a[2]; + var a10 = a[3], + a11 = a[4], + a12 = a[5]; + var a20 = a[6], + a21 = a[7], + a22 = a[8]; + return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); + } + /** + * Multiplies two mat3's + * + * @param {mat3} out the receiving matrix + * @param {ReadonlyMat3} a the first operand + * @param {ReadonlyMat3} b the second operand + * @returns {mat3} out + */ + + function multiply$2(out, a, b) { + var a00 = a[0], + a01 = a[1], + a02 = a[2]; + var a10 = a[3], + a11 = a[4], + a12 = a[5]; + var a20 = a[6], + a21 = a[7], + a22 = a[8]; + var b00 = b[0], + b01 = b[1], + b02 = b[2]; + var b10 = b[3], + b11 = b[4], + b12 = b[5]; + var b20 = b[6], + b21 = b[7], + 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; + } + /** + * Translate a mat3 by the given vector + * + * @param {mat3} out the receiving matrix + * @param {ReadonlyMat3} a the matrix to translate + * @param {ReadonlyVec2} v vector to translate by + * @returns {mat3} out + */ + + function translate$1(out, a, v) { + var a00 = a[0], + a01 = a[1], + a02 = a[2], + a10 = a[3], + a11 = a[4], + a12 = a[5], + a20 = a[6], + a21 = a[7], + a22 = a[8], + x = v[0], + 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; + } + /** + * Rotates a mat3 by the given angle + * + * @param {mat3} out the receiving matrix + * @param {ReadonlyMat3} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat3} out + */ + + function rotate$2(out, a, rad) { + var a00 = a[0], + a01 = a[1], + a02 = a[2], + a10 = a[3], + a11 = a[4], + a12 = a[5], + a20 = a[6], + a21 = a[7], + a22 = a[8], + s = Math.sin(rad), + 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; + } + /** + * Scales the mat3 by the dimensions in the given vec2 + * + * @param {mat3} out the receiving matrix + * @param {ReadonlyMat3} a the matrix to rotate + * @param {ReadonlyVec2} v the vec2 to scale the matrix by + * @returns {mat3} out + **/ + + function scale$2(out, a, v) { + var x = v[0], + 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; + } + /** + * Creates a matrix from a vector translation + * This is equivalent to (but much faster than): + * + * mat3.identity(dest); + * mat3.translate(dest, dest, vec); + * + * @param {mat3} out mat3 receiving operation result + * @param {ReadonlyVec2} v Translation vector + * @returns {mat3} out + */ + + function fromTranslation$1(out, v) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 1; + out[5] = 0; + out[6] = v[0]; + out[7] = v[1]; + out[8] = 1; + return out; + } + /** + * Creates a matrix from a given angle + * This is equivalent to (but much faster than): + * + * mat3.identity(dest); + * mat3.rotate(dest, dest, rad); + * + * @param {mat3} out mat3 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat3} out + */ + + function fromRotation$2(out, rad) { + var s = Math.sin(rad), + c = Math.cos(rad); + out[0] = c; + out[1] = s; + out[2] = 0; + out[3] = -s; + out[4] = c; + out[5] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; + } + /** + * Creates a matrix from a vector scaling + * This is equivalent to (but much faster than): + * + * mat3.identity(dest); + * mat3.scale(dest, dest, vec); + * + * @param {mat3} out mat3 receiving operation result + * @param {ReadonlyVec2} v Scaling vector + * @returns {mat3} out + */ + + function fromScaling$2(out, v) { + out[0] = v[0]; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = v[1]; + out[5] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 1; + return out; + } + /** + * Copies the values from a mat2d into a mat3 + * + * @param {mat3} out the receiving matrix + * @param {ReadonlyMat2d} a the matrix to copy + * @returns {mat3} out + **/ + + function fromMat2d(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = 0; + out[3] = a[2]; + out[4] = a[3]; + out[5] = 0; + out[6] = a[4]; + out[7] = a[5]; + out[8] = 1; + return out; + } + /** + * Calculates a 3x3 matrix from the given quaternion + * + * @param {mat3} out mat3 receiving operation result + * @param {ReadonlyQuat} q Quaternion to create matrix from + * + * @returns {mat3} out + */ + + function fromQuat(out, q) { + var x = q[0], + y = q[1], + z = q[2], + w = q[3]; + var x2 = x + x; + var y2 = y + y; + var z2 = z + z; + var xx = x * x2; + var yx = y * x2; + var yy = y * y2; + var zx = z * x2; + var zy = z * y2; + var zz = z * z2; + var wx = w * x2; + var wy = w * y2; + var wz = w * z2; + out[0] = 1 - yy - zz; + out[3] = yx - wz; + out[6] = zx + wy; + out[1] = yx + wz; + out[4] = 1 - xx - zz; + out[7] = zy - wx; + out[2] = zx - wy; + out[5] = zy + wx; + out[8] = 1 - xx - yy; + return out; + } + /** + * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix + * + * @param {mat3} out mat3 receiving operation result + * @param {ReadonlyMat4} a Mat4 to derive the normal matrix from + * + * @returns {mat3} out + */ + + function normalFromMat4(out, a) { + var a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3]; + var a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7]; + var a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; + var a30 = a[12], + a31 = a[13], + a32 = a[14], + a33 = a[15]; + var b00 = a00 * a11 - a01 * a10; + var b01 = a00 * a12 - a02 * a10; + var b02 = a00 * a13 - a03 * a10; + var b03 = a01 * a12 - a02 * a11; + var b04 = a01 * a13 - a03 * a11; + var b05 = a02 * a13 - a03 * a12; + var b06 = a20 * a31 - a21 * a30; + var b07 = a20 * a32 - a22 * a30; + var b08 = a20 * a33 - a23 * a30; + var b09 = a21 * a32 - a22 * a31; + var b10 = a21 * a33 - a23 * a31; + var b11 = a22 * a33 - a23 * a32; // Calculate the determinant + + var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + + if (!det) { + return null; + } + + det = 1.0 / det; + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + return out; + } + /** + * Generates a 2D projection matrix with the given bounds + * + * @param {mat3} out mat3 frustum matrix will be written into + * @param {number} width Width of your gl context + * @param {number} height Height of gl context + * @returns {mat3} out + */ + + function projection(out, width, height) { + out[0] = 2 / width; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = -2 / height; + out[5] = 0; + out[6] = -1; + out[7] = 1; + out[8] = 1; + return out; + } + /** + * Returns a string representation of a mat3 + * + * @param {ReadonlyMat3} a matrix to represent as a string + * @returns {String} string representation of the matrix + */ + + function str$2(a) { + return "mat3(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ")"; + } + /** + * Returns Frobenius norm of a mat3 + * + * @param {ReadonlyMat3} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ + + function frob$2(a) { + return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]); + } + /** + * Adds two mat3's + * + * @param {mat3} out the receiving matrix + * @param {ReadonlyMat3} a the first operand + * @param {ReadonlyMat3} b the second operand + * @returns {mat3} out + */ + + function add$2(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; + out[7] = a[7] + b[7]; + out[8] = a[8] + b[8]; + return out; + } + /** + * Subtracts matrix b from matrix a + * + * @param {mat3} out the receiving matrix + * @param {ReadonlyMat3} a the first operand + * @param {ReadonlyMat3} b the second operand + * @returns {mat3} out + */ + + function subtract$2(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + out[4] = a[4] - b[4]; + out[5] = a[5] - b[5]; + out[6] = a[6] - b[6]; + out[7] = a[7] - b[7]; + out[8] = a[8] - b[8]; + return out; + } + /** + * Multiply each element of the matrix by a scalar. + * + * @param {mat3} out the receiving matrix + * @param {ReadonlyMat3} a the matrix to scale + * @param {Number} b amount to scale the matrix's elements by + * @returns {mat3} out + */ + + function multiplyScalar$2(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + out[4] = a[4] * b; + out[5] = a[5] * b; + out[6] = a[6] * b; + out[7] = a[7] * b; + out[8] = a[8] * b; + return out; + } + /** + * Adds two mat3's after multiplying each element of the second operand by a scalar value. + * + * @param {mat3} out the receiving vector + * @param {ReadonlyMat3} a the first operand + * @param {ReadonlyMat3} b the second operand + * @param {Number} scale the amount to scale b's elements by before adding + * @returns {mat3} out + */ + + function multiplyScalarAndAdd$2(out, a, b, scale) { + out[0] = a[0] + b[0] * scale; + out[1] = a[1] + b[1] * scale; + out[2] = a[2] + b[2] * scale; + out[3] = a[3] + b[3] * scale; + out[4] = a[4] + b[4] * scale; + out[5] = a[5] + b[5] * scale; + out[6] = a[6] + b[6] * scale; + out[7] = a[7] + b[7] * scale; + out[8] = a[8] + b[8] * scale; + return out; + } + /** + * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) + * + * @param {ReadonlyMat3} a The first matrix. + * @param {ReadonlyMat3} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ + + function exactEquals$2(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8]; + } + /** + * Returns whether or not the matrices have approximately the same elements in the same position. + * + * @param {ReadonlyMat3} a The first matrix. + * @param {ReadonlyMat3} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ + + function equals$3(a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3], + a4 = a[4], + a5 = a[5], + a6 = a[6], + a7 = a[7], + a8 = a[8]; + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3], + b4 = b[4], + b5 = b[5], + b6 = b[6], + b7 = b[7], + b8 = b[8]; + return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)); + } + /** + * Alias for {@link mat3.multiply} + * @function + */ + + var mul$2 = multiply$2; + /** + * Alias for {@link mat3.subtract} + * @function + */ + + var sub$2 = subtract$2; + + var mat3 = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$2, + fromMat4: fromMat4, + clone: clone$2, + copy: copy$2, + fromValues: fromValues$2, + set: set$2, + identity: identity$2, + transpose: transpose$1, + invert: invert$2, + adjoint: adjoint$1, + determinant: determinant$2, + multiply: multiply$2, + translate: translate$1, + rotate: rotate$2, + scale: scale$2, + fromTranslation: fromTranslation$1, + fromRotation: fromRotation$2, + fromScaling: fromScaling$2, + fromMat2d: fromMat2d, + fromQuat: fromQuat, + normalFromMat4: normalFromMat4, + projection: projection, + str: str$2, + frob: frob$2, + add: add$2, + subtract: subtract$2, + multiplyScalar: multiplyScalar$2, + multiplyScalarAndAdd: multiplyScalarAndAdd$2, + exactEquals: exactEquals$2, + equals: equals$3, + mul: mul$2, + sub: sub$2 + }); + + /** + * 4x4 Matrix<br>Format: column-major, when typed out it looks like row-major<br>The matrices are being post multiplied. + * @module mat4 + */ + + /** + * Creates a new identity mat4 + * + * @returns {mat4} a new 4x4 matrix + */ + + function create$3() { + var out = new ARRAY_TYPE(16); + + if (ARRAY_TYPE != Float32Array) { + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + } + + out[0] = 1; + out[5] = 1; + out[10] = 1; + out[15] = 1; + return out; + } + /** + * Creates a new mat4 initialized with values from an existing matrix + * + * @param {ReadonlyMat4} a matrix to clone + * @returns {mat4} a new 4x4 matrix + */ + + function clone$3(a) { + var out = new ARRAY_TYPE(16); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; + } + /** + * Copy the values from one mat4 to another + * + * @param {mat4} out the receiving matrix + * @param {ReadonlyMat4} a the source matrix + * @returns {mat4} out + */ + + function copy$3(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; + } + /** + * Create a new mat4 with the given values + * + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m02 Component in column 0, row 2 position (index 2) + * @param {Number} m03 Component in column 0, row 3 position (index 3) + * @param {Number} m10 Component in column 1, row 0 position (index 4) + * @param {Number} m11 Component in column 1, row 1 position (index 5) + * @param {Number} m12 Component in column 1, row 2 position (index 6) + * @param {Number} m13 Component in column 1, row 3 position (index 7) + * @param {Number} m20 Component in column 2, row 0 position (index 8) + * @param {Number} m21 Component in column 2, row 1 position (index 9) + * @param {Number} m22 Component in column 2, row 2 position (index 10) + * @param {Number} m23 Component in column 2, row 3 position (index 11) + * @param {Number} m30 Component in column 3, row 0 position (index 12) + * @param {Number} m31 Component in column 3, row 1 position (index 13) + * @param {Number} m32 Component in column 3, row 2 position (index 14) + * @param {Number} m33 Component in column 3, row 3 position (index 15) + * @returns {mat4} A new mat4 + */ + + function fromValues$3(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) { + var out = new ARRAY_TYPE(16); + out[0] = m00; + out[1] = m01; + out[2] = m02; + out[3] = m03; + out[4] = m10; + out[5] = m11; + out[6] = m12; + out[7] = m13; + out[8] = m20; + out[9] = m21; + out[10] = m22; + out[11] = m23; + out[12] = m30; + out[13] = m31; + out[14] = m32; + out[15] = m33; + return out; + } + /** + * Set the components of a mat4 to the given values + * + * @param {mat4} out the receiving matrix + * @param {Number} m00 Component in column 0, row 0 position (index 0) + * @param {Number} m01 Component in column 0, row 1 position (index 1) + * @param {Number} m02 Component in column 0, row 2 position (index 2) + * @param {Number} m03 Component in column 0, row 3 position (index 3) + * @param {Number} m10 Component in column 1, row 0 position (index 4) + * @param {Number} m11 Component in column 1, row 1 position (index 5) + * @param {Number} m12 Component in column 1, row 2 position (index 6) + * @param {Number} m13 Component in column 1, row 3 position (index 7) + * @param {Number} m20 Component in column 2, row 0 position (index 8) + * @param {Number} m21 Component in column 2, row 1 position (index 9) + * @param {Number} m22 Component in column 2, row 2 position (index 10) + * @param {Number} m23 Component in column 2, row 3 position (index 11) + * @param {Number} m30 Component in column 3, row 0 position (index 12) + * @param {Number} m31 Component in column 3, row 1 position (index 13) + * @param {Number} m32 Component in column 3, row 2 position (index 14) + * @param {Number} m33 Component in column 3, row 3 position (index 15) + * @returns {mat4} out + */ + + function set$3(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) { + out[0] = m00; + out[1] = m01; + out[2] = m02; + out[3] = m03; + out[4] = m10; + out[5] = m11; + out[6] = m12; + out[7] = m13; + out[8] = m20; + out[9] = m21; + out[10] = m22; + out[11] = m23; + out[12] = m30; + out[13] = m31; + out[14] = m32; + out[15] = m33; + return out; + } + /** + * Set a mat4 to the identity matrix + * + * @param {mat4} out the receiving matrix + * @returns {mat4} out + */ + + function identity$3(out) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; + } + /** + * Transpose the values of a mat4 + * + * @param {mat4} out the receiving matrix + * @param {ReadonlyMat4} a the source matrix + * @returns {mat4} out + */ + + function transpose$2(out, a) { + // If we are transposing ourselves we can skip a few steps but have to cache some values + if (out === a) { + var a01 = a[1], + a02 = a[2], + a03 = a[3]; + var a12 = a[6], + a13 = a[7]; + var a23 = a[11]; + out[1] = a[4]; + out[2] = a[8]; + out[3] = a[12]; + out[4] = a01; + out[6] = a[9]; + out[7] = a[13]; + out[8] = a02; + out[9] = a12; + out[11] = a[14]; + out[12] = a03; + out[13] = a13; + out[14] = a23; + } else { + out[0] = a[0]; + out[1] = a[4]; + out[2] = a[8]; + out[3] = a[12]; + out[4] = a[1]; + out[5] = a[5]; + out[6] = a[9]; + out[7] = a[13]; + out[8] = a[2]; + out[9] = a[6]; + out[10] = a[10]; + out[11] = a[14]; + out[12] = a[3]; + out[13] = a[7]; + out[14] = a[11]; + out[15] = a[15]; + } + + return out; + } + /** + * Inverts a mat4 + * + * @param {mat4} out the receiving matrix + * @param {ReadonlyMat4} a the source matrix + * @returns {mat4} out + */ + + function invert$3(out, a) { + var a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3]; + var a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7]; + var a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; + var a30 = a[12], + a31 = a[13], + a32 = a[14], + a33 = a[15]; + var b00 = a00 * a11 - a01 * a10; + var b01 = a00 * a12 - a02 * a10; + var b02 = a00 * a13 - a03 * a10; + var b03 = a01 * a12 - a02 * a11; + var b04 = a01 * a13 - a03 * a11; + var b05 = a02 * a13 - a03 * a12; + var b06 = a20 * a31 - a21 * a30; + var b07 = a20 * a32 - a22 * a30; + var b08 = a20 * a33 - a23 * a30; + var b09 = a21 * a32 - a22 * a31; + var b10 = a21 * a33 - a23 * a31; + var b11 = a22 * a33 - a23 * a32; // Calculate the determinant + + var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + + if (!det) { + return null; + } + + det = 1.0 / det; + out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det; + out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det; + out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det; + out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det; + out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det; + out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det; + out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det; + out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det; + out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det; + out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det; + out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det; + out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det; + out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det; + out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det; + out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det; + out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det; + return out; + } + /** + * Calculates the adjugate of a mat4 + * + * @param {mat4} out the receiving matrix + * @param {ReadonlyMat4} a the source matrix + * @returns {mat4} out + */ + + function adjoint$2(out, a) { + var a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3]; + var a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7]; + var a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; + var a30 = a[12], + a31 = a[13], + a32 = a[14], + a33 = a[15]; + out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22); + out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22)); + out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12); + out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12)); + out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22)); + out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22); + out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12)); + out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12); + out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21); + out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21)); + out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11); + out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11)); + out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21)); + out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21); + out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11)); + out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11); + return out; + } + /** + * Calculates the determinant of a mat4 + * + * @param {ReadonlyMat4} a the source matrix + * @returns {Number} determinant of a + */ + + function determinant$3(a) { + var a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3]; + var a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7]; + var a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; + var a30 = a[12], + a31 = a[13], + a32 = a[14], + a33 = a[15]; + var b00 = a00 * a11 - a01 * a10; + var b01 = a00 * a12 - a02 * a10; + var b02 = a00 * a13 - a03 * a10; + var b03 = a01 * a12 - a02 * a11; + var b04 = a01 * a13 - a03 * a11; + var b05 = a02 * a13 - a03 * a12; + var b06 = a20 * a31 - a21 * a30; + var b07 = a20 * a32 - a22 * a30; + var b08 = a20 * a33 - a23 * a30; + var b09 = a21 * a32 - a22 * a31; + var b10 = a21 * a33 - a23 * a31; + var b11 = a22 * a33 - a23 * a32; // Calculate the determinant + + return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; + } + /** + * Multiplies two mat4s + * + * @param {mat4} out the receiving matrix + * @param {ReadonlyMat4} a the first operand + * @param {ReadonlyMat4} b the second operand + * @returns {mat4} out + */ + + function multiply$3(out, a, b) { + var a00 = a[0], + a01 = a[1], + a02 = a[2], + a03 = a[3]; + var a10 = a[4], + a11 = a[5], + a12 = a[6], + a13 = a[7]; + var a20 = a[8], + a21 = a[9], + a22 = a[10], + a23 = a[11]; + var a30 = a[12], + a31 = a[13], + a32 = a[14], + a33 = a[15]; // Cache only the current line of the second matrix + + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3]; + out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + b0 = b[4]; + b1 = b[5]; + b2 = b[6]; + b3 = b[7]; + out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + b0 = b[8]; + b1 = b[9]; + b2 = b[10]; + b3 = b[11]; + out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + b0 = b[12]; + b1 = b[13]; + b2 = b[14]; + b3 = b[15]; + out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; + out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; + out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; + out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; + return out; + } + /** + * Translate a mat4 by the given vector + * + * @param {mat4} out the receiving matrix + * @param {ReadonlyMat4} a the matrix to translate + * @param {ReadonlyVec3} v vector to translate by + * @returns {mat4} out + */ + + function translate$2(out, a, v) { + var x = v[0], + y = v[1], + z = v[2]; + var a00, a01, a02, a03; + var a10, a11, a12, a13; + var a20, a21, a22, a23; + + if (a === out) { + out[12] = a[0] * x + a[4] * y + a[8] * z + a[12]; + out[13] = a[1] * x + a[5] * y + a[9] * z + a[13]; + out[14] = a[2] * x + a[6] * y + a[10] * z + a[14]; + out[15] = a[3] * x + a[7] * y + a[11] * z + a[15]; + } else { + a00 = a[0]; + a01 = a[1]; + a02 = a[2]; + a03 = a[3]; + a10 = a[4]; + a11 = a[5]; + a12 = a[6]; + a13 = a[7]; + a20 = a[8]; + a21 = a[9]; + a22 = a[10]; + a23 = a[11]; + out[0] = a00; + out[1] = a01; + out[2] = a02; + out[3] = a03; + out[4] = a10; + out[5] = a11; + out[6] = a12; + out[7] = a13; + out[8] = a20; + out[9] = a21; + out[10] = a22; + out[11] = a23; + out[12] = a00 * x + a10 * y + a20 * z + a[12]; + out[13] = a01 * x + a11 * y + a21 * z + a[13]; + out[14] = a02 * x + a12 * y + a22 * z + a[14]; + out[15] = a03 * x + a13 * y + a23 * z + a[15]; + } + + return out; + } + /** + * Scales the mat4 by the dimensions in the given vec3 not using vectorization + * + * @param {mat4} out the receiving matrix + * @param {ReadonlyMat4} a the matrix to scale + * @param {ReadonlyVec3} v the vec3 to scale the matrix by + * @returns {mat4} out + **/ + + function scale$3(out, a, v) { + var x = v[0], + y = v[1], + z = v[2]; + out[0] = a[0] * x; + out[1] = a[1] * x; + out[2] = a[2] * x; + out[3] = a[3] * x; + out[4] = a[4] * y; + out[5] = a[5] * y; + out[6] = a[6] * y; + out[7] = a[7] * y; + out[8] = a[8] * z; + out[9] = a[9] * z; + out[10] = a[10] * z; + out[11] = a[11] * z; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + return out; + } + /** + * Rotates a mat4 by the given angle around the given axis + * + * @param {mat4} out the receiving matrix + * @param {ReadonlyMat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @param {ReadonlyVec3} axis the axis to rotate around + * @returns {mat4} out + */ + + function rotate$3(out, a, rad, axis) { + var x = axis[0], + y = axis[1], + z = axis[2]; + var len = Math.hypot(x, y, z); + var s, c, t; + var a00, a01, a02, a03; + var a10, a11, a12, a13; + var a20, a21, a22, a23; + var b00, b01, b02; + var b10, b11, b12; + var b20, b21, b22; + + if (len < EPSILON) { + return null; + } + + len = 1 / len; + x *= len; + y *= len; + z *= len; + s = Math.sin(rad); + c = Math.cos(rad); + t = 1 - c; + a00 = a[0]; + a01 = a[1]; + a02 = a[2]; + a03 = a[3]; + a10 = a[4]; + a11 = a[5]; + a12 = a[6]; + a13 = a[7]; + a20 = a[8]; + a21 = a[9]; + a22 = a[10]; + a23 = a[11]; // Construct the elements of the rotation matrix + + b00 = x * x * t + c; + b01 = y * x * t + z * s; + b02 = z * x * t - y * s; + b10 = x * y * t - z * s; + b11 = y * y * t + c; + b12 = z * y * t + x * s; + b20 = x * z * t + y * s; + b21 = y * z * t - x * s; + b22 = z * z * t + c; // Perform rotation-specific matrix multiplication + + out[0] = a00 * b00 + a10 * b01 + a20 * b02; + out[1] = a01 * b00 + a11 * b01 + a21 * b02; + out[2] = a02 * b00 + a12 * b01 + a22 * b02; + out[3] = a03 * b00 + a13 * b01 + a23 * b02; + out[4] = a00 * b10 + a10 * b11 + a20 * b12; + out[5] = a01 * b10 + a11 * b11 + a21 * b12; + out[6] = a02 * b10 + a12 * b11 + a22 * b12; + out[7] = a03 * b10 + a13 * b11 + a23 * b12; + out[8] = a00 * b20 + a10 * b21 + a20 * b22; + out[9] = a01 * b20 + a11 * b21 + a21 * b22; + out[10] = a02 * b20 + a12 * b21 + a22 * b22; + out[11] = a03 * b20 + a13 * b21 + a23 * b22; + + if (a !== out) { + // If the source and destination differ, copy the unchanged last row + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } + + return out; + } + /** + * Rotates a matrix by the given angle around the X axis + * + * @param {mat4} out the receiving matrix + * @param {ReadonlyMat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ + + function rotateX(out, a, rad) { + var s = Math.sin(rad); + var c = Math.cos(rad); + var a10 = a[4]; + var a11 = a[5]; + var a12 = a[6]; + var a13 = a[7]; + var a20 = a[8]; + var a21 = a[9]; + var a22 = a[10]; + var a23 = a[11]; + + if (a !== out) { + // If the source and destination differ, copy the unchanged rows + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } // Perform axis-specific matrix multiplication + + + out[4] = a10 * c + a20 * s; + out[5] = a11 * c + a21 * s; + out[6] = a12 * c + a22 * s; + out[7] = a13 * c + a23 * s; + out[8] = a20 * c - a10 * s; + out[9] = a21 * c - a11 * s; + out[10] = a22 * c - a12 * s; + out[11] = a23 * c - a13 * s; + return out; + } + /** + * Rotates a matrix by the given angle around the Y axis + * + * @param {mat4} out the receiving matrix + * @param {ReadonlyMat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ + + function rotateY(out, a, rad) { + var s = Math.sin(rad); + var c = Math.cos(rad); + var a00 = a[0]; + var a01 = a[1]; + var a02 = a[2]; + var a03 = a[3]; + var a20 = a[8]; + var a21 = a[9]; + var a22 = a[10]; + var a23 = a[11]; + + if (a !== out) { + // If the source and destination differ, copy the unchanged rows + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } // Perform axis-specific matrix multiplication + + + out[0] = a00 * c - a20 * s; + out[1] = a01 * c - a21 * s; + out[2] = a02 * c - a22 * s; + out[3] = a03 * c - a23 * s; + out[8] = a00 * s + a20 * c; + out[9] = a01 * s + a21 * c; + out[10] = a02 * s + a22 * c; + out[11] = a03 * s + a23 * c; + return out; + } + /** + * Rotates a matrix by the given angle around the Z axis + * + * @param {mat4} out the receiving matrix + * @param {ReadonlyMat4} a the matrix to rotate + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ + + function rotateZ(out, a, rad) { + var s = Math.sin(rad); + var c = Math.cos(rad); + var a00 = a[0]; + var a01 = a[1]; + var a02 = a[2]; + var a03 = a[3]; + var a10 = a[4]; + var a11 = a[5]; + var a12 = a[6]; + var a13 = a[7]; + + if (a !== out) { + // If the source and destination differ, copy the unchanged last row + out[8] = a[8]; + out[9] = a[9]; + out[10] = a[10]; + out[11] = a[11]; + out[12] = a[12]; + out[13] = a[13]; + out[14] = a[14]; + out[15] = a[15]; + } // Perform axis-specific matrix multiplication + + + out[0] = a00 * c + a10 * s; + out[1] = a01 * c + a11 * s; + out[2] = a02 * c + a12 * s; + out[3] = a03 * c + a13 * s; + out[4] = a10 * c - a00 * s; + out[5] = a11 * c - a01 * s; + out[6] = a12 * c - a02 * s; + out[7] = a13 * c - a03 * s; + return out; + } + /** + * Creates a matrix from a vector translation + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, dest, vec); + * + * @param {mat4} out mat4 receiving operation result + * @param {ReadonlyVec3} v Translation vector + * @returns {mat4} out + */ + + function fromTranslation$2(out, v) { + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + return out; + } + /** + * Creates a matrix from a vector scaling + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.scale(dest, dest, vec); + * + * @param {mat4} out mat4 receiving operation result + * @param {ReadonlyVec3} v Scaling vector + * @returns {mat4} out + */ + + function fromScaling$3(out, v) { + out[0] = v[0]; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = v[1]; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = v[2]; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; + } + /** + * Creates a matrix from a given angle around a given axis + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.rotate(dest, dest, rad, axis); + * + * @param {mat4} out mat4 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @param {ReadonlyVec3} axis the axis to rotate around + * @returns {mat4} out + */ + + function fromRotation$3(out, rad, axis) { + var x = axis[0], + y = axis[1], + z = axis[2]; + var len = Math.hypot(x, y, z); + var s, c, t; + + if (len < EPSILON) { + return null; + } + + len = 1 / len; + x *= len; + y *= len; + z *= len; + s = Math.sin(rad); + c = Math.cos(rad); + t = 1 - c; // Perform rotation-specific matrix multiplication + + out[0] = x * x * t + c; + out[1] = y * x * t + z * s; + out[2] = z * x * t - y * s; + out[3] = 0; + out[4] = x * y * t - z * s; + out[5] = y * y * t + c; + out[6] = z * y * t + x * s; + out[7] = 0; + out[8] = x * z * t + y * s; + out[9] = y * z * t - x * s; + out[10] = z * z * t + c; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; + } + /** + * Creates a matrix from the given angle around the X axis + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.rotateX(dest, dest, rad); + * + * @param {mat4} out mat4 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ + + function fromXRotation(out, rad) { + var s = Math.sin(rad); + var c = Math.cos(rad); // Perform axis-specific matrix multiplication + + out[0] = 1; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = c; + out[6] = s; + out[7] = 0; + out[8] = 0; + out[9] = -s; + out[10] = c; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; + } + /** + * Creates a matrix from the given angle around the Y axis + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.rotateY(dest, dest, rad); + * + * @param {mat4} out mat4 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ + + function fromYRotation(out, rad) { + var s = Math.sin(rad); + var c = Math.cos(rad); // Perform axis-specific matrix multiplication + + out[0] = c; + out[1] = 0; + out[2] = -s; + out[3] = 0; + out[4] = 0; + out[5] = 1; + out[6] = 0; + out[7] = 0; + out[8] = s; + out[9] = 0; + out[10] = c; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; + } + /** + * Creates a matrix from the given angle around the Z axis + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.rotateZ(dest, dest, rad); + * + * @param {mat4} out mat4 receiving operation result + * @param {Number} rad the angle to rotate the matrix by + * @returns {mat4} out + */ + + function fromZRotation(out, rad) { + var s = Math.sin(rad); + var c = Math.cos(rad); // Perform axis-specific matrix multiplication + + out[0] = c; + out[1] = s; + out[2] = 0; + out[3] = 0; + out[4] = -s; + out[5] = c; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 1; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; + } + /** + * Creates a matrix from a quaternion rotation and vector translation + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * let quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * + * @param {mat4} out mat4 receiving operation result + * @param {quat4} q Rotation quaternion + * @param {ReadonlyVec3} v Translation vector + * @returns {mat4} out + */ + + function fromRotationTranslation(out, q, v) { + // Quaternion math + var x = q[0], + y = q[1], + z = q[2], + w = q[3]; + var x2 = x + x; + var y2 = y + y; + var z2 = z + z; + var xx = x * x2; + var xy = x * y2; + var xz = x * z2; + var yy = y * y2; + var yz = y * z2; + var zz = z * z2; + var wx = w * x2; + var wy = w * y2; + var wz = w * z2; + out[0] = 1 - (yy + zz); + out[1] = xy + wz; + out[2] = xz - wy; + out[3] = 0; + out[4] = xy - wz; + out[5] = 1 - (xx + zz); + out[6] = yz + wx; + out[7] = 0; + out[8] = xz + wy; + out[9] = yz - wx; + out[10] = 1 - (xx + yy); + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + return out; + } + /** + * Creates a new mat4 from a dual quat. + * + * @param {mat4} out Matrix + * @param {ReadonlyQuat2} a Dual Quaternion + * @returns {mat4} mat4 receiving operation result + */ + + function fromQuat2(out, a) { + var translation = new ARRAY_TYPE(3); + var bx = -a[0], + by = -a[1], + bz = -a[2], + bw = a[3], + ax = a[4], + ay = a[5], + az = a[6], + aw = a[7]; + var magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense + + if (magnitude > 0) { + translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude; + translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude; + translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude; + } else { + translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2; + translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2; + translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2; + } + + fromRotationTranslation(out, a, translation); + return out; + } + /** + * Returns the translation vector component of a transformation + * matrix. If a matrix is built with fromRotationTranslation, + * the returned vector will be the same as the translation vector + * originally supplied. + * @param {vec3} out Vector to receive translation component + * @param {ReadonlyMat4} mat Matrix to be decomposed (input) + * @return {vec3} out + */ + + function getTranslation(out, mat) { + out[0] = mat[12]; + out[1] = mat[13]; + out[2] = mat[14]; + return out; + } + /** + * Returns the scaling factor component of a transformation + * matrix. If a matrix is built with fromRotationTranslationScale + * with a normalized Quaternion paramter, the returned vector will be + * the same as the scaling vector + * originally supplied. + * @param {vec3} out Vector to receive scaling factor component + * @param {ReadonlyMat4} mat Matrix to be decomposed (input) + * @return {vec3} out + */ + + function getScaling(out, mat) { + var m11 = mat[0]; + var m12 = mat[1]; + var m13 = mat[2]; + var m21 = mat[4]; + var m22 = mat[5]; + var m23 = mat[6]; + var m31 = mat[8]; + var m32 = mat[9]; + var m33 = mat[10]; + out[0] = Math.hypot(m11, m12, m13); + out[1] = Math.hypot(m21, m22, m23); + out[2] = Math.hypot(m31, m32, m33); + return out; + } + /** + * Returns a quaternion representing the rotational component + * of a transformation matrix. If a matrix is built with + * fromRotationTranslation, the returned quaternion will be the + * same as the quaternion originally supplied. + * @param {quat} out Quaternion to receive the rotation component + * @param {ReadonlyMat4} mat Matrix to be decomposed (input) + * @return {quat} out + */ + + function getRotation(out, mat) { + var scaling = new ARRAY_TYPE(3); + getScaling(scaling, mat); + var is1 = 1 / scaling[0]; + var is2 = 1 / scaling[1]; + var is3 = 1 / scaling[2]; + var sm11 = mat[0] * is1; + var sm12 = mat[1] * is2; + var sm13 = mat[2] * is3; + var sm21 = mat[4] * is1; + var sm22 = mat[5] * is2; + var sm23 = mat[6] * is3; + var sm31 = mat[8] * is1; + var sm32 = mat[9] * is2; + var sm33 = mat[10] * is3; + var trace = sm11 + sm22 + sm33; + var S = 0; + + if (trace > 0) { + S = Math.sqrt(trace + 1.0) * 2; + out[3] = 0.25 * S; + out[0] = (sm23 - sm32) / S; + out[1] = (sm31 - sm13) / S; + out[2] = (sm12 - sm21) / S; + } else if (sm11 > sm22 && sm11 > sm33) { + S = Math.sqrt(1.0 + sm11 - sm22 - sm33) * 2; + out[3] = (sm23 - sm32) / S; + out[0] = 0.25 * S; + out[1] = (sm12 + sm21) / S; + out[2] = (sm31 + sm13) / S; + } else if (sm22 > sm33) { + S = Math.sqrt(1.0 + sm22 - sm11 - sm33) * 2; + out[3] = (sm31 - sm13) / S; + out[0] = (sm12 + sm21) / S; + out[1] = 0.25 * S; + out[2] = (sm23 + sm32) / S; + } else { + S = Math.sqrt(1.0 + sm33 - sm11 - sm22) * 2; + out[3] = (sm12 - sm21) / S; + out[0] = (sm31 + sm13) / S; + out[1] = (sm23 + sm32) / S; + out[2] = 0.25 * S; + } + + return out; + } + /** + * Creates a matrix from a quaternion rotation, vector translation and vector scale + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * let quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * mat4.scale(dest, scale) + * + * @param {mat4} out mat4 receiving operation result + * @param {quat4} q Rotation quaternion + * @param {ReadonlyVec3} v Translation vector + * @param {ReadonlyVec3} s Scaling vector + * @returns {mat4} out + */ + + function fromRotationTranslationScale(out, q, v, s) { + // Quaternion math + var x = q[0], + y = q[1], + z = q[2], + w = q[3]; + var x2 = x + x; + var y2 = y + y; + var z2 = z + z; + var xx = x * x2; + var xy = x * y2; + var xz = x * z2; + var yy = y * y2; + var yz = y * z2; + var zz = z * z2; + var wx = w * x2; + var wy = w * y2; + var wz = w * z2; + var sx = s[0]; + var sy = s[1]; + var sz = s[2]; + out[0] = (1 - (yy + zz)) * sx; + out[1] = (xy + wz) * sx; + out[2] = (xz - wy) * sx; + out[3] = 0; + out[4] = (xy - wz) * sy; + out[5] = (1 - (xx + zz)) * sy; + out[6] = (yz + wx) * sy; + out[7] = 0; + out[8] = (xz + wy) * sz; + out[9] = (yz - wx) * sz; + out[10] = (1 - (xx + yy)) * sz; + out[11] = 0; + out[12] = v[0]; + out[13] = v[1]; + out[14] = v[2]; + out[15] = 1; + return out; + } + /** + * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin + * This is equivalent to (but much faster than): + * + * mat4.identity(dest); + * mat4.translate(dest, vec); + * mat4.translate(dest, origin); + * let quatMat = mat4.create(); + * quat4.toMat4(quat, quatMat); + * mat4.multiply(dest, quatMat); + * mat4.scale(dest, scale) + * mat4.translate(dest, negativeOrigin); + * + * @param {mat4} out mat4 receiving operation result + * @param {quat4} q Rotation quaternion + * @param {ReadonlyVec3} v Translation vector + * @param {ReadonlyVec3} s Scaling vector + * @param {ReadonlyVec3} o The origin vector around which to scale and rotate + * @returns {mat4} out + */ + + function fromRotationTranslationScaleOrigin(out, q, v, s, o) { + // Quaternion math + var x = q[0], + y = q[1], + z = q[2], + w = q[3]; + var x2 = x + x; + var y2 = y + y; + var z2 = z + z; + var xx = x * x2; + var xy = x * y2; + var xz = x * z2; + var yy = y * y2; + var yz = y * z2; + var zz = z * z2; + var wx = w * x2; + var wy = w * y2; + var wz = w * z2; + var sx = s[0]; + var sy = s[1]; + var sz = s[2]; + var ox = o[0]; + var oy = o[1]; + var oz = o[2]; + var out0 = (1 - (yy + zz)) * sx; + var out1 = (xy + wz) * sx; + var out2 = (xz - wy) * sx; + var out4 = (xy - wz) * sy; + var out5 = (1 - (xx + zz)) * sy; + var out6 = (yz + wx) * sy; + var out8 = (xz + wy) * sz; + var out9 = (yz - wx) * sz; + var out10 = (1 - (xx + yy)) * sz; + out[0] = out0; + out[1] = out1; + out[2] = out2; + out[3] = 0; + out[4] = out4; + out[5] = out5; + out[6] = out6; + out[7] = 0; + out[8] = out8; + out[9] = out9; + out[10] = out10; + out[11] = 0; + out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz); + out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz); + out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz); + out[15] = 1; + return out; + } + /** + * Calculates a 4x4 matrix from the given quaternion + * + * @param {mat4} out mat4 receiving operation result + * @param {ReadonlyQuat} q Quaternion to create matrix from + * + * @returns {mat4} out + */ + + function fromQuat$1(out, q) { + var x = q[0], + y = q[1], + z = q[2], + w = q[3]; + var x2 = x + x; + var y2 = y + y; + var z2 = z + z; + var xx = x * x2; + var yx = y * x2; + var yy = y * y2; + var zx = z * x2; + var zy = z * y2; + var zz = z * z2; + var wx = w * x2; + var wy = w * y2; + var wz = w * z2; + out[0] = 1 - yy - zz; + out[1] = yx + wz; + out[2] = zx - wy; + out[3] = 0; + out[4] = yx - wz; + out[5] = 1 - xx - zz; + out[6] = zy + wx; + out[7] = 0; + out[8] = zx + wy; + out[9] = zy - wx; + out[10] = 1 - xx - yy; + out[11] = 0; + out[12] = 0; + out[13] = 0; + out[14] = 0; + out[15] = 1; + return out; + } + /** + * Generates a frustum matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {Number} left Left bound of the frustum + * @param {Number} right Right bound of the frustum + * @param {Number} bottom Bottom bound of the frustum + * @param {Number} top Top bound of the frustum + * @param {Number} near Near bound of the frustum + * @param {Number} far Far bound of the frustum + * @returns {mat4} out + */ + + function frustum(out, left, right, bottom, top, near, far) { + var rl = 1 / (right - left); + var tb = 1 / (top - bottom); + var nf = 1 / (near - far); + out[0] = near * 2 * rl; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = near * 2 * tb; + out[6] = 0; + out[7] = 0; + out[8] = (right + left) * rl; + out[9] = (top + bottom) * tb; + out[10] = (far + near) * nf; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[14] = far * near * 2 * nf; + out[15] = 0; + return out; + } + /** + * Generates a perspective projection matrix with the given bounds. + * Passing null/undefined/no value for far will generate infinite projection matrix. + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {number} fovy Vertical field of view in radians + * @param {number} aspect Aspect ratio. typically viewport width/height + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum, can be null or Infinity + * @returns {mat4} out + */ + + function perspective(out, fovy, aspect, near, far) { + var f = 1.0 / Math.tan(fovy / 2), + nf; + out[0] = f / aspect; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = f; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[11] = -1; + out[12] = 0; + out[13] = 0; + out[15] = 0; + + if (far != null && far !== Infinity) { + nf = 1 / (near - far); + out[10] = (far + near) * nf; + out[14] = 2 * far * near * nf; + } else { + out[10] = -1; + out[14] = -2 * near; + } + + return out; + } + /** + * Generates a perspective projection matrix with the given field of view. + * This is primarily useful for generating projection matrices to be used + * with the still experiemental WebVR API. + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ + + function perspectiveFromFieldOfView(out, fov, near, far) { + var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0); + var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0); + var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0); + var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0); + var xScale = 2.0 / (leftTan + rightTan); + var yScale = 2.0 / (upTan + downTan); + out[0] = xScale; + out[1] = 0.0; + out[2] = 0.0; + out[3] = 0.0; + out[4] = 0.0; + out[5] = yScale; + out[6] = 0.0; + out[7] = 0.0; + out[8] = -((leftTan - rightTan) * xScale * 0.5); + out[9] = (upTan - downTan) * yScale * 0.5; + out[10] = far / (near - far); + out[11] = -1.0; + out[12] = 0.0; + out[13] = 0.0; + out[14] = far * near / (near - far); + out[15] = 0.0; + return out; + } + /** + * Generates a orthogonal projection matrix with the given bounds + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {number} left Left bound of the frustum + * @param {number} right Right bound of the frustum + * @param {number} bottom Bottom bound of the frustum + * @param {number} top Top bound of the frustum + * @param {number} near Near bound of the frustum + * @param {number} far Far bound of the frustum + * @returns {mat4} out + */ + + function ortho(out, left, right, bottom, top, near, far) { + var lr = 1 / (left - right); + var bt = 1 / (bottom - top); + var nf = 1 / (near - far); + out[0] = -2 * lr; + out[1] = 0; + out[2] = 0; + out[3] = 0; + out[4] = 0; + out[5] = -2 * bt; + out[6] = 0; + out[7] = 0; + out[8] = 0; + out[9] = 0; + out[10] = 2 * nf; + out[11] = 0; + out[12] = (left + right) * lr; + out[13] = (top + bottom) * bt; + out[14] = (far + near) * nf; + out[15] = 1; + return out; + } + /** + * Generates a look-at matrix with the given eye position, focal point, and up axis. + * If you want a matrix that actually makes an object look at another object, you should use targetTo instead. + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {ReadonlyVec3} eye Position of the viewer + * @param {ReadonlyVec3} center Point the viewer is looking at + * @param {ReadonlyVec3} up vec3 pointing up + * @returns {mat4} out + */ + + function lookAt(out, eye, center, up) { + var x0, x1, x2, y0, y1, y2, z0, z1, z2, len; + var eyex = eye[0]; + var eyey = eye[1]; + var eyez = eye[2]; + var upx = up[0]; + var upy = up[1]; + var upz = up[2]; + var centerx = center[0]; + var centery = center[1]; + var centerz = center[2]; + + if (Math.abs(eyex - centerx) < EPSILON && Math.abs(eyey - centery) < EPSILON && Math.abs(eyez - centerz) < EPSILON) { + return identity$3(out); + } + + z0 = eyex - centerx; + z1 = eyey - centery; + z2 = eyez - centerz; + len = 1 / Math.hypot(z0, z1, z2); + z0 *= len; + z1 *= len; + z2 *= len; + x0 = upy * z2 - upz * z1; + x1 = upz * z0 - upx * z2; + x2 = upx * z1 - upy * z0; + len = Math.hypot(x0, x1, x2); + + if (!len) { + x0 = 0; + x1 = 0; + x2 = 0; + } else { + len = 1 / len; + x0 *= len; + x1 *= len; + x2 *= len; + } + + y0 = z1 * x2 - z2 * x1; + y1 = z2 * x0 - z0 * x2; + y2 = z0 * x1 - z1 * x0; + len = Math.hypot(y0, y1, y2); + + if (!len) { + y0 = 0; + y1 = 0; + y2 = 0; + } else { + len = 1 / len; + y0 *= len; + y1 *= len; + y2 *= len; + } + + out[0] = x0; + out[1] = y0; + out[2] = z0; + out[3] = 0; + out[4] = x1; + out[5] = y1; + out[6] = z1; + out[7] = 0; + out[8] = x2; + out[9] = y2; + out[10] = z2; + out[11] = 0; + out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); + out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); + out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); + out[15] = 1; + return out; + } + /** + * Generates a matrix that makes something look at something else. + * + * @param {mat4} out mat4 frustum matrix will be written into + * @param {ReadonlyVec3} eye Position of the viewer + * @param {ReadonlyVec3} center Point the viewer is looking at + * @param {ReadonlyVec3} up vec3 pointing up + * @returns {mat4} out + */ + + function targetTo(out, eye, target, up) { + var eyex = eye[0], + eyey = eye[1], + eyez = eye[2], + upx = up[0], + upy = up[1], + upz = up[2]; + var z0 = eyex - target[0], + z1 = eyey - target[1], + z2 = eyez - target[2]; + var len = z0 * z0 + z1 * z1 + z2 * z2; + + if (len > 0) { + len = 1 / Math.sqrt(len); + z0 *= len; + z1 *= len; + z2 *= len; + } + + var x0 = upy * z2 - upz * z1, + x1 = upz * z0 - upx * z2, + x2 = upx * z1 - upy * z0; + len = x0 * x0 + x1 * x1 + x2 * x2; + + if (len > 0) { + len = 1 / Math.sqrt(len); + x0 *= len; + x1 *= len; + x2 *= len; + } + + out[0] = x0; + out[1] = x1; + out[2] = x2; + out[3] = 0; + out[4] = z1 * x2 - z2 * x1; + out[5] = z2 * x0 - z0 * x2; + out[6] = z0 * x1 - z1 * x0; + out[7] = 0; + out[8] = z0; + out[9] = z1; + out[10] = z2; + out[11] = 0; + out[12] = eyex; + out[13] = eyey; + out[14] = eyez; + out[15] = 1; + return out; + } + /** + * Returns a string representation of a mat4 + * + * @param {ReadonlyMat4} a matrix to represent as a string + * @returns {String} string representation of the matrix + */ + + function str$3(a) { + return "mat4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ", " + a[8] + ", " + a[9] + ", " + a[10] + ", " + a[11] + ", " + a[12] + ", " + a[13] + ", " + a[14] + ", " + a[15] + ")"; + } + /** + * Returns Frobenius norm of a mat4 + * + * @param {ReadonlyMat4} a the matrix to calculate Frobenius norm of + * @returns {Number} Frobenius norm + */ + + function frob$3(a) { + return Math.hypot(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]); + } + /** + * Adds two mat4's + * + * @param {mat4} out the receiving matrix + * @param {ReadonlyMat4} a the first operand + * @param {ReadonlyMat4} b the second operand + * @returns {mat4} out + */ + + function add$3(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; + out[7] = a[7] + b[7]; + out[8] = a[8] + b[8]; + out[9] = a[9] + b[9]; + out[10] = a[10] + b[10]; + out[11] = a[11] + b[11]; + out[12] = a[12] + b[12]; + out[13] = a[13] + b[13]; + out[14] = a[14] + b[14]; + out[15] = a[15] + b[15]; + return out; + } + /** + * Subtracts matrix b from matrix a + * + * @param {mat4} out the receiving matrix + * @param {ReadonlyMat4} a the first operand + * @param {ReadonlyMat4} b the second operand + * @returns {mat4} out + */ + + function subtract$3(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + out[4] = a[4] - b[4]; + out[5] = a[5] - b[5]; + out[6] = a[6] - b[6]; + out[7] = a[7] - b[7]; + out[8] = a[8] - b[8]; + out[9] = a[9] - b[9]; + out[10] = a[10] - b[10]; + out[11] = a[11] - b[11]; + out[12] = a[12] - b[12]; + out[13] = a[13] - b[13]; + out[14] = a[14] - b[14]; + out[15] = a[15] - b[15]; + return out; + } + /** + * Multiply each element of the matrix by a scalar. + * + * @param {mat4} out the receiving matrix + * @param {ReadonlyMat4} a the matrix to scale + * @param {Number} b amount to scale the matrix's elements by + * @returns {mat4} out + */ + + function multiplyScalar$3(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + out[4] = a[4] * b; + out[5] = a[5] * b; + out[6] = a[6] * b; + out[7] = a[7] * b; + out[8] = a[8] * b; + out[9] = a[9] * b; + out[10] = a[10] * b; + out[11] = a[11] * b; + out[12] = a[12] * b; + out[13] = a[13] * b; + out[14] = a[14] * b; + out[15] = a[15] * b; + return out; + } + /** + * Adds two mat4's after multiplying each element of the second operand by a scalar value. + * + * @param {mat4} out the receiving vector + * @param {ReadonlyMat4} a the first operand + * @param {ReadonlyMat4} b the second operand + * @param {Number} scale the amount to scale b's elements by before adding + * @returns {mat4} out + */ + + function multiplyScalarAndAdd$3(out, a, b, scale) { + out[0] = a[0] + b[0] * scale; + out[1] = a[1] + b[1] * scale; + out[2] = a[2] + b[2] * scale; + out[3] = a[3] + b[3] * scale; + out[4] = a[4] + b[4] * scale; + out[5] = a[5] + b[5] * scale; + out[6] = a[6] + b[6] * scale; + out[7] = a[7] + b[7] * scale; + out[8] = a[8] + b[8] * scale; + out[9] = a[9] + b[9] * scale; + out[10] = a[10] + b[10] * scale; + out[11] = a[11] + b[11] * scale; + out[12] = a[12] + b[12] * scale; + out[13] = a[13] + b[13] * scale; + out[14] = a[14] + b[14] * scale; + out[15] = a[15] + b[15] * scale; + return out; + } + /** + * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) + * + * @param {ReadonlyMat4} a The first matrix. + * @param {ReadonlyMat4} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ + + function exactEquals$3(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15]; + } + /** + * Returns whether or not the matrices have approximately the same elements in the same position. + * + * @param {ReadonlyMat4} a The first matrix. + * @param {ReadonlyMat4} b The second matrix. + * @returns {Boolean} True if the matrices are equal, false otherwise. + */ + + function equals$4(a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3]; + var a4 = a[4], + a5 = a[5], + a6 = a[6], + a7 = a[7]; + var a8 = a[8], + a9 = a[9], + a10 = a[10], + a11 = a[11]; + var a12 = a[12], + a13 = a[13], + a14 = a[14], + a15 = a[15]; + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3]; + var b4 = b[4], + b5 = b[5], + b6 = b[6], + b7 = b[7]; + var b8 = b[8], + b9 = b[9], + b10 = b[10], + b11 = b[11]; + var b12 = b[12], + b13 = b[13], + b14 = b[14], + b15 = b[15]; + return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= EPSILON * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= EPSILON * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= EPSILON * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= EPSILON * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= EPSILON * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= EPSILON * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= EPSILON * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= EPSILON * Math.max(1.0, Math.abs(a15), Math.abs(b15)); + } + /** + * Alias for {@link mat4.multiply} + * @function + */ + + var mul$3 = multiply$3; + /** + * Alias for {@link mat4.subtract} + * @function + */ + + var sub$3 = subtract$3; + + var mat4 = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$3, + clone: clone$3, + copy: copy$3, + fromValues: fromValues$3, + set: set$3, + identity: identity$3, + transpose: transpose$2, + invert: invert$3, + adjoint: adjoint$2, + determinant: determinant$3, + multiply: multiply$3, + translate: translate$2, + scale: scale$3, + rotate: rotate$3, + rotateX: rotateX, + rotateY: rotateY, + rotateZ: rotateZ, + fromTranslation: fromTranslation$2, + fromScaling: fromScaling$3, + fromRotation: fromRotation$3, + fromXRotation: fromXRotation, + fromYRotation: fromYRotation, + fromZRotation: fromZRotation, + fromRotationTranslation: fromRotationTranslation, + fromQuat2: fromQuat2, + getTranslation: getTranslation, + getScaling: getScaling, + getRotation: getRotation, + fromRotationTranslationScale: fromRotationTranslationScale, + fromRotationTranslationScaleOrigin: fromRotationTranslationScaleOrigin, + fromQuat: fromQuat$1, + frustum: frustum, + perspective: perspective, + perspectiveFromFieldOfView: perspectiveFromFieldOfView, + ortho: ortho, + lookAt: lookAt, + targetTo: targetTo, + str: str$3, + frob: frob$3, + add: add$3, + subtract: subtract$3, + multiplyScalar: multiplyScalar$3, + multiplyScalarAndAdd: multiplyScalarAndAdd$3, + exactEquals: exactEquals$3, + equals: equals$4, + mul: mul$3, + sub: sub$3 + }); + + /** + * 3 Dimensional Vector + * @module vec3 + */ + + /** + * Creates a new, empty vec3 + * + * @returns {vec3} a new 3D vector + */ + + function create$4() { + var out = new ARRAY_TYPE(3); + + if (ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + } + + return out; + } + /** + * Creates a new vec3 initialized with values from an existing vector + * + * @param {ReadonlyVec3} a vector to clone + * @returns {vec3} a new 3D vector + */ + + function clone$4(a) { + var out = new ARRAY_TYPE(3); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; + } + /** + * Calculates the length of a vec3 + * + * @param {ReadonlyVec3} a vector to calculate length of + * @returns {Number} length of a + */ + + function length(a) { + var x = a[0]; + var y = a[1]; + var z = a[2]; + return Math.hypot(x, y, z); + } + /** + * Creates a new vec3 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @returns {vec3} a new 3D vector + */ + + function fromValues$4(x, y, z) { + var out = new ARRAY_TYPE(3); + out[0] = x; + out[1] = y; + out[2] = z; + return out; + } + /** + * Copy the values from one vec3 to another + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a the source vector + * @returns {vec3} out + */ + + function copy$4(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + return out; + } + /** + * Set the components of a vec3 to the given values + * + * @param {vec3} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @returns {vec3} out + */ + + function set$4(out, x, y, z) { + out[0] = x; + out[1] = y; + out[2] = z; + return out; + } + /** + * Adds two vec3's + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a the first operand + * @param {ReadonlyVec3} b the second operand + * @returns {vec3} out + */ + + function add$4(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + return out; + } + /** + * Subtracts vector b from vector a + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a the first operand + * @param {ReadonlyVec3} b the second operand + * @returns {vec3} out + */ + + function subtract$4(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + return out; + } + /** + * Multiplies two vec3's + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a the first operand + * @param {ReadonlyVec3} b the second operand + * @returns {vec3} out + */ + + function multiply$4(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; + return out; + } + /** + * Divides two vec3's + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a the first operand + * @param {ReadonlyVec3} b the second operand + * @returns {vec3} out + */ + + function divide(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + out[2] = a[2] / b[2]; + return out; + } + /** + * Math.ceil the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a vector to ceil + * @returns {vec3} out + */ + + function ceil(out, a) { + out[0] = Math.ceil(a[0]); + out[1] = Math.ceil(a[1]); + out[2] = Math.ceil(a[2]); + return out; + } + /** + * Math.floor the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a vector to floor + * @returns {vec3} out + */ + + function floor(out, a) { + out[0] = Math.floor(a[0]); + out[1] = Math.floor(a[1]); + out[2] = Math.floor(a[2]); + return out; + } + /** + * Returns the minimum of two vec3's + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a the first operand + * @param {ReadonlyVec3} b the second operand + * @returns {vec3} out + */ + + function min(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + out[2] = Math.min(a[2], b[2]); + return out; + } + /** + * Returns the maximum of two vec3's + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a the first operand + * @param {ReadonlyVec3} b the second operand + * @returns {vec3} out + */ + + function max(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + out[2] = Math.max(a[2], b[2]); + return out; + } + /** + * Math.round the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a vector to round + * @returns {vec3} out + */ + + function round(out, a) { + out[0] = Math.round(a[0]); + out[1] = Math.round(a[1]); + out[2] = Math.round(a[2]); + return out; + } + /** + * Scales a vec3 by a scalar number + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec3} out + */ + + function scale$4(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + return out; + } + /** + * Adds two vec3's after scaling the second operand by a scalar value + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a the first operand + * @param {ReadonlyVec3} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec3} out + */ + + function scaleAndAdd(out, a, b, scale) { + out[0] = a[0] + b[0] * scale; + out[1] = a[1] + b[1] * scale; + out[2] = a[2] + b[2] * scale; + return out; + } + /** + * Calculates the euclidian distance between two vec3's + * + * @param {ReadonlyVec3} a the first operand + * @param {ReadonlyVec3} b the second operand + * @returns {Number} distance between a and b + */ + + function distance(a, b) { + var x = b[0] - a[0]; + var y = b[1] - a[1]; + var z = b[2] - a[2]; + return Math.hypot(x, y, z); + } + /** + * Calculates the squared euclidian distance between two vec3's + * + * @param {ReadonlyVec3} a the first operand + * @param {ReadonlyVec3} b the second operand + * @returns {Number} squared distance between a and b + */ + + function squaredDistance(a, b) { + var x = b[0] - a[0]; + var y = b[1] - a[1]; + var z = b[2] - a[2]; + return x * x + y * y + z * z; + } + /** + * Calculates the squared length of a vec3 + * + * @param {ReadonlyVec3} a vector to calculate squared length of + * @returns {Number} squared length of a + */ + + function squaredLength(a) { + var x = a[0]; + var y = a[1]; + var z = a[2]; + return x * x + y * y + z * z; + } + /** + * Negates the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a vector to negate + * @returns {vec3} out + */ + + function negate(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + return out; + } + /** + * Returns the inverse of the components of a vec3 + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a vector to invert + * @returns {vec3} out + */ + + function inverse(out, a) { + out[0] = 1.0 / a[0]; + out[1] = 1.0 / a[1]; + out[2] = 1.0 / a[2]; + return out; + } + /** + * Normalize a vec3 + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a vector to normalize + * @returns {vec3} out + */ + + function normalize(out, a) { + var x = a[0]; + var y = a[1]; + var z = a[2]; + var len = x * x + y * y + z * z; + + if (len > 0) { + //TODO: evaluate use of glm_invsqrt here? + len = 1 / Math.sqrt(len); + } + + out[0] = a[0] * len; + out[1] = a[1] * len; + out[2] = a[2] * len; + return out; + } + /** + * Calculates the dot product of two vec3's + * + * @param {ReadonlyVec3} a the first operand + * @param {ReadonlyVec3} b the second operand + * @returns {Number} dot product of a and b + */ + + function dot(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; + } + /** + * Computes the cross product of two vec3's + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a the first operand + * @param {ReadonlyVec3} b the second operand + * @returns {vec3} out + */ + + function cross(out, a, b) { + var ax = a[0], + ay = a[1], + az = a[2]; + var bx = b[0], + by = b[1], + bz = b[2]; + out[0] = ay * bz - az * by; + out[1] = az * bx - ax * bz; + out[2] = ax * by - ay * bx; + return out; + } + /** + * Performs a linear interpolation between two vec3's + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a the first operand + * @param {ReadonlyVec3} b the second operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {vec3} out + */ + + function lerp(out, a, b, t) { + var ax = a[0]; + var ay = a[1]; + var az = a[2]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + out[2] = az + t * (b[2] - az); + return out; + } + /** + * Performs a hermite interpolation with two control points + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a the first operand + * @param {ReadonlyVec3} b the second operand + * @param {ReadonlyVec3} c the third operand + * @param {ReadonlyVec3} d the fourth operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {vec3} out + */ + + function hermite(out, a, b, c, d, t) { + var factorTimes2 = t * t; + var factor1 = factorTimes2 * (2 * t - 3) + 1; + var factor2 = factorTimes2 * (t - 2) + t; + var factor3 = factorTimes2 * (t - 1); + var factor4 = factorTimes2 * (3 - 2 * t); + out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4; + out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4; + out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4; + return out; + } + /** + * Performs a bezier interpolation with two control points + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a the first operand + * @param {ReadonlyVec3} b the second operand + * @param {ReadonlyVec3} c the third operand + * @param {ReadonlyVec3} d the fourth operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {vec3} out + */ + + function bezier(out, a, b, c, d, t) { + var inverseFactor = 1 - t; + var inverseFactorTimesTwo = inverseFactor * inverseFactor; + var factorTimes2 = t * t; + var factor1 = inverseFactorTimesTwo * inverseFactor; + var factor2 = 3 * t * inverseFactorTimesTwo; + var factor3 = 3 * factorTimes2 * inverseFactor; + var factor4 = factorTimes2 * t; + out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4; + out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4; + out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4; + return out; + } + /** + * Generates a random vector with the given scale + * + * @param {vec3} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec3} out + */ + + function random(out, scale) { + scale = scale || 1.0; + var r = RANDOM() * 2.0 * Math.PI; + var z = RANDOM() * 2.0 - 1.0; + var zScale = Math.sqrt(1.0 - z * z) * scale; + out[0] = Math.cos(r) * zScale; + out[1] = Math.sin(r) * zScale; + out[2] = z * scale; + return out; + } + /** + * Transforms the vec3 with a mat4. + * 4th vector component is implicitly '1' + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a the vector to transform + * @param {ReadonlyMat4} m matrix to transform with + * @returns {vec3} out + */ + + function transformMat4(out, a, m) { + var x = a[0], + y = a[1], + z = a[2]; + var w = m[3] * x + m[7] * y + m[11] * z + m[15]; + w = w || 1.0; + 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; + } + /** + * Transforms the vec3 with a mat3. + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a the vector to transform + * @param {ReadonlyMat3} m the 3x3 matrix to transform with + * @returns {vec3} out + */ + + function transformMat3(out, a, m) { + var x = a[0], + y = a[1], + 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; + } + /** + * Transforms the vec3 with a quat + * Can also be used for dual quaternions. (Multiply it with the real part) + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec3} a the vector to transform + * @param {ReadonlyQuat} q quaternion to transform with + * @returns {vec3} out + */ + + function transformQuat(out, a, q) { + // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed + var qx = q[0], + qy = q[1], + qz = q[2], + qw = q[3]; + var x = a[0], + y = a[1], + z = a[2]; // var qvec = [qx, qy, qz]; + // var uv = vec3.cross([], qvec, a); + + var uvx = qy * z - qz * y, + uvy = qz * x - qx * z, + uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv); + + var uuvx = qy * uvz - qz * uvy, + uuvy = qz * uvx - qx * uvz, + uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w); + + var w2 = qw * 2; + uvx *= w2; + uvy *= w2; + uvz *= w2; // vec3.scale(uuv, uuv, 2); + + uuvx *= 2; + uuvy *= 2; + uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv)); + + out[0] = x + uvx + uuvx; + out[1] = y + uvy + uuvy; + out[2] = z + uvz + uuvz; + return out; + } + /** + * Rotate a 3D vector around the x-axis + * @param {vec3} out The receiving vec3 + * @param {ReadonlyVec3} a The vec3 point to rotate + * @param {ReadonlyVec3} b The origin of the rotation + * @param {Number} rad The angle of rotation in radians + * @returns {vec3} out + */ + + function rotateX$1(out, a, b, rad) { + var p = [], + r = []; //Translate point to the origin + + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; //perform rotation + + 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); //translate to correct position + + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + return out; + } + /** + * Rotate a 3D vector around the y-axis + * @param {vec3} out The receiving vec3 + * @param {ReadonlyVec3} a The vec3 point to rotate + * @param {ReadonlyVec3} b The origin of the rotation + * @param {Number} rad The angle of rotation in radians + * @returns {vec3} out + */ + + function rotateY$1(out, a, b, rad) { + var p = [], + r = []; //Translate point to the origin + + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; //perform rotation + + 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); //translate to correct position + + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + return out; + } + /** + * Rotate a 3D vector around the z-axis + * @param {vec3} out The receiving vec3 + * @param {ReadonlyVec3} a The vec3 point to rotate + * @param {ReadonlyVec3} b The origin of the rotation + * @param {Number} rad The angle of rotation in radians + * @returns {vec3} out + */ + + function rotateZ$1(out, a, b, rad) { + var p = [], + r = []; //Translate point to the origin + + p[0] = a[0] - b[0]; + p[1] = a[1] - b[1]; + p[2] = a[2] - b[2]; //perform rotation + + 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]; //translate to correct position + + out[0] = r[0] + b[0]; + out[1] = r[1] + b[1]; + out[2] = r[2] + b[2]; + return out; + } + /** + * Get the angle between two 3D vectors + * @param {ReadonlyVec3} a The first operand + * @param {ReadonlyVec3} b The second operand + * @returns {Number} The angle in radians + */ + + function angle(a, b) { + var ax = a[0], + ay = a[1], + az = a[2], + bx = b[0], + by = b[1], + bz = b[2], + mag1 = Math.sqrt(ax * ax + ay * ay + az * az), + mag2 = Math.sqrt(bx * bx + by * by + bz * bz), + mag = mag1 * mag2, + cosine = mag && dot(a, b) / mag; + return Math.acos(Math.min(Math.max(cosine, -1), 1)); + } + /** + * Set the components of a vec3 to zero + * + * @param {vec3} out the receiving vector + * @returns {vec3} out + */ + + function zero(out) { + out[0] = 0.0; + out[1] = 0.0; + out[2] = 0.0; + return out; + } + /** + * Returns a string representation of a vector + * + * @param {ReadonlyVec3} a vector to represent as a string + * @returns {String} string representation of the vector + */ + + function str$4(a) { + return "vec3(" + a[0] + ", " + a[1] + ", " + a[2] + ")"; + } + /** + * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===) + * + * @param {ReadonlyVec3} a The first vector. + * @param {ReadonlyVec3} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ + + function exactEquals$4(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2]; + } + /** + * Returns whether or not the vectors have approximately the same elements in the same position. + * + * @param {ReadonlyVec3} a The first vector. + * @param {ReadonlyVec3} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ + + function equals$5(a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2]; + var b0 = b[0], + b1 = b[1], + b2 = b[2]; + return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)); + } + /** + * Alias for {@link vec3.subtract} + * @function + */ + + var sub$4 = subtract$4; + /** + * Alias for {@link vec3.multiply} + * @function + */ + + var mul$4 = multiply$4; + /** + * Alias for {@link vec3.divide} + * @function + */ + + var div = divide; + /** + * Alias for {@link vec3.distance} + * @function + */ + + var dist = distance; + /** + * Alias for {@link vec3.squaredDistance} + * @function + */ + + var sqrDist = squaredDistance; + /** + * Alias for {@link vec3.length} + * @function + */ + + var len = length; + /** + * Alias for {@link vec3.squaredLength} + * @function + */ + + var sqrLen = squaredLength; + /** + * Perform some operation over an array of vec3s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ + + var forEach = function () { + var vec = create$4(); + return function (a, stride, offset, count, fn, arg) { + var i, 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; + }; + }(); + + var vec3 = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$4, + clone: clone$4, + length: length, + fromValues: fromValues$4, + copy: copy$4, + set: set$4, + add: add$4, + subtract: subtract$4, + multiply: multiply$4, + divide: divide, + ceil: ceil, + floor: floor, + min: min, + max: max, + round: round, + scale: scale$4, + scaleAndAdd: scaleAndAdd, + distance: distance, + squaredDistance: squaredDistance, + squaredLength: squaredLength, + negate: negate, + inverse: inverse, + normalize: normalize, + dot: dot, + cross: cross, + lerp: lerp, + hermite: hermite, + bezier: bezier, + random: random, + transformMat4: transformMat4, + transformMat3: transformMat3, + transformQuat: transformQuat, + rotateX: rotateX$1, + rotateY: rotateY$1, + rotateZ: rotateZ$1, + angle: angle, + zero: zero, + str: str$4, + exactEquals: exactEquals$4, + equals: equals$5, + sub: sub$4, + mul: mul$4, + div: div, + dist: dist, + sqrDist: sqrDist, + len: len, + sqrLen: sqrLen, + forEach: forEach + }); + + /** + * 4 Dimensional Vector + * @module vec4 + */ + + /** + * Creates a new, empty vec4 + * + * @returns {vec4} a new 4D vector + */ + + function create$5() { + var out = new ARRAY_TYPE(4); + + if (ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 0; + } + + return out; + } + /** + * Creates a new vec4 initialized with values from an existing vector + * + * @param {ReadonlyVec4} a vector to clone + * @returns {vec4} a new 4D vector + */ + + function clone$5(a) { + var out = new ARRAY_TYPE(4); + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; + } + /** + * Creates a new vec4 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {vec4} a new 4D vector + */ + + function fromValues$5(x, y, z, w) { + var out = new ARRAY_TYPE(4); + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; + } + /** + * Copy the values from one vec4 to another + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a the source vector + * @returns {vec4} out + */ + + function copy$5(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + return out; + } + /** + * Set the components of a vec4 to the given values + * + * @param {vec4} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {vec4} out + */ + + function set$5(out, x, y, z, w) { + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = w; + return out; + } + /** + * Adds two vec4's + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a the first operand + * @param {ReadonlyVec4} b the second operand + * @returns {vec4} out + */ + + function add$5(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + return out; + } + /** + * Subtracts vector b from vector a + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a the first operand + * @param {ReadonlyVec4} b the second operand + * @returns {vec4} out + */ + + function subtract$5(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + out[2] = a[2] - b[2]; + out[3] = a[3] - b[3]; + return out; + } + /** + * Multiplies two vec4's + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a the first operand + * @param {ReadonlyVec4} b the second operand + * @returns {vec4} out + */ + + function multiply$5(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + out[2] = a[2] * b[2]; + out[3] = a[3] * b[3]; + return out; + } + /** + * Divides two vec4's + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a the first operand + * @param {ReadonlyVec4} b the second operand + * @returns {vec4} out + */ + + function divide$1(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + out[2] = a[2] / b[2]; + out[3] = a[3] / b[3]; + return out; + } + /** + * Math.ceil the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a vector to ceil + * @returns {vec4} out + */ + + function ceil$1(out, a) { + out[0] = Math.ceil(a[0]); + out[1] = Math.ceil(a[1]); + out[2] = Math.ceil(a[2]); + out[3] = Math.ceil(a[3]); + return out; + } + /** + * Math.floor the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a vector to floor + * @returns {vec4} out + */ + + function floor$1(out, a) { + out[0] = Math.floor(a[0]); + out[1] = Math.floor(a[1]); + out[2] = Math.floor(a[2]); + out[3] = Math.floor(a[3]); + return out; + } + /** + * Returns the minimum of two vec4's + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a the first operand + * @param {ReadonlyVec4} b the second operand + * @returns {vec4} out + */ + + function min$1(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + out[2] = Math.min(a[2], b[2]); + out[3] = Math.min(a[3], b[3]); + return out; + } + /** + * Returns the maximum of two vec4's + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a the first operand + * @param {ReadonlyVec4} b the second operand + * @returns {vec4} out + */ + + function max$1(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + out[2] = Math.max(a[2], b[2]); + out[3] = Math.max(a[3], b[3]); + return out; + } + /** + * Math.round the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a vector to round + * @returns {vec4} out + */ + + function round$1(out, a) { + out[0] = Math.round(a[0]); + out[1] = Math.round(a[1]); + out[2] = Math.round(a[2]); + out[3] = Math.round(a[3]); + return out; + } + /** + * Scales a vec4 by a scalar number + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec4} out + */ + + function scale$5(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + return out; + } + /** + * Adds two vec4's after scaling the second operand by a scalar value + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a the first operand + * @param {ReadonlyVec4} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec4} out + */ + + function scaleAndAdd$1(out, a, b, scale) { + out[0] = a[0] + b[0] * scale; + out[1] = a[1] + b[1] * scale; + out[2] = a[2] + b[2] * scale; + out[3] = a[3] + b[3] * scale; + return out; + } + /** + * Calculates the euclidian distance between two vec4's + * + * @param {ReadonlyVec4} a the first operand + * @param {ReadonlyVec4} b the second operand + * @returns {Number} distance between a and b + */ + + function distance$1(a, b) { + var x = b[0] - a[0]; + var y = b[1] - a[1]; + var z = b[2] - a[2]; + var w = b[3] - a[3]; + return Math.hypot(x, y, z, w); + } + /** + * Calculates the squared euclidian distance between two vec4's + * + * @param {ReadonlyVec4} a the first operand + * @param {ReadonlyVec4} b the second operand + * @returns {Number} squared distance between a and b + */ + + function squaredDistance$1(a, b) { + var x = b[0] - a[0]; + var y = b[1] - a[1]; + var z = b[2] - a[2]; + var w = b[3] - a[3]; + return x * x + y * y + z * z + w * w; + } + /** + * Calculates the length of a vec4 + * + * @param {ReadonlyVec4} a vector to calculate length of + * @returns {Number} length of a + */ + + function length$1(a) { + var x = a[0]; + var y = a[1]; + var z = a[2]; + var w = a[3]; + return Math.hypot(x, y, z, w); + } + /** + * Calculates the squared length of a vec4 + * + * @param {ReadonlyVec4} a vector to calculate squared length of + * @returns {Number} squared length of a + */ + + function squaredLength$1(a) { + var x = a[0]; + var y = a[1]; + var z = a[2]; + var w = a[3]; + return x * x + y * y + z * z + w * w; + } + /** + * Negates the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a vector to negate + * @returns {vec4} out + */ + + function negate$1(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = -a[3]; + return out; + } + /** + * Returns the inverse of the components of a vec4 + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a vector to invert + * @returns {vec4} out + */ + + function inverse$1(out, a) { + out[0] = 1.0 / a[0]; + out[1] = 1.0 / a[1]; + out[2] = 1.0 / a[2]; + out[3] = 1.0 / a[3]; + return out; + } + /** + * Normalize a vec4 + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a vector to normalize + * @returns {vec4} out + */ + + function normalize$1(out, a) { + var x = a[0]; + var y = a[1]; + var z = a[2]; + var w = a[3]; + var len = x * x + y * y + z * z + w * w; + + if (len > 0) { + len = 1 / Math.sqrt(len); + } + + out[0] = x * len; + out[1] = y * len; + out[2] = z * len; + out[3] = w * len; + return out; + } + /** + * Calculates the dot product of two vec4's + * + * @param {ReadonlyVec4} a the first operand + * @param {ReadonlyVec4} b the second operand + * @returns {Number} dot product of a and b + */ + + function dot$1(a, b) { + return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; + } + /** + * Returns the cross-product of three vectors in a 4-dimensional space + * + * @param {ReadonlyVec4} result the receiving vector + * @param {ReadonlyVec4} U the first vector + * @param {ReadonlyVec4} V the second vector + * @param {ReadonlyVec4} W the third vector + * @returns {vec4} result + */ + + function cross$1(out, u, v, w) { + var A = v[0] * w[1] - v[1] * w[0], + B = v[0] * w[2] - v[2] * w[0], + C = v[0] * w[3] - v[3] * w[0], + D = v[1] * w[2] - v[2] * w[1], + E = v[1] * w[3] - v[3] * w[1], + F = v[2] * w[3] - v[3] * w[2]; + var G = u[0]; + var H = u[1]; + var I = u[2]; + var J = u[3]; + out[0] = H * F - I * E + J * D; + out[1] = -(G * F) + I * C - J * B; + out[2] = G * E - H * C + J * A; + out[3] = -(G * D) + H * B - I * A; + return out; + } + /** + * Performs a linear interpolation between two vec4's + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a the first operand + * @param {ReadonlyVec4} b the second operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {vec4} out + */ + + function lerp$1(out, a, b, t) { + var ax = a[0]; + var ay = a[1]; + var az = a[2]; + var aw = a[3]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + out[2] = az + t * (b[2] - az); + out[3] = aw + t * (b[3] - aw); + return out; + } + /** + * Generates a random vector with the given scale + * + * @param {vec4} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec4} out + */ + + function random$1(out, scale) { + scale = scale || 1.0; // Marsaglia, George. Choosing a Point from the Surface of a + // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646. + // http://projecteuclid.org/euclid.aoms/1177692644; + + var v1, v2, v3, v4; + var s1, s2; + + do { + v1 = RANDOM() * 2 - 1; + v2 = RANDOM() * 2 - 1; + s1 = v1 * v1 + v2 * v2; + } while (s1 >= 1); + + do { + v3 = RANDOM() * 2 - 1; + v4 = RANDOM() * 2 - 1; + s2 = v3 * v3 + v4 * v4; + } while (s2 >= 1); + + var d = Math.sqrt((1 - s1) / s2); + out[0] = scale * v1; + out[1] = scale * v2; + out[2] = scale * v3 * d; + out[3] = scale * v4 * d; + return out; + } + /** + * Transforms the vec4 with a mat4. + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a the vector to transform + * @param {ReadonlyMat4} m matrix to transform with + * @returns {vec4} out + */ + + function transformMat4$1(out, a, m) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + 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; + out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w; + return out; + } + /** + * Transforms the vec4 with a quat + * + * @param {vec4} out the receiving vector + * @param {ReadonlyVec4} a the vector to transform + * @param {ReadonlyQuat} q quaternion to transform with + * @returns {vec4} out + */ + + function transformQuat$1(out, a, q) { + var x = a[0], + y = a[1], + z = a[2]; + var qx = q[0], + qy = q[1], + qz = q[2], + qw = q[3]; // calculate quat * vec + + var ix = qw * x + qy * z - qz * y; + var iy = qw * y + qz * x - qx * z; + var iz = qw * z + qx * y - qy * x; + var iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat + + out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; + out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; + out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; + out[3] = a[3]; + return out; + } + /** + * Set the components of a vec4 to zero + * + * @param {vec4} out the receiving vector + * @returns {vec4} out + */ + + function zero$1(out) { + out[0] = 0.0; + out[1] = 0.0; + out[2] = 0.0; + out[3] = 0.0; + return out; + } + /** + * Returns a string representation of a vector + * + * @param {ReadonlyVec4} a vector to represent as a string + * @returns {String} string representation of the vector + */ + + function str$5(a) { + return "vec4(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")"; + } + /** + * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===) + * + * @param {ReadonlyVec4} a The first vector. + * @param {ReadonlyVec4} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ + + function exactEquals$5(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]; + } + /** + * Returns whether or not the vectors have approximately the same elements in the same position. + * + * @param {ReadonlyVec4} a The first vector. + * @param {ReadonlyVec4} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ + + function equals$6(a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3]; + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3]; + return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)); + } + /** + * Alias for {@link vec4.subtract} + * @function + */ + + var sub$5 = subtract$5; + /** + * Alias for {@link vec4.multiply} + * @function + */ + + var mul$5 = multiply$5; + /** + * Alias for {@link vec4.divide} + * @function + */ + + var div$1 = divide$1; + /** + * Alias for {@link vec4.distance} + * @function + */ + + var dist$1 = distance$1; + /** + * Alias for {@link vec4.squaredDistance} + * @function + */ + + var sqrDist$1 = squaredDistance$1; + /** + * Alias for {@link vec4.length} + * @function + */ + + var len$1 = length$1; + /** + * Alias for {@link vec4.squaredLength} + * @function + */ + + var sqrLen$1 = squaredLength$1; + /** + * Perform some operation over an array of vec4s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ + + var forEach$1 = function () { + var vec = create$5(); + return function (a, stride, offset, count, fn, arg) { + var i, l; + + if (!stride) { + stride = 4; + } + + 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]; + vec[3] = a[i + 3]; + fn(vec, vec, arg); + a[i] = vec[0]; + a[i + 1] = vec[1]; + a[i + 2] = vec[2]; + a[i + 3] = vec[3]; + } + + return a; + }; + }(); + + var vec4 = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$5, + clone: clone$5, + fromValues: fromValues$5, + copy: copy$5, + set: set$5, + add: add$5, + subtract: subtract$5, + multiply: multiply$5, + divide: divide$1, + ceil: ceil$1, + floor: floor$1, + min: min$1, + max: max$1, + round: round$1, + scale: scale$5, + scaleAndAdd: scaleAndAdd$1, + distance: distance$1, + squaredDistance: squaredDistance$1, + length: length$1, + squaredLength: squaredLength$1, + negate: negate$1, + inverse: inverse$1, + normalize: normalize$1, + dot: dot$1, + cross: cross$1, + lerp: lerp$1, + random: random$1, + transformMat4: transformMat4$1, + transformQuat: transformQuat$1, + zero: zero$1, + str: str$5, + exactEquals: exactEquals$5, + equals: equals$6, + sub: sub$5, + mul: mul$5, + div: div$1, + dist: dist$1, + sqrDist: sqrDist$1, + len: len$1, + sqrLen: sqrLen$1, + forEach: forEach$1 + }); + + /** + * Quaternion + * @module quat + */ + + /** + * Creates a new identity quat + * + * @returns {quat} a new quaternion + */ + + function create$6() { + var out = new ARRAY_TYPE(4); + + if (ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + } + + out[3] = 1; + return out; + } + /** + * Set a quat to the identity quaternion + * + * @param {quat} out the receiving quaternion + * @returns {quat} out + */ + + function identity$4(out) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; + } + /** + * Sets a quat from the given angle and rotation axis, + * then returns it. + * + * @param {quat} out the receiving quaternion + * @param {ReadonlyVec3} axis the axis around which to rotate + * @param {Number} rad the angle in radians + * @returns {quat} out + **/ + + function setAxisAngle(out, axis, rad) { + rad = rad * 0.5; + var s = Math.sin(rad); + out[0] = s * axis[0]; + out[1] = s * axis[1]; + out[2] = s * axis[2]; + out[3] = Math.cos(rad); + return out; + } + /** + * Gets the rotation axis and angle for a given + * quaternion. If a quaternion is created with + * setAxisAngle, this method will return the same + * values as providied in the original parameter list + * OR functionally equivalent values. + * Example: The quaternion formed by axis [0, 0, 1] and + * angle -90 is the same as the quaternion formed by + * [0, 0, 1] and 270. This method favors the latter. + * @param {vec3} out_axis Vector receiving the axis of rotation + * @param {ReadonlyQuat} q Quaternion to be decomposed + * @return {Number} Angle, in radians, of the rotation + */ + + function getAxisAngle(out_axis, q) { + var rad = Math.acos(q[3]) * 2.0; + var s = Math.sin(rad / 2.0); + + if (s > EPSILON) { + out_axis[0] = q[0] / s; + out_axis[1] = q[1] / s; + out_axis[2] = q[2] / s; + } else { + // If s is zero, return any axis (no rotation - axis does not matter) + out_axis[0] = 1; + out_axis[1] = 0; + out_axis[2] = 0; + } + + return rad; + } + /** + * Gets the angular distance between two unit quaternions + * + * @param {ReadonlyQuat} a Origin unit quaternion + * @param {ReadonlyQuat} b Destination unit quaternion + * @return {Number} Angle, in radians, between the two quaternions + */ + + function getAngle(a, b) { + var dotproduct = dot$2(a, b); + return Math.acos(2 * dotproduct * dotproduct - 1); + } + /** + * Multiplies two quat's + * + * @param {quat} out the receiving quaternion + * @param {ReadonlyQuat} a the first operand + * @param {ReadonlyQuat} b the second operand + * @returns {quat} out + */ + + function multiply$6(out, a, b) { + var ax = a[0], + ay = a[1], + az = a[2], + aw = a[3]; + var bx = b[0], + by = b[1], + bz = b[2], + bw = b[3]; + out[0] = ax * bw + aw * bx + ay * bz - az * by; + out[1] = ay * bw + aw * by + az * bx - ax * bz; + out[2] = az * bw + aw * bz + ax * by - ay * bx; + out[3] = aw * bw - ax * bx - ay * by - az * bz; + return out; + } + /** + * Rotates a quaternion by the given angle about the X axis + * + * @param {quat} out quat receiving operation result + * @param {ReadonlyQuat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ + + function rotateX$2(out, a, rad) { + rad *= 0.5; + var ax = a[0], + ay = a[1], + az = a[2], + aw = a[3]; + var bx = Math.sin(rad), + bw = Math.cos(rad); + out[0] = ax * bw + aw * bx; + out[1] = ay * bw + az * bx; + out[2] = az * bw - ay * bx; + out[3] = aw * bw - ax * bx; + return out; + } + /** + * Rotates a quaternion by the given angle about the Y axis + * + * @param {quat} out quat receiving operation result + * @param {ReadonlyQuat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ + + function rotateY$2(out, a, rad) { + rad *= 0.5; + var ax = a[0], + ay = a[1], + az = a[2], + aw = a[3]; + var by = Math.sin(rad), + bw = Math.cos(rad); + out[0] = ax * bw - az * by; + out[1] = ay * bw + aw * by; + out[2] = az * bw + ax * by; + out[3] = aw * bw - ay * by; + return out; + } + /** + * Rotates a quaternion by the given angle about the Z axis + * + * @param {quat} out quat receiving operation result + * @param {ReadonlyQuat} a quat to rotate + * @param {number} rad angle (in radians) to rotate + * @returns {quat} out + */ + + function rotateZ$2(out, a, rad) { + rad *= 0.5; + var ax = a[0], + ay = a[1], + az = a[2], + aw = a[3]; + var bz = Math.sin(rad), + bw = Math.cos(rad); + out[0] = ax * bw + ay * bz; + out[1] = ay * bw - ax * bz; + out[2] = az * bw + aw * bz; + out[3] = aw * bw - az * bz; + return out; + } + /** + * Calculates the W component of a quat from the X, Y, and Z components. + * Assumes that quaternion is 1 unit in length. + * Any existing W component will be ignored. + * + * @param {quat} out the receiving quaternion + * @param {ReadonlyQuat} a quat to calculate W component of + * @returns {quat} out + */ + + function calculateW(out, a) { + var x = a[0], + y = a[1], + z = a[2]; + out[0] = x; + out[1] = y; + out[2] = z; + out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); + return out; + } + /** + * Calculate the exponential of a unit quaternion. + * + * @param {quat} out the receiving quaternion + * @param {ReadonlyQuat} a quat to calculate the exponential of + * @returns {quat} out + */ + + function exp(out, a) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + var r = Math.sqrt(x * x + y * y + z * z); + var et = Math.exp(w); + var s = r > 0 ? et * Math.sin(r) / r : 0; + out[0] = x * s; + out[1] = y * s; + out[2] = z * s; + out[3] = et * Math.cos(r); + return out; + } + /** + * Calculate the natural logarithm of a unit quaternion. + * + * @param {quat} out the receiving quaternion + * @param {ReadonlyQuat} a quat to calculate the exponential of + * @returns {quat} out + */ + + function ln(out, a) { + var x = a[0], + y = a[1], + z = a[2], + w = a[3]; + var r = Math.sqrt(x * x + y * y + z * z); + var t = r > 0 ? Math.atan2(r, w) / r : 0; + out[0] = x * t; + out[1] = y * t; + out[2] = z * t; + out[3] = 0.5 * Math.log(x * x + y * y + z * z + w * w); + return out; + } + /** + * Calculate the scalar power of a unit quaternion. + * + * @param {quat} out the receiving quaternion + * @param {ReadonlyQuat} a quat to calculate the exponential of + * @param {Number} b amount to scale the quaternion by + * @returns {quat} out + */ + + function pow(out, a, b) { + ln(out, a); + scale$6(out, out, b); + exp(out, out); + return out; + } + /** + * Performs a spherical linear interpolation between two quat + * + * @param {quat} out the receiving quaternion + * @param {ReadonlyQuat} a the first operand + * @param {ReadonlyQuat} b the second operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {quat} out + */ + + function slerp(out, a, b, t) { + // benchmarks: + // http://jsperf.com/quaternion-slerp-implementations + var ax = a[0], + ay = a[1], + az = a[2], + aw = a[3]; + var bx = b[0], + by = b[1], + bz = b[2], + bw = b[3]; + var omega, cosom, sinom, scale0, scale1; // calc cosine + + cosom = ax * bx + ay * by + az * bz + aw * bw; // adjust signs (if necessary) + + if (cosom < 0.0) { + cosom = -cosom; + bx = -bx; + by = -by; + bz = -bz; + bw = -bw; + } // calculate coefficients + + + if (1.0 - cosom > EPSILON) { + // standard case (slerp) + omega = Math.acos(cosom); + sinom = Math.sin(omega); + scale0 = Math.sin((1.0 - t) * omega) / sinom; + scale1 = Math.sin(t * omega) / sinom; + } else { + // "from" and "to" quaternions are very close + // ... so we can do a linear interpolation + scale0 = 1.0 - t; + scale1 = t; + } // calculate final values + + + out[0] = scale0 * ax + scale1 * bx; + out[1] = scale0 * ay + scale1 * by; + out[2] = scale0 * az + scale1 * bz; + out[3] = scale0 * aw + scale1 * bw; + return out; + } + /** + * Generates a random unit quaternion + * + * @param {quat} out the receiving quaternion + * @returns {quat} out + */ + + function random$2(out) { + // Implementation of http://planning.cs.uiuc.edu/node198.html + // TODO: Calling random 3 times is probably not the fastest solution + var u1 = RANDOM(); + var u2 = RANDOM(); + var u3 = RANDOM(); + var sqrt1MinusU1 = Math.sqrt(1 - u1); + var sqrtU1 = Math.sqrt(u1); + out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2); + out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2); + out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3); + out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3); + return out; + } + /** + * Calculates the inverse of a quat + * + * @param {quat} out the receiving quaternion + * @param {ReadonlyQuat} a quat to calculate inverse of + * @returns {quat} out + */ + + function invert$4(out, a) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3]; + var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3; + var invDot = dot ? 1.0 / dot : 0; // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 + + out[0] = -a0 * invDot; + out[1] = -a1 * invDot; + out[2] = -a2 * invDot; + out[3] = a3 * invDot; + return out; + } + /** + * Calculates the conjugate of a quat + * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result. + * + * @param {quat} out the receiving quaternion + * @param {ReadonlyQuat} a quat to calculate conjugate of + * @returns {quat} out + */ + + function conjugate(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = a[3]; + return out; + } + /** + * Creates a quaternion from the given 3x3 rotation matrix. + * + * NOTE: The resultant quaternion is not normalized, so you should be sure + * to renormalize the quaternion yourself where necessary. + * + * @param {quat} out the receiving quaternion + * @param {ReadonlyMat3} m rotation matrix + * @returns {quat} out + * @function + */ + + function fromMat3(out, m) { + // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes + // article "Quaternion Calculus and Fast Animation". + var fTrace = m[0] + m[4] + m[8]; + var fRoot; + + if (fTrace > 0.0) { + // |w| > 1/2, may as well choose w > 1/2 + fRoot = Math.sqrt(fTrace + 1.0); // 2w + + out[3] = 0.5 * fRoot; + fRoot = 0.5 / fRoot; // 1/(4w) + + out[0] = (m[5] - m[7]) * fRoot; + out[1] = (m[6] - m[2]) * fRoot; + out[2] = (m[1] - m[3]) * fRoot; + } else { + // |w| <= 1/2 + var i = 0; + if (m[4] > m[0]) i = 1; + if (m[8] > m[i * 3 + i]) i = 2; + var j = (i + 1) % 3; + var k = (i + 2) % 3; + fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0); + out[i] = 0.5 * fRoot; + fRoot = 0.5 / fRoot; + out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot; + out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot; + out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot; + } + + return out; + } + /** + * Creates a quaternion from the given euler angle x, y, z. + * + * @param {quat} out the receiving quaternion + * @param {x} Angle to rotate around X axis in degrees. + * @param {y} Angle to rotate around Y axis in degrees. + * @param {z} Angle to rotate around Z axis in degrees. + * @returns {quat} out + * @function + */ + + function fromEuler(out, x, y, z) { + var halfToRad = 0.5 * Math.PI / 180.0; + x *= halfToRad; + y *= halfToRad; + z *= halfToRad; + var sx = Math.sin(x); + var cx = Math.cos(x); + var sy = Math.sin(y); + var cy = Math.cos(y); + var sz = Math.sin(z); + var cz = Math.cos(z); + out[0] = sx * cy * cz - cx * sy * sz; + out[1] = cx * sy * cz + sx * cy * sz; + out[2] = cx * cy * sz - sx * sy * cz; + out[3] = cx * cy * cz + sx * sy * sz; + return out; + } + /** + * Returns a string representation of a quatenion + * + * @param {ReadonlyQuat} a vector to represent as a string + * @returns {String} string representation of the vector + */ + + function str$6(a) { + return "quat(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ")"; + } + /** + * Creates a new quat initialized with values from an existing quaternion + * + * @param {ReadonlyQuat} a quaternion to clone + * @returns {quat} a new quaternion + * @function + */ + + var clone$6 = clone$5; + /** + * Creates a new quat initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {quat} a new quaternion + * @function + */ + + var fromValues$6 = fromValues$5; + /** + * Copy the values from one quat to another + * + * @param {quat} out the receiving quaternion + * @param {ReadonlyQuat} a the source quaternion + * @returns {quat} out + * @function + */ + + var copy$6 = copy$5; + /** + * Set the components of a quat to the given values + * + * @param {quat} out the receiving quaternion + * @param {Number} x X component + * @param {Number} y Y component + * @param {Number} z Z component + * @param {Number} w W component + * @returns {quat} out + * @function + */ + + var set$6 = set$5; + /** + * Adds two quat's + * + * @param {quat} out the receiving quaternion + * @param {ReadonlyQuat} a the first operand + * @param {ReadonlyQuat} b the second operand + * @returns {quat} out + * @function + */ + + var add$6 = add$5; + /** + * Alias for {@link quat.multiply} + * @function + */ + + var mul$6 = multiply$6; + /** + * Scales a quat by a scalar number + * + * @param {quat} out the receiving vector + * @param {ReadonlyQuat} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {quat} out + * @function + */ + + var scale$6 = scale$5; + /** + * Calculates the dot product of two quat's + * + * @param {ReadonlyQuat} a the first operand + * @param {ReadonlyQuat} b the second operand + * @returns {Number} dot product of a and b + * @function + */ + + var dot$2 = dot$1; + /** + * Performs a linear interpolation between two quat's + * + * @param {quat} out the receiving quaternion + * @param {ReadonlyQuat} a the first operand + * @param {ReadonlyQuat} b the second operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {quat} out + * @function + */ + + var lerp$2 = lerp$1; + /** + * Calculates the length of a quat + * + * @param {ReadonlyQuat} a vector to calculate length of + * @returns {Number} length of a + */ + + var length$2 = length$1; + /** + * Alias for {@link quat.length} + * @function + */ + + var len$2 = length$2; + /** + * Calculates the squared length of a quat + * + * @param {ReadonlyQuat} a vector to calculate squared length of + * @returns {Number} squared length of a + * @function + */ + + var squaredLength$2 = squaredLength$1; + /** + * Alias for {@link quat.squaredLength} + * @function + */ + + var sqrLen$2 = squaredLength$2; + /** + * Normalize a quat + * + * @param {quat} out the receiving quaternion + * @param {ReadonlyQuat} a quaternion to normalize + * @returns {quat} out + * @function + */ + + var normalize$2 = normalize$1; + /** + * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===) + * + * @param {ReadonlyQuat} a The first quaternion. + * @param {ReadonlyQuat} b The second quaternion. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ + + var exactEquals$6 = exactEquals$5; + /** + * Returns whether or not the quaternions have approximately the same elements in the same position. + * + * @param {ReadonlyQuat} a The first vector. + * @param {ReadonlyQuat} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ + + var equals$7 = equals$6; + /** + * Sets a quaternion to represent the shortest rotation from one + * vector to another. + * + * Both vectors are assumed to be unit length. + * + * @param {quat} out the receiving quaternion. + * @param {ReadonlyVec3} a the initial vector + * @param {ReadonlyVec3} b the destination vector + * @returns {quat} out + */ + + var rotationTo = function () { + var tmpvec3 = create$4(); + var xUnitVec3 = fromValues$4(1, 0, 0); + var yUnitVec3 = fromValues$4(0, 1, 0); + return function (out, a, b) { + var dot$1 = dot(a, b); + + if (dot$1 < -0.999999) { + cross(tmpvec3, xUnitVec3, a); + if (len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a); + normalize(tmpvec3, tmpvec3); + setAxisAngle(out, tmpvec3, Math.PI); + return out; + } else if (dot$1 > 0.999999) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + return out; + } else { + cross(tmpvec3, a, b); + out[0] = tmpvec3[0]; + out[1] = tmpvec3[1]; + out[2] = tmpvec3[2]; + out[3] = 1 + dot$1; + return normalize$2(out, out); + } + }; + }(); + /** + * Performs a spherical linear interpolation with two control points + * + * @param {quat} out the receiving quaternion + * @param {ReadonlyQuat} a the first operand + * @param {ReadonlyQuat} b the second operand + * @param {ReadonlyQuat} c the third operand + * @param {ReadonlyQuat} d the fourth operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {quat} out + */ + + var sqlerp = function () { + var temp1 = create$6(); + var temp2 = create$6(); + return function (out, a, b, c, d, t) { + slerp(temp1, a, d, t); + slerp(temp2, b, c, t); + slerp(out, temp1, temp2, 2 * t * (1 - t)); + return out; + }; + }(); + /** + * Sets the specified quaternion with values corresponding to the given + * axes. Each axis is a vec3 and is expected to be unit length and + * perpendicular to all other specified axes. + * + * @param {ReadonlyVec3} view the vector representing the viewing direction + * @param {ReadonlyVec3} right the vector representing the local "right" direction + * @param {ReadonlyVec3} up the vector representing the local "up" direction + * @returns {quat} out + */ + + var setAxes = function () { + var matr = create$2(); + return function (out, view, right, up) { + matr[0] = right[0]; + matr[3] = right[1]; + matr[6] = right[2]; + matr[1] = up[0]; + matr[4] = up[1]; + matr[7] = up[2]; + matr[2] = -view[0]; + matr[5] = -view[1]; + matr[8] = -view[2]; + return normalize$2(out, fromMat3(out, matr)); + }; + }(); + + var quat = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$6, + identity: identity$4, + setAxisAngle: setAxisAngle, + getAxisAngle: getAxisAngle, + getAngle: getAngle, + multiply: multiply$6, + rotateX: rotateX$2, + rotateY: rotateY$2, + rotateZ: rotateZ$2, + calculateW: calculateW, + exp: exp, + ln: ln, + pow: pow, + slerp: slerp, + random: random$2, + invert: invert$4, + conjugate: conjugate, + fromMat3: fromMat3, + fromEuler: fromEuler, + str: str$6, + clone: clone$6, + fromValues: fromValues$6, + copy: copy$6, + set: set$6, + add: add$6, + mul: mul$6, + scale: scale$6, + dot: dot$2, + lerp: lerp$2, + length: length$2, + len: len$2, + squaredLength: squaredLength$2, + sqrLen: sqrLen$2, + normalize: normalize$2, + exactEquals: exactEquals$6, + equals: equals$7, + rotationTo: rotationTo, + sqlerp: sqlerp, + setAxes: setAxes + }); + + /** + * Dual Quaternion<br> + * Format: [real, dual]<br> + * Quaternion format: XYZW<br> + * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.<br> + * @module quat2 + */ + + /** + * Creates a new identity dual quat + * + * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation] + */ + + function create$7() { + var dq = new ARRAY_TYPE(8); + + if (ARRAY_TYPE != Float32Array) { + dq[0] = 0; + dq[1] = 0; + dq[2] = 0; + dq[4] = 0; + dq[5] = 0; + dq[6] = 0; + dq[7] = 0; + } + + dq[3] = 1; + return dq; + } + /** + * Creates a new quat initialized with values from an existing quaternion + * + * @param {ReadonlyQuat2} a dual quaternion to clone + * @returns {quat2} new dual quaternion + * @function + */ + + function clone$7(a) { + var dq = new ARRAY_TYPE(8); + dq[0] = a[0]; + dq[1] = a[1]; + dq[2] = a[2]; + dq[3] = a[3]; + dq[4] = a[4]; + dq[5] = a[5]; + dq[6] = a[6]; + dq[7] = a[7]; + return dq; + } + /** + * Creates a new dual quat initialized with the given values + * + * @param {Number} x1 X component + * @param {Number} y1 Y component + * @param {Number} z1 Z component + * @param {Number} w1 W component + * @param {Number} x2 X component + * @param {Number} y2 Y component + * @param {Number} z2 Z component + * @param {Number} w2 W component + * @returns {quat2} new dual quaternion + * @function + */ + + function fromValues$7(x1, y1, z1, w1, x2, y2, z2, w2) { + var dq = new ARRAY_TYPE(8); + dq[0] = x1; + dq[1] = y1; + dq[2] = z1; + dq[3] = w1; + dq[4] = x2; + dq[5] = y2; + dq[6] = z2; + dq[7] = w2; + return dq; + } + /** + * Creates a new dual quat from the given values (quat and translation) + * + * @param {Number} x1 X component + * @param {Number} y1 Y component + * @param {Number} z1 Z component + * @param {Number} w1 W component + * @param {Number} x2 X component (translation) + * @param {Number} y2 Y component (translation) + * @param {Number} z2 Z component (translation) + * @returns {quat2} new dual quaternion + * @function + */ + + function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) { + var dq = new ARRAY_TYPE(8); + dq[0] = x1; + dq[1] = y1; + dq[2] = z1; + dq[3] = w1; + var ax = x2 * 0.5, + ay = y2 * 0.5, + az = z2 * 0.5; + dq[4] = ax * w1 + ay * z1 - az * y1; + dq[5] = ay * w1 + az * x1 - ax * z1; + dq[6] = az * w1 + ax * y1 - ay * x1; + dq[7] = -ax * x1 - ay * y1 - az * z1; + return dq; + } + /** + * Creates a dual quat from a quaternion and a translation + * + * @param {ReadonlyQuat2} dual quaternion receiving operation result + * @param {ReadonlyQuat} q a normalized quaternion + * @param {ReadonlyVec3} t tranlation vector + * @returns {quat2} dual quaternion receiving operation result + * @function + */ + + function fromRotationTranslation$1(out, q, t) { + var ax = t[0] * 0.5, + ay = t[1] * 0.5, + az = t[2] * 0.5, + bx = q[0], + by = q[1], + bz = q[2], + bw = q[3]; + out[0] = bx; + out[1] = by; + out[2] = bz; + out[3] = bw; + out[4] = ax * bw + ay * bz - az * by; + out[5] = ay * bw + az * bx - ax * bz; + out[6] = az * bw + ax * by - ay * bx; + out[7] = -ax * bx - ay * by - az * bz; + return out; + } + /** + * Creates a dual quat from a translation + * + * @param {ReadonlyQuat2} dual quaternion receiving operation result + * @param {ReadonlyVec3} t translation vector + * @returns {quat2} dual quaternion receiving operation result + * @function + */ + + function fromTranslation$3(out, t) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = t[0] * 0.5; + out[5] = t[1] * 0.5; + out[6] = t[2] * 0.5; + out[7] = 0; + return out; + } + /** + * Creates a dual quat from a quaternion + * + * @param {ReadonlyQuat2} dual quaternion receiving operation result + * @param {ReadonlyQuat} q the quaternion + * @returns {quat2} dual quaternion receiving operation result + * @function + */ + + function fromRotation$4(out, q) { + out[0] = q[0]; + out[1] = q[1]; + out[2] = q[2]; + out[3] = q[3]; + out[4] = 0; + out[5] = 0; + out[6] = 0; + out[7] = 0; + return out; + } + /** + * Creates a new dual quat from a matrix (4x4) + * + * @param {quat2} out the dual quaternion + * @param {ReadonlyMat4} a the matrix + * @returns {quat2} dual quat receiving operation result + * @function + */ + + function fromMat4$1(out, a) { + //TODO Optimize this + var outer = create$6(); + getRotation(outer, a); + var t = new ARRAY_TYPE(3); + getTranslation(t, a); + fromRotationTranslation$1(out, outer, t); + return out; + } + /** + * Copy the values from one dual quat to another + * + * @param {quat2} out the receiving dual quaternion + * @param {ReadonlyQuat2} a the source dual quaternion + * @returns {quat2} out + * @function + */ + + function copy$7(out, a) { + out[0] = a[0]; + out[1] = a[1]; + out[2] = a[2]; + out[3] = a[3]; + out[4] = a[4]; + out[5] = a[5]; + out[6] = a[6]; + out[7] = a[7]; + return out; + } + /** + * Set a dual quat to the identity dual quaternion + * + * @param {quat2} out the receiving quaternion + * @returns {quat2} out + */ + + function identity$5(out) { + out[0] = 0; + out[1] = 0; + out[2] = 0; + out[3] = 1; + out[4] = 0; + out[5] = 0; + out[6] = 0; + out[7] = 0; + return out; + } + /** + * Set the components of a dual quat to the given values + * + * @param {quat2} out the receiving quaternion + * @param {Number} x1 X component + * @param {Number} y1 Y component + * @param {Number} z1 Z component + * @param {Number} w1 W component + * @param {Number} x2 X component + * @param {Number} y2 Y component + * @param {Number} z2 Z component + * @param {Number} w2 W component + * @returns {quat2} out + * @function + */ + + function set$7(out, x1, y1, z1, w1, x2, y2, z2, w2) { + out[0] = x1; + out[1] = y1; + out[2] = z1; + out[3] = w1; + out[4] = x2; + out[5] = y2; + out[6] = z2; + out[7] = w2; + return out; + } + /** + * Gets the real part of a dual quat + * @param {quat} out real part + * @param {ReadonlyQuat2} a Dual Quaternion + * @return {quat} real part + */ + + var getReal = copy$6; + /** + * Gets the dual part of a dual quat + * @param {quat} out dual part + * @param {ReadonlyQuat2} a Dual Quaternion + * @return {quat} dual part + */ + + function getDual(out, a) { + out[0] = a[4]; + out[1] = a[5]; + out[2] = a[6]; + out[3] = a[7]; + return out; + } + /** + * Set the real component of a dual quat to the given quaternion + * + * @param {quat2} out the receiving quaternion + * @param {ReadonlyQuat} q a quaternion representing the real part + * @returns {quat2} out + * @function + */ + + var setReal = copy$6; + /** + * Set the dual component of a dual quat to the given quaternion + * + * @param {quat2} out the receiving quaternion + * @param {ReadonlyQuat} q a quaternion representing the dual part + * @returns {quat2} out + * @function + */ + + function setDual(out, q) { + out[4] = q[0]; + out[5] = q[1]; + out[6] = q[2]; + out[7] = q[3]; + return out; + } + /** + * Gets the translation of a normalized dual quat + * @param {vec3} out translation + * @param {ReadonlyQuat2} a Dual Quaternion to be decomposed + * @return {vec3} translation + */ + + function getTranslation$1(out, a) { + var ax = a[4], + ay = a[5], + az = a[6], + aw = a[7], + bx = -a[0], + by = -a[1], + bz = -a[2], + bw = a[3]; + out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2; + out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2; + out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2; + return out; + } + /** + * Translates a dual quat by the given vector + * + * @param {quat2} out the receiving dual quaternion + * @param {ReadonlyQuat2} a the dual quaternion to translate + * @param {ReadonlyVec3} v vector to translate by + * @returns {quat2} out + */ + + function translate$3(out, a, v) { + var ax1 = a[0], + ay1 = a[1], + az1 = a[2], + aw1 = a[3], + bx1 = v[0] * 0.5, + by1 = v[1] * 0.5, + bz1 = v[2] * 0.5, + ax2 = a[4], + ay2 = a[5], + az2 = a[6], + aw2 = a[7]; + out[0] = ax1; + out[1] = ay1; + out[2] = az1; + out[3] = aw1; + out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2; + out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2; + out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2; + out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2; + return out; + } + /** + * Rotates a dual quat around the X axis + * + * @param {quat2} out the receiving dual quaternion + * @param {ReadonlyQuat2} a the dual quaternion to rotate + * @param {number} rad how far should the rotation be + * @returns {quat2} out + */ + + function rotateX$3(out, a, rad) { + var bx = -a[0], + by = -a[1], + bz = -a[2], + bw = a[3], + ax = a[4], + ay = a[5], + az = a[6], + aw = a[7], + ax1 = ax * bw + aw * bx + ay * bz - az * by, + ay1 = ay * bw + aw * by + az * bx - ax * bz, + az1 = az * bw + aw * bz + ax * by - ay * bx, + aw1 = aw * bw - ax * bx - ay * by - az * bz; + rotateX$2(out, a, rad); + bx = out[0]; + by = out[1]; + bz = out[2]; + bw = out[3]; + out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by; + out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz; + out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx; + out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz; + return out; + } + /** + * Rotates a dual quat around the Y axis + * + * @param {quat2} out the receiving dual quaternion + * @param {ReadonlyQuat2} a the dual quaternion to rotate + * @param {number} rad how far should the rotation be + * @returns {quat2} out + */ + + function rotateY$3(out, a, rad) { + var bx = -a[0], + by = -a[1], + bz = -a[2], + bw = a[3], + ax = a[4], + ay = a[5], + az = a[6], + aw = a[7], + ax1 = ax * bw + aw * bx + ay * bz - az * by, + ay1 = ay * bw + aw * by + az * bx - ax * bz, + az1 = az * bw + aw * bz + ax * by - ay * bx, + aw1 = aw * bw - ax * bx - ay * by - az * bz; + rotateY$2(out, a, rad); + bx = out[0]; + by = out[1]; + bz = out[2]; + bw = out[3]; + out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by; + out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz; + out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx; + out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz; + return out; + } + /** + * Rotates a dual quat around the Z axis + * + * @param {quat2} out the receiving dual quaternion + * @param {ReadonlyQuat2} a the dual quaternion to rotate + * @param {number} rad how far should the rotation be + * @returns {quat2} out + */ + + function rotateZ$3(out, a, rad) { + var bx = -a[0], + by = -a[1], + bz = -a[2], + bw = a[3], + ax = a[4], + ay = a[5], + az = a[6], + aw = a[7], + ax1 = ax * bw + aw * bx + ay * bz - az * by, + ay1 = ay * bw + aw * by + az * bx - ax * bz, + az1 = az * bw + aw * bz + ax * by - ay * bx, + aw1 = aw * bw - ax * bx - ay * by - az * bz; + rotateZ$2(out, a, rad); + bx = out[0]; + by = out[1]; + bz = out[2]; + bw = out[3]; + out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by; + out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz; + out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx; + out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz; + return out; + } + /** + * Rotates a dual quat by a given quaternion (a * q) + * + * @param {quat2} out the receiving dual quaternion + * @param {ReadonlyQuat2} a the dual quaternion to rotate + * @param {ReadonlyQuat} q quaternion to rotate by + * @returns {quat2} out + */ + + function rotateByQuatAppend(out, a, q) { + var qx = q[0], + qy = q[1], + qz = q[2], + qw = q[3], + ax = a[0], + ay = a[1], + az = a[2], + aw = a[3]; + out[0] = ax * qw + aw * qx + ay * qz - az * qy; + out[1] = ay * qw + aw * qy + az * qx - ax * qz; + out[2] = az * qw + aw * qz + ax * qy - ay * qx; + out[3] = aw * qw - ax * qx - ay * qy - az * qz; + ax = a[4]; + ay = a[5]; + az = a[6]; + aw = a[7]; + out[4] = ax * qw + aw * qx + ay * qz - az * qy; + out[5] = ay * qw + aw * qy + az * qx - ax * qz; + out[6] = az * qw + aw * qz + ax * qy - ay * qx; + out[7] = aw * qw - ax * qx - ay * qy - az * qz; + return out; + } + /** + * Rotates a dual quat by a given quaternion (q * a) + * + * @param {quat2} out the receiving dual quaternion + * @param {ReadonlyQuat} q quaternion to rotate by + * @param {ReadonlyQuat2} a the dual quaternion to rotate + * @returns {quat2} out + */ + + function rotateByQuatPrepend(out, q, a) { + var qx = q[0], + qy = q[1], + qz = q[2], + qw = q[3], + bx = a[0], + by = a[1], + bz = a[2], + bw = a[3]; + out[0] = qx * bw + qw * bx + qy * bz - qz * by; + out[1] = qy * bw + qw * by + qz * bx - qx * bz; + out[2] = qz * bw + qw * bz + qx * by - qy * bx; + out[3] = qw * bw - qx * bx - qy * by - qz * bz; + bx = a[4]; + by = a[5]; + bz = a[6]; + bw = a[7]; + out[4] = qx * bw + qw * bx + qy * bz - qz * by; + out[5] = qy * bw + qw * by + qz * bx - qx * bz; + out[6] = qz * bw + qw * bz + qx * by - qy * bx; + out[7] = qw * bw - qx * bx - qy * by - qz * bz; + return out; + } + /** + * Rotates a dual quat around a given axis. Does the normalisation automatically + * + * @param {quat2} out the receiving dual quaternion + * @param {ReadonlyQuat2} a the dual quaternion to rotate + * @param {ReadonlyVec3} axis the axis to rotate around + * @param {Number} rad how far the rotation should be + * @returns {quat2} out + */ + + function rotateAroundAxis(out, a, axis, rad) { + //Special case for rad = 0 + if (Math.abs(rad) < EPSILON) { + return copy$7(out, a); + } + + var axisLength = Math.hypot(axis[0], axis[1], axis[2]); + rad = rad * 0.5; + var s = Math.sin(rad); + var bx = s * axis[0] / axisLength; + var by = s * axis[1] / axisLength; + var bz = s * axis[2] / axisLength; + var bw = Math.cos(rad); + var ax1 = a[0], + ay1 = a[1], + az1 = a[2], + aw1 = a[3]; + out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by; + out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz; + out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx; + out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz; + var ax = a[4], + ay = a[5], + az = a[6], + aw = a[7]; + out[4] = ax * bw + aw * bx + ay * bz - az * by; + out[5] = ay * bw + aw * by + az * bx - ax * bz; + out[6] = az * bw + aw * bz + ax * by - ay * bx; + out[7] = aw * bw - ax * bx - ay * by - az * bz; + return out; + } + /** + * Adds two dual quat's + * + * @param {quat2} out the receiving dual quaternion + * @param {ReadonlyQuat2} a the first operand + * @param {ReadonlyQuat2} b the second operand + * @returns {quat2} out + * @function + */ + + function add$7(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + out[2] = a[2] + b[2]; + out[3] = a[3] + b[3]; + out[4] = a[4] + b[4]; + out[5] = a[5] + b[5]; + out[6] = a[6] + b[6]; + out[7] = a[7] + b[7]; + return out; + } + /** + * Multiplies two dual quat's + * + * @param {quat2} out the receiving dual quaternion + * @param {ReadonlyQuat2} a the first operand + * @param {ReadonlyQuat2} b the second operand + * @returns {quat2} out + */ + + function multiply$7(out, a, b) { + var ax0 = a[0], + ay0 = a[1], + az0 = a[2], + aw0 = a[3], + bx1 = b[4], + by1 = b[5], + bz1 = b[6], + bw1 = b[7], + ax1 = a[4], + ay1 = a[5], + az1 = a[6], + aw1 = a[7], + bx0 = b[0], + by0 = b[1], + bz0 = b[2], + bw0 = b[3]; + out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0; + out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0; + out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0; + out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0; + out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0; + out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0; + out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0; + out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0; + return out; + } + /** + * Alias for {@link quat2.multiply} + * @function + */ + + var mul$7 = multiply$7; + /** + * Scales a dual quat by a scalar number + * + * @param {quat2} out the receiving dual quat + * @param {ReadonlyQuat2} a the dual quat to scale + * @param {Number} b amount to scale the dual quat by + * @returns {quat2} out + * @function + */ + + function scale$7(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + out[2] = a[2] * b; + out[3] = a[3] * b; + out[4] = a[4] * b; + out[5] = a[5] * b; + out[6] = a[6] * b; + out[7] = a[7] * b; + return out; + } + /** + * Calculates the dot product of two dual quat's (The dot product of the real parts) + * + * @param {ReadonlyQuat2} a the first operand + * @param {ReadonlyQuat2} b the second operand + * @returns {Number} dot product of a and b + * @function + */ + + var dot$3 = dot$2; + /** + * Performs a linear interpolation between two dual quats's + * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5) + * + * @param {quat2} out the receiving dual quat + * @param {ReadonlyQuat2} a the first operand + * @param {ReadonlyQuat2} b the second operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {quat2} out + */ + + function lerp$3(out, a, b, t) { + var mt = 1 - t; + if (dot$3(a, b) < 0) t = -t; + out[0] = a[0] * mt + b[0] * t; + out[1] = a[1] * mt + b[1] * t; + out[2] = a[2] * mt + b[2] * t; + out[3] = a[3] * mt + b[3] * t; + out[4] = a[4] * mt + b[4] * t; + out[5] = a[5] * mt + b[5] * t; + out[6] = a[6] * mt + b[6] * t; + out[7] = a[7] * mt + b[7] * t; + return out; + } + /** + * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper + * + * @param {quat2} out the receiving dual quaternion + * @param {ReadonlyQuat2} a dual quat to calculate inverse of + * @returns {quat2} out + */ + + function invert$5(out, a) { + var sqlen = squaredLength$3(a); + out[0] = -a[0] / sqlen; + out[1] = -a[1] / sqlen; + out[2] = -a[2] / sqlen; + out[3] = a[3] / sqlen; + out[4] = -a[4] / sqlen; + out[5] = -a[5] / sqlen; + out[6] = -a[6] / sqlen; + out[7] = a[7] / sqlen; + return out; + } + /** + * Calculates the conjugate of a dual quat + * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result. + * + * @param {quat2} out the receiving quaternion + * @param {ReadonlyQuat2} a quat to calculate conjugate of + * @returns {quat2} out + */ + + function conjugate$1(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + out[2] = -a[2]; + out[3] = a[3]; + out[4] = -a[4]; + out[5] = -a[5]; + out[6] = -a[6]; + out[7] = a[7]; + return out; + } + /** + * Calculates the length of a dual quat + * + * @param {ReadonlyQuat2} a dual quat to calculate length of + * @returns {Number} length of a + * @function + */ + + var length$3 = length$2; + /** + * Alias for {@link quat2.length} + * @function + */ + + var len$3 = length$3; + /** + * Calculates the squared length of a dual quat + * + * @param {ReadonlyQuat2} a dual quat to calculate squared length of + * @returns {Number} squared length of a + * @function + */ + + var squaredLength$3 = squaredLength$2; + /** + * Alias for {@link quat2.squaredLength} + * @function + */ + + var sqrLen$3 = squaredLength$3; + /** + * Normalize a dual quat + * + * @param {quat2} out the receiving dual quaternion + * @param {ReadonlyQuat2} a dual quaternion to normalize + * @returns {quat2} out + * @function + */ + + function normalize$3(out, a) { + var magnitude = squaredLength$3(a); + + if (magnitude > 0) { + magnitude = Math.sqrt(magnitude); + var a0 = a[0] / magnitude; + var a1 = a[1] / magnitude; + var a2 = a[2] / magnitude; + var a3 = a[3] / magnitude; + var b0 = a[4]; + var b1 = a[5]; + var b2 = a[6]; + var b3 = a[7]; + var a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3; + out[0] = a0; + out[1] = a1; + out[2] = a2; + out[3] = a3; + out[4] = (b0 - a0 * a_dot_b) / magnitude; + out[5] = (b1 - a1 * a_dot_b) / magnitude; + out[6] = (b2 - a2 * a_dot_b) / magnitude; + out[7] = (b3 - a3 * a_dot_b) / magnitude; + } + + return out; + } + /** + * Returns a string representation of a dual quatenion + * + * @param {ReadonlyQuat2} a dual quaternion to represent as a string + * @returns {String} string representation of the dual quat + */ + + function str$7(a) { + return "quat2(" + a[0] + ", " + a[1] + ", " + a[2] + ", " + a[3] + ", " + a[4] + ", " + a[5] + ", " + a[6] + ", " + a[7] + ")"; + } + /** + * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===) + * + * @param {ReadonlyQuat2} a the first dual quaternion. + * @param {ReadonlyQuat2} b the second dual quaternion. + * @returns {Boolean} true if the dual quaternions are equal, false otherwise. + */ + + function exactEquals$7(a, b) { + return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7]; + } + /** + * Returns whether or not the dual quaternions have approximately the same elements in the same position. + * + * @param {ReadonlyQuat2} a the first dual quat. + * @param {ReadonlyQuat2} b the second dual quat. + * @returns {Boolean} true if the dual quats are equal, false otherwise. + */ + + function equals$8(a, b) { + var a0 = a[0], + a1 = a[1], + a2 = a[2], + a3 = a[3], + a4 = a[4], + a5 = a[5], + a6 = a[6], + a7 = a[7]; + var b0 = b[0], + b1 = b[1], + b2 = b[2], + b3 = b[3], + b4 = b[4], + b5 = b[5], + b6 = b[6], + b7 = b[7]; + return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= EPSILON * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= EPSILON * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= EPSILON * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= EPSILON * Math.max(1.0, Math.abs(a7), Math.abs(b7)); + } + + var quat2 = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$7, + clone: clone$7, + fromValues: fromValues$7, + fromRotationTranslationValues: fromRotationTranslationValues, + fromRotationTranslation: fromRotationTranslation$1, + fromTranslation: fromTranslation$3, + fromRotation: fromRotation$4, + fromMat4: fromMat4$1, + copy: copy$7, + identity: identity$5, + set: set$7, + getReal: getReal, + getDual: getDual, + setReal: setReal, + setDual: setDual, + getTranslation: getTranslation$1, + translate: translate$3, + rotateX: rotateX$3, + rotateY: rotateY$3, + rotateZ: rotateZ$3, + rotateByQuatAppend: rotateByQuatAppend, + rotateByQuatPrepend: rotateByQuatPrepend, + rotateAroundAxis: rotateAroundAxis, + add: add$7, + multiply: multiply$7, + mul: mul$7, + scale: scale$7, + dot: dot$3, + lerp: lerp$3, + invert: invert$5, + conjugate: conjugate$1, + length: length$3, + len: len$3, + squaredLength: squaredLength$3, + sqrLen: sqrLen$3, + normalize: normalize$3, + str: str$7, + exactEquals: exactEquals$7, + equals: equals$8 + }); + + /** + * 2 Dimensional Vector + * @module vec2 + */ + + /** + * Creates a new, empty vec2 + * + * @returns {vec2} a new 2D vector + */ + + function create$8() { + var out = new ARRAY_TYPE(2); + + if (ARRAY_TYPE != Float32Array) { + out[0] = 0; + out[1] = 0; + } + + return out; + } + /** + * Creates a new vec2 initialized with values from an existing vector + * + * @param {ReadonlyVec2} a vector to clone + * @returns {vec2} a new 2D vector + */ + + function clone$8(a) { + var out = new ARRAY_TYPE(2); + out[0] = a[0]; + out[1] = a[1]; + return out; + } + /** + * Creates a new vec2 initialized with the given values + * + * @param {Number} x X component + * @param {Number} y Y component + * @returns {vec2} a new 2D vector + */ + + function fromValues$8(x, y) { + var out = new ARRAY_TYPE(2); + out[0] = x; + out[1] = y; + return out; + } + /** + * Copy the values from one vec2 to another + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a the source vector + * @returns {vec2} out + */ + + function copy$8(out, a) { + out[0] = a[0]; + out[1] = a[1]; + return out; + } + /** + * Set the components of a vec2 to the given values + * + * @param {vec2} out the receiving vector + * @param {Number} x X component + * @param {Number} y Y component + * @returns {vec2} out + */ + + function set$8(out, x, y) { + out[0] = x; + out[1] = y; + return out; + } + /** + * Adds two vec2's + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a the first operand + * @param {ReadonlyVec2} b the second operand + * @returns {vec2} out + */ + + function add$8(out, a, b) { + out[0] = a[0] + b[0]; + out[1] = a[1] + b[1]; + return out; + } + /** + * Subtracts vector b from vector a + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a the first operand + * @param {ReadonlyVec2} b the second operand + * @returns {vec2} out + */ + + function subtract$6(out, a, b) { + out[0] = a[0] - b[0]; + out[1] = a[1] - b[1]; + return out; + } + /** + * Multiplies two vec2's + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a the first operand + * @param {ReadonlyVec2} b the second operand + * @returns {vec2} out + */ + + function multiply$8(out, a, b) { + out[0] = a[0] * b[0]; + out[1] = a[1] * b[1]; + return out; + } + /** + * Divides two vec2's + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a the first operand + * @param {ReadonlyVec2} b the second operand + * @returns {vec2} out + */ + + function divide$2(out, a, b) { + out[0] = a[0] / b[0]; + out[1] = a[1] / b[1]; + return out; + } + /** + * Math.ceil the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a vector to ceil + * @returns {vec2} out + */ + + function ceil$2(out, a) { + out[0] = Math.ceil(a[0]); + out[1] = Math.ceil(a[1]); + return out; + } + /** + * Math.floor the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a vector to floor + * @returns {vec2} out + */ + + function floor$2(out, a) { + out[0] = Math.floor(a[0]); + out[1] = Math.floor(a[1]); + return out; + } + /** + * Returns the minimum of two vec2's + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a the first operand + * @param {ReadonlyVec2} b the second operand + * @returns {vec2} out + */ + + function min$2(out, a, b) { + out[0] = Math.min(a[0], b[0]); + out[1] = Math.min(a[1], b[1]); + return out; + } + /** + * Returns the maximum of two vec2's + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a the first operand + * @param {ReadonlyVec2} b the second operand + * @returns {vec2} out + */ + + function max$2(out, a, b) { + out[0] = Math.max(a[0], b[0]); + out[1] = Math.max(a[1], b[1]); + return out; + } + /** + * Math.round the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a vector to round + * @returns {vec2} out + */ + + function round$2(out, a) { + out[0] = Math.round(a[0]); + out[1] = Math.round(a[1]); + return out; + } + /** + * Scales a vec2 by a scalar number + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a the vector to scale + * @param {Number} b amount to scale the vector by + * @returns {vec2} out + */ + + function scale$8(out, a, b) { + out[0] = a[0] * b; + out[1] = a[1] * b; + return out; + } + /** + * Adds two vec2's after scaling the second operand by a scalar value + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a the first operand + * @param {ReadonlyVec2} b the second operand + * @param {Number} scale the amount to scale b by before adding + * @returns {vec2} out + */ + + function scaleAndAdd$2(out, a, b, scale) { + out[0] = a[0] + b[0] * scale; + out[1] = a[1] + b[1] * scale; + return out; + } + /** + * Calculates the euclidian distance between two vec2's + * + * @param {ReadonlyVec2} a the first operand + * @param {ReadonlyVec2} b the second operand + * @returns {Number} distance between a and b + */ + + function distance$2(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1]; + return Math.hypot(x, y); + } + /** + * Calculates the squared euclidian distance between two vec2's + * + * @param {ReadonlyVec2} a the first operand + * @param {ReadonlyVec2} b the second operand + * @returns {Number} squared distance between a and b + */ + + function squaredDistance$2(a, b) { + var x = b[0] - a[0], + y = b[1] - a[1]; + return x * x + y * y; + } + /** + * Calculates the length of a vec2 + * + * @param {ReadonlyVec2} a vector to calculate length of + * @returns {Number} length of a + */ + + function length$4(a) { + var x = a[0], + y = a[1]; + return Math.hypot(x, y); + } + /** + * Calculates the squared length of a vec2 + * + * @param {ReadonlyVec2} a vector to calculate squared length of + * @returns {Number} squared length of a + */ + + function squaredLength$4(a) { + var x = a[0], + y = a[1]; + return x * x + y * y; + } + /** + * Negates the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a vector to negate + * @returns {vec2} out + */ + + function negate$2(out, a) { + out[0] = -a[0]; + out[1] = -a[1]; + return out; + } + /** + * Returns the inverse of the components of a vec2 + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a vector to invert + * @returns {vec2} out + */ + + function inverse$2(out, a) { + out[0] = 1.0 / a[0]; + out[1] = 1.0 / a[1]; + return out; + } + /** + * Normalize a vec2 + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a vector to normalize + * @returns {vec2} out + */ + + function normalize$4(out, a) { + var x = a[0], + y = a[1]; + var len = x * x + y * y; + + if (len > 0) { + //TODO: evaluate use of glm_invsqrt here? + len = 1 / Math.sqrt(len); + } + + out[0] = a[0] * len; + out[1] = a[1] * len; + return out; + } + /** + * Calculates the dot product of two vec2's + * + * @param {ReadonlyVec2} a the first operand + * @param {ReadonlyVec2} b the second operand + * @returns {Number} dot product of a and b + */ + + function dot$4(a, b) { + return a[0] * b[0] + a[1] * b[1]; + } + /** + * Computes the cross product of two vec2's + * Note that the cross product must by definition produce a 3D vector + * + * @param {vec3} out the receiving vector + * @param {ReadonlyVec2} a the first operand + * @param {ReadonlyVec2} b the second operand + * @returns {vec3} out + */ + + function cross$2(out, a, b) { + var z = a[0] * b[1] - a[1] * b[0]; + out[0] = out[1] = 0; + out[2] = z; + return out; + } + /** + * Performs a linear interpolation between two vec2's + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a the first operand + * @param {ReadonlyVec2} b the second operand + * @param {Number} t interpolation amount, in the range [0-1], between the two inputs + * @returns {vec2} out + */ + + function lerp$4(out, a, b, t) { + var ax = a[0], + ay = a[1]; + out[0] = ax + t * (b[0] - ax); + out[1] = ay + t * (b[1] - ay); + return out; + } + /** + * Generates a random vector with the given scale + * + * @param {vec2} out the receiving vector + * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned + * @returns {vec2} out + */ + + function random$3(out, scale) { + scale = scale || 1.0; + var r = RANDOM() * 2.0 * Math.PI; + out[0] = Math.cos(r) * scale; + out[1] = Math.sin(r) * scale; + return out; + } + /** + * Transforms the vec2 with a mat2 + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a the vector to transform + * @param {ReadonlyMat2} m matrix to transform with + * @returns {vec2} out + */ + + function transformMat2(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[2] * y; + out[1] = m[1] * x + m[3] * y; + return out; + } + /** + * Transforms the vec2 with a mat2d + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a the vector to transform + * @param {ReadonlyMat2d} m matrix to transform with + * @returns {vec2} out + */ + + function transformMat2d(out, a, m) { + var x = a[0], + y = a[1]; + out[0] = m[0] * x + m[2] * y + m[4]; + out[1] = m[1] * x + m[3] * y + m[5]; + return out; + } + /** + * Transforms the vec2 with a mat3 + * 3rd vector component is implicitly '1' + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a the vector to transform + * @param {ReadonlyMat3} m matrix to transform with + * @returns {vec2} out + */ + + function transformMat3$1(out, a, m) { + var x = a[0], + 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; + } + /** + * Transforms the vec2 with a mat4 + * 3rd vector component is implicitly '0' + * 4th vector component is implicitly '1' + * + * @param {vec2} out the receiving vector + * @param {ReadonlyVec2} a the vector to transform + * @param {ReadonlyMat4} m matrix to transform with + * @returns {vec2} out + */ + + function transformMat4$2(out, a, m) { + var x = a[0]; + var 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; + } + /** + * Rotate a 2D vector + * @param {vec2} out The receiving vec2 + * @param {ReadonlyVec2} a The vec2 point to rotate + * @param {ReadonlyVec2} b The origin of the rotation + * @param {Number} rad The angle of rotation in radians + * @returns {vec2} out + */ + + function rotate$4(out, a, b, rad) { + //Translate point to the origin + var p0 = a[0] - b[0], + p1 = a[1] - b[1], + sinC = Math.sin(rad), + cosC = Math.cos(rad); //perform rotation and translate to correct position + + out[0] = p0 * cosC - p1 * sinC + b[0]; + out[1] = p0 * sinC + p1 * cosC + b[1]; + return out; + } + /** + * Get the angle between two 2D vectors + * @param {ReadonlyVec2} a The first operand + * @param {ReadonlyVec2} b The second operand + * @returns {Number} The angle in radians + */ + + function angle$1(a, b) { + var x1 = a[0], + y1 = a[1], + x2 = b[0], + y2 = b[1], + // mag is the product of the magnitudes of a and b + mag = Math.sqrt(x1 * x1 + y1 * y1) * Math.sqrt(x2 * x2 + y2 * y2), + // mag &&.. short circuits if mag == 0 + cosine = mag && (x1 * x2 + y1 * y2) / mag; // Math.min(Math.max(cosine, -1), 1) clamps the cosine between -1 and 1 + + return Math.acos(Math.min(Math.max(cosine, -1), 1)); + } + /** + * Set the components of a vec2 to zero + * + * @param {vec2} out the receiving vector + * @returns {vec2} out + */ + + function zero$2(out) { + out[0] = 0.0; + out[1] = 0.0; + return out; + } + /** + * Returns a string representation of a vector + * + * @param {ReadonlyVec2} a vector to represent as a string + * @returns {String} string representation of the vector + */ + + function str$8(a) { + return "vec2(" + a[0] + ", " + a[1] + ")"; + } + /** + * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===) + * + * @param {ReadonlyVec2} a The first vector. + * @param {ReadonlyVec2} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ + + function exactEquals$8(a, b) { + return a[0] === b[0] && a[1] === b[1]; + } + /** + * Returns whether or not the vectors have approximately the same elements in the same position. + * + * @param {ReadonlyVec2} a The first vector. + * @param {ReadonlyVec2} b The second vector. + * @returns {Boolean} True if the vectors are equal, false otherwise. + */ + + function equals$9(a, b) { + var a0 = a[0], + a1 = a[1]; + var b0 = b[0], + b1 = b[1]; + return Math.abs(a0 - b0) <= EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)); + } + /** + * Alias for {@link vec2.length} + * @function + */ + + var len$4 = length$4; + /** + * Alias for {@link vec2.subtract} + * @function + */ + + var sub$6 = subtract$6; + /** + * Alias for {@link vec2.multiply} + * @function + */ + + var mul$8 = multiply$8; + /** + * Alias for {@link vec2.divide} + * @function + */ + + var div$2 = divide$2; + /** + * Alias for {@link vec2.distance} + * @function + */ + + var dist$2 = distance$2; + /** + * Alias for {@link vec2.squaredDistance} + * @function + */ + + var sqrDist$2 = squaredDistance$2; + /** + * Alias for {@link vec2.squaredLength} + * @function + */ + + var sqrLen$4 = squaredLength$4; + /** + * Perform some operation over an array of vec2s. + * + * @param {Array} a the array of vectors to iterate over + * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed + * @param {Number} offset Number of elements to skip at the beginning of the array + * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array + * @param {Function} fn Function to call for each vector in the array + * @param {Object} [arg] additional argument to pass to fn + * @returns {Array} a + * @function + */ + + var forEach$2 = function () { + var vec = create$8(); + return function (a, stride, offset, count, fn, arg) { + var i, 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; + }; + }(); + + var vec2 = /*#__PURE__*/Object.freeze({ + __proto__: null, + create: create$8, + clone: clone$8, + fromValues: fromValues$8, + copy: copy$8, + set: set$8, + add: add$8, + subtract: subtract$6, + multiply: multiply$8, + divide: divide$2, + ceil: ceil$2, + floor: floor$2, + min: min$2, + max: max$2, + round: round$2, + scale: scale$8, + scaleAndAdd: scaleAndAdd$2, + distance: distance$2, + squaredDistance: squaredDistance$2, + length: length$4, + squaredLength: squaredLength$4, + negate: negate$2, + inverse: inverse$2, + normalize: normalize$4, + dot: dot$4, + cross: cross$2, + lerp: lerp$4, + random: random$3, + transformMat2: transformMat2, + transformMat2d: transformMat2d, + transformMat3: transformMat3$1, + transformMat4: transformMat4$2, + rotate: rotate$4, + angle: angle$1, + zero: zero$2, + str: str$8, + exactEquals: exactEquals$8, + equals: equals$9, + len: len$4, + sub: sub$6, + mul: mul$8, + div: div$2, + dist: dist$2, + sqrDist: sqrDist$2, + sqrLen: sqrLen$4, + forEach: forEach$2 + }); + + exports.glMatrix = common; + exports.mat2 = mat2; + exports.mat2d = mat2d; + exports.mat3 = mat3; + exports.mat4 = mat4; + exports.quat = quat; + exports.quat2 = quat2; + exports.vec2 = vec2; + exports.vec3 = vec3; + exports.vec4 = vec4; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); diff --git a/img/FragmentShader.png b/img/FragmentShader.png new file mode 100644 index 0000000000000000000000000000000000000000..52a0a5d5da21d01d9a5fb71b5e2a910ed4469329 GIT binary patch literal 12026 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 S={f@g1B0ilpUXO@geCxbhnC&| literal 0 HcmV?d00001 diff --git a/img/InitializeGL.png b/img/InitializeGL.png new file mode 100644 index 0000000000000000000000000000000000000000..8687c942874655fa7b176d16d0423741b31ab8a8 GIT binary patch literal 26383 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 literal 0 HcmV?d00001 diff --git a/img/VertexShader.png b/img/VertexShader.png new file mode 100644 index 0000000000000000000000000000000000000000..33144945b2cf70730e1515b353f0c5de2834a958 GIT binary patch literal 14815 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 T=QaI1L8CFAu6{1-oD!M<Ez>$* literal 0 HcmV?d00001 diff --git a/index.html b/index.html new file mode 100644 index 0000000..d128ecb --- /dev/null +++ b/index.html @@ -0,0 +1,71 @@ +<html> + +<head> +<title>WebGL1.0 to WebGL2.0</title> +<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"> +<script type="text/javascript" src="gl-matrix.js"> </script> +<script type="text/javascript" src="Script.js"> </script> + +</head> + +<body onload="main()"> + <div> + <header> + <h1>WebGL Tutorial</h1> + <h2>How to change WebGL1-based documents to WebGL2</h2> + </header> + </div> + + <canvas id="helloapicanvas" style="border: none;" width="600" height="600"></canvas> + + <br/> <br/> +<button onclick="toggleAnimation()">Toggle Animation</button> +<button onclick="speed_plus()"> + </button> +<button onclick="speed_minus()"> - </button> +<button onclick="draw_mode_change(2)"> Lines </button> +<button onclick="draw_mode_change(4)"> Triangles </button> +<button onclick="draw_mode_change(0)"> Points </button> + +<hr> +<div> + <h3>Description</h3> + <div>This document is to describe the basic method of changing the WebGL1-based document to WebGL2.</div> + <div>WebGL2 is nearly 100% back compatible with WebGL1. In this document, there will be description of very basic way to change the WebGL1 script to WebGL2.</div> + <div>Very brief comments are here, so read the source code to see the details.</div> +</div> +<hr> +<div> + <h3>Initializing</h3> + <div>First, you use "webgl2" instead of "webgl", on initializing canvas.</div> + <div>Note that there is no "experimental-webgl2". Many WebGL1 extensions are a standard part of WebGL2.</div> +</div> +<hr> +<div> + <h3>Switching the Shader Version to GLSL 3.00 ES</h3> + <div>Add "#version 300 es" to the very first line of the shader source code.</div> + <div>CAUTION: NO BLANKS AND LINES ARE ALLOWED BEFORE THIS DECLARATION.</div> +</div> +<hr> +<div> + <h3>Some Changes in Shader Code</h3> + <div>Add "#version 300 es" to the very first line of the shader source code.</div> + <div>CAUTION: NO BLANKS AND LINES ARE ALLOWED BEFORE THIS DECLARATION.</div> + <br> + <div>No more gl_fragColor. In WebGL1, your fragment shader would set the specific variable "gl_fragColor" to set the output value.</div> + <div>You can now use any name for the output, except for those starting with "gl_".</div> + <br> + <div>Change "varying" to "in" or "out", and "attribute" to "in".</div> + <div>The output of the vertex shader would be the input of the fragment shader. We call them "varying" values.</div> + <div>Simply change them to "out" in the vertex shader, and "in" in the fragment shader.</div> +</div> +<hr> +<div> + <h3>References</h3> + <div>This page is modified from Lab 06 of the Computer Graphics course.</div> + <div>Additional information is from WebGL2 Fundamentals.</div> + <div> <a href="https://webgl2fundamentals.org/webgl/lessons/webgl1-to-webgl2.html">WebGL1 to WebGL2</a> / <a href="https://webgl2fundamentals.org/webgl/lessons/ko/webgl-fundamentals.html">WebGL2 Fundamentals</a></div> +</div> + +</body> + +</html> -- GitLab