From 77bde04db3976c858da761286c51cac5a5c0761c Mon Sep 17 00:00:00 2001 From: schmelczerandras Date: Tue, 15 Sep 2020 10:08:16 +0200 Subject: [PATCH] Add files --- .eslintignore | 1 + .eslintrc.json | 29 + .gitattributes | 1 + .gitignore | 3 + .prettierrc | 7 + .vscode/settings.json | 8 + build/main-bundle.js | 7839 +++++++++++++++++ build/src/game.d.ts | 0 .../drawables/i-drawable-descriptor.d.ts | 7 + build/src/graphics/drawables/i-drawable.d.ts | 5 + .../drawables/lights/circle-light.d.ts | 14 + .../graphics/drawables/lights/flashlight.d.ts | 15 + .../graphics/drawables/lights/i-light.d.ts | 2 + .../compiling/check-program.d.ts | 1 + .../compiling/check-shader.d.ts | 1 + .../compiling/create-program.d.ts | 3 + .../compiling/create-shader.d.ts | 3 + .../frame-buffer/default-frame-buffer.d.ts | 5 + .../frame-buffer/frame-buffer.d.ts | 12 + .../intermediate-frame-buffer.d.ts | 10 + .../helper/enable-extension.d.ts | 2 + .../helper/get-webgl2-context.d.ts | 1 + .../graphics-library/helper/load-uniform.d.ts | 1 + .../graphics-library/helper/stopwatch.d.ts | 11 + .../program/fragment-shader-only-program.d.ts | 11 + .../graphics-library/program/i-program.d.ts | 10 + .../graphics-library/program/program.d.ts | 25 + .../uniform-array-autoscaling-program.d.ts | 20 + build/src/graphics/i-renderer.d.ts | 14 + .../graphics/rendering/fps-autoscaler.d.ts | 9 + .../graphics/rendering/rendering-pass.d.ts | 12 + .../graphics/rendering/uniforms-provider.d.ts | 18 + .../graphics/rendering/webgl2-renderer.d.ts | 27 + build/src/graphics/settings.d.ts | 27 + build/src/helper/array.d.ts | 11 + build/src/helper/autoscaler.d.ts | 17 + build/src/helper/clamp.d.ts | 2 + build/src/helper/exponential-decay.d.ts | 1 + build/src/helper/get-combinations.d.ts | 1 + build/src/helper/last.d.ts | 1 + build/src/helper/mix.d.ts | 1 + build/src/helper/random.d.ts | 5 + build/src/helper/rotate-90-deg.d.ts | 2 + build/src/helper/timing.d.ts | 1 + build/src/helper/to-percent.d.ts | 1 + build/src/helper/wait-while-false.d.ts | 1 + build/src/helper/wait.d.ts | 1 + build/src/main.d.ts | 1 + custom.d.ts | 24 + package.json | 50 + src/game.ts | 121 + .../drawables/i-drawable-descriptor.ts | 8 + src/graphics/drawables/i-drawable.ts | 6 + src/graphics/drawables/lights/circle-light.ts | 46 + src/graphics/drawables/lights/flashlight.ts | 50 + src/graphics/drawables/lights/i-light.ts | 3 + .../compiling/check-program.ts | 13 + .../compiling/check-shader.ts | 7 + .../compiling/create-program.ts | 48 + .../compiling/create-shader.ts | 22 + .../frame-buffer/default-frame-buffer.ts | 19 + .../frame-buffer/frame-buffer.ts | 46 + .../frame-buffer/intermediate-frame-buffer.ts | 97 + .../helper/enable-extension.ts | 39 + .../helper/get-webgl2-context.ts | 9 + .../graphics-library/helper/load-uniform.ts | 82 + .../graphics-library/helper/stopwatch.ts | 49 + .../program/fragment-shader-only-program.ts | 52 + .../graphics-library/program/i-program.ts | 9 + .../graphics-library/program/program.ts | 102 + .../uniform-array-autoscaling-program.ts | 94 + src/graphics/i-renderer.ts | 18 + src/graphics/rendering/fps-autoscaler.ts | 45 + src/graphics/rendering/rendering-pass.ts | 86 + src/graphics/rendering/uniforms-provider.ts | 94 + src/graphics/rendering/webgl2-renderer.ts | 126 + src/graphics/settings.ts | 59 + src/graphics/shaders/distance-fs.glsl | 109 + src/graphics/shaders/distance-vs.glsl | 15 + src/graphics/shaders/shading-fs.glsl | 176 + src/graphics/shaders/shading-vs.glsl | 59 + src/helper/array.ts | 49 + src/helper/autoscaler.ts | 59 + src/helper/clamp.ts | 4 + src/helper/exponential-decay.ts | 5 + src/helper/get-combinations.ts | 29 + src/helper/last.ts | 3 + src/helper/mix.ts | 1 + src/helper/random.ts | 18 + src/helper/rotate-90-deg.ts | 3 + src/helper/timing.ts | 32 + src/helper/to-percent.ts | 1 + src/helper/wait-while-false.ts | 29 + src/helper/wait.ts | 3 + src/main.ts | 18 + tsconfig.json | 17 + webpack.config.js | 73 + 97 files changed, 10327 insertions(+) create mode 100644 .eslintignore create mode 100644 .eslintrc.json create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .prettierrc create mode 100644 .vscode/settings.json create mode 100644 build/main-bundle.js create mode 100644 build/src/game.d.ts create mode 100644 build/src/graphics/drawables/i-drawable-descriptor.d.ts create mode 100644 build/src/graphics/drawables/i-drawable.d.ts create mode 100644 build/src/graphics/drawables/lights/circle-light.d.ts create mode 100644 build/src/graphics/drawables/lights/flashlight.d.ts create mode 100644 build/src/graphics/drawables/lights/i-light.d.ts create mode 100644 build/src/graphics/graphics-library/compiling/check-program.d.ts create mode 100644 build/src/graphics/graphics-library/compiling/check-shader.d.ts create mode 100644 build/src/graphics/graphics-library/compiling/create-program.d.ts create mode 100644 build/src/graphics/graphics-library/compiling/create-shader.d.ts create mode 100644 build/src/graphics/graphics-library/frame-buffer/default-frame-buffer.d.ts create mode 100644 build/src/graphics/graphics-library/frame-buffer/frame-buffer.d.ts create mode 100644 build/src/graphics/graphics-library/frame-buffer/intermediate-frame-buffer.d.ts create mode 100644 build/src/graphics/graphics-library/helper/enable-extension.d.ts create mode 100644 build/src/graphics/graphics-library/helper/get-webgl2-context.d.ts create mode 100644 build/src/graphics/graphics-library/helper/load-uniform.d.ts create mode 100644 build/src/graphics/graphics-library/helper/stopwatch.d.ts create mode 100644 build/src/graphics/graphics-library/program/fragment-shader-only-program.d.ts create mode 100644 build/src/graphics/graphics-library/program/i-program.d.ts create mode 100644 build/src/graphics/graphics-library/program/program.d.ts create mode 100644 build/src/graphics/graphics-library/program/uniform-array-autoscaling-program.d.ts create mode 100644 build/src/graphics/i-renderer.d.ts create mode 100644 build/src/graphics/rendering/fps-autoscaler.d.ts create mode 100644 build/src/graphics/rendering/rendering-pass.d.ts create mode 100644 build/src/graphics/rendering/uniforms-provider.d.ts create mode 100644 build/src/graphics/rendering/webgl2-renderer.d.ts create mode 100644 build/src/graphics/settings.d.ts create mode 100644 build/src/helper/array.d.ts create mode 100644 build/src/helper/autoscaler.d.ts create mode 100644 build/src/helper/clamp.d.ts create mode 100644 build/src/helper/exponential-decay.d.ts create mode 100644 build/src/helper/get-combinations.d.ts create mode 100644 build/src/helper/last.d.ts create mode 100644 build/src/helper/mix.d.ts create mode 100644 build/src/helper/random.d.ts create mode 100644 build/src/helper/rotate-90-deg.d.ts create mode 100644 build/src/helper/timing.d.ts create mode 100644 build/src/helper/to-percent.d.ts create mode 100644 build/src/helper/wait-while-false.d.ts create mode 100644 build/src/helper/wait.d.ts create mode 100644 build/src/main.d.ts create mode 100644 custom.d.ts create mode 100644 package.json create mode 100644 src/game.ts create mode 100644 src/graphics/drawables/i-drawable-descriptor.ts create mode 100644 src/graphics/drawables/i-drawable.ts create mode 100644 src/graphics/drawables/lights/circle-light.ts create mode 100644 src/graphics/drawables/lights/flashlight.ts create mode 100644 src/graphics/drawables/lights/i-light.ts create mode 100644 src/graphics/graphics-library/compiling/check-program.ts create mode 100644 src/graphics/graphics-library/compiling/check-shader.ts create mode 100644 src/graphics/graphics-library/compiling/create-program.ts create mode 100644 src/graphics/graphics-library/compiling/create-shader.ts create mode 100644 src/graphics/graphics-library/frame-buffer/default-frame-buffer.ts create mode 100644 src/graphics/graphics-library/frame-buffer/frame-buffer.ts create mode 100644 src/graphics/graphics-library/frame-buffer/intermediate-frame-buffer.ts create mode 100644 src/graphics/graphics-library/helper/enable-extension.ts create mode 100644 src/graphics/graphics-library/helper/get-webgl2-context.ts create mode 100644 src/graphics/graphics-library/helper/load-uniform.ts create mode 100644 src/graphics/graphics-library/helper/stopwatch.ts create mode 100644 src/graphics/graphics-library/program/fragment-shader-only-program.ts create mode 100644 src/graphics/graphics-library/program/i-program.ts create mode 100644 src/graphics/graphics-library/program/program.ts create mode 100644 src/graphics/graphics-library/program/uniform-array-autoscaling-program.ts create mode 100644 src/graphics/i-renderer.ts create mode 100644 src/graphics/rendering/fps-autoscaler.ts create mode 100644 src/graphics/rendering/rendering-pass.ts create mode 100644 src/graphics/rendering/uniforms-provider.ts create mode 100644 src/graphics/rendering/webgl2-renderer.ts create mode 100644 src/graphics/settings.ts create mode 100644 src/graphics/shaders/distance-fs.glsl create mode 100644 src/graphics/shaders/distance-vs.glsl create mode 100644 src/graphics/shaders/shading-fs.glsl create mode 100644 src/graphics/shaders/shading-vs.glsl create mode 100644 src/helper/array.ts create mode 100644 src/helper/autoscaler.ts create mode 100644 src/helper/clamp.ts create mode 100644 src/helper/exponential-decay.ts create mode 100644 src/helper/get-combinations.ts create mode 100644 src/helper/last.ts create mode 100644 src/helper/mix.ts create mode 100644 src/helper/random.ts create mode 100644 src/helper/rotate-90-deg.ts create mode 100644 src/helper/timing.ts create mode 100644 src/helper/to-percent.ts create mode 100644 src/helper/wait-while-false.ts create mode 100644 src/helper/wait.ts create mode 100644 src/main.ts create mode 100644 tsconfig.json create mode 100644 webpack.config.js diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..2cb7d2a --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +**/*.js diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..8275ed8 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,29 @@ +{ + "root": true, + "env": { + "browser": true, + "es2020": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "prettier", + "prettier/@typescript-eslint" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": 11, + "sourceType": "module" + }, + "plugins": ["unused-imports", "@typescript-eslint", "prettier"], + "rules": { + "prettier/prettier": "error", + "no-unused-vars": "off", + "unused-imports/no-unused-imports-ts": "error", + "@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }], + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/explicit-module-boundary-types": "off", + "@typescript-eslint/no-non-null-assertion": "off" + } +} diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ea544b2 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.psd filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..91a3983 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +dist +node_modules +package-lock.json diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..5aae580 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "trailingComma": "es5", + "printWidth": 90, + "tabWidth": 2, + "singleQuote": true, + "endOfLine": "lf" +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..20b972e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "typescript.tsdk": "node_modules\\typescript\\lib", + "editor.tabSize": 2, + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": true + } +} diff --git a/build/main-bundle.js b/build/main-bundle.js new file mode 100644 index 0000000..87bfcd9 --- /dev/null +++ b/build/main-bundle.js @@ -0,0 +1,7839 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +Object.defineProperty(exports, "__esModule", { value: true }); +var gl_matrix_1 = __webpack_require__(3); +var array_1 = __webpack_require__(1); +var random_1 = __webpack_require__(2); +gl_matrix_1.glMatrix.setMatrixArrayType(Array); +array_1.applyArrayPlugins(); +var main = function () { return __awaiter(void 0, void 0, void 0, function () { + return __generator(this, function (_a) { + try { + random_1.Random.seed = 42; + //await new Game().start(); + } + catch (e) { + console.error(e); + alert(e); + } + return [2 /*return*/]; + }); +}); }; +main(); + + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +exports.applyArrayPlugins = void 0; +exports.applyArrayPlugins = function () { + Object.defineProperty(Array.prototype, 'x', { + get: function () { + return this[0]; + }, + set: function (value) { + this[0] = value; + }, + }); + Object.defineProperty(Array.prototype, 'y', { + get: function () { + return this[1]; + }, + set: function (value) { + this[1] = value; + }, + }); + Object.defineProperty(Float32Array.prototype, 'x', { + get: function () { + return this[0]; + }, + set: function (value) { + this[0] = value; + }, + }); + Object.defineProperty(Float32Array.prototype, 'y', { + get: function () { + return this[1]; + }, + set: function (value) { + this[1] = value; + }, + }); +}; + + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +// src +// https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript +// Mulberry32 +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Random = void 0; +var Random = /** @class */ (function () { + function Random() { + } + Object.defineProperty(Random, "seed", { + set: function (value) { + Random._seed = value; + }, + enumerable: false, + configurable: true + }); + Random.getRandom = function () { + var t = (Random._seed += 0x6d2b79f5); + t = Math.imul(t ^ (t >>> 15), t | 1); + t ^= t + Math.imul(t ^ (t >>> 7), t | 61); + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; + }; + Random._seed = Math.random(); + return Random; +}()); +exports.Random = Random; + + +/***/ }), +/* 3 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +// ESM COMPAT FLAG +__webpack_require__.r(__webpack_exports__); + +// EXPORTS +__webpack_require__.d(__webpack_exports__, "glMatrix", function() { return /* reexport */ common_namespaceObject; }); +__webpack_require__.d(__webpack_exports__, "mat2", function() { return /* reexport */ mat2_namespaceObject; }); +__webpack_require__.d(__webpack_exports__, "mat2d", function() { return /* reexport */ mat2d_namespaceObject; }); +__webpack_require__.d(__webpack_exports__, "mat3", function() { return /* reexport */ mat3_namespaceObject; }); +__webpack_require__.d(__webpack_exports__, "mat4", function() { return /* reexport */ mat4_namespaceObject; }); +__webpack_require__.d(__webpack_exports__, "quat", function() { return /* reexport */ quat_namespaceObject; }); +__webpack_require__.d(__webpack_exports__, "quat2", function() { return /* reexport */ quat2_namespaceObject; }); +__webpack_require__.d(__webpack_exports__, "vec2", function() { return /* reexport */ vec2_namespaceObject; }); +__webpack_require__.d(__webpack_exports__, "vec3", function() { return /* reexport */ vec3_namespaceObject; }); +__webpack_require__.d(__webpack_exports__, "vec4", function() { return /* reexport */ vec4_namespaceObject; }); + +// NAMESPACE OBJECT: ./node_modules/gl-matrix/esm/common.js +var common_namespaceObject = {}; +__webpack_require__.r(common_namespaceObject); +__webpack_require__.d(common_namespaceObject, "EPSILON", function() { return EPSILON; }); +__webpack_require__.d(common_namespaceObject, "ARRAY_TYPE", function() { return ARRAY_TYPE; }); +__webpack_require__.d(common_namespaceObject, "RANDOM", function() { return RANDOM; }); +__webpack_require__.d(common_namespaceObject, "setMatrixArrayType", function() { return setMatrixArrayType; }); +__webpack_require__.d(common_namespaceObject, "toRadian", function() { return toRadian; }); +__webpack_require__.d(common_namespaceObject, "equals", function() { return equals; }); + +// NAMESPACE OBJECT: ./node_modules/gl-matrix/esm/mat2.js +var mat2_namespaceObject = {}; +__webpack_require__.r(mat2_namespaceObject); +__webpack_require__.d(mat2_namespaceObject, "create", function() { return create; }); +__webpack_require__.d(mat2_namespaceObject, "clone", function() { return clone; }); +__webpack_require__.d(mat2_namespaceObject, "copy", function() { return copy; }); +__webpack_require__.d(mat2_namespaceObject, "identity", function() { return identity; }); +__webpack_require__.d(mat2_namespaceObject, "fromValues", function() { return fromValues; }); +__webpack_require__.d(mat2_namespaceObject, "set", function() { return set; }); +__webpack_require__.d(mat2_namespaceObject, "transpose", function() { return transpose; }); +__webpack_require__.d(mat2_namespaceObject, "invert", function() { return invert; }); +__webpack_require__.d(mat2_namespaceObject, "adjoint", function() { return adjoint; }); +__webpack_require__.d(mat2_namespaceObject, "determinant", function() { return determinant; }); +__webpack_require__.d(mat2_namespaceObject, "multiply", function() { return multiply; }); +__webpack_require__.d(mat2_namespaceObject, "rotate", function() { return rotate; }); +__webpack_require__.d(mat2_namespaceObject, "scale", function() { return mat2_scale; }); +__webpack_require__.d(mat2_namespaceObject, "fromRotation", function() { return fromRotation; }); +__webpack_require__.d(mat2_namespaceObject, "fromScaling", function() { return fromScaling; }); +__webpack_require__.d(mat2_namespaceObject, "str", function() { return str; }); +__webpack_require__.d(mat2_namespaceObject, "frob", function() { return frob; }); +__webpack_require__.d(mat2_namespaceObject, "LDU", function() { return LDU; }); +__webpack_require__.d(mat2_namespaceObject, "add", function() { return add; }); +__webpack_require__.d(mat2_namespaceObject, "subtract", function() { return subtract; }); +__webpack_require__.d(mat2_namespaceObject, "exactEquals", function() { return exactEquals; }); +__webpack_require__.d(mat2_namespaceObject, "equals", function() { return mat2_equals; }); +__webpack_require__.d(mat2_namespaceObject, "multiplyScalar", function() { return multiplyScalar; }); +__webpack_require__.d(mat2_namespaceObject, "multiplyScalarAndAdd", function() { return multiplyScalarAndAdd; }); +__webpack_require__.d(mat2_namespaceObject, "mul", function() { return mul; }); +__webpack_require__.d(mat2_namespaceObject, "sub", function() { return sub; }); + +// NAMESPACE OBJECT: ./node_modules/gl-matrix/esm/mat2d.js +var mat2d_namespaceObject = {}; +__webpack_require__.r(mat2d_namespaceObject); +__webpack_require__.d(mat2d_namespaceObject, "create", function() { return mat2d_create; }); +__webpack_require__.d(mat2d_namespaceObject, "clone", function() { return mat2d_clone; }); +__webpack_require__.d(mat2d_namespaceObject, "copy", function() { return mat2d_copy; }); +__webpack_require__.d(mat2d_namespaceObject, "identity", function() { return mat2d_identity; }); +__webpack_require__.d(mat2d_namespaceObject, "fromValues", function() { return mat2d_fromValues; }); +__webpack_require__.d(mat2d_namespaceObject, "set", function() { return mat2d_set; }); +__webpack_require__.d(mat2d_namespaceObject, "invert", function() { return mat2d_invert; }); +__webpack_require__.d(mat2d_namespaceObject, "determinant", function() { return mat2d_determinant; }); +__webpack_require__.d(mat2d_namespaceObject, "multiply", function() { return mat2d_multiply; }); +__webpack_require__.d(mat2d_namespaceObject, "rotate", function() { return mat2d_rotate; }); +__webpack_require__.d(mat2d_namespaceObject, "scale", function() { return mat2d_scale; }); +__webpack_require__.d(mat2d_namespaceObject, "translate", function() { return translate; }); +__webpack_require__.d(mat2d_namespaceObject, "fromRotation", function() { return mat2d_fromRotation; }); +__webpack_require__.d(mat2d_namespaceObject, "fromScaling", function() { return mat2d_fromScaling; }); +__webpack_require__.d(mat2d_namespaceObject, "fromTranslation", function() { return fromTranslation; }); +__webpack_require__.d(mat2d_namespaceObject, "str", function() { return mat2d_str; }); +__webpack_require__.d(mat2d_namespaceObject, "frob", function() { return mat2d_frob; }); +__webpack_require__.d(mat2d_namespaceObject, "add", function() { return mat2d_add; }); +__webpack_require__.d(mat2d_namespaceObject, "subtract", function() { return mat2d_subtract; }); +__webpack_require__.d(mat2d_namespaceObject, "multiplyScalar", function() { return mat2d_multiplyScalar; }); +__webpack_require__.d(mat2d_namespaceObject, "multiplyScalarAndAdd", function() { return mat2d_multiplyScalarAndAdd; }); +__webpack_require__.d(mat2d_namespaceObject, "exactEquals", function() { return mat2d_exactEquals; }); +__webpack_require__.d(mat2d_namespaceObject, "equals", function() { return mat2d_equals; }); +__webpack_require__.d(mat2d_namespaceObject, "mul", function() { return mat2d_mul; }); +__webpack_require__.d(mat2d_namespaceObject, "sub", function() { return mat2d_sub; }); + +// NAMESPACE OBJECT: ./node_modules/gl-matrix/esm/mat3.js +var mat3_namespaceObject = {}; +__webpack_require__.r(mat3_namespaceObject); +__webpack_require__.d(mat3_namespaceObject, "create", function() { return mat3_create; }); +__webpack_require__.d(mat3_namespaceObject, "fromMat4", function() { return fromMat4; }); +__webpack_require__.d(mat3_namespaceObject, "clone", function() { return mat3_clone; }); +__webpack_require__.d(mat3_namespaceObject, "copy", function() { return mat3_copy; }); +__webpack_require__.d(mat3_namespaceObject, "fromValues", function() { return mat3_fromValues; }); +__webpack_require__.d(mat3_namespaceObject, "set", function() { return mat3_set; }); +__webpack_require__.d(mat3_namespaceObject, "identity", function() { return mat3_identity; }); +__webpack_require__.d(mat3_namespaceObject, "transpose", function() { return mat3_transpose; }); +__webpack_require__.d(mat3_namespaceObject, "invert", function() { return mat3_invert; }); +__webpack_require__.d(mat3_namespaceObject, "adjoint", function() { return mat3_adjoint; }); +__webpack_require__.d(mat3_namespaceObject, "determinant", function() { return mat3_determinant; }); +__webpack_require__.d(mat3_namespaceObject, "multiply", function() { return mat3_multiply; }); +__webpack_require__.d(mat3_namespaceObject, "translate", function() { return mat3_translate; }); +__webpack_require__.d(mat3_namespaceObject, "rotate", function() { return mat3_rotate; }); +__webpack_require__.d(mat3_namespaceObject, "scale", function() { return mat3_scale; }); +__webpack_require__.d(mat3_namespaceObject, "fromTranslation", function() { return mat3_fromTranslation; }); +__webpack_require__.d(mat3_namespaceObject, "fromRotation", function() { return mat3_fromRotation; }); +__webpack_require__.d(mat3_namespaceObject, "fromScaling", function() { return mat3_fromScaling; }); +__webpack_require__.d(mat3_namespaceObject, "fromMat2d", function() { return fromMat2d; }); +__webpack_require__.d(mat3_namespaceObject, "fromQuat", function() { return fromQuat; }); +__webpack_require__.d(mat3_namespaceObject, "normalFromMat4", function() { return normalFromMat4; }); +__webpack_require__.d(mat3_namespaceObject, "projection", function() { return projection; }); +__webpack_require__.d(mat3_namespaceObject, "str", function() { return mat3_str; }); +__webpack_require__.d(mat3_namespaceObject, "frob", function() { return mat3_frob; }); +__webpack_require__.d(mat3_namespaceObject, "add", function() { return mat3_add; }); +__webpack_require__.d(mat3_namespaceObject, "subtract", function() { return mat3_subtract; }); +__webpack_require__.d(mat3_namespaceObject, "multiplyScalar", function() { return mat3_multiplyScalar; }); +__webpack_require__.d(mat3_namespaceObject, "multiplyScalarAndAdd", function() { return mat3_multiplyScalarAndAdd; }); +__webpack_require__.d(mat3_namespaceObject, "exactEquals", function() { return mat3_exactEquals; }); +__webpack_require__.d(mat3_namespaceObject, "equals", function() { return mat3_equals; }); +__webpack_require__.d(mat3_namespaceObject, "mul", function() { return mat3_mul; }); +__webpack_require__.d(mat3_namespaceObject, "sub", function() { return mat3_sub; }); + +// NAMESPACE OBJECT: ./node_modules/gl-matrix/esm/mat4.js +var mat4_namespaceObject = {}; +__webpack_require__.r(mat4_namespaceObject); +__webpack_require__.d(mat4_namespaceObject, "create", function() { return mat4_create; }); +__webpack_require__.d(mat4_namespaceObject, "clone", function() { return mat4_clone; }); +__webpack_require__.d(mat4_namespaceObject, "copy", function() { return mat4_copy; }); +__webpack_require__.d(mat4_namespaceObject, "fromValues", function() { return mat4_fromValues; }); +__webpack_require__.d(mat4_namespaceObject, "set", function() { return mat4_set; }); +__webpack_require__.d(mat4_namespaceObject, "identity", function() { return mat4_identity; }); +__webpack_require__.d(mat4_namespaceObject, "transpose", function() { return mat4_transpose; }); +__webpack_require__.d(mat4_namespaceObject, "invert", function() { return mat4_invert; }); +__webpack_require__.d(mat4_namespaceObject, "adjoint", function() { return mat4_adjoint; }); +__webpack_require__.d(mat4_namespaceObject, "determinant", function() { return mat4_determinant; }); +__webpack_require__.d(mat4_namespaceObject, "multiply", function() { return mat4_multiply; }); +__webpack_require__.d(mat4_namespaceObject, "translate", function() { return mat4_translate; }); +__webpack_require__.d(mat4_namespaceObject, "scale", function() { return mat4_scale; }); +__webpack_require__.d(mat4_namespaceObject, "rotate", function() { return mat4_rotate; }); +__webpack_require__.d(mat4_namespaceObject, "rotateX", function() { return rotateX; }); +__webpack_require__.d(mat4_namespaceObject, "rotateY", function() { return rotateY; }); +__webpack_require__.d(mat4_namespaceObject, "rotateZ", function() { return rotateZ; }); +__webpack_require__.d(mat4_namespaceObject, "fromTranslation", function() { return mat4_fromTranslation; }); +__webpack_require__.d(mat4_namespaceObject, "fromScaling", function() { return mat4_fromScaling; }); +__webpack_require__.d(mat4_namespaceObject, "fromRotation", function() { return mat4_fromRotation; }); +__webpack_require__.d(mat4_namespaceObject, "fromXRotation", function() { return fromXRotation; }); +__webpack_require__.d(mat4_namespaceObject, "fromYRotation", function() { return fromYRotation; }); +__webpack_require__.d(mat4_namespaceObject, "fromZRotation", function() { return fromZRotation; }); +__webpack_require__.d(mat4_namespaceObject, "fromRotationTranslation", function() { return fromRotationTranslation; }); +__webpack_require__.d(mat4_namespaceObject, "fromQuat2", function() { return fromQuat2; }); +__webpack_require__.d(mat4_namespaceObject, "getTranslation", function() { return getTranslation; }); +__webpack_require__.d(mat4_namespaceObject, "getScaling", function() { return getScaling; }); +__webpack_require__.d(mat4_namespaceObject, "getRotation", function() { return getRotation; }); +__webpack_require__.d(mat4_namespaceObject, "fromRotationTranslationScale", function() { return fromRotationTranslationScale; }); +__webpack_require__.d(mat4_namespaceObject, "fromRotationTranslationScaleOrigin", function() { return fromRotationTranslationScaleOrigin; }); +__webpack_require__.d(mat4_namespaceObject, "fromQuat", function() { return mat4_fromQuat; }); +__webpack_require__.d(mat4_namespaceObject, "frustum", function() { return frustum; }); +__webpack_require__.d(mat4_namespaceObject, "perspective", function() { return perspective; }); +__webpack_require__.d(mat4_namespaceObject, "perspectiveFromFieldOfView", function() { return perspectiveFromFieldOfView; }); +__webpack_require__.d(mat4_namespaceObject, "ortho", function() { return ortho; }); +__webpack_require__.d(mat4_namespaceObject, "lookAt", function() { return lookAt; }); +__webpack_require__.d(mat4_namespaceObject, "targetTo", function() { return targetTo; }); +__webpack_require__.d(mat4_namespaceObject, "str", function() { return mat4_str; }); +__webpack_require__.d(mat4_namespaceObject, "frob", function() { return mat4_frob; }); +__webpack_require__.d(mat4_namespaceObject, "add", function() { return mat4_add; }); +__webpack_require__.d(mat4_namespaceObject, "subtract", function() { return mat4_subtract; }); +__webpack_require__.d(mat4_namespaceObject, "multiplyScalar", function() { return mat4_multiplyScalar; }); +__webpack_require__.d(mat4_namespaceObject, "multiplyScalarAndAdd", function() { return mat4_multiplyScalarAndAdd; }); +__webpack_require__.d(mat4_namespaceObject, "exactEquals", function() { return mat4_exactEquals; }); +__webpack_require__.d(mat4_namespaceObject, "equals", function() { return mat4_equals; }); +__webpack_require__.d(mat4_namespaceObject, "mul", function() { return mat4_mul; }); +__webpack_require__.d(mat4_namespaceObject, "sub", function() { return mat4_sub; }); + +// NAMESPACE OBJECT: ./node_modules/gl-matrix/esm/vec3.js +var vec3_namespaceObject = {}; +__webpack_require__.r(vec3_namespaceObject); +__webpack_require__.d(vec3_namespaceObject, "create", function() { return vec3_create; }); +__webpack_require__.d(vec3_namespaceObject, "clone", function() { return vec3_clone; }); +__webpack_require__.d(vec3_namespaceObject, "length", function() { return vec3_length; }); +__webpack_require__.d(vec3_namespaceObject, "fromValues", function() { return vec3_fromValues; }); +__webpack_require__.d(vec3_namespaceObject, "copy", function() { return vec3_copy; }); +__webpack_require__.d(vec3_namespaceObject, "set", function() { return vec3_set; }); +__webpack_require__.d(vec3_namespaceObject, "add", function() { return vec3_add; }); +__webpack_require__.d(vec3_namespaceObject, "subtract", function() { return vec3_subtract; }); +__webpack_require__.d(vec3_namespaceObject, "multiply", function() { return vec3_multiply; }); +__webpack_require__.d(vec3_namespaceObject, "divide", function() { return divide; }); +__webpack_require__.d(vec3_namespaceObject, "ceil", function() { return ceil; }); +__webpack_require__.d(vec3_namespaceObject, "floor", function() { return floor; }); +__webpack_require__.d(vec3_namespaceObject, "min", function() { return min; }); +__webpack_require__.d(vec3_namespaceObject, "max", function() { return max; }); +__webpack_require__.d(vec3_namespaceObject, "round", function() { return round; }); +__webpack_require__.d(vec3_namespaceObject, "scale", function() { return vec3_scale; }); +__webpack_require__.d(vec3_namespaceObject, "scaleAndAdd", function() { return scaleAndAdd; }); +__webpack_require__.d(vec3_namespaceObject, "distance", function() { return distance; }); +__webpack_require__.d(vec3_namespaceObject, "squaredDistance", function() { return squaredDistance; }); +__webpack_require__.d(vec3_namespaceObject, "squaredLength", function() { return squaredLength; }); +__webpack_require__.d(vec3_namespaceObject, "negate", function() { return negate; }); +__webpack_require__.d(vec3_namespaceObject, "inverse", function() { return inverse; }); +__webpack_require__.d(vec3_namespaceObject, "normalize", function() { return normalize; }); +__webpack_require__.d(vec3_namespaceObject, "dot", function() { return vec3_dot; }); +__webpack_require__.d(vec3_namespaceObject, "cross", function() { return cross; }); +__webpack_require__.d(vec3_namespaceObject, "lerp", function() { return lerp; }); +__webpack_require__.d(vec3_namespaceObject, "hermite", function() { return hermite; }); +__webpack_require__.d(vec3_namespaceObject, "bezier", function() { return bezier; }); +__webpack_require__.d(vec3_namespaceObject, "random", function() { return random; }); +__webpack_require__.d(vec3_namespaceObject, "transformMat4", function() { return transformMat4; }); +__webpack_require__.d(vec3_namespaceObject, "transformMat3", function() { return transformMat3; }); +__webpack_require__.d(vec3_namespaceObject, "transformQuat", function() { return transformQuat; }); +__webpack_require__.d(vec3_namespaceObject, "rotateX", function() { return vec3_rotateX; }); +__webpack_require__.d(vec3_namespaceObject, "rotateY", function() { return vec3_rotateY; }); +__webpack_require__.d(vec3_namespaceObject, "rotateZ", function() { return vec3_rotateZ; }); +__webpack_require__.d(vec3_namespaceObject, "angle", function() { return angle; }); +__webpack_require__.d(vec3_namespaceObject, "zero", function() { return zero; }); +__webpack_require__.d(vec3_namespaceObject, "str", function() { return vec3_str; }); +__webpack_require__.d(vec3_namespaceObject, "exactEquals", function() { return vec3_exactEquals; }); +__webpack_require__.d(vec3_namespaceObject, "equals", function() { return vec3_equals; }); +__webpack_require__.d(vec3_namespaceObject, "sub", function() { return vec3_sub; }); +__webpack_require__.d(vec3_namespaceObject, "mul", function() { return vec3_mul; }); +__webpack_require__.d(vec3_namespaceObject, "div", function() { return div; }); +__webpack_require__.d(vec3_namespaceObject, "dist", function() { return dist; }); +__webpack_require__.d(vec3_namespaceObject, "sqrDist", function() { return sqrDist; }); +__webpack_require__.d(vec3_namespaceObject, "len", function() { return vec3_len; }); +__webpack_require__.d(vec3_namespaceObject, "sqrLen", function() { return sqrLen; }); +__webpack_require__.d(vec3_namespaceObject, "forEach", function() { return forEach; }); + +// NAMESPACE OBJECT: ./node_modules/gl-matrix/esm/vec4.js +var vec4_namespaceObject = {}; +__webpack_require__.r(vec4_namespaceObject); +__webpack_require__.d(vec4_namespaceObject, "create", function() { return vec4_create; }); +__webpack_require__.d(vec4_namespaceObject, "clone", function() { return vec4_clone; }); +__webpack_require__.d(vec4_namespaceObject, "fromValues", function() { return vec4_fromValues; }); +__webpack_require__.d(vec4_namespaceObject, "copy", function() { return vec4_copy; }); +__webpack_require__.d(vec4_namespaceObject, "set", function() { return vec4_set; }); +__webpack_require__.d(vec4_namespaceObject, "add", function() { return vec4_add; }); +__webpack_require__.d(vec4_namespaceObject, "subtract", function() { return vec4_subtract; }); +__webpack_require__.d(vec4_namespaceObject, "multiply", function() { return vec4_multiply; }); +__webpack_require__.d(vec4_namespaceObject, "divide", function() { return vec4_divide; }); +__webpack_require__.d(vec4_namespaceObject, "ceil", function() { return vec4_ceil; }); +__webpack_require__.d(vec4_namespaceObject, "floor", function() { return vec4_floor; }); +__webpack_require__.d(vec4_namespaceObject, "min", function() { return vec4_min; }); +__webpack_require__.d(vec4_namespaceObject, "max", function() { return vec4_max; }); +__webpack_require__.d(vec4_namespaceObject, "round", function() { return vec4_round; }); +__webpack_require__.d(vec4_namespaceObject, "scale", function() { return vec4_scale; }); +__webpack_require__.d(vec4_namespaceObject, "scaleAndAdd", function() { return vec4_scaleAndAdd; }); +__webpack_require__.d(vec4_namespaceObject, "distance", function() { return vec4_distance; }); +__webpack_require__.d(vec4_namespaceObject, "squaredDistance", function() { return vec4_squaredDistance; }); +__webpack_require__.d(vec4_namespaceObject, "length", function() { return vec4_length; }); +__webpack_require__.d(vec4_namespaceObject, "squaredLength", function() { return vec4_squaredLength; }); +__webpack_require__.d(vec4_namespaceObject, "negate", function() { return vec4_negate; }); +__webpack_require__.d(vec4_namespaceObject, "inverse", function() { return vec4_inverse; }); +__webpack_require__.d(vec4_namespaceObject, "normalize", function() { return vec4_normalize; }); +__webpack_require__.d(vec4_namespaceObject, "dot", function() { return vec4_dot; }); +__webpack_require__.d(vec4_namespaceObject, "cross", function() { return vec4_cross; }); +__webpack_require__.d(vec4_namespaceObject, "lerp", function() { return vec4_lerp; }); +__webpack_require__.d(vec4_namespaceObject, "random", function() { return vec4_random; }); +__webpack_require__.d(vec4_namespaceObject, "transformMat4", function() { return vec4_transformMat4; }); +__webpack_require__.d(vec4_namespaceObject, "transformQuat", function() { return vec4_transformQuat; }); +__webpack_require__.d(vec4_namespaceObject, "zero", function() { return vec4_zero; }); +__webpack_require__.d(vec4_namespaceObject, "str", function() { return vec4_str; }); +__webpack_require__.d(vec4_namespaceObject, "exactEquals", function() { return vec4_exactEquals; }); +__webpack_require__.d(vec4_namespaceObject, "equals", function() { return vec4_equals; }); +__webpack_require__.d(vec4_namespaceObject, "sub", function() { return vec4_sub; }); +__webpack_require__.d(vec4_namespaceObject, "mul", function() { return vec4_mul; }); +__webpack_require__.d(vec4_namespaceObject, "div", function() { return vec4_div; }); +__webpack_require__.d(vec4_namespaceObject, "dist", function() { return vec4_dist; }); +__webpack_require__.d(vec4_namespaceObject, "sqrDist", function() { return vec4_sqrDist; }); +__webpack_require__.d(vec4_namespaceObject, "len", function() { return vec4_len; }); +__webpack_require__.d(vec4_namespaceObject, "sqrLen", function() { return vec4_sqrLen; }); +__webpack_require__.d(vec4_namespaceObject, "forEach", function() { return vec4_forEach; }); + +// NAMESPACE OBJECT: ./node_modules/gl-matrix/esm/quat.js +var quat_namespaceObject = {}; +__webpack_require__.r(quat_namespaceObject); +__webpack_require__.d(quat_namespaceObject, "create", function() { return quat_create; }); +__webpack_require__.d(quat_namespaceObject, "identity", function() { return quat_identity; }); +__webpack_require__.d(quat_namespaceObject, "setAxisAngle", function() { return setAxisAngle; }); +__webpack_require__.d(quat_namespaceObject, "getAxisAngle", function() { return getAxisAngle; }); +__webpack_require__.d(quat_namespaceObject, "getAngle", function() { return getAngle; }); +__webpack_require__.d(quat_namespaceObject, "multiply", function() { return quat_multiply; }); +__webpack_require__.d(quat_namespaceObject, "rotateX", function() { return quat_rotateX; }); +__webpack_require__.d(quat_namespaceObject, "rotateY", function() { return quat_rotateY; }); +__webpack_require__.d(quat_namespaceObject, "rotateZ", function() { return quat_rotateZ; }); +__webpack_require__.d(quat_namespaceObject, "calculateW", function() { return calculateW; }); +__webpack_require__.d(quat_namespaceObject, "exp", function() { return exp; }); +__webpack_require__.d(quat_namespaceObject, "ln", function() { return ln; }); +__webpack_require__.d(quat_namespaceObject, "pow", function() { return pow; }); +__webpack_require__.d(quat_namespaceObject, "slerp", function() { return slerp; }); +__webpack_require__.d(quat_namespaceObject, "random", function() { return quat_random; }); +__webpack_require__.d(quat_namespaceObject, "invert", function() { return quat_invert; }); +__webpack_require__.d(quat_namespaceObject, "conjugate", function() { return conjugate; }); +__webpack_require__.d(quat_namespaceObject, "fromMat3", function() { return fromMat3; }); +__webpack_require__.d(quat_namespaceObject, "fromEuler", function() { return fromEuler; }); +__webpack_require__.d(quat_namespaceObject, "str", function() { return quat_str; }); +__webpack_require__.d(quat_namespaceObject, "clone", function() { return quat_clone; }); +__webpack_require__.d(quat_namespaceObject, "fromValues", function() { return quat_fromValues; }); +__webpack_require__.d(quat_namespaceObject, "copy", function() { return quat_copy; }); +__webpack_require__.d(quat_namespaceObject, "set", function() { return quat_set; }); +__webpack_require__.d(quat_namespaceObject, "add", function() { return quat_add; }); +__webpack_require__.d(quat_namespaceObject, "mul", function() { return quat_mul; }); +__webpack_require__.d(quat_namespaceObject, "scale", function() { return quat_scale; }); +__webpack_require__.d(quat_namespaceObject, "dot", function() { return quat_dot; }); +__webpack_require__.d(quat_namespaceObject, "lerp", function() { return quat_lerp; }); +__webpack_require__.d(quat_namespaceObject, "length", function() { return quat_length; }); +__webpack_require__.d(quat_namespaceObject, "len", function() { return quat_len; }); +__webpack_require__.d(quat_namespaceObject, "squaredLength", function() { return quat_squaredLength; }); +__webpack_require__.d(quat_namespaceObject, "sqrLen", function() { return quat_sqrLen; }); +__webpack_require__.d(quat_namespaceObject, "normalize", function() { return quat_normalize; }); +__webpack_require__.d(quat_namespaceObject, "exactEquals", function() { return quat_exactEquals; }); +__webpack_require__.d(quat_namespaceObject, "equals", function() { return quat_equals; }); +__webpack_require__.d(quat_namespaceObject, "rotationTo", function() { return rotationTo; }); +__webpack_require__.d(quat_namespaceObject, "sqlerp", function() { return sqlerp; }); +__webpack_require__.d(quat_namespaceObject, "setAxes", function() { return setAxes; }); + +// NAMESPACE OBJECT: ./node_modules/gl-matrix/esm/quat2.js +var quat2_namespaceObject = {}; +__webpack_require__.r(quat2_namespaceObject); +__webpack_require__.d(quat2_namespaceObject, "create", function() { return quat2_create; }); +__webpack_require__.d(quat2_namespaceObject, "clone", function() { return quat2_clone; }); +__webpack_require__.d(quat2_namespaceObject, "fromValues", function() { return quat2_fromValues; }); +__webpack_require__.d(quat2_namespaceObject, "fromRotationTranslationValues", function() { return fromRotationTranslationValues; }); +__webpack_require__.d(quat2_namespaceObject, "fromRotationTranslation", function() { return quat2_fromRotationTranslation; }); +__webpack_require__.d(quat2_namespaceObject, "fromTranslation", function() { return quat2_fromTranslation; }); +__webpack_require__.d(quat2_namespaceObject, "fromRotation", function() { return quat2_fromRotation; }); +__webpack_require__.d(quat2_namespaceObject, "fromMat4", function() { return quat2_fromMat4; }); +__webpack_require__.d(quat2_namespaceObject, "copy", function() { return quat2_copy; }); +__webpack_require__.d(quat2_namespaceObject, "identity", function() { return quat2_identity; }); +__webpack_require__.d(quat2_namespaceObject, "set", function() { return quat2_set; }); +__webpack_require__.d(quat2_namespaceObject, "getReal", function() { return getReal; }); +__webpack_require__.d(quat2_namespaceObject, "getDual", function() { return getDual; }); +__webpack_require__.d(quat2_namespaceObject, "setReal", function() { return setReal; }); +__webpack_require__.d(quat2_namespaceObject, "setDual", function() { return setDual; }); +__webpack_require__.d(quat2_namespaceObject, "getTranslation", function() { return quat2_getTranslation; }); +__webpack_require__.d(quat2_namespaceObject, "translate", function() { return quat2_translate; }); +__webpack_require__.d(quat2_namespaceObject, "rotateX", function() { return quat2_rotateX; }); +__webpack_require__.d(quat2_namespaceObject, "rotateY", function() { return quat2_rotateY; }); +__webpack_require__.d(quat2_namespaceObject, "rotateZ", function() { return quat2_rotateZ; }); +__webpack_require__.d(quat2_namespaceObject, "rotateByQuatAppend", function() { return rotateByQuatAppend; }); +__webpack_require__.d(quat2_namespaceObject, "rotateByQuatPrepend", function() { return rotateByQuatPrepend; }); +__webpack_require__.d(quat2_namespaceObject, "rotateAroundAxis", function() { return rotateAroundAxis; }); +__webpack_require__.d(quat2_namespaceObject, "add", function() { return quat2_add; }); +__webpack_require__.d(quat2_namespaceObject, "multiply", function() { return quat2_multiply; }); +__webpack_require__.d(quat2_namespaceObject, "mul", function() { return quat2_mul; }); +__webpack_require__.d(quat2_namespaceObject, "scale", function() { return quat2_scale; }); +__webpack_require__.d(quat2_namespaceObject, "dot", function() { return quat2_dot; }); +__webpack_require__.d(quat2_namespaceObject, "lerp", function() { return quat2_lerp; }); +__webpack_require__.d(quat2_namespaceObject, "invert", function() { return quat2_invert; }); +__webpack_require__.d(quat2_namespaceObject, "conjugate", function() { return quat2_conjugate; }); +__webpack_require__.d(quat2_namespaceObject, "length", function() { return quat2_length; }); +__webpack_require__.d(quat2_namespaceObject, "len", function() { return quat2_len; }); +__webpack_require__.d(quat2_namespaceObject, "squaredLength", function() { return quat2_squaredLength; }); +__webpack_require__.d(quat2_namespaceObject, "sqrLen", function() { return quat2_sqrLen; }); +__webpack_require__.d(quat2_namespaceObject, "normalize", function() { return quat2_normalize; }); +__webpack_require__.d(quat2_namespaceObject, "str", function() { return quat2_str; }); +__webpack_require__.d(quat2_namespaceObject, "exactEquals", function() { return quat2_exactEquals; }); +__webpack_require__.d(quat2_namespaceObject, "equals", function() { return quat2_equals; }); + +// NAMESPACE OBJECT: ./node_modules/gl-matrix/esm/vec2.js +var vec2_namespaceObject = {}; +__webpack_require__.r(vec2_namespaceObject); +__webpack_require__.d(vec2_namespaceObject, "create", function() { return vec2_create; }); +__webpack_require__.d(vec2_namespaceObject, "clone", function() { return vec2_clone; }); +__webpack_require__.d(vec2_namespaceObject, "fromValues", function() { return vec2_fromValues; }); +__webpack_require__.d(vec2_namespaceObject, "copy", function() { return vec2_copy; }); +__webpack_require__.d(vec2_namespaceObject, "set", function() { return vec2_set; }); +__webpack_require__.d(vec2_namespaceObject, "add", function() { return vec2_add; }); +__webpack_require__.d(vec2_namespaceObject, "subtract", function() { return vec2_subtract; }); +__webpack_require__.d(vec2_namespaceObject, "multiply", function() { return vec2_multiply; }); +__webpack_require__.d(vec2_namespaceObject, "divide", function() { return vec2_divide; }); +__webpack_require__.d(vec2_namespaceObject, "ceil", function() { return vec2_ceil; }); +__webpack_require__.d(vec2_namespaceObject, "floor", function() { return vec2_floor; }); +__webpack_require__.d(vec2_namespaceObject, "min", function() { return vec2_min; }); +__webpack_require__.d(vec2_namespaceObject, "max", function() { return vec2_max; }); +__webpack_require__.d(vec2_namespaceObject, "round", function() { return vec2_round; }); +__webpack_require__.d(vec2_namespaceObject, "scale", function() { return vec2_scale; }); +__webpack_require__.d(vec2_namespaceObject, "scaleAndAdd", function() { return vec2_scaleAndAdd; }); +__webpack_require__.d(vec2_namespaceObject, "distance", function() { return vec2_distance; }); +__webpack_require__.d(vec2_namespaceObject, "squaredDistance", function() { return vec2_squaredDistance; }); +__webpack_require__.d(vec2_namespaceObject, "length", function() { return vec2_length; }); +__webpack_require__.d(vec2_namespaceObject, "squaredLength", function() { return vec2_squaredLength; }); +__webpack_require__.d(vec2_namespaceObject, "negate", function() { return vec2_negate; }); +__webpack_require__.d(vec2_namespaceObject, "inverse", function() { return vec2_inverse; }); +__webpack_require__.d(vec2_namespaceObject, "normalize", function() { return vec2_normalize; }); +__webpack_require__.d(vec2_namespaceObject, "dot", function() { return vec2_dot; }); +__webpack_require__.d(vec2_namespaceObject, "cross", function() { return vec2_cross; }); +__webpack_require__.d(vec2_namespaceObject, "lerp", function() { return vec2_lerp; }); +__webpack_require__.d(vec2_namespaceObject, "random", function() { return vec2_random; }); +__webpack_require__.d(vec2_namespaceObject, "transformMat2", function() { return transformMat2; }); +__webpack_require__.d(vec2_namespaceObject, "transformMat2d", function() { return transformMat2d; }); +__webpack_require__.d(vec2_namespaceObject, "transformMat3", function() { return vec2_transformMat3; }); +__webpack_require__.d(vec2_namespaceObject, "transformMat4", function() { return vec2_transformMat4; }); +__webpack_require__.d(vec2_namespaceObject, "rotate", function() { return vec2_rotate; }); +__webpack_require__.d(vec2_namespaceObject, "angle", function() { return vec2_angle; }); +__webpack_require__.d(vec2_namespaceObject, "zero", function() { return vec2_zero; }); +__webpack_require__.d(vec2_namespaceObject, "str", function() { return vec2_str; }); +__webpack_require__.d(vec2_namespaceObject, "exactEquals", function() { return vec2_exactEquals; }); +__webpack_require__.d(vec2_namespaceObject, "equals", function() { return vec2_equals; }); +__webpack_require__.d(vec2_namespaceObject, "len", function() { return vec2_len; }); +__webpack_require__.d(vec2_namespaceObject, "sub", function() { return vec2_sub; }); +__webpack_require__.d(vec2_namespaceObject, "mul", function() { return vec2_mul; }); +__webpack_require__.d(vec2_namespaceObject, "div", function() { return vec2_div; }); +__webpack_require__.d(vec2_namespaceObject, "dist", function() { return vec2_dist; }); +__webpack_require__.d(vec2_namespaceObject, "sqrDist", function() { return vec2_sqrDist; }); +__webpack_require__.d(vec2_namespaceObject, "sqrLen", function() { return vec2_sqrLen; }); +__webpack_require__.d(vec2_namespaceObject, "forEach", function() { return vec2_forEach; }); + +// CONCATENATED MODULE: ./node_modules/gl-matrix/esm/common.js +/** + * 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); +}; +// CONCATENATED MODULE: ./node_modules/gl-matrix/esm/mat2.js + +/** + * 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 mat2_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 mat2_equals(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; +// CONCATENATED MODULE: ./node_modules/gl-matrix/esm/mat2d.js + +/** + * 2x3 Matrix + * @module mat2d + * @description + * A mat2d contains six elements defined as: + *
+ * [a, b,
+ *  c, d,
+ *  tx, ty]
+ * 
+ * This is a short form for the 3x3 matrix: + *
+ * [a, b, 0,
+ *  c, d, 0,
+ *  tx, ty, 1]
+ * 
+ * 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 mat2d_create() { + 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 mat2d_clone(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 mat2d_copy(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 mat2d_identity(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 mat2d_fromValues(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 mat2d_set(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 mat2d_invert(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 mat2d_determinant(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 mat2d_multiply(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 mat2d_rotate(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 mat2d_scale(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 mat2d_fromRotation(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 mat2d_fromScaling(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 mat2d_str(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 mat2d_frob(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 mat2d_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]; + 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 mat2d_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]; + 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 mat2d_multiplyScalar(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 mat2d_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; + 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 mat2d_exactEquals(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 mat2d_equals(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 mat2d_mul = mat2d_multiply; +/** + * Alias for {@link mat2d.subtract} + * @function + */ + +var mat2d_sub = mat2d_subtract; +// CONCATENATED MODULE: ./node_modules/gl-matrix/esm/mat3.js + +/** + * 3x3 Matrix + * @module mat3 + */ + +/** + * Creates a new identity mat3 + * + * @returns {mat3} a new 3x3 matrix + */ + +function mat3_create() { + 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 mat3_clone(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 mat3_copy(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 mat3_fromValues(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 mat3_set(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 mat3_identity(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 mat3_transpose(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 mat3_invert(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 mat3_adjoint(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 mat3_determinant(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 mat3_multiply(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 mat3_translate(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 mat3_rotate(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 mat3_scale(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 mat3_fromTranslation(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 mat3_fromRotation(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 mat3_fromScaling(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 mat3_str(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 mat3_frob(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 mat3_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]; + 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 mat3_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]; + 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 mat3_multiplyScalar(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 mat3_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; + 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 mat3_exactEquals(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 mat3_equals(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 mat3_mul = mat3_multiply; +/** + * Alias for {@link mat3.subtract} + * @function + */ + +var mat3_sub = mat3_subtract; +// CONCATENATED MODULE: ./node_modules/gl-matrix/esm/mat4.js + +/** + * 4x4 Matrix
Format: column-major, when typed out it looks like row-major
The matrices are being post multiplied. + * @module mat4 + */ + +/** + * Creates a new identity mat4 + * + * @returns {mat4} a new 4x4 matrix + */ + +function mat4_create() { + 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 mat4_clone(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 mat4_copy(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 mat4_fromValues(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 mat4_set(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 mat4_identity(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 mat4_transpose(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 mat4_invert(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 mat4_adjoint(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 mat4_determinant(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 mat4_multiply(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 mat4_translate(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 mat4_scale(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 mat4_rotate(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 mat4_fromTranslation(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 mat4_fromScaling(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 mat4_fromRotation(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 mat4_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[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 mat4_identity(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 mat4_str(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 mat4_frob(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 mat4_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]; + 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 mat4_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]; + 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 mat4_multiplyScalar(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 mat4_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; + 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 mat4_exactEquals(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 mat4_equals(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 mat4_mul = mat4_multiply; +/** + * Alias for {@link mat4.subtract} + * @function + */ + +var mat4_sub = mat4_subtract; +// CONCATENATED MODULE: ./node_modules/gl-matrix/esm/vec3.js + +/** + * 3 Dimensional Vector + * @module vec3 + */ + +/** + * Creates a new, empty vec3 + * + * @returns {vec3} a new 3D vector + */ + +function vec3_create() { + 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 vec3_clone(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 vec3_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 vec3_fromValues(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 vec3_copy(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 vec3_set(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 vec3_add(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 vec3_subtract(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 vec3_multiply(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 vec3_scale(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 vec3_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 vec3_rotateX(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 vec3_rotateY(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 vec3_rotateZ(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 && vec3_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 vec3_str(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 vec3_exactEquals(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 vec3_equals(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 vec3_sub = vec3_subtract; +/** + * Alias for {@link vec3.multiply} + * @function + */ + +var vec3_mul = vec3_multiply; +/** + * 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 vec3_len = vec3_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 = vec3_create(); + 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; + }; +}(); +// CONCATENATED MODULE: ./node_modules/gl-matrix/esm/vec4.js + +/** + * 4 Dimensional Vector + * @module vec4 + */ + +/** + * Creates a new, empty vec4 + * + * @returns {vec4} a new 4D vector + */ + +function vec4_create() { + 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 vec4_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; +} +/** + * 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 vec4_fromValues(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 vec4_copy(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 vec4_set(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 vec4_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 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 vec4_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; +} +/** + * 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 vec4_multiply(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 vec4_divide(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 vec4_ceil(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 vec4_floor(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 vec4_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]); + 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 vec4_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]); + 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 vec4_round(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 vec4_scale(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 vec4_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; + 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 vec4_distance(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 vec4_squaredDistance(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 vec4_length(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 vec4_squaredLength(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 vec4_negate(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 vec4_inverse(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 vec4_normalize(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 vec4_dot(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 vec4_cross(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 vec4_lerp(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 vec4_random(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 vec4_transformMat4(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 vec4_transformQuat(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 vec4_zero(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 vec4_str(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 vec4_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 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 vec4_equals(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 vec4_sub = vec4_subtract; +/** + * Alias for {@link vec4.multiply} + * @function + */ + +var vec4_mul = vec4_multiply; +/** + * Alias for {@link vec4.divide} + * @function + */ + +var vec4_div = vec4_divide; +/** + * Alias for {@link vec4.distance} + * @function + */ + +var vec4_dist = vec4_distance; +/** + * Alias for {@link vec4.squaredDistance} + * @function + */ + +var vec4_sqrDist = vec4_squaredDistance; +/** + * Alias for {@link vec4.length} + * @function + */ + +var vec4_len = vec4_length; +/** + * Alias for {@link vec4.squaredLength} + * @function + */ + +var vec4_sqrLen = vec4_squaredLength; +/** + * 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 vec4_forEach = function () { + var vec = vec4_create(); + 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; + }; +}(); +// CONCATENATED MODULE: ./node_modules/gl-matrix/esm/quat.js + + + + +/** + * Quaternion + * @module quat + */ + +/** + * Creates a new identity quat + * + * @returns {quat} a new quaternion + */ + +function quat_create() { + 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 quat_identity(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 = quat_dot(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 quat_multiply(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 quat_rotateX(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 quat_rotateY(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 quat_rotateZ(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); + quat_scale(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 quat_random(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 quat_invert(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 quat_str(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 quat_clone = vec4_clone; +/** + * 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 quat_fromValues = vec4_fromValues; +/** + * 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 quat_copy = vec4_copy; +/** + * 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 quat_set = vec4_set; +/** + * 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 quat_add = vec4_add; +/** + * Alias for {@link quat.multiply} + * @function + */ + +var quat_mul = quat_multiply; +/** + * 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 quat_scale = vec4_scale; +/** + * 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 quat_dot = vec4_dot; +/** + * 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 quat_lerp = vec4_lerp; +/** + * Calculates the length of a quat + * + * @param {ReadonlyQuat} a vector to calculate length of + * @returns {Number} length of a + */ + +var quat_length = vec4_length; +/** + * Alias for {@link quat.length} + * @function + */ + +var quat_len = quat_length; +/** + * Calculates the squared length of a quat + * + * @param {ReadonlyQuat} a vector to calculate squared length of + * @returns {Number} squared length of a + * @function + */ + +var quat_squaredLength = vec4_squaredLength; +/** + * Alias for {@link quat.squaredLength} + * @function + */ + +var quat_sqrLen = quat_squaredLength; +/** + * Normalize a quat + * + * @param {quat} out the receiving quaternion + * @param {ReadonlyQuat} a quaternion to normalize + * @returns {quat} out + * @function + */ + +var quat_normalize = vec4_normalize; +/** + * 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 quat_exactEquals = vec4_exactEquals; +/** + * 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 quat_equals = vec4_equals; +/** + * 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 = vec3_create(); + var xUnitVec3 = vec3_fromValues(1, 0, 0); + var yUnitVec3 = vec3_fromValues(0, 1, 0); + return function (out, a, b) { + var dot = vec3_dot(a, b); + + if (dot < -0.999999) { + cross(tmpvec3, xUnitVec3, a); + if (vec3_len(tmpvec3) < 0.000001) cross(tmpvec3, yUnitVec3, a); + normalize(tmpvec3, tmpvec3); + setAxisAngle(out, tmpvec3, Math.PI); + return out; + } else if (dot > 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; + return quat_normalize(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 = quat_create(); + var temp2 = quat_create(); + 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 = mat3_create(); + 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 quat_normalize(out, fromMat3(out, matr)); + }; +}(); +// CONCATENATED MODULE: ./node_modules/gl-matrix/esm/quat2.js + + + +/** + * Dual Quaternion
+ * Format: [real, dual]
+ * Quaternion format: XYZW
+ * Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.
+ * @module quat2 + */ + +/** + * Creates a new identity dual quat + * + * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation] + */ + +function quat2_create() { + 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 quat2_clone(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 quat2_fromValues(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 quat2_fromRotationTranslation(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 quat2_fromTranslation(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 quat2_fromRotation(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 quat2_fromMat4(out, a) { + //TODO Optimize this + var outer = quat_create(); + getRotation(outer, a); + var t = new ARRAY_TYPE(3); + getTranslation(t, a); + quat2_fromRotationTranslation(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 quat2_copy(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 quat2_identity(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 quat2_set(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 = quat_copy; +/** + * 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 = quat_copy; +/** + * 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 quat2_getTranslation(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 quat2_translate(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 quat2_rotateX(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; + quat_rotateX(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 quat2_rotateY(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; + quat_rotateY(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 quat2_rotateZ(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; + quat_rotateZ(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 quat2_copy(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 quat2_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]; + 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 quat2_multiply(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 quat2_mul = quat2_multiply; +/** + * 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 quat2_scale(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 quat2_dot = quat_dot; +/** + * 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 quat2_lerp(out, a, b, t) { + var mt = 1 - t; + if (quat2_dot(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 quat2_invert(out, a) { + var sqlen = quat2_squaredLength(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 quat2_conjugate(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 quat2_length = quat_length; +/** + * Alias for {@link quat2.length} + * @function + */ + +var quat2_len = quat2_length; +/** + * 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 quat2_squaredLength = quat_squaredLength; +/** + * Alias for {@link quat2.squaredLength} + * @function + */ + +var quat2_sqrLen = quat2_squaredLength; +/** + * Normalize a dual quat + * + * @param {quat2} out the receiving dual quaternion + * @param {ReadonlyQuat2} a dual quaternion to normalize + * @returns {quat2} out + * @function + */ + +function quat2_normalize(out, a) { + var magnitude = quat2_squaredLength(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 quat2_str(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 quat2_exactEquals(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 quat2_equals(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)); +} +// CONCATENATED MODULE: ./node_modules/gl-matrix/esm/vec2.js + +/** + * 2 Dimensional Vector + * @module vec2 + */ + +/** + * Creates a new, empty vec2 + * + * @returns {vec2} a new 2D vector + */ + +function vec2_create() { + 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 vec2_clone(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 vec2_fromValues(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 vec2_copy(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 vec2_set(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 vec2_add(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 vec2_subtract(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 vec2_multiply(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 vec2_divide(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 vec2_ceil(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 vec2_floor(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 vec2_min(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 vec2_max(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 vec2_round(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 vec2_scale(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 vec2_scaleAndAdd(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 vec2_distance(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 vec2_squaredDistance(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 vec2_length(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 vec2_squaredLength(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 vec2_negate(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 vec2_inverse(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 vec2_normalize(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 vec2_dot(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 vec2_cross(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 vec2_lerp(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 vec2_random(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 vec2_transformMat3(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 vec2_transformMat4(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 vec2_rotate(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 vec2_angle(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 vec2_zero(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 vec2_str(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 vec2_exactEquals(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 vec2_equals(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 vec2_len = vec2_length; +/** + * Alias for {@link vec2.subtract} + * @function + */ + +var vec2_sub = vec2_subtract; +/** + * Alias for {@link vec2.multiply} + * @function + */ + +var vec2_mul = vec2_multiply; +/** + * Alias for {@link vec2.divide} + * @function + */ + +var vec2_div = vec2_divide; +/** + * Alias for {@link vec2.distance} + * @function + */ + +var vec2_dist = vec2_distance; +/** + * Alias for {@link vec2.squaredDistance} + * @function + */ + +var vec2_sqrDist = vec2_squaredDistance; +/** + * Alias for {@link vec2.squaredLength} + * @function + */ + +var vec2_sqrLen = vec2_squaredLength; +/** + * 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 vec2_forEach = function () { + var vec = vec2_create(); + 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; + }; +}(); +// CONCATENATED MODULE: ./node_modules/gl-matrix/esm/index.js + + + + + + + + + + + + +/***/ }) +/******/ ]); \ No newline at end of file diff --git a/build/src/game.d.ts b/build/src/game.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/build/src/graphics/drawables/i-drawable-descriptor.d.ts b/build/src/graphics/drawables/i-drawable-descriptor.d.ts new file mode 100644 index 0000000..40cd689 --- /dev/null +++ b/build/src/graphics/drawables/i-drawable-descriptor.d.ts @@ -0,0 +1,7 @@ +import { IDrawable } from './i-drawable'; +export interface IDrawableDescriptor { + uniformName: string; + countMacroName: string; + shaderCombinationSteps: Array; + readonly empty: IDrawable; +} diff --git a/build/src/graphics/drawables/i-drawable.d.ts b/build/src/graphics/drawables/i-drawable.d.ts new file mode 100644 index 0000000..38f68e0 --- /dev/null +++ b/build/src/graphics/drawables/i-drawable.d.ts @@ -0,0 +1,5 @@ +import { vec2, mat2d } from 'gl-matrix'; +export interface IDrawable { + distance(target: vec2): number; + serializeToUniforms(uniforms: any, scale: number, transform: mat2d): void; +} diff --git a/build/src/graphics/drawables/lights/circle-light.d.ts b/build/src/graphics/drawables/lights/circle-light.d.ts new file mode 100644 index 0000000..36334e5 --- /dev/null +++ b/build/src/graphics/drawables/lights/circle-light.d.ts @@ -0,0 +1,14 @@ +import { mat2d, vec2, vec3 } from 'gl-matrix'; +import { IDrawableDescriptor } from '../i-drawable-descriptor'; +import { ILight } from './i-light'; +export declare class CircleLight implements ILight { + center: vec2; + lightDrop: number; + color: vec3; + lightness: number; + static descriptor: IDrawableDescriptor; + constructor(center: vec2, lightDrop: number, color: vec3, lightness: number); + distance(_: vec2): number; + serializeToUniforms(uniforms: any, scale: number, transform: mat2d): void; + get value(): vec3; +} diff --git a/build/src/graphics/drawables/lights/flashlight.d.ts b/build/src/graphics/drawables/lights/flashlight.d.ts new file mode 100644 index 0000000..207a912 --- /dev/null +++ b/build/src/graphics/drawables/lights/flashlight.d.ts @@ -0,0 +1,15 @@ +import { mat2d, vec2, vec3 } from 'gl-matrix'; +import { IDrawableDescriptor } from '../i-drawable-descriptor'; +import { ILight } from './i-light'; +export declare class Flashlight implements ILight { + center: vec2; + direction: vec2; + lightDrop: number; + color: vec3; + lightness: number; + static descriptor: IDrawableDescriptor; + constructor(center: vec2, direction: vec2, lightDrop: number, color: vec3, lightness: number); + distance(_: vec2): number; + serializeToUniforms(uniforms: any, scale: number, transform: mat2d): void; + get value(): vec3; +} diff --git a/build/src/graphics/drawables/lights/i-light.d.ts b/build/src/graphics/drawables/lights/i-light.d.ts new file mode 100644 index 0000000..e02b26e --- /dev/null +++ b/build/src/graphics/drawables/lights/i-light.d.ts @@ -0,0 +1,2 @@ +import { IDrawable } from '../i-drawable'; +export declare type ILight = IDrawable; diff --git a/build/src/graphics/graphics-library/compiling/check-program.d.ts b/build/src/graphics/graphics-library/compiling/check-program.d.ts new file mode 100644 index 0000000..6910afe --- /dev/null +++ b/build/src/graphics/graphics-library/compiling/check-program.d.ts @@ -0,0 +1 @@ +export declare const checkProgram: (gl: WebGL2RenderingContext, program: WebGLProgram) => void; diff --git a/build/src/graphics/graphics-library/compiling/check-shader.d.ts b/build/src/graphics/graphics-library/compiling/check-shader.d.ts new file mode 100644 index 0000000..ce10e31 --- /dev/null +++ b/build/src/graphics/graphics-library/compiling/check-shader.d.ts @@ -0,0 +1 @@ +export declare const checkShader: (gl: WebGL2RenderingContext, shader: WebGLShader) => void; diff --git a/build/src/graphics/graphics-library/compiling/create-program.d.ts b/build/src/graphics/graphics-library/compiling/create-program.d.ts new file mode 100644 index 0000000..26bb6de --- /dev/null +++ b/build/src/graphics/graphics-library/compiling/create-program.d.ts @@ -0,0 +1,3 @@ +export declare const createProgram: (gl: WebGL2RenderingContext, vertexShaderSource: string, fragmentShaderSource: string, substitutions: { + [name: string]: string; +}) => Promise; diff --git a/build/src/graphics/graphics-library/compiling/create-shader.d.ts b/build/src/graphics/graphics-library/compiling/create-shader.d.ts new file mode 100644 index 0000000..1df53b4 --- /dev/null +++ b/build/src/graphics/graphics-library/compiling/create-shader.d.ts @@ -0,0 +1,3 @@ +export declare const createShader: (gl: WebGL2RenderingContext, type: GLenum, source: string, substitutions: { + [name: string]: string; +}) => WebGLShader; diff --git a/build/src/graphics/graphics-library/frame-buffer/default-frame-buffer.d.ts b/build/src/graphics/graphics-library/frame-buffer/default-frame-buffer.d.ts new file mode 100644 index 0000000..e141b7c --- /dev/null +++ b/build/src/graphics/graphics-library/frame-buffer/default-frame-buffer.d.ts @@ -0,0 +1,5 @@ +import { FrameBuffer } from './frame-buffer'; +export declare class DefaultFrameBuffer extends FrameBuffer { + constructor(gl: WebGL2RenderingContext); + setSize(): boolean; +} diff --git a/build/src/graphics/graphics-library/frame-buffer/frame-buffer.d.ts b/build/src/graphics/graphics-library/frame-buffer/frame-buffer.d.ts new file mode 100644 index 0000000..a38d9ec --- /dev/null +++ b/build/src/graphics/graphics-library/frame-buffer/frame-buffer.d.ts @@ -0,0 +1,12 @@ +import { vec2 } from 'gl-matrix'; +export declare abstract class FrameBuffer { + protected gl: WebGL2RenderingContext; + renderScale: number; + enableHighDpiRendering: boolean; + protected size: vec2; + protected frameBuffer: WebGLFramebuffer | null; + constructor(gl: WebGL2RenderingContext); + bindAndClear(colorInput?: WebGLTexture): void; + setSize(): boolean; + getSize(): vec2; +} diff --git a/build/src/graphics/graphics-library/frame-buffer/intermediate-frame-buffer.d.ts b/build/src/graphics/graphics-library/frame-buffer/intermediate-frame-buffer.d.ts new file mode 100644 index 0000000..bb0bc9a --- /dev/null +++ b/build/src/graphics/graphics-library/frame-buffer/intermediate-frame-buffer.d.ts @@ -0,0 +1,10 @@ +import { FrameBuffer } from './frame-buffer'; +export declare class IntermediateFrameBuffer extends FrameBuffer { + private frameTexture; + private floatLinearEnabled; + constructor(gl: WebGL2RenderingContext); + get colorTexture(): WebGLTexture; + setSize(): boolean; + private configureTexture; + private configureFrameBuffer; +} diff --git a/build/src/graphics/graphics-library/helper/enable-extension.d.ts b/build/src/graphics/graphics-library/helper/enable-extension.d.ts new file mode 100644 index 0000000..e93bbcb --- /dev/null +++ b/build/src/graphics/graphics-library/helper/enable-extension.d.ts @@ -0,0 +1,2 @@ +export declare const tryEnableExtension: (gl: WebGL2RenderingContext, name: string) => any | null; +export declare const enableExtension: (gl: WebGL2RenderingContext, name: string) => any; diff --git a/build/src/graphics/graphics-library/helper/get-webgl2-context.d.ts b/build/src/graphics/graphics-library/helper/get-webgl2-context.d.ts new file mode 100644 index 0000000..4445785 --- /dev/null +++ b/build/src/graphics/graphics-library/helper/get-webgl2-context.d.ts @@ -0,0 +1 @@ +export declare const getWebGl2Context: (canvas: HTMLCanvasElement) => WebGL2RenderingContext; diff --git a/build/src/graphics/graphics-library/helper/load-uniform.d.ts b/build/src/graphics/graphics-library/helper/load-uniform.d.ts new file mode 100644 index 0000000..6d95b8b --- /dev/null +++ b/build/src/graphics/graphics-library/helper/load-uniform.d.ts @@ -0,0 +1 @@ +export declare const loadUniform: (gl: WebGL2RenderingContext, value: any, type: GLenum, location: WebGLUniformLocation) => any; diff --git a/build/src/graphics/graphics-library/helper/stopwatch.d.ts b/build/src/graphics/graphics-library/helper/stopwatch.d.ts new file mode 100644 index 0000000..b38f168 --- /dev/null +++ b/build/src/graphics/graphics-library/helper/stopwatch.d.ts @@ -0,0 +1,11 @@ +export declare class WebGlStopwatch { + private gl; + private timerExtension; + private timerQuery?; + private isReady; + private resultsInNanoSeconds?; + constructor(gl: WebGL2RenderingContext); + start(): void; + stop(): void; + get resultsInMilliSeconds(): number; +} diff --git a/build/src/graphics/graphics-library/program/fragment-shader-only-program.d.ts b/build/src/graphics/graphics-library/program/fragment-shader-only-program.d.ts new file mode 100644 index 0000000..063a641 --- /dev/null +++ b/build/src/graphics/graphics-library/program/fragment-shader-only-program.d.ts @@ -0,0 +1,11 @@ +import Program from './program'; +export declare class FragmentShaderOnlyProgram extends Program { + private vao?; + constructor(gl: WebGL2RenderingContext, sources: [string, string], substitutions: { + [name: string]: string; + }); + initialize(): Promise; + bind(): void; + draw(): void; + private prepareScreenQuad; +} diff --git a/build/src/graphics/graphics-library/program/i-program.d.ts b/build/src/graphics/graphics-library/program/i-program.d.ts new file mode 100644 index 0000000..98b35bc --- /dev/null +++ b/build/src/graphics/graphics-library/program/i-program.d.ts @@ -0,0 +1,10 @@ +import { vec2 } from 'gl-matrix'; +export interface IProgram { + initialize(): Promise; + setDrawingRectangleUV(bottomLeft: vec2, size: vec2): void; + bindAndSetUniforms(values: { + [name: string]: any; + }): void; + draw(): void; + delete(): void; +} diff --git a/build/src/graphics/graphics-library/program/program.d.ts b/build/src/graphics/graphics-library/program/program.d.ts new file mode 100644 index 0000000..9dbc707 --- /dev/null +++ b/build/src/graphics/graphics-library/program/program.d.ts @@ -0,0 +1,25 @@ +import { vec2 } from 'gl-matrix'; +import { IProgram } from './i-program'; +export default abstract class Program implements IProgram { + protected gl: WebGL2RenderingContext; + protected program?: WebGLProgram; + private programPromise; + private modelTransform; + private readonly ndcToUv; + private uniforms; + constructor(gl: WebGL2RenderingContext, [vertexShaderSource, fragmentShaderSource]: [string, string], substitutions: { + [name: string]: string; + }); + initialize(): Promise; + bindAndSetUniforms(values: { + [name: string]: any; + }): void; + setDrawingRectangleUV(bottomLeft: vec2, size: vec2): void; + setUniforms(values: { + [name: string]: any; + }): void; + delete(): void; + abstract draw(): void; + protected bind(): void; + private queryUniforms; +} diff --git a/build/src/graphics/graphics-library/program/uniform-array-autoscaling-program.d.ts b/build/src/graphics/graphics-library/program/uniform-array-autoscaling-program.d.ts new file mode 100644 index 0000000..c4183e6 --- /dev/null +++ b/build/src/graphics/graphics-library/program/uniform-array-autoscaling-program.d.ts @@ -0,0 +1,20 @@ +import { vec2 } from 'gl-matrix'; +import { IDrawableDescriptor } from '../../drawables/i-drawable-descriptor'; +import { IProgram } from './i-program'; +export declare class UniformArrayAutoScalingProgram implements IProgram { + private gl; + private descriptors; + private programs; + private current?; + private drawingRectangleBottomLeft; + private drawingRectangleSize; + constructor(gl: WebGL2RenderingContext, shaderSources: [string, string], descriptors: Array); + initialize(): Promise; + bindAndSetUniforms(uniforms: { + [name: string]: any; + }): void; + setDrawingRectangleUV(bottomLeft: vec2, size: vec2): void; + draw(): void; + delete(): void; + private createProgram; +} diff --git a/build/src/graphics/i-renderer.d.ts b/build/src/graphics/i-renderer.d.ts new file mode 100644 index 0000000..4b8e99d --- /dev/null +++ b/build/src/graphics/i-renderer.d.ts @@ -0,0 +1,14 @@ +import { vec2 } from 'gl-matrix'; +import { IDrawable } from './drawables/i-drawable'; +import { ILight } from './drawables/lights/i-light'; +export interface IRenderer { + initialize(): Promise; + startFrame(deltaTime: DOMHighResTimeStamp): void; + finishFrame(): void; + drawShape(drawable: IDrawable): void; + drawLight(light: ILight): void; + drawInfoText(text: string): void; + readonly canvasSize: vec2; + setViewArea(topLeft: vec2, size: vec2): void; + setCursorPosition(position: vec2): void; +} diff --git a/build/src/graphics/rendering/fps-autoscaler.d.ts b/build/src/graphics/rendering/fps-autoscaler.d.ts new file mode 100644 index 0000000..f8cd3c6 --- /dev/null +++ b/build/src/graphics/rendering/fps-autoscaler.d.ts @@ -0,0 +1,9 @@ +import { Autoscaler as AutoScaler } from '../../helper/autoscaler'; +export declare class FpsAutoscaler extends AutoScaler { + private timeSinceLastAdjusment; + private exponentialDecayedDeltaTime; + constructor(setters: { + [key: string]: (value: number | boolean) => void; + }); + autoscale(lastDeltaTime: DOMHighResTimeStamp): void; +} diff --git a/build/src/graphics/rendering/rendering-pass.d.ts b/build/src/graphics/rendering/rendering-pass.d.ts new file mode 100644 index 0000000..25572e2 --- /dev/null +++ b/build/src/graphics/rendering/rendering-pass.d.ts @@ -0,0 +1,12 @@ +import { IDrawable } from '../drawables/i-drawable'; +import { IDrawableDescriptor } from '../drawables/i-drawable-descriptor'; +import { FrameBuffer } from '../graphics-library/frame-buffer/frame-buffer'; +export declare class RenderingPass { + private frame; + private drawables; + private program; + constructor(gl: WebGL2RenderingContext, shaderSources: [string, string], drawableDescriptors: Array, frame: FrameBuffer); + initialize(): Promise; + addDrawable(drawable: IDrawable): void; + render(commonUniforms: any, inputTexture?: WebGLTexture): void; +} diff --git a/build/src/graphics/rendering/uniforms-provider.d.ts b/build/src/graphics/rendering/uniforms-provider.d.ts new file mode 100644 index 0000000..df60f91 --- /dev/null +++ b/build/src/graphics/rendering/uniforms-provider.d.ts @@ -0,0 +1,18 @@ +import { vec2 } from 'gl-matrix'; +export declare class UniformsProvider { + private gl; + private scaleWorldLengthToNDC; + private transformWorldToNDC; + private viewAreaBottomLeft; + private worldAreaInView; + private squareToAspectRatio; + private uvToWorld; + private cursorPosition; + softShadowsEnabled?: boolean; + constructor(gl: WebGL2RenderingContext); + getUniforms(uniforms: any): any; + private getScreenToWorldTransform; + uvToWorldCoordinate(screenUvPosition: vec2): vec2; + setViewArea(topLeft: vec2, size: vec2): void; + setCursorPosition(position: vec2): void; +} diff --git a/build/src/graphics/rendering/webgl2-renderer.d.ts b/build/src/graphics/rendering/webgl2-renderer.d.ts new file mode 100644 index 0000000..20fd0ac --- /dev/null +++ b/build/src/graphics/rendering/webgl2-renderer.d.ts @@ -0,0 +1,27 @@ +import { vec2 } from 'gl-matrix'; +import { IDrawable } from '../drawables/i-drawable'; +import { ILight } from '../drawables/lights/i-light'; +import { IRenderer } from '../i-renderer'; +export declare class WebGl2Renderer implements IRenderer { + private canvas; + private overlay; + private gl; + private stopwatch?; + private uniformsProvider; + private distanceFieldFrameBuffer; + private lightingFrameBuffer; + private distancePass; + private lightingPass; + private autoscaler; + private initializePromise; + constructor(canvas: HTMLCanvasElement, overlay: HTMLElement); + initialize(): Promise; + drawShape(shape: IDrawable): void; + drawLight(light: ILight): void; + startFrame(deltaTime: DOMHighResTimeStamp): void; + finishFrame(): void; + setViewArea(topLeft: vec2, size: vec2): void; + setCursorPosition(position: vec2): void; + get canvasSize(): vec2; + drawInfoText(text: string): void; +} diff --git a/build/src/graphics/settings.d.ts b/build/src/graphics/settings.d.ts new file mode 100644 index 0000000..627e766 --- /dev/null +++ b/build/src/graphics/settings.d.ts @@ -0,0 +1,27 @@ +export declare const settings: { + enableHighDpiRendering: boolean; + qualityScaling: { + targetDeltaTimeInMilliseconds: number; + deltaTimeError: number; + deltaTimeResponsiveness: number; + adjusmentRateInMilliseconds: number; + qualityTargets: { + distanceRenderScale: number; + finalRenderScale: number; + softShadowsEnabled: boolean; + }[]; + startingTargetIndex: number; + scalingOptions: { + additiveIncrease: number; + multiplicativeDecrease: number; + }; + }; + tileMultiplier: number; + shaderMacros: {}; + shaderCombinations: { + lineSteps: number[]; + blobSteps: number[]; + circleLightSteps: number[]; + flashlightSteps: number[]; + }; +}; diff --git a/build/src/helper/array.d.ts b/build/src/helper/array.d.ts new file mode 100644 index 0000000..9c81fa9 --- /dev/null +++ b/build/src/helper/array.d.ts @@ -0,0 +1,11 @@ +declare global { + interface Array { + x: number; + y: number; + } + interface Float32Array { + x: number; + y: number; + } +} +export declare const applyArrayPlugins: () => void; diff --git a/build/src/helper/autoscaler.d.ts b/build/src/helper/autoscaler.d.ts new file mode 100644 index 0000000..20e5b03 --- /dev/null +++ b/build/src/helper/autoscaler.d.ts @@ -0,0 +1,17 @@ +export declare class Autoscaler { + private setters; + private targets; + private scalingOptions; + private index; + constructor(setters: { + [key: string]: (value: number | boolean) => void; + }, targets: Array<{ + [key: string]: number | boolean; + }>, startingIndex: number, scalingOptions: { + additiveIncrease: number; + multiplicativeDecrease: number; + }); + increase(): void; + decrease(): void; + private applyScaling; +} diff --git a/build/src/helper/clamp.d.ts b/build/src/helper/clamp.d.ts new file mode 100644 index 0000000..3b42d74 --- /dev/null +++ b/build/src/helper/clamp.d.ts @@ -0,0 +1,2 @@ +export declare const clamp: (value: number, min: number, max: number) => number; +export declare const clamp01: (value: number) => number; diff --git a/build/src/helper/exponential-decay.d.ts b/build/src/helper/exponential-decay.d.ts new file mode 100644 index 0000000..35388e7 --- /dev/null +++ b/build/src/helper/exponential-decay.d.ts @@ -0,0 +1 @@ +export declare const exponentialDecay: (accumulator: number, nextValue: number, biasOfNextValue: number) => number; diff --git a/build/src/helper/get-combinations.d.ts b/build/src/helper/get-combinations.d.ts new file mode 100644 index 0000000..f2b5ccc --- /dev/null +++ b/build/src/helper/get-combinations.d.ts @@ -0,0 +1 @@ +export declare const getCombinations: (values: Array>) => Array>; diff --git a/build/src/helper/last.d.ts b/build/src/helper/last.d.ts new file mode 100644 index 0000000..d5ce3b6 --- /dev/null +++ b/build/src/helper/last.d.ts @@ -0,0 +1 @@ +export declare function last(a: Array): T | null; diff --git a/build/src/helper/mix.d.ts b/build/src/helper/mix.d.ts new file mode 100644 index 0000000..956a58c --- /dev/null +++ b/build/src/helper/mix.d.ts @@ -0,0 +1 @@ +export declare const mix: (from: number, to: number, q: number) => number; diff --git a/build/src/helper/random.d.ts b/build/src/helper/random.d.ts new file mode 100644 index 0000000..33c85cf --- /dev/null +++ b/build/src/helper/random.d.ts @@ -0,0 +1,5 @@ +export declare abstract class Random { + private static _seed; + static set seed(value: number); + static getRandom(): number; +} diff --git a/build/src/helper/rotate-90-deg.d.ts b/build/src/helper/rotate-90-deg.d.ts new file mode 100644 index 0000000..6d20946 --- /dev/null +++ b/build/src/helper/rotate-90-deg.d.ts @@ -0,0 +1,2 @@ +import { vec2 } from 'gl-matrix'; +export declare const rotate90Deg: (vec: vec2) => vec2; diff --git a/build/src/helper/timing.d.ts b/build/src/helper/timing.d.ts new file mode 100644 index 0000000..89c666a --- /dev/null +++ b/build/src/helper/timing.d.ts @@ -0,0 +1 @@ +export declare function timeIt(interval?: number): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => PropertyDescriptor; diff --git a/build/src/helper/to-percent.d.ts b/build/src/helper/to-percent.d.ts new file mode 100644 index 0000000..3bba54a --- /dev/null +++ b/build/src/helper/to-percent.d.ts @@ -0,0 +1 @@ +export declare const toPercent: (value: number) => string; diff --git a/build/src/helper/wait-while-false.d.ts b/build/src/helper/wait-while-false.d.ts new file mode 100644 index 0000000..605b1cd --- /dev/null +++ b/build/src/helper/wait-while-false.d.ts @@ -0,0 +1 @@ +export declare const waitWhileFalse: (body: () => boolean) => Promise; diff --git a/build/src/helper/wait.d.ts b/build/src/helper/wait.d.ts new file mode 100644 index 0000000..433e4ca --- /dev/null +++ b/build/src/helper/wait.d.ts @@ -0,0 +1 @@ +export declare const wait: (ms: number) => Promise; diff --git a/build/src/main.d.ts b/build/src/main.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/build/src/main.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/custom.d.ts b/custom.d.ts new file mode 100644 index 0000000..7c29b64 --- /dev/null +++ b/custom.d.ts @@ -0,0 +1,24 @@ +declare module '*.glsl' { + const content: string; + export default content; +} + +/* +declare module '*.png' { + import { ResponsiveImage } from 'src/framework/model/misc'; + const content: ResponsiveImage; + export default content; +} + +declare module '*.jpg' { + import { ResponsiveImage } from 'src/framework/model/misc'; + const content: ResponsiveImage; + export default content; +} + +declare module '*.jpeg' { + import { ResponsiveImage } from 'src/framework/model/misc'; + const content: ResponsiveImage; + export default content; +} +*/ diff --git a/package.json b/package.json new file mode 100644 index 0000000..c666fdb --- /dev/null +++ b/package.json @@ -0,0 +1,50 @@ +{ + "name": "sdf-2d-gl", + "version": "0.0.0", + "scripts": { + "start": "webpack-dev-server --mode development", + "lint": "npx eslint --fix \"src/**/*.ts\" && npx prettier --write \"src/**/*.ts\"", + "build": "webpack && find dist -type f -not -name '*.html' | xargs rm" + }, + "keywords": [], + "author": "András Schmelczer", + "postcss": { + "plugins": { + "autoprefixer": {} + } + }, + "browserslist": [ + "defaults" + ], + "sideEffects": [ + "*.scss" + ], + "main": "./dist/sdf-2d-gl.js", + "types": "./dist/sdf-2d-gl.d.ts", + "files": [ + "dist" + ], + "optimization": { + "usedExports": true + }, + "devDependencies": { + "@types/gl-matrix": "^2.4.5", + "@typescript-eslint/eslint-plugin": "^3.9.1", + "@typescript-eslint/parser": "^3.9.1", + "eslint": "^7.2.0", + "eslint-config-prettier": "^6.11.0", + "eslint-plugin-import": "^2.21.2", + "eslint-plugin-prettier": "^3.1.4", + "eslint-plugin-unused-imports": "^0.1.3", + "gl-matrix": "^3.3.0", + "prettier": "^2.0.5", + "raw-loader": "^4.0.1", + "resolve-url-loader": "^3.1.1", + "terser-webpack-plugin": "^2.3.5", + "ts-loader": "^8.0.1", + "typescript": "^3.8.3", + "webpack": "^4.43.0", + "webpack-cli": "^3.3.12", + "webpack-dev-server": "^3.10.3" + } +} diff --git a/src/game.ts b/src/game.ts new file mode 100644 index 0000000..656b40d --- /dev/null +++ b/src/game.ts @@ -0,0 +1,121 @@ +/* +export class Game implements IGame { + public readonly objects = new Objects(); + public readonly physics = new Physics(); + public readonly camera = new Camera(); + private previousTime?: DOMHighResTimeStamp = null; + private previousFpsValues: Array = []; + private infoText = new InfoText(); + private character: Character; + private renderer: IRenderer; + private initializeRendererPromise: Promise; + + constructor() { + const canvas: HTMLCanvasElement = document.querySelector('canvas#main'); + const overlay: HTMLElement = document.querySelector('#overlay'); + + document.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this)); + + new CommandBroadcaster( + [ + new KeyboardListener(document.body), + new MouseListener(canvas), + new TouchListener(canvas), + ], + [this.objects] + ); + + this.renderer = new WebGl2Renderer(canvas, overlay); + this.initializeRendererPromise = this.renderer.initialize(); + this.initializeScene(); + this.physics.start(); + } + + public async start(): Promise { + await this.initializeRendererPromise; + requestAnimationFrame(this.gameLoop.bind(this)); + } + + public addObject(o: GameObject) { + this.objects.addObject(o); + } + + public get viewArea(): BoundingBoxBase { + return this.camera.viewArea; + } + + public findIntersecting(box: BoundingBoxBase): Array { + return this.physics.findIntersecting(box); + } + + private initializeScene() { + this.objects.addObject(this.infoText); + + const start = createDungeon(this.objects, this.physics); + createDungeon(this.objects, this.physics); + + this.character = new Character(this); + // this.physics.addDynamicBoundingBox(this.character.boundingBox); + this.addObject(this.character); + this.addObject(this.camera); + let pos: any = localStorage.getItem('character-position'); + pos = pos ? JSON.parse(pos) : start.from; + this.character.sendCommand(new TeleportToCommand(pos)); + } + + private handleVisibilityChange() { + if (!document.hidden) { + this.previousTime = null; + } + } + + @timeIt() + private gameLoop(time: DOMHighResTimeStamp) { + if (this.previousTime === null) { + this.previousTime = time; + } + + const deltaTime = time - this.previousTime; + this.previousTime = time; + this.calculateFps(deltaTime); + + this.objects.sendCommand(new StepCommand(deltaTime)); + this.camera.sendCommand(new MoveToCommand(this.character.position)); + + this.renderer.startFrame(deltaTime); + + this.camera.sendCommand(new BeforeRenderCommand(this.renderer)); + + const shouldBeDrawn = this.physics + .findIntersecting(this.camera.viewArea) + .map((b) => b.shape?.gameObject); + + for (const object of shouldBeDrawn) { + object?.sendCommand(new BeforeRenderCommand(this.renderer)); + object?.sendCommand(new RenderCommand(this.renderer)); + } + + this.character.sendCommand(new RenderCommand(this.renderer)); + this.infoText.sendCommand(new RenderCommand(this.renderer)); + this.renderer.finishFrame(); + + localStorage.setItem('character-position', JSON.stringify(this.character.position)); + window.requestAnimationFrame(this.gameLoop.bind(this)); + } + + private calculateFps(deltaTime: number) { + this.previousFpsValues.push(1000 / deltaTime); + if (this.previousFpsValues.length > 30) { + this.previousFpsValues.sort(); + const min = this.previousFpsValues[0]; + const median = this.previousFpsValues[ + Math.floor(this.previousFpsValues.length / 2) + ]; + + InfoText.modifyRecord('FPS', { min, median }); + + this.previousFpsValues = []; + } + } +} +*/ diff --git a/src/graphics/drawables/i-drawable-descriptor.ts b/src/graphics/drawables/i-drawable-descriptor.ts new file mode 100644 index 0000000..5e669bf --- /dev/null +++ b/src/graphics/drawables/i-drawable-descriptor.ts @@ -0,0 +1,8 @@ +import { IDrawable } from './i-drawable'; + +export interface IDrawableDescriptor { + uniformName: string; + countMacroName: string; + shaderCombinationSteps: Array; + readonly empty: IDrawable; +} diff --git a/src/graphics/drawables/i-drawable.ts b/src/graphics/drawables/i-drawable.ts new file mode 100644 index 0000000..cca827b --- /dev/null +++ b/src/graphics/drawables/i-drawable.ts @@ -0,0 +1,6 @@ +import { vec2, mat2d } from 'gl-matrix'; + +export interface IDrawable { + distance(target: vec2): number; + serializeToUniforms(uniforms: any, scale: number, transform: mat2d): void; +} diff --git a/src/graphics/drawables/lights/circle-light.ts b/src/graphics/drawables/lights/circle-light.ts new file mode 100644 index 0000000..8bf7001 --- /dev/null +++ b/src/graphics/drawables/lights/circle-light.ts @@ -0,0 +1,46 @@ +import { mat2d, vec2, vec3 } from 'gl-matrix'; +import { settings } from '../../settings'; +import { IDrawableDescriptor } from '../i-drawable-descriptor'; +import { ILight } from './i-light'; + +export class CircleLight implements ILight { + public static descriptor: IDrawableDescriptor = { + uniformName: 'circleLights', + countMacroName: 'circleLightCount', + shaderCombinationSteps: settings.shaderCombinations.circleLightSteps, + empty: new CircleLight(vec2.fromValues(0, 0), 0, vec3.fromValues(0, 0, 0), 0), + }; + + constructor( + public center: vec2, + public lightDrop: number, + public color: vec3, + public lightness: number + ) {} + + public distance(_: vec2): number { + return 0; + } + + public serializeToUniforms(uniforms: any, scale: number, transform: mat2d): void { + const { uniformName } = CircleLight.descriptor; + + if (!Object.prototype.hasOwnProperty.call(uniforms, uniformName)) { + uniforms[uniformName] = []; + } + + uniforms[uniformName].push({ + center: vec2.transformMat2d(vec2.create(), this.center, transform), + lightDrop: this.lightDrop, + value: this.value, + }); + } + + public get value(): vec3 { + return vec3.scale( + vec3.create(), + vec3.normalize(this.color, this.color), + this.lightness + ); + } +} diff --git a/src/graphics/drawables/lights/flashlight.ts b/src/graphics/drawables/lights/flashlight.ts new file mode 100644 index 0000000..180b464 --- /dev/null +++ b/src/graphics/drawables/lights/flashlight.ts @@ -0,0 +1,50 @@ +import { mat2d, vec2, vec3 } from 'gl-matrix'; +import { settings } from '../../settings'; +import { IDrawableDescriptor } from '../i-drawable-descriptor'; +import { ILight } from './i-light'; + +export class Flashlight implements ILight { + public static descriptor: IDrawableDescriptor = { + uniformName: 'flashlights', + countMacroName: 'flashlightCount', + shaderCombinationSteps: settings.shaderCombinations.flashlightSteps, + empty: new Flashlight( + vec2.fromValues(0, 0), + vec2.fromValues(0, 0), + 0, + vec3.fromValues(0, 0, 0), + 0 + ), + }; + + public constructor( + public center: vec2, + public direction: vec2, + public lightDrop: number, + public color: vec3, + public lightness: number + ) {} + + public distance(_: vec2): number { + return 0; + } + + public serializeToUniforms(uniforms: any, scale: number, transform: mat2d): void { + const listName = Flashlight.descriptor.uniformName; + + if (!Object.prototype.hasOwnProperty.call(uniforms, listName)) { + uniforms[listName] = []; + } + + uniforms[listName].push({ + center: vec2.transformMat2d(vec2.create(), this.center, transform), + direction: this.direction, + lightDrop: this.lightDrop, + value: this.value, + }); + } + + public get value(): vec3 { + return vec3.scale(vec3.create(), this.color, this.lightness); + } +} diff --git a/src/graphics/drawables/lights/i-light.ts b/src/graphics/drawables/lights/i-light.ts new file mode 100644 index 0000000..59e4431 --- /dev/null +++ b/src/graphics/drawables/lights/i-light.ts @@ -0,0 +1,3 @@ +import { IDrawable } from '../i-drawable'; + +export type ILight = IDrawable; diff --git a/src/graphics/graphics-library/compiling/check-program.ts b/src/graphics/graphics-library/compiling/check-program.ts new file mode 100644 index 0000000..03491fe --- /dev/null +++ b/src/graphics/graphics-library/compiling/check-program.ts @@ -0,0 +1,13 @@ +import { checkShader } from './check-shader'; + +export const checkProgram = (gl: WebGL2RenderingContext, program: WebGLProgram) => { + const success = gl.getProgramParameter(program, gl.LINK_STATUS); + + if (!success) { + gl.getAttachedShaders(program)?.forEach((s) => { + checkShader(gl, s); + }); + + throw new Error(gl.getProgramInfoLog(program)!); + } +}; diff --git a/src/graphics/graphics-library/compiling/check-shader.ts b/src/graphics/graphics-library/compiling/check-shader.ts new file mode 100644 index 0000000..cc7ff32 --- /dev/null +++ b/src/graphics/graphics-library/compiling/check-shader.ts @@ -0,0 +1,7 @@ +export const checkShader = (gl: WebGL2RenderingContext, shader: WebGLShader) => { + const success = gl.getShaderParameter(shader, gl.COMPILE_STATUS); + + if (!success) { + throw new Error(gl.getShaderInfoLog(shader)!); + } +}; diff --git a/src/graphics/graphics-library/compiling/create-program.ts b/src/graphics/graphics-library/compiling/create-program.ts new file mode 100644 index 0000000..e1f94ea --- /dev/null +++ b/src/graphics/graphics-library/compiling/create-program.ts @@ -0,0 +1,48 @@ +import { waitWhileFalse } from '../../../helper/wait-while-false'; +import { tryEnableExtension } from '../helper/enable-extension'; +import { checkProgram } from './check-program'; +import { createShader } from './create-shader'; + +export const createProgram = async ( + gl: WebGL2RenderingContext, + vertexShaderSource: string, + fragmentShaderSource: string, + substitutions: { [name: string]: string } +): Promise => { + const program = gl.createProgram(); + + if (!program) { + throw new Error('Could not create program'); + } + + const extension = tryEnableExtension(gl, 'KHR_parallel_shader_compile'); + + const vertexShader = createShader( + gl, + gl.VERTEX_SHADER, + vertexShaderSource, + substitutions + ); + gl.attachShader(program, vertexShader); + + const fragmentShader = createShader( + gl, + gl.FRAGMENT_SHADER, + fragmentShaderSource, + substitutions + ); + gl.attachShader(program, fragmentShader); + + gl.linkProgram(program); + + if (extension) { + const checkCompileStatus = () => + gl.getProgramParameter(program, extension.COMPLETION_STATUS_KHR); + + await waitWhileFalse(checkCompileStatus); + } + + checkProgram(gl, program); + + return program; +}; diff --git a/src/graphics/graphics-library/compiling/create-shader.ts b/src/graphics/graphics-library/compiling/create-shader.ts new file mode 100644 index 0000000..fab7ec8 --- /dev/null +++ b/src/graphics/graphics-library/compiling/create-shader.ts @@ -0,0 +1,22 @@ +export const createShader = ( + gl: WebGL2RenderingContext, + type: GLenum, + source: string, + substitutions: { [name: string]: string } +): WebGLShader => { + source = source.replace(/{(.+)}/gm, (_, name: string): string => { + const value = substitutions[name]; + return Number.isInteger(value) ? `${value}.0` : value; + }); + + const shader = gl.createShader(type); + + if (!shader) { + throw new Error('Could not create shader'); + } + + gl.shaderSource(shader, source); + gl.compileShader(shader); + + return shader; +}; diff --git a/src/graphics/graphics-library/frame-buffer/default-frame-buffer.ts b/src/graphics/graphics-library/frame-buffer/default-frame-buffer.ts new file mode 100644 index 0000000..be495ad --- /dev/null +++ b/src/graphics/graphics-library/frame-buffer/default-frame-buffer.ts @@ -0,0 +1,19 @@ +import { FrameBuffer } from './frame-buffer'; + +export class DefaultFrameBuffer extends FrameBuffer { + constructor(gl: WebGL2RenderingContext) { + super(gl); + this.frameBuffer = null; + this.setSize(); + } + + public setSize(): boolean { + const hasChanged = super.setSize(); + if (hasChanged) { + this.gl.canvas.width = this.size.x; + this.gl.canvas.height = this.size.y; + } + + return hasChanged; + } +} diff --git a/src/graphics/graphics-library/frame-buffer/frame-buffer.ts b/src/graphics/graphics-library/frame-buffer/frame-buffer.ts new file mode 100644 index 0000000..c56f707 --- /dev/null +++ b/src/graphics/graphics-library/frame-buffer/frame-buffer.ts @@ -0,0 +1,46 @@ +import { vec2 } from 'gl-matrix'; +import { settings } from '../../settings'; + +export abstract class FrameBuffer { + public renderScale = 1; + public enableHighDpiRendering = settings.enableHighDpiRendering; + + protected size = vec2.create(); + + // null means the default framebuffer + protected frameBuffer: WebGLFramebuffer | null = null; + + constructor(protected gl: WebGL2RenderingContext) {} + + public bindAndClear(colorInput?: WebGLTexture) { + this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.frameBuffer); + + if (colorInput) { + this.gl.bindTexture(this.gl.TEXTURE_2D, colorInput); + } + + this.gl.viewport(0, 0, this.size.x, this.size.y); + this.gl.clearColor(0, 0, 0, 0); + this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT); + } + + public setSize(): boolean { + const realToCssPixels = + (this.enableHighDpiRendering ? window.devicePixelRatio : 1) * this.renderScale; + + const canvasWidth = (this.gl.canvas as HTMLCanvasElement).clientWidth; + const canvasHeight = (this.gl.canvas as HTMLCanvasElement).clientHeight; + + const displayWidth = Math.floor(canvasWidth * realToCssPixels); + const displayHeight = Math.floor(canvasHeight * realToCssPixels); + + const oldSize = vec2.clone(this.getSize()); + this.size = vec2.fromValues(displayWidth, displayHeight); + + return this.size.x != oldSize.x || this.size.y != oldSize.y; + } + + public getSize(): vec2 { + return this.size; + } +} diff --git a/src/graphics/graphics-library/frame-buffer/intermediate-frame-buffer.ts b/src/graphics/graphics-library/frame-buffer/intermediate-frame-buffer.ts new file mode 100644 index 0000000..e16ec57 --- /dev/null +++ b/src/graphics/graphics-library/frame-buffer/intermediate-frame-buffer.ts @@ -0,0 +1,97 @@ +import { enableExtension } from '../helper/enable-extension'; +import { FrameBuffer } from './frame-buffer'; + +export class IntermediateFrameBuffer extends FrameBuffer { + private frameTexture: WebGLTexture; + private floatLinearEnabled = false; + + constructor(gl: WebGL2RenderingContext) { + super(gl); + + enableExtension(gl, 'EXT_color_buffer_float'); + + try { + enableExtension(gl, 'OES_texture_float_linear'); + this.floatLinearEnabled = true; + } catch { + // it's okay + } + + const texture = this.gl.createTexture(); + if (!texture) { + throw new Error('Could not create texture'); + } + this.frameTexture = texture; + this.configureTexture(); + + const frameBuffer = this.gl.createFramebuffer(); + if (!frameBuffer) { + throw new Error('Could not create frame buffer'); + } + this.frameBuffer = frameBuffer; + this.configureFrameBuffer(); + + this.setSize(); + } + + public get colorTexture(): WebGLTexture { + return this.frameTexture; + } + + public setSize(): boolean { + const hasChanged = super.setSize(); + if (hasChanged) { + this.gl.bindTexture(this.gl.TEXTURE_2D, this.frameTexture); + + this.gl.texImage2D( + this.gl.TEXTURE_2D, + 0, + this.gl.RG16F, + this.size.x, + this.size.y, + 0, + this.gl.RG, + this.gl.FLOAT, + null + ); + } + + return hasChanged; + } + + private configureTexture() { + this.gl.bindTexture(this.gl.TEXTURE_2D, this.frameTexture); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_MAG_FILTER, + this.floatLinearEnabled ? this.gl.LINEAR : this.gl.NEAREST + ); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_MIN_FILTER, + this.floatLinearEnabled ? this.gl.LINEAR : this.gl.NEAREST + ); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_WRAP_S, + this.gl.CLAMP_TO_EDGE + ); + this.gl.texParameteri( + this.gl.TEXTURE_2D, + this.gl.TEXTURE_WRAP_T, + this.gl.CLAMP_TO_EDGE + ); + } + + private configureFrameBuffer() { + this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, this.frameBuffer); + const attachmentPoint = this.gl.COLOR_ATTACHMENT0; + this.gl.framebufferTexture2D( + this.gl.FRAMEBUFFER, + attachmentPoint, + this.gl.TEXTURE_2D, + this.frameTexture, + 0 + ); + } +} diff --git a/src/graphics/graphics-library/helper/enable-extension.ts b/src/graphics/graphics-library/helper/enable-extension.ts new file mode 100644 index 0000000..0ad5aa5 --- /dev/null +++ b/src/graphics/graphics-library/helper/enable-extension.ts @@ -0,0 +1,39 @@ +const extensions: Map = new Map(); + +const printExtensions = () => { + const values = {}; + for (const [k, v] of extensions.entries()) { + values[k] = v !== null; + } + //InfoText.modifyRecord('extensions', values); +}; + +export const tryEnableExtension = ( + gl: WebGL2RenderingContext, + name: string +): any | null => { + if (extensions.has(name)) { + return extensions.get(name); + } + + let extension = null; + if (gl.getSupportedExtensions()!.indexOf(name) != -1) { + extension = gl.getExtension(name); + } + + extensions.set(name, extension); + + printExtensions(); + + return extension; +}; + +export const enableExtension = (gl: WebGL2RenderingContext, name: string): any => { + const extension = tryEnableExtension(gl, name); + + if (extension === null) { + throw new Error(`Unsupported extension ${name}`); + } + + return extension; +}; diff --git a/src/graphics/graphics-library/helper/get-webgl2-context.ts b/src/graphics/graphics-library/helper/get-webgl2-context.ts new file mode 100644 index 0000000..30abe93 --- /dev/null +++ b/src/graphics/graphics-library/helper/get-webgl2-context.ts @@ -0,0 +1,9 @@ +export const getWebGl2Context = (canvas: HTMLCanvasElement): WebGL2RenderingContext => { + const gl = canvas.getContext('webgl2'); + + if (!gl) { + throw new Error('WebGl2 is not supported'); + } + + return gl; +}; diff --git a/src/graphics/graphics-library/helper/load-uniform.ts b/src/graphics/graphics-library/helper/load-uniform.ts new file mode 100644 index 0000000..2b00015 --- /dev/null +++ b/src/graphics/graphics-library/helper/load-uniform.ts @@ -0,0 +1,82 @@ +import { mat3, ReadonlyVec3, vec2, vec3 } from 'gl-matrix'; + +const loaderMat3 = mat3.create(); + +export const loadUniform = ( + gl: WebGL2RenderingContext, + value: any, + type: GLenum, + location: WebGLUniformLocation +): any => { + const converters: Map< + GLenum, + (gl: WebGL2RenderingContext, value: any, location: WebGLUniformLocation) => void + > = new Map(); + { + converters.set(WebGL2RenderingContext.FLOAT, (gl, v, l) => { + if (v instanceof Array) { + if (v.length == 0) { + return; + } + + gl.uniform1fv(l, new Float32Array(v)); + } else { + gl.uniform1f(l, v); + } + }); + + converters.set(WebGL2RenderingContext.FLOAT_VEC2, (gl, v: vec2 | Array, l) => { + if (v.length == 0) { + return; + } + + if (v[0] instanceof Array) { + const result = new Float32Array(v.length * 2); + + for (let i = 0; i < v.length; i++) { + result[2 * i] = (v[i] as Array).x; + result[2 * i + 1] = (v[i] as Array).y; + } + + gl.uniform2fv(l, result); + } else { + gl.uniform2fv(l, v as vec2); + } + }); + + converters.set( + WebGL2RenderingContext.FLOAT_VEC3, + (gl, v: ReadonlyVec3 | Array, l) => { + if (v.length == 0) { + return; + } + + if (v[0] instanceof Array) { + const result = new Float32Array(v.length * 3); + + for (let i = 0; i < v.length; i++) { + result[3 * i] = (v[i] as Array)[0]; + result[3 * i + 1] = (v[i] as Array)[1]; + result[3 * i + 2] = (v[i] as Array)[2]; + } + + gl.uniform3fv(l, result); + } else { + gl.uniform3fv(l, v as vec3); + } + } + ); + + converters.set(WebGL2RenderingContext.FLOAT_MAT3, (gl, v, l) => { + gl.uniformMatrix3fv(l, true, mat3.fromMat2d(loaderMat3, v)); + }); + + converters.set(WebGL2RenderingContext.BOOL, (gl, v, l) => gl.uniform1i(l, v)); + + if (!converters.has(type)) { + throw new Error(`Unimplemented webgl type: ${type}`); + } + + converters.get(type)!(gl, value, location); + } +}; diff --git a/src/graphics/graphics-library/helper/stopwatch.ts b/src/graphics/graphics-library/helper/stopwatch.ts new file mode 100644 index 0000000..4e324b4 --- /dev/null +++ b/src/graphics/graphics-library/helper/stopwatch.ts @@ -0,0 +1,49 @@ +import { enableExtension } from './enable-extension'; + +// https://www.khronos.org/registry/webgl/extensions/EXT_disjoint_timer_query_webgl2/ + +export class WebGlStopwatch { + private timerExtension: any; + private timerQuery?: WebGLQuery; + private isReady = true; + private resultsInNanoSeconds?: number; + + constructor(private gl: WebGL2RenderingContext) { + this.timerExtension = enableExtension(gl, 'EXT_disjoint_timer_query_webgl2'); + } + + public start() { + if (this.isReady) { + this.timerQuery = this.gl.createQuery()!; + this.gl.beginQuery(this.timerExtension.TIME_ELAPSED_EXT, this.timerQuery); + } + } + + public stop() { + if (this.isReady) { + this.gl.endQuery(this.timerExtension.TIME_ELAPSED_EXT); + this.isReady = false; + } + + const available = this.gl.getQueryParameter( + this.timerQuery!, + this.gl.QUERY_RESULT_AVAILABLE + ); + const disjoint = this.gl.getParameter(this.timerExtension.GPU_DISJOINT_EXT); + + if (available && !disjoint) { + this.resultsInNanoSeconds = this.gl.getQueryParameter( + this.timerQuery!, + this.gl.QUERY_RESULT + ); + + //InfoText.modifyRecord('Draw time', `${this.resultsInMilliSeconds.toFixed(2)} ms`); + + this.isReady = true; + } + } + + public get resultsInMilliSeconds(): number { + return this.resultsInNanoSeconds! / 1000 / 1000; + } +} diff --git a/src/graphics/graphics-library/program/fragment-shader-only-program.ts b/src/graphics/graphics-library/program/fragment-shader-only-program.ts new file mode 100644 index 0000000..4c68de4 --- /dev/null +++ b/src/graphics/graphics-library/program/fragment-shader-only-program.ts @@ -0,0 +1,52 @@ +import Program from './program'; + +export class FragmentShaderOnlyProgram extends Program { + private vao?: WebGLVertexArrayObject; + + constructor( + gl: WebGL2RenderingContext, + sources: [string, string], + substitutions: { [name: string]: string } + ) { + super(gl, sources, substitutions); + } + + public async initialize(): Promise { + await super.initialize(); + this.prepareScreenQuad('vertexPosition'); + } + + public bind() { + super.bind(); + this.gl.bindVertexArray(this.vao!); + } + + public draw() { + this.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4); + } + + private prepareScreenQuad(attributeName: string) { + const positionAttributeLocation = this.gl.getAttribLocation( + this.program!, + attributeName + ); + + const positionBuffer = this.gl.createBuffer(); + + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, positionBuffer); + this.gl.bufferData( + this.gl.ARRAY_BUFFER, + new Float32Array([-1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0]), + this.gl.STATIC_DRAW + ); + const vao = this.gl.createVertexArray(); + if (!vao) { + throw new Error('Could not create vertex array object'); + } + this.vao = vao; + + this.gl.bindVertexArray(this.vao); + this.gl.enableVertexAttribArray(positionAttributeLocation); + this.gl.vertexAttribPointer(positionAttributeLocation, 2, this.gl.FLOAT, false, 0, 0); + } +} diff --git a/src/graphics/graphics-library/program/i-program.ts b/src/graphics/graphics-library/program/i-program.ts new file mode 100644 index 0000000..901c327 --- /dev/null +++ b/src/graphics/graphics-library/program/i-program.ts @@ -0,0 +1,9 @@ +import { vec2 } from 'gl-matrix'; + +export interface IProgram { + initialize(): Promise; + setDrawingRectangleUV(bottomLeft: vec2, size: vec2): void; + bindAndSetUniforms(values: { [name: string]: any }): void; + draw(): void; + delete(): void; +} diff --git a/src/graphics/graphics-library/program/program.ts b/src/graphics/graphics-library/program/program.ts new file mode 100644 index 0000000..05c77e2 --- /dev/null +++ b/src/graphics/graphics-library/program/program.ts @@ -0,0 +1,102 @@ +import { mat2d, vec2 } from 'gl-matrix'; +import { settings } from '../../settings'; +import { createProgram } from '../compiling/create-program'; +import { loadUniform } from '../helper/load-uniform'; +import { IProgram } from './i-program'; + +export default abstract class Program implements IProgram { + protected program?: WebGLProgram; + + private programPromise: Promise; + private modelTransform = mat2d.identity(mat2d.create()); + private readonly ndcToUv = mat2d.fromValues(0.5, 0, 0, 0.5, 0.5, 0.5); + private uniforms: Array<{ + name: Array; + location: WebGLUniformLocation; + type: GLenum; + }> = []; + + constructor( + protected gl: WebGL2RenderingContext, + [vertexShaderSource, fragmentShaderSource]: [string, string], + substitutions: { [name: string]: string } + ) { + substitutions = { ...settings.shaderMacros, ...substitutions }; + + this.programPromise = createProgram( + this.gl, + vertexShaderSource, + fragmentShaderSource, + substitutions + ); + } + + public async initialize(): Promise { + this.program = await this.programPromise; + this.queryUniforms(); + } + + public bindAndSetUniforms(values: { [name: string]: any }) { + this.bind(); + this.setUniforms({ modelTransform: this.modelTransform, ...values }); + } + + public setDrawingRectangleUV(bottomLeft: vec2, size: vec2) { + mat2d.invert(this.modelTransform, this.ndcToUv); + mat2d.translate(this.modelTransform, this.modelTransform, bottomLeft); + mat2d.scale(this.modelTransform, this.modelTransform, size); + mat2d.multiply(this.modelTransform, this.modelTransform, this.ndcToUv); + } + + public setUniforms(values: { [name: string]: any }) { + this.uniforms.forEach(({ name, location, type }) => { + const value = name.reduce( + (prev, prop) => (prev !== null && prop in prev ? prev[prop] : null), + values + ); + + if (value !== null) { + loadUniform(this.gl, value, type, location); + } + }); + } + + public delete() { + this.gl.getAttachedShaders(this.program!)?.forEach((s) => this.gl.deleteShader(s)); + this.gl.deleteProgram(this.program!); + } + + public abstract draw(): void; + + protected bind() { + this.gl.useProgram(this.program!); + } + + private queryUniforms() { + const uniformCount = this.gl.getProgramParameter( + this.program!, + WebGL2RenderingContext.ACTIVE_UNIFORMS + ); + + for (let i = 0; i < uniformCount; i++) { + const glUniform = this.gl.getActiveUniform(this.program!, i)!; + + this.uniforms.push({ + name: glUniform.name.split(/\[|\]\.|\]|\./).filter((p) => p !== ''), + location: this.gl.getUniformLocation(this.program!, glUniform.name)!, + type: glUniform.type, + }); + } + + this.uniforms.map((u1) => { + const isSingle = + this.uniforms.filter((u2) => u2.name.includes(u1.name[0])).length == 1; + + if (u1.name.includes('0') && isSingle) { + u1.name = u1.name.slice(0, -1); + } + + return u1; + }); + } +} diff --git a/src/graphics/graphics-library/program/uniform-array-autoscaling-program.ts b/src/graphics/graphics-library/program/uniform-array-autoscaling-program.ts new file mode 100644 index 0000000..b1d2d99 --- /dev/null +++ b/src/graphics/graphics-library/program/uniform-array-autoscaling-program.ts @@ -0,0 +1,94 @@ +import { mat2d, vec2 } from 'gl-matrix'; +import { getCombinations } from '../../../helper/get-combinations'; +import { last } from '../../../helper/last'; +import { IDrawableDescriptor } from '../../drawables/i-drawable-descriptor'; +import { FragmentShaderOnlyProgram } from './fragment-shader-only-program'; +import { IProgram } from './i-program'; + +export class UniformArrayAutoScalingProgram implements IProgram { + private programs: Array<{ + program: FragmentShaderOnlyProgram; + values: Array; + }> = []; + + private current?: FragmentShaderOnlyProgram; + private drawingRectangleBottomLeft = vec2.fromValues(0, 0); + private drawingRectangleSize = vec2.fromValues(1, 1); + + constructor( + private gl: WebGL2RenderingContext, + shaderSources: [string, string], + private descriptors: Array + ) { + const names = descriptors.map((o) => o.countMacroName); + for (const combination of getCombinations( + descriptors.map((o) => o.shaderCombinationSteps) + )) { + this.createProgram(names, combination, shaderSources); + } + } + + public async initialize(): Promise { + await Promise.all(this.programs.map((p) => p.program.initialize())); + } + + public bindAndSetUniforms(uniforms: { [name: string]: any }): void { + const values = this.descriptors.map((d) => + uniforms[d.uniformName] ? uniforms[d.uniformName].length : 0 + ); + + const closest = this.programs.find((p) => p.values.every((v, i) => v >= values[i])); + + this.current = closest ? closest.program : last(this.programs)?.program; + + if (closest) { + this.descriptors.map((d, i) => { + const difference = closest.values[i] - values[i]; + for (let i = 0; i < difference; i++) { + d.empty.serializeToUniforms(uniforms, 0, mat2d.create()); + } + }); + } + + this.current?.setDrawingRectangleUV( + this.drawingRectangleBottomLeft, + this.drawingRectangleSize + ); + this.current?.bindAndSetUniforms(uniforms); + } + + public setDrawingRectangleUV(bottomLeft: vec2, size: vec2) { + this.drawingRectangleBottomLeft = bottomLeft; + this.drawingRectangleSize = size; + } + + public draw(): void { + if (!this.current) { + throw new Error('Method bindAndSetUniforms have not been called yet'); + } + + this.current.draw(); + } + + public delete(): void { + this.programs.forEach((p) => p.program.delete()); + } + + private createProgram( + names: Array, + combination: Array, + shaderSources: [string, string] + ): FragmentShaderOnlyProgram { + const substitutions = {}; + names.forEach((v, i) => (substitutions[v] = combination[i].toString())); + + const program = new FragmentShaderOnlyProgram(this.gl, shaderSources, substitutions); + + this.programs.push({ + program, + values: combination, + }); + + return program; + } +} diff --git a/src/graphics/i-renderer.ts b/src/graphics/i-renderer.ts new file mode 100644 index 0000000..6bacd1a --- /dev/null +++ b/src/graphics/i-renderer.ts @@ -0,0 +1,18 @@ +import { vec2 } from 'gl-matrix'; +import { IDrawable } from './drawables/i-drawable'; +import { ILight } from './drawables/lights/i-light'; + +export interface IRenderer { + initialize(): Promise; + + startFrame(deltaTime: DOMHighResTimeStamp): void; + finishFrame(): void; + + drawShape(drawable: IDrawable): void; + drawLight(light: ILight): void; + drawInfoText(text: string): void; + + readonly canvasSize: vec2; + setViewArea(topLeft: vec2, size: vec2): void; + setCursorPosition(position: vec2): void; +} diff --git a/src/graphics/rendering/fps-autoscaler.ts b/src/graphics/rendering/fps-autoscaler.ts new file mode 100644 index 0000000..528cadf --- /dev/null +++ b/src/graphics/rendering/fps-autoscaler.ts @@ -0,0 +1,45 @@ +import { Autoscaler as AutoScaler } from '../../helper/autoscaler'; +import { exponentialDecay } from '../../helper/exponential-decay'; +import { settings } from '../settings'; + +export class FpsAutoscaler extends AutoScaler { + private timeSinceLastAdjusment = 0; + private exponentialDecayedDeltaTime = 0.0; + + constructor(setters: { [key: string]: (value: number | boolean) => void }) { + super( + setters, + settings.qualityScaling.qualityTargets, + settings.qualityScaling.startingTargetIndex, + settings.qualityScaling.scalingOptions + ); + } + + public autoscale(lastDeltaTime: DOMHighResTimeStamp) { + this.timeSinceLastAdjusment += lastDeltaTime; + if ( + this.timeSinceLastAdjusment >= settings.qualityScaling.adjusmentRateInMilliseconds + ) { + this.timeSinceLastAdjusment = 0; + this.exponentialDecayedDeltaTime = exponentialDecay( + this.exponentialDecayedDeltaTime, + lastDeltaTime, + settings.qualityScaling.deltaTimeResponsiveness + ); + + if ( + this.exponentialDecayedDeltaTime <= + settings.qualityScaling.targetDeltaTimeInMilliseconds - + settings.qualityScaling.deltaTimeError + ) { + this.increase(); + } else if ( + this.exponentialDecayedDeltaTime > + settings.qualityScaling.targetDeltaTimeInMilliseconds + + settings.qualityScaling.deltaTimeError + ) { + this.decrease(); + } + } + } +} diff --git a/src/graphics/rendering/rendering-pass.ts b/src/graphics/rendering/rendering-pass.ts new file mode 100644 index 0000000..54c2a14 --- /dev/null +++ b/src/graphics/rendering/rendering-pass.ts @@ -0,0 +1,86 @@ +import { vec2 } from 'gl-matrix'; +import { IDrawable } from '../drawables/i-drawable'; +import { IDrawableDescriptor } from '../drawables/i-drawable-descriptor'; +import { FrameBuffer } from '../graphics-library/frame-buffer/frame-buffer'; +import { UniformArrayAutoScalingProgram } from '../graphics-library/program/uniform-array-autoscaling-program'; +import { settings } from '../settings'; + +export class RenderingPass { + private drawables: Array = []; + private program: UniformArrayAutoScalingProgram; + + constructor( + gl: WebGL2RenderingContext, + shaderSources: [string, string], + drawableDescriptors: Array, + private frame: FrameBuffer + ) { + this.program = new UniformArrayAutoScalingProgram( + gl, + shaderSources, + drawableDescriptors + ); + } + + public async initialize(): Promise { + await this.program.initialize(); + } + + public addDrawable(drawable: IDrawable) { + this.drawables.push(drawable); + } + + public render(commonUniforms: any, inputTexture?: WebGLTexture) { + this.frame.bindAndClear(inputTexture); + + const stepsInUV = 1 / settings.tileMultiplier; + + const worldR = + 0.5 * + vec2.length(vec2.scale(vec2.create(), commonUniforms.worldAreaInView, stepsInUV)); + + const radiusInNDC = worldR * commonUniforms.scaleWorldLengthToNDC; + + const stepsInNDC = 2 * stepsInUV; + + for (let x = -1; x < 1; x += stepsInNDC) { + for (let y = -1; y < 1; y += stepsInNDC) { + const uniforms = { ...commonUniforms, maxMinDistance: 0.0 }; + + const ndcBottomLeft = vec2.fromValues(x, y); + + this.program.setDrawingRectangleUV( + [(ndcBottomLeft.x + 1) / 2, (ndcBottomLeft.y + 1) / 2], + vec2.fromValues(stepsInUV, stepsInUV) + ); + + const tileCenterWorldCoordinates = vec2.transformMat2d( + vec2.create(), + vec2.add( + vec2.create(), + [(ndcBottomLeft.x + 1) / 2, (ndcBottomLeft.y + 1) / 2], + vec2.fromValues(stepsInUV / 2, stepsInUV / 2) + ), + uniforms.uvToWorld + ); + + const primitivesNearTile = this.drawables.filter( + (d) => d.distance(tileCenterWorldCoordinates) < 2 * worldR + ); + + primitivesNearTile.forEach((p) => + p.serializeToUniforms( + uniforms, + uniforms.scaleWorldLengthToNDC, + uniforms.transformWorldToNDC + ) + ); + + this.program.bindAndSetUniforms(uniforms); + this.program.draw(); + } + } + + this.drawables = []; + } +} diff --git a/src/graphics/rendering/uniforms-provider.ts b/src/graphics/rendering/uniforms-provider.ts new file mode 100644 index 0000000..eaf7501 --- /dev/null +++ b/src/graphics/rendering/uniforms-provider.ts @@ -0,0 +1,94 @@ +import { mat2d, vec2 } from 'gl-matrix'; + +export class UniformsProvider { + private scaleWorldLengthToNDC = 1; + private transformWorldToNDC = mat2d.create(); + + private viewAreaBottomLeft = vec2.create(); + private worldAreaInView = vec2.create(); + private squareToAspectRatio = vec2.create(); + private uvToWorld = mat2d.create(); + private cursorPosition = vec2.create(); + + public softShadowsEnabled?: boolean; + + public constructor(private gl: WebGL2RenderingContext) {} + + public getUniforms(uniforms: any): any { + const cursorPosition = this.uvToWorldCoordinate(this.cursorPosition); + return { + ...uniforms, + cursorPosition, + uvToWorld: this.uvToWorld, + worldAreaInView: this.worldAreaInView, + squareToAspectRatio: this.squareToAspectRatio, + scaleWorldLengthToNDC: this.scaleWorldLengthToNDC, + transformWorldToNDC: this.transformWorldToNDC, + squareToAspectRatioTimes2: vec2.scale(vec2.create(), this.squareToAspectRatio, 2), + softShadowsEnabled: this.softShadowsEnabled, + }; + } + + private getScreenToWorldTransform(screenSize: vec2) { + const transform = mat2d.fromTranslation(mat2d.create(), this.viewAreaBottomLeft); + mat2d.scale( + transform, + transform, + vec2.divide(vec2.create(), this.worldAreaInView, screenSize) + ); + mat2d.translate(transform, transform, vec2.fromValues(0.5, 0.5)); + + return transform; + } + + public uvToWorldCoordinate(screenUvPosition: vec2): vec2 { + const resolution = vec2.fromValues(this.gl.canvas.width, this.gl.canvas.height); + + return vec2.transformMat2d( + vec2.create(), + vec2.multiply(vec2.create(), screenUvPosition, resolution), + this.getScreenToWorldTransform(resolution) + ); + } + + public setViewArea(topLeft: vec2, size: vec2) { + this.worldAreaInView = size; + + // world coordinates + this.viewAreaBottomLeft = vec2.add( + vec2.create(), + topLeft, + vec2.fromValues(0, -size.y) + ); + + const scaleLongerEdgeTo1 = + 1 / Math.max(this.worldAreaInView.x, this.worldAreaInView.y); + + this.squareToAspectRatio = vec2.fromValues( + this.worldAreaInView.x * scaleLongerEdgeTo1, + this.worldAreaInView.y * scaleLongerEdgeTo1 + ); + + this.scaleWorldLengthToNDC = scaleLongerEdgeTo1 * 2; + + mat2d.fromScaling( + this.transformWorldToNDC, + vec2.fromValues(this.scaleWorldLengthToNDC, this.scaleWorldLengthToNDC) + ); + mat2d.translate( + this.transformWorldToNDC, + this.transformWorldToNDC, + vec2.fromValues( + -this.viewAreaBottomLeft.x - 0.5 * this.worldAreaInView.x, + -this.viewAreaBottomLeft.y - 0.5 * this.worldAreaInView.y + ) + ); + + this.uvToWorld = mat2d.fromTranslation(mat2d.create(), this.viewAreaBottomLeft); + mat2d.scale(this.uvToWorld, this.uvToWorld, this.worldAreaInView); + } + + public setCursorPosition(position: vec2): void { + this.cursorPosition = position; + } +} diff --git a/src/graphics/rendering/webgl2-renderer.ts b/src/graphics/rendering/webgl2-renderer.ts new file mode 100644 index 0000000..2d507ba --- /dev/null +++ b/src/graphics/rendering/webgl2-renderer.ts @@ -0,0 +1,126 @@ +import { vec2 } from 'gl-matrix'; +import { IDrawable } from '../drawables/i-drawable'; +import { CircleLight } from '../drawables/lights/circle-light'; +import { Flashlight } from '../drawables/lights/flashlight'; +import { ILight } from '../drawables/lights/i-light'; +import { DefaultFrameBuffer } from '../graphics-library/frame-buffer/default-frame-buffer'; +import { IntermediateFrameBuffer } from '../graphics-library/frame-buffer/intermediate-frame-buffer'; +import { getWebGl2Context } from '../graphics-library/helper/get-webgl2-context'; +import { WebGlStopwatch } from '../graphics-library/helper/stopwatch'; +import { IRenderer } from '../i-renderer'; +import distanceFragmentShader from '../shaders/distance-fs.glsl'; +import distanceVertexShader from '../shaders/distance-vs.glsl'; +import lightsFragmentShader from '../shaders/shading-fs.glsl'; +import lightsVertexShader from '../shaders/shading-vs.glsl'; +import { FpsAutoscaler } from './fps-autoscaler'; +import { RenderingPass } from './rendering-pass'; +import { UniformsProvider } from './uniforms-provider'; + +export class WebGl2Renderer implements IRenderer { + private gl: WebGL2RenderingContext; + private stopwatch?: WebGlStopwatch; + private uniformsProvider: UniformsProvider; + private distanceFieldFrameBuffer: IntermediateFrameBuffer; + private lightingFrameBuffer: DefaultFrameBuffer; + private distancePass: RenderingPass; + private lightingPass: RenderingPass; + private autoscaler: FpsAutoscaler; + + private initializePromise: Promise<[void, void]>; + + constructor(private canvas: HTMLCanvasElement, private overlay: HTMLElement) { + this.gl = getWebGl2Context(canvas); + + this.distanceFieldFrameBuffer = new IntermediateFrameBuffer(this.gl); + this.lightingFrameBuffer = new DefaultFrameBuffer(this.gl); + + this.distancePass = new RenderingPass( + this.gl, + [distanceVertexShader, distanceFragmentShader], + [], + this.distanceFieldFrameBuffer + ); + + this.lightingPass = new RenderingPass( + this.gl, + [lightsVertexShader, lightsFragmentShader], + [CircleLight.descriptor, Flashlight.descriptor], + this.lightingFrameBuffer + ); + + this.initializePromise = Promise.all([ + this.distancePass.initialize(), + this.lightingPass.initialize(), + ]); + + this.uniformsProvider = new UniformsProvider(this.gl); + + this.autoscaler = new FpsAutoscaler({ + distanceRenderScale: (v) => + (this.distanceFieldFrameBuffer.renderScale = v as number), + finalRenderScale: (v) => (this.lightingFrameBuffer.renderScale = v as number), + softShadowsEnabled: (v) => + (this.uniformsProvider.softShadowsEnabled = v as boolean), + }); + + try { + this.stopwatch = new WebGlStopwatch(this.gl); + } catch { + // no problem + } + } + + public async initialize(): Promise { + await this.initializePromise; + } + + public drawShape(shape: IDrawable) { + this.distancePass.addDrawable(shape); + } + + public drawLight(light: ILight) { + this.lightingPass.addDrawable(light); + } + + public startFrame(deltaTime: DOMHighResTimeStamp) { + this.autoscaler.autoscale(deltaTime); + + this.stopwatch?.start(); + + this.distanceFieldFrameBuffer.setSize(); + this.lightingFrameBuffer.setSize(); + } + + public finishFrame() { + const common = { + distanceNdcPixelSize: 2 / Math.max(...this.distanceFieldFrameBuffer.getSize()), + shadingNdcPixelSize: 2 / Math.max(...this.distanceFieldFrameBuffer.getSize()), + }; + + this.distancePass.render(this.uniformsProvider.getUniforms(common)); + this.lightingPass.render( + this.uniformsProvider.getUniforms(common), + this.distanceFieldFrameBuffer.colorTexture + ); + + this.stopwatch?.stop(); + } + + public setViewArea(topLeft: vec2, size: vec2) { + this.uniformsProvider.setViewArea(topLeft, size); + } + + public setCursorPosition(position: vec2) { + this.uniformsProvider.setCursorPosition(position); + } + + public get canvasSize(): vec2 { + return vec2.fromValues(this.canvas.clientWidth, this.canvas.clientHeight); + } + + public drawInfoText(text: string) { + if (this.overlay.innerText != text) { + this.overlay.innerText = text; + } + } +} diff --git a/src/graphics/settings.ts b/src/graphics/settings.ts new file mode 100644 index 0000000..5d101c1 --- /dev/null +++ b/src/graphics/settings.ts @@ -0,0 +1,59 @@ +export const settings = { + enableHighDpiRendering: true, + qualityScaling: { + targetDeltaTimeInMilliseconds: 20, + deltaTimeError: 2, + deltaTimeResponsiveness: 1 / 16, + adjusmentRateInMilliseconds: 300, + qualityTargets: [ + { + distanceRenderScale: 0.1, + finalRenderScale: 0.2, + softShadowsEnabled: false, + }, + { + distanceRenderScale: 0.1, + finalRenderScale: 0.6, + softShadowsEnabled: false, + }, + { + distanceRenderScale: 0.3, + finalRenderScale: 1.0, + softShadowsEnabled: false, + }, + { + distanceRenderScale: 0.3, + finalRenderScale: 1.0, + softShadowsEnabled: true, + }, + /*{ + distanceRenderScale: 1.0, + finalRenderScale: 1.5, + softShadowsEnabled: true, + }, + { + distanceRenderScale: 1.25, + finalRenderScale: 1.75, + softShadowsEnabled: true, + }, + { + distanceRenderScale: 2, + finalRenderScale: 2, + softShadowsEnabled: true, + },*/ + ], + startingTargetIndex: 2, + scalingOptions: { + additiveIncrease: 0.2, + multiplicativeDecrease: 1.05, + }, + }, + tileMultiplier: 8, + shaderMacros: {}, + shaderCombinations: { + lineSteps: [0, 1, 2, 4, 8, 16, 128], + blobSteps: [0, 1, 2, 8], + circleLightSteps: [0, 1], + flashlightSteps: [0, 1], + }, +}; diff --git a/src/graphics/shaders/distance-fs.glsl b/src/graphics/shaders/distance-fs.glsl new file mode 100644 index 0000000..2568796 --- /dev/null +++ b/src/graphics/shaders/distance-fs.glsl @@ -0,0 +1,109 @@ +#version 300 es + +precision lowp float; + +#define LINE_COUNT {lineCount} +#define BLOB_COUNT {blobCount} + +#define SURFACE_OFFSET 0.001 + +uniform float maxMinDistance; +uniform float distanceNdcPixelSize; + +in vec2 position; + +float smoothMin(float a, float b) +{ + const float k = 2.0; + + a = pow(a, k); + b = pow(b, k); + return pow((a * b) / (a + b), 1.0 / k); +} + +#if LINE_COUNT > 0 + uniform struct { + vec2 from; + vec2 toFromDelta; + float fromRadius; + float toRadius; + }[LINE_COUNT] lines; + + void lineMinDistance(inout float minDistance, inout float color) { + float myMinDistance = maxMinDistance; + for (int i = 0; i < LINE_COUNT; i++) { + vec2 targetFromDelta = position - lines[i].from; + vec2 toFromDelta = lines[i].toFromDelta; + + float h = clamp( + dot(targetFromDelta, toFromDelta) / dot(toFromDelta, toFromDelta), + 0.0, 1.0 + ); + + float lineDistance = -mix( + lines[i].fromRadius, lines[i].toRadius, h + ) + distance( + targetFromDelta, toFromDelta * h + ); + + myMinDistance = min(myMinDistance, lineDistance); + } + + color = mix(0.0, color, step(distanceNdcPixelSize + SURFACE_OFFSET, -myMinDistance)); + minDistance = -myMinDistance; + } +#endif + +#if BLOB_COUNT > 0 + uniform struct { + vec2 headCenter; + vec2 leftFootCenter; + vec2 rightFootCenter; + float headRadius; + float footRadius; + float k; + }[BLOB_COUNT] blobs; + + float circleMinDistance(vec2 circleCenter, float radius) { + return distance(position, circleCenter) - radius; + } + + void blobMinDistance(inout float minDistance, inout float color) { + for (int i = 0; i < BLOB_COUNT; i++) { + float headDistance = circleMinDistance(blobs[i].headCenter, blobs[i].headRadius); + float leftFootDistance = circleMinDistance(blobs[i].leftFootCenter, blobs[i].footRadius); + float rightFootDistance = circleMinDistance(blobs[i].rightFootCenter, blobs[i].footRadius); + + float res = min( + smoothMin(headDistance, leftFootDistance), + smoothMin(headDistance, rightFootDistance) + ); + + res = min(100.0, headDistance); + res = min(res, leftFootDistance); + res = min(res, rightFootDistance); + //color = mix(2.0, color, step(distanceUvPixelSize + SURFACE_OFFSET, res)); + minDistance = min(minDistance, res); + color = mix(2.0, color, step(distanceNdcPixelSize + SURFACE_OFFSET, res)); + } + } +#endif + +out vec2 fragmentColor; + +void main() { + float minDistance = -maxMinDistance; + float color = 0.0; + + #if LINE_COUNT > 0 + lineMinDistance(minDistance, color); + #endif + + #if BLOB_COUNT > 0 + blobMinDistance(minDistance, color); + #endif + + + // minDistance / 2.0: NDC to UV scale + fragmentColor = vec2((minDistance - SURFACE_OFFSET) / 2.0, color); +} diff --git a/src/graphics/shaders/distance-vs.glsl b/src/graphics/shaders/distance-vs.glsl new file mode 100644 index 0000000..0e54025 --- /dev/null +++ b/src/graphics/shaders/distance-vs.glsl @@ -0,0 +1,15 @@ +#version 300 es + +precision lowp float; + +uniform mat3 modelTransform; +uniform vec2 squareToAspectRatio; + +in vec4 vertexPosition; +out vec2 position; + +void main() { + vec3 vertexPosition2D = vec3(vertexPosition.xy, 1.0) * modelTransform; + gl_Position = vec4(vertexPosition2D.xy, 0.0, 1.0); + position = vertexPosition2D.xy * squareToAspectRatio; +} diff --git a/src/graphics/shaders/shading-fs.glsl b/src/graphics/shaders/shading-fs.glsl new file mode 100644 index 0000000..8a67946 --- /dev/null +++ b/src/graphics/shaders/shading-fs.glsl @@ -0,0 +1,176 @@ +#version 300 es + +precision lowp float; + +#define INFINITY 1000.0 +#define LIGHT_DROP_INSIDE_RATIO 0.3 +#define AMBIENT_LIGHT vec3(0.25, 0.15, 0.25) +#define SHADOW_HARDNESS 150.0 + +#define CIRCLE_LIGHT_COUNT {circleLightCount} +#define FLASHLIGHT_COUNT {flashlightCount} + +uniform bool softShadowsEnabled; +uniform vec2 squareToAspectRatioTimes2; +uniform float shadingNdcPixelSize; +uniform sampler2D distanceTexture; + +in vec2 position; +in vec2 uvCoordinates; + +vec3[3] colors = vec3[]( + vec3(0.4, 0.35, 0.6), // cave color + vec3(0.0, 1.0, 0.0), + vec3(0.0, 0.0, 1.0) +); + +float getDistance(in vec2 target, out vec3 color) { + vec4 values = texture(distanceTexture, target); + color = colors[int(values[1])]; + return values[0]; +} + +float getDistance(in vec2 target) { + return texture(distanceTexture, target)[0]; +} + +float softShadowTransparency(float startingDistance, float lightCenterDistance, vec2 direction) { + float rayLength = startingDistance; + float q = 1.0 / SHADOW_HARDNESS; + + for (int j = 0; j < 128; j++) { + float minDistance = getDistance(uvCoordinates + direction * rayLength); + + q = min(q, minDistance / rayLength); + rayLength += minDistance / 2.5; + + if (rayLength >= lightCenterDistance) { + return q * SHADOW_HARDNESS; + } + } + + return 0.0; +} + +float hardShadowTransparency(float startingDistance, float lightCenterDistance, vec2 direction) { + float rayLength = startingDistance; + + for (int j = 0; j < 32; j++) { + rayLength += getDistance(uvCoordinates + direction * rayLength); + } + + return step(lightCenterDistance, rayLength); +} + +float shadowTransparency(float startingDistance, float lightCenterDistance, vec2 direction) { + return softShadowsEnabled ? + softShadowTransparency(startingDistance, lightCenterDistance, direction) : + hardShadowTransparency(startingDistance, lightCenterDistance, direction); +} + + +#if CIRCLE_LIGHT_COUNT > 0 + uniform struct CircleLight { + vec2 center; + float lightDrop; + vec3 value; + }[CIRCLE_LIGHT_COUNT] circleLights; + + in vec2[CIRCLE_LIGHT_COUNT] circleLightDirections; + + vec3 colorInPosition(CircleLight light, out float lightCenterDistance) { + lightCenterDistance = distance(light.center, position); + return light.value / pow( + lightCenterDistance / light.lightDrop + 1.0, 2.0 + ); + } + + vec3 colorInPositionInside(CircleLight light) { + float lightCenterDistance = distance(light.center, position); + return light.value / pow( + lightCenterDistance / (light.lightDrop * LIGHT_DROP_INSIDE_RATIO) + 1.0, 2.0 + ); + } +#endif + +#if FLASHLIGHT_COUNT > 0 + uniform struct Flashlight { + vec2 center; + vec2 direction; + float lightDrop; + vec3 value; + }[FLASHLIGHT_COUNT] flashlights; + + in vec2[FLASHLIGHT_COUNT] flashlightDirections; + + float intensityInDirection(vec2 lightDirection, vec2 targetDirection) { + return smoothstep(0.0, 1.0, 10.0 * max(0.0, dot(targetDirection, lightDirection) - 0.9)); + } + + vec3 colorInPosition(Flashlight light, vec2 positionDirection, out float lightCenterDistance) { + lightCenterDistance = distance(light.center, position); + return intensityInDirection(light.direction, positionDirection) * light.value / pow( + lightCenterDistance / light.lightDrop + 1.0, 2.0 + ); + } + + vec3 colorInPositionInside(Flashlight light, vec2 positionDirection) { + float lightCenterDistance = distance(light.center, position); + return intensityInDirection(light.direction, positionDirection) * light.value / pow( + lightCenterDistance / (light.lightDrop * LIGHT_DROP_INSIDE_RATIO) + 1.0, 2.0 + ); + } +#endif + +out vec4 fragmentColor; +void main() { + vec3 lighting = AMBIENT_LIGHT; + + vec3 colorAtPosition; + float startingDistance = getDistance(uvCoordinates, colorAtPosition); + + if (startingDistance < 0.0) { + #if CIRCLE_LIGHT_COUNT > 0 + for (int i = 0; i < CIRCLE_LIGHT_COUNT; i++) { + lighting += colorInPositionInside(circleLights[i]); + } + #endif + + #if FLASHLIGHT_COUNT > 0 + for (int i = 0; i < FLASHLIGHT_COUNT; i++) { + lighting += colorInPositionInside(flashlights[i], normalize(flashlightDirections[i])); + } + #endif + } else { + colorAtPosition = vec3(1.0); + + #if CIRCLE_LIGHT_COUNT > 0 + for (int i = 0; i < CIRCLE_LIGHT_COUNT; i++) { + vec2 direction = normalize(circleLightDirections[i]) / squareToAspectRatioTimes2; + + float lightCenterDistance; + vec3 lightColorAtPosition = colorInPosition(circleLights[i], lightCenterDistance); + + lighting += lightColorAtPosition * shadowTransparency(startingDistance, lightCenterDistance, direction); + } + #endif + + #if FLASHLIGHT_COUNT > 0 + for (int i = 0; i < FLASHLIGHT_COUNT; i++) { + vec2 originalDirection = normalize(flashlightDirections[i]); + vec2 direction = originalDirection / squareToAspectRatioTimes2; + + float lightCenterDistance; + vec3 lightColorAtPosition = colorInPosition(flashlights[i], originalDirection, lightCenterDistance); + + if (length(lightColorAtPosition) < 0.01) { + continue; + } + + lighting += lightColorAtPosition * shadowTransparency(startingDistance, lightCenterDistance, direction); + } + #endif + } + + fragmentColor = vec4(colorAtPosition * lighting, 1.0); +} diff --git a/src/graphics/shaders/shading-vs.glsl b/src/graphics/shaders/shading-vs.glsl new file mode 100644 index 0000000..5d13acf --- /dev/null +++ b/src/graphics/shaders/shading-vs.glsl @@ -0,0 +1,59 @@ +#version 300 es + +precision lowp float; + +#define CIRCLE_LIGHT_COUNT {circleLightCount} +#define FLASHLIGHT_COUNT {flashlightCount} + +uniform mat3 modelTransform; +in vec4 vertexPosition; + +out vec2 position; +out vec2 uvCoordinates; + +uniform vec2 squareToAspectRatio; + +#if CIRCLE_LIGHT_COUNT > 0 + uniform struct CircleLight { + vec2 center; + float lightDrop; + vec3 value; + }[CIRCLE_LIGHT_COUNT] circleLights; + + out vec2[CIRCLE_LIGHT_COUNT] circleLightDirections; +#endif + +#if FLASHLIGHT_COUNT > 0 + uniform struct Flashlight { + vec2 center; + vec2 direction; + float lightDrop; + vec3 value; + }[FLASHLIGHT_COUNT] flashlights; + + out vec2[FLASHLIGHT_COUNT] flashlightDirections; +#endif + +void main() { + vec3 vertexPosition2D = vec3(vertexPosition.xy, 1.0) * modelTransform; + gl_Position = vec4(vertexPosition2D.xy, 0.0, 1.0); + position = vertexPosition2D.xy * squareToAspectRatio; + + uvCoordinates = (vertexPosition2D * mat3( + 0.5, 0.0, 0.5, + 0.0, 0.5, 0.5, + 0.0, 0.0, 1.0 + )).xy; + + #if CIRCLE_LIGHT_COUNT > 0 + for (int i = 0; i < CIRCLE_LIGHT_COUNT; i++) { + circleLightDirections[i] = circleLights[i].center - position; + } + #endif + + #if FLASHLIGHT_COUNT > 0 + for (int i = 0; i < FLASHLIGHT_COUNT; i++) { + flashlightDirections[i] = flashlights[i].center - position; + } + #endif +} diff --git a/src/helper/array.ts b/src/helper/array.ts new file mode 100644 index 0000000..bcde98b --- /dev/null +++ b/src/helper/array.ts @@ -0,0 +1,49 @@ +declare global { + interface Array { + x: number; + y: number; + } + + interface Float32Array { + x: number; + y: number; + } +} + +export const applyArrayPlugins = () => { + Object.defineProperty(Array.prototype, 'x', { + get() { + return this[0]; + }, + set(value) { + this[0] = value; + }, + }); + + Object.defineProperty(Array.prototype, 'y', { + get() { + return this[1]; + }, + set(value) { + this[1] = value; + }, + }); + + Object.defineProperty(Float32Array.prototype, 'x', { + get() { + return this[0]; + }, + set(value) { + this[0] = value; + }, + }); + + Object.defineProperty(Float32Array.prototype, 'y', { + get() { + return this[1]; + }, + set(value) { + this[1] = value; + }, + }); +}; diff --git a/src/helper/autoscaler.ts b/src/helper/autoscaler.ts new file mode 100644 index 0000000..98d0ffa --- /dev/null +++ b/src/helper/autoscaler.ts @@ -0,0 +1,59 @@ +import { clamp } from './clamp'; +import { mix } from './mix'; + +export class Autoscaler { + // can have fractions + private index: number; + + constructor( + private setters: { [key: string]: (value: number | boolean) => void }, + private targets: Array<{ [key: string]: number | boolean }>, + startingIndex: number, + private scalingOptions: { + additiveIncrease: number; + multiplicativeDecrease: number; + } + ) { + this.index = startingIndex; + this.applyScaling(); + } + + public increase() { + this.index += this.scalingOptions.additiveIncrease; + this.applyScaling(); + } + + public decrease() { + this.index /= this.scalingOptions.multiplicativeDecrease; + this.applyScaling(); + } + + private applyScaling() { + this.index = clamp(this.index, 0, this.targets.length - 1); + + const floor = Math.floor(this.index); + const fract = this.index - floor; + + const previousTarget = this.targets[floor]; + const nextTarget = + floor + 1 == this.targets.length ? previousTarget : this.targets[floor + 1]; + + const result = {}; + for (const key in this.setters) { + const previous = previousTarget[key]; + const next = nextTarget[key]; + let current: number | boolean; + if (typeof previous == 'number') { + current = mix(previous, next as number, fract); + } else { + current = next; + } + + result[key] = current; + + this.setters[key](current); + } + + //InfoText.modifyRecord('quality', result); + } +} diff --git a/src/helper/clamp.ts b/src/helper/clamp.ts new file mode 100644 index 0000000..45da555 --- /dev/null +++ b/src/helper/clamp.ts @@ -0,0 +1,4 @@ +export const clamp = (value: number, min: number, max: number): number => + Math.min(max, Math.max(min, value)); + +export const clamp01 = (value: number): number => Math.min(1, Math.max(0, value)); diff --git a/src/helper/exponential-decay.ts b/src/helper/exponential-decay.ts new file mode 100644 index 0000000..7f321f5 --- /dev/null +++ b/src/helper/exponential-decay.ts @@ -0,0 +1,5 @@ +export const exponentialDecay = ( + accumulator: number, + nextValue: number, + biasOfNextValue: number +) => accumulator * (1 - biasOfNextValue) + nextValue * biasOfNextValue; diff --git a/src/helper/get-combinations.ts b/src/helper/get-combinations.ts new file mode 100644 index 0000000..42c36d6 --- /dev/null +++ b/src/helper/get-combinations.ts @@ -0,0 +1,29 @@ +export const getCombinations = (values: Array>): Array> => { + if (!values.every((a) => a.length > 0)) { + return []; + } + + const result: Array> = []; + const counters = values.map((_) => 0); + + const increaseCounter = (i: number) => { + if (i >= counters.length) { + return false; + } + + counters[i]++; + + if (counters[i] >= values[i].length) { + counters[i] = 0; + return increaseCounter(i + 1); + } + + return true; + }; + + do { + result.push(values.map((v, i) => v[counters[i]])); + } while (increaseCounter(0)); + + return result; +}; diff --git a/src/helper/last.ts b/src/helper/last.ts new file mode 100644 index 0000000..5c319b0 --- /dev/null +++ b/src/helper/last.ts @@ -0,0 +1,3 @@ +export function last(a: Array): T | null { + return a.length > 0 ? a[a.length - 1] : null; +} diff --git a/src/helper/mix.ts b/src/helper/mix.ts new file mode 100644 index 0000000..16a76ed --- /dev/null +++ b/src/helper/mix.ts @@ -0,0 +1 @@ +export const mix = (from: number, to: number, q: number) => from + (to - from) * q; diff --git a/src/helper/random.ts b/src/helper/random.ts new file mode 100644 index 0000000..10e93bb --- /dev/null +++ b/src/helper/random.ts @@ -0,0 +1,18 @@ +// src +// https://stackoverflow.com/questions/521295/seeding-the-random-number-generator-in-javascript +// Mulberry32 + +export abstract class Random { + private static _seed = Math.random(); + + public static set seed(value: number) { + Random._seed = value; + } + + public static getRandom(): number { + let t = (Random._seed += 0x6d2b79f5); + t = Math.imul(t ^ (t >>> 15), t | 1); + t ^= t + Math.imul(t ^ (t >>> 7), t | 61); + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; + } +} diff --git a/src/helper/rotate-90-deg.ts b/src/helper/rotate-90-deg.ts new file mode 100644 index 0000000..1911a63 --- /dev/null +++ b/src/helper/rotate-90-deg.ts @@ -0,0 +1,3 @@ +import { vec2 } from 'gl-matrix'; + +export const rotate90Deg = (vec: vec2): vec2 => vec2.fromValues(-vec.y, vec.x); diff --git a/src/helper/timing.ts b/src/helper/timing.ts new file mode 100644 index 0000000..529c715 --- /dev/null +++ b/src/helper/timing.ts @@ -0,0 +1,32 @@ +export function timeIt(interval = 60) { + return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { + let i = 0; + let previousTimes: Array = []; + + const targetFunction = descriptor.value; + + descriptor.value = function (...values) { + const start = performance.now(); + targetFunction.bind(this)(...values); + const end = performance.now(); + + previousTimes.push(end - start); + + if (i++ % interval == 0) { + previousTimes = previousTimes.sort(); + + /*const text = `Max: ${last(previousTimes).toFixed( + 2 + )} ms\n\tMedian: ${previousTimes[Math.floor(previousTimes.length / 2)].toFixed( + 2 + )} ms`;*/ + + //InfoText.modifyRecord(propertyKey, text); + + previousTimes = []; + } + }; + + return descriptor; + }; +} diff --git a/src/helper/to-percent.ts b/src/helper/to-percent.ts new file mode 100644 index 0000000..0047591 --- /dev/null +++ b/src/helper/to-percent.ts @@ -0,0 +1 @@ +export const toPercent = (value: number) => `${Math.round(value * 100)}%`; diff --git a/src/helper/wait-while-false.ts b/src/helper/wait-while-false.ts new file mode 100644 index 0000000..1e0f708 --- /dev/null +++ b/src/helper/wait-while-false.ts @@ -0,0 +1,29 @@ +export const waitWhileFalse = (body: () => boolean): Promise => { + let resolveOnDone: () => void; + let rejectOnDone: (e: Error) => void; + + const onDone = new Promise((resolve, reject) => { + resolveOnDone = resolve; + rejectOnDone = reject; + }); + + const waiter = () => { + let success: boolean; + + try { + success = body(); + } catch (e) { + rejectOnDone(e); + return; + } + + if (success) { + resolveOnDone(); + } else { + requestAnimationFrame(waiter); + } + }; + + waiter(); + return onDone; +}; diff --git a/src/helper/wait.ts b/src/helper/wait.ts new file mode 100644 index 0000000..73dd2c2 --- /dev/null +++ b/src/helper/wait.ts @@ -0,0 +1,3 @@ +export const wait = (ms: number): Promise => { + return new Promise((resolve, _) => setTimeout(resolve, ms)); +}; diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..2f44057 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,18 @@ +import { glMatrix } from 'gl-matrix'; +import { applyArrayPlugins } from './helper/array'; +import { Random } from './helper/random'; + +glMatrix.setMatrixArrayType(Array); +applyArrayPlugins(); + +const main = async () => { + try { + Random.seed = 42; + //await new Game().start(); + } catch (e) { + console.error(e); + alert(e); + } +}; + +main(); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..5ccffe4 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "outDir": "build", + "sourceMap": true, + "noImplicitAny": false, + "target": "es5", + "downlevelIteration": true, + "allowJs": true, + "esModuleInterop": true, + "strict": true, + "experimentalDecorators": true, + "moduleResolution": "Node", + "module": "commonjs", + "declaration": true, + "lib": ["es2015", "dom"] + } +} diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..805691f --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,73 @@ +const path = require('path'); +const TerserJSPlugin = require('terser-webpack-plugin'); + +const isProduction = process.env.NODE_ENV == 'production'; +const isDevelopment = !isProduction; + +module.exports = { + devtool: 'inline-source-map', + optimization: { + minimize: true, + minimizer: [ + new TerserJSPlugin({ + sourceMap: isDevelopment, + cache: true, + test: /\.ts$/i, + terserOptions: { + ecma: 5, + warnings: true, + parse: {}, + compress: { defaults: true }, + mangle: true, + module: false, + output: null, + toplevel: true, + nameCache: null, + ie8: false, + keep_classnames: false, + keep_fnames: false, + safari10: false, + }, + }), + ], + }, + plugins: [], + entry: { + main: './src/main.ts', + }, + module: { + rules: [ + { + test: /\.(glsl)$/, + use: { + loader: 'raw-loader', + }, + }, + { + test: /\.(woff2?|ttf|eot|svg)(?:[?#].+)?$/, + use: { + loader: 'file-loader', + options: { + name: '[name].[ext]', + outputPath: 'static/fonts/', + }, + }, + include: /fonts/, + }, + { + test: /\.ts$/, + use: { + loader: 'ts-loader', + }, + exclude: /node_modules/, + }, + ], + }, + resolve: { + extensions: ['.ts', '.js', '.glsl'], + }, + output: { + filename: '[name]-bundle.js', + path: path.resolve(__dirname, 'build'), + }, +};