UNPKG

@engaging-computing/aframe-physics-system

Version:

Physics system for A-Frame VR, built on Cannon.js

1,993 lines (1,693 loc) 530 kB
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ var CANNON = require('cannon-es'); require('./src/components/math'); require('./src/components/body/ammo-body'); require('./src/components/body/body'); require('./src/components/body/dynamic-body'); require('./src/components/body/static-body'); require('./src/components/shape/shape'); require('./src/components/shape/ammo-shape') require('./src/components/ammo-constraint'); require('./src/components/constraint'); require('./src/components/spring'); require('./src/system'); module.exports = { registerAll: function () { console.warn('registerAll() is deprecated. Components are automatically registered.'); } }; // Export CANNON.js. window.CANNON = window.CANNON || CANNON; },{"./src/components/ammo-constraint":8,"./src/components/body/ammo-body":9,"./src/components/body/body":10,"./src/components/body/dynamic-body":11,"./src/components/body/static-body":12,"./src/components/constraint":13,"./src/components/math":14,"./src/components/shape/ammo-shape":16,"./src/components/shape/shape":17,"./src/components/spring":18,"./src/system":28,"cannon-es":4}],2:[function(require,module,exports){ /** * CANNON.shape2mesh * * Source: http://schteppe.github.io/cannon.js/build/cannon.demo.js * Author: @schteppe */ var CANNON = require('cannon-es'); CANNON.shape2mesh = function(body){ var obj = new THREE.Object3D(); for (var l = 0; l < body.shapes.length; l++) { var shape = body.shapes[l]; var mesh; switch(shape.type){ case CANNON.Shape.types.SPHERE: var sphere_geometry = new THREE.SphereGeometry( shape.radius, 8, 8); mesh = new THREE.Mesh( sphere_geometry, this.currentMaterial ); break; case CANNON.Shape.types.PARTICLE: mesh = new THREE.Mesh( this.particleGeo, this.particleMaterial ); var s = this.settings; mesh.scale.set(s.particleSize,s.particleSize,s.particleSize); break; case CANNON.Shape.types.PLANE: var geometry = new THREE.PlaneGeometry(10, 10, 4, 4); mesh = new THREE.Object3D(); var submesh = new THREE.Object3D(); var ground = new THREE.Mesh( geometry, this.currentMaterial ); ground.scale.set(100, 100, 100); submesh.add(ground); ground.castShadow = true; ground.receiveShadow = true; mesh.add(submesh); break; case CANNON.Shape.types.BOX: var box_geometry = new THREE.BoxGeometry( shape.halfExtents.x*2, shape.halfExtents.y*2, shape.halfExtents.z*2 ); mesh = new THREE.Mesh( box_geometry, this.currentMaterial ); break; case CANNON.Shape.types.CONVEXPOLYHEDRON: var geo = new THREE.Geometry(); // Add vertices for (var i = 0; i < shape.vertices.length; i++) { var v = shape.vertices[i]; geo.vertices.push(new THREE.Vector3(v.x, v.y, v.z)); } for(var i=0; i < shape.faces.length; i++){ var face = shape.faces[i]; // add triangles var a = face[0]; for (var j = 1; j < face.length - 1; j++) { var b = face[j]; var c = face[j + 1]; geo.faces.push(new THREE.Face3(a, b, c)); } } geo.computeBoundingSphere(); geo.computeFaceNormals(); mesh = new THREE.Mesh( geo, this.currentMaterial ); break; case CANNON.Shape.types.HEIGHTFIELD: var geometry = new THREE.Geometry(); var v0 = new CANNON.Vec3(); var v1 = new CANNON.Vec3(); var v2 = new CANNON.Vec3(); for (var xi = 0; xi < shape.data.length - 1; xi++) { for (var yi = 0; yi < shape.data[xi].length - 1; yi++) { for (var k = 0; k < 2; k++) { shape.getConvexTrianglePillar(xi, yi, k===0); v0.copy(shape.pillarConvex.vertices[0]); v1.copy(shape.pillarConvex.vertices[1]); v2.copy(shape.pillarConvex.vertices[2]); v0.vadd(shape.pillarOffset, v0); v1.vadd(shape.pillarOffset, v1); v2.vadd(shape.pillarOffset, v2); geometry.vertices.push( new THREE.Vector3(v0.x, v0.y, v0.z), new THREE.Vector3(v1.x, v1.y, v1.z), new THREE.Vector3(v2.x, v2.y, v2.z) ); var i = geometry.vertices.length - 3; geometry.faces.push(new THREE.Face3(i, i+1, i+2)); } } } geometry.computeBoundingSphere(); geometry.computeFaceNormals(); mesh = new THREE.Mesh(geometry, this.currentMaterial); break; case CANNON.Shape.types.TRIMESH: var geometry = new THREE.Geometry(); var v0 = new CANNON.Vec3(); var v1 = new CANNON.Vec3(); var v2 = new CANNON.Vec3(); for (var i = 0; i < shape.indices.length / 3; i++) { shape.getTriangleVertices(i, v0, v1, v2); geometry.vertices.push( new THREE.Vector3(v0.x, v0.y, v0.z), new THREE.Vector3(v1.x, v1.y, v1.z), new THREE.Vector3(v2.x, v2.y, v2.z) ); var j = geometry.vertices.length - 3; geometry.faces.push(new THREE.Face3(j, j+1, j+2)); } geometry.computeBoundingSphere(); geometry.computeFaceNormals(); mesh = new THREE.Mesh(geometry, this.currentMaterial); break; default: throw "Visual type not recognized: "+shape.type; } mesh.receiveShadow = true; mesh.castShadow = true; if(mesh.children){ for(var i=0; i<mesh.children.length; i++){ mesh.children[i].castShadow = true; mesh.children[i].receiveShadow = true; if(mesh.children[i]){ for(var j=0; j<mesh.children[i].length; j++){ mesh.children[i].children[j].castShadow = true; mesh.children[i].children[j].receiveShadow = true; } } } } var o = body.shapeOffsets[l]; var q = body.shapeOrientations[l]; mesh.position.set(o.x, o.y, o.z); mesh.quaternion.set(q.x, q.y, q.z, q.w); obj.add(mesh); } return obj; }; module.exports = CANNON.shape2mesh; },{"cannon-es":4}],3:[function(require,module,exports){ /* global Ammo,THREE */ THREE.AmmoDebugConstants = { NoDebug: 0, DrawWireframe: 1, DrawAabb: 2, DrawFeaturesText: 4, DrawContactPoints: 8, NoDeactivation: 16, NoHelpText: 32, DrawText: 64, ProfileTimings: 128, EnableSatComparison: 256, DisableBulletLCP: 512, EnableCCD: 1024, DrawConstraints: 1 << 11, //2048 DrawConstraintLimits: 1 << 12, //4096 FastWireframe: 1 << 13, //8192 DrawNormals: 1 << 14, //16384 DrawOnTop: 1 << 15, //32768 MAX_DEBUG_DRAW_MODE: 0xffffffff }; /** * An implementation of the btIDebugDraw interface in Ammo.js, for debug rendering of Ammo shapes * @class AmmoDebugDrawer * @param {THREE.Scene} scene * @param {Ammo.btCollisionWorld} world * @param {object} [options] */ THREE.AmmoDebugDrawer = function(scene, world, options) { this.scene = scene; this.world = world; options = options || {}; this.debugDrawMode = options.debugDrawMode || THREE.AmmoDebugConstants.DrawWireframe; var drawOnTop = this.debugDrawMode & THREE.AmmoDebugConstants.DrawOnTop || false; var maxBufferSize = options.maxBufferSize || 1000000; this.geometry = new THREE.BufferGeometry(); var vertices = new Float32Array(maxBufferSize * 3); var colors = new Float32Array(maxBufferSize * 3); this.geometry.addAttribute("position", new THREE.BufferAttribute(vertices, 3).setDynamic(true)); this.geometry.addAttribute("color", new THREE.BufferAttribute(colors, 3).setDynamic(true)); this.index = 0; var material = new THREE.LineBasicMaterial({ vertexColors: THREE.VertexColors, depthTest: !drawOnTop }); this.mesh = new THREE.LineSegments(this.geometry, material); if (drawOnTop) this.mesh.renderOrder = 999; this.mesh.frustumCulled = false; this.enabled = false; this.debugDrawer = new Ammo.DebugDrawer(); this.debugDrawer.drawLine = this.drawLine.bind(this); this.debugDrawer.drawContactPoint = this.drawContactPoint.bind(this); this.debugDrawer.reportErrorWarning = this.reportErrorWarning.bind(this); this.debugDrawer.draw3dText = this.draw3dText.bind(this); this.debugDrawer.setDebugMode = this.setDebugMode.bind(this); this.debugDrawer.getDebugMode = this.getDebugMode.bind(this); this.debugDrawer.enable = this.enable.bind(this); this.debugDrawer.disable = this.disable.bind(this); this.debugDrawer.update = this.update.bind(this); this.world.setDebugDrawer(this.debugDrawer); }; THREE.AmmoDebugDrawer.prototype = function() { return this.debugDrawer; }; THREE.AmmoDebugDrawer.prototype.enable = function() { this.enabled = true; this.scene.add(this.mesh); }; THREE.AmmoDebugDrawer.prototype.disable = function() { this.enabled = false; this.scene.remove(this.mesh); }; THREE.AmmoDebugDrawer.prototype.update = function() { if (!this.enabled) { return; } if (this.index != 0) { this.geometry.attributes.position.needsUpdate = true; this.geometry.attributes.color.needsUpdate = true; } this.index = 0; this.world.debugDrawWorld(); this.geometry.setDrawRange(0, this.index); }; THREE.AmmoDebugDrawer.prototype.drawLine = function(from, to, color) { const heap = Ammo.HEAPF32; const r = heap[(color + 0) / 4]; const g = heap[(color + 4) / 4]; const b = heap[(color + 8) / 4]; const fromX = heap[(from + 0) / 4]; const fromY = heap[(from + 4) / 4]; const fromZ = heap[(from + 8) / 4]; this.geometry.attributes.position.setXYZ(this.index, fromX, fromY, fromZ); this.geometry.attributes.color.setXYZ(this.index++, r, g, b); const toX = heap[(to + 0) / 4]; const toY = heap[(to + 4) / 4]; const toZ = heap[(to + 8) / 4]; this.geometry.attributes.position.setXYZ(this.index, toX, toY, toZ); this.geometry.attributes.color.setXYZ(this.index++, r, g, b); }; //TODO: figure out how to make lifeTime work THREE.AmmoDebugDrawer.prototype.drawContactPoint = function(pointOnB, normalOnB, distance, lifeTime, color) { const heap = Ammo.HEAPF32; const r = heap[(color + 0) / 4]; const g = heap[(color + 4) / 4]; const b = heap[(color + 8) / 4]; const x = heap[(pointOnB + 0) / 4]; const y = heap[(pointOnB + 4) / 4]; const z = heap[(pointOnB + 8) / 4]; this.geometry.attributes.position.setXYZ(this.index, x, y, z); this.geometry.attributes.color.setXYZ(this.index++, r, g, b); const dx = heap[(normalOnB + 0) / 4] * distance; const dy = heap[(normalOnB + 4) / 4] * distance; const dz = heap[(normalOnB + 8) / 4] * distance; this.geometry.attributes.position.setXYZ(this.index, x + dx, y + dy, z + dz); this.geometry.attributes.color.setXYZ(this.index++, r, g, b); }; THREE.AmmoDebugDrawer.prototype.reportErrorWarning = function(warningString) { if (Ammo.hasOwnProperty("Pointer_stringify")) { console.warn(Ammo.Pointer_stringify(warningString)); } else if (!this.warnedOnce) { this.warnedOnce = true; console.warn("Cannot print warningString, please rebuild Ammo.js using 'debug' flag"); } }; THREE.AmmoDebugDrawer.prototype.draw3dText = function(location, textString) { //TODO console.warn("TODO: draw3dText"); }; THREE.AmmoDebugDrawer.prototype.setDebugMode = function(debugMode) { this.debugDrawMode = debugMode; }; THREE.AmmoDebugDrawer.prototype.getDebugMode = function() { return this.debugDrawMode; }; },{}],4:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); /** * Records what objects are colliding with each other * @class ObjectCollisionMatrix * @constructor */ var ObjectCollisionMatrix = /*#__PURE__*/function () { // The matrix storage. function ObjectCollisionMatrix() { this.matrix = {}; } /** * @method get * @param {Body} i * @param {Body} j * @return {boolean} */ var _proto = ObjectCollisionMatrix.prototype; _proto.get = function get(bi, bj) { var i = bi.id; var j = bj.id; if (j > i) { var temp = j; j = i; i = temp; } return i + "-" + j in this.matrix; } /** * @method set * @param {Body} i * @param {Body} j * @param {boolean} value */ ; _proto.set = function set(bi, bj, value) { var i = bi.id; var j = bj.id; if (j > i) { var temp = j; j = i; i = temp; } if (value) { this.matrix[i + "-" + j] = true; } else { delete this.matrix[i + "-" + j]; } } /** * Empty the matrix * @method reset */ ; _proto.reset = function reset() { this.matrix = {}; } /** * Set max number of objects * @method setNumObjects * @param {Number} n */ ; _proto.setNumObjects = function setNumObjects(n) {}; return ObjectCollisionMatrix; }(); /** * A 3x3 matrix. * @class Mat3 * @constructor * @param {Array} elements A vector of length 9, containing all matrix elements. Optional. * @author schteppe / http://github.com/schteppe */ var Mat3 = /*#__PURE__*/function () { function Mat3(elements) { if (elements === void 0) { elements = [0, 0, 0, 0, 0, 0, 0, 0, 0]; } this.elements = elements; } /** * Sets the matrix to identity * @method identity * @todo Should perhaps be renamed to setIdentity() to be more clear. * @todo Create another function that immediately creates an identity matrix eg. eye() */ var _proto = Mat3.prototype; _proto.identity = function identity() { var e = this.elements; e[0] = 1; e[1] = 0; e[2] = 0; e[3] = 0; e[4] = 1; e[5] = 0; e[6] = 0; e[7] = 0; e[8] = 1; } /** * Set all elements to zero * @method setZero */ ; _proto.setZero = function setZero() { var e = this.elements; e[0] = 0; e[1] = 0; e[2] = 0; e[3] = 0; e[4] = 0; e[5] = 0; e[6] = 0; e[7] = 0; e[8] = 0; } /** * Sets the matrix diagonal elements from a Vec3 * @method setTrace * @param {Vec3} vec3 */ ; _proto.setTrace = function setTrace(vector) { var e = this.elements; e[0] = vector.x; e[4] = vector.y; e[8] = vector.z; } /** * Gets the matrix diagonal elements * @method getTrace * @return {Vec3} */ ; _proto.getTrace = function getTrace(target) { if (target === void 0) { target = new Vec3(); } var e = this.elements; target.x = e[0]; target.y = e[4]; target.z = e[8]; } /** * Matrix-Vector multiplication * @method vmult * @param {Vec3} v The vector to multiply with * @param {Vec3} target Optional, target to save the result in. */ ; _proto.vmult = function vmult(v, target) { if (target === void 0) { target = new Vec3(); } var e = this.elements; var x = v.x; var y = v.y; var z = v.z; target.x = e[0] * x + e[1] * y + e[2] * z; target.y = e[3] * x + e[4] * y + e[5] * z; target.z = e[6] * x + e[7] * y + e[8] * z; return target; } /** * Matrix-scalar multiplication * @method smult * @param {Number} s */ ; _proto.smult = function smult(s) { for (var i = 0; i < this.elements.length; i++) { this.elements[i] *= s; } } /** * Matrix multiplication * @method mmult * @param {Mat3} matrix Matrix to multiply with from left side. * @return {Mat3} The result. */ ; _proto.mmult = function mmult(matrix, target) { if (target === void 0) { target = new Mat3(); } var elements = matrix.elements; for (var i = 0; i < 3; i++) { for (var j = 0; j < 3; j++) { var sum = 0.0; for (var k = 0; k < 3; k++) { sum += elements[i + k * 3] * this.elements[k + j * 3]; } target.elements[i + j * 3] = sum; } } return target; } /** * Scale each column of the matrix * @method scale * @param {Vec3} v * @return {Mat3} The result. */ ; _proto.scale = function scale(vector, target) { if (target === void 0) { target = new Mat3(); } var e = this.elements; var t = target.elements; for (var i = 0; i !== 3; i++) { t[3 * i + 0] = vector.x * e[3 * i + 0]; t[3 * i + 1] = vector.y * e[3 * i + 1]; t[3 * i + 2] = vector.z * e[3 * i + 2]; } return target; } /** * Solve Ax=b * @method solve * @param {Vec3} b The right hand side * @param {Vec3} target Optional. Target vector to save in. * @return {Vec3} The solution x * @todo should reuse arrays */ ; _proto.solve = function solve(b, target) { if (target === void 0) { target = new Vec3(); } // Construct equations var nr = 3; // num rows var nc = 4; // num cols var eqns = []; var i; var j; for (i = 0; i < nr * nc; i++) { eqns.push(0); } for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { eqns[i + nc * j] = this.elements[i + 3 * j]; } } eqns[3 + 4 * 0] = b.x; eqns[3 + 4 * 1] = b.y; eqns[3 + 4 * 2] = b.z; // Compute right upper triangular version of the matrix - Gauss elimination var n = 3; var k = n; var np; var kp = 4; // num rows var p; do { i = k - n; if (eqns[i + nc * i] === 0) { // the pivot is null, swap lines for (j = i + 1; j < k; j++) { if (eqns[i + nc * j] !== 0) { np = kp; do { // do ligne( i ) = ligne( i ) + ligne( k ) p = kp - np; eqns[p + nc * i] += eqns[p + nc * j]; } while (--np); break; } } } if (eqns[i + nc * i] !== 0) { for (j = i + 1; j < k; j++) { var multiplier = eqns[i + nc * j] / eqns[i + nc * i]; np = kp; do { // do ligne( k ) = ligne( k ) - multiplier * ligne( i ) p = kp - np; eqns[p + nc * j] = p <= i ? 0 : eqns[p + nc * j] - eqns[p + nc * i] * multiplier; } while (--np); } } } while (--n); // Get the solution target.z = eqns[2 * nc + 3] / eqns[2 * nc + 2]; target.y = (eqns[1 * nc + 3] - eqns[1 * nc + 2] * target.z) / eqns[1 * nc + 1]; target.x = (eqns[0 * nc + 3] - eqns[0 * nc + 2] * target.z - eqns[0 * nc + 1] * target.y) / eqns[0 * nc + 0]; if (isNaN(target.x) || isNaN(target.y) || isNaN(target.z) || target.x === Infinity || target.y === Infinity || target.z === Infinity) { throw "Could not solve equation! Got x=[" + target.toString() + "], b=[" + b.toString() + "], A=[" + this.toString() + "]"; } return target; } /** * Get an element in the matrix by index. Index starts at 0, not 1!!! * @method e * @param {Number} row * @param {Number} column * @param {Number} value Optional. If provided, the matrix element will be set to this value. * @return {Number} */ ; _proto.e = function e(row, column, value) { if (value === undefined) { return this.elements[column + 3 * row]; } else { // Set value this.elements[column + 3 * row] = value; } } /** * Copy another matrix into this matrix object. * @method copy * @param {Mat3} source * @return {Mat3} this */ ; _proto.copy = function copy(matrix) { for (var i = 0; i < matrix.elements.length; i++) { this.elements[i] = matrix.elements[i]; } return this; } /** * Returns a string representation of the matrix. * @method toString * @return string */ ; _proto.toString = function toString() { var r = ''; var sep = ','; for (var i = 0; i < 9; i++) { r += this.elements[i] + sep; } return r; } /** * reverse the matrix * @method reverse * @param {Mat3} target Optional. Target matrix to save in. * @return {Mat3} The solution x */ ; _proto.reverse = function reverse(target) { if (target === void 0) { target = new Mat3(); } // Construct equations var nr = 3; // num rows var nc = 6; // num cols var eqns = []; var i; var j; for (i = 0; i < nr * nc; i++) { eqns.push(0); } for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) { eqns[i + nc * j] = this.elements[i + 3 * j]; } } eqns[3 + 6 * 0] = 1; eqns[3 + 6 * 1] = 0; eqns[3 + 6 * 2] = 0; eqns[4 + 6 * 0] = 0; eqns[4 + 6 * 1] = 1; eqns[4 + 6 * 2] = 0; eqns[5 + 6 * 0] = 0; eqns[5 + 6 * 1] = 0; eqns[5 + 6 * 2] = 1; // Compute right upper triangular version of the matrix - Gauss elimination var n = 3; var k = n; var np; var kp = nc; // num rows var p; do { i = k - n; if (eqns[i + nc * i] === 0) { // the pivot is null, swap lines for (j = i + 1; j < k; j++) { if (eqns[i + nc * j] !== 0) { np = kp; do { // do line( i ) = line( i ) + line( k ) p = kp - np; eqns[p + nc * i] += eqns[p + nc * j]; } while (--np); break; } } } if (eqns[i + nc * i] !== 0) { for (j = i + 1; j < k; j++) { var multiplier = eqns[i + nc * j] / eqns[i + nc * i]; np = kp; do { // do line( k ) = line( k ) - multiplier * line( i ) p = kp - np; eqns[p + nc * j] = p <= i ? 0 : eqns[p + nc * j] - eqns[p + nc * i] * multiplier; } while (--np); } } } while (--n); // eliminate the upper left triangle of the matrix i = 2; do { j = i - 1; do { var _multiplier = eqns[i + nc * j] / eqns[i + nc * i]; np = nc; do { p = nc - np; eqns[p + nc * j] = eqns[p + nc * j] - eqns[p + nc * i] * _multiplier; } while (--np); } while (j--); } while (--i); // operations on the diagonal i = 2; do { var _multiplier2 = 1 / eqns[i + nc * i]; np = nc; do { p = nc - np; eqns[p + nc * i] = eqns[p + nc * i] * _multiplier2; } while (--np); } while (i--); i = 2; do { j = 2; do { p = eqns[nr + j + nc * i]; if (isNaN(p) || p === Infinity) { throw "Could not reverse! A=[" + this.toString() + "]"; } target.e(i, j, p); } while (j--); } while (i--); return target; } /** * Set the matrix from a quaterion * @method setRotationFromQuaternion * @param {Quaternion} q */ ; _proto.setRotationFromQuaternion = function setRotationFromQuaternion(q) { var x = q.x; var y = q.y; var z = q.z; var w = q.w; 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 e = this.elements; e[3 * 0 + 0] = 1 - (yy + zz); e[3 * 0 + 1] = xy - wz; e[3 * 0 + 2] = xz + wy; e[3 * 1 + 0] = xy + wz; e[3 * 1 + 1] = 1 - (xx + zz); e[3 * 1 + 2] = yz - wx; e[3 * 2 + 0] = xz - wy; e[3 * 2 + 1] = yz + wx; e[3 * 2 + 2] = 1 - (xx + yy); return this; } /** * Transpose the matrix * @method transpose * @param {Mat3} target Optional. Where to store the result. * @return {Mat3} The target Mat3, or a new Mat3 if target was omitted. */ ; _proto.transpose = function transpose(target) { if (target === void 0) { target = new Mat3(); } var Mt = target.elements; var M = this.elements; for (var i = 0; i !== 3; i++) { for (var j = 0; j !== 3; j++) { Mt[3 * i + j] = M[3 * j + i]; } } return target; }; return Mat3; }(); /** * 3-dimensional vector * @class Vec3 * @constructor * @param {Number} x * @param {Number} y * @param {Number} z * @author schteppe * @example * const v = new Vec3(1, 2, 3); * console.log('x=' + v.x); // x=1 */ var Vec3 = /*#__PURE__*/function () { function Vec3(x, y, z) { if (x === void 0) { x = 0.0; } if (y === void 0) { y = 0.0; } if (z === void 0) { z = 0.0; } this.x = x; this.y = y; this.z = z; } /** * Vector cross product * @method cross * @param {Vec3} v * @param {Vec3} target Optional. Target to save in. * @return {Vec3} */ var _proto = Vec3.prototype; _proto.cross = function cross(vector, target) { if (target === void 0) { target = new Vec3(); } var vx = vector.x; var vy = vector.y; var vz = vector.z; var x = this.x; var y = this.y; var z = this.z; target.x = y * vz - z * vy; target.y = z * vx - x * vz; target.z = x * vy - y * vx; return target; } /** * Set the vectors' 3 elements * @method set * @param {Number} x * @param {Number} y * @param {Number} z * @return Vec3 */ ; _proto.set = function set(x, y, z) { this.x = x; this.y = y; this.z = z; return this; } /** * Set all components of the vector to zero. * @method setZero */ ; _proto.setZero = function setZero() { this.x = this.y = this.z = 0; } /** * Vector addition * @method vadd * @param {Vec3} v * @param {Vec3} target Optional. * @return {Vec3} */ ; _proto.vadd = function vadd(vector, target) { if (target) { target.x = vector.x + this.x; target.y = vector.y + this.y; target.z = vector.z + this.z; } else { return new Vec3(this.x + vector.x, this.y + vector.y, this.z + vector.z); } } /** * Vector subtraction * @method vsub * @param {Vec3} v * @param {Vec3} target Optional. Target to save in. * @return {Vec3} */ ; _proto.vsub = function vsub(vector, target) { if (target) { target.x = this.x - vector.x; target.y = this.y - vector.y; target.z = this.z - vector.z; } else { return new Vec3(this.x - vector.x, this.y - vector.y, this.z - vector.z); } } /** * Get the cross product matrix a_cross from a vector, such that a x b = a_cross * b = c * @method crossmat * @see http://www8.cs.umu.se/kurser/TDBD24/VT06/lectures/Lecture6.pdf * @return {Mat3} */ ; _proto.crossmat = function crossmat() { return new Mat3([0, -this.z, this.y, this.z, 0, -this.x, -this.y, this.x, 0]); } /** * Normalize the vector. Note that this changes the values in the vector. * @method normalize * @return {Number} Returns the norm of the vector */ ; _proto.normalize = function normalize() { var x = this.x; var y = this.y; var z = this.z; var n = Math.sqrt(x * x + y * y + z * z); if (n > 0.0) { var invN = 1 / n; this.x *= invN; this.y *= invN; this.z *= invN; } else { // Make something up this.x = 0; this.y = 0; this.z = 0; } return n; } /** * Get the version of this vector that is of length 1. * @method unit * @param {Vec3} target Optional target to save in * @return {Vec3} Returns the unit vector */ ; _proto.unit = function unit(target) { if (target === void 0) { target = new Vec3(); } var x = this.x; var y = this.y; var z = this.z; var ninv = Math.sqrt(x * x + y * y + z * z); if (ninv > 0.0) { ninv = 1.0 / ninv; target.x = x * ninv; target.y = y * ninv; target.z = z * ninv; } else { target.x = 1; target.y = 0; target.z = 0; } return target; } /** * Get the length of the vector * @method length * @return {Number} */ ; _proto.length = function length() { var x = this.x; var y = this.y; var z = this.z; return Math.sqrt(x * x + y * y + z * z); } /** * Get the squared length of the vector. * @method lengthSquared * @return {Number} */ ; _proto.lengthSquared = function lengthSquared() { return this.dot(this); } /** * Get distance from this point to another point * @method distanceTo * @param {Vec3} p * @return {Number} */ ; _proto.distanceTo = function distanceTo(p) { var x = this.x; var y = this.y; var z = this.z; var px = p.x; var py = p.y; var pz = p.z; return Math.sqrt((px - x) * (px - x) + (py - y) * (py - y) + (pz - z) * (pz - z)); } /** * Get squared distance from this point to another point * @method distanceSquared * @param {Vec3} p * @return {Number} */ ; _proto.distanceSquared = function distanceSquared(p) { var x = this.x; var y = this.y; var z = this.z; var px = p.x; var py = p.y; var pz = p.z; return (px - x) * (px - x) + (py - y) * (py - y) + (pz - z) * (pz - z); } /** * Multiply all the components of the vector with a scalar. * @method scale * @param {Number} scalar * @param {Vec3} target The vector to save the result in. * @return {Vec3} */ ; _proto.scale = function scale(scalar, target) { if (target === void 0) { target = new Vec3(); } var x = this.x; var y = this.y; var z = this.z; target.x = scalar * x; target.y = scalar * y; target.z = scalar * z; return target; } /** * Multiply the vector with an other vector, component-wise. * @method vmult * @param {Number} vector * @param {Vec3} target The vector to save the result in. * @return {Vec3} */ ; _proto.vmul = function vmul(vector, target) { if (target === void 0) { target = new Vec3(); } target.x = vector.x * this.x; target.y = vector.y * this.y; target.z = vector.z * this.z; return target; } /** * Scale a vector and add it to this vector. Save the result in "target". (target = this + vector * scalar) * @method addScaledVector * @param {Number} scalar * @param {Vec3} vector * @param {Vec3} target The vector to save the result in. * @return {Vec3} */ ; _proto.addScaledVector = function addScaledVector(scalar, vector, target) { if (target === void 0) { target = new Vec3(); } target.x = this.x + scalar * vector.x; target.y = this.y + scalar * vector.y; target.z = this.z + scalar * vector.z; return target; } /** * Calculate dot product * @method dot * @param {Vec3} v * @return {Number} */ ; _proto.dot = function dot(vector) { return this.x * vector.x + this.y * vector.y + this.z * vector.z; } /** * @method isZero * @return bool */ ; _proto.isZero = function isZero() { return this.x === 0 && this.y === 0 && this.z === 0; } /** * Make the vector point in the opposite direction. * @method negate * @param {Vec3} target Optional target to save in * @return {Vec3} */ ; _proto.negate = function negate(target) { if (target === void 0) { target = new Vec3(); } target.x = -this.x; target.y = -this.y; target.z = -this.z; return target; } /** * Compute two artificial tangents to the vector * @method tangents * @param {Vec3} t1 Vector object to save the first tangent in * @param {Vec3} t2 Vector object to save the second tangent in */ ; _proto.tangents = function tangents(t1, t2) { var norm = this.length(); if (norm > 0.0) { var n = Vec3_tangents_n; var inorm = 1 / norm; n.set(this.x * inorm, this.y * inorm, this.z * inorm); var randVec = Vec3_tangents_randVec; if (Math.abs(n.x) < 0.9) { randVec.set(1, 0, 0); n.cross(randVec, t1); } else { randVec.set(0, 1, 0); n.cross(randVec, t1); } n.cross(t1, t2); } else { // The normal length is zero, make something up t1.set(1, 0, 0); t2.set(0, 1, 0); } } /** * Converts to a more readable format * @method toString * @return string */ ; _proto.toString = function toString() { return this.x + "," + this.y + "," + this.z; } /** * Converts to an array * @method toArray * @return Array */ ; _proto.toArray = function toArray() { return [this.x, this.y, this.z]; } /** * Copies value of source to this vector. * @method copy * @param {Vec3} source * @return {Vec3} this */ ; _proto.copy = function copy(vector) { this.x = vector.x; this.y = vector.y; this.z = vector.z; return this; } /** * Do a linear interpolation between two vectors * @method lerp * @param {Vec3} v * @param {Number} t A number between 0 and 1. 0 will make this function return u, and 1 will make it return v. Numbers in between will generate a vector in between them. * @param {Vec3} target */ ; _proto.lerp = function lerp(vector, t, target) { var x = this.x; var y = this.y; var z = this.z; target.x = x + (vector.x - x) * t; target.y = y + (vector.y - y) * t; target.z = z + (vector.z - z) * t; } /** * Check if a vector equals is almost equal to another one. * @method almostEquals * @param {Vec3} v * @param {Number} precision * @return bool */ ; _proto.almostEquals = function almostEquals(vector, precision) { if (precision === void 0) { precision = 1e-6; } if (Math.abs(this.x - vector.x) > precision || Math.abs(this.y - vector.y) > precision || Math.abs(this.z - vector.z) > precision) { return false; } return true; } /** * Check if a vector is almost zero * @method almostZero * @param {Number} precision */ ; _proto.almostZero = function almostZero(precision) { if (precision === void 0) { precision = 1e-6; } if (Math.abs(this.x) > precision || Math.abs(this.y) > precision || Math.abs(this.z) > precision) { return false; } return true; } /** * Check if the vector is anti-parallel to another vector. * @method isAntiparallelTo * @param {Vec3} v * @param {Number} precision Set to zero for exact comparisons * @return {Boolean} */ ; _proto.isAntiparallelTo = function isAntiparallelTo(vector, precision) { this.negate(antip_neg); return antip_neg.almostEquals(vector, precision); } /** * Clone the vector * @method clone * @return {Vec3} */ ; _proto.clone = function clone() { return new Vec3(this.x, this.y, this.z); }; return Vec3; }(); Vec3.ZERO = new Vec3(0, 0, 0); Vec3.UNIT_X = new Vec3(1, 0, 0); Vec3.UNIT_Y = new Vec3(0, 1, 0); Vec3.UNIT_Z = new Vec3(0, 0, 1); /** * Compute two artificial tangents to the vector * @method tangents * @param {Vec3} t1 Vector object to save the first tangent in * @param {Vec3} t2 Vector object to save the second tangent in */ var Vec3_tangents_n = new Vec3(); var Vec3_tangents_randVec = new Vec3(); var antip_neg = new Vec3(); /** * Axis aligned bounding box class. * @class AABB * @constructor * @param {Object} [options] * @param {Vec3} [options.upperBound] The upper bound of the bounding box. * @param {Vec3} [options.lowerBound] The lower bound of the bounding box */ var AABB = /*#__PURE__*/function () { // The lower bound of the bounding box // The upper bound of the bounding box function AABB(options) { if (options === void 0) { options = {}; } this.lowerBound = new Vec3(); this.upperBound = new Vec3(); if (options.lowerBound) { this.lowerBound.copy(options.lowerBound); } if (options.upperBound) { this.upperBound.copy(options.upperBound); } } /** * Set the AABB bounds from a set of points. * @method setFromPoints * @param {Array} points An array of Vec3's. * @param {Vec3} position Optional. * @param {Quaternion} quaternion Optional. * @param {number} skinSize Optional. * @return {AABB} The self object */ var _proto = AABB.prototype; _proto.setFromPoints = function setFromPoints(points, position, quaternion, skinSize) { var l = this.lowerBound; var u = this.upperBound; var q = quaternion; // Set to the first point l.copy(points[0]); if (q) { q.vmult(l, l); } u.copy(l); for (var i = 1; i < points.length; i++) { var p = points[i]; if (q) { q.vmult(p, tmp); p = tmp; } if (p.x > u.x) { u.x = p.x; } if (p.x < l.x) { l.x = p.x; } if (p.y > u.y) { u.y = p.y; } if (p.y < l.y) { l.y = p.y; } if (p.z > u.z) { u.z = p.z; } if (p.z < l.z) { l.z = p.z; } } // Add offset if (position) { position.vadd(l, l); position.vadd(u, u); } if (skinSize) { l.x -= skinSize; l.y -= skinSize; l.z -= skinSize; u.x += skinSize; u.y += skinSize; u.z += skinSize; } return this; } /** * Copy bounds from an AABB to this AABB * @method copy * @param {AABB} aabb Source to copy from * @return {AABB} The this object, for chainability */ ; _proto.copy = function copy(aabb) { this.lowerBound.copy(aabb.lowerBound); this.upperBound.copy(aabb.upperBound); return this; } /** * Clone an AABB * @method clone */ ; _proto.clone = function clone() { return new AABB().copy(this); } /** * Extend this AABB so that it covers the given AABB too. * @method extend * @param {AABB} aabb */ ; _proto.extend = function extend(aabb) { this.lowerBound.x = Math.min(this.lowerBound.x, aabb.lowerBound.x); this.upperBound.x = Math.max(this.upperBound.x, aabb.upperBound.x); this.lowerBound.y = Math.min(this.lowerBound.y, aabb.lowerBound.y); this.upperBound.y = Math.max(this.upperBound.y, aabb.upperBound.y); this.lowerBound.z = Math.min(this.lowerBound.z, aabb.lowerBound.z); this.upperBound.z = Math.max(this.upperBound.z, aabb.upperBound.z); } /** * Returns true if the given AABB overlaps this AABB. * @method overlaps * @param {AABB} aabb * @return {Boolean} */ ; _proto.overlaps = function overlaps(aabb) { var l1 = this.lowerBound; var u1 = this.upperBound; var l2 = aabb.lowerBound; var u2 = aabb.upperBound; // l2 u2 // |---------| // |--------| // l1 u1 var overlapsX = l2.x <= u1.x && u1.x <= u2.x || l1.x <= u2.x && u2.x <= u1.x; var overlapsY = l2.y <= u1.y && u1.y <= u2.y || l1.y <= u2.y && u2.y <= u1.y; var overlapsZ = l2.z <= u1.z && u1.z <= u2.z || l1.z <= u2.z && u2.z <= u1.z; return overlapsX && overlapsY && overlapsZ; } // Mostly for debugging ; _proto.volume = function volume() { var l = this.lowerBound; var u = this.upperBound; return (u.x - l.x) * (u.y - l.y) * (u.z - l.z); } /** * Returns true if the given AABB is fully contained in this AABB. * @method contains * @param {AABB} aabb * @return {Boolean} */ ; _proto.contains = function contains(aabb) { var l1 = this.lowerBound; var u1 = this.upperBound; var l2 = aabb.lowerBound; var u2 = aabb.upperBound; // l2 u2 // |---------| // |---------------| // l1 u1 return l1.x <= l2.x && u1.x >= u2.x && l1.y <= l2.y && u1.y >= u2.y && l1.z <= l2.z && u1.z >= u2.z; } /** * @method getCorners * @param {Vec3} a * @param {Vec3} b * @param {Vec3} c * @param {Vec3} d * @param {Vec3} e * @param {Vec3} f * @param {Vec3} g * @param {Vec3} h */ ; _proto.getCorners = function getCorners(a, b, c, d, e, f, g, h) { var l = this.lowerBound; var u = this.upperBound; a.copy(l); b.set(u.x, l.y, l.z); c.set(u.x, u.y, l.z); d.set(l.x, u.y, u.z); e.set(u.x, l.y, u.z); f.set(l.x, u.y, l.z); g.set(l.x, l.y, u.z); h.copy(u); } /** * Get the representation of an AABB in another frame. * @method toLocalFrame * @param {Transform} frame * @param {AABB} target * @return {AABB} The "target" AABB object. */ ; _proto.toLocalFrame = function toLocalFrame(frame, target) { var corners = transformIntoFrame_corners; var a = corners[0]; var b = corners[1]; var c = corners[2]; var d = corners[3]; var e = corners[4]; var f = corners[5]; var g = corners[6]; var h = corners[7]; // Get corners in current frame this.getCorners(a, b, c, d, e, f, g, h); // Transform them to new local frame for (var i = 0; i !== 8; i++) { var corner = corners[i]; frame.pointToLocal(corner, corner); } return target.setFromPoints(corners); } /** * Get the representation of an AABB in the global frame. * @method toWorldFrame * @param {Transform} frame * @param {AABB} target * @return {AABB} The "target" AABB object. */ ; _proto.toWorldFrame = function toWorldFrame(frame, target) { var corners = transformIntoFrame_corners; var a = corners[0]; var b = corners[1]; var c = corners[2]; var d = corners[3]; var e = corners[4]; var f = corners[5]; var g = corners[6]; var h = corners[7]; // Get corners in current frame this.getCorners(a, b, c, d, e, f, g, h); // Transform them to new local frame for (var i = 0; i !== 8; i++) { var corner = corners[i]; frame.pointToWorld(corner, corner); } return target.setFromPoints(corners); } /** * Check if the AABB is hit by a ray. * @param {Ray} ray * @return {Boolean} */ ; _proto.overlapsRay = function overlapsRay(ray) { var direction = ray.direction, from = ray.from; var dirFracX = 1 / direction.x; var dirFracY = 1 / direction.y; var dirFracZ = 1 / direction.z; // this.lowerBound is the corner of AABB with minimal coordinates - left bottom, rt is maximal corner var t1 = (this.lowerBound.x - from.x) * dirFracX; var t2 = (this.upperBound.x - from.x) * dirFracX; var t3 = (this.lowerBound.y - from.y) * dirFracY; var t4 = (this.upperBound.y - from.y) * dirFracY; var t5 = (this.lowerBound.z - from.z) * dirFracZ; var t6 = (this.upperBound.z - from.z) * dirFracZ; // const tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4))); // const tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4))); var tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)), Math.min(t5, t6)); var tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)), Math.max(t5, t6)); // if tmax < 0, ray (line) is intersecting AABB, but whole AABB is behing us if (tmax < 0) { //t = tmax; return false; } // if tmin > tmax, ray doesn't intersect AABB if (tmin > tmax) { //t = tmax; return false; } return true; }; return AABB; }(); var tmp = new Vec3(); var transformIntoFrame_corners = [new Vec3(), new Vec3(), new Vec3(), new Vec3(), new Vec3(), new Vec3(), new Vec3(), new Vec3()]; /** * Collision "matrix". It's actually a triangular-shaped array of whether two bodies are touching this step, for reference next step * @class ArrayCollisionMatrix * @constructor */ var ArrayCollisionMatrix = /*#__PURE__*/function () { // The matrix storage. function ArrayCollisionMatrix() { this.matrix = []; } /** * Get an element * @method get * @param {Body} i * @param {Body} j * @return {Number} */ var _proto = ArrayCollisionMatrix.prototype; _proto.get = function get(bi, bj) { var i = bi.index; var j = bj.index; if (j > i) { var temp = j; j = i; i = temp; } return this.matrix[(i * (i + 1) >> 1) + j - 1]; } /** * Set an element * @method set * @param {Body} i * @param {Body} j * @param {boolean} value */ ; _proto.set = function set(bi, bj, value) { var i = bi.index; var j = bj.index; if (j > i) { var temp = j; j = i; i = temp; } this.matrix[(i * (i + 1) >> 1) + j - 1] = value ? 1 : 0; } /** * Sets all elements to zero * @method reset */ ; _proto.reset = function reset() { for (var i = 0, l = this.matrix.length; i !== l; i++) { this.matrix[i] = 0; } } /** * Sets the max number of objects * @method setNumObjects * @param {Number} n */ ; _proto.setNumObjects = function setNumObjects(n) { this.matrix.length = n * (n - 1) >> 1; }; return ArrayCollisionMatrix; }(); function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } /** * Base class for objects that dispatches events. * @class EventTarget * @constructor */ var EventTarget = /*#__PURE__*/function () { function EventTarget() {} /** * Add an event listener * @method addEventListener * @param {String} type * @param {Function} listener * @return {EventTarget} The self object, for chainability. */ var _proto = EventTarget.prototype; _proto.addEventListener = function addEventListener(type, listener) { if (this._listeners === undefined) { this._listeners = {}; } var listeners = this._listeners; if (listeners[type] === undefined) { listeners[type] = []; } if (!listeners[type].includes(listener)) { listeners[type].push(listener); } return this; } /** * Check if an event listener is added * @method hasEventListener * @param {String} type * @param {Function} listener * @return {Boolean} */ ; _proto.hasEventListener = function hasEventListener(type, listener) { if (this._listeners === undefined) { return false; } var listeners = this._listeners; if (listeners[type] !== undefined && listeners[type].includes(listener)) { return true; } return false; } /** * Check if any event listener of the given type is added * @method hasAnyEventListener * @param {String} type * @return {Boolean} */ ; _proto.hasAnyEventListener = function hasAnyEventListener(type) { if (this._listeners === undefined) { return false; } var listeners = this._listeners; return listeners[type] !== undefined; } /** * Remove an event listener * @method removeEventListener * @param {String} type * @param {Function} listener * @return {EventTarget} The self object, for chainability. */ ; _proto.removeEventListener = function removeEventListener(type, listener) { if (this._listeners === undefined) { return this; } var listeners = this._listeners; if (listeners[type] === undefined) { return this; } var index = listeners[type].indexOf(listener); if (index !== -1) { listeners[type].splice(index, 1); } return this; } /** * Emit an event. * @method dispatchEvent * @param {Object} event * @param {String} event.type * @return {EventTarget} The self object, for chainability. */ ; _proto.dispatchEvent = function dispatchEvent(event) { if (this._listeners === undefined) { return this; } var listeners = this._listeners; var listenerArray = listeners[event.type]; if (listenerArray !== undefined) { event.target = this; for (var i = 0, l = listenerArray.length; i < l; i++) { listenerArray[i].call(this, event); } } return this; }; return EventTarget; }(); /** * A Quaternion describes a rotation in 3D space. The Quaternion is mathematically defined as Q = x*i + y*j + z*k + w, where (i,j,k) are imaginary basis vectors. (x,y,z) can be seen as a vector related to the axis of rotation, while the real multiplier, w, is related to the amount of rotation. * @param {Number} x Multiplier of the imaginary basis vector i. * @param {Number} y Multiplier of the imaginary basis vector j. * @param {Number} z Multiplier of t